From b3f85522048d80facf9863ef05b15abcda1ba05d Mon Sep 17 00:00:00 2001 From: Anthony Ettinger Date: Sun, 8 Nov 2026 17:40:39 +0000 Subject: [PATCH] auctions: 52 topics in 7 groups, nature first, with drawn stand-ins (0.50.0) Flowers were too narrow. Adds landscapes, mountains, forests, seascapes, deserts, night skies and more, plus animals, houses and places, people, still life, and craft topics (ceramics, glass, textiles, woodwork, jewelry, printmaking, photography). /topics is grouped with jump links; the home page shows an 8-topic strip (busiest first, then featured). Each new topic gets a CSS-drawn placeholder from a small set of shapes tinted per topic; palettes are emitted as stylesheet classes because the CSP forbids inline styles. Existing slugs (dahlias, mums, roses, seacliffs) are unchanged. Co-Authored-By: Claude Opus 5.5 --- package.json | 2 +- src/auctions.ts | 174 ++++++++++++++++++++++++++++++++++++------ test/auctions.test.ts | 12 ++- 3 files changed, 164 insertions(+), 24 deletions(-) diff --git a/package.json b/package.json index 68bcd9c..cc04c1f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pitworld", - "version": "0.49.2", + "version": "0.50.0", "mcpName": "world.pit/pit", "description": "pit.world MCP server: private web search and Moshpit name lookups for AI agents (stdio, no API key). Also a web app, API, CLI and TUI.", "license": "MIT", diff --git a/src/auctions.ts b/src/auctions.ts index 93be53b..dc4e783 100644 --- a/src/auctions.ts +++ b/src/auctions.ts @@ -50,15 +50,128 @@ function themePicker(theme: AuctionTheme, path: string) { return `` } +/** + * Topics are what a piece is OF (a mountain, a house, a face) or what it is MADE as (ceramics, textiles). + * Nature leads: it is what most of the house paints. Each topic has a CSS-drawn stand-in so an empty topic + * page still looks like a wall waiting for work: one of a few shapes ("kind") tinted by a five-color + * palette (sky top, sky bottom, sun, far shape, near shape). The CSP allows no inline styles, so the + * palettes are emitted as classes into the stylesheet (TOPIC_CSS). + */ +export const TOPIC_GROUPS = ['Nature', 'Flowers and gardens', 'Animals', 'Places and buildings', 'People', 'Still life and imagination', 'Craft and medium'] as const +export type TopicGroup = typeof TOPIC_GROUPS[number] +type TopicArt = { kind: string; pal: readonly [string, string, string, string, string] } +type TopicDef = { name: string; one: string; blurb: string; group: TopicGroup; art: TopicArt | 'legacy' } +const art = (kind: string, ...pal: [string, string, string, string, string]): TopicArt => ({ kind, pal }) + export const AUCTION_TOPICS = { - dahlias: { name: 'Dahlias', blurb: 'Dinner plates, pompons and cactus blooms in every medium.' }, - mums: { name: 'Mums', blurb: 'Chrysanthemums: spiders, spoons and autumn color.' }, - roses: { name: 'Roses', blurb: 'Garden roses, climbers and the classic bloom.' }, - seacliffs: { name: 'Sea cliffs', blurb: 'Coastal bluffs, surf and the edge of the land.' }, -} as const + landscapes: { name: 'Landscapes', one: 'landscape', blurb: 'Fields, valleys and the long view.', group: 'Nature', art: art('hills', '#cfe0ec', '#f1e6c8', '#f6d48a', '#93a978', '#5f7d4f') }, + mountains: { name: 'Mountains', one: 'mountain', blurb: 'Peaks, ridgelines and high country.', group: 'Nature', art: art('peaks', '#b9d0e4', '#e8eef2', '#fbe6b0', '#7d8ea3', '#4f6b55') }, + forests: { name: 'Forests', one: 'forest', blurb: 'Pines, redwoods and the light under the canopy.', group: 'Nature', art: art('forest', '#d7e4d3', '#eef0dd', '#f3dc9a', '#4e6e4a', '#33502f') }, + trees: { name: 'Trees', one: 'tree', blurb: 'Oaks, willows, lone cypress and old orchards.', group: 'Nature', art: art('tree', '#d9e8f0', '#eef1e4', '#f6d48a', '#5f8a4f', '#6b4f36') }, + seascapes: { name: 'Seascapes', one: 'seascape', blurb: 'Open water, waves and weather at sea.', group: 'Nature', art: art('water', '#c3d9ea', '#e6eef3', '#f6d48a', '#3f6f96', '#6d9cc0') }, + seacliffs: { name: 'Sea cliffs', one: 'sea cliff', blurb: 'Coastal bluffs, surf and the edge of the land.', group: 'Nature', art: 'legacy' }, + beaches: { name: 'Beaches', one: 'beach', blurb: 'Sand, tide pools and the shoreline.', group: 'Nature', art: art('beach', '#cfe6f0', '#f4ead0', '#f7cf7a', '#4f93b0', '#e8d3a2') }, + rivers: { name: 'Lakes and rivers', one: 'lake or river', blurb: 'Still lakes, creeks, waterfalls and reflections.', group: 'Nature', art: art('lake', '#d6e6e0', '#eef2e6', '#f3dc9a', '#4d7f74', '#5f8a4f') }, + deserts: { name: 'Deserts', one: 'desert', blurb: 'Dunes, cactus and big dry light.', group: 'Nature', art: art('dunes', '#f4d9b0', '#f8ecd4', '#fbf0c9', '#d9a066', '#b97843') }, + canyons: { name: 'Canyons and red rock', one: 'canyon', blurb: 'Mesas, buttes and carved stone.', group: 'Nature', art: art('mesa', '#cfe0ec', '#f3e3cc', '#f6d48a', '#b4613e', '#8a4a30') }, + skies: { name: 'Skies and clouds', one: 'sky', blurb: 'Cloud studies, storms and weather.', group: 'Nature', art: art('sky', '#a9c6e0', '#e3edf5', '#fdf3d0', '#ffffff', '#93a978') }, + sunsets: { name: 'Sunsets', one: 'sunset', blurb: 'Golden hour, dusk and first light.', group: 'Nature', art: art('hills', '#e9845b', '#f6c98a', '#fff1c4', '#9b5a5a', '#5a3e4e') }, + 'night-skies': { name: 'Night skies', one: 'night sky', blurb: 'Moons, stars and the Milky Way.', group: 'Nature', art: art('night', '#16213a', '#34406a', '#f3ecd0', '#28324f', '#1b2236') }, + seasons: { name: 'Autumn and seasons', one: 'seasonal piece', blurb: 'Fall color, spring thaw and summer heat.', group: 'Nature', art: art('forest', '#e9d8c0', '#f5ecdc', '#f6d48a', '#c86a32', '#8f4a28') }, + winter: { name: 'Snow and winter', one: 'winter scene', blurb: 'Snowfields, ice and quiet cold.', group: 'Nature', art: art('peaks', '#c9d6e3', '#eef2f6', '#f4f0e6', '#9fb0c4', '#f7f9fb') }, + + dahlias: { name: 'Dahlias', one: 'dahlia', blurb: 'Dinner plates, pompons and cactus blooms in every medium.', group: 'Flowers and gardens', art: 'legacy' }, + mums: { name: 'Mums', one: 'mum', blurb: 'Chrysanthemums: spiders, spoons and autumn color.', group: 'Flowers and gardens', art: 'legacy' }, + roses: { name: 'Roses', one: 'rose', blurb: 'Garden roses, climbers and the classic bloom.', group: 'Flowers and gardens', art: 'legacy' }, + sunflowers: { name: 'Sunflowers', one: 'sunflower', blurb: 'Tall stalks and big golden heads.', group: 'Flowers and gardens', art: art('flower', '#e7d9b8', '#f2e7c9', '#5a3a1e', '#f2b51c', '#f7d35a') }, + wildflowers: { name: 'Wildflowers', one: 'wildflower', blurb: 'Poppies, lupine, meadows and roadside blooms.', group: 'Flowers and gardens', art: art('flower', '#dfe3ef', '#eeeef3', '#f2d35b', '#6c5fb0', '#a59ce0') }, + flowers: { name: 'Other flowers', one: 'flower', blurb: 'Irises, peonies, orchids and every other bloom.', group: 'Flowers and gardens', art: art('flower', '#f0dce0', '#f6ece9', '#f2d35b', '#d0577a', '#f2a7bc') }, + gardens: { name: 'Gardens', one: 'garden', blurb: 'Borders, greenhouses, vegetable beds and paths.', group: 'Flowers and gardens', art: art('hills', '#d9e8f0', '#eef1e4', '#f6d48a', '#7fa36a', '#4f7a45') }, + botanicals: { name: 'Botanical studies', one: 'botanical', blurb: 'Leaves, seeds, ferns and careful plant portraits.', group: 'Flowers and gardens', art: art('leaf', '#eef0e2', '#f6f3e8', '#6b4f36', '#6f8f5c', '#4f6b42') }, + + birds: { name: 'Birds', one: 'bird', blurb: 'Songbirds, raptors, herons and everything with feathers.', group: 'Animals', art: art('bird', '#cfe0ec', '#f0ebdc', '#f6d48a', '#3d4a5c', '#93a978') }, + wildlife: { name: 'Wildlife', one: 'wild animal', blurb: 'Deer, bears, foxes and life in the wild.', group: 'Animals', art: art('animal', '#dfe6d6', '#f1ecdc', '#f3dc9a', '#7a5233', '#6f8f5c') }, + pets: { name: 'Pets', one: 'pet', blurb: 'Dogs, cats and the animals we live with.', group: 'Animals', art: art('animal', '#f1e3d3', '#f7efe5', '#f6d48a', '#3b3632', '#c98f63') }, + 'farm-animals': { name: 'Horses and farm animals', one: 'farm animal', blurb: 'Horses, cows, goats, chickens and the barnyard.', group: 'Animals', art: art('animal', '#d9e8f0', '#f1ecdc', '#f6d48a', '#8a5a3a', '#a7b56a') }, + 'sea-life': { name: 'Sea life', one: 'sea creature', blurb: 'Fish, whales, octopus and the reef.', group: 'Animals', art: art('fish', '#3f7fa6', '#2d5f86', '#bfe0f0', '#f28c4b', '#5f9fc6') }, + insects: { name: 'Insects and butterflies', one: 'insect', blurb: 'Butterflies, bees, beetles and moths.', group: 'Animals', art: art('butterfly', '#eef0e2', '#f6f1e4', '#3b3632', '#e98b2f', '#3b3632') }, + + houses: { name: 'Houses', one: 'house', blurb: 'Homes, cottages, porches and the places people live.', group: 'Places and buildings', art: art('house', '#cfe0ec', '#eef1e4', '#f6d48a', '#c9a27c', '#7fa36a') }, + barns: { name: 'Barns and farms', one: 'barn', blurb: 'Red barns, silos, fences and farmland.', group: 'Places and buildings', art: art('house', '#d9e8f0', '#f1ecdc', '#f6d48a', '#a63c32', '#a7b56a') }, + cityscapes: { name: 'Cityscapes', one: 'cityscape', blurb: 'Skylines, rooftops and city light.', group: 'Places and buildings', art: art('city', '#c9d6e8', '#eef0f4', '#f6d48a', '#5d6b82', '#3a4456') }, + streets: { name: 'Streets and towns', one: 'street scene', blurb: 'Main streets, cafes, markets and small towns.', group: 'Places and buildings', art: art('city', '#f0d9c0', '#f7ece0', '#f6d48a', '#b47a5a', '#7a5a48') }, + lighthouses: { name: 'Lighthouses', one: 'lighthouse', blurb: 'Beacons, harbors and the coast at night.', group: 'Places and buildings', art: art('lighthouse', '#cfe0ec', '#eef1f4', '#f6d48a', '#c8455e', '#4f7fa6') }, + boats: { name: 'Boats and harbors', one: 'boat', blurb: 'Sailboats, fishing boats, docks and marinas.', group: 'Places and buildings', art: art('boat', '#cfe0ec', '#eef1f4', '#7a4a30', '#fffdf8', '#4f7fa6') }, + interiors: { name: 'Interiors', one: 'interior', blurb: 'Rooms, windows, kitchens and quiet corners.', group: 'Places and buildings', art: art('window', '#e9dccb', '#f3ebdf', '#f6d48a', '#a9c6e0', '#8a6f55') }, + + portraits: { name: 'Portraits', one: 'portrait', blurb: 'Faces, self-portraits and the people we know.', group: 'People', art: art('figure', '#e9dccb', '#f3ebdf', '#d9a27c', '#384b36', '#384b36') }, + figures: { name: 'Figure studies', one: 'figure study', blurb: 'Gesture, the body in motion, life drawing.', group: 'People', art: art('figure', '#dde3ea', '#eef1f4', '#c98f63', '#7a5a48', '#7a5a48') }, + 'daily-life': { name: 'Everyday life', one: 'everyday scene', blurb: 'Work, play, family and ordinary moments.', group: 'People', art: art('figure', '#f0e0c8', '#f7efe2', '#c98f63', '#c2416b', '#c2416b') }, + + 'still-life': { name: 'Still life', one: 'still life', blurb: 'Fruit bowls, bottles, tabletops and arranged things.', group: 'Still life and imagination', art: art('bowl', '#e9dccb', '#f3ebdf', '#d9534f', '#3f6f96', '#8a6f55') }, + food: { name: 'Food and drink', one: 'food piece', blurb: 'Kitchens, harvests, coffee cups and feasts.', group: 'Still life and imagination', art: art('bowl', '#f3e3cc', '#f8efe0', '#e9a23b', '#fffdf8', '#a9764f') }, + abstract: { name: 'Abstract', one: 'abstract piece', blurb: 'Color, shape and line for their own sake.', group: 'Still life and imagination', art: art('abstract', '#f3eee5', '#efe6d6', '#e05a3a', '#2d5f86', '#f2b51c') }, + fantasy: { name: 'Fantasy and myth', one: 'fantasy piece', blurb: 'Dragons, dreams, fairy tales and other worlds.', group: 'Still life and imagination', art: art('night', '#3a2a5e', '#7a4f8e', '#f6e2a0', '#4a3a6e', '#2a2048') }, + + ceramics: { name: 'Ceramics', one: 'ceramic piece', blurb: 'Pots, vases, bowls, mugs and sculpture in clay.', group: 'Craft and medium', art: art('vessel', '#e9dccb', '#f3ebdf', '#f6d48a', '#b46a45', '#8a6f55') }, + glass: { name: 'Glass', one: 'glass piece', blurb: 'Blown glass, stained glass and fused work.', group: 'Craft and medium', art: art('vessel', '#dceaf0', '#eef4f6', '#f6d48a', '#4fa3a5', '#8aa0ac') }, + sculpture: { name: 'Sculpture', one: 'sculpture', blurb: 'Stone, metal, wood and form in the round.', group: 'Craft and medium', art: art('statue', '#e6e3dc', '#f2f0ea', '#cfc9bd', '#b8b2a6', '#8a857a') }, + textiles: { name: 'Textiles and fiber', one: 'textile', blurb: 'Quilts, weaving, embroidery and knitwear.', group: 'Craft and medium', art: art('weave', '#f3eee5', '#efe6d6', '#f6d48a', '#c2416b', '#2d5f86') }, + woodwork: { name: 'Woodwork', one: 'wood piece', blurb: 'Carving, turning, furniture and marquetry.', group: 'Craft and medium', art: art('grain', '#e9d3b4', '#f3e6d0', '#f6d48a', '#b07a48', '#8a5a33') }, + jewelry: { name: 'Jewelry and metal', one: 'jewelry piece', blurb: 'Rings, pendants, silversmithing and forged work.', group: 'Craft and medium', art: art('ring', '#ece6dc', '#f5f1ea', '#3f9a8a', '#c9a24a', '#8a857a') }, + printmaking: { name: 'Printmaking', one: 'print', blurb: 'Woodcuts, linocuts, etchings and screen prints.', group: 'Craft and medium', art: art('grid', '#f3eee5', '#efe6d6', '#e05a3a', '#24251f', '#f3eee5') }, + 'mixed-media': { name: 'Collage and mixed media', one: 'mixed media piece', blurb: 'Paper, found objects and everything at once.', group: 'Craft and medium', art: art('abstract', '#efe6d6', '#e6dcc8', '#3f9a8a', '#c2416b', '#f2b51c') }, + photography: { name: 'Photography', one: 'photograph', blurb: 'Film, digital, darkroom prints and the found moment.', group: 'Craft and medium', art: art('photo', '#2a2a2a', '#3a3a3a', '#f6d48a', '#cfe0ec', '#5f7d4f') }, +} as const satisfies Record export type AuctionTopic = keyof typeof AUCTION_TOPICS export const isTopic = (value: unknown): value is AuctionTopic => typeof value === 'string' && Object.hasOwn(AUCTION_TOPICS, value) const TOPIC_SLUGS = Object.keys(AUCTION_TOPICS) as AuctionTopic[] +const topicDef = (slug: AuctionTopic): TopicDef => AUCTION_TOPICS[slug] +/** The home page shows a short strip: topics with work on the walls first, then these. */ +const FEATURED_TOPICS: AuctionTopic[] = ['landscapes', 'seacliffs', 'mountains', 'forests', 'seascapes', 'wildlife', 'houses', 'ceramics'] +const HOME_TOPIC_COUNT = 8 +const groupId = (group: TopicGroup) => group.toLowerCase().replace(/[^a-z]+/g, '-') + +/** Per-topic palette classes plus the shapes each drawing kind is made of (three spans: .s-sun, .s-far, .s-near). */ +const TOPIC_CSS = TOPIC_SLUGS.map((slug) => { + const a = topicDef(slug).art + return a === 'legacy' ? '' : `.ph-${slug}{--sky1:${a.pal[0]};--sky2:${a.pal[1]};--sun:${a.pal[2]};--far:${a.pal[3]};--near:${a.pal[4]}}` +}).join('') + [ + '.scene{background:linear-gradient(var(--sky1),var(--sky2))}.scene>span{position:absolute;display:block}', + '.s-sun{right:20%;top:14%;width:16%;aspect-ratio:1;border-radius:50%;background:var(--sun)}.s-far,.s-near{left:0;right:0;bottom:0}.s-far{background:var(--far)}.s-near{background:var(--near)}', + '.k-hills .s-far{height:58%;clip-path:ellipse(75% 70% at 72% 100%)}.k-hills .s-near{height:44%;clip-path:ellipse(80% 66% at 18% 100%)}', + '.k-peaks .s-far{height:72%;clip-path:polygon(0 100%,0 62%,22% 26%,38% 58%,62% 4%,84% 50%,100% 30%,100% 100%)}.k-peaks .s-near{height:30%;clip-path:polygon(0 40%,30% 8%,58% 44%,100% 12%,100% 100%,0 100%)}', + '.k-forest .s-far{height:62%;clip-path:polygon(0 100%,0 45%,8% 5%,16% 45%,24% 0,32% 45%,40% 10%,48% 45%,56% 0,64% 45%,72% 8%,80% 45%,88% 0,96% 45%,100% 25%,100% 100%)}.k-forest .s-near{height:16%}', + '.k-tree .s-far{left:28%;right:28%;bottom:34%;height:50%;border-radius:50% 50% 46% 46%}.k-tree .s-near{left:calc(50% - 4%);right:calc(50% - 4%);height:36%;border-radius:2px}.k-tree:after{content:"";position:absolute;left:0;right:0;bottom:0;height:10%;background:var(--far);opacity:.55}', + '.k-water .s-far{height:44%;background:repeating-linear-gradient(176deg,var(--far) 0 7px,var(--near) 7px 14px)}.k-water .s-near{display:none}', + '.k-beach .s-far{height:46%;background:repeating-linear-gradient(176deg,var(--far) 0 7px,var(--sky1) 7px 12px)}.k-beach .s-near{height:30%;clip-path:polygon(0 30%,40% 50%,100% 0,100% 100%,0 100%)}', + '.k-lake .s-far{height:30%;background:linear-gradient(var(--far),var(--sky1))}.k-lake .s-near{bottom:28%;height:30%;clip-path:polygon(0 100%,0 40%,12% 10%,24% 50%,40% 0,55% 60%,70% 20%,86% 55%,100% 15%,100% 100%)}', + '.k-dunes .s-far{height:48%;clip-path:ellipse(90% 52% at 80% 100%)}.k-dunes .s-near{height:34%;clip-path:ellipse(70% 62% at 10% 100%)}', + '.k-mesa .s-far{height:62%;clip-path:polygon(0 100%,0 30%,26% 30%,32% 58%,56% 58%,60% 18%,86% 18%,92% 62%,100% 62%,100% 100%)}.k-mesa .s-near{height:18%}', + '.k-sky .s-far{top:0;height:auto;background:radial-gradient(ellipse 24% 11% at 30% 34%,var(--far) 97%,transparent),radial-gradient(ellipse 16% 9% at 42% 28%,var(--far) 97%,transparent),radial-gradient(ellipse 28% 12% at 68% 58%,var(--far) 97%,transparent),radial-gradient(ellipse 18% 10% at 58% 52%,var(--far) 97%,transparent)}.k-sky .s-near{height:12%}.k-sky .s-sun{right:auto;left:14%;top:10%}', + '.k-night .s-sun{box-shadow:inset -10px 4px 0 var(--sky1)}.k-night:before{content:"";position:absolute;inset:0;background:radial-gradient(1.5px 1.5px at 12% 18%,#fff 99%,transparent),radial-gradient(1.5px 1.5px at 30% 36%,#fff 99%,transparent),radial-gradient(1px 1px at 46% 12%,#fff 99%,transparent),radial-gradient(1.5px 1.5px at 58% 30%,#fff 99%,transparent),radial-gradient(1px 1px at 88% 44%,#fff 99%,transparent),radial-gradient(1px 1px at 22% 52%,#fff 99%,transparent)}.k-night .s-far{height:40%;clip-path:polygon(0 100%,0 50%,18% 20%,34% 60%,52% 10%,74% 55%,100% 30%,100% 100%)}.k-night .s-near{height:18%}', + '.k-flower .s-sun{left:50%;top:42%;right:auto;width:46%;transform:translate(-50%,-50%);background:radial-gradient(circle,var(--sun) 0 30%,transparent 31%),repeating-conic-gradient(var(--far) 0 9deg,var(--near) 9deg 18deg);z-index:1}.k-flower .s-far{left:calc(50% - 2px);right:auto;width:4px;top:64%;height:40%;background:#5f7d4f}.k-flower .s-near{display:none}', + '.k-leaf .s-far{left:26%;right:26%;top:16%;bottom:16%;border-radius:0 100% 0 100%;transform:rotate(-12deg);background:linear-gradient(135deg,transparent 48.5%,var(--sun) 48.5% 51.5%,transparent 51.5%),var(--far)}.k-leaf .s-near{left:58%;right:20%;top:46%;bottom:22%;border-radius:100% 0 100% 0;transform:rotate(18deg)}.k-leaf .s-sun{display:none}', + '.k-bird .s-far{left:30%;right:30%;top:30%;bottom:auto;height:22%;clip-path:polygon(0 30%,25% 8%,50% 46%,75% 8%,100% 30%,56% 64%,50% 90%,44% 64%)}.k-bird .s-near{height:16%}', + '.k-animal .s-far{left:24%;right:24%;bottom:14%;height:56%;clip-path:polygon(20% 100%,18% 58%,8% 52%,4% 36%,10% 20%,8% 0,20% 14%,30% 14%,40% 0,40% 20%,46% 36%,40% 52%,30% 56%,34% 60%,84% 54%,96% 68%,100% 100%,90% 100%,88% 76%,78% 78%,76% 100%,64% 100%,62% 80%,36% 80%,32% 100%)}.k-animal .s-near{height:16%}', + '.k-fish .s-far{left:22%;right:22%;top:34%;bottom:auto;height:32%;clip-path:polygon(0 50%,14% 18%,44% 4%,70% 18%,82% 42%,100% 12%,95% 50%,100% 88%,82% 58%,70% 82%,44% 96%,14% 82%)}.k-fish .s-near{height:14%;background:repeating-linear-gradient(90deg,var(--near) 0 10px,var(--sky2) 10px 16px)}.k-fish .s-sun{width:6%;top:24%;right:26%;background:transparent;border:2px solid var(--sun)}', + '.k-butterfly .s-far{left:26%;right:26%;top:22%;bottom:22%;background:radial-gradient(circle at 25% 30%,var(--sky1) 0 7%,transparent 8%),radial-gradient(circle at 75% 30%,var(--sky1) 0 7%,transparent 8%),var(--far);clip-path:polygon(50% 30%,78% 0,100% 18%,86% 50%,100% 80%,74% 100%,50% 66%,26% 100%,0 80%,14% 50%,0 18%,22% 0)}.k-butterfly .s-near{left:calc(50% - 2%);right:calc(50% - 2%);top:30%;bottom:30%;border-radius:4px;background:var(--sun)}.k-butterfly .s-sun{display:none}', + '.k-house .s-far{left:26%;right:26%;bottom:14%;height:56%;clip-path:polygon(50% 0,100% 42%,88% 42%,88% 100%,60% 100%,60% 70%,42% 70%,42% 100%,12% 100%,12% 42%,0 42%)}.k-house .s-near{height:16%}', + '.k-city .s-far{height:60%;clip-path:polygon(0 100%,0 40%,12% 40%,12% 20%,24% 20%,24% 55%,34% 55%,34% 8%,46% 8%,46% 35%,58% 35%,58% 25%,70% 25%,70% 50%,80% 50%,80% 15%,92% 15%,92% 45%,100% 45%,100% 100%);background:linear-gradient(90deg,transparent 0 3px,var(--sun) 3px 6px,transparent 6px) 0 0/16px 14px,var(--far)}.k-city .s-near{height:12%}', + '.k-lighthouse .s-far{left:42%;right:42%;bottom:14%;height:58%;clip-path:polygon(25% 14%,75% 14%,100% 100%,0 100%);background:repeating-linear-gradient(var(--far) 0 18%,#fffdf8 18% 36%)}.k-lighthouse .s-near{height:16%}.k-lighthouse .s-sun{left:44%;right:auto;top:20%;width:12%;border-radius:2px;box-shadow:0 0 18px 6px var(--sun)}', + '.k-boat .s-far{left:30%;right:30%;top:14%;bottom:30%;clip-path:polygon(52% 0,52% 100%,100% 100%);background:var(--far)}.k-boat .s-sun{left:22%;right:22%;top:auto;bottom:22%;width:auto;aspect-ratio:auto;height:12%;border-radius:0;clip-path:polygon(0 0,100% 0,86% 100%,14% 100%)}.k-boat .s-near{height:24%;background:repeating-linear-gradient(176deg,var(--near) 0 7px,var(--sky1) 7px 12px)}', + '.k-window .s-far{left:28%;right:28%;top:14%;bottom:32%;border:6px solid var(--near);background:linear-gradient(90deg,transparent calc(50% - 3px),var(--near) calc(50% - 3px) calc(50% + 3px),transparent 0),linear-gradient(transparent calc(50% - 3px),var(--near) calc(50% - 3px) calc(50% + 3px),transparent 0),var(--far)}.k-window .s-near{height:20%}.k-window .s-sun{display:none}', + '.k-figure .s-sun{left:50%;right:auto;top:20%;width:24%;transform:translateX(-50%)}.k-figure .s-far{left:22%;right:22%;height:40%;border-radius:50% 50% 0 0}.k-figure .s-near{display:none}', + '.k-statue .s-sun{left:50%;right:auto;top:14%;width:20%;transform:translateX(-50%)}.k-statue .s-far{left:28%;right:28%;bottom:18%;height:34%;border-radius:50% 50% 10% 10%}.k-statue .s-near{left:30%;right:30%;height:18%}', + '.k-bowl .s-sun{left:34%;right:auto;top:auto;bottom:34%;width:18%;box-shadow:42px -4px 0 -2px var(--sun)}.k-bowl .s-far{left:24%;right:24%;bottom:18%;height:22%;border-radius:0 0 50% 50%/0 0 100% 100%}.k-bowl .s-near{height:18%}', + '.k-vessel .s-far{left:31%;right:31%;bottom:16%;height:62%;clip-path:polygon(35% 0,65% 0,62% 12%,85% 35%,92% 60%,80% 90%,65% 100%,35% 100%,20% 90%,8% 60%,15% 35%,38% 12%);background:linear-gradient(90deg,var(--far) 0 30%,var(--sky1) 30% 33%,var(--far) 33%)}.k-vessel .s-near{height:16%}.k-vessel .s-sun{display:none}', + '.k-abstract .s-sun{left:16%;right:auto;top:16%;width:36%}.k-abstract .s-far{left:38%;right:12%;top:26%;bottom:20%;transform:rotate(12deg)}.k-abstract .s-near{left:8%;right:44%;height:46%;clip-path:polygon(0 100%,50% 0,100% 100%);opacity:.92}', + '.k-weave .s-far{inset:0;height:auto;background:repeating-linear-gradient(90deg,var(--far) 0 12px,transparent 12px 24px),repeating-linear-gradient(var(--near) 0 12px,var(--sun) 12px 24px)}.k-weave .s-near,.k-weave .s-sun{display:none}', + '.k-grain .s-far{left:18%;right:18%;top:18%;bottom:18%;border-radius:6px;background:repeating-radial-gradient(ellipse at 30% 50%,var(--far) 0 6px,var(--near) 6px 9px)}.k-grain .s-near,.k-grain .s-sun{display:none}', + '.k-ring .s-far{left:32%;right:32%;top:28%;bottom:auto;aspect-ratio:1;border-radius:50%;background:transparent;border:10px solid var(--far)}.k-ring .s-sun{left:50%;right:auto;top:18%;width:14%;transform:translateX(-50%) rotate(45deg);border-radius:3px;z-index:1}.k-ring .s-near{height:14%}', + '.k-grid .s-far{left:16%;right:16%;top:16%;bottom:16%;background:var(--near);border:2px solid var(--far);clip-path:none}.k-grid .s-near{left:28%;right:28%;top:28%;bottom:28%;background:repeating-linear-gradient(45deg,var(--far) 0 4px,transparent 4px 10px)}.k-grid .s-sun{right:30%;top:30%;width:18%;z-index:1}', + '.k-photo .s-far{left:20%;right:20%;top:20%;bottom:20%;border:8px solid #fffdf8;background:linear-gradient(transparent 62%,var(--near) 62%),var(--far)}.k-photo .s-sun{right:30%;top:28%;width:10%;z-index:1}.k-photo .s-near{display:none}', +].join('') function mediaTag(item: Artwork, lazy = true) { const src = `/image/${encodeURIComponent(item.id)}` @@ -69,34 +182,43 @@ function mediaTag(item: Artwork, lazy = true) { } /** Drawn stand-in art for a topic with nothing on its walls yet. */ -const flower = (slug: AuctionTopic) => slug === 'seacliffs' - ? `` - : `` +const flower = (slug: AuctionTopic) => { + const a = topicDef(slug).art + if (slug === 'seacliffs') return `` + if (a === 'legacy') return `` + return `` +} + +function topicCard(house: AuctionHouse, slug: AuctionTopic, count: number) { + const t = topicDef(slug) + const cover = count ? house.list(1, slug)[0] : undefined + return `${cover ? mediaTag(cover) : flower(slug)}${count ? `${count} ${count === 1 ? 'PIECE' : 'PIECES'}` : 'OPEN CALL'}

${t.name}

${t.blurb}

` +} +/** Home page strip: busiest topics first, topped up from the featured list. */ function topicDirectory(house: AuctionHouse) { - const cards = TOPIC_SLUGS.map((slug) => { - const t = AUCTION_TOPICS[slug] - const count = house.countTopic(slug) - const cover = house.list(1, slug)[0] - return `${cover ? mediaTag(cover) : flower(slug)}${count ? `${count} ${count === 1 ? 'PIECE' : 'PIECES'}` : 'OPEN CALL'}

${t.name}

${t.blurb}

` - }).join('') - return `

THE DIRECTORY

Browse by topic

All topics
${cards}
` + const counts = house.topicCounts() + const busy = TOPIC_SLUGS.filter((s) => counts[s]).sort((x, y) => (counts[y] ?? 0) - (counts[x] ?? 0)) + const picks = [...new Set([...busy, ...FEATURED_TOPICS])].slice(0, HOME_TOPIC_COUNT) + return `

THE DIRECTORY

Browse by topic

All ${TOPIC_SLUGS.length} topics
${picks.map((s) => topicCard(house, s, counts[s] ?? 0)).join('')}
` } function placeholderTiles(slug: AuctionTopic) { - const name = AUCTION_TOPICS[slug].name.replace(/s$/, '').toLowerCase() - return `` + return `` } function topicPage(house: AuctionHouse, slug: AuctionTopic, theme: AuctionTheme, shopCount = 0) { - const t = AUCTION_TOPICS[slug] + const t = topicDef(slug) const works = house.list(48, slug) - const others = TOPIC_SLUGS.filter((s) => s !== slug).map((s) => `${AUCTION_TOPICS[s].name}`).join('') + const others = TOPIC_SLUGS.filter((s) => s !== slug && topicDef(s).group === t.group).map((s) => `${topicDef(s).name}`).join('') + 'All topics' return page(theme, t.name, `
`, `${t.name} in the Art Auctions House: ${t.blurb}`, `/topics/${slug}`) } function topicsIndex(house: AuctionHouse, theme: AuctionTheme) { - return page(theme, 'Topics', `
${topicDirectory(house).replace('All topics ', 'Submit a piece ')}
`, 'Browse the Art Auctions House by topic.', '/topics') + const counts = house.topicCounts() + const jump = TOPIC_GROUPS.map((g) => `${g}`).join('') + const groups = TOPIC_GROUPS.map((g) => `

${g}

${TOPIC_SLUGS.filter((s) => topicDef(s).group === g).map((s) => topicCard(house, s, counts[s] ?? 0)).join('')}
`).join('') + return page(theme, 'Topics', `

THE DIRECTORY

Browse by topic

Painting, drawing, clay, glass, fiber, print and photography: ${TOPIC_SLUGS.length} topics, with nature first.

Submit a piece
${groups}
`, `Browse the Art Auctions House by topic: ${TOPIC_SLUGS.length} topics from landscapes and wildlife to ceramics and printmaking.`, '/topics') } type ArtworkImage = { image_type: string; image: Uint8Array } @@ -162,7 +284,7 @@ function home(house: AuctionHouse, theme: AuctionTheme) { } function formPage(theme: AuctionTheme, error = '', topic = '', signedIn = false) { - return page(theme, 'Submit artwork', `
← Back to the house

ADD A PIECE TO THE WALLS

Show us
what you made.

Share a clear photo or a short video and a little about the work. Your submission will appear in the public gallery.

${error ? `` : ''}
${signedIn ? `
Auction it optional
Buyers pay you directly at the CoinPay link in your account.
` : `

Sign in with CoinPay to auction your piece and see your bids.

`}

Submissions are public as soon as they are added. Sign in with CoinPay to run an auction; winning bidders pay you directly.

`, undefined, '/new') + return page(theme, 'Submit artwork', `
← Back to the house

ADD A PIECE TO THE WALLS

Show us
what you made.

Share a clear photo or a short video and a little about the work. Your submission will appear in the public gallery.

${error ? `` : ''}
${signedIn ? `
Auction it optional
Buyers pay you directly at the CoinPay link in your account.
` : `

Sign in with CoinPay to auction your piece and see your bids.

`}

Submissions are public as soon as they are added. Sign in with CoinPay to run an auction; winning bidders pay you directly.

`, undefined, '/new') } function detail(item: Artwork, theme: AuctionTheme, auctionHtml = '') { @@ -238,6 +360,13 @@ export class AuctionHouse { return this.db.query<{ n: number }, [string]>('SELECT COUNT(*) AS n FROM auction_artworks WHERE topic = ?').get(topic)?.n ?? 0 } + /** Pieces per topic in one query, for the directory pages. */ + topicCounts(): Partial> { + const out: Partial> = {} + for (const row of this.db.query<{ topic: string; n: number }, []>("SELECT topic, COUNT(*) AS n FROM auction_artworks WHERE topic != '' GROUP BY topic").all()) if (isTopic(row.topic)) out[row.topic] = row.n + return out + } + get(id: string): Artwork | null { return this.db.query('SELECT id, title, artist, medium, description, image_type, topic, created_at, owner_sub, starting_bid, ends_at, closed_at FROM auction_artworks WHERE id = ?').get(id) ?? null } @@ -655,4 +784,5 @@ const AUCTIONS_CSS = `/* Themes: "warm" (the original cream and green house look /* Blue must come after the :root default: equal specificity, so source order decides. */ html[data-theme=blue]{--ink:#16213a;--muted:#5f6b82;--soft:#46526a;--paper:#eef3fa;--white:#fbfdff;--green:#1f4f8f;--on-green:#f6f9ff;--on-green-accent:#9cc7ff;--line:#d2dcea;--accent:#2f7fe0;--frame:#dbe4f1;--panel:#e2eaf5;--art-1:#c9d8ee;--art-2:#8eaad3;--art-3:#3d6aa8;--art-4:#13294d;--art-shadow:#d6e1f1;--art-frame:#f2f7ff;--art-sun:#f1f5fb;--shape-1:#183865;--shape-2:#4b7fc4;--shape-3:#dbe7f6;--shape-4:#7aa3d9;--invite-eyebrow:#a8c9f2;--invite-em:#c6dcf8;--invite-small:#c5d1e4;--input-line:#c0cbdc;--input-bg:#fff;--upload-line:#98a8c2;--upload-bg:#f4f7fc;--error-bg:#fbe4e4;--error-ink:#8a2b2b;--focus:#3b82f6} .theme-pick{display:flex;align-items:center;gap:6px;color:var(--muted);font-size:11px;letter-spacing:.08em}.theme-pick a{display:inline-flex;align-items:center;gap:6px;padding:6px 10px;border:1px solid var(--line);border-radius:999px;color:var(--ink)}.theme-pick a[aria-current=true]{border-color:var(--green);font-weight:700}.theme-pick i{display:inline-block;width:10px;height:10px;border-radius:50%}.swatch-blue{background:#1f4f8f}.swatch-warm{background:#384b36} -:root{font-family:Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;font-synthesis:none;text-rendering:optimizeLegibility}*{box-sizing:border-box}html{scroll-behavior:smooth}body{margin:0;background:var(--paper);color:var(--ink)}a{color:inherit;text-decoration:none}.top{height:82px;padding:0 max(6vw,24px);display:flex;align-items:center;justify-content:space-between;border-bottom:1px solid var(--line)}.brand{display:flex;align-items:center;gap:12px;font-family:Georgia,serif;font-size:20px;line-height:1}.brand small{display:block;margin-top:7px;font:9px/1.1 ui-sans-serif,system-ui,sans-serif;letter-spacing:.15em;color:var(--muted)}.brand-mark{display:grid;place-items:center;width:38px;height:38px;border:1px solid var(--green);border-radius:50%;color:var(--green);font:italic 24px Georgia,serif}.top nav{display:flex;align-items:center;gap:32px;font-size:13px}.top nav a:first-child{color:var(--muted)}.nav-cta,.text-link{font-weight:650}.nav-cta span,.text-link span,.button span{margin-left:8px;color:var(--accent)}main{max-width:1440px;margin:0 auto;padding:0 max(6vw,24px)}.hero{position:relative;min-height:540px;padding:76px 0 86px;display:grid;grid-template-columns:1fr 1fr;align-items:center;gap:8%;border-bottom:1px solid var(--line)}.hero-copy{position:relative;z-index:1}.eyebrow{margin:0 0 18px;color:var(--green);font-size:10px;font-weight:750;letter-spacing:.19em}.hero h1,.form-wrap h1{margin:0;font:clamp(52px,6.5vw,88px)/.96 Georgia,"Times New Roman",serif;letter-spacing:-.055em;font-weight:400}.hero h1 em,.form-wrap h1 em,.invite h2 em{color:var(--green);font-weight:400}.lede{max-width:370px;margin:24px 0 28px;color:var(--soft);font:18px/1.55 Georgia,serif}.button{display:inline-flex;align-items:center;justify-content:center;min-height:48px;padding:0 22px;border:0;border-radius:2px;font:650 13px ui-sans-serif,system-ui,sans-serif;cursor:pointer}.button-dark{background:var(--green);color:var(--on-green)}.button-dark span{color:var(--on-green-accent)}.button-light{background:var(--paper);color:var(--ink)}.hero-note{margin:17px 0 0;color:var(--muted);font-size:11px}.hero-art{position:relative;overflow:hidden;width:min(100%,500px);height:380px;justify-self:end;background:linear-gradient(135deg,var(--art-1) 0%,var(--art-2) 47%,var(--art-3) 47%,var(--art-4) 100%);box-shadow:20px 24px 0 var(--art-shadow)}.hero-art:before{content:"";position:absolute;inset:18px;border:1px solid var(--art-frame);opacity:.7}.sun{position:absolute;top:46px;right:78px;width:132px;height:132px;border-radius:50%;background:var(--art-sun)}.shape{position:absolute;bottom:-50px;border-radius:50% 50% 0 0}.shape-one{left:4%;width:65%;height:63%;background:var(--shape-1);transform:rotate(-17deg)}.shape-two{right:-12%;width:62%;height:75%;background:var(--shape-2);transform:rotate(15deg)}.shape-three{left:27%;bottom:-28%;width:48%;height:65%;background:var(--shape-3);transform:rotate(33deg)}.shape-four{left:52%;bottom:-22%;width:30%;height:61%;background:var(--shape-4);transform:rotate(-24deg)}.art-caption{position:absolute;left:34px;bottom:28px;color:white;font:italic 18px/1.45 Georgia,serif}.art-caption b{font:10px ui-sans-serif,system-ui,sans-serif;letter-spacing:.12em;text-transform:uppercase}.hero-index{position:absolute;right:0;bottom:22px;color:var(--muted);font-size:10px;letter-spacing:.15em}.gallery-section{padding:74px 0 92px}.section-head{display:flex;align-items:end;justify-content:space-between;margin-bottom:30px}.section-head .eyebrow{margin-bottom:11px}.section-head h2,.invite h2{margin:0;font:clamp(30px,4vw,48px)/1.1 Georgia,serif;font-weight:400;letter-spacing:-.03em}.count{margin-left:7px;vertical-align:top;color:var(--muted);font:11px ui-sans-serif,system-ui,sans-serif;letter-spacing:0}.text-link{font-size:12px}.gallery{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:30px 22px}.art-card{min-width:0}.art-image{display:block;overflow:hidden;aspect-ratio:4/4.7;background:var(--frame)}.art-image img,.art-image video{width:100%;height:100%;display:block;object-fit:cover;transition:transform .35s}.art-card:hover img,.art-card:hover video{transform:scale(1.025)}.art-info{padding:16px 1px}.art-info .eyebrow{font-size:9px;margin:0 0 8px}.art-info h3{margin:0;font:23px/1.2 Georgia,serif;font-weight:400}.art-info p{margin:7px 0 0;color:var(--muted);font:14px Georgia,serif}.empty{padding:72px 24px;text-align:center;background:var(--panel)}.empty-stamp{display:grid;place-items:center;width:55px;height:55px;margin:0 auto 20px;border:1px solid var(--green);border-radius:50%;color:var(--green);font-size:25px}.empty h3{margin:0;font:30px Georgia,serif;font-weight:400}.empty p{max-width:390px;margin:12px auto 22px;color:var(--muted);font:15px/1.6 Georgia,serif}.invite{margin:0 calc(-1 * max(6vw,24px));padding:76px max(6vw,24px);background:var(--green);color:var(--on-green);display:grid;grid-template-columns:1fr 1fr;gap:8%;align-items:center}.invite .eyebrow{color:var(--invite-eyebrow)}.invite h2 em{color:var(--invite-em)}.invite-copy p{max-width:360px;margin:0 0 24px;font:18px/1.55 Georgia,serif}.invite-copy small{display:block;max-width:390px;margin-top:15px;color:var(--invite-small);font-size:11px;line-height:1.5}.form-wrap{max-width:620px;margin:0 auto;padding:64px 0 100px}.back-link{display:inline-block;margin-bottom:52px;color:var(--muted);font-size:12px}.form-wrap .eyebrow{margin-bottom:16px}.form-wrap h1{font-size:clamp(48px,8vw,70px)}.form-intro{max-width:460px;margin:20px 0 30px;color:var(--soft);font:17px/1.6 Georgia,serif}.art-form{padding:30px;background:var(--white);border:1px solid var(--line)}.field{display:block;margin-bottom:21px}.field>span{display:block;margin-bottom:8px;font-size:12px;font-weight:700}.field b{color:var(--accent)}.field small{margin-left:7px;color:var(--muted);font-weight:400}.field input:not([type=file]),.field textarea{display:block;width:100%;min-height:48px;padding:12px 13px;border:1px solid var(--input-line);border-radius:2px;background:var(--input-bg);color:var(--ink);font:15px ui-sans-serif,system-ui,sans-serif}.field textarea{min-height:120px;resize:vertical}.upload-field input[type=file]{display:block;width:100%;min-height:54px;padding:13px;border:1px dashed var(--upload-line);background:var(--upload-bg);color:var(--ink);font-size:13px}.upload-field>small{display:block;margin:8px 0 0;color:var(--muted);font-size:11px}.permission{display:flex;gap:11px;align-items:flex-start;margin:24px 0;color:var(--soft);font-size:12px;line-height:1.55}.permission input{width:18px;height:18px;margin:0;flex:0 0 auto;accent-color:var(--green)}.submit-button{width:100%}.form-foot{margin:16px 0 0;color:var(--muted);font-size:11px;line-height:1.55}.error{padding:12px 14px;background:var(--error-bg);color:var(--error-ink);font-size:13px}.hp{position:absolute;left:-10000px;width:1px;height:1px;overflow:hidden}.detail-wrap{padding:48px 0 90px}.detail-wrap .back-link{margin-bottom:30px}.detail-grid{display:grid;grid-template-columns:minmax(0,1.1fr) minmax(280px,.75fr);gap:8%;align-items:start}.detail-image{display:block;width:100%;max-height:78vh;object-fit:contain;background:var(--frame)}.detail-copy{padding:10px 0}.detail-copy h1{margin:0;font:clamp(42px,6vw,72px)/1 Georgia,serif;font-weight:400;letter-spacing:-.04em}.detail-copy .artist{margin:13px 0 28px;color:var(--muted);font:18px Georgia,serif}.detail-description{margin:0 0 28px;font:16px/1.7 Georgia,serif}.footer-brand{font-size:17px}.footer-brand .brand-mark{width:33px;height:33px;font-size:21px}footer{display:flex;justify-content:space-between;align-items:center;padding:28px max(6vw,24px);border-top:1px solid var(--line)}footer p{max-width:240px;color:var(--muted);font:13px/1.5 Georgia,serif}.field select{display:block;width:100%;min-height:48px;padding:12px 13px;border:1px solid var(--input-line);border-radius:2px;background:var(--input-bg);color:var(--ink);font:15px ui-sans-serif,system-ui,sans-serif}.topics-section{padding:0 0 92px}.topic-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(230px,1fr));gap:22px}.topic-card{display:flex;flex-direction:column;border:1px solid var(--line);background:var(--white);transition:border-color .2s}.topic-card:hover{border-color:var(--green)}.topic-cover{position:relative;display:block;overflow:hidden;aspect-ratio:4/3;background:var(--panel)}.topic-cover img,.topic-cover video{width:100%;height:100%;display:block;object-fit:cover}.topic-body{display:block;padding:18px 20px 22px}.topic-body .eyebrow{display:block;margin:0 0 8px;font-size:9px}.topic-body h3{margin:0;font:26px/1.15 Georgia,serif;font-weight:400}.topic-body p{margin:8px 0 0;color:var(--muted);font:14px/1.5 Georgia,serif}.topic-lede{max-width:460px;margin:10px 0 0;color:var(--soft);font:16px/1.55 Georgia,serif}.topic-page .back-link{margin-bottom:30px}.topic-chips{display:flex;flex-wrap:wrap;gap:8px;margin:34px 0 0}.topic-chips a{padding:7px 13px;border:1px solid var(--line);border-radius:999px;font-size:12px;font-weight:650}.topic-chips a:hover{border-color:var(--green)}.detail-topic{margin:-14px 0 24px}.flower-ph{position:absolute;inset:0;display:block;background:radial-gradient(circle at 50% 120%,var(--frame),var(--panel) 70%)}.flower{position:absolute;left:50%;top:42%;width:46%;aspect-ratio:1;transform:translate(-50%,-50%);border-radius:50%;z-index:1}.flower:after{content:"";position:absolute;inset:36%;border-radius:50%;background:var(--c3)}.stem{position:absolute;left:calc(50% - 2px);top:64%;width:4px;height:40%;background:#5f7d4f;border-radius:2px}.stem:before{content:"";position:absolute;left:4px;top:30%;width:34px;height:16px;border-radius:0 100% 0 100%;background:#6f8f5c}.ph-dahlias .flower{--c3:#f2c35b;background:repeating-conic-gradient(#c2416b 0 9deg,#e98aa6 9deg 18deg);box-shadow:0 0 0 10px #d65f86 inset}.ph-mums .flower{--c3:#9a6a22;background:repeating-conic-gradient(#d9962b 0 5deg,#f6cf6a 5deg 10deg)}.ph-roses .flower{--c3:transparent;background:radial-gradient(circle,#6e1028 0 10%,#c8455e 11% 22%,#9e1f3a 23% 36%,#c8455e 37% 50%,#9e1f3a 51% 70%)}.ph-seacliffs{background:linear-gradient(#cfe0ec 0 58%,#8fb3cc 58%)}.sky-sun{position:absolute;right:20%;top:16%;width:16%;aspect-ratio:1;border-radius:50%;background:#f6d48a}.cliff{position:absolute;left:0;bottom:22%;width:58%;height:62%;background:#8a6f55;clip-path:polygon(0 18%,30% 6%,58% 14%,82% 30%,100% 100%,0 100%);box-shadow:inset -14px 0 0 #6f5640}.cliff:before{content:"";position:absolute;left:0;top:0;width:100%;height:18%;background:#6f8f5c;clip-path:polygon(0 100%,0 0,30% 0,58% 40%,82% 100%)}.sea{position:absolute;left:0;right:0;bottom:0;height:24%;background:repeating-linear-gradient(170deg,#4f7fa6 0 8px,#5f90b6 8px 16px)}.placeholder-tile{position:relative;border:1px dashed var(--upload-line)}.placeholder-label{position:absolute;left:50%;bottom:16px;transform:translateX(-50%);padding:6px 14px;border-radius:999px;background:var(--white);color:var(--soft);font:italic 14px Georgia,serif;white-space:nowrap;z-index:2}.topics-main .topics-section{padding-top:64px}.placeholder-card .art-info h3{color:var(--muted)}.shop-page .shop-title{margin:0;font:clamp(46px,6vw,78px)/1 Georgia,"Times New Roman",serif;letter-spacing:-.045em;font-weight:400}.shop-page .shop-title em{color:var(--green)}.shop-group{padding-top:58px}.shop-art{position:relative}.shop-photo{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;display:block}.photo-credit{margin:10px 0 0;color:var(--muted);font-size:11px;line-height:1.5}.photo-credit a{text-decoration:underline}.credits{margin-top:46px;color:var(--muted);font-size:12px}.credits summary{cursor:pointer;font-weight:650}.credits ul{padding-left:18px;line-height:1.7}.credits .photo-credit{display:inline}.price{font:600 17px Georgia,serif;color:var(--ink)}.shop-hero{position:relative;aspect-ratio:4/4.4;background:var(--panel);overflow:hidden}.shop-facts{margin:0 0 26px;padding:0 0 0 18px;color:var(--soft);font:15px/1.8 Georgia,serif}.shop-form{margin-top:8px}.field-row{display:grid;grid-template-columns:2fr 1fr 1fr;gap:12px}.notice{padding:12px 14px;background:var(--panel);border-left:3px solid var(--green);font-size:13px}.shop-terms{margin-top:46px;max-width:560px}.topic-shop{margin:14px 0 0}.order-steps{margin:8px 0 28px;padding:0;list-style:none;border-left:2px solid var(--line)}.order-steps li{position:relative;padding:8px 0 8px 22px;color:var(--muted);font:16px Georgia,serif}.order-steps li:before{content:"";position:absolute;left:-7px;top:13px;width:12px;height:12px;border-radius:50%;background:var(--paper);border:2px solid var(--line)}.order-steps li.done{color:var(--ink)}.order-steps li.done:before{background:var(--green);border-color:var(--green)}.admin-table{overflow-x:auto}.admin-table table{width:100%;border-collapse:collapse;font-size:13px}.admin-table th,.admin-table td{padding:10px;border-bottom:1px solid var(--line);text-align:left;vertical-align:top}.admin-table form{display:flex;gap:6px;margin-top:6px}.admin-table input{min-width:0;padding:6px;border:1px solid var(--input-line)}.auction-box{margin:0 0 26px;padding:20px 22px;border:1px solid var(--line);background:var(--white)}.auction-box .eyebrow{margin-bottom:10px}.auction-box.ended{background:var(--panel)}.bid-now{margin:0 0 6px;font:20px Georgia,serif}.bid-form{display:flex;flex-wrap:wrap;gap:10px;align-items:end;margin-top:14px}.bid-form label{display:flex;flex-direction:column;gap:6px;font-size:12px;font-weight:700}.bid-form input{width:140px;min-height:48px;padding:10px;border:1px solid var(--input-line);background:var(--input-bg);color:var(--ink);font:16px ui-sans-serif,system-ui,sans-serif}.won{margin:12px 0 0}.won .button{margin-top:10px}.manage{margin:0 0 26px;font-size:13px}.manage summary{cursor:pointer;font-weight:650}.inline-form{display:flex;flex-wrap:wrap;gap:10px;align-items:center;margin:12px 0}.inline-form input,.inline-form select{min-height:38px;padding:6px 8px;border:1px solid var(--input-line);background:var(--input-bg);color:var(--ink)}.inline-form input{width:90px}.quiet-button{padding:8px 14px;border:1px solid var(--line);background:transparent;color:var(--ink);border-radius:2px;cursor:pointer;font:600 12px ui-sans-serif,system-ui,sans-serif}.quiet-button.danger{color:#9b2c2c;border-color:#e3b4b4}.auction-fields{margin:0 0 21px;padding:16px;border:1px dashed var(--upload-line)}.auction-fields legend{padding:0 6px;font-size:12px;font-weight:700}.auction-fields>small{display:block;color:var(--muted);font-size:11px}.field-row.two{grid-template-columns:1fr 1fr}.account .art-form .form-foot{margin:-8px 0 20px}.account>form:last-child{margin-top:40px}.account h2{margin:42px 0 14px;font:28px Georgia,serif;font-weight:400}.account-list{margin:0;padding-left:18px;font:15px/1.9 Georgia,serif}.account-list a{text-decoration:underline}input:focus-visible,select:focus-visible,textarea:focus-visible,a:focus-visible,button:focus-visible{outline:3px solid var(--focus);outline-offset:3px}@media(max-width:760px){.top nav a[href="/topics"]{display:none}.field-row{grid-template-columns:1fr 1fr}.field-row .field:first-child{grid-column:1/-1}.top nav a:first-child{display:none}.topics-main .topics-section{padding-top:42px}.topic-grid{grid-template-columns:1fr;gap:16px}.topic-cover{aspect-ratio:16/9}.top{height:70px}.top nav{gap:16px;font-size:11px}.brand{font-size:17px}.brand small{font-size:8px}.hero{min-height:auto;padding:55px 0 65px;grid-template-columns:1fr;gap:38px}.hero h1{font-size:clamp(50px,13vw,76px)}.hero-art{width:100%;height:clamp(250px,75vw,380px);justify-self:stretch}.hero-index{bottom:18px}.gallery-section{padding:58px 0 68px}.section-head{align-items:start;gap:12px}.section-head .text-link{padding-top:20px;font-size:11px}.gallery{grid-template-columns:repeat(2,minmax(0,1fr));gap:20px 13px}.art-info h3{font-size:18px}.art-info p{font-size:12px}.invite{grid-template-columns:1fr;gap:24px;padding-top:56px;padding-bottom:58px}.form-wrap{padding:42px 0 72px}.back-link{margin-bottom:36px}.art-form{padding:20px}.detail-grid{grid-template-columns:1fr;gap:30px}.detail-image{max-height:65vh}footer{gap:18px;align-items:flex-start;flex-wrap:wrap}.theme-pick{flex-basis:100%}footer p{max-width:150px;font-size:12px}}@media(max-width:380px){.top{padding-inline:16px}.top nav{gap:12px}.top nav a:first-child{display:none}main{padding-inline:16px}.invite{margin-inline:-16px;padding-inline:16px}.hero-art{height:250px}.art-form{padding:16px}footer{padding-inline:16px}}@media(prefers-reduced-motion:reduce){html{scroll-behavior:auto}*,*:before,*:after{transition:none!important}}` +:root{font-family:Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;font-synthesis:none;text-rendering:optimizeLegibility}*{box-sizing:border-box}html{scroll-behavior:smooth}body{margin:0;background:var(--paper);color:var(--ink)}a{color:inherit;text-decoration:none}.top{height:82px;padding:0 max(6vw,24px);display:flex;align-items:center;justify-content:space-between;border-bottom:1px solid var(--line)}.brand{display:flex;align-items:center;gap:12px;font-family:Georgia,serif;font-size:20px;line-height:1}.brand small{display:block;margin-top:7px;font:9px/1.1 ui-sans-serif,system-ui,sans-serif;letter-spacing:.15em;color:var(--muted)}.brand-mark{display:grid;place-items:center;width:38px;height:38px;border:1px solid var(--green);border-radius:50%;color:var(--green);font:italic 24px Georgia,serif}.top nav{display:flex;align-items:center;gap:32px;font-size:13px}.top nav a:first-child{color:var(--muted)}.nav-cta,.text-link{font-weight:650}.nav-cta span,.text-link span,.button span{margin-left:8px;color:var(--accent)}main{max-width:1440px;margin:0 auto;padding:0 max(6vw,24px)}.hero{position:relative;min-height:540px;padding:76px 0 86px;display:grid;grid-template-columns:1fr 1fr;align-items:center;gap:8%;border-bottom:1px solid var(--line)}.hero-copy{position:relative;z-index:1}.eyebrow{margin:0 0 18px;color:var(--green);font-size:10px;font-weight:750;letter-spacing:.19em}.hero h1,.form-wrap h1{margin:0;font:clamp(52px,6.5vw,88px)/.96 Georgia,"Times New Roman",serif;letter-spacing:-.055em;font-weight:400}.hero h1 em,.form-wrap h1 em,.invite h2 em{color:var(--green);font-weight:400}.lede{max-width:370px;margin:24px 0 28px;color:var(--soft);font:18px/1.55 Georgia,serif}.button{display:inline-flex;align-items:center;justify-content:center;min-height:48px;padding:0 22px;border:0;border-radius:2px;font:650 13px ui-sans-serif,system-ui,sans-serif;cursor:pointer}.button-dark{background:var(--green);color:var(--on-green)}.button-dark span{color:var(--on-green-accent)}.button-light{background:var(--paper);color:var(--ink)}.hero-note{margin:17px 0 0;color:var(--muted);font-size:11px}.hero-art{position:relative;overflow:hidden;width:min(100%,500px);height:380px;justify-self:end;background:linear-gradient(135deg,var(--art-1) 0%,var(--art-2) 47%,var(--art-3) 47%,var(--art-4) 100%);box-shadow:20px 24px 0 var(--art-shadow)}.hero-art:before{content:"";position:absolute;inset:18px;border:1px solid var(--art-frame);opacity:.7}.sun{position:absolute;top:46px;right:78px;width:132px;height:132px;border-radius:50%;background:var(--art-sun)}.shape{position:absolute;bottom:-50px;border-radius:50% 50% 0 0}.shape-one{left:4%;width:65%;height:63%;background:var(--shape-1);transform:rotate(-17deg)}.shape-two{right:-12%;width:62%;height:75%;background:var(--shape-2);transform:rotate(15deg)}.shape-three{left:27%;bottom:-28%;width:48%;height:65%;background:var(--shape-3);transform:rotate(33deg)}.shape-four{left:52%;bottom:-22%;width:30%;height:61%;background:var(--shape-4);transform:rotate(-24deg)}.art-caption{position:absolute;left:34px;bottom:28px;color:white;font:italic 18px/1.45 Georgia,serif}.art-caption b{font:10px ui-sans-serif,system-ui,sans-serif;letter-spacing:.12em;text-transform:uppercase}.hero-index{position:absolute;right:0;bottom:22px;color:var(--muted);font-size:10px;letter-spacing:.15em}.gallery-section{padding:74px 0 92px}.section-head{display:flex;align-items:end;justify-content:space-between;margin-bottom:30px}.section-head .eyebrow{margin-bottom:11px}.section-head h2,.invite h2{margin:0;font:clamp(30px,4vw,48px)/1.1 Georgia,serif;font-weight:400;letter-spacing:-.03em}.count{margin-left:7px;vertical-align:top;color:var(--muted);font:11px ui-sans-serif,system-ui,sans-serif;letter-spacing:0}.text-link{font-size:12px}.gallery{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:30px 22px}.art-card{min-width:0}.art-image{display:block;overflow:hidden;aspect-ratio:4/4.7;background:var(--frame)}.art-image img,.art-image video{width:100%;height:100%;display:block;object-fit:cover;transition:transform .35s}.art-card:hover img,.art-card:hover video{transform:scale(1.025)}.art-info{padding:16px 1px}.art-info .eyebrow{font-size:9px;margin:0 0 8px}.art-info h3{margin:0;font:23px/1.2 Georgia,serif;font-weight:400}.art-info p{margin:7px 0 0;color:var(--muted);font:14px Georgia,serif}.empty{padding:72px 24px;text-align:center;background:var(--panel)}.empty-stamp{display:grid;place-items:center;width:55px;height:55px;margin:0 auto 20px;border:1px solid var(--green);border-radius:50%;color:var(--green);font-size:25px}.empty h3{margin:0;font:30px Georgia,serif;font-weight:400}.empty p{max-width:390px;margin:12px auto 22px;color:var(--muted);font:15px/1.6 Georgia,serif}.invite{margin:0 calc(-1 * max(6vw,24px));padding:76px max(6vw,24px);background:var(--green);color:var(--on-green);display:grid;grid-template-columns:1fr 1fr;gap:8%;align-items:center}.invite .eyebrow{color:var(--invite-eyebrow)}.invite h2 em{color:var(--invite-em)}.invite-copy p{max-width:360px;margin:0 0 24px;font:18px/1.55 Georgia,serif}.invite-copy small{display:block;max-width:390px;margin-top:15px;color:var(--invite-small);font-size:11px;line-height:1.5}.form-wrap{max-width:620px;margin:0 auto;padding:64px 0 100px}.back-link{display:inline-block;margin-bottom:52px;color:var(--muted);font-size:12px}.form-wrap .eyebrow{margin-bottom:16px}.form-wrap h1{font-size:clamp(48px,8vw,70px)}.form-intro{max-width:460px;margin:20px 0 30px;color:var(--soft);font:17px/1.6 Georgia,serif}.art-form{padding:30px;background:var(--white);border:1px solid var(--line)}.field{display:block;margin-bottom:21px}.field>span{display:block;margin-bottom:8px;font-size:12px;font-weight:700}.field b{color:var(--accent)}.field small{margin-left:7px;color:var(--muted);font-weight:400}.field input:not([type=file]),.field textarea{display:block;width:100%;min-height:48px;padding:12px 13px;border:1px solid var(--input-line);border-radius:2px;background:var(--input-bg);color:var(--ink);font:15px ui-sans-serif,system-ui,sans-serif}.field textarea{min-height:120px;resize:vertical}.upload-field input[type=file]{display:block;width:100%;min-height:54px;padding:13px;border:1px dashed var(--upload-line);background:var(--upload-bg);color:var(--ink);font-size:13px}.upload-field>small{display:block;margin:8px 0 0;color:var(--muted);font-size:11px}.permission{display:flex;gap:11px;align-items:flex-start;margin:24px 0;color:var(--soft);font-size:12px;line-height:1.55}.permission input{width:18px;height:18px;margin:0;flex:0 0 auto;accent-color:var(--green)}.submit-button{width:100%}.form-foot{margin:16px 0 0;color:var(--muted);font-size:11px;line-height:1.55}.error{padding:12px 14px;background:var(--error-bg);color:var(--error-ink);font-size:13px}.hp{position:absolute;left:-10000px;width:1px;height:1px;overflow:hidden}.detail-wrap{padding:48px 0 90px}.detail-wrap .back-link{margin-bottom:30px}.detail-grid{display:grid;grid-template-columns:minmax(0,1.1fr) minmax(280px,.75fr);gap:8%;align-items:start}.detail-image{display:block;width:100%;max-height:78vh;object-fit:contain;background:var(--frame)}.detail-copy{padding:10px 0}.detail-copy h1{margin:0;font:clamp(42px,6vw,72px)/1 Georgia,serif;font-weight:400;letter-spacing:-.04em}.detail-copy .artist{margin:13px 0 28px;color:var(--muted);font:18px Georgia,serif}.detail-description{margin:0 0 28px;font:16px/1.7 Georgia,serif}.footer-brand{font-size:17px}.footer-brand .brand-mark{width:33px;height:33px;font-size:21px}footer{display:flex;justify-content:space-between;align-items:center;padding:28px max(6vw,24px);border-top:1px solid var(--line)}footer p{max-width:240px;color:var(--muted);font:13px/1.5 Georgia,serif}.field select{display:block;width:100%;min-height:48px;padding:12px 13px;border:1px solid var(--input-line);border-radius:2px;background:var(--input-bg);color:var(--ink);font:15px ui-sans-serif,system-ui,sans-serif}.topics-section{padding:0 0 92px}.topic-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(230px,1fr));gap:22px}.topic-card{display:flex;flex-direction:column;border:1px solid var(--line);background:var(--white);transition:border-color .2s}.topic-card:hover{border-color:var(--green)}.topic-cover{position:relative;display:block;overflow:hidden;aspect-ratio:4/3;background:var(--panel)}.topic-cover img,.topic-cover video{width:100%;height:100%;display:block;object-fit:cover}.topic-body{display:block;padding:18px 20px 22px}.topic-body .eyebrow{display:block;margin:0 0 8px;font-size:9px}.topic-body h3{margin:0;font:26px/1.15 Georgia,serif;font-weight:400}.topic-body p{margin:8px 0 0;color:var(--muted);font:14px/1.5 Georgia,serif}.topic-lede{max-width:460px;margin:10px 0 0;color:var(--soft);font:16px/1.55 Georgia,serif}.topic-page .back-link{margin-bottom:30px}.topic-chips{display:flex;flex-wrap:wrap;gap:8px;margin:34px 0 0}.topic-chips a{padding:7px 13px;border:1px solid var(--line);border-radius:999px;font-size:12px;font-weight:650}.topic-chips a:hover{border-color:var(--green)}.detail-topic{margin:-14px 0 24px}.flower-ph{position:absolute;inset:0;display:block;background:radial-gradient(circle at 50% 120%,var(--frame),var(--panel) 70%)}.flower{position:absolute;left:50%;top:42%;width:46%;aspect-ratio:1;transform:translate(-50%,-50%);border-radius:50%;z-index:1}.flower:after{content:"";position:absolute;inset:36%;border-radius:50%;background:var(--c3)}.stem{position:absolute;left:calc(50% - 2px);top:64%;width:4px;height:40%;background:#5f7d4f;border-radius:2px}.stem:before{content:"";position:absolute;left:4px;top:30%;width:34px;height:16px;border-radius:0 100% 0 100%;background:#6f8f5c}.ph-dahlias .flower{--c3:#f2c35b;background:repeating-conic-gradient(#c2416b 0 9deg,#e98aa6 9deg 18deg);box-shadow:0 0 0 10px #d65f86 inset}.ph-mums .flower{--c3:#9a6a22;background:repeating-conic-gradient(#d9962b 0 5deg,#f6cf6a 5deg 10deg)}.ph-roses .flower{--c3:transparent;background:radial-gradient(circle,#6e1028 0 10%,#c8455e 11% 22%,#9e1f3a 23% 36%,#c8455e 37% 50%,#9e1f3a 51% 70%)}.ph-seacliffs{background:linear-gradient(#cfe0ec 0 58%,#8fb3cc 58%)}.sky-sun{position:absolute;right:20%;top:16%;width:16%;aspect-ratio:1;border-radius:50%;background:#f6d48a}.cliff{position:absolute;left:0;bottom:22%;width:58%;height:62%;background:#8a6f55;clip-path:polygon(0 18%,30% 6%,58% 14%,82% 30%,100% 100%,0 100%);box-shadow:inset -14px 0 0 #6f5640}.cliff:before{content:"";position:absolute;left:0;top:0;width:100%;height:18%;background:#6f8f5c;clip-path:polygon(0 100%,0 0,30% 0,58% 40%,82% 100%)}.sea{position:absolute;left:0;right:0;bottom:0;height:24%;background:repeating-linear-gradient(170deg,#4f7fa6 0 8px,#5f90b6 8px 16px)}.placeholder-tile{position:relative;border:1px dashed var(--upload-line)}.placeholder-label{position:absolute;left:50%;bottom:16px;transform:translateX(-50%);padding:6px 14px;border-radius:999px;background:var(--white);color:var(--soft);font:italic 14px Georgia,serif;white-space:nowrap;z-index:2}.topics-main .topics-section{padding-top:64px}.placeholder-card .art-info h3{color:var(--muted)}.shop-page .shop-title{margin:0;font:clamp(46px,6vw,78px)/1 Georgia,"Times New Roman",serif;letter-spacing:-.045em;font-weight:400}.shop-page .shop-title em{color:var(--green)}.shop-group{padding-top:58px}.shop-art{position:relative}.shop-photo{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;display:block}.photo-credit{margin:10px 0 0;color:var(--muted);font-size:11px;line-height:1.5}.photo-credit a{text-decoration:underline}.credits{margin-top:46px;color:var(--muted);font-size:12px}.credits summary{cursor:pointer;font-weight:650}.credits ul{padding-left:18px;line-height:1.7}.credits .photo-credit{display:inline}.price{font:600 17px Georgia,serif;color:var(--ink)}.shop-hero{position:relative;aspect-ratio:4/4.4;background:var(--panel);overflow:hidden}.shop-facts{margin:0 0 26px;padding:0 0 0 18px;color:var(--soft);font:15px/1.8 Georgia,serif}.shop-form{margin-top:8px}.field-row{display:grid;grid-template-columns:2fr 1fr 1fr;gap:12px}.notice{padding:12px 14px;background:var(--panel);border-left:3px solid var(--green);font-size:13px}.shop-terms{margin-top:46px;max-width:560px}.topic-shop{margin:14px 0 0}.order-steps{margin:8px 0 28px;padding:0;list-style:none;border-left:2px solid var(--line)}.order-steps li{position:relative;padding:8px 0 8px 22px;color:var(--muted);font:16px Georgia,serif}.order-steps li:before{content:"";position:absolute;left:-7px;top:13px;width:12px;height:12px;border-radius:50%;background:var(--paper);border:2px solid var(--line)}.order-steps li.done{color:var(--ink)}.order-steps li.done:before{background:var(--green);border-color:var(--green)}.admin-table{overflow-x:auto}.admin-table table{width:100%;border-collapse:collapse;font-size:13px}.admin-table th,.admin-table td{padding:10px;border-bottom:1px solid var(--line);text-align:left;vertical-align:top}.admin-table form{display:flex;gap:6px;margin-top:6px}.admin-table input{min-width:0;padding:6px;border:1px solid var(--input-line)}.auction-box{margin:0 0 26px;padding:20px 22px;border:1px solid var(--line);background:var(--white)}.auction-box .eyebrow{margin-bottom:10px}.auction-box.ended{background:var(--panel)}.bid-now{margin:0 0 6px;font:20px Georgia,serif}.bid-form{display:flex;flex-wrap:wrap;gap:10px;align-items:end;margin-top:14px}.bid-form label{display:flex;flex-direction:column;gap:6px;font-size:12px;font-weight:700}.bid-form input{width:140px;min-height:48px;padding:10px;border:1px solid var(--input-line);background:var(--input-bg);color:var(--ink);font:16px ui-sans-serif,system-ui,sans-serif}.won{margin:12px 0 0}.won .button{margin-top:10px}.manage{margin:0 0 26px;font-size:13px}.manage summary{cursor:pointer;font-weight:650}.inline-form{display:flex;flex-wrap:wrap;gap:10px;align-items:center;margin:12px 0}.inline-form input,.inline-form select{min-height:38px;padding:6px 8px;border:1px solid var(--input-line);background:var(--input-bg);color:var(--ink)}.inline-form input{width:90px}.quiet-button{padding:8px 14px;border:1px solid var(--line);background:transparent;color:var(--ink);border-radius:2px;cursor:pointer;font:600 12px ui-sans-serif,system-ui,sans-serif}.quiet-button.danger{color:#9b2c2c;border-color:#e3b4b4}.auction-fields{margin:0 0 21px;padding:16px;border:1px dashed var(--upload-line)}.auction-fields legend{padding:0 6px;font-size:12px;font-weight:700}.auction-fields>small{display:block;color:var(--muted);font-size:11px}.field-row.two{grid-template-columns:1fr 1fr}.account .art-form .form-foot{margin:-8px 0 20px}.account>form:last-child{margin-top:40px}.account h2{margin:42px 0 14px;font:28px Georgia,serif;font-weight:400}.account-list{margin:0;padding-left:18px;font:15px/1.9 Georgia,serif}.account-list a{text-decoration:underline}input:focus-visible,select:focus-visible,textarea:focus-visible,a:focus-visible,button:focus-visible{outline:3px solid var(--focus);outline-offset:3px}@media(max-width:760px){.top nav a[href="/topics"]{display:none}.field-row{grid-template-columns:1fr 1fr}.field-row .field:first-child{grid-column:1/-1}.top nav a:first-child{display:none}.topics-main .topics-section{padding-top:42px}.topic-grid{grid-template-columns:1fr;gap:16px}.topic-cover{aspect-ratio:16/9}.top{height:70px}.top nav{gap:16px;font-size:11px}.brand{font-size:17px}.brand small{font-size:8px}.hero{min-height:auto;padding:55px 0 65px;grid-template-columns:1fr;gap:38px}.hero h1{font-size:clamp(50px,13vw,76px)}.hero-art{width:100%;height:clamp(250px,75vw,380px);justify-self:stretch}.hero-index{bottom:18px}.gallery-section{padding:58px 0 68px}.section-head{align-items:start;gap:12px}.section-head .text-link{padding-top:20px;font-size:11px}.gallery{grid-template-columns:repeat(2,minmax(0,1fr));gap:20px 13px}.art-info h3{font-size:18px}.art-info p{font-size:12px}.invite{grid-template-columns:1fr;gap:24px;padding-top:56px;padding-bottom:58px}.form-wrap{padding:42px 0 72px}.back-link{margin-bottom:36px}.art-form{padding:20px}.detail-grid{grid-template-columns:1fr;gap:30px}.detail-image{max-height:65vh}footer{gap:18px;align-items:flex-start;flex-wrap:wrap}.theme-pick{flex-basis:100%}footer p{max-width:150px;font-size:12px}}@media(max-width:380px){.top{padding-inline:16px}.top nav{gap:12px}.top nav a:first-child{display:none}main{padding-inline:16px}.invite{margin-inline:-16px;padding-inline:16px}.hero-art{height:250px}.art-form{padding:16px}footer{padding-inline:16px}}@media(prefers-reduced-motion:reduce){html{scroll-behavior:auto}*,*:before,*:after{transition:none!important}}.topic-group{margin-top:44px}.group-title{margin:0 0 18px;padding-bottom:10px;border-bottom:1px solid var(--line);font:24px Georgia,serif;font-weight:400}.group-jump{margin:0 0 6px}@media(max-width:760px){.topic-grid{grid-template-columns:repeat(2,minmax(0,1fr));gap:12px}.topic-cover{aspect-ratio:4/3}.topic-body{padding:12px 12px 14px}.topic-body h3{font-size:18px}.topic-body p{font-size:12px}}` + + TOPIC_CSS diff --git a/test/auctions.test.ts b/test/auctions.test.ts index 31dcf62..d6cf9b5 100644 --- a/test/auctions.test.ts +++ b/test/auctions.test.ts @@ -176,7 +176,17 @@ describe('Art Auctions House', () => { const house = new AuctionHouse() const app = createAuctionApp(house) const home0 = await (await app.fetch(new Request('https://auctions.pit.world/'))).text() - for (const slug of ['dahlias', 'mums', 'roses', 'seacliffs']) expect(home0).toContain(`href="/topics/${slug}"`) + for (const slug of ['landscapes', 'seacliffs', 'mountains', 'ceramics']) expect(home0).toContain(`href="/topics/${slug}"`) + expect(home0).not.toContain('href="/topics/dahlias"') + const index = await (await app.fetch(new Request('https://auctions.pit.world/topics'))).text() + for (const slug of ['dahlias', 'mums', 'roses', 'seacliffs', 'forests', 'wildlife', 'houses', 'ceramics', 'textiles']) expect(index).toContain(`href="/topics/${slug}"`) + expect(index.indexOf('id="nature"')).toBeLessThan(index.indexOf('id="flowers-and-gardens"')) + const mountains = await (await app.fetch(new Request('https://auctions.pit.world/topics/mountains'))).text() + expect(mountains).toContain('Your mountain here') + expect(mountains).toContain('k-peaks ph-mountains') + expect(mountains).toContain('href="/topics/forests"') + const css = await (await app.fetch(new Request('https://auctions.pit.world/style.css'))).text() + expect(css).toContain('.ph-mountains{--sky1:') const empty = await (await app.fetch(new Request('https://auctions.pit.world/topics/roses'))).text() expect(empty).toContain('Your rose here') expect(empty).toContain('href="/new?topic=roses"')