Pages Easy
Private Events & Catering
Private dining and catering page — three package cards with capacity, sample menu, capacity table, FAQ accordion and an enquiry form with availability hint.
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;
}
body {
font-family: var(--font-body);
background: var(--cream);
color: var(--ink);
line-height: 1.6;
-webkit-font-smoothing: antialiased;
}
/* Nav */
.nav {
padding: 16px 28px;
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid rgba(44, 26, 14, 0.08);
background: var(--bone);
}
.brand {
font-family: var(--font-display);
font-size: 1.15rem;
font-weight: 800;
color: var(--ink);
text-decoration: none;
}
.back {
font-size: 0.84rem;
color: var(--ink-2);
text-decoration: none;
font-weight: 600;
}
/* Head */
.head {
text-align: center;
padding: 80px 28px 36px;
max-width: 820px;
margin: 0 auto;
}
.kicker {
font-size: 0.72rem;
text-transform: uppercase;
letter-spacing: 0.18em;
color: var(--terracotta);
font-weight: 700;
margin-bottom: 8px;
}
.head h1 {
font-family: var(--font-display);
font-size: clamp(2.2rem, 5.5vw, 3.6rem);
font-weight: 500;
letter-spacing: -0.015em;
line-height: 1.1;
}
.head h1 em {
font-style: italic;
color: var(--terracotta-d);
}
.sub {
margin-top: 18px;
font-size: 1rem;
color: var(--ink-2);
max-width: 620px;
margin-left: auto;
margin-right: auto;
}
/* Packages */
.packages {
max-width: 1180px;
margin: 0 auto;
padding: 36px 28px 32px;
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 18px;
}
@media (max-width: 980px) {
.packages {
grid-template-columns: 1fr;
}
}
.pack {
background: var(--bone);
border: 1px solid rgba(44, 26, 14, 0.08);
border-radius: var(--r-lg);
padding: 26px 24px 22px;
display: flex;
flex-direction: column;
gap: 14px;
position: relative;
}
.pack-feat {
background: linear-gradient(180deg, var(--bone) 0%, var(--cream) 100%);
border-color: var(--gold);
}
.pack-badge {
position: absolute;
top: 16px;
right: 16px;
background: var(--gold);
color: var(--ink);
font-size: 0.62rem;
letter-spacing: 0.14em;
text-transform: uppercase;
font-weight: 700;
padding: 4px 10px;
border-radius: 999px;
}
.pack-tag {
font-size: 0.68rem;
letter-spacing: 0.14em;
text-transform: uppercase;
color: var(--warm-gray);
font-weight: 700;
}
.pack h2 {
font-family: var(--font-display);
font-size: 1.5rem;
font-weight: 700;
letter-spacing: -0.005em;
margin-top: 4px;
}
.pack-desc {
font-size: 0.92rem;
color: var(--ink-2);
}
.pack-list {
list-style: none;
display: flex;
flex-direction: column;
gap: 6px;
font-size: 0.86rem;
padding-top: 4px;
border-top: 1px dashed rgba(44, 26, 14, 0.18);
padding-top: 14px;
}
.pack-list li {
color: var(--ink-2);
position: relative;
padding-left: 16px;
}
.pack-list li::before {
content: "·";
position: absolute;
left: 4px;
top: -2px;
color: var(--terracotta);
font-size: 1.4rem;
line-height: 1;
}
.pack-price {
display: flex;
justify-content: space-between;
align-items: baseline;
padding-top: 10px;
margin-top: auto;
}
.pack-price dt {
font-size: 0.74rem;
letter-spacing: 0.12em;
text-transform: uppercase;
color: var(--warm-gray);
font-weight: 700;
}
.pack-price dd {
font-family: var(--font-mono);
font-weight: 700;
font-size: 1.3rem;
color: var(--terracotta-d);
}
.ghost,
.primary {
border-radius: 999px;
font-family: inherit;
font-size: 0.88rem;
font-weight: 700;
padding: 11px 16px;
cursor: pointer;
border: 1px solid transparent;
transition: background 0.15s;
}
.ghost {
background: transparent;
border-color: rgba(44, 26, 14, 0.18);
color: var(--ink-2);
}
.ghost:hover {
background: var(--cream-2);
color: var(--ink);
}
.primary {
background: var(--forest);
color: var(--bone);
}
.primary:hover {
background: var(--forest-d);
}
/* Two-col: capacity + sample */
.two-col {
max-width: 1080px;
margin: 0 auto;
padding: 32px 28px;
display: grid;
grid-template-columns: 1fr 1fr;
gap: 16px;
align-items: start;
}
@media (max-width: 880px) {
.two-col {
grid-template-columns: 1fr;
}
}
.capacity,
.sample {
background: var(--bone);
border: 1px solid rgba(44, 26, 14, 0.08);
border-radius: var(--r-md);
padding: 24px 26px 22px;
}
.capacity h2,
.sample h2 {
font-family: var(--font-display);
font-size: 1.3rem;
font-weight: 700;
margin-bottom: 16px;
}
.capacity table {
width: 100%;
border-collapse: collapse;
font-size: 0.88rem;
}
.capacity th,
.capacity td {
text-align: left;
padding: 8px 6px;
border-bottom: 1px dashed rgba(44, 26, 14, 0.12);
}
.capacity thead th {
font-size: 0.66rem;
letter-spacing: 0.12em;
text-transform: uppercase;
color: var(--terracotta);
font-weight: 700;
}
.capacity td:not(:first-child) {
font-family: var(--font-mono);
font-weight: 700;
text-align: center;
}
.cap-note {
margin-top: 14px;
font-size: 0.78rem;
color: var(--warm-gray);
font-style: italic;
}
.sample-list {
list-style: none;
display: flex;
flex-direction: column;
gap: 10px;
}
.sample-list li {
display: grid;
grid-template-columns: 28px 1fr;
gap: 12px;
}
.pos {
font-family: var(--font-mono);
font-weight: 700;
background: var(--cream-2);
color: var(--warm-gray);
border-radius: 999px;
width: 28px;
height: 28px;
display: grid;
place-items: center;
font-size: 0.8rem;
}
.dish {
font-weight: 700;
font-size: 0.95rem;
}
.dish-mod {
font-size: 0.78rem;
color: var(--warm-gray);
font-style: italic;
}
.sample-note {
margin-top: 14px;
font-size: 0.78rem;
color: var(--warm-gray);
font-style: italic;
}
/* FAQ */
.faq {
max-width: 760px;
margin: 0 auto;
padding: 56px 28px 32px;
}
.section-head {
text-align: center;
margin-bottom: 24px;
}
.section-head h2 {
font-family: var(--font-display);
font-size: clamp(1.6rem, 4vw, 2.2rem);
font-weight: 700;
letter-spacing: -0.015em;
}
.acc {
display: flex;
flex-direction: column;
gap: 8px;
}
.acc details {
background: var(--bone);
border: 1px solid rgba(44, 26, 14, 0.08);
border-radius: var(--r-md);
overflow: hidden;
}
.acc summary {
padding: 14px 20px;
cursor: pointer;
font-weight: 700;
font-size: 0.95rem;
list-style: none;
display: flex;
justify-content: space-between;
align-items: center;
}
.acc summary::-webkit-details-marker {
display: none;
}
.acc summary::after {
content: "+";
font-family: var(--font-mono);
font-size: 1.3rem;
color: var(--terracotta);
transition: transform 0.18s;
display: inline-block;
}
.acc details[open] summary::after {
transform: rotate(45deg);
}
.acc-body {
padding: 0 20px 16px;
font-size: 0.9rem;
color: var(--ink-2);
border-top: 1px dashed rgba(44, 26, 14, 0.1);
padding-top: 12px;
}
/* Enquiry form */
.enquiry {
max-width: 880px;
margin: 0 auto;
padding: 24px 28px 80px;
}
.enq-form {
background: var(--bone);
border: 1px solid rgba(44, 26, 14, 0.08);
border-radius: var(--r-md);
padding: 22px 24px;
display: flex;
flex-direction: column;
gap: 14px;
}
.enq-form .row {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 12px;
}
.enq-form .row:nth-of-type(2) {
grid-template-columns: 1fr 1fr 1fr;
}
@media (max-width: 720px) {
.enq-form .row {
grid-template-columns: 1fr;
}
}
.enq-form label {
display: flex;
flex-direction: column;
gap: 6px;
font-size: 0.72rem;
letter-spacing: 0.12em;
text-transform: uppercase;
color: var(--ink-2);
font-weight: 700;
}
.enq-form input,
.enq-form select,
.enq-form textarea {
border: 1px solid rgba(44, 26, 14, 0.12);
background: var(--cream);
border-radius: var(--r-md);
padding: 11px 14px;
font-family: inherit;
font-size: 0.92rem;
color: var(--ink);
outline: none;
transition: border-color 0.15s;
resize: vertical;
}
.enq-form input:focus,
.enq-form select:focus,
.enq-form textarea:focus {
border-color: var(--terracotta);
}
.enq-foot {
display: flex;
justify-content: space-between;
align-items: center;
gap: 14px;
}
.hint {
font-size: 0.84rem;
color: var(--warm-gray);
}
.hint b {
color: var(--terracotta-d);
font-family: var(--font-mono);
}
.enq-ok {
color: var(--success);
font-weight: 700;
font-size: 0.92rem;
}
/* Footer */
.footer {
border-top: 1px solid rgba(44, 26, 14, 0.08);
background: var(--bone);
text-align: center;
padding: 28px;
}
.footer-brand {
font-family: var(--font-display);
font-size: 1.2rem;
font-weight: 800;
}
.footer-meta {
font-size: 0.82rem;
color: var(--warm-gray);
margin-top: 4px;
}const LEAD_DAYS = {
"long-table": 7,
buyout: 21,
catering: 30,
};
const PRICE = {
"long-table": 78,
buyout: 140,
catering: 95,
};
const pkg = document.getElementById("pkg");
const guests = document.getElementById("guests");
const date = document.getElementById("date");
const hint = document.getElementById("hint");
const form = document.getElementById("form");
const ok = document.getElementById("ok");
function isoPlus(days) {
const d = new Date();
d.setDate(d.getDate() + days);
return d.toISOString().slice(0, 10);
}
function readableDate(iso) {
return new Date(iso).toLocaleDateString(undefined, {
weekday: "long",
day: "numeric",
month: "long",
});
}
function updateHint() {
const lead = LEAD_DAYS[pkg.value] || 7;
const earliest = isoPlus(lead);
if (!date.value || date.value < earliest) date.value = earliest;
date.min = isoPlus(0);
const estimate = (PRICE[pkg.value] || 0) * Math.max(1, Number(guests.value) || 0);
hint.innerHTML = `Earliest available <b>${readableDate(earliest)}</b> · est. <b>$${estimate.toLocaleString()}</b>`;
}
pkg.addEventListener("change", updateHint);
guests.addEventListener("input", updateHint);
date.addEventListener("change", updateHint);
document.querySelectorAll("[data-pick]").forEach((btn) =>
btn.addEventListener("click", () => {
pkg.value = btn.dataset.pick;
updateHint();
document.getElementById("form").scrollIntoView({ behavior: "smooth", block: "start" });
})
);
form.addEventListener("submit", (e) => {
e.preventDefault();
ok.hidden = false;
form.querySelector("button").disabled = true;
setTimeout(() => {
ok.hidden = true;
form.querySelector("button").disabled = false;
}, 3500);
});
updateHint();<!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:ital,wght@0,400;0,500;0,700;1,500&family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@500;700&display=swap"
/>
<link rel="stylesheet" href="style.css" />
<title>Private events · Casa Olivar</title>
</head>
<body>
<header class="nav">
<a class="brand" href="#">Casa Olivar</a>
<a class="back" href="#">← Back to home</a>
</header>
<section class="head">
<p class="kicker">Private events & catering</p>
<h1>
For the table that <em>fills the room.</em>
</h1>
<p class="sub">
Twelve to ninety guests · two minutes' walk from Metro Antón Martín ·
the hearth stays on, no matter the party.
</p>
</section>
<!-- Package cards -->
<section class="packages">
<article class="pack">
<header>
<p class="pack-tag">For 12–22 guests</p>
<h2>Long-table dinner</h2>
</header>
<p class="pack-desc">
A private long-table in the back of the dining room, kitchen running
a fixed five-course menu. Diners share family-style.
</p>
<ul class="pack-list">
<li>5 courses · garden-driven</li>
<li>2 hours, single seating</li>
<li>Open carta wine list</li>
<li>Lead time · 7 days</li>
</ul>
<dl class="pack-price">
<dt>Per guest</dt>
<dd>$78</dd>
</dl>
<button class="ghost" type="button" data-pick="long-table">Enquire</button>
</article>
<article class="pack pack-feat">
<header>
<p class="pack-tag">Most popular · 22–40 guests</p>
<h2>Full buyout</h2>
<span class="pack-badge">Recommended</span>
</header>
<p class="pack-desc">
The entire dining room and bar for the evening. Custom menu in
collaboration with Aitor, three wine pairings, and DJ-ready audio.
</p>
<ul class="pack-list">
<li>Up to 40 seated · 60 cocktail</li>
<li>Custom menu · 5–7 courses</li>
<li>3 wine pairings included</li>
<li>Lead time · 21 days</li>
</ul>
<dl class="pack-price">
<dt>Per guest</dt>
<dd>$140</dd>
</dl>
<button class="primary" type="button" data-pick="buyout">Enquire</button>
</article>
<article class="pack">
<header>
<p class="pack-tag">For 30–90 guests · your venue</p>
<h2>Off-site catering</h2>
</header>
<p class="pack-desc">
We bring the kitchen to you. Aitor, Lina, and a 3-person team plate
on-site from a fixed seasonal menu. Equipment and staff included.
</p>
<ul class="pack-list">
<li>3-course or grazing format</li>
<li>Staff & equipment included</li>
<li>Within 40 km of Madrid centro</li>
<li>Lead time · 30 days</li>
</ul>
<dl class="pack-price">
<dt>Per guest</dt>
<dd>From $95</dd>
</dl>
<button class="ghost" type="button" data-pick="catering">Enquire</button>
</article>
</section>
<!-- Capacity + sample menu -->
<section class="two-col">
<article class="capacity">
<h2>Capacity by configuration</h2>
<table>
<thead>
<tr><th>Configuration</th><th>Dining room</th><th>+ Patio</th><th>Full buyout</th></tr>
</thead>
<tbody>
<tr><td>Seated dinner</td><td>22</td><td>34</td><td>40</td></tr>
<tr><td>Long table</td><td>20</td><td>—</td><td>28</td></tr>
<tr><td>Cocktail · standing</td><td>30</td><td>48</td><td>60</td></tr>
<tr><td>Seated · talk-style</td><td>26</td><td>—</td><td>36</td></tr>
</tbody>
</table>
<p class="cap-note">
Patio available May 1 – October 15, weather permitting.
</p>
</article>
<article class="sample">
<h2>Sample menu</h2>
<ol class="sample-list">
<li>
<span class="pos">1</span>
<div>
<p class="dish">Pan de masa madre & smoked oil</p>
<p class="dish-mod">Daily sourdough · house-cured anchoa</p>
</div>
</li>
<li>
<span class="pos">2</span>
<div>
<p class="dish">Burrata, garden tomato, basil</p>
<p class="dish-mod">Pairs · Albariño 2023</p>
</div>
</li>
<li>
<span class="pos">3</span>
<div>
<p class="dish">Pulpo a la brasa</p>
<p class="dish-mod">Charred octopus, paprika potato</p>
</div>
</li>
<li>
<span class="pos">4</span>
<div>
<p class="dish">Pappardelle al ragú de cordero</p>
<p class="dish-mod">Hand-cut pasta · lamb shoulder</p>
</div>
</li>
<li>
<span class="pos">5</span>
<div>
<p class="dish">Ribeye 14oz, table-shared</p>
<p class="dish-mod">Pairs · Mencía 2022</p>
</div>
</li>
<li>
<span class="pos">6</span>
<div>
<p class="dish">Tarta de queso quemada</p>
<p class="dish-mod">Basque burnt cheesecake</p>
</div>
</li>
</ol>
<p class="sample-note">
Sample only — menu is built with Aitor 3 weeks before service.
</p>
</article>
</section>
<!-- FAQ accordion -->
<section class="faq">
<header class="section-head">
<p class="kicker">Frequently asked</p>
<h2>Before you write to us.</h2>
</header>
<div class="acc" id="acc">
<details>
<summary>Deposit and cancellation</summary>
<div class="acc-body">
<p>
We hold the date with a 25% deposit, charged on signature of the
quote. Free cancellation up to 14 days before the event; 50% refund
between 14 and 7 days; non-refundable inside 7 days.
</p>
</div>
</details>
<details>
<summary>Allergies and dietary requirements</summary>
<div class="acc-body">
<p>
We design a menu that accommodates all confirmed dietary needs at no
extra cost — please send the full list 7 days before service. Gluten,
dairy, nut and shellfish substitutions are routine.
</p>
</div>
</details>
<details>
<summary>Audio, projection and decoration</summary>
<div class="acc-body">
<p>
The room ships with a bluetooth audio system, two cordless mics, and
a 65" wall-mounted display. Floral & printed decoration are
welcome with 48 h drop-off; no open flame.
</p>
</div>
</details>
<details>
<summary>Off-site catering radius</summary>
<div class="acc-body">
<p>
We service venues within 40 km of Madrid centre. Beyond that, we can
partner with a local kitchen — get in touch and we'll see what's
possible.
</p>
</div>
</details>
</div>
</section>
<!-- Enquiry form -->
<section class="enquiry">
<header class="section-head">
<p class="kicker">Send us a note</p>
<h2>Tell us about your night.</h2>
</header>
<form class="enq-form" id="form" novalidate>
<div class="row">
<label>
<span>Package</span>
<select name="package" id="pkg">
<option value="long-table">Long-table dinner · $78/g</option>
<option value="buyout" selected>Full buyout · $140/g</option>
<option value="catering">Off-site catering · from $95/g</option>
</select>
</label>
<label>
<span>Guests</span>
<input type="number" id="guests" name="guests" min="10" max="120" value="32" />
</label>
<label>
<span>Preferred date</span>
<input type="date" id="date" name="date" />
</label>
</div>
<div class="row">
<label>
<span>Name</span>
<input type="text" name="name" required placeholder="Your name" />
</label>
<label>
<span>Email</span>
<input type="email" name="email" required placeholder="you@example.com" />
</label>
<label>
<span>Phone</span>
<input type="tel" name="phone" placeholder="+34 …" />
</label>
</div>
<label>
<span>Anything else?</span>
<textarea name="message" rows="3" maxlength="600"
placeholder="Occasion, dietary needs, AV requirements, …"></textarea>
</label>
<div class="enq-foot">
<p class="hint" id="hint">—</p>
<button class="primary" type="submit">Send enquiry</button>
</div>
<p class="enq-ok" id="ok" hidden>
✓ Thanks — we'll send a draft quote within 24 hours.
</p>
</form>
</section>
<footer class="footer">
<p class="footer-brand">Casa Olivar</p>
<p class="footer-meta">events@casaolivar.es · +34 910 555 042</p>
</footer>
<script src="script.js"></script>
</body>
</html>Private Events & Catering
The “book the room” page restaurants need. Three package cards (Long-table dinner · Full buyout · Off-site catering) with what’s included, capacity, lead time, per-guest price. Below: sample menu structure, a capacity table by configuration (cocktail / seated / patio), an FAQ accordion (deposit, allergies, cancellation, AV setup), and an enquiry form that shows a live “earliest available date” hint based on lead time + party size.