Skip to content

Branding — Typography

The type ramp follows Apple’s Human Interface scale, with sizes deliberately larger than Material’s defaults. The primary device is a tablet held at arm’s length on a job site, often in direct sunlight, so legibility under load wins.

No web font is downloaded. The ramp falls back through fonts that ship with the operating system or the Flutter engine, so estimates stay editable and exportable with no network.

Resolution order:

.SF Pro Text → iOS / macOS / iPadOS
.SF UI Text → older Apple systems
SF Pro Text → Apple systems
Roboto → everywhere else (bundled with CanvasKit, so web resolves)
Helvetica Neue → older Apple systems
Arial → final Windows fallback

Brand marketing surfaces use Segoe UI Bold / Regular on Windows for compositing. Apple SF Pro Text remains the canonical target.

TokenSizeWeightTrackingLine heightUse
largeTitle34700-0.61.18Hero headlines, marketing titles
title128700-0.451.2Page headers
title222600-0.351.25Section headers
title320600-0.31.28Card titles, dialog headers
headline17600-0.41.3Emphasised body, button labels
body17400-0.41.35Default body text
callout16400-0.31.35Secondary body
subheadline15400-0.21.35Captions under fields
footnote13400-0.11.35Helper copy, footnotes
caption11240001.3Tabular metadata
caption2114000.071.3Tab labels
measurement1560001.2Tabular figures — footage, quantities, prices

Apple tracks large type tighter and small type looser. Reproducing that is most of what makes a screen read as Apple-like rather than generic.

  • 34px and above → tight tracking (negative, around -0.6)
  • 22–28px → moderate negative tracking
  • 17–20px → slight negative tracking for body
  • 15px and below → slight positive or zero tracking

Measurement labels sit in columns and change while the estimator drags a line. Proportional digits make those columns jitter; lining figures do not.

TextStyle(
fontSize: 15,
fontWeight: FontWeight.w600,
letterSpacing: 0,
fontFeatures: [FontFeature.tabularFigures(), FontFeature.slashedZero()],
)

tabularFigures() makes 0–9 the same width. slashedZero() distinguishes 0 from O in monospaced columns.

  • Headlines — largeTitle weight 700, SF Pro Display Bold
  • Body — body weight 400, SF Pro Text
  • Eyebrow / tag — caption2 with letter-spacing 0.07, uppercase

The theme provides both a Material TextTheme and a CupertinoTextThemeData derived from the same ramp, so widgets can use either and stay consistent.

MaterialCupertinoSketch FG token
displayLargenavLargeTitleTextStylelargeTitle
displayMedium—title1
headlineLarge—title1
titleMediumactionTextStyleheadline
bodyLargetextStylebody
labelLarge—headline
labelSmalltabLabelTextStylecaption1