diff --git a/apps/admin/package.json b/apps/admin/package.json
new file mode 100644
index 00000000..1354655f
--- /dev/null
+++ b/apps/admin/package.json
@@ -0,0 +1,28 @@
+{
+ "name": "@fused-gaming/admin",
+ "version": "1.0.0",
+ "private": true,
+ "scripts": {
+ "dev": "next dev -p 3001",
+ "build": "next build",
+ "start": "next start -p 3001",
+ "type-check": "tsc --noEmit"
+ },
+ "dependencies": {
+ "next": "14.2.5",
+ "react": "^18.3.1",
+ "react-dom": "^18.3.1",
+ "framer-motion": "^11.3.8",
+ "zustand": "^4.5.4",
+ "clsx": "^2.1.1"
+ },
+ "devDependencies": {
+ "@types/node": "^20.14.10",
+ "@types/react": "^18.3.3",
+ "@types/react-dom": "^18.3.0",
+ "autoprefixer": "^10.4.19",
+ "postcss": "^8.4.39",
+ "tailwindcss": "^3.4.6",
+ "typescript": "^5.5.3"
+ }
+}
diff --git a/apps/admin/src/app/globals.css b/apps/admin/src/app/globals.css
new file mode 100644
index 00000000..a34630a0
--- /dev/null
+++ b/apps/admin/src/app/globals.css
@@ -0,0 +1,39 @@
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
+
+:root {
+ --admin-bg: #0a0a0a;
+ --admin-surface: #111111;
+ --admin-surface2: #1a1a1a;
+ --admin-border: #222222;
+ --admin-primary: #dc2626;
+ --admin-text: #f3f4f6;
+ --admin-muted: #9ca3af;
+ --admin-faint: #4b5563;
+ --admin-success: #22c55e;
+ --admin-warning: #f59e0b;
+ --admin-error: #ef4444;
+}
+
+body {
+ background: var(--admin-bg);
+ color: var(--admin-text);
+ font-family: 'Inter', system-ui, sans-serif;
+}
+
+/* Live preview iframe isolation */
+.brand-preview-frame {
+ border: 1px solid var(--admin-border);
+ border-radius: 12px;
+ overflow: hidden;
+}
+
+/* Token color swatch */
+.color-swatch {
+ width: 32px;
+ height: 32px;
+ border-radius: 6px;
+ border: 1px solid rgba(255,255,255,0.1);
+ flex-shrink: 0;
+}
diff --git a/apps/admin/src/app/layout.tsx b/apps/admin/src/app/layout.tsx
new file mode 100644
index 00000000..a55739bf
--- /dev/null
+++ b/apps/admin/src/app/layout.tsx
@@ -0,0 +1,21 @@
+import type { Metadata } from "next";
+import { Inter } from "next/font/google";
+import "./globals.css";
+
+const inter = Inter({ subsets: ["latin"], variable: "--font-inter" });
+
+export const metadata: Metadata = {
+ title: "Fused Gaming โ Admin",
+ description: "Brand management and deployment console",
+ robots: "noindex, nofollow",
+};
+
+export default function AdminLayout({ children }: { children: React.ReactNode }) {
+ return (
+
+
+ {children}
+
+
+ );
+}
diff --git a/apps/admin/src/app/page.tsx b/apps/admin/src/app/page.tsx
new file mode 100644
index 00000000..0362c3ed
--- /dev/null
+++ b/apps/admin/src/app/page.tsx
@@ -0,0 +1,5 @@
+import AdminDashboard from "@/components/AdminDashboard";
+
+export default function AdminPage() {
+ return ;
+}
diff --git a/apps/admin/src/components/AdminDashboard.tsx b/apps/admin/src/components/AdminDashboard.tsx
new file mode 100644
index 00000000..6d86c066
--- /dev/null
+++ b/apps/admin/src/components/AdminDashboard.tsx
@@ -0,0 +1,119 @@
+"use client";
+
+import { useState } from "react";
+import BrandFormPanel from "@/components/panels/BrandFormPanel";
+import TokenPanel from "@/components/panels/TokenPanel";
+import DeployPanel from "@/components/panels/DeployPanel";
+import PreviewPanel from "@/components/panels/PreviewPanel";
+
+type Tab = "form" | "tokens" | "preview" | "deploy" | "status";
+
+const TABS: { id: Tab; label: string; icon: string }[] = [
+ { id: "form", label: "Brand", icon: "โฆ" },
+ { id: "tokens", label: "Tokens", icon: "โฌก" },
+ { id: "preview", label: "Preview", icon: "โ" },
+ { id: "deploy", label: "Deploy", icon: "๐" },
+ { id: "status", label: "Status", icon: "โ" },
+];
+
+export default function AdminDashboard() {
+ const [activeTab, setActiveTab] = useState("form");
+ const [sidebarOpen, setSidebarOpen] = useState(true);
+
+ return (
+
+ {/* Sidebar */}
+
+ {/* Logo */}
+
+ setSidebarOpen((v) => !v)}
+ className="text-sm font-black"
+ style={{ color: "var(--admin-primary)" }}
+ >
+ FG
+
+ {sidebarOpen && (
+ Admin Console
+ )}
+
+
+ {/* Nav */}
+
+ {TABS.map((tab) => (
+ setActiveTab(tab.id)}
+ className="flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm font-medium text-left transition-all"
+ style={{
+ background: activeTab === tab.id ? "rgba(220,38,38,0.15)" : "transparent",
+ color: activeTab === tab.id ? "var(--admin-primary)" : "var(--admin-muted)",
+ border: `1px solid ${activeTab === tab.id ? "rgba(220,38,38,0.3)" : "transparent"}`,
+ }}
+ >
+ {tab.icon}
+ {sidebarOpen && {tab.label} }
+
+ ))}
+
+
+ {/* Status indicator */}
+ {sidebarOpen && (
+
+ )}
+
+
+ {/* Main content */}
+
+ {/* Top bar */}
+
+
+
+ {TABS.find((t) => t.id === activeTab)?.label}
+
+
+ {activeTab === "form" && "Define brand identity and copy"}
+ {activeTab === "tokens" && "Customize design tokens and CSS variables"}
+ {activeTab === "preview"&& "Live component preview across breakpoints"}
+ {activeTab === "deploy" && "Build and deploy to any target"}
+ {activeTab === "status" && "System health across all domains"}
+
+
+
+ โ /status
+
+
+
+ {/* Panel content */}
+
+ {activeTab === "form" &&
}
+ {activeTab === "tokens" &&
}
+ {activeTab === "preview" &&
}
+ {activeTab === "deploy" &&
}
+ {activeTab === "status" && (
+
+
Status dashboard โ see /apps/web/src/app/status/page.tsx
+
+ )}
+
+
+
+ );
+}
diff --git a/apps/admin/src/components/panels/BrandFormPanel.tsx b/apps/admin/src/components/panels/BrandFormPanel.tsx
new file mode 100644
index 00000000..f399716f
--- /dev/null
+++ b/apps/admin/src/components/panels/BrandFormPanel.tsx
@@ -0,0 +1,172 @@
+"use client";
+
+import { useAdminStore } from "@/lib/brandStore";
+
+const COPY_VARIANTS = ["urgency", "exclusivity", "authority", "rebellion", "data"];
+const ANIMATION_PRESETS = ["smooth", "fast", "glitch", "static"] as const;
+
+export default function BrandFormPanel() {
+ const { draft, setDraftField } = useAdminStore();
+
+ return (
+
+
+ Brand Identity
+
+
+ {/* ID */}
+
+ setDraftField("id", e.target.value)}
+ placeholder="stakeclaimbot"
+ className="admin-input"
+ />
+
+
+ {/* Name */}
+
+ setDraftField("name", e.target.value)}
+ placeholder="StakeClaimBot"
+ className="admin-input"
+ />
+
+
+ {/* Domain */}
+
+ setDraftField("domain", e.target.value)}
+ placeholder="stakeclaimbot.com"
+ className="admin-input"
+ />
+
+
+ {/* Tagline */}
+
+ setDraftField("tagline", e.target.value)}
+ placeholder="Automate Your Stake Claims"
+ className="admin-input"
+ />
+
+
+ {/* Sub tagline */}
+
+
+
+ {/* CTA */}
+
+ setDraftField("ctaPrimary", e.target.value)}
+ placeholder="Claim Now"
+ className="admin-input"
+ />
+
+
+ {/* Affiliate commission */}
+
+ setDraftField("affiliateCommission", e.target.value)}
+ placeholder="20%"
+ className="admin-input"
+ />
+
+
+ {/* Copy variant */}
+
+
+ {COPY_VARIANTS.map((v) => (
+ setDraftField("copyVariant", v)}
+ className="px-3 py-1.5 rounded-md text-xs font-medium capitalize transition-all"
+ style={{
+ background: draft.copyVariant === v ? "var(--admin-primary)" : "var(--admin-surface2)",
+ color: draft.copyVariant === v ? "white" : "var(--admin-muted)",
+ border: `1px solid ${draft.copyVariant === v ? "var(--admin-primary)" : "var(--admin-border)"}`,
+ }}
+ >
+ {v}
+
+ ))}
+
+
+
+ {/* Animation */}
+
+
+ {ANIMATION_PRESETS.map((v) => (
+ setDraftField("animation", v)}
+ className="px-3 py-1.5 rounded-md text-xs font-medium capitalize transition-all"
+ style={{
+ background: draft.animation === v ? "var(--admin-primary)" : "var(--admin-surface2)",
+ color: draft.animation === v ? "white" : "var(--admin-muted)",
+ border: `1px solid ${draft.animation === v ? "var(--admin-primary)" : "var(--admin-border)"}`,
+ }}
+ >
+ {v}
+
+ ))}
+
+
+
+
+
+ );
+}
+
+function Field({ label, hint, children }: { label: string; hint?: string; children: React.ReactNode }) {
+ return (
+
+
+ {label}
+ {hint && (
+
+ {hint}
+
+ )}
+
+ {children}
+
+ );
+}
diff --git a/apps/admin/src/components/panels/DeployPanel.tsx b/apps/admin/src/components/panels/DeployPanel.tsx
new file mode 100644
index 00000000..5fdf1b53
--- /dev/null
+++ b/apps/admin/src/components/panels/DeployPanel.tsx
@@ -0,0 +1,183 @@
+"use client";
+
+import { useState } from "react";
+import { useAdminStore, type DeployProvider } from "@/lib/brandStore";
+
+const PROVIDERS: { id: DeployProvider; label: string; desc: string; icon: string }[] = [
+ { id: "vercel", label: "Vercel", desc: "Edge CDN, instant HTTPS, CNAME setup", icon: "โฒ" },
+ { id: "vps", label: "VPS", desc: "Bare metal / PM2. Set DEPLOY_HOST env.", icon: "๐ฅ" },
+ { id: "docker", label: "Docker", desc: "Container image with brand ARGs baked in", icon: "๐ณ" },
+];
+
+export default function DeployPanel() {
+ const { draft, brands, deployJobs, startDeploy, finishDeploy, appendLog } = useAdminStore();
+ const [provider, setProvider] = useState("vercel");
+ const [deploying, setDeploying] = useState(false);
+
+ // Use draft if it has an ID, otherwise show existing brands
+ const targetId = draft.id || (brands[0]?.id ?? "");
+ const job = deployJobs.find((j) => j.brandId === targetId);
+
+ async function handleDeploy() {
+ if (!targetId) return;
+ setDeploying(true);
+ startDeploy(targetId, provider);
+
+ // Simulate deploy log stream (real impl: SSE from /api/deploy route)
+ const steps = [
+ "Installing dependencies...",
+ `Building Next.js (NEXT_PUBLIC_BRAND=${targetId})...`,
+ "Generating CSS variable bundle...",
+ provider === "vercel" ? "Uploading to Vercel edge network..." : `Syncing to ${provider}...`,
+ "Running post-build checks...",
+ "Deploy complete โ",
+ ];
+
+ for (let i = 0; i < steps.length; i++) {
+ await new Promise((r) => setTimeout(r, 800 + i * 400));
+ appendLog(targetId, steps[i]);
+ }
+
+ finishDeploy(targetId, "deployed");
+ setDeploying(false);
+ }
+
+ return (
+
+ {/* Existing brands list */}
+
+
+ Active Brands
+
+
+ {brands.map((b) => {
+ const bJob = deployJobs.find((j) => j.brandId === b.id);
+ return (
+
+
+
{b.name}
+
{b.domain}
+
+
+
+ { startDeploy(b.id, provider); }}
+ className="text-xs px-3 py-1.5 rounded-md font-medium transition-all"
+ style={{ background: "var(--admin-surface2)", border: "1px solid var(--admin-border)", color: "var(--admin-muted)" }}
+ >
+ Re-deploy
+
+
+
+ );
+ })}
+
+
+
+ {/* Provider selector */}
+
+
+ Deploy Target
+
+
+ {PROVIDERS.map((p) => (
+
setProvider(p.id)}
+ className="text-left p-4 rounded-lg transition-all"
+ style={{
+ background: provider === p.id ? "rgba(220,38,38,0.1)" : "var(--admin-surface)",
+ border: `1px solid ${provider === p.id ? "var(--admin-primary)" : "var(--admin-border)"}`,
+ }}
+ >
+ {p.icon}
+ {p.label}
+ {p.desc}
+
+ ))}
+
+
+
+ {/* Deploy command preview */}
+
+
+ Deploy Command
+
+
+ {`./scripts/deploy.sh ${targetId || ""} ${provider}`}
+
+
+
+ {/* Launch button */}
+
+ {deploying ? "Deploying..." : `๐ Deploy ${targetId || "Brand"} โ ${provider}`}
+
+
+ {/* Log output */}
+ {job && job.log.length > 0 && (
+
+
+ Build Log
+
+
+ {job.log.map((line, i) => (
+
+ {line}
+
+ ))}
+ {deploying && (
+
+ โ
+
+ )}
+
+
+ )}
+
+ );
+}
+
+function StatusBadge({ status }: { status: string }) {
+ const colors: Record = {
+ idle: "var(--admin-faint)",
+ building: "var(--admin-warning)",
+ deployed: "var(--admin-success)",
+ error: "var(--admin-error)",
+ };
+ return (
+
+ {status}
+
+ );
+}
diff --git a/apps/admin/src/components/panels/PreviewPanel.tsx b/apps/admin/src/components/panels/PreviewPanel.tsx
new file mode 100644
index 00000000..0769f504
--- /dev/null
+++ b/apps/admin/src/components/panels/PreviewPanel.tsx
@@ -0,0 +1,157 @@
+"use client";
+
+import { useAdminStore } from "@/lib/brandStore";
+
+// ASCII resolution labels
+const VIEWPORTS = [
+ { key: "xs", label: "XS โ 320px", width: 320 },
+ { key: "sm", label: "SM โ 640px", width: 640 },
+ { key: "md", label: "MD โ 768px", width: 768 },
+ { key: "lg", label: "LG โ 1024px", width: 1024 },
+ { key: "xl", label: "XL โ 1280px", width: 1280 },
+];
+
+export default function PreviewPanel() {
+ const { draft, previewCSS } = useAdminStore();
+ const palette = { ...draft.palette, ...draft.overrides };
+
+ return (
+
+
+ Live Token Preview โ {draft.name || "New Brand"}
+
+
+
+ {/* Color preview grid */}
+
+
+ Color System
+
+
+ {/* Simulated hero */}
+
+
+ โ Live โ Claiming Now
+
+
+
+ {draft.tagline || "Brand Tagline Here"}
+
+
+ {draft.subTagline || "Your brand sub-tagline will appear here."}
+
+
+
+ {draft.ctaPrimary || "Claim Now"}
+
+
+ Learn More
+
+
+
+ {/* Stats */}
+
+ {["700+", "$250K", "3 Years"].map((v, i) => (
+
+ ))}
+
+
+
+
+ {/* Card preview */}
+
+
+ Component Samples
+
+
+ {/* Card */}
+
+
+ โก
+
+
Auto Claims
+
Under 2 seconds.
+
+ {/* Credit package */}
+
+
+ Popular
+
+
$100
+
100,000 credits
+
10% Boost
+
+
+
+
+ {/* Viewport scale labels */}
+
+
+ Responsive Breakpoints
+
+
+ {VIEWPORTS.map((vp) => (
+
+
+ {vp.key.toUpperCase()}
+
+
+
{vp.label}
+
+ ))}
+
+
+
+ {/* CSS vars output */}
+
+
+ Generated :root Block
+
+
+ {`:root {\n ${previewCSS.split("\n").map(l => l.trim()).filter(Boolean).join("\n ")}\n}`}
+
+
+
+
+ );
+}
diff --git a/apps/admin/src/components/panels/TokenPanel.tsx b/apps/admin/src/components/panels/TokenPanel.tsx
new file mode 100644
index 00000000..1ab187ae
--- /dev/null
+++ b/apps/admin/src/components/panels/TokenPanel.tsx
@@ -0,0 +1,132 @@
+"use client";
+
+import { useAdminStore } from "@/lib/brandStore";
+import TokenSwatch from "@/components/ui/TokenSwatch";
+import type { BrandPalette, BrandTone } from "../../../../packages/tokens/src/tokens";
+
+const TOKEN_GROUPS: { label: string; keys: (keyof BrandPalette)[] }[] = [
+ {
+ label: "Primary",
+ keys: ["primary", "primaryDark", "primaryHover"],
+ },
+ {
+ label: "Backgrounds",
+ keys: ["background", "backgroundSecondary", "backgroundTertiary"],
+ },
+ {
+ label: "Text",
+ keys: ["text", "textMuted", "textFaint"],
+ },
+ {
+ label: "Borders",
+ keys: ["border", "borderGlow"],
+ },
+ {
+ label: "Accents",
+ keys: ["accent", "accentSecondary"],
+ },
+];
+
+const CSS_VAR_MAP: Record = {
+ primary: "--brand-primary",
+ primaryDark: "--brand-primary-dark",
+ primaryHover: "--brand-primary-hover",
+ background: "--brand-bg",
+ backgroundSecondary: "--brand-bg-secondary",
+ backgroundTertiary: "--brand-bg-tertiary",
+ accent: "--brand-accent",
+ accentSecondary: "--brand-accent-secondary",
+ text: "--brand-text",
+ textMuted: "--brand-muted",
+ textFaint: "--brand-faint",
+ border: "--brand-border",
+ borderGlow: "--brand-border-glow",
+};
+
+const TONES: BrandTone[] = ["aggressive", "corporate", "playful", "underground", "premium"];
+
+export default function TokenPanel() {
+ const { draft, setTone, setOverride, refreshPreviewCSS, previewCSS } = useAdminStore();
+
+ function handleOverride(key: keyof BrandPalette, value: string) {
+ setOverride(key, value);
+ refreshPreviewCSS();
+ }
+
+ const effectivePalette = { ...draft.palette, ...draft.overrides };
+
+ return (
+
+ {/* Tone selector */}
+
+
+ Brand Tone Preset
+
+
+ {TONES.map((tone) => (
+ { setTone(tone); refreshPreviewCSS(); }}
+ className="px-3 py-1.5 rounded-md text-xs font-medium capitalize transition-all"
+ style={{
+ background: draft.tone === tone ? "var(--admin-primary)" : "var(--admin-surface2)",
+ color: draft.tone === tone ? "white" : "var(--admin-muted)",
+ border: `1px solid ${draft.tone === tone ? "var(--admin-primary)" : "var(--admin-border)"}`,
+ }}
+ >
+ {tone}
+
+ ))}
+
+
+
+ {/* Token groups */}
+
+ {TOKEN_GROUPS.map((group) => (
+
+
+ {group.label}
+
+
+ {group.keys.map((key, i) => (
+
+ handleOverride(key, v)}
+ />
+
+ ))}
+
+
+ ))}
+
+ {/* Generated CSS output */}
+
+
+ Generated CSS Variables
+
+
+ {`:root {\n${previewCSS}\n}`}
+
+
+
+
+ );
+}
diff --git a/apps/admin/src/components/ui/TokenSwatch.tsx b/apps/admin/src/components/ui/TokenSwatch.tsx
new file mode 100644
index 00000000..2857309d
--- /dev/null
+++ b/apps/admin/src/components/ui/TokenSwatch.tsx
@@ -0,0 +1,43 @@
+"use client";
+
+interface TokenSwatchProps {
+ name: string;
+ cssVar: string;
+ hex: string;
+ onChange?: (value: string) => void;
+}
+
+export default function TokenSwatch({ name, cssVar, hex, onChange }: TokenSwatchProps) {
+ return (
+
+
+
+ {onChange && (
+ onChange(e.target.value)}
+ className="absolute inset-0 opacity-0 cursor-pointer w-full h-full"
+ />
+ )}
+
+
+
+ {cssVar}
+
+
+ {hex}
+
+
+
+ {name}
+
+
+ );
+}
diff --git a/apps/admin/src/lib/brandStore.ts b/apps/admin/src/lib/brandStore.ts
new file mode 100644
index 00000000..302ef0d4
--- /dev/null
+++ b/apps/admin/src/lib/brandStore.ts
@@ -0,0 +1,172 @@
+/**
+ * Admin Brand Store (Zustand)
+ *
+ * Manages:
+ * - List of all brand configs (loaded from /configs/brands/*.json)
+ * - Active brand being edited / previewed
+ * - Deploy state (idle | building | deployed | error)
+ * - Live CSS preview generation
+ */
+
+import { create } from "zustand";
+import {
+ type BrandTone,
+ type AnimationPreset,
+ type BrandPalette,
+ brandPalettes,
+ generateCSSVars,
+ getPaletteForTone,
+} from "../../../packages/tokens/src/tokens";
+
+export type DeployProvider = "vercel" | "vps" | "docker";
+export type DeployStatus = "idle" | "building" | "deployed" | "error";
+
+export interface BrandFormState {
+ id: string;
+ name: string;
+ domain: string;
+ tone: BrandTone;
+ animation: AnimationPreset;
+ copyVariant: string;
+ tagline: string;
+ subTagline: string;
+ ctaPrimary: string;
+ affiliateCommission: string;
+ palette: BrandPalette;
+ // override individual tokens
+ overrides: Partial;
+}
+
+export interface DeployJob {
+ brandId: string;
+ provider: DeployProvider;
+ status: DeployStatus;
+ log: string[];
+ startedAt: number;
+ finishedAt?: number;
+}
+
+interface AdminStore {
+ // Existing brands (loaded from configs)
+ brands: BrandFormState[];
+
+ // Brand being created/edited
+ draft: BrandFormState;
+ setDraftField: (key: K, value: BrandFormState[K]) => void;
+ setTone: (tone: BrandTone) => void;
+ setOverride: (key: keyof BrandPalette, value: string) => void;
+ resetDraft: () => void;
+
+ // Deploy
+ deployJobs: DeployJob[];
+ activeDeployId: string | null;
+ startDeploy: (brandId: string, provider: DeployProvider) => void;
+ appendLog: (brandId: string, line: string) => void;
+ finishDeploy: (brandId: string, status: "deployed" | "error") => void;
+
+ // Preview CSS
+ previewCSS: string;
+ refreshPreviewCSS: () => void;
+}
+
+const defaultDraft: BrandFormState = {
+ id: "",
+ name: "",
+ domain: "",
+ tone: "aggressive",
+ animation: "smooth",
+ copyVariant: "urgency",
+ tagline: "",
+ subTagline: "",
+ ctaPrimary: "Claim Now",
+ affiliateCommission: "20%",
+ palette: brandPalettes.aggressive,
+ overrides: {},
+};
+
+export const useAdminStore = create((set, get) => ({
+ brands: [
+ // Pre-seeded from the existing stakereloadxs config
+ {
+ id: "stakereloadxs",
+ name: "StakeReloadXS",
+ domain: "stakereloadxs.com",
+ tone: "aggressive",
+ animation: "smooth",
+ copyVariant: "urgency",
+ tagline: "Xtremely Simple Reloads",
+ subTagline: "Automated bonus claims for Stake in under 2 seconds.",
+ ctaPrimary: "Try It Free",
+ affiliateCommission: "20%",
+ palette: brandPalettes.aggressive,
+ overrides: {},
+ },
+ ],
+
+ draft: { ...defaultDraft },
+
+ setDraftField: (key, value) =>
+ set((s) => ({ draft: { ...s.draft, [key]: value } })),
+
+ setTone: (tone) =>
+ set((s) => ({
+ draft: {
+ ...s.draft,
+ tone,
+ palette: getPaletteForTone(tone),
+ overrides: {},
+ },
+ })),
+
+ setOverride: (key, value) =>
+ set((s) => {
+ const overrides = { ...s.draft.overrides, [key]: value };
+ const palette = { ...s.draft.palette, ...overrides };
+ return { draft: { ...s.draft, overrides, palette } };
+ }),
+
+ resetDraft: () => set({ draft: { ...defaultDraft } }),
+
+ deployJobs: [],
+ activeDeployId: null,
+
+ startDeploy: (brandId, provider) => {
+ const job: DeployJob = {
+ brandId,
+ provider,
+ status: "building",
+ log: [`[${new Date().toISOString()}] Starting deploy: ${brandId} โ ${provider}`],
+ startedAt: Date.now(),
+ };
+ set((s) => ({
+ deployJobs: [...s.deployJobs.filter((j) => j.brandId !== brandId), job],
+ activeDeployId: brandId,
+ }));
+ // Kick off server action / API call
+ get().appendLog(brandId, `Building Next.js with NEXT_PUBLIC_BRAND=${brandId}...`);
+ },
+
+ appendLog: (brandId, line) =>
+ set((s) => ({
+ deployJobs: s.deployJobs.map((j) =>
+ j.brandId === brandId
+ ? { ...j, log: [...j.log, `[${new Date().toISOString()}] ${line}`] }
+ : j
+ ),
+ })),
+
+ finishDeploy: (brandId, status) =>
+ set((s) => ({
+ deployJobs: s.deployJobs.map((j) =>
+ j.brandId === brandId ? { ...j, status, finishedAt: Date.now() } : j
+ ),
+ })),
+
+ previewCSS: generateCSSVars(brandPalettes.aggressive, "smooth"),
+
+ refreshPreviewCSS: () => {
+ const { draft } = get();
+ const palette = { ...draft.palette, ...draft.overrides };
+ set({ previewCSS: generateCSSVars(palette, draft.animation) });
+ },
+}));
diff --git a/apps/web/.env.example b/apps/web/.env.example
new file mode 100644
index 00000000..24ad6f24
--- /dev/null
+++ b/apps/web/.env.example
@@ -0,0 +1,26 @@
+# โโโ Brand โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+# ID must match a file in /configs/brands/.json
+NEXT_PUBLIC_BRAND=stakereloadxs
+
+# Public base URL (used in payment redirects and OG images)
+NEXT_PUBLIC_BASE_URL=https://stakereloadxs.com
+
+# โโโ Payments โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+# NOWPayments API key โ https://nowpayments.io/api-key
+NOWPAYMENTS_API_KEY=your_nowpayments_api_key_here
+
+# โโโ Analytics โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+# Google Analytics 4 measurement ID
+NEXT_PUBLIC_GA_ID=G-XXXXXXXXXX
+
+# Cloudflare Web Analytics beacon token
+NEXT_PUBLIC_CF_BEACON=your_cloudflare_beacon_token
+
+# โโโ Cron & Background Jobs โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+# Secret for authenticating cron endpoints (must be set for production)
+CRON_SECRET=your_secure_random_secret_here
+
+# โโโ Deployment metadata (auto-set by Vercel, set manually for VPS/Docker) โโโโ
+DEPLOY_TIMESTAMP=2025-01-01T00:00:00Z
+GIT_SHA=abc123def456
+VERCEL_REGION=iad1
diff --git a/apps/web/.gitignore b/apps/web/.gitignore
new file mode 100644
index 00000000..1ce0a224
--- /dev/null
+++ b/apps/web/.gitignore
@@ -0,0 +1,28 @@
+# Next.js
+.next/
+out/
+
+# Dependencies
+node_modules/
+
+# Environment
+.env
+.env.local
+.env.*.local
+
+# Build artifacts
+dist/
+build/
+
+# Debug
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+
+# OS
+.DS_Store
+Thumbs.db
+
+# TypeScript
+*.tsbuildinfo
+next-env.d.ts
diff --git a/apps/web/Dockerfile b/apps/web/Dockerfile
new file mode 100644
index 00000000..0a1c47f9
--- /dev/null
+++ b/apps/web/Dockerfile
@@ -0,0 +1,44 @@
+FROM node:20-alpine AS base
+
+# โโ Dependencies โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+FROM base AS deps
+WORKDIR /app
+COPY apps/web/package*.json ./apps/web/
+COPY package.json ./
+RUN npm install --prefix apps/web
+
+# โโ Builder โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+FROM base AS builder
+WORKDIR /app
+
+ARG NEXT_PUBLIC_BRAND=stakereloadxs
+ARG NEXT_PUBLIC_BASE_URL=https://stakereloadxs.com
+
+COPY --from=deps /app/apps/web/node_modules ./apps/web/node_modules
+COPY . .
+
+ENV NEXT_TELEMETRY_DISABLED=1
+ENV NEXT_PUBLIC_BRAND=$NEXT_PUBLIC_BRAND
+ENV NEXT_PUBLIC_BASE_URL=$NEXT_PUBLIC_BASE_URL
+
+RUN npm run build --prefix apps/web
+
+# โโ Runner โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+FROM base AS runner
+WORKDIR /app
+
+ENV NODE_ENV=production
+ENV NEXT_TELEMETRY_DISABLED=1
+
+RUN addgroup --system --gid 1001 nodejs && \
+ adduser --system --uid 1001 nextjs
+
+COPY --from=builder /app/apps/web/public ./public
+COPY --from=builder --chown=nextjs:nodejs /app/apps/web/.next/standalone ./
+COPY --from=builder --chown=nextjs:nodejs /app/apps/web/.next/static ./.next/static
+
+USER nextjs
+EXPOSE 3000
+ENV PORT=3000
+
+CMD ["node", "server.js"]
diff --git a/apps/web/eslint.config.mjs b/apps/web/eslint.config.mjs
new file mode 100644
index 00000000..8948ff59
--- /dev/null
+++ b/apps/web/eslint.config.mjs
@@ -0,0 +1,12 @@
+import { dirname } from "path";
+import { fileURLToPath } from "url";
+import { FlatCompat } from "@eslint/eslintrc";
+
+const __filename = fileURLToPath(import.meta.url);
+const __dirname = dirname(__filename);
+
+const compat = new FlatCompat({ baseDirectory: __dirname });
+
+export default [
+ ...compat.extends("next/core-web-vitals"),
+];
diff --git a/apps/web/next.config.js b/apps/web/next.config.js
new file mode 100644
index 00000000..b22f0e8e
--- /dev/null
+++ b/apps/web/next.config.js
@@ -0,0 +1,28 @@
+/** @type {import('next').NextConfig} */
+const nextConfig = {
+ // Multi-brand: brand key injected at build time or via env
+ env: {
+ NEXT_PUBLIC_BRAND: process.env.NEXT_PUBLIC_BRAND || "stakereloadxs",
+ },
+ // Allow serving from any domain
+ async headers() {
+ return [
+ {
+ source: "/(.*)",
+ headers: [
+ { key: "X-Frame-Options", value: "DENY" },
+ { key: "X-Content-Type-Options", value: "nosniff" },
+ { key: "Referrer-Policy", value: "strict-origin-when-cross-origin" },
+ ],
+ },
+ ];
+ },
+ images: {
+ remotePatterns: [
+ { protocol: "https", hostname: "trustpilot.xyz" },
+ { protocol: "https", hostname: "cdn.trustpilot.xyz" },
+ ],
+ },
+};
+
+module.exports = nextConfig;
diff --git a/apps/web/package.json b/apps/web/package.json
new file mode 100644
index 00000000..d14188d0
--- /dev/null
+++ b/apps/web/package.json
@@ -0,0 +1,37 @@
+{
+ "name": "@fused-gaming/web",
+ "version": "1.0.0",
+ "private": true,
+ "scripts": {
+ "dev": "next dev",
+ "build": "next build",
+ "start": "next start",
+ "lint": "next lint",
+ "type-check": "tsc --noEmit"
+ },
+ "dependencies": {
+ "next": "15.5.13",
+ "react": "^18.3.1",
+ "react-dom": "^18.3.1",
+ "framer-motion": "^11.3.8",
+ "zustand": "^4.5.4",
+ "next-intl": "^3.17.2",
+ "clsx": "^2.1.1",
+ "tailwind-merge": "^2.4.0",
+ "@radix-ui/react-dialog": "^1.1.1",
+ "@radix-ui/react-accordion": "^1.2.0",
+ "lucide-react": "^0.416.0"
+ },
+ "devDependencies": {
+ "@types/node": "^20.14.10",
+ "@types/react": "^18.3.3",
+ "@types/react-dom": "^18.3.0",
+ "autoprefixer": "^10.4.19",
+ "postcss": "^8.4.39",
+ "tailwindcss": "^3.4.6",
+ "typescript": "^5.5.3",
+ "@eslint/eslintrc": "^3.3.1",
+ "eslint": "^9.39.4",
+ "eslint-config-next": "16.2.0"
+ }
+}
diff --git a/apps/web/postcss.config.js b/apps/web/postcss.config.js
new file mode 100644
index 00000000..12a703d9
--- /dev/null
+++ b/apps/web/postcss.config.js
@@ -0,0 +1,6 @@
+module.exports = {
+ plugins: {
+ tailwindcss: {},
+ autoprefixer: {},
+ },
+};
diff --git a/apps/web/src/app/affiliates/page.tsx b/apps/web/src/app/affiliates/page.tsx
new file mode 100644
index 00000000..ed1a61c2
--- /dev/null
+++ b/apps/web/src/app/affiliates/page.tsx
@@ -0,0 +1,30 @@
+import type { Metadata } from "next";
+import { loadBrandConfig } from "@/lib/brand";
+import AffiliatesClient from "@/components/AffiliatesClient";
+
+export async function generateMetadata(): Promise {
+ const brand = await loadBrandConfig();
+ const baseUrl = process.env.NEXT_PUBLIC_BASE_URL ?? `https://${brand.domain}`;
+ const ogImage = `${baseUrl}/og?page=affiliates`;
+
+ return {
+ title: `Affiliates โ ${brand.name}`,
+ description: `Earn ${brand.affiliateCommission} commission referring players to ${brand.name}. ${brand.affiliateDescription}`,
+ openGraph: {
+ title: `Affiliates โ ${brand.name}`,
+ description: brand.affiliateDescription,
+ url: `${baseUrl}/affiliates`,
+ images: [{ url: ogImage, width: 1200, height: 630, alt: `${brand.name} Affiliates` }],
+ },
+ twitter: {
+ card: "summary_large_image",
+ title: `Affiliates โ ${brand.name}`,
+ images: [ogImage],
+ },
+ };
+}
+
+export default async function AffiliatesPage() {
+ const brand = await loadBrandConfig();
+ return ;
+}
diff --git a/apps/web/src/app/api/cron/refresh-stats/route.ts b/apps/web/src/app/api/cron/refresh-stats/route.ts
new file mode 100644
index 00000000..48933474
--- /dev/null
+++ b/apps/web/src/app/api/cron/refresh-stats/route.ts
@@ -0,0 +1,127 @@
+/**
+ * GET /api/cron/refresh-stats
+ *
+ * Runs every 15 minutes (configured in vercel.json or via external cron).
+ * Refreshes cached analytics, payment stats, and status snapshots.
+ *
+ * Auth: Bearer token via CRON_SECRET env var.
+ * Vercel Cron: add to vercel.json โ { "crons": [{ "path": "/api/cron/refresh-stats", "schedule": "0,15,30,45 * * * *" }] }
+ * External cron (VPS): Use cron expression for every 15 minutes (e.g., 0,15,30,45 * * * *) - curl -H "Authorization: Bearer $CRON_SECRET" https://example.com/api/cron/refresh-stats
+ */
+
+import { NextRequest, NextResponse } from "next/server";
+import { loadBrandConfig } from "@/lib/brand";
+
+export const runtime = "nodejs";
+export const dynamic = "force-dynamic";
+
+interface StatSnapshot {
+ brandId: string;
+ domain: string;
+ snapshotAt: string;
+ nowpaymentsOk: boolean;
+ dnsOk: boolean;
+ responseMs: number;
+ ga: {
+ configured: boolean;
+ measurementId: string | null;
+ };
+ cf: {
+ beaconConfigured: boolean;
+ dnsResolved: boolean;
+ resolvedTo: string[];
+ };
+}
+
+// Simple in-memory cache (replace with KV / DB in production)
+let lastSnapshot: StatSnapshot | null = null;
+let lastRun: Date | null = null;
+
+export async function GET(req: NextRequest) {
+ // โโ Auth โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+ const cronSecret = process.env.CRON_SECRET;
+ if (!cronSecret) {
+ return NextResponse.json({ error: "Cron secret not configured" }, { status: 500 });
+ }
+ const auth = req.headers.get("authorization");
+ if (auth !== `Bearer ${cronSecret}`) {
+ return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
+ }
+
+ const start = Date.now();
+ const brand = await loadBrandConfig();
+
+ // โโ NOWPayments health โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+ let nowpaymentsOk = false;
+ try {
+ const res = await fetch("https://api.nowpayments.io/v1/status", {
+ signal: AbortSignal.timeout(5000),
+ });
+ nowpaymentsOk = res.ok;
+ } catch { /* ignore */ }
+
+ // โโ DNS check โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+ let dnsOk = false;
+ let resolvedTo: string[] = [];
+ try {
+ const res = await fetch(
+ `https://cloudflare-dns.com/dns-query?name=${brand.domain}&type=A`,
+ { headers: { Accept: "application/dns-json" }, signal: AbortSignal.timeout(5000) }
+ );
+ if (res.ok) {
+ const data = await res.json();
+ resolvedTo = (data?.Answer ?? []).map((a: { data: string }) => a.data);
+ dnsOk = resolvedTo.length > 0;
+ }
+ } catch { /* ignore */ }
+
+ const snapshot: StatSnapshot = {
+ brandId: brand.id,
+ domain: brand.domain,
+ snapshotAt: new Date().toISOString(),
+ nowpaymentsOk,
+ dnsOk,
+ responseMs: Date.now() - start,
+ ga: {
+ configured: !!process.env.NEXT_PUBLIC_GA_ID,
+ measurementId: process.env.NEXT_PUBLIC_GA_ID ?? null,
+ },
+ cf: {
+ beaconConfigured: !!process.env.NEXT_PUBLIC_CF_BEACON,
+ dnsResolved: dnsOk,
+ resolvedTo,
+ },
+ };
+
+ // Cache the snapshot
+ lastSnapshot = snapshot;
+ lastRun = new Date();
+
+ // In production: persist to Vercel KV / Upstash / your DB here
+ // await kv.set(`status:${brand.id}`, JSON.stringify(snapshot), { ex: 1800 });
+
+ return NextResponse.json({
+ ok: true,
+ snapshot,
+ nextRunIn: "15 minutes",
+ cachedAt: lastRun.toISOString(),
+ });
+}
+
+/** POST /api/cron/refresh-stats โ return last cached snapshot without re-running */
+export async function POST(req: NextRequest) {
+ // โโ Auth โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+ const cronSecret = process.env.CRON_SECRET;
+ if (!cronSecret) {
+ return NextResponse.json({ error: "Cron secret not configured" }, { status: 500 });
+ }
+ const auth = req.headers.get("authorization");
+ if (auth !== `Bearer ${cronSecret}`) {
+ return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
+ }
+
+ if (!lastSnapshot) {
+ return NextResponse.json({ ok: false, message: "No snapshot yet. Call GET first." }, { status: 404 });
+ }
+ return NextResponse.json({ ok: true, snapshot: lastSnapshot, cachedAt: lastRun?.toISOString() });
+}
diff --git a/apps/web/src/app/api/payments/create/route.ts b/apps/web/src/app/api/payments/create/route.ts
new file mode 100644
index 00000000..2936a88f
--- /dev/null
+++ b/apps/web/src/app/api/payments/create/route.ts
@@ -0,0 +1,77 @@
+import { NextRequest, NextResponse } from "next/server";
+import { loadBrandConfig } from "@/lib/brand";
+
+interface PaymentRequestBody {
+ packageId: string;
+ packageName: string;
+ price: number;
+ credits: number;
+ telegram: string;
+}
+
+export async function POST(req: NextRequest) {
+ try {
+ const body: PaymentRequestBody = await req.json();
+
+ // Validate telegram username
+ const telegramRegex = /^@[a-zA-Z0-9_]{4,31}$/;
+ if (!telegramRegex.test(body.telegram)) {
+ return NextResponse.json({ message: "Invalid Telegram username" }, { status: 400 });
+ }
+
+ // Load brand config and validate package
+ const brand = await loadBrandConfig();
+ const validPackage = brand.creditPackages.find((pkg) => pkg.id === body.packageId);
+
+ if (!validPackage) {
+ return NextResponse.json({ message: "Invalid package" }, { status: 400 });
+ }
+
+ // Validate that submitted package details match the configured package
+ if (
+ validPackage.name !== body.packageName ||
+ validPackage.price !== body.price ||
+ validPackage.credits !== body.credits
+ ) {
+ return NextResponse.json({ message: "Invalid package" }, { status: 400 });
+ }
+
+ const nowpaymentsApiKey = process.env.NOWPAYMENTS_API_KEY;
+ if (!nowpaymentsApiKey) {
+ return NextResponse.json({ message: "Payment system not configured" }, { status: 503 });
+ }
+
+ const baseUrl = process.env.NEXT_PUBLIC_BASE_URL ?? `https://${process.env.NEXT_PUBLIC_BRAND ?? "stakereloadxs"}.com`;
+
+ // Create NOWPayments invoice using validated package data
+ const response = await fetch("https://api.nowpayments.io/v1/invoice", {
+ method: "POST",
+ headers: {
+ "x-api-key": nowpaymentsApiKey,
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify({
+ price_amount: validPackage.price,
+ price_currency: "usd",
+ order_id: `${validPackage.id}-${Date.now()}`,
+ order_description: `${validPackage.name} โ ${body.telegram}`,
+ success_url: `${baseUrl}/payment-success`,
+ cancel_url: `${baseUrl}/payment-cancel`,
+ is_fixed_rate: true,
+ is_fee_paid_by_user: false,
+ }),
+ });
+
+ if (!response.ok) {
+ const err = await response.json().catch(() => ({}));
+ console.error("NOWPayments error:", err);
+ return NextResponse.json({ message: "Payment provider error" }, { status: 502 });
+ }
+
+ const data = await response.json();
+ return NextResponse.json({ paymentUrl: data.invoice_url });
+ } catch (err) {
+ console.error("Payment route error:", err);
+ return NextResponse.json({ message: "Internal server error" }, { status: 500 });
+ }
+}
diff --git a/apps/web/src/app/api/status/route.ts b/apps/web/src/app/api/status/route.ts
new file mode 100644
index 00000000..5dccc08a
--- /dev/null
+++ b/apps/web/src/app/api/status/route.ts
@@ -0,0 +1,186 @@
+import { NextRequest, NextResponse } from "next/server";
+import { loadBrandConfig } from "@/lib/brand";
+
+/**
+ * GET /api/status
+ *
+ * Returns full operational status for this brand deployment.
+ * Used by:
+ * - /status page (HTML dashboard)
+ * - Admin console status panel
+ * - External uptime monitors (e.g. UptimeRobot, BetterUptime)
+ * - Developer CLI health checks
+ *
+ * Template variables injected from brand config:
+ * {{BRAND_ID}}, {{BRAND_NAME}}, {{BRAND_DOMAIN}}, {{DEPLOY_ENV}}
+ */
+export async function GET(req: NextRequest) {
+ const brand = await loadBrandConfig();
+ const startTime = Date.now();
+
+ // โโ Collect check results โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+ const checks = await Promise.allSettled([
+ checkPaymentApi(),
+ checkNowPayments(),
+ checkAnalyticsReachable(),
+ checkCloudflare(brand.domain),
+ ]);
+
+ const [paymentApi, nowPayments, analytics, cloudflare] = checks.map((c) =>
+ c.status === "fulfilled" ? c.value : { status: "error", message: (c as PromiseRejectedResult).reason?.message ?? "Check failed" }
+ );
+
+ const deployedAt = process.env.DEPLOY_TIMESTAMP ?? null;
+ const gitSha = process.env.VERCEL_GIT_COMMIT_SHA ?? process.env.GIT_SHA ?? null;
+ const env = process.env.NODE_ENV ?? "development";
+ const region = process.env.VERCEL_REGION ?? process.env.FLY_REGION ?? "unknown";
+
+ // โโ Features enabled per-brand โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+ const features = {
+ nowpaymentsConfigured: !!process.env.NOWPAYMENTS_API_KEY,
+ tawkConfigured: !!brand.chat?.propertyId,
+ affiliatesEnabled: true,
+ creditPackagesCount: brand.creditPackages?.length ?? 0,
+ servicesCount: brand.services?.length ?? 0,
+ demoVideoEnabled: !!brand.demoVideoId,
+ multiLanguage: false, // expand as i18n is added
+ analyticsEnabled: !!process.env.NEXT_PUBLIC_GA_ID || !!process.env.NEXT_PUBLIC_CF_BEACON,
+ };
+
+ const allHealthy = [paymentApi, nowPayments, cloudflare].every(
+ (c) => (c as { status: string }).status === "ok"
+ );
+
+ const responseTimeMs = Date.now() - startTime;
+
+ const payload = {
+ // โโ Identity โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+ brand: {
+ id: brand.id,
+ name: brand.name,
+ domain: brand.domain,
+ tone: brand.tone,
+ },
+
+ // โโ Deployment โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+ deployment: {
+ environment: env,
+ region,
+ gitSha,
+ deployedAt,
+ nextVersion: process.env.NEXT_RUNTIME_VERSION ?? null,
+ nodeVersion: process.versions?.node ?? null,
+ },
+
+ // โโ Health โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+ health: {
+ overall: allHealthy ? "healthy" : "degraded",
+ responseMs: responseTimeMs,
+ checks: {
+ paymentApi,
+ nowPayments,
+ analytics,
+ cloudflare,
+ },
+ },
+
+ // โโ Features โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+ features,
+
+ // โโ Analytics โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+ analytics: {
+ googleAnalyticsId: process.env.NEXT_PUBLIC_GA_ID ?? null,
+ cloudflareBeaconId: process.env.NEXT_PUBLIC_CF_BEACON ?? null,
+ tawkPropertyId: brand.chat?.propertyId ?? null,
+ },
+
+ // โโ Cloudflare โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+ cloudflare: cloudflare as object,
+
+ // โโ Sales Config โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+ sales: {
+ creditPackages: brand.creditPackages?.map((p) => ({ id: p.id, name: p.name, price: p.price })) ?? [],
+ affiliateCommission: brand.affiliateCommission,
+ paymentProvider: brand.payment?.provider ?? "nowpayments",
+ telegramRequired: brand.payment?.telegramRequired ?? true,
+ },
+
+ // โโ Timestamp โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+ timestamp: new Date().toISOString(),
+ };
+
+ return NextResponse.json(payload, {
+ status: 200,
+ headers: {
+ "Cache-Control": "no-store, no-cache",
+ "X-Brand-Id": brand.id,
+ "X-Brand-Domain": brand.domain,
+ },
+ });
+}
+
+// โโ Individual checks โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+
+async function checkPaymentApi() {
+ if (!process.env.NOWPAYMENTS_API_KEY) {
+ return { status: "unconfigured", message: "NOWPAYMENTS_API_KEY not set" };
+ }
+ try {
+ const res = await fetch("https://api.nowpayments.io/v1/status", {
+ headers: { "x-api-key": process.env.NOWPAYMENTS_API_KEY },
+ signal: AbortSignal.timeout(4000),
+ });
+ return res.ok
+ ? { status: "ok", message: "Payment API reachable" }
+ : { status: "error", message: `HTTP ${res.status}` };
+ } catch (e) {
+ return { status: "error", message: e instanceof Error ? e.message : "Unreachable" };
+ }
+}
+
+async function checkNowPayments() {
+ try {
+ const res = await fetch("https://api.nowpayments.io/v1/status", {
+ signal: AbortSignal.timeout(4000),
+ });
+ const data = await res.json().catch(() => ({}));
+ return { status: "ok", message: data?.message ?? "NOWPayments API online" };
+ } catch {
+ return { status: "error", message: "NOWPayments API unreachable" };
+ }
+}
+
+async function checkAnalyticsReachable() {
+ const gaId = process.env.NEXT_PUBLIC_GA_ID;
+ const cfBeacon = process.env.NEXT_PUBLIC_CF_BEACON;
+ if (!gaId && !cfBeacon) {
+ return { status: "unconfigured", message: "No analytics configured" };
+ }
+ return {
+ status: "ok",
+ providers: [
+ gaId ? "Google Analytics" : null,
+ cfBeacon ? "Cloudflare Web Analytics" : null,
+ ].filter(Boolean),
+ };
+}
+
+async function checkCloudflare(domain: string) {
+ try {
+ const res = await fetch(`https://cloudflare-dns.com/dns-query?name=${domain}&type=A`, {
+ headers: { Accept: "application/dns-json" },
+ signal: AbortSignal.timeout(5000),
+ });
+ if (!res.ok) return { status: "error", message: `DNS query failed: HTTP ${res.status}` };
+ const data = await res.json();
+ const answers = data?.Answer ?? [];
+ return {
+ status: answers.length > 0 ? "ok" : "warning",
+ domain,
+ resolvedTo: answers.map((a: { data: string }) => a.data),
+ message: answers.length > 0 ? `Domain resolves (${answers.length} record(s))` : "No DNS records found",
+ };
+ } catch (e) {
+ return { status: "error", message: e instanceof Error ? e.message : "DNS check failed" };
+ }
+}
diff --git a/apps/web/src/app/globals.css b/apps/web/src/app/globals.css
new file mode 100644
index 00000000..3ba5074b
--- /dev/null
+++ b/apps/web/src/app/globals.css
@@ -0,0 +1,110 @@
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
+
+/* โโ Brand CSS variables (overridden per-brand in layout) โโ */
+:root {
+ --brand-primary: #dc2626;
+ --brand-primary-dark: #b91c1c;
+ --brand-primary-hover: #ef4444;
+ --brand-bg: #000000;
+ --brand-bg-secondary: #111111;
+ --brand-bg-tertiary: #1a1a1a;
+ --brand-accent: #dc2626;
+ --brand-accent-secondary: #ef4444;
+ --brand-text: #f3f4f6;
+ --brand-muted: #9ca3af;
+ --brand-faint: #4b5563;
+ --brand-border: #222222;
+ --brand-border-glow: #dc2626;
+ --font-poppins: 'Poppins', sans-serif;
+ --font-inter: 'Inter', sans-serif;
+}
+
+/* โโ Base resets โโ */
+html {
+ scroll-behavior: smooth;
+}
+
+body {
+ font-family: var(--font-poppins), var(--font-inter), system-ui, sans-serif;
+ background-color: var(--brand-bg);
+ color: var(--brand-text);
+}
+
+/* โโ Utility classes โโ */
+@layer components {
+ .btn-primary {
+ @apply inline-flex items-center justify-center px-6 py-3 rounded-md font-semibold text-white transition-all duration-200;
+ background-color: var(--brand-primary);
+ }
+ .btn-primary:hover {
+ background-color: var(--brand-primary-hover);
+ }
+
+ .btn-secondary {
+ @apply inline-flex items-center justify-center px-6 py-3 rounded-md font-semibold transition-all duration-200;
+ background-color: transparent;
+ border: 1px solid var(--brand-border);
+ color: var(--brand-text);
+ }
+ .btn-secondary:hover {
+ border-color: var(--brand-primary);
+ color: var(--brand-primary);
+ }
+
+ .card {
+ @apply rounded-xl p-6;
+ background-color: var(--brand-bg-secondary);
+ border: 1px solid var(--brand-border);
+ }
+
+ .card-hover {
+ @apply transition-all duration-300;
+ }
+ .card-hover:hover {
+ border-color: var(--brand-primary);
+ }
+
+ .section-heading {
+ @apply text-3xl sm:text-4xl font-bold;
+ }
+
+ .section-subheading {
+ @apply text-lg mt-3;
+ color: var(--brand-muted);
+ }
+
+ .badge {
+ @apply inline-block text-xs font-semibold px-2 py-0.5 rounded-full;
+ background-color: var(--brand-primary);
+ color: white;
+ }
+
+ .divider {
+ @apply my-4;
+ border-color: var(--brand-border);
+ }
+}
+
+/* โโ Scrollbar โโ */
+::-webkit-scrollbar {
+ width: 6px;
+}
+::-webkit-scrollbar-track {
+ background: var(--brand-bg);
+}
+::-webkit-scrollbar-thumb {
+ background: var(--brand-border);
+ border-radius: 3px;
+}
+::-webkit-scrollbar-thumb:hover {
+ background: var(--brand-primary);
+}
+
+/* โโ Modal backdrop โโ */
+.modal-backdrop {
+ @apply fixed inset-0 z-50 flex items-center justify-center;
+ background: rgba(0, 0, 0, 0.85);
+ backdrop-filter: blur(4px);
+}
diff --git a/apps/web/src/app/layout.tsx b/apps/web/src/app/layout.tsx
new file mode 100644
index 00000000..2baebd3e
--- /dev/null
+++ b/apps/web/src/app/layout.tsx
@@ -0,0 +1,123 @@
+import type { Metadata } from "next";
+import { Poppins, Inter } from "next/font/google";
+import { loadBrandConfig, themeToCSSVars } from "@/lib/brand";
+import "./globals.css";
+
+const poppins = Poppins({
+ subsets: ["latin"],
+ weight: ["300", "400", "500", "600", "700", "800", "900"],
+ variable: "--font-poppins",
+ display: "swap",
+});
+
+const inter = Inter({
+ subsets: ["latin"],
+ variable: "--font-inter",
+ display: "swap",
+});
+
+export async function generateMetadata(): Promise {
+ const brand = await loadBrandConfig();
+ const baseUrl = process.env.NEXT_PUBLIC_BASE_URL ?? `https://${brand.domain}`;
+ const ogImage = `${baseUrl}/og`;
+
+ return {
+ title: brand.seo.title,
+ description: brand.seo.description,
+ keywords: brand.seo.keywords,
+ metadataBase: new URL(baseUrl),
+ openGraph: {
+ title: brand.seo.title,
+ description: brand.seo.description,
+ siteName: brand.name,
+ url: baseUrl,
+ type: "website",
+ images: [
+ {
+ url: ogImage,
+ width: 1200,
+ height: 630,
+ alt: brand.seo.title,
+ },
+ ],
+ },
+ twitter: {
+ card: "summary_large_image",
+ title: brand.seo.title,
+ description: brand.seo.description,
+ images: [ogImage],
+ },
+ other: {
+ // Cloudflare Web Analytics
+ ...(process.env.NEXT_PUBLIC_CF_BEACON
+ ? { "cf-beacon": JSON.stringify({ token: process.env.NEXT_PUBLIC_CF_BEACON }) }
+ : {}),
+ },
+ };
+}
+
+export default async function RootLayout({
+ children,
+}: {
+ children: React.ReactNode;
+}) {
+ const brand = await loadBrandConfig();
+ const cssVars = themeToCSSVars(brand.theme);
+ const gaId = process.env.NEXT_PUBLIC_GA_ID;
+ const cfBeacon = process.env.NEXT_PUBLIC_CF_BEACON;
+
+ return (
+
+
+
+ {/* Google Analytics */}
+ {gaId && (
+ <>
+
+
+ >
+ )}
+ {/* Cloudflare Web Analytics */}
+ {cfBeacon && (
+
+ )}
+
+
+ {children}
+ {/* Tawk.to chat โ injected per brand */}
+ {brand.chat?.provider === "tawk" && (
+
+ )}
+
+
+ );
+}
diff --git a/apps/web/src/app/og/route.tsx b/apps/web/src/app/og/route.tsx
new file mode 100644
index 00000000..b6e05249
--- /dev/null
+++ b/apps/web/src/app/og/route.tsx
@@ -0,0 +1,285 @@
+/**
+ * Dynamic OG Image Generator
+ *
+ * Routes:
+ * GET /og โ default brand OG (hero)
+ * GET /og?page=affiliates โ affiliates page OG
+ * GET /og?page=shop โ shop / credit packages OG
+ * GET /og?page=status โ system status OG
+ * GET /og?pkg=100k โ specific credit package OG (for share cards)
+ *
+ * All visuals derived from brand design tokens:
+ * --brand-primary, --brand-bg, --brand-text, etc.
+ *
+ * Uses Next.js ImageResponse (built on @vercel/og / Satori).
+ */
+
+import { ImageResponse } from "next/og";
+import { NextRequest } from "next/server";
+import { loadBrandConfig } from "@/lib/brand";
+
+export const runtime = "edge";
+
+export async function GET(req: NextRequest) {
+ const brand = await loadBrandConfig();
+ const { searchParams } = new URL(req.url);
+
+ const page = searchParams.get("page") ?? "home";
+ const pkgId = searchParams.get("pkg") ?? null;
+
+ // Resolve which copy/context to show
+ const ctx = resolveContext(brand, page, pkgId);
+
+ // Brand colors direct from config (not CSS vars โ Satori needs raw values)
+ const colors = {
+ bg: brand.theme.background,
+ bgSec: brand.theme.backgroundSecondary,
+ primary: brand.theme.primary,
+ text: brand.theme.text,
+ muted: brand.theme.textMuted,
+ faint: brand.theme.textFaint,
+ border: brand.theme.border,
+ };
+
+ return new ImageResponse(
+ (
+
+ {/* Grid background */}
+
+
+ {/* Top glow */}
+
+
+ {/* Left accent bar */}
+
+
+ {/* Content */}
+
+ {/* Top: brand name + badge */}
+
+
+ {brand.name}
+
+ {ctx.badge && (
+
+ {ctx.badge}
+
+ )}
+
+
+ {/* Main content */}
+
+
30 ? "52px" : "68px",
+ fontWeight: 900,
+ color: colors.text,
+ lineHeight: 1.05,
+ letterSpacing: "-1px",
+ maxWidth: "800px",
+ }}
+ >
+ {ctx.headline}
+
+
+ {ctx.subline}
+
+
+
+ {/* Bottom: stats / CTA */}
+
+
+ {ctx.stats.map((s) => (
+
+
+ {s.value}
+
+
+ {s.label}
+
+
+ ))}
+
+
+ {ctx.cta}
+
+
+
+
+ {/* Domain watermark */}
+
+ {brand.domain}
+
+
+ ),
+ {
+ width: 1200,
+ height: 630,
+ }
+ );
+}
+
+// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+
+interface OGContext {
+ headline: string;
+ subline: string;
+ badge: string | null;
+ cta: string;
+ stats: { value: string; label: string }[];
+}
+
+function resolveContext(
+ brand: ReturnType extends Promise ? T : never,
+ page: string,
+ pkgId: string | null
+): OGContext {
+ const defaultStats = (brand.stats ?? []).slice(0, 3);
+
+ if (pkgId) {
+ const pkg = brand.creditPackages?.find((p) => p.id === pkgId);
+ if (pkg) {
+ return {
+ headline: pkg.name,
+ subline: `${pkg.credits.toLocaleString()} credits ยท ${pkg.boost ?? "Start claiming instantly"}`,
+ badge: pkg.badge ?? "Shop",
+ cta: `$${pkg.price.toLocaleString()} โ Purchase`,
+ stats: defaultStats,
+ };
+ }
+ }
+
+ switch (page) {
+ case "affiliates":
+ return {
+ headline: `Earn Up to ${brand.affiliateCommission}`,
+ subline: brand.affiliateDescription,
+ badge: "Partner Program",
+ cta: "Join as Affiliate",
+ stats: [
+ { value: brand.affiliateCommission, label: "Max Commission" },
+ { value: "Weekly", label: "Payout Frequency" },
+ { value: "No Cap", label: "Earnings Limit" },
+ ],
+ };
+
+ case "shop":
+ return {
+ headline: "Credit Packages",
+ subline: "Top up once. The system runs indefinitely.",
+ badge: "Shop",
+ cta: "View All Packages",
+ stats: defaultStats,
+ };
+
+ case "status":
+ return {
+ headline: "System Status",
+ subline: `${brand.domain} โ Operational`,
+ badge: "Status",
+ cta: "Check Live Status",
+ stats: [
+ { value: "99.9%", label: "Uptime" },
+ { value: "<2s", label: "Claim Speed" },
+ { value: "24/7", label: "Support" },
+ ],
+ };
+
+ default:
+ return {
+ headline: brand.tagline,
+ subline: brand.subTagline,
+ badge: null,
+ cta: brand.ctaPrimary,
+ stats: defaultStats,
+ };
+ }
+}
diff --git a/apps/web/src/app/page.tsx b/apps/web/src/app/page.tsx
new file mode 100644
index 00000000..97d8ab35
--- /dev/null
+++ b/apps/web/src/app/page.tsx
@@ -0,0 +1,7 @@
+import { loadBrandConfig } from "@/lib/brand";
+import HomeClient from "@/components/HomeClient";
+
+export default async function HomePage() {
+ const brand = await loadBrandConfig();
+ return ;
+}
diff --git a/apps/web/src/app/payment-cancel/page.tsx b/apps/web/src/app/payment-cancel/page.tsx
new file mode 100644
index 00000000..fa7bd31e
--- /dev/null
+++ b/apps/web/src/app/payment-cancel/page.tsx
@@ -0,0 +1,36 @@
+import Link from "next/link";
+import { loadBrandConfig } from "@/lib/brand";
+
+export default async function PaymentCancelPage() {
+ const brand = await loadBrandConfig();
+ return (
+
+
+
+
+
+
+
+
+
+
Payment Cancelled
+
+ No charges were made. You can try again whenever you're ready.
+
+
+ Return to Homepage
+
+
+
+
+
+
+ {new Date().getFullYear()} ยฉ All Rights Reserved | {brand.name}
+
+
+ );
+}
diff --git a/apps/web/src/app/payment-success/page.tsx b/apps/web/src/app/payment-success/page.tsx
new file mode 100644
index 00000000..d9df046f
--- /dev/null
+++ b/apps/web/src/app/payment-success/page.tsx
@@ -0,0 +1,37 @@
+import Link from "next/link";
+import { loadBrandConfig } from "@/lib/brand";
+
+export default async function PaymentSuccessPage() {
+ const brand = await loadBrandConfig();
+ return (
+
+
+
+
+
+
+
+
+
+
Payment Successful!
+
+ Your order has been processed. Credits will appear in your account shortly.
+ Check your Telegram for confirmation.
+
+
+ Return to Homepage
+
+
+
+
+
+
+ {new Date().getFullYear()} ยฉ All Rights Reserved | {brand.name}
+
+
+ );
+}
diff --git a/apps/web/src/app/status/page.tsx b/apps/web/src/app/status/page.tsx
new file mode 100644
index 00000000..9ed83038
--- /dev/null
+++ b/apps/web/src/app/status/page.tsx
@@ -0,0 +1,16 @@
+import { loadBrandConfig } from "@/lib/brand";
+import StatusClient from "@/components/StatusClient";
+
+export async function generateMetadata() {
+ const brand = await loadBrandConfig();
+ return {
+ title: `System Status โ ${brand.name}`,
+ description: `Operational status and deployment info for ${brand.domain}`,
+ robots: "noindex, nofollow",
+ };
+}
+
+export default async function StatusPage() {
+ const brand = await loadBrandConfig();
+ return ;
+}
diff --git a/apps/web/src/components/AffiliatesClient.tsx b/apps/web/src/components/AffiliatesClient.tsx
new file mode 100644
index 00000000..1a4e12fb
--- /dev/null
+++ b/apps/web/src/components/AffiliatesClient.tsx
@@ -0,0 +1,164 @@
+"use client";
+
+import { motion } from "framer-motion";
+import Link from "next/link";
+import type { BrandConfig } from "@/types/brand";
+import Navbar from "@/components/layout/Navbar";
+import Footer from "@/components/layout/Footer";
+
+const steps = [
+ { num: "01", title: "Sign Up", desc: "Create your affiliate account via Telegram in under 60 seconds." },
+ { num: "02", title: "Get Your Link", desc: "Receive a unique referral URL tied to your Telegram username." },
+ { num: "03", title: "Share & Earn", desc: "Every user who purchases through your link earns you commission โ instantly." },
+];
+
+const tiers = [
+ { label: "Starter", refs: "1โ10 referrals", rate: "10%", bg: "var(--brand-bg-secondary)" },
+ { label: "Active", refs: "11โ50 referrals", rate: "15%", bg: "var(--brand-bg-tertiary)" },
+ { label: "Pro", refs: "51+ referrals", rate: "20%", bg: "var(--brand-primary)", textWhite: true },
+];
+
+interface AffiliatesClientProps {
+ brand: BrandConfig;
+}
+
+export default function AffiliatesClient({ brand }: AffiliatesClientProps) {
+ return (
+
+
+
+
+ {/* Hero */}
+
+
+
+
+
+
+
+ Partner Program
+
+
+ Earn Up to{" "}
+ {brand.affiliateCommission}
+
+
+ {brand.affiliateDescription} Refer players, watch the commission stack.
+
+
+
+
+
+
+ {/* How it works */}
+
+
+
+
How It Works
+
Three steps. No friction. No cap.
+
+
+ {steps.map((step, i) => (
+
+
+ {step.num}
+
+ {step.title}
+ {step.desc}
+
+ ))}
+
+
+
+
+ {/* Commission tiers */}
+
+
+
+
Commission Tiers
+
The more you refer, the more you earn.
+
+
+
+ {tiers.map((tier, i) => (
+
+ {tier.label}
+ {tier.rate}
+ {tier.refs}
+
+ ))}
+
+
+
+
+ Payouts are processed in crypto (BTC, ETH, USDT) weekly, directly to your wallet.
+ No minimum threshold. No paperwork.
+
+
+
+
+
+ {/* CTA */}
+
+
+
Ready to start earning?
+
+ Message us on Telegram and we'll have your affiliate link active within minutes.
+
+
+ Get Started on Telegram
+
+
+
+
+
+
+
+ );
+}
diff --git a/apps/web/src/components/HomeClient.tsx b/apps/web/src/components/HomeClient.tsx
new file mode 100644
index 00000000..632769f1
--- /dev/null
+++ b/apps/web/src/components/HomeClient.tsx
@@ -0,0 +1,79 @@
+"use client";
+
+import { useState } from "react";
+import type { BrandConfig } from "@/types/brand";
+import Navbar from "@/components/layout/Navbar";
+import Footer from "@/components/layout/Footer";
+import Hero from "@/components/sections/Hero";
+import Features from "@/components/sections/Features";
+import Services from "@/components/sections/Services";
+import Shop from "@/components/sections/Shop";
+import Demo from "@/components/sections/Demo";
+import Metrics from "@/components/sections/Metrics";
+import FAQ from "@/components/sections/FAQ";
+import Blog from "@/components/sections/Blog";
+import PaymentModal from "@/components/ui/PaymentModal";
+
+interface HomeClientProps {
+ brand: BrandConfig;
+}
+
+export default function HomeClient({ brand }: HomeClientProps) {
+ const [activePkg, setActivePkg] = useState(null);
+
+ return (
+
+
+
+
+ {/* 1 โ Hook */}
+
+
+ {/* 2 โ Why us */}
+
+
+ {/* 3 โ Video proof */}
+
+
+ {/* 4 โ Social metrics */}
+
+
+ {/* 5 โ Additional services */}
+ {
+ // Map KYC tier into a pseudo credit package for the modal
+ setActivePkg({
+ id: `kyc-${tier.label.toLowerCase().replace(/\s/g, "-")}`,
+ name: `KYC Fix โ ${tier.label}`,
+ credits: 0,
+ price: tier.price,
+ boost: null,
+ badge: null,
+ });
+ }}
+ />
+
+ {/* 6 โ Credit packages / shop */}
+
+
+ {/* 7 โ Blog */}
+
+
+ {/* 8 โ FAQ */}
+
+
+
+
+
+ {/* Payment modal */}
+ {activePkg && (
+
setActivePkg(null)}
+ />
+ )}
+
+ );
+}
diff --git a/apps/web/src/components/StatusClient.tsx b/apps/web/src/components/StatusClient.tsx
new file mode 100644
index 00000000..6052e051
--- /dev/null
+++ b/apps/web/src/components/StatusClient.tsx
@@ -0,0 +1,330 @@
+"use client";
+
+import { useEffect, useState } from "react";
+import type { BrandConfig } from "@/types/brand";
+
+interface StatusPayload {
+ brand: { id: string; name: string; domain: string; tone: string };
+ deployment: {
+ environment: string;
+ region: string;
+ gitSha: string | null;
+ deployedAt: string | null;
+ nextVersion: string | null;
+ nodeVersion: string | null;
+ };
+ health: {
+ overall: "healthy" | "degraded" | "down";
+ responseMs: number;
+ checks: Record;
+ };
+ features: Record;
+ analytics: {
+ googleAnalyticsId: string | null;
+ cloudflareBeaconId: string | null;
+ tawkPropertyId: string | null;
+ };
+ cloudflare: { status: string; domain: string; resolvedTo?: string[]; message?: string };
+ sales: {
+ creditPackages: { id: string; name: string; price: number }[];
+ affiliateCommission: string;
+ paymentProvider: string;
+ telegramRequired: boolean;
+ };
+ timestamp: string;
+}
+
+const STATUS_COLORS: Record = {
+ ok: "#22c55e",
+ healthy: "#22c55e",
+ warning: "#f59e0b",
+ degraded: "#f59e0b",
+ error: "#ef4444",
+ down: "#ef4444",
+ unconfigured: "#6b7280",
+};
+
+function StatusDot({ status }: { status: string }) {
+ const color = STATUS_COLORS[status] ?? "#6b7280";
+ return (
+
+ );
+}
+
+function Badge({ status }: { status: string }) {
+ const color = STATUS_COLORS[status] ?? "#6b7280";
+ return (
+
+ {status}
+
+ );
+}
+
+function Section({ title, children }: { title: string; children: React.ReactNode }) {
+ return (
+
+
+ {title}
+
+
{children}
+
+ );
+}
+
+function Row({ label, value, mono = false }: { label: string; value: React.ReactNode; mono?: boolean }) {
+ return (
+
+ {label}
+
+ {value}
+
+
+ );
+}
+
+interface StatusClientProps {
+ brand: BrandConfig;
+}
+
+export default function StatusClient({ brand }: StatusClientProps) {
+ const [data, setData] = useState(null);
+ const [loading, setLoading] = useState(true);
+ const [error, setError] = useState(null);
+ const [refreshedAt, setRefreshedAt] = useState(null);
+
+ async function fetchStatus() {
+ setLoading(true);
+ setError(null);
+ try {
+ const res = await fetch("/api/status", { cache: "no-store" });
+ if (!res.ok) throw new Error(`HTTP ${res.status}`);
+ setData(await res.json());
+ setRefreshedAt(new Date());
+ } catch (e) {
+ setError(e instanceof Error ? e.message : "Failed to load status");
+ } finally {
+ setLoading(false);
+ }
+ }
+
+ useEffect(() => {
+ fetchStatus();
+ const interval = setInterval(fetchStatus, 30_000);
+ return () => clearInterval(interval);
+ }, []);
+
+ const overall = data?.health.overall ?? "unknown";
+ const overallColor = STATUS_COLORS[overall] ?? "#6b7280";
+
+ return (
+
+
+ {/* Header */}
+
+
+
+ {brand.name}
+
+
System Status
+
+ {brand.domain} ยท Refreshes every 30s
+
+
+
+ โป Refresh
+
+
+
+ {/* Overall status banner */}
+
+
+
+
+ {loading ? "Checking..." : overall === "healthy" ? "All systems operational" : `System ${overall}`}
+
+ {refreshedAt && (
+
+ Last checked {refreshedAt.toLocaleTimeString()}
+
+ )}
+
+ {data &&
}
+
+
+ {error && (
+
+ Error loading status: {error}
+
+ )}
+
+ {data && (
+ <>
+ {/* Health checks */}
+
+ {Object.entries(data.health.checks).map(([key, check]) => (
+
+
+
+
+ {key.replace(/([A-Z])/g, " $1").trim()}
+
+
+
+ {check.message ?? ""}
+
+
+
+ ))}
+
+ Response time
+
+ {data.health.responseMs}ms
+
+
+
+
+ {/* Deployment */}
+
+
+
+ {data.deployment.gitSha && (
+
+ )}
+ {data.deployment.deployedAt && (
+
+ )}
+ {data.deployment.nodeVersion && (
+
+ )}
+
+
+
+
+ {/* Features */}
+
+ {Object.entries(data.features).map(([key, val]) => (
+
+
+ {key.replace(/([A-Z])/g, " $1").replace(/^./, (s) => s.toUpperCase())}
+
+
+ {typeof val === "boolean" ? (val ? "enabled" : "disabled") : String(val)}
+
+
+ ))}
+
+
+ {/* Analytics */}
+
+ Configured ({data.analytics.googleAnalyticsId})
+ : Not configured }
+ />
+ Configured
+ : Not configured }
+ />
+ Configured ({data.analytics.tawkPropertyId.slice(0, 8)}...)
+ : Not configured }
+ />
+
+
+ {/* Cloudflare DNS */}
+
+
+
}
+ />
+ {data.cloudflare.resolvedTo && data.cloudflare.resolvedTo.length > 0 && (
+
+ )}
+ {data.cloudflare.message && (
+
+ )}
+
+
+ {/* Sales config */}
+
+
+
+
+
+
+
+ {data.sales.creditPackages.map((p) => (
+
+ {p.name} ยท ${p.price}
+
+ ))}
+
+
+
+
+ {/* Raw JSON for developers */}
+
+ >
+ )}
+
+ {/* Footer */}
+
+ {brand.name} ยท {brand.domain} ยท Status endpoint: /api/status
+
+
+
+ );
+}
diff --git a/apps/web/src/components/layout/Footer.tsx b/apps/web/src/components/layout/Footer.tsx
new file mode 100644
index 00000000..4b4f1144
--- /dev/null
+++ b/apps/web/src/components/layout/Footer.tsx
@@ -0,0 +1,116 @@
+import Link from "next/link";
+import type { BrandConfig } from "@/types/brand";
+
+interface FooterProps {
+ brand: BrandConfig;
+}
+
+export default function Footer({ brand }: FooterProps) {
+ const year = new Date().getFullYear();
+
+ return (
+
+ {/* Newsletter */}
+
+
+
+
+
Stay in the loop
+
+ New features, reload windows, and platform updates โ direct to your inbox.
+
+
+
+
+
+
+
+ {/* Links grid */}
+
+
+
+
+ {brand.name}
+
+
+ {brand.subTagline}
+
+
+
+
+
+ Services
+
+
+ Credit Packages
+ KYC Account Fixes
+ Wager Guarantees
+ Affiliates
+
+
+
+
+
+ Resources
+
+
+ Help Center
+ Demo Video
+ Blog
+
+
+
+
+
+
+
+ {/* Bottom bar */}
+
+
+
+ {year} ยฉ All Rights Reserved | {brand.name}
+
+
+ For entertainment and automation use only. Not affiliated with Stake.com.
+
+
+
+
+ );
+}
diff --git a/apps/web/src/components/layout/Navbar.tsx b/apps/web/src/components/layout/Navbar.tsx
new file mode 100644
index 00000000..d4df4ceb
--- /dev/null
+++ b/apps/web/src/components/layout/Navbar.tsx
@@ -0,0 +1,85 @@
+"use client";
+
+import { useState } from "react";
+import Link from "next/link";
+import type { BrandConfig } from "@/types/brand";
+
+interface NavbarProps {
+ brand: BrandConfig;
+}
+
+export default function Navbar({ brand }: NavbarProps) {
+ const [menuOpen, setMenuOpen] = useState(false);
+
+ return (
+
+
+ {/* Logo */}
+
+
+ {brand.name}
+
+
+
+ {/* Desktop nav */}
+
+ {brand.nav.links.map((link) => (
+
+ {link.label}
+
+ ))}
+
+
+ {/* Desktop CTA */}
+
+
+ {brand.nav.cta}
+
+
+
+ {/* Mobile toggle */}
+
setMenuOpen((v) => !v)}
+ aria-label="Toggle menu"
+ >
+ {menuOpen ? (
+
+
+
+ ) : (
+
+
+
+ )}
+
+
+
+ {/* Mobile menu */}
+ {menuOpen && (
+
+
+ {brand.nav.links.map((link) => (
+ setMenuOpen(false)}
+ >
+ {link.label}
+
+ ))}
+ setMenuOpen(false)}>
+ {brand.nav.cta}
+
+
+
+ )}
+
+ );
+}
diff --git a/apps/web/src/components/sections/Blog.tsx b/apps/web/src/components/sections/Blog.tsx
new file mode 100644
index 00000000..fa6d1168
--- /dev/null
+++ b/apps/web/src/components/sections/Blog.tsx
@@ -0,0 +1,69 @@
+"use client";
+
+import { motion } from "framer-motion";
+
+const posts = [
+ {
+ title: "In BTC We Trust: The Elon Musk Effect on a US Backed Stablecoin",
+ author: "SupItsJ",
+ date: "5 JAN 2025",
+ excerpt: "How macro crypto narratives are shifting reload opportunity windows across major platforms.",
+ href: "#blog",
+ },
+ {
+ title: "The Art of Affiliate Whoring",
+ author: "SupItsJ",
+ date: "29 NOV 2024",
+ excerpt: "A tactical breakdown of stacking affiliate commission across competing reload ecosystems.",
+ href: "#blog",
+ },
+ {
+ title: "How Telegram & TON Could Revolutionize Advertising Networks in Social Media",
+ author: "SupItsJ",
+ date: "4 JUL 2024",
+ excerpt: "The next distribution layer for reload services is already here โ and most aren't using it.",
+ href: "#blog",
+ },
+];
+
+export default function Blog() {
+ return (
+
+
+
+
From the Blog
+
Intelligence from the team behind the system.
+
+
+
+ {posts.map((post, i) => (
+
+
+ {post.author}
+ ยท
+ {post.date}
+
+
+ {post.title}
+
+
+ {post.excerpt}
+
+
+ Read more โ
+
+
+ ))}
+
+
+
+ );
+}
diff --git a/apps/web/src/components/sections/Demo.tsx b/apps/web/src/components/sections/Demo.tsx
new file mode 100644
index 00000000..358cc728
--- /dev/null
+++ b/apps/web/src/components/sections/Demo.tsx
@@ -0,0 +1,41 @@
+"use client";
+
+import { motion } from "framer-motion";
+import type { BrandConfig } from "@/types/brand";
+
+interface DemoProps {
+ brand: BrandConfig;
+}
+
+export default function Demo({ brand }: DemoProps) {
+ if (!brand.demoVideoId) return null;
+
+ return (
+
+
+
+ See It in Action
+
+ Check out our demo and see for yourself โ under 2 seconds, every time.
+
+
+
+ VIDEO
+
+
+
+
+ );
+}
diff --git a/apps/web/src/components/sections/FAQ.tsx b/apps/web/src/components/sections/FAQ.tsx
new file mode 100644
index 00000000..b4e2aa5a
--- /dev/null
+++ b/apps/web/src/components/sections/FAQ.tsx
@@ -0,0 +1,75 @@
+"use client";
+
+import { useState } from "react";
+import { motion, AnimatePresence } from "framer-motion";
+import type { BrandConfig } from "@/types/brand";
+
+const defaultFAQ = [
+ { q: "Is this actually legitimate?", a: "Yes. We operate within the reload and bonus systems these platforms make available. We just maximize every cycle automatically." },
+ { q: "How fast are reloads processed?", a: "Typically under 2 seconds once a cycle triggers. Speed depends on platform response times." },
+ { q: "What's the minimum to start?", a: "The New XSID package starts at $5. Connect your Telegram and the system handles the rest." },
+ { q: "What payment methods are accepted?", a: "We accept crypto payments via NOWPayments โ Bitcoin, Ethereum, USDT, and more." },
+ { q: "How do I get support?", a: "Reach us 24/7 on Telegram. Response time is typically under 15 minutes." },
+];
+
+interface FAQProps {
+ brand: BrandConfig;
+}
+
+export default function FAQ({ brand }: FAQProps) {
+ const [openIndex, setOpenIndex] = useState(null);
+ const items = (brand as unknown as { faq?: { q: string; a: string }[] }).faq ?? defaultFAQ;
+
+ return (
+
+
+
+
Help Center
+
Answers to the questions we get most.
+
+
+
+ {items.map((item, i) => (
+
+
setOpenIndex(openIndex === i ? null : i)}
+ >
+ {item.q}
+
+
+
+
+
+ {openIndex === i && (
+
+
+ {item.a}
+
+
+ )}
+
+
+ ))}
+
+
+
+ );
+}
diff --git a/apps/web/src/components/sections/Features.tsx b/apps/web/src/components/sections/Features.tsx
new file mode 100644
index 00000000..1de21386
--- /dev/null
+++ b/apps/web/src/components/sections/Features.tsx
@@ -0,0 +1,64 @@
+"use client";
+
+import { motion } from "framer-motion";
+import type { BrandConfig } from "@/types/brand";
+
+const icons: Record = {
+ server: (
+
+
+
+ ),
+ zap: (
+
+
+
+ ),
+ headphones: (
+
+
+
+ ),
+};
+
+interface FeaturesProps {
+ brand: BrandConfig;
+}
+
+export default function Features({ brand }: FeaturesProps) {
+ return (
+
+
+
+
Why {brand.name}?
+
+ Everything you need to maximize your reload cycles โ nothing you don't.
+
+
+
+
+ {brand.features.map((feature, i) => (
+
+
+ {icons[feature.icon] ?? icons.zap}
+
+ {feature.title}
+
+ {feature.description}
+
+
+ ))}
+
+
+
+ );
+}
diff --git a/apps/web/src/components/sections/Hero.tsx b/apps/web/src/components/sections/Hero.tsx
new file mode 100644
index 00000000..84ac8d34
--- /dev/null
+++ b/apps/web/src/components/sections/Hero.tsx
@@ -0,0 +1,88 @@
+"use client";
+
+import Link from "next/link";
+import { motion } from "framer-motion";
+import type { BrandConfig } from "@/types/brand";
+
+interface HeroProps {
+ brand: BrandConfig;
+}
+
+export default function Hero({ brand }: HeroProps) {
+ return (
+
+ {/* Background grid */}
+
+ {/* Radial glow */}
+
+
+
+
+ {/* Badge */}
+
+
+
+
+
+ Live โ Claiming Now
+
+
+ {/* Headline */}
+
+ {brand.tagline}
+
+
+ {/* Sub */}
+
+ {brand.subTagline}
+
+
+ {/* CTAs */}
+
+
+ {brand.ctaPrimary}
+
+
+ {brand.ctaSecondary}
+
+
+
+
+ {/* Stats row */}
+
+ {brand.stats.map((stat) => (
+
+
+ {stat.value}
+
+
+ {stat.label}
+
+
+ ))}
+
+
+
+ );
+}
diff --git a/apps/web/src/components/sections/Metrics.tsx b/apps/web/src/components/sections/Metrics.tsx
new file mode 100644
index 00000000..232809a0
--- /dev/null
+++ b/apps/web/src/components/sections/Metrics.tsx
@@ -0,0 +1,32 @@
+"use client";
+
+import { motion } from "framer-motion";
+import type { BrandConfig } from "@/types/brand";
+
+interface MetricsProps {
+ brand: BrandConfig;
+}
+
+export default function Metrics({ brand }: MetricsProps) {
+ return (
+
+
+
+ {brand.metrics.map((m, i) => (
+
+ {m.value}
+ {m.label}
+
+ ))}
+
+
+
+ );
+}
diff --git a/apps/web/src/components/sections/Services.tsx b/apps/web/src/components/sections/Services.tsx
new file mode 100644
index 00000000..9ba279b8
--- /dev/null
+++ b/apps/web/src/components/sections/Services.tsx
@@ -0,0 +1,71 @@
+"use client";
+
+import { motion } from "framer-motion";
+import type { BrandConfig } from "@/types/brand";
+
+interface ServicesProps {
+ brand: BrandConfig;
+ onBuyKyc?: (tier: { label: string; price: number }) => void;
+}
+
+export default function Services({ brand, onBuyKyc }: ServicesProps) {
+ return (
+
+
+
+
Services
+
Specialized solutions beyond the reload system.
+
+
+
+ {brand.services.map((service, i) => (
+
+ {service.title}
+
+ {service.description}
+
+
+ {service.tiers && service.tiers.length > 0 ? (
+
+ {service.tiers.map((tier) => (
+ onBuyKyc?.(tier)}
+ className="w-full flex items-center justify-between px-4 py-2.5 rounded-md text-sm font-medium transition-all duration-200"
+ style={{ background: "var(--brand-bg-tertiary)", border: "1px solid var(--brand-border)" }}
+ onMouseEnter={(e) => {
+ (e.currentTarget as HTMLElement).style.borderColor = "var(--brand-primary)";
+ }}
+ onMouseLeave={(e) => {
+ (e.currentTarget as HTMLElement).style.borderColor = "var(--brand-border)";
+ }}
+ >
+ {tier.label}
+
+ ${tier.price.toLocaleString()}
+
+
+ ))}
+
+ ) : (
+
+ {service.id === "affiliates" ? "Learn More โ" : "Get Started โ"}
+
+ )}
+
+ ))}
+
+
+
+ );
+}
diff --git a/apps/web/src/components/sections/Shop.tsx b/apps/web/src/components/sections/Shop.tsx
new file mode 100644
index 00000000..2bec5b8a
--- /dev/null
+++ b/apps/web/src/components/sections/Shop.tsx
@@ -0,0 +1,71 @@
+"use client";
+
+import { motion } from "framer-motion";
+import type { BrandConfig } from "@/types/brand";
+
+interface ShopProps {
+ brand: BrandConfig;
+ onBuy: (pkg: BrandConfig["creditPackages"][number]) => void;
+}
+
+export default function Shop({ brand, onBuy }: ShopProps) {
+ return (
+
+
+
+
Credit Packages
+
+ Top up once. The system runs indefinitely.
+
+
+
+
+ {brand.creditPackages.map((pkg, i) => (
+
+ {pkg.badge && (
+
+ {pkg.badge}
+
+ )}
+
+
+
{pkg.name}
+
+ ${pkg.price.toLocaleString()}
+
+
+ {pkg.credits.toLocaleString()} credits
+
+ {pkg.boost && (
+
+ {pkg.boost}
+
+ )}
+
+
+ onBuy(pkg)}
+ className="btn-primary w-full mt-5 py-2.5 text-sm"
+ >
+ Purchase
+
+
+ ))}
+
+
+
+ Payments processed via NOWPayments (crypto). Telegram username required at checkout.
+
+
+
+ );
+}
diff --git a/apps/web/src/components/ui/PaymentModal.tsx b/apps/web/src/components/ui/PaymentModal.tsx
new file mode 100644
index 00000000..f87ee8ab
--- /dev/null
+++ b/apps/web/src/components/ui/PaymentModal.tsx
@@ -0,0 +1,177 @@
+"use client";
+
+import { useState } from "react";
+import { motion, AnimatePresence } from "framer-motion";
+import type { BrandConfig } from "@/types/brand";
+import { isValidRedirectUrl } from "@/lib/validation";
+
+interface PaymentModalProps {
+ pkg: BrandConfig["creditPackages"][number] | null;
+ onClose: () => void;
+ brand: BrandConfig;
+}
+
+type Step = "input" | "loading" | "success" | "error";
+
+export default function PaymentModal({ pkg, onClose, brand }: PaymentModalProps) {
+ const [telegram, setTelegram] = useState("");
+ const [step, setStep] = useState("input");
+ const [errorMsg, setErrorMsg] = useState("");
+
+ const telegramRegex = /^@[a-zA-Z0-9_]{4,31}$/;
+ const isValid = telegramRegex.test(telegram);
+
+ async function handleSubmit(e: React.FormEvent) {
+ e.preventDefault();
+ if (!isValid || !pkg) return;
+
+ setStep("loading");
+ try {
+ const res = await fetch(brand.payment.apiEndpoint, {
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify({
+ packageId: pkg.id,
+ packageName: pkg.name,
+ price: pkg.price,
+ credits: pkg.credits,
+ telegram,
+ }),
+ });
+
+ if (!res.ok) {
+ const data = await res.json().catch(() => ({}));
+ throw new Error(data?.message ?? "Payment initiation failed");
+ }
+
+ const data = await res.json();
+ if (data?.paymentUrl && isValidRedirectUrl(data.paymentUrl, ["nowpayments.io"])) {
+ window.location.href = data.paymentUrl;
+ } else if (data?.paymentUrl) {
+ // URL failed validation - treat as error
+ throw new Error("Invalid payment URL received from server");
+ } else {
+ setStep("success");
+ }
+ } catch (err) {
+ setErrorMsg(err instanceof Error ? err.message : "Something went wrong. Please try again.");
+ setStep("error");
+ }
+ }
+
+ if (!pkg) return null;
+
+ return (
+
+
+
e.stopPropagation()}
+ >
+ {/* Close */}
+
+
+
+
+
+
+ {step === "input" && (
+ <>
+ Complete Purchase
+
+ {pkg.name} โ ${pkg.price.toLocaleString()}
+ {" ยท "}{pkg.credits.toLocaleString()} credits
+ {pkg.boost && ยท {pkg.boost} }
+
+
+
+
+
+ Powered by NOWPayments ยท BTC, ETH, USDT accepted
+
+ >
+ )}
+
+ {step === "loading" && (
+
+
+
Initializing payment...
+
+ )}
+
+ {step === "success" && (
+
+
+
+
+
Payment Initiated!
+
+ Check your Telegram for next steps. Credits will be applied within minutes.
+
+
+ )}
+
+ {step === "error" && (
+
+
+
+
+
Something went wrong
+
{errorMsg}
+
setStep("input")} className="btn-primary px-6 py-2.5 text-sm">
+ Try Again
+
+
+ )}
+
+
+
+ );
+}
diff --git a/apps/web/src/lib/brand.ts b/apps/web/src/lib/brand.ts
new file mode 100644
index 00000000..286ca155
--- /dev/null
+++ b/apps/web/src/lib/brand.ts
@@ -0,0 +1,54 @@
+import type { BrandConfig } from "@/types/brand";
+
+// Brand configs are loaded at build time based on NEXT_PUBLIC_BRAND env var.
+// At runtime on the client, the CSS variables are already injected by the server layout.
+const brandModules: Record Promise> = {
+ stakereloadxs: () =>
+ import("../../../../configs/brands/stakereloadxs.json").then((m) => m.default as unknown as BrandConfig),
+};
+
+export async function loadBrandConfig(brandId?: string): Promise {
+ const id = brandId ?? process.env.NEXT_PUBLIC_BRAND ?? "stakereloadxs";
+ const loader = brandModules[id];
+ if (!loader) {
+ console.warn(`Unknown brand "${id}", falling back to stakereloadxs`);
+ return brandModules["stakereloadxs"]();
+ }
+ return loader();
+}
+
+/** Detect brand from hostname at request time (used in middleware / layout). */
+export function detectBrandFromHost(host: string): string {
+ const hostMap: Record = {
+ "stakereloadxs.com": "stakereloadxs",
+ "www.stakereloadxs.com": "stakereloadxs",
+ "stakereload.com": "stakereload",
+ "www.stakereload.com": "stakereload",
+ "gambareload.com": "gambareload",
+ "www.gambareload.com": "gambareload",
+ "gambarewards.com": "gambarewards",
+ "www.gambarewards.com": "gambarewards",
+ "stakeclaimbot.com": "stakeclaimbot",
+ "www.stakeclaimbot.com": "stakeclaimbot",
+ };
+ return hostMap[host] ?? process.env.NEXT_PUBLIC_BRAND ?? "stakereloadxs";
+}
+
+/** Convert brand theme object to CSS custom properties string. */
+export function themeToCSSVars(theme: BrandConfig["theme"]): string {
+ return [
+ `--brand-primary: ${theme.primary}`,
+ `--brand-primary-dark: ${theme.primaryDark}`,
+ `--brand-primary-hover: ${theme.primaryHover ?? theme.primary}`,
+ `--brand-bg: ${theme.background}`,
+ `--brand-bg-secondary: ${theme.backgroundSecondary}`,
+ `--brand-bg-tertiary: ${theme.backgroundTertiary}`,
+ `--brand-accent: ${theme.accent}`,
+ `--brand-accent-secondary: ${theme.accentSecondary}`,
+ `--brand-text: ${theme.text}`,
+ `--brand-muted: ${theme.textMuted}`,
+ `--brand-faint: ${theme.textFaint}`,
+ `--brand-border: ${theme.border}`,
+ `--brand-border-glow: ${theme.borderGlow}`,
+ ].join("; ");
+}
diff --git a/apps/web/src/types/brand.ts b/apps/web/src/types/brand.ts
new file mode 100644
index 00000000..efd747bc
--- /dev/null
+++ b/apps/web/src/types/brand.ts
@@ -0,0 +1,112 @@
+export interface BrandTheme {
+ primary: string;
+ primaryDark: string;
+ primaryHover?: string;
+ background: string;
+ backgroundSecondary: string;
+ backgroundTertiary: string;
+ accent: string;
+ accentSecondary: string;
+ text: string;
+ textMuted: string;
+ textFaint: string;
+ border: string;
+ borderGlow: string;
+}
+
+export interface BrandNav {
+ links: { label: string; href: string }[];
+ cta: string;
+}
+
+export interface BrandFeature {
+ icon: string;
+ title: string;
+ description: string;
+}
+
+export interface BrandStat {
+ value: string;
+ label: string;
+}
+
+export interface BrandMetric {
+ value: string;
+ label: string;
+}
+
+export interface BrandServiceTier {
+ label: string;
+ price: number;
+}
+
+export interface BrandService {
+ id: string;
+ title: string;
+ description: string;
+ tiers: BrandServiceTier[];
+}
+
+export interface BrandCreditPackage {
+ id: string;
+ name: string;
+ credits: number;
+ price: number;
+ boost: string | null;
+ badge: string | null;
+}
+
+export interface BrandFAQ {
+ q: string;
+ a: string;
+}
+
+export interface BrandConfig {
+ id: string;
+ name: string;
+ domain: string;
+ tone: "aggressive" | "corporate" | "playful" | "underground" | "premium";
+ tagline: string;
+ subTagline: string;
+ ctaPrimary: string;
+ ctaSecondary: string;
+ theme: BrandTheme;
+ ui: {
+ radius: string;
+ style: string;
+ borderStyle: string;
+ buttonStyle: string;
+ };
+ animation: string;
+ copyVariant: string;
+ languageDefault: string;
+ fonts?: {
+ heading: string;
+ body: string;
+ };
+ stats: BrandStat[];
+ metrics: BrandMetric[];
+ features: BrandFeature[];
+ services: BrandService[];
+ creditPackages: BrandCreditPackage[];
+ faq?: BrandFAQ[];
+ demoVideoId?: string;
+ affiliateCommission: string;
+ affiliateDescription: string;
+ payment: {
+ provider: string;
+ apiEndpoint: string;
+ telegramRequired: boolean;
+ };
+ chat?: {
+ provider: string;
+ propertyId: string;
+ widgetId: string;
+ };
+ nav: BrandNav;
+ seo: {
+ title: string;
+ description: string;
+ keywords: string[];
+ };
+}
diff --git a/apps/web/tailwind.config.ts b/apps/web/tailwind.config.ts
new file mode 100644
index 00000000..161b5d9b
--- /dev/null
+++ b/apps/web/tailwind.config.ts
@@ -0,0 +1,93 @@
+import type { Config } from "tailwindcss";
+
+const config: Config = {
+ content: [
+ "./src/pages/**/*.{js,ts,jsx,tsx,mdx}",
+ "./src/components/**/*.{js,ts,jsx,tsx,mdx}",
+ "./src/app/**/*.{js,ts,jsx,tsx,mdx}",
+ "../../packages/ui/src/**/*.{js,ts,jsx,tsx}",
+ ],
+ theme: {
+ extend: {
+ colors: {
+ brand: {
+ primary: "var(--brand-primary)",
+ "primary-dark": "var(--brand-primary-dark)",
+ bg: "var(--brand-bg)",
+ "bg-secondary": "var(--brand-bg-secondary)",
+ "bg-tertiary": "var(--brand-bg-tertiary)",
+ accent: "var(--brand-accent)",
+ "accent-secondary": "var(--brand-accent-secondary)",
+ text: "var(--brand-text)",
+ muted: "var(--brand-muted)",
+ faint: "var(--brand-faint)",
+ border: "var(--brand-border)",
+ "border-glow": "var(--brand-border-glow)",
+ },
+ },
+ fontFamily: {
+ mono: ["'JetBrains Mono'", "ui-monospace", "monospace"],
+ sans: ["'Inter'", "ui-sans-serif", "system-ui"],
+ },
+ animation: {
+ "glitch-1": "glitch1 0.4s steps(2) infinite",
+ "glitch-2": "glitch2 0.4s steps(2) infinite",
+ "pulse-glow": "pulseGlow 2s ease-in-out infinite",
+ "scan-line": "scanLine 3s linear infinite",
+ "flicker": "flicker 0.15s infinite linear",
+ "slide-up": "slideUp 0.4s ease-out forwards",
+ "fade-in": "fadeIn 0.6s ease-out forwards",
+ "ticker": "ticker 20s linear infinite",
+ },
+ keyframes: {
+ glitch1: {
+ "0%, 100%": { clipPath: "inset(0 0 95% 0)", transform: "translate(-2px, 0)" },
+ "50%": { clipPath: "inset(80% 0 0 0)", transform: "translate(2px, 0)" },
+ },
+ glitch2: {
+ "0%, 100%": { clipPath: "inset(50% 0 30% 0)", transform: "translate(2px, 0)" },
+ "50%": { clipPath: "inset(10% 0 60% 0)", transform: "translate(-2px, 0)" },
+ },
+ pulseGlow: {
+ "0%, 100%": { boxShadow: "0 0 20px var(--brand-primary), 0 0 40px var(--brand-primary)" },
+ "50%": { boxShadow: "0 0 40px var(--brand-primary), 0 0 80px var(--brand-primary)" },
+ },
+ scanLine: {
+ "0%": { transform: "translateY(-100%)" },
+ "100%": { transform: "translateY(100vh)" },
+ },
+ flicker: {
+ "0%, 19%, 21%, 23%, 25%, 54%, 56%, 100%": { opacity: "1" },
+ "20%, 24%, 55%": { opacity: "0.4" },
+ },
+ slideUp: {
+ "0%": { transform: "translateY(20px)", opacity: "0" },
+ "100%": { transform: "translateY(0)", opacity: "1" },
+ },
+ fadeIn: {
+ "0%": { opacity: "0" },
+ "100%": { opacity: "1" },
+ },
+ ticker: {
+ "0%": { transform: "translateX(0)" },
+ "100%": { transform: "translateX(-50%)" },
+ },
+ },
+ boxShadow: {
+ "neon-primary": "0 0 20px var(--brand-primary), 0 0 40px var(--brand-primary-dark)",
+ "neon-accent": "0 0 20px var(--brand-accent), 0 0 40px var(--brand-accent)",
+ "neon-sm": "0 0 8px var(--brand-primary)",
+ },
+ backgroundImage: {
+ "grid-pattern": "linear-gradient(var(--brand-border) 1px, transparent 1px), linear-gradient(90deg, var(--brand-border) 1px, transparent 1px)",
+ "scanline": "repeating-linear-gradient(0deg, transparent, transparent 2px, rgba(0,255,178,0.03) 2px, rgba(0,255,178,0.03) 4px)",
+ },
+ backgroundSize: {
+ "grid": "40px 40px",
+ },
+ },
+ },
+ plugins: [],
+};
+
+export default config;
diff --git a/apps/web/tsconfig.json b/apps/web/tsconfig.json
new file mode 100644
index 00000000..b8cdcc79
--- /dev/null
+++ b/apps/web/tsconfig.json
@@ -0,0 +1,23 @@
+{
+ "compilerOptions": {
+ "target": "ES2017",
+ "lib": ["dom", "dom.iterable", "esnext"],
+ "allowJs": true,
+ "skipLibCheck": true,
+ "strict": true,
+ "noEmit": true,
+ "esModuleInterop": true,
+ "module": "esnext",
+ "moduleResolution": "bundler",
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "jsx": "preserve",
+ "incremental": true,
+ "plugins": [{ "name": "next" }],
+ "paths": {
+ "@/*": ["./src/*"]
+ }
+ },
+ "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
+ "exclude": ["node_modules"]
+}
diff --git a/configs/brands/stakereloadxs.json b/configs/brands/stakereloadxs.json
new file mode 100644
index 00000000..6b4e0b13
--- /dev/null
+++ b/configs/brands/stakereloadxs.json
@@ -0,0 +1,160 @@
+{
+ "id": "stakereloadxs",
+ "name": "StakeReloadXS",
+ "domain": "stakereloadxs.com",
+ "tagline": "Xtremely Simple Reloads",
+ "subTagline": "Automated bonus claims for Stake.com and Stake.us in under 2 seconds.",
+ "ctaPrimary": "Try It Free",
+ "ctaSecondary": "Top Up Credits",
+ "tone": "aggressive",
+ "copyVariant": "urgency",
+ "languageDefault": "en",
+ "theme": {
+ "primary": "#dc2626",
+ "primaryDark": "#b91c1c",
+ "primaryHover": "#ef4444",
+ "background": "#000000",
+ "backgroundSecondary": "#111111",
+ "backgroundTertiary": "#1a1a1a",
+ "accent": "#dc2626",
+ "accentSecondary": "#ef4444",
+ "text": "#f3f4f6",
+ "textMuted": "#9ca3af",
+ "textFaint": "#4b5563",
+ "border": "#222222",
+ "borderGlow": "#dc2626"
+ },
+ "ui": {
+ "radius": "rounded",
+ "style": "dark-minimal",
+ "borderStyle": "solid",
+ "buttonStyle": "fill"
+ },
+ "animation": "smooth",
+ "fonts": {
+ "heading": "Poppins",
+ "body": "Inter"
+ },
+ "stats": [
+ { "value": "700+", "label": "Monthly Users" },
+ { "value": "25+", "label": "Years Combined Dev Experience" },
+ { "value": "0", "label": "Complaints" }
+ ],
+ "metrics": [
+ { "value": "400+", "label": "Weekly Clients Served" },
+ { "value": "$250,000", "label": "Weekly Claims" },
+ { "value": "100%", "label": "Customer Satisfaction" },
+ { "value": "3 Years", "label": "Serving Players" }
+ ],
+ "features": [
+ {
+ "icon": "server",
+ "title": "Private Servers",
+ "description": "Dedicated infrastructure for your account. Specialist setup available on request."
+ },
+ {
+ "icon": "zap",
+ "title": "Automatic Claims",
+ "description": "Fully automated bonus lifecycle. Claims trigger in under 2 seconds, every time."
+ },
+ {
+ "icon": "headphones",
+ "title": "24/7 Support",
+ "description": "Real support from the team behind the tool. Available around the clock via Telegram."
+ }
+ ],
+ "services": [
+ {
+ "id": "kyc",
+ "title": "KYC Account Fixes",
+ "description": "Resolve verification blocks fast. All levels handled.",
+ "tiers": [
+ { "label": "Level 2", "price": 75 },
+ { "label": "Level 3", "price": 500 },
+ { "label": "Level 4", "price": 1000 }
+ ]
+ },
+ {
+ "id": "wager",
+ "title": "Guaranteed $10,000 Wager",
+ "description": "We claim on $60M+ wagered on Stake. Your wager requirement handled.",
+ "tiers": []
+ },
+ {
+ "id": "affiliates",
+ "title": "Affiliates",
+ "description": "Refer players and earn up to 20% commission. No cap.",
+ "tiers": []
+ }
+ ],
+ "creditPackages": [
+ {
+ "id": "xs-id",
+ "name": "New XSID",
+ "credits": 5000,
+ "price": 5.00,
+ "boost": null,
+ "badge": null
+ },
+ {
+ "id": "50k",
+ "name": "50,000 Credits",
+ "credits": 50000,
+ "price": 50.00,
+ "boost": "5% Boost",
+ "badge": null
+ },
+ {
+ "id": "100k",
+ "name": "100,000 Credits",
+ "credits": 100000,
+ "price": 100.00,
+ "boost": "10% Boost",
+ "badge": "Popular"
+ },
+ {
+ "id": "200k",
+ "name": "200,000 Credits",
+ "credits": 200000,
+ "price": 200.00,
+ "boost": "15% Boost",
+ "badge": null
+ },
+ {
+ "id": "1m",
+ "name": "1,000,000 Credits",
+ "credits": 1000000,
+ "price": 1000.00,
+ "boost": "20% Boost",
+ "badge": "Best Value"
+ }
+ ],
+ "demoVideoId": "cLhoih4c5Lc",
+ "affiliateCommission": "20%",
+ "affiliateDescription": "Earn up to 20% referral commission. No cap on earnings.",
+ "payment": {
+ "provider": "nowpayments",
+ "apiEndpoint": "/api/payments/create",
+ "telegramRequired": true
+ },
+ "chat": {
+ "provider": "tawk",
+ "propertyId": "68013ff53e654c19146b2db9",
+ "widgetId": "1ip2e3m7d"
+ },
+ "nav": {
+ "links": [
+ { "label": "Home", "href": "/" },
+ { "label": "Team", "href": "/#team" },
+ { "label": "Shop", "href": "/#shop" },
+ { "label": "Signup Offers", "href": "/#offers" },
+ { "label": "Help Center", "href": "/#faq" }
+ ],
+ "cta": "Top Up"
+ },
+ "seo": {
+ "title": "StakeReloadXS - Xtremely Simple Reloads",
+ "description": "Automated bonus claims for Stake.com and Stake.us in under 2 seconds. 700+ monthly users. Zero complaints.",
+ "keywords": ["stake reload", "stake bonus", "stake claims", "stakereloadxs", "stake automation"]
+ }
+}
diff --git a/docs/DESIGN_TOKENS_ASCII.md b/docs/DESIGN_TOKENS_ASCII.md
new file mode 100644
index 00000000..75a8e7b8
--- /dev/null
+++ b/docs/DESIGN_TOKENS_ASCII.md
@@ -0,0 +1,477 @@
+# Design Token ASCII Mockups โ 5 Resolutions
+
+Each token category is shown at:
+- **XS** โ 320px mobile (40-col)
+- **SM** โ 640px mobile-lg (64-col)
+- **MD** โ 768px tablet (80-col)
+- **LG** โ 1024px desktop (100-col)
+- **XL** โ 1280px wide desktop (120-col)
+
+Token categories: Color ยท Typography ยท Spacing ยท Border/Radius ยท Shadow/Glow ยท Animation State
+
+---
+
+## TOKEN: `--brand-primary` (#dc2626 Red)
+
+### XS โ 320px (40 col)
+```
+โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+โ โโโโโโโโโโโโโโโโโโโโโโโโโโ PRIMARY โ
+โ #dc2626 โ
+โ โ
+โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
+โ โ [ CLAIM NOW โถ ] โ โ
+โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
+โ โ Live โ Claiming Now โ
+โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+```
+
+### SM โ 640px (64 col)
+```
+โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+โ COLOR SWATCH USAGE CONTEXT โ
+โ โโโโโโโโโโ Buttons ยท Badges ยท Alerts โ
+โ โ โโโโโโ โ #dc2626 Hover: #ef4444 Active: #b91c1c โ
+โ โ โโโโโโ โ Red-600 Border-glow ยท Stat numbers โ
+โ โโโโโโโโโโ โ
+โ โ
+โ [ CLAIM YOUR XS RELOAD โถโถโถโถโถโถโถโถโถโถโถโถโถโถโถโถโถโถ ] โ btn-primary โ
+โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+```
+
+### MD โ 768px (80 col)
+```
+โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+โ TOKEN: --brand-primary โ
+โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
+โ SWATCH HEX RGB USAGE โ
+โ โโโโโโโโโโโโ #dc2626 rgb(220,38,38) โข CTA buttons (fill) โ
+โ โ โโโโโโโโ โ โข Live pulse dot โ
+โ โ โโโโโโโโ โ Contrast On black: โ โข Metric numbers โ
+โ โ โโโโโโโโ โ ratio On white: โ โข FAQ chevron โ
+โ โโโโโโโโโโโโ 5.8:1 (WCAG AA pass) โข Border on hover โ
+โ โ
+โ States: DEFAULT #dc2626 โโhoverโโโถ #ef4444 โโactiveโโโถ #b91c1c โ
+โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+```
+
+### LG โ 1024px (100 col)
+```
+โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+โ DESIGN TOKEN: --brand-primary โ
+โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
+โ โ
+โ SWATCH SCALE (tints โ shades) COMPONENT USAGE MAP โ
+โ โโโโโ โโโโโ โโโโโ โโโโโ โโโโโ โโโโโ โโโโโ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
+โ โโโโโ โโโโโ โโโโโ โโโโโ โโโโโ โโโโโ โโโโโ โ fill bg โ โ
+โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ bg + text โ โ
+โ โโโโโ โโโโโ โโโโโ โโโโโ โโโโโ โโโโโ โโโโโ โ pulse animation โ โ
+โ 100 200 300 400 [600] 700 800 โ text color โ โ
+โ โฒ brand-primary โ border glow โ โ
+โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
+โ [ TRY IT FREE โถ ] [ TOP UP CREDITS ] โ
+โ โโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโ โ btn-secondary (no fill, border only) โ
+โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+```
+
+### XL โ 1280px (120 col)
+```
+โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+โ DESIGN TOKEN: --brand-primary ยท #dc2626 ยท Red-600 ยท Role: ACTION / ATTENTION โ
+โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
+โ โ
+โ FULL SCALE INTERACTION STATES SEMANTIC PAIRINGS โ
+โ โโโโโฌโโโโฌโโโโฌโโโโฌ[โโโ]โฌโโโโฌโโโโฌโโโโฌโโโโ DEFAULT โโโโโโโโ #dc2626 --brand-primary + --brand-bg โ
+โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ HOVER โโโโโโโโ #ef4444 --brand-primary + white โ
+โ โ050โ100โ200โ300โ 600 โ700โ800โ900โ950โ ACTIVE โโโโโโโโ #b91c1c --brand-primary + transparent โ
+โ โโโโโดโโโโดโโโโดโโโโด[โโโ]โดโโโโดโโโโดโโโโดโโโโ FOCUS โโโโโโโโ #dc2626 + ring --brand-primary/15 (bg alpha) โ
+โ โฒ brand-primary DISABLED โโโโโโโโ #dc2626 @ 40% โ
+โ โ
+โ FULL COMPONENT PREVIEW (hero section) โ
+โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
+โ โ โ Live โ Claiming Now โ โ
+โ โ โ โ
+โ โ Xtremely Simple Reloads โ โ
+โ โ โ โ
+โ โ [ TRY IT FREE โถ ]โโโโโโโโโโโโโโโ [ Top Up Credits ]โโโโโโโโโโโโโโโ โ โ
+โ โ โฒโโ btn-primary (--brand-primary fill) โฒโโ btn-secondary (--brand-primary border on hover) โ โ
+โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
+โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+```
+
+---
+
+## TOKEN: `--brand-bg` / `--brand-bg-secondary` / `--brand-bg-tertiary`
+
+### XS โ 320px
+```
+โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ โ --brand-bg #000
+โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ โ --brand-bg-secondary #111
+โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ โ --brand-bg-tertiary #1a1a1a
+โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+```
+
+### SM โ 640px
+```
+โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+โ LAYER HEX USAGE โ
+โ bg #000000 Page background, main sections โ
+โ bg-secondary #111111 Cards, nav, footer, alt sections โ
+โ bg-tertiary #1a1a1a Input fields, nested cards, dropdowns โ
+โ โ
+โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
+โ โ #000 PAGE โ โ
+โ โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ โ
+โ โ โ #111 CARD / SECTION โ โ โ
+โ โ โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ โ โ
+โ โ โ โ #1a1a1a INPUT / NESTED ELEMENT โ โ โ โ
+โ โ โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ โ โ
+โ โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ โ
+โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
+โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+```
+
+### MD โ 768px
+```
+โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+โ BACKGROUND LAYERS โ
+โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
+โ โ
+โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ #000 Z:0 โ
+โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
+โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ #111 Z:1 โ
+โ โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ โ
+โ โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ #1a1a Z:2 โ
+โ โ โ [ @telegram_input ] โ โ โ
+โ โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ โ
+โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
+โ โ
+โ Contrast ratios (white text): #000 21:1 #111 19:1 #1a1a 17:1 โ
+โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+```
+
+### LG โ 1024px
+```
+โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+โ BACKGROUND TOKEN SYSTEM โ ELEVATION MODEL โ
+โ โ
+โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
+โ โ PAGE #000000 โ โ
+โ โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ โ
+โ โ โ SECTION ALT #111111 โ โ NAV / FOOTER #111111 โ โ โ
+โ โ โ โโโโโโโโโโโโโโโโโโโโโโโโโ โ โ โ โ โ
+โ โ โ โ CARD #111111 โ โ โ [Home] [Shop] [Affiliates] โ โ โ
+โ โ โ โ โโโโโโโโโโโโโโโโโโโ โ โ โ [ TOP UP โโโโโโโโโโโโ ] โ โ โ
+โ โ โ โ โ INPUT #1a1a1a โ โ โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ โ โ
+โ โ โ โ โ @username โ โ โ โ โ
+โ โ โ โ โโโโโโโโโโโโโโโโโโโ โ โ MODAL BACKDROP rgba(0,0,0,0.85) โ โ
+โ โ โ โโโโโโโโโโโโโโโโโโโโโโโโโ โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ โ
+โ โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ MODAL #111111 โ โ โ
+โ โ โ โโโโโโโโโโโโโโโโโโโโโโโโโโโ โ โ โ
+โ โ โ โ MODAL INPUT #1a1a1a โ โ โ โ
+โ โ โ โโโโโโโโโโโโโโโโโโโโโโโโโโโ โ โ โ
+โ โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ โ
+โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
+โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+```
+
+### XL โ 1280px
+```
+โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+โ TOKEN: BACKGROUND SYSTEM ยท 3-layer depth model โ
+โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
+โ โ
+โ TOKEN NAME VALUE OPACITY VARIANTS ASSIGNED COMPONENTS โ
+โ --brand-bg #000000 /5 /10 /15 /20 /30 /50 /75 body, main sections, hero, page wrapper โ
+โ --brand-bg-secondary #111111 /5 /10 /15 /20 /30 /50 /75 cards, navbar, footer, alt sections, modal bg โ
+โ --brand-bg-tertiary #1a1a1a /5 /10 /15 /20 /30 /50 /75 inputs, nested cards, service tiers, tooltips โ
+โ โ
+โ FULL PAGE WIREFRAME โ
+โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
+โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ NAV #111 โโโโโโโโโโโโโโโโโโโโโโโโ โ
+โ โ โ โ
+โ โ HERO โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ #000 (page bg) โ โ
+โ โ โ โ
+โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ FEATURES #111 โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
+โ โ โโโโโโโโโโโโโ โโโโโโโโโโโโโ โโโโโโโโโโโโโ CARDS #111 โ โ
+โ โ โโโโโโโโโโโโโ โโโโโโโโโโโโโ โโโโโโโโโโโโโ INPUT#1a โ โ
+โ โ โโโโโโโโโโโโโ โโโโโโโโโโโโโ โโโโโโโโโโโโโ โ โ
+โ โ METRICS โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ #dc2626 full bleed โ โ
+โ โ SHOP โโ CARDS โโโ INPUTS โโโ FOOTER โโโ โ โ
+โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
+โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+```
+
+---
+
+## TOKEN: `--brand-text` / `--brand-muted` / `--brand-faint`
+
+### XS โ 320px
+```
+โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+โ Heading text #f3f4f6โ
+โ Body copy text #f3f4f6โ
+โ Supporting detail #9ca3afโ
+โ Placeholder / disabled #4b5563โ
+โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+```
+
+### SM โ 640px
+```
+โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+โ --brand-text #f3f4f6 โโโโโโโโโโโโโโ Primary copy โ
+โ --brand-muted #9ca3af โโโโโโ Secondary / supportingโ
+โ --brand-faint #4b5563 โโโโ Placeholder / disabledโ
+โ โ
+โ "Xtremely Simple Reloads" โ brand-text (hero h1) โ
+โ "Automated claims in 2 seconds" โ brand-muted (subheading) โ
+โ "Powered by NOWPayments" โ brand-faint (footer note) โ
+โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+```
+
+### MD โ 768px
+```
+โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+โ TYPOGRAPHY TOKEN MAP โ
+โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
+โ โ
+โ Xtremely Simple Reloads โ Poppins 900 ยท brand-text โ
+โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
+โ Automated bonus claims for Stake.com โ Poppins 400 ยท brand-muted โ
+โ in under 2 seconds. โ
+โ โ
+โ 700+ Monthly Users ยท 25+ Years Dev ยท 0 Complaints โ
+โ โโโ brand-primary โโ โโโ brand-primary โโโโ โโ brand-primary โโ โ
+โ โ
+โ Powered by NOWPayments ยท BTC, ETH, USDT accepted โ
+โ โโโโโโโโโโโโโโโโโโโโโโ brand-faint โโโโโโโโโโโโโโโโโโโโโโโโโโ โ
+โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+```
+
+### LG โ 1024px
+```
+โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+โ TEXT TOKEN HIERARCHY โ
+โ โ
+โ SIZE WEIGHT TOKEN SAMPLE โ
+โ 4.5rem 900 brand-text Xtremely Simple Reloads โ
+โ 1.25rem 400 brand-muted Automated bonus claims for Stake in under 2 seconds โ
+โ 0.875rem 600 brand-text Why StakeReloadXS? (section heading) โ
+โ 0.875rem 400 brand-muted Dedicated infrastructure for your account. โ
+โ 0.75rem 500 brand-primary Read more โ โ
+โ 0.75rem 400 brand-faint Powered by NOWPayments ยท BTC, ETH, USDT accepted โ
+โ โ
+โ CONTRAST CHECK ON #000000 BG: โ
+โ brand-text #f3f4f6 โโโโ 19.3:1 โ AAA โ
+โ brand-muted #9ca3af โโโโ 7.2:1 โ AA+ โ
+โ brand-faint #4b5563 โโโโ 3.1:1 โณ AA (large text only) โ
+โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+```
+
+### XL โ 1280px
+```
+โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+โ TYPOGRAPHY TOKEN SYSTEM ยท Poppins (headings) + Inter (body) โ
+โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
+โ โ
+โ SCALE TOKEN HEX WEIGHT COMPONENT ROLE SAMPLE TEXT โ
+โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
+โ text-7xl brand-text #f3f4f6 900 Hero headline Xtremely Simple Reloads โ
+โ text-4xl brand-text #f3f4f6 700 Section headings Credit Packages โ
+โ text-xl brand-text #f3f4f6 600 Card titles, nav links Private Servers โ
+โ text-base brand-muted #9ca3af 400 Body copy, descriptions Dedicated infrastructure... โ
+โ text-sm brand-muted #9ca3af 400 Sub-labels, captions 5,000 credits โ
+โ text-xs brand-primary #dc2626 600 Badges, boost tags Popular ยท 10% Boost โ
+โ text-xs brand-faint #4b5563 400 Legal, disclaimers, footnotes Not affiliated with Stake.com โ
+โ โ
+โ FLUID SCALING (clamp): โ
+โ h1: clamp(2.5rem, 5vw + 1rem, 4.5rem) h2: clamp(1.75rem, 3vw + 0.5rem, 2.5rem) โ
+โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+```
+
+---
+
+## TOKEN: `--brand-border` / Border Radius
+
+### XS โ 320px
+```
+โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
+โ โ CARD border: 1px #222 โ โ
+โ โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ โ
+โ โ โ INPUT border: 1px #222 โ โ โ
+โ โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ โ
+โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
+โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ โ hover: border #dc2626
+โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+```
+
+### SM โ 640px
+```
+โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+โ TOKEN VALUE USAGE โ
+โ --brand-border #222222 Default card/input border โ
+โ + hover state #dc2626 Card hover, input focus โ
+โ radius-sm 6px Inputs, badges, small elements โ
+โ radius-md 12px Cards, modals, sections โ
+โ radius-full 9999px Pills, live dots, round badges โ
+โ โ
+โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
+โ โ radius-md (card) โ โ radius-md (modal) โ โ
+โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
+โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+```
+
+### MD โ 768px
+```
+โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+โ BORDER + RADIUS SYSTEM โ
+โ โ
+โ DEFAULT STATE HOVER / FOCUS STATE โ
+โ โโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโ โ
+โ โ โ โ โโโโโโโโโโโโโโโโ โ โ border #dc2626 โ
+โ โ CARD โ โ CARD (hovered) โ โ
+โ โ border: #222 โ โ border: #dc2626 โ โ
+โ โโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโ โ
+โ โ
+โ RADIUS VALUES: โ
+โ none โโโโโโโโโโโโโโโ sm โโโโโโโโโโโโโโโฎ md โญโโโโโโโโโโโโโโฎ full โ โ
+โ โโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโฏ โฐโโโโโโโโโโโโโโฏ โ
+โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+```
+
+### LG โ 1024px
+```
+โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+โ BORDER SYSTEM โ States ร Components โ
+โ โ
+โ COMPONENT DEFAULT HOVER FOCUS ACTIVE โ
+โ Card 1px #222222 1px #dc2626 โ 1px #dc2626 โ
+โ Input 1px #222222 1px #dc2626 1px #dc2626 1px #dc2626 โ
+โ Button-primary none none 2px ring #dc2626 none โ
+โ Button-secondary 1px #222222 1px #dc2626 2px ring #dc2626 1px #b91c1c โ
+โ Modal 1px #222222 โ โ โ โ
+โ Service tier 1px #222222 1px #dc2626 โ โ โ
+โ โ
+โ BOX SHADOWS (neon-glow system): โ
+โ neon-sm: 0 0 8px #dc2626 โ hover on interactive elements โ
+โ neon-md: 0 0 20px #dc2626 โ active CTA, pulsing badge โ
+โ neon-lg: 0 0 20px #dc2626, 0 0 40px ... โ hero pulse, modal active state โ
+โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+```
+
+### XL โ 1280px
+```
+โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+โ BORDER + SHADOW TOKEN SYSTEM ยท Full specification โ
+โ โ
+โ BORDER TOKENS โ
+โ --brand-border: #222222 โ 1px solid border (all resting states) โ
+โ --brand-border-glow: #dc2626 โ border color on hover/focus (same as primary) โ
+โ โ
+โ RADIUS SCALE โ
+โ --radius-none: 0px form inline elements โ
+โ --radius-sm: 6px badges, tags, inputs, small buttons โ
+โ --radius-md: 12px cards, modals, section containers, service tiers โ
+โ --radius-lg: 16px large modals, feature panels โ
+โ --radius-xl: 20px credit package cards, hero CTA containers โ
+โ --radius-full: 9999px live dot, pill badges, circular avatars โ
+โ โ
+โ SHADOW SCALE (using --brand-primary color) โ
+โ --shadow-neon-xs: 0 0 4px rgba(220,38,38,0.4) subtle highlight โ
+โ --shadow-neon-sm: 0 0 8px rgba(220,38,38,0.6) card hover โ
+โ --shadow-neon-md: 0 0 20px rgba(220,38,38,0.5), 0 0 40px rgba(220,38,38,0.2) CTA pulse โ
+โ --shadow-neon-lg: 0 0 40px rgba(220,38,38,0.7), 0 0 80px rgba(220,38,38,0.3) hero glow โ
+โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+```
+
+---
+
+## TOKEN: Animation / Motion
+
+### XS โ 320px
+```
+โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+โ smooth duration: 300ms ease-out โ
+โ fast duration: 150ms ease-in-out โ
+โ fade opacity 0โ1 400ms โ
+โ slide-up translateY(20px)โ0 400ms โ
+โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+```
+
+### SM โ 640px
+```
+โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+โ MOTION TOKEN VALUE USE CASE โ
+โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+โ --dur-fast 150ms Button hover, toggle โ
+โ --dur-base 300ms Card transitions, nav โ
+โ --dur-slow 500ms Page fade, hero entrance โ
+โ --ease-out ease-out Most enter animations โ
+โ --ease-spring cubic-bezier Modal pop, scale effects โ
+โ โ
+โ [ frame 0 ]โ[ frame 1 ]โ[ frame 2 ]โ[ frame 3 ] โsmooth โ
+โ [f0]โ[f1]โ[f2]โ[f3] โfast โ
+โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+```
+
+### MD โ 768px
+```
+โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+โ ANIMATION TOKEN SYSTEM โ
+โ โ
+โ ENTRANCE (scroll-triggered via Framer Motion whileInView): โ
+โ opacity: 0โ1, translateY: 20pxโ0, duration: 400ms, delay: i*100ms โ
+โ โ
+โ [โโโโโโโโโโโโโโโโโ] card 1 โ fades in โ
+โ [โโโโโโโโโโโโโโโโโโโ] card 2 โ fades in (100ms delay) โ
+โ [โโโโโโโโโโโโโโโโโโโโโ] card 3 โ fades in (200ms delay) โ
+โ โ
+โ LIVE DOT PULSE: scale 1โ2, opacity 0.75โ0 infinite 1s ease-out โ
+โ โ โโโ ping layer (expand) โ โโโ base layer (static) โ
+โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+```
+
+### LG โ 1024px
+```
+โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+โ MOTION SYSTEM โ All animation tokens โ
+โ โ
+โ TOKEN VALUE USAGE โ
+โ --dur-instant 50ms Immediate feedback (click flash) โ
+โ --dur-fast 150ms Hover states, toggles โ
+โ --dur-base 300ms ease-out Nav, card transitions โ
+โ --dur-slow 500ms ease-out Hero entrance, page fade โ
+โ --dur-very-slow 800ms ease-in-out Metrics counter, page mount โ
+โ โ
+โ STAGGER: children delay = index ร 80ms (features, credit packages) โ
+โ VIEWPORT TRIGGER: { once: true, margin: "-50px" } (scroll-into-view) โ
+โ โ
+โ MODAL: scale(0.95)+opacity(0)โscale(1)+opacity(1) 200ms ease-out โ
+โ FAQ: height(0)โheight(auto) 250ms ease-in-out โ
+โ NAV: translateY(-100%)โ0 300ms on scroll threshold โ
+โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+```
+
+### XL โ 1280px
+```
+โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+โ ANIMATION TOKEN SYSTEM ยท Full specification for brand = "smooth" โ
+โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
+โ โ
+โ DURATION TOKENS EASING TOKENS KEYFRAME DEFINITIONS โ
+โ --dur-instant 50ms --ease-linear linear @fadeIn: 0%{opacity:0} 100%{opacity:1} โ
+โ --dur-fast 150ms --ease-out ease-out @slideUp: 0%{transform:translateY(20px);opacity:0} โ
+โ --dur-base 300ms --ease-in-out ease-in-out 100%{transform:translateY(0);opacity:1} โ
+โ --dur-slow 500ms --ease-spring cubic-bezier( @pulse: 0%,100%{opacity:1} 50%{opacity:0.4} โ
+โ --dur-slow2 800ms 0.34,1.56, @ping: to{transform:scale(2);opacity:0} โ
+โ 0.64,1) โ
+โ โ
+โ PER-BRAND ANIMATION PRESET (brand.animation field): โ
+โ "smooth" โ dur-base=300ms, easing=ease-out, stagger=80ms (StakeReloadXS, Stakereload) โ
+โ "fast" โ dur-base=150ms, easing=ease-in-out, stagger=50ms (StakeClaimBot) โ
+โ "glitch" โ dur-base=100ms, easing=steps(2), stagger=30ms (GambaReload dark variant) โ
+โ "static" โ dur-base=0ms, easing=linear, stagger=0ms (accessibility mode) โ
+โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+```
diff --git a/docs/USER_JOURNEY_MAPS.md b/docs/USER_JOURNEY_MAPS.md
new file mode 100644
index 00000000..680e2f81
--- /dev/null
+++ b/docs/USER_JOURNEY_MAPS.md
@@ -0,0 +1,262 @@
+# Fused Gaming โ User Journey Maps
+
+Five distinct personas interact with the platform at very different depths.
+Each journey is mapped below as a Mermaid flowchart, followed by a state diagram
+showing the emotional arc, then a sequence diagram for the critical path.
+
+---
+
+## Persona Definitions
+
+| # | Persona | Entry Point | Goal | Key Fear |
+|---|---------|-------------|------|----------|
+| 1 | **Prospective Customer** | Affiliate link / social | Understand the offer | Scam / account ban |
+| 2 | **First-Time Customer** | Direct purchase | Activate credits, see first claim | Setup complexity |
+| 3 | **Returning Customer** | Bookmark / Telegram reminder | Top up, check stats, re-claim | Credits running out |
+| 4 | **Super Agent** | Admin subdomain | Manage affiliate network, view volumes | Fraud, bad actors |
+| 5 | **Administrator** | Internal admin panel | Deploy brands, configure tokens, monitor all | System instability |
+
+---
+
+## 1. Prospective Customer Journey
+
+```mermaid
+journey
+ title Prospective Customer: Discovery โ First Purchase
+ section Awareness
+ Sees affiliate link / ad: 3: Prospective
+ Lands on hero section: 4: Prospective
+ Reads tagline "Xtremely Simple": 4: Prospective
+ section Consideration
+ Scrolls to Features: 4: Prospective
+ Watches demo video: 5: Prospective
+ Reads Metrics bar (400+ clients): 4: Prospective
+ Checks FAQ (legit? ban risk?): 3: Prospective
+ Views credit packages + prices: 4: Prospective
+ section Decision
+ Clicks "Try It Free" ($5 package): 5: Prospective
+ Opens PaymentModal: 3: Prospective
+ Enters Telegram username: 3: Prospective
+ Completes crypto payment: 4: Prospective
+ Lands on /payment-success: 5: Prospective
+ section Post-Purchase
+ Gets Telegram message w/ XSID: 5: Prospective
+ Becomes First-Time Customer: 5: Prospective
+```
+
+```mermaid
+stateDiagram-v2
+ direction LR
+ [*] --> Skeptical : arrives via affiliate link
+ Skeptical --> Curious : hero + stats land
+ Curious --> Interested : demo video watched
+ Interested --> Hesitant : sees payment required
+ Hesitant --> Convinced : FAQ resolves ban concern
+ Convinced --> Converting : clicks package
+ Converting --> Purchased : payment complete
+ Purchased --> [*] : Telegram confirmation received
+```
+
+---
+
+## 2. First-Time Customer Journey
+
+```mermaid
+journey
+ title First-Time Customer: Activation โ First Successful Claim
+ section Onboarding
+ Receives Telegram welcome message: 5: FirstTime
+ Follows setup instructions: 3: FirstTime
+ Connects account credentials: 3: FirstTime
+ Sees first automation run: 5: FirstTime
+ section First Use
+ Monitors claim progress: 4: FirstTime
+ Sees first reload claimed (<2s): 5: FirstTime
+ Checks credit balance in dashboard: 4: FirstTime
+ section Expansion
+ Explores affiliate program link: 4: FirstTime
+ Shares referral URL with friend: 4: FirstTime
+ Bookmarks site for top-up: 4: FirstTime
+ section Retention Hook
+ Receives "Low credits" Telegram DM: 3: FirstTime
+ Returns to shop to top up: 4: FirstTime
+ Becomes Returning Customer: 5: FirstTime
+```
+
+```mermaid
+sequenceDiagram
+ actor U as First-Time User
+ participant TG as Telegram Bot
+ participant SYS as Claim System
+ participant DB as Credits DB
+
+ U->>TG: completes payment (NOWPayments webhook)
+ TG->>DB: allocate 5000 credits to XSID
+ TG-->>U: "Welcome! Your XSID is active."
+ U->>SYS: connects Stake account
+ SYS->>DB: deduct 1 credit per claim attempt
+ SYS-->>U: claim triggered < 2s
+ SYS-->>TG: notify U "Reload claimed: $X"
+ DB-->>TG: credit balance < 500 โ alert
+ TG-->>U: "Running low โ top up here ๐"
+```
+
+---
+
+## 3. Returning Customer Journey
+
+```mermaid
+journey
+ title Returning Customer: Re-engagement โ Ongoing Value Loop
+ section Re-entry
+ Receives Telegram low-credit alert: 4: Returning
+ Opens site from bookmark: 4: Returning
+ Skips hero (already knows it): 5: Returning
+ section Top-Up
+ Goes directly to #shop: 5: Returning
+ Selects larger package (more value):5: Returning
+ Opens PaymentModal: 4: Returning
+ Pre-filled Telegram from memory: 5: Returning
+ Completes payment quickly: 5: Returning
+ section Loyalty Loop
+ Checks affiliate earnings: 4: Returning
+ Sees compounding commission: 5: Returning
+ Shares link to earn more: 5: Returning
+ Credits replenished, loop restarts: 5: Returning
+```
+
+```mermaid
+stateDiagram-v2
+ direction TB
+ [*] --> Active : credits loaded
+ Active --> LowCredits : balance < 500
+ LowCredits --> Notified : Telegram alert sent
+ Notified --> ReturningToShop : clicks top-up link
+ ReturningToShop --> Active : new credits purchased
+ Active --> Advocate : shares affiliate link
+ Advocate --> Active : earns commission credit
+ Active --> Churned : no login for 30 days
+ Churned --> Notified : win-back campaign
+```
+
+---
+
+## 4. Super Agent Journey
+
+```mermaid
+journey
+ title Super Agent: Affiliate Network Management
+ section Dashboard Access
+ Logs into agent subdomain: 4: SuperAgent
+ Views total referral volume: 5: SuperAgent
+ Sees pending commission payouts: 4: SuperAgent
+ section Network Management
+ Reviews referred user list: 4: SuperAgent
+ Flags suspicious referral pattern: 3: SuperAgent
+ Contacts support about fraud case: 3: SuperAgent
+ Fraud flagged + commission withheld: 4: SuperAgent
+ section Growth Actions
+ Generates new campaign referral URL: 5: SuperAgent
+ Posts to community channels: 5: SuperAgent
+ Tracks click-through โ conversion: 5: SuperAgent
+ section Payout
+ Requests weekly commission payout: 5: SuperAgent
+ Receives crypto to wallet: 5: SuperAgent
+ Reviews payout history: 4: SuperAgent
+```
+
+```mermaid
+sequenceDiagram
+ actor A as Super Agent
+ participant AP as Agent Portal
+ participant AFF as Affiliate Engine (Rust)
+ participant FD as Fraud Detector
+ participant PAY as Payout Service
+
+ A->>AP: view dashboard
+ AP->>AFF: GET /affiliate/stats?agentId=xxx
+ AFF-->>AP: { referrals: 42, volume: $4200, pending: $840 }
+ AP-->>A: renders commission overview
+
+ A->>AP: request payout
+ AP->>AFF: POST /affiliate/payout
+ AFF->>FD: validate referral authenticity
+ FD-->>AFF: PASS (no fraud signals)
+ AFF->>PAY: initiate crypto transfer $840
+ PAY-->>A: Telegram: "Payout sent โ"
+```
+
+---
+
+## 5. Administrator Journey
+
+```mermaid
+journey
+ title Administrator: Brand Deployment + Platform Operations
+ section Brand Launch
+ Opens Admin Panel (/admin): 5: Admin
+ Clicks "New Brand" button: 5: Admin
+ Fills brand config form: 4: Admin
+ Previews ASCII token samples: 5: Admin
+ Selects deploy target (Vercel/VPS): 4: Admin
+ Clicks "Deploy Brand": 5: Admin
+ Monitors build log output: 4: Admin
+ Brand live on new domain: 5: Admin
+ section Operations
+ Views all active brands + uptime: 4: Admin
+ Checks payment success rates: 4: Admin
+ Reviews affiliate fraud queue: 3: Admin
+ Patches brand copy variant (A/B): 5: Admin
+ Pushes config update (no redeploy): 5: Admin
+ section Monitoring
+ Views event stream (Rust service): 4: Admin
+ Sees funnel drop-off by brand: 4: Admin
+ Tunes credit package pricing: 5: Admin
+```
+
+```mermaid
+flowchart TD
+ A([Admin opens /admin]) --> B{Action?}
+
+ B --> C[New Brand]
+ C --> C1[Fill brand config form]
+ C1 --> C2[Select tone + copy variant]
+ C2 --> C3[Preview ASCII token samples]
+ C3 --> C4{Deploy target}
+ C4 --> C4a[Vercel] --> DEPLOY
+ C4 --> C4b[VPS] --> DEPLOY
+ C4 --> C4c[Docker] --> DEPLOY
+ DEPLOY([๐ Brand Live])
+
+ B --> D[Edit Brand]
+ D --> D1[Update JSON config]
+ D1 --> D2[Hot-reload CSS vars]
+ D2 --> D3[No rebuild needed]
+
+ B --> E[Monitor]
+ E --> E1[Uptime per domain]
+ E --> E2[Payment conversion rate]
+ E --> E3[Active credits issued]
+ E --> E4[Fraud queue]
+
+ B --> F[Affiliates]
+ F --> F1[Agent list + volumes]
+ F --> F2[Payout queue]
+ F --> F3[Fraud flags]
+```
+
+---
+
+## Cross-Persona Funnel Overlap
+
+```mermaid
+flowchart LR
+ PROSPECT([Prospective\nCustomer]) -->|purchases| FIRST([First-Time\nCustomer])
+ FIRST -->|repeats| RETURNING([Returning\nCustomer])
+ RETURNING -->|recruits| AGENT([Super\nAgent])
+ AGENT -->|scales network| RETURNING
+
+ ADMIN([Administrator]) -->|deploys brand| PROSPECT
+ ADMIN -->|manages agents| AGENT
+ ADMIN -->|monitors all| FIRST & RETURNING
+```
diff --git a/package.json b/package.json
new file mode 100644
index 00000000..5d327953
--- /dev/null
+++ b/package.json
@@ -0,0 +1,20 @@
+{
+ "name": "fused-gaming-monorepo",
+ "version": "1.0.0",
+ "private": true,
+ "workspaces": [
+ "apps/*",
+ "packages/*"
+ ],
+ "scripts": {
+ "dev": "npm run dev --workspace=apps/web",
+ "build": "npm run build --workspace=apps/web",
+ "build:brand": "NEXT_PUBLIC_BRAND=$BRAND npm run build --workspace=apps/web",
+ "lint": "npm run lint --workspace=apps/web",
+ "type-check": "npm run type-check --workspace=apps/web"
+ },
+ "engines": {
+ "node": "20.x",
+ "npm": ">=9.0.0"
+ }
+}
diff --git a/packages/analytics/index.ts b/packages/analytics/index.ts
new file mode 100644
index 00000000..ea1de360
--- /dev/null
+++ b/packages/analytics/index.ts
@@ -0,0 +1,2 @@
+// @fused-gaming/analytics โ analytics utilities (stub)
+export {};
diff --git a/packages/analytics/package.json b/packages/analytics/package.json
new file mode 100644
index 00000000..ded54dc8
--- /dev/null
+++ b/packages/analytics/package.json
@@ -0,0 +1,12 @@
+{
+ "name": "@fused-gaming/analytics",
+ "version": "1.0.0",
+ "private": true,
+ "types": "./index.ts",
+ "exports": {
+ ".": {
+ "types": "./index.ts",
+ "default": "./index.ts"
+ }
+ }
+}
diff --git a/packages/branding/index.ts b/packages/branding/index.ts
new file mode 100644
index 00000000..08f049f4
--- /dev/null
+++ b/packages/branding/index.ts
@@ -0,0 +1,2 @@
+// @fused-gaming/branding โ brand assets and identity (stub)
+export {};
diff --git a/packages/branding/package.json b/packages/branding/package.json
new file mode 100644
index 00000000..e2ccf7e2
--- /dev/null
+++ b/packages/branding/package.json
@@ -0,0 +1,12 @@
+{
+ "name": "@fused-gaming/branding",
+ "version": "1.0.0",
+ "private": true,
+ "types": "./index.ts",
+ "exports": {
+ ".": {
+ "types": "./index.ts",
+ "default": "./index.ts"
+ }
+ }
+}
diff --git a/packages/copy/index.ts b/packages/copy/index.ts
new file mode 100644
index 00000000..5ae9ec9b
--- /dev/null
+++ b/packages/copy/index.ts
@@ -0,0 +1,2 @@
+// @fused-gaming/copy โ marketing copy and i18n strings (stub)
+export {};
diff --git a/packages/copy/package.json b/packages/copy/package.json
new file mode 100644
index 00000000..79d06c42
--- /dev/null
+++ b/packages/copy/package.json
@@ -0,0 +1,12 @@
+{
+ "name": "@fused-gaming/copy",
+ "version": "1.0.0",
+ "private": true,
+ "types": "./index.ts",
+ "exports": {
+ ".": {
+ "types": "./index.ts",
+ "default": "./index.ts"
+ }
+ }
+}
diff --git a/packages/tokens/package.json b/packages/tokens/package.json
new file mode 100644
index 00000000..8cfc2ad8
--- /dev/null
+++ b/packages/tokens/package.json
@@ -0,0 +1,10 @@
+{
+ "name": "@fused-gaming/tokens",
+ "version": "1.0.0",
+ "private": true,
+ "main": "./src/tokens.ts",
+ "types": "./src/tokens.ts",
+ "exports": {
+ ".": "./src/tokens.ts"
+ }
+}
diff --git a/packages/tokens/src/tokens.ts b/packages/tokens/src/tokens.ts
new file mode 100644
index 00000000..a710da59
--- /dev/null
+++ b/packages/tokens/src/tokens.ts
@@ -0,0 +1,344 @@
+/**
+ * Fused Gaming โ Design Token System
+ *
+ * This is the single source of truth for all design tokens.
+ * Tokens are consumed by:
+ * - CSS custom properties (injected in layout.tsx via themeToCSSVars)
+ * - TailwindCSS config (via CSS var references)
+ * - Admin GUI brand previewer
+ * - Deploy script validation
+ *
+ * Adding a new brand:
+ * 1. Create configs/brands/.json with BrandTheme values
+ * 2. Register it in apps/web/src/lib/brand.ts brandModules map
+ * 3. Run: ./scripts/deploy.sh vercel
+ */
+
+// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+// BASE SCALE โ Raw values. Brand themes reference these.
+// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+
+export const colorScale = {
+ // Neutrals
+ black: "#000000",
+ gray950: "#0a0a0a",
+ gray900: "#111111",
+ gray850: "#1a1a1a",
+ gray800: "#222222",
+ gray700: "#333333",
+ gray600: "#4b5563",
+ gray500: "#6b7280",
+ gray400: "#9ca3af",
+ gray300: "#d1d5db",
+ gray100: "#f3f4f6",
+ white: "#ffffff",
+
+ // Red scale (StakeReloadXS / Stakereload)
+ red400: "#f87171",
+ red500: "#ef4444",
+ red600: "#dc2626",
+ red700: "#b91c1c",
+ red800: "#991b1b",
+ red900: "#7f1d1d",
+
+ // Green scale (future brand variant)
+ green400: "#4ade80",
+ green500: "#22c55e",
+ green600: "#16a34a",
+
+ // Teal / mint scale (cyberpunk variant)
+ teal400: "#2dd4bf",
+ mint400: "#00FFB2",
+ mint600: "#00CC8F",
+
+ // Purple scale (premium variant)
+ purple400: "#c084fc",
+ purple600: "#9333ea",
+ purple800: "#6b21a8",
+
+ // Orange scale (casino variant)
+ orange400: "#fb923c",
+ orange600: "#ea580c",
+
+ // Pink / neon
+ pink400: "#f472b6",
+ neon: "#FF3D81",
+} as const;
+
+export const fontFamilies = {
+ poppins: "'Poppins', system-ui, sans-serif",
+ inter: "'Inter', system-ui, sans-serif",
+ mono: "'JetBrains Mono', 'Fira Code', ui-monospace, monospace",
+ serif: "'Playfair Display', Georgia, serif",
+} as const;
+
+export const fontWeights = {
+ light: 300,
+ regular: 400,
+ medium: 500,
+ semibold: 600,
+ bold: 700,
+ extrabold: 800,
+ black: 900,
+} as const;
+
+export const fontSizes = {
+ xs: "0.75rem", // 12px
+ sm: "0.875rem", // 14px
+ base: "1rem", // 16px
+ lg: "1.125rem", // 18px
+ xl: "1.25rem", // 20px
+ "2xl":"1.5rem", // 24px
+ "3xl":"1.875rem", // 30px
+ "4xl":"2.25rem", // 36px
+ "5xl":"3rem", // 48px
+ "6xl":"3.75rem", // 60px
+ "7xl":"4.5rem", // 72px
+} as const;
+
+export const spacing = {
+ 0: "0px",
+ 1: "4px",
+ 2: "8px",
+ 3: "12px",
+ 4: "16px",
+ 5: "20px",
+ 6: "24px",
+ 8: "32px",
+ 10: "40px",
+ 12: "48px",
+ 16: "64px",
+ 20: "80px",
+ 24: "96px",
+} as const;
+
+export const radii = {
+ none: "0px",
+ sm: "6px",
+ md: "12px",
+ lg: "16px",
+ xl: "20px",
+ "2xl":"24px",
+ full: "9999px",
+} as const;
+
+export const shadows = {
+ "neon-xs": (color: string) => `0 0 4px ${color}40`,
+ "neon-sm": (color: string) => `0 0 8px ${color}99`,
+ "neon-md": (color: string) => `0 0 20px ${color}80, 0 0 40px ${color}33`,
+ "neon-lg": (color: string) => `0 0 40px ${color}b3, 0 0 80px ${color}4d`,
+} as const;
+
+export const durations = {
+ instant: "50ms",
+ fast: "150ms",
+ base: "300ms",
+ slow: "500ms",
+ verySlow: "800ms",
+} as const;
+
+export const easings = {
+ linear: "linear",
+ easeOut: "ease-out",
+ easeIn: "ease-in",
+ easeInOut: "ease-in-out",
+ spring: "cubic-bezier(0.34, 1.56, 0.64, 1)",
+ glitch: "steps(2, end)",
+} as const;
+
+// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+// ANIMATION PRESETS โ keyed by brand.animation field
+// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+
+export type AnimationPreset = "smooth" | "fast" | "glitch" | "static";
+
+export const animationPresets: Record = {
+ smooth: {
+ duration: durations.base,
+ easing: easings.easeOut,
+ staggerMs: 80,
+ entranceY: "20px",
+ },
+ fast: {
+ duration: durations.fast,
+ easing: easings.easeInOut,
+ staggerMs: 50,
+ entranceY: "12px",
+ },
+ glitch: {
+ duration: "100ms",
+ easing: easings.glitch,
+ staggerMs: 30,
+ entranceY: "4px",
+ },
+ static: {
+ duration: "0ms",
+ easing: easings.linear,
+ staggerMs: 0,
+ entranceY: "0px",
+ },
+};
+
+// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+// BRAND PRESETS โ maps a tone to a ready-made theme palette
+// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+
+export type BrandTone = "aggressive" | "corporate" | "playful" | "underground" | "premium";
+
+export interface BrandPalette {
+ primary: string;
+ primaryDark: string;
+ primaryHover: string;
+ background: string;
+ backgroundSecondary: string;
+ backgroundTertiary: string;
+ accent: string;
+ accentSecondary: string;
+ text: string;
+ textMuted: string;
+ textFaint: string;
+ border: string;
+ borderGlow: string;
+}
+
+export const brandPalettes: Record = {
+ aggressive: {
+ primary: colorScale.red600,
+ primaryDark: colorScale.red700,
+ primaryHover: colorScale.red500,
+ background: colorScale.black,
+ backgroundSecondary: colorScale.gray900,
+ backgroundTertiary: colorScale.gray850,
+ accent: colorScale.red600,
+ accentSecondary: colorScale.red500,
+ text: colorScale.gray100,
+ textMuted: colorScale.gray400,
+ textFaint: colorScale.gray600,
+ border: colorScale.gray800,
+ borderGlow: colorScale.red600,
+ },
+ corporate: {
+ primary: colorScale.purple600,
+ primaryDark: colorScale.purple800,
+ primaryHover: colorScale.purple400,
+ background: colorScale.black,
+ backgroundSecondary: colorScale.gray900,
+ backgroundTertiary: colorScale.gray850,
+ accent: colorScale.purple600,
+ accentSecondary: colorScale.purple400,
+ text: colorScale.gray100,
+ textMuted: colorScale.gray400,
+ textFaint: colorScale.gray600,
+ border: colorScale.gray800,
+ borderGlow: colorScale.purple600,
+ },
+ playful: {
+ primary: colorScale.orange600,
+ primaryDark: "#c2410c",
+ primaryHover: colorScale.orange400,
+ background: "#0d0d0d",
+ backgroundSecondary: "#141414",
+ backgroundTertiary: "#1c1c1c",
+ accent: colorScale.pink400,
+ accentSecondary: colorScale.orange400,
+ text: colorScale.white,
+ textMuted: colorScale.gray400,
+ textFaint: colorScale.gray600,
+ border: colorScale.gray800,
+ borderGlow: colorScale.orange400,
+ },
+ underground: {
+ primary: colorScale.mint400,
+ primaryDark: colorScale.mint600,
+ primaryHover: "#33ffbb",
+ background: "#0A0A0A",
+ backgroundSecondary: "#111111",
+ backgroundTertiary: "#0F0F0F",
+ accent: colorScale.neon,
+ accentSecondary: "#FF00FF",
+ text: colorScale.white,
+ textMuted: colorScale.gray500,
+ textFaint: colorScale.gray700,
+ border: "#1A1A1A",
+ borderGlow: colorScale.mint400,
+ },
+ premium: {
+ primary: "#c9a84c",
+ primaryDark: "#a8893a",
+ primaryHover: "#dfc06a",
+ background: "#080808",
+ backgroundSecondary: "#0e0e0e",
+ backgroundTertiary: "#161616",
+ accent: "#c9a84c",
+ accentSecondary: "#e8d5a3",
+ text: colorScale.gray100,
+ textMuted: colorScale.gray400,
+ textFaint: colorScale.gray600,
+ border: "#1f1f1f",
+ borderGlow: "#c9a84c",
+ },
+};
+
+// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+// CSS VARIABLE GENERATOR
+// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+
+/**
+ * Generate a full :root { } block from a BrandPalette.
+ * Used server-side in layout.tsx and for live preview in the admin GUI.
+ */
+export function generateCSSVars(palette: BrandPalette, animPreset: AnimationPreset = "smooth"): string {
+ const anim = animationPresets[animPreset];
+ return `
+ /* โโ Color โโ */
+ --brand-primary: ${palette.primary};
+ --brand-primary-dark: ${palette.primaryDark};
+ --brand-primary-hover: ${palette.primaryHover};
+ --brand-bg: ${palette.background};
+ --brand-bg-secondary: ${palette.backgroundSecondary};
+ --brand-bg-tertiary: ${palette.backgroundTertiary};
+ --brand-accent: ${palette.accent};
+ --brand-accent-secondary: ${palette.accentSecondary};
+ --brand-text: ${palette.text};
+ --brand-muted: ${palette.textMuted};
+ --brand-faint: ${palette.textFaint};
+ --brand-border: ${palette.border};
+ --brand-border-glow: ${palette.borderGlow};
+
+ /* โโ Shadows (neon glow, derived from primary) โโ */
+ --shadow-neon-xs: ${shadows["neon-xs"](palette.primary)};
+ --shadow-neon-sm: ${shadows["neon-sm"](palette.primary)};
+ --shadow-neon-md: ${shadows["neon-md"](palette.primary)};
+ --shadow-neon-lg: ${shadows["neon-lg"](palette.primary)};
+
+ /* โโ Motion โโ */
+ --dur-instant: ${durations.instant};
+ --dur-fast: ${durations.fast};
+ --dur-base: ${anim.duration};
+ --dur-slow: ${durations.slow};
+ --ease-out: ${easings.easeOut};
+ --ease-in-out: ${easings.easeInOut};
+ --ease-spring: ${easings.spring};
+ --stagger-ms: ${anim.staggerMs}ms;
+ --entrance-y: ${anim.entranceY};
+
+ /* โโ Radii โโ */
+ --radius-sm: ${radii.sm};
+ --radius-md: ${radii.md};
+ --radius-lg: ${radii.lg};
+ --radius-xl: ${radii.xl};
+ --radius-full: ${radii.full};
+`.trim();
+}
+
+/**
+ * Quick helper: get a palette by tone.
+ */
+export function getPaletteForTone(tone: BrandTone): BrandPalette {
+ return brandPalettes[tone];
+}
diff --git a/packages/ui/package.json b/packages/ui/package.json
new file mode 100644
index 00000000..f275c6b8
--- /dev/null
+++ b/packages/ui/package.json
@@ -0,0 +1,12 @@
+{
+ "name": "@fused-gaming/ui",
+ "version": "1.0.0",
+ "private": true,
+ "types": "./src/index.ts",
+ "exports": {
+ ".": {
+ "types": "./src/index.ts",
+ "default": "./src/index.ts"
+ }
+ }
+}
diff --git a/packages/ui/src/index.ts b/packages/ui/src/index.ts
new file mode 100644
index 00000000..870500e9
--- /dev/null
+++ b/packages/ui/src/index.ts
@@ -0,0 +1,2 @@
+// @fused-gaming/ui โ shared component library (stub)
+export {};
diff --git a/scripts/deploy.sh b/scripts/deploy.sh
new file mode 100755
index 00000000..73c6d975
--- /dev/null
+++ b/scripts/deploy.sh
@@ -0,0 +1,134 @@
+#!/usr/bin/env bash
+# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+# Fused Gaming โ Multi-Brand Deploy Script
+#
+# Usage:
+# ./scripts/deploy.sh [provider]
+#
+# Brands: stakereloadxs | stakereload | gambareload | gambarewards | stakeclaimbot
+# Provider: vercel (default) | vps | docker
+#
+# Examples:
+# ./scripts/deploy.sh stakereloadxs
+# ./scripts/deploy.sh gambareload vercel
+# ./scripts/deploy.sh stakereload vps
+# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+set -euo pipefail
+
+BRAND="${1:-}"
+PROVIDER="${2:-vercel}"
+ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
+WEB_DIR="$ROOT_DIR/apps/web"
+CONFIG_DIR="$ROOT_DIR/configs/brands"
+
+# โโ Validate brand โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+if [[ -z "$BRAND" ]]; then
+ echo "โ Usage: $0 [vercel|vps|docker]"
+ echo ""
+ echo " Available brands:"
+ for f in "$CONFIG_DIR"/*.json; do
+ echo " โข $(basename "$f" .json)"
+ done
+ exit 1
+fi
+
+CONFIG_FILE="$CONFIG_DIR/${BRAND}.json"
+if [[ ! -f "$CONFIG_FILE" ]]; then
+ echo "โ Brand config not found: $CONFIG_FILE"
+ exit 1
+fi
+
+# โโ Read domain from config โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+DOMAIN=$(node -e "const c=require('$CONFIG_FILE'); console.log(c.domain)")
+echo ""
+echo "๐ Deploying brand: $BRAND โ $DOMAIN"
+echo " Provider: $PROVIDER"
+echo ""
+
+# โโ Build โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+cd "$WEB_DIR"
+
+echo "๐ฆ Installing dependencies..."
+npm install --silent
+
+echo "๐ Building Next.js..."
+NEXT_PUBLIC_BRAND="$BRAND" \
+NEXT_PUBLIC_BASE_URL="https://$DOMAIN" \
+npm run build
+
+# โโ Deploy โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+case "$PROVIDER" in
+ vercel)
+ echo "โฒ Deploying to Vercel..."
+ if ! command -v vercel &>/dev/null; then
+ echo "โ vercel CLI not found. Run: npm i -g vercel"
+ exit 1
+ fi
+ vercel deploy \
+ --prod \
+ --yes \
+ --env "NEXT_PUBLIC_BRAND=$BRAND" \
+ --env "NEXT_PUBLIC_BASE_URL=https://$DOMAIN" \
+ --build-env "NEXT_PUBLIC_BRAND=$BRAND"
+ echo ""
+ echo "โ
Deployed to Vercel. Add CNAME: $DOMAIN โ cname.vercel-dns.com"
+ ;;
+
+ vps)
+ DEPLOY_USER="${DEPLOY_USER:-deploy}"
+ DEPLOY_HOST="${DEPLOY_HOST:?Set DEPLOY_HOST env var (e.g. 1.2.3.4)}"
+ DEPLOY_PATH="${DEPLOY_PATH:-/var/www/$BRAND}"
+
+ echo "๐ฅ Syncing to VPS $DEPLOY_HOST:$DEPLOY_PATH ..."
+ rsync -az --delete \
+ --exclude=".git" \
+ --exclude="node_modules" \
+ --exclude=".next/cache" \
+ "$WEB_DIR/" \
+ "$DEPLOY_USER@$DEPLOY_HOST:$DEPLOY_PATH/"
+
+ ssh "$DEPLOY_USER@$DEPLOY_HOST" bash </dev/null || \
+ pm2 start npm --name "$BRAND" -- start -- -p \${PORT:-3000}
+REMOTE
+ echo ""
+ echo "โ
Deployed to VPS. Point DNS: $DOMAIN โ $DEPLOY_HOST"
+ ;;
+
+ docker)
+ IMAGE="fused-gaming/${BRAND}:latest"
+ echo "๐ณ Building Docker image: $IMAGE ..."
+ docker build \
+ --build-arg NEXT_PUBLIC_BRAND="$BRAND" \
+ --build-arg NEXT_PUBLIC_BASE_URL="https://$DOMAIN" \
+ -t "$IMAGE" \
+ -f "$ROOT_DIR/apps/web/Dockerfile" \
+ "$ROOT_DIR"
+
+ echo ""
+ echo "โ
Docker image built: $IMAGE"
+ echo " Run with:"
+ echo " docker run -p 3000:3000 \\"
+ echo " -e NOWPAYMENTS_API_KEY=xxx \\"
+ echo " -e NEXT_PUBLIC_BRAND=$BRAND \\"
+ echo " $IMAGE"
+ ;;
+
+ *)
+ echo "โ Unknown provider: $PROVIDER (use vercel, vps, or docker)"
+ exit 1
+ ;;
+esac
+
+echo ""
+echo "โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ"
+echo " Brand: $BRAND"
+echo " Domain: $DOMAIN"
+echo " Provider: $PROVIDER"
+echo "โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ"
+echo ""
diff --git a/vercel.json b/vercel.json
new file mode 100644
index 00000000..037cac8a
--- /dev/null
+++ b/vercel.json
@@ -0,0 +1,27 @@
+{
+ "framework": "nextjs",
+ "installCommand": "npm install",
+ "buildCommand": "npm run build --workspace=apps/web",
+ "outputDirectory": "apps/web/.next",
+ "crons": [
+ {
+ "path": "/api/cron/refresh-stats",
+ "schedule": "*/15 * * * *"
+ }
+ ],
+ "headers": [
+ {
+ "source": "/api/status",
+ "headers": [
+ { "key": "Cache-Control", "value": "no-store, no-cache" },
+ { "key": "Access-Control-Allow-Origin", "value": "*" }
+ ]
+ },
+ {
+ "source": "/og",
+ "headers": [
+ { "key": "Cache-Control", "value": "public, max-age=3600, s-maxage=3600" }
+ ]
+ }
+ ]
+}