okchroma 0.1.7 → 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.
@@ -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: { inkMult: 0.95, inkMaxC: 0.15, chromaFloor: chromaFloorBase(10) },
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: { inkMult: 0.95, inkMaxC: 0.15, chromaFloor: chromaFloorBase(10) },
211
- 11: { inkMult: 0.5, inkMaxC: 0.08, chromaFloor: chromaFloorBase(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: { inkMult: 0.95, inkMaxC: 0.12, chromaFloor: chromaFloorBase(10) },
224
- 10: { inkMult: 0.95, inkMaxC: 0.12, chromaFloor: chromaFloorBase(10) },
225
- 11: { inkMult: 0.62, inkMaxC: 0.045, chromaFloor: chromaFloorBase(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 INK_9_CONTRAST = 4.5;
243
- var INK_10_CONTRAST = 4.5;
244
- var INK_11_CONTRAST_FLOOR = 7;
245
- var INK_30_GROUND = {
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-wash band, the neutral's most-branded moment
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
- // wax-74
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
- // wax-74
355
+ // crayon-26
356
356
  [0.6, 0.4],
357
357
  // knee (ex-scaffold)
358
358
  [0.64, 0.347],
@@ -723,23 +723,23 @@ function perceptualDarkC(L, H2, nativeC, keep = KEEP_DARK, gamut = MASTER_GAMUT)
723
723
 
724
724
  // src/engine/tokenNames.ts
725
725
  var SHARED_NAMES = {
726
- 1: "paper-99",
727
- 2: "paper-97",
726
+ 1: "paper-1",
727
+ 2: "paper-3",
728
728
  // stop 3 renamed wash-3 → paper-3 (owner 2026-07-24, elevation round): it is a
729
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 wash-collision machinery
731
- // (collision.ts WASH_STOPS) deliberately still spans stops 3–7. (The requirement
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
732
  // spec's `group` label followed the band to 'paper' on 2026-08-31 — labels only,
733
733
  // the spans never moved; see spec.ts groupOf.)
734
734
  // Stage B (owner 2026-08-07, names only): relabeled to the ROOT_L-derived digit,
735
- // paper-95 — same band, same index.
736
- 3: "paper-95",
737
- 4: "wash-92",
738
- 5: "wash-89",
739
- 6: "wash-85",
740
- 7: "wash-80",
741
- 8: "wax-74",
742
- // THE INK BAND (C49, owner 2026-08-05): the first text stop + emphasis fill (the
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
743
  // 2026-07-29 highlight collapse — the old highlight-9 and on-highlight are
744
744
  // deleted; this stop carries both jobs, its on-color a paper token), the between
745
745
  // text stop (a value the retired text-cta hover state used to generate bespokely,
@@ -748,9 +748,9 @@ var SHARED_NAMES = {
748
748
  // two pre-collapse stop INDICES (11, and the off-scale anchor's 12 — emitted as a
749
749
  // literal in cssRender, not through this table) with the between stop taking the
750
750
  // vacated index 10; the indices (9/10/11) are unchanged since.
751
- 9: "lead-53",
752
- 10: "ink-42",
753
- 11: "ink-30"
751
+ 9: "pencil-47",
752
+ 10: "pen-58",
753
+ 11: "pen-70"
754
754
  };
755
755
  var SCALE_STOP_COUNT = Object.keys(SHARED_NAMES).length;
756
756
  function stopTokenName(stop) {
@@ -758,8 +758,8 @@ function stopTokenName(stop) {
758
758
  if (!name) throw new Error(`stopTokenName: unexpected stop ${stop}`);
759
759
  return name;
760
760
  }
761
- var PAPER_100 = "paper-100";
762
- var INK_0 = "ink-0";
761
+ var PAPER_0 = "paper-0";
762
+ var PEN_100 = "pen-100";
763
763
  var STAMP_FILL = "stamp-fill";
764
764
  var STAMP_FILL_HOVER = "stamp-fill-hover";
765
765
  var STAMP_FILL_PRESSED = "stamp-fill-pressed";
@@ -796,7 +796,7 @@ var SYSTEM_LEAF = {
796
796
  // and the 2026-08-29 inverse ladder): away-from-bg is the page-polarity pole
797
797
  // (black in light, white in dark), toward-bg the flipped pole — STATE LAYERS for
798
798
  // INVERTED grounds, whose polarity is opposite the page's. (Never call toward-bg
799
- // a "wash": that word belongs to the tinted band stops.) The reversal lives in
799
+ // a "highlighter": that word belongs to the tinted band stops.) The reversal lives in
800
800
  // the engine: a consumer on an inverted ground names one token and never picks a
801
801
  // pole. Colored fills never ride these; their states stay engine-solved stops.
802
802
  // Rungs are two-digit percent, harmonizing with shadow-04/08/12.
@@ -812,10 +812,10 @@ var SYSTEM_LEAF = {
812
812
  }
813
813
  };
814
814
  var SURFACE_PLANE_LAW = {
815
- [SYSTEM_LEAF.SURFACE.DIM]: { light: SHARED_NAMES[3], dark: PAPER_100 },
815
+ [SYSTEM_LEAF.SURFACE.DIM]: { light: SHARED_NAMES[3], dark: PAPER_0 },
816
816
  [SYSTEM_LEAF.SURFACE.LOW]: { light: SHARED_NAMES[2], dark: SHARED_NAMES[1] },
817
817
  [SYSTEM_LEAF.SURFACE.MID]: { light: SHARED_NAMES[1], dark: SHARED_NAMES[2] },
818
- [SYSTEM_LEAF.SURFACE.HIGH]: { light: PAPER_100, dark: SHARED_NAMES[3] }
818
+ [SYSTEM_LEAF.SURFACE.HIGH]: { light: PAPER_0, dark: SHARED_NAMES[3] }
819
819
  };
820
820
  var TOKEN_ORDER = [
821
821
  ...Object.values(SHARED_NAMES),
@@ -831,26 +831,26 @@ function tokenOrder(name) {
831
831
  }
832
832
 
833
833
  // src/engine/requirements/spec.ts
834
- var inkLane = (g2) => g2 === "lead" || g2 === "ink";
835
- var groupOf = (stop) => (stop === 0 ? PAPER_100 : stopTokenName(stop)).split("-")[0];
834
+ var textLane = (g2) => g2 === "pencil" || g2 === "pen" || g2 === "lead" || g2 === "ink";
835
+ var groupOf = (stop) => (stop === 0 ? PAPER_0 : stopTokenName(stop)).split("-")[0];
836
836
  var PAPER0_DARK_ROOT_L = 0.16;
837
837
  var PL_LADDER = { hue: "warm-drift", L: "perceptual", chroma: "ladder" };
838
838
  var PL_TEXT = { hue: "warm-drift", L: "perceptual", chroma: "brand" };
839
839
  var P_LIFT = { hue: "warm-torsion", L: "perceptual-lift", chroma: "ladder" };
840
840
  var P_FIXED = { hue: "warm-torsion", L: "fixed", chroma: "ladder" };
841
841
  var P_TEXT = { hue: "warm-torsion", L: "perceptual", chroma: "brand" };
842
- var S8 = { metric: "wcag", against: "paper-95", target: STOP_8_NONTEXT_CONTRAST, level: "AA" };
843
- var T9 = { metric: "wcag", against: "paper-97", target: INK_9_CONTRAST, level: "AA" };
844
- var T10 = { metric: "wcag", against: "wash-80", target: INK_10_CONTRAST, level: "AA" };
845
- var T11 = { metric: "wcag", against: "paper-97", target: INK_11_CONTRAST_FLOOR, level: "AAA" };
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" };
846
846
  var ONS = { onFill: { metric: "apca-pole", enforce: true, ratioFloor: 4.5, coEnforceLc: 65 } };
847
847
  var LIGHT = {
848
848
  stops: [
849
- // paper-100 (paper-0 pre-Stage-B): the resolved ladder extreme — in light it genuinely is white (rootL 1.0, zero chroma)
849
+ // paper-0 (paper-0 pre-Stage-B): the resolved ladder extreme — in light it genuinely is white (rootL 1.0, zero chroma)
850
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/wash/wax-74: perceptual ladder/envelope blend on the geometric ROOT_L_LIGHT scaffold. Separation
851
+ // paper/highlighter/crayon-26: perceptual ladder/envelope blend on the geometric ROOT_L_LIGHT scaffold. Separation
852
852
  // falls out of the shape (see above) — no min-separation require. Only stop 8 carries a require: the WCAG
853
- // 3:1 vs the resolved paper-97 (paper-2) (re-solves automatically since it references paper-97 (paper-2)).
853
+ // 3:1 vs the resolved paper-3 (paper-2) (re-solves automatically since it references paper-3 (paper-2)).
854
854
  ...[1, 2, 3, 4, 5, 6, 7, 8].map((stop) => ({
855
855
  stop,
856
856
  rootL: ROOT_L_LIGHT[stop],
@@ -860,12 +860,12 @@ var LIGHT = {
860
860
  baseC: SCALE_C_LIGHT[stop].base,
861
861
  require: stop === 8 ? S8 : void 0
862
862
  })),
863
- // ink text: perceptual + contrast-required. lead-53 (ink-9) is ALSO the emphasis fill (the
864
- // highlight-9 collapse, owner 2026-07-29). ink-42 (ink-10) is the between text stop (C49) —
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) —
865
865
  // a normal stop like its neighbors; the three together are the text-register cta.
866
- { stop: 9, rootL: ROOT_L_LIGHT[9], group: groupOf(9), produce: PL_TEXT, chromaMult: SCALE_C_LIGHT[9].inkMult, inkMaxC: SCALE_C_LIGHT[9].inkMaxC, 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].inkMult, inkMaxC: SCALE_C_LIGHT[10].inkMaxC, 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].inkMult, inkMaxC: SCALE_C_LIGHT[11].inkMaxC, chromaFloor: SCALE_C_LIGHT[11].chromaFloor, require: T11 }
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 }
869
869
  ],
870
870
  roles: [
871
871
  { role: "cta", produce: { hue: "constant", L: "anchor", chroma: "brand" }, floorL: 0, chromaMult: 1 },
@@ -876,10 +876,10 @@ var LIGHT = {
876
876
  };
877
877
  var DARK = {
878
878
  stops: [
879
- // paper-100 (paper-0 pre-Stage-B): the resolved ladder extreme — one seam BELOW paper-99 (paper-1), deep and brand-tinted, never the
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
880
880
  // absolute void (the old hard-coded #000000 was "too much"). Lift applies like the rest of the scale.
881
881
  { stop: 0, rootL: PAPER0_DARK_ROOT_L, group: groupOf(0), produce: P_LIFT, satFraction: SCALE_C_DARK[0].sat },
882
- // paper/wash 1–7: perceptual on the dark scaffold. stop 8: FIXED at the hand-placed scaffold BUT with the
882
+ // paper/highlighter 1–7: perceptual on the dark scaffold. stop 8: FIXED at the hand-placed scaffold BUT with the
883
883
  // 3:1 non-text require DECLARED (the Stage-5 flip, owner-approved) — the blue-recede failure is prevented
884
884
  // BY RULE, not by patch. The require now genuinely PLACES the stop rather than catching a few low-luminance
885
885
  // hues: on the delta-carry path it solves from the sentinel every time, and the old claim that "most hues
@@ -893,11 +893,11 @@ var DARK = {
893
893
  satFraction: SCALE_C_DARK[stop].sat,
894
894
  require: stop === 8 ? S8 : void 0
895
895
  })),
896
- // ink text: perceptual + the contrast requires DECLARED in dark too (Stage-5 flip): the scaffold already
896
+ // pen text: perceptual + the contrast requires DECLARED in dark too (Stage-5 flip): the scaffold already
897
897
  // clears them for every hue (the gate proves it), so values don't move — but the guarantee is now a rule.
898
- { stop: 9, rootL: ROOT_L_DARK[9], group: groupOf(9), produce: P_TEXT, chromaMult: SCALE_C_DARK[9].inkMult, inkMaxC: SCALE_C_DARK[9].inkMaxC, 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].inkMult, inkMaxC: SCALE_C_DARK[10].inkMaxC, 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].inkMult, inkMaxC: SCALE_C_DARK[11].inkMaxC, chromaFloor: SCALE_C_DARK[11].chromaFloor, require: T11 }
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 }
901
901
  ],
902
902
  roles: [
903
903
  { role: "cta", produce: { hue: "constant", L: "anchor", chroma: "brand" }, floorL: DARK_CTA_MIN_L, chromaMult: 1 },
@@ -908,7 +908,7 @@ var DARK = {
908
908
  };
909
909
  var MODE_SPECS = { light: LIGHT, dark: DARK };
910
910
 
911
- // ../../../Users/emilygerrity/okchroma/node_modules/helmlab/dist/index.js
911
+ // node_modules/helmlab/dist/index.js
912
912
  function o0(n) {
913
913
  let t = new Float64Array(9);
914
914
  for (let e = 0; e < 3; e++) for (let s = 0; s < 3; s++) t[e * 3 + s] = n[e][s];
@@ -1824,7 +1824,7 @@ function p2Diff(a, b) {
1824
1824
  var DEFAULT_APCA_LC_MAP = { 3: 30, 4.5: 75, 6.5: 85, 7: 90 };
1825
1825
  function toApca(req, lcMap) {
1826
1826
  if (req.metric !== "wcag") return req;
1827
- if (req.against === "wash-80") return { metric: "apca", against: "paper-97", targetLc: 85 };
1827
+ if (req.against === "highlighter-20") return { metric: "apca", against: "paper-3", targetLc: 85 };
1828
1828
  const targetLc = lcMap[req.target];
1829
1829
  if (targetLc === void 0) throw new Error(`apca profile: no Lc mapping for wcag target ${req.target}`);
1830
1830
  return { metric: "apca", against: req.against, targetLc };
@@ -1838,7 +1838,7 @@ function withProfile(spec, profile, lcMap = DEFAULT_APCA_LC_MAP) {
1838
1838
  // (The stop-9 CARVE-OUT is gone with the stop, owner 2026-07-29. It existed because
1839
1839
  // highlight-9's require was a fill-vs-its-own-plane bar with no honest slot in a map
1840
1840
  // of TEXT bars — 3 → 30 non-text, 4.5 → 75 body, 7 → 90 — so the apca lane kept its
1841
- // own hl-9 placement instead. Today's stop 9 is an INK stop: 4.5 is a text bar, the
1841
+ // own hl-9 placement instead. Today's stop 9 is a PEN stop: 4.5 is a text bar, the
1842
1842
  // 75 slot is its correct translation, and it maps like every other require.)
1843
1843
  stops: spec.stops.map((s) => s.require ? { ...s, require: toApca(s.require, lcMap) } : s),
1844
1844
  ons: {
@@ -2000,16 +2000,16 @@ function separationClampLight(ctx, placed, chromaAt, ref, target) {
2000
2000
  return { L: pass, C: ceilingAt(pass), H: ctx.lightHueAt(pass) };
2001
2001
  }
2002
2002
  function placeLightText(ctx, rootL, cMult, maxLFor, deepen, maxC = Infinity) {
2003
- const inkC = Math.min(cMult * ctx.brandC, maxC);
2004
- const anchorL = perceptualRungL(rootL, clampChromaToGamut(rootL, inkC, ctx.lightHueAt(rootL)), ctx.lightHueAt(rootL));
2003
+ const textC = Math.min(cMult * ctx.brandC, maxC);
2004
+ const anchorL = perceptualRungL(rootL, clampChromaToGamut(rootL, textC, ctx.lightHueAt(rootL)), ctx.lightHueAt(rootL));
2005
2005
  let H2 = ctx.lightHueAt(anchorL);
2006
- let C2 = clampChromaToGamut(anchorL, inkC, H2);
2006
+ let C2 = clampChromaToGamut(anchorL, textC, H2);
2007
2007
  let L = Math.min(anchorL, maxLFor(C2, H2));
2008
2008
  H2 = ctx.lightHueAt(L);
2009
- C2 = clampChromaToGamut(L, inkC, H2);
2009
+ C2 = clampChromaToGamut(L, textC, H2);
2010
2010
  L = Math.min(anchorL, maxLFor(C2, H2));
2011
2011
  L = Math.min(L - deepen, maxLFor(C2, ctx.lightHueAt(L - deepen)));
2012
- return { L, C: ctx.cAt("light", L, inkC), H: ctx.lightHueAt(L) };
2012
+ return { L, C: ctx.cAt("light", L, textC), H: ctx.lightHueAt(L) };
2013
2013
  }
2014
2014
  function onFillIsWhiteLight(ctx, enforce, ratioFloor) {
2015
2015
  const fill9ApcaY = apcaYAt(ctx.scaleL, clampChromaToGamut(ctx.scaleL, ctx.cAt("light", ctx.scaleL, ctx.brandC), ctx.brandH), ctx.brandH);
@@ -2023,7 +2023,7 @@ function buildDarkContext(ctx, specFloorL = DARK_CTA_MIN_L) {
2023
2023
  return { dark9L, darkC9, darkHueAtL };
2024
2024
  }
2025
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));
2026
- var darkInkChromaAt = (ctx, dctx, floorBase, multiplier, maxC = Infinity) => (L) => ctx.cAt("dark", L, Math.min(applyChromaFloor(ctx.brandC, multiplier, floorBase, ctx.darkFloorStrength), maxC));
2026
+ var darkTextChromaAt = (ctx, dctx, floorBase, multiplier, maxC = Infinity) => (L) => ctx.cAt("dark", L, Math.min(applyChromaFloor(ctx.brandC, multiplier, floorBase, ctx.darkFloorStrength), maxC));
2027
2027
  function placeDark(dctx, rootL, chromaAt, lift = false) {
2028
2028
  let L = perceptualRungL(rootL, chromaAt(rootL), dctx.darkHueAtL(rootL));
2029
2029
  if (lift) L = Math.max(L, rootL);
@@ -2284,7 +2284,7 @@ function resolveRamp(hex, mode, spec, opts) {
2284
2284
  const seed = { hex, ...o };
2285
2285
  const ctx = buildContext(hex, opts);
2286
2286
  spec ?? (spec = MODE_SPECS[mode]);
2287
- if (ctx.opts?.inkGround) {
2287
+ if (ctx.opts?.textGround) {
2288
2288
  spec = {
2289
2289
  ...spec,
2290
2290
  stops: spec.stops.map((s) => s.stop === 10 && s.require?.metric === "wcag" ? { ...s, require: { ...s.require, target: 6.5 } } : s)
@@ -2306,12 +2306,12 @@ function resolveRamp(hex, mode, spec, opts) {
2306
2306
  if (!ref) throw new Error(`stop ${forWhom}: require against stop ${stopNum} but it is not resolved yet`);
2307
2307
  return ref;
2308
2308
  };
2309
- const AGAINST_STOP = { "paper-99": 1, "paper-97": 2, "paper-95": 3, "wash-80": 7 };
2309
+ const AGAINST_STOP = { "paper-1": 1, "paper-3": 2, "paper-5": 3, "highlighter-20": 7 };
2310
2310
  const declaredAnchor = (req) => req.metric === "min-separation" ? 1 : AGAINST_STOP[req.against] ?? 2;
2311
2311
  const wcagAnchorStop = (req, stop) => stop >= 9 && declaredAnchor(req) <= 3 ? 3 : declaredAnchor(req);
2312
- const inkGround = ctx.opts?.inkGround?.[mode];
2313
- const groundOf = (req, stop) => inkGround && stop >= 9 ? inkGround : refOf(wcagAnchorStop(req, stop), stop);
2314
- const apcaGroundOf = (req, stop) => inkGround && stop >= 9 ? inkGround : refOf(declaredAnchor(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);
2315
2315
  const NEUTRAL_P3_WORST_SHIP_Y = { light: 0.845015, dark: 0.014247 };
2316
2316
  const NEUTRAL_W80_WORST_SHIP_Y = { light: 0.506433, dark: 0.074262 };
2317
2317
  const maxLForOf = (req, forWhom, withMargin) => {
@@ -2329,14 +2329,14 @@ function resolveRamp(hex, mode, spec, opts) {
2329
2329
  }
2330
2330
  throw new Error(`stop ${forWhom}: ${req.metric} is not a contrast require`);
2331
2331
  };
2332
- const INK_DEEPEN = 0;
2332
+ const TEXT_DEEPEN = 0;
2333
2333
  for (const sp of spec.stops) {
2334
2334
  let placed;
2335
2335
  let clamped = false, unresolvable;
2336
2336
  if (mode === "light") {
2337
- if (inkLane(sp.group)) {
2338
- if (!sp.require) throw new Error(`light ink stop ${sp.stop} must declare a contrast require`);
2339
- placed = placeLightText(ctx, sp.rootL, sp.chromaMult ?? 1, maxLForOf(sp.require, sp.stop, false), INK_DEEPEN, sp.inkMaxC);
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);
2340
2340
  clamped = true;
2341
2341
  } else if (sp.produce.L === "fixed") {
2342
2342
  const chromaAt = lightScaleChromaAt(ctx, sp.baseC ?? 0, sp.satFraction ?? 1);
@@ -2348,7 +2348,7 @@ function resolveRamp(hex, mode, spec, opts) {
2348
2348
  placed = placeLightScale(ctx, sp.rootL, chromaAt, contrastReq ? maxLForOf(contrastReq, sp.stop, true) : void 0, targetChromaAt);
2349
2349
  clamped = !!contrastReq;
2350
2350
  if (sp.require?.metric === "min-separation") {
2351
- const refStop = sp.require.against === "paper-99" ? 1 : sp.stop - 1;
2351
+ const refStop = sp.require.against === "paper-1" ? 1 : sp.stop - 1;
2352
2352
  const ref = stops.find((s) => s.stop === refStop);
2353
2353
  if (!ref) throw new Error(`stop ${sp.stop}: min-separation against stop ${refStop} but it is not resolved yet`);
2354
2354
  const before = placed.L;
@@ -2358,8 +2358,8 @@ function resolveRamp(hex, mode, spec, opts) {
2358
2358
  }
2359
2359
  } else {
2360
2360
  const d = dctx;
2361
- const inkTwin = inkLane(sp.group) && ctx.opts?.deltaCarry && ctx.opts?.chromaCurve ? ctx.opts.deltaLightStops?.find((s) => s.stop === sp.stop) : void 0;
2362
- const chromaAt = inkLane(sp.group) ? inkTwin ? ((_L) => inkTwin.C) : darkInkChromaAt(ctx, d, sp.chromaFloor ?? chromaFloorBase(sp.stop), sp.chromaMult ?? 1, sp.inkMaxC) : darkScaleChromaAt(ctx, d, Math.max(0, sp.stop - 1), sp.satFraction ?? 1);
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);
2363
2363
  let spineH = null;
2364
2364
  const dl = ctx.opts?.deltaLightStops;
2365
2365
  const ls = dl && sp.stop >= 1 && sp.stop <= 8 ? dl.find((s) => s.stop === sp.stop) : void 0;
@@ -2379,7 +2379,7 @@ function resolveRamp(hex, mode, spec, opts) {
2379
2379
  }
2380
2380
  if (ctx.opts.deltaHKPlace) L = perceptualRungL(sp.rootL, ls.C, ls.H);
2381
2381
  if (ctx.opts.deltaLiftFloor) L = Math.max(L, sp.rootL);
2382
- if (ctx.opts.deltaChromaEq && !inkLane(sp.group)) C2 = ctx.cAt("dark", L, perceptualDarkC(L, ls.H, ctx.brandC));
2382
+ if (ctx.opts.deltaChromaEq && !textLane(sp.group)) C2 = ctx.cAt("dark", L, perceptualDarkC(L, ls.H, ctx.brandC));
2383
2383
  placed = { L, C: C2, H: spineH ?? ls.H };
2384
2384
  } else if (sp.produce.L === "fixed") {
2385
2385
  placed = ls ? placeDarkDelta(d, sp.rootL, chromaAt, ls) : { L: sp.rootL, C: chromaAt(sp.rootL), H: d.darkHueAtL(sp.rootL) };
@@ -2415,7 +2415,7 @@ function resolveRamp(hex, mode, spec, opts) {
2415
2415
  if (sp.require?.metric === "wcag") {
2416
2416
  const anchor = groundOf(sp.require, sp.stop);
2417
2417
  const anchorShipY = shippedY(anchor.L, anchor.C, anchor.H);
2418
- const paperBound = sp.stop >= 8 && !(inkGround && sp.stop >= 9);
2418
+ const paperBound = sp.stop >= 8 && !(textGround && sp.stop >= 9);
2419
2419
  const crossBoundY = wcagAnchorStop(sp.require, sp.stop) === 7 ? NEUTRAL_W80_WORST_SHIP_Y[mode] : NEUTRAL_P3_WORST_SHIP_Y[mode];
2420
2420
  const shipRatio = (L) => {
2421
2421
  const y2 = shippedY(L, placed.C, placed.H);
@@ -2443,7 +2443,7 @@ function resolveRamp(hex, mode, spec, opts) {
2443
2443
  const got = Math.abs(apcaLc(apcaYAt(placed.L, clampChromaToGamut(placed.L, placed.C, placed.H), placed.H), refA));
2444
2444
  if (got < sp.require.targetLc - APCA_TOL_LC) unresolvable = `stop ${sp.stop}: |Lc| ${got.toFixed(1)} < required ${sp.require.targetLc}`;
2445
2445
  } else if (sp.require?.metric === "min-separation") {
2446
- const ref = stops.find((s) => s.stop === (sp.require.against === "paper-99" ? 1 : sp.stop - 1));
2446
+ const ref = stops.find((s) => s.stop === (sp.require.against === "paper-1" ? 1 : sp.stop - 1));
2447
2447
  const rad2 = (h) => h * Math.PI / 180;
2448
2448
  const gC = clampChromaToGamut(placed.L, placed.C, placed.H);
2449
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);
@@ -2599,7 +2599,7 @@ function generateScale(hex, scaleName, forcedArchetype, opts) {
2599
2599
  const dark = darkRamp.stops.filter((s) => s.stop >= 1).map(toStop).sort((a, b) => a.stop - b.stop);
2600
2600
  const p0Light = lightRamp.stops.find((s) => s.stop === 0);
2601
2601
  const p0Dark = darkRamp.stops.find((s) => s.stop === 0);
2602
- const inkPole = (arr, L) => arr.find((s) => s.stop === 11) ? makeStop(12, L, 0, arr.find((s) => s.stop === 11).H) : void 0;
2602
+ const penPole = (arr, L) => arr.find((s) => s.stop === 11) ? makeStop(12, L, 0, arr.find((s) => s.stop === 11).H) : void 0;
2603
2603
  const cta = makeStop(9, lightRamp.roles.cta.L, lightRamp.roles.cta.C, lightRamp.roles.cta.H);
2604
2604
  const ctaDark = makeStop(9, darkRamp.roles.cta.L, darkRamp.roles.cta.C, darkRamp.roles.cta.H);
2605
2605
  const roleStop = (r, stop) => makeStop(stop, r.L, r.C, r.H);
@@ -2623,8 +2623,8 @@ function generateScale(hex, scaleName, forcedArchetype, opts) {
2623
2623
  identityHex: hex.toUpperCase(),
2624
2624
  paper0: p0Light ? makeStop(0, p0Light.L, p0Light.C, p0Light.H) : void 0,
2625
2625
  paper0Dark: p0Dark ? makeStop(0, p0Dark.L, p0Dark.C, p0Dark.H) : void 0,
2626
- ink0: inkPole(light, 0),
2627
- ink0Dark: inkPole(dark, 1)
2626
+ pen100: penPole(light, 0),
2627
+ pen100Dark: penPole(dark, 1)
2628
2628
  };
2629
2629
  }
2630
2630
  function generateNeutralScale(brandH, level = "default", contrastProfile) {
@@ -2696,8 +2696,7 @@ function generateSubtleSecondary(hex, opts) {
2696
2696
 
2697
2697
  // src/engine/tokenDescriptions.ts
2698
2698
  var AA_LARGE = "AA large text and UI elements";
2699
- var AA_BODY = "AA standard body text & Level AAA large text";
2700
- var AAA_BODY = "AAA standard body text";
2699
+ var AA_BODY = "AA standard body text";
2701
2700
  var FAMILY = {
2702
2701
  neutral: "neutral",
2703
2702
  brandPrimary: "brand",
@@ -2733,7 +2732,7 @@ var COLOR_WORD = {
2733
2732
  [FAMILY.info]: " (blue)"
2734
2733
  };
2735
2734
  var PAPER = { req: "backgrounds, inverted text", theming: (f) => TINT[f], collides: true };
2736
- var WASH = { req: "subtle interactive states, decorative borders, illos, signal hierarchy", theming: (f) => TINT[f], collides: true };
2735
+ var HIGHLIGHTER = { req: "subtle interactive states, decorative borders, illos, signal hierarchy", theming: (f) => TINT[f], collides: true };
2737
2736
  var solved = (f) => `${TINT[f]}; re-solved to clear its floor`;
2738
2737
  var OVERLAY = {
2739
2738
  req: "translucent backgrounds that hold their reading on any paper",
@@ -2741,25 +2740,25 @@ var OVERLAY = {
2741
2740
  collides: true
2742
2741
  };
2743
2742
  var SCALE = {
2744
- "paper-99": PAPER,
2743
+ "paper-1": PAPER,
2745
2744
  "paper-99-overlay": OVERLAY,
2746
- "paper-97": PAPER,
2745
+ "paper-3": PAPER,
2747
2746
  "paper-97-overlay": OVERLAY,
2748
- "paper-95": { req: "backgrounds, inverted text", theming: (f) => `${TINT[f]}. Worst background text stops must clear.`, collides: true },
2747
+ "paper-5": { req: "backgrounds, inverted text", theming: (f) => `${TINT[f]}. Worst background text stops must clear.`, collides: true },
2749
2748
  "paper-95-overlay": OVERLAY,
2750
- "wash-92": WASH,
2751
- "wash-89": WASH,
2752
- "wash-85": WASH,
2753
- "wash-80": WASH,
2749
+ "highlighter-8": HIGHLIGHTER,
2750
+ "highlighter-11": HIGHLIGHTER,
2751
+ "highlighter-15": HIGHLIGHTER,
2752
+ "highlighter-20": HIGHLIGHTER,
2754
2753
  // ("icons" KEPT through the 2026-08-28 on-flood strip (owner): an "icon" query
2755
- // landing on the wax rows is worth its ic-ON-s noise — the one surviving body carrier)
2756
- "wax-74": { req: "focus rings, icons, large text", contrast: AA_LARGE, theming: solved, collides: true },
2757
- "lead-53": { req: "regular text, inverted backgrounds", contrast: AA_BODY, theming: solved, collides: true },
2758
- "ink-42": { req: "regular text, inverted backgrounds", contrast: AA_BODY, theming: solved, collides: true },
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 },
2759
2758
  // ("high-emphasis" reworded 2026-08-12: the surface planes took low/high as label
2760
2759
  // words, and a body carrying either floods that token's picker search — the C50 law;
2761
2760
  // "strong-emphasis" reworded 2026-08-28: str-ON-g fed the "on" flood)
2762
- "ink-30": { req: "heavy-emphasis text, inverted backgrounds", contrast: AAA_BODY, theming: solved, collides: true },
2761
+ "pen-70": { req: "heavy-emphasis text, inverted backgrounds", contrast: AA_BODY, theming: solved, collides: true },
2763
2762
  // the stamp family (cta words → solid 2026-08-18, solid → stamp 2026-08-27). "CTA" stays in
2764
2763
  // these bodies on purpose: it stopped being a token label, so it floods nothing,
2765
2764
  // and a designer's "cta" query still lands on these rows.
@@ -2788,7 +2787,7 @@ var LINK_INVERSE = (state, contrast) => ({
2788
2787
  var SYSTEM = {
2789
2788
  "system/abs-black": ABS,
2790
2789
  "system/abs-white": ABS,
2791
- // (the community system/ink-0 row RETIRED 2026-08-28 with its STATIC_UTILS entry:
2790
+ // (the community system/pen-100 row RETIRED 2026-08-28 with its STATIC_UTILS entry:
2792
2791
  // the anchor is engine-resolved and rides the neutral in BOTH plugins now —
2793
2792
  // NEUTRAL_ONLY above. Old files' static rows orphan unwritten.)
2794
2793
  "system/abs-primary": { req: "identity seed reference", theming: "the theme\u2019s own input, as given" },
@@ -2804,7 +2803,7 @@ var SYSTEM = {
2804
2803
  "system/alpha/away-from-bg/08": OFFSET,
2805
2804
  "system/alpha/away-from-bg/16": OFFSET,
2806
2805
  // the inverse ladder: the offset rungs with the pole flipped per mode, for
2807
- // washes and edges over inverted backgrounds ("interaction" avoided in the
2806
+ // highlighters and edges over inverted backgrounds ("interaction" avoided in the
2808
2807
  // bodies: acti-ON would feed the "on" flood)
2809
2808
  "system/alpha/toward-bg/06": OFFSET_INVERSE,
2810
2809
  "system/alpha/toward-bg/08": OFFSET_INVERSE,
@@ -2821,10 +2820,10 @@ var SYSTEM = {
2821
2820
  "system/surface/high": PLANE("topmost plane \u2014 modals, dialogs"),
2822
2821
  "system/link/default/enabled": LINK("", AA_BODY),
2823
2822
  "system/link/default/hover": LINK(" pointer-over", AA_BODY),
2824
- "system/link/default/pressed": LINK(" pressed", AAA_BODY),
2823
+ "system/link/default/pressed": LINK(" pressed", AA_BODY),
2825
2824
  "system/link/inverse/enabled": LINK_INVERSE("", AA_BODY),
2826
2825
  "system/link/inverse/hover": LINK_INVERSE(" pointer-over", AA_BODY),
2827
- "system/link/inverse/pressed": LINK_INVERSE(" pressed", AAA_BODY)
2826
+ "system/link/inverse/pressed": LINK_INVERSE(" pressed", AA_BODY)
2828
2827
  };
2829
2828
  var PREFIXES = [
2830
2829
  // community spellings FIRST: the 2026-08-21 family rename made the ext word a
@@ -2871,15 +2870,15 @@ function checkCollision(brand, signalScale, signalDef, mode) {
2871
2870
  collides: hueGate && deltaE <= threshold
2872
2871
  };
2873
2872
  }
2874
- var HUE_COLLISION_WASH_DEG = 15;
2873
+ var HUE_COLLISION_HIGHLIGHTER_DEG = 15;
2875
2874
  var HUE_COLLISION_MIN_V = 0.5;
2876
2875
  var SECONDARY_NOTE_MIN_V = HUE_NOISE_C / VIVID_C;
2877
- var WASH_STOPS = [3, 4, 5, 6, 7];
2878
- function washProximity(brand, sig, mode) {
2876
+ var HIGHLIGHTER_STOPS = [3, 4, 5, 6, 7];
2877
+ function highlighterProximity(brand, sig, mode) {
2879
2878
  const b = mode === "light" ? brand.light : brand.dark;
2880
2879
  const s = mode === "light" ? sig.light : sig.dark;
2881
2880
  let dH = Infinity, dE = Infinity;
2882
- for (const k of WASH_STOPS) {
2881
+ for (const k of HIGHLIGHTER_STOPS) {
2883
2882
  const bs = b.find((x2) => x2.stop === k), ss = s.find((x2) => x2.stop === k);
2884
2883
  if (!bs || !ss) continue;
2885
2884
  dH = Math.min(dH, hueDistance(bs.H, ss.H));
@@ -2888,15 +2887,15 @@ function washProximity(brand, sig, mode) {
2888
2887
  return { dH, dE };
2889
2888
  }
2890
2889
  function checkHueCollision(brand, signalScale, signalDef, opts) {
2891
- const l = washProximity(brand, signalScale, "light");
2892
- const d = washProximity(brand, signalScale, "dark");
2890
+ const l = highlighterProximity(brand, signalScale, "light");
2891
+ const d = highlighterProximity(brand, signalScale, "dark");
2893
2892
  const vividness = Math.min(1, brand.brandC / VIVID_C);
2894
2893
  return {
2895
2894
  signal: signalDef.name,
2896
- dHueWash: { light: l.dH, dark: d.dH },
2897
- washDeltaE: { light: l.dE, dark: d.dE },
2895
+ dHueHighlighter: { light: l.dH, dark: d.dH },
2896
+ highlighterDeltaE: { light: l.dE, dark: d.dE },
2898
2897
  vividness,
2899
- collides: vividness >= (opts?.minV ?? HUE_COLLISION_MIN_V) && Math.min(l.dH, d.dH) <= HUE_COLLISION_WASH_DEG
2898
+ collides: vividness >= (opts?.minV ?? HUE_COLLISION_MIN_V) && Math.min(l.dH, d.dH) <= HUE_COLLISION_HIGHLIGHTER_DEG
2900
2899
  };
2901
2900
  }
2902
2901
  var YELLOW_SPLIT_H = 96;
@@ -3089,7 +3088,7 @@ function resolveBrand(hex, name, opts) {
3089
3088
  // (buildSignalScales/signalShift) — neutral alone stays outside; exact has enforce off.
3090
3089
  apcaClearance: opts?.apcaClearance ?? true,
3091
3090
  darkCtaFlatApp: opts?.darkCtaFlatApp,
3092
- inkGround: opts?.inkGround
3091
+ textGround: opts?.textGround
3093
3092
  };
3094
3093
  let scale = generateScale(hex, name, void 0, floor);
3095
3094
  let pending = [];
@@ -3172,7 +3171,7 @@ function resolveLinkTrio(linkHex, contrastProfile) {
3172
3171
  const s = resolveBrand(linkHex, "link", { skipCollisionRules: true, contrastProfile }).scale;
3173
3172
  const at = (arr, n) => {
3174
3173
  const st = arr.find((x2) => x2.stop === n);
3175
- if (!st) throw new Error(`resolveLinkTrio: the link resolve has no ink stop ${n}`);
3174
+ if (!st) throw new Error(`resolveLinkTrio: the link resolve has no pen stop ${n}`);
3176
3175
  return st;
3177
3176
  };
3178
3177
  return {
@@ -3185,16 +3184,16 @@ function resolveLinkTrio(linkHex, contrastProfile) {
3185
3184
  };
3186
3185
  }
3187
3186
  function resolveLinkInverseTrio(seedHex, contrastProfile) {
3188
- const ground = INK_30_GROUND[contrastProfile === "apca" ? "apca" : "wcag"];
3187
+ const ground = PEN_70_GROUND[contrastProfile === "apca" ? "apca" : "wcag"];
3189
3188
  const s = resolveBrand(seedHex, "link-inverse", {
3190
3189
  skipCollisionRules: true,
3191
3190
  contrastProfile,
3192
3191
  // the cross — ramp keyed, ground mode-swapped
3193
- inkGround: { light: ground.dark, dark: ground.light }
3192
+ textGround: { light: ground.dark, dark: ground.light }
3194
3193
  }).scale;
3195
3194
  const at = (arr, n) => {
3196
3195
  const st = arr.find((x2) => x2.stop === n);
3197
- if (!st) throw new Error(`resolveLinkInverseTrio: the link resolve has no ink stop ${n}`);
3196
+ if (!st) throw new Error(`resolveLinkInverseTrio: the link resolve has no pen stop ${n}`);
3198
3197
  return st;
3199
3198
  };
3200
3199
  return {
@@ -3208,12 +3207,12 @@ function resolveLinkInverseTrio(seedHex, contrastProfile) {
3208
3207
  };
3209
3208
  }
3210
3209
  function escapeCtaFamily(nScale, mode, contrastProfile) {
3211
- const strongInk = (mode === "light" ? nScale.light : nScale.dark).find((s) => s.stop === 11);
3212
- if (!strongInk) throw new Error("escapeCtaFamily: the neutral scale has no ink-11 stop");
3213
- const mk = (stop, L) => makeStop(stop, L, strongInk.C, strongInk.H);
3214
- const cta = mk(9, strongInk.L);
3215
- const ctaHover = mk(10, stateFillL(strongInk.L, mode, 1));
3216
- const ctaPressed = mk(11, stateFillL(strongInk.L, mode, 2));
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));
3217
3216
  const onEnforce = contrastProfile !== "apca";
3218
3217
  const onFloor = contrastProfile === "apca" ? void 0 : 4.5;
3219
3218
  const onFillIsWhite = onTextIsWhite(apcaY(cta.r, cta.g, cta.b), cta.L, cta.C, cta.H, onEnforce, onFloor);
@@ -3289,7 +3288,7 @@ function resolveTheme(input) {
3289
3288
  for (const def of SIGNALS2) {
3290
3289
  if (adoptedForSecondary.has(def.name)) continue;
3291
3290
  const h = checkHueCollision(scale2, effectiveOf(def.name), def, { minV: SECONDARY_NOTE_MIN_V });
3292
- if (h.collides) out.push(wording(def.name, Math.min(h.washDeltaE.light, h.washDeltaE.dark)));
3291
+ if (h.collides) out.push(wording(def.name, Math.min(h.highlighterDeltaE.light, h.highlighterDeltaE.dark)));
3293
3292
  }
3294
3293
  return out;
3295
3294
  };
@@ -3339,7 +3338,7 @@ function resolveTheme(input) {
3339
3338
  derived: true,
3340
3339
  notes: [
3341
3340
  `secondary derived from the brand color (default model, seed ${liftedHex})`,
3342
- ...signalNotesFor(scale2, (name, dE) => `derived secondary sits on the ${name} signal's hue (wash \u0394E ${dE.toFixed(3)}) \u2014 it tracks the brand color`)
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`)
3343
3342
  ],
3344
3343
  distinctness: ctaDistinctness(primary.scale, scale2)
3345
3344
  },
@@ -3364,7 +3363,7 @@ function resolveTheme(input) {
3364
3363
  derived: false,
3365
3364
  notes: [
3366
3365
  `secondary keeps your color through the ramp; the cta is a tint of it (tint seed ${tintedHex})`,
3367
- ...signalNotesFor(scale2, (name, dE) => `secondary sits on the ${name} signal's hue (wash \u0394E ${dE.toFixed(3)}) \u2014 it tracks your color`)
3366
+ ...signalNotesFor(scale2, (name, dE) => `secondary sits on the ${name} signal's hue (highlighter \u0394E ${dE.toFixed(3)}) \u2014 it tracks your color`)
3368
3367
  ],
3369
3368
  distinctness: distinctness2
3370
3369
  },
@@ -3376,7 +3375,7 @@ function resolveTheme(input) {
3376
3375
  const scale = rSec.scale;
3377
3376
  const level = "standard";
3378
3377
  mergeSecondarySignals(scale, input.secondaryHex);
3379
- const secNotes = signalNotesFor(scale, (name, dE) => `secondary reads close to the ${name} signal (wash \u0394E ${dE.toFixed(3)}) \u2014 your color ships untouched`);
3378
+ const secNotes = signalNotesFor(scale, (name, dE) => `secondary reads close to the ${name} signal (highlighter \u0394E ${dE.toFixed(3)}) \u2014 your color ships untouched`);
3380
3379
  const distinctness = ctaDistinctness(primary.scale, scale);
3381
3380
  if (distinctness.close)
3382
3381
  notes.push(`secondary reads close to the primary (\u0394E ${Math.min(distinctness.light, distinctness.dark).toFixed(2)}) \u2014 consider a more distinct color`);
@@ -3435,7 +3434,7 @@ var alphaRootVars = (mode) => [
3435
3434
  ...Object.keys(OFFSET_ALPHAS).map(Number).sort((a, b) => a - b).map((r) => ` ${offsetVarName(r)}: ${offsetRgba(r, mode)};`),
3436
3435
  // the toward-bg ladder (the 2026-08-29 inverse ladder, renamed 2026-08-31): the
3437
3436
  // same rungs, pole flipped per mode — state layers for INVERTED grounds (never
3438
- // called a "wash" — that word is the tinted band's). One spelling with the Figma
3437
+ // called a "highlighter" — that word is the tinted band's). One spelling with the Figma
3439
3438
  // row: --alpha-toward-bg-06 ↔ system/alpha/toward-bg/06.
3440
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")};`)
3441
3440
  ];
@@ -3462,7 +3461,7 @@ function brandKindBody(prefix, s, mode, page) {
3462
3461
  ` --${prefix}-stamp-fill-pressed: ${stopHex(f.ctaPressed)};`,
3463
3462
  ` --${prefix}-stamp-edge: var(${border ? offsetVarName(ctaBorderRung(prefix)) : TRANSPARENT_VAR});`,
3464
3463
  // the SOFT on-cta (owner 2026-08-04: "neutral cta on's should also be the alpha"): the
3465
- // neutral's cta is the scale-fed WASH-level fill, the system's other quiet cta, so its
3464
+ // neutral's cta is the scale-fed HIGHLIGHTER-level fill, the system's other quiet cta, so its
3466
3465
  // button text takes the pole AT ALPHA like the default-model secondary's — composited
3467
3466
  // over whatever state the fill is in, so hover/pressed carry their own legibility. Same
3468
3467
  // register both families (SOFT_ON_CTA_ALPHA), so both alias the ONE system/alpha/ink
@@ -3492,16 +3491,16 @@ function neutralCss(selector, brandH, level = "default", contrastProfile, ctaBor
3492
3491
  const p3Dark = brandKindP3Body(CSS_NEUTRAL, s, "dark");
3493
3492
  return [
3494
3493
  `${selector} {`,
3495
- ` --${PAPER_100}: ${p02(s.paper0, "#ffffff")};`,
3496
- ` --${INK_0}: ${p02(s.ink0, "#000000")};`,
3494
+ ` --${PAPER_0}: ${p02(s.paper0, "#ffffff")};`,
3495
+ ` --${PEN_100}: ${p02(s.pen100, "#000000")};`,
3497
3496
  // the neutral IS the page, so it is judged against its own paper stop
3498
3497
  // the neutral's overlays never read the visibility bar (the exempt family), so
3499
3498
  // the brandless chrome context passes 0
3500
3499
  ...brandKindBody(CSS_NEUTRAL, s, "light", nPage("light")),
3501
3500
  `}`,
3502
3501
  `${selector}[data-theme="dark"] {`,
3503
- ` --${PAPER_100}: ${p02(s.paper0Dark, "#000000")};`,
3504
- ` --${INK_0}: ${p02(s.ink0Dark, "#ffffff")};`,
3502
+ ` --${PAPER_0}: ${p02(s.paper0Dark, "#000000")};`,
3503
+ ` --${PEN_100}: ${p02(s.pen100Dark, "#ffffff")};`,
3505
3504
  ...brandKindBody(CSS_NEUTRAL, s, "dark", nPage("dark")),
3506
3505
  `}`,
3507
3506
  ...p3Light.length || p3Dark.length ? [
@@ -3590,8 +3589,8 @@ function brandCss(slug, displayName, r, secondary, noteSuffix = "", neutralLevel
3590
3589
  const brandIdentity = ` --${CSS_BRAND}-identity: ${scale.identityHex};`;
3591
3590
  const secondaryIdentity = secondary ? ` --${CSS_SECONDARY}-identity: ${secondary.identityHex};` : ` --${CSS_SECONDARY}-identity: var(--${CSS_BRAND}-identity);`;
3592
3591
  const p0hex = (s, fallback) => s ? stopHex(s) : fallback;
3593
- const lightAnchors = [` --${PAPER_100}: ${p0hex(nScale.paper0, "#ffffff")};`, ` --${INK_0}: ${p0hex(nScale.ink0, "#000000")};`];
3594
- const darkAnchors = [` --${PAPER_100}: ${p0hex(nScale.paper0Dark, "#000000")};`, ` --${INK_0}: ${p0hex(nScale.ink0Dark, "#ffffff")};`];
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")};`];
3595
3594
  const linkTrio = linkHex ? resolveLinkTrio(linkHex, contrastProfile) : null;
3596
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)};`] : [
3597
3596
  ` --link: var(--${CSS_BRAND}-${stopTokenName(9)});`,
@@ -3779,17 +3778,17 @@ function themeToFigma(r, input) {
3779
3778
  const build = (mode) => {
3780
3779
  const p02 = mode === "light" ? nScale.paper0 : nScale.paper0Dark;
3781
3780
  const ramp = rampGroup(nScale[mode], mode === "light" ? nScale.onFillTextIsWhite : nScale.onFillTextIsWhiteDark, neutralExtra(mode));
3782
- const i02 = mode === "light" ? nScale.ink0 : nScale.ink0Dark;
3783
- const spliceInk0 = (g3) => {
3781
+ const i02 = mode === "light" ? nScale.pen100 : nScale.pen100Dark;
3782
+ const splicePen100 = (g3) => {
3784
3783
  if (!i02) return g3;
3785
3784
  const out = {};
3786
3785
  for (const [k, v2] of Object.entries(g3)) {
3787
3786
  out[k] = v2;
3788
- if (k === stopTokenName(11)) out[INK_0] = colorFromStop(i02);
3787
+ if (k === stopTokenName(11)) out[PEN_100] = colorFromStop(i02);
3789
3788
  }
3790
3789
  return out;
3791
3790
  };
3792
- const neutralGroup = spliceInk0(p02 ? { [PAPER_100]: colorFromStop(p02), ...ramp } : ramp);
3791
+ const neutralGroup = splicePen100(p02 ? { [PAPER_0]: colorFromStop(p02), ...ramp } : ramp);
3793
3792
  const secondaryGroup = rampGroup(secondary[mode], mode === "light" ? secondaryOnFillLight : secondaryOnFillDark, brandExtra(secondary, mode, CSS_FAMILY.brandSecondary));
3794
3793
  if (input.secondaryStyle === "outline" && input.secondary) {
3795
3794
  const s8 = secondary[mode].find((s) => s.stop === 8);
@@ -3827,12 +3826,12 @@ function themeToFigma(r, input) {
3827
3826
  putLeaf(g3, STAMP_ON, colorFromHex(esc.onFillIsWhite));
3828
3827
  }
3829
3828
  }
3830
- const scaleInkAt = (n) => {
3829
+ const scaleTextAt = (n) => {
3831
3830
  const s = scale[mode].find((x2) => x2.stop === n);
3832
- if (!s) throw new Error(`themeToFigma link: the brand scale has no ink stop ${n}`);
3831
+ if (!s) throw new Error(`themeToFigma link: the brand scale has no pen stop ${n}`);
3833
3832
  return s;
3834
3833
  };
3835
- 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(scaleInkAt(9)), "link-hover": colorFromStop(scaleInkAt(10)), "link-pressed": colorFromStop(scaleInkAt(11)) };
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)) };
3836
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) };
3837
3836
  const g2 = {
3838
3837
  brand: brandGroup,
@@ -3948,11 +3947,11 @@ export {
3948
3947
  DEFAULT_LINK_HEX,
3949
3948
  DISABLED_OPACITY,
3950
3949
  EXT_KEY,
3951
- INK_0,
3952
3950
  MODE_SPECS,
3953
3951
  OFFSET_ALPHAS,
3954
3952
  OUTLINE_HOVER_ALPHA,
3955
- PAPER_100,
3953
+ PAPER_0,
3954
+ PEN_100,
3956
3955
  RESOLVER_ID,
3957
3956
  SCALE_STOP_COUNT,
3958
3957
  SCRIM_ALPHA,