okchroma 0.1.6 → 0.2.0
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/README.md +4 -4
- package/dist-lib/index.cjs +230 -228
- package/dist-lib/index.mjs +230 -228
- package/dist-lib/types/engine/alphaPapers.d.ts +1 -1
- package/dist-lib/types/engine/collision.d.ts +3 -3
- package/dist-lib/types/engine/colorEngine.d.ts +3 -3
- package/dist-lib/types/engine/requirements/producers.d.ts +1 -1
- package/dist-lib/types/engine/requirements/spec.d.ts +6 -5
- package/dist-lib/types/engine/resolve.d.ts +1 -1
- package/dist-lib/types/engine/stopTable.d.ts +6 -6
- package/dist-lib/types/engine/tokenNames.d.ts +2 -2
- package/dist-lib/types/index.d.ts +1 -1
- package/package.json +3 -3
- package/tokens/semantic.css +113 -113
package/dist-lib/index.mjs
CHANGED
|
@@ -203,12 +203,12 @@ var SCALE_C_LIGHT = {
|
|
|
203
203
|
6: { base: 0.068, sat: 0.85 },
|
|
204
204
|
7: { base: 0.086, sat: 0.78 },
|
|
205
205
|
8: { base: 0.142, sat: 0.78 },
|
|
206
|
-
9: {
|
|
206
|
+
9: { textMult: 0.95, textMaxC: 0.15, chromaFloor: chromaFloorBase(10) },
|
|
207
207
|
// ink-10 keeps the FIRST-text register (ink-9's row, C49): the retired hover law
|
|
208
208
|
// evaluated ink-9's chroma register at the between L, so the same params reproduce it;
|
|
209
209
|
// the damped strong register below belongs to the top text stop alone.
|
|
210
|
-
10: {
|
|
211
|
-
11: {
|
|
210
|
+
10: { textMult: 0.95, textMaxC: 0.15, chromaFloor: chromaFloorBase(10) },
|
|
211
|
+
11: { textMult: 0.5, textMaxC: 0.08, chromaFloor: chromaFloorBase(11) }
|
|
212
212
|
};
|
|
213
213
|
var SCALE_C_DARK = {
|
|
214
214
|
0: { sat: 0.4 },
|
|
@@ -220,9 +220,9 @@ var SCALE_C_DARK = {
|
|
|
220
220
|
6: { sat: 0.76 },
|
|
221
221
|
7: { sat: 0.8 },
|
|
222
222
|
8: { sat: 0.84 },
|
|
223
|
-
9: {
|
|
224
|
-
10: {
|
|
225
|
-
11: {
|
|
223
|
+
9: { textMult: 0.95, textMaxC: 0.12, chromaFloor: chromaFloorBase(10) },
|
|
224
|
+
10: { textMult: 0.95, textMaxC: 0.12, chromaFloor: chromaFloorBase(10) },
|
|
225
|
+
11: { textMult: 0.62, textMaxC: 0.045, chromaFloor: chromaFloorBase(11) }
|
|
226
226
|
};
|
|
227
227
|
var DARK_CTA_C = {
|
|
228
228
|
brand: {
|
|
@@ -239,10 +239,10 @@ var DARK_CTA_C = {
|
|
|
239
239
|
};
|
|
240
240
|
var STOP_8_NONTEXT_CONTRAST = 3;
|
|
241
241
|
var DARK_BAND_TOP_LIFT = 1.19;
|
|
242
|
-
var
|
|
243
|
-
var
|
|
244
|
-
var
|
|
245
|
-
var
|
|
242
|
+
var PENCIL_9_CONTRAST = 4.5;
|
|
243
|
+
var PEN_10_CONTRAST = 4.5;
|
|
244
|
+
var PEN_11_CONTRAST_FLOOR = 7;
|
|
245
|
+
var PEN_70_GROUND = {
|
|
246
246
|
wcag: {
|
|
247
247
|
light: { L: 0.3334966864733433, C: 0.07399966383476321, H: 104.26776675496032 },
|
|
248
248
|
dark: { L: 0.907688606079988, C: 0.045, H: 293.66431934911327 }
|
|
@@ -318,7 +318,7 @@ var NEUTRAL_TINT_POINTS = {
|
|
|
318
318
|
[0.95, 0.895],
|
|
319
319
|
// paper-3 ─┘
|
|
320
320
|
[0.924, 1],
|
|
321
|
-
// wash-4 ─┐ peak: the mid-
|
|
321
|
+
// wash-4 ─┐ peak: the mid-highlighter band, the neutral's most-branded moment
|
|
322
322
|
[0.892, 1],
|
|
323
323
|
// wash-5 ─┘
|
|
324
324
|
[0.852, 0.842],
|
|
@@ -326,7 +326,7 @@ var NEUTRAL_TINT_POINTS = {
|
|
|
326
326
|
[0.801, 0.653],
|
|
327
327
|
// wash-7 │
|
|
328
328
|
[0.738, 0.505],
|
|
329
|
-
//
|
|
329
|
+
// crayon-26
|
|
330
330
|
[0.6, 0.4],
|
|
331
331
|
// knee (ex-scaffold) the drop-off: hue fades as you climb
|
|
332
332
|
[0.56, 0.347],
|
|
@@ -352,7 +352,7 @@ var NEUTRAL_TINT_POINTS = {
|
|
|
352
352
|
[0.42, 0.653],
|
|
353
353
|
// wash-7
|
|
354
354
|
[0.55, 0.505],
|
|
355
|
-
//
|
|
355
|
+
// crayon-26
|
|
356
356
|
[0.6, 0.4],
|
|
357
357
|
// knee (ex-scaffold)
|
|
358
358
|
[0.64, 0.347],
|
|
@@ -721,26 +721,136 @@ function perceptualDarkC(L, H2, nativeC, keep = KEEP_DARK, gamut = MASTER_GAMUT)
|
|
|
721
721
|
return solveCForApparent(L, H2, grayApparentL(L, gamut) + keep * meanBoost(L, nativeC, gamut), gamut);
|
|
722
722
|
}
|
|
723
723
|
|
|
724
|
+
// src/engine/tokenNames.ts
|
|
725
|
+
var SHARED_NAMES = {
|
|
726
|
+
1: "paper-1",
|
|
727
|
+
2: "paper-3",
|
|
728
|
+
// stop 3 renamed wash-3 → paper-3 (owner 2026-07-24, elevation round): it is a
|
|
729
|
+
// PLANE in both themes (light sink / dark pop), so it belongs to the surface band.
|
|
730
|
+
// NAME ONLY — generation is index-keyed and unchanged; the highlighter-collision machinery
|
|
731
|
+
// (collision.ts HIGHLIGHTER_STOPS) deliberately still spans stops 3–7. (The requirement
|
|
732
|
+
// spec's `group` label followed the band to 'paper' on 2026-08-31 — labels only,
|
|
733
|
+
// the spans never moved; see spec.ts groupOf.)
|
|
734
|
+
// Stage B (owner 2026-08-07, names only): relabeled to the ROOT_L-derived digit,
|
|
735
|
+
// paper-5 — same band, same index.
|
|
736
|
+
3: "paper-5",
|
|
737
|
+
4: "highlighter-8",
|
|
738
|
+
5: "highlighter-11",
|
|
739
|
+
6: "highlighter-15",
|
|
740
|
+
7: "highlighter-20",
|
|
741
|
+
8: "crayon-26",
|
|
742
|
+
// THE PEN BAND (C49, owner 2026-08-05): the first text stop + emphasis fill (the
|
|
743
|
+
// 2026-07-29 highlight collapse — the old highlight-9 and on-highlight are
|
|
744
|
+
// deleted; this stop carries both jobs, its on-color a paper token), the between
|
|
745
|
+
// text stop (a value the retired text-cta hover state used to generate bespokely,
|
|
746
|
+
// promoted to a normal stop), and the strong text stop. The three read as states
|
|
747
|
+
// ARE the text-style cta (owner 2026-08-12). C49 restored the top
|
|
748
|
+
// two pre-collapse stop INDICES (11, and the off-scale anchor's 12 — emitted as a
|
|
749
|
+
// literal in cssRender, not through this table) with the between stop taking the
|
|
750
|
+
// vacated index 10; the indices (9/10/11) are unchanged since.
|
|
751
|
+
9: "pencil-47",
|
|
752
|
+
10: "pen-58",
|
|
753
|
+
11: "pen-70"
|
|
754
|
+
};
|
|
755
|
+
var SCALE_STOP_COUNT = Object.keys(SHARED_NAMES).length;
|
|
756
|
+
function stopTokenName(stop) {
|
|
757
|
+
const name = SHARED_NAMES[stop];
|
|
758
|
+
if (!name) throw new Error(`stopTokenName: unexpected stop ${stop}`);
|
|
759
|
+
return name;
|
|
760
|
+
}
|
|
761
|
+
var PAPER_0 = "paper-0";
|
|
762
|
+
var PEN_100 = "pen-100";
|
|
763
|
+
var STAMP_FILL = "stamp-fill";
|
|
764
|
+
var STAMP_FILL_HOVER = "stamp-fill-hover";
|
|
765
|
+
var STAMP_FILL_PRESSED = "stamp-fill-pressed";
|
|
766
|
+
var STAMP_EDGE = "stamp-edge";
|
|
767
|
+
var STAMP_ON = "stamp-on";
|
|
768
|
+
var STAMP_STATE_LEAVES = {
|
|
769
|
+
[STAMP_FILL]: "stamp/fill",
|
|
770
|
+
[STAMP_FILL_HOVER]: "stamp/fill-hover",
|
|
771
|
+
[STAMP_FILL_PRESSED]: "stamp/fill-pressed",
|
|
772
|
+
[STAMP_EDGE]: "stamp/edge",
|
|
773
|
+
[STAMP_ON]: "stamp/on"
|
|
774
|
+
};
|
|
775
|
+
var STAMP_LEAF = {
|
|
776
|
+
FILL: STAMP_STATE_LEAVES[STAMP_FILL],
|
|
777
|
+
FILL_HOVER: STAMP_STATE_LEAVES[STAMP_FILL_HOVER],
|
|
778
|
+
FILL_PRESSED: STAMP_STATE_LEAVES[STAMP_FILL_PRESSED],
|
|
779
|
+
EDGE: STAMP_STATE_LEAVES[STAMP_EDGE],
|
|
780
|
+
ON: STAMP_STATE_LEAVES[STAMP_ON]
|
|
781
|
+
};
|
|
782
|
+
var SYSTEM_LEAF = {
|
|
783
|
+
ABS_BLACK: "system/abs-black",
|
|
784
|
+
ABS_WHITE: "system/abs-white",
|
|
785
|
+
SURFACE: {
|
|
786
|
+
DIM: "system/surface/dim",
|
|
787
|
+
LOW: "system/surface/low",
|
|
788
|
+
MID: "system/surface/mid",
|
|
789
|
+
HIGH: "system/surface/high"
|
|
790
|
+
},
|
|
791
|
+
ALPHA: {
|
|
792
|
+
TRANSPARENT: "system/alpha/transparent",
|
|
793
|
+
SCRIM: "system/alpha/abs-black-060",
|
|
794
|
+
INK: "system/alpha/ink",
|
|
795
|
+
// the DIRECTIONAL ladders (owner 2026-08-31, renaming the 2026-08-18 bare rungs
|
|
796
|
+
// and the 2026-08-29 inverse ladder): away-from-bg is the page-polarity pole
|
|
797
|
+
// (black in light, white in dark), toward-bg the flipped pole — STATE LAYERS for
|
|
798
|
+
// INVERTED grounds, whose polarity is opposite the page's. (Never call toward-bg
|
|
799
|
+
// a "highlighter": that word belongs to the tinted band stops.) The reversal lives in
|
|
800
|
+
// the engine: a consumer on an inverted ground names one token and never picks a
|
|
801
|
+
// pole. Colored fills never ride these; their states stay engine-solved stops.
|
|
802
|
+
// Rungs are two-digit percent, harmonizing with shadow-04/08/12.
|
|
803
|
+
AWAY_FROM_BG_06: "system/alpha/away-from-bg/06",
|
|
804
|
+
AWAY_FROM_BG_08: "system/alpha/away-from-bg/08",
|
|
805
|
+
AWAY_FROM_BG_16: "system/alpha/away-from-bg/16",
|
|
806
|
+
TOWARD_BG_06: "system/alpha/toward-bg/06",
|
|
807
|
+
TOWARD_BG_08: "system/alpha/toward-bg/08",
|
|
808
|
+
TOWARD_BG_16: "system/alpha/toward-bg/16",
|
|
809
|
+
SHADOW_04: "system/alpha/shadow-04",
|
|
810
|
+
SHADOW_08: "system/alpha/shadow-08",
|
|
811
|
+
SHADOW_12: "system/alpha/shadow-12"
|
|
812
|
+
}
|
|
813
|
+
};
|
|
814
|
+
var SURFACE_PLANE_LAW = {
|
|
815
|
+
[SYSTEM_LEAF.SURFACE.DIM]: { light: SHARED_NAMES[3], dark: PAPER_0 },
|
|
816
|
+
[SYSTEM_LEAF.SURFACE.LOW]: { light: SHARED_NAMES[2], dark: SHARED_NAMES[1] },
|
|
817
|
+
[SYSTEM_LEAF.SURFACE.MID]: { light: SHARED_NAMES[1], dark: SHARED_NAMES[2] },
|
|
818
|
+
[SYSTEM_LEAF.SURFACE.HIGH]: { light: PAPER_0, dark: SHARED_NAMES[3] }
|
|
819
|
+
};
|
|
820
|
+
var TOKEN_ORDER = [
|
|
821
|
+
...Object.values(SHARED_NAMES),
|
|
822
|
+
STAMP_FILL,
|
|
823
|
+
STAMP_FILL_HOVER,
|
|
824
|
+
STAMP_FILL_PRESSED,
|
|
825
|
+
STAMP_ON,
|
|
826
|
+
"identity"
|
|
827
|
+
];
|
|
828
|
+
function tokenOrder(name) {
|
|
829
|
+
const i = TOKEN_ORDER.indexOf(name);
|
|
830
|
+
return i === -1 ? TOKEN_ORDER.length : i;
|
|
831
|
+
}
|
|
832
|
+
|
|
724
833
|
// src/engine/requirements/spec.ts
|
|
725
|
-
var
|
|
834
|
+
var textLane = (g2) => g2 === "pencil" || g2 === "pen" || g2 === "lead" || g2 === "ink";
|
|
835
|
+
var groupOf = (stop) => (stop === 0 ? PAPER_0 : stopTokenName(stop)).split("-")[0];
|
|
726
836
|
var PAPER0_DARK_ROOT_L = 0.16;
|
|
727
837
|
var PL_LADDER = { hue: "warm-drift", L: "perceptual", chroma: "ladder" };
|
|
728
838
|
var PL_TEXT = { hue: "warm-drift", L: "perceptual", chroma: "brand" };
|
|
729
839
|
var P_LIFT = { hue: "warm-torsion", L: "perceptual-lift", chroma: "ladder" };
|
|
730
840
|
var P_FIXED = { hue: "warm-torsion", L: "fixed", chroma: "ladder" };
|
|
731
841
|
var P_TEXT = { hue: "warm-torsion", L: "perceptual", chroma: "brand" };
|
|
732
|
-
var S8 = { metric: "wcag", against: "paper-
|
|
733
|
-
var T9 = { metric: "wcag", against: "paper-
|
|
734
|
-
var T10 = { metric: "wcag", against: "
|
|
735
|
-
var T11 = { metric: "wcag", against: "paper-
|
|
842
|
+
var S8 = { metric: "wcag", against: "paper-5", target: STOP_8_NONTEXT_CONTRAST, level: "AA" };
|
|
843
|
+
var T9 = { metric: "wcag", against: "paper-3", target: PENCIL_9_CONTRAST, level: "AA" };
|
|
844
|
+
var T10 = { metric: "wcag", against: "highlighter-20", target: PEN_10_CONTRAST, level: "AA" };
|
|
845
|
+
var T11 = { metric: "wcag", against: "paper-3", target: PEN_11_CONTRAST_FLOOR, level: "AAA" };
|
|
736
846
|
var ONS = { onFill: { metric: "apca-pole", enforce: true, ratioFloor: 4.5, coEnforceLc: 65 } };
|
|
737
847
|
var LIGHT = {
|
|
738
848
|
stops: [
|
|
739
|
-
// paper-
|
|
740
|
-
{ stop: 0, rootL: 1, group:
|
|
741
|
-
// paper/
|
|
849
|
+
// paper-0 (paper-0 pre-Stage-B): the resolved ladder extreme — in light it genuinely is white (rootL 1.0, zero chroma)
|
|
850
|
+
{ stop: 0, rootL: 1, group: groupOf(0), produce: { hue: "warm-drift", L: "fixed", chroma: "ladder" }, satFraction: SCALE_C_LIGHT[0].sat, baseC: SCALE_C_LIGHT[0].base },
|
|
851
|
+
// paper/highlighter/crayon-26: perceptual ladder/envelope blend on the geometric ROOT_L_LIGHT scaffold. Separation
|
|
742
852
|
// falls out of the shape (see above) — no min-separation require. Only stop 8 carries a require: the WCAG
|
|
743
|
-
// 3:1 vs the resolved paper-
|
|
853
|
+
// 3:1 vs the resolved paper-3 (paper-2) (re-solves automatically since it references paper-3 (paper-2)).
|
|
744
854
|
...[1, 2, 3, 4, 5, 6, 7, 8].map((stop) => ({
|
|
745
855
|
stop,
|
|
746
856
|
rootL: ROOT_L_LIGHT[stop],
|
|
@@ -750,12 +860,12 @@ var LIGHT = {
|
|
|
750
860
|
baseC: SCALE_C_LIGHT[stop].base,
|
|
751
861
|
require: stop === 8 ? S8 : void 0
|
|
752
862
|
})),
|
|
753
|
-
//
|
|
754
|
-
// highlight-9 collapse, owner 2026-07-29).
|
|
863
|
+
// pen text: perceptual + contrast-required. pencil-47 (ink-9) is ALSO the emphasis fill (the
|
|
864
|
+
// highlight-9 collapse, owner 2026-07-29). pen-58 (ink-10) is the between text stop (C49) —
|
|
755
865
|
// a normal stop like its neighbors; the three together are the text-register cta.
|
|
756
|
-
{ stop: 9, rootL: ROOT_L_LIGHT[9], group:
|
|
757
|
-
{ stop: 10, rootL: ROOT_L_LIGHT[10], group:
|
|
758
|
-
{ stop: 11, rootL: ROOT_L_LIGHT[11], group:
|
|
866
|
+
{ stop: 9, rootL: ROOT_L_LIGHT[9], group: groupOf(9), produce: PL_TEXT, chromaMult: SCALE_C_LIGHT[9].textMult, textMaxC: SCALE_C_LIGHT[9].textMaxC, chromaFloor: SCALE_C_LIGHT[9].chromaFloor, require: T9 },
|
|
867
|
+
{ stop: 10, rootL: ROOT_L_LIGHT[10], group: groupOf(10), produce: PL_TEXT, chromaMult: SCALE_C_LIGHT[10].textMult, textMaxC: SCALE_C_LIGHT[10].textMaxC, chromaFloor: SCALE_C_LIGHT[10].chromaFloor, require: T10 },
|
|
868
|
+
{ stop: 11, rootL: ROOT_L_LIGHT[11], group: groupOf(11), produce: PL_TEXT, chromaMult: SCALE_C_LIGHT[11].textMult, textMaxC: SCALE_C_LIGHT[11].textMaxC, chromaFloor: SCALE_C_LIGHT[11].chromaFloor, require: T11 }
|
|
759
869
|
],
|
|
760
870
|
roles: [
|
|
761
871
|
{ role: "cta", produce: { hue: "constant", L: "anchor", chroma: "brand" }, floorL: 0, chromaMult: 1 },
|
|
@@ -766,10 +876,10 @@ var LIGHT = {
|
|
|
766
876
|
};
|
|
767
877
|
var DARK = {
|
|
768
878
|
stops: [
|
|
769
|
-
// paper-
|
|
879
|
+
// paper-0 (paper-0 pre-Stage-B): the resolved ladder extreme — one seam BELOW paper-1 (paper-1), deep and brand-tinted, never the
|
|
770
880
|
// absolute void (the old hard-coded #000000 was "too much"). Lift applies like the rest of the scale.
|
|
771
|
-
{ stop: 0, rootL: PAPER0_DARK_ROOT_L, group:
|
|
772
|
-
// paper/
|
|
881
|
+
{ stop: 0, rootL: PAPER0_DARK_ROOT_L, group: groupOf(0), produce: P_LIFT, satFraction: SCALE_C_DARK[0].sat },
|
|
882
|
+
// paper/highlighter 1–7: perceptual on the dark scaffold. stop 8: FIXED at the hand-placed scaffold BUT with the
|
|
773
883
|
// 3:1 non-text require DECLARED (the Stage-5 flip, owner-approved) — the blue-recede failure is prevented
|
|
774
884
|
// BY RULE, not by patch. The require now genuinely PLACES the stop rather than catching a few low-luminance
|
|
775
885
|
// hues: on the delta-carry path it solves from the sentinel every time, and the old claim that "most hues
|
|
@@ -783,11 +893,11 @@ var DARK = {
|
|
|
783
893
|
satFraction: SCALE_C_DARK[stop].sat,
|
|
784
894
|
require: stop === 8 ? S8 : void 0
|
|
785
895
|
})),
|
|
786
|
-
//
|
|
896
|
+
// pen text: perceptual + the contrast requires DECLARED in dark too (Stage-5 flip): the scaffold already
|
|
787
897
|
// clears them for every hue (the gate proves it), so values don't move — but the guarantee is now a rule.
|
|
788
|
-
{ stop: 9, rootL: ROOT_L_DARK[9], group:
|
|
789
|
-
{ stop: 10, rootL: ROOT_L_DARK[10], group:
|
|
790
|
-
{ stop: 11, rootL: ROOT_L_DARK[11], group:
|
|
898
|
+
{ stop: 9, rootL: ROOT_L_DARK[9], group: groupOf(9), produce: P_TEXT, chromaMult: SCALE_C_DARK[9].textMult, textMaxC: SCALE_C_DARK[9].textMaxC, chromaFloor: SCALE_C_DARK[9].chromaFloor, require: T9 },
|
|
899
|
+
{ stop: 10, rootL: ROOT_L_DARK[10], group: groupOf(10), produce: P_TEXT, chromaMult: SCALE_C_DARK[10].textMult, textMaxC: SCALE_C_DARK[10].textMaxC, chromaFloor: SCALE_C_DARK[10].chromaFloor, require: T10 },
|
|
900
|
+
{ stop: 11, rootL: ROOT_L_DARK[11], group: groupOf(11), produce: P_TEXT, chromaMult: SCALE_C_DARK[11].textMult, textMaxC: SCALE_C_DARK[11].textMaxC, chromaFloor: SCALE_C_DARK[11].chromaFloor, require: T11 }
|
|
791
901
|
],
|
|
792
902
|
roles: [
|
|
793
903
|
{ role: "cta", produce: { hue: "constant", L: "anchor", chroma: "brand" }, floorL: DARK_CTA_MIN_L, chromaMult: 1 },
|
|
@@ -798,7 +908,7 @@ var DARK = {
|
|
|
798
908
|
};
|
|
799
909
|
var MODE_SPECS = { light: LIGHT, dark: DARK };
|
|
800
910
|
|
|
801
|
-
//
|
|
911
|
+
// node_modules/helmlab/dist/index.js
|
|
802
912
|
function o0(n) {
|
|
803
913
|
let t = new Float64Array(9);
|
|
804
914
|
for (let e = 0; e < 3; e++) for (let s = 0; s < 3; s++) t[e * 3 + s] = n[e][s];
|
|
@@ -1714,7 +1824,7 @@ function p2Diff(a, b) {
|
|
|
1714
1824
|
var DEFAULT_APCA_LC_MAP = { 3: 30, 4.5: 75, 6.5: 85, 7: 90 };
|
|
1715
1825
|
function toApca(req, lcMap) {
|
|
1716
1826
|
if (req.metric !== "wcag") return req;
|
|
1717
|
-
if (req.against === "
|
|
1827
|
+
if (req.against === "highlighter-20") return { metric: "apca", against: "paper-3", targetLc: 85 };
|
|
1718
1828
|
const targetLc = lcMap[req.target];
|
|
1719
1829
|
if (targetLc === void 0) throw new Error(`apca profile: no Lc mapping for wcag target ${req.target}`);
|
|
1720
1830
|
return { metric: "apca", against: req.against, targetLc };
|
|
@@ -1728,7 +1838,7 @@ function withProfile(spec, profile, lcMap = DEFAULT_APCA_LC_MAP) {
|
|
|
1728
1838
|
// (The stop-9 CARVE-OUT is gone with the stop, owner 2026-07-29. It existed because
|
|
1729
1839
|
// highlight-9's require was a fill-vs-its-own-plane bar with no honest slot in a map
|
|
1730
1840
|
// of TEXT bars — 3 → 30 non-text, 4.5 → 75 body, 7 → 90 — so the apca lane kept its
|
|
1731
|
-
// own hl-9 placement instead. Today's stop 9 is
|
|
1841
|
+
// own hl-9 placement instead. Today's stop 9 is a PEN stop: 4.5 is a text bar, the
|
|
1732
1842
|
// 75 slot is its correct translation, and it maps like every other require.)
|
|
1733
1843
|
stops: spec.stops.map((s) => s.require ? { ...s, require: toApca(s.require, lcMap) } : s),
|
|
1734
1844
|
ons: {
|
|
@@ -1890,16 +2000,16 @@ function separationClampLight(ctx, placed, chromaAt, ref, target) {
|
|
|
1890
2000
|
return { L: pass, C: ceilingAt(pass), H: ctx.lightHueAt(pass) };
|
|
1891
2001
|
}
|
|
1892
2002
|
function placeLightText(ctx, rootL, cMult, maxLFor, deepen, maxC = Infinity) {
|
|
1893
|
-
const
|
|
1894
|
-
const anchorL = perceptualRungL(rootL, clampChromaToGamut(rootL,
|
|
2003
|
+
const textC = Math.min(cMult * ctx.brandC, maxC);
|
|
2004
|
+
const anchorL = perceptualRungL(rootL, clampChromaToGamut(rootL, textC, ctx.lightHueAt(rootL)), ctx.lightHueAt(rootL));
|
|
1895
2005
|
let H2 = ctx.lightHueAt(anchorL);
|
|
1896
|
-
let C2 = clampChromaToGamut(anchorL,
|
|
2006
|
+
let C2 = clampChromaToGamut(anchorL, textC, H2);
|
|
1897
2007
|
let L = Math.min(anchorL, maxLFor(C2, H2));
|
|
1898
2008
|
H2 = ctx.lightHueAt(L);
|
|
1899
|
-
C2 = clampChromaToGamut(L,
|
|
2009
|
+
C2 = clampChromaToGamut(L, textC, H2);
|
|
1900
2010
|
L = Math.min(anchorL, maxLFor(C2, H2));
|
|
1901
2011
|
L = Math.min(L - deepen, maxLFor(C2, ctx.lightHueAt(L - deepen)));
|
|
1902
|
-
return { L, C: ctx.cAt("light", L,
|
|
2012
|
+
return { L, C: ctx.cAt("light", L, textC), H: ctx.lightHueAt(L) };
|
|
1903
2013
|
}
|
|
1904
2014
|
function onFillIsWhiteLight(ctx, enforce, ratioFloor) {
|
|
1905
2015
|
const fill9ApcaY = apcaYAt(ctx.scaleL, clampChromaToGamut(ctx.scaleL, ctx.cAt("light", ctx.scaleL, ctx.brandC), ctx.brandH), ctx.brandH);
|
|
@@ -1913,7 +2023,7 @@ function buildDarkContext(ctx, specFloorL = DARK_CTA_MIN_L) {
|
|
|
1913
2023
|
return { dark9L, darkC9, darkHueAtL };
|
|
1914
2024
|
}
|
|
1915
2025
|
var darkScaleChromaAt = (ctx, dctx, stopIndex, multiplier) => (L) => ctx.cAt("dark", L, ctx.opts?.darkChromaCurve ? ctx.opts.darkChromaCurve(L, dctx.darkHueAtL(L), ctx.brandC, dctx.darkC9) : applyChromaFloor(ctx.subtleC, multiplier, chromaFloorBase(stopIndex), ctx.darkFloorStrength));
|
|
1916
|
-
var
|
|
2026
|
+
var darkTextChromaAt = (ctx, dctx, floorBase, multiplier, maxC = Infinity) => (L) => ctx.cAt("dark", L, Math.min(applyChromaFloor(ctx.brandC, multiplier, floorBase, ctx.darkFloorStrength), maxC));
|
|
1917
2027
|
function placeDark(dctx, rootL, chromaAt, lift = false) {
|
|
1918
2028
|
let L = perceptualRungL(rootL, chromaAt(rootL), dctx.darkHueAtL(rootL));
|
|
1919
2029
|
if (lift) L = Math.max(L, rootL);
|
|
@@ -2174,7 +2284,7 @@ function resolveRamp(hex, mode, spec, opts) {
|
|
|
2174
2284
|
const seed = { hex, ...o };
|
|
2175
2285
|
const ctx = buildContext(hex, opts);
|
|
2176
2286
|
spec ?? (spec = MODE_SPECS[mode]);
|
|
2177
|
-
if (ctx.opts?.
|
|
2287
|
+
if (ctx.opts?.textGround) {
|
|
2178
2288
|
spec = {
|
|
2179
2289
|
...spec,
|
|
2180
2290
|
stops: spec.stops.map((s) => s.stop === 10 && s.require?.metric === "wcag" ? { ...s, require: { ...s.require, target: 6.5 } } : s)
|
|
@@ -2196,12 +2306,12 @@ function resolveRamp(hex, mode, spec, opts) {
|
|
|
2196
2306
|
if (!ref) throw new Error(`stop ${forWhom}: require against stop ${stopNum} but it is not resolved yet`);
|
|
2197
2307
|
return ref;
|
|
2198
2308
|
};
|
|
2199
|
-
const AGAINST_STOP = { "paper-
|
|
2309
|
+
const AGAINST_STOP = { "paper-1": 1, "paper-3": 2, "paper-5": 3, "highlighter-20": 7 };
|
|
2200
2310
|
const declaredAnchor = (req) => req.metric === "min-separation" ? 1 : AGAINST_STOP[req.against] ?? 2;
|
|
2201
2311
|
const wcagAnchorStop = (req, stop) => stop >= 9 && declaredAnchor(req) <= 3 ? 3 : declaredAnchor(req);
|
|
2202
|
-
const
|
|
2203
|
-
const groundOf = (req, stop) =>
|
|
2204
|
-
const apcaGroundOf = (req, stop) =>
|
|
2312
|
+
const textGround = ctx.opts?.textGround?.[mode];
|
|
2313
|
+
const groundOf = (req, stop) => textGround && stop >= 9 ? textGround : refOf(wcagAnchorStop(req, stop), stop);
|
|
2314
|
+
const apcaGroundOf = (req, stop) => textGround && stop >= 9 ? textGround : refOf(declaredAnchor(req), stop);
|
|
2205
2315
|
const NEUTRAL_P3_WORST_SHIP_Y = { light: 0.845015, dark: 0.014247 };
|
|
2206
2316
|
const NEUTRAL_W80_WORST_SHIP_Y = { light: 0.506433, dark: 0.074262 };
|
|
2207
2317
|
const maxLForOf = (req, forWhom, withMargin) => {
|
|
@@ -2219,14 +2329,14 @@ function resolveRamp(hex, mode, spec, opts) {
|
|
|
2219
2329
|
}
|
|
2220
2330
|
throw new Error(`stop ${forWhom}: ${req.metric} is not a contrast require`);
|
|
2221
2331
|
};
|
|
2222
|
-
const
|
|
2332
|
+
const TEXT_DEEPEN = 0;
|
|
2223
2333
|
for (const sp of spec.stops) {
|
|
2224
2334
|
let placed;
|
|
2225
2335
|
let clamped = false, unresolvable;
|
|
2226
2336
|
if (mode === "light") {
|
|
2227
|
-
if (sp.group
|
|
2228
|
-
if (!sp.require) throw new Error(`light
|
|
2229
|
-
placed = placeLightText(ctx, sp.rootL, sp.chromaMult ?? 1, maxLForOf(sp.require, sp.stop, false),
|
|
2337
|
+
if (textLane(sp.group)) {
|
|
2338
|
+
if (!sp.require) throw new Error(`light pen stop ${sp.stop} must declare a contrast require`);
|
|
2339
|
+
placed = placeLightText(ctx, sp.rootL, sp.chromaMult ?? 1, maxLForOf(sp.require, sp.stop, false), TEXT_DEEPEN, sp.textMaxC);
|
|
2230
2340
|
clamped = true;
|
|
2231
2341
|
} else if (sp.produce.L === "fixed") {
|
|
2232
2342
|
const chromaAt = lightScaleChromaAt(ctx, sp.baseC ?? 0, sp.satFraction ?? 1);
|
|
@@ -2238,7 +2348,7 @@ function resolveRamp(hex, mode, spec, opts) {
|
|
|
2238
2348
|
placed = placeLightScale(ctx, sp.rootL, chromaAt, contrastReq ? maxLForOf(contrastReq, sp.stop, true) : void 0, targetChromaAt);
|
|
2239
2349
|
clamped = !!contrastReq;
|
|
2240
2350
|
if (sp.require?.metric === "min-separation") {
|
|
2241
|
-
const refStop = sp.require.against === "paper-
|
|
2351
|
+
const refStop = sp.require.against === "paper-1" ? 1 : sp.stop - 1;
|
|
2242
2352
|
const ref = stops.find((s) => s.stop === refStop);
|
|
2243
2353
|
if (!ref) throw new Error(`stop ${sp.stop}: min-separation against stop ${refStop} but it is not resolved yet`);
|
|
2244
2354
|
const before = placed.L;
|
|
@@ -2248,8 +2358,8 @@ function resolveRamp(hex, mode, spec, opts) {
|
|
|
2248
2358
|
}
|
|
2249
2359
|
} else {
|
|
2250
2360
|
const d = dctx;
|
|
2251
|
-
const
|
|
2252
|
-
const chromaAt = sp.group
|
|
2361
|
+
const textTwin = textLane(sp.group) && ctx.opts?.deltaCarry && ctx.opts?.chromaCurve ? ctx.opts.deltaLightStops?.find((s) => s.stop === sp.stop) : void 0;
|
|
2362
|
+
const chromaAt = textLane(sp.group) ? textTwin ? ((_L) => textTwin.C) : darkTextChromaAt(ctx, d, sp.chromaFloor ?? chromaFloorBase(sp.stop), sp.chromaMult ?? 1, sp.textMaxC) : darkScaleChromaAt(ctx, d, Math.max(0, sp.stop - 1), sp.satFraction ?? 1);
|
|
2253
2363
|
let spineH = null;
|
|
2254
2364
|
const dl = ctx.opts?.deltaLightStops;
|
|
2255
2365
|
const ls = dl && sp.stop >= 1 && sp.stop <= 8 ? dl.find((s) => s.stop === sp.stop) : void 0;
|
|
@@ -2269,7 +2379,7 @@ function resolveRamp(hex, mode, spec, opts) {
|
|
|
2269
2379
|
}
|
|
2270
2380
|
if (ctx.opts.deltaHKPlace) L = perceptualRungL(sp.rootL, ls.C, ls.H);
|
|
2271
2381
|
if (ctx.opts.deltaLiftFloor) L = Math.max(L, sp.rootL);
|
|
2272
|
-
if (ctx.opts.deltaChromaEq && sp.group
|
|
2382
|
+
if (ctx.opts.deltaChromaEq && !textLane(sp.group)) C2 = ctx.cAt("dark", L, perceptualDarkC(L, ls.H, ctx.brandC));
|
|
2273
2383
|
placed = { L, C: C2, H: spineH ?? ls.H };
|
|
2274
2384
|
} else if (sp.produce.L === "fixed") {
|
|
2275
2385
|
placed = ls ? placeDarkDelta(d, sp.rootL, chromaAt, ls) : { L: sp.rootL, C: chromaAt(sp.rootL), H: d.darkHueAtL(sp.rootL) };
|
|
@@ -2305,7 +2415,7 @@ function resolveRamp(hex, mode, spec, opts) {
|
|
|
2305
2415
|
if (sp.require?.metric === "wcag") {
|
|
2306
2416
|
const anchor = groundOf(sp.require, sp.stop);
|
|
2307
2417
|
const anchorShipY = shippedY(anchor.L, anchor.C, anchor.H);
|
|
2308
|
-
const paperBound = sp.stop >= 8 && !(
|
|
2418
|
+
const paperBound = sp.stop >= 8 && !(textGround && sp.stop >= 9);
|
|
2309
2419
|
const crossBoundY = wcagAnchorStop(sp.require, sp.stop) === 7 ? NEUTRAL_W80_WORST_SHIP_Y[mode] : NEUTRAL_P3_WORST_SHIP_Y[mode];
|
|
2310
2420
|
const shipRatio = (L) => {
|
|
2311
2421
|
const y2 = shippedY(L, placed.C, placed.H);
|
|
@@ -2333,7 +2443,7 @@ function resolveRamp(hex, mode, spec, opts) {
|
|
|
2333
2443
|
const got = Math.abs(apcaLc(apcaYAt(placed.L, clampChromaToGamut(placed.L, placed.C, placed.H), placed.H), refA));
|
|
2334
2444
|
if (got < sp.require.targetLc - APCA_TOL_LC) unresolvable = `stop ${sp.stop}: |Lc| ${got.toFixed(1)} < required ${sp.require.targetLc}`;
|
|
2335
2445
|
} else if (sp.require?.metric === "min-separation") {
|
|
2336
|
-
const ref = stops.find((s) => s.stop === (sp.require.against === "paper-
|
|
2446
|
+
const ref = stops.find((s) => s.stop === (sp.require.against === "paper-1" ? 1 : sp.stop - 1));
|
|
2337
2447
|
const rad2 = (h) => h * Math.PI / 180;
|
|
2338
2448
|
const gC = clampChromaToGamut(placed.L, placed.C, placed.H);
|
|
2339
2449
|
const got = Math.sqrt((placed.L - ref.L) ** 2 + (gC * Math.cos(rad2(placed.H)) - ref.C * Math.cos(rad2(ref.H))) ** 2 + (gC * Math.sin(rad2(placed.H)) - ref.C * Math.sin(rad2(ref.H))) ** 2);
|
|
@@ -2489,7 +2599,7 @@ function generateScale(hex, scaleName, forcedArchetype, opts) {
|
|
|
2489
2599
|
const dark = darkRamp.stops.filter((s) => s.stop >= 1).map(toStop).sort((a, b) => a.stop - b.stop);
|
|
2490
2600
|
const p0Light = lightRamp.stops.find((s) => s.stop === 0);
|
|
2491
2601
|
const p0Dark = darkRamp.stops.find((s) => s.stop === 0);
|
|
2492
|
-
const
|
|
2602
|
+
const penPole = (arr, L) => arr.find((s) => s.stop === 11) ? makeStop(12, L, 0, arr.find((s) => s.stop === 11).H) : void 0;
|
|
2493
2603
|
const cta = makeStop(9, lightRamp.roles.cta.L, lightRamp.roles.cta.C, lightRamp.roles.cta.H);
|
|
2494
2604
|
const ctaDark = makeStop(9, darkRamp.roles.cta.L, darkRamp.roles.cta.C, darkRamp.roles.cta.H);
|
|
2495
2605
|
const roleStop = (r, stop) => makeStop(stop, r.L, r.C, r.H);
|
|
@@ -2513,8 +2623,8 @@ function generateScale(hex, scaleName, forcedArchetype, opts) {
|
|
|
2513
2623
|
identityHex: hex.toUpperCase(),
|
|
2514
2624
|
paper0: p0Light ? makeStop(0, p0Light.L, p0Light.C, p0Light.H) : void 0,
|
|
2515
2625
|
paper0Dark: p0Dark ? makeStop(0, p0Dark.L, p0Dark.C, p0Dark.H) : void 0,
|
|
2516
|
-
|
|
2517
|
-
|
|
2626
|
+
pen100: penPole(light, 0),
|
|
2627
|
+
pen100Dark: penPole(dark, 1)
|
|
2518
2628
|
};
|
|
2519
2629
|
}
|
|
2520
2630
|
function generateNeutralScale(brandH, level = "default", contrastProfile) {
|
|
@@ -2586,8 +2696,7 @@ function generateSubtleSecondary(hex, opts) {
|
|
|
2586
2696
|
|
|
2587
2697
|
// src/engine/tokenDescriptions.ts
|
|
2588
2698
|
var AA_LARGE = "AA large text and UI elements";
|
|
2589
|
-
var AA_BODY = "AA standard body text
|
|
2590
|
-
var AAA_BODY = "AAA standard body text";
|
|
2699
|
+
var AA_BODY = "AA standard body text";
|
|
2591
2700
|
var FAMILY = {
|
|
2592
2701
|
neutral: "neutral",
|
|
2593
2702
|
brandPrimary: "brand",
|
|
@@ -2623,7 +2732,7 @@ var COLOR_WORD = {
|
|
|
2623
2732
|
[FAMILY.info]: " (blue)"
|
|
2624
2733
|
};
|
|
2625
2734
|
var PAPER = { req: "backgrounds, inverted text", theming: (f) => TINT[f], collides: true };
|
|
2626
|
-
var
|
|
2735
|
+
var HIGHLIGHTER = { req: "subtle interactive states, decorative borders, illos, signal hierarchy", theming: (f) => TINT[f], collides: true };
|
|
2627
2736
|
var solved = (f) => `${TINT[f]}; re-solved to clear its floor`;
|
|
2628
2737
|
var OVERLAY = {
|
|
2629
2738
|
req: "translucent backgrounds that hold their reading on any paper",
|
|
@@ -2631,25 +2740,25 @@ var OVERLAY = {
|
|
|
2631
2740
|
collides: true
|
|
2632
2741
|
};
|
|
2633
2742
|
var SCALE = {
|
|
2634
|
-
"paper-
|
|
2743
|
+
"paper-1": PAPER,
|
|
2635
2744
|
"paper-99-overlay": OVERLAY,
|
|
2636
|
-
"paper-
|
|
2745
|
+
"paper-3": PAPER,
|
|
2637
2746
|
"paper-97-overlay": OVERLAY,
|
|
2638
|
-
"paper-
|
|
2747
|
+
"paper-5": { req: "backgrounds, inverted text", theming: (f) => `${TINT[f]}. Worst background text stops must clear.`, collides: true },
|
|
2639
2748
|
"paper-95-overlay": OVERLAY,
|
|
2640
|
-
"
|
|
2641
|
-
"
|
|
2642
|
-
"
|
|
2643
|
-
"
|
|
2749
|
+
"highlighter-8": HIGHLIGHTER,
|
|
2750
|
+
"highlighter-11": HIGHLIGHTER,
|
|
2751
|
+
"highlighter-15": HIGHLIGHTER,
|
|
2752
|
+
"highlighter-20": HIGHLIGHTER,
|
|
2644
2753
|
// ("icons" KEPT through the 2026-08-28 on-flood strip (owner): an "icon" query
|
|
2645
|
-
// landing on the
|
|
2646
|
-
"
|
|
2647
|
-
"
|
|
2648
|
-
"
|
|
2754
|
+
// landing on the crayon rows is worth its ic-ON-s noise — the one surviving body carrier)
|
|
2755
|
+
"crayon-26": { req: "focus rings, icons, large text", contrast: AA_LARGE, theming: solved, collides: true },
|
|
2756
|
+
"pencil-47": { req: "regular text, inverted backgrounds", contrast: AA_BODY, theming: solved, collides: true },
|
|
2757
|
+
"pen-58": { req: "regular text, inverted backgrounds", contrast: AA_BODY, theming: solved, collides: true },
|
|
2649
2758
|
// ("high-emphasis" reworded 2026-08-12: the surface planes took low/high as label
|
|
2650
2759
|
// words, and a body carrying either floods that token's picker search — the C50 law;
|
|
2651
2760
|
// "strong-emphasis" reworded 2026-08-28: str-ON-g fed the "on" flood)
|
|
2652
|
-
"
|
|
2761
|
+
"pen-70": { req: "heavy-emphasis text, inverted backgrounds", contrast: AA_BODY, theming: solved, collides: true },
|
|
2653
2762
|
// the stamp family (cta words → solid 2026-08-18, solid → stamp 2026-08-27). "CTA" stays in
|
|
2654
2763
|
// these bodies on purpose: it stopped being a token label, so it floods nothing,
|
|
2655
2764
|
// and a designer's "cta" query still lands on these rows.
|
|
@@ -2678,7 +2787,7 @@ var LINK_INVERSE = (state, contrast) => ({
|
|
|
2678
2787
|
var SYSTEM = {
|
|
2679
2788
|
"system/abs-black": ABS,
|
|
2680
2789
|
"system/abs-white": ABS,
|
|
2681
|
-
// (the community system/
|
|
2790
|
+
// (the community system/pen-100 row RETIRED 2026-08-28 with its STATIC_UTILS entry:
|
|
2682
2791
|
// the anchor is engine-resolved and rides the neutral in BOTH plugins now —
|
|
2683
2792
|
// NEUTRAL_ONLY above. Old files' static rows orphan unwritten.)
|
|
2684
2793
|
"system/abs-primary": { req: "identity seed reference", theming: "the theme\u2019s own input, as given" },
|
|
@@ -2694,7 +2803,7 @@ var SYSTEM = {
|
|
|
2694
2803
|
"system/alpha/away-from-bg/08": OFFSET,
|
|
2695
2804
|
"system/alpha/away-from-bg/16": OFFSET,
|
|
2696
2805
|
// the inverse ladder: the offset rungs with the pole flipped per mode, for
|
|
2697
|
-
//
|
|
2806
|
+
// highlighters and edges over inverted backgrounds ("interaction" avoided in the
|
|
2698
2807
|
// bodies: acti-ON would feed the "on" flood)
|
|
2699
2808
|
"system/alpha/toward-bg/06": OFFSET_INVERSE,
|
|
2700
2809
|
"system/alpha/toward-bg/08": OFFSET_INVERSE,
|
|
@@ -2711,10 +2820,10 @@ var SYSTEM = {
|
|
|
2711
2820
|
"system/surface/high": PLANE("topmost plane \u2014 modals, dialogs"),
|
|
2712
2821
|
"system/link/default/enabled": LINK("", AA_BODY),
|
|
2713
2822
|
"system/link/default/hover": LINK(" pointer-over", AA_BODY),
|
|
2714
|
-
"system/link/default/pressed": LINK(" pressed",
|
|
2823
|
+
"system/link/default/pressed": LINK(" pressed", AA_BODY),
|
|
2715
2824
|
"system/link/inverse/enabled": LINK_INVERSE("", AA_BODY),
|
|
2716
2825
|
"system/link/inverse/hover": LINK_INVERSE(" pointer-over", AA_BODY),
|
|
2717
|
-
"system/link/inverse/pressed": LINK_INVERSE(" pressed",
|
|
2826
|
+
"system/link/inverse/pressed": LINK_INVERSE(" pressed", AA_BODY)
|
|
2718
2827
|
};
|
|
2719
2828
|
var PREFIXES = [
|
|
2720
2829
|
// community spellings FIRST: the 2026-08-21 family rename made the ext word a
|
|
@@ -2761,15 +2870,15 @@ function checkCollision(brand, signalScale, signalDef, mode) {
|
|
|
2761
2870
|
collides: hueGate && deltaE <= threshold
|
|
2762
2871
|
};
|
|
2763
2872
|
}
|
|
2764
|
-
var
|
|
2873
|
+
var HUE_COLLISION_HIGHLIGHTER_DEG = 15;
|
|
2765
2874
|
var HUE_COLLISION_MIN_V = 0.5;
|
|
2766
2875
|
var SECONDARY_NOTE_MIN_V = HUE_NOISE_C / VIVID_C;
|
|
2767
|
-
var
|
|
2768
|
-
function
|
|
2876
|
+
var HIGHLIGHTER_STOPS = [3, 4, 5, 6, 7];
|
|
2877
|
+
function highlighterProximity(brand, sig, mode) {
|
|
2769
2878
|
const b = mode === "light" ? brand.light : brand.dark;
|
|
2770
2879
|
const s = mode === "light" ? sig.light : sig.dark;
|
|
2771
2880
|
let dH = Infinity, dE = Infinity;
|
|
2772
|
-
for (const k of
|
|
2881
|
+
for (const k of HIGHLIGHTER_STOPS) {
|
|
2773
2882
|
const bs = b.find((x2) => x2.stop === k), ss = s.find((x2) => x2.stop === k);
|
|
2774
2883
|
if (!bs || !ss) continue;
|
|
2775
2884
|
dH = Math.min(dH, hueDistance(bs.H, ss.H));
|
|
@@ -2778,15 +2887,15 @@ function washProximity(brand, sig, mode) {
|
|
|
2778
2887
|
return { dH, dE };
|
|
2779
2888
|
}
|
|
2780
2889
|
function checkHueCollision(brand, signalScale, signalDef, opts) {
|
|
2781
|
-
const l =
|
|
2782
|
-
const d =
|
|
2890
|
+
const l = highlighterProximity(brand, signalScale, "light");
|
|
2891
|
+
const d = highlighterProximity(brand, signalScale, "dark");
|
|
2783
2892
|
const vividness = Math.min(1, brand.brandC / VIVID_C);
|
|
2784
2893
|
return {
|
|
2785
2894
|
signal: signalDef.name,
|
|
2786
|
-
|
|
2787
|
-
|
|
2895
|
+
dHueHighlighter: { light: l.dH, dark: d.dH },
|
|
2896
|
+
highlighterDeltaE: { light: l.dE, dark: d.dE },
|
|
2788
2897
|
vividness,
|
|
2789
|
-
collides: vividness >= (opts?.minV ?? HUE_COLLISION_MIN_V) && Math.min(l.dH, d.dH) <=
|
|
2898
|
+
collides: vividness >= (opts?.minV ?? HUE_COLLISION_MIN_V) && Math.min(l.dH, d.dH) <= HUE_COLLISION_HIGHLIGHTER_DEG
|
|
2790
2899
|
};
|
|
2791
2900
|
}
|
|
2792
2901
|
var YELLOW_SPLIT_H = 96;
|
|
@@ -2979,7 +3088,7 @@ function resolveBrand(hex, name, opts) {
|
|
|
2979
3088
|
// (buildSignalScales/signalShift) — neutral alone stays outside; exact has enforce off.
|
|
2980
3089
|
apcaClearance: opts?.apcaClearance ?? true,
|
|
2981
3090
|
darkCtaFlatApp: opts?.darkCtaFlatApp,
|
|
2982
|
-
|
|
3091
|
+
textGround: opts?.textGround
|
|
2983
3092
|
};
|
|
2984
3093
|
let scale = generateScale(hex, name, void 0, floor);
|
|
2985
3094
|
let pending = [];
|
|
@@ -3062,7 +3171,7 @@ function resolveLinkTrio(linkHex, contrastProfile) {
|
|
|
3062
3171
|
const s = resolveBrand(linkHex, "link", { skipCollisionRules: true, contrastProfile }).scale;
|
|
3063
3172
|
const at = (arr, n) => {
|
|
3064
3173
|
const st = arr.find((x2) => x2.stop === n);
|
|
3065
|
-
if (!st) throw new Error(`resolveLinkTrio: the link resolve has no
|
|
3174
|
+
if (!st) throw new Error(`resolveLinkTrio: the link resolve has no pen stop ${n}`);
|
|
3066
3175
|
return st;
|
|
3067
3176
|
};
|
|
3068
3177
|
return {
|
|
@@ -3075,16 +3184,16 @@ function resolveLinkTrio(linkHex, contrastProfile) {
|
|
|
3075
3184
|
};
|
|
3076
3185
|
}
|
|
3077
3186
|
function resolveLinkInverseTrio(seedHex, contrastProfile) {
|
|
3078
|
-
const ground =
|
|
3187
|
+
const ground = PEN_70_GROUND[contrastProfile === "apca" ? "apca" : "wcag"];
|
|
3079
3188
|
const s = resolveBrand(seedHex, "link-inverse", {
|
|
3080
3189
|
skipCollisionRules: true,
|
|
3081
3190
|
contrastProfile,
|
|
3082
3191
|
// the cross — ramp keyed, ground mode-swapped
|
|
3083
|
-
|
|
3192
|
+
textGround: { light: ground.dark, dark: ground.light }
|
|
3084
3193
|
}).scale;
|
|
3085
3194
|
const at = (arr, n) => {
|
|
3086
3195
|
const st = arr.find((x2) => x2.stop === n);
|
|
3087
|
-
if (!st) throw new Error(`resolveLinkInverseTrio: the link resolve has no
|
|
3196
|
+
if (!st) throw new Error(`resolveLinkInverseTrio: the link resolve has no pen stop ${n}`);
|
|
3088
3197
|
return st;
|
|
3089
3198
|
};
|
|
3090
3199
|
return {
|
|
@@ -3098,12 +3207,12 @@ function resolveLinkInverseTrio(seedHex, contrastProfile) {
|
|
|
3098
3207
|
};
|
|
3099
3208
|
}
|
|
3100
3209
|
function escapeCtaFamily(nScale, mode, contrastProfile) {
|
|
3101
|
-
const
|
|
3102
|
-
if (!
|
|
3103
|
-
const mk = (stop, L) => makeStop(stop, L,
|
|
3104
|
-
const cta = mk(9,
|
|
3105
|
-
const ctaHover = mk(10, stateFillL(
|
|
3106
|
-
const ctaPressed = mk(11, stateFillL(
|
|
3210
|
+
const strongText = (mode === "light" ? nScale.light : nScale.dark).find((s) => s.stop === 11);
|
|
3211
|
+
if (!strongText) throw new Error("escapeCtaFamily: the neutral scale has no ink-11 stop");
|
|
3212
|
+
const mk = (stop, L) => makeStop(stop, L, strongText.C, strongText.H);
|
|
3213
|
+
const cta = mk(9, strongText.L);
|
|
3214
|
+
const ctaHover = mk(10, stateFillL(strongText.L, mode, 1));
|
|
3215
|
+
const ctaPressed = mk(11, stateFillL(strongText.L, mode, 2));
|
|
3107
3216
|
const onEnforce = contrastProfile !== "apca";
|
|
3108
3217
|
const onFloor = contrastProfile === "apca" ? void 0 : 4.5;
|
|
3109
3218
|
const onFillIsWhite = onTextIsWhite(apcaY(cta.r, cta.g, cta.b), cta.L, cta.C, cta.H, onEnforce, onFloor);
|
|
@@ -3179,7 +3288,7 @@ function resolveTheme(input) {
|
|
|
3179
3288
|
for (const def of SIGNALS2) {
|
|
3180
3289
|
if (adoptedForSecondary.has(def.name)) continue;
|
|
3181
3290
|
const h = checkHueCollision(scale2, effectiveOf(def.name), def, { minV: SECONDARY_NOTE_MIN_V });
|
|
3182
|
-
if (h.collides) out.push(wording(def.name, Math.min(h.
|
|
3291
|
+
if (h.collides) out.push(wording(def.name, Math.min(h.highlighterDeltaE.light, h.highlighterDeltaE.dark)));
|
|
3183
3292
|
}
|
|
3184
3293
|
return out;
|
|
3185
3294
|
};
|
|
@@ -3229,7 +3338,7 @@ function resolveTheme(input) {
|
|
|
3229
3338
|
derived: true,
|
|
3230
3339
|
notes: [
|
|
3231
3340
|
`secondary derived from the brand color (default model, seed ${liftedHex})`,
|
|
3232
|
-
...signalNotesFor(scale2, (name, dE) => `derived secondary sits on the ${name} signal's hue (
|
|
3341
|
+
...signalNotesFor(scale2, (name, dE) => `derived secondary sits on the ${name} signal's hue (highlighter \u0394E ${dE.toFixed(3)}) \u2014 it tracks the brand color`)
|
|
3233
3342
|
],
|
|
3234
3343
|
distinctness: ctaDistinctness(primary.scale, scale2)
|
|
3235
3344
|
},
|
|
@@ -3254,7 +3363,7 @@ function resolveTheme(input) {
|
|
|
3254
3363
|
derived: false,
|
|
3255
3364
|
notes: [
|
|
3256
3365
|
`secondary keeps your color through the ramp; the cta is a tint of it (tint seed ${tintedHex})`,
|
|
3257
|
-
...signalNotesFor(scale2, (name, dE) => `secondary sits on the ${name} signal's hue (
|
|
3366
|
+
...signalNotesFor(scale2, (name, dE) => `secondary sits on the ${name} signal's hue (highlighter \u0394E ${dE.toFixed(3)}) \u2014 it tracks your color`)
|
|
3258
3367
|
],
|
|
3259
3368
|
distinctness: distinctness2
|
|
3260
3369
|
},
|
|
@@ -3266,7 +3375,7 @@ function resolveTheme(input) {
|
|
|
3266
3375
|
const scale = rSec.scale;
|
|
3267
3376
|
const level = "standard";
|
|
3268
3377
|
mergeSecondarySignals(scale, input.secondaryHex);
|
|
3269
|
-
const secNotes = signalNotesFor(scale, (name, dE) => `secondary reads close to the ${name} signal (
|
|
3378
|
+
const secNotes = signalNotesFor(scale, (name, dE) => `secondary reads close to the ${name} signal (highlighter \u0394E ${dE.toFixed(3)}) \u2014 your color ships untouched`);
|
|
3270
3379
|
const distinctness = ctaDistinctness(primary.scale, scale);
|
|
3271
3380
|
if (distinctness.close)
|
|
3272
3381
|
notes.push(`secondary reads close to the primary (\u0394E ${Math.min(distinctness.light, distinctness.dark).toFixed(2)}) \u2014 consider a more distinct color`);
|
|
@@ -3279,113 +3388,6 @@ function resolveTheme(input) {
|
|
|
3279
3388
|
};
|
|
3280
3389
|
}
|
|
3281
3390
|
|
|
3282
|
-
// src/engine/tokenNames.ts
|
|
3283
|
-
var SHARED_NAMES = {
|
|
3284
|
-
1: "paper-99",
|
|
3285
|
-
2: "paper-97",
|
|
3286
|
-
// stop 3 renamed wash-3 → paper-3 (owner 2026-07-24, elevation round): it is a
|
|
3287
|
-
// PLANE in both themes (light sink / dark pop), so it belongs to the surface band.
|
|
3288
|
-
// NAME ONLY — generation is index-keyed and unchanged; the internal wash machinery
|
|
3289
|
-
// (reqtoken groupOf, collision WASH_STOPS) deliberately still spans stops 3–7.
|
|
3290
|
-
// Stage B (owner 2026-08-07, names only): relabeled to the ROOT_L-derived digit,
|
|
3291
|
-
// paper-95 — same band, same index.
|
|
3292
|
-
3: "paper-95",
|
|
3293
|
-
4: "wash-92",
|
|
3294
|
-
5: "wash-89",
|
|
3295
|
-
6: "wash-85",
|
|
3296
|
-
7: "wash-80",
|
|
3297
|
-
8: "wax-74",
|
|
3298
|
-
// THE INK BAND (C49, owner 2026-08-05): the first text stop + emphasis fill (the
|
|
3299
|
-
// 2026-07-29 highlight collapse — the old highlight-9 and on-highlight are
|
|
3300
|
-
// deleted; this stop carries both jobs, its on-color a paper token), the between
|
|
3301
|
-
// text stop (a value the retired text-cta hover state used to generate bespokely,
|
|
3302
|
-
// promoted to a normal stop), and the strong text stop. The three read as states
|
|
3303
|
-
// ARE the text-style cta (owner 2026-08-12). C49 restored the top
|
|
3304
|
-
// two pre-collapse stop INDICES (11, and the off-scale anchor's 12 — emitted as a
|
|
3305
|
-
// literal in cssRender, not through this table) with the between stop taking the
|
|
3306
|
-
// vacated index 10; the indices (9/10/11) are unchanged since.
|
|
3307
|
-
9: "lead-53",
|
|
3308
|
-
10: "ink-42",
|
|
3309
|
-
11: "ink-30"
|
|
3310
|
-
};
|
|
3311
|
-
var SCALE_STOP_COUNT = Object.keys(SHARED_NAMES).length;
|
|
3312
|
-
function stopTokenName(stop) {
|
|
3313
|
-
const name = SHARED_NAMES[stop];
|
|
3314
|
-
if (!name) throw new Error(`stopTokenName: unexpected stop ${stop}`);
|
|
3315
|
-
return name;
|
|
3316
|
-
}
|
|
3317
|
-
var PAPER_100 = "paper-100";
|
|
3318
|
-
var INK_0 = "ink-0";
|
|
3319
|
-
var STAMP_FILL = "stamp-fill";
|
|
3320
|
-
var STAMP_FILL_HOVER = "stamp-fill-hover";
|
|
3321
|
-
var STAMP_FILL_PRESSED = "stamp-fill-pressed";
|
|
3322
|
-
var STAMP_EDGE = "stamp-edge";
|
|
3323
|
-
var STAMP_ON = "stamp-on";
|
|
3324
|
-
var STAMP_STATE_LEAVES = {
|
|
3325
|
-
[STAMP_FILL]: "stamp/fill",
|
|
3326
|
-
[STAMP_FILL_HOVER]: "stamp/fill-hover",
|
|
3327
|
-
[STAMP_FILL_PRESSED]: "stamp/fill-pressed",
|
|
3328
|
-
[STAMP_EDGE]: "stamp/edge",
|
|
3329
|
-
[STAMP_ON]: "stamp/on"
|
|
3330
|
-
};
|
|
3331
|
-
var STAMP_LEAF = {
|
|
3332
|
-
FILL: STAMP_STATE_LEAVES[STAMP_FILL],
|
|
3333
|
-
FILL_HOVER: STAMP_STATE_LEAVES[STAMP_FILL_HOVER],
|
|
3334
|
-
FILL_PRESSED: STAMP_STATE_LEAVES[STAMP_FILL_PRESSED],
|
|
3335
|
-
EDGE: STAMP_STATE_LEAVES[STAMP_EDGE],
|
|
3336
|
-
ON: STAMP_STATE_LEAVES[STAMP_ON]
|
|
3337
|
-
};
|
|
3338
|
-
var SYSTEM_LEAF = {
|
|
3339
|
-
ABS_BLACK: "system/abs-black",
|
|
3340
|
-
ABS_WHITE: "system/abs-white",
|
|
3341
|
-
SURFACE: {
|
|
3342
|
-
DIM: "system/surface/dim",
|
|
3343
|
-
LOW: "system/surface/low",
|
|
3344
|
-
MID: "system/surface/mid",
|
|
3345
|
-
HIGH: "system/surface/high"
|
|
3346
|
-
},
|
|
3347
|
-
ALPHA: {
|
|
3348
|
-
TRANSPARENT: "system/alpha/transparent",
|
|
3349
|
-
SCRIM: "system/alpha/abs-black-060",
|
|
3350
|
-
INK: "system/alpha/ink",
|
|
3351
|
-
// the DIRECTIONAL ladders (owner 2026-08-31, renaming the 2026-08-18 bare rungs
|
|
3352
|
-
// and the 2026-08-29 inverse ladder): away-from-bg is the page-polarity pole
|
|
3353
|
-
// (black in light, white in dark), toward-bg the flipped pole — STATE LAYERS for
|
|
3354
|
-
// INVERTED grounds, whose polarity is opposite the page's. (Never call toward-bg
|
|
3355
|
-
// a "wash": that word belongs to the tinted band stops.) The reversal lives in
|
|
3356
|
-
// the engine: a consumer on an inverted ground names one token and never picks a
|
|
3357
|
-
// pole. Colored fills never ride these; their states stay engine-solved stops.
|
|
3358
|
-
// Rungs are two-digit percent, harmonizing with shadow-04/08/12.
|
|
3359
|
-
AWAY_FROM_BG_06: "system/alpha/away-from-bg/06",
|
|
3360
|
-
AWAY_FROM_BG_08: "system/alpha/away-from-bg/08",
|
|
3361
|
-
AWAY_FROM_BG_16: "system/alpha/away-from-bg/16",
|
|
3362
|
-
TOWARD_BG_06: "system/alpha/toward-bg/06",
|
|
3363
|
-
TOWARD_BG_08: "system/alpha/toward-bg/08",
|
|
3364
|
-
TOWARD_BG_16: "system/alpha/toward-bg/16",
|
|
3365
|
-
SHADOW_04: "system/alpha/shadow-04",
|
|
3366
|
-
SHADOW_08: "system/alpha/shadow-08",
|
|
3367
|
-
SHADOW_12: "system/alpha/shadow-12"
|
|
3368
|
-
}
|
|
3369
|
-
};
|
|
3370
|
-
var SURFACE_PLANE_LAW = {
|
|
3371
|
-
[SYSTEM_LEAF.SURFACE.DIM]: { light: SHARED_NAMES[3], dark: PAPER_100 },
|
|
3372
|
-
[SYSTEM_LEAF.SURFACE.LOW]: { light: SHARED_NAMES[2], dark: SHARED_NAMES[1] },
|
|
3373
|
-
[SYSTEM_LEAF.SURFACE.MID]: { light: SHARED_NAMES[1], dark: SHARED_NAMES[2] },
|
|
3374
|
-
[SYSTEM_LEAF.SURFACE.HIGH]: { light: PAPER_100, dark: SHARED_NAMES[3] }
|
|
3375
|
-
};
|
|
3376
|
-
var TOKEN_ORDER = [
|
|
3377
|
-
...Object.values(SHARED_NAMES),
|
|
3378
|
-
STAMP_FILL,
|
|
3379
|
-
STAMP_FILL_HOVER,
|
|
3380
|
-
STAMP_FILL_PRESSED,
|
|
3381
|
-
STAMP_ON,
|
|
3382
|
-
"identity"
|
|
3383
|
-
];
|
|
3384
|
-
function tokenOrder(name) {
|
|
3385
|
-
const i = TOKEN_ORDER.indexOf(name);
|
|
3386
|
-
return i === -1 ? TOKEN_ORDER.length : i;
|
|
3387
|
-
}
|
|
3388
|
-
|
|
3389
3391
|
// src/engine/cssRender.ts
|
|
3390
3392
|
var { brandPrimary: CSS_BRAND, brandSecondary: CSS_SECONDARY, neutral: CSS_NEUTRAL } = CSS_FAMILY;
|
|
3391
3393
|
function toHex2(r, g2, b) {
|
|
@@ -3432,7 +3434,7 @@ var alphaRootVars = (mode) => [
|
|
|
3432
3434
|
...Object.keys(OFFSET_ALPHAS).map(Number).sort((a, b) => a - b).map((r) => ` ${offsetVarName(r)}: ${offsetRgba(r, mode)};`),
|
|
3433
3435
|
// the toward-bg ladder (the 2026-08-29 inverse ladder, renamed 2026-08-31): the
|
|
3434
3436
|
// same rungs, pole flipped per mode — state layers for INVERTED grounds (never
|
|
3435
|
-
// called a "
|
|
3437
|
+
// called a "highlighter" — that word is the tinted band's). One spelling with the Figma
|
|
3436
3438
|
// row: --alpha-toward-bg-06 ↔ system/alpha/toward-bg/06.
|
|
3437
3439
|
...Object.keys(OFFSET_ALPHAS).map(Number).sort((a, b) => a - b).map((r) => ` --alpha-toward-bg-${offsetLeafName(r)}: ${offsetRgba(r, mode === "light" ? "dark" : "light")};`)
|
|
3438
3440
|
];
|
|
@@ -3459,7 +3461,7 @@ function brandKindBody(prefix, s, mode, page) {
|
|
|
3459
3461
|
` --${prefix}-stamp-fill-pressed: ${stopHex(f.ctaPressed)};`,
|
|
3460
3462
|
` --${prefix}-stamp-edge: var(${border ? offsetVarName(ctaBorderRung(prefix)) : TRANSPARENT_VAR});`,
|
|
3461
3463
|
// the SOFT on-cta (owner 2026-08-04: "neutral cta on's should also be the alpha"): the
|
|
3462
|
-
// neutral's cta is the scale-fed
|
|
3464
|
+
// neutral's cta is the scale-fed HIGHLIGHTER-level fill, the system's other quiet cta, so its
|
|
3463
3465
|
// button text takes the pole AT ALPHA like the default-model secondary's — composited
|
|
3464
3466
|
// over whatever state the fill is in, so hover/pressed carry their own legibility. Same
|
|
3465
3467
|
// register both families (SOFT_ON_CTA_ALPHA), so both alias the ONE system/alpha/ink
|
|
@@ -3489,16 +3491,16 @@ function neutralCss(selector, brandH, level = "default", contrastProfile, ctaBor
|
|
|
3489
3491
|
const p3Dark = brandKindP3Body(CSS_NEUTRAL, s, "dark");
|
|
3490
3492
|
return [
|
|
3491
3493
|
`${selector} {`,
|
|
3492
|
-
` --${
|
|
3493
|
-
` --${
|
|
3494
|
+
` --${PAPER_0}: ${p02(s.paper0, "#ffffff")};`,
|
|
3495
|
+
` --${PEN_100}: ${p02(s.pen100, "#000000")};`,
|
|
3494
3496
|
// the neutral IS the page, so it is judged against its own paper stop
|
|
3495
3497
|
// the neutral's overlays never read the visibility bar (the exempt family), so
|
|
3496
3498
|
// the brandless chrome context passes 0
|
|
3497
3499
|
...brandKindBody(CSS_NEUTRAL, s, "light", nPage("light")),
|
|
3498
3500
|
`}`,
|
|
3499
3501
|
`${selector}[data-theme="dark"] {`,
|
|
3500
|
-
` --${
|
|
3501
|
-
` --${
|
|
3502
|
+
` --${PAPER_0}: ${p02(s.paper0Dark, "#000000")};`,
|
|
3503
|
+
` --${PEN_100}: ${p02(s.pen100Dark, "#ffffff")};`,
|
|
3502
3504
|
...brandKindBody(CSS_NEUTRAL, s, "dark", nPage("dark")),
|
|
3503
3505
|
`}`,
|
|
3504
3506
|
...p3Light.length || p3Dark.length ? [
|
|
@@ -3587,8 +3589,8 @@ function brandCss(slug, displayName, r, secondary, noteSuffix = "", neutralLevel
|
|
|
3587
3589
|
const brandIdentity = ` --${CSS_BRAND}-identity: ${scale.identityHex};`;
|
|
3588
3590
|
const secondaryIdentity = secondary ? ` --${CSS_SECONDARY}-identity: ${secondary.identityHex};` : ` --${CSS_SECONDARY}-identity: var(--${CSS_BRAND}-identity);`;
|
|
3589
3591
|
const p0hex = (s, fallback) => s ? stopHex(s) : fallback;
|
|
3590
|
-
const lightAnchors = [` --${
|
|
3591
|
-
const darkAnchors = [` --${
|
|
3592
|
+
const lightAnchors = [` --${PAPER_0}: ${p0hex(nScale.paper0, "#ffffff")};`, ` --${PEN_100}: ${p0hex(nScale.pen100, "#000000")};`];
|
|
3593
|
+
const darkAnchors = [` --${PAPER_0}: ${p0hex(nScale.paper0Dark, "#000000")};`, ` --${PEN_100}: ${p0hex(nScale.pen100Dark, "#ffffff")};`];
|
|
3592
3594
|
const linkTrio = linkHex ? resolveLinkTrio(linkHex, contrastProfile) : null;
|
|
3593
3595
|
const link = (mode) => linkTrio ? mode === "light" ? [` --link: ${stopHex(linkTrio.link)};`, ` --link-hover: ${stopHex(linkTrio.linkHover)};`, ` --link-pressed: ${stopHex(linkTrio.linkPressed)};`] : [` --link: ${stopHex(linkTrio.linkDark)};`, ` --link-hover: ${stopHex(linkTrio.linkHoverDark)};`, ` --link-pressed: ${stopHex(linkTrio.linkPressedDark)};`] : [
|
|
3594
3596
|
` --link: var(--${CSS_BRAND}-${stopTokenName(9)});`,
|
|
@@ -3776,17 +3778,17 @@ function themeToFigma(r, input) {
|
|
|
3776
3778
|
const build = (mode) => {
|
|
3777
3779
|
const p02 = mode === "light" ? nScale.paper0 : nScale.paper0Dark;
|
|
3778
3780
|
const ramp = rampGroup(nScale[mode], mode === "light" ? nScale.onFillTextIsWhite : nScale.onFillTextIsWhiteDark, neutralExtra(mode));
|
|
3779
|
-
const i02 = mode === "light" ? nScale.
|
|
3780
|
-
const
|
|
3781
|
+
const i02 = mode === "light" ? nScale.pen100 : nScale.pen100Dark;
|
|
3782
|
+
const splicePen100 = (g3) => {
|
|
3781
3783
|
if (!i02) return g3;
|
|
3782
3784
|
const out = {};
|
|
3783
3785
|
for (const [k, v2] of Object.entries(g3)) {
|
|
3784
3786
|
out[k] = v2;
|
|
3785
|
-
if (k === stopTokenName(11)) out[
|
|
3787
|
+
if (k === stopTokenName(11)) out[PEN_100] = colorFromStop(i02);
|
|
3786
3788
|
}
|
|
3787
3789
|
return out;
|
|
3788
3790
|
};
|
|
3789
|
-
const neutralGroup =
|
|
3791
|
+
const neutralGroup = splicePen100(p02 ? { [PAPER_0]: colorFromStop(p02), ...ramp } : ramp);
|
|
3790
3792
|
const secondaryGroup = rampGroup(secondary[mode], mode === "light" ? secondaryOnFillLight : secondaryOnFillDark, brandExtra(secondary, mode, CSS_FAMILY.brandSecondary));
|
|
3791
3793
|
if (input.secondaryStyle === "outline" && input.secondary) {
|
|
3792
3794
|
const s8 = secondary[mode].find((s) => s.stop === 8);
|
|
@@ -3824,12 +3826,12 @@ function themeToFigma(r, input) {
|
|
|
3824
3826
|
putLeaf(g3, STAMP_ON, colorFromHex(esc.onFillIsWhite));
|
|
3825
3827
|
}
|
|
3826
3828
|
}
|
|
3827
|
-
const
|
|
3829
|
+
const scaleTextAt = (n) => {
|
|
3828
3830
|
const s = scale[mode].find((x2) => x2.stop === n);
|
|
3829
|
-
if (!s) throw new Error(`themeToFigma link: the brand scale has no
|
|
3831
|
+
if (!s) throw new Error(`themeToFigma link: the brand scale has no pen stop ${n}`);
|
|
3830
3832
|
return s;
|
|
3831
3833
|
};
|
|
3832
|
-
const linkGroup = lt ? mode === "light" ? { "link": colorFromStop(lt.link), "link-hover": colorFromStop(lt.linkHover), "link-pressed": colorFromStop(lt.linkPressed) } : { "link": colorFromStop(lt.linkDark), "link-hover": colorFromStop(lt.linkHoverDark), "link-pressed": colorFromStop(lt.linkPressedDark) } : { "link": colorFromStop(
|
|
3834
|
+
const linkGroup = lt ? mode === "light" ? { "link": colorFromStop(lt.link), "link-hover": colorFromStop(lt.linkHover), "link-pressed": colorFromStop(lt.linkPressed) } : { "link": colorFromStop(lt.linkDark), "link-hover": colorFromStop(lt.linkHoverDark), "link-pressed": colorFromStop(lt.linkPressedDark) } : { "link": colorFromStop(scaleTextAt(9)), "link-hover": colorFromStop(scaleTextAt(10)), "link-pressed": colorFromStop(scaleTextAt(11)) };
|
|
3833
3835
|
const linkInverseGroup = mode === "light" ? { "link": colorFromStop(invLt.link), "link-hover": colorFromStop(invLt.linkHover), "link-pressed": colorFromStop(invLt.linkPressed) } : { "link": colorFromStop(invLt.linkDark), "link-hover": colorFromStop(invLt.linkHoverDark), "link-pressed": colorFromStop(invLt.linkPressedDark) };
|
|
3834
3836
|
const g2 = {
|
|
3835
3837
|
brand: brandGroup,
|
|
@@ -3945,11 +3947,11 @@ export {
|
|
|
3945
3947
|
DEFAULT_LINK_HEX,
|
|
3946
3948
|
DISABLED_OPACITY,
|
|
3947
3949
|
EXT_KEY,
|
|
3948
|
-
INK_0,
|
|
3949
3950
|
MODE_SPECS,
|
|
3950
3951
|
OFFSET_ALPHAS,
|
|
3951
3952
|
OUTLINE_HOVER_ALPHA,
|
|
3952
|
-
|
|
3953
|
+
PAPER_0,
|
|
3954
|
+
PEN_100,
|
|
3953
3955
|
RESOLVER_ID,
|
|
3954
3956
|
SCALE_STOP_COUNT,
|
|
3955
3957
|
SCRIM_ALPHA,
|