Pages Medium
Restaurant Landing Page
Generic restaurant landing — sticky nav, editorial hero, signature dishes, chef story, hours strip, and a reserve CTA in the shared warm Casa Olivar palette.
Open in Lab
MCP
html css vanilla-js
Targets: JS HTML
Code
:root {
--cream: #f5f0e8;
--cream-2: #ece4d4;
--bone: #faf7f1;
--terracotta: #c1714a;
--terracotta-d: #a05a38;
--forest: #2d4a3e;
--forest-d: #1e3329;
--gold: #c9a84c;
--gold-light: #e6c97a;
--ink: #2c1a0e;
--ink-2: #4a3828;
--warm-gray: #7a6a58;
--success: #4f7a3a;
--danger: #b3432a;
--warning: #d99020;
--font-display: "Playfair Display", Georgia, serif;
--font-body: "Inter", system-ui, sans-serif;
--font-mono: "JetBrains Mono", ui-monospace, monospace;
--r-sm: 6px;
--r-md: 10px;
--r-lg: 16px;
--shadow-1: 0 1px 2px rgba(44, 26, 14, 0.08), 0 2px 6px rgba(44, 26, 14, 0.06);
--shadow-2: 0 8px 24px rgba(44, 26, 14, 0.12);
}
*,
*::before,
*::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
html {
scroll-behavior: smooth;
}
body {
font-family: var(--font-body);
background: var(--cream);
color: var(--ink);
line-height: 1.6;
-webkit-font-smoothing: antialiased;
}
/* ── Nav ── */
.nav {
position: sticky;
top: 0;
z-index: 20;
display: flex;
align-items: center;
gap: 24px;
padding: 14px 28px;
background: rgba(245, 240, 232, 0.85);
backdrop-filter: saturate(140%) blur(10px);
border-bottom: 1px solid rgba(44, 26, 14, 0.06);
}
.nav-brand {
font-family: var(--font-display);
font-weight: 800;
font-size: 1.1rem;
letter-spacing: -0.005em;
color: var(--ink);
text-decoration: none;
}
.nav-links {
display: flex;
gap: 18px;
margin-left: auto;
}
.nav-links a {
color: var(--ink-2);
text-decoration: none;
font-size: 0.86rem;
font-weight: 600;
letter-spacing: 0.02em;
transition: color 0.15s;
}
.nav-links a:hover {
color: var(--terracotta);
}
.nav-cta {
background: var(--forest);
color: var(--bone);
border-radius: 999px;
padding: 9px 16px;
font-size: 0.84rem;
font-weight: 700;
text-decoration: none;
transition: background 0.15s;
}
.nav-cta:hover {
background: var(--forest-d);
}
@media (max-width: 720px) {
.nav-links {
display: none;
}
}
/* ── Hero ── */
.hero {
display: grid;
grid-template-columns: 1.05fr 1fr;
gap: 40px;
align-items: center;
padding: 56px 28px 80px;
max-width: 1180px;
margin: 0 auto;
}
.hero-inner {
display: flex;
flex-direction: column;
gap: 16px;
max-width: 540px;
}
.kicker {
font-size: 0.72rem;
text-transform: uppercase;
letter-spacing: 0.18em;
color: var(--terracotta);
font-weight: 600;
}
.hero-title {
font-family: var(--font-display);
font-weight: 700;
font-size: clamp(2.6rem, 6vw, 4.4rem);
line-height: 1.02;
letter-spacing: -0.02em;
color: var(--ink);
}
.hero-title em {
font-style: italic;
color: var(--terracotta-d);
font-weight: 500;
}
.hero-sub {
font-size: 1.05rem;
color: var(--ink-2);
max-width: 460px;
}
.hero-cta {
display: flex;
gap: 10px;
margin-top: 8px;
flex-wrap: wrap;
}
.btn-primary,
.btn-ghost {
border-radius: 999px;
padding: 13px 22px;
font-size: 0.92rem;
font-weight: 700;
text-decoration: none;
display: inline-flex;
align-items: center;
cursor: pointer;
font-family: inherit;
border: 1px solid transparent;
transition: background 0.15s, color 0.15s, border-color 0.15s;
}
.btn-primary {
background: var(--forest);
color: var(--bone);
}
.btn-primary:hover {
background: var(--forest-d);
}
.btn-ghost {
background: transparent;
color: var(--ink);
border-color: rgba(44, 26, 14, 0.2);
}
.btn-ghost:hover {
background: var(--bone);
border-color: var(--terracotta);
color: var(--terracotta-d);
}
.hero-meta {
display: grid;
grid-template-columns: repeat(3, auto);
gap: 18px;
margin-top: 18px;
}
.hero-meta div {
display: flex;
flex-direction: column;
gap: 2px;
}
.hero-meta dt {
font-size: 0.66rem;
letter-spacing: 0.14em;
text-transform: uppercase;
color: var(--warm-gray);
font-weight: 700;
}
.hero-meta dd {
font-size: 0.86rem;
font-weight: 600;
color: var(--ink);
}
@media (max-width: 720px) {
.hero {
grid-template-columns: 1fr;
}
.hero-meta {
grid-template-columns: 1fr;
gap: 8px;
}
}
.hero-art {
position: relative;
height: 420px;
}
.plate {
position: absolute;
border-radius: 999px;
display: grid;
place-items: center;
font-size: 4rem;
box-shadow: var(--shadow-2);
border: 1px solid rgba(44, 26, 14, 0.08);
}
.plate-1 {
width: 240px;
height: 240px;
top: 20px;
left: 14%;
background: radial-gradient(circle at 30% 30%, var(--bone), var(--cream-2));
animation: float 6s ease-in-out infinite;
}
.plate-2 {
width: 160px;
height: 160px;
bottom: 30px;
right: 12%;
background: radial-gradient(circle at 70% 30%, var(--cream-2), var(--gold-light));
animation: float 7s ease-in-out infinite reverse;
}
.plate-3 {
width: 120px;
height: 120px;
top: 60px;
right: 30%;
background: radial-gradient(circle at 50% 30%, var(--bone), var(--cream));
animation: float 8s ease-in-out infinite;
}
@keyframes float {
0%,
100% {
transform: translateY(0);
}
50% {
transform: translateY(-12px);
}
}
@media (max-width: 720px) {
.hero-art {
display: none;
}
}
/* ── Strip ── */
.strip {
background: var(--forest);
color: var(--bone);
text-align: center;
padding: 12px 16px;
font-size: 0.86rem;
letter-spacing: 0.06em;
}
.strip em {
color: var(--gold-light);
font-style: normal;
font-weight: 700;
margin: 0 6px;
}
.strip-star {
color: var(--gold);
margin: 0 12px;
}
/* ── Section base ── */
.section,
.story,
.visit,
.reserve {
max-width: 1080px;
margin: 0 auto;
padding: 80px 28px;
scroll-margin-top: 70px;
}
.section-head {
text-align: center;
margin-bottom: 36px;
}
.section-head h2 {
font-family: var(--font-display);
font-size: clamp(1.8rem, 4vw, 2.8rem);
font-weight: 700;
letter-spacing: -0.015em;
margin-top: 6px;
}
/* ── Dishes ── */
.dishes {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
gap: 16px;
}
.dish {
position: relative;
background: var(--bone);
border: 1px solid rgba(44, 26, 14, 0.08);
border-radius: var(--r-lg);
padding: 22px 20px 18px;
display: flex;
flex-direction: column;
gap: 8px;
transition: transform 0.18s, box-shadow 0.18s;
}
.dish:hover {
transform: translateY(-3px);
box-shadow: var(--shadow-2);
}
.dish-glyph {
font-size: 2rem;
filter: drop-shadow(0 4px 8px rgba(44, 26, 14, 0.18));
}
.dish h3 {
font-family: var(--font-display);
font-size: 1.15rem;
font-weight: 700;
letter-spacing: -0.005em;
}
.dish p {
font-size: 0.88rem;
color: var(--ink-2);
flex: 1;
}
.dish-price {
font-family: var(--font-mono);
font-weight: 700;
font-size: 0.95rem;
color: var(--terracotta-d);
}
.dish-feat {
background: linear-gradient(180deg, var(--bone) 0%, var(--cream) 100%);
border-color: var(--gold);
}
.dish-badge {
position: absolute;
top: 14px;
right: 14px;
background: var(--gold);
color: var(--ink);
font-size: 0.62rem;
font-weight: 700;
letter-spacing: 0.12em;
text-transform: uppercase;
padding: 4px 9px;
border-radius: 999px;
}
.section-cta {
display: inline-block;
margin-top: 32px;
font-weight: 700;
color: var(--terracotta-d);
text-decoration: none;
border-bottom: 1px solid currentColor;
padding-bottom: 2px;
}
.section-cta:hover {
color: var(--ink);
}
.section .section-cta {
display: block;
text-align: center;
}
/* ── Story ── */
.story {
display: grid;
grid-template-columns: 1fr 1.2fr;
gap: 56px;
align-items: center;
}
@media (max-width: 720px) {
.story {
grid-template-columns: 1fr;
gap: 28px;
}
}
.story-art {
position: relative;
height: 380px;
}
.story-photo {
position: absolute;
border-radius: var(--r-md);
box-shadow: var(--shadow-2);
}
.story-photo-1 {
width: 60%;
height: 60%;
top: 0;
left: 0;
background: linear-gradient(135deg, var(--terracotta) 0%, var(--gold) 100%);
}
.story-photo-2 {
width: 50%;
height: 55%;
bottom: 8%;
right: 0;
background: linear-gradient(135deg, var(--forest) 0%, var(--forest-d) 100%);
}
.story-photo-3 {
width: 36%;
height: 30%;
bottom: 0;
left: 18%;
background: linear-gradient(135deg, var(--gold-light) 0%, var(--cream-2) 100%);
}
.story-body {
display: flex;
flex-direction: column;
gap: 12px;
}
.story-body h2 {
font-family: var(--font-display);
font-size: clamp(1.6rem, 3.5vw, 2.4rem);
font-weight: 700;
letter-spacing: -0.015em;
line-height: 1.1;
}
.story-body p {
color: var(--ink-2);
font-size: 1rem;
}
.awards {
margin-top: 14px;
display: flex;
flex-direction: column;
gap: 8px;
}
.awards div {
display: flex;
align-items: baseline;
gap: 12px;
font-size: 0.88rem;
}
.awards dt {
color: var(--gold);
font-family: var(--font-display);
font-size: 1.1rem;
}
.awards dd {
color: var(--ink-2);
font-weight: 500;
}
/* ── Visit ── */
.visit-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 16px;
}
@media (max-width: 640px) {
.visit-grid {
grid-template-columns: 1fr;
}
}
.visit-card {
background: var(--bone);
border: 1px solid rgba(44, 26, 14, 0.08);
border-radius: var(--r-md);
padding: 24px 26px;
}
.visit-card h3 {
font-family: var(--font-display);
font-size: 1.2rem;
margin-bottom: 14px;
letter-spacing: -0.005em;
}
.visit-card ul {
list-style: none;
}
.visit-card li {
display: flex;
justify-content: space-between;
padding: 7px 0;
border-bottom: 1px dashed rgba(44, 26, 14, 0.12);
font-size: 0.9rem;
color: var(--ink-2);
}
.visit-card li span:last-child {
color: var(--ink);
font-weight: 600;
font-variant-numeric: tabular-nums;
}
.visit-card li.closed span:last-child {
color: var(--warm-gray);
}
.visit-card address {
font-style: normal;
font-size: 0.95rem;
color: var(--ink-2);
line-height: 1.7;
}
.visit-note {
margin-top: 14px;
padding-top: 14px;
border-top: 1px dashed rgba(44, 26, 14, 0.12);
font-size: 0.84rem;
color: var(--warm-gray);
font-style: italic;
}
/* ── Reserve ── */
.reserve {
text-align: center;
background: var(--forest);
color: var(--bone);
border-radius: var(--r-lg);
margin: 24px 28px 64px;
padding: 60px 28px;
max-width: none;
}
.reserve h2 {
font-family: var(--font-display);
font-size: clamp(1.8rem, 4vw, 2.6rem);
font-weight: 700;
letter-spacing: -0.015em;
}
.reserve p {
color: var(--gold-light);
margin-top: 8px;
font-size: 0.95rem;
}
.reserve-form {
margin: 28px auto 0;
max-width: 720px;
display: grid;
grid-template-columns: repeat(2, 1fr) auto;
gap: 10px;
align-items: end;
}
.reserve-form label {
display: flex;
flex-direction: column;
gap: 4px;
font-size: 0.74rem;
letter-spacing: 0.1em;
text-transform: uppercase;
color: var(--gold-light);
font-weight: 700;
text-align: left;
}
.reserve-form select,
.reserve-form input {
background: var(--bone);
border: 1px solid rgba(250, 247, 241, 0.16);
color: var(--ink);
font-family: inherit;
font-size: 0.94rem;
padding: 11px 14px;
border-radius: var(--r-md);
outline: none;
}
.reserve-form select:focus,
.reserve-form input:focus {
border-color: var(--gold);
}
.reserve-form .btn-primary {
background: var(--gold);
color: var(--ink);
height: 47px;
padding: 0 24px;
}
.reserve-form .btn-primary:hover {
background: var(--gold-light);
}
.reserve-confirm {
margin-top: 16px;
font-weight: 700;
color: var(--gold-light);
}
@media (max-width: 720px) {
.reserve-form {
grid-template-columns: 1fr 1fr;
}
.reserve-form .btn-primary {
grid-column: 1 / -1;
}
}
/* ── Footer ── */
.footer {
border-top: 1px solid rgba(44, 26, 14, 0.08);
background: var(--bone);
}
.footer-inner {
max-width: 1080px;
margin: 0 auto;
padding: 32px 28px;
text-align: center;
}
.footer-brand {
font-family: var(--font-display);
font-size: 1.4rem;
font-weight: 800;
letter-spacing: -0.005em;
}
.footer-meta {
font-size: 0.84rem;
color: var(--warm-gray);
margin-top: 4px;
}// Default reservation date to tomorrow
const dateInput = document.querySelector('input[name="date"]');
if (dateInput) {
const t = new Date();
t.setDate(t.getDate() + 1);
dateInput.value = t.toISOString().slice(0, 10);
}
// Reserve form: faux submit + confirmation pill
const form = document.getElementById("reserveForm");
const confirmEl = document.getElementById("reserveConfirm");
form.addEventListener("submit", (e) => {
e.preventDefault();
confirmEl.hidden = false;
const btn = form.querySelector("button");
const originalText = btn.textContent;
btn.textContent = "Reserved ✓";
btn.disabled = true;
setTimeout(() => {
btn.textContent = originalText;
btn.disabled = false;
confirmEl.hidden = true;
}, 3000);
});
// Sticky nav: shadow on scroll
const nav = document.getElementById("nav");
const onScroll = () => {
if (window.scrollY > 8) nav.style.boxShadow = "0 2px 14px rgba(44, 26, 14, 0.08)";
else nav.style.boxShadow = "";
};
window.addEventListener("scroll", onScroll, { passive: true });
onScroll();<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
rel="stylesheet"
href="https://fonts.googleapis.com/css2?family=Playfair+Display:wght@400;500;700;800&family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@500;700&display=swap"
/>
<link rel="stylesheet" href="style.css" />
<title>Casa Olivar · Stone-fired cooking</title>
</head>
<body>
<header class="nav" id="nav">
<a class="nav-brand" href="#top">Casa Olivar</a>
<nav class="nav-links" aria-label="Main">
<a href="#menu">Menu</a>
<a href="#story">Story</a>
<a href="#visit">Visit</a>
<a href="#reserve">Reserve</a>
</nav>
<a class="nav-cta" href="#reserve">Reserve a table</a>
</header>
<main id="top">
<!-- ── Hero ── -->
<section class="hero">
<div class="hero-inner">
<p class="kicker">Stone-fired · Garden · Natural wine</p>
<h1 class="hero-title">
Honest cooking,<br />
<em>plated quietly.</em>
</h1>
<p class="hero-sub">
A neighbourhood dining room in Madrid serving stone-fired cooking,
garden produce, and natural wine. Six nights a week, since 2017.
</p>
<div class="hero-cta">
<a class="btn-primary" href="#reserve">Reserve a table</a>
<a class="btn-ghost" href="#menu">See the carta</a>
</div>
<dl class="hero-meta">
<div><dt>Open</dt><dd>Tue–Sun · 19:00–23:00</dd></div>
<div><dt>Address</dt><dd>42 Calle del Olivar, Madrid</dd></div>
<div><dt>Average</dt><dd>$48–72 per guest</dd></div>
</dl>
</div>
<div class="hero-art" aria-hidden="true">
<div class="plate plate-1"><span>🥩</span></div>
<div class="plate plate-2"><span>🍷</span></div>
<div class="plate plate-3"><span>🌿</span></div>
</div>
</section>
<!-- ── Featured strip ── -->
<section class="strip">
<p>
<span class="strip-star">★</span> Featured in
<em>El País</em> · <em>Eater Madrid</em> · <em>Time Out</em>
<span class="strip-star">★</span>
</p>
</section>
<!-- ── Signature dishes ── -->
<section class="section" id="menu">
<header class="section-head">
<p class="kicker">Signature dishes</p>
<h2>What we cook.</h2>
</header>
<div class="dishes">
<article class="dish">
<span class="dish-glyph" aria-hidden="true">🥖</span>
<h3>Pan de masa madre</h3>
<p>Sourdough baked daily, smoked olive oil, Maldon salt.</p>
<span class="dish-price">$8</span>
</article>
<article class="dish dish-feat">
<span class="dish-glyph" aria-hidden="true">🥩</span>
<span class="dish-badge">Signature</span>
<h3>Ribeye 14oz</h3>
<p>Dry-aged 28 days, bone marrow butter, house chimichurri.</p>
<span class="dish-price">$48</span>
</article>
<article class="dish">
<span class="dish-glyph" aria-hidden="true">🐟</span>
<h3>Branzino entero</h3>
<p>Whole roasted sea bass, fennel, preserved lemon.</p>
<span class="dish-price">$38</span>
</article>
<article class="dish">
<span class="dish-glyph" aria-hidden="true">🍰</span>
<h3>Tarta de queso quemada</h3>
<p>Basque-style burnt cheesecake, salted caramel.</p>
<span class="dish-price">$11</span>
</article>
</div>
<a class="section-cta" href="#reserve">See the full carta →</a>
</section>
<!-- ── Story ── -->
<section class="story" id="story">
<div class="story-art" aria-hidden="true">
<div class="story-photo story-photo-1"></div>
<div class="story-photo story-photo-2"></div>
<div class="story-photo story-photo-3"></div>
</div>
<div class="story-body">
<p class="kicker">Our story</p>
<h2>A garden, a fire, a table for thirty.</h2>
<p>
Casa Olivar opened in 2017 in a converted carriage house on Calle
del Olivar. The kitchen is built around a single wood-fired hearth
and a half-hectare garden in Aravaca that supplies the herbs,
tomatoes, and figs from May through October.
</p>
<p>
Our menu changes weekly with what the garden gives us. The
constants are a hand-cut pasta, a whole grilled fish, and a
dry-aged steak — finished with whatever herb is loudest that
morning.
</p>
<dl class="awards">
<div><dt>★</dt><dd>Michelin Bib Gourmand · 2023, 2024</dd></div>
<div><dt>★</dt><dd>Top 50 Madrid Restaurants · Eater</dd></div>
<div><dt>★</dt><dd>Best Wine List, Spain · World of Fine Wine</dd></div>
</dl>
</div>
</section>
<!-- ── Visit ── -->
<section class="visit" id="visit">
<header class="section-head">
<p class="kicker">Visit</p>
<h2>Find us.</h2>
</header>
<div class="visit-grid">
<article class="visit-card">
<h3>Hours</h3>
<ul>
<li><span>Tuesday</span><span>19:00 – 23:00</span></li>
<li><span>Wed – Fri</span><span>19:00 – 23:30</span></li>
<li><span>Saturday</span><span>13:00 – 16:00 · 19:00 – 23:30</span></li>
<li><span>Sunday</span><span>13:00 – 16:00</span></li>
<li class="closed"><span>Monday</span><span>Closed</span></li>
</ul>
</article>
<article class="visit-card">
<h3>Address</h3>
<address>
42 Calle del Olivar<br />
28012 Madrid · Spain<br />
+34 910 555 042<br />
hola@casaolivar.es
</address>
<p class="visit-note">
Metro Antón Martín · 4 min walk. Two patio tables available
May–October.
</p>
</article>
</div>
</section>
<!-- ── Reserve ── -->
<section class="reserve" id="reserve">
<h2>Reserve a table.</h2>
<p>Bookings open 30 days in advance. We hold tables for 15 min.</p>
<form class="reserve-form" id="reserveForm" novalidate>
<label>
<span>Guests</span>
<select name="guests">
<option>2 guests</option>
<option>3 guests</option>
<option>4 guests</option>
<option>5 guests</option>
<option>6 guests</option>
<option>7+ (we'll call)</option>
</select>
</label>
<label>
<span>Date</span>
<input type="date" name="date" />
</label>
<label>
<span>Time</span>
<select name="time">
<option>19:00</option>
<option>19:30</option>
<option selected>20:00</option>
<option>20:30</option>
<option>21:00</option>
<option>21:30</option>
</select>
</label>
<label>
<span>Email</span>
<input type="email" name="email" placeholder="you@example.com" />
</label>
<button class="btn-primary" type="submit">Reserve</button>
</form>
<p class="reserve-confirm" id="reserveConfirm" hidden>
✓ Held — confirmation sent to your email.
</p>
</section>
</main>
<footer class="footer">
<div class="footer-inner">
<p class="footer-brand">Casa Olivar</p>
<p class="footer-meta">
42 Calle del Olivar · Madrid · +34 910 555 042
</p>
<p class="footer-meta">© 2026 · Crafted with stone and fire</p>
</div>
</footer>
<script src="script.js"></script>
</body>
</html>Restaurant Landing Page
A scrollable single-page landing for a neighbourhood restaurant. Sticky nav with anchor links, full-bleed hero with concept-specific gradient, signature dishes block, chef story alongside an awards column, hours strip, and a reserve CTA pinned at the bottom of the page.
Sits in the shared warm palette so it composes naturally with the operations + customer surfaces. The 5 themed dinner landings in Section 27.F override the palette per concept.