Design Tokens¶
The shared vocabulary between design (Figma), web (Next.js/CSS variables), and mobile (Flutter ThemeExtension). Tokens are the single source of truth: no raw hex values, pixel sizes, or durations in component code.
Status: extracted from the Figma — 2026-08-26
The colour values below are measured from the Yam3at Figma file (FANCPIgWZwUJNuM0QPCplp, last modified 2026-07-11), not proposed. They supersede the earlier deep-purple proposal, which predated the yellow brand identity and was never adopted by either app.
Two deliberate deviations from the Figma, both documented inline: the type scale is normalised (the Figma's traced screens carry 6–10px Arabic text, well below a legible floor) and radii are rounded to a scale (the Figma carries scaling artefacts such as 14.23888874 and 31.54999923). Everything else — hues, tints, layout intent — is taken as measured.
Naming convention¶
--{category}-{concept}-{variant} in kebab-case. The same names map 1:1 to Flutter (YamTokens.colorPrimary500) and to the Tailwind theme config. Semantic tokens (e.g. --color-text-primary) reference primitive tokens (e.g. --color-neutral-900) — components consume semantic tokens wherever one exists, so dark mode is a semantic remap, not a component rewrite.
1. Color¶
Values marked (Figma) were read directly out of the design file. Values marked (derived) are tints/shades computed to complete the ramp — the Figma has no published styles or variables, so only the hues it actually paints with exist as ground truth.
Primitive palette¶
Primary — Yam3at Yellow. The signature brand colour: CTA fills, active nav, accent icons.
| Token | Hex | Source & notes |
|---|---|---|
--color-primary-50 |
#FFFBEB |
derived — tint washes, selected rows |
--color-primary-100 |
#FFF3CC |
derived — chips, hover washes |
--color-primary-200 |
#FEE79A |
derived — borders on tinted surfaces |
--color-primary-300 |
#FEDA68 |
derived — decorative |
--color-primary-400 |
#FECC2D |
(Figma) — the brand yellow; primary CTA fill, active tab label, accent glyphs |
--color-primary-500 |
#FEC40D |
(Figma) — pressed / strong CTA fill |
--color-primary-600 |
#FBBF0D |
(Figma) — CTA border / stroke |
--color-primary-700 |
#D9A200 |
derived — hover on light grounds |
--color-primary-800 |
#8A6800 |
derived — text on yellow tints (AA on primary-100) |
--color-primary-900 |
#362A0E |
(Figma) — ink used on yellow fills (login CTA label) |
Yellow is never a text colour on white
#FECC2D on white is ~1.6:1 — far below AA. It is a fill, always paired with primary-900/neutral-900 ink on top. The one Figma screen that puts yellow on white (الرئيسية, the active nav label at 8px) fails contrast twice over and is corrected in the build.
Neutrals. Read off the Figma's greys; they are true neutrals, not the warm sand family the mobile app drifted into.
| Token | Hex | Source & notes |
|---|---|---|
--color-neutral-0 |
#FFFFFF |
(Figma) — every screen ground is white |
--color-neutral-50 |
#FDFDFD |
(Figma) — raised cards, the floating bottom nav |
--color-neutral-100 |
#F7F6F1 |
app background (kept from the shipped apps; Figma paints screens flat white) |
--color-neutral-200 |
#EAEAEA |
(Figma) — dividers, input borders |
--color-neutral-400 |
#B1B2BB |
(Figma) — placeholder text |
--color-neutral-500 |
#7C7E87 |
(Figma) — tertiary text, chip labels |
--color-neutral-600 |
#646465 |
(Figma) — secondary text (the most-used grey in the file) |
--color-neutral-800 |
#464546 |
(Figma) — primary text alt |
--color-neutral-900 |
#000000 |
(Figma) — primary text, headings |
Category tints. Measured off the home-screen category cards (screen 7). These replace the ad-hoc pastels each app invented.
| Domain | Hex | Figma label |
|---|---|---|
--color-cat-home |
#E8F0E1 |
المنزل |
--color-cat-events |
#ECE6F1 |
المناسبات |
--color-cat-cars |
#E5E9EE |
السيارات |
--color-cat-beauty |
#F7E8E6 |
الجمال |
--color-cat-business |
#FCEFD6 |
الأعمال |
Status colors¶
The Figma defines no status colours — it has no error, empty, or validation states at all. These are retained from the shipped apps, which already use them consistently across both platforms:
| Token | Fg / Bg | Used for |
|---|---|---|
--color-success-600 / --color-success-bg |
#2F8659 / #E7F2EB |
Confirmed, Completed, payment success |
--color-warning-600 / --color-warning-bg |
#B7791F / #FDF3D7 |
Pending, Negotiating, expiring soon |
--color-error-600 / --color-error-bg |
#DC2626 / #F3E7E3 |
Rejected, Cancelled, failed payment, validation |
--color-info-600 / --color-info-bg |
#2C6DB0 / #E7F0F8 |
Draft, informational banners, Quoted |
Semantic tokens (light / dark)¶
| Token | Light | Dark |
|---|---|---|
--color-bg-page |
neutral-100 |
#141414 |
--color-bg-surface |
neutral-0 |
#1E1E1E |
--color-bg-surface-raised |
neutral-50 |
#272727 |
--color-text-primary |
neutral-900 |
#F5F5F5 |
--color-text-secondary |
neutral-600 |
#A8A8AB |
--color-text-on-primary |
primary-900 (#362A0E) |
primary-900 |
--color-action-primary |
primary-400 |
primary-400 |
--color-action-primary-hover |
primary-500 |
primary-300 |
--color-border |
neutral-200 |
#333333 |
--color-focus-ring |
neutral-900 |
primary-400 |
The Figma has no dark-mode screens; the dark column is a semantic remap, not a measured design. Yellow holds its hue on dark grounds (it already carries dark ink on top), so action-primary is unchanged across themes.
2. Typography¶
Families — what both apps actually ship today (see Arabic-First & RTL for pairing rationale):
--font-family-arabic: "Tajawal"; /* body + UI, both platforms */
--font-family-latin: "Tajawal"; /* Latin fragments fall through */
--font-family-display-arabic: "Reem Kufi"; /* headings, marketing/hero */
Both are Google Fonts — web loads Tajawal via next/font, mobile via the google_fonts package. The Figma itself is set in FF Shamel Family, a commercial Monotype face that is not licensed here; see §9. An earlier draft of this document specified IBM Plex Sans Arabic and Noto Kufi Arabic — neither was ever adopted by either app.
Type scale (rem, base 16 px). lh-ar applies when lang="ar":
| Token | Size | Weight | lh (en) | lh (ar) | Use |
|---|---|---|---|---|---|
--text-display |
2.25rem / 36px | 700 | 1.2 | 1.4 | Hero, marketing |
--text-h1 |
1.75rem / 28px | 700 | 1.25 | 1.45 | Screen titles |
--text-h2 |
1.375rem / 22px | 600 | 1.3 | 1.5 | Section headers |
--text-h3 |
1.125rem / 18px | 600 | 1.4 | 1.6 | Card titles |
--text-body-lg |
1rem / 16px | 400 | 1.5 | 1.75 | Primary body |
--text-body |
0.9375rem / 15px | 400 | 1.5 | 1.75 | Default body (15px floor protects Arabic legibility) |
--text-caption |
0.8125rem / 13px | 400 | 1.4 | 1.6 | Timestamps, helper text |
--text-overline |
0.75rem / 12px | 600 | 1.3 | 1.5 | Eyebrows (EN: +0.06em tracking; AR: tracking 0, weight only) |
Weights: --font-weight-regular: 400, --font-weight-medium: 500, --font-weight-semibold: 600, --font-weight-bold: 700. No italics token — Arabic has none; emphasis is weight/color.
3. Spacing (4pt scale)¶
| Token | Value | Typical use |
|---|---|---|
--space-1 |
4px | Icon-to-label gaps |
--space-2 |
8px | Inside chips, tight stacks |
--space-3 |
12px | Card internal padding (compact) |
--space-4 |
16px | Default screen gutter (mobile), card padding |
--space-5 |
20px | Between form fields |
--space-6 |
24px | Section spacing |
--space-8 |
32px | Between major blocks |
--space-10 |
40px | Page-level separation (web) |
--space-12 |
48px | Hero padding |
--space-16 |
64px | Marketing sections |
Rule: only these steps. Always applied via logical properties (padding-inline-*) so RTL is automatic.
4. Radii¶
Rounded to a scale from the Figma's measured values (which carry scaling artefacts — 11.6499996, 14.2388887, 16.1805553, 20.7111110, 31.5499992). The intent behind them is a 14px default with fully-pill CTAs.
| Token | Value | Use | Figma evidence |
|---|---|---|---|
--radius-sm |
6px | Rating badges, tags | 5.99, 6.31 on the rating pills |
--radius-md |
10px | Category cards, small tiles | 10.36, 11.65 on the domain cards |
--radius-lg |
14px | Default — inputs, cards, chips, sheets | 13.55, 14.19, 14.24, 14.89 — by far the most common |
--radius-xl |
20px | Floating bottom nav, hero cards | 20.71 on the home nav bar |
--radius-full |
9999px | Primary CTAs, avatars, pills | 27.0, 31.55 on 59px/51px-tall buttons = fully round |
5. Elevation¶
The Figma uses no drop shadows at all — depth comes from a near-white raised fill (neutral-50 #FDFDFD) against the page ground. The ramp below is retained for the web admin/vendor consoles, which need real elevation for dropdowns and modals; it is re-tinted neutral (the old values were purple-tinted, from the abandoned proposal).
| Token | Value | Use |
|---|---|---|
--elevation-0 |
none | Default — cards, nav, tiles (matches the Figma) |
--elevation-1 |
0 1px 3px rgba(0,0,0,.06) |
Cards at rest (web consoles) |
--elevation-2 |
0 4px 12px rgba(0,0,0,.08) |
Dropdowns, sticky CTA bars |
--elevation-3 |
0 8px 24px rgba(0,0,0,.12) |
Modals, bottom sheets |
--elevation-4 |
0 16px 48px rgba(0,0,0,.16) |
Dialogs above modals (rare) |
Dark mode replaces shadows with surface-lightening (bg-surface → bg-surface-raised) plus a 20%-opacity shadow.
6. Motion¶
| Token | Value | Use |
|---|---|---|
--duration-instant |
80ms | Hover/pressed feedback |
--duration-fast |
150ms | Toggles, chips, checkbox |
--duration-base |
240ms | Sheets, dropdowns, screen transitions |
--duration-slow |
400ms | Full-screen modals, celebration entrances |
--easing-standard |
cubic-bezier(0.2, 0, 0, 1) |
Default for everything |
--easing-decelerate |
cubic-bezier(0, 0, 0, 1) |
Elements entering the screen |
--easing-accelerate |
cubic-bezier(0.3, 0, 1, 1) |
Elements leaving the screen |
Directional motion (slides, wizard step transitions) mirrors in RTL: "forward" slides leftward in Arabic. All motion collapses to opacity-only under prefers-reduced-motion. Celebration moments (payment success, booking confirmed) may use up to 800ms one-shot animation — the only exception to --duration-slow.
7. Breakpoints & layout¶
| Token | Value | Meaning |
|---|---|---|
--breakpoint-sm |
640px | Large phones landscape / small tablet |
--breakpoint-md |
768px | Tablet portrait — 2-column layouts begin |
--breakpoint-lg |
1024px | Desktop — persistent side nav (vendor/admin) |
--breakpoint-xl |
1280px | Wide desktop — max content width applies |
--layout-max-width |
1200px | Customer web content column |
--layout-max-width-admin |
1440px | Admin tables need width |
Design baseline: 360×800 (mobile-first, per Design Principles).
8. Z-index & misc¶
--z-sticky: 100 (sticky CTA bars) · --z-dropdown: 400 · --z-overlay: 800 (sheet/modal scrim) · --z-modal: 900 · --z-toast: 1000.
Touch target minimum: --size-touch-target: 48px. Focus ring: --focus-ring: 2px solid var(--color-focus-ring); outline-offset: 2px — never removed, only restyled.
9. The Figma source¶
File: FANCPIgWZwUJNuM0QPCplp ("Yam3at"), last modified 2026-07-11. One page, 17 iPhone 14/15 Pro Max frames (430×932).
Reference PNGs are exported at 2× into docs/ux/figma/ as screen-01.png … screen-17.png, named by frame name, which is not the same as the file's visual left-to-right order.
What the file does and does not contain:
| Components / component sets | 0 |
| Published colour or text styles | 0 |
| Variables | 0 |
| Fully layered frames | 6 — frames 2, 3, 4, 5 (login), 6 (OTP), 7 (home) |
| Flattened single-image frames | 11 — frames 1, 8–17 |
Frames 8–17 (service detail, booking, payment, confirmation, tracking, review, bookings, messages, account, AI assistant) are rendered images with zero text layers. They can be looked at and matched by eye, but nothing can be measured out of them — every spec for those screens is an interpretation, not an extraction.
Typography in the file is FF Shamel Family (66 of 73 text layers) with Inter for Latin numerals. FF Shamel is a commercial Monotype face and is not licensed for the apps; both platforms ship Tajawal (body/UI) and Reem Kufi (display) from Google Fonts instead. This is a deliberate, permanent substitution — the token names below are what components consume, so a future licence purchase is a one-line change.
Platform delivery¶
There is no tokens.json pipeline and no design-system repo — this document is the source of truth, and each platform hand-maintains its own mirror of it:
| Platform | File | Mechanism |
|---|---|---|
| Source of truth | docs/ux/design-tokens.md (this file) |
Values measured from the Figma |
| Web | apps/web/src/app/globals.css |
CSS custom properties in @theme; Tailwind 4 reads them directly |
| Mobile | apps/mobile/lib/core/theme.dart |
Dart const Color primitives + yam3atTheme() |
| Email templates | inline hex | Hand-synced at template-edit time |
Because the mirrors are hand-maintained, any colour change here must be applied to both platform files in the same commit. A Style Dictionary pipeline is worth building only if a third surface appears.
Related: Design Principles · Arabic-First & RTL · Key Screens