[Overview](https://rickylabs.github.io/netscript/design-system/)[Guidelines](https://rickylabs.github.io/netscript/design-system/guidelines/)[Token contract](https://rickylabs.github.io/netscript/design-system/token-contract/)[Docs kit](https://rickylabs.github.io/netscript/design-system/docs-kit/)[Theme builder](https://rickylabs.github.io/netscript/create/)[Components](https://rickylabs.github.io/netscript/design-system/components/)[Create your own theme](https://rickylabs.github.io/netscript/design-system/create-your-own-theme/)[Studio](https://rickylabs.github.io/netscript/design-system/themes/studio/)[Tonal](https://rickylabs.github.io/netscript/design-system/themes/tonal/)[Bloom](https://rickylabs.github.io/netscript/design-system/themes/bloom/)[Cupertino](https://rickylabs.github.io/netscript/design-system/themes/cupertino/)[Liquid](https://rickylabs.github.io/netscript/design-system/themes/liquid/)[Fluent](https://rickylabs.github.io/netscript/design-system/themes/fluent/)[Brutal](https://rickylabs.github.io/netscript/design-system/themes/brutal/)[Filigrane](https://rickylabs.github.io/netscript/design-system/themes/filigrane/)[Terminal](https://rickylabs.github.io/netscript/design-system/themes/terminal/)[Pixel](https://rickylabs.github.io/netscript/design-system/themes/pixel/)[Tactile](https://rickylabs.github.io/netscript/design-system/themes/tactile/)

# 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](https://raw.githubusercontent.com/rickylabs/netscript/main/docs/design-system/themes/tonal/DESIGN.md) [SKILL.md](https://raw.githubusercontent.com/rickylabs/netscript/main/docs/design-system/themes/tonal/SKILL.md)

On this page

- [Light and dark](#design-specimens)
- [Theme values](#design-values)
- [Values: Colors](#values-colors)
- [Values: Typography](#values-typography)
- [Values: Radii](#values-rounded)
- [Values: Spacing](#values-spacing)
- [Values: Component recipes](#values-components)
- [Overview](#overview)
- [Colors](#colors)
- [Typography](#typography)
- [Layout](#layout)
- [Elevation & Depth](#elevation-depth)
- [Shapes](#shapes)
- [Components](#components)
- [Do's and Don'ts](#dos-and-donts)
- [Iconography & Imagery](#iconography-imagery)
- [Motion & States](#motion-states)
- [Accessibility](#accessibility)
- [NetScript Mapping](#netscript-mapping)
- [Sources](#sources)

## Light and dark

### Tonal

![Tonal Orders specimen, light scheme](https://rickylabs.github.io/netscript/assets/design-system/tonal--light.webp)

*Light*

![Tonal Orders specimen, dark scheme](https://rickylabs.github.io/netscript/assets/design-system/tonal--dark.webp)

*Dark*

Specification values · alpha

## Theme values

### Values: Colors

**Tonal · Colors**

| Property | Value |
| --- | --- |
| `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**

| Property | Value |
| --- | --- |
| `display.fontFamily` | `Roboto Flex` |
| `display.fontSize` | `57px` |
| `display.fontWeight` | `500` |
| `display.lineHeight` | `64px` |
| `display.letterSpacing` | `-0.25px` |
| `title.fontFamily` | `Roboto Flex` |
| `title.fontSize` | `36px` |
| `title.fontWeight` | `500` |
| `title.lineHeight` | `44px` |
| `heading.fontFamily` | `Roboto Flex` |
| `heading.fontSize` | `16px` |
| `heading.fontWeight` | `500` |
| `heading.lineHeight` | `24px` |
| `heading.letterSpacing` | `0.15px` |
| `kpi.fontFamily` | `Roboto Flex` |
| `kpi.fontSize` | `45px` |
| `kpi.fontWeight` | `500` |
| `kpi.lineHeight` | `52px` |
| `kpi.fontFeature` | `"tnum" 1, "lnum" 1` |
| `kpi-sm.fontFamily` | `Roboto Flex` |
| `kpi-sm.fontSize` | `32px` |
| `kpi-sm.fontWeight` | `500` |
| `kpi-sm.lineHeight` | `40px` |
| `kpi-sm.fontFeature` | `"tnum" 1, "lnum" 1` |
| `body-lg.fontFamily` | `Roboto Flex` |
| `body-lg.fontSize` | `16px` |
| `body-lg.fontWeight` | `400` |
| `body-lg.lineHeight` | `24px` |
| `body.fontFamily` | `Roboto Flex` |
| `body.fontSize` | `14px` |
| `body.fontWeight` | `400` |
| `body.lineHeight` | `20px` |
| `body.letterSpacing` | `0.25px` |
| `strong.fontFamily` | `Roboto Flex` |
| `strong.fontSize` | `14px` |
| `strong.fontWeight` | `600` |
| `strong.lineHeight` | `20px` |
| `strong.letterSpacing` | `0.1px` |
| `label.fontFamily` | `Roboto Flex` |
| `label.fontSize` | `12px` |
| `label.fontWeight` | `600` |
| `label.lineHeight` | `16px` |
| `label.letterSpacing` | `0.4px` |
| `small.fontFamily` | `Roboto Flex` |
| `small.fontSize` | `12px` |
| `small.fontWeight` | `400` |
| `small.lineHeight` | `16px` |
| `small.letterSpacing` | `0.4px` |

### Values: Radii

**Tonal · Radii**

| Property | Value |
| --- | --- |
| `input` | `4px` |
| `connected-pressed` | `4px` |
| `segment-inner` | `6px` |
| `chip` | `8px` |
| `connected-inner` | `8px` |
| `fab` | `20px` |
| `card` | `28px` |
| `card-hero` | `32px` |
| `full` | `9999px` |

### Values: Spacing

**Tonal · Spacing**

| Property | Value |
| --- | --- |
| `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` |

### Values: Component recipes

**Tonal · Component recipes**

| Property | Value |
| --- | --- |
| `button-filled.backgroundColor` | `{colors.primary}` |
| `button-filled.textColor` | `{colors.primary-fg}` |
| `button-filled.typography` | `{typography.strong}` |
| `button-filled.rounded` | `{rounded.full}` |
| `button-filled.height` | `40px` |
| `button-filled.padding` | `0 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.height` | `40px` |
| `button-outlined.textColor` | `{colors.primary-text}` |
| `button-outlined.typography` | `{typography.strong}` |
| `button-outlined.rounded` | `{rounded.full}` |
| `button-outlined.height` | `40px` |
| `button-outlined.padding` | `0 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.height` | `40px` |
| `connected-selected.backgroundColor` | `{colors.primary}` |
| `connected-selected.textColor` | `{colors.primary-fg}` |
| `connected-selected.typography` | `{typography.strong}` |
| `connected-selected.rounded` | `{rounded.full}` |
| `connected-selected.height` | `48px` |
| `connected-item.backgroundColor` | `{colors.container-high}` |
| `connected-item.textColor` | `{colors.fg}` |
| `connected-item.typography` | `{typography.strong}` |
| `connected-item.rounded` | `{rounded.connected-inner}` |
| `connected-item.height` | `48px` |
| `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.height` | `32px` |
| `text-field.backgroundColor` | `{colors.container-highest}` |
| `text-field.textColor` | `{colors.fg}` |
| `text-field.typography` | `{typography.body-lg}` |
| `text-field.rounded` | `{rounded.input}` |
| `text-field.height` | `56px` |
| `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.height` | `56px` |
| `list-row.backgroundColor` | `{colors.container}` |
| `list-row.textColor` | `{colors.fg}` |
| `list-row.typography` | `{typography.strong}` |
| `list-row.rounded` | `{rounded.segment-inner}` |
| `list-row.height` | `72px` |
| `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.height` | `72px` |
| `status-success.backgroundColor` | `{colors.success-subtle}` |
| `status-success.textColor` | `{colors.success-text}` |
| `status-success.typography` | `{typography.label}` |
| `status-success.rounded` | `{rounded.chip}` |
| `status-success.height` | `28px` |
| `kpi-hero.backgroundColor` | `{colors.primary}` |
| `kpi-hero.textColor` | `{colors.primary-fg}` |
| `kpi-hero.typography` | `{typography.kpi}` |
| `kpi-hero.rounded` | `{rounded.card-hero}` |
| `kpi-hero.padding` | `24px 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.padding` | `20px 20px 16px` |
| `floating-toolbar.backgroundColor` | `{colors.primary-container}` |
| `floating-toolbar.textColor` | `{colors.primary-on-container}` |
| `floating-toolbar.rounded` | `{rounded.full}` |
| `floating-toolbar.height` | `64px` |
| `floating-toolbar.padding` | `8px` |
| `fab.backgroundColor` | `{colors.primary}` |
| `fab.textColor` | `{colors.primary-fg}` |
| `fab.rounded` | `{rounded.fab}` |
| `fab.size` | `64px` |

Read YAML values and notes

```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".
