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 Light: body text

Barlow Condensed: labels


Headline scale

TokenSizeLine height, tracking
text-displayclamp(48px, 11vw, 144px)0.9, -0.04em
text-h1-lgclamp(56px, 8vw, 100px)0.92, -0.03em
text-h1clamp(48px, 7vw, 92px)0.95, -0.03em
text-h1-smclamp(44px, 6vw, 84px)0.95, -0.03em
text-slabclamp(40px, 6vw, 80px)0.97, -0.03em
text-slab-smclamp(36px, 5vw, 64px)1.05, -0.03em
text-h2-lgclamp(34px, 4vw, 48px)-0.025em
text-h2clamp(26px, 3vw, 36px)-0.025em
text-h3clamp(22px, 2.5vw, 30px)1.2, -0.02em
text-h3-smclamp(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

01

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.

Decision-Making Lens v3

Free

Eight clear questions to align strategy and move work forward. Includes a free checklist.

  • Use before big decisions, during planning, or when a project stalls
  • Four sections with two focused prompts each
  • A quick-reference checklist you can copy or share
Use the Lens

Badges

New Live Early Access

A badge is the product's own state. The section heading is the tier, and the two are independent.

Toast

Source: src/components/Toast.tsx · The only feedback overlay. Bottom right, auto-dismissed after 5 seconds.

Your message did not send. Please try again, or email support@articulatedigital.co.

Success type

Info type

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.

Email

alex@studio.com

Looks good

Email

alex@studio

Please enter a valid email address

Sending your message...

Message Sent!

Thank you for reaching out. I'll get back to you within one business day.

Send Another Message

Header

Source: src/components/Header.tsx · The full nav appears from lg (1024px). Below that, a 48px menu toggle.

Articulate Digital HomeWork With MeProductsArticlesAboutContactBook Your $99 Scan

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.

9:41 articulatedigital.co

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 closeWhat happens
Browser backOpening pushed a history entry, so back closes the menu instead of leaving the page
EscapeCloses the dropdown first, then the menu, and returns focus to the toggle
Tap outsideCloses the menu
Tap a linkCloses 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

ServiceUsed byAfter
FormspreeContact form, free guideInline success, or an error toast
Stripe payment linkOpportunity Scan/scan-access?session_id=
Stripe payment linkBuild Decision System, DIY Workflow Kit, Emoji DecoderSign-in on the product platform
localStorageThe URL typed before the scan checkoutKept 30 days as auditWebsiteData for the support email
PlausibleCTA clicks, contact submits, product clicksEvents only

The scan purchase, in code

// src/pages/Contact.tsx
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.

Articulate Digital: Living IXD Spec

Built by Articulate Digital · September 2026