Design system

Tokens and components extracted from the Figma file "Inwallsept2025" (canvas "MVP Flows TO BE USED FOR MVP ONLY"), then renamed onto one consistent scale and re-typeset in Manrope. Source code: css/styles.css.

Token architecture

A raw value (hex, px) never appears directly in a component. It goes through a semantic token, itself built on a primitive token.

LayerRoleExample
PrimitiveFigma value, renamed onto a standard scale--brand-700: #551BCD;
SemanticAlias with meaning--color-accent: var(--brand-700);
ComponentSpecific use in one component--button-primary-bg: var(--gradient-cta);

Naming contract

Figma's own keys were sparse and inconsistent per color family — brand went 300 / 400 / 500 then an unnumbered "enabled," then "800"; warning only had 200 and 600; success only 200 and 600. Every family below has been renumbered onto one shared scale, so a token's role is predictable from its number alone without opening the color to check — the same contract Tailwind and Material use.

StepRoleRule
-100Lightest tintBackgrounds and tint fills only, never text
-300 / -400Light / midDecorative, large fills, never small text
-500BaseDefault interactive state — links, mid-emphasis icons
-700StrongAlways safe as text/icon on white (≥4.5:1, verified per color below)
-900DarkestInverted surfaces (dark panels, tab bar), max-emphasis text
Figma nameRenamed to
brand InWall/300--brand-300 (unchanged)
brand InWall/400--brand-400 (unchanged)
brand InWall/500 / Link-Active--brand-500 (unchanged)
interactive-primary-brand/enabled--brand-700
brand InWall/800 / Surface-Inverted--brand-900
success/200--success-100
success/600--success-700
warning/200--warning-100
Text-Thirdary (Figma's own typo)--text-tertiary

Colors

One brand hue — a violet-purple — carries the entire app, advertiser and Inwaller screens alike. Depth is what varies (a light tint for secondary surfaces, the same brand purple for every primary action), not a second accent — the earlier provisional lime/indigo split didn't match the real file.

Brand InWall

brand-100#F3EBFE
brand-300#D8AFFA
brand-400#B179F4
brand-500 / Link-Active#803CF2
brand-700 (primary CTA)#551BCD
brand-900 / Surface-Inverted#220863

Gradients

The app icon's diagonal sweep is Inwall's most distinctive visual asset — the first pass of this page under-used it, applying it only to the logo mark. Two variants now exist, because one gradient isn't safe in every context text can sit on it:

Inwall
+
TokenStopsUse
--gradient-hero#9F68F8 → #530BC9, Figma's exact logo gradientIcon-only contexts: app icon, FAB, avatars — never under text (light end alone is 3.6:1, fails AA text)
--gradient-cta--brand-500 → --brand-700Primary button fill — both stops independently clear 4.5:1 with a white label, safe wherever it sits

Text

text-primary#1E2028
text-secondary#323442
text-tertiary (fixed)#5B5F7A

See accessibility for why text-tertiary was darkened from the raw Figma export (also renamed: Figma's own key was misspelled "Thirdary").

Surface

surface-secondary (app bg)#F2F7FF
surface-primary#FFFFFF
neutral-100 (tertiary fill)#EDEEF3

Feedback & data

Success, warning, critical, plus the three network colors used in the shares donut chart on the advertiser dashboard.

success-700#08711D
success-100#B9E9C3
warning-600 (fills/borders only)#D1870A
warning-700 (text/icon, fixed)#9A6208
warning-100#FBEFA4
critical-500 / Instagram#DB195A
Facebook#3568B8
Snapchat#EAAD00
Live Share unverified V1, out of MVP scope
Status "Live": green filled circle with a checkmark, next to the campaign status field on the Details tab.

Typography

One family across the app: Manrope, replacing the SF Pro Display pass this page shipped with earlier. Variable weight 200–800, one license, one look on iOS, Android, and the web — the cross-platform gap SF Pro had (Apple-only, no native Android equivalent) doesn't exist with Manrope, so it's used directly rather than paired with a fallback face.

Letter-spacing is expressed in em below, not the fixed px values Figma exports — an em value scales with font-size automatically, a px value has to be hand-picked at every step. Values are the corrected scale; see the type fixes table for what changed and why.

Display Huge
Manrope Bold, 40/44, −0.02em
$500
Display Small Bold
Manrope Bold, 20/26, +0.01em
Create an ad
Text Semibold
Manrope Semibold, 18/24, +0.01em
Your ad is now live
Text Large
Manrope Regular, 20/28, +0.01em
Ôde à la vie
Text Small
Manrope Regular, 15/19, +0.015em
Instagram username
Link Small
Manrope Bold, 15/24, +0.05em
See all
Text X-Small
Manrope Regular, 13/16, +0.02em
Followers

Spacing & radius

--space-1 (4px)
--space-2 (8px)
--space-3 (12px)
--space-4 (16px)
--space-5 (20px)
--space-6 (24px)
--space-8 (32px)
--space-9 (48px)

Radius reads very rounded throughout the file: list rows and input pills go almost fully round, not just soft corners.

TokenValueUsage
--radius-sm10pxSmall UI elements
--radius-md20pxCards, dashboard tiles
--radius-lg28pxLarge surfaces, sheet corners
--radius-pill999pxButtons, list rows, badges, tab bar, FAB

Buttons & inputs

Primary button now carries the brand gradient (--gradient-cta) instead of a flat fill — the first pass of this system flattened Inwall's most recognizable visual signature into a plain color. Stepper: circular +/− buttons in brand purple, used to set price-per-share per network, sized to the 44px touch-target minimum.

$5

Tags & badges

MVP Advertiser Future Risk Success

Loop steps

The four-step core loop component used on the specs page, colored by which side owns the step.

01

Fund & split

Set budget, price per network.

02

Scroll & share

Browse feed, share an ad.

Side cards

Advertiser

Campaign console

  • Set budget and price per share
Inwaller

Vertical feed

  • Share, get paid instantly

App chrome

Bottom tab bar: dark brand-900 fill, floating pill, rounded top corners on the screen itself. The FAB on the advertiser dashboard now carries --gradient-hero (icon-only, safe); the feed's own bottom-right button reuses the logomark instead of a generic icon.

+
ScreenRight chrome element
Advertiser dashboard (Full ad)Gradient circular "+" FAB — create a new ad
Feed (explore / infinite scroll)Circular button using the Inwall logomark — share this ad

Accessibility

Target: WCAG 2.1/2.2 level AA. Checked against the real Figma export values (computed contrast ratios, not visual guesses). Four issues found and fixed in the tokens above; three more verified as already passing.

Contrast fixes

TokenBeforeAfterWhy
--text-tertiaryFigma export #6B6F8C — 4.56:1 on --surface-secondary#5B5F7A — 5.81:1 on --surface-secondary, 6.25:1 on whiteUsed for secondary/placeholder text down to 13px ("Text X-Small"). At 4.56:1 it clears the 4.5:1 AA floor by less than a rounding error. Same exact color and same fix HugeOne's design system needed.
--color-warning (text/icon)#D1870A — 2.9:1 on white#9A6208 — 5.1:1 on whiteUsed as text color on .tag.risk and .note.open. 2.9:1 fails AA outright for text (needs 4.5:1). The original is kept as --color-warning-border for fills/borders, where the lower 3:1 non-text threshold applies and it already passes.
Verified passing, no change needed: --brand-700 #551BCD reaches 8.7:1 with white button labels — well past AA and close to AAA. --brand-500 #803CF2 (Figma's "Link-Active") reaches 5.5:1 as running text on white. --gradient-cta's two stops (500 and 700) both independently clear 4.5:1, so the gradient stays safe under a button label at every point along it — unlike --gradient-hero, whose light end (#9F68F8) drops to 3.6:1 and is restricted to icon-only use for exactly that reason.

Type scale fixes

Figma's line-heights and tracking were copied from the file as-is for the first pass of this page; on review, three headings ran looser than any mainstream mobile guideline (iOS HIG, Material) recommends, and the largest display size used positive tracking where large numerals read better tight. Tracking is now in em, not px, for the reason noted above the type scale.

StyleBeforeAfterWhy
Display Huge (money amounts)40/44, +0.5px tracking40/44, −0.02em trackingPositive tracking on a 40px numeral loosens exactly the figure the app most wants to read as solid and precise (a budget, a payout). Large display sizes read better with neutral-to-negative tracking; small text is where positive tracking earns its keep (see Link Small, X-Small below).
Display Small Bold20/32 (1.6 ratio)20/26 (1.3 ratio)1.6 is loose even for a multi-line paragraph, let alone a one-line screen title ("Create an ad"). 1.2–1.3 is standard for headings at this size.
Text Semibold18/28 (1.56 ratio)18/24 (1.33 ratio)Same over-loose pattern, used for short confirmation copy ("Your ad is now live") that doesn't need paragraph-level breathing room.
Text Large20/32 (1.6 ratio)20/28 (1.4 ratio)Used for a one-line ad title ("Ôde à la vie"); 1.4 is the standard upper bound for body-adjacent text, 1.6 is paragraph territory.

Typeface (cross-platform gap)

Figma specified SF Pro Display with no fallback — an Apple-only font that, on Android (half the target platforms per the specs), silently drops to the OS default and the two builds stop matching. Now replaced app-wide with Manrope: one variable face, licensed for iOS, Android (via Flutter's google_fonts package or a bundled asset), and the web, so the cross-platform gap doesn't need a fallback face to paper over it.

Touch targets

The budget screen's price-per-share steppers render at 32×32px in Figma — under the 44×44px minimum (WCAG 2.5.8 AA / Apple HIG), and the WCAG 2.2 floor of 24×24px doesn't leave much margin either for a control that adjusts a money amount. Fixed: .stepper-btn is now 44×44px (token --touch-target-min).

Open, not yet resolved

  • The feed's share button sits over a variable video/photo background — contrast needs checking against real creative, not a static mock, since the button has no solid background of its own in that context.
  • Spacing scale had a 32px → 56px jump (skipping 40/48) inconsistent with the otherwise steady 4px progression below it — closed to 32 → 48 in --space-9, but the scale hasn't been re-audited past that single fix.
  • Donut-chart legend colors (Facebook blue, Instagram pink, Snapchat yellow) haven't been checked for color-blind distinguishability — a shares-by-network chart that only differs by hue is a real risk for deuteranopia/protanopia; needs a pattern or label fallback, not color alone.

Usage notes

  • Extraction covers the 11 top-level frames on the "MVP Flows TO BE USED FOR MVP ONLY" canvas — inputs, modals, and empty states beyond what's shown on those screens still need documenting.
  • Manrope isn't embedded as a variable-font file on this web page (loaded from Google Fonts instead); the Flutter app should bundle it directly via google_fonts or a local asset rather than a network fetch.
  • Only one brand accent exists in the file (violet-purple) — resist introducing a second "advertiser accent," a second hue doesn't match the actual design.
  • --warning-600 and --warning-700 are not interchangeable: 600 for fills/borders/large icons (3:1 threshold), 700 for text and small icons (4.5:1 threshold). Reaching for 600 as a text color is exactly the bug this page fixed.
  • --gradient-hero and --gradient-cta are not interchangeable either: hero for icon-only surfaces, cta for anything with a text label on top. Reaching for hero under a button label reintroduces the 3.6:1 contrast failure cta was built to avoid.