Town Design System
Overview
Town's visual identity is that of a quietly confident editorial product — a near-white {colors.canvas} page warmed by a single degree of sepia, carrying dense but breathable content in a precise geometric sans ({typography.body-md}), while monumental headlines in an ultra-thin slab-serif ({typography.display-xl}) declare the brand's ambition at 88px. The design lives in the tension between these two voices: the display type is impossibly light (weight 80, tracked at –2.64px), almost architectural in its delicacy, while body copy sits at a firm 445 weight with generous 0.42px tracking — a pairing that feels both literary and engineered.
Brand voltage concentrates in {colors.primary}, a rust-orange (#a5380b) that reads as earthy rather than digital. It appears sparingly: on the hero CTA ({component.button-primary}), as accent dots and small interactive highlights, never as a field color. The real chromatic drama happens in the pastel surface tokens — {colors.surface-peach}, {colors.surface-sky}, {colors.surface-gold}, and {colors.surface-mint} — which tint integration icons, badge backgrounds, and decorative card accents without ever competing with the ink-on-paper core palette. Dark-band inversions ({component.dark-section-band}) flip the script entirely: near-black #1c1b1b backgrounds carry white or near-white text, creating high-contrast anchors for testimonials, pricing, and footer regions.
Shape language defaults to {rounded.DEFAULT} (6px) squircles — not fully round, not sharp-cornered, with a distinctive superellipse feel reinforced by the corner-shape: squircle CSS property visible on navigation buttons. Cards step up to {rounded.md} (8px), featured tiers to {rounded.lg} (12px), while pills and badges go fully round ({rounded.full}). The overall effect is friendly but disciplined — no blobby excess, no brutalist severity.
Sub-systems include: a pricing dialect where the featured tier inverts to dark-surface treatment ({component.pricing-tier-card-featured}); an integration showcase with color-coded icon circles; and a testimonial pattern using elevated white cards on neutral ground. The handwriting font face appears in signature moments — likely user-quote treatments or annotation-style callouts — adding a humanist counterpoint to the mechanical precision elsewhere.
Key Characteristics:
- Off-white canvas (
{colors.canvas}— #fdfdfc) with warm undertone, never pure #ffffff - Ultra-light slab display type (
{typography.display-xl}) at 88px / weight 80 with aggressive –2.64px tracking - Rust-orange primary (
{colors.primary}— #a5380b) used sparingly on CTAs and micro-accent - Dark-surface inversion zones (
{colors.surface-dark}— #1c1b1b) for footer, pricing featured tier, and CTA bands - Squircle-default radius (
{rounded.DEFAULT}— 6px) on all UI chrome viacorner-shapeproperty - Pastel badge palette ({
colors.surface-peach},{colors.surface-sky},{colors.surface-gold},{colors.surface-mint}) for categorization - Inset-border shadow pattern (
{shadows.inset-border}) replacing traditional border declarations - Body text at
{typography.body-md}— 14px / weight 445 / 0.42px letter-spacing — tighter than industry norm
Colors
Brand & Accent
- Primary (
{colors.primary}— #a5380b): Rust-orange brand voltage used on the main hero CTA ({component.button-primary}), interactive highlights, and small accent elements. Earthy, restrained, never neon. - Primary Active (
{colors.primary-active}— #8a2e09): Pressed/darker state for primary buttons, approximately 12% darker than base. - Primary Hover (
{colors.primary-hover}— #b94a15): Hover brightening of primary, approximately 8% lighter saturation shift. - Primary Disabled (
{colors.primary-disabled}— #d9a08a): Muted peach tone for disabled primary buttons, maintaining hue relationship at low contrast. - Error (
{colors.error}— #b1120b): Deep red for validation errors and destructive action states.
Surface
- Canvas (
{colors.canvas}— #fdfdfc): The page background — off-white with barely-perceptible warmth, one stop from pure white. All light-section content sits here. - Surface Soft (
{colors.surface-soft}— #f5f4f2): Subtle gray-warm elevation for secondary surfaces, badge backgrounds on light mode. - Surface Strong (
{colors.surface-strong}— #ebeae7): Visible container backgrounds, card surfaces needing slight separation from canvas. - Surface Elevated (
{colors.surface-elevated}— #ffffff): Pure white used specifically for raised cards ({component.card-surface}) that float above the off-white canvas. - Surface Dark (
{colors.surface-dark}— #1c1b1b): Near-black inversion zone — footer, dark section bands, featured pricing tier, sign-in button fill. - Surface Peach (
{colors.surface-peach}— #f9b28c): Warm pastel for category badges, likely "personal" or "inbox" features. - Surface Sky (
{colors.surface-sky}— #c4e2fb): Light blue pastel for integration-category badges, likely calendar/scheduling features. - Surface Gold (
{colors.surface-gold}— #f5d188): Yellow-gold pastel for highlight badges, possibly "AI" or intelligence-related tags. - Surface Mint (
{colors.surface-mint}— #f7f8f4): Pale green pastel for success-state or completion-related badges. - Surface Overlay (
{colors.surface-overlay}): Near-transparent dark wash at 2.4% opacity for subtle hover/tint states on light backgrounds. - Overlay Strong (
{colors.surface-overlay-strong}): 10% opacity dark overlay for more visible interaction states.
Text / Ink
- Ink (
{colors.ink}— #1c1b1b): Primary text color on light surfaces — near-black with tiny warmth. Used for headlines, body copy, all readable content on{colors.canvas}. - Body (on dark) (
{colors.body}— #ffffff): Primary text color on{colors.surface-dark}backgrounds — pure white for maximum contrast in inverted zones. - Body Muted (
{colors.body-muted}): Slightly softened white at 95% opacity for secondary text on dark surfaces. - Muted (
{colors.muted}): 70% opacity ink for secondary text, captions, supporting copy on light surfaces. - Muted Soft (
{colors.muted-soft}): 50% opacity ink for tertiary/disabled text, placeholder hints, timestamps. - On Primary (
{colors.on-primary}— #ffffff): White text atop{colors.primary}buttons, satisfying AA contrast requirements. - On Dark (
{colors.on-dark}— #ffffff): White text on any{colors.surface-dark}context. - On Surface (
{colors.on-surface}— #1c1b1b): Alias for{colors.ink}when referencing generic surface text tokens.
Hairlines & Borders
- Hairline (
{colors.hairline}): 5% opacity ink for dividers, rule lines, subtle separators between list items. - Hairline Soft (
{colors.hairline-soft}): Slightly cooler 5% border using the 26,25,26 RGB variant — detected on specific container edges. - Border Strong (
{colors.border-strong}): 10% opacity ink for visible field borders, card outlines, focus rings without color injection. - Border Inset (
{colors.border-inset}): The signature inner shadow used instead of CSSborder: 1px solid— 20% opacity ink as a 1px inset shadow, giving a laser-etched quality to inputs and buttons.
Semantic / Link Colors
- Link Blue Deep (
{colors.link-blue-deep}— #1335b1): Deep navy blue for primary links and integration brand colors. - Link Blue Vivid (
{colors.link-blue-vivid}— #2322b8): Slightly brighter/violet-shifted blue for active/hover link states or secondary integrations. - Link Blue Steel (
{colors.link-blue-steel}— #2665b8): Muted steel blue for tertiary link states or less-prominent integration badges. - Link (
{colors.link}— #1335b1): Default semantic link color, mapped to deep blue. - Link Active (
{colors.link-active}— #2322b8): Visited or active state for semantic links.
Typography
Font Family
Town employs three distinct typefaces, each serving a clearly differentiated role. The display face is Material Upright Variable (exposed as "slab" in the CSS stack), a variable-weight slab-serif ranging from weight 38 to 248. It carries all headline and title work — the 88px hero statement, section titles, card headers — and falls back to Georgia then generic serif. Its character is deliberately extreme: the extracted weights drop to 80 (barely there) for the largest display and 100 for title roles, producing a hairline elegance that feels architectural rather than delicate.
The body face is ABC Diatype Variable (exposed as "sans"), a geometric sans-serif with weight range 200–1000. This handles all UI text, paragraphs, button labels, navigation items, and metadata. Weight sits at 445 for standard body (firmly medium, avoiding the frailty of 300–400 at small sizes) and 450 for buttons (imperceptibly bolder). The fallback chain is "sans Fallback", system-ui, arial, where the custom fallback uses Arial with precise metric overrides to match Diatype's proportions.
The accent face is a handwriting font (exposed as "handwriting"), falling back to generic cursive. This appears in signature moments — user quotes, annotation-style callouts, or personality-driven microcopy — adding organic counterpoint to the two systematic faces.
Hierarchy
| Token | Size | Weight | Line Height | Letter Spacing | Use |
|---|---|---|---|---|---|
| {typography.display-xl} | 88px | 80 | 88px (1.0) | –2.64px | Hero headline, major section statements |
| {typography.display-lg} | 48px | 100 | ~53px (1.1) | –0.02em | Section headings (inferred from scale) |
| {typography.title-md} | 18px | 100 | 28.8px (1.6) | normal | Slab subtitles, card titles, bylines |
| {typography.title-sm} | 16px | 100 | 24px (1.5) | normal | Small slab labels, minor titles |
| {typography.heading-md} | 20px | 445 | 28px (1.4) | 0.1px | Sans-serif section heads, feature titles |
| {typography.body-md} | 14px | 445 | 21.7px (1.55) | 0.42px | Paragraph text, descriptions, body copy |
| {typography.body-sm} | 13px | 445 | ~20px (1.55) | 0.39px | Secondary text, metadata, captions |
| {typography.button} | 14px | 450 | ~18px (1.25) | 0 | Button labels, nav items, CTAs |
| {typography.caption} | 12px | 400 | ~17px (1.4) | 0.04em | Badges, timestamps, legal text |
| {typography.handwriting} | inherit | 400 | 1.4 | 0 | Quotes, annotations, personality text |
Principles
The typography system's defining move is its weight inversion: display type is impossibly light (weights 80–100) while body type is decidedly medium (445–450). This reverses the common SaaS convention where headlines go bold and body goes normal. The effect is editorial rather than promotional — the headline feels like it was set in a design journal, while body text has the clarity of technical documentation. Letter-spacing reinforces this: the display gets aggressively negative tracking (–2.64px at 88px, roughly –3%) to tighten the hairline strokes, while body text gets positive tracking (+0.42px at 14px, roughly +3%) to aerate the denser weight.
Hierarchy is carried primarily through size and family, not weight. A {typography.title-md} at 18px/weight-100 in the slab face carries equal authority to a {typography.heading-md} at 20px/weight-445 in the sans face — they're simply different registers. Color plays a minimal role in typographic hierarchy; almost all text is {colors.ink} or {colors.body}, with only muted opacity shifts ({colors.muted}, {colors.muted-soft}) for secondary information.
The slab-serif display face is reserved exclusively for moments of declaration — the hero statement ("Learns how you work, then gets to work."), section openers, and title-level card headers. It never appears below 16px, and its ultra-low weights would be illegible at smaller sizes anyway. The handwriting face is the wildcard: used perhaps 2–3 times per page, it signals "human voice here" — a user testimonial pull quote, a founder's note, or an annotated example.
Uppercase is absent from the extracted type scale; the voice is sentence-case throughout. Italics don't appear as a distinct token but are available in both variable font axes.
Note on Font Substitutes
Material Upright Variable and ABC Diatype Variable are proprietary commercial fonts (from ABC Type / Dinamo). For open-source reimplementation, substitute:
- Display/Slab: Use Roboto Slab (Google Fonts) at weight 100–200 with
font-optical-sizing. Define CSS variable--font-slab: 'Roboto Slab', Georgia, serif. Roboto Slab approximates the geometric slab construction, though it lacks Material Upright's extreme weight range (38–248). - Body/Sans: Use IBM Plex Sans (Google Fonts) at weight 400–500. Define
--font-sans: 'IBM Plex Sans', system-ui, -apple-system, sans-serif. Plex Sans shares ABC Diatype's geometric skeleton and slightly squared apertures. Applyfont-variation-settings: 'wght' 445if using the variable font version. - Handwriting: Use Caveat (Google Fonts) at weight 400–500. Define
--font-handwriting: 'Caveat', cursive.
Layout
Spacing System
- Base unit: 4px (with 3px and 6px sub-units for micro-adjustments).
- Tokens:
{spacing.xxs}(3px — micro-offsets),{spacing.xs}(4px — icon gaps, tight internals),{spacing.xxs-plus}(6px — badge padding),{spacing.sm}(8px — most common internal gap),{spacing.sm-plus}(10px — button padding axis),{spacing.md}(12px — form label gaps),{spacing.lg}(16px — standard component padding),{spacing.xl}(24px — card internal spacing),{spacing.section-sm}(32px — inter-element vertical rhythm),{spacing.section-md}(56px — section-to-section gap),{spacing.section-lg}(58px — alternate section gap),{spacing.section-xl}(135px — hero vertical padding). - Section padding (vertical):
{spacing.section-xl}(135px) for hero band;{spacing.section-md}(56px) for standard content sections;{spacing.section-lg}(58px) for alternating rhythm. - Card internal padding:
{spacing.xl}(24px) on{component.card-surface}and{component.pricing-tier-card}. - Gutters: Inter-column gutters appear at
{spacing.lg}(16px) to{spacing.xl}(24px) depending on density context.
Grid & Container
- Max content width: 1440px for main content areas (detected on
<main>and<section>elements); nav expands to 1952px max-width with 1440px effective content width plus 16px horizontal padding. - Density choice: Editorial-dense — the 1440px viewport and 14px body size pack substantial information into each viewport without feeling crowded. This is a reading-heavy landing page, not a minimalist single-scroll pitch.
- Grid behavior at desktop: Likely a 12-column implicit grid given the 1440px width and 16/24px gutter system. Feature grids appear to use 2–3 column layouts within that constraint. No explicit CSS Grid/flexbox properties were extracted from container queries, suggesting utility-class-based layout (consistent with Next.js + Tailwind patterns).
- Hero column split: Asymmetric — the 88px headline occupies roughly 60% width left-aligned, with supporting visual/interactive content in the right rail. Vertical padding of 135px gives the headline room to breathe at its massive size.
Whitespace Philosophy
Town practices generous-but-purposeful whitespace. The 135px hero vertical padding and 56px+ section gaps prevent the dense 14px body text from feeling oppressive. However, this isn't airy-minimalist whitespace — it's structural breathing room. Card interiors use only 24px padding (tight for their content density), and inline spacing between paragraph-level elements stays at 8–16px. The whitespace earns its keep by framing the ultra-light display type, which needs surrounding emptiness to read as intentional rather than fragile.
Header Architecture
┌─────────────────────────────────────────────────────────────── ┐
│ [Logo] Features Routines Integrations Pricing [Sign In] │ ← 78px tall, 16px h-pad
│ (nav-btn) (nav-btn) (nav-btn) (nav-link) (dark btn)
└─────────────────────────────────────────────────────────────────┘
↑ 1440px content max, 1952px nav shell
Navigation is a single-row flex layout with flush-left logo (not explicitly sized but occupying natural width), center-spaced navigation buttons ({component.nav-button}) with transparent backgrounds and {colors.ink} text, and a flush-right {component.nav-button-sign-in} that inverts to {colors.surface-dark} fill with white text. Each nav item gets 10px padding with {rounded.DEFAULT} (6px) squircle radius. The entire nav area has 16px internal padding and lives at a fixed height of {spacing.navbar-height} (78px).
Hero Section
┌──────────────────────────────────────────────────────────────────┐
│ │
│ Learns how you work, ┌─────┐ │
│ then gets to work. │ │ │
│ │ VIS │ │
│ [subhead in slab title-md] │ │ │
│ └─────┘ │
│ [Button Primary] [Button Secondary] │
│ │
│ ← 135px vertical pad → │
└──────────────────────────────────────────────────────────────────┘
The hero uses {component.hero-band} with {colors.canvas} background and 135px vertical padding. The headline {component.hero-headline} renders in {typography.display-xl} (88px slab, weight 80, –2.64px tracking) in {colors.ink}. Below it, a {component.hero-subhead} in {typography.title-md} (18px slab, weight 100) provides the narrative subtitle in {colors.muted}. The CTA pair consists of a filled {component.button-primary} in {colors.primary} alongside a ghost {component.button-secondary}. Right-rail content (illustration, product preview, or animated element) occupies approximately 40% of the width.
Dark Band Sections
┌──────────────────────────────────────────────────────────────────┐
│ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ │
│ ░ [White/muted headline] ░ │
│ ░ ░ │
│ ░ [Body text in body-muted] ░ │
│ ░ ░ │
│ ░ [Cards or grid content] ░ │
│ ░ ░ │
│ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ │
└──────────────────────────────────────────────────────────────────┘
Dark section bands ({component.dark-section-band}) invert to {colors.surface-dark} background with {colors.body} or {colors.body-muted} text. These appear for testimonials, the pricing table (where the featured tier remains dark while others may sit on {colors.surface-elevated}), the footer, and potentially a final CTA band. Padding matches the hero at 135px vertical, or compresses to 56–58px for shorter content bands.
Elevation & Depth
| Level | Treatment | Use |
|---|---|---|
| 0 — Flat baseline | No shadow, direct-on-canvas | Body text, nav bar, flat sections |
| 1 — Hairline outline | {shadows.hairline-shadow} (5% opacity 1px spread) | Dividers, subtle card boundaries |
| 2 — Inset border | {shadows.inset-border} (20% opacity 1px inset) | Input fields, buttons, focusable chrome |
| 3 — Soft glow | {shadows.soft-glow} (3% opacity 160px blur) | Hero or featured element ambient glow |
| 4 — Soft drop | {shadows.soft-drop} (5% opacity, 1px/2px offset) | Elevated cards, dropdown surfaces |
| 5 — Layered | {shadows.layered} (multi-layer 5%/4%/4% stack) | Modals, tooltips, persistent overlays |
The depth philosophy here is almost-flat with precision etching. Rather than traditional box-shadows, the system prefers inset shadows as border substitutes — the {shadows.inset-border} treatment creates a "laser-cut" edge on inputs and buttons that reads as finer than a CSS border. True elevation is rare: most cards appear to use {shadows.none} or {shadows.hairline-shadow} at most, relying on background-color contrast ({colors.surface-elevated} white on {colors.canvas} off-white) rather than cast shadows for separation. When shadows do appear, they're cool-toned (using the 26,25,26 black variant) and extremely soft — the 160px blur on {shadows.soft-glow} suggests atmospheric diffusion rather than directional lighting.
Decorative Depth
Pastel surface colors ({colors.surface-peach}, {colors.surface-sky}, {colors.surface-gold}, {colors.surface-mint}) function as decorative depth — flat color blocks that create visual layering without shadow. These appear behind badge pills, inside icon circles for integrations, and as subtle card-background tints. They operate at near-zero elevation (no shadow, sometimes a {shadows.inset-subtle} inner edge) but carry significant visual weight through hue contrast against the warm-gray canvas.
Shapes
Border Radius Scale
| Token | Value | Use |
|---|---|---|
| {rounded.sm} | 4px | Tight corners on small elements, feature card containers |
| {rounded.DEFAULT} | 6px | Default UI chrome — nav buttons, inputs, standard buttons (via corner-shape: squircle) |
| {rounded.md} | 8px | Standard cards ({component.card-surface}), pricing tiers, testimonial cards |
| {rounded.lg} | 12px | Featured/highlighted cards ({component.pricing-tier-card-featured}), hero elements |
| {rounded.xl} | 16px | Large containers, image frames, modal dialogs |
| {rounded.squircle} | 9999px | CTAs ({component.button-primary}), prominent action buttons — mathematically squircle via CSS property |
| {rounded.full} | 9999px | Badge pills, avatar circles, tag chips ({component.badge-pill}) |
The shape vocabulary is tightly constrained. The signature move is the squircle default: the corner-shape: squircle CSS property detected on navigation buttons produces a continuous-curvature superellipse rather than a circular arc, giving buttons a "soft-square" silhouette that feels more refined than standard border-radius. This applies at the 6px default level. Pills go fully circular (or effectively so at 9999px), while cards stay in the 8–12px range — never approaching the "blobby" 20px+ radii common in contemporary SaaS design.
Photography Geometry
No significant photography detected in the extracted DOM structure. The site relies on vector/UI illustration, product screenshots (likely contained in rounded frames at {rounded.md} or {rounded.lg}), and icon-based imagery. If photography is added in implementation, it should follow the card rounding conventions (8px for embedded photos, 12px for hero images) and avoid heavy vignettes or filters that would conflict with the clean depth system.
Components
No hover states documented. Hover behavior is unreliable to extract from a single screenshot. State variants live as separate entries in the
components:frontmatter (e.g.{component.button-primary-active},{component.text-input-focus}); add hover styling at implementation time per your stack's conventions.
Buttons & CTAs
{component.top-nav} — The fixed navigation bar spanning the full viewport width at 78px height ({spacing.navbar-height}). Background {colors.canvas}, containing logo left, nav items center, and utilities right. No visible shadow, separated from content by implied spacing alone.
{component.nav-button} — Transparent-background navigation item with {colors.ink} text rendered in {typography.button} (14px/450). Rounded to {rounded.DEFAULT} (6px) with corner-shape: squircle, 10px padding on all sides. Uses {shadows.inset-border} treatment for subtle inner edge definition on focus/hover. Appears for Features, Routines, Integrations, and Pricing links.
{component.nav-button-sign-in} — The authenticated-entry CTA in the nav right-rail. Identical geometry to {component.nav-button} but with {colors.surface-dark} background fill and {colors.body} white text. Creates a strong visual anchor in the otherwise transparent nav.
{component.button-primary} — The principal conversion button. Background {colors.primary} (#a5380b rust-orange), text {colors.on-primary} white in {typography.button} style. Rounded {rounded.squircle} (full squircle via CSS property), padding 14px vertical × 28px horizontal. Shadow treatment is {shadows.inset-border} for the etched-edge look. State variants: {component.button-primary-active} (darker {colors.primary-active}), {component.button-primary-hover} (lighter {colors.primary-hover}), {component.button-primary-disabled} (muted {colors.primary-disabled}). Transitions use 200ms cubic-bezier(0.4, 0, 0.2, 1) for background-color and color.
{component.button-secondary} — Ghost/outline companion to primary. Transparent background, {colors.ink} text, identical geometry (14×28px padding, squircle radius). On dark surfaces, use {component.button-secondary-dark} variant with {colors.body} text. Border is implemented as {shadows.inset-border} rather than CSS border property.
{component.button-ghost} — Tertiary/minimal action button. Transparent background, {colors.muted} text (lower contrast), smaller 10×16px padding, still squircle-rounded. Used for dismiss actions, "learn more" links styled as buttons, or non-primary pathways.
Cards & Containers
{component.card-surface} — Standard content card. White {colors.surface-elevated} background floating subtly above the {colors.canvas} page. Text in {colors.ink}, body copy in {typography.body-md}. Rounded {rounded.md} (8px), internal padding {spacing.xl} (24px). Shadow typically {shadows.hairline-shadow} or {shadows.soft-drop} depending on stacking context. Used for feature descriptions, testimonial blocks, and content modules in grid layouts.
{component.card-dark} — Inverted card for dark-band contexts. Background {colors.surface-dark}, text {colors.body} or {colors.body-muted}. Same geometry as {component.card-surface} (8px radius, 24px padding). Appears inside {component.dark-section-band} areas for testimonial cards, FAQ panels, or highlighted content.
{component.feature-card} — Lightweight feature listing container. Often transparent background (letting the section surface show through) with tight {rounded.sm} (4px) radius and {spacing.lg} (16px) padding. Holds a feature icon, heading in {typography.heading-md} (20px sans), and description in {typography.body-md}. May contain nested {component.badge-pill} for categorization.
{component.pricing-tier-card} — Pricing plan container on light surface. White/elevated background, {rounded.md} (8px), 24px padding. Contains plan name ({typography.title-md} slab), price ({typography.display-lg} or large number), feature checklist ({typography.body-md}), and CTA button. Non-featured plans use this base.
{component.pricing-tier-card-featured} — The promoted pricing tier. Inverts to {colors.surface-dark} background with {colors.body} text. Steps up to {rounded.lg} (12px) for emphasis, may include a "Popular" or "Recommended" badge ({component.badge-dark}). Same internal padding (24px) but visually dominant through inversion.
{component.dark-section-band} — Full-width inverted background band. Background {colors.surface-dark}, padding 135px vertical (matching hero) or 56–58px for compressed sections. Contains white/muted text content, dark cards, or CTA groups. Creates rhythmic alternation with light canvas sections.
{component.footer} — Site footer in dark context. Background {colors.surface-dark}, text in {colors.muted-soft} (50% white), {typography.body-sm} (13px) for legal/small print. Padding {spacing.section-md} (56px) vertical, 16px horizontal matching nav. Contains link columns ({component.footer-link}), legal text, and brand mark.
Inputs & Forms
{component.input-field} — Text/email input. Background {colors.canvas}, {colors.ink} text in {typography.body-md}. Height 44px (touch-friendly), horizontal padding 14px, rounded {rounded.DEFAULT} (6px). Border implemented as {shadows.inset-border} (20% opacity 1px inset) — this is the signature input treatment, appearing as a fine etched line rather than a drawn border. Focus state transitions to {component.input-focus} with ring/shadow enhancement.
{component.input-focus} — Focus state for inputs. Retains {colors.canvas} background and geometry but enhances the inset border or adds a subtle {colors.primary}-tinted focus indicator. Transition timing: 200ms cubic-bezier(0.4, 0, 0.2, 1) matching button transitions.
Navigation & Links
{component.link-text} — Inline text link. Transparent background, {colors.link} (#1335b1 deep blue) text in body size. Underline appears on hover/interaction (transition timing 350ms with delayed start for underline reveal). Used in body copy, footnotes, and cross-references.
{component.link-text-active} — Active/visited link state. Shifts to {colors.link-active} (#2322b8 vivid blue), slightly brighter/violet. Maintains same transition curve.
{component.footer-link} — Footer navigation link. Transparent background, {colors.muted-soft} text (50% white) in {typography.body-sm} size. Smaller click target, lower contrast appropriate for footer context.
Badges & Tags
{component.badge-pill} — Standard categorical badge. {colors.surface-soft} (warm gray) background, {colors.ink} text in {typography.caption} (12px). Fully rounded ({rounded.full} = 9999px), tight padding 4px × 10px. Used for feature categories, status labels, or filter tags on light backgrounds.
{component.badge-dark} — Badge for dark-surface contexts. {colors.border-strong} (10% white) background, {colors.body} white text. Same dimensions as {component.badge-pill}. Appears on {component.pricing-tier-card-featured} or inside {component.dark-section-band}.
{component.badge-peach} — Category-specific badge in warm tone. {colors.surface-peach} (#f9b28c) background, {colors.ink} text. Indicates personal/inbox-related features or "new" status.
{component.badge-sky} — Category-specific badge in blue tone. {colors.surface-sky} (#c4e2fb) background, {colors.ink} text. Indicates scheduling/calendar integrations or sync-related features.
{component.badge-gold} — Category-specific badge in yellow tone. {colors.surface-gold} (#f5d188) background, {colors.ink} text. Indicates AI-powered features, intelligence markers, or premium capabilities.
{component.badge-mint} — Category-specific badge in green tone. {colors.surface-mint} (#f7f8f4) background, {colors.ink} text. Indicates completion states, health status, or eco-friendly messaging.
Signature & Specialized Components
{component.integration-icon-circle} — 40px square container (rendered circular via rounding) holding an integration service icon. {colors.surface-soft} background, likely contains an SVG or image of the integrated tool (Google Workspace, Slack, etc.). Size {spacing.xl} plus margin for consistent icon grid alignment.
{component.stat-label} — Label for a statistic or metric. Transparent background, {colors.muted} text in {typography.caption} size. Sits above or beside a {component.stat-value}.
{component.stat-value} — Large numeric value for statistics. Transparent background, {colors.ink} text in {typography.display-lg} (48px slab, weight 100) for editorial impact. Used in social-proof sections ("X teams," "Y tasks completed").
{component.testimonial-card} — Customer quote container. {colors.surface-elevated} white background, {colors.ink} text, 8px radius, 24px padding. Contains quote body ({typography.body-md}), author name ({typography.heading-md}), and role/company ({typography.caption} in muted). May include handwriting-font excerpt.
{component.accordion-header} — Expandable section trigger. Transparent background, {colors.ink} text in {typography.heading-md} (20px/445), 16px vertical padding. Click/tap expands associated {component.accordion-content}. Includes rotation chevron icon (not separately tokenized).
{component.accordion-content} — Expanded accordion panel. Transparent background, {colors.muted} text in {typography.body-md}, 8px top padding and 24px bottom padding. Content reveals with {keyframes.accordion-down} animation (200ms+ easing).
{component.divider-line} — Horizontal rule separator. {colors.hairline} background (5% ink), full available width, 1px inferred height. Used between list items, sections, or content blocks.
Do's and Don'ts
Do
- Do use
{typography.display-xl}(88px/weight 80/–2.64px tracking) exclusively for the hero headline and one major section statement per page — its fragility requires scale to succeed. - Do apply
corner-shape: squircle(or approximate via high border-radius) on all{rounded.DEFAULT}(6px) UI elements to maintain the superellipse signature shape. - Do reserve
{colors.primary}(#a5380b) for the single most important CTA per section — it's a voltage accent, not a field color. - Do use
{shadows.inset-border}(20% opacity 1px inset shadow) instead ofborder: 1px solidon inputs, buttons, and focusable chrome for the etched-edge aesthetic. - Do set body copy at
{typography.body-md}(14px/weight 445/+0.42px tracking) even though it's smaller than the 16px industry norm — the positive tracking compensates for density. - Do alternate between light (
{colors.canvas}) and dark ({colors.surface-dark}) section bands every 2–3 scroll-lengths for rhythmic pacing. - Do use the pastel badge palette (
{colors.surface-peach},{colors.surface-sky},{colors.surface-gold},{colors.surface-mint}) consistently for category coding — establish a legend and maintain it across the page. - Do give the hero band
{spacing.section-xl}(135px) vertical padding — the 88px headline demands that much air to avoid crowding the viewport edges. - Do apply
{typography.title-md}(18px slab/weight 100) for subtitles and bylines beneath display type — it bridges the extreme weight differential gracefully. - Do keep the handwriting font (
{typography.handwriting}) to 2–3 instances per page maximum — it's powerful precisely because it's scarce.
Don't
- Don't bold the display headlines —
{typography.display-xl}at weight 80 is intentionally hairline; increasing weight destroys the editorial character. - Don't use
{colors.primary}as a background fill for large areas — it's an accent color, not a surface color; for dark fills, use{colors.surface-dark}. - Don't substitute
{colors.link}(blue) for{colors.primary}(rust-orange) on CTAs — links are informational, buttons are conversional. - Don't exceed
{rounded.lg}(12px) on any card or container — the shape system tops out there for rectangular elements; larger values break the disciplined squircle vocabulary. - Don't add gradient backdrops or colored washes to the hero — the
{colors.canvas}background is intentionally plain, letting the 88px type carry the visual weight. - Don't let body copy drop below 14px (
{typography.body-md}) — the 445 weight already pushes legibility limits; smaller would fail WCAG AA for extended reading. - Don't mix the handwriting face into body copy or UI labels — it exists for quoted/signature moments only.
- Don't apply drop shadows heavier than
{shadows.soft-drop}(5% opacity, 1px/2px offset) to cards — the system prefers flat/color-block separation over cast-shadow depth. - Don't use pure #000 or #fff when
{colors.ink}(#1c1b1b) and{colors.canvas}(#fdfdfc) exist — the warmth difference is subtle but essential to the atmosphere. - Don't implement hover-only interactions without a focus-visible equivalent — the 200ms
cubic-bezier(0.4, 0, 0.2, 1)transition must apply to both states for accessibility.
Motion & Animation
Transition Tokens
--transition-base: color 0.2s cubic-bezier(0.4, 0, 0.2, 1), background-color 0.2s cubic-bezier(0.4, 0, 0.2, 1), border-color 0.2s cubic-bezier(0.4, 0, 0.2, 1), outline-color 0.2s cubic-bezier(0.4, 0, 0.2, 1);
--transition-chromatic: color 0.15s cubic-bezier(0.4, 0, 0.2, 1), background-color 0.15s cubic-bezier(0.4, 0, 0.2, 1), border-color 0.15s cubic-bezier(0.4, 0, 0.2, 1);
--transition-ui: background-color 0.2s ease, box-shadow 0.2s ease, color 0.2s ease;
--transition-opacity: opacity 0.2s ease-out, filter 0.2s ease-out;
--transition-stepped: opacity 0.3s steps(4);
--transition-underline: text-decoration-color 0.35s cubic-bezier(0.165, 0.84, 0.44, 1) 0.36s;
Keyframe Animations
hero-rise— Entrance animation for the hero headline and supporting elements; likely a combined translateY + opacity fade from below viewport.townie-tile-spin— 3D rotational animation on mascot/character tiles (the "Townie" avatar system), probably a continuous slow rotation or flip on interaction.accordion-down/accordion-up— Height-reveal animations for expandable FAQ/content panels, using clip-path or max-height techniques.shimmer-text/shimmer— Gradient sweep across text or surface for loading/skeleton states or premium feature highlighting; linear-gradient translate-x mask technique.buttonShimmer— Highlight sweep across primary CTA buttons on hover or initial load, reinforcing the button as the conversion focal point.pill-pop— Scale/bounce entrance for badge pills and tag components, drawing attention to new or updated categorization.fade-in/scale-in/slide-down— Utility entrance animations for modals, dropdowns, and revealed content panels.playHintPulse— Pulsing opacity/size animation on play buttons or interactive demo triggers to indicate clickability.assignee-bounce— Subtle bounce on assignment/avatar elements in task-management UI previews.task-dot-wave— Sequential dot animation for task progress indicators, wave-pattern opacity stagger.selection-pulse/selection-pulse-dark— Pulse ring on selected items, with light and dark variants for different surface contexts.shake— Horizontal displacement for error/validation feedback (input rejection, form errors).
Interaction Patterns
- Button hover lift: Buttons transition background-color and box-shadow simultaneously over 200ms with the
cubic-bezier(0.4, 0, 0.2, 1)ease — snappy but not jarring. - Scroll-triggered entrance: Hero content uses
{keyframes.hero-rise}(fade-up + slight translateY) on page load; subsequent sections likely use IntersectionObserver-triggered{keyframes.fade-in}variants. - Accordion expansion: FAQ/collapsible panels animate height via
{keyframes.accordion-down}over ~250ms, with content opacity fading in after height stabilizes. - Shimmer highlights: Premium badges, featured pricing tier, and primary CTA receive periodic
{keyframes.shimmer}or{keyframes.buttonShimmer}sweeps — a gradient moving left-to-right behind the content. - Focus ring reveal: Inputs and buttons show enhanced
{shadows.inset-border}or a subtle{colors.primary}ring on focus, transitioning over 150–200ms. - Underline reveal: Text links don't show underlines by default; on hover/interaction, an underline animates in from left-to-right using
{transition-underline}(350ms with 360ms delay before start — creates a "pause then reveal" feel). - Stepped opacity: Certain loading or transitional states use
{transition-stepped}(opacity over 300ms in 4 discrete steps) for a mechanical/rather-than-smooth temporal feel. - Pill bounce-in: Category badges and notification pills enter with
{keyframes.pill-pop}— quick scale from 0.9→1.05→1.0 over ~300ms with spring-like easing.
Imagery Style
- Primary illustration style: Vector-based UI illustration with flat or subtly gradient-filled shapes, likely custom-designed for the product marketing context. Colors pulled from the palette (inks,
{colors.primary}, pastel accents). - Product screenshot treatment: App interface captures presented in rounded containers (
{rounded.md}or{rounded.lg}), often with a subtle{shadows.soft-drop}or no shadow at all, floating on{colors.canvas}or{colors.surface-dark}backgrounds. - Iconography: Custom SVG icons (detected as non-library), geometric and minimal, rendered in
{colors.ink}or currentColor, typically at 16px, 20px, or 24px depending on context (inline vs standalone). - Integration logos: Third-party service icons (Slack, Google, etc.) displayed inside
{component.integration-icon-circle}(40px, rounded-full,{colors.surface-soft}background), creating a unified grid regardless of source logo geometry. - Avatar/Townie imagery: Character or mascot assets (the "Townie" referenced in
townie-tile-spin) appear to be illustrated or 3D-rendered figures, possibly with subtle animation states. - Photographic absence: No stock photography detected in the DOM structure; the site relies entirely on designed/graphic imagery rather than lifestyle photography.
- Decorative color blocks: Solid pastel rectangles (
{colors.surface-peach},{colors.surface-sky}, etc.) used as abstract decorative elements behind text or as section dividers, contributing to the editorial-layout feel. - Dark-mode imagery: On
{colors.surface-dark}sections, imagery either inverts (light-colored illustrations) or maintains contrast through brightness/opacity adjustments. - Image-as-depth: Some hero or section visuals likely serve dual purpose as decorative depth layers — large, soft shapes behind text that occupy z-index between background and content.
Icon System
- Library: Custom SVG (no Lucide, Heroicons, or Material icon library detected in class names or font references).
- Specific icons observed: Navigation chevron/down-arrow (accordion triggers), external-link arrows, checkmarks (feature lists/pricing), integration service marks (inside circles), social proof symbols, play button (demo video trigger), close/dismiss (x-mark), menu/hamburger (mobile nav).
- Treatment: Predominantly stroke-based with consistent 1.5–2px stroke width; color set to
currentColorinheriting from parent text color (usually{colors.ink}or{colors.body}). Fill icons used selectively for integration logos and decorative elements. - Size spectrum: 16px for inline/contextual icons (beside links, inside buttons), 20px for navigation and UI controls, 24px for standalone feature icons, 40px container size for integration icon circles.
- Alignment: Icons center-aligned vertically with adjacent text using flexbox
items-center; button icons have{spacing.sm-plus}(10px) gap from text label pervar(--button-gap)reference.
Recommended Frontend Stack
- Framework: Next.js 14+ (App Router) — detected via __next_f push chunks, React server component patterns, font-face preloading strategy
- Styling: Tailwind CSS v3.4+ (custom config) — utility-class naming conventions detected (brand: prefix on classes), arbitrary value usage, custom shadow/spacing extensions
- Fonts: Self-hosted variable fonts: Material Upright Variable (.woff2), ABC Diatype Variable (.woff2) — served from /fonts/ path with font-display: swap
- Animation: CSS keyframes + Tailwind animation utilities (custom keyframe definitions for hero-rise, shimmer, etc.); likely lightweight JS for IntersectionObserver scroll triggers
- Icons: Custom SVG components (React-based inline SVG, no external icon library dependency)
- Component lib: Custom component layer (no shadcn/Radix detection) — homegrown primitives with Tailwind utility composition
- Build: Turbopack or Webpack via Next.js build pipeline
Responsive Behavior
Breakpoints
| Name | Width | Key Changes | |---|---|---| | Mobile | < 640px | Single column; nav collapses to hamburger; hero headline scales down (~48–56px); 16px horizontal padding | | Tablet | 640–1024px | Two-column feature grids; nav may persist simplified; hero headline ~64–72px | | Desktop | 1025–1440px | Full layout as documented; 1440px max content width; 3-column grids possible | | Wide | > 1440px | Content centers at 1440px with remaining space as margin; nav may expand to 1952px shell |
Touch Targets
{component.button-primary}: 14×28px internal padding plus text width — estimated minimum 44×44px touch area meets WCAG AAA.{component.button-secondary}: Identical dimensions to primary — passes 44×44px requirement.{component.nav-button}: 10px padding all sides — with ~14px text height reaches ~34px, potentially failing AAA; recommend increasing to 12px padding for mobile.{component.input-field}: 44px explicit height — exactly meets WCAG AAA minimum.{component.badge-pill}: 4×10px padding with 12px text — ~20px height, too small for reliable touch; acceptable as non-interactive label only.- Accordion headers: 16px vertical padding plus 20px text height — ~52px, comfortably exceeds minimum.
Collapsing Strategy
- Navigation: At mobile breakpoint, the horizontal nav items (Features, Routines, Integrations, Pricing) collapse into a hamburger-menu drawer or bottom-sheet overlay; Sign-In button persists in the header bar or moves into the menu.
- Hero section: The asymmetric two-column layout (headline left, visual right) stacks vertically — headline above, visual below.
{typography.display-xl}scales down via clamp() or breakpoint-specific class to ~48–56px (approaching{typography.display-lg}territory) to fit mobile viewports. 135px vertical padding compresses to 56–80px. - Feature grids: 3-column desktop grids collapse to 2-column on tablet, single-column on mobile. Card padding may reduce from 24px to 16px on smallest screens.
- Pricing table: Horizontal card layout (side-by-side tiers) stacks vertically; featured tier may move to top position for visibility.
- Footer: Multi-column link grid collapses to stacked sections; legal text remains full-width.
- Typography scaling:
{typography.display-xl}(88px) is viewport-dependent — likely uses CSSclamp(2.5rem, 8vw, 5.5rem)or similar fluid type approach.{typography.body-md}(14px) may increase to 16px on mobile for legibility. - Spacing compression:
{spacing.section-xl}(135px) reduces to{spacing.section-md}(56px) or{spacing.section-sm}(32px) on mobile to preserve vertical rhythm without excessive scrolling.
Image Behavior
- Hero right-rail visual: On mobile, scales to full container width (minus padding), aspect-ratio maintained or shifted to 4:3/16:9. Max-height likely constrained to prevent the visual from dominating the stacked layout.
- Integration icon circles: Maintain 40px size or reduce to 32px on mobile; grid collapses from multi-column to horizontal scroll or wrapping flex.
- Product screenshots: Contained within card rounding, scale proportionally, may switch from side-by-side to stacked (description above, screenshot below) on narrow viewports.
- Testimonial avatars (if present): Circular crop maintained at 40–48px, reduce from larger desktop sizes.
Iteration Guide
-
Initialize a Next.js project with App Router and configure Tailwind CSS v3.4+. Add the custom theme extension for Town's design tokens — define all
{colors.*},{typography.*},{rounded.*},{spacing.*}, and{shadows.*}values intailwind.config.tsundertheme.extend. -
Register the three variable font families in your CSS or Next.js
font.jsconfiguration: Material Upright Variable (as--font-slab), ABC Diatype Variable (as--font-sans), and a handwriting fallback (as--font-handwriting). Serve the.woff2files from/public/fonts/withfont-display: swap. Map them to the CSS variable names used in the extracted classes:font-sans,font-slab,font-handwriting. -
Implement the
{component.top-nav}first: 78px fixed height,{colors.canvas}background, 1440px centered content area, 16px horizontal padding. Build the flex layout with logo-left, nav-items-center (using{component.nav-button}withcorner-shape: squircle), and Sign-In button-right ({component.nav-button-sign-in}with dark background). -
Construct the hero section (
{component.hero-band}) with 135px vertical padding and{colors.canvas}background. Set the<h1>to{typography.display-xl}(88px, weight 80, –2.64px tracking, slab font). Add the subhead in{typography.title-md}(18px slab, weight 100). Place the CTA pair:{component.button-primary}(filled rust-orange, squircle) beside{component.button-secondary}(ghost, squircle). Build the right-rail visual area at ~40% width. -
Build the component library following the exact YAML specifications: each component entry maps to a React component (or HTML template) with props for backgroundColor, textColor, typography, rounded, and padding. Use Tailwind's arbitrary value syntax for non-token values (e.g.,
p-[14px_28px]). Implement state variants as separate components or conditional className application. -
Implement the alternating section rhythm: light band (
{colors.canvas}) → content → dark band ({component.dark-section-band}) → content → repeat. Inside dark bands, use inverted text colors ({colors.body},{colors.body-muted}) and{component.card-dark}or{component.pricing-tier-card-featured}components. -
Add motion last, after static layout is pixel-correct. Implement the keyframe animations defined in the Motion & Animation section as Tailwind
@keyframesdirectives. Applyanimate-hero-riseto hero content on mount,animate-fade-into sections on scroll (via IntersectionObserver hook), andtransition-baseclass to all interactive elements. -
For responsive behavior, use Tailwind's responsive prefixes (sm:, md:, lg:, xl:) to adjust typography sizes, collapse grids, modify padding tokens, and toggle the navigation layout. Ensure
{component.input-field}maintains 44px height at all breakpoints. -
Run contrast checks:
{colors.primary}(#a5380b) on{colors.on-primary}(#ffffff) must exceed 4.5:1 (it does — approximately 5.2:1).{colors.ink}(#1c1b1b) on{colors.canvas}(#fdfdfc) exceeds 15:1 (excellent). Verify all text-on-surface combinations meet WCAG AA minimums. -
Font setup for development environment (if proprietary fonts unavailable):
:root {
--font-slab: 'Roboto Slab', 'slab Fallback', Georgia, serif;
--font-sans: 'IBM Plex Sans', 'sans Fallback', system-ui, -apple-system, sans-serif;
--font-handwriting: 'Caveat', 'handwriting Fallback', cursive;
}
/* Load from Google Fonts in layout.tsx or _app.js */
Known Gaps
- Hover state styling: Per the no-hover policy, hover background-color changes, transform lifts, and shadow enhancements are documented as separate frontmatter entries (
{component.button-primary-hover}) but the exact property values for intermediate hover states (not pressed, not resting) are interpolated from active/default. - Loading skeletons: No skeleton/placeholder component detected; the
{keyframes.shimmer}and{keyframes.shimmer-text}animations suggest shimmer loading states exist but their exact markup structure (pulse boxes, gradient masks) wasn't captured. - Form validation states beyond focus: Error state styling for inputs (red border, error icon, message text) is partially covered by
{colors.error}but the complete invalid-input component (including message placement, icon, animation) wasn't extractable from the landing page context. - Dashboard/product UI surfaces: The landing page shows marketing content only; authenticated dashboard views, settings panels, inbox interfaces, and calendar surfaces weren't captured and likely extend the design system with additional components.
- Mobile navigation drawer: The collapsed mobile menu structure (hamburger contents, animation, backdrop) is assumed from responsive patterns but not directly observed in the desktop-focused extraction.
- Exact pastel surface hex precision: Values for
{colors.surface-peach},{colors.surface-sky},{colors.surface-gold},{colors.surface-mint}were extracted from computed background colors but may be generated programmatically (HSL manipulations) rather than hardcoded; verify against design source if available. - Corner-shape: squircle browser support: The
corner-shapeCSS property used on nav buttons is part of the CSS Round Display Level 1 specification with limited browser support; fallback to highborder-radiusvalues (9999px for squircle approximation) is necessary for production. - Animation orchestration: The sequencing between
{keyframes.hero-rise}, staggered child entrances, and scroll-triggered reveals requires JavaScript coordination (GSAP ScrollTrigger, Framer Motion useInView, or custom IntersectionObserver) that isn't encoded in the static CSS. - Dark mode variant: While the system includes
{colors.surface-dark}for sectional inversion, a true dark-mode color theme (swapping canvas/ink roles globally) wasn't detected —{extensions.mode}is"light"indicating the site is light-mode primary.