Skip to content

2 cases built from this template

Same prompt, different [VARIABLES]. Click one to preview it above.

About this template

Driftline is a single-page fundraising site for a small community campaign, built to read like a documentary feature rather than a software landing page. The default content follows an invented volunteer crew raising money to clear litter from a four-kilometre stretch of river, but the structure works for any local cause with a goal, a track record and a call for helpers: tree planting, a community garden, a library appeal or a beach restoration. The page opens with a large serif headline beside a line-drawn map of the stretch, then moves through a donation meter that fills toward the goal with milestone ticks, a ledger of big figures that count up as they scroll into view, and an impact calculator where a slider turns a gift into concrete outcomes, such as bags of litter removed and metres of bank cleared. A vertical timeline tells the story of past seasons with short dispatches and small line drawings, followed by a volunteer sign-up form with inline validation and a ticket-style confirmation, a plain-spoken FAQ and a closing donate band. The palette is warm paper, deep river teal and silt brown, with a single orange accent kept for donate actions and the meter fill. Fraunces sets the headlines and numbers, Public Sans the body and IBM Plex Mono the captions and section numbers, all self-hosted. Every illustration is drawn in SVG, so there are no photos to license or replace. It suits nonprofits, neighbourhood groups and organisers who want a campaign page that feels credible and calm. To adapt it, change the brand, cause, place, goal and impact rate; the calculator maths, meter and copy all read from one content file, and nothing is ever submitted to a server.

The template prompt

The live demo was built from exactly this text — nothing added. The other cases only change the values of the [VARIABLES].

# Driftline — Nonprofit Donation Page with Impact Slider

Build this website exactly as described below. Replace the [VARIABLES] with your own values; keep everything else.

## Brief
A single-page fundraising campaign site for [BRAND], a small volunteer group [CAUSE] in [PLACE]. It reads like a documentary newspaper feature: big serif headlines, hairline rules, numbered sections, oversized figures and line-drawn SVG illustrations on warm paper. Interactive pieces do the persuading: an animated donation meter toward the [GOAL] goal, a slider-driven impact calculator based on [IMPACT_RATE], a scroll-linked timeline of past seasons, a volunteer sign-up form with client-side validation and a ticket-style success state, and an accordion FAQ. Everything runs in the browser; nothing is sent anywhere.

- Audience: Local residents, past volunteers and small donors who find the page through a newsletter or a shared link, mostly on their phones, and want to know quickly what the money does and how to help in person.
- Goal: Get the visitor to pledge a donation (the impact calculator's Donate button) or sign up for a clean-up day (the volunteer form). Secondary: share the page.
- Tone: Plain-spoken, warm and factual, like a good local reporter. Short sentences, concrete numbers, no exclamation marks, no guilt, no buzzwords.

## Stack
- Framework: Vite 5 + React 18 + TypeScript
- Styling: Tailwind CSS 3.4
- Libraries: react (MIT), react-dom (MIT), motion (MIT), lucide-react (ISC), @fontsource-variable/fraunces (OFL-1.1), @fontsource-variable/public-sans (OFL-1.1), @fontsource/ibm-plex-mono (OFL-1.1), tailwindcss (MIT), postcss (MIT), autoprefixer (MIT), vite (MIT), @vitejs/plugin-react (MIT), typescript (Apache-2.0)
- Build: `npm run build` → static files in `dist/`. No backend, no server code, no external APIs.
- Setup:
  - Scaffold with the Vite react-ts template; package.json scripts: dev = vite, build = tsc -b && vite build, preview = vite preview.
  - vite.config.ts: plugins [react()], base './', build.outDir 'dist', build.sourcemap false, build.assetsInlineLimit 0.
  - tailwind.config.js: content ['./index.html', './src/**/*.{ts,tsx}']; extend colors with paper #F4EFE6, paper-deep #EAE2D3, ink #1B2422, river #1F4E4A, river-light #6E9A93, silt #8A6E4B, rule #CFC4B1, signal #E2582B, error #A8321E; fontFamily display ['Fraunces Variable', 'Georgia', 'serif'], sans ['Public Sans Variable', 'system-ui', 'sans-serif'], mono ['IBM Plex Mono', 'ui-monospace', 'monospace']; maxWidth page 1200px.
  - src/main.tsx imports '@fontsource-variable/fraunces', '@fontsource-variable/public-sans', '@fontsource/ibm-plex-mono/400.css', '@fontsource/ibm-plex-mono/500.css' and './index.css' before rendering App.
  - src/index.css holds the three Tailwind layers, body defaults (bg paper, text ink, font sans, 17px/1.6, antialiased), html { scroll-behavior: smooth }, the @keyframes water-drift used by the closing band, the range-slider styles, and one @media (prefers-reduced-motion: reduce) block that sets scroll-behavior auto and disables every CSS animation.
  - src/content.ts holds all copy and every number: brand, nav labels, hero copy, raised (31620), goal (48000), donors (214), milestones, ledger figures, impact rate (rateAmount 12, outputA { per: 1, unit: 'bag of litter', unitPlural: 'bags of litter', verb: 'removed' }, outputB { per: 2, unit: 'metre of riverbank', unitPlural: 'metres of riverbank', verb: 'cleared' }), slider settings, timeline entries, form options, FAQ items and footer text. Components only read from it.
  - Components live in src/components/: SiteHeader, Hero, CampaignMeter, Ledger, ImpactCalculator, Dispatches, VolunteerForm, Faq, DonateBand, SiteFooter, plus shared SectionLabel, CountUp and Reveal. Line drawings live in src/art/ as React SVG components: RiverMap, WaveMark, BagGlyph, Vignette (variant prop), CheckStamp, WaterLines.
  - App.tsx owns one piece of shared state, raisedTotal (starts at content.raised), passed to CampaignMeter and ImpactCalculator so a pledge in the calculator moves the meter.
  - Use useReducedMotion() from 'motion/react' in every animated component; when true, render final values and final states with no animation.
  - CountUp: animates from 0 to the target with Motion's animate() over 1.4s, easing [0.22, 1, 0.36, 1], triggered once by useInView (amount 0.4). It stacks the final formatted value invisibly under the animated one (CSS grid, both in the same cell) so the width never jitters, and uses font-variant-numeric: lining-nums tabular-nums.
  - index.html: <title>[BRAND] — Help us finish the clean-up</title>, <link rel='icon' href='./favicon.svg'>, lang='en'. public/favicon.svg is the WaveMark: three stacked sine strokes in #1F4E4A on a #F4EFE6 rounded square.
  - Add ASSETS.md at the project root listing the three Fontsource packages and lucide-react with source URL, author and license, and stating that all illustrations are original SVG drawn in code.

## Variables
- [BRAND] — Organisation name (default: "Fernmouth River Crew"). An invented group name. Used in the header wordmark, hero copy, form and footer.
- [CAUSE] — What the campaign does (default: "clearing litter from the banks of the River Fern"). A short phrase that completes “a volunteer group …”. Drives the hero, the map figure and the timeline drawings.
- [PLACE] — Town or area (default: "Ashby Vale"). Invented, never a real town presented as the campaign’s home.
- [GOAL] — Fundraising goal (default: "$48,000"). Sets the meter target and milestones (25/50/75/100%).
- [IMPACT_RATE] — What one unit of money achieves (default: "Every $12 removes 1 bag of litter and clears 2 metres of riverbank"). One price and two outcomes; the calculator computes both from the slider amount.
- [CREDIT] — keep a small "Template by VibeFather" link to https://vibefather.ai/t/driftline in the footer (default: yes; delete this line to remove it)

The copy under Pages & Sections is written for the default values. If your values differ, rewrite every headline, paragraph, label and image for them — same length, tone and structure. Layout, colors, type and motion stay as described.
Keep all copy, image paths and links in one content file (for example `src/content.ts`), keyed by section, so the content can be swapped later without touching components.

## Design
### Colors
- Paper `#F4EFE6` — Page background, text on dark bands
- Paper Deep `#EAE2D3` — Meter band and volunteer section background, illustration panels
- Ink `#1B2422` — Body text, headlines, closing band and footer background
- River `#1F4E4A` — Impact calculator band background, drop caps, river strokes, form submit button, links
- River Light `#6E9A93` — Contour lines, vignette strokes, unreached timeline dots
- Silt `#8A6E4B` — Captions, section numbers, timeline numerals, unreached milestone labels
- Rule `#CFC4B1` — 1px hairlines, meter track, input borders
- Signal `#E2582B` — Only for donate buttons, the meter fill, the slider fill and map site dots
- Error `#A8321E` — Form error text and invalid field borders

### Typography
- Display (headlines, big figures, FAQ questions): Fraunces Variable (OFL), weights 400/600/800
- Text (body, form fields, buttons): Public Sans Variable (OFL), weights 400/500/600
- Mono (captions, section numbers, nav, labels): IBM Plex Mono (OFL), weights 400/500

### Layout & motion
- Spacing: 12-column grid inside a 1200px max-width container, 24px gutters; side padding 40px desktop, 20px mobile. Sections are separated by 128px vertical padding on desktop and 80px on mobile. Every section starts with a SectionLabel: mono 12px uppercase, letter-spacing 0.14em, Silt, e.g. “01 — The record so far”, followed by a full-width 1px Rule hairline and 32px gap before the heading. Section headings are Fraunces 600, clamp(32px, 4vw, 52px), line-height 1.05, letter-spacing -0.015em. Body columns never exceed 62ch.
- Radius: Square editorial edges: 0 on panels, cards, meter track and images; 2px on buttons, inputs and chips; full circle only for the slider thumb, timeline dots and map dots.
- Motion: Default ease is [0.22, 1, 0.36, 1]. Reveal: elements fade from opacity 0 and y 16px to 0 over 0.6s when 30% in view, once; siblings stagger 0.08s.
- Motion: Big figures count up once with CountUp (1.4s); the meter fill grows from 0 to its percentage over 1.8s when 40% in view, and re-animates smoothly (0.6s) whenever raisedTotal changes.
- Motion: SVG line drawings draw themselves with Motion pathLength 0 to 1 (river map 1.6s, vignettes 1.2s, check stamp 0.5s).
- Motion: The timeline’s vertical progress line is scroll-linked: useScroll on the Dispatches section (offset ['start 60%', 'end 60%']) drives scaleY of a River-coloured line from 0 to 1, transform-origin top.
- Motion: Hover: buttons darken 8% and lift 1px over 150ms; text links animate an underline from 0 to 100% width over 200ms.
- Motion: With prefers-reduced-motion: no reveals, count-ups, path drawing, scroll-linked line or water drift; everything renders in its final state and smooth scroll is off.
- Imagery: No photographs. All imagery is original line art drawn in SVG components: a contour-line map of the river stretch, six small vignettes for the timeline, a bag glyph for the calculator, a check stamp, and drifting water lines. Strokes are 1.5px, round caps, River Light or River, on Paper Deep panels, each with a mono figure caption (“Fig. 1 — …”). No people, faces, animals with personality, or real places.

## Pages & Sections
### Campaign page (`index.html`)
1. **Site header** — Wordmark: the WaveMark SVG (three stacked 2px sine strokes, 22px wide, River) followed by “Fernmouth River Crew” in Fraunces 600 italic 20px. Nav links: “The river” (#top), “Impact” (#impact), “Dispatches” (#dispatches), “Volunteer” (#volunteer), “FAQ” (#faq). Right-hand button: “Donate” linking to #impact.
   Layout: Sticky top bar, 64px tall, Paper background at 92% opacity with backdrop-blur 8px and a 1px Rule bottom border. Wordmark left; nav links centred in mono 12px uppercase, letter-spacing 0.12em, Ink at 70%, the link of the section in view turns Ink 100% with a 1px underline (IntersectionObserver); Donate button right: Signal background, Paper text, Public Sans 600 14px, padding 10px 18px, radius 2px. Below 1024px the nav links hide and a Lucide Menu icon button (44px hit area) appears left of Donate; it toggles a full-width panel under the header (Paper, Rule bottom border) listing the five links in Fraunces 28px with 1px hairlines between, closing on link tap or Escape; the icon swaps to X.
   Motion: Mobile panel opens with height 0 to auto and opacity over 0.3s. In-page links scroll smoothly with a 72px scroll-margin-top on every section.
2. **Hero** — Caption above the headline: “Spring campaign · Year 7 · Ashby Vale”. Headline (three lines): “Give the River Fern / its banks / back.” Standfirst: “Fernmouth River Crew is a group of 312 neighbours clearing litter from 4.2 kilometres of the River Fern. Six springs in, 2.6 km is clear. This year we need $48,000 to finish the last 1.6 km.” Primary button: “Donate to the clean-up” (to #impact). Secondary link: “Join a clean-up day” with a Lucide ArrowRight 16px (to #volunteer). Figure caption under the map: “Fig. 1 — The 4.2 km stretch through Ashby Vale. Orange marks the six clean-up sites so far; the dashed line is still to do.”
   Layout: id='top'. Starts 56px below the header. A 1px Ink rule spans the container top, then the mono caption row (12px uppercase, Silt) with a 1px Rule underneath, 48px gap. Desktop 12-column grid: columns 1–7 hold the headline (Fraunces 800, clamp(52px, 7.4vw, 116px), line-height 0.94, letter-spacing -0.025em, Ink; the word “back.” is Fraunces 400 italic), then the standfirst (Public Sans 400, 20px/1.55, Ink at 85%, max 46ch, 32px below headline) and the actions row 40px below (primary button 52px tall, Signal, Paper text, 600 16px, padding 0 24px, radius 2px; secondary as an underlined River text link, 24px gap). Columns 9–12 hold the RiverMap figure: a Paper Deep panel with 4:5 aspect ratio and 1px Rule border containing 9 wavy contour paths in River Light (1px), one thick 6px River path snaking top to bottom for the river, a 2px dashed Ink path along the lower third marking the unfinished stretch, six 10px Signal dots with mono 10px numbers 1–6 beside them, a small north arrow and a 1 km scale bar in mono 10px; the caption sits below the panel in mono 12px Silt. Mobile: single column, headline clamp at 52px, map panel full width at 4:3 below the actions.
   Motion: Headline lines rise from y 28px and fade in, staggered 0.08s, 0.7s each. Standfirst and actions follow with Reveal. In the map, contours fade in (0.6s), the river path draws via pathLength over 1.6s, then the six dots scale from 0 to 1 staggered 0.1s, then the dashed path fades in.
3. **Campaign meter** — Label: “Raised so far”. Big figure: “$31,620” (raisedTotal). Under it: “of $48,000 goal · 66%”. Right-hand facts: “214 donors” and “3 clean-up days to go”. Milestones on the track: 25% “$12k · Gloves and grabbers”, 50% “$24k · Skip hire for the season”, 75% “$36k · Willow and sedge for the bank”, 100% “$48k · The final 1.6 km”.
   Layout: id='meter'. Full-bleed band in Paper Deep with 1px Rule borders top and bottom, padding 64px desktop / 48px mobile, content in the container. Top row, desktop: left the mono label (12px uppercase Silt), the big figure (Fraunces 800, clamp(56px, 7vw, 96px), Ink, tabular figures via CountUp) and the goal line (Public Sans 500 18px, Ink 75%; the percentage rounds Math.round(raisedTotal / goal * 100)); right, aligned to the bottom, two stacked facts separated by a hairline, each with a Fraunces 600 32px number and a mono 12px label. Then 40px gap and the meter: a 14px tall Rule track spanning the container, the Signal fill from the left with square ends, capped at 100%. Four milestone ticks sit at 25/50/75/100%: a 1px Ink line rising 10px above the track and a label above in mono 11px (value on line 1, description on line 2), Ink when raisedTotal has passed it, Silt at 70% otherwise; the 100% tick carries a small 8px Signal triangle flag. Below 768px the milestone descriptions hide from the track (only values remain) and appear as a 2×2 list underneath, each with a 10px square marker filled Signal if reached or outlined Rule if not.
   Motion: On entering view the fill grows from 0 to 66% over 1.8s while the big figure counts up in sync; when raisedTotal increases later, the fill and figure animate to the new value over 0.6s, and any milestone newly passed flashes its label to Signal for 0.8s.
4. **Ledger (big numbers)** — SectionLabel: “01 — The record so far”. Heading: “Six springs on the Fern, counted.” Paragraph (with drop cap): “We started with nine people, borrowed gloves and a length of rope. Every clean-up since has been weighed on the bank and written down. These are the totals, and they are the reason we think the last stretch is within reach.” Figures: “11,480 kg” — “of litter lifted from the water and the banks”; “1,904” — “bags hauled to recycling or landfill”; “312” — “neighbours on the volunteer register”; “2.6 km” — “of riverbank cleared out of 4.2 km”.
   Layout: id='record'. SectionLabel and heading, then a 12-column grid with 48px top gap: columns 1–4 hold the paragraph (Public Sans 400 18px/1.65) whose first letter is a drop cap in Fraunces 800, River, spanning 3 lines (float left, 4.2em font size, line-height 0.8, 8px right margin). Columns 6–12 hold a 2×2 grid of figures divided by 1px Rule hairlines (one vertical, one horizontal, no outer border); each cell has 32px padding, the number in Fraunces 800 clamp(44px, 5vw, 72px) Ink with the unit (“kg”, “km”) in Fraunces 400 at 45% size, and the label in mono 12px uppercase Silt, max 24ch. Mobile: paragraph first, then the 2×2 grid at full width with number size 40px.
   Motion: Paragraph uses Reveal. Each figure counts up with CountUp (decimals kept for 2.6 km); cells stagger 0.1s.
5. **Impact calculator** — SectionLabel: “02 — What your gift does”. Heading: “Slide to see what your money moves.” Note: “Based on last spring’s costs: every $12 removes 1 bag of litter and clears 2 metres of riverbank.” Amount display: “$60” (current value). Preset chips: “$25”, “$60”, “$120”, “$250”. Outputs (default $60): “5” “bags of litter removed” and “10” “metres of riverbank cleared”. Donate button: “Donate $60” (amount updates live). After pledging, an inline confirmation: “Thank you. $60 has been added to the meter. This is a demo page, so no payment was taken.” with a “Back to the meter” link to #meter.
   Layout: id='impact'. Full-bleed band in River with Paper text; the SectionLabel, hairline and note use Paper at 65% and the hairline is Paper at 20%. Desktop 12-column grid: columns 1–5 hold label, heading (Paper) and the note (Public Sans 17px, max 36ch). Columns 7–12 hold the calculator panel: 1px border Paper at 25%, padding 40px, no fill. Inside, top to bottom: mono label “Your gift”; the amount in Fraunces 800 96px Paper with tabular figures; a range input (min 5, max 500, step 5, default 60, aria-label “Donation amount in dollars”) styled with a 4px track Paper at 25%, the filled part left of the thumb in Signal (CSS background linear-gradient driven by a --fill custom property), and a 24px round Paper thumb with a 3px Signal ring and a 3px Paper focus-visible outline offset 3px; under the track mono 11px “$5” left and “$500” right. Then the four preset chips in a row (mono 13px, 36px tall, 1px Paper 35% border, radius 2px; the chip equal to the current amount gets a Signal border and Signal text). Then two output blocks side by side divided by a vertical Paper 20% hairline: A shows the number of bags = Math.floor(amount / 12) in Fraunces 600 56px plus the label, and below it a wrapping row of BagGlyph icons (16px line-drawn sacks in Paper), one per bag up to 24, followed by a mono “+N” when there are more; B shows metres = Math.floor(amount / 12) * 2 with its label, and below it a horizontal ruler 100% wide (1px Paper 40% line with ticks every 10%) whose Signal bar width is min(metres / 100, 1) and a mono caption “of a 100 m stretch”. Last row: the Donate button full width, 56px, Signal background, Paper text, 600 17px. Clicking it adds the amount to raisedTotal in App state and swaps the button row for the confirmation text (Public Sans 16px Paper) with a Lucide Check icon; changing the amount afterwards brings the button back. Mobile: one column, panel padding 24px, amount 72px, output blocks stack with a horizontal hairline between.
   Motion: The amount number springs to each new value (Motion animate, 0.35s). Bag glyphs added on increase pop from scale 0.6 and opacity 0 with a 0.02s stagger; removed ones fade out over 0.15s. The ruler bar width transitions over 0.4s. The confirmation fades and rises 8px over 0.3s.
6. **Dispatches (timeline)** — SectionLabel: “03 — Dispatches from the bank”. Heading: “Six springs, one stretch at a time.” Six entries, each with marker, numeral, title, body, stats line and figure caption:
Year 1 · 01 · “One trolley and a length of rope” — “Nine of us met at the Mill Lane footbridge with borrowed gloves. By noon we had pulled a shopping trolley, four tyres and thirty bags out of the shallows.” Stats: “620 kg · 9 volunteers · 300 m”. Vignette: trolley. Caption: “Fig. 2 — The first find.”
Year 2 · 02 · “Under the footbridge” — “Litter collects in the slack water below the bridge. The council agreed to collect large finds if we stacked them by the lane, so we did.” Stats: “1,140 kg · 68 volunteers · 350 m”. Vignette: footbridge. Caption: “Fig. 3 — Mill Lane footbridge.”
Year 3 · 03 · “Sorting on the bank” — “We began sorting everything on site into metal, plastics and the rest. Almost half of what we lifted went to recycling instead of landfill.” Stats: “1,860 kg · 104 volunteers · 400 m”. Vignette: crates. Caption: “Fig. 4 — Three crates, three streams.”
Year 4 · 04 · “The weir pool” — “The weir traps whatever the river carries down. Two trained crew in waders worked the pool while sixty people sorted on the bank.” Stats: “2,210 kg · 156 volunteers · 450 m”. Vignette: weir. Caption: “Fig. 5 — The weir at low water.”
Year 5 · 05 · “The reeds came back” — “On the first stretches we cleared, sedge and reed beds returned without any planting. We counted herons on four of our six visits.” Stats: “2,450 kg · 221 volunteers · 500 m”. Vignette: reeds. Caption: “Fig. 6 — New reed beds, east bank.”
Year 6 · 06 · “Planting the bank” — “We planted 400 native willow whips to hold the bank where litter used to pile up. Most of them have taken.” Stats: “3,200 kg · 312 volunteers · 600 m”. Vignette: willows. Caption: “Fig. 7 — Willow whips, first summer.”
   Layout: id='dispatches'. SectionLabel and heading, then a list with 64px between entries. Desktop: a vertical 1px Rule line runs the full height of the list at the boundary between grid columns 3 and 4, with the scroll-linked River progress line overlaid on it. Each entry is a 12-column row: columns 1–2, right-aligned, hold the marker “Year 1” (mono 12px uppercase Silt) above the numeral “01” (Fraunces 400 64px Silt, tabular). On the line sits a 13px circle dot: Paper fill with a 1px River Light border until the entry is in view, then River fill. Columns 4–8 hold the title (Fraunces 600 28px/1.15 Ink), body (Public Sans 17px/1.6, Ink 85%, 16px below) and the stats line (mono 12px, Silt, 16px below, values separated by middle dots). Columns 9–12 hold the Vignette: a Paper Deep panel at 4:3 with a 1px Rule border containing the variant line drawing (1.5px River Light strokes, River accents, about 12–20 paths each: trolley = wire basket on wheels tilted in wavy water lines; footbridge = a shallow arch with railings over water lines; crates = three open crates of different heights; weir = stepped horizontal bands with falling water strokes; reeds = clusters of tall curved stems with a standing heron outline at one side; willows = a row of five thin saplings with ties and stakes on a sloping bank), and its mono 11px caption below. Mobile: the line moves to 7px from the left edge, entries get 32px left padding, marker and numeral sit inline (“Year 1 · 01”) above the title, and the vignette goes full width below the stats.
   Motion: Scroll-linked progress line as described in Design. Each entry uses Reveal when 30% in view; its dot fills River over 0.3s; its vignette paths draw with pathLength over 1.2s, staggered 0.03s per path.
7. **Volunteer sign-up** — SectionLabel: “04 — Volunteer”. Heading: “Bring boots. We’ll bring the rest.” Paragraph: “Three Saturday mornings this spring, each on a different part of the last 1.6 km. Gloves, grabbers, bags and tea are provided. You don’t need any experience; a crew lead will show you what to do.” Fact list with Lucide icons (18px, River): Clock “Saturdays, 9:00 to 12:30”; MapPin “Meet at the Mill Lane Boathouse”; Footprints “Wear boots you don’t mind getting muddy”; Users “Crews of eight, each with a trained lead”. Form title: “Put me on the register”. Fields: “Full name” (required); “Email” (required); “Phone (optional)”; “Which day?” radio cards (required): “Day 1 — Mill Lane to the weir”, “Day 2 — The weir to Carter’s Meadow”, “Day 3 — Carter’s Meadow to the river mouth”; “I can help with” checkboxes (optional): “Hauling bags”, “Sorting on the bank”, “Tea and first aid”, “Taking photos”; “Anything we should know?” textarea (optional, max 300 characters, counter “0 / 300”); consent checkbox (required): “I’m 16 or over, or I’ll come with a parent or guardian.” Submit: “Put me on the register”. Error messages: “Please enter your name.”, “Please enter a valid email address.”, “Please enter a phone number with at least 7 digits, or leave it blank.”, “Please choose a day.”, “Please confirm this to sign up.” Success ticket: stamp heading “You’re on the register, {first name}.”, rows “Volunteer No. 313”, “Day: {chosen day}”, “Meet: Mill Lane Boathouse, 9:00”, “Bring: boots, water, a warm layer”; footnote “Demo form: your details stay in this browser tab and are not sent anywhere.”; button “Sign up someone else”.
   Layout: id='volunteer'. Full-bleed Paper Deep band. Desktop 12-column grid: columns 1–5 hold SectionLabel, heading, paragraph and the fact list (each row icon + Public Sans 16px, 14px row gap, 1px Rule hairline between rows). Columns 7–12 hold the form card: Paper background, 1px Rule border, padding 40px, radius 0, a mono 12px uppercase form title with a hairline below. Fields stack with 22px gaps; labels Public Sans 600 14px Ink with “(optional)” in Silt 400; inputs 48px tall, Paper background, 1px Rule border, radius 2px, 16px text, padding 0 14px; focus state 2px River border with no glow. The three day options are full-width radio cards (1px Rule border, 14px padding, custom 18px round indicator; selected card gets a 2px River border and Paper Deep fill). Checkboxes sit in a 2×2 grid with 18px square custom boxes (checked: River fill with a Paper Lucide Check 14px). Textarea 4 rows with the counter right-aligned in mono 11px beneath (turns Error at 300). Submit button full width 52px, River background, Paper text, Public Sans 600 16px, radius 2px. Validation in the browser only, using noValidate on the form: each field validates on blur and again on submit; email matches /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/; phone, if filled, needs at least 7 digits after stripping non-digits; name needs 2+ trimmed characters. Invalid fields get a 1px Error border, aria-invalid='true' and aria-describedby pointing to an error line under the field (mono 12px Error with a Lucide CircleAlert 14px). On submit with errors, focus moves to the first invalid field. On a valid submit, the button shows a spinning Lucide LoaderCircle with “Adding you…” for 900ms (setTimeout, no network), then the card content is replaced by the success ticket: a Paper card with a 2px dashed Rule perforation line 72px from the top, a 64px CheckStamp (River circle with a Paper tick) above the heading (Fraunces 600 32px), the ticket rows as a two-column mono 13px table with hairlines, the footnote in Public Sans 13px Silt, and “Sign up someone else” as an outlined River button that resets the form and returns focus to the name field. Mobile: one column, form card padding 24px, checkboxes in one column.
   Motion: Error lines slide down from height 0 over 0.2s. The form-to-ticket swap uses AnimatePresence: the form fades out (0.2s), the ticket fades in and rises 12px (0.4s) while the CheckStamp circle and tick draw via pathLength (0.5s).
8. **FAQ** — SectionLabel: “05 — Questions”. Heading: “Questions, answered plainly.” Side note: “Still unsure? Write to [email protected] and a person will reply within two days.” Items:
“Where does my money go?” — “Skip hire and landfill fees take 41%, bank replanting with native willow and sedge 27%, safety kit and grabbers 22%, and insurance and first-aid training 10%. We post the receipts after every clean-up day.”
“Is it safe to volunteer near the water?” — “Volunteers stay on the bank. Only trained crew in waders go into the shallows, never above knee depth, and every site has a life ring, a first-aid kit and a lead who has done the training.”
“Can I bring children?” — “Yes, from age 8 with an adult. Under-16s work on the bank and help with sorting.”
“What happens to the litter we collect?” — “We sort it on the bank. Metal and hard plastics go to recycling, the rest goes to licensed landfill, and large finds like trolleys and tyres are collected separately.”
“Do I have to come to every clean-up?” — “No. Most people come once or twice a season. Sign up for one day and see how it feels.”
“Can a local business sponsor a stretch?” — “Yes. Adopting 100 metres costs $600 and puts your name on the marker post for that stretch. Write to us and we’ll send the details.”
   Layout: id='faq'. Desktop 12-column grid: columns 1–4 hold SectionLabel, heading and the side note (Public Sans 16px, Ink 75%, the email as an underlined River link with a mailto: href). Columns 6–12 hold the accordion: a 1px Ink rule on top, then each item as a full-width button row (min 72px, 20px vertical padding) with the question in Fraunces 400 22px/1.3 Ink on the left and a Lucide Plus 20px icon on the right; rows divided by 1px Rule hairlines. The answer panel sits under its question in Public Sans 17px/1.65, Ink 85%, max 60ch, padding-bottom 24px. Only one item is open at a time; the first is open on load. Buttons carry aria-expanded and aria-controls; panels have role='region' and aria-labelledby. Mobile: one column, questions 20px.
   Motion: Opening animates the panel from height 0 to auto with opacity over 0.3s (AnimatePresence) and rotates the Plus icon 45° into a cross over 0.2s; closing reverses.
9. **Closing donate band** — Mono caption: “The last stretch”. Headline: “The last 1.6 km is the hardest. Help us finish it.” Line: “$16,380 to go. Every gift is weighed against the same costs as the calculator above.” (the amount to go is goal minus raisedTotal, never below $0). Primary button: “Donate to the clean-up” (to #impact). Secondary button: “Share this page” with a Lucide Copy icon; on click it copies window.location.href with navigator.clipboard.writeText inside try/catch and changes its label to “Link copied” with a Lucide Check for 2s (on failure: “Copy failed — use your browser’s share menu”).
   Layout: Full-bleed Ink band, Paper text, padding 120px desktop / 80px mobile, overflow hidden. Behind the content, the WaterLines SVG spans the full width of the lower half: three horizontal sine paths (River at 45%, 1.5px stroke, 1200px wavelength, different amplitudes) drawn twice the viewport width so they can drift. Content centred in max 820px: mono caption (12px uppercase Paper 60%), headline Fraunces 800 clamp(40px, 6vw, 84px)/1.0 Paper with “Help us finish it.” in Fraunces 400 italic on its own line, the line in Public Sans 18px Paper 75%, then the buttons centred 40px below with 16px gap: primary Signal background, Paper text, 52px tall; secondary 52px, transparent with a 1px Paper 40% border and Paper text. Mobile: buttons stack full width.
   Motion: Each water line translates horizontally in a seamless loop using the CSS water-drift keyframes (translateX 0 to -50%), durations 28s, 36s and 44s, linear, infinite; disabled under reduced motion. Headline uses Reveal.
10. **Footer** — Wordmark and line: “A volunteer crew looking after 4.2 km of the River Fern.” Column “Visit”: “Mill Lane Boathouse”, “Ashby Vale”. Column “Contact”: “[email protected]”. Column “Read”: “Spring newsletter”, “Field notes”, “Receipts and accounts” (text links to #top). Bottom line: “© Fernmouth River Crew · An unincorporated community group” and, if [CREDIT] is kept, the “Template by VibeFather” link on the right.
   Layout: Continues the Ink background with a 1px Paper 15% top rule inside the container, padding 64px top / 40px bottom. Desktop 12-column grid: columns 1–5 wordmark (WaveMark in Paper plus name in Fraunces 600 italic 22px Paper) and the line in Public Sans 15px Paper 65%; columns 7–8, 9–10, 11–12 each hold a column title in mono 11px uppercase Paper 50% and items in Public Sans 15px Paper 80% with 10px gaps. A bottom row 48px below with a 1px Paper 15% top rule and mono 11px Paper 50% text, left and right aligned. No social media icons or logos. Mobile: wordmark block, then the three columns in a 2-column grid, then the bottom row stacked.
   Motion: None beyond the link underline hover.

## Assets
- image: All illustrations are original inline SVG React components in src/art/, drawn in code: RiverMap (contour map with river path, dashed unfinished stretch, six numbered dots, north arrow, scale bar), Vignette with six variants (trolley, footbridge, crates, weir, reeds with a heron outline, willows), BagGlyph, CheckStamp, WaveMark and WaterLines. No bitmap images, no photos, no stock or placeholder services.
- image: public/favicon.svg: the WaveMark (three stacked sine strokes, #1F4E4A) on a #F4EFE6 rounded square, drawn by hand in SVG.
- icon: lucide-react (ISC), imported per icon: Menu, X, ArrowRight, Check, Plus, Clock, MapPin, Footprints, Users, CircleAlert, LoaderCircle, Copy. 1.75px stroke, sized as described per section.
- font: Self-hosted via Fontsource npm packages imported in src/main.tsx: @fontsource-variable/fraunces, @fontsource-variable/public-sans, @fontsource/ibm-plex-mono (400 and 500). All OFL-1.1. List them in ASSETS.md with source URL, author and license.

## Don'ts
- No backend: no server code, API routes, databases, auth, payment SDKs or third-party APIs. The volunteer form and the Donate button never send data anywhere; they only change state in the page.
- No real payment provider buttons, logos or wording (no PayPal, Stripe, Apple Pay or card marks). Donate buttons are plain styled buttons.
- No names, logos or slogans of real river, water or clean-up charities, and no real rivers, towns or landmarks presented as the campaign’s home. All names, places, people and numbers are invented.
- No photos of people and no faces anywhere; no stock photography, no placeholder-image services, no hotlinked files.
- Do not present invented totals, statistics or quotes as real-world facts about any real organisation.
- Fonts are self-hosted through Fontsource only. Never load fonts from fonts.googleapis.com, fonts.gstatic.com or any CDN, and do not use commercial or newspaper-masthead typefaces.
- No CDN <script> or <link> tags, no analytics, no tracking pixels, no external embeds (maps, video, social widgets).
- Use the Signal orange only for donate actions, the meter fill, the slider fill and the map dots. Do not add other accent colours, gradients, glassmorphism or drop shadows.
- Keep the square editorial look: no rounded cards, pill buttons or emoji.
- Production build must be minified with no source maps, output only to dist/, with relative asset paths (Vite base './') and no src/ files copied into dist/. Keep dist/ under 20 MB.
- This is a single page: internal links are in-page anchors (#impact, #volunteer…) or point to ./index.html, never to a bare directory.
- Do not change the stack or add libraries beyond those listed.
- No SEO extras: no meta descriptions, Open Graph tags, JSON-LD or sitemaps. Only the plain <title> and the favicon.
- Must work at 1440×900 and 390×844 with zero console errors, keyboard-accessible controls with visible focus, and full respect for prefers-reduced-motion.
- Do not mention VibeFather anywhere in the site except the optional [CREDIT] footer link.

---
— Prompt by VibeFather · https://vibefather.ai/t/driftline · CC BY-NC 4.0 (non-commercial; commercial use needs a VibeFather Pro license) · Request removal: https://vibefather.ai/takedown

Free for personal projects under CC BY-NC 4.0. Commercial use comes with Pro.

DESIGN.md

The design system on its own — colors, type, spacing and motion. Apply this look to a project you already have.

---
name: "Driftline"
colors:
  paper: "#F4EFE6"
  paper_deep: "#EAE2D3"
  ink: "#1B2422"
  river: "#1F4E4A"
  river_light: "#6E9A93"
  silt: "#8A6E4B"
  rule: "#CFC4B1"
  signal: "#E2582B"
  error: "#A8321E"
typography:
  display_headlines_big_figures_faq_questions: { family: "Fraunces Variable", weights: [400, 600, 800] }
  text_body_form_fields_buttons: { family: "Public Sans Variable", weights: [400, 500, 600] }
  mono_captions_section_numbers_nav_labels: { family: "IBM Plex Mono", weights: [400, 500] }
spacing: "12-column grid inside a 1200px max-width container, 24px gutters; side padding 40px desktop, 20px mobile. Sections are separated by 128px vertical padding on desktop and 80px on mobile. Every section starts with a SectionLabel: mono 12px uppercase, letter-spacing 0.14em, Silt, e.g. “01 — The record so far”, followed by a full-width 1px Rule hairline and 32px gap before the heading. Section headings are Fraunces 600, clamp(32px, 4vw, 52px), line-height 1.05, letter-spacing -0.015em. Body columns never exceed 62ch."
radius: "Square editorial edges: 0 on panels, cards, meter track and images; 2px on buttons, inputs and chips; full circle only for the slider thumb, timeline dots and map dots."
---

# Driftline — Design System

Apply this design system to an existing project. It describes the look and feel only; for the full site, use prompt.md.

## Colors
- **Paper** `#F4EFE6` — Page background, text on dark bands
- **Paper Deep** `#EAE2D3` — Meter band and volunteer section background, illustration panels
- **Ink** `#1B2422` — Body text, headlines, closing band and footer background
- **River** `#1F4E4A` — Impact calculator band background, drop caps, river strokes, form submit button, links
- **River Light** `#6E9A93` — Contour lines, vignette strokes, unreached timeline dots
- **Silt** `#8A6E4B` — Captions, section numbers, timeline numerals, unreached milestone labels
- **Rule** `#CFC4B1` — 1px hairlines, meter track, input borders
- **Signal** `#E2582B` — Only for donate buttons, the meter fill, the slider fill and map site dots
- **Error** `#A8321E` — Form error text and invalid field borders

## Typography
- **Display (headlines, big figures, FAQ questions)** — Fraunces Variable (OFL), weights 400/600/800. Self-host the font files.
- **Text (body, form fields, buttons)** — Public Sans Variable (OFL), weights 400/500/600. Self-host the font files.
- **Mono (captions, section numbers, nav, labels)** — IBM Plex Mono (OFL), weights 400/500. Self-host the font files.

## Spacing & shape
- Spacing: 12-column grid inside a 1200px max-width container, 24px gutters; side padding 40px desktop, 20px mobile. Sections are separated by 128px vertical padding on desktop and 80px on mobile. Every section starts with a SectionLabel: mono 12px uppercase, letter-spacing 0.14em, Silt, e.g. “01 — The record so far”, followed by a full-width 1px Rule hairline and 32px gap before the heading. Section headings are Fraunces 600, clamp(32px, 4vw, 52px), line-height 1.05, letter-spacing -0.015em. Body columns never exceed 62ch.
- Radius: Square editorial edges: 0 on panels, cards, meter track and images; 2px on buttons, inputs and chips; full circle only for the slider thumb, timeline dots and map dots.

## Motion
- Default ease is [0.22, 1, 0.36, 1]. Reveal: elements fade from opacity 0 and y 16px to 0 over 0.6s when 30% in view, once; siblings stagger 0.08s.
- Big figures count up once with CountUp (1.4s); the meter fill grows from 0 to its percentage over 1.8s when 40% in view, and re-animates smoothly (0.6s) whenever raisedTotal changes.
- SVG line drawings draw themselves with Motion pathLength 0 to 1 (river map 1.6s, vignettes 1.2s, check stamp 0.5s).
- The timeline’s vertical progress line is scroll-linked: useScroll on the Dispatches section (offset ['start 60%', 'end 60%']) drives scaleY of a River-coloured line from 0 to 1, transform-origin top.
- Hover: buttons darken 8% and lift 1px over 150ms; text links animate an underline from 0 to 100% width over 200ms.
- With prefers-reduced-motion: no reveals, count-ups, path drawing, scroll-linked line or water drift; everything renders in its final state and smooth scroll is off.

## Imagery
No photographs. All imagery is original line art drawn in SVG components: a contour-line map of the river stretch, six small vignettes for the timeline, a bag glyph for the calculator, a check stamp, and drifting water lines. Strokes are 1.5px, round caps, River Light or River, on Paper Deep panels, each with a mono figure caption (“Fig. 1 — …”). No people, faces, animals with personality, or real places.

## Tone
Plain-spoken, warm and factual, like a good local reporter. Short sentences, concrete numbers, no exclamation marks, no guilt, no buzzwords.

---
— Prompt by VibeFather · https://vibefather.ai/t/driftline · CC BY-NC 4.0 (non-commercial; commercial use needs a VibeFather Pro license) · Request removal: https://vibefather.ai/takedown