Pages Hard
Fine Dining Restaurant
Warm editorial restaurant page with cream/terracotta palette, Playfair Display serif typography, SplitText char-by-char hero entrance, menu section with parallax images, and a vintage story section.
Open in Lab
MCP
gsap scrolltrigger lenis splittext playfair-display
Targets: JS HTML
Code
/* ═══════════════════════════════════════════════════════
MAISON DORÉE — Warm Editorial Style
Palette: Cream, Terracotta, Deep Brown, Gold
Fonts: Playfair Display (headlines), Cormorant Garamond (body), DM Sans (UI)
Feel: Luxury French restaurant, editorial magazine
═══════════════════════════════════════════════════════ */
:root {
--cream: #f5f0e8;
--cream-dark: #ede5d8;
--parchment: #e8ddc8;
--terracotta: #c1714a;
--terracotta-d: #a05a38;
--brown: #2c1a0e;
--brown-mid: #4a2e1a;
--gold: #c9a84c;
--gold-light: #e6c97a;
--charcoal: #1a1209;
--warm-gray: #7a6a58;
--warm-muted: #9a8878;
--font-display: "Playfair Display", Georgia, serif;
--font-body: "Cormorant Garamond", Georgia, serif;
--font-ui: "DM Sans", system-ui, sans-serif;
}
*,
*::before,
*::after {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html {
scroll-behavior: smooth;
}
body {
font-family: var(--font-body);
background: var(--cream);
color: var(--brown);
overflow-x: hidden;
font-size: 18px;
line-height: 1.7;
}
/* ── Navigation ── */
.nav {
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 100;
display: flex;
align-items: center;
justify-content: space-between;
padding: 1.5rem 3rem;
transition: all 0.4s ease;
}
.nav.scrolled {
background: rgba(245, 240, 232, 0.95);
backdrop-filter: blur(12px);
padding: 1rem 3rem;
border-bottom: 1px solid rgba(201, 168, 76, 0.2);
}
.nav-logo {
font-family: var(--font-display);
font-size: 1.4rem;
font-weight: 700;
color: var(--cream);
letter-spacing: 0.5px;
transition: color 0.4s ease;
}
.nav.scrolled .nav-logo {
color: var(--brown);
}
.nav-links {
list-style: none;
display: flex;
gap: 2.5rem;
}
.nav-links a {
font-family: var(--font-ui);
font-size: 0.8rem;
font-weight: 500;
letter-spacing: 1.5px;
text-transform: uppercase;
color: rgba(245, 240, 232, 0.8);
text-decoration: none;
transition: color 0.3s ease;
}
.nav.scrolled .nav-links a {
color: var(--warm-gray);
}
.nav-links a:hover {
color: var(--gold);
}
.nav.scrolled .nav-links a:hover {
color: var(--terracotta);
}
.nav-cta {
font-family: var(--font-ui);
font-size: 0.75rem;
font-weight: 500;
letter-spacing: 1.5px;
text-transform: uppercase;
color: var(--gold);
text-decoration: none;
border: 1px solid var(--gold);
padding: 0.5rem 1.2rem;
border-radius: 1px;
transition: all 0.3s ease;
}
.nav-cta:hover {
background: var(--gold);
color: var(--brown);
}
.nav.scrolled .nav-cta {
color: var(--terracotta);
border-color: var(--terracotta);
}
.nav.scrolled .nav-cta:hover {
background: var(--terracotta);
color: var(--cream);
}
/* ── Hero ── */
.hero {
position: relative;
height: 100vh;
min-height: 700px;
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
}
.hero-image {
position: absolute;
inset: 0;
background: linear-gradient(135deg, rgba(193, 113, 74, 0.3) 0%, rgba(44, 26, 14, 0.2) 100%),
radial-gradient(ellipse at 70% 40%, rgba(201, 168, 76, 0.15) 0%, transparent 60%);
background-color: var(--brown);
/* Simulated food photo with CSS gradients */
background-image: radial-gradient(
ellipse at 30% 60%,
rgba(201, 168, 76, 0.08) 0%,
transparent 50%
), radial-gradient(ellipse at 70% 30%, rgba(193, 113, 74, 0.12) 0%, transparent 50%),
linear-gradient(160deg, #1a0e06 0%, #2c1a0e 40%, #3a2010 70%, #1a0e06 100%);
}
.hero-overlay {
position: absolute;
inset: 0;
background: linear-gradient(
to bottom,
rgba(26, 18, 9, 0.3) 0%,
rgba(26, 18, 9, 0.1) 40%,
rgba(26, 18, 9, 0.6) 100%
);
}
.hero-content {
position: relative;
z-index: 2;
text-align: center;
max-width: 800px;
padding: 0 2rem;
}
.hero-pre {
font-family: var(--font-ui);
font-size: 0.72rem;
font-weight: 400;
letter-spacing: 3px;
text-transform: uppercase;
color: var(--gold-light);
margin-bottom: 2rem;
opacity: 0.9;
}
.hero-title {
font-family: var(--font-display);
font-size: clamp(3.5rem, 8vw, 7rem);
font-weight: 400;
line-height: 1.05;
color: var(--cream);
margin-bottom: 2rem;
display: flex;
flex-direction: column;
align-items: center;
gap: 0.1em;
}
.hero-title .line {
display: block;
overflow: hidden;
}
.hero-title .italic {
font-style: italic;
color: var(--gold-light);
}
.hero-desc {
font-family: var(--font-body);
font-size: 1.15rem;
font-weight: 300;
color: rgba(245, 240, 232, 0.75);
max-width: 500px;
margin: 0 auto 3rem;
line-height: 1.8;
}
.hero-actions {
display: flex;
gap: 1.5rem;
justify-content: center;
flex-wrap: wrap;
}
.btn-gold {
font-family: var(--font-ui);
font-size: 0.75rem;
font-weight: 500;
letter-spacing: 2px;
text-transform: uppercase;
text-decoration: none;
padding: 1rem 2.5rem;
background: var(--gold);
color: var(--brown);
border: none;
border-radius: 1px;
transition: all 0.3s ease;
display: inline-block;
}
.btn-gold:hover {
background: var(--gold-light);
transform: translateY(-1px);
box-shadow: 0 8px 24px rgba(201, 168, 76, 0.3);
}
.btn-ghost-warm {
font-family: var(--font-ui);
font-size: 0.75rem;
font-weight: 500;
letter-spacing: 2px;
text-transform: uppercase;
text-decoration: none;
padding: 1rem 2.5rem;
color: var(--cream);
border: 1px solid rgba(245, 240, 232, 0.3);
border-radius: 1px;
transition: all 0.3s ease;
display: inline-block;
}
.btn-ghost-warm:hover {
border-color: var(--gold);
color: var(--gold);
}
.btn-outline-warm {
font-family: var(--font-ui);
font-size: 0.75rem;
font-weight: 500;
letter-spacing: 1.5px;
text-transform: uppercase;
text-decoration: none;
padding: 0.8rem 2rem;
color: var(--terracotta);
border: 1px solid var(--terracotta);
border-radius: 1px;
transition: all 0.3s ease;
display: inline-block;
}
.btn-outline-warm:hover {
background: var(--terracotta);
color: var(--cream);
}
.hero-scroll {
position: absolute;
bottom: 3rem;
left: 50%;
transform: translateX(-50%);
display: flex;
flex-direction: column;
align-items: center;
gap: 0.8rem;
z-index: 2;
}
.scroll-line {
width: 1px;
height: 50px;
background: linear-gradient(to bottom, var(--gold), transparent);
animation: scrollPulse 2s ease-in-out infinite;
}
@keyframes scrollPulse {
0%,
100% {
opacity: 0.4;
transform: scaleY(1);
}
50% {
opacity: 0.9;
transform: scaleY(1.2);
}
}
.hero-scroll span {
font-family: var(--font-ui);
font-size: 0.6rem;
letter-spacing: 3px;
text-transform: uppercase;
color: var(--gold-light);
opacity: 0.6;
}
/* ── Section Shared ── */
.section-label {
display: block;
font-family: var(--font-ui);
font-size: 0.68rem;
font-weight: 500;
letter-spacing: 3px;
text-transform: uppercase;
color: var(--terracotta);
margin-bottom: 1.2rem;
}
/* ── Philosophy ── */
.philosophy-section {
padding: 8rem 2rem;
background: var(--brown);
position: relative;
overflow: hidden;
}
.philosophy-inner {
max-width: 900px;
margin: 0 auto;
display: grid;
grid-template-columns: 1fr 2fr;
gap: 4rem;
align-items: center;
}
.philosophy-deco {
position: relative;
}
.deco-circle {
width: 200px;
height: 200px;
border-radius: 50%;
border: 1px solid rgba(201, 168, 76, 0.2);
position: relative;
}
.deco-circle::after {
content: "";
position: absolute;
inset: 20px;
border-radius: 50%;
border: 1px solid rgba(201, 168, 76, 0.1);
}
.deco-line-h {
width: 60px;
height: 1px;
background: var(--gold);
margin-top: 2rem;
opacity: 0.4;
}
.philosophy-text h2 {
font-family: var(--font-display);
font-size: clamp(2rem, 4vw, 3.2rem);
font-weight: 400;
color: var(--cream);
line-height: 1.25;
margin-bottom: 0.5rem;
}
.philosophy-text h2 em {
font-style: italic;
color: var(--gold-light);
}
.attr {
font-family: var(--font-ui);
font-size: 0.75rem;
letter-spacing: 1.5px;
color: var(--warm-muted);
margin-bottom: 2rem;
}
.body-text {
font-family: var(--font-body);
font-size: 1.05rem;
font-weight: 300;
color: rgba(232, 221, 200, 0.7);
line-height: 1.9;
}
/* ── Menu ── */
.menu-section {
padding: 8rem 2rem;
background: var(--cream-dark);
}
.menu-header {
text-align: center;
max-width: 600px;
margin: 0 auto 5rem;
}
.menu-header h2 {
font-family: var(--font-display);
font-size: clamp(2.2rem, 4vw, 3.5rem);
font-weight: 400;
color: var(--brown);
margin-top: 0.5rem;
}
.menu-grid {
max-width: 1100px;
margin: 0 auto;
display: flex;
flex-direction: column;
gap: 0;
}
.menu-item {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 0;
border-top: 1px solid rgba(44, 26, 14, 0.12);
}
.menu-item:last-child {
border-bottom: 1px solid rgba(44, 26, 14, 0.12);
}
.menu-item--reverse {
direction: rtl;
}
.menu-item--reverse > * {
direction: ltr;
}
.menu-img {
height: 360px;
background-color: var(--brown-mid);
position: relative;
overflow: hidden;
}
.menu-img--1 {
background: linear-gradient(135deg, #3a1e0a 0%, #5a2e12 40%, #8a4a22 70%, #3a1e0a 100%);
}
.menu-img--2 {
background: linear-gradient(135deg, #1a1005 0%, #3a2010 40%, #6a3820 70%, #1a1005 100%);
}
.menu-img--3 {
background: linear-gradient(135deg, #2a1808 0%, #4a2810 40%, #7a4830 70%, #2a1808 100%);
}
.menu-img::after {
content: "";
position: absolute;
inset: 0;
background: radial-gradient(ellipse at 50% 50%, rgba(201, 168, 76, 0.08) 0%, transparent 70%);
}
.menu-info {
padding: 4rem 4rem;
display: flex;
flex-direction: column;
justify-content: center;
background: var(--cream);
}
.menu-course {
font-family: var(--font-ui);
font-size: 0.65rem;
font-weight: 500;
letter-spacing: 2.5px;
text-transform: uppercase;
color: var(--terracotta);
margin-bottom: 1rem;
}
.menu-info h3 {
font-family: var(--font-display);
font-size: 1.8rem;
font-weight: 400;
color: var(--brown);
margin-bottom: 1rem;
line-height: 1.2;
}
.menu-info p {
font-family: var(--font-body);
font-size: 1rem;
font-weight: 300;
color: var(--warm-gray);
line-height: 1.8;
margin-bottom: 2rem;
}
.menu-price {
font-family: var(--font-display);
font-size: 1.4rem;
font-weight: 400;
color: var(--gold);
letter-spacing: 1px;
}
.menu-footer {
text-align: center;
margin-top: 4rem;
padding-top: 3rem;
border-top: 1px solid rgba(44, 26, 14, 0.12);
}
.menu-footer p {
font-family: var(--font-body);
font-size: 1rem;
font-style: italic;
color: var(--warm-gray);
margin-bottom: 1.5rem;
}
/* ── Story ── */
.story-section {
padding: 8rem 2rem;
background: var(--parchment);
}
.story-grid {
max-width: 1100px;
margin: 0 auto;
display: grid;
grid-template-columns: 1fr 1fr;
gap: 6rem;
align-items: center;
}
.story-images {
position: relative;
}
.story-img {
border-radius: 2px;
}
.story-img--main {
width: 100%;
height: 500px;
background: linear-gradient(160deg, #2c1a0e 0%, #4a2e1a 40%, #6a3820 70%, #2c1a0e 100%);
}
.story-img--accent {
width: 55%;
height: 200px;
position: absolute;
bottom: -3rem;
right: -3rem;
background: linear-gradient(160deg, #c1714a 0%, #a05a38 50%, #c1714a 100%);
border: 4px solid var(--parchment);
}
.story-year {
position: absolute;
top: 2rem;
left: -2rem;
font-family: var(--font-display);
font-size: 5rem;
font-weight: 900;
color: rgba(201, 168, 76, 0.12);
line-height: 1;
pointer-events: none;
user-select: none;
}
.story-content .section-label {
margin-bottom: 1.5rem;
}
.story-content h2 {
font-family: var(--font-display);
font-size: clamp(2rem, 3.5vw, 2.8rem);
font-weight: 400;
color: var(--brown);
line-height: 1.2;
margin-bottom: 2rem;
}
.story-content p {
font-family: var(--font-body);
font-size: 1.05rem;
font-weight: 300;
color: var(--warm-gray);
line-height: 1.9;
margin-bottom: 1.5rem;
}
.story-awards {
display: flex;
gap: 2.5rem;
margin-top: 3rem;
padding-top: 2.5rem;
border-top: 1px solid rgba(44, 26, 14, 0.15);
}
.award {
display: flex;
flex-direction: column;
gap: 0.3rem;
}
.award-num {
font-family: var(--font-display);
font-size: 1.8rem;
font-weight: 700;
color: var(--terracotta);
line-height: 1;
}
.award span:last-child {
font-family: var(--font-ui);
font-size: 0.68rem;
font-weight: 400;
letter-spacing: 1px;
text-transform: uppercase;
color: var(--warm-muted);
}
/* ── Reservation ── */
.reservation-section {
padding: 8rem 2rem;
background: var(--brown);
text-align: center;
}
.res-inner {
max-width: 600px;
margin: 0 auto;
}
.reservation-section .section-label {
color: var(--gold);
}
.reservation-section h2 {
font-family: var(--font-display);
font-size: clamp(2.2rem, 4vw, 3.5rem);
font-weight: 400;
color: var(--cream);
margin-bottom: 1.5rem;
}
.reservation-section p {
font-family: var(--font-body);
font-size: 1.05rem;
font-weight: 300;
color: rgba(232, 221, 200, 0.65);
line-height: 1.8;
margin-bottom: 3rem;
}
.res-info {
display: flex;
flex-direction: column;
gap: 1rem;
margin-bottom: 3rem;
padding: 2.5rem;
border: 1px solid rgba(201, 168, 76, 0.2);
border-radius: 2px;
text-align: left;
}
.res-detail {
display: flex;
gap: 1rem;
align-items: baseline;
}
.res-label {
font-family: var(--font-ui);
font-size: 0.65rem;
letter-spacing: 1.5px;
text-transform: uppercase;
color: var(--gold);
min-width: 80px;
}
.res-detail span:last-child {
font-family: var(--font-body);
font-size: 1rem;
color: rgba(232, 221, 200, 0.75);
}
/* ── Footer ── */
.footer {
padding: 3rem 2rem;
background: var(--charcoal);
text-align: center;
border-top: 1px solid rgba(201, 168, 76, 0.1);
}
.footer-logo {
font-family: var(--font-display);
font-size: 1.5rem;
font-weight: 400;
color: var(--gold);
margin-bottom: 0.8rem;
}
.footer p {
font-family: var(--font-ui);
font-size: 0.8rem;
color: var(--warm-muted);
letter-spacing: 0.5px;
}
.footer-copy {
margin-top: 1rem;
font-size: 0.7rem !important;
color: rgba(122, 106, 88, 0.5) !important;
}
/* ── Responsive ── */
@media (max-width: 900px) {
.philosophy-inner {
grid-template-columns: 1fr;
gap: 3rem;
}
.philosophy-deco {
display: none;
}
.menu-item,
.menu-item--reverse {
grid-template-columns: 1fr;
direction: ltr;
}
.menu-img {
height: 250px;
}
.story-grid {
grid-template-columns: 1fr;
gap: 3rem;
}
.story-img--accent {
display: none;
}
.story-year {
display: none;
}
}
@media (max-width: 768px) {
.nav {
padding: 1rem 1.5rem;
}
.nav-links {
display: none;
}
.hero-title {
font-size: clamp(2.5rem, 10vw, 5rem);
}
.menu-info {
padding: 2.5rem 2rem;
}
.story-awards {
flex-direction: column;
gap: 1.5rem;
}
.res-info {
padding: 1.5rem;
}
}
html.reduced-motion * {
animation-duration: 0.01ms !important;
transition-duration: 0.01ms !important;
}if (!window.MotionPreference) {
const __mql = window.matchMedia("(prefers-reduced-motion: reduce)");
const __listeners = new Set();
const MotionPreference = {
prefersReducedMotion() {
return __mql.matches;
},
setOverride(value) {
const reduced = Boolean(value);
document.documentElement.classList.toggle("reduced-motion", reduced);
window.dispatchEvent(new CustomEvent("motion-preference", { detail: { reduced } }));
for (const listener of __listeners) {
try {
listener({ reduced, override: reduced, systemReduced: __mql.matches });
} catch {}
}
},
onChange(listener) {
__listeners.add(listener);
try {
listener({
reduced: __mql.matches,
override: null,
systemReduced: __mql.matches,
});
} catch {}
return () => __listeners.delete(listener);
},
getState() {
return { reduced: __mql.matches, override: null, systemReduced: __mql.matches };
},
};
window.MotionPreference = MotionPreference;
}
function prefersReducedMotion() {
return window.MotionPreference.prefersReducedMotion();
}
function initDemoShell() {
// No-op shim in imported standalone snippets.
}
import gsap from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";
import { SplitText } from "gsap/SplitText";
import Lenis from "lenis";
gsap.registerPlugin(ScrollTrigger, SplitText);
initDemoShell({
title: "Fine Dining Restaurant",
category: "pages",
tech: ["gsap", "splittext", "scrolltrigger", "lenis"],
});
const lenis = new Lenis({ lerp: 0.08, smoothWheel: true });
lenis.on("scroll", ScrollTrigger.update);
gsap.ticker.add((time) => lenis.raf(time * 1000));
gsap.ticker.lagSmoothing(0);
const reduced = prefersReducedMotion();
if (reduced) document.documentElement.classList.add("reduced-motion");
// ── Nav scroll effect ────────────────────────────────────
const nav = document.getElementById("nav");
ScrollTrigger.create({
start: "top -80",
onUpdate: (self) => {
nav.classList.toggle("scrolled", self.scroll() > 80);
},
});
// ── Hero entrance ────────────────────────────────────────
if (!reduced) {
gsap.set(".hero-pre", { opacity: 0, y: 15 });
gsap.set(".hero-desc", { opacity: 0, y: 20 });
gsap.set(".hero-actions", { opacity: 0, y: 20 });
gsap.set(".hero-scroll", { opacity: 0 });
const heroSplit = new SplitText(".hero-title .line", { type: "chars" });
gsap.set(heroSplit.chars, { opacity: 0, y: 60, rotationX: -30 });
const tl = gsap.timeline({ defaults: { ease: "expo.out" } });
tl.to(".hero-pre", { opacity: 1, y: 0, duration: 0.9, delay: 0.5 })
.to(heroSplit.chars, { opacity: 1, y: 0, rotationX: 0, duration: 1.2, stagger: 0.025 }, "-=0.5")
.to(".hero-desc", { opacity: 1, y: 0, duration: 0.9 }, "-=0.6")
.to(".hero-actions", { opacity: 1, y: 0, duration: 0.7 }, "-=0.5")
.to(".hero-scroll", { opacity: 1, duration: 0.6 }, "-=0.2");
}
// ── Hero parallax ─────────────────────────────────────────
if (!reduced) {
gsap.to(".hero-image", {
yPercent: 25,
ease: "none",
scrollTrigger: { trigger: ".hero", start: "top top", end: "bottom top", scrub: true },
});
gsap.to(".hero-content", {
yPercent: 15,
opacity: 0,
ease: "none",
scrollTrigger: { trigger: ".hero", start: "60% top", end: "bottom top", scrub: true },
});
}
// ── Philosophy ───────────────────────────────────────────
if (!reduced) {
gsap.set(".deco-circle", { scale: 0.6, opacity: 0 });
gsap.to(".deco-circle", {
scale: 1,
opacity: 1,
duration: 1.5,
ease: "expo.out",
scrollTrigger: { trigger: ".philosophy-section", start: "top 70%" },
});
const philSplit = new SplitText(".philosophy-text h2", { type: "lines" });
gsap.set(philSplit.lines, { opacity: 0, y: 40 });
gsap.to(philSplit.lines, {
opacity: 1,
y: 0,
duration: 1,
stagger: 0.15,
ease: "expo.out",
scrollTrigger: {
trigger: ".philosophy-text",
start: "top 70%",
toggleActions: "play none none reverse",
},
});
gsap.set(".attr, .body-text", { opacity: 0, y: 20 });
gsap.to(".attr, .body-text", {
opacity: 1,
y: 0,
duration: 0.8,
stagger: 0.2,
ease: "expo.out",
scrollTrigger: {
trigger: ".philosophy-text",
start: "top 65%",
toggleActions: "play none none reverse",
},
});
}
// ── Menu items stagger ───────────────────────────────────
document.querySelectorAll(".menu-item").forEach((item, i) => {
if (!reduced) {
gsap.set(item, { opacity: 0, y: 50 });
gsap.to(item, {
opacity: 1,
y: 0,
duration: 1,
ease: "expo.out",
scrollTrigger: { trigger: item, start: "top 80%", toggleActions: "play none none reverse" },
});
// Image parallax within item
const img = item.querySelector(".menu-img");
if (img) {
gsap.to(img, {
yPercent: -10,
ease: "none",
scrollTrigger: { trigger: item, start: "top bottom", end: "bottom top", scrub: true },
});
}
}
});
// Menu header
if (!reduced) {
gsap.set(".menu-header .section-label, .menu-header h2", { opacity: 0, y: 30 });
gsap.to(".menu-header .section-label, .menu-header h2", {
opacity: 1,
y: 0,
duration: 0.9,
stagger: 0.15,
ease: "expo.out",
scrollTrigger: {
trigger: ".menu-header",
start: "top 75%",
toggleActions: "play none none reverse",
},
});
}
// ── Story section ────────────────────────────────────────
if (!reduced) {
// Images reveal
gsap.set(".story-img--main", { opacity: 0, scale: 1.05 });
gsap.to(".story-img--main", {
opacity: 1,
scale: 1,
duration: 1.3,
ease: "expo.out",
scrollTrigger: {
trigger: ".story-grid",
start: "top 70%",
toggleActions: "play none none reverse",
},
});
gsap.set(".story-img--accent", { opacity: 0, x: 30 });
gsap.to(".story-img--accent", {
opacity: 1,
x: 0,
duration: 1,
delay: 0.3,
ease: "expo.out",
scrollTrigger: {
trigger: ".story-grid",
start: "top 70%",
toggleActions: "play none none reverse",
},
});
// Story year parallax
gsap.to(".story-year", {
yPercent: -20,
ease: "none",
scrollTrigger: {
trigger: ".story-section",
start: "top bottom",
end: "bottom top",
scrub: true,
},
});
// Text reveal
const storySplit = new SplitText(".story-content h2", { type: "lines" });
gsap.set(storySplit.lines, { opacity: 0, y: 30 });
gsap.to(storySplit.lines, {
opacity: 1,
y: 0,
duration: 0.9,
stagger: 0.12,
ease: "expo.out",
scrollTrigger: {
trigger: ".story-content",
start: "top 75%",
toggleActions: "play none none reverse",
},
});
gsap.set(".story-content p", { opacity: 0, y: 20 });
gsap.to(".story-content p", {
opacity: 1,
y: 0,
duration: 0.8,
stagger: 0.15,
ease: "expo.out",
scrollTrigger: {
trigger: ".story-content",
start: "top 70%",
toggleActions: "play none none reverse",
},
});
// Awards counter reveal
gsap.set(".award", { opacity: 0, y: 25 });
gsap.to(".award", {
opacity: 1,
y: 0,
duration: 0.7,
stagger: 0.1,
ease: "back.out(1.5)",
scrollTrigger: {
trigger: ".story-awards",
start: "top 80%",
toggleActions: "play none none reverse",
},
});
}
// ── Reservation ──────────────────────────────────────────
if (!reduced) {
gsap.set(".res-inner > *", { opacity: 0, y: 30 });
gsap.to(".res-inner > *", {
opacity: 1,
y: 0,
duration: 0.8,
stagger: 0.12,
ease: "expo.out",
scrollTrigger: {
trigger: ".reservation-section",
start: "top 70%",
toggleActions: "play none none reverse",
},
});
}
// ── Motion preference ────────────────────────────────────
window.addEventListener("motion-preference", (e) => {
gsap.globalTimeline.paused(e.detail.reduced);
});<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Maison Dorée — Fine Dining</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Playfair+Display:ital,wght@0,400;0,700;0,900;1,400;1,700&family=Cormorant+Garamond:ital,wght@0,300;0,400;1,300;1,400&family=DM+Sans:wght@300;400;500&display=swap" rel="stylesheet">
<link rel="stylesheet" href="style.css">
<script type="importmap">{"imports":{"gsap":"https://esm.sh/gsap@3.13.0","gsap/ScrollTrigger":"https://esm.sh/gsap@3.13.0/ScrollTrigger","gsap/SplitText":"https://esm.sh/gsap@3.13.0/SplitText","gsap/Flip":"https://esm.sh/gsap@3.13.0/Flip","gsap/ScrambleTextPlugin":"https://esm.sh/gsap@3.13.0/ScrambleTextPlugin","gsap/TextPlugin":"https://esm.sh/gsap@3.13.0/TextPlugin","gsap/all":"https://esm.sh/gsap@3.13.0/all","gsap/":"https://esm.sh/gsap@3.13.0/","lenis":"https://esm.sh/lenis@1.1.13/dist/lenis.mjs","three":"https://esm.sh/three@0.171.0","three/addons/":"https://esm.sh/three@0.171.0/examples/jsm/"}}</script>
<style>html.lenis,
html.lenis body {
height: auto;
}
.lenis:not(.lenis-autoToggle).lenis-stopped {
overflow: clip;
}
.lenis [data-lenis-prevent],
.lenis [data-lenis-prevent-wheel],
.lenis [data-lenis-prevent-touch] {
overscroll-behavior: contain;
}
.lenis.lenis-smooth iframe {
pointer-events: none;
}
.lenis.lenis-autoToggle {
transition-property: overflow;
transition-duration: 1ms;
transition-behavior: allow-discrete;
}</style>
</head>
<body>
<!-- Nav -->
<nav class="nav" id="nav">
<div class="nav-logo">Maison Dorée</div>
<ul class="nav-links">
<li><a href="#menu">Menu</a></li>
<li><a href="#story">Notre Histoire</a></li>
<li><a href="#reservation">Réserver</a></li>
</ul>
<a href="#reservation" class="nav-cta">Book a Table</a>
</nav>
<!-- Hero -->
<section class="hero" id="hero">
<div class="hero-image" aria-hidden="true">
<div class="hero-overlay"></div>
</div>
<div class="hero-content">
<p class="hero-pre">Est. 1987 · Paris · 2 Michelin Stars</p>
<h1 class="hero-title">
<span class="line">An evening of</span>
<span class="line italic">extraordinary</span>
<span class="line">pleasure</span>
</h1>
<p class="hero-desc">Where French culinary tradition meets the poetry of the seasons. Chef Laurent Beaumont invites you to a table unlike any other.</p>
<div class="hero-actions">
<a href="#reservation" class="btn-gold">Reserve Your Table</a>
<a href="#menu" class="btn-ghost-warm">Explore the Menu</a>
</div>
</div>
<div class="hero-scroll" aria-hidden="true">
<div class="scroll-line"></div>
<span>Scroll</span>
</div>
</section>
<!-- Philosophy -->
<section class="philosophy-section">
<div class="philosophy-inner">
<div class="philosophy-deco" aria-hidden="true">
<div class="deco-circle"></div>
<div class="deco-line-h"></div>
</div>
<div class="philosophy-text">
<span class="section-label">Notre Philosophie</span>
<h2>"Cooking is the art of<br><em>adjusting</em>"</h2>
<p class="attr">— Auguste Escoffier</p>
<p class="body-text">At Maison Dorée, each dish begins with a walk through the market at dawn. The menu changes with the light — a living expression of what is freshest, most beautiful, most true to the moment. We do not follow trends. We follow nature.</p>
</div>
</div>
</section>
<!-- Menu Highlights -->
<section class="menu-section" id="menu">
<div class="menu-header">
<span class="section-label">Carte du Soir</span>
<h2>This Season's Menu</h2>
</div>
<div class="menu-grid">
<div class="menu-item">
<div class="menu-img menu-img--1" aria-hidden="true"></div>
<div class="menu-info">
<div class="menu-course">Entrée</div>
<h3>Foie Gras de Canard</h3>
<p>Sauternes gelée, brioche perdue, fig compote, microgreens from our garden</p>
<div class="menu-price">€ 38</div>
</div>
</div>
<div class="menu-item menu-item--reverse">
<div class="menu-img menu-img--2" aria-hidden="true"></div>
<div class="menu-info">
<div class="menu-course">Plat Principal</div>
<h3>Pigeon Rôti en Croûte</h3>
<p>Truffle jus, celeriac purée, chanterelles, Périgord black truffle shavings</p>
<div class="menu-price">€ 72</div>
</div>
</div>
<div class="menu-item">
<div class="menu-img menu-img--3" aria-hidden="true"></div>
<div class="menu-info">
<div class="menu-course">Dessert</div>
<h3>Soufflé Grand Marnier</h3>
<p>Bittersweet chocolate sauce, candied orange peel, crème chantilly</p>
<div class="menu-price">€ 24</div>
</div>
</div>
</div>
<div class="menu-footer">
<p>Tasting menu available nightly — 7 courses with wine pairing</p>
<a href="#" class="btn-outline-warm">View Full Menu →</a>
</div>
</section>
<!-- Story -->
<section class="story-section" id="story">
<div class="story-grid">
<div class="story-images" aria-hidden="true">
<div class="story-img story-img--main"></div>
<div class="story-img story-img--accent"></div>
<div class="story-year">1987</div>
</div>
<div class="story-content">
<span class="section-label">Notre Histoire</span>
<h2>Three generations of passion</h2>
<p>Maison Dorée was born in the winter of 1987 when Jean-Pierre Beaumont opened his first restaurant on Rue Saint-Honoré. His son Laurent took the helm in 2009, earning a second Michelin star in 2014. Today, granddaughter Élise brings her training from Tokyo and Copenhagen to the pastry kitchen.</p>
<p>The dining room has seen heads of state, celebrated artists, quiet first dates, and last anniversary dinners. Every guest is treated as family.</p>
<div class="story-awards">
<div class="award"><span class="award-num">★★</span><span>Michelin Stars</span></div>
<div class="award"><span class="award-num">37</span><span>Years of service</span></div>
<div class="award"><span class="award-num">12</span><span>Sommelier awards</span></div>
</div>
</div>
</div>
</section>
<!-- Reservation -->
<section class="reservation-section" id="reservation">
<div class="res-inner">
<span class="section-label">Réservations</span>
<h2>Reserve your evening</h2>
<p>We welcome guests Tuesday through Sunday from 19h00. The dining room seats 38. For parties of six or more, please contact us directly.</p>
<div class="res-info">
<div class="res-detail">
<span class="res-label">Address</span>
<span>14 Rue Saint-Honoré, Paris 75001</span>
</div>
<div class="res-detail">
<span class="res-label">Phone</span>
<span>+33 1 42 96 00 14</span>
</div>
<div class="res-detail">
<span class="res-label">Hours</span>
<span>Tue–Sun · 19:00–23:30</span>
</div>
</div>
<a href="#" class="btn-gold">Make a Reservation</a>
</div>
</section>
<!-- Footer -->
<footer class="footer">
<div class="footer-logo">Maison Dorée</div>
<p>14 Rue Saint-Honoré · Paris · +33 1 42 96 00 14</p>
<p class="footer-copy">© 2025 Maison Dorée. All rights reserved.</p>
</footer>
<script type="module" src="script.js"></script>
</body>
</html>Fine Dining Restaurant
Warm editorial restaurant page with cream/terracotta palette, Playfair Display serif typography, SplitText char-by-char hero entrance, menu section with parallax images, and a vintage story section.
Source
- Repository:
libs-genclaude - Original demo id:
44-restaurant-fine-dining
Notes
Warm editorial restaurant page with cream/terracotta palette, Playfair Display serif typography, SplitText char-by-char hero entrance, menu section with parallax images, and a vintage story section.