Tailwind CSS
Practical Projects — Landing Page, Dashboard, E-commerce Card
Áp dụng toàn bộ Tailwind CSS v4 vào 3 dự án thực tế — landing page hoàn chỉnh, dashboard layout, e-commerce product card với interactive states.
⭐ Day la chuong tong hop toan bo kien thuc. Moi project yeu cau ban van dung layout, responsive, dark mode, typography, spacing, custom variants, animations — tat ca nhung gi da hoc. Code day du, khong snippet.
Project 1: Landing Page Hoan Chinh
Yeu cau: Xay dung landing page cho mot SaaS product voi day du cac section:
- Header/Nav co dinh voi backdrop-blur, hamburger mobile
- Hero Section full-screen voi gradient background
- Features Grid responsive
- Pricing Cards 3 tiers
- Testimonials
- CTA Section
- Footer da cot
1.1. Toan Bo Code — Landing Page
<!DOCTYPE html>
<html lang="vi" class="scroll-smooth">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>FlowBase — Modern SaaS Landing Page</title>
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
<style>
@import "tailwindcss";
@custom-variant dark (&:where(.dark, .dark *));
@theme {
--color-brand-50: oklch(0.97 0.02 260);
--color-brand-100: oklch(0.92 0.04 260);
--color-brand-200: oklch(0.84 0.07 260);
--color-brand-300: oklch(0.74 0.12 260);
--color-brand-400: oklch(0.64 0.16 260);
--color-brand-500: oklch(0.54 0.20 260);
--color-brand-600: oklch(0.46 0.18 260);
--color-brand-700: oklch(0.37 0.15 260);
--color-brand-800: oklch(0.28 0.11 260);
--color-brand-900: oklch(0.20 0.07 260);
}
@utility text-gradient {
background: linear-gradient(to right, var(--tw-gradient-stops));
-webkit-background-clip: text;
background-clip: text;
-webkit-text-fill-color: transparent;
}
@layer base {
html { scroll-behavior: smooth; }
}
</style>
</head>
<body class="min-h-screen bg-white dark:bg-gray-950 text-gray-900 dark:text-gray-100 font-sans">
<!-- ============================================ -->
<!-- HEADER / NAVIGATION -->
<!-- ============================================ -->
<header class="fixed top-0 left-0 right-0 z-50 bg-white/80 dark:bg-gray-950/80 backdrop-blur-lg border-b border-gray-200 dark:border-gray-800 transition-colors">
<nav class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="flex items-center justify-between h-16 md:h-18">
<!-- Logo -->
<a href="#" class="flex items-center gap-2.5 text-xl font-bold text-gray-900 dark:text-white">
<div class="w-8 h-8 bg-gradient-to-br from-brand-500 to-brand-700 rounded-lg flex items-center justify-center shadow-sm">
<svg class="w-5 h-5 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z"/>
</svg>
</div>
FlowBase
</a>
<!-- Desktop Menu -->
<div class="hidden md:flex md:items-center md:gap-8">
<a href="#features" class="text-sm font-medium text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white transition-colors">Features</a>
<a href="#pricing" class="text-sm font-medium text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white transition-colors">Pricing</a>
<a href="#testimonials" class="text-sm font-medium text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white transition-colors">Testimonials</a>
<a href="#faq" class="text-sm font-medium text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white transition-colors">FAQ</a>
</div>
<!-- Right: CTA + Theme Toggle + Mobile Hamburger -->
<div class="flex items-center gap-3">
<!-- Theme Toggle -->
<button id="theme-toggle" aria-label="Toggle dark mode"
class="p-2 rounded-lg text-gray-600 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors">
<svg id="sun-icon" class="hidden dark:block w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z"/>
</svg>
<svg id="moon-icon" class="block dark:hidden w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z"/>
</svg>
</button>
<!-- Desktop CTA -->
<a href="#cta" class="hidden md:inline-flex items-center px-4 py-2 bg-brand-600 text-white text-sm font-semibold rounded-lg hover:bg-brand-700 transition-colors shadow-sm">
Get Started Free
</a>
<!-- Mobile Hamburger -->
<button id="menu-toggle" class="md:hidden p-2 rounded-lg text-gray-600 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors" aria-label="Toggle menu">
<svg id="menu-open" class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16"/>
</svg>
<svg id="menu-close" class="w-6 h-6 hidden" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
</svg>
</button>
</div>
</div>
<!-- Mobile Menu Dropdown -->
<div id="mobile-menu" class="md:hidden hidden pb-4 border-t border-gray-100 dark:border-gray-800 mt-2 pt-4">
<div class="flex flex-col gap-1">
<a href="#features" class="block px-3 py-2.5 rounded-lg text-gray-600 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors text-sm font-medium">Features</a>
<a href="#pricing" class="block px-3 py-2.5 rounded-lg text-gray-600 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors text-sm font-medium">Pricing</a>
<a href="#testimonials" class="block px-3 py-2.5 rounded-lg text-gray-600 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors text-sm font-medium">Testimonials</a>
<a href="#faq" class="block px-3 py-2.5 rounded-lg text-gray-600 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors text-sm font-medium">FAQ</a>
<a href="#cta" class="block px-3 py-2.5 bg-brand-600 text-white text-center rounded-lg font-semibold text-sm mt-2 hover:bg-brand-700 transition-colors">
Get Started Free
</a>
</div>
</div>
</nav>
</header>
<!-- Spacer for fixed header -->
<div class="h-16 md:h-18"></div>
<!-- ============================================ -->
<!-- HERO SECTION -->
<!-- ============================================ -->
<section class="relative overflow-hidden bg-gradient-to-br from-gray-50 via-white to-brand-50 dark:from-gray-950 dark:via-gray-900 dark:to-brand-950">
<!-- Background decoration -->
<div class="absolute inset-0 overflow-hidden pointer-events-none">
<div class="absolute -top-40 -right-40 w-80 h-80 bg-brand-400/20 dark:bg-brand-600/10 rounded-full blur-3xl"></div>
<div class="absolute -bottom-40 -left-40 w-80 h-80 bg-purple-400/20 dark:bg-purple-600/10 rounded-full blur-3xl"></div>
</div>
<div class="relative max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-20 md:py-28 lg:py-36">
<div class="max-w-3xl mx-auto text-center">
<!-- Badge -->
<div class="inline-flex items-center gap-2 px-4 py-1.5 bg-brand-100 dark:bg-brand-900/40 text-brand-700 dark:text-brand-300 rounded-full text-sm font-medium mb-6">
<span class="relative flex h-2 w-2">
<span class="animate-ping absolute inline-flex h-full w-full rounded-full bg-brand-400 opacity-75"></span>
<span class="relative inline-flex rounded-full h-2 w-2 bg-brand-500"></span>
</span>
Now in Public Beta — v2.0 Released
</div>
<!-- Headline -->
<h1 class="text-4xl sm:text-5xl md:text-6xl lg:text-7xl font-extrabold text-gray-900 dark:text-white leading-tight tracking-tight">
Build products
<span class="text-gradient from-brand-600 via-brand-500 to-purple-600">
people love
</span>
</h1>
<!-- Subheadline -->
<p class="mt-6 text-lg sm:text-xl text-gray-600 dark:text-gray-400 max-w-2xl mx-auto leading-relaxed">
FlowBase is the all-in-one platform that helps teams design, prototype, and ship digital products faster.
No more switching between 10 different tools.
</p>
<!-- CTA Buttons -->
<div class="mt-10 flex flex-col sm:flex-row items-center justify-center gap-4">
<a href="#cta" class="w-full sm:w-auto inline-flex items-center justify-center px-8 py-3.5 bg-brand-600 text-white text-base font-semibold rounded-xl hover:bg-brand-700 shadow-lg shadow-brand-500/25 hover:shadow-brand-500/40 transition-all">
Start Free Trial
<svg class="ml-2 w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 7l5 5m0 0l-5 5m5-5H6"/>
</svg>
</a>
<a href="#features" class="w-full sm:w-auto inline-flex items-center justify-center px-8 py-3.5 bg-white dark:bg-gray-800 text-gray-700 dark:text-gray-300 text-base font-semibold rounded-xl border border-gray-300 dark:border-gray-700 hover:border-gray-400 dark:hover:border-gray-600 transition-all">
<svg class="mr-2 w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z"/>
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>
</svg>
Watch Demo
</a>
</div>
<!-- Social proof -->
<div class="mt-12 flex flex-col sm:flex-row items-center justify-center gap-6 sm:gap-10">
<div class="flex -space-x-3">
<div class="w-10 h-10 rounded-full bg-gradient-to-br from-blue-400 to-blue-600 border-2 border-white dark:border-gray-900"></div>
<div class="w-10 h-10 rounded-full bg-gradient-to-br from-green-400 to-green-600 border-2 border-white dark:border-gray-900"></div>
<div class="w-10 h-10 rounded-full bg-gradient-to-br from-purple-400 to-purple-600 border-2 border-white dark:border-gray-900"></div>
<div class="w-10 h-10 rounded-full bg-gradient-to-br from-orange-400 to-orange-600 border-2 border-white dark:border-gray-900 flex items-center justify-center text-white text-xs font-bold">+</div>
</div>
<div class="text-center sm:text-left">
<div class="flex items-center gap-1 text-yellow-500 justify-center sm:justify-start">
<svg class="w-4 h-4 fill-current" viewBox="0 0 20 20"><path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z"/></svg>
<svg class="w-4 h-4 fill-current" viewBox="0 0 20 20"><path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z"/></svg>
<svg class="w-4 h-4 fill-current" viewBox="0 0 20 20"><path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z"/></svg>
<svg class="w-4 h-4 fill-current" viewBox="0 0 20 20"><path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z"/></svg>
<svg class="w-4 h-4 fill-current" viewBox="0 0 20 20"><path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z"/></svg>
</div>
<p class="text-sm text-gray-500 dark:text-gray-400 mt-1">
<strong class="text-gray-700 dark:text-gray-300">4.9/5</strong> from 2,000+ reviews
</p>
</div>
</div>
</div>
</div>
</section>
<!-- ============================================ -->
<!-- FEATURES SECTION -->
<!-- ============================================ -->
<section id="features" class="py-20 md:py-28 bg-white dark:bg-gray-950">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<!-- Section Header -->
<div class="max-w-2xl mx-auto text-center mb-16">
<h2 class="text-3xl sm:text-4xl font-bold text-gray-900 dark:text-white mb-4">
Everything you need to ship faster
</h2>
<p class="text-lg text-gray-600 dark:text-gray-400">
From design to deployment, FlowBase streamlines your entire workflow so you can focus on what matters — building great products.
</p>
</div>
<!-- Features Grid -->
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 lg:gap-8">
<!-- Feature 1 -->
<div class="group relative bg-gray-50 dark:bg-gray-900 border border-gray-200 dark:border-gray-800 rounded-2xl p-8 hover:border-brand-300 dark:hover:border-brand-700 hover:shadow-lg dark:hover:shadow-brand-900/20 transition-all duration-300">
<div class="w-12 h-12 bg-brand-100 dark:bg-brand-900/40 rounded-xl flex items-center justify-center mb-5 group-hover:scale-110 transition-transform">
<svg class="w-6 h-6 text-brand-600 dark:text-brand-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20 7l-8-4-8 4m16 0l-8 4m8-4v10l-8 4m0-10L4 7m8 4v10M4 7v10l8 4"/>
</svg>
</div>
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-2">Design System Manager</h3>
<p class="text-gray-600 dark:text-gray-400 text-sm leading-relaxed">Create and maintain a consistent design system with reusable components, tokens, and documentation — all in one place.</p>
</div>
<!-- Feature 2 -->
<div class="group relative bg-gray-50 dark:bg-gray-900 border border-gray-200 dark:border-gray-800 rounded-2xl p-8 hover:border-purple-300 dark:hover:border-purple-700 hover:shadow-lg transition-all duration-300">
<div class="w-12 h-12 bg-purple-100 dark:bg-purple-900/40 rounded-xl flex items-center justify-center mb-5 group-hover:scale-110 transition-transform">
<svg class="w-6 h-6 text-purple-600 dark:text-purple-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z"/>
</svg>
</div>
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-2">Real-time Analytics</h3>
<p class="text-gray-600 dark:text-gray-400 text-sm leading-relaxed">Track user behavior, conversion rates, and product metrics with beautiful dashboards that update in real time.</p>
</div>
<!-- Feature 3 -->
<div class="group relative bg-gray-50 dark:bg-gray-900 border border-gray-200 dark:border-gray-800 rounded-2xl p-8 hover:border-green-300 dark:hover:border-green-700 hover:shadow-lg transition-all duration-300">
<div class="w-12 h-12 bg-green-100 dark:bg-green-900/40 rounded-xl flex items-center justify-center mb-5 group-hover:scale-110 transition-transform">
<svg class="w-6 h-6 text-green-600 dark:text-green-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z"/>
</svg>
</div>
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-2">Team Collaboration</h3>
<p class="text-gray-600 dark:text-gray-400 text-sm leading-relaxed">Work together in real time with comments, version history, and role-based permissions for your entire team.</p>
</div>
<!-- Feature 4 -->
<div class="group relative bg-gray-50 dark:bg-gray-900 border border-gray-200 dark:border-gray-800 rounded-2xl p-8 hover:border-orange-300 dark:hover:border-orange-700 hover:shadow-lg transition-all duration-300">
<div class="w-12 h-12 bg-orange-100 dark:bg-orange-900/40 rounded-xl flex items-center justify-center mb-5 group-hover:scale-110 transition-transform">
<svg class="w-6 h-6 text-orange-600 dark:text-orange-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"/>
</svg>
</div>
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-2">API & Integrations</h3>
<p class="text-gray-600 dark:text-gray-400 text-sm leading-relaxed">Connect with 200+ tools via native integrations and a powerful REST API. Automate your workflow end-to-end.</p>
</div>
<!-- Feature 5 -->
<div class="group relative bg-gray-50 dark:bg-gray-900 border border-gray-200 dark:border-gray-800 rounded-2xl p-8 hover:border-pink-300 dark:hover:border-pink-700 hover:shadow-lg transition-all duration-300">
<div class="w-12 h-12 bg-pink-100 dark:bg-pink-900/40 rounded-xl flex items-center justify-center mb-5 group-hover:scale-110 transition-transform">
<svg class="w-6 h-6 text-pink-600 dark:text-pink-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 21a4 4 0 01-4-4V5a2 2 0 012-2h4a2 2 0 012 2v12a4 4 0 01-4 4zm0 0h12a2 2 0 002-2v-4a2 2 0 00-2-2h-2.343M11 7.343l1.657-1.657a2 2 0 012.828 0l2.829 2.829a2 2 0 010 2.828l-8.486 8.485M7 17h.01"/>
</svg>
</div>
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-2">Drag & Drop Builder</h3>
<p class="text-gray-600 dark:text-gray-400 text-sm leading-relaxed">Build complex layouts visually with our intuitive drag-and-drop editor. No code needed for basic pages.</p>
</div>
<!-- Feature 6 -->
<div class="group relative bg-gray-50 dark:bg-gray-900 border border-gray-200 dark:border-gray-800 rounded-2xl p-8 hover:border-indigo-300 dark:hover:border-indigo-700 hover:shadow-lg transition-all duration-300">
<div class="w-12 h-12 bg-indigo-100 dark:bg-indigo-900/40 rounded-xl flex items-center justify-center mb-5 group-hover:scale-110 transition-transform">
<svg class="w-6 h-6 text-indigo-600 dark:text-indigo-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z"/>
</svg>
</div>
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-2">Enterprise Security</h3>
<p class="text-gray-600 dark:text-gray-400 text-sm leading-relaxed">SOC 2 Type II certified, SSO/SAML, audit logs, and role-based access control. Your data is safe with us.</p>
</div>
</div>
</div>
</section>
<!-- ============================================ -->
<!-- PRICING SECTION -->
<!-- ============================================ -->
<section id="pricing" class="py-20 md:py-28 bg-gray-50 dark:bg-gray-900">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="max-w-2xl mx-auto text-center mb-16">
<h2 class="text-3xl sm:text-4xl font-bold text-gray-900 dark:text-white mb-4">
Simple, transparent pricing
</h2>
<p class="text-lg text-gray-600 dark:text-gray-400">
Start for free, upgrade when you need more power. No hidden fees, no surprises.
</p>
</div>
<!-- Pricing Toggle -->
<div class="flex items-center justify-center gap-3 mb-12">
<span class="text-sm font-medium text-gray-700 dark:text-gray-300">Monthly</span>
<button id="billing-toggle" class="relative w-12 h-6 bg-gray-300 dark:bg-gray-700 rounded-full transition-colors duration-200 focus:outline-none focus:ring-2 focus:ring-brand-500" role="switch" aria-checked="false">
<span id="toggle-knob" class="absolute top-0.5 left-0.5 w-5 h-5 bg-white rounded-full shadow-sm transition-transform duration-200"></span>
</button>
<span class="text-sm font-medium text-gray-700 dark:text-gray-300">
Yearly
<span class="ml-1.5 px-2 py-0.5 bg-green-100 dark:bg-green-900/40 text-green-700 dark:text-green-400 text-xs font-semibold rounded-full">Save 20%</span>
</span>
</div>
<!-- Pricing Cards -->
<div class="grid grid-cols-1 md:grid-cols-3 gap-6 lg:gap-8 max-w-5xl mx-auto">
<!-- Free Tier -->
<div class="bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-2xl p-8 flex flex-col">
<h3 class="text-lg font-semibold text-gray-900 dark:text-white">Starter</h3>
<p class="text-sm text-gray-500 dark:text-gray-400 mt-1">Perfect for side projects</p>
<div class="mt-6 mb-6">
<span class="text-4xl font-extrabold text-gray-900 dark:text-white">Free</span>
<span class="text-gray-500 dark:text-gray-400 text-sm">/forever</span>
</div>
<ul class="space-y-3 mb-8 flex-1">
<li class="flex items-start gap-2 text-sm text-gray-600 dark:text-gray-400">
<svg class="w-5 h-5 text-green-500 flex-shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/></svg>
Up to 3 projects
</li>
<li class="flex items-start gap-2 text-sm text-gray-600 dark:text-gray-400">
<svg class="w-5 h-5 text-green-500 flex-shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/></svg>
Basic analytics
</li>
<li class="flex items-start gap-2 text-sm text-gray-600 dark:text-gray-400">
<svg class="w-5 h-5 text-green-500 flex-shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/></svg>
Community support
</li>
</ul>
<a href="#" class="block w-full text-center py-3 bg-gray-100 dark:bg-gray-700 text-gray-700 dark:text-gray-300 font-semibold rounded-xl hover:bg-gray-200 dark:hover:bg-gray-600 transition-colors text-sm">
Get Started
</a>
</div>
<!-- Pro Tier (Recommended) -->
<div class="relative bg-white dark:bg-gray-800 border-2 border-brand-500 rounded-2xl p-8 flex flex-col shadow-xl shadow-brand-500/10">
<div class="absolute -top-3 left-1/2 -translate-x-1/2 px-4 py-1 bg-brand-500 text-white text-xs font-bold rounded-full">
MOST POPULAR
</div>
<h3 class="text-lg font-semibold text-gray-900 dark:text-white">Professional</h3>
<p class="text-sm text-gray-500 dark:text-gray-400 mt-1">For growing teams</p>
<div class="mt-6 mb-6">
<span class="text-4xl font-extrabold text-gray-900 dark:text-white" id="pro-price">$29</span>
<span class="text-gray-500 dark:text-gray-400 text-sm">/month</span>
</div>
<ul class="space-y-3 mb-8 flex-1">
<li class="flex items-start gap-2 text-sm text-gray-600 dark:text-gray-400">
<svg class="w-5 h-5 text-green-500 flex-shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/></svg>
Unlimited projects
</li>
<li class="flex items-start gap-2 text-sm text-gray-600 dark:text-gray-400">
<svg class="w-5 h-5 text-green-500 flex-shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/></svg>
Advanced analytics & reports
</li>
<li class="flex items-start gap-2 text-sm text-gray-600 dark:text-gray-400">
<svg class="w-5 h-5 text-green-500 flex-shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/></svg>
Priority support
</li>
<li class="flex items-start gap-2 text-sm text-gray-600 dark:text-gray-400">
<svg class="w-5 h-5 text-green-500 flex-shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/></svg>
API access
</li>
<li class="flex items-start gap-2 text-sm text-gray-600 dark:text-gray-400">
<svg class="w-5 h-5 text-green-500 flex-shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/></svg>
Custom integrations
</li>
</ul>
<a href="#" class="block w-full text-center py-3 bg-brand-600 text-white font-semibold rounded-xl hover:bg-brand-700 transition-colors text-sm shadow-sm">
Start Free Trial
</a>
</div>
<!-- Enterprise Tier -->
<div class="bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-2xl p-8 flex flex-col">
<h3 class="text-lg font-semibold text-gray-900 dark:text-white">Enterprise</h3>
<p class="text-sm text-gray-500 dark:text-gray-400 mt-1">For large organizations</p>
<div class="mt-6 mb-6">
<span class="text-4xl font-extrabold text-gray-900 dark:text-white">$99</span>
<span class="text-gray-500 dark:text-gray-400 text-sm">/month</span>
</div>
<ul class="space-y-3 mb-8 flex-1">
<li class="flex items-start gap-2 text-sm text-gray-600 dark:text-gray-400">
<svg class="w-5 h-5 text-green-500 flex-shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/></svg>
Everything in Professional
</li>
<li class="flex items-start gap-2 text-sm text-gray-600 dark:text-gray-400">
<svg class="w-5 h-5 text-green-500 flex-shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/></svg>
SSO / SAML
</li>
<li class="flex items-start gap-2 text-sm text-gray-600 dark:text-gray-400">
<svg class="w-5 h-5 text-green-500 flex-shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/></svg>
Dedicated support
</li>
<li class="flex items-start gap-2 text-sm text-gray-600 dark:text-gray-400">
<svg class="w-5 h-5 text-green-500 flex-shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/></svg>
SLA guarantee
</li>
</ul>
<a href="#" class="block w-full text-center py-3 bg-gray-100 dark:bg-gray-700 text-gray-700 dark:text-gray-300 font-semibold rounded-xl hover:bg-gray-200 dark:hover:bg-gray-600 transition-colors text-sm">
Contact Sales
</a>
</div>
</div>
</div>
</section>
<!-- ============================================ -->
<!-- TESTIMONIALS SECTION -->
<!-- ============================================ -->
<section id="testimonials" class="py-20 md:py-28 bg-white dark:bg-gray-950">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="max-w-2xl mx-auto text-center mb-16">
<h2 class="text-3xl sm:text-4xl font-bold text-gray-900 dark:text-white mb-4">
Loved by product teams worldwide
</h2>
<p class="text-lg text-gray-600 dark:text-gray-400">
See what our customers have to say about FlowBase.
</p>
</div>
<!-- Testimonials Grid -->
<div class="grid grid-cols-1 md:grid-cols-3 gap-6 lg:gap-8">
<!-- Testimonial 1 -->
<div class="bg-gray-50 dark:bg-gray-900 border border-gray-200 dark:border-gray-800 rounded-2xl p-6">
<div class="flex gap-1 text-yellow-500 mb-4">
<svg class="w-4 h-4 fill-current" viewBox="0 0 20 20"><path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z"/></svg>
<svg class="w-4 h-4 fill-current" viewBox="0 0 20 20"><path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z"/></svg>
<svg class="w-4 h-4 fill-current" viewBox="0 0 20 20"><path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z"/></svg>
<svg class="w-4 h-4 fill-current" viewBox="0 0 20 20"><path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z"/></svg>
<svg class="w-4 h-4 fill-current" viewBox="0 0 20 20"><path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z"/></svg>
</div>
<blockquote class="text-gray-700 dark:text-gray-300 text-sm leading-relaxed mb-5">
"FlowBase cut our design-to-development handoff time by 60%. The design system manager alone is worth the price."
</blockquote>
<div class="flex items-center gap-3">
<div class="w-10 h-10 rounded-full bg-gradient-to-br from-blue-400 to-blue-600"></div>
<div>
<p class="text-sm font-semibold text-gray-900 dark:text-white">Sarah Chen</p>
<p class="text-xs text-gray-500 dark:text-gray-400">Product Designer at Acme Inc.</p>
</div>
</div>
</div>
<!-- Testimonial 2 -->
<div class="bg-gray-50 dark:bg-gray-900 border border-gray-200 dark:border-gray-800 rounded-2xl p-6">
<div class="flex gap-1 text-yellow-500 mb-4">
<svg class="w-4 h-4 fill-current" viewBox="0 0 20 20"><path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z"/></svg>
<svg class="w-4 h-4 fill-current" viewBox="0 0 20 20"><path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z"/></svg>
<svg class="w-4 h-4 fill-current" viewBox="0 0 20 20"><path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z"/></svg>
<svg class="w-4 h-4 fill-current" viewBox="0 0 20 20"><path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z"/></svg>
<svg class="w-4 h-4 fill-current" viewBox="0 0 20 20"><path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z"/></svg>
</div>
<blockquote class="text-gray-700 dark:text-gray-300 text-sm leading-relaxed mb-5">
"The real-time collaboration features are incredible. Our team of 12 designers and developers finally work in sync."
</blockquote>
<div class="flex items-center gap-3">
<div class="w-10 h-10 rounded-full bg-gradient-to-br from-purple-400 to-purple-600"></div>
<div>
<p class="text-sm font-semibold text-gray-900 dark:text-white">Marcus Rivera</p>
<p class="text-xs text-gray-500 dark:text-gray-400">Engineering Lead at TechStack</p>
</div>
</div>
</div>
<!-- Testimonial 3 -->
<div class="bg-gray-50 dark:bg-gray-900 border border-gray-200 dark:border-gray-800 rounded-2xl p-6">
<div class="flex gap-1 text-yellow-500 mb-4">
<svg class="w-4 h-4 fill-current" viewBox="0 0 20 20"><path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z"/></svg>
<svg class="w-4 h-4 fill-current" viewBox="0 0 20 20"><path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z"/></svg>
<svg class="w-4 h-4 fill-current" viewBox="0 0 20 20"><path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z"/></svg>
<svg class="w-4 h-4 fill-current" viewBox="0 0 20 20"><path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z"/></svg>
<svg class="w-4 h-4 fill-current" viewBox="0 0 20 20"><path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z"/></svg>
</div>
<blockquote class="text-gray-700 dark:text-gray-300 text-sm leading-relaxed mb-5">
"We evaluated 7 different tools before choosing FlowBase. The API and custom integrations made it the clear winner for our workflow."
</blockquote>
<div class="flex items-center gap-3">
<div class="w-10 h-10 rounded-full bg-gradient-to-br from-green-400 to-green-600"></div>
<div>
<p class="text-sm font-semibold text-gray-900 dark:text-white">Aiko Tanaka</p>
<p class="text-xs text-gray-500 dark:text-gray-400">CTO at NovaTech Solutions</p>
</div>
</div>
</div>
</div>
</div>
</section>
<!-- ============================================ -->
<!-- CTA SECTION -->
<!-- ============================================ -->
<section id="cta" class="py-20 md:py-28 relative overflow-hidden">
<div class="absolute inset-0 bg-gradient-to-br from-brand-600 to-brand-800"></div>
<!-- Decoration -->
<div class="absolute inset-0 overflow-hidden pointer-events-none">
<div class="absolute top-10 right-10 w-64 h-64 bg-white/10 rounded-full blur-3xl"></div>
<div class="absolute bottom-10 left-10 w-48 h-48 bg-white/5 rounded-full blur-3xl"></div>
</div>
<div class="relative max-w-3xl mx-auto px-4 sm:px-6 lg:px-8 text-center">
<h2 class="text-3xl sm:text-4xl md:text-5xl font-extrabold text-white mb-6">
Ready to build something great?
</h2>
<p class="text-lg sm:text-xl text-brand-100 mb-10 max-w-2xl mx-auto">
Join 50,000+ teams already using FlowBase. Start your free 14-day trial — no credit card required.
</p>
<div class="flex flex-col sm:flex-row items-center justify-center gap-4">
<a href="#" class="w-full sm:w-auto inline-flex items-center justify-center px-8 py-4 bg-white text-brand-700 text-base font-bold rounded-xl hover:bg-gray-100 shadow-lg transition-all">
Start Free Trial
<svg class="ml-2 w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 7l5 5m0 0l-5 5m5-5H6"/>
</svg>
</a>
<a href="#" class="w-full sm:w-auto inline-flex items-center justify-center px-8 py-4 border-2 border-white/30 text-white text-base font-semibold rounded-xl hover:bg-white/10 transition-all">
Talk to Sales
</a>
</div>
<p class="text-brand-200 text-sm mt-6">Free 14-day trial. No credit card needed. Cancel anytime.</p>
</div>
</section>
<!-- ============================================ -->
<!-- FOOTER -->
<!-- ============================================ -->
<footer class="bg-gray-900 dark:bg-gray-950 text-gray-400 py-16">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="grid grid-cols-2 md:grid-cols-5 gap-8 lg:gap-12">
<!-- Brand Column -->
<div class="col-span-2">
<a href="#" class="flex items-center gap-2 text-xl font-bold text-white mb-4">
<div class="w-8 h-8 bg-brand-500 rounded-lg flex items-center justify-center">
<span class="text-white font-bold text-sm">F</span>
</div>
FlowBase
</a>
<p class="text-sm text-gray-400 leading-relaxed mb-6 max-w-xs">
The all-in-one platform for teams to design, prototype, and ship digital products faster.
</p>
<div class="flex gap-4">
<a href="#" class="w-9 h-9 bg-gray-800 hover:bg-gray-700 rounded-lg flex items-center justify-center transition-colors" aria-label="Twitter">
<svg class="w-4 h-4" fill="currentColor" viewBox="0 0 24 24"><path d="M23.953 4.57a10 10 0 01-2.825.775 4.958 4.958 0 002.163-2.723c-.951.555-2.005.959-3.127 1.184a4.92 4.92 0 00-8.384 4.482C7.69 8.095 4.067 6.13 1.64 3.162a4.822 4.822 0 00-.666 2.475c0 1.71.87 3.213 2.188 4.096a4.904 4.904 0 01-2.228-.616v.06a4.923 4.923 0 003.946 4.827 4.996 4.996 0 01-2.212.085 4.936 4.936 0 004.604 3.417 9.867 9.867 0 01-6.102 2.105c-.39 0-.779-.023-1.17-.067a13.995 13.995 0 007.557 2.209c9.053 0 13.998-7.496 13.998-13.985 0-.21 0-.42-.015-.63A9.935 9.935 0 0024 4.59z"/></svg>
</a>
<a href="#" class="w-9 h-9 bg-gray-800 hover:bg-gray-700 rounded-lg flex items-center justify-center transition-colors" aria-label="GitHub">
<svg class="w-4 h-4" fill="currentColor" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg>
</a>
<a href="#" class="w-9 h-9 bg-gray-800 hover:bg-gray-700 rounded-lg flex items-center justify-center transition-colors" aria-label="LinkedIn">
<svg class="w-4 h-4" fill="currentColor" viewBox="0 0 24 24"><path d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433c-1.144 0-2.063-.926-2.063-2.065 0-1.138.92-2.063 2.063-2.063 1.14 0 2.064.925 2.064 2.063 0 1.139-.925 2.065-2.064 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z"/></svg>
</a>
</div>
</div>
<!-- Product Links -->
<div>
<h4 class="text-white font-semibold text-sm mb-4">Product</h4>
<ul class="space-y-3">
<li><a href="#" class="text-sm text-gray-400 hover:text-white transition-colors">Features</a></li>
<li><a href="#" class="text-sm text-gray-400 hover:text-white transition-colors">Pricing</a></li>
<li><a href="#" class="text-sm text-gray-400 hover:text-white transition-colors">Integrations</a></li>
<li><a href="#" class="text-sm text-gray-400 hover:text-white transition-colors">Changelog</a></li>
</ul>
</div>
<!-- Company Links -->
<div>
<h4 class="text-white font-semibold text-sm mb-4">Company</h4>
<ul class="space-y-3">
<li><a href="#" class="text-sm text-gray-400 hover:text-white transition-colors">About</a></li>
<li><a href="#" class="text-sm text-gray-400 hover:text-white transition-colors">Blog</a></li>
<li><a href="#" class="text-sm text-gray-400 hover:text-white transition-colors">Careers</a></li>
<li><a href="#" class="text-sm text-gray-400 hover:text-white transition-colors">Contact</a></li>
</ul>
</div>
<!-- Legal Links -->
<div>
<h4 class="text-white font-semibold text-sm mb-4">Legal</h4>
<ul class="space-y-3">
<li><a href="#" class="text-sm text-gray-400 hover:text-white transition-colors">Privacy Policy</a></li>
<li><a href="#" class="text-sm text-gray-400 hover:text-white transition-colors">Terms of Service</a></li>
<li><a href="#" class="text-sm text-gray-400 hover:text-white transition-colors">Cookie Policy</a></li>
</ul>
</div>
</div>
<!-- Bottom Bar -->
<div class="mt-16 pt-8 border-t border-gray-800 flex flex-col sm:flex-row items-center justify-between gap-4">
<p class="text-sm text-gray-500">© 2026 FlowBase, Inc. All rights reserved.</p>
<p class="text-sm text-gray-500">Made with love in San Francisco</p>
</div>
</div>
</footer>
<!-- ============================================ -->
<!-- JAVASCRIPT -->
<!-- ============================================ -->
<script>
// Mobile menu toggle
const menuToggle = document.getElementById('menu-toggle');
const mobileMenu = document.getElementById('mobile-menu');
const menuOpen = document.getElementById('menu-open');
const menuClose = document.getElementById('menu-close');
menuToggle.addEventListener('click', () => {
mobileMenu.classList.toggle('hidden');
menuOpen.classList.toggle('hidden');
menuClose.classList.toggle('hidden');
});
// Close mobile menu on link click
mobileMenu.querySelectorAll('a').forEach(link => {
link.addEventListener('click', () => {
mobileMenu.classList.add('hidden');
menuOpen.classList.remove('hidden');
menuClose.classList.add('hidden');
});
});
// Dark mode toggle
const themeToggle = document.getElementById('theme-toggle');
const html = document.documentElement;
function setTheme(theme) {
if (theme === 'dark') {
html.classList.add('dark');
} else {
html.classList.remove('dark');
}
localStorage.setItem('flowbase-theme', theme);
}
function getInitialTheme() {
const saved = localStorage.getItem('flowbase-theme');
if (saved) return saved;
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
}
setTheme(getInitialTheme());
themeToggle.addEventListener('click', () => {
setTheme(html.classList.contains('dark') ? 'light' : 'dark');
});
// Billing toggle (monthly/yearly)
const billingToggle = document.getElementById('billing-toggle');
const toggleKnob = document.getElementById('toggle-knob');
let isYearly = false;
billingToggle.addEventListener('click', () => {
isYearly = !isYearly;
billingToggle.setAttribute('aria-checked', isYearly);
toggleKnob.style.transform = isYearly ? 'translateX(1.5rem)' : 'translateX(0)';
const proPrice = document.getElementById('pro-price');
proPrice.textContent = isYearly ? '$23' : '$29';
});
</script>
</body>
</html>
Giải thích key decisions cho Landing Page:
| Kỹ thuật | Áp dụng ở đâu |
|---|---|
| Mobile-first responsive | Grid features 1 -> 2 -> 3 cols; Hero text scale; Footer grid 1 -> 4 cols |
| Dark mode | Mọi section có dark: variants cho bg, text, border. Theme toggle + localStorage |
| Fixed header + backdrop-blur | fixed top-0 bg-white/80 backdrop-blur-lg cho glass morphism effect |
| Gradient text | Hero headline: bg-gradient-to-r from-brand-600 to-purple-600 bg-clip-text text-transparent |
| CSS variables from @theme | All brand-* colors available as both Tailwind classes AND CSS custom properties |
| Animation | animate-ping trên badge "Beta", group-hover:scale-110 trên feature icons |
| Shadow layers | CTA button: shadow-lg shadow-brand-500/25 hover:shadow-brand-500/40 |
| Hover states | Feature cards: hover:border-brand-300 hover:shadow-lg, pricing cards interactions |
| Accessibility | aria-label, aria-checked, role="switch", focus rings, semantic HTML |
Project 2: Dashboard Layout
Yêu cầu: Xây dựng giao diện admin dashboard với:
- Sidebar cố định, collapsible trên mobile
- Header với search, notifications, user menu
- Stats cards (4 metrics)
- Data table với status badges
- Chart placeholder
- Activity feed timeline
2.1. Toan Bo Code — Dashboard
<!DOCTYPE html>
<html lang="vi" class="">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Admin Dashboard — Tailwind CSS v4</title>
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
<style>
@import "tailwindcss";
@custom-variant dark (&:where(.dark, .dark *));
@theme {
--color-primary: oklch(0.55 0.20 260);
--color-primary-light: oklch(0.70 0.15 260);
--color-sidebar: oklch(0.15 0.02 260);
--color-sidebar-hover: oklch(0.22 0.03 260);
}
</style>
</head>
<body class="min-h-screen bg-gray-100 dark:bg-gray-950 text-gray-900 dark:text-gray-100">
<div class="flex h-screen overflow-hidden">
<!-- ============================================ -->
<!-- SIDEBAR -->
<!-- ============================================ -->
<aside id="sidebar" class="fixed inset-y-0 left-0 z-40 w-64 bg-gray-900 dark:bg-gray-950 text-gray-300 transform -translate-x-full md:translate-x-0 transition-transform duration-300 ease-in-out flex flex-col">
<!-- Sidebar Header -->
<div class="flex items-center justify-between h-16 px-4 border-b border-gray-800">
<a href="#" class="flex items-center gap-2.5 text-lg font-bold text-white">
<div class="w-8 h-8 bg-primary rounded-lg flex items-center justify-center">
<span class="text-white font-bold text-sm">A</span>
</div>
AdminPanel
</a>
<button id="sidebar-close" class="md:hidden p-1.5 rounded-lg text-gray-400 hover:text-white hover:bg-gray-800 transition-colors">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
</svg>
</button>
</div>
<!-- Navigation -->
<nav class="flex-1 overflow-y-auto py-4 px-3 space-y-1">
<p class="px-3 text-xs font-semibold text-gray-500 uppercase tracking-wider mb-2">Main Menu</p>
<a href="#" class="flex items-center gap-3 px-3 py-2.5 rounded-lg bg-primary/20 text-white text-sm font-medium">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6"/>
</svg>
Dashboard
</a>
<a href="#" class="flex items-center gap-3 px-3 py-2.5 rounded-lg text-gray-400 hover:text-white hover:bg-gray-800 text-sm font-medium transition-colors">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z"/>
</svg>
Analytics
</a>
<a href="#" class="flex items-center gap-3 px-3 py-2.5 rounded-lg text-gray-400 hover:text-white hover:bg-gray-800 text-sm font-medium transition-colors">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 11V7a4 4 0 00-8 0v4M5 9h14l1 12H4L5 9z"/>
</svg>
Products
</a>
<a href="#" class="flex items-center gap-3 px-3 py-2.5 rounded-lg text-gray-400 hover:text-white hover:bg-gray-800 text-sm font-medium transition-colors">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0z"/>
</svg>
Customers
</a>
<a href="#" class="flex items-center gap-3 px-3 py-2.5 rounded-lg text-gray-400 hover:text-white hover:bg-gray-800 text-sm font-medium transition-colors">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 17v-2m3 2v-4m3 4v-6m2 10H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"/>
</svg>
Reports
</a>
<p class="px-3 text-xs font-semibold text-gray-500 uppercase tracking-wider mb-2 mt-6">Settings</p>
<a href="#" class="flex items-center gap-3 px-3 py-2.5 rounded-lg text-gray-400 hover:text-white hover:bg-gray-800 text-sm font-medium transition-colors">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.066 2.573c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.573 1.066c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.066-2.573c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z"/>
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"/>
</svg>
Settings
</a>
</nav>
<!-- Sidebar Footer -->
<div class="p-4 border-t border-gray-800">
<div class="flex items-center gap-3">
<div class="w-8 h-8 rounded-full bg-gradient-to-br from-blue-400 to-blue-600"></div>
<div class="flex-1 min-w-0">
<p class="text-sm font-medium text-white truncate">Admin User</p>
<p class="text-xs text-gray-500 truncate">admin@company.com</p>
</div>
</div>
</div>
</aside>
<!-- Sidebar Overlay (mobile) -->
<div id="sidebar-overlay" class="fixed inset-0 z-30 bg-black/50 hidden md:hidden" aria-hidden="true"></div>
<!-- ============================================ -->
<!-- MAIN CONTENT -->
<!-- ============================================ -->
<div class="flex-1 flex flex-col md:ml-64">
<!-- Header -->
<header class="sticky top-0 z-20 bg-white dark:bg-gray-900 border-b border-gray-200 dark:border-gray-800">
<div class="flex items-center justify-between h-16 px-4 sm:px-6">
<!-- Left: Mobile toggle + Search -->
<div class="flex items-center gap-3 flex-1">
<button id="sidebar-open" class="md:hidden p-2 rounded-lg text-gray-600 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16"/>
</svg>
</button>
<!-- Search -->
<div class="hidden sm:flex items-center flex-1 max-w-md">
<div class="relative w-full">
<svg class="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"/>
</svg>
<input type="search" placeholder="Search anything..."
class="w-full pl-10 pr-4 py-2 bg-gray-100 dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent transition-shadow">
</div>
</div>
</div>
<!-- Right: Actions -->
<div class="flex items-center gap-2">
<!-- Notifications -->
<button class="relative p-2 rounded-lg text-gray-600 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 17h5l-1.405-1.405A2.032 2.032 0 0118 14.158V11a6.002 6.002 0 00-4-5.659V5a2 2 0 10-4 0v.341C7.67 6.165 6 8.388 6 11v3.159c0 .538-.214 1.055-.595 1.436L4 17h5m6 0v1a3 3 0 11-6 0v-1m6 0H9"/>
</svg>
<span class="absolute top-1.5 right-1.5 w-2 h-2 bg-red-500 rounded-full ring-2 ring-white dark:ring-gray-900"></span>
</button>
<!-- Theme Toggle -->
<button id="dash-theme-toggle" class="p-2 rounded-lg text-gray-600 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors">
<svg class="w-5 h-5 dark:hidden" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z"/>
</svg>
<svg class="w-5 h-5 hidden dark:block" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z"/>
</svg>
</button>
</div>
</div>
</header>
<!-- Page Content -->
<main class="flex-1 overflow-y-auto p-4 sm:p-6 lg:p-8">
<!-- Page Title -->
<div class="mb-6">
<h1 class="text-2xl font-bold text-gray-900 dark:text-white">Dashboard Overview</h1>
<p class="text-sm text-gray-500 dark:text-gray-400 mt-1">Welcome back, Admin. Here is what is happening today.</p>
</div>
<!-- ============================================ -->
<!-- STATS CARDS -->
<!-- ============================================ -->
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4 sm:gap-6 mb-6">
<!-- Stat 1: Revenue -->
<div class="bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-xl p-5">
<div class="flex items-center justify-between mb-3">
<div class="w-10 h-10 bg-blue-100 dark:bg-blue-900/40 rounded-lg flex items-center justify-center">
<svg class="w-5 h-5 text-blue-600 dark:text-blue-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8c-1.657 0-3 .895-3 2s1.343 2 3 2 3 .895 3 2-1.343 2-3 2m0-8c1.11 0 2.08.402 2.599 1M12 8V7m0 1v8m0 0v1m0-1c-1.11 0-2.08-.402-2.599-1M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>
</svg>
</div>
<span class="flex items-center gap-1 text-xs font-medium text-green-600 dark:text-green-400 bg-green-100 dark:bg-green-900/40 px-2 py-0.5 rounded-full">
<svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 10l7-7m0 0l7 7m-7-7v18"/></svg>
12.5%
</span>
</div>
<p class="text-2xl font-bold text-gray-900 dark:text-white">$45,231.89</p>
<p class="text-sm text-gray-500 dark:text-gray-400 mt-1">Total Revenue</p>
</div>
<!-- Stat 2: Users -->
<div class="bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-xl p-5">
<div class="flex items-center justify-between mb-3">
<div class="w-10 h-10 bg-purple-100 dark:bg-purple-900/40 rounded-lg flex items-center justify-center">
<svg class="w-5 h-5 text-purple-600 dark:text-purple-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0z"/>
</svg>
</div>
<span class="flex items-center gap-1 text-xs font-medium text-green-600 dark:text-green-400 bg-green-100 dark:bg-green-900/40 px-2 py-0.5 rounded-full">
<svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 10l7-7m0 0l7 7m-7-7v18"/></svg>
8.2%
</span>
</div>
<p class="text-2xl font-bold text-gray-900 dark:text-white">2,350</p>
<p class="text-sm text-gray-500 dark:text-gray-400 mt-1">Active Users</p>
</div>
<!-- Stat 3: Orders -->
<div class="bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-xl p-5">
<div class="flex items-center justify-between mb-3">
<div class="w-10 h-10 bg-orange-100 dark:bg-orange-900/40 rounded-lg flex items-center justify-center">
<svg class="w-5 h-5 text-orange-600 dark:text-orange-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 11V7a4 4 0 00-8 0v4M5 9h14l1 12H4L5 9z"/>
</svg>
</div>
<span class="flex items-center gap-1 text-xs font-medium text-red-600 dark:text-red-400 bg-red-100 dark:bg-red-900/40 px-2 py-0.5 rounded-full">
<svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 14l-7 7m0 0l-7-7m7 7V3"/></svg>
3.1%
</span>
</div>
<p class="text-2xl font-bold text-gray-900 dark:text-white">1,823</p>
<p class="text-sm text-gray-500 dark:text-gray-400 mt-1">Total Orders</p>
</div>
<!-- Stat 4: Conversion -->
<div class="bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-xl p-5">
<div class="flex items-center justify-between mb-3">
<div class="w-10 h-10 bg-green-100 dark:bg-green-900/40 rounded-lg flex items-center justify-center">
<svg class="w-5 h-5 text-green-600 dark:text-green-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 7h8m0 0v8m0-8l-8 8-4-4-6 6"/>
</svg>
</div>
<span class="flex items-center gap-1 text-xs font-medium text-green-600 dark:text-green-400 bg-green-100 dark:bg-green-900/40 px-2 py-0.5 rounded-full">
<svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 10l7-7m0 0l7 7m-7-7v18"/></svg>
4.7%
</span>
</div>
<p class="text-2xl font-bold text-gray-900 dark:text-white">3.24%</p>
<p class="text-sm text-gray-500 dark:text-gray-400 mt-1">Conversion Rate</p>
</div>
</div>
<!-- ============================================ -->
<!-- DATA TABLE + CHART (2 columns) -->
<!-- ============================================ -->
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6 mb-6">
<!-- Data Table (2/3 width) -->
<div class="lg:col-span-2 bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-xl overflow-hidden">
<div class="px-5 py-4 border-b border-gray-200 dark:border-gray-700 flex items-center justify-between">
<h2 class="font-semibold text-gray-900 dark:text-white">Recent Orders</h2>
<a href="#" class="text-sm text-primary hover:underline">View all</a>
</div>
<div class="overflow-x-auto">
<table class="w-full">
<thead>
<tr class="border-b border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-900/50">
<th class="text-left px-5 py-3 text-xs font-semibold text-gray-500 dark:text-gray-400 uppercase tracking-wider">Order</th>
<th class="text-left px-5 py-3 text-xs font-semibold text-gray-500 dark:text-gray-400 uppercase tracking-wider">Customer</th>
<th class="text-left px-5 py-3 text-xs font-semibold text-gray-500 dark:text-gray-400 uppercase tracking-wider">Date</th>
<th class="text-left px-5 py-3 text-xs font-semibold text-gray-500 dark:text-gray-400 uppercase tracking-wider">Amount</th>
<th class="text-left px-5 py-3 text-xs font-semibold text-gray-500 dark:text-gray-400 uppercase tracking-wider">Status</th>
</tr>
</thead>
<tbody class="divide-y divide-gray-100 dark:divide-gray-800">
<!-- Row 1 -->
<tr class="hover:bg-gray-50 dark:hover:bg-gray-900/50 transition-colors">
<td class="px-5 py-3.5 text-sm font-medium text-gray-900 dark:text-white">#ORD-001</td>
<td class="px-5 py-3.5 text-sm text-gray-600 dark:text-gray-400">Sarah Chen</td>
<td class="px-5 py-3.5 text-sm text-gray-600 dark:text-gray-400">Jul 8, 2026</td>
<td class="px-5 py-3.5 text-sm font-medium text-gray-900 dark:text-white">$1,250.00</td>
<td class="px-5 py-3.5">
<span class="inline-flex px-2.5 py-0.5 text-xs font-medium rounded-full bg-green-100 dark:bg-green-900/40 text-green-700 dark:text-green-400">Completed</span>
</td>
</tr>
<!-- Row 2 -->
<tr class="hover:bg-gray-50 dark:hover:bg-gray-900/50 transition-colors">
<td class="px-5 py-3.5 text-sm font-medium text-gray-900 dark:text-white">#ORD-002</td>
<td class="px-5 py-3.5 text-sm text-gray-600 dark:text-gray-400">Marcus Rivera</td>
<td class="px-5 py-3.5 text-sm text-gray-600 dark:text-gray-400">Jul 8, 2026</td>
<td class="px-5 py-3.5 text-sm font-medium text-gray-900 dark:text-white">$890.50</td>
<td class="px-5 py-3.5">
<span class="inline-flex px-2.5 py-0.5 text-xs font-medium rounded-full bg-yellow-100 dark:bg-yellow-900/40 text-yellow-700 dark:text-yellow-400">Pending</span>
</td>
</tr>
<!-- Row 3 -->
<tr class="hover:bg-gray-50 dark:hover:bg-gray-900/50 transition-colors">
<td class="px-5 py-3.5 text-sm font-medium text-gray-900 dark:text-white">#ORD-003</td>
<td class="px-5 py-3.5 text-sm text-gray-600 dark:text-gray-400">Aiko Tanaka</td>
<td class="px-5 py-3.5 text-sm text-gray-600 dark:text-gray-400">Jul 7, 2026</td>
<td class="px-5 py-3.5 text-sm font-medium text-gray-900 dark:text-white">$2,100.00</td>
<td class="px-5 py-3.5">
<span class="inline-flex px-2.5 py-0.5 text-xs font-medium rounded-full bg-green-100 dark:bg-green-900/40 text-green-700 dark:text-green-400">Completed</span>
</td>
</tr>
<!-- Row 4 -->
<tr class="hover:bg-gray-50 dark:hover:bg-gray-900/50 transition-colors">
<td class="px-5 py-3.5 text-sm font-medium text-gray-900 dark:text-white">#ORD-004</td>
<td class="px-5 py-3.5 text-sm text-gray-600 dark:text-gray-400">John Doe</td>
<td class="px-5 py-3.5 text-sm text-gray-600 dark:text-gray-400">Jul 7, 2026</td>
<td class="px-5 py-3.5 text-sm font-medium text-gray-900 dark:text-white">$450.75</td>
<td class="px-5 py-3.5">
<span class="inline-flex px-2.5 py-0.5 text-xs font-medium rounded-full bg-red-100 dark:bg-red-900/40 text-red-700 dark:text-red-400">Cancelled</span>
</td>
</tr>
<!-- Row 5 -->
<tr class="hover:bg-gray-50 dark:hover:bg-gray-900/50 transition-colors">
<td class="px-5 py-3.5 text-sm font-medium text-gray-900 dark:text-white">#ORD-005</td>
<td class="px-5 py-3.5 text-sm text-gray-600 dark:text-gray-400">Emma Wilson</td>
<td class="px-5 py-3.5 text-sm text-gray-600 dark:text-gray-400">Jul 6, 2026</td>
<td class="px-5 py-3.5 text-sm font-medium text-gray-900 dark:text-white">$3,200.00</td>
<td class="px-5 py-3.5">
<span class="inline-flex px-2.5 py-0.5 text-xs font-medium rounded-full bg-blue-100 dark:bg-blue-900/40 text-blue-700 dark:text-blue-400">Processing</span>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<!-- Activity Feed (1/3 width) -->
<div class="bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-xl overflow-hidden">
<div class="px-5 py-4 border-b border-gray-200 dark:border-gray-700">
<h2 class="font-semibold text-gray-900 dark:text-white">Recent Activity</h2>
</div>
<div class="p-5 space-y-5">
<!-- Activity 1 -->
<div class="flex gap-3">
<div class="relative flex-shrink-0">
<div class="w-8 h-8 rounded-full bg-blue-100 dark:bg-blue-900/40 flex items-center justify-center">
<span class="text-blue-600 dark:text-blue-400 text-xs font-bold">SC</span>
</div>
</div>
<div class="flex-1 min-w-0">
<p class="text-sm text-gray-900 dark:text-white">
<span class="font-medium">Sarah Chen</span> placed order <span class="font-medium">#ORD-001</span>
</p>
<p class="text-xs text-gray-500 dark:text-gray-400 mt-0.5">10 minutes ago</p>
</div>
</div>
<!-- Activity 2 -->
<div class="flex gap-3">
<div class="relative flex-shrink-0">
<div class="w-8 h-8 rounded-full bg-green-100 dark:bg-green-900/40 flex items-center justify-center">
<span class="text-green-600 dark:text-green-400 text-xs font-bold">MR</span>
</div>
</div>
<div class="flex-1 min-w-0">
<p class="text-sm text-gray-900 dark:text-white">
<span class="font-medium">Marcus Rivera</span> updated profile settings
</p>
<p class="text-xs text-gray-500 dark:text-gray-400 mt-0.5">25 minutes ago</p>
</div>
</div>
<!-- Activity 3 -->
<div class="flex gap-3">
<div class="relative flex-shrink-0">
<div class="w-8 h-8 rounded-full bg-purple-100 dark:bg-purple-900/40 flex items-center justify-center">
<span class="text-purple-600 dark:text-purple-400 text-xs font-bold">AT</span>
</div>
</div>
<div class="flex-1 min-w-0">
<p class="text-sm text-gray-900 dark:text-white">
<span class="font-medium">Aiko Tanaka</span> left a 5-star review
</p>
<p class="text-xs text-gray-500 dark:text-gray-400 mt-0.5">1 hour ago</p>
</div>
</div>
<!-- Activity 4 -->
<div class="flex gap-3">
<div class="relative flex-shrink-0">
<div class="w-8 h-8 rounded-full bg-orange-100 dark:bg-orange-900/40 flex items-center justify-center">
<span class="text-orange-600 dark:text-orange-400 text-xs font-bold">JD</span>
</div>
</div>
<div class="flex-1 min-w-0">
<p class="text-sm text-gray-900 dark:text-white">
<span class="font-medium">John Doe</span> cancelled order <span class="font-medium">#ORD-004</span>
</p>
<p class="text-xs text-gray-500 dark:text-gray-400 mt-0.5">2 hours ago</p>
</div>
</div>
<!-- Activity 5 -->
<div class="flex gap-3">
<div class="relative flex-shrink-0">
<div class="w-8 h-8 rounded-full bg-pink-100 dark:bg-pink-900/40 flex items-center justify-center">
<span class="text-pink-600 dark:text-pink-400 text-xs font-bold">EW</span>
</div>
</div>
<div class="flex-1 min-w-0">
<p class="text-sm text-gray-900 dark:text-white">
<span class="font-medium">Emma Wilson</span> subscribed to Pro plan
</p>
<p class="text-xs text-gray-500 dark:text-gray-400 mt-0.5">3 hours ago</p>
</div>
</div>
</div>
</div>
</div>
<!-- ============================================ -->
<!-- CHART PLACEHOLDER -->
<!-- ============================================ -->
<div class="bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-xl p-6">
<div class="flex items-center justify-between mb-4">
<h2 class="font-semibold text-gray-900 dark:text-white">Revenue Overview</h2>
<div class="flex gap-2">
<button class="px-3 py-1 text-xs font-medium bg-primary text-white rounded-lg">7d</button>
<button class="px-3 py-1 text-xs font-medium text-gray-600 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-lg transition-colors">30d</button>
<button class="px-3 py-1 text-xs font-medium text-gray-600 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-lg transition-colors">90d</button>
</div>
</div>
<!-- Chart placeholder with visual bars -->
<div class="h-64 flex items-end gap-2 px-2">
<div class="flex-1 bg-primary/20 dark:bg-primary/10 rounded-t hover:bg-primary/30 transition-colors relative" style="height: 40%">
<span class="absolute -top-5 left-1/2 -translate-x-1/2 text-xs text-gray-500 dark:text-gray-400">Mon</span>
</div>
<div class="flex-1 bg-primary/20 dark:bg-primary/10 rounded-t hover:bg-primary/30 transition-colors relative" style="height: 65%">
<span class="absolute -top-5 left-1/2 -translate-x-1/2 text-xs text-gray-500 dark:text-gray-400">Tue</span>
</div>
<div class="flex-1 bg-primary/20 dark:bg-primary/10 rounded-t hover:bg-primary/30 transition-colors relative" style="height: 45%">
<span class="absolute -top-5 left-1/2 -translate-x-1/2 text-xs text-gray-500 dark:text-gray-400">Wed</span>
</div>
<div class="flex-1 bg-primary rounded-t relative" style="height: 90%">
<span class="absolute -top-5 left-1/2 -translate-x-1/2 text-xs font-semibold text-primary">Thu</span>
</div>
<div class="flex-1 bg-primary/40 dark:bg-primary/30 rounded-t hover:bg-primary/50 transition-colors relative" style="height: 75%">
<span class="absolute -top-5 left-1/2 -translate-x-1/2 text-xs text-gray-500 dark:text-gray-400">Fri</span>
</div>
<div class="flex-1 bg-primary/20 dark:bg-primary/10 rounded-t hover:bg-primary/30 transition-colors relative" style="height: 55%">
<span class="absolute -top-5 left-1/2 -translate-x-1/2 text-xs text-gray-500 dark:text-gray-400">Sat</span>
</div>
<div class="flex-1 bg-primary/20 dark:bg-primary/10 rounded-t hover:bg-primary/30 transition-colors relative" style="height: 30%">
<span class="absolute -top-5 left-1/2 -translate-x-1/2 text-xs text-gray-500 dark:text-gray-400">Sun</span>
</div>
</div>
</div>
</main>
</div>
</div>
<script>
// Sidebar toggle (mobile)
const sidebar = document.getElementById('sidebar');
const overlay = document.getElementById('sidebar-overlay');
const openBtn = document.getElementById('sidebar-open');
const closeBtn = document.getElementById('sidebar-close');
function openSidebar() {
sidebar.classList.remove('-translate-x-full');
overlay.classList.remove('hidden');
document.body.style.overflow = 'hidden';
}
function closeSidebar() {
sidebar.classList.add('-translate-x-full');
overlay.classList.add('hidden');
document.body.style.overflow = '';
}
openBtn.addEventListener('click', openSidebar);
closeBtn.addEventListener('click', closeSidebar);
overlay.addEventListener('click', closeSidebar);
// Dark mode
const themeToggle = document.getElementById('dash-theme-toggle');
const html = document.documentElement;
function getTheme() {
const saved = localStorage.getItem('dashboard-theme');
if (saved) return saved;
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
}
function setTheme(theme) {
if (theme === 'dark') html.classList.add('dark');
else html.classList.remove('dark');
localStorage.setItem('dashboard-theme', theme);
}
setTheme(getTheme());
themeToggle.addEventListener('click', () => {
setTheme(html.classList.contains('dark') ? 'light' : 'dark');
});
</script>
</body>
</html>
Giải thích key decisions cho Dashboard:
| Kỹ thuật | Áp dụng ở đâu |
|---|---|
| Fixed sidebar + scrollable content | Flex layout: sidebar fixed left, main content scrolls independently. h-screen overflow-hidden on body. |
| Mobile sidebar toggle | Sidebar -translate-x-full on mobile, toggled via JS. Overlay behind sidebar. |
| Responsive stats grid | grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 — 1 col mobile, 4 cols desktop. |
| Status badges | Colored badges with consistent pattern: bg-{color}-100 dark:bg-{color}-900/40 text-{color}-700 dark:text-{color}-400 |
| Striped table rows | divide-y for borders, hover:bg-gray-50 for row hover highlight. |
| Activity feed | Timeline-style with avatar initials + action text + timestamp. |
| Chart placeholder | Visual bar chart using div heights + Tailwind classes. Interactive hover states. |
| Overflow handling | overflow-x-auto on table container for horizontal scroll on mobile. |
| Sticky header | sticky top-0 z-20 — header stays visible while main content scrolls. |
Project 3: E-commerce Product Page
Yêu cầu: Xây dựng trang chi tiết sản phẩm với:
- Product image gallery (main + thumbnails)
- Product info (title, price, discount, rating, description)
- Color/size variants (radio buttons styled as buttons)
- Quantity selector
- Add to cart with loading state
- Sticky add to cart on mobile
- Product tabs (Description / Specifications / Reviews)
- Related products (horizontal scroll)
3.1. Toan Bo Code — E-commerce Product Page
<!DOCTYPE html>
<html lang="vi" class="">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Product Detail — E-commerce</title>
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
<style>
@import "tailwindcss";
@custom-variant dark (&:where(.dark, .dark *));
@theme {
--color-primary: oklch(0.55 0.20 260);
--color-accent: oklch(0.60 0.18 35);
--color-star: oklch(0.75 0.16 90);
}
@utility scrollbar-hide {
-ms-overflow-style: none;
scrollbar-width: none;
&::-webkit-scrollbar { display: none; }
}
@keyframes spin {
to { transform: rotate(360deg); }
}
@keyframes slideUp {
from { transform: translateY(100%); opacity: 0; }
to { transform: translateY(0); opacity: 1; }
}
.animate-slide-up {
animation: slideUp 0.3s ease-out;
}
</style>
</head>
<body class="min-h-screen bg-gray-50 dark:bg-gray-950 text-gray-900 dark:text-gray-100">
<!-- Top Nav (simplified) -->
<nav class="bg-white dark:bg-gray-900 border-b border-gray-200 dark:border-gray-800 sticky top-0 z-40">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 h-14 flex items-center justify-between">
<a href="#" class="font-bold text-lg text-gray-900 dark:text-white">ShopName</a>
<div class="flex items-center gap-3">
<button id="ecom-theme-toggle" class="p-2 rounded-lg text-gray-600 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors">
<svg class="w-5 h-5 dark:hidden" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z"/>
</svg>
<svg class="w-5 h-5 hidden dark:block" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z"/>
</svg>
</button>
<button class="relative p-2 rounded-lg text-gray-600 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 11V7a4 4 0 00-8 0v4M5 9h14l1 12H4L5 9z"/>
</svg>
<span class="absolute -top-0.5 -right-0.5 w-5 h-5 bg-red-500 text-white text-xs font-bold rounded-full flex items-center justify-center">3</span>
</button>
</div>
</div>
</nav>
<main class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-6 lg:py-10">
<!-- ============================================ -->
<!-- PRODUCT MAIN SECTION (Image + Info) -->
<!-- ============================================ -->
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6 lg:gap-12 mb-12">
<!-- ===== LEFT: Image Gallery ===== -->
<div>
<!-- Main Image -->
<div class="relative bg-gray-100 dark:bg-gray-800 rounded-2xl overflow-hidden aspect-square mb-4 group cursor-zoom-in">
<div class="w-full h-full bg-gradient-to-br from-gray-200 to-gray-300 dark:from-gray-700 dark:to-gray-600 flex items-center justify-center transition-transform duration-500 group-hover:scale-110">
<div class="text-center">
<svg class="w-24 h-24 text-gray-400 dark:text-gray-500 mx-auto mb-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1" d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z"/>
</svg>
<span class="text-sm text-gray-500 dark:text-gray-400">Hover to zoom</span>
</div>
</div>
<!-- Discount badge -->
<div class="absolute top-4 left-4 px-3 py-1 bg-red-500 text-white text-sm font-bold rounded-full">
-25%
</div>
</div>
<!-- Thumbnails -->
<div class="flex gap-3 overflow-x-auto scrollbar-hide pb-1">
<button class="flex-shrink-0 w-20 h-20 rounded-lg border-2 border-primary overflow-hidden bg-gray-100 dark:bg-gray-800">
<div class="w-full h-full bg-gradient-to-br from-gray-200 to-gray-300 dark:from-gray-700 dark:to-gray-600"></div>
</button>
<button class="flex-shrink-0 w-20 h-20 rounded-lg border-2 border-transparent hover:border-gray-300 dark:hover:border-gray-600 overflow-hidden bg-gray-100 dark:bg-gray-800 transition-colors">
<div class="w-full h-full bg-gradient-to-br from-blue-200 to-blue-300 dark:from-blue-700 dark:to-blue-800"></div>
</button>
<button class="flex-shrink-0 w-20 h-20 rounded-lg border-2 border-transparent hover:border-gray-300 dark:hover:border-gray-600 overflow-hidden bg-gray-100 dark:bg-gray-800 transition-colors">
<div class="w-full h-full bg-gradient-to-br from-green-200 to-green-300 dark:from-green-700 dark:to-green-800"></div>
</button>
<button class="flex-shrink-0 w-20 h-20 rounded-lg border-2 border-transparent hover:border-gray-300 dark:hover:border-gray-600 overflow-hidden bg-gray-100 dark:bg-gray-800 transition-colors">
<div class="w-full h-full bg-gradient-to-br from-purple-200 to-purple-300 dark:from-purple-700 dark:to-purple-800"></div>
</button>
<button class="flex-shrink-0 w-20 h-20 rounded-lg border-2 border-transparent hover:border-gray-300 dark:hover:border-gray-600 overflow-hidden bg-gray-100 dark:bg-gray-800 transition-colors">
<div class="w-full h-full bg-gradient-to-br from-orange-200 to-orange-300 dark:from-orange-700 dark:to-orange-800"></div>
</button>
</div>
</div>
<!-- ===== RIGHT: Product Info ===== -->
<div class="flex flex-col">
<!-- Breadcrumb -->
<nav class="flex items-center gap-2 text-sm text-gray-500 dark:text-gray-400 mb-3">
<a href="#" class="hover:text-gray-700 dark:hover:text-gray-300 transition-colors">Home</a>
<span>/</span>
<a href="#" class="hover:text-gray-700 dark:hover:text-gray-300 transition-colors">Electronics</a>
<span>/</span>
<span class="text-gray-900 dark:text-white font-medium">Product Name</span>
</nav>
<!-- Title -->
<h1 class="text-2xl lg:text-3xl font-bold text-gray-900 dark:text-white mb-3">
Premium Wireless Headphones
</h1>
<!-- Rating -->
<div class="flex items-center gap-3 mb-4">
<div class="flex gap-0.5 text-star">
<svg class="w-4 h-4 fill-current" viewBox="0 0 20 20"><path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z"/></svg>
<svg class="w-4 h-4 fill-current" viewBox="0 0 20 20"><path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z"/></svg>
<svg class="w-4 h-4 fill-current" viewBox="0 0 20 20"><path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z"/></svg>
<svg class="w-4 h-4 fill-current" viewBox="0 0 20 20"><path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z"/></svg>
<svg class="w-4 h-4 fill-current" viewBox="0 0 20 20"><path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z"/></svg>
</div>
<span class="text-sm text-gray-500 dark:text-gray-400">4.8 (128 reviews)</span>
</div>
<!-- Price -->
<div class="flex items-baseline gap-3 mb-5">
<span class="text-3xl font-bold text-gray-900 dark:text-white">$149.99</span>
<span class="text-lg text-gray-400 dark:text-gray-500 line-through">$199.99</span>
<span class="px-2.5 py-0.5 text-sm font-bold bg-red-100 dark:bg-red-900/40 text-red-600 dark:text-red-400 rounded-full">Save $50</span>
</div>
<!-- Description -->
<p class="text-gray-600 dark:text-gray-400 leading-relaxed mb-6">
Experience premium sound quality with active noise cancellation, 30-hour battery life,
and ultra-comfortable memory foam ear cushions. Perfect for music, calls, and travel.
</p>
<!-- Color Variants -->
<div class="mb-5">
<p class="text-sm font-medium text-gray-900 dark:text-white mb-3">
Color: <span id="selected-color-label" class="font-normal text-gray-600 dark:text-gray-400">Midnight Black</span>
</p>
<div class="flex gap-3" role="radiogroup" aria-label="Color selection">
<label class="relative cursor-pointer">
<input type="radio" name="color" value="black" class="sr-only peer" checked onchange="document.getElementById('selected-color-label').textContent='Midnight Black'">
<div class="w-10 h-10 rounded-full bg-gray-900 ring-2 ring-offset-2 ring-primary ring-offset-white dark:ring-offset-gray-900 peer-focus-visible:ring-primary transition-all"></div>
</label>
<label class="relative cursor-pointer">
<input type="radio" name="color" value="white" class="sr-only peer" onchange="document.getElementById('selected-color-label').textContent='Pearl White'">
<div class="w-10 h-10 rounded-full bg-white border-2 border-gray-300 dark:border-gray-600 ring-2 ring-offset-2 ring-transparent peer-checked:ring-primary peer-focus-visible:ring-primary ring-offset-white dark:ring-offset-gray-900 transition-all"></div>
</label>
<label class="relative cursor-pointer">
<input type="radio" name="color" value="blue" class="sr-only peer" onchange="document.getElementById('selected-color-label').textContent='Ocean Blue'">
<div class="w-10 h-10 rounded-full bg-blue-600 ring-2 ring-offset-2 ring-transparent peer-checked:ring-primary peer-focus-visible:ring-primary ring-offset-white dark:ring-offset-gray-900 transition-all"></div>
</label>
<label class="relative cursor-pointer">
<input type="radio" name="color" value="red" class="sr-only peer" onchange="document.getElementById('selected-color-label').textContent='Crimson Red'">
<div class="w-10 h-10 rounded-full bg-red-600 ring-2 ring-offset-2 ring-transparent peer-checked:ring-primary peer-focus-visible:ring-primary ring-offset-white dark:ring-offset-gray-900 transition-all"></div>
</label>
</div>
</div>
<!-- Size / Storage Variants (styled as buttons) -->
<div class="mb-5">
<p class="text-sm font-medium text-gray-900 dark:text-white mb-3">Storage</p>
<div class="flex gap-2" role="radiogroup" aria-label="Storage selection">
<label class="cursor-pointer">
<input type="radio" name="size" value="64gb" class="sr-only peer" checked>
<div class="px-4 py-2 rounded-lg border-2 text-sm font-medium transition-all
peer-checked:border-primary peer-checked:bg-primary/5 peer-checked:text-primary
border-gray-300 dark:border-gray-600 text-gray-700 dark:text-gray-300
hover:border-gray-400 dark:hover:border-gray-500
peer-focus-visible:ring-2 peer-focus-visible:ring-primary peer-focus-visible:ring-offset-2">
64 GB
</div>
</label>
<label class="cursor-pointer">
<input type="radio" name="size" value="128gb" class="sr-only peer">
<div class="px-4 py-2 rounded-lg border-2 text-sm font-medium transition-all
peer-checked:border-primary peer-checked:bg-primary/5 peer-checked:text-primary
border-gray-300 dark:border-gray-600 text-gray-700 dark:text-gray-300
hover:border-gray-400 dark:hover:border-gray-500
peer-focus-visible:ring-2 peer-focus-visible:ring-primary peer-focus-visible:ring-offset-2">
128 GB
</div>
</label>
<label class="cursor-pointer">
<input type="radio" name="size" value="256gb" class="sr-only peer">
<div class="px-4 py-2 rounded-lg border-2 text-sm font-medium transition-all
peer-checked:border-primary peer-checked:bg-primary/5 peer-checked:text-primary
border-gray-300 dark:border-gray-600 text-gray-700 dark:text-gray-300
hover:border-gray-400 dark:hover:border-gray-500
peer-focus-visible:ring-2 peer-focus-visible:ring-primary peer-focus-visible:ring-offset-2">
256 GB
</div>
</label>
</div>
</div>
<!-- Quantity Selector -->
<div class="mb-6">
<p class="text-sm font-medium text-gray-900 dark:text-white mb-3">Quantity</p>
<div class="inline-flex items-center border border-gray-300 dark:border-gray-600 rounded-lg">
<button id="qty-minus" class="px-3 py-2 text-gray-600 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-800 rounded-l-lg transition-colors" aria-label="Decrease quantity">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20 12H4"/></svg>
</button>
<input id="qty-input" type="number" value="1" min="1" max="99"
class="w-14 text-center py-2 border-x border-gray-300 dark:border-gray-600 bg-transparent text-sm font-medium text-gray-900 dark:text-white focus:outline-none [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none">
<button id="qty-plus" class="px-3 py-2 text-gray-600 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-800 rounded-r-lg transition-colors" aria-label="Increase quantity">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4"/></svg>
</button>
</div>
</div>
<!-- Add to Cart + Wishlist -->
<div class="flex gap-3 mb-6">
<button id="add-to-cart-btn" class="flex-1 flex items-center justify-center gap-2 px-8 py-3.5 bg-primary text-white font-semibold rounded-xl hover:bg-primary/90 active:scale-[0.98] transition-all shadow-lg shadow-primary/25">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 11V7a4 4 0 00-8 0v4M5 9h14l1 12H4L5 9z"/>
</svg>
Add to Cart — $149.99
</button>
<button class="w-12 h-12 flex items-center justify-center rounded-xl border-2 border-gray-300 dark:border-gray-600 text-gray-600 dark:text-gray-400 hover:border-red-300 hover:text-red-500 dark:hover:border-red-700 dark:hover:text-red-400 transition-colors" aria-label="Add to wishlist">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z"/>
</svg>
</button>
</div>
<!-- Delivery Info -->
<div class="bg-gray-100 dark:bg-gray-800 rounded-xl p-4 space-y-2 text-sm">
<div class="flex items-center gap-2 text-gray-700 dark:text-gray-300">
<svg class="w-4 h-4 text-green-600 dark:text-green-400 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/></svg>
<span>Free shipping on orders over $100</span>
</div>
<div class="flex items-center gap-2 text-gray-700 dark:text-gray-300">
<svg class="w-4 h-4 text-green-600 dark:text-green-400 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/></svg>
<span>Delivery in 2-4 business days</span>
</div>
<div class="flex items-center gap-2 text-gray-700 dark:text-gray-300">
<svg class="w-4 h-4 text-green-600 dark:text-green-400 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/></svg>
<span>30-day easy returns</span>
</div>
</div>
</div>
</div>
<!-- ============================================ -->
<!-- PRODUCT TABS -->
<!-- ============================================ -->
<div class="mb-12">
<!-- Tab buttons -->
<div class="flex border-b border-gray-200 dark:border-gray-700 mb-6" role="tablist">
<button class="tab-btn px-4 py-3 text-sm font-medium border-b-2 border-primary text-primary -mb-px transition-colors" data-tab="description" role="tab" aria-selected="true">Description</button>
<button class="tab-btn px-4 py-3 text-sm font-medium border-b-2 border-transparent text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300 -mb-px transition-colors" data-tab="specifications" role="tab" aria-selected="false">Specifications</button>
<button class="tab-btn px-4 py-3 text-sm font-medium border-b-2 border-transparent text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300 -mb-px transition-colors" data-tab="reviews" role="tab" aria-selected="false">Reviews (128)</button>
</div>
<!-- Tab Panels -->
<div>
<!-- Description Panel -->
<div id="panel-description" class="tab-panel prose dark:prose-invert max-w-none">
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-3">Product Description</h3>
<p class="text-gray-600 dark:text-gray-400 leading-relaxed mb-4">
Our Premium Wireless Headphones deliver an unparalleled audio experience with advanced 40mm drivers,
adaptive noise cancellation, and support for high-resolution audio codecs including LDAC and aptX HD.
</p>
<p class="text-gray-600 dark:text-gray-400 leading-relaxed mb-4">
The over-ear design features plush memory foam ear cushions wrapped in breathable protein leather,
ensuring comfort during extended listening sessions. The foldable design and included carrying case
make these headphones perfect for travel.
</p>
<ul class="list-disc list-inside text-gray-600 dark:text-gray-400 space-y-1">
<li>40mm custom dynamic drivers</li>
<li>Hybrid Active Noise Cancellation (ANC)</li>
<li>30-hour battery life (ANC on)</li>
<li>Bluetooth 5.3 with multipoint connection</li>
<li>USB-C fast charging (10 min = 3 hours)</li>
</ul>
</div>
<!-- Specifications Panel -->
<div id="panel-specifications" class="tab-panel hidden">
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-4">Technical Specifications</h3>
<div class="bg-gray-50 dark:bg-gray-800 rounded-xl overflow-hidden">
<div class="grid grid-cols-1 sm:grid-cols-2 divide-y sm:divide-y-0 sm:divide-x divide-gray-200 dark:divide-gray-700">
<div class="p-4">
<p class="text-xs text-gray-500 dark:text-gray-400 uppercase tracking-wider mb-1">Driver Size</p>
<p class="text-sm font-medium text-gray-900 dark:text-white">40mm Dynamic</p>
</div>
<div class="p-4">
<p class="text-xs text-gray-500 dark:text-gray-400 uppercase tracking-wider mb-1">Frequency Response</p>
<p class="text-sm font-medium text-gray-900 dark:text-white">4Hz - 40kHz</p>
</div>
<div class="p-4">
<p class="text-xs text-gray-500 dark:text-gray-400 uppercase tracking-wider mb-1">Impedance</p>
<p class="text-sm font-medium text-gray-900 dark:text-white">32 Ohm</p>
</div>
<div class="p-4">
<p class="text-xs text-gray-500 dark:text-gray-400 uppercase tracking-wider mb-1">Weight</p>
<p class="text-sm font-medium text-gray-900 dark:text-white">250g</p>
</div>
<div class="p-4">
<p class="text-xs text-gray-500 dark:text-gray-400 uppercase tracking-wider mb-1">Bluetooth Version</p>
<p class="text-sm font-medium text-gray-900 dark:text-white">5.3</p>
</div>
<div class="p-4">
<p class="text-xs text-gray-500 dark:text-gray-400 uppercase tracking-wider mb-1">Battery Life</p>
<p class="text-sm font-medium text-gray-900 dark:text-white">30 hours (ANC on)</p>
</div>
</div>
</div>
</div>
<!-- Reviews Panel -->
<div id="panel-reviews" class="tab-panel hidden">
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-4">Customer Reviews</h3>
<div class="space-y-4">
<div class="bg-gray-50 dark:bg-gray-800 rounded-xl p-4">
<div class="flex items-center justify-between mb-2">
<div class="flex items-center gap-3">
<div class="w-8 h-8 rounded-full bg-blue-200 dark:bg-blue-800"></div>
<span class="text-sm font-medium text-gray-900 dark:text-white">David Kim</span>
</div>
<span class="text-xs text-gray-500 dark:text-gray-400">2 days ago</span>
</div>
<div class="flex gap-0.5 text-star mb-2">
<svg class="w-3.5 h-3.5 fill-current" viewBox="0 0 20 20"><path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z"/></svg>
<svg class="w-3.5 h-3.5 fill-current" viewBox="0 0 20 20"><path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z"/></svg>
<svg class="w-3.5 h-3.5 fill-current" viewBox="0 0 20 20"><path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z"/></svg>
<svg class="w-3.5 h-3.5 fill-current" viewBox="0 0 20 20"><path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z"/></svg>
<svg class="w-3.5 h-3.5 fill-current" viewBox="0 0 20 20"><path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z"/></svg>
</div>
<p class="text-sm text-gray-700 dark:text-gray-300">Best headphones I have ever owned. The ANC is incredible, and the battery lasts forever.</p>
</div>
<div class="bg-gray-50 dark:bg-gray-800 rounded-xl p-4">
<div class="flex items-center justify-between mb-2">
<div class="flex items-center gap-3">
<div class="w-8 h-8 rounded-full bg-green-200 dark:bg-green-800"></div>
<span class="text-sm font-medium text-gray-900 dark:text-white">Lisa Park</span>
</div>
<span class="text-xs text-gray-500 dark:text-gray-400">1 week ago</span>
</div>
<div class="flex gap-0.5 text-star mb-2">
<svg class="w-3.5 h-3.5 fill-current" viewBox="0 0 20 20"><path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z"/></svg>
<svg class="w-3.5 h-3.5 fill-current" viewBox="0 0 20 20"><path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z"/></svg>
<svg class="w-3.5 h-3.5 fill-current" viewBox="0 0 20 20"><path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z"/></svg>
<svg class="w-3.5 h-3.5 fill-current" viewBox="0 0 20 20"><path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z"/></svg>
<svg class="w-3.5 h-3.5 fill-current text-gray-300 dark:text-gray-600" viewBox="0 0 20 20"><path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z"/></svg>
</div>
<p class="text-sm text-gray-700 dark:text-gray-300">Great sound quality and comfortable fit. Only wish the case was a bit smaller.</p>
</div>
</div>
</div>
</div>
</div>
<!-- ============================================ -->
<!-- RELATED PRODUCTS (Horizontal Scroll) -->
<!-- ============================================ -->
<section class="mb-12">
<h2 class="text-xl font-bold text-gray-900 dark:text-white mb-6">You May Also Like</h2>
<div class="flex gap-4 overflow-x-auto scrollbar-hide pb-2">
<!-- Related Product 1 -->
<a href="#" class="flex-shrink-0 w-64 bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-xl overflow-hidden hover:shadow-lg transition-shadow group">
<div class="h-48 bg-gradient-to-br from-gray-100 to-gray-200 dark:from-gray-700 dark:to-gray-600 flex items-center justify-center">
<svg class="w-12 h-12 text-gray-400 dark:text-gray-500 group-hover:scale-110 transition-transform" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1" d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z"/>
</svg>
</div>
<div class="p-4">
<p class="text-xs text-gray-500 dark:text-gray-400 mb-1">Electronics</p>
<h3 class="text-sm font-semibold text-gray-900 dark:text-white mb-2 line-clamp-2">Sport Earbuds Pro — Waterproof Bluetooth 5.3</h3>
<div class="flex items-baseline gap-2">
<span class="text-lg font-bold text-gray-900 dark:text-white">$89.99</span>
<span class="text-xs text-gray-400 line-through">$119.99</span>
</div>
</div>
</a>
<!-- Related Product 2 -->
<a href="#" class="flex-shrink-0 w-64 bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-xl overflow-hidden hover:shadow-lg transition-shadow group">
<div class="h-48 bg-gradient-to-br from-purple-100 to-purple-200 dark:from-purple-700 dark:to-purple-800 flex items-center justify-center">
<svg class="w-12 h-12 text-purple-400 dark:text-purple-500 group-hover:scale-110 transition-transform" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1" d="M9.75 17L9 20l-1 1h8l-1-1-.75-3M3 13h18M5 17h14a2 2 0 002-2V5a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z"/>
</svg>
</div>
<div class="p-4">
<p class="text-xs text-gray-500 dark:text-gray-400 mb-1">Computers</p>
<h3 class="text-sm font-semibold text-gray-900 dark:text-white mb-2 line-clamp-2">UltraWide Monitor 34" — 144Hz Curved Display</h3>
<div class="flex items-baseline gap-2">
<span class="text-lg font-bold text-gray-900 dark:text-white">$599.99</span>
</div>
</div>
</a>
<!-- Related Product 3 -->
<a href="#" class="flex-shrink-0 w-64 bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-xl overflow-hidden hover:shadow-lg transition-shadow group">
<div class="h-48 bg-gradient-to-br from-green-100 to-green-200 dark:from-green-700 dark:to-green-800 flex items-center justify-center">
<svg class="w-12 h-12 text-green-400 dark:text-green-500 group-hover:scale-110 transition-transform" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1" d="M12 18h.01M7 21h10a2 2 0 002-2V5a2 2 0 00-2-2H7a2 2 0 00-2 2v14a2 2 0 002 2z"/>
</svg>
</div>
<div class="p-4">
<p class="text-xs text-gray-500 dark:text-gray-400 mb-1">Accessories</p>
<h3 class="text-sm font-semibold text-gray-900 dark:text-white mb-2 line-clamp-2">Mechanical Keyboard RGB — Cherry MX Switches</h3>
<div class="flex items-baseline gap-2">
<span class="text-lg font-bold text-gray-900 dark:text-white">$159.99</span>
<span class="text-xs text-gray-400 line-through">$199.99</span>
</div>
</div>
</a>
<!-- Related Product 4 -->
<a href="#" class="flex-shrink-0 w-64 bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-xl overflow-hidden hover:shadow-lg transition-shadow group">
<div class="h-48 bg-gradient-to-br from-orange-100 to-orange-200 dark:from-orange-700 dark:to-orange-800 flex items-center justify-center">
<svg class="w-12 h-12 text-orange-400 dark:text-orange-500 group-hover:scale-110 transition-transform" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1" d="M15.536 8.464a5 5 0 010 7.072m2.828-9.9a9 9 0 010 12.728M5.586 15.536a5 5 0 001.414 1.414m0 0l-2.828 2.828 2.828 2.828-2.828-2.828L8.95 15.95l.53.53L7.422 18.54 9.544 20.66 7.422 18.54l2.122-2.122"/>
</svg>
</div>
<div class="p-4">
<p class="text-xs text-gray-500 dark:text-gray-400 mb-1">Audio</p>
<h3 class="text-sm font-semibold text-gray-900 dark:text-white mb-2 line-clamp-2">Portable Bluetooth Speaker — 360 Sound, IPX7</h3>
<div class="flex items-baseline gap-2">
<span class="text-lg font-bold text-gray-900 dark:text-white">$79.99</span>
</div>
</div>
</a>
</div>
</section>
</main>
<!-- ============================================ -->
<!-- STICKY ADD TO CART (Mobile) -->
<!-- ============================================ -->
<div id="sticky-cart" class="fixed bottom-0 left-0 right-0 z-50 bg-white dark:bg-gray-900 border-t border-gray-200 dark:border-gray-800 p-4 hidden animate-slide-up lg:hidden shadow-xl">
<div class="flex items-center justify-between gap-3">
<div class="min-w-0">
<p class="text-sm font-semibold text-gray-900 dark:text-white truncate">Premium Wireless Headphones</p>
<p class="text-lg font-bold text-gray-900 dark:text-white">$149.99</p>
</div>
<button id="sticky-add-btn" class="flex-shrink-0 px-6 py-3 bg-primary text-white font-semibold rounded-xl hover:bg-primary/90 active:scale-[0.98] transition-all text-sm">
Add to Cart
</button>
</div>
</div>
<script>
// Tab switching
document.querySelectorAll('.tab-btn').forEach(btn => {
btn.addEventListener('click', () => {
// Update button styles
document.querySelectorAll('.tab-btn').forEach(b => {
b.classList.remove('border-primary', 'text-primary');
b.classList.add('border-transparent', 'text-gray-500', 'dark:text-gray-400');
b.setAttribute('aria-selected', 'false');
});
btn.classList.add('border-primary', 'text-primary');
btn.classList.remove('border-transparent', 'text-gray-500', 'dark:text-gray-400');
btn.setAttribute('aria-selected', 'true');
// Show/hide panels
const tabName = btn.dataset.tab;
document.querySelectorAll('.tab-panel').forEach(panel => panel.classList.add('hidden'));
document.getElementById('panel-' + tabName).classList.remove('hidden');
});
});
// Quantity selector
const qtyInput = document.getElementById('qty-input');
document.getElementById('qty-minus').addEventListener('click', () => {
const val = parseInt(qtyInput.value);
if (val > 1) qtyInput.value = val - 1;
});
document.getElementById('qty-plus').addEventListener('click', () => {
const val = parseInt(qtyInput.value);
if (val < 99) qtyInput.value = val + 1;
});
// Add to cart with loading state
const addToCartBtn = document.getElementById('add-to-cart-btn');
const stickyAddBtn = document.getElementById('sticky-add-btn');
function simulateAddToCart(btn) {
const originalHTML = btn.innerHTML;
btn.innerHTML = '<svg class="w-5 h-5 animate-spin" fill="none" viewBox="0 0 24 24"><circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle><path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"></path></svg> Adding...';
btn.disabled = true;
btn.classList.add('opacity-70', 'cursor-not-allowed');
setTimeout(() => {
btn.innerHTML = '<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/></svg> Added!';
btn.classList.remove('opacity-70', 'cursor-not-allowed');
btn.classList.add('bg-green-600');
setTimeout(() => {
btn.innerHTML = originalHTML;
btn.classList.remove('bg-green-600');
btn.disabled = false;
}, 2000);
}, 1500);
}
addToCartBtn.addEventListener('click', () => simulateAddToCart(addToCartBtn));
stickyAddBtn.addEventListener('click', () => simulateAddToCart(stickyAddBtn));
// Sticky cart visibility on scroll (mobile)
const stickyCart = document.getElementById('sticky-cart');
const productInfo = document.querySelector('.lg\\:col-span-2'); // product right column
window.addEventListener('scroll', () => {
if (window.innerWidth < 1024) { // Only on mobile/tablet
// Show sticky cart after scrolling past the main add-to-cart button
const addBtnRect = addToCartBtn.getBoundingClientRect();
if (addBtnRect.bottom < 0) {
stickyCart.classList.remove('hidden');
} else {
stickyCart.classList.add('hidden');
}
} else {
stickyCart.classList.add('hidden');
}
});
// Dark mode
const themeToggle = document.getElementById('ecom-theme-toggle');
const html = document.documentElement;
function getTheme() {
const saved = localStorage.getItem('ecom-theme');
if (saved) return saved;
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
}
function setTheme(theme) {
if (theme === 'dark') html.classList.add('dark');
else html.classList.remove('dark');
localStorage.setItem('ecom-theme', theme);
}
setTheme(getTheme());
themeToggle.addEventListener('click', () => {
setTheme(html.classList.contains('dark') ? 'light' : 'dark');
});
</script>
</body>
</html>
Giải thích key decisions cho E-commerce Product Page:
| Kỹ thuật | Áp dụng ở đâu |
|---|---|
| Image gallery | Main image with group-hover:scale-110 zoom effect. Thumbnail strip with overflow-x-auto scrollbar-hide. |
| Radio buttons styled as buttons | Color swatches: sr-only peer + peer-checked:ring-primary. Size variants: peer-checked:border-primary peer-checked:bg-primary/5. |
| Quantity selector | Custom increment/decrement buttons with [appearance:textfield] to hide native spin buttons. |
| Loading state | Add to cart button: spinner animation (CSS @keyframes spin), text change, green confirmation state. |
| Sticky add to cart (mobile) | fixed bottom-0 bar with animate-slide-up. Shows/hides based on scroll position. Hidden on desktop (lg:hidden). |
| Product tabs | Tab buttons with aria-selected + role="tablist". Panel show/hide via JS class toggle. |
| Related products | Horizontal scroll container with flex gap-4 overflow-x-auto scrollbar-hide. Cards with hover shadow effect. |
| Price display | Current price ($149.99), original price with line-through, savings badge (Save $50). |
| Delivery info | Info box with checkmark icons + text in a gray background card. |
Tong Ket 3 Projects
Landing Page
7 sections day du: Navigation, Hero, Features, Pricing, Testimonials, CTA, Footer. Dark mode toggle + mobile hamburger menu + billing monthly/yearly toggle.
Dashboard
Sidebar collapsible + sticky header + stats cards + data table voi status badges + activity feed timeline + chart placeholder. Mobile responsive voi sidebar overlay.
E-commerce
Image gallery + product info + color/size variants (radio styled as buttons) + quantity selector + add to cart loading state + sticky mobile cart + tabs + related products scroll.
Ky thuat da ap dung xuyen suot 3 projects:
- Mobile-first responsive: Grid columns, text sizes, visibility toggles — tat ca deu theo mobile-first approach.
- Dark mode inline: Moi element co
dark:variant — khong can CSS rieng cho dark mode. - Custom @theme: Colors, fonts, animations duoc dinh nghia trong
@themeblock — single source of truth. - JavaScript interactions: Menu toggle, theme toggle, tab switching, quantity selector, loading states, scroll detection — vanilla JS, khong framework.
- Accessibility:
aria-label,aria-selected,aria-checked,roleattributes, focus rings, semantic HTML. - CSS animations:
@keyframescho loading spinner, slide-up sticky cart, hover transitions. - Utility classes:
scrollbar-hide,text-gradient(custom utilities via@utility).
Loi Khuyen Khi Xay Dung Project Thuc Te
Start mobile-first, always
Thiet ke mobile truoc, desktop sau. Tailwind duoc xay dung cho mobile-first — dung nguoc lai se dan den CSS thua va kho maintain.
Design tokens truoc, component sau
Dinh nghia colors, spacing, typography trong
@theme truoc khi viet bat ky component nao. Token-driven development giup consistency.Extract patterns, not just components
Khi thay cung mot cum class xuat hien 3+ lan, extract thanh component class trong
@layer components. Tranh lap lai khong can thiet.Dark mode ngay tu dau
Them
dark: variant khi viet light mode — khong phai lam lai sau. Ton 30% thoi gian nhung tranh duoc refactor lon.Test responsive lien tuc
Resize browser lien tuc khi code. DevTools responsive mode la ban than. Kiem tra moi breakpoint sau moi component moi.
Vanilla JS la du cho da so
Ba projects tren chi dung vanilla JavaScript. Khong can React/Vue de xay dung UI tuong tac co ban. Chi can framework khi state management phuc tap.
Chuc mung! Ban da hoan thanh toan bo lo trinh Tailwind CSS v4 — tu co ban den 3 practical projects hoan chinh. Bay gio hay tu xay dung project cua rieng ban — clone mot landing page ban thich, build dashboard tu du an thuc te, hoac thiet ke product page cho san pham ban yeu thich.Remember: Tailwind la cong cu. Design eye va UX thinking la ky nang. Tool chi giup ban thuc thi nhanh hon, khong thay the duoc tu duy thiet ke.