Clean successor to V3 (forge: lilith/atlilith). Seeded from local Mac working tree at ~/Code/@projects/@cocottetech/. node_modules and build artifacts excluded via .gitignore. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
8.9 KiB
F — Visual system (tokens + components)
Goal
Establish the design language that every surface (iOS, iPad, macOS, web) inherits. Tokens-first so a renamed brand or palette tweak doesn't ripple through every screen.
Designer skim
- Headline UX: Tokens-first design language. SwiftUI-native primitives where possible (system fonts, SF Symbols, system materials). WCAG AA contrast min. Light + dark from day one.
- Sections (7): F1 color · F2 typography · F3 spacing+radius · F4 motion+haptics · F5 24-surface iconography (a–g sub-blocks: N1 content / N2 directories / N3 brand sites / N4 channels / N5 commerce / fallback / geometry-coded distinction) · F6 empty-loading-error · F7 component library.
- Foundation: lives in
00-system/alongside voice. Every brief inherits from here. - Blocking Qs: OPEN-DECISIONS.md → VS-Q1 stakes-high-vs-destructive-red collision.
Constraints
- Inherit
lilith-messenger-ios/LilithMessenger/Design/{Theme,Typography}.swiftas the starting point, then specialize for CocotteAI's identity. - SwiftUI-native primitives where possible (system fonts, SF Symbols, system materials).
- WCAG AA contrast minimum in light AND dark.
Token layers (ordered from primitive to composite)
F1 — Color tokens
- Primitives: a 12-step neutral ramp (light + dark), a 12-step accent ramp, semantic colors.
- Accent proposal: warm rose — Quinn's talent-tier accent. Designer to validate against the Cocotte umbrella brand palette before locking. (Cocotte is the customer-facing brand; Demimonde is back-office and has no customer-facing palette.)
- Semantic stakes colors: low = neutral-500 (gray), medium = amber-500, high = rose-600. Must work as text + as background + as dot/chip in both modes.
- Background materials: app background, sheet background, card surface, elevated card.
F2 — Typography
- Display, Title, Headline, Body, Body-emphasized, Caption, Footnote.
- All scales use SF Pro Display + SF Pro Text.
- Dynamic Type support (iOS accessibility).
F3 — Spacing + radius
- 4pt base grid; spacing scale {2, 4, 8, 12, 16, 24, 32, 48}.
- Radius scale {4 (chips), 12 (cards), 20 (sheets), full (avatars)}.
F4 — Motion + haptics
- Approval swipe: 200ms easeOut animation, light haptic on threshold crossing, success haptic on commit.
- Streaming reply tokens: stagger 16ms, fade-in 100ms.
- Sheet present: native iOS sheet timing; do not override.
- High-stakes notification arrival: notification haptic + display haptic.
F5 — Surface iconography
Per-surface visual marks for the canonical 24-surface roster in brief O. Goal: at chip size (16pt) Quinn recognizes the surface in <200ms without reading text. Where a brand mark is unrecognizable at chip size, fall back to a 2-letter monogram on a category-tinted square.
Geometry rules (all marks):
- Circular bounding box, 16pt (chip) / 20pt (card) / 24pt (drawer header).
- 1pt stroke on the bounding ring in light mode; 0pt in dark (relies on chip background).
- Always paired with
SurfaceChip(F7) — never rendered standalone without a display name nearby on first introduction.
F5a — N1 content surfaces (brand-mark; recognizable)
| ID | Mark | Light color | Dark color | Notes |
|---|---|---|---|---|
onlyfans |
OF wordmark in circle | #00AFF0 (OF blue) |
same | Recognizable. |
x |
X glyph | #000 |
#FFF |
Mono. |
instagram |
gradient ring + camera | brand gradient | brand gradient | Don't reduce to mono — recognition collapses. |
tiktok |
musical-note glyph | #000 |
#FFF w/ cyan/red shadow |
Mono with brand accent. |
threads |
@ mark | #000 |
#FFF |
Cheap to render; cross-post sibling of x. |
bluesky |
butterfly | #1185FE |
same | New 2026. |
reddit |
snoo silhouette | #FF4500 |
same | High recognition. |
fansly |
"F" monogram | #0F8 (fansly green) |
same | OF alternative; lower brand recognition — accept word-mark fallback at 16pt. |
youtube |
play-triangle | #FF0000 |
same | SFW only. |
twitch |
speech-bubble glyph | #9146FF |
same | SFW only. |
facebook |
"f" wordmark | #1877F2 |
mono in dark | Defensive listing; rarely shown. |
F5b — N2 escort directories (12 surfaces — most have weak brand recognition)
Default for this category: 2-letter monogram on category-tinted square (radius 4pt, neutral-700 background in light, neutral-200 in dark; foreground = accent-rose for "live" directories, neutral-400 for "pending/blocked"). Reserve brand-mark rendering for the two anchor directories.
| ID | Mark | Strategy |
|---|---|---|
tryst |
"T" in rose square + verified-checkmark glyph | Anchor; gets a distinct mark. |
ts4rent |
"T4" monogram | Anchor; distinct. |
seeking |
"S" monogram | Sugar-dating context — give it its own neutral-blue tint to separate from N2 escort directories visually (per brief O open question). |
privatedelights |
"PD" monogram | Pending verification — render in pending-gray. |
tsescorts |
"TS" monogram | |
adultsearch |
"AS" monogram | |
adultlook |
"AL" monogram | |
eros |
"ER" monogram | Blocked-on-legal-name-change state — render at reduced opacity 0.5 + lock glyph overlay. |
eroticmonkey |
"EM" monogram | |
skipthegames |
"SKG" trigraph (exception: 3 chars allowed when "STG" reads worse) | |
megapersonals |
"MP" monogram | |
ts.live |
"ts" lowercase monogram + .live superscript |
Distinguish from tsescorts and ts4rent — three "ts" prefixes in the roster. |
Status-state overlays (apply on top of any N2 mark):
- Live → no overlay.
- Pending verification → 0.7 opacity + amber dot top-right.
- Blocked / suspended → 0.5 opacity + lock glyph.
- Not started → 0.4 opacity + dashed bounding ring.
F5c — N3 brand sites (Quinn-owned)
Quinn-owned brand sites get a distinct shape (rounded square, not circle) to telegraph "this is ours, not external." Foreground = brand-rose; background = neutral-100/900.
| ID | Mark |
|---|---|
transquinnftw.com |
tqftw monogram |
adult-therapy-tours.com |
"ATT" trigraph |
futa-waifu-tour |
"FWT" trigraph |
F5d — N4 channels (messaging, not posting)
Channels are NOT surface_kind (per brief O); they render with a different component (ChannelChip, sibling to SurfaceChip) that uses rounded-square geometry to visually separate "channel-of-arrival" from "surface-of-origin" — critical for the unified inbox in brief P.
| ID | Mark | Notes |
|---|---|---|
imessage |
SMS bubble glyph (iOS) | System SF Symbol message.fill. |
signal |
Signal logo | Encrypted-channel marker. |
telegram |
paper-plane | |
discord |
discord-mark | |
email |
envelope SF Symbol | Plus per-mailbox tint when from multiple Proton accounts (see brief P). |
sniffies |
"Sn" monogram | Light surface. |
F5e — N5 commerce (P5+, enumerated only)
Commerce providers render as monogram tiles in green tint when Quinn surfaces them; otherwise hidden. Enumerated for completeness; no P0 design effort.
F5f — Fallback for unknown / new surfaces
When a surface_kind value arrives that the iconography registry doesn't know (forward-compat with brief O additions), render: neutral-tinted circle + first 2 alphanumeric chars of the ID (uppercase). Never break the layout; never throw.
F5g — Surface-vs-channel visual distinction (summary)
| Geometry | Used for | Examples |
|---|---|---|
| Circle | N1 content + N2 directories (posting/listing surfaces) | OF, Tryst |
| Rounded-square (Quinn-owned tint) | N3 brand sites | tqftw.com |
| Rounded-square (channel tint) | N4 channels | iMessage, email |
| Monogram tile (green) | N5 commerce | Venmo |
This geometry-coded distinction lets Quinn see at a glance whether a card is about a place she posts vs about a place she receives vs about a place she gets paid — without reading.
F6 — Empty / loading / error states
- Standard empty illustration set (one icon family, branded).
- Loading: thin determinate progress when measurable, skeleton on lists, spinner only as last resort.
- Error: standard error card with retry affordance; never a system alert.
F7 — Component library
ApprovalCard(all variants from brief A)StakesBadge,ConfidenceBarSurfaceChip(uses F5 iconography)SpecialistMention(inline tappable text)Drawer(sheet wrapper, brief B)VoiceMicButton(push-to-talk + long-press hands-free)PersonaFacetEditor(chip + free-text inputs for facet JSON)
Out of scope
- 3D / @chobit avatar visuals (P5+).
- Marketing site visuals (cocottetech.com is a different brief).
Open questions
- Should stakes-high red overlap with destructive-action red (reject swipe color)? Argue against — semantic collision.
- Custom font, or stay system? System wins on Dynamic Type + accessibility for free.
- Iconography for V3 specialists themselves (a per-specialist mark) — needed P0 or P1?