@epa-wg/custom-element-dist 0.0.33 → 0.0.34
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.local.json +18 -0
- package/.github/workflows/deploy.yml +59 -0
- package/.idea/copilot.data.migration.agent.xml +6 -0
- package/.idea/copilot.data.migration.ask.xml +6 -0
- package/.idea/copilot.data.migration.edit.xml +6 -0
- package/.idea/custom-element-dist.iml +2 -0
- package/.storybook/main.ts +20 -17
- package/.storybook/preview.ts +23 -23
- package/README.md +6 -4
- package/coverage/block-navigation.js +1 -1
- package/coverage/coverage-final.json +4 -3
- package/coverage/index.html +34 -19
- package/coverage/sorter.js +21 -7
- package/coverage/src/custom-element/coverage.svg +1 -1
- package/coverage/src/custom-element/custom-element.js/coverage.svg +1 -1
- package/coverage/src/custom-element/custom-element.js.html +435 -378
- package/coverage/src/custom-element/http-request.js/coverage.svg +1 -1
- package/coverage/src/custom-element/http-request.js.html +38 -17
- package/coverage/src/custom-element/index.html +26 -26
- package/coverage/src/custom-element/local-storage.js.html +1 -1
- package/coverage/src/custom-element/location-element.js.html +1 -1
- package/coverage/src/custom-element/module-url.js.html +1 -1
- package/coverage/src/index.html +1 -1
- package/coverage/src/material/theme/colors.js/coverage.svg +10 -0
- package/coverage/src/material/theme/colors.js.html +217 -0
- package/coverage/src/material/theme/coverage.svg +10 -0
- package/coverage/src/material/theme/index.html +116 -0
- package/coverage/src/mocks/handlers.ts.html +1 -1
- package/coverage/src/mocks/index.html +1 -1
- package/coverage/src/stories/frame.canvas.ts.html +1 -1
- package/coverage/src/stories/http-request.stories.ts.html +1 -1
- package/coverage/src/stories/index.html +1 -1
- package/coverage/src/stories/testStoryBook.ts.html +12 -12
- package/coverage/src/sum.ts.html +1 -1
- package/dist/{custom-element-WnOqmEOe.js → custom-element-BoYMoUtP.js} +193 -183
- package/dist/custom-element-BqtjrCRF.cjs +97 -0
- package/dist/custom-element-bundle.cjs +1 -1
- package/dist/custom-element-bundle.js +3 -3
- package/dist/demo/a.html +10 -3
- package/dist/demo/a.svg +26 -26
- package/dist/demo/html-template.html +4 -3
- package/dist/demo/s.xml +3856 -67
- package/dist/demo/s.xslt +13 -72
- package/dist/demo/s1.xml +3706 -0
- package/dist/http-request-DSaowcG1.cjs +1 -0
- package/dist/{http-request-BOvP4KTl.js → http-request-DTCzZ1gc.js} +15 -9
- package/package.json +2 -2
- package/public/demo/a.html +10 -3
- package/public/demo/a.svg +26 -26
- package/public/demo/html-template.html +4 -3
- package/public/demo/s.xml +3856 -67
- package/public/demo/s.xslt +13 -72
- package/public/demo/s1.xml +3706 -0
- package/src/custom-element/custom-element.js +28 -9
- package/src/custom-element/demo/a.html +10 -3
- package/src/custom-element/demo/a.svg +26 -26
- package/src/custom-element/demo/html-template.html +4 -3
- package/src/custom-element/demo/s.xml +3856 -67
- package/src/custom-element/demo/s.xslt +13 -72
- package/src/custom-element/demo/s1.xml +3706 -0
- package/src/custom-element/http-request.js +7 -0
- package/src/custom-element/ide/web-types-dce.json +1 -1
- package/src/custom-element/ide/web-types-xsl.json +1 -1
- package/src/material/angular.css +987 -987
- package/src/material/components/action.html +262 -0
- package/src/material/components/autocomplete.html +167 -239
- package/src/material/components/badge.html +238 -239
- package/src/material/components/dropdown.html +0 -1
- package/src/material/components/icon-link.html +160 -161
- package/src/material/components/icon.html +251 -252
- package/src/material/components/input.html +569 -570
- package/src/material/components/menu.html +235 -236
- package/src/material/components.html +157 -158
- package/src/material/demo.css +36 -36
- package/src/material/index.html +109 -110
- package/src/material/material.css +356 -356
- package/src/material/theme/Base-Principles.md +339 -0
- package/src/material/theme/README.md +298 -18
- package/src/material/theme/UI Domain Model in web applications.svg +1 -0
- package/src/material/theme/User Semantic Theme tokens.svg +1 -0
- package/src/material/theme/action-pending-poc.html +62 -0
- package/src/material/theme/actions-color.html +141 -0
- package/src/material/theme/colors-light.html +631 -0
- package/src/material/theme/colors-native.html +51 -0
- package/src/material/theme/colors-poc.html +66 -0
- package/src/material/theme/colors.html +297 -0
- package/src/material/theme/colors.js +44 -0
- package/src/material/theme/consumer-theme.css +745 -0
- package/src/material/theme/semantic.css +132 -132
- package/src/material/theme/style-bug.html +123 -0
- package/src/material/theme/theme-data.css +43 -0
- package/src/material/theme/theme-data.xhtml +2926 -0
- package/src/material/theme/todo.md +274 -0
- package/src/material/theme/tokens/action-colors.png +0 -0
- package/src/material/theme/tokens/cem-article-illustration-4x1-letterbox-2000x500.png +0 -0
- package/src/material/theme/tokens/cem-breakpoints.md +519 -0
- package/src/material/theme/tokens/cem-colors.md +715 -0
- package/src/material/theme/tokens/cem-consumerflow-typography-matrix.svg +198 -0
- package/src/material/theme/tokens/cem-coupling.md +372 -0
- package/src/material/theme/tokens/cem-data-vs-reading-numerals.svg +164 -0
- package/src/material/theme/tokens/cem-dimension.md +625 -0
- package/src/material/theme/tokens/cem-layering.md +562 -0
- package/src/material/theme/tokens/cem-m3-parity.md +343 -0
- package/src/material/theme/tokens/cem-responsive.md +238 -0
- package/src/material/theme/tokens/cem-shape.md +691 -0
- package/src/material/theme/tokens/cem-stroke-density-illustration-4to1-v3.svg +102 -0
- package/src/material/theme/tokens/cem-stroke.md +480 -0
- package/src/material/theme/tokens/cem-timing.md +198 -0
- package/src/material/theme/tokens/cem-typography-model-stack.svg +64 -0
- package/src/material/theme/tokens/cem-voice-fonts-typography.md +718 -0
- package/src/material/theme/tokens/cem-voice-ladder.svg +91 -0
- package/src/material/theme/tokens/chips.png +0 -0
- package/src/material/theme/tokens/columns-page.png +0 -0
- package/src/material/theme/tokens/initials.png +0 -0
- package/src/material/theme/tokens/nav-buttons.png +0 -0
- package/src/material/theme/tokens/script.png +0 -0
- package/src/material/theme/tokens/sufler.png +0 -0
- package/src/material/theme/tokens/typography-icons.png +0 -0
- package/src/mocks/versions.mock.ts +1 -1
- package/src/stories/__screenshots__/dom-merge.test.stories.ts/dom-merge-dom-merge-OrderPreservingOn2ndTransform-1.png +0 -0
- package/src/stories/__screenshots__/xslt-conditionals.test.stories.ts/xslt-conditionals-xslt-conditionals-MultipleIfOrderingWorkaround-1.png +0 -0
- package/src/stories/dom-merge.test.stories.ts +25 -1
- package/src/stories/xslt-conditionals.test.stories.ts +492 -0
- package/src/stories/xslt-if.test.stories.ts +89 -0
- package/storybook-static/assets/{Color-F6OSRLHC-Cbp293x2.js → Color-F6OSRLHC-CzTOSlqB.js} +1 -1
- package/storybook-static/assets/{Configure-BrFr4SLE.js → Configure-7GqRsAoJ.js} +1 -1
- package/storybook-static/assets/{DocsRenderer-CFRXHY34-DhHzJiIO.js → DocsRenderer-CFRXHY34-Duc5rSIm.js} +2 -2
- package/storybook-static/assets/{attributes.test.stories-Gg9LQTEK.js → attributes.test.stories-DYuxF8h1.js} +1 -1
- package/storybook-static/assets/{css.test.stories-B_3ltOrx.js → css.test.stories-LOmvINyb.js} +1 -1
- package/storybook-static/assets/{custom-element-CPnvJnn8.js → custom-element-Bwx7otrT.js} +6 -6
- package/storybook-static/assets/{dom-merge.test.stories-nQxcgLoM.js → dom-merge.test.stories-CEKhWjaS.js} +47 -6
- package/storybook-static/assets/entry-preview-BNCt9WBs.js +26 -0
- package/storybook-static/assets/{entry-preview-docs-Dwczwtsc.js → entry-preview-docs-CbF8-81D.js} +2 -2
- package/storybook-static/assets/{external-template.test.stories-DZ-rjnfd.js → external-template.test.stories-jHu0wsJ-.js} +1 -1
- package/storybook-static/assets/{form.test.stories-DQhPYtMj.js → form.test.stories-CUyUnmwP.js} +1 -1
- package/storybook-static/assets/{frame.canvas-ClTqYyMN.js → frame.canvas-E5n9h6j1.js} +1 -1
- package/storybook-static/assets/{handlers-CLkps6Nz.js → handlers-F7GUfMqr.js} +1 -1
- package/storybook-static/assets/http-request-BWeEEBkP.js +1 -0
- package/storybook-static/assets/{http-request.stories-jo0f73nw.js → http-request.stories-wyX5-QOv.js} +1 -1
- package/storybook-static/assets/{iframe-CZwRpnn9.js → iframe-BS_DPWl0.js} +11 -11
- package/storybook-static/assets/{index-Dr4PwNfd.js → index-CGuyH0k-.js} +87 -87
- package/storybook-static/assets/{index-CJQtnF9V.js → index-DB7LLObI.js} +1 -1
- package/storybook-static/assets/index-DO1nmyvI.js +11 -0
- package/storybook-static/assets/{index-B68YUdzy.js → index-V1EGs-wm.js} +3 -3
- package/storybook-static/assets/{local-storage.test.stories-uA5EKRPf.js → local-storage.test.stories-BxOhsf1k.js} +1 -1
- package/storybook-static/assets/{location-element.test.stories-Cu-6Elcg.js → location-element.test.stories-DqhvvUoa.js} +1 -1
- package/storybook-static/assets/{module-url.test.stories-CD_wusXQ.js → module-url.test.stories-C1gG9G7Y.js} +1 -1
- package/storybook-static/assets/{preview-BFlNN3Wj.js → preview-Bn8igYMp.js} +1 -1
- package/storybook-static/assets/{preview-CuCH40jj.js → preview-Cwy1XFu2.js} +2 -2
- package/storybook-static/assets/{preview-Cm4PPhHS.js → preview-D6sehqkw.js} +1 -1
- package/storybook-static/assets/{set-url.test.stories-CY7B9BVZ.js → set-url.test.stories-BKQNdknJ.js} +1 -1
- package/storybook-static/assets/{slice-events.test.stories-BVnPXm6e.js → slice-events.test.stories-ChqULCeA.js} +1 -1
- package/storybook-static/assets/{slots.test.stories-Dxsa9KdA.js → slots.test.stories-BlyLoCRe.js} +1 -1
- package/storybook-static/assets/{version-select.test.stories-Buga1PAa.js → version-select.test.stories-CPGSh1tR.js} +1 -1
- package/storybook-static/assets/xslt-conditionals.test.stories-YC6QPqWZ.js +633 -0
- package/storybook-static/assets/xslt-if.test.stories-BRSWy2-x.js +71 -0
- package/storybook-static/demo/a.html +10 -3
- package/storybook-static/demo/a.svg +26 -26
- package/storybook-static/demo/html-template.html +4 -3
- package/storybook-static/demo/s.xml +3856 -67
- package/storybook-static/demo/s.xslt +13 -72
- package/storybook-static/demo/s1.xml +3706 -0
- package/storybook-static/iframe.html +2 -2
- package/storybook-static/index.json +1 -1
- package/storybook-static/project.json +1 -1
- package/storybook-static/sb-addons/essentials-controls-1/manager-bundle.js +69 -66
- package/storybook-static/sb-addons/essentials-docs-3/manager-bundle.js +62 -59
- package/dist/custom-element-6slVaFEs.cjs +0 -97
- package/dist/http-request-DPrY7mGh.cjs +0 -1
- package/storybook-static/assets/attributes.test.stories-CzWkKw0e.js +0 -1
- package/storybook-static/assets/entry-preview-DHVXbf3x.js +0 -26
- package/storybook-static/assets/external-template.test.stories-BivZqBTp.js +0 -1
- package/storybook-static/assets/http-request-DNq59pnj.js +0 -1
- package/storybook-static/assets/index-BwkS7JH_.js +0 -8
- package/storybook-static/assets/module-url.test.stories-CTjUAk3J.js +0 -1
|
@@ -0,0 +1,625 @@
|
|
|
1
|
+
# Semantic Spacing and Layout Rhythm Tokens (CEM × M3)
|
|
2
|
+
|
|
3
|
+
**Status:** Canonical (D1 v1.0)
|
|
4
|
+
|
|
5
|
+
**Last updated:** December 19, 2025
|
|
6
|
+
|
|
7
|
+
**Audience:** Design Systems, Product Design, Front-End Engineering
|
|
8
|
+
|
|
9
|
+
**Taxonomy placement:** D1. Space & Rhythm (part of the 7-dimensional CEM token framework)
|
|
10
|
+
|
|
11
|
+
**Companion specs:**
|
|
12
|
+
- **D0. Color (Emotional Palette)** ([`cem-colors.md`](./cem-colors.md)) — color weight pairs with spacing rhythm
|
|
13
|
+
- **D2. Coupling & Compactness** ([`cem-coupling.md`](./cem-coupling.md)) — normative for interactive operability
|
|
14
|
+
- **D3. Shape & Bend** ([`cem-shape.md`](./cem-shape.md)) — bend/inset harmony rules
|
|
15
|
+
- **D4. Layering** ([`cem-layering.md`](./cem-layering.md)) — prominent layers "earn" breathing room
|
|
16
|
+
- **D5. Stroke & Separation** ([`cem-stroke.md`](./cem-stroke.md)) — boundaries, dividers, focus indicators
|
|
17
|
+
- **D6. Typography** ([`cem-voice-fonts-typography.md`](./cem-voice-fonts-typography.md)) — reading rhythm validation
|
|
18
|
+
- **D7. Time & Motion** ([`cem-timing.md`](./cem-timing.md)) — rhythm perception
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Table of Contents
|
|
23
|
+
|
|
24
|
+
1. [Scope](#1-scope)
|
|
25
|
+
2. [CEM alignment principles applied to spacing](#2-cem-alignment-principles-applied-to-spacing)
|
|
26
|
+
- [2.1 Semantic intent first](#21-semantic-intent-first)
|
|
27
|
+
- [2.2 Bounded variation](#22-bounded-variation)
|
|
28
|
+
- [2.3 Accessibility and operability by construction](#23-accessibility-and-operability-by-construction)
|
|
29
|
+
3. [Token model](#3-token-model)
|
|
30
|
+
4. [Relation to Dimensional Tokens](#4-relation-to-dimensional-tokens)
|
|
31
|
+
- [4.1 Dimensional Tokens: where spacing lives](#41-dimensional-tokens-where-spacing-lives)
|
|
32
|
+
- [4.2 Governance rules (cross-category contracts)](#42-governance-rules-cross-category-contracts)
|
|
33
|
+
5. [Reference spacing scale (semantic)](#5-reference-spacing-scale-semantic)
|
|
34
|
+
- [5.1 Primary dimension scale](#51-primary-dimension-scale-semanticcss)
|
|
35
|
+
- [5.2 Mapping to M3 rhythm](#52-mapping-to-m3-rhythm)
|
|
36
|
+
6. [Consumer-semantic spacing taxonomy](#6-consumer-semantic-spacing-taxonomy)
|
|
37
|
+
- [6.1 Relationship gaps (between items)](#61-relationship-gaps-between-items)
|
|
38
|
+
- [6.2 Insets (inside a surface)](#62-insets-inside-a-surface)
|
|
39
|
+
- [6.3 Coupling and interaction safety (D2 cross-reference)](#63-coupling-and-interaction-safety-d2-cross-reference)
|
|
40
|
+
- [6.4 Reading rhythm (vertical cadence for prose)](#64-reading-rhythm-vertical-cadence-for-prose)
|
|
41
|
+
- [6.5 Data/scan rhythm (dense but legible)](#65-datascan-rhythm-dense-but-legible)
|
|
42
|
+
7. [Layout rhythm tokens (compositional semantics)](#7-layout-rhythm-tokens-compositional-semantics)
|
|
43
|
+
- [7.1 Stack rhythm (vertical composition)](#71-stack-rhythm-vertical-composition)
|
|
44
|
+
- [7.2 Cluster rhythm (horizontal groups)](#72-cluster-rhythm-horizontal-groups)
|
|
45
|
+
- [7.3 Page gutters (responsive breathing room)](#73-page-gutters-responsive-breathing-room)
|
|
46
|
+
8. [Spacing modes knob (dense / normal / sparse)](#8-spacing-modes-knob-dense--normal--sparse)
|
|
47
|
+
- [8.1 Adjustment policy](#81-adjustment-policy)
|
|
48
|
+
- [8.2 Concrete overrides](#82-concrete-overrides-recommended-default-mapping)
|
|
49
|
+
- [8.3 Notes on component mapping](#83-notes-on-component-mapping)
|
|
50
|
+
- [8.4 Layout mapping checklist](#84-layout-mapping-checklist-how-to-apply)
|
|
51
|
+
9. [Mapping notes: M3 ↔ CEM](#9-mapping-notes-m3--cem)
|
|
52
|
+
10. [Quick adoption checklist](#10-quick-adoption-checklist)
|
|
53
|
+
|
|
54
|
+
**Appendices**
|
|
55
|
+
- [Appendix A. D2 Coupling Mode Matrix (excerpt)](#appendix-a-d2-coupling-mode-matrix-excerpt)
|
|
56
|
+
- [Appendix B. Governance and versioning](#appendix-b-governance-and-versioning)
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## 1. Scope
|
|
61
|
+
|
|
62
|
+
This document defines a **consumer-semantic** spacing and layout rhythm token set that:
|
|
63
|
+
|
|
64
|
+
- Preserves the **Material 3 rhythm** (4dp increments, common 8dp cadence) as a *reference lattice*.
|
|
65
|
+
- Exposes **semantic endpoints** that describe *intent* (relationship, grouping, task flow) rather than
|
|
66
|
+
*implementation* (e.g., `margin: 16px`).
|
|
67
|
+
- Supports an optional D1 knob for **spacing modes** (`dense | normal | sparse`) **without** conflating it with D2
|
|
68
|
+
operability.
|
|
69
|
+
|
|
70
|
+
This document is **D1 (Space & Rhythm)**. It intentionally does *not* define interactive minimums; it **consumes** D2
|
|
71
|
+
coupling minimums as hard constraints.
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## 2. CEM alignment principles applied to spacing
|
|
76
|
+
|
|
77
|
+
### 2.1 Semantic intent first
|
|
78
|
+
|
|
79
|
+
Developers should apply tokens like:
|
|
80
|
+
|
|
81
|
+
- `gap-related`, `gap-group`, `gap-section` (relationship semantics)
|
|
82
|
+
- `inset-control`, `inset-container` (surface semantics)
|
|
83
|
+
- `coupling-guard-min` (interaction safety contract; defined in D2)
|
|
84
|
+
|
|
85
|
+
…and not value-centric names like `space-16` in component code.
|
|
86
|
+
|
|
87
|
+
### 2.2 Bounded variation
|
|
88
|
+
|
|
89
|
+
A small set of *distinct, repeatable* space steps should cover most UI. Extended values exist but are intentionally
|
|
90
|
+
"rare".
|
|
91
|
+
|
|
92
|
+
### 2.3 Accessibility and operability by construction
|
|
93
|
+
|
|
94
|
+
Spacing must preserve:
|
|
95
|
+
|
|
96
|
+
- **Modality-neutral operability** (pointer, touch, stylus, gaze, switch, remote) via D2 coupling minimums
|
|
97
|
+
- **Readability** (line/paragraph rhythm)
|
|
98
|
+
- **User scaling** (prefer `rem` / `em` and allow platform scaling)
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## 3. Token model
|
|
103
|
+
|
|
104
|
+
We use three layers:
|
|
105
|
+
|
|
106
|
+
1. **Reference scale tokens** (M3-aligned numeric steps; safe to map to dp/px)
|
|
107
|
+
2. **System/semantic tokens** (consumer-intent endpoints; what teams apply)
|
|
108
|
+
3. **Component mapping** (component-specific tokens map to semantic tokens; typically owned in component adapters)
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
## 4. Relation to Dimensional Tokens
|
|
113
|
+
|
|
114
|
+
### 4.1 Dimensional Tokens: where spacing lives
|
|
115
|
+
|
|
116
|
+
In CEM, spacing/rhythm is not "just layout." It is a primary subset of **Dimensional Tokens** (the physical layer: size,
|
|
117
|
+
distance, bend, stroke, depth).
|
|
118
|
+
|
|
119
|
+
Use this **legend-level** dimensional taxonomy to keep token categories coherent:
|
|
120
|
+
|
|
121
|
+
- **D1. Space & Rhythm** (this document)
|
|
122
|
+
- gaps, insets, gutters, composition cadence, reading cadence, scan cadence
|
|
123
|
+
|
|
124
|
+
- **D2. Coupling & Compactness** (adjacent; constrains D1) — see [`cem-coupling.md`](./cem-coupling.md)
|
|
125
|
+
- operable zone minimums
|
|
126
|
+
- interference/isolation minimums
|
|
127
|
+
- halo/expansion policy (visual size vs operable size)
|
|
128
|
+
- control geometry endpoints that affect operability (heights/paddings/row sizes)
|
|
129
|
+
|
|
130
|
+
- **D3. Shape & Bend** — see [`cem-shape.md`](./cem-shape.md)
|
|
131
|
+
- bend / corner radius roles
|
|
132
|
+
- bend-inset harmony (see §4.2 rule 5)
|
|
133
|
+
|
|
134
|
+
- **D4. Layering** — see [`cem-layering.md`](./cem-layering.md)
|
|
135
|
+
- signed 7-tier ladder (recess → base → raised → floating → overlay → command)
|
|
136
|
+
- tonal shift, shadow, contour, scrim as depth channels
|
|
137
|
+
- state-driven lift (hover, drag)
|
|
138
|
+
|
|
139
|
+
- **D5. Stroke & Separation** — see [`cem-stroke.md`](./cem-stroke.md)
|
|
140
|
+
- boundaries (control container edges), dividers (sibling separation)
|
|
141
|
+
- focus/selection/target indicators (including zebra pattern)
|
|
142
|
+
- stroke basis (`--cem-stroke-none`, `--cem-stroke-hair`, `--cem-stroke-standard`, `--cem-stroke-strong`)
|
|
143
|
+
|
|
144
|
+
- **D6. Typography Thickness** — see [`cem-voice-fonts-typography.md`](./cem-voice-fonts-typography.md)
|
|
145
|
+
- weight/mass roles that affect perceived density and hierarchy
|
|
146
|
+
|
|
147
|
+
- **D7. Time & Motion Timing** — see [`cem-timing.md`](./cem-timing.md)
|
|
148
|
+
- durations/easing groups (not geometry, but participates in "rhythm" perception)
|
|
149
|
+
|
|
150
|
+
### 4.2 Governance rules (cross-category contracts)
|
|
151
|
+
|
|
152
|
+
These rules prevent spacing changes from degrading operability, accessibility, or visual hierarchy:
|
|
153
|
+
|
|
154
|
+
1. **Spacing modes are a D1 adjustment; never a D2 coupling regression**
|
|
155
|
+
|
|
156
|
+
- `dense | normal | sparse` may adjust *gaps/insets/gutters* (D1) selectively.
|
|
157
|
+
- D1 changes must not reduce the D2 safety minimums (**zone**, **guard**) and must not cause halo overlap.
|
|
158
|
+
|
|
159
|
+
2. **Normative layout contract for interactive adjacency**
|
|
160
|
+
|
|
161
|
+
When spacing occurs **between two interactive affordances**, layout must respect D2 guard:
|
|
162
|
+
|
|
163
|
+
```css
|
|
164
|
+
/* If the gap separates adjacent interactive affordances: */
|
|
165
|
+
.cem-gap-interactive {
|
|
166
|
+
gap: max(var(--cem-gap-related), var(--cem-coupling-guard-min));
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
3. **When D1 can't grow, D5 may need to compensate**
|
|
171
|
+
|
|
172
|
+
- In tight layouts or contrast themes, increase stroke/separation to maintain scannability.
|
|
173
|
+
|
|
174
|
+
4. **Elevated/prominent surfaces "earn" breathing room**
|
|
175
|
+
|
|
176
|
+
- Higher layer prominence (D4) should generally correlate with more surrounding space (D1).
|
|
177
|
+
|
|
178
|
+
5. **Bend and inset should harmonize** (D1 × D3)
|
|
179
|
+
|
|
180
|
+
- Larger bend (D3) with very tight inset (D1) reads crowded; prefer stepping inset up.
|
|
181
|
+
- See [`cem-shape.md`](./cem-shape.md) §8.5 for detailed guidance on bend vs inset readability.
|
|
182
|
+
|
|
183
|
+
6. **Reading cadence is jointly governed by typography + spacing**
|
|
184
|
+
|
|
185
|
+
- Reading rhythm tokens (D1) must be validated against typescale/line-height policy (D6).
|
|
186
|
+
- See [`cem-voice-fonts-typography.md`](./cem-voice-fonts-typography.md) for typography tokens.
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
## 5. Reference spacing scale (semantic)
|
|
191
|
+
|
|
192
|
+
The spacing scale uses semantic size names rather than pixel values, making intent clear while preserving M3 rhythm (4dp
|
|
193
|
+
increments).
|
|
194
|
+
|
|
195
|
+
### 5.1 Primary dimension scale (semantic.css)
|
|
196
|
+
|
|
197
|
+
Eight steps covering common UI needs:
|
|
198
|
+
|
|
199
|
+
```css
|
|
200
|
+
:root {
|
|
201
|
+
--cem-dim-xx-small : 0.25rem; /* 4px — micro gaps, icon padding */
|
|
202
|
+
--cem-dim-x-small : 0.5rem; /* 8px — related item gaps, control insets */
|
|
203
|
+
--cem-dim-small : 0.75rem; /* 12px — group gaps, inline rhythm */
|
|
204
|
+
--cem-dim-medium : 1rem; /* 16px — block gaps, container insets */
|
|
205
|
+
--cem-dim-large : 1.5rem; /* 24px — section gaps, surface insets */
|
|
206
|
+
--cem-dim-x-large : 2rem; /* 32px — page gaps, wide gutters */
|
|
207
|
+
--cem-dim-xx-large : 4rem; /* 64px — extended layout, hero spacing */
|
|
208
|
+
--cem-dim-xxx-large : 8rem; /* 128px — maximum breathing room */
|
|
209
|
+
}
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
**Cross-reference:** These tokens are consumed by D3 Shape ([`cem-shape.md`](./cem-shape.md)) for bend values:
|
|
213
|
+
- `--cem-bend-smooth` uses `--cem-dim-x-small` (8px)
|
|
214
|
+
- `--cem-bend-surface` uses `--cem-dim-small` (12px)
|
|
215
|
+
- `--cem-bend-modal` uses `--cem-dim-large` + `--cem-dim-xx-small` (~28px)
|
|
216
|
+
|
|
217
|
+
### 5.2 Mapping to M3 rhythm
|
|
218
|
+
|
|
219
|
+
| Semantic token | Value | M3 dp equivalent | Typical use |
|
|
220
|
+
|-----------------------|---------|------------------|-------------------------------|
|
|
221
|
+
| `--cem-dim-xx-small` | 0.25rem | 4dp | Micro gaps, tight padding |
|
|
222
|
+
| `--cem-dim-x-small` | 0.5rem | 8dp | Related items, control insets |
|
|
223
|
+
| `--cem-dim-small` | 0.75rem | 12dp | Group gaps, inline spacing |
|
|
224
|
+
| `--cem-dim-medium` | 1rem | 16dp | Block gaps, container insets |
|
|
225
|
+
| `--cem-dim-large` | 1.5rem | 24dp | Section gaps, surface padding |
|
|
226
|
+
| `--cem-dim-x-large` | 2rem | 32dp | Page gaps, wide gutters |
|
|
227
|
+
| `--cem-dim-xx-large` | 4rem | 64dp | Extended layout spacing |
|
|
228
|
+
| `--cem-dim-xxx-large` | 8rem | 128dp | Maximum layout spacing |
|
|
229
|
+
|
|
230
|
+
---
|
|
231
|
+
|
|
232
|
+
## 6. Consumer-semantic spacing taxonomy
|
|
233
|
+
|
|
234
|
+
The taxonomy is organized by what the space *means to the user*.
|
|
235
|
+
|
|
236
|
+
### 6.1 Relationship gaps (between items)
|
|
237
|
+
|
|
238
|
+
Use when arranging siblings.
|
|
239
|
+
|
|
240
|
+
```css
|
|
241
|
+
:root {
|
|
242
|
+
/* Siblings that are clearly part of the same unit */
|
|
243
|
+
--cem-gap-related: var(--cem-dim-x-small); /* 8px */
|
|
244
|
+
|
|
245
|
+
/* Items in the same group, but distinct */
|
|
246
|
+
--cem-gap-group: var(--cem-dim-small); /* 12px */
|
|
247
|
+
|
|
248
|
+
/* Between groups/blocks inside one surface */
|
|
249
|
+
--cem-gap-block: var(--cem-dim-medium); /* 16px */
|
|
250
|
+
|
|
251
|
+
/* Between major sections (cards, panels, page regions) */
|
|
252
|
+
--cem-gap-section: var(--cem-dim-large); /* 24px */
|
|
253
|
+
|
|
254
|
+
/* Between page-level regions */
|
|
255
|
+
--cem-gap-page: var(--cem-dim-x-large); /* 32px */
|
|
256
|
+
}
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
**Guideline:** if users perceive two things as "one unit," use `gap-related`. If they perceive "these are separate
|
|
260
|
+
things," move up to `gap-group` or `gap-block`.
|
|
261
|
+
|
|
262
|
+
> Important: for interactive adjacency, apply the D2 guard contract (`gap = max(D1 gap, D2 guard)`).
|
|
263
|
+
|
|
264
|
+
### 6.2 Insets (inside a surface)
|
|
265
|
+
|
|
266
|
+
Use when padding content within a container.
|
|
267
|
+
|
|
268
|
+
```css
|
|
269
|
+
:root {
|
|
270
|
+
/* Smallest safe inset for tight controls */
|
|
271
|
+
--cem-inset-control: var(--cem-dim-x-small); /* 8px */
|
|
272
|
+
|
|
273
|
+
/* Default inset for common containers */
|
|
274
|
+
--cem-inset-container: var(--cem-dim-medium); /* 16px */
|
|
275
|
+
|
|
276
|
+
/* Comfortable inset for reading surfaces and prominent cards */
|
|
277
|
+
--cem-inset-surface: var(--cem-dim-large); /* 24px */
|
|
278
|
+
}
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
**Cross-reference:** When combining insets with bend (D3), ensure inset is large enough to prevent content crowding in
|
|
282
|
+
rounded corners. See [`cem-shape.md`](./cem-shape.md) §8.5 for guidance.
|
|
283
|
+
|
|
284
|
+
### 6.3 Coupling and interaction safety (D2 cross-reference)
|
|
285
|
+
|
|
286
|
+
These tokens are **defined and governed in D2** ([`cem-coupling.md`](./cem-coupling.md)). They are listed here as a **normative constraint**
|
|
287
|
+
because they bound how far D1 spacing modes can compress interactive adjacency. **Do not set or tune these in D1**;
|
|
288
|
+
treat them as sourced from the D2 theme.
|
|
289
|
+
|
|
290
|
+
```css
|
|
291
|
+
:root {
|
|
292
|
+
/* Minimum distancing between adjacent operable zones (prevents interference). */
|
|
293
|
+
--cem-coupling-guard-min: 0.5rem; /* nominally 8px */
|
|
294
|
+
|
|
295
|
+
/* Minimum operable zone (layout-level). Keep invariant across modes. */
|
|
296
|
+
--cem-coupling-zone-min: 3rem; /* nominally 48px @ 16px root */
|
|
297
|
+
|
|
298
|
+
/* Invisible expansion beyond visuals (halo). */
|
|
299
|
+
--cem-coupling-halo: 0.25rem; /* nominally 4px */
|
|
300
|
+
|
|
301
|
+
/* Legacy aliases (deprecated): keep only while migrating older code */
|
|
302
|
+
--cem-touch-separation-min: var(--cem-coupling-guard-min);
|
|
303
|
+
--cem-touch-target-min: var(--cem-coupling-zone-min);
|
|
304
|
+
}
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
Interpretation (summary):
|
|
308
|
+
|
|
309
|
+
- **Zone**: can the user reliably couple intent to the control?
|
|
310
|
+
- **Guard**: will adjacent controls accidentally steal intent?
|
|
311
|
+
- **Halo**: can we keep visuals compact while preserving operability?
|
|
312
|
+
|
|
313
|
+
### 6.4 Reading rhythm (vertical cadence for prose)
|
|
314
|
+
|
|
315
|
+
This is distinct from UI rhythm.
|
|
316
|
+
|
|
317
|
+
```css
|
|
318
|
+
:root {
|
|
319
|
+
/* Default paragraph spacing for prose (pairs with typography) */
|
|
320
|
+
--cem-rhythm-reading-paragraph: 0.75em;
|
|
321
|
+
|
|
322
|
+
/* Space between reading sections within one surface */
|
|
323
|
+
--cem-rhythm-reading-section: var(--cem-dim-large); /* 24px */
|
|
324
|
+
}
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
**Cross-reference:** Reading rhythm must be validated against typography tokens. See [`cem-voice-fonts-typography.md`](./cem-voice-fonts-typography.md).
|
|
328
|
+
|
|
329
|
+
### 6.5 Data/scan rhythm (dense but legible)
|
|
330
|
+
|
|
331
|
+
Optimized for scan/compare flows (tables, metrics).
|
|
332
|
+
|
|
333
|
+
```css
|
|
334
|
+
:root {
|
|
335
|
+
/* Table-like, scan-first row padding */
|
|
336
|
+
--cem-rhythm-data-row: var(--cem-dim-x-small); /* 8px */
|
|
337
|
+
|
|
338
|
+
/* Scan grouping (subtotals, row groups, metric clusters) */
|
|
339
|
+
--cem-rhythm-data-group: var(--cem-dim-medium); /* 16px */
|
|
340
|
+
}
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
---
|
|
344
|
+
|
|
345
|
+
## 7. Layout rhythm tokens (compositional semantics)
|
|
346
|
+
|
|
347
|
+
These describe **layout structures** without baking in specific components.
|
|
348
|
+
|
|
349
|
+
### 7.1 Stack rhythm (vertical composition)
|
|
350
|
+
|
|
351
|
+
```css
|
|
352
|
+
:root {
|
|
353
|
+
/* Default vertical stack gap for general UI stacks */
|
|
354
|
+
--cem-layout-stack-gap: var(--cem-gap-block);
|
|
355
|
+
|
|
356
|
+
/* Optional derived endpoints (rare): keep if your system needs tight/loose variants */
|
|
357
|
+
--cem-layout-stack-tight: var(--cem-gap-related);
|
|
358
|
+
--cem-layout-stack-loose: var(--cem-gap-section);
|
|
359
|
+
}
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
### 7.2 Cluster rhythm (horizontal groups)
|
|
363
|
+
|
|
364
|
+
```css
|
|
365
|
+
:root {
|
|
366
|
+
/* Default cluster gap for inline groups (icons + text, toolbars, button clusters) */
|
|
367
|
+
--cem-layout-cluster-gap: var(--cem-gap-related);
|
|
368
|
+
|
|
369
|
+
/* Optional legacy aliases (deprecated): */
|
|
370
|
+
--cem-layout-inline-tight: var(--cem-dim-x-small); /* 8px */
|
|
371
|
+
--cem-layout-inline: var(--cem-dim-small); /* 12px */
|
|
372
|
+
--cem-layout-inline-loose: var(--cem-dim-medium); /* 16px */
|
|
373
|
+
}
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
### 7.3 Page gutters (responsive breathing room)
|
|
377
|
+
|
|
378
|
+
These are *responsive* and should be treated as semantics, not fixed numbers.
|
|
379
|
+
|
|
380
|
+
```css
|
|
381
|
+
:root {
|
|
382
|
+
/* Default content gutter */
|
|
383
|
+
--cem-layout-gutter: var(--cem-dim-medium); /* 16px */
|
|
384
|
+
|
|
385
|
+
/* Wide screens */
|
|
386
|
+
--cem-layout-gutter-wide: var(--cem-dim-x-large); /* 32px */
|
|
387
|
+
|
|
388
|
+
/* Maximum breathing room */
|
|
389
|
+
--cem-layout-gutter-max: var(--cem-dim-xx-large); /* 64px */
|
|
390
|
+
}
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
---
|
|
394
|
+
|
|
395
|
+
## 8. Spacing modes knob (dense / normal / sparse)
|
|
396
|
+
|
|
397
|
+
Material often frames this as "density." In CEM, treat this explicitly as a **D1 spacing mode** that shifts Space &
|
|
398
|
+
Rhythm while preserving D2 coupling invariants.
|
|
399
|
+
|
|
400
|
+
```css
|
|
401
|
+
:root {
|
|
402
|
+
/* dense | normal | sparse */
|
|
403
|
+
--cem-layout-spacing: normal;
|
|
404
|
+
}
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
### 8.1 Adjustment policy
|
|
408
|
+
|
|
409
|
+
Mode intent summary:
|
|
410
|
+
|
|
411
|
+
| D1 spacing mode | Primary goal | What changes | What must not change |
|
|
412
|
+
|-----------------|------------------------------|--------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------|
|
|
413
|
+
| `dense` | Increase information density | Step down gaps/insets/gutters ~1 step where safe | D2 coupling invariants (zone/guard), and any gap that separates interactive affordances must still satisfy `gap = max(D1 gap, D2 guard)` |
|
|
414
|
+
| `normal` | Baseline | Use canonical endpoints as defined | Same invariants |
|
|
415
|
+
| `sparse` | Increase calm/readability | Step up gaps/insets/gutters ~1 step | Same invariants |
|
|
416
|
+
|
|
417
|
+
- **normal**: baseline values as defined in Sections 6–7.
|
|
418
|
+
- **dense**: reduce gaps/insets by ~1 step where it does not harm reading cadence or interactive coupling.
|
|
419
|
+
- **sparse**: increase gaps/insets by ~1 step to improve readability and perceived calm.
|
|
420
|
+
|
|
421
|
+
Hard constraints (never override):
|
|
422
|
+
|
|
423
|
+
- `--cem-coupling-zone-min`
|
|
424
|
+
- `--cem-coupling-guard-min` (may force some "gaps" to stay at or above the minimum)
|
|
425
|
+
- `--cem-coupling-halo` (must be considered when validating dense clusters)
|
|
426
|
+
|
|
427
|
+
### 8.2 Concrete overrides (recommended default mapping)
|
|
428
|
+
|
|
429
|
+
```css
|
|
430
|
+
/* NORMAL is the baseline already defined above */
|
|
431
|
+
|
|
432
|
+
:root[data-cem-spacing="dense"] {
|
|
433
|
+
/* Relationship gaps — step down by one level */
|
|
434
|
+
--cem-gap-related: var(--cem-dim-x-small); /* 8px */
|
|
435
|
+
--cem-gap-group: var(--cem-dim-x-small); /* 8px */
|
|
436
|
+
--cem-gap-block: var(--cem-dim-small); /* 12px */
|
|
437
|
+
--cem-gap-section: var(--cem-dim-medium); /* 16px */
|
|
438
|
+
--cem-gap-page: var(--cem-dim-large); /* 24px */
|
|
439
|
+
|
|
440
|
+
/* Insets */
|
|
441
|
+
--cem-inset-control: var(--cem-dim-x-small); /* 8px */
|
|
442
|
+
--cem-inset-container: var(--cem-dim-small); /* 12px */
|
|
443
|
+
--cem-inset-surface: var(--cem-dim-medium); /* 16px */
|
|
444
|
+
|
|
445
|
+
/* Layout gutters */
|
|
446
|
+
--cem-layout-gutter: var(--cem-dim-small); /* 12px */
|
|
447
|
+
--cem-layout-gutter-wide: var(--cem-dim-large); /* 24px */
|
|
448
|
+
--cem-layout-gutter-max: var(--cem-dim-x-large); /* 32px */
|
|
449
|
+
|
|
450
|
+
/* Content cadence */
|
|
451
|
+
--cem-rhythm-reading-paragraph: 0.6em;
|
|
452
|
+
--cem-rhythm-reading-section: var(--cem-dim-medium); /* 16px */
|
|
453
|
+
--cem-rhythm-data-row: var(--cem-dim-xx-small); /* 4px */
|
|
454
|
+
--cem-rhythm-data-group: var(--cem-dim-small); /* 12px */
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
:root[data-cem-spacing="sparse"] {
|
|
458
|
+
/* Relationship gaps — step up by one level */
|
|
459
|
+
--cem-gap-related: var(--cem-dim-small); /* 12px */
|
|
460
|
+
--cem-gap-group: var(--cem-dim-medium); /* 16px */
|
|
461
|
+
--cem-gap-block: var(--cem-dim-large); /* 24px */
|
|
462
|
+
--cem-gap-section: var(--cem-dim-x-large); /* 32px */
|
|
463
|
+
--cem-gap-page: var(--cem-dim-xx-large); /* 64px */
|
|
464
|
+
|
|
465
|
+
/* Insets */
|
|
466
|
+
--cem-inset-control: var(--cem-dim-small); /* 12px */
|
|
467
|
+
--cem-inset-container: var(--cem-dim-large); /* 24px */
|
|
468
|
+
--cem-inset-surface: var(--cem-dim-x-large); /* 32px */
|
|
469
|
+
|
|
470
|
+
/* Layout gutters */
|
|
471
|
+
--cem-layout-gutter: var(--cem-dim-large); /* 24px */
|
|
472
|
+
--cem-layout-gutter-wide: var(--cem-dim-xx-large); /* 64px */
|
|
473
|
+
--cem-layout-gutter-max: var(--cem-dim-xxx-large); /* 128px */
|
|
474
|
+
|
|
475
|
+
/* Content cadence */
|
|
476
|
+
--cem-rhythm-reading-paragraph: 1em;
|
|
477
|
+
--cem-rhythm-reading-section: var(--cem-dim-x-large); /* 32px */
|
|
478
|
+
--cem-rhythm-data-row: var(--cem-dim-small); /* 12px */
|
|
479
|
+
--cem-rhythm-data-group: var(--cem-dim-large); /* 24px */
|
|
480
|
+
}
|
|
481
|
+
```
|
|
482
|
+
|
|
483
|
+
### 8.3 Notes on component mapping
|
|
484
|
+
|
|
485
|
+
* Components should bind to semantic endpoints (`gap-*`, `inset-*`, `rhythm-*`) and inherit spacing mode automatically.
|
|
486
|
+
|
|
487
|
+
* If a component is interactive and uses layout gaps between peer affordances, resolve its gap as:
|
|
488
|
+
`gap = max(D1 semantic gap, D2 coupling guard)`.
|
|
489
|
+
* If a component must remain stable across spacing modes (rare), bind it to reference steps explicitly and document why.
|
|
490
|
+
|
|
491
|
+
### 8.4 Layout mapping checklist (how to apply)
|
|
492
|
+
|
|
493
|
+
Use these patterns so teams can implement screens without inventing spacing semantics.
|
|
494
|
+
|
|
495
|
+
**Stacks (vertical composition)**
|
|
496
|
+
|
|
497
|
+
- Default: use `--cem-layout-stack-gap` (maps to `--cem-gap-block`).
|
|
498
|
+
- Within a group of tightly related elements (e.g., label + control + helper): use `--cem-gap-related`.
|
|
499
|
+
|
|
500
|
+
**Clusters (horizontal composition)**
|
|
501
|
+
|
|
502
|
+
- Default: use `--cem-layout-cluster-gap` (maps to `--cem-gap-related`).
|
|
503
|
+
- If cluster members are independently interactive (e.g., icon button groups), resolve as:
|
|
504
|
+
- `gap: max(var(--cem-layout-cluster-gap), var(--cem-coupling-guard-min))`.
|
|
505
|
+
|
|
506
|
+
**Cards / panels / surfaces**
|
|
507
|
+
|
|
508
|
+
- Container padding: `--cem-inset-container`.
|
|
509
|
+
- Reading- or emphasis-first surfaces: `--cem-inset-surface`.
|
|
510
|
+
- Tight control trays: `--cem-inset-control` (only when content remains legible).
|
|
511
|
+
- **Note:** When using rounded surfaces, ensure inset accommodates bend. See [`cem-shape.md`](./cem-shape.md) §8.5.
|
|
512
|
+
|
|
513
|
+
**Sections and page regions**
|
|
514
|
+
|
|
515
|
+
- Between blocks: `--cem-gap-block`.
|
|
516
|
+
- Between major sections: `--cem-gap-section`.
|
|
517
|
+
- Between page regions: `--cem-gap-page`.
|
|
518
|
+
|
|
519
|
+
**Gutters (responsive framing)**
|
|
520
|
+
|
|
521
|
+
- Default: `--cem-layout-gutter`.
|
|
522
|
+
- Wide screens: `--cem-layout-gutter-wide`.
|
|
523
|
+
- Maximum breathing room: `--cem-layout-gutter-max`.
|
|
524
|
+
|
|
525
|
+
**Reading and data cadence**
|
|
526
|
+
|
|
527
|
+
- Prose: use `--cem-rhythm-reading-paragraph` and `--cem-rhythm-reading-section`.
|
|
528
|
+
- Scan-heavy: use `--cem-rhythm-data-row` and `--cem-rhythm-data-group`.
|
|
529
|
+
|
|
530
|
+
---
|
|
531
|
+
|
|
532
|
+
## 9. Mapping notes: M3 ↔ CEM
|
|
533
|
+
|
|
534
|
+
### 9.1 Where this matches Material 3
|
|
535
|
+
|
|
536
|
+
- 4dp-based reference steps provide the same rhythmic lattice.
|
|
537
|
+
- "Micro/standard/macro/extended" groupings align with common M3 guidance.
|
|
538
|
+
|
|
539
|
+
### 9.2 Where this differs (intentionally)
|
|
540
|
+
|
|
541
|
+
- CEM exposes **consumer-intent** tokens as the *primary interface*.
|
|
542
|
+
- Value-centric tokens are kept as **reference** only.
|
|
543
|
+
- Component tokens should map to semantic tokens, not to raw numbers.
|
|
544
|
+
|
|
545
|
+
---
|
|
546
|
+
|
|
547
|
+
## 10. Quick adoption checklist
|
|
548
|
+
|
|
549
|
+
1. Use the dimension scale (`--cem-dim-*`) as the foundation.
|
|
550
|
+
2. Map semantic endpoints (`gap-*`, `inset-*`, `rhythm-*`) to dimension tokens.
|
|
551
|
+
3. Treat D2 coupling (`zone/guard/halo`) as **hard constraints** for interactive adjacency — see [`cem-coupling.md`](./cem-coupling.md).
|
|
552
|
+
4. Update component tokens to use semantic endpoints.
|
|
553
|
+
5. Add optional `data-cem-spacing="dense|normal|sparse"` only if product needs spacing modes.
|
|
554
|
+
6. Validate on representative surfaces:
|
|
555
|
+
- interactive clusters: guard is respected and no halo overlap occurs
|
|
556
|
+
- reading rhythm (articles/help)
|
|
557
|
+
- scan rhythm (tables/metric panels)
|
|
558
|
+
- responsive gutters
|
|
559
|
+
7. Validate bend-inset harmony on rounded surfaces — see [`cem-shape.md`](./cem-shape.md) §8.5.
|
|
560
|
+
|
|
561
|
+
---
|
|
562
|
+
|
|
563
|
+
## Appendix A. D2 Coupling Mode Matrix (excerpt)
|
|
564
|
+
|
|
565
|
+
This excerpt is provided for convenience when working in D1. The canonical definitions and governance live in **D2.
|
|
566
|
+
Coupling & Compactness** ([`cem-coupling.md`](./cem-coupling.md)).
|
|
567
|
+
|
|
568
|
+
| D2 coupling mode | Product intent | Visual geometry trend | Halo (`--cem-coupling-halo`) trend | Typical surfaces |
|
|
569
|
+
|------------------|-----------------------------------------------------------|---------------------------------------------|-------------------------------------|-------------------------------------------------------|
|
|
570
|
+
| `forgiving` | Minimize mis-coupling for imprecise input | Larger controls/rows; more internal padding | Smaller (visuals already meet zone) | mobile-first, kiosks, accessibility-first, gaze/dwell |
|
|
571
|
+
| `balanced` | Default across modalities | Baseline control heights/rows | Baseline | mixed pointer + touch, general app UI |
|
|
572
|
+
| `compact` | Increase information density without breaking operability | Smaller visuals; reduced chrome | Larger (use halo to preserve zone) | data grids, admin tools, scan-heavy panels |
|
|
573
|
+
|
|
574
|
+
Normative invariants (do not override in D1):
|
|
575
|
+
|
|
576
|
+
- `--cem-coupling-zone-min` is mode-invariant.
|
|
577
|
+
- `--cem-coupling-guard-min` is mode-invariant.
|
|
578
|
+
- D1 gaps between interactive affordances must resolve as: `gap = max(D1 semantic gap, D2 coupling guard)`.
|
|
579
|
+
|
|
580
|
+
---
|
|
581
|
+
|
|
582
|
+
## Appendix B. Governance and versioning
|
|
583
|
+
|
|
584
|
+
This D1 spec is a **contract**. Changes must be intentional, reviewable, and versioned.
|
|
585
|
+
|
|
586
|
+
### B.1 What counts as breaking
|
|
587
|
+
|
|
588
|
+
Treat as **major** (breaking) if you:
|
|
589
|
+
|
|
590
|
+
- Rename or remove any canonical D1 semantic endpoint (`gap-*`, `inset-*`, `layout-*`, `rhythm-*`).
|
|
591
|
+
- Change the semantic meaning of an endpoint (e.g., `gap-group` stops meaning "within a group").
|
|
592
|
+
- Change mode names or add/remove spacing modes.
|
|
593
|
+
- Weaken the D1↔D2 constraint model (anything that could permit violating D2 coupling guard/zone).
|
|
594
|
+
|
|
595
|
+
### B.2 What is non-breaking
|
|
596
|
+
|
|
597
|
+
Treat as **minor/patch** if you:
|
|
598
|
+
|
|
599
|
+
- Adjust numeric values within a mode while preserving semantics and invariants.
|
|
600
|
+
- Add new semantic endpoints that are clearly scoped, optional, and do not redefine existing meaning.
|
|
601
|
+
- Clarify documentation, examples, or mapping guidance.
|
|
602
|
+
|
|
603
|
+
### B.3 Versioning guidance
|
|
604
|
+
|
|
605
|
+
- **PATCH**: documentation clarifications; no token/value changes.
|
|
606
|
+
- **MINOR**: additive tokens or additive examples; safe value tuning.
|
|
607
|
+
- **MAJOR**: renames, removals, meaning shifts, or mode changes.
|
|
608
|
+
|
|
609
|
+
### B.4 Canonical cross-spec invariants
|
|
610
|
+
|
|
611
|
+
D1 is subordinate to D2 for operability. The following must hold in every release:
|
|
612
|
+
|
|
613
|
+
- D2 coupling invariants remain enforceable from D1.
|
|
614
|
+
- Any D1 spacing used between interactive affordances must resolve as `gap = max(D1 semantic gap, D2 coupling guard)`.
|
|
615
|
+
|
|
616
|
+
---
|
|
617
|
+
|
|
618
|
+
## References
|
|
619
|
+
|
|
620
|
+
**Local CEM documentation**
|
|
621
|
+
- [D2. Coupling & Compactness](./cem-coupling.md) — interactive operability constraints
|
|
622
|
+
- [D3. Shape & Bend](./cem-shape.md) — bend tokens, bend-inset harmony
|
|
623
|
+
- [D5. Stroke & Separation](./cem-stroke.md) — boundaries, dividers, focus/selection/target indicators
|
|
624
|
+
- [D6. Typography](./cem-voice-fonts-typography.md) — reading rhythm validation
|
|
625
|
+
- [D7. Time & Motion](./cem-timing.md) — rhythm perception
|