Back to studio index

Style Studio — Embellishments

Decoration inventory, rebuild work, and the secondary-accent surface pass.

Theme: light
Viewport: Desktop
Full-width stage

Batch 3 — Decoration Inventory

Read-mostly audit surface tracking keep/collapse/defer/delete decisions.

Embellishment Role Inventory

20 atoms in components/ui/decorations/** plus 3 compositions in board-decorations.tsx. (Code keeps the decoration identifier; human-facing copy uses embellishment.) Verdicts locked 2026-04-17 — see docs/embellishment-vocabulary.md.

22 entries audited
12 Keep
2 Collapse
8 Defer

Legend

Keep — first-class primitive, consumers unchanged.
Collapse — folds into a unified primitive in Batch 4.
Defer — held for launch palette; revisit in Batch 16.
Delete — scheduled for removal. (Zero entries this batch.)

PaperGrain — keep standalone

17 callers across 15 files. Chat cluster dominates but 10 non-chat callers justify public access.

Batch 6 ChatSurface will consume PaperGrain internally for chat surfaces only. Non-chat callers (communities, polaroid-card, app routes) keep the direct import. No deprecation.

Stamp family — SVG pair collapses

CategoryStamp + ConditionStamp → <Stamp variant=rectangular|circular>. CommunityStamp stays separate.

The SVG-generated pair shares displacement-filter logic and visual language. CommunityStamp is an image wrapper — different primitive class. Forcing it into the union would add a meaningless src prop to SVG variants.

Zero-caller atoms — deferred, not deleted

WashiTape, FilmStrip, StringConnector, WoodGrainTexture, PhotoVignette retained.

Held for launch embellishment palette. Each represents a unique material vocabulary slot with no replacement candidate. Revisit in Batch 16 cleanup if still zero-caller post-launch.

Attachment

Fasten one surface to another. Lives on top of the composition it anchors.

2 Keep
1 Defer

PushPin

Keep
9 calls · 7 files

Core scrapbook attachment. Used across notebook steps, trade chains, chain discovery.

Paperclip

Keep
10 calls · 6 files

Post/offer detail sheets. Three variants already consolidated inside the atom.

WashiTape

Defer
0 callers

Zero production callers. Held for launch embellishment palette.

Follow-up: Revisit in Batch 16 if still zero-caller post-launch.

Label / Mark

Name, classify, or authenticate. Adds identity ink, not structure.

3 Keep
2 Collapse

WaxSeal

Keep
11 calls · 8 files

Trust tier badges + trade confirmation seals. Status prop handles the color story.

PostageStamp

Keep
9 calls · 6 files

Distinct primitive class (postage indicia, serrated edges). Not part of Stamp collapse.

CategoryStamp

Collapse
6 calls · 4 files

SVG rubber stamp with displacement filter. Collapses into <Stamp variant="rectangular"> in Batch 4.

Follow-up: Batch 4: ship unified <Stamp variant="rectangular|circular">, migrate 4 call sites.

ConditionStamp

Collapse
6 calls · 4 files

SVG circular postmark with displacement filter. Collapses into <Stamp variant="circular"> in Batch 4.

Follow-up: Batch 4: retain condition→color map as a table consumed by the unified atom.

placeholder

CommunityStamp

Keep
1 call · 1 file

Image primitive (next/image wrapper for AI-generated PNGs). Different mechanism from SVG stamps — does NOT collapse.

Edge / Tear

Surface perimeter language. Defines where paper ends.

1 Keep

TornPaperEdge

Keep
13 calls · 8 files

Action-strip pattern across 6 routes. Widest edge-language primitive.

Texture / Grain

Material fill. Runs underneath content, never on top.

2 Keep
2 Defer
overlay on card bg

PaperGrain

Keep
17 calls · 15 files

Load-bearing. Chat cluster (5 files) + communities (4 files) + polaroid/app routes. Stays public — Batch 6 ChatSurface consumes it internally, non-chat callers keep direct access.

fills parent

CorkTexture

Keep
3 calls · 3 files

CorkBoard + CorkStrip primitives + MarketTableHero (broken-board hero). Material foundation for the board language.

border grain

WoodGrainTexture

Defer
1 call · 1 file

Only cork-board.tsx imports it. Part of cork/wood material pair — held for launch palette.

Follow-up: Revisit in Batch 16 if still single-caller post-launch.

radial overlay

PhotoVignette

Defer
1 call · 1 file

Only polaroid-card references it. Part of photo-material vocabulary — held for launch palette.

Follow-up: Revisit in Batch 16 if still single-caller post-launch.

Connector

Visual line between two points. Carries a relationship.

1 Defer

StringConnector

Defer
0 callers

Zero production callers. Held for launch palette (connector vocabulary has no other candidate).

Follow-up: Revisit in Batch 16 if still zero-caller post-launch.

Paper Fragment / Note

Standalone paper artefact that carries its own content block.

2 Keep
1 Defer

StickyNote

Keep
12 calls · 9 files

Filters, empty states, OfferingCard. Accent variants already consolidated.

IndexCardFragment

Keep
3 calls · 2 files

trust-metrics.tsx only. Low callers but unique visual surface (index card material).

bottom edge

FilmStrip

Defer
1 call · 1 file

Only its own index entry. Held for launch palette (media fragment vocabulary).

Follow-up: Revisit in Batch 16 if still zero-caller post-launch.

Tool / Utility

Interactive affordance or app-wide scaffolding. Not strictly decorative.

2 Keep

Eraser

Keep
3 calls · 2 files

GlobalAiWidget's erase affordance. Single functional consumer but load-bearing.

Infrastructure primitive — renders invisible <defs> once at the app root. Not visually testable in isolation.

no visible render

MaterialSvgFilters

Keep
1 call · 1 file

App-wide <defs> injected by layout.tsx. Infrastructure, not a user-facing atom.

Composition (non-primitive)

Pre-composed embellishments built from primitives. Audited for consumer count only.

3 Defer

Composition — interactive search surface. Requires state + handlers.

no visible render

SearchStickyNote

Defer
0 callers

Exported from board-decorations.tsx but zero JSX callers. Composition around StickyNote.

Follow-up: Verify before Batch 16 whether a planned board-search surface still intends to consume this.

Composition — board banner with inline pushpins + handwriting headline.

no visible render

BoardTitle

Defer
0 callers

Exported from board-decorations.tsx but zero JSX callers.

Follow-up: Verify before Batch 16 whether a planned board-title surface still intends to consume this.

Composition — empty-state surface with clear-filter CTA. Requires handler.

no visible render

EmptyBoardState

Defer
0 callers

Exported from board-decorations.tsx but zero JSX callers.

Follow-up: Verify before Batch 16 whether a planned empty-board surface still intends to consume this.

Batch 4 — Decoration Rebuild

Approved launch atoms after the inventory verdicts were locked.

Batch 4 active
Existing atom bench restored
This is the visual workbench for the current decoration atoms before we collapse, rebuild, and wire them into the system. Batch 3 locked the vocabulary; Batch 4 is where we inspect the atoms in real material contexts and then tighten their final system form.

Material Contexts

Paper
Clean paper context for note fragments, stamps, clips, and small labels.
Paper language
Labels, marks, and small attachment cues.
Cork
Board context for pins, thread, seals, and pinned paper fragments.
pinned idea
trusted match
Vintage Paper
Aged note context for torn edges, fragments, postage, and vignette language.

Atom Shelf

PushPin
keep
Board pin and polaroid thumbtack variants stay in the launch vocabulary.
Paperclip
keep
Wire and butterfly variants cover the attachment grammar on paper surfaces.
StickyNote
keep
Paper fragment pill used in filters, labels, and lightweight callouts.
Stamp · Rectangular
collapse
Unified rectangular stamp contract replacing CategoryStamp at the renderer/editor boundary.
Stamp · Circular
collapse
Unified circular stamp contract replacing ConditionStamp at the renderer/editor boundary.
PostageStamp
keep
Distinct postage vocabulary stays separate from the rubber stamp family.
WaxSeal
keep
Status embellishment with physical wax identity.
WashiTape
defer
Still visible for iteration even though it is not yet a production launch default.
StringConnector
defer
Connector vocabulary is still deferred, but the bench keeps it visible for evaluation.
TornPaperEdge
keep
The main torn-note edge language is already load-bearing and worth iterating in-context.
IndexCardFragment
keep
Fragmented paper artefact for more deliberate note blocks.
CommunityStamp
keep
Image-based stamp stays distinct from the SVG stamp family.
PaperGrain
keep
Material overlay that should be judged on actual paper shells, not in isolation.
PhotoVignette
defer
Lightweight photo-well effect held for the launch palette.
FilmStrip
defer
Chemical strip detail remains a palette item, but we keep it on the bench for comparison.
CorkTexture
keep
Board material foundation. This is one of the most important context setters on the bench.
WoodGrainTexture
defer
Frame-only texture still sits in the launch palette rather than the default public surface set.
Eraser
defer
Utility embellishment stays visible here even though it is not yet part of the main launch vocabulary.

Batch 9 — Secondary Accent

Secondary-accent surface contract and its migrated usage patterns.

Decision framing

7 live sites share a 'secondary-accent tinted notice/panel' shape that lives outside Card's current 7-intent grammar. Two proposals: extend Card to 8 intents (Option A), or ship a dedicated <SecondaryPanel> named pattern (Option B). Each of the 5 representative shapes below renders in all 3 modes side-by-side.

Evidence sites (7 total, 5 shapes)
listings/AestheticAdvisor.tsx
“Consider adding” AI suggestion (icon + badges)
listings/attribute-verification.tsx
“AI has some questions” clarifying list
board/SeekingDetailSheet.tsx (×2)
Seeker info row + “Potential match” banner
trade/NLProposalInput.tsx
Multi-party trade hint (icon + one-liner)
trade/TradeExtensionSearch.tsx
Credit cost hint (subtle, explicit dark mode)
common/StockPhotoWarning.tsx (banner)
Inline warning strip (icon + strong + muted)

Shape 1 — 'Consider adding' (AI suggestion)

Emphasized tint (10% bg / 20% border). Icon + strong title + badge row. Stacked layout. Anchors Option B's slot API strongly.

Today (raw div)
drift — 7 sites
Consider adding
front
back
scale ref
close-up
Option A — <Card intent="secondary">
extend card · 8 intents
Consider adding
front
back
scale ref
close-up
Option B — <SecondaryPanel>
named pattern · slots
Consider adding
front
back
scale ref
close-up

Shape 2 — 'AI has some questions' (clarifying list)

Subtle tint (5% bg / 20% border). Icon-start + strong title + bulleted list. Also fits Option B's slot API cleanly.

Today (raw div)
drift — 7 sites

AI has some questions:

  • What brand is the camera?
  • Is the shutter functional?
  • Do you have the original case?
Option A — <Card intent="secondary">
extend card · 8 intents
AI has some questions:
  • What brand is the camera?
  • Is the shutter functional?
  • Do you have the original case?
Option B — <SecondaryPanel>
named pattern · slots
AI has some questions:
  • What brand is the camera?
  • Is the shutter functional?
  • Do you have the original case?

Shape 3 — 'Potential match found!' (emphasized banner)

Emphasized tint. Icon + strong title + caption stack. Covers both SeekingDetailSheet sites' emphasized-tint usage.

Today (raw div)
drift — 7 sites
Potential match found!

Check your posts to see if you have what they want.

Option A — <Card intent="secondary">
extend card · 8 intents
Potential match found!

Check your posts to see if you have what they want.

Option B — <SecondaryPanel>
named pattern · slots
Potential match found!

Check your posts to see if you have what they want.

Shape 4 — Seeker info row (avatar + name + cta)

Subtle tint. Avatar + identity + trailing button — NOT an icon+title shape. This is the hardest case for Option B: the slot grammar collapses. Option A treats it as a plain Card container.

Today (raw div)
drift — 7 sites
M
@maya

Wants this item

Option A — <Card intent="secondary">
extend card · 8 intents
M
@maya

Wants this item

Option B — <SecondaryPanel>
named pattern · slots
M
@maya

Wants this item

Shape 5 — Inline warning banner (px-3 py-2)

Emphasized tint. Compact horizontal row with icon + strong + muted copy. Padding is tighter than Card's cozy/compact densities — Option A needs a className override here; Option B could ship a dedicated 'banner' density.

Today (raw div)
drift — 7 sites
Stock photo detected. This image may not be the actual item. Ask for real photos.
Option A — <Card intent="secondary">
extend card · 8 intents
Stock photo detected. This image may not be the actual item. Ask for real photos.
Option B — <SecondaryPanel>
named pattern · slots
Stock photo detected. This image may not be the actual item. Ask for real photos.

Shape 6 — Multi-party trade hint (icon + caption, no title)

Emphasized tint. Icon + single caption line, no strong title. Option B handles this with the title slot omitted.

Today (raw div)
drift — 7 sites

This looks like a multi-party trade. Chain trading is available for complex swaps.

Option A — <Card intent="secondary">
extend card · 8 intents

This looks like a multi-party trade. Chain trading is available for complex swaps.

Option B — <SecondaryPanel>
named pattern · slots

This looks like a multi-party trade. Chain trading is available for complex swaps.

Decision

Per-criterion comparison, followed by a recommendation. Sign off on one option to proceed — the mocks above will be replaced by the real primitive code only after explicit approval.

Decision matrix

Eight criteria, per-row winner. Weight each criterion yourself — the “winner” column is one reading, not a verdict.

CriterionOption A — CardOption B — SecondaryPanelEdge
File count+0 files (extend existing Card)+1 file (components/patterns/secondary-panel.tsx)
Option A
API cohesionFollows existing pattern (accent/destructive/warning all work this way)Introduces parallel type (tone=subtle|emphasized vs softness=solid|soft)
Option A
Closed enum growthCardIntent: 7 → 8SecondaryPanelTone: 2 values, new enum surface
tie
Handles non-icon+title shapes (Shape 4 seeker row)Natural — Card is a container, consumer fills itAwkward — slot grammar collapses; icon/title become optional
Option A
Prevents future drift (raw bg-secondary-accent-*)Card's anti-slop variant lint covers itStronger: closed-enum slot API blocks freestyle content
Option B
Consumer compressionintent='secondary' softness='soft' → 2 propstone='subtle' icon={...} title='...' → 3-4 props (more declarative)
Option B
Padding flexibility (Shape 5 inline banner px-3 py-2)Needs density hack or className override (erodes closed API)Could ship with banner density tier
Option B
Material coverage (paper/cork/vintage)Inherits — any material × secondary intent worksWould need to duplicate Card material grammar or skip it
Option A

Recommendation: Option A — extend Card to 8 intents

Secondary-accent is a color, not a layer or material. Card already owns the intent-as-color-tint pattern for accent / destructive / warning / success / info. Adding secondaryfills the exact slot this family occupies. It reuses Card's existing softness / material / density grammar and inheritsintentTintStyle() + INT_CLASS_SOFT/SOLID without duplicating them.

Option B wins two criteria — drift prevention strength and consumer compression — but pays for both by duplicating Card's material + softness work and falling apart on Shape 4 (avatar+name+cta row has no icon/title slot to fill). Those two Option B wins collapse if we ship strict lint for bg-secondary-accent-* alongside Option A, which is already cheap to add.

Proposed migration plan if Option A is chosen: (1) add secondary to CardIntent in card.tsx; (2) update intentTintStyle to route the --secondary-accent token; (3) migrate all 7 sites to <Card intent="secondary">; (4) add an ESLint rule blocking raw bg-secondary-accent-* / border-secondary-accent-* panel classes outside card.tsx + lib/brand.ts.