Token reference
Token reference
Section titled “Token reference”Every token, its value and where it comes from. The rules for when to use
each one are in README.md. Code lives in
lib/presentation/theme/app_tokens.dart and app_text.dart, and
test/presentation/theme/app_tokens_test.dart pins every property below that
can be checked (contrast, ordering, scale).
Colour
Section titled “Colour”AppColors.* roles point at appTheme.* primitives in theme_helper.dart.
| Role | Primitive | Hex |
|---|---|---|
background |
black |
#000000 |
surface |
blueGray |
#18181B |
surfaceRaised |
popUp |
#27272A |
border |
stroke |
#3F3F46 |
textPrimary |
white |
#FFFFFF |
textSecondary |
gray300 |
#D4D4D8 |
textTertiary |
gray100 |
#A1A1AA |
textDisabled |
gray |
#7E7E83 |
accent |
primary |
#E11D48 |
onAccent |
white |
#FFFFFF |
accentText |
rose400 |
#FB7185 |
selection |
white |
#FFFFFF |
onSelection |
black |
#000000 |
danger |
errorBorder |
#EF4444 |
onDanger |
white |
#FFFFFF |
premium |
premium |
#F97316 |
award |
award |
#EAB308 |
pillIdle |
gray700 |
#2D2D32 |
pillSelected |
primary (= accent) |
#E11D48 |
Contrast (WCAG 2)
Section titled “Contrast (WCAG 2)”Text on each ground. AA is 4.5:1 for body text and 3:1 for large or bold text.
The glass column uses the glass tint colour (navBar #202023) opaque, which
is the lightest a glass surface gets over dark content.
| Text role | background | surface | surfaceRaised | glass |
|---|---|---|---|---|
textPrimary |
21.0 | 17.7 | 14.9 | 16.3 |
textSecondary |
14.2 | 12.0 | 10.1 | 11.0 |
textTertiary |
8.2 | 6.9 | 5.8 | 6.3 |
accentText |
7.8 | 6.6 | 5.5 | 6.0 |
textDisabled (exempt) |
5.2 | 4.4 | 3.7 | 4.0 |
| accent #E11D48 as text ✗ | 4.47 | 3.8 | 3.2 | 3.5 |
| legacy gray600 hint ✗ | 3.6 | 3.1 | 2.6 | 2.8 |
| Pair | Contrast |
|---|---|
onAccent on accent |
4.7 |
onSelection on selection |
21.0 |
onDanger on danger |
3.8 (bold labels only) |
Why textTertiary is #A1A1AA and accentText is #FB7185: the first
candidates (#7E7E83 and #F43F5E) passed on black but failed on raised
surfaces (3.7 and 4.1). The contrast test caught this before any screen
used them.
AppText.* uses Inter at fixed sizes, and textPrimary by default.
| Role | Size | Weight |
|---|---|---|
display |
24 | 700 |
titleLarge |
20 | 600 |
title |
18 | 600 |
section |
16 | 500 |
body |
14 | 400 |
label |
13 | 500 |
caption |
12 | 400 |
micro |
11 | 500 |
Legacy CustomTextStyles → role
Section titled “Legacy CustomTextStyles → role”Migrate a style by picking its role and changing the tone with copyWith(color:).
| Legacy style(s) | Size / weight | Role |
|---|---|---|
text2Xl, text3Xl and up |
24–60 | display (hero sizes above 24 are one-offs; keep them local) |
textXl, textXl700 |
20 / 600–700 | titleLarge |
textLg, textLg600 |
18 / 600–700 | title |
textBase, bodyMedium, bodyMediumW500, bodyMediumW600 |
16 / 400–600 | section |
bodySmall, inputText, textPopUpGray, textTitleCardGray |
14 / 400 | body |
textTitleCard, bodySmallw500 |
14 / 500 | body + w500 |
bodySmallHint |
14, gray600 | body + textTertiary |
bodySmallBlue, bodyMediumBlue, textTitleCardBlue |
14–16, primaryButton | body / section + accentText |
textXs, textXsLight, textXsMedium, textSmallContent, bodySmallExtra |
12 | caption |
errorText |
12 / 500 | caption + w500 + danger |
textXsContent, bodyMediumBrownW600 |
11 | micro |
textTn, textTn400, textSmall |
10 | micro (10 is below the floor) |
Space: AppSpace
Section titled “Space: AppSpace”Design points; the getters apply s (see README.md).
| Token | Value |
|---|---|
xxs |
2 |
xs |
4 |
sm |
8 |
md |
12 |
lg |
16 |
xl |
24 |
xxl |
32 |
gutter |
= lg |
Radius: AppRadius
Section titled “Radius: AppRadius”| Token | Value |
|---|---|
xs |
4 |
sm |
8 |
md |
12 |
lg |
16 |
xl |
20 |
pill |
GlassTokens.stadium (999) |
Motion: AppMotion
Section titled “Motion: AppMotion”| Token | Value |
|---|---|
quick |
140 ms (= GlassTokens.liftDuration) |
standard |
250 ms |
curve |
Curves.easeOutCubic |
The travelling spring is GlassTokens.spring; see glass.md.
Size: AppSize
Section titled “Size: AppSize”Design points at the kDesignWidth-wide (370) phone. The getters already apply s, so never add .s to a token.
| Token | Value |
|---|---|
minTouch |
44 |
controlCompact |
28 |
control |
44 |
controlLarge |
48 |
iconSm |
16 |
icon |
20 |
iconLg |
24 |
headerBar |
44 |
bottomNav |
56 |
sheetMaxWidth |
480 |
dialogMaxWidth |
480 |
Poster layout
Section titled “Poster layout”PosterShape in widgets/content_widget/poster/poster_metrics.dart. Widths are
design points: phone values go through s, tablet values do not.
| Shape | Ratio | Grid min tile (phone / tablet) | Columns | Rail visible | Rail card cap |
|---|---|---|---|---|---|
portrait |
2:3 | 96 / 140 | 3–8 | 2.4 | 180 |
landscape |
16:9 | 150 / 220 | 2–5 | 1.7 | 260 |
square |
1:1 | 96 / 140 | 3–8 | 2.7 | 170 |
rounded |
1:1 | 96 / 130 | 3–8 | 3.3 | 150 |
Grid (PosterGridLayout), for a row W wide with gap g:
columns = clamp(floor((W + g) / (minTile + g)), min, max)tileWidth = (W − g·(columns − 1)) / columns // tiles add up to W exactlyheight = tileWidth / ratio + metaHeightRail (PosterRailLayout), for a viewport W, leading gutter G, gap g
and visible count v:
cardWidth = (W − G − g·floor(v)) / v // the last card peeks by v − floor(v)When that is wider than the cap (tablets), the rail shows the fewest whole
cards that bring it under the cap, keeping the same peek. The rail’s height is
cardWidth / ratio + metaHeight, so it cannot drift from the card.
Meta line (PosterMeta.height): the gap, two title lines of 11 × 1.3, and
for artists a type line of 10 × 1.1, all at the viewer’s text scale.
Layout metrics
Section titled “Layout metrics”| Metric | Where | What |
|---|---|---|
FloatingNavBarMetrics.accessoryBottomOffset(context, p) |
floating_nav_bar_metrics.dart |
Bottom of an accessory above the nav bar at hide progress p |
FloatingNavBarMetrics.accessoryGap |
same | AppSpace.sm.v between the accessory and the bar |
SearchCapsule.height |
search_capsule.dart |
AppSize.controlLarge (48) |
SearchFacetBar.height |
search_facet_bar.dart |
AppSize.minTouch (44), the chip row |
GlassChip.height |
glass_chip.dart |
AppSize.controlCompact (28) drawn, 44 hit; the shared flat pill |
FloatingNavBarMetrics.pillHeight |
floating_nav_bar_metrics.dart |
AppSize.bottomNav (56) |
NavStripMetrics.headerRowHeight / chipHeight |
nav_strip_metrics.dart |
AppSize.headerBar (44) / AppSize.controlCompact (28) |