Articulate Digital
Living Interaction Design Specification
The site of a solo design studio for founder-led creative businesses. Its job is to make the studio's discipline legible and to attract inquiries that fit. The site is built to read as a considered document rather than a sales page.
Platform
Web
Stack
React + Vite + Tailwind
Services
Formspree, Stripe
Updated
September 2026
System Specification
This living specification documents the interaction patterns, design constraints, and system decisions that govern how the product behaves.
It is the reference for design tokens, component patterns, and interaction rules used across the product.
Product Philosophy
The thinking behind the design decisions.
The core insight
Most problems are not tool problems. They are structure problems.
The studio sells deciding what is worth building before building it. So the site reads as a considered document: large serif for editorial authority, ledger splits because the work is structured comparison, numbered sections because a diagnosis has a sequence, and nothing decorative competing with the argument. The restraint is the demonstration.
Who it is for
Founder-led creative businesses of roughly one to five people, whose reputation is strong and whose digital presence undersells it. They often get inquiries, just the wrong ones. The reframe that lands is "you're probably trying to fix the wrong thing." It is not for budget shoppers, template seekers, or anyone who wants tools or automation as the goal.
Design principles
Diagnostic before prescriptive
The work is identifying what matters, what can wait, and what should not be built. The entry point is a written review of a site rather than a sales call.
Terracotta means you can act on this
One accent color, #c94117, and it marks an action. The italic terracotta accent appears in four named places and is never added for consistency.
Sharp corners, no shadows
Corners are sharp and page content carries no shadow. The exceptions are named and none of them is content: the toast, the nav dropdown, image frames, focus rings, and the status dot.
Three type families, fixed roles
DM Serif Display for headlines at weight 400 only, Barlow for body text, Barlow Condensed for labels. A serif is never set bold.
Accessibility is a delivery standard
The studio sells WCAG 2.1 AA on core flows as a build standard, so its own site has to meet the bar it sells.
Language Standard
From docs/articulate-digital-voice-system.md and docs/UX_PATTERNS.md.
Voice
"The studio does not sell urgency. It sells clarity."
Calm, precise, observant, restrained, structured, grounded. Diagnostic, not salesy. The copy speaks as "I," because the studio is one practitioner, and it never justifies a price with hours, deliverable counts, or a comparison to cheaper providers. No em dashes.
Locked names
- Opportunity Scan
- Build Decision System
- DIY Workflow Kit
- Emoji Decoder
- Website Design
- App Development
Never
"Audit"or"discovery call"for the Opportunity Scan"Quiz"or"assessment"for the Build Decision System"We"in visible studio copy
Banned phrases
high-converting, scale fast, explosive growth, maximize conversions, optimize your funnel, skyrocket, dominate, pain points, conversion hacks, lead leaks, crushing it, six figures, book now before spots fill, launch in 72 hours
Calls to action
The scan action, one label
"Book Your $99 Scan"
Every control that fires the scan action carries this label, and every button with these words uses the same color.
Verbs
"Book" for scan and consult actions. "View" for portfolio and collection links.
Section headings are sentence case. H1s are title case by default and sentence case where the headline is a plain statement.
Design Tokens
Every token rendered as a live specimen. Source of truth: tailwind.config.js. Contrast ratios are measured.
Colors
Accent
accent-500 #c94117
Purchase actions and active states. 4.94:1 on white
accent-600 #b33710
Hover on purchase actions. 6.05:1
accent-50 #F5F0EB
Tints: the New badge, the sent-message panel
accent-200 #E5C9B8
Tint borders
Neutrals (primary)
primary-900 #111009, 19.06:1, headlines, dark slabs, navigation buttons
primary-800 #4A4840, 9.16:1, outline button text
primary-700 #404040, 10.37:1, form labels
primary-600 #525252, 7.81:1, secondary text
primary-500 #737373, 4.74:1, labels, supporting text, and form field borders
primary-400 #9B9B9B, 2.78:1, decorative on white; text on dark slabs at 6.86:1
primary-200 #e5e5e5, hairline rules
primary-muted #8A8780, 3.58:1 on white, so dark slabs only, where it is 5.32:1
Color by intent
Purchase and scan actions are terracotta. Navigation actions are black. On a dark slab the action is cream. The same words always use the same color, and terracotta never sits on bg-primary-900, where it measures 3.86:1.
Typography
Families
DM Serif Display: headlines, weight 400 only
Barlow Condensed: labels
Headline scale
| Token | Size | Line height, tracking |
|---|---|---|
| text-display | clamp(48px, 11vw, 144px) | 0.9, -0.04em |
| text-h1-lg | clamp(56px, 8vw, 100px) | 0.92, -0.03em |
| text-h1 | clamp(48px, 7vw, 92px) | 0.95, -0.03em |
| text-h1-sm | clamp(44px, 6vw, 84px) | 0.95, -0.03em |
| text-slab | clamp(40px, 6vw, 80px) | 0.97, -0.03em |
| text-slab-sm | clamp(36px, 5vw, 64px) | 1.05, -0.03em |
| text-h2-lg | clamp(34px, 4vw, 48px) | -0.025em |
| text-h2 | clamp(26px, 3vw, 36px) | -0.025em |
| text-h3 | clamp(22px, 2.5vw, 30px) | 1.2, -0.02em |
| text-h3-sm | clamp(20px, 2.2vw, 26px) | 1.25, -0.02em |
Heading size follows the role an element plays on the page, not its tag. An item name inside a list is 20px serif at -0.01em.
Shape, elevation, focus, and motion
Corners
Square on buttons, cards, and inputs.
Shadows
Two, both on overlays: shadow-md on the toast and shadow-sm on the nav dropdown.
Focus
focus:ring-2 focus:ring-accent-500 focus:ring-offset-2
Touch targets
48px for buttons and utility controls. Text links in running copy are exempt.
Buttons
200ms transitions, and a press scales to 0.96.
Reduced motion
Durations drop to 0.01ms, and the navigation and outline variants stop scaling.
Component Library
Live specimens rendered with the site's classes and token values.
Buttons
Source: src/index.css .btn · Class combinations on one base. <Button> is used only for form submits.
By intent
Purchase: btn bg-accent-500 text-white hover:bg-accent-600 + focus ring · Navigation: btn btn-accent · Secondary: btn btn-outline
On a dark slab
Sizes
Kickers and section bars
A diagnosis has a sequence, so sections are numbered and split by hairline rules.
Purchase directly
What happens now
Product card
Source: src/pages/Products.tsx ProductCard · Shared by every tier except "Start here." Bullets use a primary-200 marker; only "Start here" uses terracotta.
Toast
Source: src/components/Toast.tsx · The only feedback overlay. Bottom right, auto-dismissed after 5 seconds.
An error toast is role="alert" and interrupts. Success and info are role="status" and wait. The dismiss button is 24px, and its tap area is 48px.
Contact form
Source: src/components/ContactForm.tsx · Validation is live on the email field. Success replaces the form inline; failure keeps the form filled and raises a toast.
Header
Source: src/components/Header.tsx · The full nav appears from lg (1024px). Below that, a 48px menu toggle.
Interactive Prototype
The Opportunity Scan path on a phone, using the site's classes: the homepage, the menu, the scan module with its validation, and the confirmation page. The message form on the same page submits too.
Home
Checkout happens on Stripe's own page, so the prototype shows a stand-in for it.
Interaction Patterns
Recurring patterns across the site, from docs/UX_PATTERNS.md.
A multi-page site, on purpose
Every internal navigation is a full document load. Each route is prerendered as its own HTML file, so a hard navigation is what guarantees every visitor receives that document with its own meta and content. The local Link lets modifier keys through, so opening in a new tab still works.
No modals
No modals, dialogs, or drawers. Feedback is the toast, and forms confirm inline or with a toast.
The mobile menu
The one full-screen overlay. It is navigation, not a dialog, so it does not trap Tab. It marks the page behind it inert instead.
| Way to close | What happens |
|---|---|
| Browser back | Opening pushed a history entry, so back closes the menu instead of leaving the page |
| Escape | Closes the dropdown first, then the menu, and returns focus to the toggle |
| Tap outside | Closes the menu |
| Tap a link | Closes without popping history, so going back does not race the navigation |
tests/navigation.spec.ts checks that focus stays inside across twenty tabs and that inert is released on close.
Pages behind a purchase
A confirmation page opened without a session_id shows an explicit state, "This Page Is for Confirmed Purchases," with a way to email support. It is prerendered, so a buyer whose JavaScript fails still gets a page and a support path.
A failure names a way out
Every error toast ends with something the person can do next, usually a support address. "Your message did not send. Please try again, or email support@articulatedigital.co."
The fold is not a criterion
Nothing is placed above the fold to win attention. Pushing everything upward is the layout expression of a worldview the brand rules ban.
State matrices
New screens and patterns are planned with a state matrix: what a person sees in each state, what they can still do, how they recover, and which component renders it. The matrices are committed to docs/state-matrices.md.
Data Architecture
No database and no accounts on the site. Forms post to Formspree, and purchases hand off to Stripe payment links.
Routes
| Studio | / · /website-design · /app-development · /products · /about · /apps · /contact |
| Products | /sample-scan · /build-decision-system · /diy-workflow-kit · /emoji-decoder · /lens · /free-guide |
| After purchase | /scan-access · /kit-access · /decision-system-access · /gate-access · /decoder-access |
| Articles | /articles · /articles/:slug |
Redirects live in public/_redirects, which wins over netlify.toml. An unknown path gets shell.html.
Where data goes
| Service | Used by | After |
|---|---|---|
| Formspree | Contact form, free guide | Inline success, or an error toast |
| Stripe payment link | Opportunity Scan | /scan-access?session_id= |
| Stripe payment link | Build Decision System, DIY Workflow Kit, Emoji Decoder | Sign-in on the product platform |
| localStorage | The URL typed before the scan checkout | Kept 30 days as auditWebsiteData for the support email |
| Plausible | CTA clicks, contact submits, product clicks | Events only |
The scan purchase, in code
let formattedUrl = websiteUrl.trim();
if (!formattedUrl) return setUrlError('Please enter your website URL.');
if (!/^https?:\/\//i.test(formattedUrl)) formattedUrl = 'https://' + formattedUrl;
try {
const parsed = new URL(formattedUrl);
if (/\s/.test(formattedUrl) || !parsed.hostname.includes('.')) throw new Error();
} catch { return setUrlError('Please enter a valid website URL.'); }
writeAuditWebsite(formattedUrl);
window.location.href = STRIPE_SCAN_LINK;
There is no loading state, because a valid URL leaves the page at once.
Prerendering
scripts/prerender.mjs takes its routes from public/sitemap.xml, adds /apps and the five after-purchase routes, and writes shell.html as the fallback. Every page carries its own title, description, canonical URL, and Open Graph tags.
Decision Log
Product decisions with rationale. The "why" behind the product.
One button system, colored by intent
Context
A button on this site does one of three things: buys, navigates, or acts from a dark slab.
Decision
Every page CTA is a class combination on .btn. The <Button> component is used only for form submits.
Rationale
The same words always use the same color: purchase is terracotta, navigation is black, a dark slab is cream.
Trade-offs
Purchase and dark-slab combinations have to append the focus ring themselves; the two named variants bring their own.
App Development names what the apps are
Context
The apps on the site are the studio's own products, shipped on the App Store.
Decision
The tier is called App Development, and its link reads "See six apps on the App Store."
Rationale
A label is a claim about evidence, so it names what a visitor will find.
Trade-offs
Naming the evidence sets a bar: every app the page counts has to stay live on the App Store.
A multi-page site, not a single-page app
Context
Every route is prerendered as its own HTML document.
Decision
Every internal navigation is a full document load.
Rationale
A hard navigation guarantees every visitor receives each page's own prerendered document, meta, and content.
Trade-offs
No client-side transitions between pages.
The menu closes on back and makes the page inert
Context
The mobile menu covers the whole page, and on a phone back is the most instinctive way to close anything.
Decision
Opening pushes a history entry, and the page behind is marked inert.
Rationale
Back closes the menu instead of leaving the page. inert removes the hidden page from the tab order and the accessibility tree at once, without turning navigation into a modal.
Trade-offs
A crawl-based audit cannot see either behavior, so both are asserted in a test.
One document owns the accessibility target
Context
Both the product context and the design system describe accessibility.
Decision
PRODUCT_CONTEXT.md owns the target, WCAG 2.1 AA on core flows. The design system records measurements only.
Rationale
A commitment and a measurement are different kinds of statement, so one document makes the commitment and the other measures against it.
Trade-offs
The body type earns AAA on white while the interactive layer is AA, so neither label alone describes the whole site.
One label for the scan
Context
The Scan is the studio's primary action, reachable from the header, the menu, the homepage, and the Contact page.
Decision
Every control that fires it reads "Book Your $99 Scan."
Rationale
The same action should carry the same words everywhere it appears, and a button with those words always uses the same color.
Trade-offs
The final checkout button carries the same label, so it is less explicit at the moment of payment. The line under it says the payment is secure, through Stripe, and one-time.
The Scan has no meeting
Context
The Scan is a written review of a site, delivered by email within 48 hours.
Decision
Nothing about the Scan books a meeting. The confirmation page says "There is nothing to schedule."
Rationale
The Scan is diagnostic and low-pressure, and a buyer can act on it without a call.
Trade-offs
A buyer who wants the review to look at something specific emails instead, and it is worked in.