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"')