@echelon-foundry/design-system 0.4.0 → 0.4.1-main.224.1

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/CHANGELOG.md ADDED
@@ -0,0 +1,46 @@
1
+ # Changelog
2
+
3
+ Forma follows semantic versioning for its public HTML, class, and token
4
+ contracts (`requirements/QUALITY-AND-DISTRIBUTION.md`, QD-004). Releases are
5
+ published as GitHub release tarballs
6
+ (`https://github.com/kemiller2002/forma/releases/download/vX.Y.Z/echelon-foundry-design-system-X.Y.Z.tgz`)
7
+ and to npm. Earlier releases are described in `docs/CONSUMING-FORMA.md` and
8
+ `HANDOFF.md`.
9
+
10
+ ## 0.4.1
11
+
12
+ Patch release. There are no markup, class, or token-name changes, so no
13
+ consumer migration is required.
14
+
15
+ ### Fixed
16
+
17
+ - **WCAG AA contrast on the secondary surface (FORMA-A11Y-002).** Body,
18
+ severity, reference, hint, and link text inside components that paint
19
+ `--ef-color-surface-secondary` now meets 4.5:1 in every theme and brand.
20
+ Affected components include `.ef-fault--inline`, `.ef-surface`, assistant
21
+ conversation turns, file drop zones, master-detail rows, evidence-age rows,
22
+ and checked choices. Previously, text inside them used `text-secondary` or
23
+ an accent role. For example, inline-fault text was `#686d68` on `#e3e0d7`,
24
+ 4.0:1. Every rule that paints the secondary surface now rebinds secondary
25
+ and muted text to `text-on-secondary-surface`, and links and accent labels
26
+ to `text-primary`, through the new `--ef-surface-accent-text-color` hook.
27
+ Consumer workarounds such as `.operational-fault p { color: inherit }` can
28
+ be removed.
29
+ - **Forced colors.** In Chromium, ibm-3270 character-grid text was painted in
30
+ the profile palette on the forced white Canvas, at 1.1 to 2.4:1. Profile
31
+ tokens now resolve to system colors under `forced-colors: active`.
32
+ - **Built CSS.** Forma 0.3.0 shipped a literal `\n` before
33
+ `.ef-surface :where(h1, …, p)` in `foundations.css` and `all.css`, so that
34
+ rule never applied. The source was corrected in 0.4.0. 0.4.1 adds a check of
35
+ the built output that would have caught it.
36
+
37
+ ### Added checks
38
+
39
+ - `tests/browser/pattern-contrast.spec.mjs` runs axe color-contrast over every
40
+ documented pattern, in every theme, every brand (light and dark), and forced
41
+ colors.
42
+ - `tests/contrast-pairs.test.mjs` checks documented token pairs and
43
+ secondary-surface pairing for every compiled theme and brand.
44
+ - `tests/dist-css.test.mjs` parses every built stylesheet and fails on stray
45
+ escape sequences, unbalanced blocks, selectors that name nonexistent
46
+ elements, and composed outputs whose selectors differ from their sources.
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "forma-machine-operability",
3
+ "version": "1.0.0",
4
+ "referenceAutomation": "Playwright",
5
+ "toolNeutral": true,
6
+ "principle": "Every human-operable action has a deterministic semantically discoverable machine-operable path to the same authoritative application state.",
7
+ "locatorPriority": [
8
+ "role-and-accessible-name",
9
+ "native-label-id-name-value-or-url-target",
10
+ "documented-application-owned-stable-object-identity",
11
+ "documented-public-state-hook-for-inspection"
12
+ ],
13
+ "completionSignals": [
14
+ "native-state-change",
15
+ "documented-public-state-change",
16
+ "navigation-or-url-change",
17
+ "live-or-status-output",
18
+ "authoritative-application-state-rendered-into-the-dom"
19
+ ],
20
+ "directManipulation": {
21
+ "coordinateGestureMayBeConvenience": true,
22
+ "semanticEquivalentRequiredForMeaningfulStateChanges": true,
23
+ "examples": [
24
+ "move-buttons",
25
+ "named-commands",
26
+ "keyboard-actions",
27
+ "form-controls",
28
+ "application-or-limen-command-surface"
29
+ ]
30
+ },
31
+ "forbiddenAsOnlyPublicPath": [
32
+ "hard-coded-screen-coordinates",
33
+ "image-recognition",
34
+ "hover-only-actions",
35
+ "pointer-only-actions",
36
+ "generated-css-class-locators",
37
+ "dom-position-or-nth-child-locators",
38
+ "fixed-sleep-completion",
39
+ "color-only-state",
40
+ "animation-only-state",
41
+ "closed-shadow-dom-hiding-required-interaction"
42
+ ],
43
+ "authority": {
44
+ "forma": "semantic markup, accessible naming, public structure and presentation-state hooks",
45
+ "applicationOrLimen": "behavior beyond native HTML and application state synchronization",
46
+ "ordoOrDomain": "legality, capabilities, obligations, permissions and consequential transitions"
47
+ }
48
+ }
package/dist/all.css CHANGED
@@ -572,8 +572,12 @@
572
572
  max-inline-size: 72ch;
573
573
  }
574
574
 
575
+ /*
576
+ * --ef-surface-accent-text-color is set by secondary-surface rules (see
577
+ * "Secondary-surface pairing" below); elsewhere accent text uses the accent.
578
+ */
575
579
  :where(a) {
576
- color: var(--ef-color-accent-primary, #905831);
580
+ color: var(--ef-surface-accent-text-color, var(--ef-color-accent-primary, #905831));
577
581
  text-decoration-thickness: 0.08em;
578
582
  text-underline-offset: 0.18em;
579
583
  }
@@ -611,6 +615,9 @@
611
615
  }
612
616
 
613
617
  :where(button, .ef-button):where(:not(:disabled)):hover {
618
+ --ef-color-text-secondary: var(--ef-color-text-on-secondary-surface, #3a403c);
619
+ --ef-color-text-muted: var(--ef-color-text-on-secondary-surface, #3a403c);
620
+ --ef-surface-accent-text-color: var(--ef-color-text-primary, #171a18);
614
621
  background: var(--ef-color-surface-secondary, #e3e0d7);
615
622
  }
616
623
 
@@ -646,7 +653,7 @@
646
653
  .ef-actions { display: flex; flex-wrap: wrap; gap: var(--ef-primitive-spacing-3, 0.75rem); align-items: center; }
647
654
  .ef-grid { display: grid; gap: var(--ef-grid-gap, var(--ef-primitive-spacing-4, 1rem)); grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--ef-grid-min, 16rem)), 1fr)); }
648
655
  .ef-section { padding-block: var(--ef-section-space, var(--ef-primitive-spacing-7, 3rem)); }
649
- .ef-surface { min-inline-size: 0; padding: var(--ef-surface-space, var(--ef-primitive-spacing-5, 1.5rem)); background: var(--ef-color-surface-secondary, #e3e0d7); color: var(--ef-color-text-on-secondary-surface, #3a403c); border: 1px solid var(--ef-color-border-subtle, #e3e0d7); }
656
+ .ef-surface { --ef-color-text-secondary: var(--ef-color-text-on-secondary-surface, #3a403c); --ef-color-text-muted: var(--ef-color-text-on-secondary-surface, #3a403c); --ef-surface-accent-text-color: var(--ef-color-text-primary, #171a18); min-inline-size: 0; padding: var(--ef-surface-space, var(--ef-primitive-spacing-5, 1.5rem)); background: var(--ef-color-surface-secondary, #e3e0d7); color: var(--ef-color-text-on-secondary-surface, #3a403c); border: 1px solid var(--ef-color-border-subtle, #e3e0d7); }
650
657
  .ef-surface :where(h1, h2, h3, h4, h5, h6, p) { color: inherit; }
651
658
 
652
659
  :where(h1, h2, h3, h4, h5, h6, p, a, label, legend, td, th) {
@@ -1207,6 +1214,9 @@
1207
1214
 
1208
1215
  /* Segmented control --------------------------------------------------- */
1209
1216
  .ef-segmented {
1217
+ --ef-color-text-secondary: var(--ef-color-text-on-secondary-surface, #3a403c);
1218
+ --ef-color-text-muted: var(--ef-color-text-on-secondary-surface, #3a403c);
1219
+ --ef-surface-accent-text-color: var(--ef-color-text-primary, #171a18);
1210
1220
  max-inline-size: 100%;
1211
1221
  display: inline-flex;
1212
1222
  flex-wrap: wrap;
@@ -1430,6 +1440,9 @@
1430
1440
  }
1431
1441
 
1432
1442
  .ef-menu__list :where(button, a):hover {
1443
+ --ef-color-text-secondary: var(--ef-color-text-on-secondary-surface, #3a403c);
1444
+ --ef-color-text-muted: var(--ef-color-text-on-secondary-surface, #3a403c);
1445
+ --ef-surface-accent-text-color: var(--ef-color-text-primary, #171a18);
1433
1446
  background: var(--ef-color-surface-secondary, #e3e0d7);
1434
1447
  }
1435
1448
 
@@ -1821,7 +1834,7 @@
1821
1834
  }
1822
1835
 
1823
1836
  .ef-component-kicker {
1824
- color: var(--ef-color-accent-secondary, #47756b);
1837
+ color: var(--ef-surface-accent-text-color, var(--ef-color-accent-secondary, #47756b));
1825
1838
  font-family: var(--ef-primitive-font-family-mono, ui-monospace, monospace);
1826
1839
  font-size: 0.6875rem;
1827
1840
  letter-spacing: 0.08em;
@@ -1968,6 +1981,9 @@
1968
1981
  }
1969
1982
 
1970
1983
  .ef-data-grid th {
1984
+ --ef-color-text-secondary: var(--ef-color-text-on-secondary-surface, #3a403c);
1985
+ --ef-color-text-muted: var(--ef-color-text-on-secondary-surface, #3a403c);
1986
+ --ef-surface-accent-text-color: var(--ef-color-text-primary, #171a18);
1971
1987
  background: var(--ef-color-surface-secondary, #e3e0d7);
1972
1988
  color: var(--ef-color-text-primary, #171a18);
1973
1989
  font-size: 0.75rem;
@@ -2057,6 +2073,9 @@
2057
2073
  }
2058
2074
 
2059
2075
  .ef-tabs__list [aria-selected="true"] {
2076
+ --ef-color-text-secondary: var(--ef-color-text-on-secondary-surface, #3a403c);
2077
+ --ef-color-text-muted: var(--ef-color-text-on-secondary-surface, #3a403c);
2078
+ --ef-surface-accent-text-color: var(--ef-color-text-primary, #171a18);
2060
2079
  background: var(--ef-color-surface-secondary, #e3e0d7);
2061
2080
  translate: 0 0;
2062
2081
  }
@@ -2234,6 +2253,9 @@
2234
2253
 
2235
2254
  @starting-style {
2236
2255
  :where([data-ef-value-change]) {
2256
+ --ef-color-text-secondary: var(--ef-color-text-on-secondary-surface, #3a403c);
2257
+ --ef-color-text-muted: var(--ef-color-text-on-secondary-surface, #3a403c);
2258
+ --ef-surface-accent-text-color: var(--ef-color-text-primary, #171a18);
2237
2259
  background-color: var(--ef-color-surface-secondary, #e3e0d7);
2238
2260
  }
2239
2261
  }
@@ -2702,6 +2724,9 @@
2702
2724
  }
2703
2725
 
2704
2726
  .ef-file-upload__drop {
2727
+ --ef-color-text-secondary: var(--ef-color-text-on-secondary-surface, #3a403c);
2728
+ --ef-color-text-muted: var(--ef-color-text-on-secondary-surface, #3a403c);
2729
+ --ef-surface-accent-text-color: var(--ef-color-text-primary, #171a18);
2705
2730
  padding: 1.5rem;
2706
2731
  border: 1px dashed var(--ef-color-border-functional, #3a403c);
2707
2732
  background: var(--ef-color-surface-secondary, #e3e0d7);
@@ -2754,7 +2779,7 @@
2754
2779
  }
2755
2780
  .ef-record-header__title h2 { margin: 0.15rem 0 0; }
2756
2781
  .ef-record-header__type {
2757
- color: var(--ef-color-accent-secondary, #47756b);
2782
+ color: var(--ef-surface-accent-text-color, var(--ef-color-accent-secondary, #47756b));
2758
2783
  font-family: var(--ef-primitive-font-family-mono, ui-monospace, monospace);
2759
2784
  font-size: 0.6875rem;
2760
2785
  letter-spacing: 0.08em;
@@ -2805,6 +2830,9 @@
2805
2830
  }
2806
2831
 
2807
2832
  .ef-master-detail__master a[aria-current="page"] {
2833
+ --ef-color-text-secondary: var(--ef-color-text-on-secondary-surface, #3a403c);
2834
+ --ef-color-text-muted: var(--ef-color-text-on-secondary-surface, #3a403c);
2835
+ --ef-surface-accent-text-color: var(--ef-color-text-primary, #171a18);
2808
2836
  border-inline-start: 0.35rem solid var(--ef-color-accent-primary, #905831);
2809
2837
  background: var(--ef-color-surface-secondary, #e3e0d7);
2810
2838
  }
@@ -2870,6 +2898,9 @@
2870
2898
  align-items: center;
2871
2899
  }
2872
2900
  .ef-preview-surface__canvas {
2901
+ --ef-color-text-secondary: var(--ef-color-text-on-secondary-surface, #3a403c);
2902
+ --ef-color-text-muted: var(--ef-color-text-on-secondary-surface, #3a403c);
2903
+ --ef-surface-accent-text-color: var(--ef-color-text-primary, #171a18);
2873
2904
  padding: clamp(1rem, 4vw, 3rem);
2874
2905
  background: var(--ef-color-surface-secondary, #e3e0d7);
2875
2906
  }
@@ -3194,6 +3225,9 @@
3194
3225
  }
3195
3226
 
3196
3227
  .ef-turn[data-ef-speaker="assistant"] {
3228
+ --ef-color-text-secondary: var(--ef-color-text-on-secondary-surface, #3a403c);
3229
+ --ef-color-text-muted: var(--ef-color-text-on-secondary-surface, #3a403c);
3230
+ --ef-surface-accent-text-color: var(--ef-color-text-primary, #171a18);
3197
3231
  background: var(--ef-color-surface-secondary, #e3e0d7);
3198
3232
  }
3199
3233
 
@@ -3403,6 +3437,9 @@
3403
3437
  }
3404
3438
 
3405
3439
  .ef-fault--inline {
3440
+ --ef-color-text-secondary: var(--ef-color-text-on-secondary-surface, #3a403c);
3441
+ --ef-color-text-muted: var(--ef-color-text-on-secondary-surface, #3a403c);
3442
+ --ef-surface-accent-text-color: var(--ef-color-text-primary, #171a18);
3406
3443
  grid-template-columns: auto minmax(0, 1fr) auto;
3407
3444
  padding: 0.75rem;
3408
3445
  background: var(--ef-color-surface-secondary, #e3e0d7);
@@ -3543,6 +3580,9 @@
3543
3580
  }
3544
3581
 
3545
3582
  .ef-diagnostic-status {
3583
+ --ef-color-text-secondary: var(--ef-color-text-on-secondary-surface, #3a403c);
3584
+ --ef-color-text-muted: var(--ef-color-text-on-secondary-surface, #3a403c);
3585
+ --ef-surface-accent-text-color: var(--ef-color-text-primary, #171a18);
3546
3586
  display: inline-flex;
3547
3587
  align-items: center;
3548
3588
  gap: var(--ef-primitive-spacing-2, 0.5rem);
@@ -3696,7 +3736,7 @@
3696
3736
  .ef-security-posture__blockers,.ef-security-blockers { border-inline-start:.35rem solid currentColor; }
3697
3737
  .ef-security-posture__qualification { color:var(--ef-color-text-secondary,#686d68); font-size:.8125rem; }
3698
3738
  .ef-security-state-matrix__grid { display:grid; grid-template-columns:repeat(auto-fit,minmax(7rem,1fr)); gap:.5rem; margin:0; }
3699
- .ef-security-state-matrix__grid div { border-block-start:.25rem solid currentColor; padding:.75rem; background:var(--ef-color-surface-secondary,#e3e0d7); }
3739
+ .ef-security-state-matrix__grid div { --ef-color-text-secondary: var(--ef-color-text-on-secondary-surface, #3a403c); --ef-color-text-muted: var(--ef-color-text-on-secondary-surface, #3a403c); --ef-surface-accent-text-color: var(--ef-color-text-primary, #171a18); border-block-start:.25rem solid currentColor; padding:.75rem; background:var(--ef-color-surface-secondary,#e3e0d7); }
3700
3740
  .ef-security-state-matrix__grid dt { font-size:.75rem; font-weight:700; }
3701
3741
  .ef-security-state-matrix__grid dd { margin:0; font-size:clamp(1.4rem,4vw,2rem); font-weight:750; }
3702
3742
  .ef-security-blockers ul { display:grid; gap:.75rem; padding-inline-start:1.25rem; }
@@ -3714,7 +3754,7 @@
3714
3754
  .ef-invariant-result dl { display:grid; grid-template-columns:repeat(auto-fit,minmax(min(10rem,100%),1fr)); gap:.75rem; }
3715
3755
  .ef-invariant-result dt { color:var(--ef-color-text-secondary,#686d68); font-size:.75rem; font-weight:700; } .ef-invariant-result dd { margin:0; overflow-wrap:anywhere; }
3716
3756
  :where(.ef-evidence-age,.ef-security-trend) ul { display:grid; gap:.5rem; margin:0; padding:0; list-style:none; }
3717
- :where(.ef-evidence-age,.ef-security-trend) li { display:grid; gap:.2rem; border-inline-start:.3rem solid currentColor; padding:.65rem .75rem; background:var(--ef-color-surface-secondary,#e3e0d7); }
3757
+ :where(.ef-evidence-age,.ef-security-trend) li { --ef-color-text-secondary: var(--ef-color-text-on-secondary-surface, #3a403c); --ef-color-text-muted: var(--ef-color-text-on-secondary-surface, #3a403c); --ef-surface-accent-text-color: var(--ef-color-text-primary, #171a18); display:grid; gap:.2rem; border-inline-start:.3rem solid currentColor; padding:.65rem .75rem; background:var(--ef-color-surface-secondary,#e3e0d7); }
3718
3758
  :where(.ef-evidence-age,.ef-security-trend) li span { overflow-wrap:anywhere; }
3719
3759
 
3720
3760
  /* Composition primitives ---------------------------------------------- */
@@ -3861,6 +3901,9 @@
3861
3901
  }
3862
3902
 
3863
3903
  [data-ef-drop="rejected"] {
3904
+ --ef-color-text-secondary: var(--ef-color-text-on-secondary-surface, #3a403c);
3905
+ --ef-color-text-muted: var(--ef-color-text-on-secondary-surface, #3a403c);
3906
+ --ef-surface-accent-text-color: var(--ef-color-text-primary, #171a18);
3864
3907
  outline: 2px dashed var(--ef-color-border-functional, #3a403c);
3865
3908
  outline-offset: 2px;
3866
3909
  background: var(--ef-color-surface-secondary, #e3e0d7);
@@ -5030,6 +5073,34 @@
5030
5073
  }
5031
5074
 
5032
5075
  @media (forced-colors: active) {
5076
+ /*
5077
+ * Forced-colors profile projection (FORMA-A11Y-002). Profiles set
5078
+ * literal palette colors that the semantic token projection
5079
+ * in foundations.css does not reach. Chromium forces color and
5080
+ * background but paints text with -webkit-text-fill-color, which keeps
5081
+ * the author color, so reference-profile text (#7aa7ff, #f2f2f2) was painted on a
5082
+ * forced white Canvas at 1.1-2.4:1. Every grid role resolves to a system
5083
+ * color instead; !important lets the user's forced-colors choice win over
5084
+ * any consumer-defined profile, as in the foundations projection.
5085
+ */
5086
+ .ef-character-grid,
5087
+ .ef-character-grid[data-ef-profile] {
5088
+ --ef-grid-background: Canvas !important;
5089
+ --ef-grid-foreground: CanvasText !important;
5090
+ --ef-grid-protected: CanvasText !important;
5091
+ --ef-grid-emphasis: CanvasText !important;
5092
+ --ef-grid-muted: CanvasText !important;
5093
+ --ef-grid-field: CanvasText !important;
5094
+ --ef-grid-field-surface: Canvas !important;
5095
+ --ef-grid-boundary: CanvasText !important;
5096
+ --ef-grid-focus: Highlight !important;
5097
+ --ef-grid-information: CanvasText !important;
5098
+ --ef-grid-success: CanvasText !important;
5099
+ --ef-grid-warning: CanvasText !important;
5100
+ --ef-grid-validation: CanvasText !important;
5101
+ --ef-grid-error: CanvasText !important;
5102
+ }
5103
+
5033
5104
  .ef-character-grid__viewport {
5034
5105
  border-color: CanvasText;
5035
5106
  }
@@ -6118,7 +6189,7 @@
6118
6189
  overflow-wrap: anywhere;
6119
6190
  }
6120
6191
 
6121
- .ef-ordinal-option:hover { background: var(--ef-color-surface-secondary, #e3e0d7); }
6192
+ .ef-ordinal-option:hover { --ef-color-text-secondary: var(--ef-color-text-on-secondary-surface, #3a403c); --ef-color-text-muted: var(--ef-color-text-on-secondary-surface, #3a403c); --ef-surface-accent-text-color: var(--ef-color-text-primary, #171a18); background: var(--ef-color-surface-secondary, #e3e0d7); }
6122
6193
  /* Light inertial press on the marker only; the option (hit target) never
6123
6194
  moves or shrinks (MOT-014). */
6124
6195
  .ef-ordinal-option:has(input:active:not(:disabled)) .ef-ordinal-option__marker { scale: 0.92; }
@@ -6203,6 +6274,9 @@
6203
6274
  .ef-choice:has(input[type="checkbox"])::before { border-radius: 0.2rem; }
6204
6275
 
6205
6276
  .ef-choice:has(input:checked) {
6277
+ --ef-color-text-secondary: var(--ef-color-text-on-secondary-surface, #3a403c);
6278
+ --ef-color-text-muted: var(--ef-color-text-on-secondary-surface, #3a403c);
6279
+ --ef-surface-accent-text-color: var(--ef-color-text-primary, #171a18);
6206
6280
  border-color: var(--ef-color-accent-primary, #905831);
6207
6281
  background: var(--ef-color-surface-secondary, #e3e0d7);
6208
6282
  }
@@ -6260,6 +6334,9 @@
6260
6334
  }
6261
6335
 
6262
6336
  .ef-validation-summary {
6337
+ --ef-color-text-secondary: var(--ef-color-text-on-secondary-surface, #3a403c);
6338
+ --ef-color-text-muted: var(--ef-color-text-on-secondary-surface, #3a403c);
6339
+ --ef-surface-accent-text-color: var(--ef-color-text-primary, #171a18);
6263
6340
  display: grid;
6264
6341
  grid-template-columns: auto minmax(0, 1fr);
6265
6342
  gap: var(--ef-primitive-spacing-3, 0.75rem);
@@ -6419,7 +6496,7 @@
6419
6496
 
6420
6497
  .ef-allocation__total[data-ef-state="invalid"] {
6421
6498
  border-block-start-width: 2px;
6422
- color: var(--ef-color-accent-primary, #905831);
6499
+ color: var(--ef-surface-accent-text-color, var(--ef-color-accent-primary, #905831));
6423
6500
  }
6424
6501
 
6425
6502
  /* Rule builder visual contract --------------------------------------- */
@@ -6485,6 +6562,9 @@
6485
6562
  }
6486
6563
 
6487
6564
  .ef-rule-builder__summary {
6565
+ --ef-color-text-secondary: var(--ef-color-text-on-secondary-surface, #3a403c);
6566
+ --ef-color-text-muted: var(--ef-color-text-on-secondary-surface, #3a403c);
6567
+ --ef-surface-accent-text-color: var(--ef-color-text-primary, #171a18);
6488
6568
  margin: 0;
6489
6569
  padding: var(--ef-primitive-spacing-3, 0.75rem) var(--ef-primitive-spacing-4, 1rem);
6490
6570
  border-block-start: 1px solid var(--ef-color-border-subtle, #e3e0d7);
@@ -6775,6 +6855,9 @@
6775
6855
  .ef-choice--media::before { display: none; }
6776
6856
 
6777
6857
  .ef-choice__media {
6858
+ --ef-color-text-secondary: var(--ef-color-text-on-secondary-surface, #3a403c);
6859
+ --ef-color-text-muted: var(--ef-color-text-on-secondary-surface, #3a403c);
6860
+ --ef-surface-accent-text-color: var(--ef-color-text-primary, #171a18);
6778
6861
  display: grid;
6779
6862
  place-items: center;
6780
6863
  overflow: hidden;
@@ -154,7 +154,7 @@
154
154
  overflow-wrap: anywhere;
155
155
  }
156
156
 
157
- .ef-ordinal-option:hover { background: var(--ef-color-surface-secondary, #e3e0d7); }
157
+ .ef-ordinal-option:hover { --ef-color-text-secondary: var(--ef-color-text-on-secondary-surface, #3a403c); --ef-color-text-muted: var(--ef-color-text-on-secondary-surface, #3a403c); --ef-surface-accent-text-color: var(--ef-color-text-primary, #171a18); background: var(--ef-color-surface-secondary, #e3e0d7); }
158
158
  /* Light inertial press on the marker only; the option (hit target) never
159
159
  moves or shrinks (MOT-014). */
160
160
  .ef-ordinal-option:has(input:active:not(:disabled)) .ef-ordinal-option__marker { scale: 0.92; }
@@ -239,6 +239,9 @@
239
239
  .ef-choice:has(input[type="checkbox"])::before { border-radius: 0.2rem; }
240
240
 
241
241
  .ef-choice:has(input:checked) {
242
+ --ef-color-text-secondary: var(--ef-color-text-on-secondary-surface, #3a403c);
243
+ --ef-color-text-muted: var(--ef-color-text-on-secondary-surface, #3a403c);
244
+ --ef-surface-accent-text-color: var(--ef-color-text-primary, #171a18);
242
245
  border-color: var(--ef-color-accent-primary, #905831);
243
246
  background: var(--ef-color-surface-secondary, #e3e0d7);
244
247
  }
@@ -296,6 +299,9 @@
296
299
  }
297
300
 
298
301
  .ef-validation-summary {
302
+ --ef-color-text-secondary: var(--ef-color-text-on-secondary-surface, #3a403c);
303
+ --ef-color-text-muted: var(--ef-color-text-on-secondary-surface, #3a403c);
304
+ --ef-surface-accent-text-color: var(--ef-color-text-primary, #171a18);
299
305
  display: grid;
300
306
  grid-template-columns: auto minmax(0, 1fr);
301
307
  gap: var(--ef-primitive-spacing-3, 0.75rem);
@@ -455,7 +461,7 @@
455
461
 
456
462
  .ef-allocation__total[data-ef-state="invalid"] {
457
463
  border-block-start-width: 2px;
458
- color: var(--ef-color-accent-primary, #905831);
464
+ color: var(--ef-surface-accent-text-color, var(--ef-color-accent-primary, #905831));
459
465
  }
460
466
 
461
467
  /* Rule builder visual contract --------------------------------------- */
@@ -521,6 +527,9 @@
521
527
  }
522
528
 
523
529
  .ef-rule-builder__summary {
530
+ --ef-color-text-secondary: var(--ef-color-text-on-secondary-surface, #3a403c);
531
+ --ef-color-text-muted: var(--ef-color-text-on-secondary-surface, #3a403c);
532
+ --ef-surface-accent-text-color: var(--ef-color-text-primary, #171a18);
524
533
  margin: 0;
525
534
  padding: var(--ef-primitive-spacing-3, 0.75rem) var(--ef-primitive-spacing-4, 1rem);
526
535
  border-block-start: 1px solid var(--ef-color-border-subtle, #e3e0d7);
@@ -811,6 +820,9 @@
811
820
  .ef-choice--media::before { display: none; }
812
821
 
813
822
  .ef-choice__media {
823
+ --ef-color-text-secondary: var(--ef-color-text-on-secondary-surface, #3a403c);
824
+ --ef-color-text-muted: var(--ef-color-text-on-secondary-surface, #3a403c);
825
+ --ef-surface-accent-text-color: var(--ef-color-text-primary, #171a18);
814
826
  display: grid;
815
827
  place-items: center;
816
828
  overflow: hidden;
@@ -177,13 +177,13 @@
177
177
  "tokens.css"
178
178
  ],
179
179
  "bytes": {
180
- "all.css": 309758,
181
- "assessment.css": 34482,
180
+ "all.css": 316368,
181
+ "assessment.css": 35692,
182
182
  "brands/echelon.css": 3621,
183
183
  "brands/example-harbor.css": 3637,
184
184
  "brands/index.json": 335,
185
- "components.css": 198383,
186
- "foundations.css": 10893,
185
+ "components.css": 203118,
186
+ "foundations.css": 11558,
187
187
  "marketing.css": 45073,
188
188
  "patterns/active-filter-summary.html": 532,
189
189
  "patterns/alert.html": 384,
@@ -321,7 +321,7 @@
321
321
  "patterns/skeleton.html": 354,
322
322
  "patterns/skip-link.html": 186,
323
323
  "patterns/slider.html": 403,
324
- "patterns/spatial-canvas.html": 951,
324
+ "patterns/spatial-canvas.html": 976,
325
325
  "patterns/special-choice.html": 568,
326
326
  "patterns/spinner.html": 175,
327
327
  "patterns/split-pane.html": 348,
@@ -466,6 +466,9 @@
466
466
 
467
467
  /* Segmented control --------------------------------------------------- */
468
468
  .ef-segmented {
469
+ --ef-color-text-secondary: var(--ef-color-text-on-secondary-surface, #3a403c);
470
+ --ef-color-text-muted: var(--ef-color-text-on-secondary-surface, #3a403c);
471
+ --ef-surface-accent-text-color: var(--ef-color-text-primary, #171a18);
469
472
  max-inline-size: 100%;
470
473
  display: inline-flex;
471
474
  flex-wrap: wrap;
@@ -689,6 +692,9 @@
689
692
  }
690
693
 
691
694
  .ef-menu__list :where(button, a):hover {
695
+ --ef-color-text-secondary: var(--ef-color-text-on-secondary-surface, #3a403c);
696
+ --ef-color-text-muted: var(--ef-color-text-on-secondary-surface, #3a403c);
697
+ --ef-surface-accent-text-color: var(--ef-color-text-primary, #171a18);
692
698
  background: var(--ef-color-surface-secondary, #e3e0d7);
693
699
  }
694
700
 
@@ -1080,7 +1086,7 @@
1080
1086
  }
1081
1087
 
1082
1088
  .ef-component-kicker {
1083
- color: var(--ef-color-accent-secondary, #47756b);
1089
+ color: var(--ef-surface-accent-text-color, var(--ef-color-accent-secondary, #47756b));
1084
1090
  font-family: var(--ef-primitive-font-family-mono, ui-monospace, monospace);
1085
1091
  font-size: 0.6875rem;
1086
1092
  letter-spacing: 0.08em;
@@ -1227,6 +1233,9 @@
1227
1233
  }
1228
1234
 
1229
1235
  .ef-data-grid th {
1236
+ --ef-color-text-secondary: var(--ef-color-text-on-secondary-surface, #3a403c);
1237
+ --ef-color-text-muted: var(--ef-color-text-on-secondary-surface, #3a403c);
1238
+ --ef-surface-accent-text-color: var(--ef-color-text-primary, #171a18);
1230
1239
  background: var(--ef-color-surface-secondary, #e3e0d7);
1231
1240
  color: var(--ef-color-text-primary, #171a18);
1232
1241
  font-size: 0.75rem;
@@ -1316,6 +1325,9 @@
1316
1325
  }
1317
1326
 
1318
1327
  .ef-tabs__list [aria-selected="true"] {
1328
+ --ef-color-text-secondary: var(--ef-color-text-on-secondary-surface, #3a403c);
1329
+ --ef-color-text-muted: var(--ef-color-text-on-secondary-surface, #3a403c);
1330
+ --ef-surface-accent-text-color: var(--ef-color-text-primary, #171a18);
1319
1331
  background: var(--ef-color-surface-secondary, #e3e0d7);
1320
1332
  translate: 0 0;
1321
1333
  }
@@ -1493,6 +1505,9 @@
1493
1505
 
1494
1506
  @starting-style {
1495
1507
  :where([data-ef-value-change]) {
1508
+ --ef-color-text-secondary: var(--ef-color-text-on-secondary-surface, #3a403c);
1509
+ --ef-color-text-muted: var(--ef-color-text-on-secondary-surface, #3a403c);
1510
+ --ef-surface-accent-text-color: var(--ef-color-text-primary, #171a18);
1496
1511
  background-color: var(--ef-color-surface-secondary, #e3e0d7);
1497
1512
  }
1498
1513
  }
@@ -1961,6 +1976,9 @@
1961
1976
  }
1962
1977
 
1963
1978
  .ef-file-upload__drop {
1979
+ --ef-color-text-secondary: var(--ef-color-text-on-secondary-surface, #3a403c);
1980
+ --ef-color-text-muted: var(--ef-color-text-on-secondary-surface, #3a403c);
1981
+ --ef-surface-accent-text-color: var(--ef-color-text-primary, #171a18);
1964
1982
  padding: 1.5rem;
1965
1983
  border: 1px dashed var(--ef-color-border-functional, #3a403c);
1966
1984
  background: var(--ef-color-surface-secondary, #e3e0d7);
@@ -2013,7 +2031,7 @@
2013
2031
  }
2014
2032
  .ef-record-header__title h2 { margin: 0.15rem 0 0; }
2015
2033
  .ef-record-header__type {
2016
- color: var(--ef-color-accent-secondary, #47756b);
2034
+ color: var(--ef-surface-accent-text-color, var(--ef-color-accent-secondary, #47756b));
2017
2035
  font-family: var(--ef-primitive-font-family-mono, ui-monospace, monospace);
2018
2036
  font-size: 0.6875rem;
2019
2037
  letter-spacing: 0.08em;
@@ -2064,6 +2082,9 @@
2064
2082
  }
2065
2083
 
2066
2084
  .ef-master-detail__master a[aria-current="page"] {
2085
+ --ef-color-text-secondary: var(--ef-color-text-on-secondary-surface, #3a403c);
2086
+ --ef-color-text-muted: var(--ef-color-text-on-secondary-surface, #3a403c);
2087
+ --ef-surface-accent-text-color: var(--ef-color-text-primary, #171a18);
2067
2088
  border-inline-start: 0.35rem solid var(--ef-color-accent-primary, #905831);
2068
2089
  background: var(--ef-color-surface-secondary, #e3e0d7);
2069
2090
  }
@@ -2129,6 +2150,9 @@
2129
2150
  align-items: center;
2130
2151
  }
2131
2152
  .ef-preview-surface__canvas {
2153
+ --ef-color-text-secondary: var(--ef-color-text-on-secondary-surface, #3a403c);
2154
+ --ef-color-text-muted: var(--ef-color-text-on-secondary-surface, #3a403c);
2155
+ --ef-surface-accent-text-color: var(--ef-color-text-primary, #171a18);
2132
2156
  padding: clamp(1rem, 4vw, 3rem);
2133
2157
  background: var(--ef-color-surface-secondary, #e3e0d7);
2134
2158
  }
@@ -2453,6 +2477,9 @@
2453
2477
  }
2454
2478
 
2455
2479
  .ef-turn[data-ef-speaker="assistant"] {
2480
+ --ef-color-text-secondary: var(--ef-color-text-on-secondary-surface, #3a403c);
2481
+ --ef-color-text-muted: var(--ef-color-text-on-secondary-surface, #3a403c);
2482
+ --ef-surface-accent-text-color: var(--ef-color-text-primary, #171a18);
2456
2483
  background: var(--ef-color-surface-secondary, #e3e0d7);
2457
2484
  }
2458
2485
 
@@ -2662,6 +2689,9 @@
2662
2689
  }
2663
2690
 
2664
2691
  .ef-fault--inline {
2692
+ --ef-color-text-secondary: var(--ef-color-text-on-secondary-surface, #3a403c);
2693
+ --ef-color-text-muted: var(--ef-color-text-on-secondary-surface, #3a403c);
2694
+ --ef-surface-accent-text-color: var(--ef-color-text-primary, #171a18);
2665
2695
  grid-template-columns: auto minmax(0, 1fr) auto;
2666
2696
  padding: 0.75rem;
2667
2697
  background: var(--ef-color-surface-secondary, #e3e0d7);
@@ -2802,6 +2832,9 @@
2802
2832
  }
2803
2833
 
2804
2834
  .ef-diagnostic-status {
2835
+ --ef-color-text-secondary: var(--ef-color-text-on-secondary-surface, #3a403c);
2836
+ --ef-color-text-muted: var(--ef-color-text-on-secondary-surface, #3a403c);
2837
+ --ef-surface-accent-text-color: var(--ef-color-text-primary, #171a18);
2805
2838
  display: inline-flex;
2806
2839
  align-items: center;
2807
2840
  gap: var(--ef-primitive-spacing-2, 0.5rem);
@@ -2955,7 +2988,7 @@
2955
2988
  .ef-security-posture__blockers,.ef-security-blockers { border-inline-start:.35rem solid currentColor; }
2956
2989
  .ef-security-posture__qualification { color:var(--ef-color-text-secondary,#686d68); font-size:.8125rem; }
2957
2990
  .ef-security-state-matrix__grid { display:grid; grid-template-columns:repeat(auto-fit,minmax(7rem,1fr)); gap:.5rem; margin:0; }
2958
- .ef-security-state-matrix__grid div { border-block-start:.25rem solid currentColor; padding:.75rem; background:var(--ef-color-surface-secondary,#e3e0d7); }
2991
+ .ef-security-state-matrix__grid div { --ef-color-text-secondary: var(--ef-color-text-on-secondary-surface, #3a403c); --ef-color-text-muted: var(--ef-color-text-on-secondary-surface, #3a403c); --ef-surface-accent-text-color: var(--ef-color-text-primary, #171a18); border-block-start:.25rem solid currentColor; padding:.75rem; background:var(--ef-color-surface-secondary,#e3e0d7); }
2959
2992
  .ef-security-state-matrix__grid dt { font-size:.75rem; font-weight:700; }
2960
2993
  .ef-security-state-matrix__grid dd { margin:0; font-size:clamp(1.4rem,4vw,2rem); font-weight:750; }
2961
2994
  .ef-security-blockers ul { display:grid; gap:.75rem; padding-inline-start:1.25rem; }
@@ -2973,7 +3006,7 @@
2973
3006
  .ef-invariant-result dl { display:grid; grid-template-columns:repeat(auto-fit,minmax(min(10rem,100%),1fr)); gap:.75rem; }
2974
3007
  .ef-invariant-result dt { color:var(--ef-color-text-secondary,#686d68); font-size:.75rem; font-weight:700; } .ef-invariant-result dd { margin:0; overflow-wrap:anywhere; }
2975
3008
  :where(.ef-evidence-age,.ef-security-trend) ul { display:grid; gap:.5rem; margin:0; padding:0; list-style:none; }
2976
- :where(.ef-evidence-age,.ef-security-trend) li { display:grid; gap:.2rem; border-inline-start:.3rem solid currentColor; padding:.65rem .75rem; background:var(--ef-color-surface-secondary,#e3e0d7); }
3009
+ :where(.ef-evidence-age,.ef-security-trend) li { --ef-color-text-secondary: var(--ef-color-text-on-secondary-surface, #3a403c); --ef-color-text-muted: var(--ef-color-text-on-secondary-surface, #3a403c); --ef-surface-accent-text-color: var(--ef-color-text-primary, #171a18); display:grid; gap:.2rem; border-inline-start:.3rem solid currentColor; padding:.65rem .75rem; background:var(--ef-color-surface-secondary,#e3e0d7); }
2977
3010
  :where(.ef-evidence-age,.ef-security-trend) li span { overflow-wrap:anywhere; }
2978
3011
 
2979
3012
  /* Composition primitives ---------------------------------------------- */
@@ -3120,6 +3153,9 @@
3120
3153
  }
3121
3154
 
3122
3155
  [data-ef-drop="rejected"] {
3156
+ --ef-color-text-secondary: var(--ef-color-text-on-secondary-surface, #3a403c);
3157
+ --ef-color-text-muted: var(--ef-color-text-on-secondary-surface, #3a403c);
3158
+ --ef-surface-accent-text-color: var(--ef-color-text-primary, #171a18);
3123
3159
  outline: 2px dashed var(--ef-color-border-functional, #3a403c);
3124
3160
  outline-offset: 2px;
3125
3161
  background: var(--ef-color-surface-secondary, #e3e0d7);
@@ -4289,6 +4325,34 @@
4289
4325
  }
4290
4326
 
4291
4327
  @media (forced-colors: active) {
4328
+ /*
4329
+ * Forced-colors profile projection (FORMA-A11Y-002). Profiles set
4330
+ * literal palette colors that the semantic token projection
4331
+ * in foundations.css does not reach. Chromium forces color and
4332
+ * background but paints text with -webkit-text-fill-color, which keeps
4333
+ * the author color, so reference-profile text (#7aa7ff, #f2f2f2) was painted on a
4334
+ * forced white Canvas at 1.1-2.4:1. Every grid role resolves to a system
4335
+ * color instead; !important lets the user's forced-colors choice win over
4336
+ * any consumer-defined profile, as in the foundations projection.
4337
+ */
4338
+ .ef-character-grid,
4339
+ .ef-character-grid[data-ef-profile] {
4340
+ --ef-grid-background: Canvas !important;
4341
+ --ef-grid-foreground: CanvasText !important;
4342
+ --ef-grid-protected: CanvasText !important;
4343
+ --ef-grid-emphasis: CanvasText !important;
4344
+ --ef-grid-muted: CanvasText !important;
4345
+ --ef-grid-field: CanvasText !important;
4346
+ --ef-grid-field-surface: Canvas !important;
4347
+ --ef-grid-boundary: CanvasText !important;
4348
+ --ef-grid-focus: Highlight !important;
4349
+ --ef-grid-information: CanvasText !important;
4350
+ --ef-grid-success: CanvasText !important;
4351
+ --ef-grid-warning: CanvasText !important;
4352
+ --ef-grid-validation: CanvasText !important;
4353
+ --ef-grid-error: CanvasText !important;
4354
+ }
4355
+
4292
4356
  .ef-character-grid__viewport {
4293
4357
  border-color: CanvasText;
4294
4358
  }
@@ -37,8 +37,12 @@
37
37
  max-inline-size: 72ch;
38
38
  }
39
39
 
40
+ /*
41
+ * --ef-surface-accent-text-color is set by secondary-surface rules (see
42
+ * "Secondary-surface pairing" below); elsewhere accent text uses the accent.
43
+ */
40
44
  :where(a) {
41
- color: var(--ef-color-accent-primary, #905831);
45
+ color: var(--ef-surface-accent-text-color, var(--ef-color-accent-primary, #905831));
42
46
  text-decoration-thickness: 0.08em;
43
47
  text-underline-offset: 0.18em;
44
48
  }
@@ -76,6 +80,9 @@
76
80
  }
77
81
 
78
82
  :where(button, .ef-button):where(:not(:disabled)):hover {
83
+ --ef-color-text-secondary: var(--ef-color-text-on-secondary-surface, #3a403c);
84
+ --ef-color-text-muted: var(--ef-color-text-on-secondary-surface, #3a403c);
85
+ --ef-surface-accent-text-color: var(--ef-color-text-primary, #171a18);
79
86
  background: var(--ef-color-surface-secondary, #e3e0d7);
80
87
  }
81
88
 
@@ -111,7 +118,7 @@
111
118
  .ef-actions { display: flex; flex-wrap: wrap; gap: var(--ef-primitive-spacing-3, 0.75rem); align-items: center; }
112
119
  .ef-grid { display: grid; gap: var(--ef-grid-gap, var(--ef-primitive-spacing-4, 1rem)); grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--ef-grid-min, 16rem)), 1fr)); }
113
120
  .ef-section { padding-block: var(--ef-section-space, var(--ef-primitive-spacing-7, 3rem)); }
114
- .ef-surface { min-inline-size: 0; padding: var(--ef-surface-space, var(--ef-primitive-spacing-5, 1.5rem)); background: var(--ef-color-surface-secondary, #e3e0d7); color: var(--ef-color-text-on-secondary-surface, #3a403c); border: 1px solid var(--ef-color-border-subtle, #e3e0d7); }
121
+ .ef-surface { --ef-color-text-secondary: var(--ef-color-text-on-secondary-surface, #3a403c); --ef-color-text-muted: var(--ef-color-text-on-secondary-surface, #3a403c); --ef-surface-accent-text-color: var(--ef-color-text-primary, #171a18); min-inline-size: 0; padding: var(--ef-surface-space, var(--ef-primitive-spacing-5, 1.5rem)); background: var(--ef-color-surface-secondary, #e3e0d7); color: var(--ef-color-text-on-secondary-surface, #3a403c); border: 1px solid var(--ef-color-border-subtle, #e3e0d7); }
115
122
  .ef-surface :where(h1, h2, h3, h4, h5, h6, p) { color: inherit; }
116
123
 
117
124
  :where(h1, h2, h3, h4, h5, h6, p, a, label, legend, td, th) {
@@ -1,4 +1,4 @@
1
- /*! Forma 0.4.0 | forma-all.css | bundle echelon-marketing
1
+ /*! Forma 0.4.1 | forma-all.css | bundle echelon-marketing
2
2
  Complete Forma surface (application components, assessment, and marketing layers) for sites that also present Forma application patterns such as data grids or status lozenges.
3
3
  Generated by tools/PresentationBundler. Do not edit; pin by version and sha256. */
4
4
 
@@ -577,8 +577,12 @@
577
577
  max-inline-size: 72ch;
578
578
  }
579
579
 
580
+ /*
581
+ * --ef-surface-accent-text-color is set by secondary-surface rules (see
582
+ * "Secondary-surface pairing" below); elsewhere accent text uses the accent.
583
+ */
580
584
  :where(a) {
581
- color: var(--ef-color-accent-primary, #905831);
585
+ color: var(--ef-surface-accent-text-color, var(--ef-color-accent-primary, #905831));
582
586
  text-decoration-thickness: 0.08em;
583
587
  text-underline-offset: 0.18em;
584
588
  }
@@ -616,6 +620,9 @@
616
620
  }
617
621
 
618
622
  :where(button, .ef-button):where(:not(:disabled)):hover {
623
+ --ef-color-text-secondary: var(--ef-color-text-on-secondary-surface, #3a403c);
624
+ --ef-color-text-muted: var(--ef-color-text-on-secondary-surface, #3a403c);
625
+ --ef-surface-accent-text-color: var(--ef-color-text-primary, #171a18);
619
626
  background: var(--ef-color-surface-secondary, #e3e0d7);
620
627
  }
621
628
 
@@ -651,7 +658,7 @@
651
658
  .ef-actions { display: flex; flex-wrap: wrap; gap: var(--ef-primitive-spacing-3, 0.75rem); align-items: center; }
652
659
  .ef-grid { display: grid; gap: var(--ef-grid-gap, var(--ef-primitive-spacing-4, 1rem)); grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--ef-grid-min, 16rem)), 1fr)); }
653
660
  .ef-section { padding-block: var(--ef-section-space, var(--ef-primitive-spacing-7, 3rem)); }
654
- .ef-surface { min-inline-size: 0; padding: var(--ef-surface-space, var(--ef-primitive-spacing-5, 1.5rem)); background: var(--ef-color-surface-secondary, #e3e0d7); color: var(--ef-color-text-on-secondary-surface, #3a403c); border: 1px solid var(--ef-color-border-subtle, #e3e0d7); }
661
+ .ef-surface { --ef-color-text-secondary: var(--ef-color-text-on-secondary-surface, #3a403c); --ef-color-text-muted: var(--ef-color-text-on-secondary-surface, #3a403c); --ef-surface-accent-text-color: var(--ef-color-text-primary, #171a18); min-inline-size: 0; padding: var(--ef-surface-space, var(--ef-primitive-spacing-5, 1.5rem)); background: var(--ef-color-surface-secondary, #e3e0d7); color: var(--ef-color-text-on-secondary-surface, #3a403c); border: 1px solid var(--ef-color-border-subtle, #e3e0d7); }
655
662
  .ef-surface :where(h1, h2, h3, h4, h5, h6, p) { color: inherit; }
656
663
 
657
664
  :where(h1, h2, h3, h4, h5, h6, p, a, label, legend, td, th) {
@@ -1212,6 +1219,9 @@
1212
1219
 
1213
1220
  /* Segmented control --------------------------------------------------- */
1214
1221
  .ef-segmented {
1222
+ --ef-color-text-secondary: var(--ef-color-text-on-secondary-surface, #3a403c);
1223
+ --ef-color-text-muted: var(--ef-color-text-on-secondary-surface, #3a403c);
1224
+ --ef-surface-accent-text-color: var(--ef-color-text-primary, #171a18);
1215
1225
  max-inline-size: 100%;
1216
1226
  display: inline-flex;
1217
1227
  flex-wrap: wrap;
@@ -1435,6 +1445,9 @@
1435
1445
  }
1436
1446
 
1437
1447
  .ef-menu__list :where(button, a):hover {
1448
+ --ef-color-text-secondary: var(--ef-color-text-on-secondary-surface, #3a403c);
1449
+ --ef-color-text-muted: var(--ef-color-text-on-secondary-surface, #3a403c);
1450
+ --ef-surface-accent-text-color: var(--ef-color-text-primary, #171a18);
1438
1451
  background: var(--ef-color-surface-secondary, #e3e0d7);
1439
1452
  }
1440
1453
 
@@ -1826,7 +1839,7 @@
1826
1839
  }
1827
1840
 
1828
1841
  .ef-component-kicker {
1829
- color: var(--ef-color-accent-secondary, #47756b);
1842
+ color: var(--ef-surface-accent-text-color, var(--ef-color-accent-secondary, #47756b));
1830
1843
  font-family: var(--ef-primitive-font-family-mono, ui-monospace, monospace);
1831
1844
  font-size: 0.6875rem;
1832
1845
  letter-spacing: 0.08em;
@@ -1973,6 +1986,9 @@
1973
1986
  }
1974
1987
 
1975
1988
  .ef-data-grid th {
1989
+ --ef-color-text-secondary: var(--ef-color-text-on-secondary-surface, #3a403c);
1990
+ --ef-color-text-muted: var(--ef-color-text-on-secondary-surface, #3a403c);
1991
+ --ef-surface-accent-text-color: var(--ef-color-text-primary, #171a18);
1976
1992
  background: var(--ef-color-surface-secondary, #e3e0d7);
1977
1993
  color: var(--ef-color-text-primary, #171a18);
1978
1994
  font-size: 0.75rem;
@@ -2062,6 +2078,9 @@
2062
2078
  }
2063
2079
 
2064
2080
  .ef-tabs__list [aria-selected="true"] {
2081
+ --ef-color-text-secondary: var(--ef-color-text-on-secondary-surface, #3a403c);
2082
+ --ef-color-text-muted: var(--ef-color-text-on-secondary-surface, #3a403c);
2083
+ --ef-surface-accent-text-color: var(--ef-color-text-primary, #171a18);
2065
2084
  background: var(--ef-color-surface-secondary, #e3e0d7);
2066
2085
  translate: 0 0;
2067
2086
  }
@@ -2239,6 +2258,9 @@
2239
2258
 
2240
2259
  @starting-style {
2241
2260
  :where([data-ef-value-change]) {
2261
+ --ef-color-text-secondary: var(--ef-color-text-on-secondary-surface, #3a403c);
2262
+ --ef-color-text-muted: var(--ef-color-text-on-secondary-surface, #3a403c);
2263
+ --ef-surface-accent-text-color: var(--ef-color-text-primary, #171a18);
2242
2264
  background-color: var(--ef-color-surface-secondary, #e3e0d7);
2243
2265
  }
2244
2266
  }
@@ -2707,6 +2729,9 @@
2707
2729
  }
2708
2730
 
2709
2731
  .ef-file-upload__drop {
2732
+ --ef-color-text-secondary: var(--ef-color-text-on-secondary-surface, #3a403c);
2733
+ --ef-color-text-muted: var(--ef-color-text-on-secondary-surface, #3a403c);
2734
+ --ef-surface-accent-text-color: var(--ef-color-text-primary, #171a18);
2710
2735
  padding: 1.5rem;
2711
2736
  border: 1px dashed var(--ef-color-border-functional, #3a403c);
2712
2737
  background: var(--ef-color-surface-secondary, #e3e0d7);
@@ -2759,7 +2784,7 @@
2759
2784
  }
2760
2785
  .ef-record-header__title h2 { margin: 0.15rem 0 0; }
2761
2786
  .ef-record-header__type {
2762
- color: var(--ef-color-accent-secondary, #47756b);
2787
+ color: var(--ef-surface-accent-text-color, var(--ef-color-accent-secondary, #47756b));
2763
2788
  font-family: var(--ef-primitive-font-family-mono, ui-monospace, monospace);
2764
2789
  font-size: 0.6875rem;
2765
2790
  letter-spacing: 0.08em;
@@ -2810,6 +2835,9 @@
2810
2835
  }
2811
2836
 
2812
2837
  .ef-master-detail__master a[aria-current="page"] {
2838
+ --ef-color-text-secondary: var(--ef-color-text-on-secondary-surface, #3a403c);
2839
+ --ef-color-text-muted: var(--ef-color-text-on-secondary-surface, #3a403c);
2840
+ --ef-surface-accent-text-color: var(--ef-color-text-primary, #171a18);
2813
2841
  border-inline-start: 0.35rem solid var(--ef-color-accent-primary, #905831);
2814
2842
  background: var(--ef-color-surface-secondary, #e3e0d7);
2815
2843
  }
@@ -2875,6 +2903,9 @@
2875
2903
  align-items: center;
2876
2904
  }
2877
2905
  .ef-preview-surface__canvas {
2906
+ --ef-color-text-secondary: var(--ef-color-text-on-secondary-surface, #3a403c);
2907
+ --ef-color-text-muted: var(--ef-color-text-on-secondary-surface, #3a403c);
2908
+ --ef-surface-accent-text-color: var(--ef-color-text-primary, #171a18);
2878
2909
  padding: clamp(1rem, 4vw, 3rem);
2879
2910
  background: var(--ef-color-surface-secondary, #e3e0d7);
2880
2911
  }
@@ -3199,6 +3230,9 @@
3199
3230
  }
3200
3231
 
3201
3232
  .ef-turn[data-ef-speaker="assistant"] {
3233
+ --ef-color-text-secondary: var(--ef-color-text-on-secondary-surface, #3a403c);
3234
+ --ef-color-text-muted: var(--ef-color-text-on-secondary-surface, #3a403c);
3235
+ --ef-surface-accent-text-color: var(--ef-color-text-primary, #171a18);
3202
3236
  background: var(--ef-color-surface-secondary, #e3e0d7);
3203
3237
  }
3204
3238
 
@@ -3408,6 +3442,9 @@
3408
3442
  }
3409
3443
 
3410
3444
  .ef-fault--inline {
3445
+ --ef-color-text-secondary: var(--ef-color-text-on-secondary-surface, #3a403c);
3446
+ --ef-color-text-muted: var(--ef-color-text-on-secondary-surface, #3a403c);
3447
+ --ef-surface-accent-text-color: var(--ef-color-text-primary, #171a18);
3411
3448
  grid-template-columns: auto minmax(0, 1fr) auto;
3412
3449
  padding: 0.75rem;
3413
3450
  background: var(--ef-color-surface-secondary, #e3e0d7);
@@ -3548,6 +3585,9 @@
3548
3585
  }
3549
3586
 
3550
3587
  .ef-diagnostic-status {
3588
+ --ef-color-text-secondary: var(--ef-color-text-on-secondary-surface, #3a403c);
3589
+ --ef-color-text-muted: var(--ef-color-text-on-secondary-surface, #3a403c);
3590
+ --ef-surface-accent-text-color: var(--ef-color-text-primary, #171a18);
3551
3591
  display: inline-flex;
3552
3592
  align-items: center;
3553
3593
  gap: var(--ef-primitive-spacing-2, 0.5rem);
@@ -3701,7 +3741,7 @@
3701
3741
  .ef-security-posture__blockers,.ef-security-blockers { border-inline-start:.35rem solid currentColor; }
3702
3742
  .ef-security-posture__qualification { color:var(--ef-color-text-secondary,#686d68); font-size:.8125rem; }
3703
3743
  .ef-security-state-matrix__grid { display:grid; grid-template-columns:repeat(auto-fit,minmax(7rem,1fr)); gap:.5rem; margin:0; }
3704
- .ef-security-state-matrix__grid div { border-block-start:.25rem solid currentColor; padding:.75rem; background:var(--ef-color-surface-secondary,#e3e0d7); }
3744
+ .ef-security-state-matrix__grid div { --ef-color-text-secondary: var(--ef-color-text-on-secondary-surface, #3a403c); --ef-color-text-muted: var(--ef-color-text-on-secondary-surface, #3a403c); --ef-surface-accent-text-color: var(--ef-color-text-primary, #171a18); border-block-start:.25rem solid currentColor; padding:.75rem; background:var(--ef-color-surface-secondary,#e3e0d7); }
3705
3745
  .ef-security-state-matrix__grid dt { font-size:.75rem; font-weight:700; }
3706
3746
  .ef-security-state-matrix__grid dd { margin:0; font-size:clamp(1.4rem,4vw,2rem); font-weight:750; }
3707
3747
  .ef-security-blockers ul { display:grid; gap:.75rem; padding-inline-start:1.25rem; }
@@ -3719,7 +3759,7 @@
3719
3759
  .ef-invariant-result dl { display:grid; grid-template-columns:repeat(auto-fit,minmax(min(10rem,100%),1fr)); gap:.75rem; }
3720
3760
  .ef-invariant-result dt { color:var(--ef-color-text-secondary,#686d68); font-size:.75rem; font-weight:700; } .ef-invariant-result dd { margin:0; overflow-wrap:anywhere; }
3721
3761
  :where(.ef-evidence-age,.ef-security-trend) ul { display:grid; gap:.5rem; margin:0; padding:0; list-style:none; }
3722
- :where(.ef-evidence-age,.ef-security-trend) li { display:grid; gap:.2rem; border-inline-start:.3rem solid currentColor; padding:.65rem .75rem; background:var(--ef-color-surface-secondary,#e3e0d7); }
3762
+ :where(.ef-evidence-age,.ef-security-trend) li { --ef-color-text-secondary: var(--ef-color-text-on-secondary-surface, #3a403c); --ef-color-text-muted: var(--ef-color-text-on-secondary-surface, #3a403c); --ef-surface-accent-text-color: var(--ef-color-text-primary, #171a18); display:grid; gap:.2rem; border-inline-start:.3rem solid currentColor; padding:.65rem .75rem; background:var(--ef-color-surface-secondary,#e3e0d7); }
3723
3763
  :where(.ef-evidence-age,.ef-security-trend) li span { overflow-wrap:anywhere; }
3724
3764
 
3725
3765
  /* Composition primitives ---------------------------------------------- */
@@ -3866,6 +3906,9 @@
3866
3906
  }
3867
3907
 
3868
3908
  [data-ef-drop="rejected"] {
3909
+ --ef-color-text-secondary: var(--ef-color-text-on-secondary-surface, #3a403c);
3910
+ --ef-color-text-muted: var(--ef-color-text-on-secondary-surface, #3a403c);
3911
+ --ef-surface-accent-text-color: var(--ef-color-text-primary, #171a18);
3869
3912
  outline: 2px dashed var(--ef-color-border-functional, #3a403c);
3870
3913
  outline-offset: 2px;
3871
3914
  background: var(--ef-color-surface-secondary, #e3e0d7);
@@ -5035,6 +5078,34 @@
5035
5078
  }
5036
5079
 
5037
5080
  @media (forced-colors: active) {
5081
+ /*
5082
+ * Forced-colors profile projection (FORMA-A11Y-002). Profiles set
5083
+ * literal palette colors that the semantic token projection
5084
+ * in foundations.css does not reach. Chromium forces color and
5085
+ * background but paints text with -webkit-text-fill-color, which keeps
5086
+ * the author color, so reference-profile text (#7aa7ff, #f2f2f2) was painted on a
5087
+ * forced white Canvas at 1.1-2.4:1. Every grid role resolves to a system
5088
+ * color instead; !important lets the user's forced-colors choice win over
5089
+ * any consumer-defined profile, as in the foundations projection.
5090
+ */
5091
+ .ef-character-grid,
5092
+ .ef-character-grid[data-ef-profile] {
5093
+ --ef-grid-background: Canvas !important;
5094
+ --ef-grid-foreground: CanvasText !important;
5095
+ --ef-grid-protected: CanvasText !important;
5096
+ --ef-grid-emphasis: CanvasText !important;
5097
+ --ef-grid-muted: CanvasText !important;
5098
+ --ef-grid-field: CanvasText !important;
5099
+ --ef-grid-field-surface: Canvas !important;
5100
+ --ef-grid-boundary: CanvasText !important;
5101
+ --ef-grid-focus: Highlight !important;
5102
+ --ef-grid-information: CanvasText !important;
5103
+ --ef-grid-success: CanvasText !important;
5104
+ --ef-grid-warning: CanvasText !important;
5105
+ --ef-grid-validation: CanvasText !important;
5106
+ --ef-grid-error: CanvasText !important;
5107
+ }
5108
+
5038
5109
  .ef-character-grid__viewport {
5039
5110
  border-color: CanvasText;
5040
5111
  }
@@ -6123,7 +6194,7 @@
6123
6194
  overflow-wrap: anywhere;
6124
6195
  }
6125
6196
 
6126
- .ef-ordinal-option:hover { background: var(--ef-color-surface-secondary, #e3e0d7); }
6197
+ .ef-ordinal-option:hover { --ef-color-text-secondary: var(--ef-color-text-on-secondary-surface, #3a403c); --ef-color-text-muted: var(--ef-color-text-on-secondary-surface, #3a403c); --ef-surface-accent-text-color: var(--ef-color-text-primary, #171a18); background: var(--ef-color-surface-secondary, #e3e0d7); }
6127
6198
  /* Light inertial press on the marker only; the option (hit target) never
6128
6199
  moves or shrinks (MOT-014). */
6129
6200
  .ef-ordinal-option:has(input:active:not(:disabled)) .ef-ordinal-option__marker { scale: 0.92; }
@@ -6208,6 +6279,9 @@
6208
6279
  .ef-choice:has(input[type="checkbox"])::before { border-radius: 0.2rem; }
6209
6280
 
6210
6281
  .ef-choice:has(input:checked) {
6282
+ --ef-color-text-secondary: var(--ef-color-text-on-secondary-surface, #3a403c);
6283
+ --ef-color-text-muted: var(--ef-color-text-on-secondary-surface, #3a403c);
6284
+ --ef-surface-accent-text-color: var(--ef-color-text-primary, #171a18);
6211
6285
  border-color: var(--ef-color-accent-primary, #905831);
6212
6286
  background: var(--ef-color-surface-secondary, #e3e0d7);
6213
6287
  }
@@ -6265,6 +6339,9 @@
6265
6339
  }
6266
6340
 
6267
6341
  .ef-validation-summary {
6342
+ --ef-color-text-secondary: var(--ef-color-text-on-secondary-surface, #3a403c);
6343
+ --ef-color-text-muted: var(--ef-color-text-on-secondary-surface, #3a403c);
6344
+ --ef-surface-accent-text-color: var(--ef-color-text-primary, #171a18);
6268
6345
  display: grid;
6269
6346
  grid-template-columns: auto minmax(0, 1fr);
6270
6347
  gap: var(--ef-primitive-spacing-3, 0.75rem);
@@ -6424,7 +6501,7 @@
6424
6501
 
6425
6502
  .ef-allocation__total[data-ef-state="invalid"] {
6426
6503
  border-block-start-width: 2px;
6427
- color: var(--ef-color-accent-primary, #905831);
6504
+ color: var(--ef-surface-accent-text-color, var(--ef-color-accent-primary, #905831));
6428
6505
  }
6429
6506
 
6430
6507
  /* Rule builder visual contract --------------------------------------- */
@@ -6490,6 +6567,9 @@
6490
6567
  }
6491
6568
 
6492
6569
  .ef-rule-builder__summary {
6570
+ --ef-color-text-secondary: var(--ef-color-text-on-secondary-surface, #3a403c);
6571
+ --ef-color-text-muted: var(--ef-color-text-on-secondary-surface, #3a403c);
6572
+ --ef-surface-accent-text-color: var(--ef-color-text-primary, #171a18);
6493
6573
  margin: 0;
6494
6574
  padding: var(--ef-primitive-spacing-3, 0.75rem) var(--ef-primitive-spacing-4, 1rem);
6495
6575
  border-block-start: 1px solid var(--ef-color-border-subtle, #e3e0d7);
@@ -6780,6 +6860,9 @@
6780
6860
  .ef-choice--media::before { display: none; }
6781
6861
 
6782
6862
  .ef-choice__media {
6863
+ --ef-color-text-secondary: var(--ef-color-text-on-secondary-surface, #3a403c);
6864
+ --ef-color-text-muted: var(--ef-color-text-on-secondary-surface, #3a403c);
6865
+ --ef-surface-accent-text-color: var(--ef-color-text-primary, #171a18);
6783
6866
  display: grid;
6784
6867
  place-items: center;
6785
6868
  overflow: hidden;
@@ -1,4 +1,4 @@
1
- /*! Forma 0.4.0 | forma-echelon-marketing.css | bundle echelon-marketing
1
+ /*! Forma 0.4.1 | forma-echelon-marketing.css | bundle echelon-marketing
2
2
  Single-file Echelon marketing presentation: forma-marketing.css followed by the Echelon theme. Most sites load only this file.
3
3
  Generated by tools/PresentationBundler. Do not edit; pin by version and sha256. */
4
4
 
@@ -677,8 +677,12 @@
677
677
  max-inline-size: 72ch;
678
678
  }
679
679
 
680
+ /*
681
+ * --ef-surface-accent-text-color is set by secondary-surface rules (see
682
+ * "Secondary-surface pairing" below); elsewhere accent text uses the accent.
683
+ */
680
684
  :where(a) {
681
- color: var(--ef-color-accent-primary, #905831);
685
+ color: var(--ef-surface-accent-text-color, var(--ef-color-accent-primary, #905831));
682
686
  text-decoration-thickness: 0.08em;
683
687
  text-underline-offset: 0.18em;
684
688
  }
@@ -716,6 +720,9 @@
716
720
  }
717
721
 
718
722
  :where(button, .ef-button):where(:not(:disabled)):hover {
723
+ --ef-color-text-secondary: var(--ef-color-text-on-secondary-surface, #3a403c);
724
+ --ef-color-text-muted: var(--ef-color-text-on-secondary-surface, #3a403c);
725
+ --ef-surface-accent-text-color: var(--ef-color-text-primary, #171a18);
719
726
  background: var(--ef-color-surface-secondary, #e3e0d7);
720
727
  }
721
728
 
@@ -751,7 +758,7 @@
751
758
  .ef-actions { display: flex; flex-wrap: wrap; gap: var(--ef-primitive-spacing-3, 0.75rem); align-items: center; }
752
759
  .ef-grid { display: grid; gap: var(--ef-grid-gap, var(--ef-primitive-spacing-4, 1rem)); grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--ef-grid-min, 16rem)), 1fr)); }
753
760
  .ef-section { padding-block: var(--ef-section-space, var(--ef-primitive-spacing-7, 3rem)); }
754
- .ef-surface { min-inline-size: 0; padding: var(--ef-surface-space, var(--ef-primitive-spacing-5, 1.5rem)); background: var(--ef-color-surface-secondary, #e3e0d7); color: var(--ef-color-text-on-secondary-surface, #3a403c); border: 1px solid var(--ef-color-border-subtle, #e3e0d7); }
761
+ .ef-surface { --ef-color-text-secondary: var(--ef-color-text-on-secondary-surface, #3a403c); --ef-color-text-muted: var(--ef-color-text-on-secondary-surface, #3a403c); --ef-surface-accent-text-color: var(--ef-color-text-primary, #171a18); min-inline-size: 0; padding: var(--ef-surface-space, var(--ef-primitive-spacing-5, 1.5rem)); background: var(--ef-color-surface-secondary, #e3e0d7); color: var(--ef-color-text-on-secondary-surface, #3a403c); border: 1px solid var(--ef-color-border-subtle, #e3e0d7); }
755
762
  .ef-surface :where(h1, h2, h3, h4, h5, h6, p) { color: inherit; }
756
763
 
757
764
  :where(h1, h2, h3, h4, h5, h6, p, a, label, legend, td, th) {
@@ -1,4 +1,4 @@
1
- /*! Forma 0.4.0 | forma-marketing-theme-echelon.css | bundle echelon-marketing
1
+ /*! Forma 0.4.1 | forma-marketing-theme-echelon.css | bundle echelon-marketing
2
2
  Echelon Marketing Theme: compiled theme tokens and theme hooks. Load after forma-marketing.css.
3
3
  Generated by tools/PresentationBundler. Do not edit; pin by version and sha256. */
4
4
 
@@ -1,4 +1,4 @@
1
- /*! Forma 0.4.0 | forma-marketing.css | bundle echelon-marketing
1
+ /*! Forma 0.4.1 | forma-marketing.css | bundle echelon-marketing
2
2
  Brand-neutral marketing layer: core tokens, role defaults, Forma foundations, marketing foundations, components, and layouts.
3
3
  Generated by tools/PresentationBundler. Do not edit; pin by version and sha256. */
4
4
 
@@ -676,8 +676,12 @@
676
676
  max-inline-size: 72ch;
677
677
  }
678
678
 
679
+ /*
680
+ * --ef-surface-accent-text-color is set by secondary-surface rules (see
681
+ * "Secondary-surface pairing" below); elsewhere accent text uses the accent.
682
+ */
679
683
  :where(a) {
680
- color: var(--ef-color-accent-primary, #905831);
684
+ color: var(--ef-surface-accent-text-color, var(--ef-color-accent-primary, #905831));
681
685
  text-decoration-thickness: 0.08em;
682
686
  text-underline-offset: 0.18em;
683
687
  }
@@ -715,6 +719,9 @@
715
719
  }
716
720
 
717
721
  :where(button, .ef-button):where(:not(:disabled)):hover {
722
+ --ef-color-text-secondary: var(--ef-color-text-on-secondary-surface, #3a403c);
723
+ --ef-color-text-muted: var(--ef-color-text-on-secondary-surface, #3a403c);
724
+ --ef-surface-accent-text-color: var(--ef-color-text-primary, #171a18);
718
725
  background: var(--ef-color-surface-secondary, #e3e0d7);
719
726
  }
720
727
 
@@ -750,7 +757,7 @@
750
757
  .ef-actions { display: flex; flex-wrap: wrap; gap: var(--ef-primitive-spacing-3, 0.75rem); align-items: center; }
751
758
  .ef-grid { display: grid; gap: var(--ef-grid-gap, var(--ef-primitive-spacing-4, 1rem)); grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--ef-grid-min, 16rem)), 1fr)); }
752
759
  .ef-section { padding-block: var(--ef-section-space, var(--ef-primitive-spacing-7, 3rem)); }
753
- .ef-surface { min-inline-size: 0; padding: var(--ef-surface-space, var(--ef-primitive-spacing-5, 1.5rem)); background: var(--ef-color-surface-secondary, #e3e0d7); color: var(--ef-color-text-on-secondary-surface, #3a403c); border: 1px solid var(--ef-color-border-subtle, #e3e0d7); }
760
+ .ef-surface { --ef-color-text-secondary: var(--ef-color-text-on-secondary-surface, #3a403c); --ef-color-text-muted: var(--ef-color-text-on-secondary-surface, #3a403c); --ef-surface-accent-text-color: var(--ef-color-text-primary, #171a18); min-inline-size: 0; padding: var(--ef-surface-space, var(--ef-primitive-spacing-5, 1.5rem)); background: var(--ef-color-surface-secondary, #e3e0d7); color: var(--ef-color-text-on-secondary-surface, #3a403c); border: 1px solid var(--ef-color-border-subtle, #e3e0d7); }
754
761
  .ef-surface :where(h1, h2, h3, h4, h5, h6, p) { color: inherit; }
755
762
 
756
763
  :where(h1, h2, h3, h4, h5, h6, p, a, label, legend, td, th) {
@@ -1,15 +1,15 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "forma": "0.4.0",
3
+ "forma": "0.4.1",
4
4
  "bundle": "echelon-marketing",
5
5
  "description": "Forma presentation artifacts for Echelon marketing sites. Every artifact is a single self-contained CSS file with no imports or relative URLs.",
6
- "releaseTag": "v0.4.0",
6
+ "releaseTag": "v0.4.1",
7
7
  "artifacts": [
8
8
  {
9
9
  "file": "forma-marketing.css",
10
10
  "description": "Brand-neutral marketing layer: core tokens, role defaults, Forma foundations, marketing foundations, components, and layouts.",
11
- "bytes": 77452,
12
- "sha256": "e9f2f952cbec98bbdf270d8a6ed639fa8abc57d45053a78acbb85775102f35ea",
11
+ "bytes": 78117,
12
+ "sha256": "28874da37c70ac0f820a73d7a39e2e44a9fcc04df3ed213e424a9f3271a65c03",
13
13
  "sources": [
14
14
  "dist/tokens.css",
15
15
  "src/marketing/roles.css",
@@ -23,7 +23,7 @@
23
23
  "file": "forma-marketing-theme-echelon.css",
24
24
  "description": "Echelon Marketing Theme: compiled theme tokens and theme hooks. Load after forma-marketing.css.",
25
25
  "bytes": 6295,
26
- "sha256": "295da09137526ef046ec46101db12231755d13b5ce5377a180f34ea1064417c6",
26
+ "sha256": "01deabdbc7fc522c56e261657e62a06b084876b920a117da6e78e81b5ae952ef",
27
27
  "sources": [
28
28
  "build/marketing/echelon-marketing.tokens.css",
29
29
  "themes/echelon/marketing.css"
@@ -32,8 +32,8 @@
32
32
  {
33
33
  "file": "forma-echelon-marketing.css",
34
34
  "description": "Single-file Echelon marketing presentation: forma-marketing.css followed by the Echelon theme. Most sites load only this file.",
35
- "bytes": 83592,
36
- "sha256": "c0634b649d91f3a4fda166c3b926655fd1dc0270406e0a2bb43dc38303fa7709",
35
+ "bytes": 84257,
36
+ "sha256": "bf6be3078b577d013fa9eacd50a9dcf71afba73382cf82b41c3069502d2b7212",
37
37
  "sources": [
38
38
  "artifact:forma-marketing.css",
39
39
  "artifact:forma-marketing-theme-echelon.css"
@@ -42,8 +42,8 @@
42
42
  {
43
43
  "file": "forma-all.css",
44
44
  "description": "Complete Forma surface (application components, assessment, and marketing layers) for sites that also present Forma application patterns such as data grids or status lozenges.",
45
- "bytes": 310120,
46
- "sha256": "0d74d63c0cf65c732e32c1cdc66d241cec660b198b1151c54b2edafc5e32fa68",
45
+ "bytes": 316730,
46
+ "sha256": "84dd284067615b97e29ebaba34de54daf6204a3d99cabdc59e6f786b44ad35e3",
47
47
  "sources": [
48
48
  "dist/all.css"
49
49
  ]
@@ -1,4 +1,4 @@
1
- e9f2f952cbec98bbdf270d8a6ed639fa8abc57d45053a78acbb85775102f35ea forma-marketing.css
2
- 295da09137526ef046ec46101db12231755d13b5ce5377a180f34ea1064417c6 forma-marketing-theme-echelon.css
3
- c0634b649d91f3a4fda166c3b926655fd1dc0270406e0a2bb43dc38303fa7709 forma-echelon-marketing.css
4
- 0d74d63c0cf65c732e32c1cdc66d241cec660b198b1151c54b2edafc5e32fa68 forma-all.css
1
+ 28874da37c70ac0f820a73d7a39e2e44a9fcc04df3ed213e424a9f3271a65c03 forma-marketing.css
2
+ 01deabdbc7fc522c56e261657e62a06b084876b920a117da6e78e81b5ae952ef forma-marketing-theme-echelon.css
3
+ bf6be3078b577d013fa9eacd50a9dcf71afba73382cf82b41c3069502d2b7212 forma-echelon-marketing.css
4
+ 84dd284067615b97e29ebaba34de54daf6204a3d99cabdc59e6f786b44ad35e3 forma-all.css
@@ -5,8 +5,8 @@
5
5
  </header>
6
6
  <div class="ef-spatial-canvas__viewport" tabindex="0" aria-label="Scrollable system map">
7
7
  <div class="ef-spatial-canvas__surface">
8
- <article class="ef-surface"><h3>Billing</h3><p>Selected node</p></article>
9
- <article class="ef-surface"><h3>Chrona</h3><p>Time source</p></article>
8
+ <article class="ef-surface" id="billing"><h3>Billing</h3><p>Selected node</p></article>
9
+ <article class="ef-surface" id="chrona"><h3>Chrona</h3><p>Time source</p></article>
10
10
  </div>
11
11
  </div>
12
12
  <details class="ef-spatial-canvas__index"><summary>Objects in this view</summary><nav aria-label="Canvas objects"><a href="#billing">Billing</a><a href="#chrona">Chrona</a></nav></details>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@echelon-foundry/design-system",
3
- "version": "0.4.0",
3
+ "version": "0.4.1-main.224.1",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "Zero-runtime HTML and CSS design system for Echelon Foundry applications.",
@@ -27,7 +27,8 @@
27
27
  "./contracts/diagram-presentation.json": "./contracts/diagram-presentation.json",
28
28
  "./workflow/forma-workflow.schema.json": "./schemas/workflow/1.0/forma-workflow.schema.json",
29
29
  "./contracts/workflow-capabilities.json": "./contracts/workflow-capabilities.json",
30
- "./workflow/examples/*": "./examples/workflows/forma/workflows/*"
30
+ "./workflow/examples/*": "./examples/workflows/forma/workflows/*",
31
+ "./contracts/machine-operability.json": "./contracts/machine-operability.json"
31
32
  },
32
33
  "files": [
33
34
  "dist",
@@ -42,7 +43,9 @@
42
43
  "contracts/workflow-capabilities.json",
43
44
  "examples/workflows/forma/workflows",
44
45
  "examples/workflows/fixtures.json",
45
- "docs/workflow"
46
+ "docs/workflow",
47
+ "contracts/machine-operability.json",
48
+ "CHANGELOG.md"
46
49
  ],
47
50
  "scripts": {
48
51
  "clean": "node tools/clean.mjs",
@@ -62,7 +65,8 @@
62
65
  "site:mobile": "playwright test --config=playwright.site.config.mjs",
63
66
  "pack:verify": "npm run build && npm pack --dry-run",
64
67
  "test:package": "node --test tests/package-contract.test.mjs",
65
- "test:css": "node --test tests/css-source.test.mjs tests/diagram-contract.test.mjs",
68
+ "test:css": "node --test tests/css-source.test.mjs tests/dist-css.test.mjs tests/contrast-pairs.test.mjs tests/diagram-contract.test.mjs",
69
+ "test:contrast": "node --test tests/contrast-pairs.test.mjs && playwright test tests/browser/pattern-contrast.spec.mjs --project=chromium",
66
70
  "brands:build": "dotnet run --project tools/BrandCompiler/BrandCompiler.fsproj -- brands dist/brands",
67
71
  "test:brands": "node --test tests/brand-compiler.test.mjs",
68
72
  "test:character-grid": "node --test tests/character-grid.test.mjs",
@@ -71,7 +75,7 @@
71
75
  "test:marketing": "node --test tests/marketing-tokens.test.mjs tests/marketing-distribution.test.mjs tests/marketing-structure.test.mjs tests/site-css-policy.test.mjs",
72
76
  "example:install": "mkdir -p build/example && cp examples/echelon-marketing-site/forma.lock build/example/forma.lock && bash actions/install-presentation/install.sh --lock build/example/forma.lock --source dist/marketing --update --output examples/echelon-marketing-site/assets/forma",
73
77
  "policy:check": "dotnet run --project tools/SiteCssPolicy/SiteCssPolicy.fsproj --",
74
- "release:check": "npm run build && npm run test:tokens && npm run test:brands && npm run test:runtime && npm run test:motion && npm run test:marketing && npm run test:character-grid && npm run test:css && npm run test:package && playwright test tests/browser/marketing.spec.mjs && npm run site:check",
78
+ "release:check": "npm run build && npm run test:tokens && npm run test:brands && npm run test:runtime && npm run test:motion && npm run test:marketing && npm run test:character-grid && npm run test:css && npm run test:package && npm run test:machine && playwright test tests/browser/marketing.spec.mjs && npm run site:check",
75
79
  "test:figma": "node --test tests/figma-contract.test.mjs",
76
80
  "catalog:check": "node tools/catalog/validate.mjs && node tools/catalog/inventory.mjs --check",
77
81
  "catalog:inventory": "node tools/catalog/inventory.mjs",
@@ -80,7 +84,8 @@
80
84
  "workflow:validate": "dotnet run --project src/workflow/Forma.Workflow.Cli -c Release -- validate examples/workflows/forma/workflows/*.forma-workflow.json",
81
85
  "test:workflow-package": "node --test tests/workflow-package.test.mjs",
82
86
  "test:workflow-browser": "playwright test tests/browser/workflow-static.spec.mjs tests/browser/workflow-embed.spec.mjs",
83
- "workflow:check": "npm run workflow:test && npm run workflow:build && npm run test:workflow-package && npm run test:workflow-browser"
87
+ "workflow:check": "npm run workflow:test && npm run workflow:build && npm run test:workflow-package && npm run test:workflow-browser",
88
+ "test:machine": "playwright test tests/browser/machine-operability.spec.mjs"
84
89
  },
85
90
  "devDependencies": {
86
91
  "@axe-core/playwright": "4.13.0",
@@ -100,6 +105,7 @@
100
105
  "zero-runtime",
101
106
  "marketing-presentation",
102
107
  "accessibility",
103
- "workflow"
108
+ "workflow",
109
+ "machine-operability"
104
110
  ]
105
111
  }
@@ -5,8 +5,8 @@
5
5
  </header>
6
6
  <div class="ef-spatial-canvas__viewport" tabindex="0" aria-label="Scrollable system map">
7
7
  <div class="ef-spatial-canvas__surface">
8
- <article class="ef-surface"><h3>Billing</h3><p>Selected node</p></article>
9
- <article class="ef-surface"><h3>Chrona</h3><p>Time source</p></article>
8
+ <article class="ef-surface" id="billing"><h3>Billing</h3><p>Selected node</p></article>
9
+ <article class="ef-surface" id="chrona"><h3>Chrona</h3><p>Time source</p></article>
10
10
  </div>
11
11
  </div>
12
12
  <details class="ef-spatial-canvas__index"><summary>Objects in this view</summary><nav aria-label="Canvas objects"><a href="#billing">Billing</a><a href="#chrona">Chrona</a></nav></details>