STYLE.md ·
How Stem works. Every rule, written down.
The florist as a website: a bouquet you build stem by stem as each one drops into a kraft wrap, a ring of the twelve months that shows what's in season now, a live same-day cut-off with a delivery zone checker, and the card written in handwriting as you type. Caprasimo headlines with the promise written by hand in Caveat, on linen with deep leaf ink and one marigold.
Fresh · generous · seasonal
Best for
- Florists: build-your-own and ready-made bouquets, what's in season, same-day delivery with a cut-off and zone fees shown up front, swaps said plainly, weddings, sympathy and hospital deliveries
- Anyone who sells a made-up bundle of seasonal things with a delivery cut-off: farm and produce boxes (Rootstock, a paper bag filled item by item), gift hampers (Hamper & Co., a kraft box of pantry things), cake and grazing boxes, plant shops, bakeries with order-by times
- Audiences: people buying for someone else, today, who want to see it, know the price with delivery, and write the card
Less suited to: clinical or regulated services (Lucent, Remedy); anything technical (Signal, Catalogue); loud nightlife (Marquee).
Personality and voice
Fresh and generous, like a florist who knows the growers: here's what's good this week, here's what it costs to get there, and if a stem isn't at its best we'll tell you.
- Headlines: "Flowers, picked this week." · "Twelve months, what's good now." · "Today, if you're quick." · "Say it in writing."
- Buttons: "Build a bouquet" · "Check delivery" · "Take one out" · "Order and pay"
- Microcopy: "Tap a stem to add it." · "Order in 2 h 14 min for delivery today." · "Like for like: same colours, as good or better."
Colour
| Token | Morning (light) | Cool room (dark) | Role |
|---|---|---|---|
--paper |
#f4f1e8 |
#0f1712 |
Linen; the cool room |
--card |
#fdfbf5 |
#16211a |
Cards, the bouquet, forms |
--well |
#ebe6d8 |
#121b15 |
Alternate sections, chips |
--line |
#d9d2c0 |
#2a3a2f |
Hairlines |
--ink / --ink-2 |
#1d2a21 / #3c4a3f |
#eef2e8 / #ccd5c8 |
Deep leaf text |
--muted |
#58635a |
#a2ad9f |
Labels |
--marigold |
#a8430c |
#ff9d5c |
The one accent: buttons, links, the written promise, counts |
--leaf |
#3d6b48 |
#8fcf9b |
Greenery marks, zones that match |
--kraft, --note |
#d9b98a, #fffaf0 |
same | The wrap and the card stay paper at night |
--bloom-1…8 |
peony, butter, coral, white, lilac, deep red, sky, marigold | same | Flowers: decoration, never text |
Measured contrast (WCAG): ink on paper 13.2:1 · muted on paper 5.6:1 (on well 5.0:1) · marigold on paper 5.4:1 (on well 4.9:1, on its soft fill 4.7:1) · white on marigold 6.1:1 · leaf on card 6.0:1 · kraft ink on kraft 7.4:1. Cool room: ink 16.1:1 · muted 7.8:1 (on card 7.1:1) · marigold 8.9:1 · text on marigold 8.6:1 · marigold on its soft fill 7.6:1 · leaf 9.1:1. Example accents on paper: beetroot (Rootstock) 6.8:1, claret (Hamper & Co.) 8.6:1, plum (Petal & Pine) 7.1:1.
Typography
- Display: Caprasimo 400: soft, round and generous.
- Body: Nunito Sans 400–800: friendly and clear; labels in 800 caps.
- Handwriting: Caveat 600–700: the promise in every headline, the price tag, the card.
| Token | Size | Use |
|---|---|---|
--fs-h1 |
clamp(46px, 6.4vw, 96px) | Page headline |
--fs-h2 |
clamp(34px, 4.2vw, 60px) | Section headline |
--fs-h3 |
22px | Card titles |
--fs-lead |
clamp(17.5px, 1.35vw, 20.5px) | Intro paragraphs |
--fs-body |
17px | Body |
--fs-label |
12.5px, 800 caps | Eyebrows after a leaf (FF·01) |
The signature move: the end of every headline is written by hand, in marigold Caveat at 116%, like the florist finished the sign with a marker.
Layout
- 1220px wrap, gutter
max(20px, 4vw). A leaf-green top line for today's news; a sticky, blurred header with pill links. - Hero: copy left, the bouquet right (the posy beside the bench). Then the season ring, the shop as mini posies, the cut-off beside the zone checker, the card, visit facts and FAQ, and a deep green closing card with a slow-turning flower.
Shape
- Soft and generous:
--r-s12px,--r-m22px,--r-l34px, pill buttons, chips and links. - Flowers are flat shapes: round (roses, peonies), daisy, spray (waxflower), spike (delphinium), cup (tulip) and leaf (eucalyptus), on green stalks gathered into a kraft wrap with a marigold tie.
- The brand mark is a five-petal flower; list marks are leaves.
Motion language
- The bouquet: each stem's stalk grows (0.5s) as its head drops into place with a little bounce (0.64s); a size fills the wrap one stem after another. Taking one out lifts it away. Count badges pop.
- The season ring: the chosen month's flowers pop in one after another (50ms apart).
- The cut-off bar fills through the day; the closing card's flower turns very slowly.
- Buttons rise 2px on hover. Reveals: 18px rise and fade, 700ms. The phone menu drops in.
- Motion switch in the footer (
[data-motion-toggle],html.calm, remembered assite-motion, default fromprefers-reduced-motion). Calm shows the bouquet already made and stills the rest. - Cool room switch (
[data-theme-toggle]), remembered assite-theme;theme-colorfollows.
Imagery and illustration
The posies are the picture: drawn, flat and in the season's colours. Real photography works when it's the shop's own work in daylight (on the bench, in hands, at the door), never a stock bouquet that isn't for sale.
Signature components
.bouquet[data-bouquet][data-max][data-wrap]›.posy-wrap(svg.posywith.wrap-back,g.stalks,g.greens,g.blooms,.wrap-front,.wrap-fold,.tie;.posy-tagwith[data-bq-count],[data-bq-price]) +.bench(.seg[data-bq-size] > button[data-recipe="key:n,…"],.stems-bench > button.stem[data-key][data-name][data-price][data-shape][data-c],[data-bq-full],ul[data-bq-list],[data-bq-undo],[data-bq-clear])..mini-posy[data-recipe="shape/colour/n,…"]inside.product(h3,p,.price > span)..season[data-season]›.season-dial(twelvebutton[data-m]made for you;.nowwith[data-season-season],[data-season-name],[data-season-count]) +.season-key+.season-list > section.season-month[data-m] > h3 + p + ul > li > i[style="--c"]..cutoff[data-cutoff][data-from][data-days][data-before][data-after]([data-cut-text],.bar > i,[data-cut-start],[data-cut-end]).form.zones[data-zones](JSON list of{name, fee, when, areas}) ›input[data-zone-in],output[data-zone-out][data-empty][data-miss],.zone-key..note-card[data-note]›textarea[data-note-in][maxlength],[data-note-count],input[data-note-from],.note-paper > p[data-note-out][data-placeholder] + small[data-note-sign]..card,.facts(.stack),.notice,.topline,.faq,.licence,.close-card(--close-em),.grid-4.
Multi-page kit
- Phone menu:
.menu-btn[aria-controls]opens.site-menu(links withdata-no); Escape, outside click and links close it; Tab stays inside while open. - Current page:
aria-current="page"(a soft marigold pill). - Inner pages:
.page-head,.crumbs, a.tagand a smaller.h1. - Fields:
.field,.fields,.field-wide,fieldset.field-set,.check,.form-card,[aria-invalid="true"];form[data-template]. - Tiles:
.choices›label.choice > input + span > b + small. Segmented control:.seg(filters work on[data-tags]). - Gate:
[data-gate]withbutton[data-show="panel-id"]. - Slider, switch, tables, layout:
input.range,.switch[role=switch],.table/.table.stack,.r,.grid-2.lean. - Events and helpers:
bouquet(detail.stems, count, price);Stem.posy(svg, list),Stem.refresh(root).
Florists: what we build in
- The price with delivery, before checkout: the zone checker gives the fee for the suburb, and the order summary adds it to the flowers.
- Swaps said up front: "like for like, same colours, as good or better", agreed on the order form.
- A cut-off that's honest: the countdown is to the real same-day time; after it, or on a day you don't deliver, it names the next delivery day, and the date field won't take a day you can't do.
- Sympathy and hospitals: delivered to the right place, on the right days, with a check on wards that don't take flowers.
These notes are design guidance, not legal advice.
Do and don't
- Do show what's in season, and price it lower when it is.
- Do put the delivery fee next to the suburb, not at the last step.
- Do let people take a stem out as easily as they put one in.
- Don't use the bloom colours for text.
- Don't show a flower on the bench that you can't get this week.
- Don't put more than eight stems on the bench; rotate them with the seasons.
Accessibility
AA contrast throughout (measured above). Skip link and a 3px focus ring. The bouquet is a labelled group: each stem is a real button with its name and price, the count and price are announced politely, and the posy itself is decoration with a text list of what's in it. The season ring's months are buttons with full month names, the chosen month's flowers are a list. The cut-off and zone results are announced politely. The card preview mirrors a labelled textarea with a live character count. Forms label every field, mark errors with aria-invalid and say what's missing in an alert. Responsive to 360px; tested with motion on and off, in Morning and Cool room.
How to make it yours
| Dial | Range |
|---|---|
| Accent | Marigold (default), beetroot (Rootstock), claret (Hamper & Co.), plum (Petal & Pine); set --marigold, --marigold-2, --marigold-soft (and --on-marigold at night) and --close-em |
| The bench | Up to eight stems, each a shape and a colour; sizes are recipes |
| The seasons | Twelve months of what you actually stock, for your region |
| Delivery | Your cut-off, days and wording (data-before, data-after); zones with fees and suburbs |
| Not negotiable | Caprasimo with the handwritten promise, a bouquet you build stem by stem, the season ring, a cut-off that tells the truth, fees by suburb before checkout, the handwritten card, and the Motion switch |



