2 Commits

Author SHA1 Message Date
Unchained
0b4e3f89d1 Add playwright for visual testing 2026-03-21 17:25:45 +02:00
Unchained
ec287c85ea Fix CSS cascade layers and header layout
- Rewrite globals.css to work properly with Tailwind 4 cascade layers
  - Remove conflicting * { padding: 0 } reset that broke Tailwind utilities
  - Organize styles into @layer base, @layer components, @layer utilities
- Fix newsletter centering (was off due to CSS layer conflicts)
- Fix header overlap on products pages (proper pt-[72px] spacing)
- Add solid header background (bg-white/80) instead of transparent
- Fix logo/nav positioning on desktop

Verified fixes with Playwright screenshots at 1280x800 and 390x844
2026-03-21 17:21:00 +02:00
6 changed files with 396 additions and 406 deletions

48
package-lock.json generated
View File

@@ -27,6 +27,7 @@
"@types/react-dom": "^19", "@types/react-dom": "^19",
"eslint": "^9", "eslint": "^9",
"eslint-config-next": "16.1.6", "eslint-config-next": "16.1.6",
"playwright": "^1.58.2",
"tailwindcss": "^4", "tailwindcss": "^4",
"typescript": "^5" "typescript": "^5"
} }
@@ -4308,6 +4309,21 @@
} }
} }
}, },
"node_modules/fsevents": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
},
"node_modules/function-bind": { "node_modules/function-bind": {
"version": "1.1.2", "version": "1.1.2",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
@@ -6204,6 +6220,38 @@
"url": "https://github.com/sponsors/jonschlinkert" "url": "https://github.com/sponsors/jonschlinkert"
} }
}, },
"node_modules/playwright": {
"version": "1.58.2",
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.58.2.tgz",
"integrity": "sha512-vA30H8Nvkq/cPBnNw4Q8TWz1EJyqgpuinBcHET0YVJVFldr8JDNiU9LaWAE1KqSkRYazuaBhTpB5ZzShOezQ6A==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"playwright-core": "1.58.2"
},
"bin": {
"playwright": "cli.js"
},
"engines": {
"node": ">=18"
},
"optionalDependencies": {
"fsevents": "2.3.2"
}
},
"node_modules/playwright-core": {
"version": "1.58.2",
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.58.2.tgz",
"integrity": "sha512-yZkEtftgwS8CsfYo7nm0KE8jsvm6i/PTgVtB8DL726wNf6H2IMsDuxCpJj59KDaxCtSnrWan2AeDqM7JBaultg==",
"dev": true,
"license": "Apache-2.0",
"bin": {
"playwright-core": "cli.js"
},
"engines": {
"node": ">=18"
}
},
"node_modules/po-parser": { "node_modules/po-parser": {
"version": "2.1.1", "version": "2.1.1",
"resolved": "https://registry.npmjs.org/po-parser/-/po-parser-2.1.1.tgz", "resolved": "https://registry.npmjs.org/po-parser/-/po-parser-2.1.1.tgz",

View File

@@ -28,6 +28,7 @@
"@types/react-dom": "^19", "@types/react-dom": "^19",
"eslint": "^9", "eslint": "^9",
"eslint-config-next": "16.1.6", "eslint-config-next": "16.1.6",
"playwright": "^1.58.2",
"tailwindcss": "^4", "tailwindcss": "^4",
"typescript": "^5" "typescript": "^5"
} }

View File

@@ -2,61 +2,11 @@
/* ============================================ /* ============================================
MANOONOILS DESIGN SYSTEM MANOONOILS DESIGN SYSTEM
Inspired by premium skincare brands Tailwind 4 compatible - uses CSS layers
============================================ */ ============================================ */
:root {
/* Primary Colors */
--color-white: #ffffff;
--color-background: #fafafa;
--color-background-alt: #f5f5f5;
--color-foreground: #1a1a1a;
--color-foreground-muted: #666666;
--color-foreground-subtle: #999999;
/* Accent Colors */
--color-accent: #e8f0f5;
--color-accent-dark: #a8c5d8;
--color-accent-blue: #e8f0f5;
--color-gold: #c9a962;
--color-gold-light: #d4b978;
/* UI Colors */
--color-border: #e5e5e5;
--color-border-dark: #d1d1d1;
--color-cta: #000000;
--color-cta-hover: #333333;
--color-overlay: rgba(0, 0, 0, 0.4);
/* Spacing */
--space-xs: 4px;
--space-sm: 8px;
--space-md: 16px;
--space-lg: 24px;
--space-xl: 32px;
--space-2xl: 48px;
--space-3xl: 64px;
--space-4xl: 96px;
--space-5xl: 128px;
/* Typography */
--font-display: 'DM Sans', sans-serif;
--font-body: 'Inter', sans-serif;
/* Transitions */
--transition-fast: 150ms ease;
--transition-base: 250ms ease;
--transition-slow: 350ms ease;
/* Shadows */
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);
--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
--shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
--shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.1);
}
@theme inline { @theme inline {
/* Colors - reference :root variables */ /* Colors - reference CSS variables */
--color-white: var(--color-white); --color-white: var(--color-white);
--color-background: var(--color-background); --color-background: var(--color-background);
--color-background-alt: var(--color-background-alt); --color-background-alt: var(--color-background-alt);
@@ -79,6 +29,43 @@
--font-body: var(--font-body); --font-body: var(--font-body);
} }
/* ============================================
CSS VARIABLES
============================================ */
:root {
--color-white: #ffffff;
--color-background: #fafafa;
--color-background-alt: #f5f5f5;
--color-foreground: #1a1a1a;
--color-foreground-muted: #666666;
--color-foreground-subtle: #999999;
--color-accent: #e8f0f5;
--color-accent-dark: #a8c5d8;
--color-accent-blue: #e8f0f5;
--color-gold: #c9a962;
--color-gold-light: #d4b978;
--color-border: #e5e5e5;
--color-border-dark: #d1d1d1;
--color-cta: #000000;
--color-cta-hover: #333333;
--color-overlay: rgba(0, 0, 0, 0.4);
--font-display: 'DM Sans', sans-serif;
--font-body: 'Inter', sans-serif;
--transition-fast: 150ms ease;
--transition-base: 250ms ease;
--transition-slow: 350ms ease;
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);
--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
--shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
--shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.1);
}
/* ============================================ /* ============================================
FONT IMPORTS FONT IMPORTS
============================================ */ ============================================ */
@@ -98,20 +85,15 @@
} }
/* ============================================ /* ============================================
BASE STYLES BASE STYLES (in Tailwind base layer)
============================================ */ ============================================ */
* { @layer base {
box-sizing: border-box; html {
margin: 0;
padding: 0;
}
html {
scroll-behavior: smooth; scroll-behavior: smooth;
} }
body { body {
background: var(--color-background); background: var(--color-background);
color: var(--color-foreground); color: var(--color-foreground);
font-family: var(--font-body); font-family: var(--font-body);
@@ -119,120 +101,80 @@ body {
line-height: 1.6; line-height: 1.6;
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;
} }
/* ============================================ h1, h2, h3, h4, h5, h6 {
TYPOGRAPHY
============================================ */
h1, h2, h3, h4, h5, h6 {
font-family: var(--font-display); font-family: var(--font-display);
font-weight: 500; font-weight: 500;
line-height: 1.2; line-height: 1.2;
letter-spacing: -0.02em; letter-spacing: -0.02em;
} }
h1 { h1 {
font-size: clamp(2rem, 5vw, 3.5rem); font-size: clamp(2rem, 5vw, 3.5rem);
} }
h2 { h2 {
font-size: clamp(1.5rem, 4vw, 2.5rem); font-size: clamp(1.5rem, 4vw, 2.5rem);
} }
h3 { h3 {
font-size: clamp(1.25rem, 3vw, 1.75rem); font-size: clamp(1.25rem, 3vw, 1.75rem);
} }
.text-display { input, textarea, select {
font-family: var(--font-display);
font-weight: 500;
letter-spacing: -0.02em;
}
.text-body {
font-family: var(--font-body); font-family: var(--font-body);
} font-size: 16px;
}
.text-uppercase { input:focus, textarea:focus, select:focus {
text-transform: uppercase; outline: none;
letter-spacing: 0.05em; border-color: var(--color-foreground);
} }
.text-caption { :focus-visible {
font-size: 12px; outline: 2px solid var(--color-foreground);
text-transform: uppercase; outline-offset: 2px;
letter-spacing: 0.1em; }
font-weight: 500;
}
.text-muted {
color: var(--color-foreground-muted);
}
.text-subtle {
color: var(--color-foreground-subtle);
} }
/* ============================================ /* ============================================
UTILITY CLASSES COMPONENTS
============================================ */ ============================================ */
.container { @layer components {
.container {
width: 100%; width: 100%;
max-width: 1400px; max-width: 1400px;
margin-left: auto; margin-left: auto;
margin-right: auto; margin-right: auto;
padding-left: 24px; padding-left: 24px;
padding-right: 24px; padding-right: 24px;
} }
@media (min-width: 640px) { @media (min-width: 640px) {
.container { .container {
padding-left: 32px; padding-left: 32px;
padding-right: 32px; padding-right: 32px;
} }
} }
@media (min-width: 1024px) { @media (min-width: 1024px) {
.container { .container {
padding-left: 48px; padding-left: 48px;
padding-right: 48px; padding-right: 48px;
} }
} }
.container-narrow { .container-narrow {
max-width: 1200px; max-width: 1200px;
} }
.container-wide { .container-wide {
max-width: 1600px; max-width: 1600px;
} }
/* Section spacing */ .btn {
.section {
padding-top: var(--space-4xl);
padding-bottom: var(--space-4xl);
}
.section-sm {
padding-top: var(--space-2xl);
padding-bottom: var(--space-2xl);
}
/* Flex utilities */
.flex-center {
display: flex;
align-items: center;
justify-content: center;
}
/* ============================================
INTERACTIVE ELEMENTS
============================================ */
/* Button Base */
.btn {
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
@@ -244,36 +186,35 @@ h3 {
border: none; border: none;
cursor: pointer; cursor: pointer;
transition: all var(--transition-base); transition: all var(--transition-base);
} }
.btn-primary { .btn-primary {
background: var(--color-cta); background: var(--color-cta);
color: var(--color-white); color: var(--color-white);
} }
.btn-primary:hover { .btn-primary:hover {
background: var(--color-cta-hover); background: var(--color-cta-hover);
} }
.btn-secondary { .btn-secondary {
background: transparent; background: transparent;
color: var(--color-foreground); color: var(--color-foreground);
border: 1px solid var(--color-border-dark); border: 1px solid var(--color-border-dark);
} }
.btn-secondary:hover { .btn-secondary:hover {
background: var(--color-foreground); background: var(--color-foreground);
color: var(--color-white); color: var(--color-white);
border-color: var(--color-foreground); border-color: var(--color-foreground);
} }
/* Link underline animation */ .link-underline {
.link-underline {
position: relative; position: relative;
text-decoration: none; text-decoration: none;
} }
.link-underline::after { .link-underline::after {
content: ''; content: '';
position: absolute; position: absolute;
bottom: -2px; bottom: -2px;
@@ -282,123 +223,138 @@ h3 {
height: 1px; height: 1px;
background: currentColor; background: currentColor;
transition: width var(--transition-base); transition: width var(--transition-base);
} }
.link-underline:hover::after { .link-underline:hover::after {
width: 100%; width: 100%;
} }
/* ============================================ .text-display {
FORM ELEMENTS font-family: var(--font-display);
============================================ */ font-weight: 500;
letter-spacing: -0.02em;
}
input, textarea, select { .text-body {
font-family: var(--font-body); font-family: var(--font-body);
font-size: 16px; }
}
input:focus, textarea:focus, select:focus { .text-uppercase {
outline: none; text-transform: uppercase;
border-color: var(--color-foreground); letter-spacing: 0.05em;
}
.text-caption {
font-size: 12px;
text-transform: uppercase;
letter-spacing: 0.1em;
font-weight: 500;
}
.text-muted {
color: var(--color-foreground-muted);
}
.text-subtle {
color: var(--color-foreground-subtle);
}
.flex-center {
display: flex;
align-items: center;
justify-content: center;
}
} }
/* ============================================ /* ============================================
SCROLLBAR UTILITIES
============================================ */ ============================================ */
::-webkit-scrollbar { @layer utilities {
.section {
padding-top: 96px;
padding-bottom: 96px;
}
.section-sm {
padding-top: 48px;
padding-bottom: 48px;
}
::-webkit-scrollbar {
width: 8px; width: 8px;
} }
::-webkit-scrollbar-track { ::-webkit-scrollbar-track {
background: var(--color-background-alt); background: var(--color-background-alt);
} }
::-webkit-scrollbar-thumb { ::-webkit-scrollbar-thumb {
background: var(--color-border-dark); background: var(--color-border-dark);
border-radius: 4px; border-radius: 4px;
} }
::-webkit-scrollbar-thumb:hover { ::-webkit-scrollbar-thumb:hover {
background: var(--color-foreground-muted); background: var(--color-foreground-muted);
} }
/* ============================================ .animate-fade-in {
ANIMATIONS
============================================ */
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes slideUp {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes slideInRight {
from {
opacity: 0;
transform: translateX(100%);
}
to {
opacity: 1;
transform: translateX(0);
}
}
.animate-fade-in {
animation: fadeIn var(--transition-slow) forwards; animation: fadeIn var(--transition-slow) forwards;
} }
.animate-slide-up { .animate-slide-up {
animation: slideUp var(--transition-slow) forwards; animation: slideUp var(--transition-slow) forwards;
} }
.animate-slide-in-right { .animate-slide-in-right {
animation: slideInRight var(--transition-slow) forwards; animation: slideInRight var(--transition-slow) forwards;
}
/* Marquee Animations */
@keyframes marquee {
0% {
transform: translateX(0);
} }
100% {
transform: translateX(-50%);
}
}
.animate-marquee { @keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
@keyframes slideUp {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
}
@keyframes slideInRight {
from { opacity: 0; transform: translateX(100%); }
to { opacity: 1; transform: translateX(0); }
}
@keyframes marquee {
0% { transform: translateX(0); }
100% { transform: translateX(-50%); }
}
.animate-marquee {
animation: marquee 25s linear infinite; animation: marquee 25s linear infinite;
} }
.animate-marquee-slow { .animate-marquee-slow {
animation: marquee 35s linear infinite; animation: marquee 35s linear infinite;
}
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border-width: 0;
}
} }
/* ============================================ /* ============================================
ACCESSIBILITY REDUCED MOTION
============================================ */ ============================================ */
/* Focus visible styles */
:focus-visible {
outline: 2px solid var(--color-foreground);
outline-offset: 2px;
}
/* Reduced motion */
@media (prefers-reduced-motion: reduce) { @media (prefers-reduced-motion: reduce) {
*, *,
*::before, *::before,
@@ -412,16 +368,3 @@ input:focus, textarea:focus, select:focus {
scroll-behavior: auto; scroll-behavior: auto;
} }
} }
/* Screen reader only */
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border-width: 0;
}

View File

@@ -162,15 +162,15 @@ export default async function Homepage() {
Subscribe to receive exclusive offers, beauty tips, and be the first to know about new products. Subscribe to receive exclusive offers, beauty tips, and be the first to know about new products.
</p> </p>
{/* Newsletter Form - Centered */} {/* Newsletter Form - Centered */}
<form className="flex flex-col sm:flex-row items-center justify-center w-full sm:w-auto gap-0"> <form className="flex flex-col sm:flex-row items-stretch justify-center max-w-md mx-auto gap-0">
<input <input
type="email" type="email"
placeholder="Enter your email" placeholder="Enter your email"
className="w-full sm:w-64 md:w-80 px-5 h-14 bg-white/10 border border-white/20 border-b-0 sm:border-b border-r-0 sm:border-r border-white/20 text-white placeholder:text-white/50 focus:border-white focus:outline-none transition-colors text-base text-center sm:text-left" className="flex-1 min-w-0 px-5 h-14 bg-white/10 border border-white/20 border-b-0 sm:border-b border-r-0 sm:border-r border-white/20 text-white placeholder:text-white/50 focus:border-white focus:outline-none transition-colors text-base text-center sm:text-left rounded-t sm:rounded-l sm:rounded-tr-none"
/> />
<button <button
type="submit" type="submit"
className="w-full sm:w-auto px-8 h-14 bg-white text-black text-sm uppercase tracking-[0.1em] font-medium hover:bg-white/90 transition-colors whitespace-nowrap flex-shrink-0" className="px-8 h-14 bg-white text-black text-sm uppercase tracking-[0.1em] font-medium hover:bg-white/90 transition-colors whitespace-nowrap flex-shrink-0 rounded-b sm:rounded-r sm:rounded-bl-none"
> >
Subscribe Subscribe
</button> </button>

View File

@@ -24,7 +24,7 @@ export default async function ProductsPage({ params }: ProductsPageProps) {
<main className="min-h-screen bg-white"> <main className="min-h-screen bg-white">
{/* Page Header */} {/* Page Header */}
<div className="pt-[140px] lg:pt-[160px]"> <div className="pt-[72px] lg:pt-[72px]">
<div className="border-b border-[#e5e5e5]"> <div className="border-b border-[#e5e5e5]">
<div className="container py-8 md:py-12"> <div className="container py-8 md:py-12">
<div className="flex flex-col md:flex-row md:items-end md:justify-between gap-4"> <div className="flex flex-col md:flex-row md:items-end md:justify-between gap-4">

View File

@@ -53,11 +53,10 @@ export default function Header() {
className={`fixed top-0 left-0 right-0 z-50 transition-all duration-300 ${ className={`fixed top-0 left-0 right-0 z-50 transition-all duration-300 ${
scrolled scrolled
? "bg-white/95 backdrop-blur-md shadow-sm" ? "bg-white/95 backdrop-blur-md shadow-sm"
: "bg-transparent" : "bg-white/80 backdrop-blur-sm"
}`} }`}
> >
<div className="container"> <div className="relative flex items-center justify-between h-[72px]">
<div className="flex items-center justify-between h-[72px]">
{/* Mobile Menu Button */} {/* Mobile Menu Button */}
<button <button
className="lg:hidden p-2 -ml-2 hover:bg-black/5 rounded-full transition-colors" className="lg:hidden p-2 -ml-2 hover:bg-black/5 rounded-full transition-colors"
@@ -67,20 +66,8 @@ export default function Header() {
<Menu className="w-5 h-5" /> <Menu className="w-5 h-5" />
</button> </button>
{/* Logo */} {/* Left side - Desktop Nav */}
<Link href="/" className="flex-shrink-0 lg:absolute lg:left-1/2 lg:-translate-x-1/2"> <nav className="hidden lg:flex items-center gap-10">
<Image
src="https://minio-api.nodecrew.me/manoon-media/2024/09/cropped-manoon-logo_256x-1-1.png"
alt="ManoonOils"
width={150}
height={40}
className="h-7 w-auto object-contain"
priority
/>
</Link>
{/* Desktop Navigation - Centered */}
<nav className="hidden lg:flex items-center gap-10 mx-auto">
{navLinks.map((link) => ( {navLinks.map((link) => (
<Link <Link
key={link.href} key={link.href}
@@ -93,7 +80,19 @@ export default function Header() {
))} ))}
</nav> </nav>
{/* Icons */} {/* Logo - Centered (absolute on desktop, flex on mobile) */}
<Link href="/" className="flex-shrink-0 lg:absolute lg:left-1/2 lg:-translate-x-1/2">
<Image
src="https://minio-api.nodecrew.me/manoon-media/2024/09/cropped-manoon-logo_256x-1-1.png"
alt="ManoonOils"
width={150}
height={40}
className="h-7 w-auto object-contain"
priority
/>
</Link>
{/* Right side - Icons */}
<div className="flex items-center gap-1"> <div className="flex items-center gap-1">
<button <button
className="p-2 hover:bg-black/5 rounded-full transition-colors hidden sm:block" className="p-2 hover:bg-black/5 rounded-full transition-colors hidden sm:block"
@@ -116,7 +115,6 @@ export default function Header() {
</button> </button>
</div> </div>
</div> </div>
</div>
</header> </header>
{/* Mobile Menu Overlay */} {/* Mobile Menu Overlay */}