Skip to content

Spacing & Elevation

How we use space (between elements) and depth (between layers). Both compose into the "tonal layering" approach that defines Tomoda's UI.

Spacing scale

A 4-pixel base with named steps. Stick to the scale — half-steps and arbitrary pixels make the system feel sloppy.

xs — 4px
sm — 8px
md — 12px
lg — 16px
xl — 24px
2xl — 32px
3xl — 48px

When to use which

Step Use
xs (4) Icon-to-text gap, inline label-value pairing
sm (8) Tight grouping — within a card, between list metadata
md (12) List item vertical separation
lg (16) Section padding inside a card
xl (24) Card internal padding, top-of-section margin
2xl (32) Between major content blocks
3xl (48) Hero / display surfaces, generous landing spacing

Avoid lg for card internal padding when content is rich — xl or 2xl lets the content breathe and reinforces the "curator's frame" feel.

Border radius

Three corner sizes. Use one consistently per surface tier.

Token Value Use
sm 6px Chips, pills, tight controls
md 10px Buttons, inputs, small cards
lg 16px Cards, modals, sheets
xl 24px Large hero surfaces, full-bleed cards

Don't mix md and lg for elements at the same hierarchy level — the inconsistency reads as accidental.

Surface ladder (depth without shadow)

The core insight: depth comes from stepping the surface ladder, not from shadows. Place a higher-tier surface on top of a lower-tier one and the eye sees real depth.

The four tiers

Tier Dark hex Light hex Use
background #0e0e0f #FFFFFF App root, scroll background
surface #18181a #FFFFFF Cards on top of background
surfaceContainerLow #1c1c1f #F4F4F5 Grouping containers, list backgrounds
surfaceContainerHigh #252528 #E4E4E7 Interactive layers, inputs
surfaceContainerHighest #2e2e32 #D4D4D8 Popovers, focused inputs, hover states

Composition rules

  1. One step up at a time. Don't jump from background straight to surfaceContainerHighest — the contrast looks broken. Step gradually.
  2. Nest to imply depth. A surface card containing a surfaceContainerLow section reads as "carved" — depth without a shadow.
  3. Reverse the ladder in light mode. In light mode the same semantic tokens still mean "deeper" — they just step down in luminance rather than up. The component code never branches on mode.

Shadows (used sparingly)

Reserved for elements that genuinely float. The surface ladder handles all in-context depth.

Token Value Use
shadow-modal 0px 24px 48px rgba(0, 0, 0, 0.35) Modals, fullscreen sheets
shadow-floating 0px 12px 24px rgba(0, 0, 0, 0.25) Dropdowns, popovers
shadow-elevated 0px 4px 12px rgba(0, 0, 0, 0.20) Sticky bottom bars, FABs

Shadow rules

  • Never pure black. Shadow opacity tops out at 0.4 to keep the warm-charcoal feel.
  • Diffused, not crisp. Large blur radius, no spread. Shadows should feel like ambient occlusion, not hard cutouts.
  • No top shadow. Light always falls from above; shadow always falls below. Top-shadows look like floating UFOs.
  • No shadow on a background surface. If the underlying surface is the app root, you don't need a shadow to imply depth — use the surface ladder.

Glassmorphism

A specific exception to the no-shadow rule: floating UI that should feel frosted rather than opaque.

  • Surface: surfaceContainerLow at 70% opacity
  • Backdrop filter: blur(24px)
  • Wrapped by the GlassView component which handles native (expo-blur) and web (backdrop-filter CSS) paths.

Use for floating navigation pills, contextual overlays on top of imagery, and the chat composer when it sits over content. Don't use as a default — every glass surface is a moment.

Ghost borders

When a border is absolutely required (focus state, error state, accessibility outline), use the border token, never solid:

  • Dark: rgba(255, 255, 255, 0.15)
  • Light: rgba(0, 0, 0, 0.10)

This is the only sanctioned use of a border in product UI. Solid #000 / #fff borders are forbidden — see the no-line rule.

Layout density

Two density modes appear in production:

  • Comfortable (default)xl padding on cards, lg/xl between list items. Used everywhere user-content lives (chat, event detail, profile).
  • Denselg padding, md between items. Used in admin tables, settings lists, anywhere the screen is configuration-heavy.

Don't introduce a third density. Comfortable defaults serve almost everything; dense covers the rest.