/* * The public site's own classes — the ones that would be unreadable as a string of utilities in every * template that needs them. The admin's controls are in admin.css; the type ladder is in type.css. * * Almost everything here is @utility rather than a plain class in a layer, for two reasons Tailwind v4 * enforces: only a registered utility can be @applied by another rule (panel-mark builds on mark), and * only a registered utility can take a variant (`hover:`, `md:`, `file:`). */ /* The exception. In @layer components, matching the old site — and that ordering matters: a utility like `px-4`, which the markup applies alongside `container` on nearly every section, has to win over this, or every gutter on the site silently widens. */ @layer components { .container { @apply max-w-7xl mx-auto px-4 sm:px-6 lg:px-8; } } /* * THE BRANCH MARKS of the wordmark, as masks rather than inline SVG. * * They have to take their colour from the surrounding text — sage in the header, cream on the hero and in * the footer — which an cannot do. React solved that by inlining them through svgr, but these files * are 31 KB each and the lockup appears up to three times on a page: inlining them in server-rendered * HTML would add ~190 KB to every response. A mask over `currentColor` keeps the tinting, keeps the files * cacheable, and costs two requests once. */ @utility mark { background-color: currentColor; -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat; -webkit-mask-position: center; mask-position: center; -webkit-mask-size: contain; mask-size: contain; } @utility mark-r { -webkit-mask-image: url('/images/logo_R.svg'); mask-image: url('/images/logo_R.svg'); } @utility mark-l { -webkit-mask-image: url('/images/logo_L.svg'); mask-image: url('/images/logo_L.svg'); } /* * The photo strip on a product card scrolls, but a scrollbar across the bottom of a photo is not part of * the design. Hiding it is safe here because the strip is not the only way through the photos: it snaps, * it takes arrow keys, and the arrows and dots are on top of it. */ @utility no-scrollbar { scrollbar-width: none; &::-webkit-scrollbar { display: none; } } /* * SURFACES. * * These were plain white boxes with a grey drop shadow — the default card of every web app, on a page * that is otherwise cream, sage and a hand-drawn vine. Three things make them the shop's: * * a warm hairline, so a card has an EDGE and reads as stock rather than as a floating panel; * a shadow tinted with the darkest sage instead of black (see theme.css); * a head that can be tinted cream, the way a printed menu separates the price from what you get. * * `panel-lift` is one you can click, and it rises rather than just darkening. */ @utility panel { @apply bg-white rounded-3xl border border-bakery-200/70; box-shadow: var(--shadow-card); } @utility panel-lift { @apply panel transition duration-300; &:hover { box-shadow: var(--shadow-card-lift); transform: translateY(-2px); } } /* The cream band on a card: a size and its price, or a photo's caption. */ @utility panel-head { @apply bg-bakery-50/70 border-b border-bakery-200/70; } /* * The branch, laid into a corner at the weight of a watermark. It is the one mark that is unmistakably * this shop, and at this size and colour it is texture rather than decoration. */ @utility panel-mark { @apply mark mark-l absolute pointer-events-none text-bakery-200/70; } /* * BUTTONS. One shape — a full pill, generous, letterspaced — in four colourways, because the site puts * buttons on cream and on sage and they cannot be the same colour on both. * * pill-sage filled, on a light background pill-outline quiet, on a light background * pill-cream filled, on a sage background pill-ghost quiet, on a sage background */ @utility pill { @apply inline-flex items-center justify-center gap-2 rounded-full px-8 py-3.5 font-medium tracking-wide transition-colors; } @utility pill-sage { @apply pill bg-bakery-600 text-white hover:bg-bakery-700; } @utility pill-cream { @apply pill bg-bakery-50 text-bakery-900 hover:bg-white shadow-lg; } @utility pill-outline { @apply pill border border-bakery-300 text-bakery-800 hover:bg-bakery-100; } @utility pill-ghost { @apply pill border border-bakery-200/60 text-bakery-50 hover:bg-bakery-50/10; } /* Smaller, for a filter row rather than a call to action. */ @utility chip { @apply inline-flex items-center rounded-full border px-6 py-2 label bg-white border-bakery-300 text-bakery-700 transition-colors hover:bg-bakery-100; } @utility chip-on { @apply chip bg-bakery-600 border-bakery-600 text-white hover:bg-bakery-600; } /* * RHYTHM. Two vertical sizes, so the page has a beat instead of nine hand-picked paddings: `section` for * a block of content, `band` for a photographic or coloured strip, which sits tighter because its * background is already doing the separating. */ @utility section { @apply py-16 md:py-24; } @utility band { @apply py-14 md:py-20; }