noticed

Design foundations — single reference for the new system. Locked decisions only; open explorations live at /brand-sandbox.

last updated 2026-06-10

Visual

Wordmark

Fraunces. Locked variable axes: opsz 144, wght 550, SOFT 50, WONK 1 (the "wonky" axis — the cocked serifs + flared terminals that give the mark its character), roman. Tracking -0.02em (em-relative, scales with size). opsz is pinned at 144 (optical sizing off) so every render is the same display cut, at any size — and matches the outlined favicon/SVG exports.

One source of truth: the font-wordmark token (composes over font-display). Every logotype render uses it; retune the axes once in shared-styles.css.

Always lowercase. "noticed", never "Noticed".

Logo and display moments only — never in product UI.

noticed
light
noticed
dark

Brand mark

Lowercase "n" in Fraunces inside a square. Rounded uses the iOS-app-icon corner ratio (22.5% of side); the square (non-rounded) version is the one used for the favicon + browser/app icons.

Used as favicon, app icon, and avatar. Light + dark variants, rounded + square. Download is a single 1024×1024 asset — scale down as needed. The favicon ships the dark square mark (regenerate via scripts/generate-brand-icons.mjs).

Re-tune at /brand/tune.

noticed
noticed
noticed
light · 1024×1024
noticed
noticed
noticed
dark · 1024×1024
noticed
noticed
noticed
light · square · 1024×1024
noticed
noticed
noticed
dark · square · 1024×1024

Typography — product UI

Switzer for every product surface. Hierarchy comes from weight (400 / 500 / 600), not from changing typefaces.

These specimens render the live type tokens — size and line-height come from the token itself, so this page can never drift from the system.

text-body · 15/22The agent finds the right person.
text-body-sm · 14/20The agent finds the right person.
text-row · 13/20The agent finds the right person.
text-label · 12/16The agent finds the right person.
text-micro · 11/16The agent finds the right person.
400 — body

Row text, nav items, captions.

500 — emphasis

Row names, buttons, sub-bar.

600 — heading

Headings, section titles.

Typography — display

Fraunces, regular, tracking -0.04em at large sizes.

Always lowercase. Sentence case for longer marketing copy; never title case or all caps.

Roman only; never italic. Emphasis comes from cadence and line breaks, not from leaning the letterforms.

Used only for the wordmark and marketing display moments. Never appears inside the product UI.

72noticed
48be noticed
24your networking agent

Color — surfaces

Warm monochrome on cream (light) and white-on-near-black (dark).

Muted variants use alpha — oklch(0 0 0 / N) in light, oklch(1 0 0 / N) in dark. Each row shows both modes so the symmetric pattern is visible at a glance.

Two surface levels: the background canvas, and the raised surface shared by card, popover, and sidebar — borders and shadows define hierarchy, bg contrast stays minimal.

--backgroundlight:oklch(0.985 0.002 90)stone-50dark:oklch(0.147 0.004 49)stone-950body / canvas
--sidebarlight:oklch(1 0 0)whitedark:oklch(0.216 0.006 56)stone-900shares the card raised surface
--cardlight:oklch(1 0 0)whitedark:oklch(0.216 0.006 56)stone-900raised surfaces (popovers, + create)
--foregroundlight:oklch(0 0 0 / 0.85)black/85dark:oklch(0.985 0.001 106)stone-50primary text
--muted-foregroundlight:oklch(0 0 0 / 0.6)black/60dark:oklch(0.709 0.01 56)stone-400sub, section, footer text
--borderlight:oklch(0 0 0 / 0.12)black/12dark:oklch(1 0 0 / 0.1)white/10every divider — rendered at 0.5px
--accentlight:oklch(0 0 0 / 0.04)black/4dark:oklch(1 0 0 / 0.06)white/6hover, selected, subtle fills
--destructivelight:oklch(0.577 0.245 27.325)red-600dark:oklch(0.704 0.191 22.216)red-400errors + destructive only — never brand

Brand accent — spring

spring. A warm yellow-green that sits between the canvas and the deep ink — the moment of new growth, of being noticed.

The hue (125°) is honest about what it is: not fern, not lime, not money green. It pairs with the stone canvas without competing, and stays distinctive against the warm grays that do most of the work.

5-stop ramp · semantic aliases swap by theme.

Brand-colored text is always text-brand-text — never text-brand. The chip fill (brand-200) is ~1.2:1 on light surfaces as text. Lint-enforced.

ramp · theme-independent
--brand-50
wash · hover (rarely direct)
oklch(0.98 0.04 125)
--brand-100
soft fill (rarely direct)
oklch(0.95 0.09 125)
--brand-200
base · the chip
oklch(0.92 0.13 125)
--brand-700
text on chip · accent text
oklch(0.45 0.09 145)
--brand-900
deepest · dark-chip text
oklch(0.25 0.06 150)
semantic aliases · swap by theme
tokenlightdarkuse
--brandbrand-200brand-200the chip — marketing primary CTA
--brand-foregroundbrand-700brand-900text on chip
--brand-textbrand-700brand-200brand-colored text + icons
--brand-wash22% alpha22% alphaselection wash · brand callout bg
--button-app (light)white cardapp primary chip · sublime CRM
--button-app (dark)10% whiteapp primary chip · sublime CRM
applied
Add personintro readysee all 14 matches →your network is your most underused asset.
categorical palette

Six muted hues for tags, industry labels, persona categories, project types — anywhere categorization is required. Spring (our brand) is not in this set: categorical color shouldn't compete with brand identity. Pattern: base color for icons + text, 10% alpha of the same hue for the bg.

SoftwareFinanceStrategyBrandUrgentOperations

--tag-blue · --tag-amber · --tag-purple · --tag-pink · --tag-coral · --tag-teal

Surface rules

Marketing and app share the same discipline for everything except three things.

Two elements differ between marketing and app surfaces — primary CTA and secondary CTA. Everything else is identical. Brand appears as interactive state: selection wash, text-selection highlight, focus rings, checkbox/switch ON, tiny unread dots, chat send button, links to data, display accent.

elementmarketingapp
Primary CTA

Loud green chip — the brand event

White card chip + border — neutral

Secondary CTA

Recessed gray chip — no border, matches primary

Active = bordered elevation chip (matches primary). Inactive = ghost (no bg, no border, muted text). Sampled from a segmented control on Lightfield CRM.

Borders, radius, surfaces

0.5px subpixel borders. 6px radius. One elevation level.

Shadows reserved for popovers and dialogs only.

Tokens: border-hairline all-sides, border-{t|r|b|l|x|y}-hairline directional. Never an arbitrary border-[…].

card · 6px · 0.5px border
create

divider · 0.5px · border-border

Shadows

Two elevation tiers + one menu treatment. Neutral, no glow.

Tokens: shadow-raised / shadow-floating / shadow-popover, defined in packages/tailwind-config/shared-styles.css. The drops are identical in both modes; the popover hairline ring is themed per mode. The demos below render the live utilities.

raised · for buttons + small lifted controls

shadow-raised · 0 1px 3px / 0.04

The minimum "lift" — used on primary CTAs, the + create chip, any control that should feel raised by ~1px.

floating · for panels off the page

shadow-floating · 0 8px 24px / 0.06

Bigger lift for surfaces that overlap the canvas — chat side panel, peek panes, floating cards. Reads as "detached."

popover · for menus + dialogs

shadow-popover · 0.5px themed ring + 0 6px 18px / 0.06

Hairline ring + soft drop. Menus + dropdowns + dialogs need the ring because they portal over arbitrary content; a drop shadow alone can't separate them on busy backgrounds.

Badge patterns

Three variants plus a special count chip. Hierarchy goes outlined → subtle → categorical.

Categorical lives in its own palette (see Brand accent · categorical palette). Outlined + subtle share the same chip shape; only fill + text-weight differ. State-change moments that want emphasis (new, urgent, unread) use the count chip's recipe — brand-wash bg + brand-text — rather than a fourth neutral variant.

variantexamplerecipe + use
outlinedBetaTransparent bg · 0.5px standard border · full ink text · 4px radius. Used for status labels that should sit quietly next to a title (Beta, New, v0.1.0).
subtleintro ready--button-app bg · 0.5px border · muted text. Used for soft status (intro ready, warm lead) — visible but doesn't shout.
categorical
SoftwareFinance
Hue at 10% alpha bg · same hue at full saturation text. Six hues available; see Brand accent · categorical palette. Used for tags, industries, persona categories.
count1--brand-wash bg + --brand-text. Used for nav unread counts, notification numbers, any small numeric "new state" indicator. Brand-tinted so the number reads as a state signal, not a neutral counter.

Buttons on surfaces

One convention, so a button's weight always means the same thing. Weight is fixed by role; width adapts to the label (with a shared min so a column of actions still aligns).

Filled default = the one action that moves you forward (Connect, Import, Request). surface = the grey secondary on any white card (Manage, Disconnect, Share, a done state). ghost = icon + row controls. Never put outline on a card — it's for non-card chrome. Full reference: docs/brand/buttons.md.

weightexamplerecipe + use
default · primaryFilled brand. The single "do this" action on a card — at most one per card. Also the connected-state signal: filled while there's an action left to take.
surface · secondaryRaised white card + hairline + shadow-raised. The grey secondary on any white surface — Manage, Disconnect, Share, and done/disabled states. Goes grey once the action is complete.
ghost · minimalTransparent until hover. Icon-only buttons, pagination, table row actions — low-affordance controls that shouldn't compete with the card's content.
outline · not on cardsRecessed off-white. Reserved for non-card chrome (toolbars, consent forms). On a card it reads as a third elevation and competes with surface — use surface instead.

Icons

Phosphor, Regular weight only.

All icons render through <Icon>, which defaults to weight="regular".

UsersThree
User
Briefcase
Buildings
Clock
At
LinkedinLogo
SidebarSimple
Plus
Sparkle
MagnifyingGlass
Bell

Motion

150–200ms, ease-out.

No bounce, no spring.

Baked into the transition defaults (--default-transition-duration 200ms + ease-out) — a bare transition-* utility is already brand-correct. Declare a duration/easing only to intentionally diverge.

transition-colors · 200ms ease-out from the defaults · color transition only, no transform.

Imagery / art direction

Photo treatment, illustration policy, and where each applies.

Marketing scope. Product UI uses no imagery beyond avatars and icons.

Voice & copy

Positioning

Who we are, who for, what we replace. One paragraph.

Anchors every copy decision downstream.

Personas — user

Who we're designing for.

Distinct from the landing page's investor / client / hire rows — those are marketing slots, not foundational personas.

Personas — agent

Three voices the agent can take. Default donna.

Tone only — capabilities are identical. Voice rules below always win.

Source: packages/agent-core/src/persona-catalog.ts.

ari
the enforceraggressive loyalty. does what you won't.
donnadefault
the strategistquiet omniscience. three moves ahead.
ted
the cheerleaderwarm encouragement. makes it feel easy.

Voice

How the brand speaks. Applies to every agent reply, marketing line, and UI label.

Canonical source: docs/brand/voice.mdx. The principles below are a synced snapshot of its core rules.

Hover any rule for approve · edit · dismiss. Picks live in localStorage.

don'ts
  • care first. the reader is busy, distracted, maybe a little lost. the job of the copy is to make their day a fraction lighter. warmth is the brand. everything else is technique.

  • say less, but stay human. one sentence often beats two. white space gives the eye somewhere to land. but short isn't the goal; care is. a sentence that breathes beats one that snaps.

  • write how people talk. read it out loud. if it sounds like a press release, rewrite it. if it sounds like a text to a smart friend, ship it.

  • casing follows the typeface. fraunces display headlines + the wordmark are lowercase; everything in switzer (product UI, headings, body, copy) is normal sentence case, with title case for proper nouns. two exceptions stay all-lowercase: the agent's chat replies and @noticedso social posts. the brand name 'noticed' is always lowercase, never a capital N.

  • don't explain AI. never say "powered by AI" or "leveraging machine learning." the product just works. the agent goes unnoticed. the result is what matters.

  • use "you," not "users" or "customers." noticed is a conversation between the product and one person.

  • no emojis in copy, marketing, pitch decks, or product UI. only exception: chat reactions (a single emoji, the way a friend would on Slack).

  • no em dashes (—). default to a period, a colon, or a new sentence. hyphens are a different mark, not a substitute.

dos
  • lead with the person, not the product. the user is the founder, the builder, the operator who already has the connections. say what they become, not what we do.

  • break for breath, not for layout. in display copy, line breaks set rhythm. one thought per line. let the period do the work the comma can't.

  • earn the irreverent line. once per page, allow one line that breaks formality ("wtf is networking, anyway?"). never twice. never as a default — always as a hook.

Lexicon

What to call things. What to avoid.

Lexicon = copy / voice level — the words the brand says (you not users, agent not assistant). Drives consistency across copy, product UI, and agent replies.

Glossary = technical / internal — definitions of company-specific concepts (signals, opportunities, relationships). Lives elsewhere; don't conflate.

UseRule
noticed
always lowercase. never "Noticed" or "NOTICED".
agent
not "assistant", not "bot".
you
not "users", not "customers". one person, in conversation.

System

Token system

How tokens are organized and enforced. Three tiers: primitives feed role tokens (content-*, fill-*, border-*, interactive-*) which feed shadcn compat.

Always use a token, never an arbitrary value. The rules + WCAG exemption that used to live in design-system-rules.md.

RuleRationale
Never use arbitrary values
`text-[13px]`, `border-[0.5px]`, `text-foreground/60` all forbidden. Use the token (`text-row`, `border-hairline`, `text-content-tertiary`).
WCAG AA floor
Normal text ≥ `content-tertiary` (.60). Muted (.50) and faint (.44) reserved for ≥18px text, icons, and disabled states.
`border-field` is an intentional exemption
At .16 it sits below the 3:1 threshold by design (WCAG 1.4.11): a form field is identified by its fill + label, not its border alone.
Compose off primitives
Use shadcn before custom. Three similar lines beat a premature abstraction.
Phosphor via `<Icon>` wrapper
No inline SVG. Defaults to `weight="regular"`. Lucide as fallback.
React 19 patterns
No `forwardRef`. Use the `use()` / Context patterns.
Enforced
ESLint errors on arbitrary type/border. `npm run audit:tokens` is a CI ratchet that counts 7 bypass axes. Brand, auth, data-viz allowlisted.

Layout architecture

The three-area shell + single-page detail view + persistent agent rail. Locked structural decisions for the noticed app.

The anatomy that used to live in design-layout.md. URL patterns + keyboard nav + terminology lock.

DecisionDetail
Three-area shell
Sidebar (250px, toggleable, ⌘\) left, canvas middle, agent rail (~30vw, toggleable, ⌘J) right.
Single-page detail view
No tabs. Header → brief → timeline (gbrain-style, append-only).
Brief is agent synthesis
4–6 lines max, rewritten on new evidence. Also serves as the fast-read context layer.
Agent rail is persistent
~30vw. Context chip auto-attaches the current page so the agent always has scope.
Keyboard nav
↑↓ row, Enter open, Space toggle.
URL patterns
`/relationships`, `/relationships/{id}`, `/chat?t={thread_id}`.
Terminology lock
“Relationships” (not “contacts”). A record refers to itself by name.

What we explicitly skipped

Documented to prevent re-litigation. Visual and layout decisions considered and dropped on the way to the current system.

SkippedReason
Purple accent (Linear, Anthropic-ish)
AI-default color. Dilutes brand.
Green accent (Granola, fintech)
Ties us to Granola or old-fintech.
Orange / warm amber (Claude)
Too close to Anthropic.
Linear-style dark-first
Fights warmth + light-default.
Multiple display faces
One face (Switzer) across the hierarchy.
`success` / `warning` color tokens
Semantic monochrome + iconography instead.
Separate hue tokens for muted variants
Alpha layering (`oklch(0 0 0 / N)`) matches Lightfield.
Phosphor Thin (1px)
Too faint at our icon sizes vs Lightfield — switched to Regular.
shadcn default 10px radius
Lightfield uses 6px; we matched.
Italic emphasis in marketing headlines
Roman only. Avoids the editorial/serif-italic trope and keeps headlines flat.
Loud badge variant
Visually indistinguishable from outlined. State-change moments use the count chip's brand-wash + brand-text recipe instead.
Right-rail property panel
Data lives in the brief, not a sidebar.
Details / Updates / Interactions / Memories tabs
Single page reads as a story, not a folder.
Reminders on the page
Live in the agent rail, not the record.
Side panel on row click
Open full detail; keep the table the surface.
View tabs
Filter chips on the sub-bar instead.
Skills dropdown
Skills are agent capabilities, not menu items.
Persistent trigger strip
Context chip + cmd-K instead.
Sparkle icon / FAB for agent
Agent rail is always-on; no floating CTA needed.