Cookbook — Food Magazine (Bon Appétit-style) landing
A glossy, high-contrast food-magazine landing page with a full-bleed cover-story hero, issue tag and byline, a varied-tile featured-stories grid with category tab filters, a horizontally scrolling trending-recipes strip, and a bold subscribe band. Built with editorial serif and sans typography, CSS-gradient food photography and emoji accents, a sticky condensing header, scroll-reveal animations, and a validating subscribe form — all vanilla HTML, CSS, and JavaScript with no images or libraries.
MCP
Code
:root {
/* Themed: white + black + one bold accent (tomato red), glossy magazine */
--paper: #ffffff;
--cream: #f6f4f1;
--ink: #0c0c0d;
--ink-2: #3a3a3e;
--muted: #8c8c92;
--accent: #ec3a1e;
--accent-d: #c42d14;
--line: rgba(12, 12, 13, 0.12);
--line-2: rgba(12, 12, 13, 0.22);
--r-sm: 8px;
--r-md: 14px;
--r-lg: 22px;
--sh-1: 0 1px 2px rgba(12, 12, 13, 0.08);
--sh-2: 0 14px 40px rgba(12, 12, 13, 0.16);
--serif: "Fraunces", Georgia, serif;
--sans: "Inter", system-ui, -apple-system, sans-serif;
}
* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
margin: 0;
font-family: var(--sans);
background: var(--paper);
color: var(--ink);
line-height: 1.6;
-webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility;
}
h1, h2, h3, h4 { font-family: var(--serif); line-height: 1.05; margin: 0; letter-spacing: -0.01em; }
a { color: inherit; text-decoration: none; }
.skip {
position: absolute;
left: -999px;
top: 0;
background: var(--ink);
color: #fff;
padding: 10px 16px;
z-index: 100;
border-radius: 0 0 var(--r-sm) 0;
}
.skip:focus { left: 0; }
.visually-hidden {
position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0);
}
:focus-visible {
outline: 3px solid var(--accent);
outline-offset: 2px;
border-radius: 4px;
}
.kicker {
font-family: var(--sans);
font-size: 0.72rem;
font-weight: 700;
letter-spacing: 0.18em;
text-transform: uppercase;
color: var(--accent);
margin: 0 0 0.6rem;
}
.kicker.light { color: rgba(255, 255, 255, 0.85); }
/* ---------- Header ---------- */
.site {
position: sticky;
top: 0;
z-index: 60;
background: rgba(255, 255, 255, 0.92);
backdrop-filter: blur(10px);
border-bottom: 1px solid var(--line);
transition: padding 0.25s ease, box-shadow 0.25s ease;
}
.site.condensed { box-shadow: var(--sh-1); }
.bar {
max-width: 1180px;
margin: 0 auto;
padding: 18px 24px;
display: flex;
align-items: center;
gap: 22px;
transition: padding 0.25s ease;
}
.site.condensed .bar { padding: 10px 24px; }
.menu-btn {
display: none;
background: none;
border: none;
font-size: 1.4rem;
cursor: pointer;
color: var(--ink);
}
.brand { display: flex; align-items: center; gap: 10px; }
.brand-mark {
width: 34px; height: 34px;
display: grid; place-items: center;
background: var(--accent);
color: #fff;
font-family: var(--serif);
font-weight: 700;
border-radius: var(--r-sm);
font-size: 1.2rem;
}
.brand-word {
font-family: var(--serif);
font-weight: 700;
font-size: 1.35rem;
letter-spacing: 0.04em;
}
.sections {
display: flex;
gap: 24px;
margin-left: 14px;
font-size: 0.9rem;
font-weight: 600;
}
.sections a {
position: relative;
padding: 4px 0;
color: var(--ink-2);
transition: color 0.15s ease;
}
.sections a:hover, .sections a.active { color: var(--ink); }
.sections a.active::after {
content: "";
position: absolute; left: 0; right: 0; bottom: -2px;
height: 2px; background: var(--accent);
}
.bar-actions { margin-left: auto; display: flex; align-items: center; gap: 16px; }
.issue-tag {
font-size: 0.72rem;
font-weight: 700;
letter-spacing: 0.1em;
color: var(--muted);
border: 1px solid var(--line-2);
padding: 4px 10px;
border-radius: 999px;
}
.btn-sub {
background: var(--ink);
color: #fff;
padding: 9px 18px;
border-radius: 999px;
font-weight: 600;
font-size: 0.88rem;
transition: background 0.15s ease, transform 0.1s ease;
}
.btn-sub:hover { background: var(--accent); }
.btn-sub:active { transform: scale(0.97); }
/* ---------- Hero ---------- */
.hero {
position: relative;
max-width: 1180px;
margin: 0 auto;
padding: 48px 24px 64px;
display: grid;
grid-template-columns: 1.1fr 0.9fr;
gap: 48px;
align-items: center;
}
.hero-photo {
position: relative;
aspect-ratio: 4 / 5;
border-radius: var(--r-lg);
overflow: hidden;
background:
radial-gradient(120% 90% at 20% 10%, #ff6a4d 0%, transparent 55%),
radial-gradient(120% 120% at 90% 100%, #7a1808 0%, transparent 60%),
linear-gradient(160deg, var(--accent) 0%, #8c1c08 100%);
box-shadow: var(--sh-2);
order: 2;
}
.blob {
position: absolute;
border-radius: 50%;
filter: blur(8px);
opacity: 0.55;
}
.blob.b1 {
width: 240px; height: 240px;
top: -40px; left: -40px;
background: radial-gradient(circle, #ffd0a8, transparent 70%);
}
.blob.b2 {
width: 300px; height: 300px;
bottom: -60px; right: -50px;
background: radial-gradient(circle, #ffe9b0, transparent 70%);
}
.hero-emoji {
position: absolute;
font-size: clamp(3.5rem, 12vw, 7rem);
top: 50%; left: 50%;
transform: translate(-50%, -50%) rotate(-6deg);
filter: drop-shadow(0 8px 16px rgba(0, 0, 0, 0.3));
}
.hero-emoji.e2 { font-size: 3rem; top: 22%; left: 78%; transform: rotate(12deg); }
.hero-emoji.e3 { font-size: 2.6rem; top: 80%; left: 24%; transform: rotate(-14deg); }
.hero-copy { order: 1; }
.hero-copy h1 {
font-size: clamp(2.6rem, 6vw, 4.6rem);
font-weight: 600;
margin: 0 0 18px;
}
.hero-dek {
font-size: 1.18rem;
color: var(--ink-2);
max-width: 30ch;
margin: 0 0 22px;
}
.hero-meta {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 8px;
font-size: 0.86rem;
color: var(--muted);
margin-bottom: 26px;
}
.hero-meta .byline strong { color: var(--ink); }
.hero-meta .dot { color: var(--line-2); }
.hero-meta .read { color: var(--accent); font-weight: 600; }
.btn-read {
display: inline-block;
font-weight: 600;
border-bottom: 2px solid var(--accent);
padding-bottom: 3px;
transition: gap 0.15s ease, color 0.15s ease;
}
.btn-read:hover { color: var(--accent); }
/* ---------- Section heads ---------- */
.sec-head { max-width: 1180px; margin: 0 auto; padding: 0 24px; }
.sec-head h2 {
font-size: clamp(2rem, 4vw, 3rem);
font-weight: 600;
margin-bottom: 22px;
}
/* ---------- Tabs ---------- */
.tabs { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 8px; }
.tab {
font-family: var(--sans);
font-size: 0.85rem;
font-weight: 600;
padding: 8px 16px;
border: 1px solid var(--line-2);
background: var(--paper);
color: var(--ink-2);
border-radius: 999px;
cursor: pointer;
transition: all 0.15s ease;
}
.tab:hover { border-color: var(--ink); color: var(--ink); }
.tab.active { background: var(--ink); color: #fff; border-color: var(--ink); }
/* ---------- Feature grid ---------- */
.feature { padding: 56px 0; }
.grid {
max-width: 1180px;
margin: 28px auto 0;
padding: 0 24px;
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 22px;
}
.tile {
display: flex;
flex-direction: column;
border: 1px solid var(--line);
border-radius: var(--r-md);
overflow: hidden;
background: var(--paper);
transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.tile:hover { transform: translateY(-4px); box-shadow: var(--sh-2); }
.tile.big { grid-row: span 2; grid-column: span 1; }
.tile.wide { grid-column: span 2; }
.tile-photo {
position: relative;
aspect-ratio: 16 / 10;
display: grid;
place-items: center;
font-size: 3.4rem;
}
.tile.big .tile-photo { aspect-ratio: 4 / 5; font-size: 5rem; }
.tile.wide .tile-photo { aspect-ratio: 21 / 9; }
.tile-photo span { filter: drop-shadow(0 6px 12px rgba(0, 0, 0, 0.22)); }
.tile-body { padding: 20px; display: flex; flex-direction: column; gap: 8px; flex: 1; }
.tile-body h3 { font-size: 1.32rem; font-weight: 600; line-height: 1.12; }
.tile.big .tile-body h3 { font-size: 1.7rem; }
.excerpt { color: var(--ink-2); font-size: 0.95rem; margin: 0; }
.read-time {
margin-top: auto;
font-size: 0.78rem;
font-weight: 600;
letter-spacing: 0.04em;
color: var(--muted);
}
.tile.hidden { display: none; }
.empty {
max-width: 1180px;
margin: 24px auto 0;
padding: 0 24px;
color: var(--muted);
font-style: italic;
}
/* photo gradients */
.p-tomato { background: linear-gradient(150deg, #ff6a4d, #b8200a); }
.p-saffron { background: linear-gradient(150deg, #ffc857, #e08200); }
.p-sage { background: linear-gradient(150deg, #b7c79e, #5e7349); }
.p-clay { background: linear-gradient(150deg, #e0a07f, #9e4e2e); }
.p-lemon { background: linear-gradient(150deg, #ffe27a, #e0a900); }
.p-dark { background: linear-gradient(150deg, #5a4636, #2a1c12); }
.p-green { background: linear-gradient(150deg, #8fbf8f, #2f6b42); }
/* ---------- Trending strip ---------- */
.trending { padding: 40px 0 64px; background: var(--cream); }
.strip {
max-width: 1180px;
margin: 28px auto 0;
padding: 4px 24px 16px;
display: grid;
grid-auto-flow: column;
grid-auto-columns: minmax(220px, 1fr);
gap: 20px;
overflow-x: auto;
scroll-snap-type: x mandatory;
scrollbar-width: thin;
}
.strip .card {
scroll-snap-align: start;
background: var(--paper);
border-radius: var(--r-md);
border: 1px solid var(--line);
overflow: hidden;
transition: transform 0.18s ease, box-shadow 0.18s ease;
}
.strip .card:hover { transform: translateY(-4px); box-shadow: var(--sh-2); }
.card-photo {
aspect-ratio: 16 / 11;
display: grid;
place-items: center;
font-size: 2.8rem;
}
.card-photo span { filter: drop-shadow(0 5px 10px rgba(0, 0, 0, 0.22)); }
.card h4 { font-size: 1.12rem; font-weight: 600; padding: 14px 16px 4px; }
.card-meta { font-size: 0.82rem; color: var(--muted); padding: 0 16px 16px; margin: 0; }
/* ---------- Subscribe ---------- */
.subscribe { background: var(--ink); color: #fff; }
.sub-inner {
max-width: 1180px;
margin: 0 auto;
padding: 64px 24px;
display: grid;
grid-template-columns: 1fr 1fr;
gap: 48px;
align-items: center;
}
.sub-copy h2 { font-size: clamp(2rem, 4vw, 3rem); font-weight: 600; margin-bottom: 14px; }
.sub-dek { color: rgba(255, 255, 255, 0.7); max-width: 36ch; margin: 0; }
.sub-form { display: flex; flex-wrap: wrap; gap: 12px; align-items: flex-start; }
.sub-form input {
flex: 1;
min-width: 200px;
padding: 15px 18px;
font-size: 1rem;
font-family: var(--sans);
border: none;
border-radius: var(--r-sm);
background: #fff;
color: var(--ink);
}
.sub-form button {
padding: 15px 26px;
font-size: 1rem;
font-weight: 600;
font-family: var(--sans);
background: var(--accent);
color: #fff;
border: none;
border-radius: var(--r-sm);
cursor: pointer;
transition: background 0.15s ease, transform 0.1s ease;
}
.sub-form button:hover { background: var(--accent-d); }
.sub-form button:active { transform: scale(0.97); }
.form-msg { flex-basis: 100%; margin: 4px 0 0; font-size: 0.88rem; min-height: 1.2em; }
.form-msg.ok { color: #7fe0a0; }
.form-msg.err { color: #ff9a8a; }
/* ---------- Footer ---------- */
.site-foot {
text-align: center;
padding: 40px 24px;
border-top: 1px solid var(--line);
}
.site-foot .brand-word { display: block; margin-bottom: 6px; }
.site-foot p { color: var(--muted); font-size: 0.85rem; margin: 0; }
/* ---------- Reveal ---------- */
.reveal {
opacity: 0;
transform: translateY(24px);
transition: opacity 0.6s ease, transform 0.6s ease;
}
.reveal.in { opacity: 1; transform: none; }
/* ---------- Toast ---------- */
.toast {
position: fixed;
bottom: 24px;
left: 50%;
transform: translateX(-50%) translateY(20px);
background: var(--ink);
color: #fff;
padding: 12px 22px;
border-radius: 999px;
font-size: 0.9rem;
font-weight: 500;
box-shadow: var(--sh-2);
opacity: 0;
pointer-events: none;
transition: opacity 0.25s ease, transform 0.25s ease;
z-index: 90;
}
.toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }
/* ---------- Responsive ---------- */
@media (max-width: 980px) {
.grid { grid-template-columns: repeat(2, 1fr); }
.tile.big { grid-row: span 1; }
.tile.wide { grid-column: span 2; }
}
@media (max-width: 720px) {
.sections { display: none; }
.menu-btn { display: block; }
.sections.open {
display: flex;
position: absolute;
top: 100%; left: 0; right: 0;
flex-direction: column;
gap: 0;
background: var(--paper);
border-bottom: 1px solid var(--line);
padding: 8px 24px 16px;
}
.hero {
grid-template-columns: 1fr;
gap: 28px;
padding-top: 32px;
}
.hero-photo { order: 1; }
.hero-copy { order: 2; }
.grid { grid-template-columns: 1fr; }
.tile.wide { grid-column: span 1; }
.sub-inner { grid-template-columns: 1fr; gap: 28px; }
}
@media (prefers-reduced-motion: reduce) {
html { 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("show");
clearTimeout(toastTimer);
toastTimer = setTimeout(function () {
toastEl.classList.remove("show");
}, 2600);
}
/* ---------- Sticky condensing header ---------- */
var header = document.getElementById("siteHeader");
function onScroll() {
if (!header) return;
if (window.scrollY > 40) header.classList.add("condensed");
else header.classList.remove("condensed");
}
window.addEventListener("scroll", onScroll, { passive: true });
onScroll();
/* ---------- Mobile menu toggle ---------- */
var menuBtn = document.getElementById("menuBtn");
var sectionNav = document.getElementById("sectionNav");
if (menuBtn && sectionNav) {
menuBtn.addEventListener("click", function () {
var open = sectionNav.classList.toggle("open");
menuBtn.setAttribute("aria-expanded", String(open));
});
sectionNav.querySelectorAll("a").forEach(function (a) {
a.addEventListener("click", function () {
sectionNav.classList.remove("open");
menuBtn.setAttribute("aria-expanded", "false");
});
});
}
/* ---------- Section nav active state ---------- */
if (sectionNav) {
var navLinks = sectionNav.querySelectorAll("a");
navLinks.forEach(function (link) {
link.addEventListener("click", function () {
navLinks.forEach(function (l) { l.classList.remove("active"); });
link.classList.add("active");
});
});
}
/* ---------- Category tab filter ---------- */
var tabs = document.querySelectorAll(".tab");
var tiles = document.querySelectorAll("#grid .tile");
var emptyState = document.getElementById("emptyState");
function applyFilter(cat) {
var visible = 0;
tiles.forEach(function (tile) {
var match = cat === "all" || tile.getAttribute("data-cat") === cat;
tile.classList.toggle("hidden", !match);
if (match) visible++;
});
if (emptyState) emptyState.hidden = visible !== 0;
}
tabs.forEach(function (tab) {
tab.addEventListener("click", function () {
tabs.forEach(function (t) {
t.classList.remove("active");
t.setAttribute("aria-selected", "false");
});
tab.classList.add("active");
tab.setAttribute("aria-selected", "true");
var cat = tab.getAttribute("data-cat");
applyFilter(cat);
toast(cat === "all" ? "Showing all stories" : "Filtered: " + tab.textContent);
});
});
/* ---------- Scroll reveal ---------- */
var reveals = document.querySelectorAll(".reveal");
if ("IntersectionObserver" in window) {
var io = new IntersectionObserver(function (entries) {
entries.forEach(function (entry) {
if (entry.isIntersecting) {
entry.target.classList.add("in");
io.unobserve(entry.target);
}
});
}, { threshold: 0.12, rootMargin: "0px 0px -8% 0px" });
reveals.forEach(function (el) { io.observe(el); });
} else {
reveals.forEach(function (el) { el.classList.add("in"); });
}
/* ---------- Subscribe form ---------- */
var form = document.getElementById("subForm");
var emailInput = document.getElementById("email");
var formMsg = document.getElementById("formMsg");
function setMsg(text, kind) {
if (!formMsg) return;
formMsg.textContent = text;
formMsg.className = "form-msg" + (kind ? " " + kind : "");
}
if (form && emailInput) {
form.addEventListener("submit", function (e) {
e.preventDefault();
var value = emailInput.value.trim();
var valid = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value);
if (!valid) {
setMsg("Please enter a valid email address.", "err");
emailInput.focus();
return;
}
setMsg("You're in — welcome to FOLIO. Issue 042 ships Sunday.", "ok");
toast("Subscribed ✓");
form.reset();
});
}
})();<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>SAVOR — Food Magazine</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],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>
<header class="site-head" id="siteHead" role="banner">
<div class="head-inner">
<a class="brand" href="#top" aria-label="SAVOR home">
<span class="brand-mark">●</span>
<span class="brand-word">SAVOR</span>
</a>
<nav class="nav" aria-label="Sections">
<a href="#recipes">Recipes</a>
<a href="#technique">Technique</a>
<a href="#travel">Travel</a>
<a href="#wine">Wine</a>
</nav>
<div class="head-actions">
<span class="issue-tag">Issue 47 · Summer</span>
<a class="btn btn-solid head-sub" href="#subscribe">Subscribe</a>
</div>
</div>
</header>
<main id="main" tabindex="-1">
<!-- COVER STORY HERO -->
<section class="hero" id="top" aria-labelledby="heroTitle">
<div class="hero-photo" aria-hidden="true">
<span class="blob b1"></span>
<span class="blob b2"></span>
<span class="blob b3"></span>
<span class="hero-emoji e1">🍅</span>
<span class="hero-emoji e2">🌿</span>
<span class="hero-emoji e3">🍋</span>
</div>
<div class="hero-copy">
<p class="kicker">The Cover Story</p>
<h1 id="heroTitle" class="hero-title">The New<br />Summer<br /><em>Table</em></h1>
<p class="hero-dek">
Sun-blistered tomatoes, charred stone fruit, and a vinaigrette
you'll put on everything. Twelve recipes that taste like July.
</p>
<div class="hero-meta">
<span class="byline">Words by <strong>Marlena Ferro</strong></span>
<span class="dot">·</span>
<span class="readtime">14 min read</span>
</div>
<div class="hero-cta">
<a class="btn btn-solid" href="#recipes">Read the story</a>
<a class="btn btn-ghost" href="#trending">See what's trending</a>
</div>
</div>
</section>
<!-- FEATURED GRID -->
<section class="features" id="recipes" aria-labelledby="featTitle">
<div class="section-head reveal">
<div>
<p class="kicker">Featured</p>
<h2 id="featTitle" class="section-title">This Week's Plate</h2>
</div>
<div class="tabs" role="tablist" aria-label="Filter articles by category">
<button class="tab is-active" role="tab" aria-selected="true" data-cat="all">All</button>
<button class="tab" role="tab" aria-selected="false" data-cat="recipes">Recipes</button>
<button class="tab" role="tab" aria-selected="false" data-cat="technique">Technique</button>
<button class="tab" role="tab" aria-selected="false" data-cat="travel">Travel</button>
<button class="tab" role="tab" aria-selected="false" data-cat="wine">Wine</button>
</div>
</div>
<div class="grid" id="featGrid">
<article class="card lg reveal" data-cat="recipes">
<div class="card-photo p-tomato" aria-hidden="true"><span class="ce">🍝</span></div>
<div class="card-body">
<p class="kicker">Recipes</p>
<h3>Bucatini all'Amatriciana, Made Faster</h3>
<p class="excerpt">Guanciale, a whisper of chili, and the trick to a glossy sauce in under 30 minutes.</p>
<span class="readtime">9 min</span>
</div>
</article>
<article class="card reveal" data-cat="technique">
<div class="card-photo p-sage" aria-hidden="true"><span class="ce">🔪</span></div>
<div class="card-body">
<p class="kicker">Technique</p>
<h3>How to Properly Sear a Scallop</h3>
<p class="excerpt">Dry, hot, patient. The golden crust is closer than you think.</p>
<span class="readtime">6 min</span>
</div>
</article>
<article class="card reveal" data-cat="travel">
<div class="card-photo p-clay" aria-hidden="true"><span class="ce">🌍</span></div>
<div class="card-body">
<p class="kicker">Travel</p>
<h3>48 Hours of Eating in Oaxaca</h3>
<p class="excerpt">Mole at dawn, tlayudas at midnight, and every mezcal between.</p>
<span class="readtime">12 min</span>
</div>
</article>
<article class="card reveal" data-cat="wine">
<div class="card-photo p-wine" aria-hidden="true"><span class="ce">🍷</span></div>
<div class="card-body">
<p class="kicker">Wine</p>
<h3>Chilled Reds for a Heatwave</h3>
<p class="excerpt">Six bottles built for the cooler — bright, juicy, and unfussy.</p>
<span class="readtime">5 min</span>
</div>
</article>
<article class="card wide reveal" data-cat="recipes">
<div class="card-photo p-saffron" aria-hidden="true"><span class="ce">🥘</span></div>
<div class="card-body">
<p class="kicker">Recipes</p>
<h3>The One-Pan Saffron Chicken Everyone Asks About</h3>
<p class="excerpt">Crisp skin, soft fennel, and a broth you'll mop up with crusty bread.</p>
<span class="readtime">11 min</span>
</div>
</article>
<article class="card reveal" data-cat="technique">
<div class="card-photo p-ink" aria-hidden="true"><span class="ce">🍞</span></div>
<div class="card-body">
<p class="kicker">Technique</p>
<h3>Sourdough Without the Anxiety</h3>
<p class="excerpt">A forgiving schedule for people with actual jobs.</p>
<span class="readtime">8 min</span>
</div>
</article>
</div>
<p class="empty" id="emptyState" hidden>No stories in this section yet — try another tab.</p>
</section>
<!-- TRENDING STRIP -->
<section class="trending" id="trending" aria-labelledby="trendTitle">
<div class="trend-head reveal">
<p class="kicker">Right now</p>
<h2 id="trendTitle" class="section-title">Trending Recipes</h2>
</div>
<ol class="trend-list">
<li class="trend reveal"><span class="rank">01</span><span class="t-emoji">🍑</span><div><h4>Grilled Peach & Burrata</h4><span class="readtime">7 min</span></div></li>
<li class="trend reveal"><span class="rank">02</span><span class="t-emoji">🥗</span><div><h4>Crunchy Charred Corn Salad</h4><span class="readtime">5 min</span></div></li>
<li class="trend reveal"><span class="rank">03</span><span class="t-emoji">🍤</span><div><h4>Garlic Butter Shrimp Skewers</h4><span class="readtime">9 min</span></div></li>
<li class="trend reveal"><span class="rank">04</span><span class="t-emoji">🍨</span><div><h4>No-Churn Olive Oil Gelato</h4><span class="readtime">4 min</span></div></li>
<li class="trend reveal"><span class="rank">05</span><span class="t-emoji">🌽</span><div><h4>Elote Three Ways</h4><span class="readtime">6 min</span></div></li>
</ol>
</section>
<!-- SECTIONS RAIL -->
<section class="sections" aria-labelledby="secTitle">
<h2 id="secTitle" class="visually-hidden">Browse by section</h2>
<a class="sec-card reveal" href="#recipes"><span class="se">🍳</span><span>Recipes</span></a>
<a class="sec-card reveal" href="#technique"><span class="se">🧑🍳</span><span>Technique</span></a>
<a class="sec-card reveal" href="#travel"><span class="se">✈️</span><span>Travel</span></a>
<a class="sec-card reveal" href="#wine"><span class="se">🍇</span><span>Wine</span></a>
</section>
<!-- SUBSCRIBE BAND -->
<section class="subscribe" id="subscribe" aria-labelledby="subTitle">
<div class="sub-inner reveal">
<div class="sub-copy">
<p class="kicker on-dark">Join the table</p>
<h2 id="subTitle" class="section-title on-dark">A new recipe in your inbox every Friday.</h2>
<p class="sub-dek">No spam, no filler. Just one excellent thing to cook this weekend.</p>
</div>
<form class="sub-form" id="subForm" novalidate>
<label class="visually-hidden" for="subEmail">Email address</label>
<input id="subEmail" name="email" type="email" inputmode="email" autocomplete="email"
placeholder="[email protected]" required aria-describedby="subMsg" />
<button class="btn btn-solid" type="submit">Subscribe</button>
<p class="sub-msg" id="subMsg" role="status" aria-live="polite"></p>
</form>
</div>
</section>
</main>
<footer class="site-foot" role="contentinfo">
<p>SAVOR Magazine · Issue 47 — illustrative demo. Recipes & data are fictional.</p>
</footer>
<div class="toast" id="toast" role="status" aria-live="polite"></div>
<script src="script.js"></script>
</body>
</html>Food Magazine (Bon Appétit-style) landing
A glossy, high-contrast magazine front page for a fictional food title, FOLIO. The cover story opens with a full-bleed gradient “photo” frame, a big editorial headline in Fraunces, an issue tag, and a byline — the magazine voice set before you scroll. Below it, a featured-stories grid mixes tall, wide, and standard tiles with kickers and read-times, followed by a horizontally scrollable trending-recipes strip and a bold black subscribe band.
All food imagery is built from layered CSS gradients, radial blobs, and tasteful emoji accents — no images or external libraries. The sticky header condenses on scroll, story tiles and recipe cards animate in via an IntersectionObserver scroll-reveal, and the section tabs filter the grid live (with an empty state when a category is unused). The subscribe form validates the email client-side and confirms with an accessible aria-live message plus a toast.
Everything is keyboard-usable with visible focus rings, landmark roles, and AA-contrast type, and the multi-column layouts collapse cleanly to a single column on small screens with a toggleable mobile menu.
Illustrative UI only — recipes & nutrition data are fictional, not dietary advice.