Commit aeca9efa authored by Mahmoud Aglan's avatar Mahmoud Aglan

Add marketing site (Next.js 16 + Tailwind + Framer Motion)

Arabic-first landing page with pricing, features, about, and contact pages.
Includes business model docs and infrastructure capacity planning.
Co-Authored-By: 's avatarClaude Opus 4.6 <noreply@anthropic.com>
parent 0d159f8c
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/versions
# testing
/coverage
# next.js
/.next/
/out/
# production
/build
# misc
.DS_Store
*.pem
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*
# env files (can opt-in for committing if needed)
.env*
# vercel
.vercel
# typescript
*.tsbuildinfo
next-env.d.ts
<!-- BEGIN:nextjs-agent-rules -->
# This is NOT the Next.js you know
This version has breaking changes — APIs, conventions, and file structure may all differ from your training data. Read the relevant guide in `node_modules/next/dist/docs/` before writing any code. Heed deprecation notices.
<!-- END:nextjs-agent-rules -->
This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).
## Getting Started
First, run the development server:
```bash
npm run dev
# or
yarn dev
# or
pnpm dev
# or
bun dev
```
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
## Learn More
To learn more about Next.js, take a look at the following resources:
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
## Deploy on Vercel
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "base-nova",
"rsc": true,
"tsx": true,
"tailwind": {
"config": "",
"css": "src/app/globals.css",
"baseColor": "neutral",
"cssVariables": true,
"prefix": ""
},
"iconLibrary": "lucide",
"rtl": false,
"aliases": {
"components": "@/components",
"utils": "@/lib/utils",
"ui": "@/components/ui",
"lib": "@/lib",
"hooks": "@/hooks"
},
"menuColor": "default",
"menuAccent": "subtle",
"registries": {}
}
# El Captain — Marketing Website
Premium marketing site for the El Captain Sports Management SaaS platform.
## Concept
**"The Command Center"** — A clean, authoritative marketing site that sells control and clarity to Egyptian sports academy owners. The site demonstrates the product's power through interactive dashboard mockups, scroll-driven animations, and confident Arabic-first copy.
## Design Direction
- **Emotion:** Power & Control
- **Visual:** Clean & Trustworthy (Stripe-level clarity)
- **Audience:** Academy owners/directors in Egypt
- **Language:** Arabic-first (RTL), English toggle
## Stack
| Layer | Tech |
|-------|------|
| Framework | Next.js 14 (App Router) |
| Styling | Tailwind CSS 3.4 |
| Components | shadcn/ui (branded) |
| Animation | Framer Motion 11 |
| Icons | Lucide React |
| Fonts | Cairo (AR) + Inter (EN) |
| Deploy | Vercel |
## Documentation
| Document | Purpose |
|----------|---------|
| [Brand Guidelines](docs/brand-guidelines.md) | Colors, typography, voice, imagery rules |
| [Design System](docs/design-system.md) | Tokens, Tailwind config, component specs |
| [Site Specification](docs/site-specification.md) | Pages, SEO, performance, i18n, deploy |
| [Messaging Framework](docs/messaging-framework.md) | Copy strategy, elevator pitches, objection handling |
| [UX Strategy](docs/ux-strategy.md) | User journey, conversion, accessibility |
| [Animation Spec](docs/animation-spec.md) | Framer Motion variants, timing, scroll orchestration |
| [Wireframes](docs/wireframes.md) | ASCII layout wireframes (desktop + mobile) |
| [Implementation Plan](docs/implementation-plan.md) | Phased build schedule + decisions needed |
## Quick Start
```bash
# When ready to build:
npx create-next-app@latest . --typescript --tailwind --app --src-dir
npm install framer-motion lucide-react class-variance-authority clsx tailwind-merge
npx shadcn-ui@latest init
npm run dev
```
## Key Design Decisions
1. **No stock photos** — Product screenshots and geometric illustrations only
2. **No video autoplay** — Respects bandwidth (Egyptian mobile networks)
3. **Numbers as heroes** — Stats count up on scroll (builds credibility)
4. **WhatsApp floating** — Egyptian users expect instant messaging access
5. **Progressive disclosure** — Show 6 modules on homepage, full 14 on features page
6. **Scroll as narrative** — Problem → Solution → Proof → Action flow
# El Captain Marketing Site — Animation & Motion Specification
## Animation Philosophy
> Motion serves comprehension. Every animation must earn its frame budget by making content clearer, transitions smoother, or data more meaningful.
---
## Framer Motion Variants Library
### Base Variants
```typescript
// src/lib/animations.ts
export const fadeUp = {
hidden: { opacity: 0, y: 20 },
visible: {
opacity: 1,
y: 0,
transition: { duration: 0.6, ease: [0.25, 0.46, 0.45, 0.94] }
}
};
export const fadeIn = {
hidden: { opacity: 0 },
visible: {
opacity: 1,
transition: { duration: 0.4 }
}
};
export const scaleIn = {
hidden: { opacity: 0, scale: 0.95 },
visible: {
opacity: 1,
scale: 1,
transition: { duration: 0.5, ease: [0.25, 0.46, 0.45, 0.94] }
}
};
export const staggerContainer = {
hidden: {},
visible: {
transition: {
staggerChildren: 0.1,
delayChildren: 0.1
}
}
};
export const staggerItem = {
hidden: { opacity: 0, y: 16 },
visible: {
opacity: 1,
y: 0,
transition: { duration: 0.4, ease: 'easeOut' }
}
};
```
---
## Section-by-Section Animation Plan
### 1. Navbar
| Element | Animation | Trigger | Duration |
|---------|-----------|---------|----------|
| Entire nav | Slide down + fade | Page load | 400ms |
| Background blur | Opacity 0 → 0.8 | Scroll > 50px | 200ms |
| Border bottom | Opacity 0 → 1 | Scroll > 50px | 200ms |
| Active link indicator | Width grows from center | Route change | 300ms |
| Mobile menu | Slide from right (RTL: left) | Toggle | 300ms |
### 2. Hero Section
| Element | Animation | Trigger | Duration | Delay |
|---------|-----------|---------|----------|-------|
| Headline | Fade up from 30px below | Page load | 600ms | 0ms |
| Subheadline | Fade up | Page load | 600ms | 150ms |
| CTA buttons | Fade up + scale from 0.95 | Page load | 500ms | 300ms |
| Dashboard mockup | Fade in + float up from 40px + slight rotate | Page load | 800ms | 400ms |
| Stats bar | Stagger fade up (3 items) | Page load | 400ms each | 600ms start |
| Stats numbers | Count from 0 to value | When stats bar visible | 1200ms | 800ms |
**Dashboard Mockup Continuous Animation:**
```typescript
// Subtle floating effect (always active)
animate={{
y: [0, -8, 0],
rotateX: [0, 1, 0],
rotateY: [0, -0.5, 0],
}}
transition={{
duration: 6,
repeat: Infinity,
ease: "easeInOut"
}}
```
### 3. Problem → Solution Transition
| Phase | What Happens | Duration |
|-------|-------------|----------|
| Enter viewport | "Before" state visible: scattered papers, Excel icon, WhatsApp icon | Static |
| Scroll 30% | Elements begin to scatter/dissolve (opacity fade + scale down + blur) | 800ms |
| Scroll 50% | Midpoint: brief clean slate | 200ms |
| Scroll 70% | Dashboard mockup assembles from the same positions | 800ms |
| Scroll 100% | "After" state fully revealed, clean and organized | Static |
**Implementation: Scroll-linked (not time-based)**
```typescript
const { scrollYProgress } = useScroll({ target: sectionRef });
const opacity = useTransform(scrollYProgress, [0, 0.3, 0.5, 0.7, 1], [1, 0.5, 0, 0.5, 1]);
const scale = useTransform(scrollYProgress, [0, 0.3, 0.7, 1], [1, 0.8, 0.8, 1]);
```
### 4. Module Showcase (6 Cards)
| Element | Animation | Trigger | Duration |
|---------|-----------|---------|----------|
| Section heading | Fade up | Viewport entry (20%) | 500ms |
| Cards container | Stagger children | Viewport entry | 100ms between |
| Each card | Fade up from 20px | Stagger | 400ms |
| Card icon | Scale from 0.8 + fade | Card appears | 300ms |
| Card on hover | translateY(-4px) + shadow increase + border color change | Mouse enter | 200ms |
| Card arrow | translate 4px inline-end | Card hover | 200ms |
### 5. Feature Deep-Dives (3 Sections)
| Element | Animation | Trigger | Duration |
|---------|-----------|---------|----------|
| Text block | Fade up + slide from inline-start (right in RTL) | Viewport entry | 600ms |
| Mockup image | Fade in + slight perspective tilt | 200ms after text | 700ms |
| Chart in mockup | Draw-in (SVG path) | Mockup fully visible | 1000ms |
| Numbers in mockup | Count up | Chart completes | 800ms |
| Progress bars | Width grows from 0 to target | Mockup visible | 600ms staggered |
**Interactive Cursor Response (desktop only):**
```typescript
// Mockup tilts slightly toward cursor position
const rotateX = useTransform(mouseY, [-300, 300], [3, -3]);
const rotateY = useTransform(mouseX, [-300, 300], [-3, 3]);
```
### 6. Testimonials Carousel
| Element | Animation | Trigger | Duration |
|---------|-----------|---------|----------|
| Cards | Slide in from inline-end | Auto-rotate or swipe | 500ms |
| Quote mark | Scale pulse | Card enters | 400ms |
| Avatar | Fade + scale from 0.9 | Card enters | 300ms |
| Dots indicator | Width transition (active dot wider) | Slide change | 200ms |
| Auto-rotate | Every 5 seconds | Always (pauses on hover) | — |
### 7. Stats Section (Big Numbers)
| Element | Animation | Trigger | Duration |
|---------|-----------|---------|----------|
| Numbers | Count up from 0 | Viewport entry (once) | 1500ms |
| Suffix (ج.م / +) | Fade in | Count reaches 80% | 200ms |
| Label text | Fade up | Number completes | 300ms |
| Background glow | Radial gradient pulse | Section in view | 3s loop |
**Count-up Easing:** ease-out (fast start, slow end — feels natural)
### 8. CTA Section
| Element | Animation | Trigger | Duration |
|---------|-----------|---------|----------|
| Background gradient | Subtle shift (dark navy → slightly lighter) | Always | 8s loop |
| Headline | Fade up | Viewport entry | 500ms |
| Subtext | Fade up | 150ms after headline | 400ms |
| Buttons | Fade up + scale | 300ms after subtext | 400ms |
| Decorative dots/grid | Very subtle parallax (2-3px) | Scroll | Continuous |
### 9. Footer
| Element | Animation | Trigger | Duration |
|---------|-----------|---------|----------|
| Content | Fade in | Viewport entry | 400ms |
| No complex animations (footer = utility, not spectacle) |
---
## Scroll-Triggered Orchestration
### IntersectionObserver Settings
```typescript
// AnimateOnScroll wrapper component
const defaultViewport = {
once: true, // animate only first time
amount: 0.2, // trigger at 20% visibility
margin: "-50px" // start slightly before fully in view
};
```
### Scroll Progress Sections
Only the "Problem → Solution" section uses scroll-linked (useScroll) animation.
Everything else uses viewport entry triggers (simpler, better performance).
---
## Performance Budget
### Animation Constraints
- Maximum simultaneous animations: 8 elements
- Maximum particle count: 0 (no particles — too playful)
- Maximum parallax layers: 3
- Transform-only animations (no layout thrashing):
- OK: opacity, transform (translate, scale, rotate)
- AVOID: width, height, top, left, margin, padding
- Will-change applied only during animation, removed after
- GPU-accelerated only: `transform: translateZ(0)` where needed
### Reduced Motion Support
```typescript
// Every animated component checks this
const prefersReducedMotion = useReducedMotion();
// If true: show final state immediately, no transitions
const variants = prefersReducedMotion ? {} : fadeUp;
```
### Mobile Performance
- Disable cursor-responsive tilt on touch devices
- Reduce stagger count (show all at once below 768px)
- Disable parallax entirely on mobile
- Reduce animation durations by 30% on mobile
- Skip "Problem → Solution" scroll animation on mobile (show static before/after)
---
## Micro-Interactions
### Buttons
```css
/* Hover (desktop only) */
transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(14,165,233,0.25);
transition: all 150ms ease;
/* Active/Press */
transform: translateY(0) scale(0.98);
transition: all 100ms ease;
/* Focus */
outline: 2px solid var(--color-sky-500);
outline-offset: 2px;
```
### Cards
```css
/* Hover */
transform: translateY(-4px);
border-color: var(--color-sky-200);
box-shadow: var(--shadow-lg);
transition: all 200ms ease;
/* The internal arrow moves */
.card-arrow { transform: translateX(4px); /* inline-end */ }
```
### Links
```css
/* Underline grows from center */
.link::after {
content: '';
width: 0;
height: 2px;
background: var(--color-sky-500);
transition: width 200ms ease;
}
.link:hover::after { width: 100%; }
```
### Language Toggle
```css
/* Smooth text direction change */
[dir] { transition: none; } /* No transition on dir change — instant */
/* But content fades: */
.content { animation: fadeIn 200ms ease; }
```
### Number Counters
```typescript
// Animated number component
function CountUp({ target, duration = 1200, suffix = '' }) {
// Use requestAnimationFrame
// Easing: easeOutExpo for "fast start, dramatic slow end"
// Format: Arabic-Indic numerals in AR locale
}
```
---
## Page Transition Spec
### Route Changes
```typescript
// Layout wrapper with AnimatePresence
<AnimatePresence mode="wait">
<motion.main
key={pathname}
initial={{ opacity: 0, y: 8 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -8 }}
transition={{ duration: 0.25 }}
>
{children}
</motion.main>
</AnimatePresence>
```
### Shared Elements (No Transition)
- Navbar: persists across routes (no animation)
- Footer: persists across routes
- Floating WhatsApp button: persists
---
## Animation Do's and Don'ts
### DO
- Use easeOut for enters (natural deceleration)
- Use easeIn for exits (natural acceleration)
- Stagger related items (cards, list items)
- Animate on first viewport entry only (once: true)
- Test on real Egyptian 4G speed (throttle Chrome)
- Keep total animation time under 1s for any single element
- Use transform properties only (GPU accelerated)
### DON'T
- Bounce effects (too playful, wrong brand)
- Spin/rotate more than 5 degrees (disorienting)
- Animate text color (not perceivable, wastes frames)
- Delay more than 500ms total (feels broken)
- Animate on scroll UP (confusing, breaks mental model)
- Use spring physics with high bounciness (wrong brand energy)
- Autoplay video (bandwidth cost in Egypt)
- Animate elements the user can't see (waste of resources)
- Add loading animations that block content (perceived as slow)
# El Captain Brand Guidelines v1.0
## Quick Reference
- **Primary Color:** #1E3A5F (Deep Navy)
- **Secondary Color:** #0EA5E9 (Electric Sky)
- **Accent:** #10B981 (Success Green)
- **Primary Font (Arabic):** Cairo
- **Primary Font (Latin):** Inter
- **Voice:** Authoritative, Clear, Empowering
---
## 1. Brand Identity
### Mission Statement
We build the command center for sports organizations — giving academy owners total operational control so they can focus on what matters: developing athletes.
### Vision Statement
A world where every sports academy in the Arab region operates with the precision and intelligence of a professional club.
### Value Proposition
For sports academy owners who struggle with scattered operations, manual tracking, and financial uncertainty —
**El Captain** is the all-in-one management platform
that puts every player, every pound, and every session under one command center.
Unlike generic ERPs or spreadsheets,
we're purpose-built for the sports business model — from enrollment to graduation.
### Positioning Statement
El Captain is the sports operations platform for academy directors who want complete visibility and control over their business, because it was designed by people who understand how sports academies actually work.
### Tagline Options
- **Primary (AR):** كل شيء تحت إدارتك — "Everything under your command"
- **Secondary (AR):** منصة واحدة. تحكم كامل. — "One platform. Complete control."
- **English:** "Your Command Center for Sports Operations"
---
## 2. Color Palette
### Primary Colors
| Name | Hex | RGB | Tailwind | Usage |
|------|-----|-----|----------|-------|
| Deep Navy | #1E3A5F | rgb(30,58,95) | `navy-900` | Headers, primary text, authority |
| Electric Sky | #0EA5E9 | rgb(14,165,233) | `sky-500` | CTAs, interactive elements, links |
### Secondary Colors
| Name | Hex | RGB | Tailwind | Usage |
|------|-----|-----|----------|-------|
| Success Green | #10B981 | rgb(16,185,129) | `emerald-500` | Positive metrics, confirmations |
| Warm Amber | #F59E0B | rgb(245,158,11) | `amber-500` | Highlights, attention, badges |
| Soft Violet | #8B5CF6 | rgb(139,92,246) | `violet-500` | Charts, secondary data viz |
### Neutral Palette
| Name | Hex | RGB | Tailwind | Usage |
|------|-----|-----|----------|-------|
| Background | #FAFBFC | rgb(250,251,252) | `slate-50` | Page background |
| Surface | #FFFFFF | rgb(255,255,255) | `white` | Cards, modals |
| Text Primary | #0F172A | rgb(15,23,42) | `slate-900` | Headings, primary text |
| Text Secondary | #64748B | rgb(100,116,139) | `slate-500` | Descriptions, muted text |
| Text Tertiary | #94A3B8 | rgb(148,163,184) | `slate-400` | Placeholders, disabled |
| Border | #E2E8F0 | rgb(226,232,240) | `slate-200` | Dividers, card borders |
| Border Subtle | #F1F5F9 | rgb(241,245,249) | `slate-100` | Section separators |
### Gradient System
```css
/* Hero gradient — subtle authority */
--gradient-hero: linear-gradient(135deg, #FAFBFC 0%, #EFF6FF 50%, #F0F9FF 100%);
/* CTA gradient — action energy */
--gradient-cta: linear-gradient(135deg, #0EA5E9 0%, #0284C7 100%);
/* Feature card hover */
--gradient-card: linear-gradient(180deg, #FFFFFF 0%, #F8FAFC 100%);
/* Data visualization glow */
--gradient-glow: radial-gradient(circle, rgba(14,165,233,0.08) 0%, transparent 70%);
```
### Accessibility
- Text Primary on Background: 15.3:1 (WCAG AAA)
- Electric Sky on White: 3.2:1 (Large text / UI components AA)
- Electric Sky on Navy: 5.8:1 (WCAG AA)
- All interactive elements meet WCAG 2.1 AA minimum
---
## 3. Typography
### Font Stack
```css
/* Arabic (primary) */
--font-heading-ar: 'Cairo', 'Noto Sans Arabic', system-ui, sans-serif;
--font-body-ar: 'Cairo', 'Noto Sans Arabic', system-ui, sans-serif;
/* Latin (secondary) */
--font-heading-en: 'Inter', system-ui, sans-serif;
--font-body-en: 'Inter', system-ui, sans-serif;
/* Monospace (data/code) */
--font-mono: 'JetBrains Mono', 'Fira Code', monospace;
/* Numbers (always LTR) */
--font-numbers: 'Inter', 'Tabular Nums', monospace;
```
### Type Scale (Arabic)
| Element | Font | Weight | Size Desktop | Size Mobile | Line Height | Letter Spacing |
|---------|------|--------|-------------|-------------|-------------|----------------|
| Display | Cairo | 800 | 64px | 40px | 1.1 | -0.02em |
| H1 | Cairo | 700 | 48px | 32px | 1.2 | -0.01em |
| H2 | Cairo | 700 | 36px | 28px | 1.25 | 0 |
| H3 | Cairo | 600 | 28px | 24px | 1.3 | 0 |
| H4 | Cairo | 600 | 24px | 20px | 1.35 | 0 |
| Body Large | Cairo | 400 | 18px | 16px | 1.6 | 0 |
| Body | Cairo | 400 | 16px | 16px | 1.6 | 0 |
| Small | Cairo | 400 | 14px | 14px | 1.5 | 0 |
| Caption | Cairo | 500 | 12px | 12px | 1.4 | 0.01em |
### Type Rules
- Arabic body text: minimum 16px (never smaller for readability)
- Numbers in data displays: always use Inter with tabular figures
- Headings: Cairo Bold/ExtraBold for commanding presence
- Maximum line length: 65 characters (Arabic) / 75 characters (English)
---
## 4. Voice & Tone
### Brand Personality Traits
1. **Authoritative, not arrogant** — We know this space. We speak with confidence but never talk down.
2. **Clear, not simplistic** — Complex features explained simply. Jargon-free but not dumbed down.
3. **Empowering, not pushy** — We give you power. We never pressure or create false urgency.
### Voice Chart
| Trait | We Are | We Are Not |
|-------|--------|------------|
| Authoritative | Confident, knowledgeable, direct | Boastful, condescending, rigid |
| Clear | Precise, structured, scannable | Oversimplified, vague, verbose |
| Empowering | Enabling, supportive, practical | Pushy, manipulative, salesy |
### Tone by Context
| Context | Tone | Example (AR) | Example (EN) |
|---------|------|-------------|-------------|
| Hero/Headlines | Commanding | "كل شيء تحت إدارتك" | "Everything under your command" |
| Features | Confident | "تتبع كل جنيه من لحظة الدفع حتى التقرير" | "Track every pound from payment to report" |
| Social Proof | Grounded | "٤٧ أكاديمية تدير عملياتها عبر المنصة" | "47 academies run their operations through the platform" |
| Support/Help | Helpful | "فريقنا جاهز لمساعدتك في الإعداد" | "Our team is ready to help you get set up" |
| CTA | Direct | "ابدأ الآن" / "احجز عرض تجريبي" | "Start now" / "Book a demo" |
| Error/Empty | Reassuring | "لا مشكلة، نقدر نساعدك" | "No problem, we can help" |
### Prohibited Terms & Patterns
- "Revolutionary" / "ثوري" — overused, meaningless
- "Best in class" — unprovable
- "Easy" without showing why — claim without evidence
- Exclamation marks in headlines — reduces authority
- "Just" / "Simply" — minimizes real challenges
- Tech jargon without context — "SaaS", "cloud-native", "AI-powered" alone
- Fear-based copy — "Don't lose your data!" / "You're falling behind!"
### Arabic Copy Standards
- Use Modern Standard Arabic (فصحى مبسطة) — not colloquial, not overly formal
- Short sentences: 10-15 words maximum per sentence in marketing copy
- Active voice always: "تدير" not "يتم إدارة"
- Address the reader directly: "أنت" / "أكاديميتك"
- Numbers: Arabic-Indic numerals (٤٧) in headlines, Western (47) in data
---
## 5. Imagery Guidelines
### Photography Style
- **NO stock photos** — ever. Use product screenshots, custom illustrations, or abstract visuals.
- If people appear: real sports settings (training halls, pitches), never staged office shots
- Lighting: bright, clean, natural
- Color treatment: desaturated slightly, brand tint overlay acceptable
### Product Screenshots
- Always show Arabic interface (RTL)
- Real-looking data (never "Lorem ipsum" or obviously fake)
- Clean, populated state (not empty states)
- Subtle shadow/float effect to lift off page
- Device mockup: MacBook Pro or iPad, minimal chrome
### Illustrations & Graphics
- Style: Geometric, structured, grid-based (reflects "command center" metaphor)
- Colors: Brand palette only — primary navy + sky accents
- No cartoon/playful illustrations — too casual for target audience
- Data visualization style: clean charts with brand colors, subtle gradients
- Module icons: outlined, consistent 2px stroke, rounded corners
### Icons
- Style: Outlined with 1.5px stroke (Lucide or Heroicons aesthetic)
- Size: 24px base grid
- Corner radius: 2px
- Color: Single tone (slate-500 default, sky-500 on hover/active)
- Never filled icons in navigation — filled only for active/selected states
---
## 6. Logo Usage
### Variants
- **Primary:** Arabic wordmark "الكابتن" + icon mark (horizontal)
- **English:** "El Captain" wordmark + icon mark (horizontal)
- **Stacked:** Icon above wordmark (for square formats)
- **Icon Only:** Shield/command mark (favicons, app icons, small spaces)
- **Monochrome:** Single color versions (navy on light, white on dark)
### Icon Concept
The icon should evoke: command/authority + sports + technology.
Direction: Abstract shield shape with data-grid pattern inside — combines protection/authority with structured information.
### Clear Space
Minimum clear space = 1.5x height of the icon mark on all sides
### Minimum Size
- Digital: 100px width (full logo), 32px (icon only)
- Print: 30mm width (full logo), 10mm (icon only)
### Don'ts
- Don't rotate, skew, or add perspective effects
- Don't use colors outside the approved palette
- Don't add drop shadows, glows, or 3D effects
- Don't place on busy/patterned backgrounds
- Don't stretch or modify proportions
- Don't use the English logo in Arabic contexts (and vice versa)
---
## 7. Motion & Animation Principles
### Core Philosophy
Motion serves comprehension. Every animation must answer: "Does this help the user understand something?"
### Timing
| Type | Duration | Easing | Use |
|------|----------|--------|-----|
| Micro | 150-200ms | ease-out | Button hover, toggle |
| Standard | 300-400ms | ease-in-out | Card reveal, panel transition |
| Emphasis | 500-700ms | spring(0.6) | Hero elements, feature reveals |
| Cinematic | 800-1200ms | custom bezier | Scroll-triggered sequences |
### Scroll Animations
- Elements enter from below with subtle fade (not from sides — RTL makes lateral motion ambiguous)
- Stagger delay: 50-100ms between items in a list
- Parallax: maximum 20% offset (subtle, not nauseating)
- Dashboard mockups: 3-5 degree tilt on scroll, with depth shadow
### Interaction Animations
- Buttons: scale(1.02) on hover, scale(0.98) on press
- Cards: translateY(-4px) + shadow increase on hover
- Numbers: count-up animation when scrolling into view
- Charts: draw-in animation (lines/bars grow from zero)
### Don'ts
- No bounce effects (too playful)
- No spin/rotate animations (disorienting in RTL)
- No animation on every element (cluttered)
- No animation that blocks reading (user should never wait)
- No autoplay video in hero (distracting, bandwidth-heavy in Egypt)
---
## 8. Component & Layout Principles
### Grid System
- 12-column grid, 1280px max width
- Gutters: 24px (mobile), 32px (tablet), 40px (desktop)
- Section padding: 80px vertical (desktop), 48px (mobile)
- Cards: 16px-24px internal padding, 1px border, 8px radius
### Card Hierarchy
1. **Primary Card:** White bg, 1px slate-200 border, 12px radius, subtle shadow
2. **Feature Card:** White bg, on hover: border-sky-200, shadow-lg, slight lift
3. **Stat Card:** Slate-50 bg, no border, internal padding, bold number
4. **CTA Card:** Gradient bg (navy → darker), white text, rounded-2xl
### Button Styles
| Variant | Background | Text | Border | Use |
|---------|-----------|------|--------|-----|
| Primary | sky-500 → sky-600 gradient | white | none | Main CTA |
| Secondary | white | navy-900 | slate-200 | Secondary actions |
| Ghost | transparent | sky-600 | none | Tertiary, in-nav |
| Dark | navy-900 | white | none | On light sections |
### Spacing Scale (Tailwind)
- Section gaps: `space-y-20` (80px) or `space-y-16` (64px)
- Component gaps: `gap-6` (24px) or `gap-8` (32px)
- Text gaps: `space-y-4` (16px) between paragraphs
- Element gaps: `gap-2` (8px) or `gap-3` (12px) within components
---
## 9. Data Visualization Style
Since the product IS data and dashboards, the marketing site's visual language borrows from data viz:
### Chart Colors (ordered)
1. Electric Sky (#0EA5E9) — primary data series
2. Soft Violet (#8B5CF6) — secondary series
3. Success Green (#10B981) — positive trends
4. Warm Amber (#F59E0B) — highlights/alerts
5. Slate (#64748B) — neutral/comparison
### Data Display Rules
- Numbers are heroes — display large, bold, with unit labels
- Show real-ish metrics: "٢,٤٥٠ لاعب" / "١.٢ مليون ج.م إيرادات شهرية"
- Growth indicators: green arrow + percentage for positive
- Dashboard mockups: 3-4 widgets visible, not cluttered
---
## 10. Responsive Breakpoints
| Name | Min Width | Target |
|------|-----------|--------|
| Mobile | 0px | Phone (portrait) |
| Tablet | 768px | iPad/tablet |
| Desktop | 1024px | Laptop |
| Wide | 1280px | Desktop monitor |
| Ultra | 1536px | Large displays |
### Mobile-Specific Rules
- Hero: single column, headline + CTA above fold
- Navigation: hamburger menu (Arabic text remains RTL)
- Cards: full width, stacked
- Mockup images: reduce to 80% width, remove tilt effects
- Font sizes follow mobile column in type scale
# El Captain — Business Model & Cost Analysis
> Exchange rate used: **1 USD = 50 EGP**
---
## Pricing Structure
| Tier | Monthly Price | Platform Fee | Target |
|------|--------------|--------------|--------|
| Starter | $20 (١,٠٠٠ ج.م) | 5% of collections | Small academies (50–200 players, 1 branch) |
| Pro | $60 (٣,٠٠٠ ج.م) | 3% of collections | Medium academies (200–1,000 players, up to 5 branches) |
| Enterprise | $100 (٥,٠٠٠ ج.م) | 1% of collections | Large clubs (1,000+ players, unlimited) |
**Annual discount:** 20% (2 months free)
### Tier Comparison
```mermaid
graph LR
subgraph Starter["Starter - $20/mo (١,٠٠٠ ج.م)"]
S1[200 players max]
S2[1 branch]
S3[5 users]
S4[5% platform fee]
end
subgraph Pro["Pro - $60/mo (٣,٠٠٠ ج.م)"]
P1[1,000 players]
P2[5 branches]
P3[15 users]
P4[3% platform fee]
end
subgraph Enterprise["Enterprise - $100/mo (٥,٠٠٠ ج.م)"]
E1[Unlimited players]
E2[Unlimited branches]
E3[Unlimited users]
E4[1% platform fee]
end
```
### Revenue Per Customer (Monthly)
| Academy Size | Monthly Collections | Starter | Pro | Enterprise |
|---|---|---|---|---|
| 50 players | $1,000 (٥٠,٠٠٠ ج.م) | $70 (٣,٥٠٠ ج.م) | $90 (٤,٥٠٠ ج.م) | $110 (٥,٥٠٠ ج.م) |
| 150 players | $3,000 (١٥٠,٠٠٠ ج.م) | $170 (٨,٥٠٠ ج.م) | $150 (٧,٥٠٠ ج.م) | $130 (٦,٥٠٠ ج.م) |
| 300 players | $6,000 (٣٠٠,٠٠٠ ج.م) | $320 (١٦,٠٠٠ ج.م) | $240 (١٢,٠٠٠ ج.م) | $160 (٨,٠٠٠ ج.م) |
| 500 players | $10,000 (٥٠٠,٠٠٠ ج.م) | $520 (٢٦,٠٠٠ ج.م) | $360 (١٨,٠٠٠ ج.م) | $200 (١٠,٠٠٠ ج.م) |
| 1,000 players | $20,000 (١,٠٠٠,٠٠٠ ج.م) | $1,020 (٥١,٠٠٠ ج.م) | $660 (٣٣,٠٠٠ ج.م) | $300 (١٥,٠٠٠ ج.م) |
### Natural Upgrade Breakpoints
```mermaid
graph LR
A["Academy < $1,333/mo<br/>(< ٦٦,٦٥٠ ج.م)"] -->|Starter cheapest| B[Starter $20 + 5%]
C["Academy $1,333–$2,000/mo<br/>(٦٦,٦٥٠–١٠٠,٠٠٠ ج.م)"] -->|Pro cheapest| D[Pro $60 + 3%]
E["Academy > $2,000/mo<br/>(> ١٠٠,٠٠٠ ج.م)"] -->|Enterprise cheapest| F[Enterprise $100 + 1%]
```
Most real academies (100+ players) self-select into Pro or Enterprise within 1-2 months.
---
## Cost Structure
### Cost Breakdown
```mermaid
pie title Monthly Costs at Launch Phase ($600 / ٣٠,٠٠٠ ج.م)
"Hosting & Infra" : 110
"Third-Party Services" : 40
"Dev Tools" : 150
"Marketing" : 300
```
### 1. Infrastructure / Hosting
| Item | Provider | Monthly (USD) | Monthly (EGP) | Notes |
|------|----------|:---:|:---:|-------|
| Production Server | AWS EC2 (m5.2xlarge) | $280 | ١٤,٠٠٠ ج.م | 8 vCPU, 30GB RAM, 620GB SSD. Shared across 58 containers |
| El Captain's share | ~30% of server | $84 | ٤,٢٠٠ ج.م | PostgreSQL + Laravel app + queue workers |
| Domain | Namecheap/Route53 | $1.50 | ٧٥ ج.م | $15-18/year |
| SSL | Let's Encrypt (CapRover) | $0 | ٠ | Free wildcard |
| Email (transactional) | Poste.io (self-hosted) | $0 | ٠ | Already running on server |
| Backups (DB) | AWS EBS snapshots | $5 | ٢٥٠ ج.م | Daily, 30-day retention |
| CDN (marketing site) | Vercel | $0–20 | ٠–١,٠٠٠ ج.م | Free tier covers launch traffic |
| **Subtotal** | | **$90–110** | **٤,٥٠٠–٥,٥٠٠ ج.م** | |
### 2. Third-Party Services
| Item | Provider | Monthly (USD) | Monthly (EGP) | Notes |
|------|----------|:---:|:---:|-------|
| SMS Gateway | Twilio / Vonage | $0–50 | ٠–٢,٥٠٠ ج.م | Per-message; can pass cost to academy |
| Payment Gateway | Paymob / Fawry | 2.5% + fees | — | Future feature; not current cost |
| Analytics | Plausible Cloud | $9 | ٤٥٠ ج.م | Privacy-friendly, no cookie banner |
| Error Tracking | Sentry (free tier) | $0 | ٠ | 5K errors/month free |
| Uptime Monitoring | UptimeRobot | $0 | ٠ | Free tier (50 monitors) |
| **Subtotal** | | **$10–60** | **٥٠٠–٣,٠٠٠ ج.م** | |
### 3. Development & Operations
| Item | Monthly (USD) | Monthly (EGP) | Notes |
|------|:---:|:---:|-------|
| Claude Code (AI development) | $100–200 | ٥,٠٠٠–١٠,٠٠٠ ج.م | Primary development tool |
| GitLab (self-hosted) | $0 | ٠ | Already on server |
| Domain email (info@) | $0 | ٠ | Poste.io |
| **Subtotal** | **$100–200** | **٥,٠٠٠–١٠,٠٠٠ ج.م** | |
### 4. Marketing (Launch Phase)
| Channel | Monthly (USD) | Monthly (EGP) | Expected Outcome |
|---------|:---:|:---:|------------------|
| Facebook/Instagram Ads (Egypt) | $200–400 | ١٠,٠٠٠–٢٠,٠٠٠ ج.م | CPL ~$2-5 (١٠٠–٢٥٠ ج.م) in sports niche |
| Google Ads (Arabic keywords) | $100–200 | ٥,٠٠٠–١٠,٠٠٠ ج.م | Low competition for "برنامج إدارة أكاديمية" |
| Content (blog posts, videos) | $0 | ٠ | Self-produced; SEO compounds over time |
| WhatsApp Business | $0 | ٠ | Direct sales channel |
| Sports community groups | $0 | ٠ | Organic outreach in Facebook groups |
| Referral program (1 month free) | Variable | — | Best channel once 5+ happy customers |
| **Subtotal** | **$300–600** | **١٥,٠٠٠–٣٠,٠٠٠ ج.م** | |
### 5. Total Monthly Costs Summary
| Phase | Fixed (USD) | Marketing (USD) | Total (USD) | Total (EGP) |
|-------|:---:|:---:|:---:|:---:|
| Pre-launch (now) | $200 | $0 | **$200** | **١٠,٠٠٠ ج.م** |
| Launch (months 1-3) | $200 | $400 | **$600** | **٣٠,٠٠٠ ج.م** |
| Growth (months 3-12) | $300 | $600 | **$900** | **٤٥,٠٠٠ ج.م** |
| Scale (12+ months) | $500 | $1,000 | **$1,500** | **٧٥,٠٠٠ ج.م** |
### Cost Scaling Over Time
```mermaid
graph TB
subgraph "Costs by Phase"
direction LR
PL["Pre-launch<br/>$200/mo<br/>١٠K ج.م"] --> L["Launch<br/>$600/mo<br/>٣٠K ج.م"]
L --> G["Growth<br/>$900/mo<br/>٤٥K ج.م"]
G --> S["Scale<br/>$1,500/mo<br/>٧٥K ج.م"]
end
```
---
## Revenue Projections
### Conservative Scenario
| Month | Customers | Mix | Subscriptions (USD) | Platform Fees (USD) | **Total MRR (USD)** | **Total MRR (EGP)** |
|:---:|:---:|---|:---:|:---:|:---:|:---:|
| 1 | 2 | 2 Starter | $40 | $100 | **$140** | **٧,٠٠٠ ج.م** |
| 3 | 8 | 4S + 3P + 1E | $360 | $650 | **$1,010** | **٥٠,٥٠٠ ج.م** |
| 6 | 20 | 8S + 9P + 3E | $1,000 | $2,200 | **$3,200** | **١٦٠,٠٠٠ ج.م** |
| 12 | 45 | 15S + 22P + 8E | $2,420 | $6,500 | **$8,920** | **٤٤٦,٠٠٠ ج.م** |
*Assumptions: Avg. collections — Starter: $2,000 (١٠٠K ج.م), Pro: $5,000 (٢٥٠K ج.م), Enterprise: $15,000 (٧٥٠K ج.م)*
### MRR Growth Trajectory
```mermaid
xychart-beta
title "Monthly Recurring Revenue (USD)"
x-axis ["M1", "M2", "M3", "M4", "M5", "M6", "M7", "M8", "M9", "M10", "M11", "M12"]
y-axis "MRR ($)" 0 --> 9500
line [140, 400, 1010, 1500, 2200, 3200, 4100, 5000, 5900, 7000, 8000, 8920]
line [600, 600, 600, 750, 750, 900, 900, 900, 1000, 1200, 1500, 1500]
```
> Blue = Revenue, Red = Costs. Breakeven at month 3.
### Revenue Composition Over Time
```mermaid
pie title Revenue Split at Month 12
"Subscription Revenue ($2,420)" : 2420
"Platform Fees ($6,500)" : 6500
```
### Breakeven Analysis
| Phase | Monthly Costs (USD/EGP) | Breakeven At |
|-------|:---:|---|
| Pre-launch | $200 (١٠,٠٠٠ ج.م) | 3 Pro customers |
| Launch | $600 (٣٠,٠٠٠ ج.م) | 5 Pro + 2 Starter |
| Growth | $900 (٤٥,٠٠٠ ج.م) | 7 Pro + 3 Starter |
**Breakeven at ~5-7 paying customers.** Everything after is profit until you hire or upgrade infrastructure.
### Profit Projections
| Month | Revenue (USD) | Costs (USD) | **Net Profit (USD)** | **Net Profit (EGP)** |
|:---:|:---:|:---:|:---:|:---:|
| 1 | $140 | $600 | -$460 | -٢٣,٠٠٠ ج.م |
| 3 | $1,010 | $600 | +$410 | +٢٠,٥٠٠ ج.م |
| 6 | $3,200 | $900 | +$2,300 | +١١٥,٠٠٠ ج.م |
| 12 | $8,920 | $1,500 | +$7,420 | +٣٧١,٠٠٠ ج.م |
**Annual profit at month 12 run rate: $89,040/year (٤.٤٥ مليون ج.م/سنة)**
### Cumulative Profit/Loss
```mermaid
xychart-beta
title "Cumulative Net Profit (USD)"
x-axis ["M1", "M2", "M3", "M4", "M5", "M6", "M7", "M8", "M9", "M10", "M11", "M12"]
y-axis "Cumulative ($)" -1000 --> 35000
line [-460, -660, -250, 500, 1950, 4250, 7450, 11550, 16450, 22250, 28750, 36170]
```
---
## Unit Economics
| Metric | USD | EGP |
|--------|:---:|:---:|
| CAC (Customer Acquisition Cost) | $30–100 | ١,٥٠٠–٥,٠٠٠ ج.م |
| LTV @ 12 months, Pro tier | $2,520 | ١٢٦,٠٠٠ ج.م |
| LTV @ 12 months, Starter tier | $1,440 | ٧٢,٠٠٠ ج.م |
| LTV @ 12 months, Enterprise tier | $3,000 | ١٥٠,٠٠٠ ج.م |
| LTV/CAC ratio | 14–84x | — |
| Payback period | < 1 month | — |
| Gross margin | ~90% | — |
| Net margin (at 20 customers) | ~70% | — |
### LTV by Tier
```mermaid
xychart-beta
title "Customer Lifetime Value - 12 Months (USD)"
x-axis ["Starter", "Pro", "Enterprise"]
y-axis "LTV ($)" 0 --> 3500
bar [1440, 2520, 3000]
```
---
## Customer Journey & Funnel
```mermaid
flowchart TD
A[Facebook/Google Ad<br/>CPL: $2-5 / ١٠٠-٢٥٠ ج.م] --> B[Marketing Site Visit]
B --> C{Demo Request?}
C -->|Yes| D[30-min Demo Call]
C -->|No| E[Free Trial Signup]
D --> F[14-Day Free Trial]
E --> F
F --> G{Convert?}
G -->|60% convert| H[Paying Customer]
G -->|40% churn| I[Nurture Email Sequence]
I -->|20% return| H
H --> J{Growth?}
J -->|Collections > $1,333| K[Self-upgrade to Pro]
J -->|Collections > $2,000| L[Self-upgrade to Enterprise]
J -->|Happy| M[Referral → New Lead]
M --> B
```
---
## Revenue Model Flow
```mermaid
flowchart LR
subgraph "Revenue Streams"
SUB[Monthly Subscription<br/>$20-100 / ١,٠٠٠-٥,٠٠٠ ج.م]
FEE[Platform Fee<br/>1-5% of collections]
ANN[Annual Prepay<br/>20% discount]
end
subgraph "How Fee Works"
COL[Academy collects<br/>from parents] --> INV[Invoice generated<br/>in El Captain]
INV --> PAY[Payment recorded]
PAY --> CALC[Fee auto-calculated]
CALC --> SPLIT{Customer pays?}
SPLIT -->|Yes| ADD[Added to invoice total]
SPLIT -->|No| DED[Deducted from academy revenue]
end
```
---
## Competitive Landscape (Egypt/MENA)
| Competitor | Price (USD) | Price (EGP) | What They Lack |
|-----------|:---:|:---:|----------------|
| Excel/WhatsApp | Free | Free | Everything — no automation, no reports, data loss |
| Jeelapp | ~$50/mo | ~٢,٥٠٠ ج.م | No finance, no POS, no inventory |
| Mawaheb | Custom | Custom | No double-entry, limited customization |
| Generic ERPs (Odoo) | $100+/user | ٥,٠٠٠+/مستخدم | Not sports-specific, complex, not Arabic-first |
| **El Captain** | **$20–100/mo** | **١,٠٠٠–٥,٠٠٠ ج.م** | **Full vertical stack, Arabic-first** |
### Competitive Positioning
```mermaid
quadrantChart
title Feature Completeness vs Price
x-axis "Low Price" --> "High Price"
y-axis "Basic Features" --> "Full Platform"
quadrant-1 "Sweet Spot"
quadrant-2 "Overbuilt"
quadrant-3 "Cheap & Basic"
quadrant-4 "Expensive & Limited"
"El Captain": [0.3, 0.9]
"Jeelapp": [0.4, 0.4]
"Odoo": [0.8, 0.7]
"Excel": [0.05, 0.1]
"Mawaheb": [0.6, 0.5]
```
**Positioning:** The only all-in-one Arabic-first sports ERP with POS, double-entry finance, pricing engine, and attendance — at a price accessible to a 50-player football academy.
---
## Key Metrics to Track
| Metric | Target (Month 6) | Target (Month 12) |
|--------|:---:|:---:|
| MRR | $3,000 (١٥٠K ج.م) | $9,000 (٤٥٠K ج.م) |
| Customers | 20 | 45 |
| Monthly churn | < 5% | < 3% |
| NPS | > 40 | > 50 |
| Fee revenue as % of total | > 60% | > 65% |
| Starter → Pro upgrade rate | > 30% in 3 months | > 40% |
| Average Revenue Per Account | $160 (٨,٠٠٠ ج.م) | $198 (٩,٩٠٠ ج.م) |
---
## Risk Factors & Mitigations
| Risk | Impact | Mitigation |
|------|--------|-----------|
| 5% fee scares small academies | Low Starter conversion | Frame as "transaction processing"; show actual EGP amount not raw % |
| Large academy demands lower % | Revenue pressure | Enterprise at 1% already; offer cap (e.g., max ١٠,٠٠٠ ج.م/month fee) |
| Server shared with 58 apps | Reliability risk | Isolate DB to dedicated RDS when MRR > $2K (١٠٠K ج.م) |
| Single developer dependency | Bus factor = 1 | Comprehensive CLAUDE.md + rules = any AI dev can continue |
| EGP devaluation | USD pricing becomes expensive | Monitor; offer EGP billing option if rate moves past 55 |
| Payment gateway delay | No online payments at launch | Start with cash/bank transfer; add Paymob in month 4 |
| Competitor copies features | Market share loss | Speed of execution + deep sports domain = 12-month moat minimum |
### Risk Matrix
```mermaid
quadrantChart
title Risk Impact vs Likelihood
x-axis "Low Likelihood" --> "High Likelihood"
y-axis "Low Impact" --> "High Impact"
quadrant-1 "Monitor Closely"
quadrant-2 "Critical"
quadrant-3 "Accept"
quadrant-4 "Mitigate"
"5% fee scares": [0.5, 0.4]
"Server reliability": [0.3, 0.7]
"EGP devaluation": [0.7, 0.5]
"Competitor copies": [0.4, 0.6]
"Single dev": [0.2, 0.8]
"Payment gateway": [0.6, 0.3]
```
---
## 90-Day Launch Plan
### Timeline
```mermaid
gantt
title 90-Day Launch Plan
dateFormat YYYY-MM-DD
axisFormat %b %d
section Week 1-2: Polish
Fix UI issues :a1, 2026-07-03, 7d
Deploy marketing site :a2, 2026-07-07, 3d
Setup domain :a3, 2026-07-08, 2d
Onboard 2 pilot academies :a4, 2026-07-10, 7d
section Week 3-4: Soft Launch
Pilot feedback & fixes :b1, 2026-07-17, 7d
Record demo video :b2, 2026-07-20, 3d
Collect testimonials :b3, 2026-07-24, 5d
Setup Paymob billing :b4, 2026-07-24, 5d
section Month 2: Marketing
Launch Facebook Ads :c1, 2026-08-01, 30d
Sports group outreach :c2, 2026-08-01, 14d
WhatsApp outreach (50) :c3, 2026-08-07, 21d
Target 5 customers :milestone, c4, 2026-08-31, 0d
section Month 3: Growth
Referral program :d1, 2026-09-01, 30d
SEO blog posts (4) :d2, 2026-09-01, 28d
Sports event attendance :d3, 2026-09-15, 2d
Target 12 customers :milestone, d4, 2026-09-30, 0d
```
### Week 1-2: Polish
- [ ] Fix remaining UI issues (est. cost: $0 — AI dev time only)
- [ ] Deploy marketing site to Vercel ($0)
- [ ] Purchase & configure domain (~$15 / ٧٥٠ ج.م)
- [ ] Onboard 2 pilot academies (free, for testimonials)
### Week 3-4: Soft Launch
- [ ] Collect pilot feedback, fix critical issues
- [ ] Record 2-minute demo video in Arabic ($0 — self-produced)
- [ ] Get 2-3 written testimonials from pilots
- [ ] Set up Paymob for subscription billing ($0 setup, 2.5% per transaction)
### Month 2: Marketing Push
- [ ] Launch Facebook Ads: 3 creatives × 2 audiences ($300 / ١٥,٠٠٠ ج.م)
- [ ] Post in 10+ Egyptian sports Facebook groups ($0)
- [ ] WhatsApp outreach to 50 academy owners ($0)
- [ ] Target: **5 paying customers** by end of month
### Month 3: Growth
- [ ] Launch referral program (1 month free for both parties)
- [ ] Publish 4 SEO blog posts targeting Arabic keywords ($0)
- [ ] Attend 1 local sports event/exhibition ($50-100 / ٢,٥٠٠–٥,٠٠٠ ج.م)
- [ ] Target: **12 total paying customers**
### Total Launch Investment (90 days)
| Category | USD | EGP |
|----------|:---:|:---:|
| Infrastructure (3 months) | $270 | ١٣,٥٠٠ ج.م |
| Marketing (3 months) | $1,000 | ٥٠,٠٠٠ ج.م |
| Domain + misc | $20 | ١,٠٠٠ ج.م |
| Dev tools (3 months) | $450 | ٢٢,٥٠٠ ج.م |
| **Total to launch** | **$1,740** | **٨٧,٠٠٠ ج.م** |
**Expected revenue by end of month 3:** $1,010/month (٥٠,٥٠٠ ج.م/month) — investment recovered by month 5.
---
## Financial Summary
```mermaid
flowchart TD
subgraph "Year 1 Summary"
INV["Total Investment<br/>$1,740 / ٨٧K ج.م"]
BE["Breakeven<br/>Month 3 (5-7 customers)"]
Y1["Year 1 Revenue<br/>~$45K / ٢.٢٥M ج.م"]
NP["Year 1 Net Profit<br/>~$36K / ١.٨M ج.م"]
RR["Month 12 Run Rate<br/>$8,920/mo / ٤٤٦K ج.م"]
end
INV --> BE --> Y1 --> NP
Y1 --> RR
```
# El Captain Marketing Site — Design System
## Design Tokens
### Primitive Tokens (raw values)
```css
:root {
/* Colors - Primitive */
--color-navy-50: #EFF6FF;
--color-navy-100: #DBEAFE;
--color-navy-200: #BFDBFE;
--color-navy-500: #3B82F6;
--color-navy-700: #1D4ED8;
--color-navy-800: #1E3A5F;
--color-navy-900: #0F172A;
--color-sky-50: #F0F9FF;
--color-sky-100: #E0F2FE;
--color-sky-200: #BAE6FD;
--color-sky-400: #38BDF8;
--color-sky-500: #0EA5E9;
--color-sky-600: #0284C7;
--color-sky-700: #0369A1;
--color-slate-50: #F8FAFC;
--color-slate-100: #F1F5F9;
--color-slate-200: #E2E8F0;
--color-slate-300: #CBD5E1;
--color-slate-400: #94A3B8;
--color-slate-500: #64748B;
--color-slate-600: #475569;
--color-slate-700: #334155;
--color-slate-800: #1E293B;
--color-slate-900: #0F172A;
--color-emerald-500: #10B981;
--color-amber-500: #F59E0B;
--color-violet-500: #8B5CF6;
--color-red-500: #EF4444;
/* Spacing - Primitive */
--space-1: 4px;
--space-2: 8px;
--space-3: 12px;
--space-4: 16px;
--space-5: 20px;
--space-6: 24px;
--space-8: 32px;
--space-10: 40px;
--space-12: 48px;
--space-16: 64px;
--space-20: 80px;
--space-24: 96px;
/* Radius - Primitive */
--radius-sm: 4px;
--radius-md: 8px;
--radius-lg: 12px;
--radius-xl: 16px;
--radius-2xl: 24px;
--radius-full: 9999px;
/* Shadows - Primitive */
--shadow-sm: 0 1px 2px rgba(0,0,0,0.05);
--shadow-md: 0 4px 6px -1px rgba(0,0,0,0.07), 0 2px 4px -2px rgba(0,0,0,0.05);
--shadow-lg: 0 10px 15px -3px rgba(0,0,0,0.08), 0 4px 6px -4px rgba(0,0,0,0.04);
--shadow-xl: 0 20px 25px -5px rgba(0,0,0,0.08), 0 8px 10px -6px rgba(0,0,0,0.04);
--shadow-glow: 0 0 40px rgba(14,165,233,0.15);
}
```
### Semantic Tokens (purpose-driven)
```css
:root {
/* Text */
--text-primary: var(--color-slate-900);
--text-secondary: var(--color-slate-500);
--text-tertiary: var(--color-slate-400);
--text-inverse: #FFFFFF;
--text-brand: var(--color-sky-600);
--text-success: var(--color-emerald-500);
--text-warning: var(--color-amber-500);
--text-error: var(--color-red-500);
/* Background */
--bg-page: var(--color-slate-50);
--bg-surface: #FFFFFF;
--bg-elevated: #FFFFFF;
--bg-muted: var(--color-slate-100);
--bg-brand: var(--color-sky-500);
--bg-brand-subtle: var(--color-sky-50);
--bg-dark: var(--color-navy-800);
/* Border */
--border-default: var(--color-slate-200);
--border-subtle: var(--color-slate-100);
--border-strong: var(--color-slate-300);
--border-brand: var(--color-sky-200);
--border-focus: var(--color-sky-500);
/* Interactive */
--interactive-primary: var(--color-sky-500);
--interactive-primary-hover: var(--color-sky-600);
--interactive-primary-active: var(--color-sky-700);
--interactive-secondary: var(--color-slate-100);
--interactive-secondary-hover: var(--color-slate-200);
}
```
### Component Tokens
```css
:root {
/* Button */
--btn-primary-bg: var(--interactive-primary);
--btn-primary-bg-hover: var(--interactive-primary-hover);
--btn-primary-text: var(--text-inverse);
--btn-primary-radius: var(--radius-lg);
--btn-primary-padding: var(--space-3) var(--space-6);
--btn-primary-font-weight: 600;
--btn-secondary-bg: var(--bg-surface);
--btn-secondary-border: var(--border-default);
--btn-secondary-text: var(--text-primary);
/* Card */
--card-bg: var(--bg-surface);
--card-border: var(--border-default);
--card-radius: var(--radius-xl);
--card-padding: var(--space-6);
--card-shadow: var(--shadow-sm);
--card-shadow-hover: var(--shadow-lg);
/* Nav */
--nav-height: 72px;
--nav-bg: rgba(255,255,255,0.8);
--nav-backdrop: blur(12px);
--nav-border: var(--border-subtle);
/* Section */
--section-padding-y: var(--space-20);
--section-padding-y-mobile: var(--space-12);
--section-max-width: 1280px;
}
```
---
## Tailwind Configuration
```javascript
// tailwind.config.js
module.exports = {
content: ['./src/**/*.{js,ts,jsx,tsx}'],
theme: {
extend: {
colors: {
brand: {
50: '#F0F9FF',
100: '#E0F2FE',
200: '#BAE6FD',
300: '#7DD3FC',
400: '#38BDF8',
500: '#0EA5E9',
600: '#0284C7',
700: '#0369A1',
},
navy: {
800: '#1E3A5F',
900: '#0F172A',
},
},
fontFamily: {
cairo: ['Cairo', 'Noto Sans Arabic', 'system-ui', 'sans-serif'],
inter: ['Inter', 'system-ui', 'sans-serif'],
mono: ['JetBrains Mono', 'Fira Code', 'monospace'],
},
fontSize: {
'display': ['64px', { lineHeight: '1.1', letterSpacing: '-0.02em' }],
'display-mobile': ['40px', { lineHeight: '1.15', letterSpacing: '-0.01em' }],
},
animation: {
'fade-up': 'fadeUp 0.6s ease-out forwards',
'count-up': 'countUp 1.2s ease-out forwards',
'draw-in': 'drawIn 1s ease-out forwards',
'float': 'float 6s ease-in-out infinite',
},
keyframes: {
fadeUp: {
'0%': { opacity: '0', transform: 'translateY(20px)' },
'100%': { opacity: '1', transform: 'translateY(0)' },
},
float: {
'0%, 100%': { transform: 'translateY(0px)' },
'50%': { transform: 'translateY(-10px)' },
},
},
},
},
}
```
---
## Component Specifications
### Navigation Bar
```
┌─────────────────────────────────────────────────────────────┐
│ [Logo] الرئيسية المميزات الأسعار تواصل [CTA] │
│ ───────── ابدأ │
└─────────────────────────────────────────────────────────────┘
- Height: 72px
- Background: white/80% + backdrop-blur-xl
- Position: sticky top-0
- Border: 1px bottom slate-100
- Logo: left in RTL (right side visually)
- CTA button: primary small variant
- Active link: sky-600 with 2px bottom indicator
- Mobile: hamburger → full-screen overlay menu
```
### Hero Section
```
┌─────────────────────────────────────────────────────────────┐
│ │
│ كل شيء تحت إدارتك ┌─────────┐ │
│ ────────────────── │ Dashboard│ │
│ منصة إدارة رياضية متكاملة تضع │ Mockup │ │
│ كل لاعب وكل جنيه وكل حصة │ (tilted) │ │
│ تحت تحكمك الكامل │ │ │
│ └─────────┘ │
│ [ابدأ مجاناً] [احجز عرض] │
│ │
│ ٤٧+ أكاديمية │ ١٢,٠٠٠+ لاعب │ ٩٩.٩% وقت تشغيل │
│ │
└─────────────────────────────────────────────────────────────┘
- Min-height: 90vh
- Background: subtle gradient (white → sky-50)
- Headline: Display size, Cairo ExtraBold, navy-900
- Subheadline: Body Large, slate-500, max-w-xl
- Stats bar: bottom of hero, 3 metrics with dividers
- Dashboard mockup: perspective(1000px) rotateY(-5deg) rotateX(3deg)
- Animation: headline fades up 0.4s, subtext 0.6s, mockup 0.8s, stats 1.0s
```
### Feature Module Card
```
┌───────────────────────────┐
│ [icon] │
│ │
│ إدارة مالية متكاملة │
│ ───────────────── │
│ تتبع كل جنيه من لحظة │
│ الدفع حتى التقرير │
│ الشهري │
│ │
│ → اكتشف المزيد │
└───────────────────────────┘
- Width: 1/3 on desktop, full on mobile
- Padding: 32px
- Border: 1px slate-200
- Radius: 16px
- Hover: border-sky-200, shadow-lg, translateY(-4px)
- Icon: 48px, sky-500, outlined stroke
- Title: H4, Cairo SemiBold, navy-900
- Description: Body, slate-500, 2-3 lines max
- Link: sky-600, arrow animates 4px right on hover
- Transition: all 300ms ease
```
### Pricing Card
```
┌───────────────────────────┐ ┌───────────────────────────┐
│ أساسي │ │ ★ احترافي (مُوصى به) │
│ │ │ │
│ ٤٩٩ ج.م │ │ ٩٩٩ ج.م │
│ /شهرياً │ │ /شهرياً │
│ │ │ │
│ ✓ حتى ٢٠٠ لاعب │ │ ✓ لاعبين غير محدودين │
│ ✓ فرع واحد │ │ ✓ حتى ٥ فروع │
│ ✓ إدارة مالية │ │ ✓ كل المميزات │
│ ✓ تقارير أساسية │ │ ✓ POS + مخزون │
│ ✗ POS │ │ ✓ تقارير متقدمة │
│ │ │ │
│ [ابدأ مجاناً] │ │ [ابدأ الآن] │
└───────────────────────────┘ └───────────────────────────┘
- Recommended: sky-500 border-2, "مُوصى به" badge top-right
- Regular: slate-200 border
- Price: Display size, navy-900, Cairo ExtraBold
- Features: check = emerald-500, cross = slate-300
- CTA: Primary button (recommended) / Secondary button (regular)
```
### Testimonial Card
```
┌───────────────────────────────────────────┐
│ │
│ "المنصة غيرت طريقة إدارتنا للأكاديمية │
│ بالكامل. كل شيء واضح ومنظم." │
│ │
│ ┌──┐ أحمد محمد │
│ │ │ مدير أكاديمية النجوم │
│ └──┘ القاهرة │
│ │
└───────────────────────────────────────────┘
- Background: white
- Border: 1px slate-200
- Quote: Body Large, slate-700, italic
- Avatar: 48px circle, slate-200 border
- Name: Body, font-semibold, navy-900
- Role: Small, slate-500
```
### CTA Section (Bottom)
```
┌─────────────────────────────────────────────────────────────┐
│ ██████████████████████████████████████████████████████████ │
│ ██ ██ │
│ ██ جاهز تأخذ التحكم الكامل؟ ██ │
│ ██ ██ │
│ ██ ابدأ بتجربة مجانية ١٤ يوم ██ │
│ ██ بدون بطاقة ائتمان ██ │
│ ██ ██ │
│ ██ [ابدأ مجاناً] [تحدث مع فريقنا] ██ │
│ ██ ██ │
│ ██████████████████████████████████████████████████████████ │
└─────────────────────────────────────────────────────────────┘
- Background: navy-800 → navy-900 gradient
- Text: white
- Headline: H2, Cairo Bold
- Subtext: Body Large, slate-300
- Primary CTA: white bg, navy-900 text (inverted)
- Secondary CTA: ghost, white text, white border
- Radius: 2xl (24px)
- Padding: 80px vertical
```
---
## Interaction Patterns
### Scroll Reveal
- Elements start: opacity-0, translateY(20px)
- Trigger: when 20% of element enters viewport
- Duration: 600ms, ease-out
- Stagger: 100ms between siblings
### Number Counter
- Triggers on viewport entry
- Counts from 0 to target over 1.2s
- Easing: ease-out (fast start, slow end)
- Suffix/prefix animate in separately
### Dashboard Mockup
- Subtle floating animation (6s infinite, ease-in-out, 10px amplitude)
- On scroll: perspective shift (rotateY responds to scroll position, max 5deg)
- Charts inside mockup: draw-in animation on viewport entry
- Numbers inside mockup: count-up animation with slight delay
### Page Transitions
- Route change: current page fades out (200ms), new page fades up (400ms)
- Shared elements (nav, footer): persist, no transition
- Loading state: progress bar top of viewport (sky-500, 2px height)
---
## Accessibility Requirements
### Focus States
- All interactive elements: 2px sky-500 outline, 2px offset
- Tab order follows visual order (RTL-aware)
- Skip-to-content link visible on focus
### Motion Preferences
- `prefers-reduced-motion: reduce` → disable all animations
- Parallax effects → static positioning
- Auto-playing counters → show final value immediately
### Screen Reader
- All images: descriptive alt text (Arabic)
- All icons: aria-label or aria-hidden
- Section landmarks: proper heading hierarchy (h1 → h2 → h3)
- Language attribute switches for English segments: `lang="en"`
### Color
- Never rely on color alone for meaning
- All states have non-color indicators (icons, text, borders)
- Tested with deuteranopia, protanopia, tritanopia simulators
# El Captain Marketing Site — Implementation Plan
## Phase 1: Foundation (Week 1)
### Setup
- [ ] Initialize Next.js 14 with App Router + TypeScript
- [ ] Configure Tailwind with custom theme (design tokens)
- [ ] Set up Cairo + Inter fonts via next/font
- [ ] Configure i18n routing (ar/en with ar as default)
- [ ] Install: framer-motion, lucide-react, shadcn/ui
- [ ] Set up RTL layout wrapper
- [ ] Create base components: Button, Card, Container, Section
### Layout
- [ ] Build Navbar (sticky, glass effect, RTL)
- [ ] Build Footer
- [ ] Build MobileMenu (slide overlay)
- [ ] Build LanguageToggle component
- [ ] Create AnimateOnScroll wrapper component
- [ ] Create CountUpNumber component
---
## Phase 2: Homepage (Week 2-3)
### Sections (in order)
- [ ] Hero section (headline + dashboard mockup + stats bar)
- [ ] Problem → Solution scroll transition
- [ ] Module Showcase (6 cards grid)
- [ ] Feature Deep-Dive #1: Financial Command
- [ ] Feature Deep-Dive #2: Smart Enrollment
- [ ] Feature Deep-Dive #3: Attendance Intelligence
- [ ] Testimonials carousel
- [ ] Stats section (counting numbers)
- [ ] CTA section (dark gradient)
### Content
- [ ] Write all Arabic copy (from messaging framework)
- [ ] Create dashboard mockup images (screenshot from real app)
- [ ] Design 6 module icons (SVG, outlined)
- [ ] Create feature section mockups (3 screenshots)
---
## Phase 3: Secondary Pages (Week 3-4)
- [ ] Features page (14 module detail cards)
- [ ] Pricing page (3-tier cards + FAQ accordion)
- [ ] About page (mission + values + team placeholder)
- [ ] Contact page (form + calendar embed)
- [ ] 404 page (branded)
---
## Phase 4: Polish & Performance (Week 4-5)
- [ ] All animations tuned and tested
- [ ] Responsive testing (320px → 2560px)
- [ ] RTL testing thoroughness
- [ ] Performance optimization (< 2.5s LCP)
- [ ] SEO: meta tags, OG images, structured data
- [ ] Accessibility audit (axe-core, VoiceOver)
- [ ] Cross-browser testing (Chrome, Safari, Firefox, Samsung Internet)
- [ ] Form backend connection (demo request → email/CRM)
- [ ] WhatsApp floating button integration
- [ ] Analytics setup (Plausible or PostHog)
---
## Phase 5: Launch (Week 5-6)
- [ ] Domain setup (DNS → Vercel)
- [ ] Final content review (Arabic proofreading)
- [ ] Lighthouse scores all green (90+ across board)
- [ ] Social sharing preview correct (OG images)
- [ ] Google Search Console submission
- [ ] Launch announcement prep
---
## Dependencies & Decisions Still Needed
| Decision | Options | Impact |
|----------|---------|--------|
| Domain name | elcaptain.com / elcaptain.app / elcaptain.io | SEO, branding |
| Pricing numbers | Final EGP amounts per tier | Pricing page content |
| Testimonials | Need 3-5 real quotes from existing users | Social proof section |
| Demo booking tool | Cal.com / Calendly / custom | Contact page |
| Analytics | Plausible (simple) / PostHog (powerful) | Privacy vs. features |
| Blog (phase 2) | MDX in repo / Sanity CMS / Contentlayer | Content workflow |
| Logo | Need final designed logo files | Header, favicon, OG |
---
## Quick Start Commands
```bash
cd marketing-site
# Initialize (when ready to code)
npx create-next-app@latest . --typescript --tailwind --app --src-dir
npm install framer-motion lucide-react class-variance-authority clsx tailwind-merge
npx shadcn-ui@latest init
# Development
npm run dev # localhost:3000
npm run build # Production build
npm run lint # ESLint
npm run lighthouse # Performance audit
```
# El Captain Sports Management — Infrastructure & Capacity Planning
## Current Production Hardware Usage
**Server:** AWS EC2 (Frankfurt — eu-central-1)
**IP:** 18.192.166.221
**OS:** Ubuntu 24.04.4 LTS
**Orchestration:** CapRover (Docker Swarm)
### Current Container Stats
| Container | RAM Usage | CPU Usage | Image Size |
|-----------|-----------|-----------|------------|
| App (Laravel + Nginx + PHP-FPM) | 111.1 MiB | 0.02% | 975 MB |
| Database (PostgreSQL 16) | 37.4 MiB | 0.00% | ~400 MB |
| **Total System** | **148.5 MiB** | **~0.02%** | **~1.4 GB** |
### Current Database Stats
| Metric | Value |
|--------|-------|
| Total DB Size | 15 MB |
| Total Tables | 76 |
| Total Rows | 1,797 |
| Active Connections | 3 |
| Total Index Size | 3.8 MB |
| Largest Table | permission_role (344 KB / 1,002 rows) |
### Current Data Volume (10 Participants)
| Entity | Row Count |
|--------|-----------|
| Participants | 10 |
| Invoices | 9 |
| Payments | 6 |
| Audit Logs | 135 |
| Permission-Role | 1,002 |
### App Configuration
| Setting | Value |
|---------|-------|
| PHP Memory Limit | 256 MB |
| PHP-FPM Workers | Default (dynamic) |
| Queue Workers | 2 (supervisor) |
| PostgreSQL shared_buffers | 128 MB |
| PostgreSQL work_mem | 4 MB |
| PostgreSQL max_connections | 100 |
| PostgreSQL effective_cache_size | 4 GB |
---
## Scaling Projections
### Methodology
Based on current data (10 participants = 1,797 rows / 15 MB / 148.5 MiB RAM), we extrapolate using realistic ratios for a sports academy:
**Per participant (annual, normal usage):**
- ~15 invoices/year (monthly fees + extras)
- ~12 payments/year
- ~150 attendance records/year (3 sessions/week × 50 weeks)
- ~200 audit log entries/year (CRUD on profile, payments, attendance)
- ~3 enrollments/year (seasonal programs)
- ~5 inventory movements/year (equipment, uniforms)
- ~30 notifications/year
### Row Growth Formula (per year)
```
Annual Rows per Participant ≈ 415 rows
Base System Rows (roles, permissions, settings, accounts) ≈ 2,000 rows (fixed)
```
### Storage Growth Formula
```
DB Size ≈ 2 MB (base) + (participants × 0.8 MB/year)
Audit Logs ≈ participants × 200 rows × 0.5 KB/row = participants × 100 KB/year
Total Annual Growth ≈ participants × 1.0 MB/year
```
---
## Capacity Tiers
### Tier Breakdown
| Tier | Players | Annual DB Growth | Year-End DB Size | RAM (App) | RAM (DB) | Total RAM | vCPUs |
|------|---------|-----------------|------------------|-----------|----------|-----------|-------|
| Starter | 50 | 50 MB | ~65 MB | 256 MB | 256 MB | 512 MB | 1 |
| Small | 200 | 200 MB | ~215 MB | 512 MB | 512 MB | 1 GB | 1 |
| Medium | 500 | 500 MB | ~515 MB | 1 GB | 1 GB | 2 GB | 2 |
| Large | 2,000 | 2 GB | ~2.1 GB | 2 GB | 2 GB | 4 GB | 2 |
| Enterprise | 5,000 | 5 GB | ~5.1 GB | 4 GB | 4 GB | 8 GB | 4 |
| Multi-Academy | 10,000+ | 10+ GB | ~10.1 GB | 8 GB | 8 GB | 16 GB | 8 |
### Concurrent Users Estimation
| Players | Peak Concurrent Users | Requests/sec (peak) | PHP Workers Needed |
|---------|----------------------|--------------------|--------------------|
| 50 | 5-10 | 2-5 | 2 |
| 200 | 20-40 | 10-20 | 4 |
| 500 | 50-100 | 25-50 | 8 |
| 2,000 | 200-400 | 100-200 | 16 |
| 5,000 | 500-1000 | 250-500 | 32 |
| 10,000 | 1000-2000 | 500-1000 | 64 (clustered) |
---
## 500-Player Academy — Full Year Projection
### Monthly Data Growth
| Month | Cumulative Rows | DB Size | Audit Logs | Attendance Records |
|-------|----------------|---------|------------|-------------------|
| Jan | 12,000 | 12 MB | 8,300 | 6,000 |
| Feb | 29,000 | 25 MB | 16,600 | 12,000 |
| Mar | 46,000 | 42 MB | 24,900 | 18,000 |
| Apr | 63,000 | 58 MB | 33,200 | 24,000 |
| May | 80,000 | 72 MB | 41,500 | 30,000 |
| Jun | 97,000 | 88 MB | 49,800 | 36,000 |
| Jul | 114,000 | 105 MB | 58,100 | 42,000 |
| Aug | 131,000 | 120 MB | 66,400 | 48,000 |
| Sep | 148,000 | 138 MB | 74,700 | 54,000 |
| Oct | 165,000 | 155 MB | 83,000 | 60,000 |
| Nov | 182,000 | 170 MB | 91,300 | 66,000 |
| Dec | 209,500 | 515 MB* | 100,000 | 75,000 |
*Year-end includes indexes, TOAST data, and bloat factor (~3x raw data for PostgreSQL with indexes)
### Recommended Hardware (500 Players)
| Component | Minimum | Recommended | Notes |
|-----------|---------|-------------|-------|
| vCPUs | 1 | 2 | Handles peak registration days |
| RAM | 1.5 GB | 2 GB | 1 GB app + 1 GB PG |
| Storage | 5 GB | 20 GB | Room for 3 years + backups |
| Network | Shared | Shared | <100 Mbps sufficient |
| Backup | Daily | Daily + WAL | Point-in-time recovery |
### Hosting Cost Estimate (500 Players)
| Provider | Instance | Monthly Cost (USD) | Monthly Cost (EGP) |
|----------|----------|-------------------|--------------------|
| AWS EC2 | t3.small (2 vCPU / 2 GB) | $18.40 | 920 ج.م |
| Hetzner | CX22 (2 vCPU / 4 GB) | $5.39 | 270 ج.م |
| DigitalOcean | Basic (2 vCPU / 2 GB) | $18.00 | 900 ج.م |
| CapRover (current) | Shared | ~$5.00 | 250 ج.م |
---
## Mermaid Diagrams
### System Architecture
```mermaid
graph TB
subgraph "CapRover Host (18.192.166.221)"
subgraph "App Container"
NGINX[Nginx Reverse Proxy]
PHP[PHP-FPM Workers]
QUEUE[Queue Workers x2]
SCHED[Scheduler]
end
subgraph "DB Container"
PG[(PostgreSQL 16)]
end
NGINX --> PHP
PHP --> PG
QUEUE --> PG
end
CLIENT[Browser / Mobile] -->|HTTPS| NGINX
CAPROVER[CapRover Proxy] --> NGINX
```
### RAM Usage by Player Count
```mermaid
xychart-beta
title "RAM Requirements by Player Count"
x-axis ["50", "200", "500", "1K", "2K", "5K", "10K"]
y-axis "RAM (GB)" 0 --> 16
bar [0.5, 1, 2, 3, 4, 8, 16]
```
### Database Size Growth (500 Players — 12 Months)
```mermaid
xychart-beta
title "Database Size Growth — 500 Player Academy (Year 1)"
x-axis ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
y-axis "Size (MB)" 0 --> 550
line [12, 25, 42, 58, 72, 88, 105, 120, 138, 155, 170, 515]
bar [12, 25, 42, 58, 72, 88, 105, 120, 138, 155, 170, 515]
```
### Row Count Growth (500 Players — 12 Months)
```mermaid
xychart-beta
title "Total Row Count — 500 Player Academy (Year 1)"
x-axis ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
y-axis "Rows (thousands)" 0 --> 220
line [12, 29, 46, 63, 80, 97, 114, 131, 148, 165, 182, 209]
```
### Concurrent Users vs Required PHP Workers
```mermaid
xychart-beta
title "PHP-FPM Workers Needed by Concurrent Users"
x-axis ["10", "40", "100", "200", "400", "1000"]
y-axis "Workers" 0 --> 64
bar [2, 4, 8, 16, 32, 64]
```
### Cost vs Player Count (Monthly USD)
```mermaid
xychart-beta
title "Monthly Hosting Cost by Tier (USD)"
x-axis ["50 players", "200 players", "500 players", "2K players", "5K players"]
y-axis "USD/month" 0 --> 80
bar [5, 10, 18, 40, 75]
```
### Data Distribution (500 Players — Year End)
```mermaid
pie title "Row Distribution at Year End (500 Players)"
"Attendance Records" : 75000
"Audit Logs" : 100000
"Invoices & Payments" : 13500
"Notifications" : 15000
"Enrollments & Groups" : 4000
"Base System" : 2000
```
### Scaling Decision Tree
```mermaid
flowchart TD
START[Current Load] --> CHECK{Response Time > 200ms?}
CHECK -->|No| MONITOR[Continue Monitoring]
CHECK -->|Yes| CPU{CPU > 70%?}
CPU -->|Yes| SCALE_CPU[Add vCPUs / More Workers]
CPU -->|No| RAM{RAM > 80%?}
RAM -->|Yes| SCALE_RAM[Upgrade Instance RAM]
RAM -->|No| DB{DB Queries Slow?}
DB -->|Yes| DB_OPT[Add Indexes / Tune PG]
DB -->|No| QUEUE{Queue Backlog?}
QUEUE -->|Yes| SCALE_QUEUE[Add Queue Workers]
QUEUE -->|No| NETWORK[Check Network / CDN]
SCALE_CPU --> VERIFY[Verify Fix]
SCALE_RAM --> VERIFY
DB_OPT --> VERIFY
SCALE_QUEUE --> VERIFY
NETWORK --> VERIFY
VERIFY --> MONITOR
```
### Year-Over-Year Projection (500 Players)
```mermaid
xychart-beta
title "3-Year Storage Projection — 500 Players (GB)"
x-axis ["Year 1", "Year 2", "Year 3"]
y-axis "Storage (GB)" 0 --> 2
bar [0.5, 1.1, 1.7]
```
---
## Key Recommendations
### For a 500-Player Academy (Standard Deployment)
1. **Hosting:** 2 vCPU / 2 GB RAM instance (t3.small or equivalent) — $18/month
2. **Storage:** 20 GB SSD (allows 3+ years of growth with headroom)
3. **Database:** PostgreSQL 16, shared_buffers=512MB, work_mem=8MB
4. **PHP-FPM:** 8 workers (handles 50-100 concurrent users)
5. **Queue:** 2-4 workers for background jobs (notifications, attendance, reports)
6. **Backup:** Daily pg_dump + WAL archiving for point-in-time recovery
7. **Monitoring:** Set alerts at 80% RAM, 70% CPU, 80% disk
### When to Scale Up
| Signal | Action |
|--------|--------|
| p95 response > 500ms | Add PHP workers or vCPUs |
| RAM consistently > 80% | Upgrade to 4 GB instance |
| DB > 5 GB | Consider read replicas |
| Concurrent users > 200 | Move to 4 vCPU instance |
| Multiple academies on same DB | Shard or separate databases |
### Current System Health
The system is **massively over-provisioned** for its current 10 participants:
- Using 0.02% CPU (needs ~0.0001% per player)
- Using 148 MB of RAM (needs ~15 MB per player for app overhead)
- Database at 15 MB (well under the 515 MB projected for 500 players after a full year)
- 97 idle PostgreSQL connections available
**Bottom line:** The current infrastructure can handle **500+ players** without any changes. Scaling only becomes necessary at **2,000+ players** or when adding multiple academies.
---
## Summary Table
| Metric | Current (10 players) | Target (500 players) | Growth Factor |
|--------|---------------------|---------------------|---------------|
| DB Size | 15 MB | 515 MB | 34x |
| Total Rows | 1,797 | 209,500 | 117x |
| RAM Usage | 148 MB | ~1.5 GB | 10x |
| CPU Usage | 0.02% | ~5-15% | 250-750x |
| Monthly Cost | $5 (shared) | $18 (dedicated) | 3.6x |
| Annual Cost | $60 | $216 | 3.6x |
# El Captain — Messaging Framework
## Core Statements
### Mission
We build the command center for sports organizations — giving academy owners total operational control so they can focus on developing athletes, not managing spreadsheets.
### Vision
A world where every sports academy in the Arab region operates with the precision, intelligence, and professionalism of an elite club.
### Value Proposition
For **sports academy owners** who struggle with scattered operations, manual tracking, and financial blind spots —
**El Captain** is the all-in-one management platform that puts every player, every pound, and every session under one command center.
Unlike generic ERPs, scattered Excel sheets, or WhatsApp groups,
**we're purpose-built for how sports academies actually work** — from the first enrollment to graduation.
### Positioning Statement
El Captain is the sports operations platform for academy directors who demand complete visibility and control, built by people who understand the Egyptian sports business from the inside.
---
## Message Architecture
### Primary Message
**"كل شيء تحت إدارتك"** — Everything under your command.
One platform gives you total operational control: financial clarity, player tracking, attendance automation, and real-time performance data.
### Supporting Messages
| # | Message | Audience Need | Proof Point |
|---|---------|---------------|-------------|
| 1 | **تحكم مالي كامل** — Track every pound from enrollment to report | Financial visibility | Double-entry accounting, real-time dashboards |
| 2 | **صفر ورق، صفر فوضى** — Replace papers, WhatsApp, and Excel chaos | Operational efficiency | Automated enrollment, attendance, billing |
| 3 | **مصمم للرياضة** — Not a generic tool adapted, built for academies | Domain fit | Sports-specific workflows, Arabic-first |
| 4 | **ينمو معك** — Start with 50 players or 5000, same power | Scalability | Multi-branch, unlimited modules, API |
| 5 | **كل لاعب، كل تفصيلة** — Complete player lifecycle management | Data completeness | Enrollment → attendance → billing → graduation |
---
## Elevator Pitches
### 10 Seconds (Arabic)
> الكابتن هو منصة إدارة متكاملة للأكاديميات الرياضية — كل شيء من التسجيل للحضور للمالية في مكان واحد.
### 10 Seconds (English)
> El Captain is an all-in-one management platform for sports academies — enrollment, attendance, and finance in one place.
### 30 Seconds (Arabic)
> لو بتدير أكاديمية رياضية وزهقت من الإكسيل والورق والواتساب — الكابتن يحل المشكلة دي.
> منصة واحدة فيها تسجيل اللاعبين، الحضور الآلي، المالية، نقاط البيع، والتقارير.
> مصممة خصيصاً للأكاديميات الرياضية المصرية. ٤٧ أكاديمية شغالة عليها دلوقتي.
### 60 Seconds (Arabic)
> تخيل إنك تفتح تطبيق واحد وتشوف: كام لاعب حاضر النهاردة، كام جنيه دخل، مين متأخر في الدفع، وأي مجموعة محتاجة مدرب بديل.
>
> الكابتن بيديك كل ده — من غير ورق، من غير واتساب، من غير إكسيل.
>
> المنصة فيها: تسجيل لاعبين ذكي، حضور آلي بتنبيهات، نظام مالي بالقرش، نقاط بيع، مخزون، وتقارير لحظية.
>
> الفرق بيننا وبين أي نظام تاني: إحنا مصممين للأكاديمية الرياضية من الأول. مش نظام عام حد عدّله. كل تفصيلة — من الاشتراك الشهري لنظام التسعير للحضور — مبنية على فهم حقيقي لشغل الأكاديمية.
>
> ٤٧ أكاديمية بتدير عملياتها عبر المنصة. جرب مجاناً ١٤ يوم.
---
## Message by Audience Segment
| Audience | Pain Point | Key Message | CTA |
|----------|------------|-------------|-----|
| Academy Owner | "I don't know my real numbers" | تحكم مالي كامل — شوف أرقامك الحقيقية لحظياً | احجز عرض |
| Operations Manager | "I'm drowning in manual work" | وفر ٨٠% من الشغل اليدوي مع أتمتة ذكية | ابدأ تجربة مجانية |
| Head Trainer | "Attendance tracking is chaos" | حضور آلي — بتنبيهات فورية وتقارير أسبوعية | شوف المميزات |
| Accountant | "Reconciliation is a nightmare" | نظام محاسبي بالقرش — قيد مزدوج تلقائي | اطلب عرض |
| Parent (future) | "I never know what's happening with my child" | تابع ابنك — حضور، تقييم، ومواعيد | حمّل التطبيق |
---
## Objection Handling
| Objection | Response |
|-----------|----------|
| "Excel شغال معايا" | Excel مش بيتابع الحضور، مش بيبعت تنبيهات، ومش بيقفل الورديات. الكابتن بيعمل اللي الإكسيل مش قادر عليه. |
| "أنا أكاديميتي صغيرة" | الباقة الأساسية مصممة لحد ٢٠٠ لاعب. لما تكبر، المنصة تكبر معاك — من غير ما تغير نظامك. |
| "أنظمة ERP غالية ومعقدة" | إحنا مش ERP عام. مش هتحتاج مستشار يشتغل ٣ شهور. تبدأ في يوم واحد وتشتغل بكرة. |
| "فريقي مش بيتعامل مع تكنولوجيا" | الواجهة عربي ١٠٠% وبسيطة. المدرب مش محتاج غير يضغط "حاضر" بدل ما يكتب في ورقة. |
| "بياناتي أمان؟" | سيرفرات أوروبية، تشفير كامل، ونسخ احتياطي يومي. بياناتك ملكك وبس. |
---
## Content Tone Examples
### Headlines (Commanding, Short)
- ✅ كل شيء تحت إدارتك
- ✅ تحكم. تتبع. تنمو.
- ✅ أكاديميتك تستحق أفضل
- ✅ من الفوضى للنظام في يوم
- ❌ أفضل نظام إدارة أكاديميات في مصر!! (too salesy, exclamation)
- ❌ هل تعاني من إدارة أكاديميتك؟ (question-based, weak)
### Feature Descriptions (Clear, Benefit-First)
- ✅ تتبع كل جنيه من لحظة الدفع حتى التقرير الشهري
- ✅ حضور آلي — يسجل اللاعب ويبلغك عن الغياب فوراً
- ❌ نظام حضور متطور يستخدم أحدث التقنيات (vague, doesn't say what it does)
- ❌ إدارة مالية شاملة ومتكاملة (means nothing specific)
### CTAs (Direct, No Fluff)
- ✅ ابدأ مجاناً
- ✅ احجز عرض تجريبي
- ✅ شوف المميزات
- ✅ تحدث مع فريقنا
- ❌ اكتشف المزيد الآن! (vague + exclamation)
- ❌ لا تفوت الفرصة (fear-based, prohibited)
---
## Competitive Positioning
### vs. Excel / Google Sheets
"Excel doesn't send absence alerts. Doesn't auto-generate invoices. Doesn't track who owes what. El Captain does all that — and you set it up in a day, not a month."
### vs. WhatsApp Groups
"WhatsApp is for chatting, not for running a business. When you need to find who paid last month, or which trainer was absent Tuesday — good luck searching 4,000 messages."
### vs. Generic ERP (Odoo, etc.)
"Generic ERPs need months of customization and a consultant. El Captain is ready for sports academies out of the box — training groups, attendance, enrollment, pricing rules — all built in."
### vs. Competitor Academy Apps
"Most 'academy apps' are just attendance trackers with a payment reminder. El Captain is the full business: double-entry finance, POS, inventory, facility scheduling, smart pricing — the complete operations platform."
# El Captain Marketing Site — Full Specification
## Tech Stack
| Layer | Technology | Why |
|-------|-----------|-----|
| Framework | Next.js 14 (App Router) | SSR for SEO, image optimization, i18n routing |
| Styling | Tailwind CSS 3.4 | Utility-first, RTL support via logical properties |
| Components | shadcn/ui (customized) | Accessible primitives, easy to brand |
| Animation | Framer Motion 11 | Declarative scroll animations, layout transitions |
| 3D (optional) | Spline / Three.js | Interactive dashboard mockup (hero only) |
| Icons | Lucide React | Consistent 1.5px stroke icons |
| Forms | React Hook Form + Zod | Validation for demo request / contact |
| Analytics | Plausible / PostHog | Privacy-friendly, no cookie banner needed |
| CMS (future) | Sanity / MDX | Blog content management |
| Deploy | Vercel | Edge CDN, automatic HTTPS, preview deploys |
| Font Loading | next/font | Zero layout shift, subset for Arabic |
---
## Project Structure
```
marketing-site/
├── src/
│ ├── app/
│ │ ├── [locale]/
│ │ │ ├── page.tsx # Home
│ │ │ ├── features/page.tsx # Features deep-dive
│ │ │ ├── pricing/page.tsx # Pricing plans
│ │ │ ├── about/page.tsx # About / team
│ │ │ ├── contact/page.tsx # Demo request form
│ │ │ ├── blog/page.tsx # Blog listing (future)
│ │ │ └── layout.tsx # Locale layout (dir, lang, font)
│ │ ├── layout.tsx # Root layout
│ │ └── globals.css # Tailwind base + tokens
│ ├── components/
│ │ ├── ui/ # shadcn/ui base components
│ │ ├── layout/
│ │ │ ├── Navbar.tsx
│ │ │ ├── Footer.tsx
│ │ │ └── MobileMenu.tsx
│ │ ├── sections/
│ │ │ ├── Hero.tsx
│ │ │ ├── ProblemSolution.tsx
│ │ │ ├── ModuleShowcase.tsx
│ │ │ ├── FeatureDeepDive.tsx
│ │ │ ├── DashboardPreview.tsx
│ │ │ ├── Testimonials.tsx
│ │ │ ├── PricingTable.tsx
│ │ │ ├── StatsBar.tsx
│ │ │ ├── CTASection.tsx
│ │ │ └── FAQ.tsx
│ │ ├── shared/
│ │ │ ├── AnimateOnScroll.tsx
│ │ │ ├── CountUpNumber.tsx
│ │ │ ├── ModuleIcon.tsx
│ │ │ ├── DashboardMockup.tsx
│ │ │ └── LanguageToggle.tsx
│ │ └── forms/
│ │ ├── DemoRequestForm.tsx
│ │ └── NewsletterForm.tsx
│ ├── lib/
│ │ ├── i18n.ts # Locale config
│ │ ├── fonts.ts # Cairo + Inter loading
│ │ └── animations.ts # Framer Motion variants
│ ├── content/
│ │ ├── ar/ # Arabic content files
│ │ └── en/ # English content files
│ └── assets/
│ ├── mockups/ # Dashboard screenshots
│ ├── icons/ # Custom SVG module icons
│ └── illustrations/ # Geometric illustrations
├── public/
│ ├── og-image-ar.png # Social share (Arabic)
│ ├── og-image-en.png # Social share (English)
│ └── favicon.svg # Brand icon
├── docs/
│ ├── brand-guidelines.md
│ ├── design-system.md
│ └── site-specification.md (this file)
├── tailwind.config.ts
├── next.config.js
└── package.json
```
---
## Page Specifications
### Home Page (الرئيسية)
#### Section Flow (scroll order)
1. **Navbar** — sticky, glass effect
2. **Hero** — headline + dashboard mockup + stats bar
3. **Problem → Solution** — brief chaos-to-order transition
4. **Module Showcase** — 6 key modules as cards (grid)
5. **Feature Deep-Dive** — 3 spotlight features with interactive previews
6. **Social Proof** — testimonials carousel + logos
7. **Stats Section** — large numbers (academies, players, revenue tracked)
8. **CTA Section** — dark gradient, strong Arabic CTA
9. **Footer** — links, social, language toggle
#### Hero Content
```
Headline (AR): كل شيء تحت إدارتك
Subheadline (AR): منصة إدارة رياضية متكاملة تضع كل لاعب وكل جنيه وكل حصة تحت تحكمك الكامل
CTA Primary: ابدأ تجربة مجانية
CTA Secondary: احجز عرض تجريبي
Stats: ٤٧+ أكاديمية | ١٢,٠٠٠+ لاعب | ٩٩.٩% وقت تشغيل
```
#### Problem → Solution Section
```
Before state: "من غير نظام..." + scattered elements (papers, WhatsApp messages, Excel icons)
Transition: elements morph/dissolve into organized dashboard UI
After state: "مع الكابتن..." + clean dashboard preview
Duration: triggered on scroll, 2-3 second animation sequence
```
#### Module Showcase (6 primary)
| Module | Icon | Headline | One-liner |
|--------|------|----------|-----------|
| المالية | Wallet | إدارة مالية متكاملة | تتبع كل جنيه من الدفع حتى التقرير |
| اللاعبين | Users | ملفات لاعبين شاملة | كل بيانات اللاعب في مكان واحد |
| التدريب | Calendar | برامج ومجموعات | جدولة ذكية وتتبع تلقائي |
| الحضور | CheckCircle | حضور آلي | تسجيل، تنبيهات، ومتابعة |
| نقاط البيع | ShoppingCart | POS متكامل | بيع، تحصيل، ومخزون |
| المنشآت | Building | إدارة المنشآت | حجز، جدولة، وتخصيص |
#### Feature Deep-Dives (3 spotlights)
Each has: left = text block, right = interactive mockup
1. **Financial Command** — Dashboard with live-looking charts (revenue, outstanding, collections)
2. **Smart Enrollment** — Wizard preview showing the enrollment flow
3. **Attendance Intelligence** — Heat map / calendar view with absence alerts
#### Stats Section
```
١.٢ مليون+ ج.م — إيرادات مُدارة شهرياً
٥٠,٠٠٠+ — حصة مسجلة
٩٨% — رضا العملاء
```
Numbers count up on scroll with staggered timing.
---
### Features Page (المميزات)
#### Structure
- Hero: "كل ما تحتاجه في منصة واحدة" + module count badge
- Module grid: all 14 modules with expandable detail cards
- Each module expands to show: 4-5 specific capabilities, screenshot, related modules
- Comparison table: El Captain vs Excel vs WhatsApp vs generic ERP
- CTA: "اكتشف كيف تناسب أكاديميتك"
#### All 14 Modules Listed
1. الإدارة المالية (Finance)
2. إدارة اللاعبين (Participants)
3. البرامج التدريبية (Training Programs)
4. المجموعات (Training Groups)
5. الحضور والغياب (Attendance)
6. نقاط البيع (POS)
7. المخزون (Inventory)
8. إدارة المنشآت (Facilities)
9. الجدولة (Scheduling)
10. التقارير (Reports)
11. الإشعارات (Notifications)
12. الأدوار والصلاحيات (Permissions)
13. المحافظ الإلكترونية (Wallets)
14. التسعير الذكي (Pricing Engine)
---
### Pricing Page (الأسعار)
#### Plans
| Feature | أساسي (Starter) | احترافي (Pro) | مؤسسي (Enterprise) |
|---------|-----------------|---------------|---------------------|
| Price | ٤٩٩ ج.م/شهر | ٩٩٩ ج.م/شهر | تواصل معنا |
| Players | حتى ٢٠٠ | حتى ١,٠٠٠ | غير محدود |
| Branches | ١ | ٥ | غير محدود |
| Users | ٥ | ١٥ | غير محدود |
| Finance | ✓ | ✓ | ✓ |
| Attendance | ✓ | ✓ | ✓ |
| POS | ✗ | ✓ | ✓ |
| Inventory | ✗ | ✓ | ✓ |
| Reports | Basic | Advanced | Custom |
| Support | Email | Priority | Dedicated |
| API | ✗ | ✗ | ✓ |
#### Toggle: Monthly / Annual (20% discount on annual)
#### FAQ section below pricing cards (6-8 common questions)
---
### About Page (عن الكابتن)
- Mission statement (brand guidelines version)
- Team section (if ready) or "Built by sports people for sports people" story
- Timeline: product development milestones
- Values: 3-4 core values with icons
- Partners/integrations (if any)
---
### Contact / Demo Page
- Split layout: form left, info right
- Form fields: name, academy name, phone, email, player count (dropdown), message
- Right side: calendar embed (Cal.com or Calendly) for booking demo calls
- Below: FAQ about onboarding, data migration, support
---
## SEO Strategy
### Meta Structure
```html
<!-- Arabic (default) -->
<html dir="rtl" lang="ar">
<title>الكابتن — منصة إدارة الأكاديميات الرياضية</title>
<meta name="description" content="منصة متكاملة لإدارة الأكاديميات الرياضية: تسجيل اللاعبين، الحضور، المالية، نقاط البيع. جرب مجاناً." />
<!-- English -->
<html dir="ltr" lang="en">
<title>El Captain — Sports Academy Management Platform</title>
<meta name="description" content="All-in-one platform for sports academies: enrollment, attendance, finance, POS. Start your free trial." />
```
### Target Keywords (Arabic)
- إدارة أكاديمية رياضية
- برنامج إدارة نادي رياضي
- نظام حضور لاعبين
- برنامج محاسبة أكاديمية
- تسجيل لاعبين أونلاين
### Structured Data
- Organization schema
- SoftwareApplication schema
- FAQ schema (pricing page)
- BreadcrumbList schema
---
## Performance Targets
| Metric | Target | How |
|--------|--------|-----|
| LCP | < 2.5s | next/image, font preload, static hero |
| FID | < 100ms | Defer non-critical JS, code split |
| CLS | < 0.1 | Fixed dimensions on images, font-display: swap |
| TTI | < 3.5s | Progressive hydration, lazy animations |
| Bundle | < 150KB first load | Tree-shake, dynamic imports for Framer Motion |
### Egypt-Specific Performance
- Target: 3G/4G mobile (dominant in Egypt)
- Image format: WebP with AVIF fallback
- Font: subset Arabic glyphs only (reduce Cairo from 200KB to ~60KB)
- CDN: Vercel Edge with Middle East PoP (Bahrain)
- Critical CSS: inline above-fold styles
---
## i18n Architecture
### URL Structure
```
elcaptain.com/ → Arabic (default, redirects to /ar)
elcaptain.com/ar/ → Arabic
elcaptain.com/en/ → English
```
### Content Strategy
- Arabic is FULL content (primary)
- English is TRANSLATED (not separate content)
- Numbers: Arabic-Indic in Arabic, Western in English
- Currency: always EGP (ج.م in Arabic, EGP in English)
### Implementation
```typescript
// src/lib/i18n.ts
export const locales = ['ar', 'en'] as const;
export const defaultLocale = 'ar';
// Direction mapping
export const localeConfig = {
ar: { dir: 'rtl', font: 'cairo' },
en: { dir: 'ltr', font: 'inter' },
};
```
---
## Deployment & Infrastructure
### Hosting
- **Platform:** Vercel (Pro plan for analytics + team)
- **Domain:** elcaptain.com (or elcaptain.app / elcaptain.io)
- **SSL:** Automatic via Vercel
- **CDN:** Vercel Edge Network
### Environment Variables
```
NEXT_PUBLIC_SITE_URL=https://elcaptain.com
NEXT_PUBLIC_ANALYTICS_ID=...
CONTACT_FORM_ENDPOINT=... (could hit the Laravel app's API)
CALENDAR_EMBED_URL=...
```
### CI/CD
- Push to `main` → auto-deploy to production
- Push to PR branches → preview deploy with unique URL
- Lighthouse CI check on every PR (block if LCP > 3s)
---
## Content Checklist (Before Launch)
- [ ] All Arabic copy reviewed by native speaker
- [ ] Dashboard mockup screenshots (from actual El Captain app)
- [ ] Testimonials collected (even 2-3 is enough for launch)
- [ ] Pricing finalized with stakeholders
- [ ] Contact form backend connected
- [ ] Calendar booking tool configured
- [ ] OG images designed (Arabic + English)
- [ ] Favicon and app icons
- [ ] Legal pages (privacy policy, terms) — Arabic
- [ ] Google Search Console + Analytics connected
- [ ] Performance audit passed (< 2.5s LCP on 4G)
# El Captain Marketing Site — UX Strategy
## User Journey Map
### Primary Persona: Academy Owner / Director
- **Name:** أحمد (Ahmed), 38
- **Role:** Owns/runs a mid-size sports academy (200-500 players)
- **Tech level:** Uses smartphone daily, comfortable with apps, not a developer
- **Current tools:** Excel + WhatsApp + paper receipts + maybe a basic accounting app
- **Pain:** Doesn't know real-time numbers, spends evenings reconciling, trainers forget attendance
- **Goal:** Run a professional operation without being chained to paperwork
### Journey Stages
```
Awareness → Interest → Evaluation → Decision → Onboarding
↓ ↓ ↓ ↓ ↓
Google/ Landing Features/ Pricing Demo/
Referral Page Demo Video Page Trial
```
---
## Page-by-Page UX Flows
### Homepage Flow (120 seconds target dwell time)
```
[0-3s] Hero catches attention — bold Arabic headline + dashboard visual
[3-8s] Scans stats bar — social proof numbers build trust
[8-15s] Scrolls — problem statement resonates ("أنا كده!")
[15-25s] Sees solution transition — "ok this solves MY problem"
[25-45s] Module cards — understands breadth without reading details
[45-70s] Feature spotlight — sees actual product depth (1 of 3 resonates)
[70-90s] Testimonial — someone like them validates the choice
[90-110s] Stats section — scale/trust reinforced
[110-120s] CTA section — ready to act (demo or trial)
```
### Key UX Decisions
| Decision | Choice | Why |
|----------|--------|-----|
| Above-fold CTA | Yes (2 options) | Don't make them scroll to act |
| Module count visible | Show "١٤ وحدة" badge | Communicates completeness |
| Pricing on homepage | No (link in nav) | Don't distract from value story |
| Live demo embed | No | Too complex, breaks flow. Video or interactive mockup instead. |
| WhatsApp button | Yes (floating) | Egyptian users expect instant messaging |
| Phone number | Yes (in header) | Trust signal for Egyptian market |
---
## Interaction Design Principles
### 1. Progressive Disclosure
Don't dump all 14 modules at once. Show 6 key ones → "وأكثر..." link → Features page.
Feature deep-dives: title + one-liner visible, expand for full detail.
### 2. Scroll as Narrative
Each scroll section builds on the previous one:
- Problem (pain) → Solution (relief) → Proof (trust) → Action (conversion)
- Never show a feature without first establishing WHY they need it
### 3. Micro-Interactions That Build Confidence
- Numbers counting up = "this is real, this is measurable"
- Dashboard elements responding to cursor = "this is interactive, alive"
- Smooth transitions = "this is polished, professional"
- Instant language toggle = "they care about Arabic users"
### 4. Mobile-First Affordances
- Large tap targets (minimum 44px)
- Thumb-zone CTAs (bottom of screen)
- Sticky mobile CTA bar on scroll (appears after hero)
- Swipeable testimonial cards
- Collapsible FAQ sections
---
## Conversion Optimization
### Primary Conversion Goals (Priority Order)
1. **Demo booking** — highest intent, personal touch
2. **Free trial signup** — self-serve, lower friction
3. **WhatsApp inquiry** — low commitment, very Egyptian
4. **Newsletter** — nurture for later
### CTA Placement Strategy
| Location | CTA | Type |
|----------|-----|------|
| Navbar (always visible) | ابدأ مجاناً | Primary button |
| Hero section | ابدأ تجربة مجانية + احجز عرض | Primary + Secondary |
| After module showcase | اكتشف كل المميزات | Ghost link |
| After feature deep-dive | جرب بنفسك | Primary button |
| After testimonials | ابدأ مجاناً | Primary button |
| CTA section (bottom) | ابدأ مجاناً + تحدث مع فريقنا | Primary + Ghost |
| Floating (mobile) | WhatsApp icon | FAB |
| Exit intent (desktop) | Modal with offer | Form |
### Trust Signals
- Stats bar (academies, players, uptime)
- Customer logos (if available)
- "١٤ يوم تجربة مجانية — بدون بطاقة ائتمان"
- Security badges (SSL, EU servers)
- Arabic-first interface (shows they understand the market)
### Friction Reducers
- Demo form: 4 fields max (name, phone, academy name, player count)
- Trial signup: email + password only (academy details on onboarding)
- No credit card required for trial
- WhatsApp as escape valve for anyone uncomfortable with forms
---
## Accessibility & Inclusivity
### RTL-First Implementation
- All layouts flow right-to-left by default
- Navigation: logo on right, CTA on left (RTL visual flow)
- Text alignment: right-aligned by default
- Bidirectional icons: arrows/chevrons flip for RTL
- Numbers: always LTR within RTL text
### Egyptian Market Considerations
- Phone numbers in +20 format
- Currency: EGP (ج.م)
- Date format: DD/MM/YYYY (Arabic)
- Performance: optimize for 4G (not fiber)
- WhatsApp Business integration (support channel)
- Social proof: Egyptian academies specifically
- Imagery: Egyptian sports contexts (not Western stock)
### Screen Reader & Keyboard
- Semantic HTML5 landmarks throughout
- All images have Arabic alt text
- Skip navigation link
- Focus indicators visible and branded
- ARIA labels on interactive elements
- Tab order: logical RTL flow
---
## Content Strategy
### Content Types
1. **Static pages** — Home, Features, Pricing, About, Contact
2. **Blog** (phase 2) — SEO content, product updates, sports management tips
3. **Case studies** (phase 2) — Customer success stories with data
4. **Help center** (phase 3) — User documentation, onboarding guides
### SEO Content Calendar (Blog Topics)
| Month | Topic (AR) | Target Keyword |
|-------|-----------|----------------|
| 1 | كيف تدير أكاديمية رياضية ناجحة | إدارة أكاديمية رياضية |
| 2 | ٥ علامات إن أكاديميتك محتاجة نظام إدارة | نظام إدارة نادي |
| 3 | دليل تسعير الاشتراكات للأكاديميات | تسعير أكاديمية |
| 4 | كيف تتابع حضور اللاعبين بدون ورق | نظام حضور لاعبين |
| 5 | إزاي تزود إيرادات أكاديميتك ٣٠% | زيادة إيرادات أكاديمية |
| 6 | مقارنة: إكسيل vs نظام إدارة متخصص | برنامج إدارة نادي رياضي |
### Social Proof Strategy
- Collect 3-5 testimonials before launch (WhatsApp messages work as source)
- Screenshot real dashboard data (anonymized) for mockups
- "X أكاديمية تثق بنا" counter (update monthly)
- Video testimonial from 1 happy customer (60s, Arabic, real)
---
## Technical UX Patterns
### Loading States
- Skeleton screens for dynamic content (not spinners)
- Route transitions: progress bar top of page
- Form submission: button text changes + spinner inside button
- Image loading: blur placeholder → sharp (next/image handles this)
### Error States
- Form validation: inline Arabic errors below each field, red border
- Network error: toast notification with retry button
- 404 page: branded, helpful, links to homepage
### Empty States
- N/A for marketing site (all content is static)
- Demo/trial state: redirect to app with welcome flow
### Performance Perception
- Critical CSS inlined (hero renders instantly)
- Fonts: display:swap (text visible immediately, font loads async)
- Above-fold images: priority loading
- Below-fold: intersection observer lazy loading
- Animations: only trigger when element enters viewport
# El Captain Marketing Site — Wireframes (ASCII)
## Homepage — Desktop (RTL)
```
┌─────────────────────────────────────────────────────────────────────────────┐
│ NAVBAR │
│ ───────────────────────────────────────────────────────────────────────────── │
│ [ابدأ مجاناً] تواصل الأسعار المميزات الرئيسية [🏴 الكابتن] │
│ ▼ │
│ [AR | EN] │
└─────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────┐
│ HERO (min-h: 90vh) │
│ │
│ ┌──────────────────────────┐ │
│ │ ┌────┐ ┌────┐ ┌────┐ │ كل شيء تحت إدارتك │
│ │ │ $$ │ │ 📊 │ │ 👥 │ │ ───────────────────── │
│ │ └────┘ └────┘ └────┘ │ │
│ │ ┌──────────────────┐ │ منصة إدارة رياضية متكاملة │
│ │ │ Revenue Chart │ │ تضع كل لاعب وكل جنيه وكل │
│ │ │ ╱─────╲ │ │ حصة تحت تحكمك الكامل │
│ │ │ ╱ ╲ │ │ │
│ │ │ ╱ ╲── │ │ [احجز عرض] [ابدأ تجربة مجانية] │
│ │ └──────────────────┘ │ │
│ │ Dashboard Mockup │ │
│ │ (floating + tilted) │ │
│ └──────────────────────────┘ │
│ │
│ ─────────────────────────────────────────────────────────────────────────── │
│ ٩٩.٩% وقت تشغيل │ ١٢,٠٠٠+ لاعب │ ٤٧+ أكاديمية │
└─────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────┐
│ PROBLEM → SOLUTION (scroll-driven) │
│ │
│ ┌─── Before ───┐ ┌─── After ────┐ │
│ │ 📋 Excel │ │ ┌──────────┐ │ │
│ │ 💬 WhatsApp │ ──[scroll]──▶ │ │ Dashboard│ │ │
│ │ 📝 Papers │ │ │ Clean │ │ │
│ │ 🤯 Chaos │ │ │ Data │ │ │
│ └──────────────┘ │ └──────────┘ │ │
│ └──────────────┘ │
│ │
│ "من غير نظام، أنت بتدير "مع الكابتن، كل شيء │
│ أكاديميتك في الضلمة" واضح ومنظم وتحت إيدك" │
└─────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────┐
│ MODULE SHOWCASE │
│ │
│ منصة متكاملة لكل جوانب عملك │
│ ─────────────────────────────── │
│ ١٤ وحدة متكاملة تغطي كل احتياجات أكاديميتك │
│ │
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │
│ │ [💰] │ │ [👥] │ │ [📅] │ │
│ │ │ │ │ │ │ │
│ │ إدارة مالية │ │ إدارة اللاعبين │ │ البرامج │ │
│ │ متكاملة │ │ │ │ التدريبية │ │
│ │ │ │ كل بيانات │ │ │ │
│ │ تتبع كل جنيه │ │ اللاعب في │ │ جدولة ذكية │ │
│ │ من الدفع حتى │ │ مكان واحد │ │ وتتبع تلقائي │ │
│ │ التقرير │ │ │ │ │ │
│ │ │ │ │ │ │ │
│ │ ← اكتشف │ │ ← اكتشف │ │ ← اكتشف │ │
│ └─────────────────┘ └─────────────────┘ └─────────────────┘ │
│ │
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │
│ │ [✓] │ │ [🛒] │ │ [🏟️] │ │
│ │ الحضور │ │ نقاط البيع │ │ المنشآت │ │
│ │ ... │ │ ... │ │ ... │ │
│ └─────────────────┘ └─────────────────┘ └─────────────────┘ │
│ │
│ [شوف كل المميزات ←] │
└─────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────┐
│ FEATURE DEEP-DIVE #1 │
│ │
│ ┌──────────────────────────┐ │
│ │ │ تحكم مالي كامل │
│ │ ┌─── Revenue ─────┐ │ ───────────────── │
│ │ │ ١٢٥,٠٠٠ ج.م │ │ │
│ │ │ ↑ ٢٣% │ │ تتبع كل جنيه من لحظة دفعه │
│ │ │ ╱──────────╲ │ │ حتى يظهر في تقريرك الشهري. │
│ │ │ ╱ ╲ │ │ قيد مزدوج تلقائي، فواتير │
│ │ └──────────────────┘ │ ذكية، وتنبيهات متأخرات. │
│ │ │ │
│ │ ┌── Due ──┐ ┌── Paid ──┐│ ✓ قيد مزدوج تلقائي │
│ │ │ ٣,٢٠٠ │ │ ١٢١,٨٠٠ ││ ✓ فواتير وأقساط │
│ │ └─────────┘ └──────────┘│ ✓ تقارير لحظية │
│ │ │ ✓ تنبيهات متأخرات │
│ └──────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────┐
│ FEATURE DEEP-DIVE #2 (reversed layout) │
│ │
│ تسجيل ذكي ┌──────────────────────────┐ │
│ ───────── │ ┌─── Enrollment ────────┐│ │
│ │ │ Step 1 ─ 2 ─ [3] ─ 4││ │
│ من أول ما يسجل │ │ ││ │
│ اللاعب لحد ما يبدأ │ │ اختيار المجموعة: ││ │
│ التدريب — كل شيء آلي. │ │ ○ مبتدئين صباحي ││ │
│ │ │ ● متوسط مسائي ││ │
│ ✓ ويزارد تسجيل سريع │ │ ○ متقدم ││ │
│ ✓ تسعير آلي │ │ ││ │
│ ✓ فاتورة فورية │ │ [التالي →] ││ │
│ ✓ إشعار للمدرب │ └────────────────────────┘│ │
│ └──────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────┐
│ TESTIMONIALS │
│ │
│ ماذا يقول عملاؤنا │
│ ────────────────── │
│ │
│ ┌──────────────────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ "المنصة غيرت طريقة إدارتنا للأكاديمية بالكامل. │ │
│ │ دلوقتي أعرف أرقامي الحقيقية في أي لحظة." │ │
│ │ │ │
│ │ ┌──┐ أحمد محمد — مدير أكاديمية النجوم، القاهرة │ │
│ │ └──┘ │ │
│ └──────────────────────────────────────────────────────────────────────┘ │
│ │
│ ● ○ ○ ○ │
└─────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────┐
│ STATS SECTION │
│ │
│ ٩٨% ٥٠,٠٠٠+ ١.٢ مليون+ │
│ رضا العملاء حصة مسجلة ج.م إيرادات مُدارة شهرياً │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────┐
│ CTA SECTION (navy-800 background) │
│ ██████████████████████████████████████████████████████████████████████████████│
│ ██ ██│
│ ██ جاهز تأخذ التحكم الكامل؟ ██│
│ ██ ────────────────────────── ██│
│ ██ ██│
│ ██ ابدأ بتجربة مجانية ١٤ يوم ██│
│ ██ بدون بطاقة ائتمان. بدون التزام. ██│
│ ██ ██│
│ ██ [تحدث مع فريقنا] [ابدأ مجاناً] ██│
│ ██ ██│
│ ██████████████████████████████████████████████████████████████████████████████│
└─────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────┐
│ FOOTER │
│ │
│ [AR | EN] تواصل معنا روابط سريعة الكابتن │
│ info@elcaptain.com الرئيسية منصة إدارة │
│ +20 xxx xxx xxxx المميزات الأكاديميات │
│ WhatsApp الأسعار الرياضية │
│ تواصل │
│ المدونة │
│ │
│ ─────────────────────────────────────────────────────────────────────────── │
│ © ٢٠٢٥ الكابتن. جميع الحقوق محفوظة. سياسة الخصوصية | الشروط │
└─────────────────────────────────────────────────────────────────────────────┘
```
---
## Homepage — Mobile (RTL)
```
┌───────────────────────────┐
│ NAVBAR │
│ [☰] [🏴 الكابتن] │
└───────────────────────────┘
┌───────────────────────────┐
│ HERO │
│ │
│ كل شيء تحت إدارتك │
│ ───────────────── │
│ منصة إدارة رياضية │
│ متكاملة تضع كل لاعب │
│ وكل جنيه تحت تحكمك │
│ │
│ [ابدأ تجربة مجانية] │
│ [احجز عرض تجريبي] │
│ │
│ ┌─────────────────────┐ │
│ │ Dashboard Mockup │ │
│ │ (no tilt on │ │
│ │ mobile) │ │
│ └─────────────────────┘ │
│ │
│ ٤٧+ أكاديمية │
│ ١٢,٠٠٠+ لاعب │
│ ٩٩.٩% وقت تشغيل │
└───────────────────────────┘
┌───────────────────────────┐
│ MODULES (2-col grid) │
│ │
│ ┌──────┐ ┌──────┐ │
│ │ 💰 │ │ 👥 │ │
│ │ مالية│ │لاعبين│ │
│ └──────┘ └──────┘ │
│ ┌──────┐ ┌──────┐ │
│ │ 📅 │ │ ✓ │ │
│ │تدريب │ │حضور │ │
│ └──────┘ └──────┘ │
│ ┌──────┐ ┌──────┐ │
│ │ 🛒 │ │ 🏟️ │ │
│ │ POS │ │منشآت │ │
│ └──────┘ └──────┘ │
└───────────────────────────┘
┌───────────────────────────┐
│ STICKY MOBILE CTA │
│ (appears on scroll down) │
│ │
│ [ ابدأ مجاناً ] │
└───────────────────────────┘
```
---
## Pricing Page — Desktop
```
┌─────────────────────────────────────────────────────────────────────────────┐
│ │
│ اختر الباقة المناسبة │
│ ──────────────────── │
│ │
│ [شهري] ───●─── [سنوي (وفر ٢٠%)] │
│ │
│ ┌───────────────┐ ┌─── ★ مُوصى به ───┐ ┌───────────────┐ │
│ │ أساسي │ │ احترافي │ │ مؤسسي │ │
│ │ │ │ │ │ │ │
│ │ ٤٩٩ │ │ ٩٩٩ │ │ تواصل │ │
│ │ ج.م/شهر │ │ ج.م/شهر │ │ معنا │ │
│ │ │ │ │ │ │ │
│ │ ✓ ٢٠٠ لاعب │ │ ✓ ١,٠٠٠ لاعب │ │ ✓ غير محدود │ │
│ │ ✓ فرع واحد │ │ ✓ ٥ فروع │ │ ✓ غير محدود │ │
│ │ ✓ ٥ مستخدم │ │ ✓ ١٥ مستخدم │ │ ✓ غير محدود │ │
│ │ ✓ مالية │ │ ✓ كل المميزات │ │ ✓ كل شيء │ │
│ │ ✓ حضور │ │ ✓ POS │ │ ✓ API │ │
│ │ ✗ POS │ │ ✓ مخزون │ │ ✓ دعم مخصص │ │
│ │ ✗ مخزون │ │ ✓ تقارير متقدمة │ │ ✓ تخصيص │ │
│ │ │ │ │ │ │ │
│ │ [ابدأ مجاناً]│ │ [ابدأ الآن] │ │ [تحدث معنا] │ │
│ └───────────────┘ └────────────────────┘ └───────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────┐
│ FAQ (Accordion) │
│ │
│ ▼ هل فيه فترة تجربة مجانية؟ │
│ نعم، ١٤ يوم تجربة كاملة بدون بطاقة ائتمان. │
│ │
│ ▶ هل أقدر أغير الباقة بعدين؟ │
│ ▶ إيه اللي بيحصل لبياناتي لو لغيت؟ │
│ ▶ هل فيه خصم للدفع السنوي؟ │
│ ▶ هل المنصة بتشتغل على الموبايل؟ │
│ ▶ هل بتدعموا أكثر من فرع؟ │
└─────────────────────────────────────────────────────────────────────────────┘
```
---
## Features Page — Module Detail (Expanded State)
```
┌─────────────────────────────────────────────────────────────────────────────┐
│ MODULE CARD (expanded) │
│ │
│ ┌──────────────────────────────────────────────────────────────────────┐ │
│ │ [💰] إدارة مالية متكاملة [▲] │ │
│ │ ─────────────────────────────────────────────────────────────────── │ │
│ │ │ │
│ │ ┌──────────────────────┐ ✓ قيد مزدوج تلقائي لكل عملية │ │
│ │ │ Screenshot of │ ✓ فواتير ذكية مع أقساط وتذكيرات │ │
│ │ │ Finance Module │ ✓ محافظ إلكترونية للاعبين │ │
│ │ │ │ ✓ تقارير لحظية (يومي/شهري/سنوي) │ │
│ │ │ │ ✓ ورديات كاشير وإغلاق يومي │ │
│ │ └──────────────────────┘ │ │
│ │ │ │
│ │ وحدات مرتبطة: نقاط البيع، المحافظ، التقارير │ │
│ └──────────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────────────────────────┐ │
│ │ [👥] إدارة اللاعبين [▼] │ │
│ └──────────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────────────────────────┐ │
│ │ [📅] البرامج التدريبية [▼] │ │
│ └──────────────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────────┘
```
---
## Contact / Demo Page
```
┌─────────────────────────────────────────────────────────────────────────────┐
│ │
│ احجز عرض تجريبي │
│ ─────────────── │
│ شوف المنصة بنفسك في ٣٠ دقيقة │
│ │
│ ┌─── Form ───────────────────┐ ┌─── Info ──────────────────┐ │
│ │ │ │ │ │
│ │ الاسم: [____________] │ │ 📞 اتصل بنا │ │
│ │ │ │ +20 xxx xxx xxxx │ │
│ │ اسم الأكاديمية: │ │ │ │
│ │ [____________________] │ │ 💬 واتساب │ │
│ │ │ │ wa.me/20xxxxxxxxx │ │
│ │ الموبايل: │ │ │ │
│ │ [____________________] │ │ 📧 ايميل │ │
│ │ │ │ info@elcaptain.com │ │
│ │ البريد الإلكتروني: │ │ │ │
│ │ [____________________] │ │ ───────────────── │ │
│ │ │ │ │ │
│ │ عدد اللاعبين: │ │ أو احجز موعد مباشرة: │ │
│ │ [▼ اختر _____________] │ │ ┌──────────────────┐ │ │
│ │ │ │ │ Calendar Embed │ │ │
│ │ رسالة (اختياري): │ │ │ (Cal.com) │ │ │
│ │ [____________________] │ │ └──────────────────┘ │ │
│ │ [____________________] │ │ │ │
│ │ │ │ │ │
│ │ [ إرسال الطلب ] │ │ │ │
│ │ │ │ │ │
│ └────────────────────────────┘ └────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────────┘
```
import { defineConfig, globalIgnores } from "eslint/config";
import nextVitals from "eslint-config-next/core-web-vitals";
import nextTs from "eslint-config-next/typescript";
const eslintConfig = defineConfig([
...nextVitals,
...nextTs,
// Override default ignores of eslint-config-next.
globalIgnores([
// Default ignores of eslint-config-next:
".next/**",
"out/**",
"build/**",
"next-env.d.ts",
]),
]);
export default eslintConfig;
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
/* config options here */
};
export default nextConfig;
This source diff could not be displayed because it is too large. You can view the blob instead.
{
"name": "marketing-site",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "eslint"
},
"dependencies": {
"@base-ui/react": "^1.6.0",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"framer-motion": "^12.42.2",
"lucide-react": "^1.23.0",
"next": "16.2.10",
"react": "19.2.4",
"react-dom": "19.2.4",
"shadcn": "^4.12.0",
"tailwind-merge": "^3.6.0",
"tw-animate-css": "^1.4.0"
},
"devDependencies": {
"@tailwindcss/postcss": "^4",
"@types/node": "^20",
"@types/react": "^19",
"@types/react-dom": "^19",
"eslint": "^9",
"eslint-config-next": "16.2.10",
"tailwindcss": "^4",
"typescript": "^5"
}
}
const config = {
plugins: {
"@tailwindcss/postcss": {},
},
};
export default config;
<svg fill="none" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="M14.5 13.5V5.41a1 1 0 0 0-.3-.7L9.8.29A1 1 0 0 0 9.08 0H1.5v13.5A2.5 2.5 0 0 0 4 16h8a2.5 2.5 0 0 0 2.5-2.5m-1.5 0v-7H8v-5H3v12a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1M9.5 5V2.12L12.38 5zM5.13 5h-.62v1.25h2.12V5zm-.62 3h7.12v1.25H4.5zm.62 3h-.62v1.25h7.12V11z" clip-rule="evenodd" fill="#666" fill-rule="evenodd"/></svg>
\ No newline at end of file
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><g clip-path="url(#a)"><path fill-rule="evenodd" clip-rule="evenodd" d="M10.27 14.1a6.5 6.5 0 0 0 3.67-3.45q-1.24.21-2.7.34-.31 1.83-.97 3.1M8 16A8 8 0 1 0 8 0a8 8 0 0 0 0 16m.48-1.52a7 7 0 0 1-.96 0H7.5a4 4 0 0 1-.84-1.32q-.38-.89-.63-2.08a40 40 0 0 0 3.92 0q-.25 1.2-.63 2.08a4 4 0 0 1-.84 1.31zm2.94-4.76q1.66-.15 2.95-.43a7 7 0 0 0 0-2.58q-1.3-.27-2.95-.43a18 18 0 0 1 0 3.44m-1.27-3.54a17 17 0 0 1 0 3.64 39 39 0 0 1-4.3 0 17 17 0 0 1 0-3.64 39 39 0 0 1 4.3 0m1.1-1.17q1.45.13 2.69.34a6.5 6.5 0 0 0-3.67-3.44q.65 1.26.98 3.1M8.48 1.5l.01.02q.41.37.84 1.31.38.89.63 2.08a40 40 0 0 0-3.92 0q.25-1.2.63-2.08a4 4 0 0 1 .85-1.32 7 7 0 0 1 .96 0m-2.75.4a6.5 6.5 0 0 0-3.67 3.44 29 29 0 0 1 2.7-.34q.31-1.83.97-3.1M4.58 6.28q-1.66.16-2.95.43a7 7 0 0 0 0 2.58q1.3.27 2.95.43a18 18 0 0 1 0-3.44m.17 4.71q-1.45-.12-2.69-.34a6.5 6.5 0 0 0 3.67 3.44q-.65-1.27-.98-3.1" fill="#666"/></g><defs><clipPath id="a"><path fill="#fff" d="M0 0h16v16H0z"/></clipPath></defs></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 394 80"><path fill="#000" d="M262 0h68.5v12.7h-27.2v66.6h-13.6V12.7H262V0ZM149 0v12.7H94v20.4h44.3v12.6H94v21h55v12.6H80.5V0h68.7zm34.3 0h-17.8l63.8 79.4h17.9l-32-39.7 32-39.6h-17.9l-23 28.6-23-28.6zm18.3 56.7-9-11-27.1 33.7h17.8l18.3-22.7z"/><path fill="#000" d="M81 79.3 17 0H0v79.3h13.6V17l50.2 62.3H81Zm252.6-.4c-1 0-1.8-.4-2.5-1s-1.1-1.6-1.1-2.6.3-1.8 1-2.5 1.6-1 2.6-1 1.8.3 2.5 1a3.4 3.4 0 0 1 .6 4.3 3.7 3.7 0 0 1-3 1.8zm23.2-33.5h6v23.3c0 2.1-.4 4-1.3 5.5a9.1 9.1 0 0 1-3.8 3.5c-1.6.8-3.5 1.3-5.7 1.3-2 0-3.7-.4-5.3-1s-2.8-1.8-3.7-3.2c-.9-1.3-1.4-3-1.4-5h6c.1.8.3 1.6.7 2.2s1 1.2 1.6 1.5c.7.4 1.5.5 2.4.5 1 0 1.8-.2 2.4-.6a4 4 0 0 0 1.6-1.8c.3-.8.5-1.8.5-3V45.5zm30.9 9.1a4.4 4.4 0 0 0-2-3.3 7.5 7.5 0 0 0-4.3-1.1c-1.3 0-2.4.2-3.3.5-.9.4-1.6 1-2 1.6a3.5 3.5 0 0 0-.3 4c.3.5.7.9 1.3 1.2l1.8 1 2 .5 3.2.8c1.3.3 2.5.7 3.7 1.2a13 13 0 0 1 3.2 1.8 8.1 8.1 0 0 1 3 6.5c0 2-.5 3.7-1.5 5.1a10 10 0 0 1-4.4 3.5c-1.8.8-4.1 1.2-6.8 1.2-2.6 0-4.9-.4-6.8-1.2-2-.8-3.4-2-4.5-3.5a10 10 0 0 1-1.7-5.6h6a5 5 0 0 0 3.5 4.6c1 .4 2.2.6 3.4.6 1.3 0 2.5-.2 3.5-.6 1-.4 1.8-1 2.4-1.7a4 4 0 0 0 .8-2.4c0-.9-.2-1.6-.7-2.2a11 11 0 0 0-2.1-1.4l-3.2-1-3.8-1c-2.8-.7-5-1.7-6.6-3.2a7.2 7.2 0 0 1-2.4-5.7 8 8 0 0 1 1.7-5 10 10 0 0 1 4.3-3.5c2-.8 4-1.2 6.4-1.2 2.3 0 4.4.4 6.2 1.2 1.8.8 3.2 2 4.3 3.4 1 1.4 1.5 3 1.5 5h-5.8z"/></svg>
\ No newline at end of file
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1155 1000"><path d="m577.3 0 577.4 1000H0z" fill="#fff"/></svg>
\ No newline at end of file
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill-rule="evenodd" clip-rule="evenodd" d="M1.5 2.5h13v10a1 1 0 0 1-1 1h-11a1 1 0 0 1-1-1zM0 1h16v11.5a2.5 2.5 0 0 1-2.5 2.5h-11A2.5 2.5 0 0 1 0 12.5zm3.75 4.5a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5M7 4.75a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0m1.75.75a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5" fill="#666"/></svg>
\ No newline at end of file
import type { Metadata } from "next";
export const metadata: Metadata = {
title: "عن الكابتن — منصة إدارة الأكاديميات الرياضية",
description:
"نبني مركز القيادة للمنظمات الرياضية — نمنح أصحاب الأكاديميات تحكماً تشغيلياً كاملاً ليركزوا على ما يهم: تطوير الرياضيين.",
};
export default function AboutLayout({
children,
}: {
children: React.ReactNode;
}) {
return children;
}
"use client";
import { Target, Eye, Sparkles, Shield, TrendingUp, Heart } from "lucide-react";
import Navbar from "@/components/layout/Navbar";
import Footer from "@/components/layout/Footer";
import Container from "@/components/shared/Container";
import AnimateOnScroll from "@/components/shared/AnimateOnScroll";
import { content } from "@/lib/content";
import { staggerContainer, staggerItem } from "@/lib/animations";
import { motion } from "framer-motion";
const about = content.ar.about;
const valueIcons = [Sparkles, Shield, Heart, TrendingUp];
export default function AboutPage() {
return (
<>
<Navbar />
<main className="min-h-screen">
{/* Hero */}
<section className="pt-24 pb-16 bg-gradient-to-b from-sky-50/50 to-white">
<Container className="text-center">
<AnimateOnScroll>
<h1 className="text-3xl sm:text-4xl lg:text-5xl font-bold text-navy-800">
{about.title}
</h1>
</AnimateOnScroll>
</Container>
</section>
{/* Mission */}
<section className="py-16">
<Container className="max-w-4xl">
<AnimateOnScroll>
<div className="flex flex-col items-center text-center">
<div className="flex items-center justify-center w-14 h-14 rounded-full bg-sky-100 mb-6">
<Target className="h-7 w-7 text-sky-600" />
</div>
<h2 className="text-2xl sm:text-3xl font-bold text-navy-800 mb-4">
{about.mission.title}
</h2>
<p className="text-lg sm:text-xl text-slate-600 leading-relaxed max-w-3xl">
{about.mission.text}
</p>
</div>
</AnimateOnScroll>
</Container>
</section>
{/* Vision */}
<section className="py-16 bg-slate-50">
<Container className="max-w-4xl">
<AnimateOnScroll>
<div className="flex flex-col items-center text-center">
<div className="flex items-center justify-center w-14 h-14 rounded-full bg-amber-100 mb-6">
<Eye className="h-7 w-7 text-amber-600" />
</div>
<h2 className="text-2xl sm:text-3xl font-bold text-navy-800 mb-4">
{about.vision.title}
</h2>
<p className="text-lg sm:text-xl text-slate-600 leading-relaxed max-w-3xl">
{about.vision.text}
</p>
</div>
</AnimateOnScroll>
</Container>
</section>
{/* Values */}
<section className="py-16">
<Container>
<AnimateOnScroll>
<h2 className="text-2xl sm:text-3xl font-bold text-navy-800 text-center mb-12">
قيمنا
</h2>
</AnimateOnScroll>
<motion.div
variants={staggerContainer}
initial="hidden"
whileInView="visible"
viewport={{ once: true, amount: 0.2 }}
className="grid grid-cols-1 sm:grid-cols-2 gap-6 lg:gap-8 max-w-4xl mx-auto"
>
{about.values.map((value, index) => {
const Icon = valueIcons[index];
return (
<motion.div
key={value.title}
variants={staggerItem}
className="rounded-xl border border-slate-200 bg-white p-6 lg:p-8 hover:shadow-md transition-shadow"
>
<div className="flex items-center justify-center w-11 h-11 rounded-lg bg-sky-50 mb-4">
<Icon className="h-5 w-5 text-sky-600" />
</div>
<h3 className="text-lg font-bold text-navy-800 mb-2">
{value.title}
</h3>
<p className="text-sm text-slate-600 leading-relaxed">
{value.description}
</p>
</motion.div>
);
})}
</motion.div>
</Container>
</section>
</main>
<Footer />
</>
);
}
import type { Metadata } from "next";
export const metadata: Metadata = {
title: "احجز عرض تجريبي — الكابتن | منصة إدارة الأكاديميات الرياضية",
description:
"شوف المنصة بنفسك في ٣٠ دقيقة. احجز عرض تجريبي مجاني وهنوريك كل المميزات.",
};
export default function ContactLayout({
children,
}: {
children: React.ReactNode;
}) {
return children;
}
"use client";
import { useState } from "react";
import { Phone, Mail, MessageCircle, CheckCircle } from "lucide-react";
import Navbar from "@/components/layout/Navbar";
import Footer from "@/components/layout/Footer";
import Container from "@/components/shared/Container";
import AnimateOnScroll from "@/components/shared/AnimateOnScroll";
import { Button } from "@/components/ui/button";
import { content } from "@/lib/content";
const contactContent = content.ar.contact;
export default function ContactPage() {
const [formData, setFormData] = useState({
name: "",
academy: "",
phone: "",
email: "",
players: "",
message: "",
});
const [submitted, setSubmitted] = useState(false);
const [submitting, setSubmitting] = useState(false);
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
setSubmitting(true);
// Simulate submission (replace with actual endpoint later)
await new Promise((resolve) => setTimeout(resolve, 1000));
setSubmitted(true);
setSubmitting(false);
};
const handleChange = (
e: React.ChangeEvent<
HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement
>
) => {
setFormData((prev) => ({ ...prev, [e.target.name]: e.target.value }));
};
return (
<>
<Navbar />
<main className="min-h-screen">
{/* Hero */}
<section className="pt-24 pb-12 bg-gradient-to-b from-sky-50/50 to-white">
<Container className="text-center">
<AnimateOnScroll>
<h1 className="text-3xl sm:text-4xl lg:text-5xl font-bold text-navy-800">
{contactContent.title}
</h1>
<p className="mt-4 text-lg text-slate-600 max-w-2xl mx-auto">
{contactContent.subtitle}
</p>
</AnimateOnScroll>
</Container>
</section>
{/* Split Layout */}
<section className="py-16">
<Container>
<div className="grid grid-cols-1 lg:grid-cols-5 gap-12 lg:gap-16">
{/* Form (Right side in RTL) */}
<AnimateOnScroll className="lg:col-span-3">
<form
onSubmit={handleSubmit}
className="space-y-5 rounded-2xl border border-slate-200 bg-white p-6 lg:p-8 shadow-sm"
>
{/* Name */}
<div>
<label
htmlFor="name"
className="block text-sm font-medium text-navy-800 mb-1.5"
>
{contactContent.form.name}
</label>
<input
type="text"
id="name"
name="name"
value={formData.name}
onChange={handleChange}
required
className="w-full rounded-lg border border-slate-200 px-4 py-2.5 text-sm text-navy-800 placeholder:text-slate-400 focus:border-sky-500 focus:ring-2 focus:ring-sky-500/20 outline-none transition-all"
/>
</div>
{/* Academy */}
<div>
<label
htmlFor="academy"
className="block text-sm font-medium text-navy-800 mb-1.5"
>
{contactContent.form.academy}
</label>
<input
type="text"
id="academy"
name="academy"
value={formData.academy}
onChange={handleChange}
required
className="w-full rounded-lg border border-slate-200 px-4 py-2.5 text-sm text-navy-800 placeholder:text-slate-400 focus:border-sky-500 focus:ring-2 focus:ring-sky-500/20 outline-none transition-all"
/>
</div>
{/* Phone & Email row */}
<div className="grid grid-cols-1 sm:grid-cols-2 gap-5">
<div>
<label
htmlFor="phone"
className="block text-sm font-medium text-navy-800 mb-1.5"
>
{contactContent.form.phone}
</label>
<input
type="tel"
id="phone"
name="phone"
value={formData.phone}
onChange={handleChange}
required
dir="ltr"
className="w-full rounded-lg border border-slate-200 px-4 py-2.5 text-sm text-navy-800 placeholder:text-slate-400 focus:border-sky-500 focus:ring-2 focus:ring-sky-500/20 outline-none transition-all"
/>
</div>
<div>
<label
htmlFor="email"
className="block text-sm font-medium text-navy-800 mb-1.5"
>
{contactContent.form.email}
</label>
<input
type="email"
id="email"
name="email"
value={formData.email}
onChange={handleChange}
required
dir="ltr"
className="w-full rounded-lg border border-slate-200 px-4 py-2.5 text-sm text-navy-800 placeholder:text-slate-400 focus:border-sky-500 focus:ring-2 focus:ring-sky-500/20 outline-none transition-all"
/>
</div>
</div>
{/* Player Count */}
<div>
<label
htmlFor="players"
className="block text-sm font-medium text-navy-800 mb-1.5"
>
{contactContent.form.players}
</label>
<select
id="players"
name="players"
value={formData.players}
onChange={handleChange}
required
className="w-full rounded-lg border border-slate-200 px-4 py-2.5 text-sm text-navy-800 focus:border-sky-500 focus:ring-2 focus:ring-sky-500/20 outline-none transition-all bg-white"
>
<option value="" disabled>
اختر...
</option>
{contactContent.form.playersOptions.map((option) => (
<option key={option} value={option}>
{option}
</option>
))}
</select>
</div>
{/* Message */}
<div>
<label
htmlFor="message"
className="block text-sm font-medium text-navy-800 mb-1.5"
>
{contactContent.form.message}
</label>
<textarea
id="message"
name="message"
value={formData.message}
onChange={handleChange}
rows={4}
className="w-full rounded-lg border border-slate-200 px-4 py-2.5 text-sm text-navy-800 placeholder:text-slate-400 focus:border-sky-500 focus:ring-2 focus:ring-sky-500/20 outline-none transition-all resize-none"
/>
</div>
{/* Submit */}
<Button
disabled={submitting}
className="w-full h-11 bg-sky-500 text-white font-semibold hover:bg-sky-600 text-sm disabled:opacity-60"
>
{submitting ? "جارٍ الإرسال..." : contactContent.form.submit}
</Button>
{submitted && (
<div className="flex items-center gap-3 rounded-lg bg-emerald-50 border border-emerald-200 p-4">
<CheckCircle className="h-5 w-5 text-emerald-600 shrink-0" />
<p className="text-sm text-emerald-800">
تم إرسال طلبك بنجاح! سنتواصل معك خلال ٢٤ ساعة.
</p>
</div>
)}
</form>
</AnimateOnScroll>
{/* Contact Info (Left side in RTL) */}
<AnimateOnScroll delay={0.2} className="lg:col-span-2">
<div className="space-y-8 lg:pt-8">
<div>
<h2 className="text-xl font-bold text-navy-800 mb-6">
أو تواصل معنا مباشرة
</h2>
</div>
{/* Phone */}
<div className="flex items-start gap-4">
<div className="flex items-center justify-center w-11 h-11 rounded-lg bg-sky-50 shrink-0">
<Phone className="h-5 w-5 text-sky-600" />
</div>
<div>
<p className="text-sm font-medium text-navy-800 mb-1">
اتصل بنا
</p>
<a
href={`tel:${contactContent.info.phone.replace(/\s/g, "")}`}
dir="ltr"
className="text-sm text-slate-600 hover:text-sky-600 transition-colors"
>
{contactContent.info.phone}
</a>
</div>
</div>
{/* WhatsApp */}
<div className="flex items-start gap-4">
<div className="flex items-center justify-center w-11 h-11 rounded-lg bg-emerald-50 shrink-0">
<MessageCircle className="h-5 w-5 text-emerald-600" />
</div>
<div>
<p className="text-sm font-medium text-navy-800 mb-1">
واتساب
</p>
<a
href={`https://wa.me/${contactContent.info.phone.replace(/[\s+]/g, "")}`}
target="_blank"
rel="noopener noreferrer"
className="text-sm text-slate-600 hover:text-emerald-600 transition-colors"
>
{contactContent.info.whatsapp}
</a>
</div>
</div>
{/* Email */}
<div className="flex items-start gap-4">
<div className="flex items-center justify-center w-11 h-11 rounded-lg bg-amber-50 shrink-0">
<Mail className="h-5 w-5 text-amber-600" />
</div>
<div>
<p className="text-sm font-medium text-navy-800 mb-1">
البريد الإلكتروني
</p>
<a
href={`mailto:${contactContent.info.email}`}
dir="ltr"
className="text-sm text-slate-600 hover:text-amber-600 transition-colors"
>
{contactContent.info.email}
</a>
</div>
</div>
{/* Extra CTA */}
<div className="rounded-xl bg-slate-50 border border-slate-200 p-5 mt-8">
<p className="text-sm text-slate-600 leading-relaxed">
العرض التجريبي يستغرق ٣٠ دقيقة فقط. هنوريك كل المميزات
وهنجاوب على كل أسئلتك.
</p>
</div>
</div>
</AnimateOnScroll>
</div>
</Container>
</section>
</main>
<Footer />
</>
);
}
import type { Metadata } from "next";
export const metadata: Metadata = {
title: "المميزات — الكابتن | ١٤ وحدة متكاملة لإدارة أكاديميتك",
description:
"كل ما تحتاجه في منصة واحدة — ١٤ وحدة تغطي المالية واللاعبين والحضور والمخزون والتسعير وأكثر.",
};
export default function FeaturesLayout({
children,
}: {
children: React.ReactNode;
}) {
return children;
}
"use client";
import Link from "next/link";
import {
Wallet,
Users,
Calendar,
CheckCircle,
ShoppingCart,
Building,
Package,
MapPin,
Clock,
BarChart3,
Bell,
Shield,
CreditCard,
Zap,
} from "lucide-react";
import { motion } from "framer-motion";
import Navbar from "@/components/layout/Navbar";
import Footer from "@/components/layout/Footer";
import Container from "@/components/shared/Container";
import AnimateOnScroll from "@/components/shared/AnimateOnScroll";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { staggerContainer, staggerItem } from "@/lib/animations";
import { content } from "@/lib/content";
const modules = [
{
icon: Wallet,
title: "الإدارة المالية",
description: "قيد مزدوج، فواتير، أقساط، وتقارير مالية شاملة",
},
{
icon: Users,
title: "إدارة اللاعبين",
description: "ملفات شاملة لكل لاعب مع تاريخ كامل",
},
{
icon: Calendar,
title: "البرامج التدريبية",
description: "إنشاء وإدارة برامج تدريبية بمستويات متعددة",
},
{
icon: Users,
title: "المجموعات",
description: "تنظيم اللاعبين في مجموعات مع جدولة تلقائية",
},
{
icon: CheckCircle,
title: "الحضور والغياب",
description: "تسجيل آلي مع تنبيهات وتقارير فورية",
},
{
icon: ShoppingCart,
title: "نقاط البيع",
description: "بيع وتحصيل وإدارة مخزون في شاشة واحدة",
},
{
icon: Package,
title: "المخزون",
description: "تتبع المنتجات والمشتريات وحركة المخزون",
},
{
icon: Building,
title: "إدارة المنشآت",
description: "حجز وجدولة وتخصيص الملاعب والقاعات",
},
{
icon: Clock,
title: "الجدولة",
description: "جدولة ذكية للحصص مع كشف التعارضات",
},
{
icon: BarChart3,
title: "التقارير",
description: "تقارير تفصيلية وإحصائيات لحظية لكل الأقسام",
},
{
icon: Bell,
title: "الإشعارات",
description: "تنبيهات ذكية عبر التطبيق والإيميل والرسائل",
},
{
icon: Shield,
title: "الأدوار والصلاحيات",
description: "تحكم كامل في صلاحيات كل مستخدم",
},
{
icon: CreditCard,
title: "المحافظ الإلكترونية",
description: "محفظة لكل لاعب مع تتبع الرصيد والحركات",
},
{
icon: Zap,
title: "التسعير الذكي",
description: "قواعد تسعير مرنة وخصومات تلقائية حسب الشروط",
},
];
export default function FeaturesPage() {
return (
<>
<Navbar />
<main className="min-h-screen">
{/* Hero */}
<section className="pt-24 pb-16 bg-gradient-to-b from-sky-50/50 to-white">
<Container className="text-center">
<AnimateOnScroll>
<Badge className="bg-sky-100 text-sky-700 px-3 py-1 text-xs mb-4">
١٤ وحدة
</Badge>
<h1 className="text-3xl sm:text-4xl lg:text-5xl font-bold text-navy-800">
كل ما تحتاجه في منصة واحدة
</h1>
<p className="mt-4 text-lg text-slate-600 max-w-2xl mx-auto">
{content.ar.modules.sectionSubtitle}
</p>
</AnimateOnScroll>
</Container>
</section>
{/* Modules Grid */}
<section className="py-16">
<Container>
<motion.div
variants={staggerContainer}
initial="hidden"
whileInView="visible"
viewport={{ once: true, amount: 0.1 }}
className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-5 lg:gap-6"
>
{modules.map((module) => {
const Icon = module.icon;
return (
<motion.div
key={module.title}
variants={staggerItem}
className="group rounded-xl border border-slate-200 bg-white p-5 lg:p-6 hover:shadow-md hover:border-sky-200 transition-all"
>
<div className="flex items-center justify-center w-10 h-10 rounded-lg bg-sky-50 group-hover:bg-sky-100 transition-colors mb-4">
<Icon className="h-5 w-5 text-sky-600" />
</div>
<h3 className="text-base font-bold text-navy-800 mb-1.5">
{module.title}
</h3>
<p className="text-sm text-slate-600 leading-relaxed">
{module.description}
</p>
</motion.div>
);
})}
</motion.div>
</Container>
</section>
{/* CTA Section */}
<section className="py-16 bg-navy-800">
<Container className="text-center">
<AnimateOnScroll>
<h2 className="text-2xl sm:text-3xl font-bold text-white mb-4">
{content.ar.cta.headline}
</h2>
<p className="text-slate-300 mb-8 max-w-xl mx-auto">
{content.ar.cta.subheadline}
</p>
<div className="flex flex-col sm:flex-row items-center justify-center gap-4">
<Link
href="/contact"
className="inline-flex items-center justify-center rounded-lg bg-sky-500 px-6 py-3 text-sm font-semibold text-white shadow-sm transition-all hover:bg-sky-600 hover:shadow-md active:scale-[0.98]"
>
{content.ar.cta.ctaPrimary}
</Link>
<Link
href="/pricing"
className="inline-flex items-center justify-center rounded-lg border border-white/20 bg-white/10 px-6 py-3 text-sm font-semibold text-white backdrop-blur-sm transition-all hover:bg-white/20"
>
{content.ar.cta.ctaSecondary}
</Link>
</div>
</AnimateOnScroll>
</Container>
</section>
</main>
<Footer />
</>
);
}
@import "tailwindcss";
@import "tw-animate-css";
@import "shadcn/tailwind.css";
@custom-variant dark (&:is(.dark *));
@theme inline {
--color-background: var(--background);
--color-foreground: var(--foreground);
--font-sans: var(--font-cairo), var(--font-inter), system-ui, sans-serif;
--font-mono: var(--font-geist-mono);
--font-heading: var(--font-cairo), var(--font-inter), system-ui, sans-serif;
--font-cairo: var(--font-cairo);
--font-inter: var(--font-inter);
--color-sidebar-ring: var(--sidebar-ring);
--color-sidebar-border: var(--sidebar-border);
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
--color-sidebar-accent: var(--sidebar-accent);
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
--color-sidebar-primary: var(--sidebar-primary);
--color-sidebar-foreground: var(--sidebar-foreground);
--color-sidebar: var(--sidebar);
--color-chart-5: var(--chart-5);
--color-chart-4: var(--chart-4);
--color-chart-3: var(--chart-3);
--color-chart-2: var(--chart-2);
--color-chart-1: var(--chart-1);
--color-ring: var(--ring);
--color-input: var(--input);
--color-border: var(--border);
--color-destructive: var(--destructive);
--color-accent-foreground: var(--accent-foreground);
--color-accent: var(--accent);
--color-muted-foreground: var(--muted-foreground);
--color-muted: var(--muted);
--color-secondary-foreground: var(--secondary-foreground);
--color-secondary: var(--secondary);
--color-primary-foreground: var(--primary-foreground);
--color-primary: var(--primary);
--color-popover-foreground: var(--popover-foreground);
--color-popover: var(--popover);
--color-card-foreground: var(--card-foreground);
--color-card: var(--card);
--radius-sm: calc(var(--radius) * 0.6);
--radius-md: calc(var(--radius) * 0.8);
--radius-lg: var(--radius);
--radius-xl: calc(var(--radius) * 1.4);
--radius-2xl: calc(var(--radius) * 1.8);
--radius-3xl: calc(var(--radius) * 2.2);
--radius-4xl: calc(var(--radius) * 2.6);
/* Brand Colors */
--color-navy-50: #f0f4f8;
--color-navy-100: #d9e2ec;
--color-navy-200: #bcccdc;
--color-navy-300: #9fb3c8;
--color-navy-400: #6b8aad;
--color-navy-500: #3d6b99;
--color-navy-600: #2d5280;
--color-navy-700: #264a70;
--color-navy-800: #1e3a5f;
--color-navy-900: #162b45;
--color-navy-950: #0f1d2f;
--color-sky-50: #f0f9ff;
--color-sky-100: #e0f2fe;
--color-sky-200: #bae6fd;
--color-sky-300: #7dd3fc;
--color-sky-400: #38bdf8;
--color-sky-500: #0ea5e9;
--color-sky-600: #0284c7;
--color-sky-700: #0369a1;
--color-sky-800: #075985;
--color-sky-900: #0c4a6e;
--color-emerald-50: #ecfdf5;
--color-emerald-100: #d1fae5;
--color-emerald-200: #a7f3d0;
--color-emerald-300: #6ee7b7;
--color-emerald-400: #34d399;
--color-emerald-500: #10b981;
--color-emerald-600: #059669;
--color-emerald-700: #047857;
--color-emerald-800: #065f46;
--color-emerald-900: #064e3b;
--color-amber-50: #fffbeb;
--color-amber-100: #fef3c7;
--color-amber-200: #fde68a;
--color-amber-300: #fcd34d;
--color-amber-400: #fbbf24;
--color-amber-500: #f59e0b;
--color-amber-600: #d97706;
--color-amber-700: #b45309;
--color-amber-800: #92400e;
--color-amber-900: #78350f;
}
:root {
--background: oklch(1 0 0);
--foreground: oklch(0.145 0 0);
--card: oklch(1 0 0);
--card-foreground: oklch(0.145 0 0);
--popover: oklch(1 0 0);
--popover-foreground: oklch(0.145 0 0);
--primary: oklch(0.205 0 0);
--primary-foreground: oklch(0.985 0 0);
--secondary: oklch(0.97 0 0);
--secondary-foreground: oklch(0.205 0 0);
--muted: oklch(0.97 0 0);
--muted-foreground: oklch(0.556 0 0);
--accent: oklch(0.97 0 0);
--accent-foreground: oklch(0.205 0 0);
--destructive: oklch(0.577 0.245 27.325);
--border: oklch(0.922 0 0);
--input: oklch(0.922 0 0);
--ring: oklch(0.708 0 0);
--chart-1: oklch(0.87 0 0);
--chart-2: oklch(0.556 0 0);
--chart-3: oklch(0.439 0 0);
--chart-4: oklch(0.371 0 0);
--chart-5: oklch(0.269 0 0);
--radius: 0.625rem;
--sidebar: oklch(0.985 0 0);
--sidebar-foreground: oklch(0.145 0 0);
--sidebar-primary: oklch(0.205 0 0);
--sidebar-primary-foreground: oklch(0.985 0 0);
--sidebar-accent: oklch(0.97 0 0);
--sidebar-accent-foreground: oklch(0.205 0 0);
--sidebar-border: oklch(0.922 0 0);
--sidebar-ring: oklch(0.708 0 0);
}
.dark {
--background: oklch(0.145 0 0);
--foreground: oklch(0.985 0 0);
--card: oklch(0.205 0 0);
--card-foreground: oklch(0.985 0 0);
--popover: oklch(0.205 0 0);
--popover-foreground: oklch(0.985 0 0);
--primary: oklch(0.922 0 0);
--primary-foreground: oklch(0.205 0 0);
--secondary: oklch(0.269 0 0);
--secondary-foreground: oklch(0.985 0 0);
--muted: oklch(0.269 0 0);
--muted-foreground: oklch(0.708 0 0);
--accent: oklch(0.269 0 0);
--accent-foreground: oklch(0.985 0 0);
--destructive: oklch(0.704 0.191 22.216);
--border: oklch(1 0 0 / 10%);
--input: oklch(1 0 0 / 15%);
--ring: oklch(0.556 0 0);
--chart-1: oklch(0.87 0 0);
--chart-2: oklch(0.556 0 0);
--chart-3: oklch(0.439 0 0);
--chart-4: oklch(0.371 0 0);
--chart-5: oklch(0.269 0 0);
--sidebar: oklch(0.205 0 0);
--sidebar-foreground: oklch(0.985 0 0);
--sidebar-primary: oklch(0.488 0.243 264.376);
--sidebar-primary-foreground: oklch(0.985 0 0);
--sidebar-accent: oklch(0.269 0 0);
--sidebar-accent-foreground: oklch(0.985 0 0);
--sidebar-border: oklch(1 0 0 / 10%);
--sidebar-ring: oklch(0.556 0 0);
}
@layer base {
* {
@apply border-border outline-ring/50;
}
body {
@apply bg-background text-foreground;
}
html {
@apply font-sans scroll-smooth;
}
::selection {
background-color: #0ea5e9;
color: white;
}
}
import type { Metadata } from "next";
import { cairo, inter } from "@/lib/fonts";
import WhatsAppButton from "@/components/shared/WhatsAppButton";
import "./globals.css";
export const metadata: Metadata = {
title: {
default: "الكابتن — منصة إدارة الأكاديميات الرياضية",
template: "%s | الكابتن",
},
description:
"منصة إدارة رياضية متكاملة تضع كل لاعب وكل جنيه وكل حصة تحت تحكمك الكامل. مصممة خصيصاً للأكاديميات الرياضية في مصر والعالم العربي.",
keywords: [
"إدارة أكاديمية رياضية",
"برنامج إدارة نادي رياضي",
"نظام حضور لاعبين",
"برنامج محاسبة أكاديمية",
"تسجيل لاعبين أونلاين",
],
openGraph: {
type: "website",
locale: "ar_EG",
siteName: "الكابتن",
title: "الكابتن — منصة إدارة الأكاديميات الرياضية",
description:
"منصة متكاملة لإدارة الأكاديميات الرياضية: تسجيل اللاعبين، الحضور، المالية، نقاط البيع.",
},
twitter: {
card: "summary_large_image",
title: "الكابتن — منصة إدارة الأكاديميات الرياضية",
description:
"منصة متكاملة لإدارة الأكاديميات الرياضية: تسجيل اللاعبين، الحضور، المالية، نقاط البيع.",
},
};
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html
lang="ar"
dir="rtl"
className={`${cairo.variable} ${inter.variable} antialiased`}
>
<body className="min-h-screen bg-background">
{children}
<WhatsAppButton />
</body>
</html>
);
}
import Link from "next/link";
export default function NotFound() {
return (
<div className="min-h-screen flex items-center justify-center bg-gradient-to-b from-sky-50/50 to-white">
<div className="text-center px-4">
<p className="text-8xl font-bold text-sky-500 mb-4">404</p>
<h1 className="text-2xl font-bold text-navy-800 mb-2">
الصفحة غير موجودة
</h1>
<p className="text-slate-500 mb-8">
الصفحة التي تبحث عنها غير موجودة أو تم نقلها.
</p>
<Link
href="/"
className="inline-flex items-center justify-center rounded-lg bg-sky-500 px-6 py-3 text-sm font-semibold text-white shadow-sm transition-all hover:bg-sky-600"
>
العودة للرئيسية
</Link>
</div>
</div>
);
}
import Navbar from "@/components/layout/Navbar";
import Footer from "@/components/layout/Footer";
import Hero from "@/components/sections/Hero";
import ProblemSolution from "@/components/sections/ProblemSolution";
import ModuleShowcase from "@/components/sections/ModuleShowcase";
import FeatureDeepDive from "@/components/sections/FeatureDeepDive";
import Testimonials from "@/components/sections/Testimonials";
import StatsSection from "@/components/sections/StatsSection";
import CTASection from "@/components/sections/CTASection";
export default function Home() {
return (
<>
<Navbar />
<main>
<Hero />
<ProblemSolution />
<ModuleShowcase />
<FeatureDeepDive />
<Testimonials />
<StatsSection />
<CTASection />
</main>
<Footer />
</>
);
}
import type { Metadata } from "next";
export const metadata: Metadata = {
title: "الأسعار — الكابتن | منصة إدارة الأكاديميات الرياضية",
description:
"اختر الباقة المناسبة لأكاديميتك. ١٤ يوم تجربة مجانية على كل الباقات بدون بطاقة ائتمان.",
};
export default function PricingLayout({
children,
}: {
children: React.ReactNode;
}) {
return children;
}
"use client";
import { useState } from "react";
import { Check, X } from "lucide-react";
import { motion } from "framer-motion";
import Navbar from "@/components/layout/Navbar";
import Footer from "@/components/layout/Footer";
import Container from "@/components/shared/Container";
import AnimateOnScroll from "@/components/shared/AnimateOnScroll";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import {
Accordion,
AccordionItem,
AccordionTrigger,
AccordionContent,
} from "@/components/ui/accordion";
import { content } from "@/lib/content";
import { fadeUp, staggerContainer, staggerItem } from "@/lib/animations";
const pricing = content.ar.pricing;
export default function PricingPage() {
const [billingCycle, setBillingCycle] = useState<"monthly" | "yearly">(
"monthly"
);
return (
<>
<Navbar />
<main className="min-h-screen">
{/* Hero */}
<section className="pt-24 pb-12 bg-gradient-to-b from-sky-50/50 to-white">
<Container className="text-center">
<AnimateOnScroll>
<h1 className="text-3xl sm:text-4xl lg:text-5xl font-bold text-navy-800">
{pricing.title}
</h1>
<p className="mt-4 text-lg text-slate-600 max-w-2xl mx-auto">
{pricing.subtitle}
</p>
</AnimateOnScroll>
{/* Billing Toggle */}
<AnimateOnScroll delay={0.2}>
<div className="mt-8 inline-flex items-center gap-1 rounded-lg bg-slate-100 p-1">
<button
onClick={() => setBillingCycle("monthly")}
className={`rounded-md px-5 py-2 text-sm font-medium transition-all ${
billingCycle === "monthly"
? "bg-white text-navy-800 shadow-sm"
: "text-slate-600 hover:text-slate-900"
}`}
>
{pricing.monthly}
</button>
<button
onClick={() => setBillingCycle("yearly")}
className={`rounded-md px-5 py-2 text-sm font-medium transition-all flex items-center gap-2 ${
billingCycle === "yearly"
? "bg-white text-navy-800 shadow-sm"
: "text-slate-600 hover:text-slate-900"
}`}
>
{pricing.yearly}
<Badge className="bg-emerald-100 text-emerald-700 text-[10px]">
{pricing.yearlyDiscount}
</Badge>
</button>
</div>
</AnimateOnScroll>
</Container>
</section>
{/* Pricing Cards */}
<section className="py-16">
<Container>
<motion.div
variants={staggerContainer}
initial="hidden"
whileInView="visible"
viewport={{ once: true, amount: 0.2 }}
className="grid grid-cols-1 md:grid-cols-3 gap-6 lg:gap-8 items-stretch"
>
{pricing.plans.map((plan, index) => (
<motion.div
key={plan.name}
variants={staggerItem}
className={`relative flex flex-col rounded-2xl border bg-white p-6 lg:p-8 shadow-sm transition-shadow hover:shadow-md ${
plan.highlighted
? "border-2 border-sky-500 shadow-sky-100"
: "border-slate-200"
}`}
>
{/* Badge for highlighted plan */}
{"badge" in plan && plan.badge && (
<div className="absolute -top-3 start-1/2 -translate-x-1/2 rtl:translate-x-1/2">
<Badge className="bg-sky-500 text-white px-3 py-1 text-xs">
{plan.badge}
</Badge>
</div>
)}
{/* Plan Header */}
<div className="text-center mb-6">
<h3 className="text-xl font-bold text-navy-800">
{plan.name}
</h3>
<p className="mt-1 text-sm text-slate-500">
{plan.description}
</p>
</div>
{/* Price */}
<div className="text-center mb-2">
<span className="text-4xl lg:text-5xl font-bold text-navy-800" dir="ltr">
{plan.price}
</span>
{plan.period && (
<span className="text-sm text-slate-500 ms-1">
{plan.period}
</span>
)}
</div>
{/* Platform Fee */}
{"platformFee" in plan && plan.platformFee && (
<div className="text-center mb-6">
<span className="inline-flex items-center gap-1.5 rounded-full bg-sky-50 px-3 py-1 text-xs font-medium text-sky-700">
{pricing.platformFeeLabel}: {plan.platformFee}
</span>
</div>
)}
{/* Features */}
<ul className="flex-1 space-y-3 mb-8">
{plan.features.map((feature) => (
<li
key={feature.text}
className="flex items-center gap-3"
>
{feature.included ? (
<Check className="h-4 w-4 text-emerald-500 shrink-0" />
) : (
<X className="h-4 w-4 text-slate-300 shrink-0" />
)}
<span
className={`text-sm ${
feature.included
? "text-slate-700"
: "text-slate-400"
}`}
>
{feature.text}
</span>
</li>
))}
</ul>
{/* CTA */}
<Button
className={`w-full py-3 h-11 text-sm font-semibold ${
plan.highlighted
? "bg-sky-500 text-white hover:bg-sky-600"
: "bg-slate-100 text-navy-800 hover:bg-slate-200"
}`}
>
{plan.cta}
</Button>
</motion.div>
))}
</motion.div>
</Container>
</section>
{/* FAQ */}
<section className="py-16 bg-slate-50">
<Container className="max-w-3xl">
<AnimateOnScroll>
<h2 className="text-2xl sm:text-3xl font-bold text-navy-800 text-center mb-10">
الأسئلة الشائعة
</h2>
</AnimateOnScroll>
<AnimateOnScroll delay={0.1}>
<Accordion className="space-y-2">
{pricing.faq.map((item, index) => (
<AccordionItem
key={index}
className="rounded-lg border border-slate-200 bg-white px-4"
>
<AccordionTrigger className="py-4 text-base font-medium text-navy-800 hover:no-underline">
{item.q}
</AccordionTrigger>
<AccordionContent className="text-slate-600 leading-relaxed">
{item.a}
</AccordionContent>
</AccordionItem>
))}
</Accordion>
</AnimateOnScroll>
</Container>
</section>
</main>
<Footer />
</>
);
}
import Link from "next/link";
import { content } from "@/lib/content";
const quickLinks = [
{ label: content.ar.nav.home, href: "/" },
{ label: content.ar.nav.features, href: "/features" },
{ label: content.ar.nav.pricing, href: "/pricing" },
{ label: content.ar.nav.about, href: "/about" },
{ label: content.ar.nav.contact, href: "/contact" },
];
export default function Footer() {
return (
<footer className="bg-navy-800 text-white">
<div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8 py-12 lg:py-16">
<div className="grid grid-cols-1 md:grid-cols-3 gap-10 lg:gap-16">
{/* Brand Info */}
<div className="space-y-4">
<Link href="/" className="inline-flex items-center gap-2 text-xl font-bold">
<span className="text-sky-400">&#9670;</span>
الكابتن
</Link>
<p className="text-slate-300 text-sm leading-relaxed max-w-xs">
{content.ar.footer.description}
</p>
</div>
{/* Quick Links */}
<div className="space-y-4">
<h3 className="text-base font-semibold">{content.ar.footer.quickLinks}</h3>
<ul className="space-y-2.5">
{quickLinks.map((link) => (
<li key={link.href}>
<Link
href={link.href}
className="text-sm text-slate-300 transition-colors hover:text-white"
>
{link.label}
</Link>
</li>
))}
</ul>
</div>
{/* Contact Info */}
<div className="space-y-4">
<h3 className="text-base font-semibold">{content.ar.footer.contactUs}</h3>
<ul className="space-y-2.5 text-sm text-slate-300">
<li>
<a
href={`tel:${content.ar.contact.info.phone.replace(/\s/g, "")}`}
className="transition-colors hover:text-white"
dir="ltr"
>
{content.ar.contact.info.phone}
</a>
</li>
<li>
<a
href={`mailto:${content.ar.contact.info.email}`}
className="transition-colors hover:text-white"
dir="ltr"
>
{content.ar.contact.info.email}
</a>
</li>
<li>
<a
href={`https://wa.me/${content.ar.contact.info.phone.replace(/[\s+]/g, "")}`}
className="transition-colors hover:text-white"
target="_blank"
rel="noopener noreferrer"
>
{content.ar.contact.info.whatsapp}
</a>
</li>
</ul>
</div>
</div>
</div>
{/* Bottom Bar */}
<div className="border-t border-white/10">
<div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8 py-5">
<div className="flex flex-col sm:flex-row items-center justify-between gap-3 text-sm text-slate-400">
<p>
&copy; {new Date().getFullYear()} الكابتن. {content.ar.footer.rights}
</p>
<div className="flex items-center gap-4">
<Link href="/privacy" className="transition-colors hover:text-white">
{content.ar.footer.privacy}
</Link>
<Link href="/terms" className="transition-colors hover:text-white">
{content.ar.footer.terms}
</Link>
</div>
</div>
</div>
</div>
</footer>
);
}
"use client";
import { useState, useEffect } from "react";
import Link from "next/link";
import { Menu, X } from "lucide-react";
import { motion, AnimatePresence } from "framer-motion";
import { content } from "@/lib/content";
const navLinks = [
{ label: content.ar.nav.home, href: "/" },
{ label: content.ar.nav.features, href: "/features" },
{ label: content.ar.nav.pricing, href: "/pricing" },
{ label: content.ar.nav.about, href: "/about" },
{ label: content.ar.nav.contact, href: "/contact" },
];
export default function Navbar() {
const [isScrolled, setIsScrolled] = useState(false);
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
useEffect(() => {
const handleScroll = () => {
setIsScrolled(window.scrollY > 10);
};
window.addEventListener("scroll", handleScroll, { passive: true });
return () => window.removeEventListener("scroll", handleScroll);
}, []);
useEffect(() => {
if (isMobileMenuOpen) {
document.body.style.overflow = "hidden";
} else {
document.body.style.overflow = "";
}
return () => {
document.body.style.overflow = "";
};
}, [isMobileMenuOpen]);
return (
<header
className={`sticky top-0 z-50 w-full backdrop-blur-xl transition-all duration-300 ${
isScrolled
? "bg-white/80 border-b border-slate-200/60 shadow-sm"
: "bg-white/60"
}`}
>
<nav className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
<div className="flex h-16 items-center justify-between">
{/* Logo */}
<Link
href="/"
className="flex items-center gap-2 text-xl font-bold text-navy-800"
>
<span className="text-sky-500">&#9670;</span>
الكابتن
</Link>
{/* Desktop Nav Links */}
<div className="hidden md:flex items-center gap-8">
{navLinks.map((link) => (
<Link
key={link.href}
href={link.href}
className="text-sm font-medium text-slate-600 transition-colors hover:text-navy-800"
>
{link.label}
</Link>
))}
</div>
{/* Desktop CTA */}
<div className="hidden md:block">
<Link
href="/contact"
className="inline-flex items-center justify-center rounded-lg bg-sky-500 px-5 py-2.5 text-sm font-semibold text-white shadow-sm transition-all hover:bg-sky-600 hover:shadow-md active:scale-[0.98]"
>
{content.ar.nav.cta}
</Link>
</div>
{/* Mobile Menu Button */}
<button
type="button"
className="md:hidden inline-flex items-center justify-center rounded-md p-2 text-slate-600 hover:bg-slate-100 hover:text-slate-900 transition-colors"
onClick={() => setIsMobileMenuOpen(!isMobileMenuOpen)}
aria-label={isMobileMenuOpen ? "إغلاق القائمة" : "فتح القائمة"}
aria-expanded={isMobileMenuOpen}
>
{isMobileMenuOpen ? (
<X className="h-6 w-6" />
) : (
<Menu className="h-6 w-6" />
)}
</button>
</div>
</nav>
{/* Mobile Menu Overlay */}
<AnimatePresence>
{isMobileMenuOpen && (
<motion.div
initial={{ opacity: 0, y: -10 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -10 }}
transition={{ duration: 0.2, ease: "easeOut" }}
className="fixed inset-0 top-16 z-40 bg-white md:hidden"
>
<div className="flex flex-col gap-1 px-4 py-6">
{navLinks.map((link) => (
<Link
key={link.href}
href={link.href}
onClick={() => setIsMobileMenuOpen(false)}
className="rounded-lg px-4 py-3 text-base font-medium text-slate-700 transition-colors hover:bg-slate-50 hover:text-navy-800"
>
{link.label}
</Link>
))}
<div className="mt-4 pt-4 border-t border-slate-200">
<Link
href="/contact"
onClick={() => setIsMobileMenuOpen(false)}
className="flex w-full items-center justify-center rounded-lg bg-sky-500 px-5 py-3 text-base font-semibold text-white shadow-sm transition-all hover:bg-sky-600"
>
{content.ar.nav.cta}
</Link>
</div>
</div>
</motion.div>
)}
</AnimatePresence>
</header>
);
}
"use client";
import { motion } from "framer-motion";
import { content } from "@/lib/content";
import { fadeUp, staggerContainer, staggerItem } from "@/lib/animations";
const cta = content.ar.cta;
export default function CTASection() {
return (
<section className="py-20 md:py-28 bg-slate-900 relative overflow-hidden">
{/* Decorative grid dots pattern */}
<div
className="absolute inset-0 opacity-[0.07]"
style={{
backgroundImage:
"radial-gradient(circle, rgba(255,255,255,0.8) 1px, transparent 1px)",
backgroundSize: "32px 32px",
}}
/>
{/* Gradient overlay */}
<div className="absolute inset-0 bg-gradient-to-b from-slate-900/80 via-transparent to-slate-900/80" />
<div className="container mx-auto px-4 md:px-6 relative z-10">
<motion.div
initial="hidden"
whileInView="visible"
viewport={{ once: true, margin: "-80px" }}
variants={staggerContainer}
className="bg-slate-800/50 border border-slate-700/50 backdrop-blur-sm rounded-2xl p-10 md:p-16 max-w-3xl mx-auto text-center"
>
<motion.h2
variants={staggerItem}
className="text-3xl md:text-4xl lg:text-5xl font-bold text-white mb-4"
>
{cta.headline}
</motion.h2>
<motion.p
variants={staggerItem}
className="text-lg md:text-xl text-slate-300 mb-10 max-w-xl mx-auto"
>
{cta.subheadline}
</motion.p>
<motion.div
variants={staggerItem}
className="flex flex-col sm:flex-row items-center justify-center gap-4"
>
<a
href="#contact"
className="inline-flex items-center justify-center px-8 py-4 text-lg font-bold bg-white text-slate-900 rounded-xl hover:bg-slate-100 transition-colors w-full sm:w-auto"
>
{cta.ctaPrimary}
</a>
<a
href="#contact"
className="inline-flex items-center justify-center px-8 py-4 text-lg font-medium border-2 border-white/30 text-white rounded-xl hover:bg-white/10 transition-colors w-full sm:w-auto"
>
{cta.ctaSecondary}
</a>
</motion.div>
</motion.div>
</div>
</section>
);
}
"use client";
import { motion } from "framer-motion";
import { Check } from "lucide-react";
import { content } from "@/lib/content";
import { fadeUp, staggerContainer, staggerItem } from "@/lib/animations";
const features = content.ar.features;
const mockupColors = [
{ bg: "bg-blue-50", accent: "bg-blue-500", secondary: "bg-blue-200" },
{ bg: "bg-emerald-50", accent: "bg-emerald-500", secondary: "bg-emerald-200" },
{ bg: "bg-purple-50", accent: "bg-purple-500", secondary: "bg-purple-200" },
];
function FeatureMockup({ colorIndex }: { colorIndex: number }) {
const colors = mockupColors[colorIndex];
return (
<div
className={`${colors.bg} rounded-2xl p-6 w-full max-w-md aspect-[4/3] flex flex-col gap-4 shadow-lg`}
>
{/* Header bar */}
<div className="flex items-center gap-3">
<div className={`${colors.accent} w-3 h-3 rounded-full`} />
<div className={`${colors.secondary} h-3 rounded-full flex-1 max-w-[60%]`} />
</div>
{/* Content rows */}
<div className="flex-1 flex flex-col gap-3 justify-center">
<div className="flex gap-3 items-center">
<div className={`${colors.accent} w-10 h-10 rounded-lg opacity-80`} />
<div className="flex-1 space-y-2">
<div className={`${colors.secondary} h-3 rounded-full w-3/4`} />
<div className={`${colors.secondary} h-2 rounded-full w-1/2 opacity-60`} />
</div>
</div>
<div className="flex gap-3 items-center">
<div className={`${colors.accent} w-10 h-10 rounded-lg opacity-60`} />
<div className="flex-1 space-y-2">
<div className={`${colors.secondary} h-3 rounded-full w-2/3`} />
<div className={`${colors.secondary} h-2 rounded-full w-2/5 opacity-60`} />
</div>
</div>
<div className="flex gap-3 items-center">
<div className={`${colors.accent} w-10 h-10 rounded-lg opacity-40`} />
<div className="flex-1 space-y-2">
<div className={`${colors.secondary} h-3 rounded-full w-4/5`} />
<div className={`${colors.secondary} h-2 rounded-full w-1/3 opacity-60`} />
</div>
</div>
</div>
{/* Bottom bar */}
<div className="flex gap-2">
<div className={`${colors.accent} h-8 rounded-lg flex-1 opacity-90`} />
<div className={`${colors.secondary} h-8 rounded-lg w-20`} />
</div>
</div>
);
}
export default function FeatureDeepDive() {
return (
<section className="py-16 md:py-24">
<div className="container mx-auto px-4 md:px-6">
{features.map((feature, index) => {
const isReversed = index % 2 !== 0;
return (
<motion.div
key={index}
initial="hidden"
whileInView="visible"
viewport={{ once: true, margin: "-100px" }}
variants={staggerContainer}
className={`flex flex-col ${
isReversed ? "md:flex-row-reverse" : "md:flex-row"
} items-center gap-10 md:gap-16 py-16 md:py-20`}
>
{/* Text side */}
<motion.div variants={fadeUp} className="flex-1 space-y-6">
<span className="inline-block px-3 py-1 text-sm font-medium bg-sky-100 text-sky-700 rounded-full">
{feature.tag}
</span>
<h3 className="text-3xl md:text-4xl font-bold text-slate-900">
{feature.title}
</h3>
<p className="text-lg text-slate-600 leading-relaxed">
{feature.description}
</p>
<motion.ul
variants={staggerContainer}
initial="hidden"
whileInView="visible"
viewport={{ once: true }}
className="space-y-3 pt-2"
>
{feature.points.map((point, i) => (
<motion.li
key={i}
variants={staggerItem}
className="flex items-center gap-3"
>
<span className="flex-shrink-0 w-6 h-6 bg-emerald-100 text-emerald-600 rounded-full flex items-center justify-center">
<Check size={14} strokeWidth={3} />
</span>
<span className="text-slate-700 font-medium">{point}</span>
</motion.li>
))}
</motion.ul>
</motion.div>
{/* Mockup side */}
<motion.div
variants={fadeUp}
className="flex-1 flex justify-center"
>
<FeatureMockup colorIndex={index} />
</motion.div>
</motion.div>
);
})}
</div>
</section>
);
}
"use client";
import { motion } from "framer-motion";
import { content } from "@/lib/content";
import { staggerContainer, staggerItem, fadeUp, scaleIn } from "@/lib/animations";
import CountUpNumber from "@/components/shared/CountUpNumber";
import { ArrowLeft, TrendingUp, Users, BarChart3 } from "lucide-react";
const heroContent = content.ar.hero;
function DashboardMockup() {
return (
<motion.div
variants={scaleIn}
className="relative"
style={{ perspective: "1200px" }}
>
<motion.div
animate={{ y: [0, -8, 0] }}
transition={{ duration: 4, repeat: Infinity, ease: "easeInOut" }}
className="relative rounded-2xl border border-slate-200 bg-white p-4 shadow-2xl"
style={{
transform: "rotateY(-5deg) rotateX(3deg)",
transformStyle: "preserve-3d",
}}
>
{/* Browser header */}
<div className="mb-4 flex items-center gap-2 border-b border-slate-100 pb-3">
<div className="h-3 w-3 rounded-full bg-red-400" />
<div className="h-3 w-3 rounded-full bg-yellow-400" />
<div className="h-3 w-3 rounded-full bg-green-400" />
<div className="ms-3 h-5 flex-1 rounded-md bg-slate-100" />
</div>
{/* Dashboard content */}
<div className="space-y-4">
{/* Revenue card */}
<div className="rounded-xl bg-gradient-to-l from-sky-50 to-white p-4 border border-sky-100">
<div className="flex items-center justify-between">
<div>
<p className="text-xs text-slate-400 mb-1">الإيرادات الشهرية</p>
<p className="text-2xl font-bold text-slate-900">١٢٥,٠٠٠ ج.م</p>
</div>
<div className="flex items-center gap-1 rounded-full bg-emerald-50 px-2 py-1">
<TrendingUp className="h-3 w-3 text-emerald-600" />
<span className="text-xs font-medium text-emerald-600">+١٢%</span>
</div>
</div>
</div>
{/* Chart placeholder */}
<div className="rounded-xl border border-slate-100 p-4">
<div className="flex items-center justify-between mb-3">
<p className="text-xs text-slate-400">إحصائيات الأسبوع</p>
<BarChart3 className="h-4 w-4 text-slate-300" />
</div>
<svg
viewBox="0 0 200 60"
className="h-16 w-full"
fill="none"
preserveAspectRatio="none"
>
<path
d="M0 50 C20 45, 40 30, 60 35 S100 15, 120 20 S160 10, 180 15 L200 8"
stroke="rgb(14 165 233)"
strokeWidth="2"
strokeLinecap="round"
/>
<path
d="M0 50 C20 45, 40 30, 60 35 S100 15, 120 20 S160 10, 180 15 L200 8 L200 60 L0 60 Z"
fill="url(#chartGradient)"
opacity="0.15"
/>
<defs>
<linearGradient id="chartGradient" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stopColor="rgb(14 165 233)" />
<stop offset="100%" stopColor="rgb(14 165 233)" stopOpacity="0" />
</linearGradient>
</defs>
</svg>
</div>
{/* Bottom stats row */}
<div className="grid grid-cols-2 gap-3">
<div className="rounded-lg bg-slate-50 p-3">
<div className="flex items-center gap-2 mb-1">
<Users className="h-3.5 w-3.5 text-sky-500" />
<span className="text-xs text-slate-400">اللاعبين</span>
</div>
<p className="text-lg font-bold text-slate-800">٢,٤٥٠</p>
</div>
<div className="rounded-lg bg-slate-50 p-3">
<div className="flex items-center gap-2 mb-1">
<div className="h-3.5 w-3.5 rounded-full bg-emerald-400" />
<span className="text-xs text-slate-400">نسبة الحضور</span>
</div>
<p className="text-lg font-bold text-slate-800">٩٢%</p>
</div>
</div>
</div>
</motion.div>
</motion.div>
);
}
export default function Hero() {
return (
<section className="relative min-h-[90vh] flex items-center overflow-hidden bg-gradient-to-b from-white to-sky-50">
<div className="container mx-auto px-4 py-20 lg:py-24">
<motion.div
variants={staggerContainer}
initial="hidden"
animate="visible"
className="grid items-center gap-12 lg:grid-cols-2 lg:gap-16"
>
{/* Text content (visually right in RTL) */}
<div className="order-2 lg:order-1">
<motion.div variants={staggerContainer} initial="hidden" animate="visible">
<motion.h1
variants={staggerItem}
className="text-5xl font-extrabold leading-tight text-slate-900 md:text-6xl lg:text-7xl"
>
{heroContent.headline}
</motion.h1>
<motion.p
variants={staggerItem}
className="mt-6 max-w-xl text-lg leading-relaxed text-slate-500"
>
{heroContent.subheadline}
</motion.p>
<motion.div
variants={staggerItem}
className="mt-8 flex flex-wrap items-center gap-4"
>
<button className="inline-flex items-center gap-2 rounded-xl bg-sky-500 px-6 py-3.5 text-base font-semibold text-white shadow-lg shadow-sky-200 transition-all hover:bg-sky-600 hover:shadow-xl hover:shadow-sky-200">
{heroContent.ctaPrimary}
<ArrowLeft className="h-4 w-4" />
</button>
<button className="inline-flex items-center gap-2 rounded-xl border-2 border-slate-200 bg-white px-6 py-3.5 text-base font-semibold text-slate-700 transition-all hover:border-sky-200 hover:text-sky-600">
{heroContent.ctaSecondary}
</button>
</motion.div>
</motion.div>
</div>
{/* Dashboard mockup (visually left in RTL) */}
<motion.div
variants={scaleIn}
initial="hidden"
animate="visible"
className="order-1 lg:order-2"
>
<DashboardMockup />
</motion.div>
</motion.div>
{/* Bottom stats bar */}
<motion.div
variants={fadeUp}
initial="hidden"
whileInView="visible"
viewport={{ once: true }}
className="mt-16 rounded-2xl border border-slate-100 bg-white/80 p-6 shadow-sm backdrop-blur-sm lg:mt-20"
>
<div className="grid grid-cols-1 divide-y divide-slate-100 md:grid-cols-3 md:divide-x md:divide-x-reverse md:divide-y-0">
{heroContent.stats.map((stat, index) => (
<div key={index} className="flex flex-col items-center py-4 md:py-0">
<span className="text-3xl font-bold text-sky-600 lg:text-4xl">
<CountUpNumber value={parseFloat(stat.value)} suffix={stat.suffix} />
</span>
<span className="mt-1 text-sm text-slate-500">{stat.label}</span>
</div>
))}
</div>
</motion.div>
</div>
</section>
);
}
"use client";
import { motion } from "framer-motion";
import { content } from "@/lib/content";
import { fadeUp, staggerContainer, staggerItem } from "@/lib/animations";
import {
Wallet,
Users,
Calendar,
CheckCircle,
ShoppingCart,
Building2,
ArrowLeft,
} from "lucide-react";
const modulesContent = content.ar.modules;
const iconMap: Record<string, React.ComponentType<{ className?: string }>> = {
Wallet,
Users,
Calendar,
CheckCircle,
ShoppingCart,
Building: Building2,
};
function ModuleCard({
icon,
title,
description,
}: {
icon: string;
title: string;
description: string;
}) {
const Icon = iconMap[icon] || Wallet;
return (
<motion.div
variants={staggerItem}
className="group relative rounded-2xl border border-slate-100 bg-white p-6 transition-all duration-300 hover:-translate-y-1 hover:border-sky-200 hover:shadow-lg"
>
<div className="mb-4 inline-flex rounded-xl bg-sky-50 p-3">
<Icon className="h-6 w-6 text-sky-600" />
</div>
<h3 className="mb-2 text-lg font-bold text-slate-900">{title}</h3>
<p className="text-sm leading-relaxed text-slate-500">{description}</p>
<div className="mt-4 flex items-center gap-1 text-sm font-medium text-sky-500 opacity-0 transition-opacity duration-300 group-hover:opacity-100">
<span>اعرف أكثر</span>
<ArrowLeft className="h-3.5 w-3.5" />
</div>
</motion.div>
);
}
export default function ModuleShowcase() {
return (
<section className="bg-slate-50/50 py-20 lg:py-28">
<div className="container mx-auto px-4">
{/* Section header */}
<motion.div
variants={fadeUp}
initial="hidden"
whileInView="visible"
viewport={{ once: true }}
className="mb-14 text-center"
>
<h2 className="text-3xl font-bold text-slate-900 md:text-4xl">
{modulesContent.sectionTitle}
</h2>
<p className="mx-auto mt-4 max-w-lg text-slate-500">
{modulesContent.sectionSubtitle}
</p>
</motion.div>
{/* Module cards grid */}
<motion.div
variants={staggerContainer}
initial="hidden"
whileInView="visible"
viewport={{ once: true, margin: "-50px" }}
className="grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3"
>
{modulesContent.items.map((item, index) => (
<ModuleCard
key={index}
icon={item.icon}
title={item.title}
description={item.description}
/>
))}
</motion.div>
{/* View all link */}
<motion.div
variants={fadeUp}
initial="hidden"
whileInView="visible"
viewport={{ once: true }}
className="mt-12 text-center"
>
<a
href="#features"
className="inline-flex items-center gap-2 rounded-xl border border-slate-200 bg-white px-6 py-3 text-sm font-semibold text-slate-700 transition-all hover:border-sky-200 hover:text-sky-600 hover:shadow-sm"
>
{modulesContent.viewAll}
<ArrowLeft className="h-4 w-4" />
</a>
</motion.div>
</div>
</section>
);
}
"use client";
import { motion } from "framer-motion";
import { content } from "@/lib/content";
import { fadeUp, staggerContainer, staggerItem } from "@/lib/animations";
import {
FileSpreadsheet,
MessageCircle,
FileText,
AlertTriangle,
LayoutDashboard,
CheckCircle2,
TrendingUp,
Users,
} from "lucide-react";
const problemContent = content.ar.problem;
const beforeIcons = [
{ Icon: FileSpreadsheet, label: "إكسيل", rotation: -6, x: 10, y: 5 },
{ Icon: MessageCircle, label: "واتساب", rotation: 4, x: 55, y: 15 },
{ Icon: FileText, label: "ورق", rotation: -3, x: 25, y: 55 },
{ Icon: AlertTriangle, label: "فوضى", rotation: 8, x: 65, y: 60 },
];
function BeforeState() {
return (
<motion.div
variants={staggerContainer}
initial="hidden"
whileInView="visible"
viewport={{ once: true }}
className="relative flex flex-col items-center"
>
<div className="relative h-64 w-full max-w-sm rounded-2xl border-2 border-dashed border-slate-200 bg-slate-50/50 p-8 md:h-72">
{beforeIcons.map(({ Icon, label, rotation, x, y }, index) => (
<motion.div
key={label}
variants={staggerItem}
className="absolute"
style={{
left: `${x}%`,
top: `${y}%`,
transform: `rotate(${rotation}deg)`,
}}
>
<div className="flex flex-col items-center gap-1 opacity-60">
<div className="rounded-lg bg-white p-3 shadow-sm border border-slate-100">
<Icon className="h-6 w-6 text-slate-400" />
</div>
<span className="text-xs text-slate-400">{label}</span>
</div>
</motion.div>
))}
{/* Scattered lines for chaos effect */}
<svg
className="absolute inset-0 h-full w-full opacity-10"
viewBox="0 0 200 200"
>
<path d="M20 80 L80 40 L140 90 L180 30" stroke="currentColor" strokeWidth="1" fill="none" strokeDasharray="4 4" />
<path d="M30 140 L90 160 L150 120 L170 170" stroke="currentColor" strokeWidth="1" fill="none" strokeDasharray="4 4" />
</svg>
</div>
<motion.p
variants={fadeUp}
className="mt-6 max-w-xs text-center text-base font-medium text-slate-600"
>
{problemContent.before}
</motion.p>
</motion.div>
);
}
function AfterState() {
return (
<motion.div
initial={{ opacity: 0, x: -30 }}
whileInView={{ opacity: 1, x: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.7, delay: 1 }}
className="relative flex flex-col items-center"
>
<div className="relative h-64 w-full max-w-sm rounded-2xl border border-sky-100 bg-white p-6 shadow-xl md:h-72">
{/* Mini dashboard */}
<div className="space-y-3">
<div className="flex items-center gap-3 rounded-lg bg-sky-50 p-3">
<LayoutDashboard className="h-5 w-5 text-sky-500" />
<div className="flex-1">
<div className="h-2 w-3/4 rounded bg-sky-200" />
<div className="mt-1.5 h-2 w-1/2 rounded bg-sky-100" />
</div>
</div>
<div className="flex items-center gap-3 rounded-lg bg-emerald-50 p-3">
<CheckCircle2 className="h-5 w-5 text-emerald-500" />
<div className="flex-1">
<div className="h-2 w-2/3 rounded bg-emerald-200" />
<div className="mt-1.5 h-2 w-2/5 rounded bg-emerald-100" />
</div>
</div>
<div className="flex items-center gap-3 rounded-lg bg-amber-50 p-3">
<TrendingUp className="h-5 w-5 text-amber-500" />
<div className="flex-1">
<div className="h-2 w-4/5 rounded bg-amber-200" />
<div className="mt-1.5 h-2 w-1/3 rounded bg-amber-100" />
</div>
</div>
<div className="flex items-center gap-3 rounded-lg bg-violet-50 p-3">
<Users className="h-5 w-5 text-violet-500" />
<div className="flex-1">
<div className="h-2 w-3/5 rounded bg-violet-200" />
<div className="mt-1.5 h-2 w-1/4 rounded bg-violet-100" />
</div>
</div>
</div>
</div>
<motion.p
initial={{ opacity: 0 }}
whileInView={{ opacity: 1 }}
viewport={{ once: true }}
transition={{ delay: 1.3 }}
className="mt-6 max-w-xs text-center text-base font-medium text-slate-700"
>
{problemContent.after}
</motion.p>
</motion.div>
);
}
export default function ProblemSolution() {
return (
<section className="py-20 lg:py-28">
<div className="container mx-auto px-4">
<motion.div
variants={fadeUp}
initial="hidden"
whileInView="visible"
viewport={{ once: true }}
className="mb-12 text-center"
>
<span className="inline-block rounded-full bg-sky-50 px-4 py-1.5 text-sm font-medium text-sky-600">
المشكلة والحل
</span>
</motion.div>
<div className="grid items-center gap-8 md:grid-cols-2 lg:gap-16">
<BeforeState />
<AfterState />
</div>
</div>
</section>
);
}
"use client";
import { motion } from "framer-motion";
import { content } from "@/lib/content";
import { fadeUp, staggerContainer, staggerItem } from "@/lib/animations";
import CountUpNumber from "@/components/shared/CountUpNumber";
const stats = content.ar.stats.items;
export default function StatsSection() {
return (
<section className="py-20 md:py-28 bg-sky-50 relative overflow-hidden">
<div className="container mx-auto px-4 md:px-6">
<motion.div
initial="hidden"
whileInView="visible"
viewport={{ once: true, margin: "-80px" }}
variants={staggerContainer}
className="grid grid-cols-1 md:grid-cols-3 gap-10 md:gap-8"
>
{stats.map((stat, index) => (
<motion.div
key={index}
variants={staggerItem}
className="flex flex-col items-center text-center relative"
>
{/* Subtle glow behind number */}
<div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-40 h-40 bg-sky-200/40 rounded-full blur-3xl pointer-events-none" />
<CountUpNumber
value={parseFloat(stat.value)}
suffix={stat.suffix}
className="relative text-4xl md:text-5xl font-bold text-slate-900"
/>
<p className="mt-3 text-lg text-slate-600 font-medium relative">
{stat.label}
</p>
</motion.div>
))}
</motion.div>
</div>
</section>
);
}
"use client";
import { useState, useEffect, useCallback } from "react";
import { motion, AnimatePresence } from "framer-motion";
import { content } from "@/lib/content";
import { fadeUp } from "@/lib/animations";
const testimonials = content.ar.testimonials;
const avatarColors = ["bg-blue-500", "bg-emerald-500", "bg-purple-500"];
function getInitials(name: string): string {
const parts = name.split(" ");
return parts.length > 1
? parts[0][0] + parts[1][0]
: parts[0].slice(0, 2);
}
const slideVariants = {
enter: (direction: number) => ({
x: direction > 0 ? 200 : -200,
opacity: 0,
}),
center: {
x: 0,
opacity: 1,
transition: { duration: 0.4, ease: [0.25, 0.46, 0.45, 0.94] as const },
},
exit: (direction: number) => ({
x: direction > 0 ? -200 : 200,
opacity: 0,
transition: { duration: 0.3 },
}),
};
export default function Testimonials() {
const [current, setCurrent] = useState(0);
const [direction, setDirection] = useState(1);
const [isPaused, setIsPaused] = useState(false);
const goTo = useCallback(
(index: number) => {
setDirection(index > current ? 1 : -1);
setCurrent(index);
},
[current]
);
useEffect(() => {
if (isPaused) return;
const timer = setInterval(() => {
setDirection(1);
setCurrent((prev) => (prev + 1) % testimonials.items.length);
}, 5000);
return () => clearInterval(timer);
}, [isPaused]);
const item = testimonials.items[current];
return (
<section className="py-20 md:py-28 bg-white">
<div className="container mx-auto px-4 md:px-6">
<motion.h2
initial="hidden"
whileInView="visible"
viewport={{ once: true }}
variants={fadeUp}
className="text-3xl md:text-4xl font-bold text-center text-slate-900 mb-16"
>
{testimonials.title}
</motion.h2>
<div
className="relative max-w-3xl mx-auto min-h-[280px]"
onMouseEnter={() => setIsPaused(true)}
onMouseLeave={() => setIsPaused(false)}
>
<AnimatePresence mode="wait" custom={direction}>
<motion.div
key={current}
custom={direction}
variants={slideVariants}
initial="enter"
animate="center"
exit="exit"
className="absolute inset-0 flex flex-col items-center text-center px-4"
>
{/* Quote */}
<p className="text-xl md:text-2xl text-slate-700 leading-relaxed mb-8 max-w-2xl">
&ldquo;{item.quote}&rdquo;
</p>
{/* Avatar and info */}
<div className="flex flex-col items-center gap-3">
<div
className={`w-14 h-14 rounded-full ${avatarColors[current]} flex items-center justify-center text-white font-bold text-lg`}
>
{getInitials(item.name)}
</div>
<div className="text-center">
<p className="font-bold text-slate-900 text-lg">
{item.name}
</p>
<p className="text-slate-500">
{item.role}{item.location}
</p>
</div>
</div>
</motion.div>
</AnimatePresence>
</div>
{/* Navigation dots */}
<div className="flex justify-center gap-2 mt-8">
{testimonials.items.map((_, index) => (
<button
key={index}
onClick={() => goTo(index)}
aria-label={`شهادة ${index + 1}`}
className={`w-3 h-3 rounded-full transition-all duration-300 ${
index === current
? "bg-sky-500 w-8"
: "bg-slate-300 hover:bg-slate-400"
}`}
/>
))}
</div>
</div>
</section>
);
}
"use client";
import { useRef } from "react";
import { motion, useReducedMotion, type Variants } from "framer-motion";
import { fadeUp } from "@/lib/animations";
interface AnimateOnScrollProps {
children: React.ReactNode;
variant?: Variants;
delay?: number;
className?: string;
}
export default function AnimateOnScroll({
children,
variant = fadeUp,
delay = 0,
className,
}: AnimateOnScrollProps) {
const prefersReducedMotion = useReducedMotion();
const ref = useRef(null);
if (prefersReducedMotion) {
return <div className={className}>{children}</div>;
}
return (
<motion.div
ref={ref}
variants={variant}
initial="hidden"
whileInView="visible"
viewport={{ once: true, amount: 0.2 }}
transition={{ delay }}
className={className}
>
{children}
</motion.div>
);
}
interface ContainerProps {
children: React.ReactNode;
className?: string;
}
export default function Container({ children, className = "" }: ContainerProps) {
return (
<div className={`mx-auto max-w-7xl px-4 sm:px-6 lg:px-8 ${className}`}>
{children}
</div>
);
}
"use client";
import { useEffect, useRef, useState, useCallback } from "react";
interface CountUpNumberProps {
value: number;
suffix?: string;
prefix?: string;
duration?: number;
className?: string;
}
export default function CountUpNumber({
value,
suffix = "",
prefix = "",
duration = 1500,
className,
}: CountUpNumberProps) {
const [displayValue, setDisplayValue] = useState(0);
const [hasTriggered, setHasTriggered] = useState(false);
const elementRef = useRef<HTMLSpanElement>(null);
const animationRef = useRef<number | null>(null);
const animate = useCallback(() => {
const startTime = performance.now();
const step = (currentTime: number) => {
const elapsed = currentTime - startTime;
const progress = Math.min(elapsed / duration, 1);
// easeOut cubic
const eased = 1 - Math.pow(1 - progress, 3);
const current = eased * value;
setDisplayValue(current);
if (progress < 1) {
animationRef.current = requestAnimationFrame(step);
}
};
animationRef.current = requestAnimationFrame(step);
}, [value, duration]);
useEffect(() => {
const element = elementRef.current;
if (!element) return;
const observer = new IntersectionObserver(
(entries) => {
const entry = entries[0];
if (entry.isIntersecting && !hasTriggered) {
setHasTriggered(true);
animate();
}
},
{ threshold: 0.3 }
);
observer.observe(element);
return () => {
observer.disconnect();
if (animationRef.current !== null) {
cancelAnimationFrame(animationRef.current);
}
};
}, [animate, hasTriggered]);
const formatNumber = (num: number): string => {
// If the target value has a decimal, show one decimal place
if (value % 1 !== 0) {
return num.toFixed(1);
}
return Math.floor(num).toLocaleString("ar-EG");
};
return (
<span ref={elementRef} className={`tabular-nums ${className || ""}`}>
{prefix}
{formatNumber(displayValue)}
{suffix}
</span>
);
}
"use client";
import { MessageCircle } from "lucide-react";
export default function WhatsAppButton() {
return (
<a
href="https://wa.me/201000000000"
target="_blank"
rel="noopener noreferrer"
aria-label="تواصل عبر واتساب"
className="fixed bottom-6 start-6 z-50 flex h-14 w-14 items-center justify-center rounded-full bg-emerald-500 text-white shadow-lg shadow-emerald-200 transition-all hover:bg-emerald-600 hover:scale-110 hover:shadow-xl"
>
<MessageCircle className="h-6 w-6" />
</a>
);
}
import { Accordion as AccordionPrimitive } from "@base-ui/react/accordion"
import { cn } from "@/lib/utils"
import { ChevronDownIcon, ChevronUpIcon } from "lucide-react"
function Accordion({ className, ...props }: AccordionPrimitive.Root.Props) {
return (
<AccordionPrimitive.Root
data-slot="accordion"
className={cn("flex w-full flex-col", className)}
{...props}
/>
)
}
function AccordionItem({ className, ...props }: AccordionPrimitive.Item.Props) {
return (
<AccordionPrimitive.Item
data-slot="accordion-item"
className={cn("not-last:border-b", className)}
{...props}
/>
)
}
function AccordionTrigger({
className,
children,
...props
}: AccordionPrimitive.Trigger.Props) {
return (
<AccordionPrimitive.Header className="flex">
<AccordionPrimitive.Trigger
data-slot="accordion-trigger"
className={cn(
"group/accordion-trigger relative flex flex-1 items-start justify-between rounded-lg border border-transparent py-2.5 text-left text-sm font-medium transition-all outline-none hover:underline focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 focus-visible:after:border-ring aria-disabled:pointer-events-none aria-disabled:opacity-50 **:data-[slot=accordion-trigger-icon]:ml-auto **:data-[slot=accordion-trigger-icon]:size-4 **:data-[slot=accordion-trigger-icon]:text-muted-foreground",
className
)}
{...props}
>
{children}
<ChevronDownIcon data-slot="accordion-trigger-icon" className="pointer-events-none shrink-0 group-aria-expanded/accordion-trigger:hidden" />
<ChevronUpIcon data-slot="accordion-trigger-icon" className="pointer-events-none hidden shrink-0 group-aria-expanded/accordion-trigger:inline" />
</AccordionPrimitive.Trigger>
</AccordionPrimitive.Header>
)
}
function AccordionContent({
className,
children,
...props
}: AccordionPrimitive.Panel.Props) {
return (
<AccordionPrimitive.Panel
data-slot="accordion-content"
className="overflow-hidden text-sm data-open:animate-accordion-down data-closed:animate-accordion-up"
{...props}
>
<div
className={cn(
"h-(--accordion-panel-height) pt-0 pb-2.5 data-ending-style:h-0 data-starting-style:h-0 [&_a]:underline [&_a]:underline-offset-3 [&_a]:hover:text-foreground [&_p:not(:last-child)]:mb-4",
className
)}
>
{children}
</div>
</AccordionPrimitive.Panel>
)
}
export { Accordion, AccordionItem, AccordionTrigger, AccordionContent }
import { mergeProps } from "@base-ui/react/merge-props"
import { useRender } from "@base-ui/react/use-render"
import { cva, type VariantProps } from "class-variance-authority"
import { cn } from "@/lib/utils"
const badgeVariants = cva(
"group/badge inline-flex h-5 w-fit shrink-0 items-center justify-center gap-1 overflow-hidden rounded-4xl border border-transparent px-2 py-0.5 text-xs font-medium whitespace-nowrap transition-all focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&>svg]:pointer-events-none [&>svg]:size-3!",
{
variants: {
variant: {
default: "bg-primary text-primary-foreground [a]:hover:bg-primary/80",
secondary:
"bg-secondary text-secondary-foreground [a]:hover:bg-secondary/80",
destructive:
"bg-destructive/10 text-destructive focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:focus-visible:ring-destructive/40 [a]:hover:bg-destructive/20",
outline:
"border-border text-foreground [a]:hover:bg-muted [a]:hover:text-muted-foreground",
ghost:
"hover:bg-muted hover:text-muted-foreground dark:hover:bg-muted/50",
link: "text-primary underline-offset-4 hover:underline",
},
},
defaultVariants: {
variant: "default",
},
}
)
function Badge({
className,
variant = "default",
render,
...props
}: useRender.ComponentProps<"span"> & VariantProps<typeof badgeVariants>) {
return useRender({
defaultTagName: "span",
props: mergeProps<"span">(
{
className: cn(badgeVariants({ variant }), className),
},
props
),
render,
state: {
slot: "badge",
variant,
},
})
}
export { Badge, badgeVariants }
import { Button as ButtonPrimitive } from "@base-ui/react/button"
import { cva, type VariantProps } from "class-variance-authority"
import { cn } from "@/lib/utils"
const buttonVariants = cva(
"group/button inline-flex shrink-0 items-center justify-center rounded-lg border border-transparent bg-clip-padding text-sm font-medium whitespace-nowrap transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 active:not-aria-[haspopup]:translate-y-px disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
{
variants: {
variant: {
default: "bg-primary text-primary-foreground hover:bg-primary/80",
outline:
"border-border bg-background hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50",
secondary:
"bg-secondary text-secondary-foreground hover:bg-[color-mix(in_oklch,var(--secondary),var(--foreground)_5%)] aria-expanded:bg-secondary aria-expanded:text-secondary-foreground",
ghost:
"hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-muted/50",
destructive:
"bg-destructive/10 text-destructive hover:bg-destructive/20 focus-visible:border-destructive/40 focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:hover:bg-destructive/30 dark:focus-visible:ring-destructive/40",
link: "text-primary underline-offset-4 hover:underline",
},
size: {
default:
"h-8 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",
xs: "h-6 gap-1 rounded-[min(var(--radius-md),10px)] px-2 text-xs in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3",
sm: "h-7 gap-1 rounded-[min(var(--radius-md),12px)] px-2.5 text-[0.8rem] in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3.5",
lg: "h-9 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",
icon: "size-8",
"icon-xs":
"size-6 rounded-[min(var(--radius-md),10px)] in-data-[slot=button-group]:rounded-lg [&_svg:not([class*='size-'])]:size-3",
"icon-sm":
"size-7 rounded-[min(var(--radius-md),12px)] in-data-[slot=button-group]:rounded-lg",
"icon-lg": "size-9",
},
},
defaultVariants: {
variant: "default",
size: "default",
},
}
)
function Button({
className,
variant = "default",
size = "default",
...props
}: ButtonPrimitive.Props & VariantProps<typeof buttonVariants>) {
return (
<ButtonPrimitive
data-slot="button"
className={cn(buttonVariants({ variant, size, className }))}
{...props}
/>
)
}
export { Button, buttonVariants }
import * as React from "react"
import { cn } from "@/lib/utils"
function Card({
className,
size = "default",
...props
}: React.ComponentProps<"div"> & { size?: "default" | "sm" }) {
return (
<div
data-slot="card"
data-size={size}
className={cn(
"group/card flex flex-col gap-(--card-spacing) overflow-hidden rounded-xl bg-card py-(--card-spacing) text-sm text-card-foreground ring-1 ring-foreground/10 [--card-spacing:--spacing(4)] has-data-[slot=card-footer]:pb-0 has-[>img:first-child]:pt-0 data-[size=sm]:[--card-spacing:--spacing(3)] data-[size=sm]:has-data-[slot=card-footer]:pb-0 *:[img:first-child]:rounded-t-xl *:[img:last-child]:rounded-b-xl",
className
)}
{...props}
/>
)
}
function CardHeader({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="card-header"
className={cn(
"group/card-header @container/card-header grid auto-rows-min items-start gap-1 rounded-t-xl px-(--card-spacing) has-data-[slot=card-action]:grid-cols-[1fr_auto] has-data-[slot=card-description]:grid-rows-[auto_auto] [.border-b]:pb-(--card-spacing)",
className
)}
{...props}
/>
)
}
function CardTitle({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="card-title"
className={cn(
"font-heading text-base leading-snug font-medium group-data-[size=sm]/card:text-sm",
className
)}
{...props}
/>
)
}
function CardDescription({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="card-description"
className={cn("text-sm text-muted-foreground", className)}
{...props}
/>
)
}
function CardAction({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="card-action"
className={cn(
"col-start-2 row-span-2 row-start-1 self-start justify-self-end",
className
)}
{...props}
/>
)
}
function CardContent({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="card-content"
className={cn("px-(--card-spacing)", className)}
{...props}
/>
)
}
function CardFooter({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="card-footer"
className={cn(
"flex items-center rounded-b-xl border-t bg-muted/50 p-(--card-spacing)",
className
)}
{...props}
/>
)
}
export {
Card,
CardHeader,
CardFooter,
CardTitle,
CardAction,
CardDescription,
CardContent,
}
"use client"
import { Separator as SeparatorPrimitive } from "@base-ui/react/separator"
import { cn } from "@/lib/utils"
function Separator({
className,
orientation = "horizontal",
...props
}: SeparatorPrimitive.Props) {
return (
<SeparatorPrimitive
data-slot="separator"
orientation={orientation}
className={cn(
"shrink-0 bg-border data-horizontal:h-px data-horizontal:w-full data-vertical:w-px data-vertical:self-stretch",
className
)}
{...props}
/>
)
}
export { Separator }
import type { Variants } from "framer-motion";
export const fadeUp: Variants = {
hidden: { opacity: 0, y: 20 },
visible: {
opacity: 1,
y: 0,
transition: { duration: 0.6, ease: [0.25, 0.46, 0.45, 0.94] },
},
};
export const fadeIn: Variants = {
hidden: { opacity: 0 },
visible: {
opacity: 1,
transition: { duration: 0.4 },
},
};
export const scaleIn: Variants = {
hidden: { opacity: 0, scale: 0.95 },
visible: {
opacity: 1,
scale: 1,
transition: { duration: 0.5, ease: [0.25, 0.46, 0.45, 0.94] },
},
};
export const staggerContainer: Variants = {
hidden: {},
visible: {
transition: {
staggerChildren: 0.1,
delayChildren: 0.1,
},
},
};
export const staggerItem: Variants = {
hidden: { opacity: 0, y: 16 },
visible: {
opacity: 1,
y: 0,
transition: { duration: 0.4, ease: "easeOut" },
},
};
export const slideUp: Variants = {
hidden: { opacity: 0, y: 40 },
visible: {
opacity: 1,
y: 0,
transition: { duration: 0.7, ease: [0.25, 0.46, 0.45, 0.94] },
},
};
export const content = {
ar: {
nav: {
home: "الرئيسية",
features: "المميزات",
pricing: "الأسعار",
about: "عن الكابتن",
contact: "تواصل",
cta: "ابدأ مجاناً",
},
hero: {
headline: "كل شيء تحت إدارتك",
subheadline:
"منصة إدارة رياضية متكاملة تضع كل لاعب وكل جنيه وكل حصة تحت تحكمك الكامل",
ctaPrimary: "ابدأ تجربة مجانية",
ctaSecondary: "احجز عرض تجريبي",
stats: [
{ value: "47", suffix: "+", label: "أكاديمية" },
{ value: "12000", suffix: "+", label: "لاعب" },
{ value: "99.9", suffix: "%", label: "وقت تشغيل" },
],
},
problem: {
before: "من غير نظام، أنت بتدير أكاديميتك في الضلمة",
after: "مع الكابتن، كل شيء واضح ومنظم وتحت إيدك",
items: ["إكسيل", "واتساب", "ورق", "فوضى"],
},
modules: {
sectionTitle: "منصة متكاملة لكل جوانب عملك",
sectionSubtitle: "١٤ وحدة متكاملة تغطي كل احتياجات أكاديميتك",
items: [
{
icon: "Wallet",
title: "إدارة مالية متكاملة",
description: "تتبع كل جنيه من لحظة الدفع حتى التقرير الشهري",
},
{
icon: "Users",
title: "ملفات لاعبين شاملة",
description: "كل بيانات اللاعب في مكان واحد",
},
{
icon: "Calendar",
title: "برامج ومجموعات",
description: "جدولة ذكية وتتبع تلقائي للحصص",
},
{
icon: "CheckCircle",
title: "حضور آلي",
description: "تسجيل، تنبيهات، ومتابعة الغياب فوراً",
},
{
icon: "ShoppingCart",
title: "نقاط بيع متكاملة",
description: "بيع، تحصيل، ومخزون في شاشة واحدة",
},
{
icon: "Building",
title: "إدارة المنشآت",
description: "حجز، جدولة، وتخصيص الملاعب والقاعات",
},
],
viewAll: "شوف كل المميزات",
},
features: [
{
tag: "المالية",
title: "تحكم مالي كامل",
description:
"تتبع كل جنيه من لحظة دفعه حتى يظهر في تقريرك الشهري. قيد مزدوج تلقائي، فواتير ذكية، وتنبيهات متأخرات.",
points: [
"قيد مزدوج تلقائي",
"فواتير وأقساط",
"تقارير لحظية",
"تنبيهات متأخرات",
],
},
{
tag: "التسجيل",
title: "تسجيل ذكي",
description:
"من أول ما يسجل اللاعب لحد ما يبدأ التدريب — كل شيء آلي. ويزارد سريع، تسعير تلقائي، وفاتورة فورية.",
points: [
"ويزارد تسجيل سريع",
"تسعير آلي",
"فاتورة فورية",
"إشعار للمدرب",
],
},
{
tag: "الحضور",
title: "حضور ذكي",
description:
"تسجيل حضور بضغطة واحدة. تنبيهات فورية عند الغياب. تقارير أسبوعية تلقائية لأولياء الأمور.",
points: [
"تسجيل بضغطة واحدة",
"تنبيهات غياب فورية",
"تقارير أسبوعية",
"إحصائيات ذكية",
],
},
],
testimonials: {
title: "ماذا يقول عملاؤنا",
items: [
{
quote:
"المنصة غيرت طريقة إدارتنا للأكاديمية بالكامل. دلوقتي أعرف أرقامي الحقيقية في أي لحظة.",
name: "أحمد محمد",
role: "مدير أكاديمية النجوم",
location: "القاهرة",
},
{
quote:
"وفّرت علينا ساعات من الشغل اليدوي كل يوم. الحضور والفواتير بقت أوتوماتيك.",
name: "محمد حسن",
role: "مدير العمليات",
location: "الإسكندرية",
},
{
quote:
"أخيراً نظام يفهم شغل الأكاديمية. مش محتاج أشرح لحد إيه اللي عايزه.",
name: "سارة أحمد",
role: "مالكة أكاديمية ستارز",
location: "المنصورة",
},
],
},
stats: {
items: [
{ value: "1.2", suffix: " مليون+", label: "ج.م إيرادات مُدارة شهرياً" },
{ value: "50000", suffix: "+", label: "حصة مسجلة" },
{ value: "98", suffix: "%", label: "رضا العملاء" },
],
},
cta: {
headline: "جاهز تأخذ التحكم الكامل؟",
subheadline: "ابدأ بتجربة مجانية ١٤ يوم. بدون بطاقة ائتمان. بدون التزام.",
ctaPrimary: "ابدأ مجاناً",
ctaSecondary: "تحدث مع فريقنا",
},
footer: {
description: "منصة إدارة الأكاديميات الرياضية",
quickLinks: "روابط سريعة",
contactUs: "تواصل معنا",
rights: "جميع الحقوق محفوظة",
privacy: "سياسة الخصوصية",
terms: "الشروط والأحكام",
},
pricing: {
title: "اختر الباقة المناسبة",
subtitle: "١٤ يوم تجربة مجانية على كل الباقات",
monthly: "شهري",
yearly: "سنوي",
yearlyDiscount: "وفر ٢٠%",
platformFeeLabel: "رسوم معاملات",
plans: [
{
name: "أساسي",
price: "$20",
period: "/شهر",
platformFee: "5%",
description: "مثالي للأكاديميات الصغيرة والناشئة",
features: [
{ text: "حتى ٢٠٠ لاعب", included: true },
{ text: "فرع واحد", included: true },
{ text: "٥ مستخدمين", included: true },
{ text: "إدارة مالية", included: true },
{ text: "حضور وغياب", included: true },
{ text: "تقارير أساسية", included: true },
{ text: "نقاط البيع", included: false },
{ text: "المخزون", included: false },
],
cta: "ابدأ مجاناً",
highlighted: false,
},
{
name: "احترافي",
price: "$60",
period: "/شهر",
platformFee: "3%",
description: "للأكاديميات المتوسطة والكبيرة",
badge: "الأكثر شيوعاً",
features: [
{ text: "حتى ١,٠٠٠ لاعب", included: true },
{ text: "حتى ٥ فروع", included: true },
{ text: "١٥ مستخدم", included: true },
{ text: "كل المميزات", included: true },
{ text: "نقاط البيع", included: true },
{ text: "المخزون", included: true },
{ text: "تقارير متقدمة", included: true },
{ text: "دعم أولوية", included: true },
],
cta: "ابدأ الآن",
highlighted: true,
},
{
name: "مؤسسي",
price: "$100",
period: "/شهر",
platformFee: "1%",
description: "للمؤسسات والأندية الكبيرة",
features: [
{ text: "لاعبين غير محدودين", included: true },
{ text: "فروع غير محدودة", included: true },
{ text: "مستخدمين غير محدودين", included: true },
{ text: "كل المميزات", included: true },
{ text: "API كامل", included: true },
{ text: "دعم مخصص", included: true },
{ text: "تخصيص حسب الطلب", included: true },
{ text: "مدير حساب", included: true },
],
cta: "تحدث معنا",
highlighted: false,
},
],
faq: [
{
q: "هل فيه فترة تجربة مجانية؟",
a: "نعم، ١٤ يوم تجربة كاملة على أي باقة بدون بطاقة ائتمان. لو مش مناسبة، لا تدفع شيء.",
},
{
q: "إيه هي رسوم المعاملات؟",
a: "نسبة بسيطة تُضاف على كل تحصيل يتم عبر المنصة. كل ما ترقيت باقتك، قلت النسبة. الباقة المؤسسية ١% فقط.",
},
{
q: "هل أقدر أغير الباقة بعدين؟",
a: "طبعاً، تقدر تترقى أو تخفّض باقتك في أي وقت. الفرق يتحسب تلقائياً.",
},
{
q: "إيه اللي بيحصل لبياناتي لو لغيت؟",
a: "بياناتك تفضل متاحة لمدة ٣٠ يوم بعد الإلغاء. تقدر تصدّرها في أي وقت.",
},
{
q: "هل المنصة بتشتغل على الموبايل؟",
a: "نعم، المنصة متجاوبة بالكامل وتشتغل على أي جهاز — موبايل، تابلت، أو كمبيوتر.",
},
{
q: "هل بتدعموا أكثر من فرع؟",
a: "نعم، الباقة الاحترافية تدعم حتى ٥ فروع والمؤسسية بدون حد.",
},
{
q: "هل فيه خصم للدفع السنوي؟",
a: "نعم، الدفع السنوي يوفر ٢٠% — يعني شهرين ببلاش.",
},
],
},
about: {
title: "عن الكابتن",
mission: {
title: "مهمتنا",
text: "نبني مركز القيادة للمنظمات الرياضية — نمنح أصحاب الأكاديميات تحكماً تشغيلياً كاملاً ليركزوا على ما يهم: تطوير الرياضيين.",
},
vision: {
title: "رؤيتنا",
text: "عالم تعمل فيه كل أكاديمية رياضية في المنطقة العربية بدقة واحترافية النوادي الكبرى.",
},
values: [
{
title: "مصمم للرياضة",
description: "مش نظام عام حد عدّله. كل تفصيلة مبنية على فهم حقيقي لشغل الأكاديمية.",
},
{
title: "البساطة قوة",
description: "واجهة بسيطة لا تحتاج تدريب. المدرب يقدر يستخدمها من أول يوم.",
},
{
title: "بياناتك ملكك",
description: "تشفير كامل، سيرفرات أوروبية، ونسخ احتياطي يومي. صفر تنازلات.",
},
{
title: "ينمو معك",
description: "من ٥٠ لاعب لـ ٥٠٠٠ — نفس القوة، نفس السهولة.",
},
],
},
contact: {
title: "احجز عرض تجريبي",
subtitle: "شوف المنصة بنفسك في ٣٠ دقيقة",
form: {
name: "الاسم",
academy: "اسم الأكاديمية",
phone: "رقم الموبايل",
email: "البريد الإلكتروني",
players: "عدد اللاعبين",
playersOptions: [
"أقل من ١٠٠",
"١٠٠ - ٣٠٠",
"٣٠٠ - ٥٠٠",
"٥٠٠ - ١٠٠٠",
"أكثر من ١٠٠٠",
],
message: "رسالة (اختياري)",
submit: "إرسال الطلب",
},
info: {
phone: "+20 100 000 0000",
whatsapp: "تواصل عبر واتساب",
email: "info@elcaptain.com",
},
},
},
} as const;
import { Cairo, Inter } from "next/font/google";
export const cairo = Cairo({
subsets: ["arabic", "latin"],
variable: "--font-cairo",
display: "swap",
weight: ["400", "500", "600", "700", "800"],
});
export const inter = Inter({
subsets: ["latin"],
variable: "--font-inter",
display: "swap",
weight: ["400", "500", "600", "700"],
});
import { clsx, type ClassValue } from "clsx"
import { twMerge } from "tailwind-merge"
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
}
{
"compilerOptions": {
"target": "ES2017",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "react-jsx",
"incremental": true,
"plugins": [
{
"name": "next"
}
],
"paths": {
"@/*": ["./src/*"]
}
},
"include": [
"next-env.d.ts",
"**/*.ts",
"**/*.tsx",
".next/types/**/*.ts",
".next/dev/types/**/*.ts",
"**/*.mts"
],
"exclude": ["node_modules"]
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment