A design pass: the type ladder from the logo, and one name per thing

TYPOGRAPHY, taken from the lockup and walked down to something you can read a paragraph in. "The Vine" in
LeJour Script over COFFEEHOUSE + BAKERY in AdBhashitha is the whole brand voice, so: the script stays in
the wordmark and nowhere else (it is unreadable at length); AdBhashitha carries h1–h4 and the price, and
keeps the wordmark's 0.01em letter-spacing so a heading sits on the same rhythm as the logo above it;
`eyebrow` and `label` are the hinge — sans, but letterspaced like the tagline — and then plain Raleway.
Sizes are declared once in type.css instead of being re-chosen per template, and none of the type classes
set a colour, because the same heading appears in sage on cream and in cream on sage.

BUTTONS AND SURFACES have names now. `panel` is the white box that was "bg-white rounded-3xl shadow-xs"
written out in nine places (which is how two of them end up with different corners); `panel-lift` is one
that reacts. `pill` is one shape in four colourways, which exist because this site puts buttons on cream
AND on sage and they cannot be the same colour on both. `chip`/`chip-on` are the products filter.

RHYTHM: `section` (py-16 md:py-24) and `band` (py-14 md:py-20, tighter because a coloured strip is already
doing the separating) replace nine hand-picked paddings.

FOCUS: one visible ring for everything reachable by keyboard, as an outline rather than a shadow so it
works on cream, on white and on the sage bands, at zero specificity so a utility can still win.

Z-INDEX: written down in base.css, all two of it — 40 the sticky header, 30 the mobile panel, which is a
child of the header and so can only ever sit under the bar. Everything else stacks in document order. The
point of the comment is that a third layer doesn't get invented at 9999.

DROPDOWNS: the admin's category selects were drawing the platform's own arrow in the platform's grey; they
get the site's chevron and room for it.

53 tests green. Every class used across all nine pages — five public, four admin — resolves in the
compiled stylesheet, so nothing here is styled by a name that doesn't exist.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
This commit is contained in:
2026-07-26 18:10:47 -05:00
co-authored by Claude Opus 5
parent 8d54db7c30
commit 6b6ddcea42
14 changed files with 266 additions and 76 deletions
+15 -17
View File
@@ -8,7 +8,7 @@
that is selling something, and the same treatment as the homepage hero — blurred photo, sage wash —
carries the brand rather than inventing a new look for it.
*/-->
<section class="relative flex items-center py-14 md:py-20 bg-bakery-900 text-white overflow-hidden">
<section class="band relative flex items-center bg-bakery-900 text-white overflow-hidden">
<img th:src="${photos.of('gallery/Cakes.webp')}" alt=""
class="absolute inset-0 w-full h-full object-cover blur-[3px] scale-110">
<div class="absolute inset-0 bg-bakery-900/80"></div>
@@ -16,9 +16,9 @@
<div class="relative container mx-auto px-4 w-full min-w-0">
<div class="max-w-3xl mx-auto text-center">
<p class="text-xs sm:text-sm uppercase tracking-[0.2em] text-bakery-200">Order ahead</p>
<h1 class="mt-3 font-adbhashitha text-4xl md:text-5xl text-bakery-50">Goodie boxes &amp; catering</h1>
<p class="mt-5 text-base sm:text-lg text-bakery-100 text-balance leading-relaxed">
<p class="eyebrow text-bakery-200">Order ahead</p>
<h1 class="h1 mt-3 text-bakery-50">Goodie boxes &amp; catering</h1>
<p class="lede mt-5 text-bakery-100">
Boxes for the office, packages for a party, and cakes and desserts for a wedding.
</p>
</div>
@@ -55,7 +55,7 @@
*/-->
<section th:each="table : ${menu.packages}">
<header class="max-w-2xl mx-auto text-center">
<h2 class="font-adbhashitha text-3xl md:text-4xl text-bakery-900" th:text="${table.name}">Office boxes</h2>
<h2 class="h2 text-bakery-900" th:text="${table.name}">Office boxes</h2>
<p th:if="${table.blurb}" class="mt-3 text-bakery-700 leading-relaxed" th:text="${table.blurb}">
Mini pastries for a morning meeting.
</p>
@@ -67,12 +67,11 @@
: (${#lists.size(table.tiers) == 2} ? 'sm:grid-cols-2 max-w-3xl mx-auto'
: 'sm:grid-cols-2 lg:grid-cols-3')">
<article th:each="tier, t : ${table.tiers}"
class="flex flex-col bg-white rounded-3xl shadow-xs p-6 md:p-8
transition-shadow duration-300 hover:shadow-lg">
<p class="text-xs uppercase tracking-[0.15em] text-bakery-600" th:text="${tier.label}">Small</p>
<p th:if="${tier.price}" class="mt-2 font-adbhashitha text-4xl text-bakery-900" th:text="${tier.price}">$24</p>
class="flex flex-col panel-lift p-6 md:p-8">
<p class="label text-bakery-600" th:text="${tier.label}">Small</p>
<p th:if="${tier.price}" class="price mt-2 text-bakery-900" th:text="${tier.price}">$24</p>
<!--/* No price means "ask us" — say so rather than leaving a hole in the card. */-->
<p th:unless="${tier.price}" class="mt-2 font-adbhashitha text-2xl text-bakery-700">Ask us</p>
<p th:unless="${tier.price}" class="price mt-2 text-2xl text-bakery-700">Ask us</p>
<!--/* "Small" doesn't tell anyone how many it feeds. A column whose heading is already a
head count leaves this blank rather than saying it twice. */-->
<p th:if="${tier.serves}" class="mt-1 text-sm text-bakery-600" th:text="${tier.serves}">About 68 people</p>
@@ -107,14 +106,13 @@
*/-->
<div class="mt-8 max-w-2xl mx-auto text-center">
<div th:if="${!#lists.isEmpty(table.notes)}">
<h3 class="text-xs uppercase tracking-[0.15em] text-bakery-500 font-medium">Good to know</h3>
<h3 class="label text-bakery-500">Good to know</h3>
<ul class="mt-3 space-y-2 text-sm text-bakery-700">
<li th:each="note : ${table.notes}" th:text="${note}">Everything is baked in sixes.</li>
</ul>
</div>
<a th:href="|/contact?about=${#uris.escapeQueryParam(table.name)}|"
class="mt-6 inline-block border border-bakery-300 hover:bg-bakery-100 text-bakery-800
px-7 py-3 rounded-full font-medium tracking-wide transition-colors"
class="pill-outline mt-6"
th:text="|Ask about ${#strings.toLowerCase(table.name)}|">Ask about office boxes</a>
</div>
</section>
@@ -131,20 +129,20 @@
<!--/* The terms that apply whichever table you were reading, and the one real call to action. On sage,
like the homepage's story band, so the page ends rather than trailing off. */-->
<section class="bg-bakery-800 text-white py-16 md:py-20">
<section class="section bg-bakery-800 text-white">
<div class="container mx-auto px-4">
<div class="max-w-2xl mx-auto text-center">
<h2 class="font-adbhashitha text-2xl md:text-3xl">Before you order</h2>
<h2 class="h3">Before you order</h2>
<ul th:if="${!#lists.isEmpty(menu.notes)}" class="mt-6 space-y-3 text-bakery-100 leading-relaxed">
<li th:each="note : ${menu.notes}" th:text="${note}">These are a guide rather than a menu.</li>
</ul>
<div class="mt-10 flex flex-col sm:flex-row gap-3 justify-center">
<a href="/contact"
class="bg-bakery-50 hover:bg-white text-bakery-900 px-8 py-3.5 rounded-full font-medium tracking-wide inline-block transition shadow-lg">
class="pill-cream">
Tell us what you need
</a>
<a href="tel:+13097010660"
class="border border-bakery-200/60 hover:bg-bakery-50/10 text-bakery-50 px-8 py-3.5 rounded-full font-medium tracking-wide inline-block transition">
class="pill-ghost">
(309) 701-0660
</a>
</div>
+9 -9
View File
@@ -4,7 +4,7 @@
<div th:fragment="content" class="min-h-screen bg-bakery-50">
<header class="container mx-auto px-4 pt-14 pb-10 md:pt-20 md:pb-12 text-center">
<h1 class="font-adbhashitha text-4xl md:text-5xl text-bakery-900">Contact us</h1>
<h1 class="h1 text-bakery-900">Contact us</h1>
<p class="mt-4 text-bakery-800 max-w-xl mx-auto leading-relaxed">
Ask about a cake, a date, or an order for a crowd. We read everything that comes in.
</p>
@@ -17,8 +17,8 @@
*/-->
<div class="container mx-auto px-4 pb-16 md:pb-24">
<div class="grid gap-8 lg:grid-cols-[1.4fr_1fr] max-w-5xl mx-auto items-start">
<div class="bg-white p-8 md:p-10 rounded-3xl shadow-xs">
<h2 class="font-adbhashitha text-2xl md:text-3xl text-bakery-900 mb-2">Get in touch</h2>
<div class="panel p-8 md:p-10">
<h2 class="h3 text-bakery-900 mb-2">Get in touch</h2>
<p class="text-bakery-700 mb-8">
Or call us: <a href="tel:+13097010660" class="underline underline-offset-4 hover:text-bakery-600">(309) 701-0660</a>
</p>
@@ -52,7 +52,7 @@
</div>
<div class="flex flex-col items-center gap-4">
<button type="submit"
class="px-8 py-3 bg-bakery-600 text-white rounded-full tracking-wide hover:bg-bakery-700 transition-colors">
class="pill-sage">
Send message
</button>
@@ -71,18 +71,18 @@
</div>
<aside class="space-y-6">
<div class="bg-white p-6 md:p-8 rounded-3xl shadow-xs">
<h2 class="font-adbhashitha text-xl text-bakery-900">Our hours</h2>
<div class="panel p-6 md:p-8">
<h2 class="h4 text-bakery-900">Our hours</h2>
<div class="mt-4 text-bakery-800"
th:replace="~{fragments/visit :: hours('text-bakery-800')}"></div>
</div>
<div class="bg-white p-6 md:p-8 rounded-3xl shadow-xs">
<h2 class="font-adbhashitha text-xl text-bakery-900">Find us</h2>
<div class="panel p-6 md:p-8">
<h2 class="h4 text-bakery-900">Find us</h2>
<div class="mt-4 text-bakery-800"
th:replace="~{fragments/visit :: address('hover:text-bakery-600 underline underline-offset-4')}"></div>
</div>
<div class="rounded-3xl border border-bakery-200 p-6 md:p-8">
<h2 class="font-adbhashitha text-xl text-bakery-900">Ordering for a crowd?</h2>
<h2 class="h4 text-bakery-900">Ordering for a crowd?</h2>
<p class="mt-2 text-sm text-bakery-700 leading-relaxed">
Goodie boxes, party packages and wedding desserts have their own page, with sizes and prices.
</p>
+2 -2
View File
@@ -14,13 +14,13 @@
<body>
<div th:fragment="content" class="bg-bakery-50">
<div class="container mx-auto px-4 py-24 md:py-32 text-center">
<h1 class="font-adbhashitha text-4xl md:text-5xl text-bakery-900 mb-6">Something went wrong</h1>
<h1 class="h1 text-bakery-900 mb-6">Something went wrong</h1>
<p class="text-bakery-800 mb-10">
That is our fault, not yours. Try again in a moment, or call us on
<a href="tel:+13097010660" class="underline underline-offset-4">(309) 701-0660</a>.
</p>
<a href="/"
class="bg-bakery-600 hover:bg-bakery-700 text-white px-8 py-3.5 rounded-full font-medium tracking-wide inline-block transition">
class="pill-sage">
Back home
</a>
</div>
+3 -3
View File
@@ -17,7 +17,7 @@
<body>
<div th:fragment="content" class="bg-bakery-50">
<div class="container mx-auto px-4 py-24 md:py-32 text-center">
<h1 class="font-adbhashitha text-4xl md:text-5xl text-bakery-900 mb-6">
<h1 class="h1 text-bakery-900 mb-6">
We could not find that page
</h1>
<p class="text-bakery-800 mb-10">
@@ -25,11 +25,11 @@
</p>
<div class="flex flex-col sm:flex-row gap-3 justify-center">
<a href="/"
class="bg-bakery-600 hover:bg-bakery-700 text-white px-8 py-3.5 rounded-full font-medium tracking-wide inline-block transition">
class="pill-sage">
Back home
</a>
<a href="/products"
class="border border-bakery-300 hover:bg-bakery-100 text-bakery-700 px-8 py-3.5 rounded-full font-medium tracking-wide inline-block transition">
class="pill-outline">
See the menu
</a>
</div>
@@ -9,7 +9,7 @@
</div>
<div>
<h3 class="font-adbhashitha text-sm uppercase tracking-[0.18em] text-bakery-300 mb-4">Navigation</h3>
<h3 class="label text-bakery-300 mb-4 font-adbhashitha">Navigation</h3>
<ul class="space-y-2">
<li><a href="/products" class="hover:text-white transition">Our Products</a></li>
<li><a href="/catering" class="hover:text-white transition">Goodie Boxes &amp; Catering</a></li>
@@ -19,7 +19,7 @@
</div>
<div>
<h3 class="font-adbhashitha text-sm uppercase tracking-[0.18em] text-bakery-300 mb-4">Visit</h3>
<h3 class="label text-bakery-300 mb-4 font-adbhashitha">Visit</h3>
<div th:replace="~{fragments/visit :: address('hover:text-white transition')}"></div>
<!--/* The hours are the thing people come to a bakery's site for, and the footer is on every
page. */-->
@@ -22,7 +22,7 @@
<div th:replace="~{fragments/lockup :: small('text-bakery-700')}"></div>
<nav class="hidden md:flex items-center gap-8">
<th:block th:replace="~{:: links('text-sm uppercase tracking-[0.15em] text-bakery-700 hover:text-bakery-900 transition')}"></th:block>
<th:block th:replace="~{:: links('label text-bakery-700 hover:text-bakery-900 transition-colors')}"></th:block>
</nav>
<details class="group md:hidden shrink-0">
+12 -12
View File
@@ -4,16 +4,16 @@
<div th:fragment="content" class="bg-bakery-50">
<!--/* The shop's own front, which is what the story is about. Same band as the catering page. */-->
<section class="relative flex items-center py-14 md:py-20 bg-bakery-900 text-white overflow-hidden">
<section class="band relative flex items-center bg-bakery-900 text-white overflow-hidden">
<img th:src="${photos.of('gallery/Outside.webp')}" alt=""
class="absolute inset-0 w-full h-full object-cover object-bottom blur-[3px] scale-110">
<div class="absolute inset-0 bg-bakery-900/80"></div>
<div class="absolute inset-0 bg-gradient-to-t from-bakery-900 via-bakery-800/60 to-bakery-900/80"></div>
<div class="relative container mx-auto px-4 w-full min-w-0">
<div class="max-w-3xl mx-auto text-center">
<p class="text-xs sm:text-sm uppercase tracking-[0.2em] text-bakery-200">Since 2024</p>
<h1 class="mt-3 font-adbhashitha text-4xl md:text-5xl text-bakery-50">Our story</h1>
<p class="mt-5 text-base sm:text-lg text-bakery-100 text-balance leading-relaxed">
<p class="eyebrow text-bakery-200">Since 2024</p>
<h1 class="h1 mt-3 text-bakery-50">Our story</h1>
<p class="lede mt-5 text-bakery-100">
215 E Main Street, in the middle of downtown Princeville.
</p>
</div>
@@ -25,7 +25,7 @@
<div class="container mx-auto px-4 pb-16 md:pb-24">
<div class="max-w-2xl mx-auto space-y-12">
<section>
<h2 class="font-adbhashitha text-2xl md:text-3xl text-bakery-900 mb-4">How it started</h2>
<h2 class="h3 text-bakery-900 mb-4">How it started</h2>
<p class="text-bakery-800 leading-relaxed">
Morissa Bennett opened The Vine in 2024, at 215 E Main Street, in the middle of downtown
Princeville. The plan was not complicated. Bake it ourselves, sell it ourselves, and keep
@@ -34,7 +34,7 @@
</section>
<section>
<h2 class="font-adbhashitha text-2xl md:text-3xl text-bakery-900 mb-4">What we make</h2>
<h2 class="h3 text-bakery-900 mb-4">What we make</h2>
<p class="text-bakery-800 leading-relaxed">
We opened with coffee and pastries. The menu kept growing. Now there are cinnamon rolls
and caramel rolls, scones, cookie bars, macarons, brownies, and pies, plus sandwiches and
@@ -43,7 +43,7 @@
</section>
<section>
<h2 class="font-adbhashitha text-2xl md:text-3xl text-bakery-900 mb-4">The cakes are the fun part</h2>
<h2 class="h3 text-bakery-900 mb-4">The cakes are the fun part</h2>
<p class="text-bakery-800 leading-relaxed">
Cakes and decorated cookies are made to order, which means we mostly bake whatever
Princeville is celebrating that week. We have done a tractor, a cow, a 76th birthday, a
@@ -54,7 +54,7 @@
</section>
<section>
<h2 class="font-adbhashitha text-2xl md:text-3xl text-bakery-900 mb-4">Around town</h2>
<h2 class="h3 text-bakery-900 mb-4">Around town</h2>
<p class="text-bakery-800 leading-relaxed">
We turn out for Christmas in the Village every year and for other civic events, and the
Princeville Civic Association counts us among the town&apos;s small businesses. Enjoy
@@ -66,21 +66,21 @@
</div>
<!--/* Somewhere to go after reading: the story is a preamble to an order. */-->
<section class="bg-bakery-800 text-white py-16 md:py-20">
<section class="section bg-bakery-800 text-white">
<div class="container mx-auto px-4">
<div class="max-w-2xl mx-auto text-center">
<h2 class="font-adbhashitha text-2xl md:text-3xl">Come and see us</h2>
<h2 class="h3">Come and see us</h2>
<p class="mt-4 text-bakery-100 leading-relaxed">
We open at 7:00am, Tuesday through Saturday. If you are after something for a date in the
diary, it is worth asking early.
</p>
<div class="mt-8 flex flex-col sm:flex-row gap-3 justify-center">
<a href="/products"
class="bg-bakery-50 hover:bg-white text-bakery-900 px-8 py-3.5 rounded-full font-medium tracking-wide inline-block transition shadow-lg">
class="pill-cream">
See what we make
</a>
<a href="/contact"
class="border border-bakery-200/60 hover:bg-bakery-50/10 text-bakery-50 px-8 py-3.5 rounded-full font-medium tracking-wide inline-block transition">
class="pill-ghost">
Get in touch
</a>
</div>
+18 -18
View File
@@ -18,16 +18,16 @@
<div class="relative container mx-auto px-4 w-full min-w-0">
<div class="max-w-3xl mx-auto text-center">
<div th:replace="~{fragments/lockup :: large('text-bakery-50 mb-10')}"></div>
<p class="text-lg sm:text-xl text-bakery-100 mb-10 text-balance leading-relaxed">
<p class="lede sm:text-xl text-bakery-100 mb-10">
A coffeehouse and bakery in downtown Princeville, Illinois.
</p>
<div class="flex flex-col sm:flex-row gap-3 justify-center">
<a href="/products"
class="bg-bakery-50 hover:bg-white text-bakery-900 px-8 py-3.5 rounded-full font-medium tracking-wide inline-block transition shadow-lg">
class="pill-cream">
See the menu
</a>
<a href="#visit"
class="border border-bakery-200/60 hover:bg-bakery-50/10 text-bakery-50 px-8 py-3.5 rounded-full font-medium tracking-wide inline-block transition">
class="pill-ghost">
Visit us
</a>
</div>
@@ -36,28 +36,28 @@
</section>
<!--/* What people come in for */-->
<section class="py-16 md:py-24 bg-bakery-50">
<section class="section bg-bakery-50">
<div class="container mx-auto px-4">
<h2 class="font-adbhashitha text-3xl md:text-4xl text-center text-bakery-900 mb-12">What people come in for</h2>
<h2 class="h2 text-center text-bakery-900 mb-12">What people come in for</h2>
<div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-6 md:gap-8">
<div th:each="item : ${ {'Cinnamon Rolls', 'Sugar Cookies', 'Cakes'} }"
class="group text-center bg-white rounded-3xl overflow-hidden shadow-xs hover:shadow-lg hover:-translate-y-1 transition duration-300">
class="group panel-lift overflow-hidden text-center hover:-translate-y-1">
<div class="overflow-hidden">
<!--/* The filenames carry the spaces in these names; SitePhotos encodes them. */-->
<img th:src="${photos.of('gallery/' + item + '.webp')}" th:alt="${item}" width="600" height="400" loading="lazy"
class="w-full h-56 object-cover transition-transform duration-500 group-hover:scale-105">
</div>
<h3 class="font-adbhashitha text-xl md:text-2xl text-bakery-800 py-6 tracking-wide" th:text="${item}">Cinnamon Rolls</h3>
<h3 class="h4 md:text-2xl text-bakery-800 py-6" th:text="${item}">Cinnamon Rolls</h3>
</div>
</div>
</div>
</section>
<!--/* Our story */-->
<section class="py-16 md:py-24 bg-bakery-800 text-white">
<section class="section bg-bakery-800 text-white">
<div class="container mx-auto px-4">
<div class="max-w-3xl mx-auto text-center">
<h2 class="font-adbhashitha text-3xl md:text-4xl mb-8" style="letter-spacing: 0.01em">Our story</h2>
<h2 class="h2 mb-8" style="letter-spacing: 0.01em">Our story</h2>
<p class="text-base md:text-lg text-bakery-100 mb-8 leading-relaxed">
Morissa Bennett opened The Vine in 2024. We bake in our own kitchen on Main Street:
cinnamon rolls, cookies, custom cakes, sandwiches, paninis, and coffee.
@@ -74,20 +74,20 @@
found it by reading the nav. Photo on one side, the offer on the other, and the three tables named so
the link is worth following.
*/-->
<section class="py-16 md:py-24 bg-bakery-50">
<section class="section bg-bakery-50">
<div class="container mx-auto px-4">
<div class="grid md:grid-cols-2 gap-8 md:gap-12 items-center max-w-5xl mx-auto">
<img th:src="${photos.of('gallery/Sugar Cookies.webp')}" alt="Iced sugar cookies from The Vine"
width="800" height="600" loading="lazy"
class="w-full h-64 md:h-80 object-cover rounded-3xl shadow-xs">
<div>
<h2 class="font-adbhashitha text-3xl md:text-4xl text-bakery-900">Ordering for a crowd?</h2>
<h2 class="h2 text-bakery-900">Ordering for a crowd?</h2>
<p class="mt-4 text-bakery-800 leading-relaxed">
Goodie boxes for the office, packages for a party, and cakes and desserts for a wedding —
with prices, sizes and what each one includes, so you can see where to start.
</p>
<a href="/catering"
class="mt-6 inline-block bg-bakery-600 hover:bg-bakery-700 text-white px-8 py-3.5 rounded-full font-medium tracking-wide transition">
class="pill-sage mt-6">
Goodie boxes &amp; catering
</a>
</div>
@@ -96,16 +96,16 @@
</section>
<!--/* Visit us */-->
<section id="visit" class="py-16 md:py-24 bg-bakery-50 scroll-mt-24">
<section id="visit" class="section bg-bakery-50 scroll-mt-24">
<div class="container mx-auto px-4">
<h2 class="font-adbhashitha text-3xl md:text-4xl text-center text-bakery-900 mb-12">Visit us</h2>
<h2 class="h2 text-center text-bakery-900 mb-12">Visit us</h2>
<div class="grid grid-cols-1 md:grid-cols-2 gap-8 md:gap-12 max-w-4xl mx-auto">
<div class="bg-white rounded-3xl p-6 md:p-8">
<h2 class="font-adbhashitha text-2xl md:text-3xl text-bakery-900 mb-6">Our hours</h2>
<div class="panel p-6 md:p-8">
<h2 class="h3 text-bakery-900 mb-6">Our hours</h2>
<div th:replace="~{fragments/visit :: hours('text-bakery-800')}"></div>
</div>
<div class="bg-white rounded-3xl p-6 md:p-8">
<h2 class="font-adbhashitha text-2xl md:text-3xl text-bakery-900 mb-6">Find us</h2>
<div class="panel p-6 md:p-8">
<h2 class="h3 text-bakery-900 mb-6">Find us</h2>
<div class="text-bakery-800"
th:replace="~{fragments/visit :: address('hover:text-bakery-600 underline underline-offset-4')}"></div>
</div>
+9 -12
View File
@@ -4,7 +4,7 @@
<div th:fragment="content" class="min-h-screen bg-bakery-50">
<header class="container mx-auto px-4 pt-14 pb-10 md:pt-20 md:pb-12 text-center">
<h1 class="font-adbhashitha text-4xl md:text-5xl text-bakery-900">Our products</h1>
<h1 class="h1 text-bakery-900">Our products</h1>
<p class="mt-4 text-bakery-800 max-w-2xl mx-auto leading-relaxed">
What comes out of the kitchen on Main Street. Cakes and decorated cookies are made to order, so
most of what follows started as somebody describing what they wanted.
@@ -23,10 +23,7 @@
th:href="${category == 'All' ? '/products' : '/products?category=' + #uris.escapeQueryParam(category)}"
th:text="${category}"
th:aria-current="${category == selected ? 'page' : null}"
th:class="'px-6 py-2 rounded-full border text-sm uppercase tracking-[0.12em] transition-colors '
+ (${category == selected}
? 'bg-bakery-600 text-white border-bakery-600'
: 'bg-white border-bakery-300 text-bakery-700 hover:bg-bakery-100')">All</a>
th:class="${category == selected} ? 'chip-on' : 'chip'">All</a>
</div>
<!--/* Deliberately unanimated, as before: filtering used to run a layout reflow plus an enter/exit
@@ -34,13 +31,13 @@
responding. The only motion left is the shadow on hover. */-->
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
<div th:each="product : ${products}"
class="group bg-white rounded-3xl overflow-hidden shadow-xs transition-shadow duration-300 hover:shadow-lg">
class="group panel-lift overflow-hidden">
<div class="relative w-full overflow-hidden">
<div th:replace="~{:: gallery(${product})}"></div>
</div>
<div class="p-6 text-center">
<h3 class="font-adbhashitha text-xl text-bakery-900 mb-2 tracking-wide" th:text="${product.name}">Name</h3>
<span class="text-xs uppercase tracking-[0.15em] text-bakery-600" th:text="${product.category}">Category</span>
<h3 class="h4 text-bakery-900 mb-2" th:text="${product.name}">Name</h3>
<span class="label text-bakery-600" th:text="${product.category}">Category</span>
</div>
</div>
</div>
@@ -52,21 +49,21 @@
</div>
<!--/* A catalogue with no way to order from it is a gallery. */-->
<section class="bg-bakery-800 text-white py-16 md:py-20">
<section class="section bg-bakery-800 text-white">
<div class="container mx-auto px-4">
<div class="max-w-2xl mx-auto text-center">
<h2 class="font-adbhashitha text-2xl md:text-3xl">Want one of these, or something else?</h2>
<h2 class="h3">Want one of these, or something else?</h2>
<p class="mt-4 text-bakery-100 leading-relaxed">
Cakes and decorated cookies are made to order. Tell us the date and roughly what you have in
mind — a tractor, a retirement, the class of 1964 — and we will work from there.
</p>
<div class="mt-8 flex flex-col sm:flex-row gap-3 justify-center">
<a href="/contact"
class="bg-bakery-50 hover:bg-white text-bakery-900 px-8 py-3.5 rounded-full font-medium tracking-wide inline-block transition shadow-lg">
class="pill-cream">
Ask about an order
</a>
<a href="/catering"
class="border border-bakery-200/60 hover:bg-bakery-50/10 text-bakery-50 px-8 py-3.5 rounded-full font-medium tracking-wide inline-block transition">
class="pill-ghost">
Ordering for a crowd
</a>
</div>