Coworking — Café-Style Landing
A warm, café-style coworking landing page built with vanilla HTML, CSS and JavaScript. Espresso, cream and brass tones meet a Fraunces serif for a cozy, social feel. Includes a sticky nav with mobile drawer, a hero with live seat availability and animated steam, count-up stats, an amenities grid, a drop-in versus membership pricing toggle, a coffee-menu teaser, member quotes, a validated day-pass form and toast notifications.
MCP
Code
:root {
/* Café palette: Espresso + cream + brass */
--espresso: #3b2a21;
--espresso-d: #2a1d16;
--espresso-l: #5a4234;
--cream: #f7efe2;
--cream-d: #efe3cf;
--cream-2: #fbf6ec;
--brass: #b88a3e;
--brass-d: #9c7330;
--brass-l: #d8b878;
--ink: #2a1f18;
--ink-2: #5c4d41;
--muted: #8a7a6b;
--bg: #f3e9d8;
--surface: #fffdf8;
--line: rgba(59, 42, 33, 0.12);
--line-2: rgba(59, 42, 33, 0.22);
--ok: #4f8a5b;
--r-sm: 8px;
--r-md: 14px;
--r-lg: 22px;
--sh-sm: 0 1px 3px rgba(59, 42, 33, 0.08);
--sh-md: 0 10px 30px -12px rgba(59, 42, 33, 0.28);
--sh-lg: 0 30px 60px -24px rgba(59, 42, 33, 0.4);
--serif: "Fraunces", Georgia, "Times New Roman", serif;
--sans: "Inter", system-ui, -apple-system, sans-serif;
}
* { box-sizing: border-box; margin: 0; padding: 0; }
html { scroll-behavior: smooth; }
body {
font-family: var(--sans);
color: var(--ink);
background: var(--bg);
line-height: 1.5;
-webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility;
}
img, svg { display: block; max-width: 100%; }
.wrap { width: min(1140px, 92vw); margin-inline: auto; }
.sr-only, .skip {
position: absolute; width: 1px; height: 1px;
padding: 0; margin: -1px; overflow: hidden;
clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.skip:focus {
left: 12px; top: 12px; width: auto; height: auto;
clip: auto; z-index: 100; background: var(--espresso);
color: var(--cream); padding: 10px 16px; border-radius: var(--r-sm);
}
a { color: inherit; text-decoration: none; }
h1, h2, h3 { font-family: var(--serif); font-weight: 600; line-height: 1.08; letter-spacing: -0.01em; color: var(--espresso); }
/* ---------- Buttons ---------- */
.btn {
display: inline-flex; align-items: center; justify-content: center; gap: 8px;
font-family: var(--sans); font-weight: 600; font-size: 0.95rem;
padding: 12px 22px; border-radius: 999px; border: 1.5px solid transparent;
cursor: pointer; transition: transform 0.18s ease, box-shadow 0.18s ease, background 0.18s ease, color 0.18s ease, border-color 0.18s ease;
white-space: nowrap;
}
.btn:focus-visible { outline: 3px solid var(--brass); outline-offset: 2px; }
.btn--solid { background: var(--espresso); color: var(--cream); box-shadow: var(--sh-sm); }
.btn--solid:hover { background: var(--espresso-d); transform: translateY(-2px); box-shadow: var(--sh-md); }
.btn--line { background: transparent; color: var(--espresso); border-color: var(--line-2); }
.btn--line:hover { border-color: var(--brass); color: var(--brass-d); transform: translateY(-2px); }
.btn--ghost { background: transparent; color: var(--espresso); padding: 10px 16px; }
.btn--ghost:hover { color: var(--brass-d); }
/* ---------- Nav ---------- */
.nav {
position: sticky; top: 0; z-index: 40;
background: rgba(247, 239, 226, 0.82);
backdrop-filter: saturate(150%) blur(12px);
border-bottom: 1px solid transparent;
transition: border-color 0.25s ease, box-shadow 0.25s ease, background 0.25s ease;
}
.nav.is-stuck { border-color: var(--line); box-shadow: var(--sh-sm); background: rgba(247, 239, 226, 0.94); }
.nav__inner { display: flex; align-items: center; justify-content: space-between; gap: 16px; height: 68px; }
.brand { display: inline-flex; align-items: center; gap: 9px; font-weight: 700; }
.brand__mark { font-size: 1.4rem; line-height: 1; }
.brand__name { font-family: var(--serif); font-size: 1.18rem; font-weight: 600; color: var(--espresso); }
.nav__links { display: flex; gap: 26px; }
.nav__links a { font-size: 0.94rem; font-weight: 500; color: var(--ink-2); position: relative; padding: 4px 0; }
.nav__links a::after { content: ""; position: absolute; left: 0; bottom: -2px; width: 0; height: 2px; background: var(--brass); transition: width 0.22s ease; }
.nav__links a:hover { color: var(--espresso); }
.nav__links a:hover::after { width: 100%; }
.nav__cta { display: flex; align-items: center; gap: 10px; }
.nav__burger { display: none; flex-direction: column; gap: 5px; width: 42px; height: 42px; align-items: center; justify-content: center; background: transparent; border: 1px solid var(--line-2); border-radius: var(--r-sm); cursor: pointer; }
.nav__burger span { width: 20px; height: 2px; background: var(--espresso); border-radius: 2px; transition: transform 0.25s ease, opacity 0.2s ease; }
.nav__burger[aria-expanded="true"] span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.nav__burger[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.nav__burger[aria-expanded="true"] span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }
/* ---------- Hero ---------- */
.hero { position: relative; overflow: hidden; background: linear-gradient(180deg, var(--cream) 0%, var(--bg) 100%); }
.hero::before { content: ""; position: absolute; inset: 0; background: radial-gradient(60% 50% at 85% 0%, rgba(184, 138, 62, 0.18), transparent 70%); pointer-events: none; }
.hero__inner { position: relative; display: grid; grid-template-columns: 1.05fr 0.95fr; gap: 56px; align-items: center; padding: 72px 0 88px; }
.eyebrow { display: inline-flex; align-items: center; gap: 8px; font-size: 0.82rem; font-weight: 600; letter-spacing: 0.02em; color: var(--brass-d); background: var(--cream-2); border: 1px solid var(--line); padding: 7px 14px; border-radius: 999px; }
.eyebrow .dot { width: 8px; height: 8px; border-radius: 50%; background: var(--brass); box-shadow: 0 0 0 3px rgba(184, 138, 62, 0.25); }
.hero h1 { font-size: clamp(2.3rem, 5.4vw, 4rem); margin: 18px 0 16px; }
.lead { font-size: 1.12rem; color: var(--ink-2); max-width: 38ch; }
.hero__actions { display: flex; flex-wrap: wrap; gap: 12px; margin: 26px 0 30px; }
.hero__stats { list-style: none; display: flex; gap: 30px; border-top: 1px solid var(--line); padding-top: 20px; }
.hero__stats strong { font-family: var(--serif); font-size: 1.7rem; color: var(--espresso); display: block; }
.hero__stats span { font-size: 0.82rem; color: var(--muted); }
.hero__media { position: relative; }
.photo {
position: relative; border-radius: var(--r-lg); overflow: hidden; box-shadow: var(--sh-lg);
border: 1px solid var(--line);
}
.photo--hero {
aspect-ratio: 4 / 5;
background:
radial-gradient(120% 80% at 70% 15%, rgba(216, 184, 120, 0.55), transparent 55%),
linear-gradient(160deg, var(--espresso-l) 0%, var(--espresso) 55%, var(--espresso-d) 100%);
}
.photo--hero::after {
content: ""; position: absolute; left: 12%; bottom: 0; width: 76%; height: 34%;
background: linear-gradient(180deg, rgba(247, 239, 226, 0.14), rgba(184, 138, 62, 0.32));
border-top-left-radius: 40% 60%; border-top-right-radius: 40% 60%;
filter: blur(2px);
}
.photo__steam {
position: absolute; top: 24%; left: 46%; width: 8px; height: 56px;
background: linear-gradient(180deg, rgba(255, 253, 248, 0.5), transparent);
border-radius: 50%; filter: blur(4px); transform-origin: bottom;
animation: steam 4.5s ease-in-out infinite;
}
.photo__steam--2 { left: 54%; top: 20%; animation-delay: 1.4s; height: 64px; }
@keyframes steam {
0% { opacity: 0; transform: translateY(8px) scaleX(0.8); }
40% { opacity: 0.7; }
100% { opacity: 0; transform: translateY(-26px) scaleX(1.4); }
}
.hero__card {
position: absolute; left: -18px; bottom: 26px; width: min(280px, 78%);
background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-md);
padding: 16px 18px; box-shadow: var(--sh-md);
}
.hero__card-status { display: inline-flex; align-items: center; gap: 8px; font-size: 0.8rem; font-weight: 600; color: var(--ok); }
.pulse { width: 9px; height: 9px; border-radius: 50%; background: var(--ok); position: relative; }
.pulse::after { content: ""; position: absolute; inset: -4px; border-radius: 50%; border: 2px solid var(--ok); animation: pulse 1.8s ease-out infinite; }
@keyframes pulse { 0% { transform: scale(0.6); opacity: 0.8; } 100% { transform: scale(1.8); opacity: 0; } }
.hero__card-row { display: flex; justify-content: space-between; align-items: baseline; margin: 14px 0 8px; font-size: 0.9rem; color: var(--ink-2); }
.hero__card-row strong { font-family: var(--serif); font-size: 1.05rem; color: var(--espresso); }
.meter { height: 8px; border-radius: 999px; background: var(--cream-d); overflow: hidden; }
.meter span { display: block; height: 100%; border-radius: 999px; background: linear-gradient(90deg, var(--brass), var(--brass-d)); transition: width 0.9s cubic-bezier(0.22, 1, 0.36, 1); }
/* ---------- Sections ---------- */
.section { padding: 78px 0; }
.section__head { max-width: 620px; margin-bottom: 40px; }
.kicker { display: inline-block; font-size: 0.78rem; font-weight: 700; letter-spacing: 0.14em; text-transform: uppercase; color: var(--brass-d); margin-bottom: 10px; }
.section__head h2 { font-size: clamp(1.7rem, 3.4vw, 2.5rem); }
/* Amenities */
.amenities { background: var(--cream); }
.cards { display: grid; grid-template-columns: repeat(4, 1fr); gap: 18px; }
.card {
background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-md);
padding: 26px 22px; transition: transform 0.22s ease, box-shadow 0.22s ease, border-color 0.22s ease;
}
.card:hover { transform: translateY(-6px); box-shadow: var(--sh-md); border-color: var(--brass-l); }
.card__ico { display: inline-flex; align-items: center; justify-content: center; width: 48px; height: 48px; font-size: 1.5rem; background: var(--cream-2); border: 1px solid var(--line); border-radius: 14px; margin-bottom: 16px; }
.card h3 { font-size: 1.18rem; margin-bottom: 8px; }
.card p { font-size: 0.92rem; color: var(--ink-2); }
/* Plans */
.plans { background: var(--bg); }
.plans .section__head { display: flex; flex-direction: column; align-items: flex-start; }
.toggle { display: inline-flex; background: var(--cream-2); border: 1px solid var(--line); border-radius: 999px; padding: 4px; margin-top: 18px; }
.toggle__btn { border: 0; background: transparent; font-family: var(--sans); font-weight: 600; font-size: 0.9rem; color: var(--ink-2); padding: 8px 18px; border-radius: 999px; cursor: pointer; transition: background 0.2s ease, color 0.2s ease; }
.toggle__btn.is-active { background: var(--espresso); color: var(--cream); }
.plans__grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; align-items: stretch; }
.plan {
position: relative; background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-lg);
padding: 30px 26px; display: flex; flex-direction: column; transition: transform 0.22s ease, box-shadow 0.22s ease;
}
.plan:hover { transform: translateY(-6px); box-shadow: var(--sh-md); }
.plan--feat { border-color: var(--brass); box-shadow: var(--sh-md); background: linear-gradient(180deg, var(--cream-2), var(--surface)); }
.plan__flag { position: absolute; top: -13px; left: 26px; background: var(--brass); color: #fff; font-size: 0.72rem; font-weight: 700; letter-spacing: 0.04em; padding: 5px 12px; border-radius: 999px; box-shadow: var(--sh-sm); }
.plan__name { font-size: 1.4rem; }
.plan__price { margin: 12px 0 4px; display: flex; align-items: baseline; gap: 6px; }
.plan__price .amt { font-family: var(--serif); font-size: 2.4rem; font-weight: 600; color: var(--espresso); }
.plan__price .per { font-size: 0.9rem; color: var(--muted); }
.plan__note { font-size: 0.9rem; color: var(--ink-2); margin-bottom: 18px; }
.plan__list { list-style: none; display: grid; gap: 11px; margin-bottom: 24px; flex: 1; }
.plan__list li { position: relative; padding-left: 26px; font-size: 0.92rem; color: var(--ink-2); }
.plan__list li::before { content: "\2713"; position: absolute; left: 0; top: 0; width: 18px; height: 18px; display: grid; place-items: center; font-size: 0.7rem; font-weight: 700; color: var(--brass-d); background: var(--cream-2); border: 1px solid var(--line); border-radius: 50%; }
.plan__cta { width: 100%; }
/* Menu */
.menu { background: var(--espresso); color: var(--cream); }
.menu h2, .menu .plan__name { color: var(--cream); }
.menu .kicker { color: var(--brass-l); }
.menu__inner { display: grid; grid-template-columns: 0.9fr 1.1fr; gap: 56px; align-items: center; }
.menu__copy h2 { font-size: clamp(1.7rem, 3.4vw, 2.5rem); margin-bottom: 14px; }
.menu__copy p { color: rgba(247, 239, 226, 0.78); margin-bottom: 24px; max-width: 36ch; }
.menu .btn--line { color: var(--cream); border-color: rgba(247, 239, 226, 0.32); }
.menu .btn--line:hover { border-color: var(--brass-l); color: var(--brass-l); }
.menu__list { list-style: none; background: rgba(247, 239, 226, 0.05); border: 1px solid rgba(247, 239, 226, 0.14); border-radius: var(--r-lg); padding: 12px 22px; }
.menu__row { display: flex; align-items: baseline; gap: 12px; padding: 15px 0; border-bottom: 1px dashed rgba(247, 239, 226, 0.16); }
.menu__row:last-child { border-bottom: 0; }
.menu__name { font-weight: 500; color: var(--cream); white-space: nowrap; }
.menu__dots { flex: 1; border-bottom: 2px dotted rgba(247, 239, 226, 0.28); transform: translateY(-4px); }
.menu__cost { font-family: var(--serif); font-weight: 600; color: var(--brass-l); white-space: nowrap; }
.tag { font-family: var(--sans); font-style: normal; font-size: 0.66rem; font-weight: 700; letter-spacing: 0.03em; text-transform: uppercase; color: var(--espresso); background: var(--brass-l); padding: 2px 7px; border-radius: 999px; margin-left: 8px; vertical-align: 2px; }
/* Community */
.community { background: var(--cream); }
.quotes { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; }
.quote { background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-md); padding: 26px 24px; box-shadow: var(--sh-sm); }
.quote blockquote { font-family: var(--serif); font-size: 1.12rem; line-height: 1.4; color: var(--espresso); margin-bottom: 18px; }
.quote figcaption { display: flex; align-items: center; gap: 11px; font-size: 0.88rem; font-weight: 500; color: var(--ink-2); }
.ava { width: 38px; height: 38px; border-radius: 50%; display: grid; place-items: center; font-size: 0.8rem; font-weight: 700; color: #fff; background: linear-gradient(135deg, var(--brass), var(--espresso-l)); flex: none; }
.ava::before { content: attr(data-init); }
/* CTA */
.cta { background: var(--bg); }
.cta__inner { text-align: center; max-width: 640px; margin-inline: auto; background: linear-gradient(160deg, var(--cream-2), var(--cream)); border: 1px solid var(--line); border-radius: var(--r-lg); padding: 54px 40px; box-shadow: var(--sh-md); }
.cta__inner h2 { font-size: clamp(1.8rem, 4vw, 2.7rem); margin-bottom: 12px; }
.cta__inner > p { color: var(--ink-2); margin-bottom: 26px; }
.cta__form { display: flex; gap: 10px; max-width: 440px; margin: 0 auto 12px; }
.cta__form input { flex: 1; font-family: var(--sans); font-size: 0.95rem; padding: 13px 16px; border: 1.5px solid var(--line-2); border-radius: 999px; background: var(--surface); color: var(--ink); }
.cta__form input:focus-visible { outline: 3px solid var(--brass); outline-offset: 1px; border-color: var(--brass); }
.cta__form input.is-error { border-color: #c4543e; }
.cta__fine { font-size: 0.82rem; color: var(--muted); }
.cta__fine.is-ok { color: var(--ok); font-weight: 600; }
/* ---------- Footer ---------- */
.footer { background: var(--espresso-d); color: rgba(247, 239, 226, 0.78); padding: 56px 0 28px; }
.footer__inner { display: grid; grid-template-columns: 2fr 1fr 1fr; gap: 30px; padding-bottom: 30px; border-bottom: 1px solid rgba(247, 239, 226, 0.12); }
.footer__brand { display: flex; flex-direction: column; gap: 8px; }
.footer__brand .brand__mark { font-size: 1.6rem; }
.footer__brand strong { font-family: var(--serif); font-size: 1.2rem; color: var(--cream); }
.footer__brand p { font-size: 0.86rem; max-width: 34ch; }
.footer__col { display: flex; flex-direction: column; gap: 10px; }
.footer__h { font-size: 0.78rem; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase; color: var(--brass-l); margin-bottom: 4px; }
.footer__col a { font-size: 0.9rem; transition: color 0.18s ease; }
.footer__col a:hover { color: var(--cream); }
.footer__base { display: flex; align-items: center; justify-content: space-between; padding-top: 22px; font-size: 0.82rem; }
/* ---------- Reveal ---------- */
.reveal { opacity: 0; transform: translateY(22px); transition: opacity 0.7s ease, transform 0.7s cubic-bezier(0.22, 1, 0.36, 1); }
.reveal.is-in { opacity: 1; transform: none; }
/* ---------- Toast ---------- */
.toast {
position: fixed; left: 50%; bottom: 26px; transform: translate(-50%, 24px);
background: var(--espresso); color: var(--cream); font-size: 0.9rem; font-weight: 500;
padding: 13px 20px; border-radius: 999px; box-shadow: var(--sh-lg);
opacity: 0; pointer-events: none; transition: opacity 0.3s ease, transform 0.3s ease; z-index: 80;
border: 1px solid rgba(216, 184, 120, 0.4);
}
.toast.is-show { opacity: 1; transform: translate(-50%, 0); }
/* ---------- Responsive ---------- */
@media (max-width: 920px) {
.hero__inner { grid-template-columns: 1fr; gap: 40px; }
.hero__media { max-width: 460px; }
.cards { grid-template-columns: repeat(2, 1fr); }
.plans__grid { grid-template-columns: 1fr; max-width: 460px; }
.menu__inner { grid-template-columns: 1fr; gap: 32px; }
.quotes { grid-template-columns: 1fr; }
.footer__inner { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 760px) {
.nav__links {
position: fixed; inset: 68px 0 auto 0; flex-direction: column; gap: 0;
background: var(--cream); border-bottom: 1px solid var(--line);
padding: 8px 6vw 18px; box-shadow: var(--sh-md);
transform: translateY(-130%); transition: transform 0.3s ease; visibility: hidden;
}
.nav__links.is-open { transform: translateY(0); visibility: visible; }
.nav__links a { padding: 14px 0; border-bottom: 1px solid var(--line); }
.nav__cta .btn--ghost { display: none; }
.nav__burger { display: flex; }
}
@media (max-width: 520px) {
.section { padding: 56px 0; }
.cards { grid-template-columns: 1fr; }
.hero__stats { gap: 22px; }
.hero__card { left: 0; right: 0; margin-inline: auto; }
.cta__form { flex-direction: column; }
.cta__form .btn { width: 100%; }
.footer__inner { grid-template-columns: 1fr; }
.footer__base { flex-direction: column; gap: 8px; text-align: center; }
}
@media (prefers-reduced-motion: reduce) {
* { animation: none !important; scroll-behavior: auto; }
.reveal { opacity: 1; transform: none; transition: none; }
}(function () {
"use strict";
/* ---------- Toast helper ---------- */
var toastEl = document.getElementById("toast");
var toastTimer;
function toast(msg) {
if (!toastEl) return;
toastEl.textContent = msg;
toastEl.classList.add("is-show");
clearTimeout(toastTimer);
toastTimer = setTimeout(function () {
toastEl.classList.remove("is-show");
}, 2600);
}
/* ---------- Sticky nav shadow ---------- */
var nav = document.getElementById("nav");
function onScroll() {
if (!nav) return;
nav.classList.toggle("is-stuck", window.scrollY > 8);
}
window.addEventListener("scroll", onScroll, { passive: true });
onScroll();
/* ---------- Mobile nav ---------- */
var burger = document.getElementById("burger");
var navLinks = document.getElementById("navLinks");
if (burger && navLinks) {
burger.addEventListener("click", function () {
var open = navLinks.classList.toggle("is-open");
burger.setAttribute("aria-expanded", String(open));
});
navLinks.addEventListener("click", function (e) {
if (e.target.closest("a")) {
navLinks.classList.remove("is-open");
burger.setAttribute("aria-expanded", "false");
}
});
}
/* ---------- Scroll reveal ---------- */
var revealEls = document.querySelectorAll(".reveal");
if ("IntersectionObserver" in window) {
var io = new IntersectionObserver(
function (entries) {
entries.forEach(function (entry) {
if (entry.isIntersecting) {
entry.target.classList.add("is-in");
io.unobserve(entry.target);
}
});
},
{ threshold: 0.14, rootMargin: "0px 0px -8% 0px" }
);
revealEls.forEach(function (el) {
io.observe(el);
});
} else {
revealEls.forEach(function (el) {
el.classList.add("is-in");
});
}
/* ---------- Count-up stats ---------- */
var counted = false;
function runCounts() {
if (counted) return;
counted = true;
document.querySelectorAll("[data-count]").forEach(function (el) {
var target = parseInt(el.getAttribute("data-count"), 10) || 0;
var start = performance.now();
var dur = 1300;
function tick(now) {
var p = Math.min((now - start) / dur, 1);
var eased = 1 - Math.pow(1 - p, 3);
el.textContent = Math.round(target * eased).toLocaleString();
if (p < 1) requestAnimationFrame(tick);
}
requestAnimationFrame(tick);
});
}
var hero = document.getElementById("top");
if (hero && "IntersectionObserver" in window) {
var heroIo = new IntersectionObserver(
function (entries) {
if (entries[0].isIntersecting) {
runCounts();
heroIo.disconnect();
}
},
{ threshold: 0.4 }
);
heroIo.observe(hero);
} else {
runCounts();
}
/* ---------- Live seat availability ---------- */
var seatsFree = document.getElementById("seatsFree");
var seatMeter = document.getElementById("seatMeter");
var TOTAL = 42;
function refreshSeats(notify) {
var free = 8 + Math.floor(Math.random() * 22); // 8..29
var occupied = TOTAL - free;
if (seatsFree) seatsFree.textContent = free + " / " + TOTAL;
if (seatMeter) seatMeter.style.width = Math.round((occupied / TOTAL) * 100) + "%";
if (notify) toast("Updated · " + free + " of " + TOTAL + " seats free right now");
}
// gentle drift every 12s
setInterval(function () {
refreshSeats(false);
}, 12000);
/* ---------- Plans billing toggle ---------- */
var toggleBtns = document.querySelectorAll(".toggle__btn");
function applyPeriod(period) {
toggleBtns.forEach(function (b) {
var active = b.getAttribute("data-period") === period;
b.classList.toggle("is-active", active);
b.setAttribute("aria-pressed", String(active));
});
document.querySelectorAll(".plan__price .amt").forEach(function (amt) {
var val = amt.getAttribute("data-" + period);
if (val) amt.textContent = "$" + val;
});
document.querySelectorAll(".plan__price .per").forEach(function (per) {
var val = per.getAttribute("data-" + period);
if (val) per.textContent = val;
});
}
toggleBtns.forEach(function (b) {
b.addEventListener("click", function () {
applyPeriod(b.getAttribute("data-period"));
});
});
/* ---------- Plan CTA ---------- */
document.querySelectorAll(".plan__cta").forEach(function (btn) {
btn.addEventListener("click", function () {
var plan = btn.getAttribute("data-plan") || "this plan";
toast("Nice choice — " + plan + " added. We'll hold your seat.");
});
});
/* ---------- Reserve a seat (nav) ---------- */
var reserve = document.querySelector('.btn--ghost[href="#plans"]');
if (reserve) {
reserve.addEventListener("click", function () {
refreshSeats(true);
});
}
/* ---------- Email pass form ---------- */
var emailRe = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
var passForm = document.getElementById("passForm");
if (passForm) {
var input = passForm.querySelector("input[type=email]");
var note = document.getElementById("formNote");
passForm.addEventListener("submit", function (e) {
e.preventDefault();
var val = (input.value || "").trim();
if (!emailRe.test(val)) {
input.classList.add("is-error");
input.focus();
if (note) {
note.textContent = "Hmm, that email doesn't look right — try again.";
note.classList.remove("is-ok");
}
return;
}
input.classList.remove("is-error");
if (note) {
note.textContent = "Pass link sent — check your inbox ☕";
note.classList.add("is-ok");
}
toast("Day-pass link on its way to " + val);
input.value = "";
});
input.addEventListener("input", function () {
input.classList.remove("is-error");
});
}
})();<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Bean & Bureau — Café-Style Coworking</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=Fraunces:opsz,[email protected],400;9..144,500;9..144,600;9..144,700&family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="style.css" />
</head>
<body>
<a class="skip" href="#main">Skip to content</a>
<!-- NAV -->
<header class="nav" id="nav">
<div class="wrap nav__inner">
<a class="brand" href="#top" aria-label="Bean and Bureau home">
<span class="brand__mark" aria-hidden="true">☕</span>
<span class="brand__name">Bean & Bureau</span>
</a>
<nav class="nav__links" id="navLinks" aria-label="Primary">
<a href="#amenities">Amenities</a>
<a href="#plans">Day Pass</a>
<a href="#menu">Menu</a>
<a href="#community">Community</a>
</nav>
<div class="nav__cta">
<a class="btn btn--ghost" href="#plans">Reserve a seat</a>
<button class="nav__burger" id="burger" aria-label="Toggle menu" aria-expanded="false" aria-controls="navLinks">
<span></span><span></span><span></span>
</button>
</div>
</div>
</header>
<main id="main">
<!-- HERO -->
<section class="hero" id="top" aria-labelledby="heroTitle">
<div class="wrap hero__inner">
<div class="hero__copy reveal">
<span class="eyebrow"><span class="dot"></span> Now brewing in the Old Roastery District</span>
<h1 id="heroTitle">Where good coffee<br />meets great work.</h1>
<p class="lead">A cozy café-style workspace for makers, writers and small teams. Order a flat white, claim a worn-leather armchair, and get the deep-focus hours you came for.</p>
<div class="hero__actions">
<a class="btn btn--solid" href="#plans">Buy a day pass — $19</a>
<a class="btn btn--line" href="#tour">Take the tour</a>
</div>
<ul class="hero__stats" aria-label="Space highlights">
<li><strong data-count="42">0</strong><span>cozy seats</span></li>
<li><strong data-count="300">0</strong><span>Mbps wifi</span></li>
<li><strong data-count="7">0</strong><span>days a week</span></li>
</ul>
</div>
<div class="hero__media reveal" id="tour">
<div class="photo photo--hero" role="img" aria-label="Warm café interior with hanging lamps and a barista counter">
<span class="photo__steam" aria-hidden="true"></span>
<span class="photo__steam photo__steam--2" aria-hidden="true"></span>
</div>
<div class="hero__card">
<span class="hero__card-status"><span class="pulse"></span> Open · 7:00 – 22:00</span>
<div class="hero__card-row">
<span>Seats free now</span>
<strong id="seatsFree">17 / 42</strong>
</div>
<div class="meter" role="meter" aria-valuemin="0" aria-valuemax="42" aria-valuenow="25" aria-label="Seats occupied">
<span id="seatMeter" style="width:60%"></span>
</div>
</div>
</div>
</div>
</section>
<!-- AMENITIES -->
<section class="section amenities" id="amenities" aria-labelledby="amenTitle">
<div class="wrap">
<header class="section__head reveal">
<span class="kicker">The good stuff</span>
<h2 id="amenTitle">Everything you need, nothing you don’t</h2>
</header>
<div class="cards">
<article class="card reveal">
<span class="card__ico" aria-hidden="true">☕</span>
<h3>Specialty coffee</h3>
<p>Single-origin beans roasted two doors down, pulled by award-winning baristas. First cup’s on your pass.</p>
</article>
<article class="card reveal">
<span class="card__ico" aria-hidden="true">🔌</span>
<h3>Fast, reliable wifi</h3>
<p>Symmetric 300 Mbps fibre, mesh coverage to every nook, and outlets at every seat. No more outlet hunting.</p>
</article>
<article class="card reveal">
<span class="card__ico" aria-hidden="true">🪑</span>
<h3>Comfy seating</h3>
<p>Worn-leather armchairs, sun-soaked window benches and quiet booths. Sit how you actually want to work.</p>
</article>
<article class="card reveal">
<span class="card__ico" aria-hidden="true">🌿</span>
<h3>Plants & calm</h3>
<p>Soft jazz, leafy corners and a no-loud-calls rule. The hum of a café without the chaos of one.</p>
</article>
</div>
</div>
</section>
<!-- PLANS -->
<section class="section plans" id="plans" aria-labelledby="plansTitle">
<div class="wrap">
<header class="section__head reveal">
<span class="kicker">Pick your pace</span>
<h2 id="plansTitle">Day pass or make it a habit</h2>
<div class="toggle" role="group" aria-label="Billing period">
<button class="toggle__btn is-active" data-period="day" aria-pressed="true">Drop in</button>
<button class="toggle__btn" data-period="month" aria-pressed="false">Membership</button>
</div>
</header>
<div class="plans__grid">
<article class="plan reveal">
<h3 class="plan__name">Espresso</h3>
<p class="plan__price"><span class="amt" data-day="19" data-month="149">$19</span><span class="per" data-day="/ day" data-month="/ mo">/ day</span></p>
<p class="plan__note">A single focused session, coffee included.</p>
<ul class="plan__list">
<li>1 day of open seating</li>
<li>First coffee on the house</li>
<li>Fast wifi & power</li>
<li>Quiet booth access</li>
</ul>
<button class="btn btn--line plan__cta" data-plan="Espresso">Choose Espresso</button>
</article>
<article class="plan plan--feat reveal">
<span class="plan__flag">Most loved</span>
<h3 class="plan__name">Cortado</h3>
<p class="plan__price"><span class="amt" data-day="29" data-month="229">$29</span><span class="per" data-day="/ day" data-month="/ mo">/ day</span></p>
<p class="plan__note">All-day access with the comfy perks.</p>
<ul class="plan__list">
<li>Unlimited daily refills</li>
<li>Reserved armchair or bench</li>
<li>2 meeting-nook hours</li>
<li>Locker & printing</li>
</ul>
<button class="btn btn--solid plan__cta" data-plan="Cortado">Choose Cortado</button>
</article>
<article class="plan reveal">
<h3 class="plan__name">Pour Over</h3>
<p class="plan__price"><span class="amt" data-day="49" data-month="389">$49</span><span class="per" data-day="/ day" data-month="/ mo">/ day</span></p>
<p class="plan__note">For small teams who want a corner of their own.</p>
<ul class="plan__list">
<li>Up to 4 seats together</li>
<li>Private booth half-day</li>
<li>Catered coffee tray</li>
<li>Guest day passes ×2</li>
</ul>
<button class="btn btn--line plan__cta" data-plan="Pour Over">Choose Pour Over</button>
</article>
</div>
</div>
</section>
<!-- MENU TEASER -->
<section class="section menu" id="menu" aria-labelledby="menuTitle">
<div class="wrap menu__inner">
<div class="menu__copy reveal">
<span class="kicker">From the bar</span>
<h2 id="menuTitle">A little menu to fuel the focus</h2>
<p>Everything is made in-house, all day long. Members get 15% off the lot.</p>
<a class="btn btn--line" href="#plans">See the full menu & join</a>
</div>
<ul class="menu__list reveal" aria-label="Menu sample">
<li class="menu__row">
<span class="menu__name">House Flat White <em class="tag">popular</em></span>
<span class="menu__dots" aria-hidden="true"></span>
<span class="menu__cost">$4.20</span>
</li>
<li class="menu__row">
<span class="menu__name">Slow Pour Over</span>
<span class="menu__dots" aria-hidden="true"></span>
<span class="menu__cost">$5.00</span>
</li>
<li class="menu__row">
<span class="menu__name">Cardamom Cold Brew</span>
<span class="menu__dots" aria-hidden="true"></span>
<span class="menu__cost">$5.50</span>
</li>
<li class="menu__row">
<span class="menu__name">Sourdough & Honey Toast</span>
<span class="menu__dots" aria-hidden="true"></span>
<span class="menu__cost">$6.00</span>
</li>
<li class="menu__row">
<span class="menu__name">Olive-Oil Citrus Cake <em class="tag">vegan</em></span>
<span class="menu__dots" aria-hidden="true"></span>
<span class="menu__cost">$4.80</span>
</li>
</ul>
</div>
</section>
<!-- COMMUNITY -->
<section class="section community" id="community" aria-labelledby="commTitle">
<div class="wrap">
<header class="section__head reveal">
<span class="kicker">The regulars</span>
<h2 id="commTitle">A table of good company</h2>
</header>
<div class="quotes">
<figure class="quote reveal">
<blockquote>“I wrote most of my novel in the window bench. The coffee’s ruined me for anywhere else.”</blockquote>
<figcaption><span class="ava" data-init="MR"></span> Mara Reyes · Author</figcaption>
</figure>
<figure class="quote reveal">
<blockquote>“Our two-person studio runs out of the corner booth. Cheaper than an office, ten times nicer.”</blockquote>
<figcaption><span class="ava" data-init="DK"></span> Devon Kahn · Designer</figcaption>
</figure>
<figure class="quote reveal">
<blockquote>“Thursday community lunches are how I found my last three freelance clients.”</blockquote>
<figcaption><span class="ava" data-init="PL"></span> Priya Lall · Developer</figcaption>
</figure>
</div>
</div>
</section>
<!-- CTA -->
<section class="section cta" aria-labelledby="ctaTitle">
<div class="wrap cta__inner reveal">
<h2 id="ctaTitle">Your seat is getting cold.</h2>
<p>Grab a day pass, sip something good, and ship the work that’s been waiting.</p>
<form class="cta__form" id="passForm" novalidate>
<label class="sr-only" for="email">Email address</label>
<input type="email" id="email" name="email" placeholder="[email protected]" autocomplete="email" required />
<button class="btn btn--solid" type="submit">Send my pass link</button>
</form>
<p class="cta__fine" id="formNote">No card needed to reserve. Cancel anytime.</p>
</div>
</section>
</main>
<!-- FOOTER -->
<footer class="footer">
<div class="wrap footer__inner">
<div class="footer__brand">
<span class="brand__mark" aria-hidden="true">☕</span>
<strong>Bean & Bureau</strong>
<p>14 Roastery Lane · Open 7 days · [email protected]</p>
</div>
<nav class="footer__col" aria-label="Visit">
<span class="footer__h">Visit</span>
<a href="#amenities">Amenities</a>
<a href="#menu">Menu</a>
<a href="#community">Community</a>
</nav>
<nav class="footer__col" aria-label="Plans">
<span class="footer__h">Plans</span>
<a href="#plans">Day pass</a>
<a href="#plans">Membership</a>
<a href="#plans">Teams</a>
</nav>
</div>
<div class="wrap footer__base">
<span>© 2026 Bean & Bureau. A fictional café-workspace.</span>
<span class="footer__plant" aria-hidden="true">🌿</span>
</div>
</footer>
<div class="toast" id="toast" role="status" aria-live="polite"></div>
<script src="script.js"></script>
</body>
</html>Café-Style Landing
A complete marketing landing for Bean & Bureau, a fictional café-style coworking space. The page leads with a cozy hero — warm espresso-to-brass gradient “photo”, drifting steam, and a floating live-status card that shows how many of the 42 seats are free. Hero stat numbers count up the first time the section scrolls into view, and a sticky nav gains a soft shadow on scroll with a slide-down drawer on mobile.
Below the fold sit the core sections of a workspace pitch: an amenities grid (specialty coffee, fast wifi, comfy seating, plants and calm), a pricing block that flips between Drop in and Membership rates with a single toggle, a dark espresso menu teaser with dotted leader lines, member quotes with generated avatar initials, and a final call-to-action with an inline-validated email field. Every section animates in on scroll.
Interactions are pure vanilla JavaScript: a reusable toast() helper, IntersectionObserver-driven reveals and count-ups, a periodically refreshing seat meter, the billing toggle, plan-selection toasts, and email validation with accessible error and success states. The palette uses an espresso, cream and brass scheme with a Fraunces serif over Inter, and the layout stays usable down to ~360px.
Illustrative UI only — fictional coworking space, not a real booking system.