&text&type=phone_number&app_absent=0`
+- Phone in URL: country code + number, **no `+` or spaces**.
+- Display phone format: `+CC XX XXX XXXX`.
+- Anchor: `target="_blank" rel="noopener noreferrer" aria-label="Chat with [Brand] on WhatsApp"`.
+- Icon: inline SVG (lucide has no WhatsApp glyph). Refined gold tint, not bright green.
+- Two surfaces: nav (circular icon button) + footer (icon + display number).
+- Optional third surface: contact page row.
+
+---
+
+## Client logo section
+
+- Horizontal marquee, `animation: marquee 50s linear infinite`.
+- Hover pauses via `onMouseEnter/Leave` setting `animationPlayState`.
+- Duplicate the data array `[...clients, ...clients]` for seamless loop.
+- Tiles: `h-24 w-44 sm:h-28 sm:w-52 rounded-2xl border border-bone/10 bg-graphite/40 backdrop-blur-sm`.
+- Logos: `object-contain max-h-14 sm:max-h-16`. Default `grayscale opacity-70`. Hover: `grayscale-0 opacity-100 scale-105`.
+- Edge fade via `mask-image: linear-gradient(90deg, transparent, black 8%, black 92%, transparent)`.
+- Reduced-motion fallback: render a static `grid-cols-2 sm:grid-cols-3 lg:grid-cols-6`.
+
+---
+
+## Certificate gallery
+
+- 4-col on desktop, 2-col tablet, 1-col mobile.
+- Each tile: portrait `aspect-[3/4]` with `next/image fill object-cover object-top`.
+- Top-left badge: page indicator (`Page 1`, `Page 2 · Annex`).
+- Top-right: ArrowUpRight disc (links open in new tab).
+- Click anywhere on tile opens the PDF.
+- Hover: scale 1.04 (1.2s ease-out), gold ring border, amber radial glow, caption title → gold-light.
+- Caption below image: `font-mono` micro-label (document name in gold) + title + "Open PDF" CTA.
+- Optional "Need the full PDFs?" pill row below grid for direct downloads.
+
+---
+
+## Final CTA section
+
+- Wraps inside a premium gold-bordered glass card.
+- Animated halo (`!reduce && motion.div opacity pulse`).
+- Grid: `lg:grid-cols-12` (8/4 split).
+- Left col: SectionLabel + h2 with one gold-accent phrase + paragraph.
+- Right col: 2 buttons (`primary` + `outline`).
+- Place at the end of every long page, before the footer.
+
+---
+
+## Privacy / Legal pages
+
+- Single-column max-w-3xl reading layout.
+- Each section gets `id="..."` + `scroll-mt-28` for anchored navigation.
+- `font-display` h2 per section, `text-mist` body, `text-pretty` on every ``.
+- Effective date + `metallic-divider` at top.
+- Bottom disclaimer: `text-sm text-mist/70` with mailto link.
+
+---
+
+## Don't
+
+- Don't add hover effects without `transition-*` for smoothness.
+- Don't use `transform-origin` defaults on rotated icon discs — keep them small (8-12°).
+- Don't use `whileHover={{ scale: 1.1 }}` on cards — too theatrical. Use `-translate-y-1` instead.
+- Don't add box-shadows with multiple layers and bright colors. One subtle amber glow max.
+- Don't introduce a new font family per page — stick to display + sans.
+- Don't render placeholder images (`via.placeholder.com`, gray boxes) in production code. Always use real assets the user provided.
diff --git a/.claude/skills/premium-frontend-designer/COMPONENT_SNIPPETS.md b/.claude/skills/premium-frontend-designer/COMPONENT_SNIPPETS.md
new file mode 100644
index 0000000..98642b6
--- /dev/null
+++ b/.claude/skills/premium-frontend-designer/COMPONENT_SNIPPETS.md
@@ -0,0 +1,45 @@
+# Component Snippets
+
+Overview of the reusable TSX snippets in `snippets/`. Each is a copy-paste base for a new project — adapt brand tokens + content via your own `lib/content.ts`.
+
+| File | Purpose | Depends on |
+|---|---|---|
+| `PremiumButton.tsx` | Gold-gradient primary + outline + ghost variants, optional magnetic wrapper | `lib/cn`, lucide ArrowUpRight |
+| `SectionHeading.tsx` | Premium section heading w/ eyebrow + serif h2 + sub paragraph | `lib/cn`, framer Reveal |
+| `GlassCard.tsx` | Dark glass card w/ hover lift, amber glow, gold underline sweep | lucide LucideIcon |
+| `Footer.tsx` | 4-column footer w/ no duplication, watermark, agency credit | brand contact data |
+| `AppBadges.tsx` | Official App Store + Google Play badge anchors (plain `
`) | `/public/images/*-badge.svg` |
+| `WhatsAppLink.tsx` | Refined gold WhatsApp icon button + label variant | inline SVG (no lucide glyph) |
+| `ClientLogoMarquee.tsx` | Auto-scroll logo marquee w/ hover pause + reduced-motion grid fallback | logos array, marquee keyframe in globals.css |
+| `CertificateGallery.tsx` | 4-image bento gallery linking to PDFs in new tab | `next/image`, certs array |
+
+## How to use
+
+1. Copy the file you need into your project's `src/components/` (or wherever your component layer lives).
+2. Update import paths (`@/lib/cn`, `@/components/ui/...`) to match your project alias.
+3. Wire data: the snippets accept props or read from a `lib/content.ts` you control.
+4. Confirm Tailwind v4 `@theme` tokens (`obsidian`, `gold`, `bone`, `mist`, etc.) exist — see `DESIGN_SYSTEM.md`.
+5. Confirm Framer Motion + lucide-react installed:
+ ```bash
+ npm i framer-motion lucide-react
+ ```
+
+## Adapt patterns
+
+The snippets show the **shape**. Your brand may need:
+- Different palette (warm copper instead of gold? `--color-gold` → your token, keep the same usage rules).
+- Different copy hierarchy (more / fewer columns in footer).
+- Different surfaces (e.g., add a Resources column).
+
+Keep the **interaction grammar** consistent:
+- Hover lift `-translate-y-1`.
+- Amber/gold glow bottom-right.
+- Underline sweep on cards.
+- 1.4 strokeWidth on icons.
+- Serif on h1/h2 only.
+
+That's what makes any palette feel "Luxam-class" premium.
+
+## Don't fork without reason
+
+If a snippet does 95% of what you need, **wrap** it with project-specific props rather than forking. Forks drift.
diff --git a/.claude/skills/premium-frontend-designer/DESIGN_SYSTEM.md b/.claude/skills/premium-frontend-designer/DESIGN_SYSTEM.md
new file mode 100644
index 0000000..817d8f2
--- /dev/null
+++ b/.claude/skills/premium-frontend-designer/DESIGN_SYSTEM.md
@@ -0,0 +1,204 @@
+# Design System
+
+Reusable design tokens + scales extracted from the Luxam reference build. Drop into `globals.css` (Tailwind v4 `@theme`) of any new project to start with the same DNA.
+
+---
+
+## Color palette
+
+```css
+@theme {
+ /* Backgrounds — obsidian → graphite layering */
+ --color-obsidian: #08080A; /* page background */
+ --color-graphite: #15161A; /* dark glass card */
+ --color-graphite-2: #1C1D22; /* slightly lifted card variant */
+
+ /* Foreground */
+ --color-bone: #F4F0E6; /* primary text on dark */
+ --color-mist: #C7C2B5; /* secondary/muted text */
+
+ /* Brand — gold spectrum (use sparingly + structurally) */
+ --color-gold: #D4A437; /* core brand gold */
+ --color-gold-light: #F2C25B; /* hover, highlight, gradient stops */
+ --color-gold-deep: #7A4A12; /* gradient base */
+ --color-ember: #B5731A; /* warm secondary */
+
+ /* Sustainability accent (use only where ecology theme applies) */
+ --color-emerald: #1F8F6B;
+ --color-emerald-glow: #3FD8A4;
+}
+```
+
+**Usage rules**
+- **Background:** `bg-obsidian` body, `bg-graphite/40 backdrop-blur-sm` cards.
+- **Borders:** `border-bone/10` default, `border-gold/30` on hover, `border-gold/40` active.
+- **Text:** `text-bone` titles, `text-mist` body/secondary, `text-gold-light` brand accents.
+- **Never use** raw `#fff` or pure `#000`. Always `bone` or `obsidian`.
+- **Gradients:** single-axis brand gradient `from-gold-light via-gold to-gold-deep`. No rainbow.
+
+---
+
+## Typography
+
+```ts
+// app/layout.tsx
+import { Cormorant_Garamond, Geist, Geist_Mono } from "next/font/google";
+
+const display = Cormorant_Garamond({
+ subsets: ["latin"],
+ variable: "--font-display",
+ weight: ["400", "500", "600"],
+ display: "swap",
+});
+const sans = Geist({ subsets: ["latin"], variable: "--font-sans", display: "swap" });
+const mono = Geist_Mono({ subsets: ["latin"], variable: "--font-mono", display: "swap" });
+```
+
+**Hierarchy**
+
+| Role | Font | Size |
+|---|---|---|
+| Hero H1 | `font-display` (serif) | `text-[clamp(2.6rem,7vw,6.4rem)] leading-[1.0] tracking-[-0.02em]` |
+| Section H2 | `font-display` | `text-[clamp(2.4rem,5vw,4.6rem)] leading-[1.02] tracking-[-0.02em]` |
+| Card H3/H4 | `font-display` | `text-2xl md:text-3xl` |
+| Body | `font-sans` (inherited default) | `text-base md:text-lg leading-[1.7]` |
+| UI label | `font-sans` | `text-[10px] md:text-[11px] font-medium uppercase tracking-[0.22em]` |
+| Nav link | `font-sans` | `text-sm font-medium tracking-[0.005em]` |
+| Stats number | `font-display` | `text-5xl md:text-6xl` (responsive smaller on mobile) |
+
+**Avoid**
+- `font-mono` on long values or body text.
+- `tracking-[0.3em]+` on small labels.
+- `leading-[0.95]` on serif headlines (clips ascenders).
+
+**Helper class** for one-color brand text:
+```css
+.gold-text {
+ background: linear-gradient(90deg, #FFEFC5, #F2C25B 40%, #D4A437 80%, #7A4A12);
+ -webkit-background-clip: text;
+ background-clip: text;
+ color: transparent;
+}
+```
+
+---
+
+## Spacing scale
+
+Section padding lives **only** on the `Section` primitive:
+
+```tsx
+// components/ui/Section.tsx
+className={cn("relative scroll-mt-24 py-16 md:scroll-mt-28 md:py-20 lg:py-24", className)}
+```
+
+- Mobile: `py-16` (64 px)
+- Tablet: `md:py-20` (80 px)
+- Desktop: `lg:py-24` (96 px)
+- All anchored sections get `scroll-mt-24 md:scroll-mt-28` for sticky-nav clearance.
+
+**Don't** override per-section unless there's a structural reason. Centralize.
+
+Card padding: `p-6 md:p-7` standard, `p-7 md:p-10` for hero/feature cards.
+
+Grid gaps: `gap-4 md:gap-5` standard, `gap-6 md:gap-8` for large cards.
+
+---
+
+## Border radius scale
+
+```css
+--radius-xs: 4px;
+--radius-sm: 8px;
+--radius-md: 14px;
+--radius-lg: 22px;
+--radius-xl: 32px;
+```
+
+Tailwind shortcuts to match: `rounded-2xl` (cards), `rounded-3xl` (hero panels), `rounded-full` (pills + buttons).
+
+---
+
+## Motion
+
+```ts
+// shared variants
+const cardGrid: Variants = {
+ hidden: {},
+ visible: { transition: { staggerChildren: 0.08, delayChildren: 0.15 } },
+};
+const cardCell: Variants = {
+ hidden: { opacity: 0, y: 24, filter: "blur(6px)" },
+ visible: {
+ opacity: 1, y: 0, filter: "blur(0px)",
+ transition: { duration: 0.8, ease: [0.16, 1, 0.3, 1] },
+ },
+};
+```
+
+- Entrance ease: `[0.16, 1, 0.3, 1]` (cubic-bezier "out-quart-ish").
+- Duration: hero 1.3s, cards 0.8s, hover 0.3-0.5s.
+- Hover lift: `-translate-y-1` max. No `-translate-y-2`+ (jumpy).
+- Halo pulse: `[0.5, 0.85, 0.5]` opacity, 6s loop. Wrap in `!reduce && (...)`.
+- `useReducedMotion()` must be read in any animated component.
+
+**Forbidden**
+- Bouncy springs (`stiffness > 200`) on entrance.
+- Scale jumps > 1.05 on hover for cards.
+- Parallax > 200 px translate range.
+- Marquees without `mask-image` edge fade.
+
+---
+
+## Visual textures
+
+| Class | Purpose |
+|---|---|
+| `noise-bg` | Subtle film-grain background overlay |
+| `grain` | Animated grain (use sparingly on cards) |
+| `metallic-divider` | Thin gold-tinted divider line |
+| `radial-gold` | Faint amber radial wash (positioned absolute, blur-3xl) |
+| `radial-emerald` | Same, emerald variant |
+| `hairline-t`, `hairline-b` | 1 px top/bottom hairline borders |
+| `mask-fade-y`, `mask-fade-x` | Edge fade masks |
+
+Define these as utilities in `globals.css` per the Luxam reference.
+
+---
+
+## Hover state pattern
+
+Every card/button uses the same hover vocabulary:
+
+1. `-translate-y-1` lift (cards) or `-translate-y-0.5` (buttons).
+2. Border step up: `border-bone/10 → border-gold/30 (or /35 /40)`.
+3. Background step up: `bg-graphite/40 → bg-graphite/60`.
+4. Amber radial glow bottom-right: `radial-gradient(circle, rgba(212,164,55,0.28), transparent 70%)` blurred.
+5. Gold underline sweep (cards): `absolute bottom-0 left-0 h-px w-0 ... group-hover:w-full`.
+6. Optional: top hairline gold gradient fade-in.
+7. Icon disc gets `rotate-[8deg]` + amber halo shadow.
+
+Apply via `group` + `group-hover:` Tailwind variants — never per-element JS listeners.
+
+---
+
+## Container widths
+
+```tsx
+// components/ui/Container.tsx — three variants
+size="default" → max-w-7xl
+size="wide" → max-w-[1480px]
+size="narrow" → max-w-3xl
+```
+
+All variants: `mx-auto px-6 md:px-10`.
+
+---
+
+## When in doubt
+
+- More dark, less gold.
+- More space, less content.
+- Less motion, more restraint.
+- Real photography > illustration.
+- Editorial typography > corporate sans.
diff --git a/.claude/skills/premium-frontend-designer/PROMPT_TEMPLATES.md b/.claude/skills/premium-frontend-designer/PROMPT_TEMPLATES.md
new file mode 100644
index 0000000..53923a5
--- /dev/null
+++ b/.claude/skills/premium-frontend-designer/PROMPT_TEMPLATES.md
@@ -0,0 +1,274 @@
+# Prompt Templates
+
+Copy-paste prompts for common tasks. Replace `{{placeholders}}` with project specifics.
+
+---
+
+## 1. Create homepage from scratch
+
+```
+Act as a senior frontend architect.
+Build a premium, cinematic, dark/gold luxury homepage for {{BRAND}} ({{INDUSTRY}}) using the design DNA in .claude/skills/premium-frontend-designer/.
+
+Stack: Next.js 16 App Router · TypeScript · Tailwind v4 · Framer Motion · lucide-react.
+
+Composition (top → bottom):
+1. Nav (fixed, scroll-aware)
+2. Hero (min-h-100svh, parallax halos, 2 CTAs, eyebrow + serif h1 + sub + body)
+3. BrandStrip (marquee of capability keywords)
+4. About / Story (split 5/7, copy + visual)
+5. WhyUCO-style problem→solution comparison
+6. Services overview (6 cards)
+7. Trusted Clients marquee (use ONLY logos I provide)
+8. Stats / Impact metrics (animated counters)
+9. Cinematic reel (lazy video)
+10. Process / Closed loop (timeline)
+11. Industries served
+12. Certifications
+13. Gallery (4-image bento)
+14. Final CTA section
+15. Footer (4 columns, no duplication)
+
+Brand details I will provide:
+{{BRAND_LEGAL_NAME, PHONE, EMAIL, WHATSAPP_URL, INSTAGRAM, APP_STORE, GOOGLE_PLAY, AGENCY_CREDIT}}
+
+Do NOT invent links. Ask if missing.
+```
+
+---
+
+## 2. Redesign an existing page
+
+```
+Inspect {{PAGE_ROUTE}}. Keep the content + intent but rebuild it to match the design DNA in .claude/skills/premium-frontend-designer/.
+
+Requirements:
+- Reuse existing primitives (Section, Container, Button, Reveal, SectionLabel, etc.) — don't duplicate.
+- Apply the cardGrid + cardCell motion variants for grid entrances.
+- Add a single gold-accent phrase per h2.
+- Centralize section padding via the Section primitive (no per-page overrides).
+- Run typecheck + grep for placeholder hrefs before reporting done.
+
+Return a clear file change list with NEW / MODIFIED markers.
+```
+
+---
+
+## 3. Add a polished footer
+
+```
+Build a 4-column premium footer for {{BRAND}}.
+
+Columns:
+1. Brand + contact (logo, tagline, phone, email, WhatsApp, Instagram)
+2. Navigation (top-level pages)
+3. Services (specific service items)
+4. Legal & App (Privacy Policy + 2 store badges)
+
+No duplicate link labels across columns. External links open in new tab.
+
+Footer bottom row: copyright + tagline + subtle agency credit (gold underline on hover).
+
+Watermark: project name in serif, large, opacity-0.025, contained inside footer overflow.
+
+Brand details:
+{{PHONE, EMAIL, WHATSAPP_URL, INSTAGRAM_URL, APP_STORE_URL, GOOGLE_PLAY_URL, AGENCY_CREDIT_URL}}
+```
+
+---
+
+## 4. Add WhatsApp button
+
+```
+Add a refined WhatsApp button to:
+1. Footer contact stack (icon + label "WhatsApp · {{DISPLAY_NUMBER}}").
+2. Nav (circular icon-only button next to primary CTA, mobile menu pill).
+3. Contact page info card (full-width tile w/ icon disc).
+
+URL: {{WHATSAPP_API_URL}}
+Display number: {{+CC XX XXX XXXX}}
+
+Use inline SVG (lucide has no WhatsApp glyph). Refined gold tint, not bright green. Hover: gold border + soft glow + scale 1.04. aria-label="Chat with {{BRAND}} on WhatsApp". target="_blank" rel="noopener noreferrer".
+```
+
+---
+
+## 5. Add app store badges
+
+```
+Add official App Store + Google Play badge SVGs.
+
+URLs:
+- App Store: {{APP_STORE_URL}}
+- Google Play: {{GOOGLE_PLAY_URL}}
+
+Tasks:
+1. Download from svgrepo.com (use /show/ path not /download/):
+ - https://www.svgrepo.com/show/303128/download-on-the-app-store-apple-logo.svg
+ - https://www.svgrepo.com/show/303139/google-play-badge-logo.svg
+2. Save to public/images/app-store-badge.svg + public/images/google-play-badge.svg.
+3. Render via plain
(next/image blocks SVG in Next 16).
+4. Width: 132 px footer / 140-160 px in hero CTA section.
+5. Hover: opacity-85 + -translate-y-0.5. No gold circles.
+6. Stack gap-2 (8 px) in footer.
+7. aria-label on every anchor. target="_blank" rel="noopener noreferrer".
+
+Use the snippet from snippets/AppBadges.tsx as a starting point.
+```
+
+---
+
+## 6. Add client logo section
+
+```
+Add a premium "Trusted by leading {{INDUSTRY}} partners" client logo marquee to the homepage (after Services) and About page (after process).
+
+Use ONLY these 12 logos I provide:
+{{LIST OF LOGO URLS}}
+
+Tasks:
+1. Download each into public/images/clients/ with clean filenames.
+2. Create src/lib/clients.ts with typed array { src, alt }.
+3. Use recognisable brand names for alt text; for unidentified logos use "{{BRAND}} client logo".
+4. Marquee: 50s linear infinite, hover-pause, mask-image edge fade.
+5. Tile: h-24 w-44 mobile / h-28 w-52 tablet+. Default grayscale + opacity 70%, hover full color + scale 1.05.
+6. Reduced-motion fallback: render a static grid-cols-2 sm:grid-cols-3 lg:grid-cols-6.
+
+Use snippets/ClientLogoMarquee.tsx as the base.
+```
+
+---
+
+## 7. Add certificate gallery
+
+```
+Replace the document-card list on /certifications with a 4-image gallery showing the actual certificate pages.
+
+Use these exact images (download to public/images/certifications/):
+{{IMG1_URL, IMG2_URL, IMG3_URL, IMG4_URL}}
+
+Each image links to the corresponding PDF (already in public/documents/certifications/).
+
+Layout: sm:grid-cols-2 lg:grid-cols-4 with aspect-[3/4] portrait tiles.
+
+Tile chrome:
+- Top-left page badge (Page 1 / Page 2 · Annex).
+- Top-right ArrowUpRight disc.
+- Bottom caption: mono category in gold + serif title + "Open PDF" CTA.
+- Hover: scale 1.04, gold ring border, amber radial glow, gold underline sweep.
+
+External: target="_blank" rel="noopener noreferrer" on every anchor.
+
+Optional: secondary "Need the full PDFs?" pill row below grid with direct download links.
+
+Use snippets/CertificateGallery.tsx as a starting point.
+```
+
+---
+
+## 8. Fix mobile responsiveness
+
+```
+The {{PAGE}} layout breaks on mobile. Specific issues:
+{{ISSUES_LIST}}
+
+Walk through the responsive checklist in .claude/skills/premium-frontend-designer/RESPONSIVE_CHECKLIST.md and fix every applicable item.
+
+Test at 320 / 375 / 390 / 414 / 768 / 1024 viewports.
+
+Don't redesign — only fix layout, spacing, overflow, clipping. Preserve the visual identity.
+
+Return a table of issues + fixes (Before / After columns).
+```
+
+---
+
+## 9. Polish typography sitewide
+
+```
+Audit and refine typography across all pages:
+
+1. Hero h1: clamp(2.4rem, 7vw, 6.4rem), leading-[1.0], tracking-[-0.02em]. Add pt buffer for sticky-nav clearance.
+2. Two-font system: serif for h1/h2 only, clean sans (Geist/Inter) for everything else.
+3. Remove font-mono from long values + body text. Keep only on tiny brand-pattern eyebrow tags if at all.
+4. Tracking: reduce all tracking-[0.32em+] on small labels to tracking-[0.22em].
+5. Nav links: text-sm font-medium tracking-[0.005em] (slightly larger + medium weight, near-zero tracking).
+6. BrandStrip marquee: smaller (text-xs md:text-sm uppercase) so it doesn't compete with hero.
+7. Section labels via SectionLabel primitive — never inline.
+8. text-balance on h1/h2, text-pretty on body paragraphs.
+
+Confirm:
+- typecheck clean
+- HTTP 200 on every route
+- zero tracking-[0.32em] remaining
+- no font-mono on user-facing body content
+```
+
+---
+
+## 10. Add Privacy Policy
+
+```
+Create /privacy-policy route matching the premium dark/gold style.
+
+9 sections with id="..." anchors + scroll-mt-28:
+- introduction
+- information-we-collect
+- how-we-use-information
+- contact-form-data
+- cookies-and-analytics
+- data-protection
+- third-party-services
+- user-rights
+- contact-information
+
+Use brand contact details from lib/content.ts.
+
+Effective date stamp at top + metallic-divider. Bottom disclaimer with mailto link in gold underline.
+
+Single column max-w-3xl. font-display h2 per section. text-pretty body.
+
+Don't write fake legal claims. General professional language only. Tell users they can contact for privacy questions.
+
+Add to footer Legal column.
+```
+
+---
+
+## 11. Coolify deploy via Dockerfile
+
+```
+Deploy {{PROJECT}} to Coolify with a Dockerfile build pack.
+
+Tasks:
+1. Add `output: "standalone"` to next.config.ts.
+2. Create multi-stage Dockerfile (node:22-alpine, 3 stages: deps → build → run).
+3. Add .dockerignore (skip .git, node_modules, .next cache, env files, .claude).
+4. Run-stage as non-root user (UID 1001).
+5. EXPOSE 3000, CMD ["node", "server.js"] using standalone output.
+
+Then via Coolify API:
+- PATCH application: build_pack="dockerfile", dockerfile_location="/Dockerfile", ports_exposes="3000", domains="https://{{DOMAIN}}"
+- POST /api/v1/deploy?uuid={{APP_UUID}}&force=true
+- Poll deployment until terminal status.
+
+If "no available server" appears on the domain after deploy: verify DNS resolves to Coolify host IP, then redeploy to trigger Let's Encrypt cert issuance.
+```
+
+---
+
+## 12. General "make this premium" polish
+
+```
+Inspect {{COMPONENT_OR_PAGE}}. Identify what doesn't match the premium dark/gold luxury direction in .claude/skills/premium-frontend-designer/DESIGN_SYSTEM.md.
+
+Specifically check:
+- Are buttons using premium variants (gold gradient primary, outline secondary)?
+- Are cards using the hover lift + amber glow + gold underline sweep pattern?
+- Is there any cheap iconography or stock-photo placeholder?
+- Are headings using the serif font with one gold-accent phrase?
+- Is spacing centralized via Section primitive?
+- Is motion subtle (no bounces, no scale > 1.05 on hover)?
+
+Apply only the changes needed — don't rewrite working sections. Return a list of refinements made.
+```
diff --git a/.claude/skills/premium-frontend-designer/RESPONSIVE_CHECKLIST.md b/.claude/skills/premium-frontend-designer/RESPONSIVE_CHECKLIST.md
new file mode 100644
index 0000000..91cdba2
--- /dev/null
+++ b/.claude/skills/premium-frontend-designer/RESPONSIVE_CHECKLIST.md
@@ -0,0 +1,108 @@
+# Responsive Checklist
+
+Run through every item before declaring a page done.
+
+## Viewports to verify
+
+- **320 px** (iPhone SE 1st gen, smallest practical)
+- **375 px** (iPhone SE 2/3, iPhone 13 mini)
+- **390 px** (iPhone 14/15/16 default)
+- **414 px** (iPhone Plus)
+- **768 px** (iPad portrait, `md:` breakpoint)
+- **1024 px** (iPad landscape / small laptop, `lg:` breakpoint)
+- **1440 px** (full laptop)
+
+## Global guards
+
+- [ ] `body { overflow-x: hidden }` in `globals.css`.
+- [ ] No `min-w-[...]` on root containers.
+- [ ] All decorative absolute elements live inside `relative isolate overflow-hidden` parents.
+- [ ] `max-w-*` containers always paired with `mx-auto px-6 md:px-10`.
+
+## Header / Nav
+
+- [ ] Logo left, menu/CTA right on mobile.
+- [ ] Hamburger button is `size-10` minimum (touch target).
+- [ ] Mobile menu drawer closes when a link is clicked.
+- [ ] No sticky-nav overlap on anchored sections — `scroll-mt-24 md:scroll-mt-28` on ``.
+- [ ] Logo height responsive: `h-11 sm:h-14 md:h-16`.
+
+## Hero
+
+- [ ] H1 clamp: `clamp(2.4rem, 7vw, 6.4rem)` — never larger upper bound.
+- [ ] `leading-[1.0]` on serif H1 (not `0.95` — clips ascenders).
+- [ ] Top padding generous: `pt-32 sm:pt-36 md:pt-44` (clears sticky nav + breathing room).
+- [ ] CTAs use `flex flex-wrap items-center gap-4` so they stack on narrow screens.
+- [ ] Stats panel: collapse 1-col-tall mobile layouts to a horizontal 3-col compact row.
+
+## Cards & grids
+
+- [ ] Mobile: `grid-cols-1`. Tablet: `sm:grid-cols-2`. Desktop: `lg:grid-cols-N` matched to card count.
+- [ ] Avoid `lg:grid-cols-3` for a 5-card list (leaves orphan) — use 5 or 2-row layout matched to count.
+- [ ] Aspect-ratio used over fixed heights: `aspect-[4/3]` or `aspect-[3/4]`.
+
+## Typography
+
+- [ ] No tracking > `0.22em` on small labels.
+- [ ] `text-balance` on h1/h2.
+- [ ] `text-pretty` on body paragraphs.
+- [ ] Long tokens (cert numbers, emails) use `break-all` or `break-words` to wrap.
+
+## Images
+
+- [ ] `next/image` with `sizes` attribute matched to layout.
+- [ ] Hero LCP image gets `priority`.
+- [ ] `object-cover` only when crop is visually intentional.
+- [ ] `object-contain` for logos.
+- [ ] Alt text meaningful — never "image" or filename.
+
+## Forms
+
+- [ ] Field grid: `grid gap-5 sm:grid-cols-2` for first/last + email/phone.
+- [ ] Inputs `text-base` (16 px+) on mobile to prevent iOS zoom-on-focus.
+- [ ] Submit button respects pending state w/ spinner.
+- [ ] Field errors render below field, not in a popup.
+- [ ] Success/error banner renders outside button.
+
+## Motion
+
+- [ ] `useReducedMotion()` checked in every component using motion props.
+- [ ] Heavy halos / parallax skipped when reduced-motion is on.
+- [ ] Marquee paused when reduced-motion is on (or replaced with grid).
+
+## External links
+
+- [ ] All `` carry `rel="noopener noreferrer"`.
+- [ ] WhatsApp / Instagram / store badges have `aria-label`.
+- [ ] App badges sized 132 px (footer) / 140-160 px (CTA).
+
+## Footer
+
+- [ ] No duplicated link labels across columns.
+- [ ] Privacy Policy only in Legal column.
+- [ ] Agency credit row sits below copyright, subtle.
+- [ ] Watermark contained via `overflow-hidden` on footer root.
+
+## Accessibility
+
+- [ ] Every interactive element keyboard-reachable.
+- [ ] `focus-visible:` rings on buttons, inputs, anchors.
+- [ ] Modal/lightbox: scroll-locked body + `Escape` closes + arrows navigate.
+- [ ] Color contrast checked (`text-bone` on obsidian = 16:1).
+
+## Final smoke test
+
+```bash
+npx tsc --noEmit # clean
+curl -s -o NUL -w "%{http_code}" http://localhost:3000/... # 200 on every route
+```
+
+Grep for placeholder leaks:
+
+```bash
+grep -rn 'href="#"' src/
+grep -rn 'href=""' src/
+grep -rn 'href="/#' src/
+```
+
+Should all return zero (unless intentional same-page anchors with matching IDs).
diff --git a/.claude/skills/premium-frontend-designer/SKILL.md b/.claude/skills/premium-frontend-designer/SKILL.md
new file mode 100644
index 0000000..715208e
--- /dev/null
+++ b/.claude/skills/premium-frontend-designer/SKILL.md
@@ -0,0 +1,143 @@
+---
+name: premium-frontend-designer
+description: Build, redesign, and polish premium dark/gold luxury websites with React/Next.js/Tailwind. Use when the user asks to create a website, redesign a page, polish a section, fix mobile responsiveness, add premium components (hero, footer, CTA, client logos, certificates, app badges, WhatsApp button), or apply the Luxam-style luxury design DNA to another project.
+---
+
+# Premium Frontend Designer & Implementation Agent
+
+You are a senior frontend architect + UI/UX designer + implementation engineer.
+
+Your job: create production-ready, premium, cinematic, dark/gold luxury websites that feel high-end, trustworthy, and conversion-focused — the way the Luxam reference site does.
+
+This skill captures the design DNA, component patterns, prompt templates, and snippets so any future project can match the same quality bar.
+
+---
+
+## When to use this skill
+
+Auto-trigger whenever the user:
+- asks for a "premium", "luxury", "cinematic", "dark/gold", or "Luxam-style" design
+- creates or redesigns a page (homepage, about, services, contact, gallery, certifications, purchase-sale)
+- polishes typography, spacing, or motion
+- fixes mobile responsiveness
+- adds: WhatsApp link, app store buttons, client logos, certificate gallery, premium hero, premium footer
+- imports brand contact details into a layout
+- wants reusable React/Tailwind components in the Luxam style
+
+Refuse silently if the project explicitly uses a different design language (e.g. bright corporate, neobrutalist, retro 8-bit). In that case ask before applying this skill's DNA.
+
+---
+
+## Visual principles
+
+1. **Dark cinematic background** — obsidian-class blacks (`#08080A`), graphite layering (`#15161A` / `#1C1D22`). Never pure white. Never bright primary colors as backgrounds.
+2. **Gold/amber accents** — restrained, structural, single-tone gradient. Use on numbers, labels, dividers, hover states, hero highlights. Never bright yellow. Never multi-color rainbow gradients.
+3. **Editorial typography pairing**
+ - Serif (Cormorant Garamond / Playfair / Libre Baskerville) for hero H1 + section H2 only.
+ - Sans (Geist / Inter / Manrope / Satoshi) for nav, body, buttons, labels, metadata.
+ - No monospace on user-facing copy or long values.
+4. **Glass + grain** — semi-transparent `bg-bone/[0.03]` cards with `backdrop-blur`. Subtle noise/grain overlays to break flat surfaces.
+5. **Cinematic motion** — Framer Motion: slow, restrained. `cubic-bezier(0.16, 1, 0.3, 1)`, 0.8-1.2s entrance, `useReducedMotion()` respected.
+6. **Responsive from the start** — every layout works at 320 / 375 / 768 / 1024 / 1440 viewports.
+7. **No corporate basic** — no boxy stock layouts, no flat colorful cards, no generic stock-photo hero, no cheap icon dumps.
+
+Read `DESIGN_SYSTEM.md` for the full token palette + typography clamps.
+
+---
+
+## Coding principles
+
+1. **Inspect before changing.** Always read the existing files, lockfile, framework version, and existing primitives. Reuse — don't duplicate.
+2. **Preserve project identity.** Don't rewrite the whole brand for a small request.
+3. **Real content only.** Never invent links, social handles, certifications, addresses, phone numbers, or legal claims. Ask if missing.
+4. **External links** carry `target="_blank"` + `rel="noopener noreferrer"`.
+5. **Reusable primitives first.** Look for existing `Section`, `Container`, `Button`, `Reveal`, `SectionLabel`, `GlassCard` before writing new ones.
+6. **Clean imports.** Remove unused icons / helpers after edits.
+7. **One source of truth** for spacing — push to a shared `Section` primitive instead of overriding per page.
+8. **Typecheck after every change.** `npx tsc --noEmit` must pass.
+9. **No backwards-compat shims.** Don't leave `// removed` comments, dead aliases, or "for future" stubs.
+10. **No commented-out code** in committed work.
+11. **No emojis** in code or files unless user asks.
+
+Read `COMPONENT_RULES.md` for per-element rules (buttons, cards, footer, forms, icons).
+
+---
+
+## Accessibility requirements
+
+- All anchors have meaningful text or `aria-label`.
+- All interactive elements reachable by keyboard.
+- Focus-visible states: `focus-visible:border-gold/60 focus-visible:ring-2 focus-visible:ring-gold/40`.
+- Modal/lightbox: `role="dialog" aria-modal="true"`, `Escape` closes, scroll-lock on body.
+- Decorative SVGs: `aria-hidden`.
+- Color contrast: body text `text-bone` (≈ #F4F0E6) on obsidian = 16:1 ratio, well above WCAG AA.
+- `prefers-reduced-motion` respected via Framer's `useReducedMotion()` — disable transforms/parallax, keep opacity fades.
+
+---
+
+## Responsive requirements
+
+Test mentally (or in browser) at: **320, 375, 390, 414, 768, 1024, 1440**.
+
+- Hero h1 clamp: `clamp(2.4rem, 7vw, 6.4rem)` with `leading-[1.0]`.
+- Section padding: `py-16 md:py-20 lg:py-24` (uniform).
+- Anchored sections: `scroll-mt-24 md:scroll-mt-28` for sticky-nav clearance.
+- `body { overflow-x: hidden }` in `globals.css` as a global guard.
+- Sticky decorations (halos, watermarks, blurs) must not introduce horizontal scroll — use `overflow-hidden` on parent + `translate` instead of fixed widths.
+- Mobile cards stack `grid-cols-1 sm:grid-cols-2 lg:grid-cols-N`.
+
+Read `RESPONSIVE_CHECKLIST.md` before shipping any page.
+
+---
+
+## Output requirements
+
+Every meaningful change returns:
+
+1. **Files changed** — explicit list with `NEW` / `MODIFIED` / `DELETED` markers.
+2. **What was kept** vs **what was replaced** when redesigning.
+3. **Receipts** — `HTTP 200`, typecheck clean, key content rendered (grep output).
+4. **Responsive breakdown** — desktop / tablet / mobile behavior.
+5. **Confirmations** — explicit yes/no on every checklist item the user asked.
+6. **No placeholder leaks** — confirm zero `href="#"`, `href=""`, `href="/#"` remain in modified files.
+
+---
+
+## QA checklist (run before reporting done)
+
+```
+[ ] npx tsc --noEmit clean
+[ ] dev server HTTP 200 on every modified route
+[ ] grep zero placeholder hrefs in modified files
+[ ] grep zero hardcoded brand values that should be in lib/content.ts
+[ ] mobile (<640px) no horizontal overflow, hero not clipped, CTAs not cut
+[ ] tablet (≥640 <1024) grids transition cleanly to 2-col
+[ ] desktop (≥1024) spacing balanced, no orphan cards
+[ ] external links target="_blank" + rel="noopener noreferrer"
+[ ] focus-visible visible on every button/anchor
+[ ] reduced-motion heavy parallax/scale animations disabled
+[ ] no leftover console.log or commented-out code
+```
+
+---
+
+## Brand-specific config (Luxam reference)
+
+`examples/luxam-config.md` holds the exact Luxam contact details, WhatsApp URL, app store links, agency credit, etc. **Do not copy these values into other projects** — use them only as the shape pattern. Each new project gets its own `lib/content.ts` populated from real values the user provides.
+
+---
+
+## File map of this skill
+
+```
+SKILL.md — this file (entry point, principles, when to use)
+DESIGN_SYSTEM.md — color tokens, typography, spacing scale, motion
+COMPONENT_RULES.md — per-component rules (buttons, cards, footer, forms, icons)
+RESPONSIVE_CHECKLIST.md — pre-ship checklist for every viewport
+PROMPT_TEMPLATES.md — copy-paste prompts for common tasks
+COMPONENT_SNIPPETS.md — high-level component overview
+snippets/ — 8 reusable TSX component files
+examples/luxam-config.md — Luxam-specific values (reference, not boilerplate)
+```
+
+Read the relevant section(s) for the task at hand. Don't dump the whole skill into the user's reply — surface only the rules + snippets relevant to the change being made.
diff --git a/.claude/skills/premium-frontend-designer/examples/luxam-config.md b/.claude/skills/premium-frontend-designer/examples/luxam-config.md
new file mode 100644
index 0000000..b83e224
--- /dev/null
+++ b/.claude/skills/premium-frontend-designer/examples/luxam-config.md
@@ -0,0 +1,118 @@
+# Luxam Reference Config
+
+Concrete values used in the Luxam project. **Reference only** — do not paste into other projects unless the user explicitly says these are also their values.
+
+## `src/lib/content.ts`
+
+```ts
+export const brand = {
+ name: "LUXAM",
+ legalName: "Luxam Oils Trading LLC",
+ tagline: "Sustainable Energy. Refined.",
+ promise: "Converting waste into the fuel of tomorrow.",
+ phone: "04 262 3314",
+ email: "info@luxam.ae",
+ location: "United Arab Emirates",
+ instagram: "@luxamtrading",
+};
+
+export const nav = [
+ { label: "Home", href: "/" },
+ { label: "About us", href: "/about-us" },
+ { label: "Services", href: "/services" },
+ { label: "Purchase & Sale", href: "/purchase-sale" },
+ { label: "Gallery", href: "/gallery" },
+ { label: "Certifications", href: "/certifications" },
+ { label: "Contact us", href: "/contact-us" },
+];
+
+export const socials = {
+ instagram: "https://www.instagram.com/luxamtrading/",
+ whatsapp:
+ "https://api.whatsapp.com/send/?phone=971527312190&text&type=phone_number&app_absent=0",
+ whatsappDisplay: "+971 52 731 2190",
+};
+
+export const app = {
+ googlePlay: "https://play.google.com/store/apps/details?id=com.lootah.luxam",
+ appStore: "https://apps.apple.com/ae/app/luxam/id6740183015",
+};
+
+export const credit = {
+ agency: "YS Lootah Tech",
+ url: "https://yslootahtech.com/",
+};
+```
+
+## Footer link cluster
+
+```ts
+const navigationLinks = [
+ { label: "Home", href: "/" },
+ { label: "About us", href: "/about-us" },
+ { label: "Services", href: "/services" },
+ { label: "Purchase & Sale", href: "/purchase-sale" },
+ { label: "Gallery", href: "/gallery" },
+ { label: "Certifications", href: "/certifications" },
+ { label: "Contact us", href: "/contact-us" },
+];
+
+const serviceItems = [
+ { label: "UCO Collection", href: "/services" },
+ { label: "Logistics & Handling", href: "/services" },
+ { label: "Recycling & Feedstock", href: "/services" },
+ { label: "Compliance & Documentation", href: "/certifications" },
+ { label: "Partner with us", href: "/contact-us" },
+];
+
+const legalLinks = [{ label: "Privacy Policy", href: "/privacy-policy" }];
+```
+
+## Deployment (Coolify)
+
+```
+Coolify project luxam (uuid h0840c84kgo0g4cgwg0os88c)
+ env production uuid s4ow44cwgo08g88g04gwkkcs
+Application uuid zc4s4k4k0c44c8cs8oc8so4k
+build_pack dockerfile
+dockerfile_location /Dockerfile
+ports_exposes 3000
+fqdn https://luxamnew.yslootahtech.com
+DNS A record luxamnew → 51.255.193.254 (DNS only)
+```
+
+Git remote:
+
+```
+origin https://git.devxsupport.com/mohammad/luxam-web.git (main)
+```
+
+Token policy: never commit. Use `COOLIFY_TOKEN` env var when scripting deploys.
+
+## Dockerfile pattern
+
+Multi-stage:
+1. `deps` (node:22-alpine, `apk add libc6-compat`, `npm ci`)
+2. `build` (`next build` w/ `output: "standalone"`)
+3. `run` (non-root UID 1001, copies `.next/standalone` + `.next/static` + `public`, `CMD ["node","server.js"]`)
+
+`.dockerignore` skips `.git`, `node_modules`, `.next/cache`, `.env*`, `.claude`.
+
+## ISCC certificate facts (Luxam-specific)
+
+Use only as a precedent for how to surface certificate metadata. Do not copy into other projects.
+
+```
+Certificate number EU-ISCC-Cert-DE100-27002125
+Standard ISCC EU
+Framework RED III (Directive (EU) 2023/2413)
+Issuer SGS Germany GmbH (Europa Allee 12, D-49685 Emstek, Germany)
+Certified entity Luxam Oils Trading LLC
+Site Al Ttay – Al Khawaneej, Dubai, UAE
+Scope Collecting point, warehouse
+Material UCO (entirely of vegetable origin)
+Valid from 11 August 2025
+Valid to 10 August 2026
+```
+
+For any new project that surfaces compliance docs, follow the same data shape: number, standard, issuer, certified entity, site, scope, material, validity dates. Pull only from official documents — never invent.
diff --git a/.claude/skills/premium-frontend-designer/snippets/AppBadges.tsx b/.claude/skills/premium-frontend-designer/snippets/AppBadges.tsx
new file mode 100644
index 0000000..be32a14
--- /dev/null
+++ b/.claude/skills/premium-frontend-designer/snippets/AppBadges.tsx
@@ -0,0 +1,71 @@
+/**
+ * Official App Store + Google Play badge anchors.
+ *
+ * Setup steps:
+ * 1. Download official SVGs (use the /show/ path which returns clean SVG):
+ * https://www.svgrepo.com/show/303128/download-on-the-app-store-apple-logo.svg
+ * https://www.svgrepo.com/show/303139/google-play-badge-logo.svg
+ * 2. Save to public/images/app-store-badge.svg + public/images/google-play-badge.svg.
+ * 3. Add to lib/content.ts:
+ * export const app = {
+ * googlePlay: "https://play.google.com/store/apps/details?id=...",
+ * appStore: "https://apps.apple.com/ae/app/.../id...",
+ * };
+ *
+ * next/image blocks raw SVG by default in Next 16 — keep plain
.
+ */
+import { app } from "@/lib/content";
+
+type Props = {
+ store: "appstore" | "googleplay";
+ small?: boolean;
+};
+
+export function AppBadge({ store, small }: Props) {
+ const isApple = store === "appstore";
+ const href = isApple ? app.appStore : app.googlePlay;
+ const src = isApple
+ ? "/images/app-store-badge.svg"
+ : "/images/google-play-badge.svg";
+ const alt = isApple ? "Download on the App Store" : "Get it on Google Play";
+ const label = isApple
+ ? "Download on the App Store"
+ : "Get it on Google Play";
+ const width = small ? 132 : 160;
+
+ return (
+
+ {/* eslint-disable-next-line @next/next/no-img-element */}
+
+
+ );
+}
+
+/** Both badges in a vertical stack. Use in footer Legal column. */
+export function AppBadgeStack({ small }: { small?: boolean }) {
+ return (
+
+ );
+}
diff --git a/.claude/skills/premium-frontend-designer/snippets/CertificateGallery.tsx b/.claude/skills/premium-frontend-designer/snippets/CertificateGallery.tsx
new file mode 100644
index 0000000..be5b5da
--- /dev/null
+++ b/.claude/skills/premium-frontend-designer/snippets/CertificateGallery.tsx
@@ -0,0 +1,125 @@
+"use client";
+
+/**
+ * 4-image certificate gallery — each tile links to a PDF in a new tab.
+ *
+ * Expected data shape:
+ * export type CertPage = {
+ * src: string; // /images/certifications/page.jpg
+ * alt: string;
+ * title: string; // ISCC Certificate 2025
+ * page: string; // Page 1 · Annex
+ * document: string; // ISCC Certificate
+ * href: string; // /documents/certifications/iscc.pdf OR upstream URL
+ * };
+ * export const certificatePages: CertPage[] = [ ... ];
+ */
+import Image from "next/image";
+import { ArrowUpRight, FileText } from "lucide-react";
+import { motion, type Variants } from "framer-motion";
+
+export type CertPage = {
+ src: string;
+ alt: string;
+ title: string;
+ page: string;
+ document: string;
+ href: string;
+};
+
+const grid: Variants = {
+ hidden: {},
+ visible: { transition: { staggerChildren: 0.08, delayChildren: 0.15 } },
+};
+const cell: Variants = {
+ hidden: { opacity: 0, y: 24, filter: "blur(6px)" },
+ visible: {
+ opacity: 1,
+ y: 0,
+ filter: "blur(0px)",
+ transition: { duration: 0.8, ease: [0.16, 1, 0.3, 1] },
+ },
+};
+
+export function CertificateGallery({ pages }: { pages: CertPage[] }) {
+ return (
+
+ {pages.map((p) => (
+
+
+
+ ))}
+
+ );
+}
+
+function CertCard({ src, alt, title, page, document, href }: CertPage) {
+ return (
+
+
+
+
+
+
+
+ {page}
+
+
+
+
+
+
+
+
+
+ {document}
+
+
+ {title}
+
+
+
+ Open PDF
+
+
+
+
+ );
+}
diff --git a/.claude/skills/premium-frontend-designer/snippets/ClientLogoMarquee.tsx b/.claude/skills/premium-frontend-designer/snippets/ClientLogoMarquee.tsx
new file mode 100644
index 0000000..bdbfdb7
--- /dev/null
+++ b/.claude/skills/premium-frontend-designer/snippets/ClientLogoMarquee.tsx
@@ -0,0 +1,132 @@
+"use client";
+
+/**
+ * Premium horizontal logo marquee.
+ *
+ * Setup:
+ * 1. globals.css must have:
+ * @keyframes marquee {
+ * 0% { transform: translateX(0); }
+ * 100% { transform: translateX(-50%); }
+ * }
+ * 2. Pass clients prop or create lib/clients.ts:
+ * export const clients = [
+ * { src: "/images/clients/brand-a.png", alt: "Brand A" },
+ * ...
+ * ];
+ */
+import Image from "next/image";
+import { useReducedMotion } from "framer-motion";
+
+export type Client = { src: string; alt: string };
+
+export function ClientLogoMarquee({
+ clients,
+ eyebrow = "Our Clients",
+ title,
+ subtitle,
+}: {
+ clients: Client[];
+ eyebrow?: string;
+ title: React.ReactNode;
+ subtitle?: React.ReactNode;
+}) {
+ const reduce = useReducedMotion();
+ const loop = [...clients, ...clients];
+
+ return (
+
+
+
+
+
+
+ {eyebrow}
+
+
+ {title}
+
+ {subtitle ? (
+
{subtitle}
+ ) : null}
+
+
+
+ {/* edge fades */}
+
+
+
+ {reduce ? (
+
+ ) : (
+
+ (e.currentTarget.style.animationPlayState = "paused")
+ }
+ onMouseLeave={(e) =>
+ (e.currentTarget.style.animationPlayState = "running")
+ }
+ >
+ {loop.map((c, i) => (
+
+ ))}
+
+ )}
+
+
+
+
+ );
+}
+
+function LogoTile({ client }: { client: Client }) {
+ return (
+
+ );
+}
+
+function ClientGrid({ clients }: { clients: Client[] }) {
+ return (
+
+ {clients.map((c) => (
+
+ ))}
+
+ );
+}
diff --git a/.claude/skills/premium-frontend-designer/snippets/Footer.tsx b/.claude/skills/premium-frontend-designer/snippets/Footer.tsx
new file mode 100644
index 0000000..f006c0a
--- /dev/null
+++ b/.claude/skills/premium-frontend-designer/snippets/Footer.tsx
@@ -0,0 +1,188 @@
+/**
+ * Premium 4-column footer w/ no duplicated nav links.
+ *
+ * Expected lib/content.ts shape:
+ *
+ * export const brand = {
+ * name: "BRAND",
+ * legalName: "Brand Legal LLC",
+ * phone: "00 000 0000",
+ * email: "info@example.com",
+ * instagram: "@brand_handle",
+ * };
+ * export const socials = {
+ * instagram: "https://www.instagram.com/brand_handle/",
+ * whatsapp: "https://api.whatsapp.com/send/?phone=000000000000&text&type=phone_number&app_absent=0",
+ * whatsappDisplay: "+00 00 000 0000",
+ * };
+ * export const credit = {
+ * agency: "YS Lootah Tech",
+ * url: "https://yslootahtech.com/",
+ * };
+ */
+import { Mail, Phone } from "lucide-react";
+import { brand, socials, credit } from "@/lib/content";
+import { WhatsAppLink } from "./WhatsAppLink";
+import { AppBadge } from "./AppBadges";
+
+function InstagramIcon({ className }: { className?: string }) {
+ return (
+
+ );
+}
+
+type Link = { label: string; href: string };
+
+type Props = {
+ navigationLinks: Link[];
+ serviceItems: Link[];
+ legalLinks: Link[];
+ /** Brand logo node (provide your own LogoMark) */
+ logo?: React.ReactNode;
+};
+
+export function Footer({ navigationLinks, serviceItems, legalLinks, logo }: Props) {
+ return (
+
+ );
+}
+
+function FooterCol({ title, links }: { title: string; links: Link[] }) {
+ return (
+
+ );
+}
diff --git a/.claude/skills/premium-frontend-designer/snippets/GlassCard.tsx b/.claude/skills/premium-frontend-designer/snippets/GlassCard.tsx
new file mode 100644
index 0000000..f39c9ec
--- /dev/null
+++ b/.claude/skills/premium-frontend-designer/snippets/GlassCard.tsx
@@ -0,0 +1,75 @@
+"use client";
+
+import type { LucideIcon } from "lucide-react";
+import type { ReactNode } from "react";
+
+type Props = {
+ Icon?: LucideIcon;
+ title: ReactNode;
+ body?: ReactNode;
+ href?: string;
+ external?: boolean;
+ className?: string;
+ /** Append custom inner content below the body */
+ children?: ReactNode;
+};
+
+export function GlassCard({
+ Icon,
+ title,
+ body,
+ href,
+ external,
+ className,
+ children,
+}: Props) {
+ const inner = (
+ <>
+ {/* hover amber radial glow */}
+
+ {Icon ? (
+
+
+
+ ) : null}
+
+ {title}
+
+ {body ? (
+
+ {body}
+
+ ) : null}
+ {children}
+ {/* gold underline sweep */}
+
+ >
+ );
+
+ const base = `group relative isolate h-full overflow-hidden rounded-2xl border border-bone/10 bg-graphite/40 p-6 backdrop-blur-sm transition-all duration-500 hover:-translate-y-1 hover:border-gold/30 hover:bg-graphite/60 md:p-7 ${className ?? ""}`;
+
+ if (href) {
+ return (
+
+ {inner}
+
+ );
+ }
+ return {inner}
;
+}
diff --git a/.claude/skills/premium-frontend-designer/snippets/PremiumButton.tsx b/.claude/skills/premium-frontend-designer/snippets/PremiumButton.tsx
new file mode 100644
index 0000000..259c969
--- /dev/null
+++ b/.claude/skills/premium-frontend-designer/snippets/PremiumButton.tsx
@@ -0,0 +1,40 @@
+"use client";
+
+import { cn } from "@/lib/cn";
+import { ArrowUpRight } from "lucide-react";
+import type { ComponentPropsWithoutRef } from "react";
+
+type Variant = "primary" | "ghost" | "outline";
+
+type Props = ComponentPropsWithoutRef<"a"> & {
+ variant?: Variant;
+ arrow?: boolean;
+};
+
+const base =
+ "relative inline-flex items-center gap-2 rounded-full px-7 py-3.5 text-sm font-medium tracking-wide transition-all duration-500";
+
+const variants: Record = {
+ primary:
+ "bg-gradient-to-r from-gold-light via-gold to-gold-deep text-obsidian shadow-[0_10px_40px_-12px_rgba(212,164,55,0.6)] hover:shadow-[0_18px_50px_-12px_rgba(242,194,91,0.8)]",
+ outline:
+ "border border-bone/20 text-bone hover:border-gold/60 hover:text-gold-light",
+ ghost: "text-bone hover:text-gold-light",
+};
+
+export function PremiumButton({
+ variant = "primary",
+ className,
+ children,
+ arrow = true,
+ ...rest
+}: Props) {
+ return (
+
+ {children}
+ {arrow ? (
+
+ ) : null}
+
+ );
+}
diff --git a/.claude/skills/premium-frontend-designer/snippets/SectionHeading.tsx b/.claude/skills/premium-frontend-designer/snippets/SectionHeading.tsx
new file mode 100644
index 0000000..66cd829
--- /dev/null
+++ b/.claude/skills/premium-frontend-designer/snippets/SectionHeading.tsx
@@ -0,0 +1,76 @@
+"use client";
+
+import { cn } from "@/lib/cn";
+import { motion, useReducedMotion, type Variants } from "framer-motion";
+import type { ReactNode } from "react";
+
+type Props = {
+ eyebrow?: string;
+ index?: string;
+ title: ReactNode;
+ /** The gold-accent phrase rendered inside the title — pass as JSX or separate prop. */
+ accent?: ReactNode;
+ subtitle?: ReactNode;
+ align?: "left" | "center";
+ className?: string;
+};
+
+export function SectionHeading({
+ eyebrow,
+ index,
+ title,
+ accent,
+ subtitle,
+ align = "left",
+ className,
+}: Props) {
+ const reduce = useReducedMotion();
+ const v: Variants = {
+ hidden: { opacity: 0, y: reduce ? 0 : 24, filter: reduce ? "blur(0px)" : "blur(6px)" },
+ visible: {
+ opacity: 1,
+ y: 0,
+ filter: "blur(0px)",
+ transition: { duration: 0.9, ease: [0.16, 1, 0.3, 1] },
+ },
+ };
+ return (
+
+ {eyebrow ? (
+
+ {index ? {index} : null}
+
+ {eyebrow}
+
+ ) : null}
+
+ {title}
+ {accent ? <> {accent}> : null}
+
+ {subtitle ? (
+
+ {subtitle}
+
+ ) : null}
+
+ );
+}
diff --git a/.claude/skills/premium-frontend-designer/snippets/WhatsAppLink.tsx b/.claude/skills/premium-frontend-designer/snippets/WhatsAppLink.tsx
new file mode 100644
index 0000000..2e5c7f3
--- /dev/null
+++ b/.claude/skills/premium-frontend-designer/snippets/WhatsAppLink.tsx
@@ -0,0 +1,88 @@
+/**
+ * Refined gold WhatsApp link.
+ *
+ * Use 3 surfaces:
+ * - (footer row)
+ * - (nav)
+ * - (contact card)
+ *
+ * URL format expected: https://api.whatsapp.com/send/?phone=COUNTRYCODE+DIGITS&text&type=phone_number&app_absent=0
+ * Phone in URL = digits only (no + or spaces). Display string = formatted "+CC XX XXX XXXX".
+ *
+ * lucide-react has no WhatsApp glyph → use this inline SVG.
+ */
+import type { SVGProps } from "react";
+
+export function WhatsAppIcon({ className, ...rest }: SVGProps) {
+ return (
+
+ );
+}
+
+type LinkProps = {
+ href: string;
+ display: string;
+ ariaLabel: string;
+ inline?: boolean; // true = footer row; false = larger contact-card row
+};
+
+export function WhatsAppLink({ href, display, ariaLabel, inline }: LinkProps) {
+ if (inline) {
+ return (
+
+
+ WhatsApp · {display}
+
+ );
+ }
+ return (
+
+
+
+
+
+ WhatsApp · {display}
+
+
+ );
+}
+
+type ButtonProps = {
+ href: string;
+ ariaLabel: string;
+ className?: string;
+};
+
+export function WhatsAppIconButton({ href, ariaLabel, className }: ButtonProps) {
+ return (
+
+
+
+ );
+}
diff --git a/.gitignore b/.gitignore
index 11c8a90..a070c9a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -37,3 +37,7 @@ next-env.d.ts
.vscode
/src/generated/prisma
+
+# Local design references — not part of project
+/references
+
diff --git a/YS Lootah Robotics final-1.png b/YS Lootah Robotics final-1.png
new file mode 100644
index 0000000..f21914e
Binary files /dev/null and b/YS Lootah Robotics final-1.png differ
diff --git a/public/images/robots/pudu-bellabot.svg b/public/images/robots/pudu-bellabot.svg
new file mode 100644
index 0000000..5bc36fd
--- /dev/null
+++ b/public/images/robots/pudu-bellabot.svg
@@ -0,0 +1,39 @@
+
diff --git a/public/images/robots/pudu-cc1.svg b/public/images/robots/pudu-cc1.svg
new file mode 100644
index 0000000..c8142d1
--- /dev/null
+++ b/public/images/robots/pudu-cc1.svg
@@ -0,0 +1,31 @@
+
diff --git a/public/images/robots/pudu-kettybot.svg b/public/images/robots/pudu-kettybot.svg
new file mode 100644
index 0000000..7e2b7b8
--- /dev/null
+++ b/public/images/robots/pudu-kettybot.svg
@@ -0,0 +1,35 @@
+
diff --git a/public/images/robots/pudu-pudubot.svg b/public/images/robots/pudu-pudubot.svg
new file mode 100644
index 0000000..287e02f
--- /dev/null
+++ b/public/images/robots/pudu-pudubot.svg
@@ -0,0 +1,29 @@
+
diff --git a/public/images/robots/unitree-a2.png b/public/images/robots/unitree-a2.png
new file mode 100644
index 0000000..53b0c93
Binary files /dev/null and b/public/images/robots/unitree-a2.png differ
diff --git a/public/images/robots/unitree-as2.png b/public/images/robots/unitree-as2.png
new file mode 100644
index 0000000..7629eaa
Binary files /dev/null and b/public/images/robots/unitree-as2.png differ
diff --git a/public/images/robots/unitree-b2.png b/public/images/robots/unitree-b2.png
new file mode 100644
index 0000000..f9fb8c4
Binary files /dev/null and b/public/images/robots/unitree-b2.png differ
diff --git a/public/images/robots/unitree-g1.png b/public/images/robots/unitree-g1.png
new file mode 100644
index 0000000..07d8373
Binary files /dev/null and b/public/images/robots/unitree-g1.png differ
diff --git a/public/images/robots/unitree-go2.png b/public/images/robots/unitree-go2.png
new file mode 100644
index 0000000..e8a3b61
Binary files /dev/null and b/public/images/robots/unitree-go2.png differ
diff --git a/public/images/robots/unitree-h2.png b/public/images/robots/unitree-h2.png
new file mode 100644
index 0000000..30ffccd
Binary files /dev/null and b/public/images/robots/unitree-h2.png differ
diff --git a/public/images/robots/unitree-r1.png b/public/images/robots/unitree-r1.png
new file mode 100644
index 0000000..089de12
Binary files /dev/null and b/public/images/robots/unitree-r1.png differ
diff --git a/src/app/about/page.tsx b/src/app/about/page.tsx
new file mode 100644
index 0000000..14d0714
--- /dev/null
+++ b/src/app/about/page.tsx
@@ -0,0 +1,55 @@
+import type { Metadata } from 'next';
+import { Navbar } from '@/components/Navbar';
+import { FooterAndContact } from '@/components/FooterAndContact';
+import { MotionSection } from '@/components/ui/MotionSection';
+import { DemoCTA } from '@/components/robotics/DemoCTA';
+import { WhyUs } from '@/components/robotics/WhyUs';
+import { FloatingTechPanel } from '@/components/robotics/FloatingTechPanel';
+
+export const metadata: Metadata = {
+ title: 'About YS Lootah Robotics — Exclusive UAE Access to Unitree & Pudu',
+ description:
+ 'YS Lootah Robotics holds exclusive UAE sales rights for selected Unitree and Pudu Robotics solutions — with a Dubai-based team managing sales, demo, configuration, and deployment.',
+};
+
+export default function AboutPage() {
+ return (
+ <>
+
+
+
+
+
+
About · Exclusive UAE Access
+
+ The UAE's dedicated destination for Unitree and Pudu Robotics.
+
+
+ YS Lootah Robotics is the robotics arm of the YS Lootah group — a UAE-based technology partner that holds exclusive sales rights in the UAE for selected Unitree and Pudu Robotics solutions. Our Dubai team manages sales, live demos, configuration, deployment, and ongoing service across the UAE.
+
+
+ Brand names and product trademarks are property of their respective owners. Available exclusively in the UAE through YS Lootah Robotics.
+
+
+
+
+
+
+
+
+
+
+ Why work with us
+
+
+
+
+
+
+
+
+
+
+ >
+ );
+}
diff --git a/src/app/admin/login/page.tsx b/src/app/admin/login/page.tsx
index e93b842..d30f307 100644
--- a/src/app/admin/login/page.tsx
+++ b/src/app/admin/login/page.tsx
@@ -1,172 +1,172 @@
-'use client';
-
-import { useState, FormEvent } from 'react';
-import { useRouter } from 'next/navigation';
-
-export default function AdminLoginPage() {
- const router = useRouter();
- const [username, setUsername] = useState('');
- const [password, setPassword] = useState('');
- const [error, setError] = useState('');
- const [loading, setLoading] = useState(false);
-
- const handleSubmit = async (e: FormEvent) => {
- e.preventDefault();
- setError('');
- setLoading(true);
- try {
- const res = await fetch('/api/admin/login/', {
- method: 'POST',
- headers: { 'Content-Type': 'application/json' },
- body: JSON.stringify({ username, password }),
- });
- const data = await res.json();
- if (res.ok) {
- router.push('/admin/');
- router.refresh();
- } else {
- setError(data.error ?? 'Login failed');
- }
- } catch {
- setError('Network error. Please try again.');
- } finally {
- setLoading(false);
- }
- };
-
- return (
-
-
-
-
- 🔐
-
-
- Admin Login
-
-
- Lootah Robotics — G1 Configurator
-
-
-
-
-
-
- );
-}
-
-const pageStyle: React.CSSProperties = {
- minHeight: '100vh',
- background: '#ffffff',
- display: 'flex',
- alignItems: 'center',
- justifyContent: 'center',
- padding: '2rem',
- fontFamily: 'system-ui, -apple-system, sans-serif',
-};
-
-const cardStyle: React.CSSProperties = {
- width: '100%',
- maxWidth: '380px',
- background: 'rgba(255, 255, 255, 0.95)',
- backdropFilter: 'blur(20px)',
- border: '1px solid rgba(0, 0, 0, 0.06)',
- borderRadius: '1rem',
- padding: '2rem',
-};
-
-const labelStyle: React.CSSProperties = {
- display: 'block',
- fontSize: '0.75rem',
- fontWeight: 600,
- color: '#374151',
- marginBottom: '0.375rem',
- letterSpacing: '0.02em',
-};
-
-const inputStyle: React.CSSProperties = {
- width: '100%',
- padding: '0.6rem 0.875rem',
- borderRadius: '0.5rem',
- border: '1px solid rgba(0, 0, 0, 0.1)',
- background: '#ffffff',
- color: '#1a1a2e',
- fontSize: '0.875rem',
- outline: 'none',
- transition: 'border-color 0.2s ease',
- boxSizing: 'border-box',
-};
+'use client';
+
+import { useState, FormEvent } from 'react';
+import { useRouter } from 'next/navigation';
+
+export default function AdminLoginPage() {
+ const router = useRouter();
+ const [username, setUsername] = useState('');
+ const [password, setPassword] = useState('');
+ const [error, setError] = useState('');
+ const [loading, setLoading] = useState(false);
+
+ const handleSubmit = async (e: FormEvent) => {
+ e.preventDefault();
+ setError('');
+ setLoading(true);
+ try {
+ const res = await fetch('/api/admin/login/', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ username, password }),
+ });
+ const data = await res.json();
+ if (res.ok) {
+ router.push('/admin/');
+ router.refresh();
+ } else {
+ setError(data.error ?? 'Login failed');
+ }
+ } catch {
+ setError('Network error. Please try again.');
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ return (
+
+
+
+
+ 🔐
+
+
+ Admin Login
+
+
+ Lootah Robotics — G1 Configurator
+
+
+
+
+
+
+ );
+}
+
+const pageStyle: React.CSSProperties = {
+ minHeight: '100vh',
+ background: '#ffffff',
+ display: 'flex',
+ alignItems: 'center',
+ justifyContent: 'center',
+ padding: '2rem',
+ fontFamily: 'system-ui, -apple-system, sans-serif',
+};
+
+const cardStyle: React.CSSProperties = {
+ width: '100%',
+ maxWidth: '380px',
+ background: 'rgba(255, 255, 255, 0.95)',
+ backdropFilter: 'blur(20px)',
+ border: '1px solid rgba(0, 0, 0, 0.06)',
+ borderRadius: '1rem',
+ padding: '2rem',
+};
+
+const labelStyle: React.CSSProperties = {
+ display: 'block',
+ fontSize: '0.75rem',
+ fontWeight: 600,
+ color: '#374151',
+ marginBottom: '0.375rem',
+ letterSpacing: '0.02em',
+};
+
+const inputStyle: React.CSSProperties = {
+ width: '100%',
+ padding: '0.6rem 0.875rem',
+ borderRadius: '0.5rem',
+ border: '1px solid rgba(0, 0, 0, 0.1)',
+ background: '#ffffff',
+ color: '#0a0907',
+ fontSize: '0.875rem',
+ outline: 'none',
+ transition: 'border-color 0.2s ease',
+ boxSizing: 'border-box',
+};
diff --git a/src/app/admin/page.tsx b/src/app/admin/page.tsx
index 52fb41d..8097426 100644
--- a/src/app/admin/page.tsx
+++ b/src/app/admin/page.tsx
@@ -488,7 +488,7 @@ export default function AdminPage() {
new Date(ts * 1000).toLocaleDateString('en-AE', { day: 'numeric', month: 'short', year: 'numeric' });
if (!isPricingHydrated) {
- return ;
+ return ;
}
return (
@@ -497,10 +497,10 @@ export default function AdminPage() {
{/* HEADER */}
-
+
Admin Dashboard
-
Lootah Robotics G1 Configurator
+
Lootah Robotics G1 Configurator
@@ -527,7 +527,7 @@ export default function AdminPage() {
borderRadius: '0.375rem',
border: 'none',
background: activeTab === t ? 'rgba(59,130,246,0.08)' : 'transparent',
- color: activeTab === t ? '#2563eb' : '#64748b',
+ color: activeTab === t ? '#2563eb' : '#6b6862',
fontSize: '0.8rem',
fontWeight: activeTab === t ? 600 : 400,
cursor: 'pointer',
@@ -558,9 +558,9 @@ export default function AdminPage() {
aria-label={`Label for ${item.label}`}
/>
-
{item.id}
+
{item.id}
-
AED
+
AED
{
const f = e.target.files?.[0] ?? null;
@@ -642,7 +642,7 @@ export default function AdminPage() {
background: addItemGlb ? 'rgba(59,130,246,0.04)' : '#fff',
cursor: 'pointer',
fontSize: '0.8rem',
- color: addItemGlb ? '#2563eb' : '#94a3b8',
+ color: addItemGlb ? '#2563eb' : '#94908a',
transition: 'all 0.2s',
}}>
{ e.preventDefault(); setAddItemGlb(null); }}
- style={{ marginLeft: 'auto', background: 'none', border: 'none', cursor: 'pointer', color: '#94a3b8', fontSize: '0.75rem', padding: '0 2px' }}
+ style={{ marginLeft: 'auto', background: 'none', border: 'none', cursor: 'pointer', color: '#94908a', fontSize: '0.75rem', padding: '0 2px' }}
>✕
)}
@@ -686,7 +686,7 @@ export default function AdminPage() {
{activeTab === 'personas' && (
{!isPersonaHydrated ? (
-
Loading personas…
+
Loading personas…
) : (
@@ -694,15 +694,15 @@ export default function AdminPage() {
{p.label}
-
{p.description}
+
{p.description}
-
{p.colors.torso}
+
{p.colors.torso}
-
{p.colors.legs}
+
{p.colors.legs}
{p.id !== 'none' && (
@@ -762,7 +762,7 @@ export default function AdminPage() {
{ordersError &&
{ordersError}
}
{!ordersLoading && orders.length === 0 && !ordersError && (
-
No orders found.
+
No orders found.
)}
{orders.length > 0 && (
@@ -791,7 +791,7 @@ export default function AdminPage() {
{contactsError && {contactsError}
}
{!contactsLoading && contacts.length === 0 && !contactsError && (
- No contact inquiries yet.
+ No contact inquiries yet.
)}
{contacts.length > 0 && (
@@ -799,10 +799,10 @@ export default function AdminPage() {
{contacts.map((c, i) => (
{c.name}
-
-
+
+
{c.message}
-
{new Date(c.createdAt).toLocaleDateString('en-AE')}
+
{new Date(c.createdAt).toLocaleDateString('en-AE')}
))}
@@ -813,15 +813,15 @@ export default function AdminPage() {
{/* SETTINGS TAB */}
{activeTab === 'settings' && (
-
App Settings
+
App Settings
{settingError &&
{settingError}
}
{settingsLoading ? (
-
Loading…
+
Loading…
) : (
{settings.length === 0 && (
- No settings yet.
+ No settings yet.
)}
{settings.map((s, i) => (
- Add Setting
+
+
Add Setting
@@ -869,7 +869,7 @@ export default function AdminPage() {
{showPwModal && (
-
Change Password
+
Change Password
{(['current', 'next', 'confirm'] as const).map((field) => (
@@ -918,7 +918,7 @@ function SettingRow({
useEffect(() => { setEditVal(setting.value); }, [setting.value]);
return (
-
0 ? '1px solid rgba(0,0,0,0.04)' : 'none' }}>
+
0 ? '1px solid rgba(0,0,0,0.04)' : 'none' }}>
{setting.key}
{name}
- {email &&
{email}
}
-
{order.id}
+ {email &&
{email}
}
+
{order.id}
{formatAmount(order.amount, order.currency)}
@@ -1008,17 +1008,17 @@ function OrderRow({
fontSize: '0.65rem',
fontWeight: 600,
textTransform: 'uppercase',
- background: order.status === 'succeeded' ? 'rgba(34,197,94,0.1)' : order.status === 'canceled' ? 'rgba(239,68,68,0.08)' : 'rgba(148,163,184,0.15)',
- color: order.status === 'succeeded' ? '#16a34a' : order.status === 'canceled' ? '#dc2626' : '#64748b',
+ background: order.status === 'succeeded' ? 'rgba(34,197,94,0.1)' : order.status === 'canceled' ? 'rgba(239,68,68,0.08)' : 'rgba(196, 162, 101,0.15)',
+ color: order.status === 'succeeded' ? '#16a34a' : order.status === 'canceled' ? '#dc2626' : '#6b6862',
}}>
{order.status}
-
{formatDate(order.created)}
+
{formatDate(order.created)}
@@ -1073,16 +1073,16 @@ function OrderRow({
))}
- Total
-
+ Total
+
{formatAmount(order.amount, order.currency)}
) : (
- Total (legacy order)
-
+ Total (legacy order)
+
{formatAmount(order.amount, order.currency)}
@@ -1090,16 +1090,16 @@ function OrderRow({
{/* Payment ID */}
-
{/* Right: snapshot */}
-
Robot Snapshot
+
Robot Snapshot
{snapshot === 'loading' && (
-
Loading…
+
Loading…
)}
{snapshot && snapshot !== 'loading' && snapshot !== 'none' && (
/* eslint-disable-next-line @next/next/no-img-element */
@@ -1110,7 +1110,7 @@ function OrderRow({
/>
)}
{snapshot === 'none' && (
-
No snapshot
+
No snapshot
)}
@@ -1122,7 +1122,7 @@ function OrderRow({
function SectionBox({ title, children }: { title: string; children: React.ReactNode }) {
return (
-
{title}
+
{title}
{children}
);
@@ -1138,7 +1138,7 @@ function InfoField({ label, value }: { label: string; value?: string | null }) {
if (!value) return null;
return (
-
{label}
+
{label}
{value}
);
@@ -1147,8 +1147,8 @@ function InfoField({ label, value }: { label: string; value?: string | null }) {
function StatCard({ label, value }: { label: string; value: string }) {
return (
-
{label}
-
{value}
+
{label}
+
{value}
);
}
@@ -1165,7 +1165,7 @@ function TableHeader({ cols, labels }: { cols: string; labels: string[] }) {
return (
{labels.map((l) => (
- {l}
+ {l}
))}
);
@@ -1204,7 +1204,7 @@ const formInputStyle: React.CSSProperties = {
borderRadius: '0.375rem',
border: '1px solid rgba(0,0,0,0.1)',
background: '#ffffff',
- color: '#1a1a2e',
+ color: '#0a0907',
fontSize: '0.8rem',
outline: 'none',
boxSizing: 'border-box',
@@ -1216,7 +1216,7 @@ const tableInputStyle: React.CSSProperties = {
borderRadius: '0.375rem',
border: '1px solid rgba(0,0,0,0.1)',
background: '#ffffff',
- color: '#1a1a2e',
+ color: '#0a0907',
fontSize: '0.8rem',
fontFamily: 'monospace',
textAlign: 'right' as const,
diff --git a/src/app/book-demo/page.tsx b/src/app/book-demo/page.tsx
new file mode 100644
index 0000000..eec4658
--- /dev/null
+++ b/src/app/book-demo/page.tsx
@@ -0,0 +1,56 @@
+import type { Metadata } from 'next';
+import { Navbar } from '@/components/Navbar';
+import { FooterAndContact } from '@/components/FooterAndContact';
+import { InquiryForm } from '@/components/robotics/InquiryForm';
+
+export const metadata: Metadata = {
+ title: 'Book a Robotics Demo in Dubai — YS Lootah Robotics',
+ description:
+ 'Book a live robot demo at our Dubai showroom or at your venue. See selected Unitree and Pudu Robotics solutions in action — available exclusively in the UAE through YS Lootah Robotics.',
+};
+
+export default function BookDemoPage() {
+ return (
+ <>
+
+
+
+
+
+
Book a live demo · Dubai showroom
+
+ See the future in person.
+
+
+ Book a live robot demo at our Dubai showroom or schedule an on-site demo at your venue. Our team will tailor the demo to your use case before you arrive.
+
+
+
+ {[
+ 'Choose a humanoid, quadruped, or service robot to see live',
+ 'Designed around your industry — restaurant, mall, hotel, security, etc.',
+ 'Walk through configuration and deployment options',
+ 'Get UAE-specific pricing and availability',
+ ].map((b) => (
+ -
+
+ {b}
+
+ ))}
+
+
+
+
+
+ Demo request
+
Tell us when and where
+
+
+
+
+
+
+
+ >
+ );
+}
diff --git a/src/app/brands/page.tsx b/src/app/brands/page.tsx
new file mode 100644
index 0000000..75509a2
--- /dev/null
+++ b/src/app/brands/page.tsx
@@ -0,0 +1,95 @@
+import type { Metadata } from 'next';
+import { Navbar } from '@/components/Navbar';
+import { FooterAndContact } from '@/components/FooterAndContact';
+import { BRANDS, ROBOTS, type RobotBrand } from '@/data/robots';
+import { RobotProductCard } from '@/components/robotics/RobotProductCard';
+import { MotionSection } from '@/components/ui/MotionSection';
+import { DemoCTA } from '@/components/robotics/DemoCTA';
+
+export const metadata: Metadata = {
+ title: 'Robotics Brands — Unitree & Pudu | Exclusive UAE Access via YS Lootah Robotics',
+ description:
+ 'Selected Unitree and Pudu Robotics solutions — available exclusively in the UAE through YS Lootah Robotics. Humanoid, quadruped, service, delivery, and cleaning robots.',
+};
+
+const ORDER: RobotBrand[] = ['unitree', 'pudu'];
+
+export default function BrandsPage() {
+ return (
+ <>
+
+
+
+
+
+
Exclusive UAE Access · Dubai
+
+
+ Selected Unitree and Pudu solutions — exclusively in the UAE.
+
+
+
+ YS Lootah Robotics holds exclusive UAE sales rights for selected Unitree and Pudu Robotics solutions — with on-the-ground sales, demo, and deployment support across Dubai and the UAE.
+
+
+ Brand names and product trademarks are property of their respective owners. Available exclusively in the UAE through YS Lootah Robotics.
+
+
+
+ {ORDER.map((id) => {
+ const brand = BRANDS[id];
+ const robots = ROBOTS.filter((r) => r.brand === id);
+ return (
+
+
+
+
+ {brand.name.split(' ')[0]} {brand.name.split(' ').slice(1).join(' ')}
+
+
+ {robots.length} model{robots.length === 1 ? '' : 's'}
+
+
+
+ {brand.description}
+
+
+
+ {robots.map((r) => (
+
+ ))}
+
+
+
+ );
+ })}
+
+
+
+
+
+
+ >
+ );
+}
diff --git a/src/app/configure/page.tsx b/src/app/configure/page.tsx
index 9d3e37f..40f4162 100644
--- a/src/app/configure/page.tsx
+++ b/src/app/configure/page.tsx
@@ -1,20 +1,50 @@
-'use client';
-
-import { ConfiguratorSection } from '@/components/ConfiguratorSection';
-import { Navbar } from '@/components/Navbar';
-import { FooterAndContact } from '@/components/FooterAndContact';
-
-export default function ConfigurePage() {
- return (
- <>
-
-
- {/* Configurator section takes up full height minus navbar height roughly, or we just let it take its normal height */}
-
-
-
-
-
- >
- );
-}
+'use client';
+
+import { ConfiguratorSection } from '@/components/ConfiguratorSection';
+import { Navbar } from '@/components/Navbar';
+import { FooterAndContact } from '@/components/FooterAndContact';
+
+export default function ConfigurePage() {
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+ >
+ );
+}
diff --git a/src/app/contact/page.tsx b/src/app/contact/page.tsx
new file mode 100644
index 0000000..c71b3ae
--- /dev/null
+++ b/src/app/contact/page.tsx
@@ -0,0 +1,72 @@
+import type { Metadata } from 'next';
+import { Navbar } from '@/components/Navbar';
+import { FooterAndContact } from '@/components/FooterAndContact';
+import { InquiryForm } from '@/components/robotics/InquiryForm';
+
+export const metadata: Metadata = {
+ title: 'Contact YS Lootah Robotics Dubai — Robotics Sales & Demo Inquiries',
+ description:
+ 'Dubai robotics sales, support, and demo inquiries. Contact YS Lootah Robotics — the exclusive UAE destination for selected Unitree and Pudu Robotics solutions — by phone, email, or WhatsApp.',
+};
+
+export default function ContactPage() {
+ return (
+ <>
+
+
+
+
+
+
Contact · Dubai · UAE
+
+ Talk to our Dubai robotics team.
+
+
+ Tell us about your venue, timeline, and use case. We will recommend a robot, share availability, and book a live demo at our Dubai showroom.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Inquiry form
+
Send us a message
+
+
+
+
+
+
+
+ >
+ );
+}
+
+function ContactRow({ label, value, href, external = false }: { label: string; value: string; href: string; external?: boolean }) {
+ return (
+
+ {label}
+ {value}
+
+ );
+}
diff --git a/src/app/globals.css b/src/app/globals.css
index cb435dc..e7898a7 100644
--- a/src/app/globals.css
+++ b/src/app/globals.css
@@ -1,24 +1,46 @@
@import "tailwindcss";
@theme {
- /* Light Mode Color Palette */
- --color-primary: #ffffff;
- --color-secondary: #f8f8f6;
- --color-accent: #3b82f6;
- --color-accent-hover: #2563eb;
+ /* === Luxury robotics — Black + Gold === */
+ --color-bg: #050505;
+ --color-bg-2: #0a0a0c;
+ --color-bg-3: #111114;
+ --color-bg-4: #18181c;
+ --color-surface: rgba(20, 18, 14, 0.7);
+ --color-primary: #050505;
+ --color-secondary: #0a0a0c;
+
+ /* Gold spectrum (matches YS Lootah brand) */
--color-gold: #c4a265;
- --color-text-primary: #1a1a2e;
- --color-text-secondary: #64748b;
- --color-text-muted: #94a3b8;
- --color-border: #e2e8f0;
- --color-border-light: #cbd5e1;
+ --color-gold-light: #e0c896;
+ --color-gold-rich: #d4af6a;
+ --color-gold-bronze: #8b6f47;
+ --color-gold-deep: #6b5436;
- /* Glassmorphism Colors - Light */
- --color-glass-bg: rgba(255, 255, 255, 0.85);
- --color-glass-border: rgba(0, 0, 0, 0.08);
- --color-glass-highlight: rgba(255, 255, 255, 0.5);
+ /* Accent aliases */
+ --color-accent: #c4a265;
+ --color-accent-2: #d4af6a;
+ --color-accent-3: #8b6f47;
+ --color-accent-hover: #d4af6a;
- /* Spacing & Sizing */
+ /* Text */
+ --color-text-primary: #f5f1e8;
+ --color-text-secondary: #cbc4b3;
+ --color-text-muted: #94908a;
+ --color-text-dim: #6b6862;
+
+ /* Borders */
+ --color-border: rgba(196, 162, 101, 0.18);
+ --color-border-strong: rgba(196, 162, 101, 0.36);
+ --color-border-light: rgba(196, 162, 101, 0.08);
+ --color-border-neutral: rgba(245, 241, 232, 0.08);
+
+ /* Glass */
+ --color-glass-bg: rgba(20, 18, 14, 0.55);
+ --color-glass-border: rgba(196, 162, 101, 0.22);
+ --color-glass-highlight: rgba(245, 241, 232, 0.05);
+
+ /* Spacing */
--spacing-xs: 0.25rem;
--spacing-sm: 0.5rem;
--spacing-md: 1rem;
@@ -26,15 +48,17 @@
--spacing-xl: 2rem;
--spacing-2xl: 3rem;
- /* Border Radius */
+ /* Radius */
--radius-sm: 0.375rem;
--radius-md: 0.5rem;
--radius-lg: 0.75rem;
--radius-xl: 1rem;
+ --radius-2xl: 1.5rem;
/* Shadows */
- --shadow-glow: 0 2px 20px rgba(0, 0, 0, 0.06);
- --shadow-glow-lg: 0 4px 40px rgba(0, 0, 0, 0.08);
+ --shadow-glow: 0 0 30px rgba(196, 162, 101, 0.22);
+ --shadow-glow-lg: 0 0 60px rgba(196, 162, 101, 0.28);
+ --shadow-card: 0 14px 50px rgba(0, 0, 0, 0.55);
/* Transitions */
--transition-fast: 150ms ease;
@@ -42,101 +66,165 @@
--transition-slow: 300ms ease;
}
-/* Base Styles */
html,
body {
margin: 0;
padding: 0;
min-height: 100vh;
- background-color: var(--color-primary);
+ background-color: var(--color-bg);
color: var(--color-text-primary);
font-family: 'Inter', system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
overflow-x: hidden;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+
+body {
+ background:
+ radial-gradient(1200px 700px at 80% -10%, rgba(196, 162, 101, 0.10), transparent 60%),
+ radial-gradient(900px 500px at -10% 30%, rgba(196, 162, 101, 0.06), transparent 60%),
+ radial-gradient(800px 500px at 50% 110%, rgba(139, 111, 71, 0.10), transparent 60%),
+ linear-gradient(180deg, #030303 0%, #050505 50%, #030303 100%);
+ background-attachment: fixed;
}
-/* Scroll Snap */
html {
scroll-behavior: smooth;
- scroll-snap-type: y mandatory;
}
-/* Focus Styles for Accessibility */
:focus-visible {
- outline: 2px solid var(--color-accent);
+ outline: 2px solid var(--color-gold);
outline-offset: 2px;
}
-/* Selection Styles */
::selection {
- background-color: var(--color-accent);
+ background-color: rgba(196, 162, 101, 0.4);
color: #ffffff;
}
-/* Glassmorphism Utilities - Light */
+/* === Glassmorphism === */
+.glass {
+ background: var(--color-glass-bg);
+ backdrop-filter: blur(18px);
+ -webkit-backdrop-filter: blur(18px);
+ border: 1px solid var(--color-glass-border);
+ box-shadow: var(--shadow-card);
+}
+
.glass-panel {
background: var(--color-glass-bg);
- backdrop-filter: blur(16px);
- -webkit-backdrop-filter: blur(16px);
+ backdrop-filter: blur(20px);
+ -webkit-backdrop-filter: blur(20px);
border: 1px solid var(--color-glass-border);
- box-shadow: var(--shadow-glow);
+ box-shadow: var(--shadow-card);
}
.glass-panel-highlight {
- background: linear-gradient(
- 135deg,
- var(--color-glass-highlight) 0%,
- transparent 50%
- );
+ background: linear-gradient(135deg, var(--color-glass-highlight) 0%, transparent 60%);
}
-/* Hero animated gradient - Light */
+/* === Typography gradients === */
+.text-gradient {
+ background: linear-gradient(135deg, #ffffff 0%, #f5e9c8 40%, #d4af6a 100%);
+ -webkit-background-clip: text;
+ background-clip: text;
+ -webkit-text-fill-color: transparent;
+ color: transparent;
+}
+
+.text-gradient-accent {
+ background: linear-gradient(135deg, #e0c896 0%, #c4a265 50%, #8b6f47 100%);
+ -webkit-background-clip: text;
+ background-clip: text;
+ -webkit-text-fill-color: transparent;
+ color: transparent;
+}
+
+.text-gold {
+ color: var(--color-gold);
+}
+
+/* Metallic gold border */
+.metallic-border {
+ position: relative;
+}
+.metallic-border::before {
+ content: '';
+ position: absolute;
+ inset: 0;
+ border-radius: inherit;
+ padding: 1px;
+ background: linear-gradient(135deg, rgba(224, 200, 150, 0.6), rgba(196, 162, 101, 0.25) 45%, rgba(139, 111, 71, 0.0) 100%);
+ -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
+ -webkit-mask-composite: xor;
+ mask-composite: exclude;
+ pointer-events: none;
+}
+
+/* === Hero animated gradient === */
.hero-gradient {
position: absolute;
inset: 0;
- background: radial-gradient(ellipse 80% 60% at 50% 40%, rgba(59, 130, 246, 0.04) 0%, transparent 60%),
- radial-gradient(ellipse 60% 50% at 30% 70%, rgba(196, 162, 101, 0.03) 0%, transparent 50%),
- linear-gradient(180deg, #f0f0ec 0%, #e8e8e4 50%, #f0f0ec 100%);
- animation: heroShift 12s ease-in-out infinite alternate;
+ background:
+ radial-gradient(ellipse 70% 60% at 60% 40%, rgba(196, 162, 101, 0.20) 0%, transparent 60%),
+ radial-gradient(ellipse 60% 50% at 20% 70%, rgba(139, 111, 71, 0.18) 0%, transparent 55%),
+ radial-gradient(ellipse 80% 70% at 80% 100%, rgba(224, 200, 150, 0.14) 0%, transparent 60%),
+ linear-gradient(180deg, #050505 0%, #070605 50%, #030303 100%);
+ animation: heroShift 16s ease-in-out infinite alternate;
}
@keyframes heroShift {
- 0% {
- background-position: 0% 0%, 0% 0%, 0% 0%;
- opacity: 1;
- }
- 50% {
- opacity: 0.9;
- }
- 100% {
- background-position: 100% 100%, 100% 0%, 0% 0%;
- opacity: 1;
- }
+ 0% { background-position: 0% 0%, 0% 0%, 0% 0%, 0% 0%; }
+ 100% { background-position: 100% 100%, 80% 0%, 0% 100%, 0% 0%; }
}
-/* Fade in up animation */
-.fade-in-up {
- animation: fadeInUp 0.8s cubic-bezier(0.16, 1, 0.3, 1) both;
+/* Grid overlay */
+.grid-overlay {
+ position: absolute;
+ inset: 0;
+ background-image:
+ linear-gradient(rgba(196, 162, 101, 0.04) 1px, transparent 1px),
+ linear-gradient(90deg, rgba(196, 162, 101, 0.04) 1px, transparent 1px);
+ background-size: 48px 48px;
+ mask-image: radial-gradient(ellipse 60% 50% at 50% 40%, #000 30%, transparent 80%);
+ -webkit-mask-image: radial-gradient(ellipse 60% 50% at 50% 40%, #000 30%, transparent 80%);
+ pointer-events: none;
}
+/* === Animations === */
+.fade-in-up { animation: fadeInUp 0.8s cubic-bezier(0.16, 1, 0.3, 1) both; }
@keyframes fadeInUp {
- from {
- opacity: 0;
- transform: translateY(24px);
- }
- to {
- opacity: 1;
- transform: translateY(0);
- }
+ from { opacity: 0; transform: translateY(24px); }
+ to { opacity: 1; transform: translateY(0); }
}
-/* Scroll indicator - dark for light mode */
+.shimmer {
+ background: linear-gradient(110deg, transparent 35%, rgba(224, 200, 150, 0.12) 50%, transparent 65%);
+ background-size: 200% 100%;
+ animation: shimmer 3.5s linear infinite;
+}
+@keyframes shimmer { from { background-position: 200% 0; } to { background-position: -200% 0; } }
+
+.float-y { animation: floatY 6s ease-in-out infinite; }
+@keyframes floatY {
+ 0%, 100% { transform: translateY(0); }
+ 50% { transform: translateY(-12px); }
+}
+
+@keyframes spin { to { transform: rotate(360deg); } }
+
+@keyframes pulseGlow {
+ 0%, 100% { box-shadow: 0 0 0 0 rgba(196, 162, 101, 0.55), 0 0 40px rgba(196, 162, 101, 0.25); }
+ 50% { box-shadow: 0 0 0 12px rgba(196, 162, 101, 0), 0 0 60px rgba(196, 162, 101, 0.45); }
+}
+
+/* Scroll indicator */
.scroll-indicator {
width: 1px;
height: 40px;
position: relative;
overflow: hidden;
}
-
.scroll-indicator::after {
content: '';
position: absolute;
@@ -144,58 +232,111 @@ html {
left: 0;
width: 1px;
height: 100%;
- background: linear-gradient(180deg, #c4a265, transparent);
+ background: linear-gradient(180deg, var(--color-gold), transparent);
animation: scrollPulse 2s ease-in-out infinite;
}
-
@keyframes scrollPulse {
- 0%, 100% {
- transform: translateY(-100%);
- opacity: 0;
- }
- 50% {
- transform: translateY(0);
- opacity: 1;
- }
+ 0%, 100% { transform: translateY(-100%); opacity: 0; }
+ 50% { transform: translateY(0); opacity: 1; }
}
-/* Spin animation for loaders */
-@keyframes spin {
- to {
- transform: rotate(360deg);
- }
+/* === Scrollbar === */
+::-webkit-scrollbar { width: 8px; height: 8px; }
+::-webkit-scrollbar-track { background: var(--color-bg-2); }
+::-webkit-scrollbar-thumb { background: rgba(196, 162, 101, 0.25); border-radius: var(--radius-sm); }
+::-webkit-scrollbar-thumb:hover { background: rgba(196, 162, 101, 0.55); }
+
+/* === Buttons === */
+.btn {
+ display: inline-flex;
+ align-items: center;
+ gap: 0.625rem;
+ padding: 0.875rem 1.75rem;
+ border-radius: 999px;
+ font-size: 0.85rem;
+ font-weight: 600;
+ letter-spacing: 0.08em;
+ text-transform: uppercase;
+ text-decoration: none;
+ cursor: pointer;
+ transition: transform 0.25s cubic-bezier(0.16,1,0.3,1), box-shadow 0.25s ease, background 0.25s ease, color 0.25s ease;
+ border: 1px solid transparent;
+ white-space: nowrap;
+}
+.btn:hover { transform: translateY(-1px); }
+
+.btn-primary {
+ background: linear-gradient(135deg, #e0c896 0%, #c4a265 55%, #8b6f47 100%);
+ color: #0b0905;
+ box-shadow: 0 8px 28px rgba(196, 162, 101, 0.35), inset 0 1px 0 rgba(255, 244, 220, 0.4);
+}
+.btn-primary:hover {
+ box-shadow: 0 12px 38px rgba(224, 200, 150, 0.55), inset 0 1px 0 rgba(255, 244, 220, 0.5);
}
-/* Scrollbar Styling - Light */
-::-webkit-scrollbar {
- width: 8px;
- height: 8px;
+.btn-ghost {
+ background: rgba(245, 241, 232, 0.04);
+ color: #f5f1e8;
+ border-color: rgba(196, 162, 101, 0.28);
+ backdrop-filter: blur(12px);
+}
+.btn-ghost:hover {
+ background: rgba(196, 162, 101, 0.10);
+ border-color: rgba(196, 162, 101, 0.55);
+ color: #e0c896;
}
-::-webkit-scrollbar-track {
- background: var(--color-secondary);
+.btn-outline {
+ background: transparent;
+ color: #e0c896;
+ border-color: rgba(196, 162, 101, 0.55);
+}
+.btn-outline:hover {
+ background: rgba(196, 162, 101, 0.10);
}
-::-webkit-scrollbar-thumb {
- background: var(--color-border-light);
- border-radius: var(--radius-sm);
+/* === Layout helpers === */
+.container-wide { max-width: 1320px; margin: 0 auto; padding-left: clamp(1rem, 4vw, 2rem); padding-right: clamp(1rem, 4vw, 2rem); }
+
+.eyebrow {
+ display: inline-flex;
+ align-items: center;
+ gap: 0.625rem;
+ font-size: 0.72rem;
+ letter-spacing: 0.34em;
+ text-transform: uppercase;
+ color: var(--color-text-muted);
+ font-weight: 600;
+}
+.eyebrow::before {
+ content: '';
+ width: 28px;
+ height: 1px;
+ background: linear-gradient(90deg, transparent, var(--color-gold));
}
-::-webkit-scrollbar-thumb:hover {
- background: var(--color-text-muted);
+/* === Cards === */
+.card {
+ position: relative;
+ background: rgba(10, 9, 7, 0.72);
+ backdrop-filter: blur(16px);
+ -webkit-backdrop-filter: blur(16px);
+ border: 1px solid var(--color-border);
+ border-radius: var(--radius-2xl);
+ transition: transform 0.4s cubic-bezier(0.16,1,0.3,1), border-color 0.3s, box-shadow 0.3s;
+ overflow: hidden;
+}
+.card:hover {
+ transform: translateY(-6px);
+ border-color: rgba(196, 162, 101, 0.55);
+ box-shadow: 0 20px 60px rgba(0,0,0,0.7), 0 0 40px rgba(196, 162, 101, 0.15);
}
-/* Snap children */
-.snap-section {
- scroll-snap-align: start;
- height: 100vh;
-}
+/* === Configurator (preserve previous theme rules) === */
+.snap-section { scroll-snap-align: start; }
-/* Responsive Layout Styles */
@media (max-width: 1024px) {
- .glass-panel-responsive {
- width: 360px !important;
- }
+ .glass-panel-responsive { width: 360px !important; }
}
@media (max-width: 768px) {
@@ -203,7 +344,6 @@ html {
flex-direction: column-reverse !important;
height: 100dvh !important;
}
-
.glass-panel-responsive {
order: unset !important;
position: relative !important;
@@ -223,8 +363,6 @@ html {
z-index: 50;
padding-bottom: env(safe-area-inset-bottom, 0px) !important;
}
-
- /* Expanded (fullscreen) state overrides */
.glass-panel-responsive.panel-expanded {
position: fixed !important;
top: 0 !important;
@@ -240,7 +378,6 @@ html {
-webkit-overflow-scrolling: touch !important;
padding-bottom: 0 !important;
}
-
.canvas-area {
height: 45dvh !important;
max-height: 45dvh !important;
@@ -248,59 +385,32 @@ html {
width: 100% !important;
flex: none !important;
}
-
- #configurator {
- height: 100dvh !important;
- }
-
- .mobile-handle {
- display: flex !important;
- }
+ #configurator { height: 100dvh !important; }
+ .mobile-handle { display: flex !important; }
}
-/* Small phones */
@media (max-width: 480px) {
.glass-panel-responsive {
height: 58dvh !important;
max-height: 58dvh !important;
border-radius: 0.75rem 0.75rem 0 0 !important;
}
-
.canvas-area {
height: 42dvh !important;
max-height: 42dvh !important;
min-height: 160px !important;
}
-
- .glass-panel-responsive header {
- padding: 0.75rem 1rem !important;
- }
-
- .glass-panel-responsive > div[role="region"] {
- padding: 1rem !important;
- }
+ .glass-panel-responsive header { padding: 0.75rem 1rem !important; }
+ .glass-panel-responsive > div[role="region"] { padding: 1rem !important; }
}
-/* Very small phones (iPhone SE, etc.) */
@media (max-width: 375px) {
- .glass-panel-responsive {
- height: 60dvh !important;
- max-height: 60dvh !important;
- }
-
- .canvas-area {
- height: 40dvh !important;
- max-height: 40dvh !important;
- min-height: 140px !important;
- }
+ .glass-panel-responsive { height: 60dvh !important; max-height: 60dvh !important; }
+ .canvas-area { height: 40dvh !important; max-height: 40dvh !important; min-height: 140px !important; }
}
-/* Landscape mobile */
@media (max-height: 500px) and (orientation: landscape) {
- .layout-container {
- flex-direction: row !important;
- }
-
+ .layout-container { flex-direction: row !important; }
.glass-panel-responsive {
order: unset !important;
position: relative !important;
@@ -313,35 +423,15 @@ html {
border-left: 1px solid var(--color-border) !important;
overflow-y: auto !important;
}
-
- .canvas-area {
- height: 100% !important;
- max-height: 100% !important;
- width: auto !important;
- flex: 1 !important;
- }
-
- .mobile-handle {
- display: none !important;
- }
+ .canvas-area { height: 100% !important; max-height: 100% !important; width: auto !important; flex: 1 !important; }
+ .mobile-handle { display: none !important; }
}
-.mobile-handle {
- display: none;
-}
+.mobile-handle { display: none; }
-/* Hide expand button on desktop */
-.panel-expand-btn {
- display: none !important;
-}
-
-/* Show expand button only on mobile */
+.panel-expand-btn { display: none !important; }
@media (max-width: 768px) {
- .panel-expand-btn {
- display: flex !important;
- }
-
- /* Expanded (fullscreen) panel state – position handled by React inline styles */
+ .panel-expand-btn { display: flex !important; }
.layout-expanded .canvas-area {
height: 0 !important;
max-height: 0 !important;
@@ -351,193 +441,26 @@ html {
}
@media (max-width: 480px) {
- .glass-panel-responsive.panel-expanded {
- height: 100dvh !important;
- max-height: 100dvh !important;
- }
+ .glass-panel-responsive.panel-expanded { height: 100dvh !important; max-height: 100dvh !important; }
}
-
@media (max-width: 375px) {
- .glass-panel-responsive.panel-expanded {
- height: 100dvh !important;
- max-height: 100dvh !important;
- }
+ .glass-panel-responsive.panel-expanded { height: 100dvh !important; max-height: 100dvh !important; }
}
-/* ===== Scroll Overlay Responsive ===== */
-
-/* Overlay glass panels (side sections) */
-.overlay-panel {
- max-width: 450px;
- padding: 2.5rem;
- border-radius: 1.5rem;
-}
-
-/* Overlay section positioning */
-.overlay-section-left {
- left: clamp(2rem, 6vw, 6rem);
-}
-
-.overlay-section-right {
- right: clamp(2rem, 6vw, 6rem);
-}
-
-.overlay-heading {
- font-size: clamp(2rem, 3.5vw, 3rem);
-}
-
-.overlay-hero-heading {
- font-size: clamp(2.5rem, 5vw, 4.5rem);
-}
-
-.overlay-stat {
- font-size: 1.8rem;
-}
-
-/* Tablet */
-@media (max-width: 1024px) {
- .overlay-panel {
- max-width: 380px;
- padding: 2rem;
- }
-}
-
-/* Mobile */
-@media (max-width: 768px) {
- .overlay-section-left,
- .overlay-section-right {
- left: 50% !important;
- right: auto !important;
- transform: translateX(-50%);
- width: 90vw;
- max-width: 400px;
- }
-
- .overlay-section-left {
- top: auto !important;
- bottom: 4vh !important;
- align-items: center !important;
- }
-
- .overlay-section-right {
- top: auto !important;
- bottom: 4vh !important;
- align-items: center !important;
- }
-
- .overlay-panel {
- max-width: 100%;
- padding: 1.25rem;
- border-radius: 1rem;
- text-align: center !important;
- }
-
- .overlay-panel > div {
- align-items: center !important;
- }
-
- .overlay-hero-heading {
- font-size: clamp(1.8rem, 8vw, 2.8rem);
- }
-
- .overlay-heading {
- font-size: clamp(1.5rem, 6vw, 2rem);
- }
-
- .overlay-stat {
- font-size: 1.4rem;
- }
-
- .overlay-brand {
- top: 4vh !important;
- bottom: auto !important;
- left: 50% !important;
- transform: translateX(-50%);
- width: 90vw;
- }
-
- .overlay-brand span {
- font-size: 0.6rem !important;
- letter-spacing: 0.25em !important;
- }
-
- .overlay-brand p {
- font-size: 0.75rem !important;
- }
-
- .overlay-scroll-hint {
- bottom: 1.5rem !important;
- }
-
- .overlay-cta-section {
- top: 12vh !important;
- bottom: auto !important;
- }
-
- .overlay-cta-btn {
- padding: 1.2rem 3rem !important;
- font-size: 1.1rem !important;
- }
-}
-
-/* Hide overlay CTA on desktop since it takes over the screen */
-@media (min-width: 769px) {
- .overlay-cta-section {
- display: none !important;
- }
-}
-
-/* Specific class to ensure configurator shows only on desktop */
.desktop-configurator {
display: block !important;
position: relative;
z-index: 10;
- background-color: #ffffff;
}
-@media (max-width: 768px) {
- .desktop-configurator {
- display: none !important;
+@media (prefers-reduced-motion: reduce) {
+ *, *::before, *::after {
+ animation-duration: 0.001ms !important;
+ animation-iteration-count: 1 !important;
+ transition-duration: 0.001ms !important;
+ scroll-behavior: auto !important;
}
+ .hero-gradient { animation: none !important; }
}
-/* Small phones */
-@media (max-width: 480px) {
- .overlay-section-left,
- .overlay-section-right {
- width: 92vw;
- bottom: 4vh !important;
- }
-
- .overlay-panel {
- padding: 1.25rem;
- border-radius: 1rem;
- }
-
- .overlay-hero-heading {
- font-size: clamp(1.5rem, 7vw, 2.2rem);
- }
-
- .overlay-heading {
- font-size: clamp(1.3rem, 5.5vw, 1.8rem);
- }
-
- .overlay-stat {
- font-size: 1.2rem;
- }
-}
-
-/* Very small phones */
-@media (max-width: 375px) {
- .overlay-panel {
- padding: 1rem;
- }
-
- .overlay-hero-heading {
- font-size: 1.5rem;
- }
-
- .overlay-heading {
- font-size: 1.3rem;
- }
-}
+html, body { overflow-x: hidden; max-width: 100vw; }
diff --git a/src/app/industries/page.tsx b/src/app/industries/page.tsx
new file mode 100644
index 0000000..e837d4b
--- /dev/null
+++ b/src/app/industries/page.tsx
@@ -0,0 +1,47 @@
+import type { Metadata } from 'next';
+import { Navbar } from '@/components/Navbar';
+import { FooterAndContact } from '@/components/FooterAndContact';
+import { IndustryUseCases } from '@/components/robotics/IndustryUseCases';
+import { DemoCTA } from '@/components/robotics/DemoCTA';
+import { MotionSection } from '@/components/ui/MotionSection';
+
+export const metadata: Metadata = {
+ title: 'Robotics for UAE Industries — YS Lootah Robotics Dubai',
+ description:
+ 'Robotics solutions for hospitality, restaurants, hotels, healthcare, education, security, warehouses, smart buildings, and government across the UAE.',
+};
+
+export default function IndustriesPage() {
+ return (
+ <>
+
+
+
+
+
+
Industries served · Dubai · UAE
+
+
+ Robotics solutions for UAE businesses.
+
+
+
+ We deploy humanoid, quadruped, and service robots across industries that are reshaping how the UAE operates — every venue is matched to the right robot.
+
+
+
+
+
+
+
+
+
+
+
+
+ >
+ );
+}
diff --git a/src/app/layout.tsx b/src/app/layout.tsx
index f7845a5..814846e 100644
--- a/src/app/layout.tsx
+++ b/src/app/layout.tsx
@@ -4,14 +4,48 @@ import { I18nProvider } from "@/components/I18nProvider";
import "./globals.css";
export const metadata: Metadata = {
- title: "Lootah Robotics | G1 Configurator",
- description: "3D Configurator for the G1 Robot by Lootah Robotics",
+ metadataBase: new URL('https://yslootahrobotics.com'),
+ title: {
+ default: 'YS Lootah Robotics — Exclusive UAE Access to Unitree & Pudu Robotics',
+ template: '%s | YS Lootah Robotics',
+ },
+ description:
+ 'YS Lootah Robotics is the exclusive UAE sales destination for selected Unitree and Pudu Robotics solutions. Explore, configure, book demos, and deploy advanced robots across Dubai and the UAE.',
+ keywords: [
+ 'YS Lootah Robotics',
+ 'robotics Dubai',
+ 'robotics UAE',
+ 'exclusive robotics UAE',
+ 'Unitree robots UAE',
+ 'Pudu Robotics UAE',
+ 'humanoid robots Dubai',
+ 'quadruped robots UAE',
+ 'service robots UAE',
+ 'robot sales Dubai',
+ 'book robot demo UAE',
+ 'robotics showroom Dubai',
+ 'robotics configuration UAE',
+ ],
+ openGraph: {
+ type: 'website',
+ title: 'YS Lootah Robotics — Exclusive UAE Access to Unitree & Pudu Robotics',
+ description:
+ 'Advanced robotics. Exclusive UAE access. Selected Unitree and Pudu solutions available through YS Lootah Robotics in Dubai.',
+ locale: 'en_AE',
+ siteName: 'YS Lootah Robotics',
+ },
+ twitter: {
+ card: 'summary_large_image',
+ title: 'YS Lootah Robotics — Exclusive UAE Access to Unitree & Pudu Robotics',
+ description:
+ 'The UAE’s dedicated destination for Unitree and Pudu Robotics sales, demo inquiries, and business deployment.',
+ },
};
export const viewport: Viewport = {
- width: "device-width",
+ width: 'device-width',
initialScale: 1,
- themeColor: "#ffffff",
+ themeColor: '#050505',
};
export default function RootLayout({
@@ -20,7 +54,7 @@ export default function RootLayout({
children: React.ReactNode;
}) {
return (
-
+
diff --git a/src/app/page.tsx b/src/app/page.tsx
index fda02ff..d2253c3 100644
--- a/src/app/page.tsx
+++ b/src/app/page.tsx
@@ -1,41 +1,167 @@
-"use client";
+import type { Metadata } from 'next';
+import { Navbar } from '@/components/Navbar';
+import { FooterAndContact } from '@/components/FooterAndContact';
+import { Hero3DRobotics } from '@/components/robotics/Hero3DRobotics';
+import { BrandShowcase } from '@/components/robotics/BrandShowcase';
+import { RobotCategoryGrid } from '@/components/robotics/RobotCategoryGrid';
+import { RobotProductCard } from '@/components/robotics/RobotProductCard';
+import { IndustryUseCases } from '@/components/robotics/IndustryUseCases';
+import { DemoCTA } from '@/components/robotics/DemoCTA';
+import { ConfigureCTA } from '@/components/robotics/ConfigureCTA';
+import { ExclusiveAccessSection } from '@/components/robotics/ExclusiveAccessSection';
+import { MarqueeStrip } from '@/components/robotics/MarqueeStrip';
+import { BentoGrid } from '@/components/robotics/BentoGrid';
+import { HowItWorks } from '@/components/robotics/HowItWorks';
+import { MotionSection } from '@/components/ui/MotionSection';
+import { FEATURED_ROBOTS } from '@/data/robots';
-import { useRef } from "react";
-import { ClientOnly } from "@/components/ClientOnly";
-import { ScrollScene } from "@/components/ScrollScene";
-import { ScrollOverlays } from "@/components/ScrollOverlays";
-import { FooterAndContact } from "@/components/FooterAndContact";
-import { Navbar } from "@/components/Navbar";
+export const metadata: Metadata = {
+ title: 'YS Lootah Robotics — Exclusive UAE Access to Unitree & Pudu Robotics',
+ description:
+ 'YS Lootah Robotics is the exclusive UAE sales destination for selected Unitree and Pudu Robotics solutions. Explore, configure, book demos, and deploy advanced robots across Dubai and the UAE.',
+ keywords: [
+ 'YS Lootah Robotics',
+ 'robotics Dubai',
+ 'robotics UAE',
+ 'exclusive robotics UAE',
+ 'Unitree robots UAE',
+ 'Pudu Robotics UAE',
+ 'humanoid robots Dubai',
+ 'quadruped robots UAE',
+ 'service robots UAE',
+ 'robotics showroom Dubai',
+ 'robotics configuration UAE',
+ 'robot sales and demo UAE',
+ ],
+};
export default function HomePage() {
- const scrollContainerRef = useRef
(null);
-
return (
<>
-
- {/* Fixed 3D scene behind everything */}
-
-
-
- {/* Text overlays that fade based on scroll */}
-
+
+
- {/* Scroll spacer with snap sections -- 7 sections for the landing */}
-
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {FEATURED_ROBOTS.map((r, idx) => (
+
+ ))}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
>
);
}
+
+function SectionHeading({ eyebrow, title, description }: { eyebrow: string; title: string; description?: string }) {
+ return (
+
+
{eyebrow}
+
+ {title}
+
+ {description && (
+
+ {description}
+
+ )}
+
+ );
+}
diff --git a/src/app/privacy-policy/page.tsx b/src/app/privacy-policy/page.tsx
index 0ae8967..4ba77b1 100644
--- a/src/app/privacy-policy/page.tsx
+++ b/src/app/privacy-policy/page.tsx
@@ -9,32 +9,32 @@ export default function PrivacyPolicyPage() {
Privacy Policy
- Effective Date: {new Date().toLocaleDateString('en-AE')}
+ Effective Date: {new Date().toLocaleDateString('en-AE')}
- 1. Information We Collect
-
+
1. Information We Collect
+
At YS Lootah Robotics, we collect information you provide directly to us when you request information, use the G1 Customizer, or contact us. This includes your name, email address, phone number, and any other information you choose to provide in your message.
- 2. How We Use Your Information
-
+
2. How We Use Your Information
+
We use the information we collect to respond to your inquiries, deliver our robotics enterprise solutions, maintain our dashboard, and communicate with you about your custom humanoid configurations.
- 3. Data Security
-
+
3. Data Security
+
We implement robust security measures designed to protect your personal information. Your contact data is stored securely in our private databases strictly for administrative and operational purposes.
- 4. Contact Us
-
+
4. Contact Us
+
If you have questions or concerns about this Privacy Policy, please reach out to us at:
YS Lootah Robotics
diff --git a/src/app/robots/CatalogClient.tsx b/src/app/robots/CatalogClient.tsx
new file mode 100644
index 0000000..229a31e
--- /dev/null
+++ b/src/app/robots/CatalogClient.tsx
@@ -0,0 +1,125 @@
+'use client';
+
+import { Suspense, useMemo, useState } from 'react';
+import { useSearchParams, useRouter, usePathname } from 'next/navigation';
+import { ROBOTS, CATEGORY_LABELS, BRANDS, type RobotCategory, type RobotBrand } from '@/data/robots';
+import { RobotProductCard } from '@/components/robotics/RobotProductCard';
+import { ProductFilterTabs, type Tab } from '@/components/robotics/ProductFilterTabs';
+
+type Filter = { brand: RobotBrand | 'all'; category: RobotCategory | 'all' };
+
+function CatalogInner() {
+ const params = useSearchParams();
+ const router = useRouter();
+ const pathname = usePathname();
+
+ const initialBrand = (params.get('brand') as RobotBrand) || 'all';
+ const initialCategory = (params.get('category') as RobotCategory) || 'all';
+
+ const [filter, setFilter] = useState({ brand: initialBrand, category: initialCategory });
+
+ const filtered = useMemo(() => {
+ return ROBOTS.filter((r) => {
+ if (filter.brand !== 'all' && r.brand !== filter.brand) return false;
+ if (filter.category !== 'all' && !r.categories.includes(filter.category)) return false;
+ return true;
+ });
+ }, [filter]);
+
+ const updateFilter = (next: Partial) => {
+ const newFilter = { ...filter, ...next };
+ setFilter(newFilter);
+ const sp = new URLSearchParams();
+ if (newFilter.brand !== 'all') sp.set('brand', newFilter.brand);
+ if (newFilter.category !== 'all') sp.set('category', newFilter.category);
+ const qs = sp.toString();
+ router.replace(qs ? `${pathname}?${qs}` : pathname, { scroll: false });
+ };
+
+ const brandTabs: Tab[] = [
+ { id: 'all', label: 'All brands' },
+ ...(Object.keys(BRANDS) as RobotBrand[]).map((b) => ({
+ id: b,
+ label: BRANDS[b].name.split(' ')[0],
+ accent: BRANDS[b].accent,
+ })),
+ ];
+
+ const categoryTabs: Tab[] = [
+ { id: 'all', label: 'All' },
+ ...(Object.keys(CATEGORY_LABELS) as RobotCategory[]).map((c) => ({
+ id: c,
+ label: CATEGORY_LABELS[c],
+ })),
+ ];
+
+ return (
+
+
+
updateFilter({ brand: id as RobotBrand | 'all' })}
+ />
+ updateFilter({ category: id as RobotCategory | 'all' })}
+ />
+
+
+
+
+ {filtered.length} robot{filtered.length === 1 ? '' : 's'} found
+
+ {(filter.brand !== 'all' || filter.category !== 'all') && (
+
+ )}
+
+
+ {filtered.length === 0 ? (
+
+ No robots match these filters yet. Try a different brand or category, or{' '}
+
contact us for tailored options.
+
+ ) : (
+
+ {filtered.map((r) => (
+
+ ))}
+
+ )}
+
+ );
+}
+
+export function CatalogClient() {
+ return (
+ Loading catalog…
}>
+
+
+ );
+}
diff --git a/src/app/robots/[slug]/page.tsx b/src/app/robots/[slug]/page.tsx
new file mode 100644
index 0000000..172cd6a
--- /dev/null
+++ b/src/app/robots/[slug]/page.tsx
@@ -0,0 +1,226 @@
+import type { Metadata } from 'next';
+import { notFound } from 'next/navigation';
+import Link from 'next/link';
+import { Navbar } from '@/components/Navbar';
+import { FooterAndContact } from '@/components/FooterAndContact';
+import { InquiryForm } from '@/components/robotics/InquiryForm';
+import { RobotProductCard } from '@/components/robotics/RobotProductCard';
+import { DemoCTA } from '@/components/robotics/DemoCTA';
+import { ConfigureCTA } from '@/components/robotics/ConfigureCTA';
+import { ProductSpecTable } from '@/components/robotics/ProductSpecTable';
+import { ProductGallery } from '@/components/robotics/ProductGallery';
+import { MotionSection } from '@/components/ui/MotionSection';
+import { ROBOTS, getRobotBySlug, BRANDS, CATEGORY_LABELS } from '@/data/robots';
+
+type Params = { slug: string };
+
+export function generateStaticParams() {
+ return ROBOTS.map((r) => ({ slug: r.slug }));
+}
+
+export async function generateMetadata({ params }: { params: Promise }): Promise {
+ const { slug } = await params;
+ const robot = getRobotBySlug(slug);
+ if (!robot) return { title: 'Robot not found — YS Lootah Robotics' };
+ return {
+ title: `${robot.brandLabel} ${robot.name} — Available in Dubai | YS Lootah Robotics`,
+ description: `${robot.shortDescription} Available through YS Lootah Robotics in Dubai — request a price or book a live demo.`,
+ keywords: [robot.brandLabel, robot.name, 'Dubai', 'UAE', CATEGORY_LABELS[robot.category], 'robotics'],
+ };
+}
+
+export default async function RobotDetailPage({ params }: { params: Promise }) {
+ const { slug } = await params;
+ const robot = getRobotBySlug(slug);
+ if (!robot) notFound();
+
+ const brand = BRANDS[robot.brand];
+ const related = ROBOTS.filter((r) => r.id !== robot.id && (r.brand === robot.brand || r.category === robot.category)).slice(0, 3);
+
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+ {robot.imageType === 'placeholder' && (
+
+ Brand visual placeholder
+
+ )}
+
+
+
+
+ {brand.name} · {CATEGORY_LABELS[robot.category]}
+
+
+
+ {robot.name}
+
+
+
{robot.tagline}
+
{robot.longDescription}
+
+
+
+
+
+
+
+
+
+ {robot.features.map((f) => (
+ - {f}
+ ))}
+
+
+
+
+ {robot.useCases.map((u) => (
+ - {u}
+ ))}
+
+
+
+
+
+
+
+
+
+
+
+
+
Inquiry
+
+
+ Request a quotation for {robot.name}.
+
+
+
+ Tell us about your venue, timeline, and use case. We will respond with availability, configuration options, and pricing for the UAE.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {related.length > 0 && (
+
+
+
+ Related robots
+
+ You might also consider…
+
+
+
+ {related.map((r) => (
+
+ ))}
+
+
+
+ )}
+
+
+
+
+
+
+ >
+ );
+}
+
+function Block({ title, children }: { title: string; children: React.ReactNode }) {
+ return (
+
+ );
+}
diff --git a/src/app/robots/page.tsx b/src/app/robots/page.tsx
new file mode 100644
index 0000000..75d2886
--- /dev/null
+++ b/src/app/robots/page.tsx
@@ -0,0 +1,37 @@
+import type { Metadata } from 'next';
+import { Navbar } from '@/components/Navbar';
+import { FooterAndContact } from '@/components/FooterAndContact';
+import { CatalogClient } from './CatalogClient';
+import { ROBOTS } from '@/data/robots';
+
+export const metadata: Metadata = {
+ title: 'Robots Catalog — YS Lootah Robotics Dubai',
+ description:
+ 'Explore selected humanoid, quadruped, service, delivery, hospitality, and cleaning robots from Unitree and Pudu — available exclusively in the UAE through YS Lootah Robotics.',
+};
+
+export default function RobotsPage() {
+ return (
+ <>
+
+
+
+
+
Robot Catalog · Dubai · UAE
+
+
+ Robots ready to deploy across the UAE.
+
+
+
+ Browse {ROBOTS.length}+ models across our portfolio. Filter by brand or category, then request a price or book a live demo at our Dubai showroom.
+
+
+
+
+
+
+
+ >
+ );
+}
diff --git a/src/app/sitemap.ts b/src/app/sitemap.ts
index 6300561..53073f1 100644
--- a/src/app/sitemap.ts
+++ b/src/app/sitemap.ts
@@ -1,32 +1,29 @@
import { MetadataRoute } from 'next';
+import { ROBOTS } from '@/data/robots';
+
+const baseUrl = 'https://yslootahrobotics.com';
export default function sitemap(): MetadataRoute.Sitemap {
- const baseUrl = 'https://lootahrobotics.com'; // Adjust to your actual production domain
-
- return [
- {
- url: `${baseUrl}`,
- lastModified: new Date(),
- changeFrequency: 'weekly',
- priority: 1,
- },
- {
- url: `${baseUrl}/configure`,
- lastModified: new Date(),
- changeFrequency: 'monthly',
- priority: 0.8,
- },
- {
- url: `${baseUrl}/privacy-policy`,
- lastModified: new Date(),
- changeFrequency: 'yearly',
- priority: 0.5,
- },
- {
- url: `${baseUrl}/terms-of-service`,
- lastModified: new Date(),
- changeFrequency: 'yearly',
- priority: 0.5,
- },
+ const now = new Date();
+ const staticRoutes: MetadataRoute.Sitemap = [
+ { url: `${baseUrl}/`, lastModified: now, changeFrequency: 'weekly', priority: 1 },
+ { url: `${baseUrl}/robots/`, lastModified: now, changeFrequency: 'weekly', priority: 0.9 },
+ { url: `${baseUrl}/brands/`, lastModified: now, changeFrequency: 'weekly', priority: 0.8 },
+ { url: `${baseUrl}/industries/`, lastModified: now, changeFrequency: 'weekly', priority: 0.8 },
+ { url: `${baseUrl}/about/`, lastModified: now, changeFrequency: 'monthly', priority: 0.6 },
+ { url: `${baseUrl}/contact/`, lastModified: now, changeFrequency: 'monthly', priority: 0.7 },
+ { url: `${baseUrl}/book-demo/`, lastModified: now, changeFrequency: 'monthly', priority: 0.8 },
+ { url: `${baseUrl}/configure/`, lastModified: now, changeFrequency: 'monthly', priority: 0.8 },
+ { url: `${baseUrl}/privacy-policy/`, lastModified: now, changeFrequency: 'yearly', priority: 0.3 },
+ { url: `${baseUrl}/terms-of-service/`, lastModified: now, changeFrequency: 'yearly', priority: 0.3 },
];
+
+ const robotRoutes: MetadataRoute.Sitemap = ROBOTS.map((r) => ({
+ url: `${baseUrl}/robots/${r.slug}/`,
+ lastModified: now,
+ changeFrequency: 'monthly',
+ priority: 0.7,
+ }));
+
+ return [...staticRoutes, ...robotRoutes];
}
diff --git a/src/app/terms-of-service/page.tsx b/src/app/terms-of-service/page.tsx
index 98ac221..3809e06 100644
--- a/src/app/terms-of-service/page.tsx
+++ b/src/app/terms-of-service/page.tsx
@@ -9,32 +9,32 @@ export default function TermsOfServicePage() {
Terms of Service
- Effective Date: {new Date().toLocaleDateString('en-AE')}
+ Effective Date: {new Date().toLocaleDateString('en-AE')}
- 1. Acceptance of Terms
-
+
1. Acceptance of Terms
+
By accessing and utilizing the YS Lootah Robotics web platform and the G1 Configurator, you accept and agree to be bound by the terms and provisions of this agreement.
- 2. Use of the Site & Configurator
-
+
2. Use of the Site & Configurator
+
The 3D G1 Configurator is provided for informational and demonstrative purposes to showcase the capabilities of YS Lootah technologies. You agree to use this site strictly for lawful purposes resulting in enterprise robotics inquiries and configurations.
- 3. Intellectual Property Rights
-
+
3. Intellectual Property Rights
+
All original content on this website, including but not limited to text, graphics, 3D models (GLB files), logos, and software, is the exclusive property of YS Lootah Robotics and is protected by United Arab Emirates and international copyright laws.
- 4. Disclaimer of Warranties
-
+
4. Disclaimer of Warranties
+
The materials on our platform are provided "as is". We make no warranties, expressed or implied, and hereby disclaim to the fullest extent permitted by law all warranties regarding the immediate enterprise availability of the rendered concepts displayed in the Configurator.
diff --git a/src/components/CheckoutOverlay.tsx b/src/components/CheckoutOverlay.tsx
index 9095899..ca7a157 100644
--- a/src/components/CheckoutOverlay.tsx
+++ b/src/components/CheckoutOverlay.tsx
@@ -103,7 +103,7 @@ export function CheckoutOverlay() {
borderRadius: '0.375rem',
border: '1px solid rgba(0, 0, 0, 0.08)',
background: 'transparent',
- color: '#94a3b8',
+ color: '#94908a',
cursor: 'pointer',
fontSize: '0.75rem',
transition: 'all 0.2s ease',
@@ -111,7 +111,7 @@ export function CheckoutOverlay() {
>
Back
-
+
Checkout
@@ -216,7 +216,7 @@ export function CheckoutOverlay() {
) : (
- Initializing secure payment...
+ Initializing secure payment...
)}
) : null}
diff --git a/src/components/ConfigPanel.tsx b/src/components/ConfigPanel.tsx
index ab74646..b0fff7b 100644
--- a/src/components/ConfigPanel.tsx
+++ b/src/components/ConfigPanel.tsx
@@ -141,14 +141,14 @@ export function ConfigPanel() {
{persona.label}
{persona.description}
@@ -221,14 +221,14 @@ export function ConfigPanel() {
{opt.label}
{opt.description}
@@ -282,7 +282,7 @@ function ColorInput({ label, value, onChange }: { label: string; value: string;
/>
{label}
-
{value}
+
{value}
);
@@ -291,7 +291,7 @@ function ColorInput({ label, value, onChange }: { label: string; value: string;
const sectionTitleStyle: React.CSSProperties = {
fontSize: '0.75rem',
fontWeight: 500,
- color: '#94a3b8',
+ color: '#94908a',
textTransform: 'uppercase',
letterSpacing: '0.05em',
margin: 0,
diff --git a/src/components/ConfiguratorSection.tsx b/src/components/ConfiguratorSection.tsx
index 45da857..a59361a 100644
--- a/src/components/ConfiguratorSection.tsx
+++ b/src/components/ConfiguratorSection.tsx
@@ -41,7 +41,7 @@ export function ConfiguratorSection() {
background: 'rgba(255, 255, 255, 0.9)',
backdropFilter: 'blur(20px)',
WebkitBackdropFilter: 'blur(20px)',
- borderRight: '1px solid #e2e8f0',
+ borderRight: '1px solid #e8e0cf',
boxShadow: '4px 0 30px rgba(0, 0, 0, 0.04)',
display: 'flex',
flexDirection: 'column',
@@ -74,7 +74,7 @@ export function ConfiguratorSection() {
style={{
width: '40px',
height: '4px',
- backgroundColor: '#e2e8f0',
+ backgroundColor: '#e8e0cf',
borderRadius: '2px',
transition: 'width 0.2s, background-color 0.2s',
}}
@@ -85,7 +85,7 @@ export function ConfiguratorSection() {
diff --git a/src/components/FooterAndContact.tsx b/src/components/FooterAndContact.tsx
index ad975e3..4870695 100644
--- a/src/components/FooterAndContact.tsx
+++ b/src/components/FooterAndContact.tsx
@@ -1,378 +1,209 @@
'use client';
-import React, { useState } from 'react';
import Link from 'next/link';
-import PhoneInput from 'react-country-phone-input';
-import 'react-country-phone-input/lib/style.css';
+import { BRANDS } from '@/data/robots';
+
+const CONTACT = {
+ phonePrimary: '+971 55 948 2728',
+ phoneSecondary: '+971 4 349 9319',
+ email: 'info@yslootahtech.com',
+ address: 'Office 408, City Bay Business Center, Dubai, UAE',
+ whatsapp: 'https://wa.me/971559482728',
+ maps: 'https://maps.google.com/?q=Office+408+City+Bay+Business+Center+Dubai',
+ instagram: 'https://www.instagram.com/yslootahtech',
+ linkedin: 'https://www.linkedin.com/company/ys-lootah-tech',
+ facebook: 'https://www.facebook.com/yslootahtech',
+};
export function FooterAndContact() {
- const [formData, setFormData] = useState({ name: '', email: '', phone: '', message: '' });
- const [status, setStatus] = useState<'idle' | 'loading' | 'success' | 'error'>('idle');
-
- const handleSubmit = async (e: React.FormEvent) => {
- e.preventDefault();
- setStatus('loading');
- try {
- const res = await fetch('/api/contact', {
- method: 'POST',
- headers: { 'Content-Type': 'application/json' },
- body: JSON.stringify(formData)
- });
- if (res.ok) {
- setStatus('success');
- setFormData({ name: '', email: '', phone: '', message: '' });
- setTimeout(() => setStatus('idle'), 4000);
- } else {
- setStatus('error');
- setTimeout(() => setStatus('idle'), 4000);
- }
- } catch {
- setStatus('error');
- setTimeout(() => setStatus('idle'), 4000);
- }
- };
-
return (
-
-
- {/* Premium Desktop CTA section */}
-
- {/* Subtle background glow */}
-
-
-
- Ready to Build Your G1?
-
-
- Customize every detail. From intelligent locomotion to identity and purpose. Your enterprise-grade humanoid is just a few clicks away.
-
-
+
+
{
- e.currentTarget.style.background = 'var(--color-gold)';
- e.currentTarget.style.color = '#ffffff';
- e.currentTarget.style.boxShadow = '0 0 30px rgba(196, 162, 101, 0.4)';
- e.currentTarget.style.transform = 'translateY(-2px)';
- }}
- onMouseOut={(e) => {
- e.currentTarget.style.background = 'transparent';
- e.currentTarget.style.color = 'var(--color-gold)';
- e.currentTarget.style.boxShadow = 'none';
- e.currentTarget.style.transform = 'translateY(0)';
+ display: 'grid',
+ gap: 'clamp(2rem, 4vw, 3.5rem)',
+ gridTemplateColumns: 'repeat(auto-fit, minmax(min(220px, 100%), 1fr))',
+ paddingBottom: '2.5rem',
}}
>
- Configure Your G1
-
-
-
-
- {/* Contact Section */}
-