diff --git a/.gitignore b/.gitignore
index 5e10cc7..676841b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,8 +1,14 @@
+# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
+
# dependencies
/node_modules
/.pnp
-.pnp.js
-.yarn/install-state.gz
+.pnp.*
+.yarn/*
+!.yarn/patches
+!.yarn/plugins
+!.yarn/releases
+!.yarn/versions
# testing
/coverage
@@ -22,13 +28,28 @@
npm-debug.log*
yarn-debug.log*
yarn-error.log*
+.pnpm-debug.log*
-# local env files
-.env*.local
+# env files (can opt-in for committing if needed)
+.env*
# vercel
.vercel
# typescript
*.tsbuildinfo
-next-env.d.ts
\ No newline at end of file
+next-env.d.ts
+
+# Developer / deployment instructions
+# Contains sensitive production credentials (Gitea admin password, DB password, secrets, SSH keys, etc.)
+# This file MUST NEVER be committed or pushed.
+developer_instructions.txt
+
+# Video optimization artifacts and temp files
+# Generated by optimize-food-videos.sh, optimize-videos.sh, extract-video-posters.sh, ffmpeg passes etc.
+# These should not pollute the working tree or be committed.
+public/videos/*-optimized.*
+public/videos/*-optimized.mp4
+public/videos/*-optimized.webm
+error*.jpeg
+ffmpeg2pass*.log
diff --git a/AGENTS.md b/AGENTS.md
new file mode 100644
index 0000000..8bd0e39
--- /dev/null
+++ b/AGENTS.md
@@ -0,0 +1,5 @@
+
+# This is NOT the Next.js you know
+
+This version has breaking changes — APIs, conventions, and file structure may all differ from your training data. Read the relevant guide in `node_modules/next/dist/docs/` before writing any code. Heed deprecation notices.
+
diff --git a/CLAUDE.md b/CLAUDE.md
new file mode 100644
index 0000000..43c994c
--- /dev/null
+++ b/CLAUDE.md
@@ -0,0 +1 @@
+@AGENTS.md
diff --git a/README.md b/README.md
index a1c21f2..187dad4 100644
--- a/README.md
+++ b/README.md
@@ -1,69 +1,100 @@
-# Kött Gård — Premium Halal Meat Delivery
+# Shahikitchen — Animated Restaurant Website
-A modern, premium e-commerce website for 100% Halal meat delivery. Built with Next.js, TypeScript, and Tailwind CSS.
+This directory contains the official website for **Shahi Kitchen**, a popular Indian & Pakistani restaurant in Gothenburg (Göteborg), Sweden.
-## Features
+**Domain**: [shahikitchen.se](https://shahikitchen.se)
-- **Premium Design** — Green, white, and gold color palette with luxurious typography
-- **Multi-language** — Swedish (default), English, and Urdu with RTL support
-- **Product Customization**
- - Chicken: Choose quantity in pieces (4, 8, 10, 12, 14)
- - Beef & Lamb: Choose cutting style (Nihari, Karahi, Qeema, Boneless, Steak)
- - Fish: Standard professional cut
-- **Full E-commerce Flow** — Shop, product details, cart, secure checkout
-- **User Accounts** — Registration, login, order history
-- **Wishlist** — Save favorite products
-- **Responsive** — Mobile-first design
-- **SEO Optimized** — Meta tags, semantic HTML, Open Graph
+---
-## Getting Started
+## About Shahi Kitchen
-```bash
-npm install
-npm run dev
-```
+Shahi Kitchen is an authentic Indian and Pakistani restaurant specializing in flavorful curries, tandoori dishes, biryanis, haleem, fresh naan, and traditional sweets. The restaurant is particularly well-known for its generous **lunch buffet**, which offers excellent value and is popular among locals in the Gothenburg area.
-Open [http://localhost:3000](http://localhost:3000).
+### Key Information
-### Demo Account
+| Detail | Information |
+|---------------------|--------------------------------------------------|
+| **Full Name** | Shahi Kitchen (Shahikitchen / Shahi Kitchen Sisjön) |
+| **Cuisine** | Indian & Pakistani (Halal options available) |
+| **Address** | Datavägen 10A, 436 32 Askim, Sweden |
+| **Area** | Sisjön / Askim (suburb of Gothenburg) |
+| **Phone** | 031-28 89 10 / 0739-381089 (Imran) |
+| **Email** | hello@shahikitchen.se |
+| **Opened** | Around 2016 |
+| **Specialties** | Lunch buffet, Biryani, Lamb Karahi, Curries, Sweets (Shahi Sweets) |
-- Email: `demo@kottgard.se`
-- Password: `demo123`
+### Current Online Presence
-### Languages
+- **Instagram**: [@shahikitchen](https://www.instagram.com/Shahikitchen/)
+- **Facebook**: [facebook.com/shahikitchengbg](https://www.facebook.com/shahikitchengbg/)
+- **Reviews**: ~4.1/5 on Google (600+ reviews)
+- **Note**: As of 2026, the domain `shahikitchen.se` is parked. This project will give the restaurant a proper modern website.
-Use the language bar or globe icon to switch between:
-- **Svenska** (Swedish) — default
-- **English**
-- **اردو** (Urdu) — RTL
-- **العربية** (Arabic) — RTL
-- **فارسی** (Persian) — RTL
-- **Türkçe** (Turkish)
+---
## Tech Stack
-- **Framework:** Next.js 13 (App Router)
-- **Language:** TypeScript
-- **Styling:** Tailwind CSS
-- **State:** Zustand (persisted cart, auth, wishlist, locale)
-- **i18n:** Custom translation system with locale store
-- **Icons:** Lucide React
+- **Next.js 15** (App Router) + TypeScript
+- **Tailwind CSS**
+- **GSAP** — for advanced scroll and UI animations
+- **React Three Fiber** — for 3D experiences (dishes)
+- **Spline** (optional) — for high-quality hosted 3D scenes
+- **Framer Motion** (optional alternative to GSAP for simpler animations)
-## Project Structure (Clean Architecture)
+---
+
+## Project Structure (Planned)
```
-src/
-├── domain/ # Entities + business rules (no React/Next)
-├── application/ # Use cases, ports, container.ts
-├── infrastructure/ # Zustand, product data, i18n adapters
-├── presentation/ # useCart, useAuth, useCatalog hooks
-├── app/ # Next.js pages (thin UI)
-├── components/ # React UI components
-├── i18n/ # Translation dictionaries (en, sv, ur)
-├── hooks/ # useTranslation
-├── lib/ # Backward-compatible facades
-├── store/ # Backward-compatible re-exports
-└── types/ # Re-exports domain entities
+shahikitchen/
+├── app/
+│ ├── layout.tsx
+│ ├── page.tsx # Homepage (Hero + Menu + About + Contact)
+│ └── globals.css
+├── components/
+│ ├── MenuSection.tsx
+│ ├── Dish3D.tsx # React Three Fiber or Spline component
+│ ├── ReservationForm.tsx
+│ └── ...
+├── lib/
+│ └── menu-data.ts # Menu items
+├── public/
+│ └── images/
+└── ...
```
-See **[docs/CLEAN-ARCHITECTURE.md](docs/CLEAN-ARCHITECTURE.md)** for the full step-by-step guide.
\ No newline at end of file
+---
+
+## Development
+
+### Getting Started
+
+```bash
+# Install dependencies
+npm install
+
+# Run development server
+npm run dev
+```
+
+Open [http://localhost:3000](http://localhost:3000) in your browser.
+
+### Planned Features (in order)
+
+1. ✅ Create Next.js project
+2. ⏳ Build normal restaurant homepage (Hero, Navigation, About)
+3. ⏳ Add menu items (name, description, price)
+4. ⏳ Style with Tailwind CSS
+5. ⏳ Add animations (GSAP / Framer Motion)
+6. ⏳ Add 3D dishes (React Three Fiber + Spline)
+7. ⏳ Reservation / Contact form
+8. ⏳ Mobile responsive
+9. ⏳ Deploy to Vercel
+
+---
+
+## License
+
+This project is being built for Shahi Kitchen. All rights reserved.
+
+
diff --git a/app/catering/page.tsx b/app/catering/page.tsx
new file mode 100644
index 0000000..f9609bb
--- /dev/null
+++ b/app/catering/page.tsx
@@ -0,0 +1,107 @@
+'use client';
+
+import Navbar from '@/components/Navbar';
+import Footer from '@/components/Footer';
+import PageHeader from '@/components/PageHeader';
+import CateringPackageCard from '@/components/CateringPackageCard';
+import {
+ cateringPackages,
+ CATERING_DISH_CATALOG,
+ CATERING_CATEGORY_ORDER,
+} from '@/lib/catering-data';
+import { useLanguage } from '@/lib/language-context';
+import { getTranslation } from '@/lib/translations';
+import { container } from '@/infrastructure/di/container';
+import { Sparkles } from 'lucide-react';
+
+export default function CateringPage() {
+ const { language } = useLanguage();
+ const t = getTranslation(language);
+
+ const handleSendInquiry = () => {
+ container.messagingGateway.openWhatsApp(t.catering.inquiryMessage);
+ };
+
+ return (
+
+
+
+
+
+
+ {/* Packages grid */}
+
+
+ {cateringPackages.map((pkg, index) => (
+
+ ))}
+
+
+
+ {/* Full dish catalog reference */}
+
+
+
+
+
+ {t.catering.catalogBadge}
+
+
+
+
+ {t.catering.catalogTitle}
+
+
+ {t.catering.catalogSubtitle}
+
+
+
+
+
+
+
+ {CATERING_CATEGORY_ORDER.map((category) => {
+ const dishes = CATERING_DISH_CATALOG.filter((d) => d.category === category);
+ const categoryLabel =
+ (t.catering.categories as Record
)?.[category] ?? category;
+
+ return (
+
+
+ {categoryLabel}
+
+
+ {dishes.map((dish) => (
+ -
+ {dish.name}
+
+ ))}
+
+
+ );
+ })}
+
+
+
+
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/app/favicon.ico b/app/favicon.ico
new file mode 100644
index 0000000..87d7dbb
Binary files /dev/null and b/app/favicon.ico differ
diff --git a/app/globals.css b/app/globals.css
new file mode 100644
index 0000000..00e4b31
--- /dev/null
+++ b/app/globals.css
@@ -0,0 +1,482 @@
+/**
+ * =============================================================================
+ * GLOBAL DESIGN SYSTEM — Shahi Kitchen
+ * =============================================================================
+ *
+ * Shahi cream + gold visual identity for Shahi Kitchen.
+ * Bright, warm, appetizing, and luxurious without being dark.
+ */
+
+@import "tailwindcss";
+
+:root {
+ /* === Refined Shahi Light Palette - Warm Cream + Gold === */
+
+ /* Backgrounds */
+ --bg: #F8F5F0;
+ --bg-elevated: #F5F1E9;
+ --surface: #FFFFFF;
+ --surface-subtle: #F2EDE4;
+
+ /* Gold System */
+ --gold: #B38B4D;
+ --gold-dark: #8C6B3A;
+ --gold-light: #C9A46B;
+ --gold-muted: #d4a73d;
+
+ /* Emerald for contrast */
+ --emerald: #0f5a4a;
+ --emerald-deep: #0a4a3d;
+
+ /* Text */
+ --text: #2C2520;
+ --text-muted: #6B665F;
+ --text-light: #8A8478;
+
+ /* Borders */
+ --border: #EDE6D9;
+
+ /* Typography */
+ --font-display: var(--font-playfair);
+ --font-sans: var(--font-geist-sans);
+ --font-mono: var(--font-geist-mono);
+ --font-arabic: var(--font-arabic);
+
+ /* Motion */
+ --ease: cubic-bezier(0.25, 1, 0.5, 1);
+
+ /* Layout — language banner (48px) + navbar (68px) */
+ --header-height: 116px;
+ --page-top-gap: 1rem;
+}
+
+/* Anchor links (/#menu, /#experience) land below the fixed header */
+.scroll-mt-header {
+ scroll-margin-top: var(--header-height);
+}
+
+/* Base */
+body,
+.shahi-body {
+ font-family: var(--font-sans);
+ background-color: var(--bg);
+ color: var(--text);
+ background-image:
+ radial-gradient(ellipse 80% 50% at 50% -20%, rgba(201, 154, 46, 0.08), transparent),
+ radial-gradient(ellipse 60% 40% at 100% 100%, rgba(15, 90, 74, 0.04), transparent);
+ background-attachment: fixed;
+}
+
+/* RTL typography */
+html[dir="rtl"] body {
+ font-family: var(--font-arabic), var(--font-sans);
+}
+
+html[dir="rtl"] h1,
+html[dir="rtl"] h2,
+html[dir="rtl"] h3,
+html[dir="rtl"] h4 {
+ font-family: var(--font-arabic), var(--font-display);
+ letter-spacing: 0;
+}
+
+h1, h2, h3, h4 {
+ font-family: var(--font-display);
+ font-weight: 600;
+ letter-spacing: -0.025em;
+ color: var(--text);
+}
+
+/* Premium Buttons */
+.btn-primary {
+ background: linear-gradient(135deg, var(--gold), var(--gold-muted));
+ color: #241806;
+ font-weight: 700;
+ transition: all 0.2s var(--ease);
+}
+
+.btn-primary:hover {
+ transform: translateY(-1px);
+}
+
+.btn-outline {
+ border: 1px solid var(--gold);
+ color: var(--gold-dark);
+ background: transparent;
+ font-weight: 600;
+ transition: all 0.2s var(--ease);
+}
+
+.btn-outline:hover {
+ background: var(--gold);
+ color: #241806;
+}
+
+/* Glass effect helper */
+.glass {
+ background: rgba(255, 253, 248, 0.72);
+ backdrop-filter: blur(20px);
+}
+
+/* Luxury card style */
+.luxury-card {
+ border-radius: 2rem;
+ transition: transform 0.4s var(--ease), box-shadow 0.4s var(--ease);
+}
+
+.luxury-card:hover {
+ transform: translateY(-4px);
+ box-shadow: 0 25px 50px -12px rgb(0 0 0 / 0.12);
+}
+
+/* Signature dish cards */
+.signature-card {
+ box-shadow: 0 4px 24px -4px rgb(16 23 36 / 0.06);
+ transition: transform 0.35s var(--ease), box-shadow 0.35s var(--ease), border-color 0.35s var(--ease);
+}
+
+.signature-card:hover {
+ box-shadow: 0 20px 40px -12px rgb(179 139 77 / 0.18);
+ border-color: rgba(201, 154, 46, 0.45);
+}
+
+/* Section ornament */
+.section-ornament {
+ position: relative;
+}
+
+.section-ornament::before {
+ content: '';
+ position: absolute;
+ top: 0;
+ left: 50%;
+ transform: translateX(-50%);
+ width: 80px;
+ height: 3px;
+ background: linear-gradient(90deg, transparent, var(--gold-muted), transparent);
+ border-radius: 2px;
+}
+
+/* Hero overlay text */
+.hero-glass {
+ background: linear-gradient(
+ 135deg,
+ rgba(255, 253, 248, 0.92) 0%,
+ rgba(255, 250, 240, 0.88) 50%,
+ rgba(248, 245, 240, 0.85) 100%
+ );
+ backdrop-filter: blur(20px);
+ border: 1px solid rgba(201, 154, 46, 0.2);
+ box-shadow:
+ 0 25px 50px -12px rgba(16, 23, 36, 0.15),
+ inset 0 1px 0 rgba(255, 255, 255, 0.8);
+}
+
+/* =============================================================================
+ * FOOTER — Matches header cream + gold palette
+ * ============================================================================= */
+.shahi-footer {
+ background: linear-gradient(
+ 180deg,
+ #fffcf7 0%,
+ #fbf7ef 55%,
+ #f5f0e6 100%
+ );
+ color: #101724;
+ border-top: 1px solid rgba(201, 154, 46, 0.25);
+ box-shadow: 0 -4px 24px -4px rgba(16, 23, 36, 0.06);
+}
+
+.footer-top-rail {
+ height: 4px;
+ background: linear-gradient(
+ 90deg,
+ transparent 0%,
+ #8a6a25 15%,
+ #c99a2e 35%,
+ #f4d47f 50%,
+ #c99a2e 65%,
+ #8a6a25 85%,
+ transparent 100%
+ );
+}
+
+.footer-main {
+ position: relative;
+}
+
+.footer-glow {
+ position: absolute;
+ border-radius: 50%;
+ pointer-events: none;
+ filter: blur(80px);
+}
+
+.footer-glow--gold {
+ top: -40px;
+ right: 10%;
+ width: 280px;
+ height: 280px;
+ background: rgba(201, 154, 46, 0.08);
+}
+
+.footer-glow--emerald {
+ bottom: 0;
+ left: -5%;
+ width: 320px;
+ height: 320px;
+ background: rgba(15, 90, 74, 0.05);
+}
+
+.footer-heading-line {
+ display: inline-block;
+ width: 20px;
+ height: 2px;
+ background: linear-gradient(90deg, #c99a2e, #f4d47f);
+ border-radius: 1px;
+}
+
+.footer-info-card {
+ border-radius: 1rem;
+ border: 1px solid rgba(201, 154, 46, 0.22);
+ background: rgba(255, 255, 255, 0.72);
+ padding: 1rem 1.125rem;
+ backdrop-filter: blur(8px);
+ transition: border-color 0.25s var(--ease), background 0.25s var(--ease), box-shadow 0.25s var(--ease);
+}
+
+.footer-info-card:hover {
+ border-color: rgba(201, 154, 46, 0.45);
+ background: #ffffff;
+ box-shadow: 0 4px 16px -6px rgba(16, 23, 36, 0.08);
+}
+
+.footer-link {
+ color: #3d4654;
+ transition: color 0.2s var(--ease), transform 0.2s var(--ease);
+}
+
+.footer-link:hover {
+ color: #0f5a4a;
+}
+
+html[dir="rtl"] .footer-link:hover {
+ transform: translateX(-2px);
+}
+
+html[dir="ltr"] .footer-link:hover {
+ transform: translateX(2px);
+}
+
+.footer-social-btn {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 2.75rem;
+ height: 2.75rem;
+ border-radius: 0.875rem;
+ border: 1px solid rgba(201, 154, 46, 0.35);
+ background: rgba(255, 255, 255, 0.85);
+ color: #8a6a25;
+ transition: all 0.25s var(--ease);
+}
+
+.footer-social-btn:hover {
+ background: linear-gradient(135deg, #c99a2e, #e8c56a);
+ color: #241806;
+ border-color: #c99a2e;
+ transform: translateY(-2px);
+ box-shadow: 0 8px 24px -4px rgba(201, 154, 46, 0.35);
+}
+
+.footer-logo-ring {
+ border-color: rgba(201, 154, 46, 0.35);
+ background: #ffffff;
+ box-shadow: 0 4px 20px -6px rgba(16, 23, 36, 0.1);
+}
+
+.footer-bottom {
+ background: rgba(255, 255, 255, 0.55);
+ border-top: 1px solid rgba(201, 154, 46, 0.2);
+}
+
+.footer-cta {
+ backdrop-filter: blur(12px);
+ background: linear-gradient(
+ 135deg,
+ rgba(255, 255, 255, 0.92) 0%,
+ rgba(255, 252, 247, 0.88) 100%
+ );
+ border-color: rgba(201, 154, 46, 0.35);
+}
+
+/* Language banner subtle shine */
+.lang-banner {
+ position: relative;
+ overflow: hidden;
+}
+
+.lang-banner::after {
+ content: '';
+ position: absolute;
+ inset: 0;
+ background: linear-gradient(
+ 90deg,
+ transparent 0%,
+ rgba(255, 255, 255, 0.06) 50%,
+ transparent 100%
+ );
+ pointer-events: none;
+}
+
+/* Mesmerizing shimmer animation for premium buttons (used in Navbar) */
+@keyframes shimmer {
+ 0% { transform: translateX(-100%); }
+ 100% { transform: translateX(200%); }
+}
+
+/* Continuous menu reel marquee for 43" displays - items move LEFT (enter from right, exit left), seamless loop with 2x duplication */
+@keyframes menu-reel {
+ 0% { transform: translateX(0); }
+ 100% { transform: translateX(-50%); }
+}
+
+.menu-reel-track {
+ will-change: transform;
+ animation: menu-reel linear infinite;
+ /* Force GPU layer for stable poster/video during transform */
+ transform: translateZ(0);
+ backface-visibility: hidden;
+}
+
+/* Homepage signature menu — dishes scroll left to right */
+@keyframes signature-menu-reel-ltr {
+ 0% { transform: translateX(-50%); }
+ 100% { transform: translateX(0); }
+}
+
+.signature-menu-reel-track {
+ will-change: transform;
+ animation: signature-menu-reel-ltr linear infinite;
+ transform: translateZ(0);
+ backface-visibility: hidden;
+}
+
+.signature-menu-reel:hover .signature-menu-reel-track {
+ animation-play-state: paused;
+}
+
+@media (prefers-reduced-motion: reduce) {
+ .signature-menu-reel-track {
+ animation: none;
+ flex-wrap: wrap;
+ width: 100% !important;
+ justify-content: center;
+ }
+}
+
+/* =============================================================================
+ * KIOSK / FULLSCREEN DISPLAY PAGES (screen1 & screen2)
+ * Professional clean TV/window look: no scrollbars ever, even in browser
+ * fullscreen (F11) or kiosk mode. User zooms browser (in/out) to adjust
+ * visible reel density instead of scrolling. Content sized to fit 100vh.
+ * ============================================================================= */
+html.screen-kiosk,
+body.screen-kiosk {
+ overflow: hidden !important;
+ overscroll-behavior: none;
+ /* Hide scrollbars cross-browser */
+ scrollbar-width: none; /* Firefox */
+ -ms-overflow-style: none; /* IE/Edge */
+}
+
+html.screen-kiosk::-webkit-scrollbar,
+body.screen-kiosk::-webkit-scrollbar {
+ display: none; /* Chrome/Safari/Opera */
+}
+
+.screen-root {
+ height: 100vh;
+ overflow: hidden;
+ display: flex;
+ flex-direction: column;
+ /* Extra insurance: hide any descendant scrollbars */
+ scrollbar-width: none;
+ -ms-overflow-style: none;
+}
+
+.screen-root::-webkit-scrollbar,
+.screen-root *::-webkit-scrollbar {
+ display: none;
+}
+
+/* Subtle polish for pure display (no accidental text selection or pointer) */
+.screen-root {
+ cursor: default;
+}
+
+/* =============================================================================
+ * VERTICAL REEL for screen3 order columns
+ * Orders move UP (from below to above) in a loop, like screen2 horizontal but vertical.
+ * Cards have fixed px height; viewport h-full of available column space (after header) =>
+ * fills entire screen height with no white space (max top to bottom).
+ * Zoom in browser: fewer items visible per column (larger cards relative).
+ * Zoom out: more items visible per column (smaller cards relative).
+ * When > visible count, the track loops seamlessly (duplicated list + 50% translateY).
+ * ============================================================================= */
+@keyframes order-reel-up {
+ 0% { transform: translateY(0); }
+ 100% { transform: translateY(-50%); }
+}
+
+.order-reel-track {
+ display: flex;
+ flex-direction: column;
+ will-change: transform;
+ animation: order-reel-up linear infinite;
+ /* Force GPU layer for stable animation */
+ transform: translateZ(0);
+ backface-visibility: hidden;
+}
+
+.reel-viewport {
+ overflow: hidden;
+ /* Height 100% of available (flex h-full after section header) to fill screen.
+ Fixed card heights + zoom changes visible count dynamically. */
+}
+
+/* Menu page — smooth category filter scrolling */
+.menu-category-scroll {
+ scroll-behavior: smooth;
+ scrollbar-width: none;
+ -ms-overflow-style: none;
+}
+
+.menu-category-scroll::-webkit-scrollbar {
+ display: none;
+}
+
+@media (min-width: 1024px) {
+ .menu-category-scroll {
+ scrollbar-width: thin;
+ scrollbar-color: #d4c9b8 transparent;
+ }
+
+ .menu-category-scroll::-webkit-scrollbar {
+ display: block;
+ width: 5px;
+ }
+
+ .menu-category-scroll::-webkit-scrollbar-track {
+ background: transparent;
+ }
+
+ .menu-category-scroll::-webkit-scrollbar-thumb {
+ background: #d4c9b8;
+ border-radius: 999px;
+ }
+
+ .menu-category-scroll::-webkit-scrollbar-thumb:hover {
+ background: #c99a2e;
+ }
+}
diff --git a/app/layout.tsx b/app/layout.tsx
new file mode 100644
index 0000000..2fd67c1
--- /dev/null
+++ b/app/layout.tsx
@@ -0,0 +1,123 @@
+/**
+ * ROOT LAYOUT — Shahi Kitchen (shahikitchen.se)
+ *
+ * This is the single root layout for the entire Next.js App Router application.
+ *
+ * RESPONSIBILITIES:
+ * - Set up global metadata (title, description, favicon) for SEO and social sharing
+ * - Load the premium typography system:
+ * • Playfair Display (display/serif) → used for headings via --font-playfair
+ * • Geist Sans (system UI) → body text
+ * • Geist Mono → code / tabular data
+ * - Initialize the GLOBAL CART SYSTEM:
+ * • CartProvider wraps the whole tree so any page/component can use `useCart()`
+ * • CartDrawer is rendered once at the root (slide-in basket panel)
+ * • Sonner provides beautiful toast notifications used by the cart
+ *
+ * ARCHITECTURAL NOTES:
+ * - We deliberately render and at the root level instead of
+ * inside individual pages. This guarantees only ONE instance exists and prevents
+ * duplicate drawers/toasts when navigating.
+ * - The cream/gold Shahi theme tokens live in globals.css and are referenced via
+ * Tailwind arbitrary values (e.g. bg-[#F8F5F0]).
+ *
+ * FUTURE DEVELOPERS:
+ * - To add a new global provider (theme, analytics, etc.), wrap it here.
+ * - WhatsApp number for orders is currently hardcoded in CartDrawer.tsx (46739381089).
+ * - If you ever split the cart into a separate modal library, keep the provider here.
+ */
+
+import type { Metadata } from "next";
+import { Playfair_Display, Geist, Geist_Mono, Noto_Sans_Arabic } from "next/font/google";
+import "./globals.css";
+import { Toaster } from "sonner";
+import CartDrawer from "@/components/CartDrawer";
+import WishlistDrawer from "@/components/WishlistDrawer";
+import { CartProvider } from "@/presentation/providers/cart-provider";
+import { WishlistProvider } from "@/presentation/providers/wishlist-provider";
+import { LanguageProvider } from "@/presentation/providers/language-provider";
+
+const playfair = Playfair_Display({
+ variable: "--font-playfair",
+ subsets: ["latin"],
+ weight: ["400", "500", "600", "700"],
+ style: ["normal", "italic"],
+});
+
+const geistSans = Geist({
+ variable: "--font-geist-sans",
+ subsets: ["latin"],
+ weight: ["400", "500", "600", "700"],
+});
+
+const geistMono = Geist_Mono({
+ variable: "--font-geist-mono",
+ subsets: ["latin"],
+ weight: ["400", "500", "600"],
+});
+
+const notoArabic = Noto_Sans_Arabic({
+ variable: "--font-arabic",
+ subsets: ["arabic"],
+ weight: ["400", "500", "600", "700"],
+});
+
+/**
+ * Next.js Metadata API (static)
+ * These values power:
+ * - Browser tab title
+ * - Search engine results
+ * - Social cards (Open Graph / Twitter) when shared
+ *
+ * For dynamic per-page metadata, use `generateMetadata()` in page files.
+ */
+export const metadata: Metadata = {
+ title: "Shahi Kitchen | Authentic Indian & Pakistani Restaurant in Gothenburg",
+ description: "Experience Shahi flavors at Shahi Kitchen in Askim, Gothenburg. Authentic Indian & Pakistani cuisine, famous lunch buffet, and traditional sweets since 2016.",
+ icons: {
+ icon: "/favicon.ico",
+ },
+};
+
+/**
+ * RootLayout
+ *
+ * The ONLY place in the app where we initialize:
+ * 1. CartProvider → gives every descendant access to `useCart()` hook
+ * 2. CartDrawer → the actual slide-in basket UI (controlled via context)
+ * 3. Toaster → global toast surface used by cart (Sonner library)
+ *
+ * IMPORTANT:
+ * - Never wrap the entire app in another CartProvider — it will break the singleton.
+ * - The body uses the Shahi cream background (#F8F5F0) as the base canvas.
+ * - `antialiased` + font variables are applied once at the root for consistency.
+ */
+export default function RootLayout({
+ children,
+}: Readonly<{
+ children: React.ReactNode;
+}>) {
+ return (
+
+
+
+
+
+ {children}
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/app/locations/page.tsx b/app/locations/page.tsx
new file mode 100644
index 0000000..edfd503
--- /dev/null
+++ b/app/locations/page.tsx
@@ -0,0 +1,144 @@
+/**
+ * LOCATIONS PAGE
+ *
+ * Dedicated page for the restaurant's two physical branches.
+ *
+ * ARCHITECTURE:
+ * - Two branches are modeled as distinct concepts:
+ * 1. Shahi Kitchen Askim (Sisjön) → Full restaurant + famous lunch buffet
+ * 2. Shahi Sweets Backaplan → Sweets, snacks, café, halwa puri etc.
+ * - Both are operated by the same team (explicitly stated at the bottom)
+ * - Google Maps embeds are intentionally simple (lazy loaded)
+ *
+ * FUTURE:
+ * - When real online ordering launches, this page could show "Order from Askim"
+ * vs "Order from Backaplan" with different delivery radii.
+ * - Both branches now have the same opening hours.
+ */
+
+'use client';
+
+import Navbar from "@/components/Navbar";
+import Footer from "@/components/Footer";
+import PageHeader from "@/components/PageHeader";
+import { useLanguage } from "@/lib/language-context";
+import { getTranslation } from "@/lib/translations";
+
+export default function LocationsPage() {
+ const { language } = useLanguage();
+ const t = getTranslation(language);
+ return (
+
+
+
+
+
+
+
+
+
+
+ {/* Branch 1: Askim */}
+
+
RESTAURANT & BUFFET
+
Shahi Kitchen – Askim (Sisjön)
+
+
+
+
ADDRESS
+
Datavägen 10A
436 32 Askim, Gothenburg
+
+
+
+
+
+
OPENING HOURS
+
Monday – Sunday • 11:00 – 21:00
+
+
+
+
WHAT TO EXPECT
+
Full restaurant experience with our popular lunch buffet, à la carte, and traditional Pakistani & Indian dishes.
+
+
+
+
+
+
+
+
+ {/* Branch 2: Backaplan */}
+
+
SWEETS, SNACKS & CAFÉ
+
Shahi Sweets – Backaplan
+
+
+
+
ADDRESS
+
Krokegårdsgatan 5
417 30 Göteborg (Backaplan)
+
+
+
+
+
+
OPENING HOURS
+
Monday – Sunday • 11:00 – 21:00
+
+
+
+
WHAT TO EXPECT
+
Fresh mithai (sweets), savory snacks, halwa puri, biryani, nihari, and café-style seating.
+
+
+
+
+
+
+
+
+
+
+
+ Both branches are operated by the same team and share the same passion for authentic flavors.
+
+
+
+
+
+ );
+}
diff --git a/app/login/page.tsx b/app/login/page.tsx
new file mode 100644
index 0000000..fce4154
--- /dev/null
+++ b/app/login/page.tsx
@@ -0,0 +1,281 @@
+'use client';
+
+import { logoUrl } from "@/lib/assets";
+import Navbar from "@/components/Navbar";
+
+import Footer from "@/components/Footer";
+import { useLanguage } from "@/lib/language-context";
+import { getTranslation } from "@/lib/translations";
+import { useState } from 'react';
+import { motion, AnimatePresence } from "framer-motion";
+import { User, Lock, MapPin, LogIn, Phone, MessageCircle } from "lucide-react";
+
+/**
+ * =============================================================================
+ * STAFF LOGIN / AUTHENTICATION PAGE
+ * =============================================================================
+ *
+ * Beautiful, theme-matched placeholder login experience.
+ * - Fully language compatible (sv default + en/hi/ur)
+ * - No real backend yet — always shows friendly "under construction" message
+ * - Mobile-first: large tap targets, excellent spacing, easy form on phones
+ * - Desktop: elegant split layout with dark luxury graphic panel + form
+ * - Uses existing design tokens (gold accents, cream bg, rounded cards, serif titles)
+ *
+ * Future: when real auth is added, this will become the entry to a protected staff area
+ * (per-site menus, orders, inventory etc. for Askim vs Backaplan).
+ */
+
+export default function LoginPage() {
+ const { language } = useLanguage();
+ const t = getTranslation(language);
+
+ const [formData, setFormData] = useState({
+ username: '',
+ password: '',
+ site: '',
+ });
+ const [isSubmitted, setIsSubmitted] = useState(false);
+
+ const handleChange = (e: React.ChangeEvent) => {
+ const { name, value } = e.target;
+ setFormData((prev) => ({ ...prev, [name]: value }));
+ };
+
+ const handleSubmit = (e: React.FormEvent) => {
+ e.preventDefault();
+ // Placeholder behaviour: always show the construction notice.
+ // No validation beyond native required fields — real auth coming later.
+ setIsSubmitted(true);
+ };
+
+ const resetForm = () => {
+ setFormData({ username: '', password: '', site: '' });
+ setIsSubmitted(false);
+ };
+
+ return (
+
+
+
+
+ {/* Elegant header */}
+
+
+ STAFF PORTAL
+
+
+ {t.auth.title}
+
+
+ {t.auth.subtitle}
+
+
+
+ {/* Content area — beautiful split layout on desktop, clean single column on mobile */}
+
+
+ {/* LEFT: Premium dark graphic panel (desktop only). Matches Shahi theme with gold details. */}
+
+
+ {/* Subtle gold frame lines */}
+
+
+
+
+
+
})
+
+
+
+ Shahi
Kitchen
+
+
+ STAFF ACCESS
+
+
+
+
+
+
+ Two locations serving Shahi Indian & Pakistani hospitality in Gothenburg since 2016.
+
+
+ ASKIM • BACKAPLAN
+
+
+
+
+
+ {/* RIGHT / MOBILE: The actual elegant login card */}
+
+
+ {/* Mobile-only logo accent for visual continuity */}
+
+
+
})
+
+
+
+
+ {!isSubmitted ? (
+
+
+
+
+ {t.auth.footerNote}
+
+
+ ) : (
+ /* Beautiful result state — always shows the construction notice */
+
+
+
+
+
+
+ {t.auth.construction.title}
+
+
+
+ {t.auth.construction.message}
+
+
+ {/* Helpful contact actions (real numbers from the site) */}
+
+
+
+ We appreciate your patience while we build a seamless experience.
+
+
+ )}
+
+
+
+ {/* Small trust line */}
+
+ SHAHI KITCHEN • GOTHENBURG • EST 2016
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/app/menu/page.tsx b/app/menu/page.tsx
new file mode 100644
index 0000000..52b441a
--- /dev/null
+++ b/app/menu/page.tsx
@@ -0,0 +1,418 @@
+"use client";
+
+/**
+ * MENU PAGE — Premium Sidebar Navigation
+ */
+
+import { useEffect, useRef, useState, useMemo } from "react";
+import { menuCategories } from "@/lib/menu-data";
+import { buildCartLineFromMenuItem } from "@/application/cart/cart-line-builder";
+import type { MenuItem } from "@/domain/menu/entities";
+import { gsap } from "gsap";
+import { ScrollTrigger } from "gsap/ScrollTrigger";
+import { motion } from "framer-motion";
+import Navbar from "@/components/Navbar";
+import PageHeader from "@/components/PageHeader";
+import Footer from "@/components/Footer";
+import { useCart } from "@/components/CartContext";
+import WishlistButton from "@/components/WishlistButton";
+import { useLanguage } from "@/lib/language-context";
+import { getTranslation } from "@/lib/translations";
+import {
+ dishImageUrl,
+ getMenuPosterSrc,
+ getMenuPosterCandidates,
+ applyNextImageFallback,
+} from "@/lib/assets";
+import { playHoverSound } from "@/lib/sounds";
+import DishDetailsModal from "@/components/DishDetailsModal";
+import { hasDishDetailModal } from "@/domain/menu/dish-details";
+
+gsap.registerPlugin(ScrollTrigger);
+
+export default function MenuPage() {
+ const [activeCategory, setActiveCategory] = useState("All");
+ const [searchQuery, setSearchQuery] = useState("");
+ const [showVegetarianOnly, setShowVegetarianOnly] = useState(false);
+ const [isMobile, setIsMobile] = useState(false);
+ const [detailItem, setDetailItem] = useState