Cookbook — Recipe Page (ingredients · steps · notes)
A polished editorial recipe page for a cookbook library, pairing a serif headline with a warm cream layout. A gradient food-photo hero opens onto meta badges for prep, cook and total time, servings and diet tags, then a two-column body of check-off ingredients beside numbered method steps with inline tips and notes. A sticky action bar saves, prints and shares, and a live counter tracks how many ingredients you have gathered.
MCP
Code
:root {
--cream: #faf6ef;
--paper: #fffdf8;
--ink: #2b2622;
--ink-2: #5c534a;
--muted: #8a7f73;
--tomato: #d6452b;
--tomato-d: #b8351e;
--saffron: #e8a33d;
--sage: #7c8a6b;
--clay: #c8775a;
--line: rgba(43, 38, 34, 0.12);
--line-2: rgba(43, 38, 34, 0.2);
--ok: #3f8f5f;
--warn: #d98a2b;
--danger: #c8412b;
--r-sm: 8px;
--r-md: 14px;
--r-lg: 22px;
--shadow-sm: 0 1px 2px rgba(43, 38, 34, 0.1);
--shadow-lg: 0 10px 30px rgba(43, 38, 34, 0.1);
--serif: "Fraunces", Georgia, serif;
--sans: "Inter", system-ui, -apple-system, sans-serif;
}
*,
*::before,
*::after {
box-sizing: border-box;
}
html {
scroll-behavior: smooth;
}
body {
margin: 0;
font-family: var(--sans);
font-size: 16px;
line-height: 1.6;
color: var(--ink);
background-color: var(--cream);
background-image:
radial-gradient(circle at 12% 8%, rgba(232, 163, 61, 0.08), transparent 38%),
radial-gradient(circle at 88% 92%, rgba(124, 138, 107, 0.08), transparent 40%);
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
a {
color: var(--tomato-d);
text-decoration: none;
}
:focus-visible {
outline: 2.5px solid var(--tomato);
outline-offset: 3px;
border-radius: 4px;
}
/* ---------- Top bar ---------- */
.topbar {
display: flex;
align-items: center;
justify-content: space-between;
gap: 1rem;
padding: 0.9rem clamp(1rem, 4vw, 2.5rem);
background: var(--paper);
border-bottom: 1px solid var(--line);
position: sticky;
top: 0;
z-index: 30;
}
.brand {
display: inline-flex;
align-items: center;
gap: 0.55rem;
color: var(--ink);
}
.brand-mark {
font-size: 1.4rem;
}
.brand-name {
font-family: var(--serif);
font-weight: 600;
font-size: 1.15rem;
letter-spacing: 0.01em;
}
.topnav {
display: flex;
gap: 1.4rem;
}
.topnav a {
color: var(--ink-2);
font-size: 0.86rem;
font-weight: 500;
letter-spacing: 0.04em;
text-transform: uppercase;
padding: 0.25rem 0;
border-bottom: 2px solid transparent;
transition: color 0.15s, border-color 0.15s;
}
.topnav a:hover {
color: var(--tomato-d);
border-bottom-color: var(--saffron);
}
/* ---------- Layout ---------- */
main {
max-width: 1080px;
margin: 0 auto;
padding: clamp(1.25rem, 4vw, 3rem) clamp(1rem, 4vw, 2.5rem) 3rem;
}
.recipe {
display: block;
}
/* ---------- Hero ---------- */
.hero {
display: grid;
grid-template-columns: 1.05fr 1fr;
gap: clamp(1.5rem, 4vw, 3rem);
align-items: center;
margin-bottom: 2rem;
}
.hero-photo {
position: relative;
margin: 0;
aspect-ratio: 4 / 3;
border-radius: var(--r-lg);
overflow: hidden;
border: 6px solid var(--paper);
box-shadow: var(--shadow-lg);
background:
radial-gradient(circle at 30% 28%, rgba(255, 255, 255, 0.5), transparent 45%),
radial-gradient(circle at 70% 30%, var(--tomato) 0 14%, transparent 32%),
radial-gradient(circle at 38% 62%, var(--clay) 0 12%, transparent 30%),
radial-gradient(circle at 64% 70%, var(--saffron) 0 16%, transparent 34%),
radial-gradient(circle at 50% 50%, #e9b15c, #d6452b 78%);
}
.hero-photo::after {
content: "";
position: absolute;
inset: 0;
background: radial-gradient(circle at 50% 120%, rgba(43, 38, 34, 0.28), transparent 60%);
}
.hero-emoji {
position: absolute;
font-size: clamp(1.6rem, 4vw, 2.6rem);
filter: drop-shadow(0 3px 6px rgba(43, 38, 34, 0.35));
z-index: 1;
}
.hero-emoji--1 { top: 18%; left: 22%; transform: rotate(-12deg); }
.hero-emoji--2 { top: 26%; right: 20%; transform: rotate(10deg); }
.hero-emoji--3 { bottom: 22%; left: 28%; transform: rotate(8deg); }
.hero-emoji--4 { bottom: 24%; right: 26%; transform: rotate(-8deg); }
.kicker {
margin: 0 0 0.5rem;
font-size: 0.78rem;
font-weight: 600;
letter-spacing: 0.16em;
text-transform: uppercase;
color: var(--clay);
}
.dish-title {
font-family: var(--serif);
font-weight: 600;
font-size: clamp(2rem, 5vw, 3rem);
line-height: 1.08;
margin: 0 0 0.85rem;
color: var(--ink);
}
.intro {
margin: 0 0 1.4rem;
color: var(--ink-2);
font-size: 1.02rem;
}
.dropcap {
float: left;
font-family: var(--serif);
font-weight: 700;
font-size: 3.2rem;
line-height: 0.74;
padding: 0.1rem 0.5rem 0 0;
color: var(--tomato);
}
.meta {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
list-style: none;
margin: 0 0 1rem;
padding: 0;
}
.meta-item {
display: flex;
flex-direction: column;
gap: 0.1rem;
padding: 0.5rem 0.85rem;
background: var(--paper);
border: 1px solid var(--line);
border-radius: var(--r-sm);
box-shadow: var(--shadow-sm);
}
.meta-item--total {
border-color: var(--saffron);
background: linear-gradient(180deg, #fff6e6, var(--paper));
}
.meta-label {
font-size: 0.66rem;
font-weight: 600;
letter-spacing: 0.1em;
text-transform: uppercase;
color: var(--muted);
}
.meta-value {
font-family: var(--serif);
font-weight: 600;
font-size: 1.02rem;
color: var(--ink);
}
.diet-tags {
display: flex;
flex-wrap: wrap;
gap: 0.45rem;
list-style: none;
margin: 0;
padding: 0;
}
.tag {
font-size: 0.78rem;
font-weight: 600;
padding: 0.3rem 0.7rem;
border-radius: 999px;
border: 1px solid var(--line-2);
color: var(--ink-2);
background: var(--paper);
}
.tag--veg { color: var(--sage); border-color: rgba(124, 138, 107, 0.5); background: #f1f4ec; }
.tag--one { color: var(--clay); border-color: rgba(200, 119, 90, 0.5); background: #f9efe9; }
/* ---------- Action bar ---------- */
.actionbar {
position: sticky;
top: 64px;
z-index: 20;
display: flex;
flex-wrap: wrap;
gap: 0.6rem;
padding: 0.7rem;
margin: 0 0 2.25rem;
background: rgba(255, 253, 248, 0.92);
backdrop-filter: blur(8px);
border: 1px solid var(--line);
border-radius: var(--r-md);
box-shadow: var(--shadow-sm);
}
.btn {
display: inline-flex;
align-items: center;
gap: 0.45rem;
font-family: var(--sans);
font-size: 0.9rem;
font-weight: 600;
padding: 0.6rem 1rem;
border-radius: var(--r-sm);
border: 1px solid var(--line-2);
background: var(--paper);
color: var(--ink);
cursor: pointer;
transition: transform 0.12s, box-shadow 0.15s, background 0.15s, color 0.15s;
}
.btn:hover {
box-shadow: var(--shadow-sm);
transform: translateY(-1px);
}
.btn:active {
transform: translateY(0);
}
.btn--ghost:hover {
background: #fdf3e7;
}
.btn--solid {
background: var(--tomato);
border-color: var(--tomato-d);
color: #fff;
}
.btn--solid:hover {
background: var(--tomato-d);
}
.btn--jump {
margin-left: auto;
}
.btn[aria-pressed="true"] {
background: var(--sage);
border-color: var(--sage);
color: #fff;
}
.btn-icon {
font-size: 1rem;
line-height: 1;
}
.btn--block {
width: 100%;
justify-content: center;
margin-top: 1rem;
}
/* ---------- Body grid ---------- */
.body {
display: grid;
grid-template-columns: 0.85fr 1.15fr;
gap: clamp(1.5rem, 3vw, 2.5rem);
align-items: start;
}
.section-title {
font-family: var(--serif);
font-weight: 600;
font-size: 1.5rem;
margin: 0 0 1rem;
color: var(--ink);
}
/* ---------- Ingredients ---------- */
.ingredients {
position: sticky;
top: 130px;
}
.panel {
background: var(--paper);
border: 1px solid var(--line);
border-radius: var(--r-lg);
padding: 1.5rem;
box-shadow: var(--shadow-lg);
}
.panel-head {
display: flex;
align-items: baseline;
justify-content: space-between;
gap: 0.5rem;
flex-wrap: wrap;
margin-bottom: 0.5rem;
}
.panel-head .section-title {
margin: 0;
}
.ing-count {
margin: 0;
font-size: 0.8rem;
font-weight: 600;
color: var(--muted);
}
.ing-group-title {
font-size: 0.74rem;
font-weight: 700;
letter-spacing: 0.12em;
text-transform: uppercase;
color: var(--clay);
margin: 1.1rem 0 0.5rem;
}
.ing-list {
list-style: none;
margin: 0;
padding: 0;
}
.ing {
border-bottom: 1px dashed var(--line);
}
.ing:last-child {
border-bottom: none;
}
.ing-check {
display: flex;
align-items: flex-start;
gap: 0.7rem;
padding: 0.6rem 0.2rem;
cursor: pointer;
}
.ing-check input {
position: absolute;
opacity: 0;
width: 1px;
height: 1px;
}
.ing-box {
flex: 0 0 auto;
width: 1.25rem;
height: 1.25rem;
margin-top: 0.15rem;
border: 2px solid var(--line-2);
border-radius: 6px;
background: var(--cream);
display: grid;
place-items: center;
transition: background 0.15s, border-color 0.15s;
}
.ing-box::after {
content: "✓";
font-size: 0.85rem;
font-weight: 700;
color: #fff;
opacity: 0;
transform: scale(0.6);
transition: opacity 0.15s, transform 0.15s;
}
.ing-check input:checked ~ .ing-box {
background: var(--sage);
border-color: var(--sage);
}
.ing-check input:checked ~ .ing-box::after {
opacity: 1;
transform: scale(1);
}
.ing-check input:focus-visible ~ .ing-box {
outline: 2.5px solid var(--tomato);
outline-offset: 2px;
}
.ing-text {
color: var(--ink);
transition: color 0.15s;
}
.ing-check input:checked ~ .ing-text {
text-decoration: line-through;
text-decoration-color: var(--muted);
color: var(--muted);
}
.amt {
font-weight: 700;
color: var(--tomato-d);
}
.ing-check input:checked ~ .ing-text .amt {
color: var(--muted);
}
.note-inline {
color: var(--muted);
font-style: italic;
font-size: 0.85rem;
}
/* ---------- Steps ---------- */
.step-list {
list-style: none;
margin: 0 0 2.5rem;
padding: 0;
counter-reset: step;
}
.step {
display: grid;
grid-template-columns: auto 1fr;
gap: 1.1rem;
padding: 1.1rem 0;
border-top: 1px solid var(--line);
}
.step:first-child {
border-top: none;
padding-top: 0;
}
.step-num {
flex: 0 0 auto;
width: 2.4rem;
height: 2.4rem;
display: grid;
place-items: center;
border-radius: 50%;
background: linear-gradient(160deg, var(--saffron), var(--clay));
color: #fff;
font-family: var(--serif);
font-weight: 700;
font-size: 1.2rem;
box-shadow: var(--shadow-sm);
}
.step-body p {
margin: 0 0 0.6rem;
color: var(--ink-2);
}
.step-body p:last-child {
margin-bottom: 0;
}
.tip,
.note {
display: flex;
gap: 0.5rem;
font-size: 0.9rem;
padding: 0.65rem 0.8rem;
border-radius: var(--r-sm);
border-left: 3px solid var(--saffron);
background: #fff6e6;
color: var(--ink-2);
}
.note {
border-left-color: var(--sage);
background: #f1f4ec;
}
.tip-icon {
flex: 0 0 auto;
}
/* ---------- Notes ---------- */
.cooknotes {
background: var(--paper);
border: 1px solid var(--line);
border-radius: var(--r-lg);
padding: 1.5rem;
box-shadow: var(--shadow-sm);
}
.notes-list {
margin: 0;
padding-left: 1.1rem;
color: var(--ink-2);
}
.notes-list li {
margin-bottom: 0.5rem;
}
.notes-list strong {
color: var(--ink);
}
/* ---------- Footer ---------- */
.sitefoot {
text-align: center;
padding: 2rem 1rem;
color: var(--muted);
font-size: 0.85rem;
border-top: 1px solid var(--line);
}
/* ---------- Toast ---------- */
.toast {
position: fixed;
left: 50%;
bottom: 1.5rem;
transform: translateX(-50%) translateY(140%);
background: var(--ink);
color: var(--paper);
font-size: 0.9rem;
font-weight: 500;
padding: 0.7rem 1.2rem;
border-radius: 999px;
box-shadow: var(--shadow-lg);
z-index: 50;
opacity: 0;
transition: transform 0.3s ease, opacity 0.3s ease;
pointer-events: none;
}
.toast.show {
transform: translateX(-50%) translateY(0);
opacity: 1;
}
/* ---------- Responsive ---------- */
@media (max-width: 860px) {
.hero {
grid-template-columns: 1fr;
}
.body {
grid-template-columns: 1fr;
}
.ingredients {
position: static;
}
.actionbar {
top: 60px;
}
}
@media (max-width: 720px) {
.topnav {
display: none;
}
}
@media (max-width: 480px) {
.btn--jump {
margin-left: 0;
width: 100%;
justify-content: center;
}
.btn span:not(.btn-icon) {
font-size: 0.85rem;
}
}
/* ---------- Print ---------- */
@media print {
body {
background: #fff;
}
.topbar,
.actionbar,
.btn,
.sitefoot,
.toast,
.hero-photo {
display: none !important;
}
.hero {
grid-template-columns: 1fr;
margin-bottom: 1rem;
}
.body {
grid-template-columns: 1fr 1fr;
}
.panel,
.cooknotes {
box-shadow: none;
border: 1px solid #ccc;
}
.dish-title {
font-size: 1.8rem;
}
a[href]::after {
content: "";
}
}(function () {
"use strict";
/* ---------- Toast helper ---------- */
var toastEl = document.getElementById("toast");
var toastTimer = null;
function toast(msg) {
if (!toastEl) return;
toastEl.textContent = msg;
toastEl.classList.add("show");
clearTimeout(toastTimer);
toastTimer = setTimeout(function () {
toastEl.classList.remove("show");
}, 2200);
}
/* ---------- Ingredient check-off ---------- */
var checkboxes = Array.prototype.slice.call(
document.querySelectorAll(".ing-check input[type='checkbox']")
);
var countEl = document.getElementById("ingCount");
var total = checkboxes.length;
function updateCount() {
var done = checkboxes.filter(function (cb) {
return cb.checked;
}).length;
if (countEl) {
countEl.textContent = done + " of " + total + " gathered";
}
if (done === total && total > 0) {
toast("All ingredients gathered — let's cook 🍳");
}
}
checkboxes.forEach(function (cb) {
cb.addEventListener("change", updateCount);
});
updateCount();
/* ---------- Reset checklist ---------- */
var clearBtn = document.getElementById("clearBtn");
if (clearBtn) {
clearBtn.addEventListener("click", function () {
checkboxes.forEach(function (cb) {
cb.checked = false;
});
updateCount();
toast("Checklist reset");
});
}
/* ---------- Save (toggle) ---------- */
var saveBtn = document.getElementById("saveBtn");
if (saveBtn) {
saveBtn.addEventListener("click", function () {
var saved = saveBtn.getAttribute("aria-pressed") === "true";
saved = !saved;
saveBtn.setAttribute("aria-pressed", String(saved));
var label = saveBtn.querySelector("span:last-child");
if (label) label.textContent = saved ? "Saved" : "Save";
toast(saved ? "Recipe saved to your book 🔖" : "Removed from saved");
});
}
/* ---------- Print ---------- */
var printBtn = document.getElementById("printBtn");
if (printBtn) {
printBtn.addEventListener("click", function () {
window.print();
});
}
/* ---------- Share ---------- */
var shareBtn = document.getElementById("shareBtn");
if (shareBtn) {
shareBtn.addEventListener("click", function () {
var data = {
title: document.title,
text: "Charred Tomato & Saffron Orzo — a 37-minute one-pan supper.",
url: window.location.href,
};
if (navigator.share) {
navigator.share(data).catch(function () {});
return;
}
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard
.writeText(data.url)
.then(function () {
toast("Link copied to clipboard 🔗");
})
.catch(function () {
toast("Couldn't copy link");
});
} else {
toast("Share: " + data.url);
}
});
}
})();<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Charred Tomato & Saffron Orzo — Cookbook</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,wght@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>
<header class="topbar" role="banner">
<a class="brand" href="#top">
<span class="brand-mark" aria-hidden="true">🍅</span>
<span class="brand-name">The Slow Pantry</span>
</a>
<nav class="topnav" aria-label="Cookbook sections">
<a href="#ingredients">Ingredients</a>
<a href="#steps">Method</a>
<a href="#notes">Notes</a>
</nav>
</header>
<main id="top" role="main">
<article class="recipe">
<!-- HERO -->
<header class="hero">
<figure class="hero-photo" role="img" aria-label="Bowl of charred tomato and saffron orzo garnished with herbs">
<span class="hero-emoji hero-emoji--1" aria-hidden="true">🍅</span>
<span class="hero-emoji hero-emoji--2" aria-hidden="true">🌿</span>
<span class="hero-emoji hero-emoji--3" aria-hidden="true">🍋</span>
<span class="hero-emoji hero-emoji--4" aria-hidden="true">🧄</span>
</figure>
<div class="hero-text">
<p class="kicker">Mediterranean · Weeknight</p>
<h1 class="dish-title">Charred Tomato & Saffron Orzo</h1>
<p class="intro">
<span class="dropcap">A</span> one-pan supper that tastes like a long Sunday but cooks
in under forty minutes. Blistered cherry tomatoes melt into a saffron-stained broth,
the orzo drinks it all up, and a shower of lemon and basil pulls it bright at the end.
</p>
<ul class="meta" aria-label="Recipe details">
<li class="meta-item"><span class="meta-label">Prep</span><span class="meta-value">15 min</span></li>
<li class="meta-item"><span class="meta-label">Cook</span><span class="meta-value">22 min</span></li>
<li class="meta-item meta-item--total"><span class="meta-label">Total</span><span class="meta-value">37 min</span></li>
<li class="meta-item"><span class="meta-label">Serves</span><span class="meta-value">4</span></li>
<li class="meta-item"><span class="meta-label">Difficulty</span><span class="meta-value">Easy</span></li>
</ul>
<ul class="diet-tags" aria-label="Dietary tags">
<li class="tag tag--veg">🌿 Vegetarian</li>
<li class="tag tag--df">Dairy-free option</li>
<li class="tag tag--one">🍲 One pan</li>
</ul>
</div>
</header>
<!-- ACTION BAR (sticky) -->
<div class="actionbar" role="toolbar" aria-label="Recipe actions">
<button type="button" class="btn btn--ghost" id="saveBtn" aria-pressed="false">
<span class="btn-icon" aria-hidden="true">🔖</span><span>Save</span>
</button>
<button type="button" class="btn btn--ghost" id="printBtn">
<span class="btn-icon" aria-hidden="true">🖨️</span><span>Print</span>
</button>
<button type="button" class="btn btn--ghost" id="shareBtn">
<span class="btn-icon" aria-hidden="true">🔗</span><span>Share</span>
</button>
<a class="btn btn--solid btn--jump" href="#steps">
<span>Jump to method</span><span class="btn-icon" aria-hidden="true">↓</span>
</a>
</div>
<!-- BODY -->
<div class="body">
<!-- INGREDIENTS -->
<section class="ingredients" id="ingredients" aria-labelledby="ing-h">
<div class="panel">
<div class="panel-head">
<h2 class="section-title" id="ing-h">Ingredients</h2>
<p class="ing-count" aria-live="polite" id="ingCount">0 of 11 gathered</p>
</div>
<h3 class="ing-group-title">For the orzo</h3>
<ul class="ing-list" id="ingList">
<li class="ing">
<label class="ing-check">
<input type="checkbox" />
<span class="ing-box" aria-hidden="true"></span>
<span class="ing-text"><span class="amt">2 tbsp</span> olive oil</span>
</label>
</li>
<li class="ing">
<label class="ing-check">
<input type="checkbox" />
<span class="ing-box" aria-hidden="true"></span>
<span class="ing-text"><span class="amt">4 cloves</span> garlic, thinly sliced</span>
</label>
</li>
<li class="ing">
<label class="ing-check">
<input type="checkbox" />
<span class="ing-box" aria-hidden="true"></span>
<span class="ing-text"><span class="amt">1 pinch</span> saffron threads</span>
</label>
</li>
<li class="ing">
<label class="ing-check">
<input type="checkbox" />
<span class="ing-box" aria-hidden="true"></span>
<span class="ing-text"><span class="amt">500 g</span> cherry tomatoes</span>
</label>
</li>
<li class="ing">
<label class="ing-check">
<input type="checkbox" />
<span class="ing-box" aria-hidden="true"></span>
<span class="ing-text"><span class="amt">300 g</span> dried orzo</span>
</label>
</li>
<li class="ing">
<label class="ing-check">
<input type="checkbox" />
<span class="ing-box" aria-hidden="true"></span>
<span class="ing-text"><span class="amt">750 ml</span> hot vegetable stock</span>
</label>
</li>
<li class="ing">
<label class="ing-check">
<input type="checkbox" />
<span class="ing-box" aria-hidden="true"></span>
<span class="ing-text"><span class="amt">1 tsp</span> smoked paprika</span>
</label>
</li>
</ul>
<h3 class="ing-group-title">To finish</h3>
<ul class="ing-list" id="ingList2">
<li class="ing">
<label class="ing-check">
<input type="checkbox" />
<span class="ing-box" aria-hidden="true"></span>
<span class="ing-text"><span class="amt">1</span> lemon, zest & juice</span>
</label>
</li>
<li class="ing">
<label class="ing-check">
<input type="checkbox" />
<span class="ing-box" aria-hidden="true"></span>
<span class="ing-text"><span class="amt">1 handful</span> fresh basil, torn</span>
</label>
</li>
<li class="ing">
<label class="ing-check">
<input type="checkbox" />
<span class="ing-box" aria-hidden="true"></span>
<span class="ing-text"><span class="amt">40 g</span> feta, crumbled <span class="note-inline">(optional)</span></span>
</label>
</li>
<li class="ing">
<label class="ing-check">
<input type="checkbox" />
<span class="ing-box" aria-hidden="true"></span>
<span class="ing-text"><span class="amt">to taste</span> sea salt & black pepper</span>
</label>
</li>
</ul>
<button type="button" class="btn btn--ghost btn--block" id="clearBtn">Reset checklist</button>
</div>
</section>
<!-- STEPS -->
<section class="steps" id="steps" aria-labelledby="steps-h">
<h2 class="section-title" id="steps-h">Method</h2>
<ol class="step-list">
<li class="step">
<div class="step-num" aria-hidden="true">1</div>
<div class="step-body">
<p>Warm the olive oil in a wide, deep pan over medium heat. Add the sliced garlic and saffron and let them sizzle for about a minute, just until the garlic turns pale gold and fragrant.</p>
</div>
</li>
<li class="step">
<div class="step-num" aria-hidden="true">2</div>
<div class="step-body">
<p>Tip in the cherry tomatoes and smoked paprika. Cook for 6–8 minutes, pressing the tomatoes gently with a spoon, until their skins blister and burst and the pan smells deeply savoury.</p>
<p class="tip"><span class="tip-icon" aria-hidden="true">💡</span> Resist stirring too early — a little char on the tomato skins is where the flavour lives.</p>
</div>
</li>
<li class="step">
<div class="step-num" aria-hidden="true">3</div>
<div class="step-body">
<p>Stir in the dried orzo and toast for 1 minute, coating every grain in the saffron oil. Pour in the hot vegetable stock and bring to a gentle simmer.</p>
</div>
</li>
<li class="step">
<div class="step-num" aria-hidden="true">4</div>
<div class="step-body">
<p>Simmer uncovered for 10–12 minutes, stirring often, until the orzo is tender and the liquid has thickened to a glossy, risotto-like sauce. Add a splash more stock if it tightens too much.</p>
<p class="note"><span class="tip-icon" aria-hidden="true">📝</span> Note: orzo keeps absorbing liquid off the heat — pull it a touch looser than you think.</p>
</div>
</li>
<li class="step">
<div class="step-num" aria-hidden="true">5</div>
<div class="step-body">
<p>Off the heat, fold through the lemon zest, lemon juice and most of the basil. Season generously. Spoon into warm bowls, scatter with feta and the reserved basil, and serve at once.</p>
</div>
</li>
</ol>
<!-- NOTES -->
<section class="cooknotes" id="notes" aria-labelledby="notes-h">
<h2 class="section-title" id="notes-h">Cook’s notes</h2>
<ul class="notes-list">
<li><strong>Make it vegan:</strong> skip the feta or swap for a marinated almond ricotta.</li>
<li><strong>Add greens:</strong> stir a few handfuls of baby spinach in with the lemon at the end.</li>
<li><strong>Storage:</strong> keeps 3 days chilled; loosen with a splash of stock when reheating.</li>
</ul>
</section>
</section>
</div>
</article>
</main>
<footer class="sitefoot" role="contentinfo">
<p>The Slow Pantry — illustrative cookbook UI. Recipe & nutrition data are fictional.</p>
</footer>
<div class="toast" id="toast" role="status" aria-live="polite"></div>
<script src="script.js"></script>
</body>
</html>Recipe Page (ingredients · steps · notes)
A full cookbook recipe detail page built with an editorial serif/sans pairing on warm cream surfaces. The hero uses layered CSS radial gradients and food emoji to evoke a glossy food photograph — no images or libraries — beside a serif dish title, a cuisine kicker, a drop-cap intro, and a row of meta badges (prep, cook, total time, servings, difficulty) plus dietary tags.
The two-column body keeps a sticky ingredient checklist on the left and numbered method steps on the right, with inline tip and note callouts. Tick ingredients off and they strike through while a live counter reports how many of the eleven you have gathered; a reset button clears the list. The sticky action bar saves the recipe (toggling its pressed state), prints via the browser dialog, and shares using the Web Share API with a clipboard fallback. A “jump to method” anchor scrolls to the steps.
Everything is keyboard-usable with visible focus rings, aria-live regions for the counter and toast, and a print stylesheet that drops the chrome for a clean recipe card.
Illustrative UI only — recipes & nutrition data are fictional, not dietary advice.