name: AB Mobile Design System
description: Dark-first, media-forward voting interface for the AB Expo app.
colors:
dark-bg: "#0d0e10"
dark-bg-deep: "#020409"
dark-surface: "#15171a"
dark-surface-raised: "#1a1d23"
dark-surface-alt: "#111113"
dark-text-primary: "#ffffff"
dark-text-secondary: "#c5ccd8"
dark-text-muted: "#9aa3b2"
dark-border: "rgba(255,255,255,0.12)"
dark-border-strong: "rgba(255,255,255,0.18)"
light-bg: "#f5f7fb"
light-bg-deep: "#eaecf2"
light-surface: "#ffffff"
light-surface-raised: "#eef1f6"
light-surface-alt: "#f1f3f6"
light-text-primary: "#101012"
light-text-secondary: "#475467"
light-text-muted: "#7c8595"
light-border: "rgba(0,0,0,0.10)"
light-border-strong: "rgba(0,0,0,0.16)"
accent: "#d7ff42"
on-accent: "#0d0e10"
on-accent-alt: "#111113"
danger: "#e11d48"
danger-text-dark: "#ff6b6b"
danger-text-light: "#d11f43"
stage: "#0d0e10"
stage-surface-a: "#101012"
stage-surface-b: "#171719"
stage-surface-c: "#111113"
stage-text: "#ffffff"
typography:
body: { fontFamily: "system React Native font", fontSize: 16px, fontWeight: 400, lineHeight: 1.4, letterSpacing: 0 }
label: { fontFamily: "system React Native font", fontSize: 13px, fontWeight: 700, lineHeight: 1.25, letterSpacing: 0 }
voteLabel: { fontFamily: "system React Native font", fontSize: 23px, fontWeight: 800, lineHeight: 1.1, letterSpacing: 0 }
control: { fontFamily: "system React Native font", fontSize: 15px, fontWeight: 700, lineHeight: 1.25, letterSpacing: 0 }
spacing:
xs: 4px
sm: 8px
md: 12px
lg: 16px
xl: 20px
xxl: 24px
rounded:
sm: 8px
md: 12px
lg: 16px
xl: 20px
full: 999px
components:
themeMode: { values: "system light dark", storageKey: "ab.themeMode", default: "dark" }
primaryButton: { minHeight: 48px, radius: 999px, background: "{colors.accent}", color: "{colors.on-accent}" }
secondaryButton: { minHeight: 44px, radius: 999px, border: "1px solid current palette border" }
choiceCard: { radius: 20px, border: "1px solid current palette border-strong", overflow: "hidden" }
stageSurface: { background: "{colors.stage}", color: "{colors.stage-text}" }
livePill: { radius: 999px, background: "{colors.accent}", color: "{colors.on-accent}" }
bottomTab: { minHeight: 50px, radius: 999px }Overview
AB Mobile is a React Native and Expo app for media-first A/B voting. The design is dark by default, with a persistent system, light, or dark theme mode exposed through a palette-driven theme provider. The visual system must support fast voting, creator upload flows, profiles, rankings, battle rooms, notifications, authentication, and settings without fragmenting into screen-specific colors.
The source of truth is src/theme/styles/palette.ts, src/theme/ThemeContext.tsx, and the makeStyles(palette) architecture exported from src/theme/styles.ts.
Colors
The dark palette is the default and should be treated as the primary product identity. It uses near-black backgrounds, layered dark surfaces, white primary text, cool gray secondary text, and a sharp lime accent.
The light palette keeps the same accent while replacing the base with pale blue-gray backgrounds and white surfaces. stage tokens stay dark in both themes so media voting stages remain visually consistent.
Use accent for primary actions, live/vote emphasis, active controls, and highly visible progress states. Use danger only for destructive or failed states. Avoid introducing additional feature colors unless they map to established ranking, notification, or media status semantics.
Typography
Typography relies on the native React Native system font. Keep screen titles, vote labels, and card labels bold and compact. The voteLabel token captures the larger, high-contrast labels used by choice cards and voting moments.
Body and helper text should use textSecondary or textMuted to keep attention on media and primary actions. Do not use reduced contrast on critical voting, upload, or authentication affordances.
Layout
Screens are mobile-first and should respect safe areas. Primary flows should place the dominant media or voting choice above controls, with actions anchored near the reachable lower area when possible.
The palette-driven styles include launch, home status, authentication, demographic setup, choice, report, creator reward, battle list, battle compose, battle room, create, profile, ranking, public profile, settings, tabs, and notification surfaces. New screens should be added through the same makeStyles(palette) path so dark, light, and system modes stay in sync.
Elevation & Depth
Depth is created with dark surface layering, borders, overlays, and media contrast. Use surfaceRaised for controls that need to sit above the base screen. Use overlaySubtle and overlayWash for image overlays, pressed states, and modal separation.
Avoid web-like shadows as the default depth language. On mobile, the app should feel like a native stage around media, not like a stack of floating desktop cards.
Shapes
Use 999px radii for primary pills, segmented controls, bottom tabs, and live badges. Use 20px or similar larger radii for media choice cards and profile hero surfaces. Use 8px to 12px for compact settings rows, chips, and secondary controls.
When displaying media, keep clipping intentional and avoid mismatched radii between image containers, labels, and overlay controls.
Components
Theme state is provided by ThemeProvider; components should consume useThemedStyles() and useThemeMode() rather than importing palette constants directly for screen styling.
Primary buttons use accent fill and dark text. Secondary buttons use transparent or surface backgrounds with palette borders. Choice cards need strong media hierarchy, clear A/B labels, and unmistakable selected or live states. Bottom tabs use compact icons and labels with pill-like active states.
Authentication and settings screens should make theme selection explicit through the existing system, light, and dark modes. Creator, report, and battle flows should keep error, consent, and upload states plain and readable.
Do's and Don'ts
Do default new screens to the dark-first palette and verify light mode through the same style factory.
Do reserve lime for decisive product actions and active live states.
Do keep media edges, labels, and voting controls visually locked together.
Don't hardcode colors inside screen components when a palette token exists.
Don't use decorative gradients or large web-style cards that compete with voting media.
Don't bury destructive, reporting, or authentication state under muted text.