Skip to main content
NetScriptdocs Search docs ⌘K v0.0.9
Browse documentation

Tonal

Material 3 Expressive for NetScript. Tonal surfaces replace borders, with a saturated hero KPI, shape-morphing connected controls and a floating toolbar with a FAB.

DESIGN.md SKILL.md

On this page

Light and dark

Tonal

Tonal Orders specimen, light scheme
Light
Tonal Orders specimen, dark scheme
Dark

Specification values · alpha

Theme values

Values: Colors

Tonal · Colors
PropertyValue
bg#fdfcfd
bg-dark#121113
surface#faf9fb
surface-dark#1a191b
card#faf9fb
card-dark#1a191b
container#f2eff3
container-dark#232225
container-high#eae7ec
container-high-dark#2b292d
container-highest#e3dfe6
container-highest-dark#323035
selected#f4f0fe
selected-dark#291f43
fg#211f26
fg-dark#eeeef0
muted-fg#605e67
muted-fg-dark#bab7c0
border#dbd8e0
border-dark#3c393f
input-border#84828e
input-border-dark#7c7a85
ring#6550b9
ring-dark#baa7ff
primary#6550b9
primary-dark#6e56cf
primary-hover#6550b9
primary-hover-dark#7d66d9
primary-fg#ffffff
primary-fg-dark#ffffff
primary-text#6550b9
primary-text-dark#baa7ff
primary-container#ebe4ff
primary-container-dark#33255b
primary-on-container#2f265f
primary-on-container-dark#e2ddfe
inverse#211f26
inverse-dark#eeeef0
inverse-fg#fdfcfd
inverse-fg-dark#121113
success-subtle#e9f6e9
success-subtle-dark#1b2a1e
success-text#2a7e3b
success-text-dark#71d083
warning-subtle#fff7c2
warning-subtle-dark#302008
warning-text#4f3422
warning-text-dark#ffca16
destructive-subtle#feebec
destructive-subtle-dark#3b1219
destructive-text#641723
destructive-text-dark#ff9592
info-subtle#e6f4fe
info-subtle-dark#0d2847
info-text#113264
info-text-dark#70b8ff

Values: Typography

Tonal · Typography
PropertyValue
display.fontFamilyRoboto Flex
display.fontSize57px
display.fontWeight500
display.lineHeight64px
display.letterSpacing-0.25px
title.fontFamilyRoboto Flex
title.fontSize36px
title.fontWeight500
title.lineHeight44px
heading.fontFamilyRoboto Flex
heading.fontSize16px
heading.fontWeight500
heading.lineHeight24px
heading.letterSpacing0.15px
kpi.fontFamilyRoboto Flex
kpi.fontSize45px
kpi.fontWeight500
kpi.lineHeight52px
kpi.fontFeature"tnum" 1, "lnum" 1
kpi-sm.fontFamilyRoboto Flex
kpi-sm.fontSize32px
kpi-sm.fontWeight500
kpi-sm.lineHeight40px
kpi-sm.fontFeature"tnum" 1, "lnum" 1
body-lg.fontFamilyRoboto Flex
body-lg.fontSize16px
body-lg.fontWeight400
body-lg.lineHeight24px
body.fontFamilyRoboto Flex
body.fontSize14px
body.fontWeight400
body.lineHeight20px
body.letterSpacing0.25px
strong.fontFamilyRoboto Flex
strong.fontSize14px
strong.fontWeight600
strong.lineHeight20px
strong.letterSpacing0.1px
label.fontFamilyRoboto Flex
label.fontSize12px
label.fontWeight600
label.lineHeight16px
label.letterSpacing0.4px
small.fontFamilyRoboto Flex
small.fontSize12px
small.fontWeight400
small.lineHeight16px
small.letterSpacing0.4px

Values: Radii

Tonal · Radii
PropertyValue
input4px
connected-pressed4px
segment-inner6px
chip8px
connected-inner8px
fab20px
card28px
card-hero32px
full9999px

Values: Spacing

Tonal · Spacing
PropertyValue
button-height40px
icon-button40px
connected-height48px
chip-height32px
field-height56px
search-height56px
list-row-height72px
list-gap2px
rail-width96px
rail-item-width80px
fab-size64px
toolbar-height64px
card-padding24px

Values: Component recipes

Tonal · Component recipes
PropertyValue
button-filled.backgroundColor{colors.primary}
button-filled.textColor{colors.primary-fg}
button-filled.typography{typography.strong}
button-filled.rounded{rounded.full}
button-filled.height40px
button-filled.padding0 24px
button-filled-dark.backgroundColor{colors.primary-dark}
button-filled-dark.textColor{colors.primary-fg-dark}
button-filled-dark.rounded{rounded.full}
button-filled-dark.height40px
button-outlined.textColor{colors.primary-text}
button-outlined.typography{typography.strong}
button-outlined.rounded{rounded.full}
button-outlined.height40px
button-outlined.padding0 24px 0 16px
button-tonal.backgroundColor{colors.primary-container}
button-tonal.textColor{colors.primary-on-container}
button-tonal.typography{typography.strong}
button-tonal.rounded{rounded.full}
button-tonal.height40px
connected-selected.backgroundColor{colors.primary}
connected-selected.textColor{colors.primary-fg}
connected-selected.typography{typography.strong}
connected-selected.rounded{rounded.full}
connected-selected.height48px
connected-item.backgroundColor{colors.container-high}
connected-item.textColor{colors.fg}
connected-item.typography{typography.strong}
connected-item.rounded{rounded.connected-inner}
connected-item.height48px
chip-selected.backgroundColor{colors.primary-container}
chip-selected.textColor{colors.primary-on-container}
chip-selected.typography{typography.strong}
chip-selected.rounded{rounded.chip}
chip-selected.height32px
text-field.backgroundColor{colors.container-highest}
text-field.textColor{colors.fg}
text-field.typography{typography.body-lg}
text-field.rounded{rounded.input}
text-field.height56px
search-bar.backgroundColor{colors.container-high}
search-bar.textColor{colors.muted-fg}
search-bar.typography{typography.body-lg}
search-bar.rounded{rounded.full}
search-bar.height56px
list-row.backgroundColor{colors.container}
list-row.textColor{colors.fg}
list-row.typography{typography.strong}
list-row.rounded{rounded.segment-inner}
list-row.height72px
list-row-selected.backgroundColor{colors.primary-container}
list-row-selected.textColor{colors.primary-on-container}
list-row-selected.rounded{rounded.segment-inner}
list-row-selected.height72px
status-success.backgroundColor{colors.success-subtle}
status-success.textColor{colors.success-text}
status-success.typography{typography.label}
status-success.rounded{rounded.chip}
status-success.height28px
kpi-hero.backgroundColor{colors.primary}
kpi-hero.textColor{colors.primary-fg}
kpi-hero.typography{typography.kpi}
kpi-hero.rounded{rounded.card-hero}
kpi-hero.padding24px 24px 20px
kpi-hero-dark.backgroundColor{colors.primary-dark}
kpi-hero-dark.textColor{colors.primary-fg-dark}
kpi-hero-dark.rounded{rounded.card-hero}
kpi.backgroundColor{colors.container}
kpi.textColor{colors.fg}
kpi.typography{typography.kpi-sm}
kpi.rounded{rounded.card}
kpi.padding20px 20px 16px
floating-toolbar.backgroundColor{colors.primary-container}
floating-toolbar.textColor{colors.primary-on-container}
floating-toolbar.rounded{rounded.full}
floating-toolbar.height64px
floating-toolbar.padding8px
fab.backgroundColor{colors.primary}
fab.textColor{colors.primary-fg}
fab.rounded{rounded.fab}
fab.size64px
Read YAML values and notes
Plain text
version: alpha
name: Tonal
description: Material 3 Expressive for NetScript. Tonal surfaces replace borders, with a saturated hero KPI, shape-morphing connected controls and a floating toolbar with a FAB.
colors:
  # Theme mode Tonal (aliases gray → Radix mauve, accent → Radix violet). Light, then `-dark`.
  # Resolved Figma variables of the Light and Dark frames.
  bg: '#fdfcfd'
  bg-dark: '#121113'
  surface: '#faf9fb'
  surface-dark: '#1a191b'
  card: '#faf9fb'
  card-dark: '#1a191b'
  container: '#f2eff3'
  container-dark: '#232225'
  container-high: '#eae7ec'
  container-high-dark: '#2b292d'
  container-highest: '#e3dfe6'
  container-highest-dark: '#323035'
  selected: '#f4f0fe'
  selected-dark: '#291f43'
  fg: '#211f26'
  fg-dark: '#eeeef0'
  muted-fg: '#605e67' # also the 1px enabled filled-field and textarea indicator
  muted-fg-dark: '#bab7c0'
  border: '#dbd8e0'
  border-dark: '#3c393f'
  input-border: '#84828e' # outlined buttons, chips, checkbox outlines; not the filled-field indicator
  input-border-dark: '#7c7a85'
  ring: '#6550b9'
  ring-dark: '#baa7ff'
  primary: '#6550b9'
  primary-dark: '#6e56cf'
  primary-hover: '#6550b9'
  primary-hover-dark: '#7d66d9'
  primary-fg: '#ffffff'
  primary-fg-dark: '#ffffff'
  primary-text: '#6550b9'
  primary-text-dark: '#baa7ff'
  primary-container: '#ebe4ff'
  primary-container-dark: '#33255b'
  primary-on-container: '#2f265f'
  primary-on-container-dark: '#e2ddfe'
  inverse: '#211f26'
  inverse-dark: '#eeeef0'
  inverse-fg: '#fdfcfd'
  inverse-fg-dark: '#121113'
  success-subtle: '#e9f6e9'
  success-subtle-dark: '#1b2a1e'
  success-text: '#2a7e3b'
  success-text-dark: '#71d083'
  warning-subtle: '#fff7c2'
  warning-subtle-dark: '#302008'
  warning-text: '#4f3422'
  warning-text-dark: '#ffca16'
  destructive-subtle: '#feebec'
  destructive-subtle-dark: '#3b1219'
  destructive-text: '#641723'
  destructive-text-dark: '#ff9592'
  info-subtle: '#e6f4fe'
  info-subtle-dark: '#0d2847'
  info-text: '#113264'
  info-text-dark: '#70b8ff'
typography:
  display: {
    fontFamily: Roboto Flex,
    fontSize: 57px,
    fontWeight: 500,
    lineHeight: 64px,
    letterSpacing: -0.25px,
  }
  title: { fontFamily: Roboto Flex, fontSize: 36px, fontWeight: 500, lineHeight: 44px }
  heading: {
    fontFamily: Roboto Flex,
    fontSize: 16px,
    fontWeight: 500,
    lineHeight: 24px,
    letterSpacing: 0.15px,
  }
  kpi: {
    fontFamily: Roboto Flex,
    fontSize: 45px,
    fontWeight: 500,
    lineHeight: 52px,
    fontFeature: '"tnum" 1, "lnum" 1',
  }
  kpi-sm: {
    fontFamily: Roboto Flex,
    fontSize: 32px,
    fontWeight: 500,
    lineHeight: 40px,
    fontFeature: '"tnum" 1, "lnum" 1',
  }
  body-lg: { fontFamily: Roboto Flex, fontSize: 16px, fontWeight: 400, lineHeight: 24px }
  body: {
    fontFamily: Roboto Flex,
    fontSize: 14px,
    fontWeight: 400,
    lineHeight: 20px,
    letterSpacing: 0.25px,
  }
  strong: {
    fontFamily: Roboto Flex,
    fontSize: 14px,
    fontWeight: 600,
    lineHeight: 20px,
    letterSpacing: 0.1px,
  }
  label: {
    fontFamily: Roboto Flex,
    fontSize: 12px,
    fontWeight: 600,
    lineHeight: 16px,
    letterSpacing: 0.4px,
  }
  small: {
    fontFamily: Roboto Flex,
    fontSize: 12px,
    fontWeight: 400,
    lineHeight: 16px,
    letterSpacing: 0.4px,
  }
rounded:
  input: 4px # filled field top corners; bottom corners 0
  connected-pressed: 4px
  segment-inner: 6px
  chip: 8px
  connected-inner: 8px
  fab: 20px
  card: 28px
  card-hero: 32px
  full: 9999px
spacing:
  button-height: 40px
  icon-button: 40px
  connected-height: 48px
  chip-height: 32px
  field-height: 56px
  search-height: 56px
  list-row-height: 72px
  list-gap: 2px
  rail-width: 96px
  rail-item-width: 80px
  fab-size: 64px
  toolbar-height: 64px
  card-padding: 24px
components:
  button-filled: {
    backgroundColor: '{colors.primary}',
    textColor: '{colors.primary-fg}',
    typography: '{typography.strong}',
    rounded: '{rounded.full}',
    height: 40px,
    padding: 0 24px,
  }
  button-filled-dark: {
    backgroundColor: '{colors.primary-dark}',
    textColor: '{colors.primary-fg-dark}',
    rounded: '{rounded.full}',
    height: 40px,
  }
  button-outlined: {
    textColor: '{colors.primary-text}',
    typography: '{typography.strong}',
    rounded: '{rounded.full}',
    height: 40px,
    padding: 0 24px 0 16px,
  }
  button-tonal: {
    backgroundColor: '{colors.primary-container}',
    textColor: '{colors.primary-on-container}',
    typography: '{typography.strong}',
    rounded: '{rounded.full}',
    height: 40px,
  }
  connected-selected: {
    backgroundColor: '{colors.primary}',
    textColor: '{colors.primary-fg}',
    typography: '{typography.strong}',
    rounded: '{rounded.full}',
    height: 48px,
  }
  connected-item: {
    backgroundColor: '{colors.container-high}',
    textColor: '{colors.fg}',
    typography: '{typography.strong}',
    rounded: '{rounded.connected-inner}',
    height: 48px,
  }
  chip-selected: {
    backgroundColor: '{colors.primary-container}',
    textColor: '{colors.primary-on-container}',
    typography: '{typography.strong}',
    rounded: '{rounded.chip}',
    height: 32px,
  }
  text-field: {
    backgroundColor: '{colors.container-highest}',
    textColor: '{colors.fg}',
    typography: '{typography.body-lg}',
    rounded: '{rounded.input}',
    height: 56px,
  }
  search-bar: {
    backgroundColor: '{colors.container-high}',
    textColor: '{colors.muted-fg}',
    typography: '{typography.body-lg}',
    rounded: '{rounded.full}',
    height: 56px,
  }
  list-row: {
    backgroundColor: '{colors.container}',
    textColor: '{colors.fg}',
    typography: '{typography.strong}',
    rounded: '{rounded.segment-inner}',
    height: 72px,
  }
  list-row-selected: {
    backgroundColor: '{colors.primary-container}',
    textColor: '{colors.primary-on-container}',
    rounded: '{rounded.segment-inner}',
    height: 72px,
  }
  status-success: {
    backgroundColor: '{colors.success-subtle}',
    textColor: '{colors.success-text}',
    typography: '{typography.label}',
    rounded: '{rounded.chip}',
    height: 28px,
  }
  kpi-hero: {
    backgroundColor: '{colors.primary}',
    textColor: '{colors.primary-fg}',
    typography: '{typography.kpi}',
    rounded: '{rounded.card-hero}',
    padding: 24px 24px 20px,
  }
  kpi-hero-dark: {
    backgroundColor: '{colors.primary-dark}',
    textColor: '{colors.primary-fg-dark}',
    rounded: '{rounded.card-hero}',
  }
  kpi: {
    backgroundColor: '{colors.container}',
    textColor: '{colors.fg}',
    typography: '{typography.kpi-sm}',
    rounded: '{rounded.card}',
    padding: 20px 20px 16px,
  }
  floating-toolbar: {
    backgroundColor: '{colors.primary-container}',
    textColor: '{colors.primary-on-container}',
    rounded: '{rounded.full}',
    height: 64px,
    padding: 8px,
  }
  fab: {
    backgroundColor: '{colors.primary}',
    textColor: '{colors.primary-fg}',
    rounded: '{rounded.fab}',
    size: 64px,
  }

Overview

  • Thesis: Material 3 Expressive on NetScript roles. Tonal containers and shape carry the hierarchy, without borders or shadows.
  • Signature moves:
    1. Saturated hero on a tonal ladder. One violet hero KPI (primary) over container → container-high → container-highest surfaces; no card borders.
    2. Connected and segmented shapes. Connected button groups (selected = full pill, inner corners 8px, pressed 4px), segmented list rows (outer 28px, inner 6px, 2px gaps), and the Expressive "sunny" shape, used only for the selected order.
    3. Floating toolbar and FAB at the bottom centre, plus a wavy progress indicator and filled text fields with the label inside.
  • Anchor: Material 3 Expressive (May 2025, m3.material.io): shape scale, emphasized type, colour roles, state layers, connected button groups, floating toolbar, wavy progress. The Material 3 Design Kit is used for calibration. Do not copy Google marks, the Material Symbols set (use our Lucide-style icons) or Google Sans.
  • Family: System. Best for: Android-adjacent and consumer-facing apps, mobile-first admin. Avoid for: dense desktop finance grids (use Studio Ledger).
  • Feel: soft and tactile. It must match current Material 3 Expressive, not the 2019-era Material look.

Colors

  • Ladder: bg #fdfcfd → container #f2eff3 (KPIs, form, list rows) → container-high #eae7ec (search, connected items, options, banner) → container-highest #e3dfe6 (filled fields, switch track). Dark: #121113 → #232225 → #2b292d → #323035.
  • Accent policy: violet primary fills only the hero KPI, the selected connected button, the FAB and filled buttons. primary-container (#ebe4ff / #33255b) marks selection: the selected row, the selected chip, the floating toolbar, the sync card, tonal buttons and the rail indicator. primary-text (#6550b9 / #baa7ff) is for text buttons, focused labels and progress.
  • Status: chips use *-subtle fills with *-text (success #2a7e3b / #71d083, warning #4f3422 / #ffca16, destructive #641723 / #ff9592, info #113264 / #70b8ff) plus a leading icon.
  • Dark design notes: the hero, Save and FAB keep a saturated #6e56cf fill with white text (5.39:1), never a pale inverse slab. Selection stays deep (#33255b). Shadows turn to #000 at 50%. Surfaces lighten with height.

Typography

Roboto Flex (OFL, Google Fonts) sets every role except mono, which is Geist Mono (OFL). Fallback: system-ui, sans-serif. Emphasized scale: display 57/64 Medium −0.25; title 36/44 Medium; hero KPI 45/52 Medium; secondary KPIs 32/40 Medium (type/kpi-sm); headings and names 16/24 Medium +0.15; body 14/20 +0.25; strong and button labels 14/20 SemiBold +0.1; field values and search 16/24; field labels and captions 12/16 +0.4. Order IDs and totals are SemiBold 14/20. Numerals must be tabular lining in code (pending in #2414 and #2416). Sentence case throughout.

Layout

  • Frame (1280×1876): a 96px navigation rail (menu icon button, five 80×60 destinations) and a main column (1144px content): search bar (640×56) and notification button → header (title, subtitle, outlined Export) → KPI row (hero 380×210 + three 243×152) → orders section (toolbar with connected group and chips, column labels, six 72px segmented rows, "Load more") → bottom row: order form (728) beside a side column (400: sync card, banner, recent activity).
  • Floating toolbar + FAB: 292×64, bottom centre, over content.
  • Rhythm: 4px grid; list gaps 2px; card padding 24 (hero) / 20 (KPI); form groups 16. Density defaults to Comfortable, but Tonal controls use the fixed M3 sizes in spacing.

Elevation & Depth

Tonal elevation: a raised surface takes the next container step instead of a shadow.

Level Recipe Applied to
0 bg page
1–3 container / container-high / container-highest fills, no stroke cards, rows, fields
Floating box-shadow: 0 3px 8px #0f0f1414 (dark #00000080) floating toolbar
Floating action box-shadow: 0 4px 10px #0f0f1414 (dark #00000080) FAB

Focus: 2px ring at a 2px gap ("Focus 2/2" on the state sheets).

Shapes

M3 shape scale, drawn as literal radii: full (buttons, search, floating toolbar, delta pills), 32 (hero, form), 28 (KPIs, sync card, banner, first/last segmented row), 24 (first/last activity item), 20 (FAB, options group ends), 8 (chips, status, connected inner corners), 6 (segmented inner), 4 (field top corners, pressed connected inner corners, activity inner). Expressive shapes: the "sunny" 8-point shape for the selected order's avatar (list and form header, 56px) and shape badges (44px) on the sync card and banner. Strokes: 1px field indicator, 2px focused/error indicator, 1px outlined button.

Components

States come from the Light and Dark state sheets; state layers use the on-colour.

  • Buttons: filled (primary), tonal (primary-container), outlined (1px input-border, primary-text label), text (primary-text). 40px, full radius, 24px padding (16px on the icon side). Hover 8%, pressed 12% layer behind the label, focus 2/2, disabled = state/disabled-container 12% + state/disabled-fg 38%, parent opacity 1.
  • Connected button group: 48px, 2px gaps; selected item becomes a full pill in primary; others container-high with 8px inner corners; pressed inner corners morph to 4px.
  • Chips: 32px, radius 8. Filter chip = 1px input-border, muted-fg label, trailing chevron. Selected chip = primary-container with a leading check.
  • Filled text field: 56px, container-highest, top corners 4px, label inside (12/16) and value (16/24). Enabled indicator 1px muted-fg (text/muted, #605e67 / #bab7c0; measured 4.8459:1 / 6.5985:1 on the field fill); hover indicator fg; focused 2px ring with a primary-text label; error 2px destructive-text, trailing alert icon and a full repair sentence; error + focus adds the outer ring; disabled 38%.
  • Text area: 112px container, label inside, 1px muted-fg bottom indicator, counter "Optional · 0 / 500".
  • Checkbox / switch: checkbox in a 40px round state target; switch 52×32, off track container-highest with a 2px muted-fg outline; on track primary with a check in the thumb.
  • Segmented list row (table): 72px rows, 2px apart, container; outer corners 28, inner 6; checkbox, ID, avatar + name/email, channel, status chip, date, total, overflow icon button. Selected = primary-container with primary-on-container text and the sunny avatar.
  • Status chip: 28px, radius 8, *-subtle fill, leading status icon, *-text label.
  • KPI: hero 380×210 r32 primary with label, 45/52 value, delta and an area sparkline (white at 18% + 2.5px line); secondary 243×152 r28 container with a shape-badge icon, 32/40 value and a delta pill; no sparklines.
  • Notice / banner: r28 container-high, shape badge, body, text + tonal actions.
  • Navigation rail: 80×60 items, 56×32 r16 indicator in primary-container, 24px icon, 12/16 label (Medium when active). No compose FAB in the rail.
  • Top bar: 56px pill search in container-high with a trailing avatar; tonal bell button.
  • Floating toolbar + FAB: 220×64 pill in primary-container holding four 48px named icon actions (Filter, Export, Copy order ID, More); 64px r20 primary FAB "Create order".
  • Wavy progress: 4px wave in primary-text with a 4px stop dot; remainder muted-fg.
  • Dialog/sheet: not drawn in the fixture; pending in #2416 (use r28 container-high).

Do's and Don'ts

  • Do match current M3 Expressive anatomy, component by component.
  • Don't separate surfaces with borders or shadows; use a higher container step instead.
  • Don't paint a pale hero, pale selected segment or pale primary in dark: use #6e56cf with white.
  • Do bind enabled field labels to fg, focused labels to primary-text, and errors to destructive-text with a 2px indicator and a full repair sentence.
  • Do draw outlined buttons, chips, checkboxes and icon buttons with input-border, and the 1px enabled indicator of filled fields and text areas with muted-fg (≥ 3:1 on the field fill).
  • Do compose hover/pressed as 8%/12% on-colour layers behind the label; disabled as 12% container + 38% label at parent opacity 1, never an opaque grey.
  • Do morph shape on interaction: pressed connected inner corners 8 → 4.
  • Do reserve the sunny shape for the selected order; all other avatars are circles; no decorative blob on the hero.
  • Don't add sparklines to secondary KPIs or a second compose FAB in the rail.
  • Do give every icon-only action a name ("Filter orders", "Export orders", "Copy order ID", "More order actions", "Create order").
  • Do keep the emphasized scale: 36/44 title, 45/52 hero, 32/40 secondary KPIs, 16/24 names; keep the wave and stop dot in primary-text.
  • Do keep the Priority switch off in the fixture, as in every theme.
  • Don't treat the floating toolbar as proven: its viewport and scroll behaviour is pending in #2419.

Iconography & Imagery

The shared icon/* set (Lucide-style strokes, ISC): 24px in the rail, search and toolbar, 18px in buttons and chips, 28px in the FAB. Avatars are 40px circles with initials on primary-container; the selected order uses the sunny shape. Shape badges (44px) hold product icons. No photos.

Motion & States

Shown statically: hover 8%, pressed 12%, focus 2/2, disabled 12%/38%, selected primary-container, selected + hover. M3 Expressive spring motion and the shape-morph transition are not specified yet. They are pending in #2419, with a reduced-motion equivalent (no morph, instant state change) and RTL mirroring of the rail, chevrons and wavy progress.

Accessibility

Pair (light / dark) Ratio
fg on bg 15.92 / 16.25
muted-fg on container 5.59 / 8.00
muted-fg on container-highest (field placeholder) 4.85 / 6.60
primary-fg on primary (hero, FAB, Save) 6.17 / 5.39
primary-on-container on primary-container 10.92 / 10.28
ring on container-highest 4.69 / 6.25
destructive-text on container-highest 9.45 / 6.19
Enabled field indicator muted-fg on the field fill (#e3dfe6 / #323035), measured 4.8459 / 6.5985
input-border (outlined buttons, chips) on container 3.31 / 3.75

The enabled filled-field indicator meets 3:1 in both schemes, measured on rendered pixels. Disabled fields (38%) are inactive components and are exempt from the contrast minimums; enabled states are not. Hit targets: 40px buttons and checkbox targets, 48px toolbar actions, 72px rows.

NetScript Mapping

Layer Value
Figma Theme mode Tonal
Base gray × accent Mauve × Violet (aliased inside the Tonal mode; frames set no Base modes)
Density Comfortable (default); M3 component sizes are fixed
Flavor n/a
data-theme tonal
Language roles none; Tonal reads only core roles (--ns-container*, --ns-primary-container, …)
  • Shape scale: container radii (32, 28, 24, 20, 8, 6, 4) are literal values and do not use the Theme radius/card (16). Role pending in #2414: an M3 shape scale. Buttons use radius/control (999).
  • Field indicator: the enabled active indicator of the filled text field and the text area binds muted-fg, the M3 on-surface-variant role, not input-border.
    • Light: #605e67 on the #e3dfe6 field fill, measured 4.8459:1.
    • Dark: #bab7c0 on the #323035 field fill, measured 6.5985:1.
    • Enabled and Disabled indicators share the colour; Disabled keeps its 38% treatment.
  • Status: values come from the NetScript Figma library. Fonts, numerals, shape-scale tokens and the contrast matrix are tracked in #2414; the canonical state matrix, tooltips for named actions and the dialog in #2416; floating-toolbar viewport and scroll behaviour and motion in #2419. Runtime behaviour stays unproven until #2419.

Sources

  • References: m3.material.io (Material 3 Expressive, May 2025); the Material 3 Design Kit (Figma community) for calibration. What to take and what never to copy is listed under Overview → Anchor.
  • Fonts and icons: Roboto Flex (OFL, Google Fonts) and Geist Mono (OFL); Lucide-style icons (ISC).
  • Invented fixture content: Northwind data, customers, order IDs, amounts, "Importing marketplace orders · 214 of 314".
Search all documentation

Type a term to search the documentation.