@taprootio/espalier 4.17.0 → 4.19.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/CHANGELOG.md +23 -0
- package/custom-elements.json +2542 -2400
- package/dist/cli/theme-check.js +2 -2
- package/dist/date-picker/helpers/styles.js +17 -7
- package/dist/footer/esp-footer.d.ts +1 -0
- package/dist/footer/esp-footer.js +8 -5
- package/dist/header/esp-header-button.d.ts +37 -0
- package/dist/header/esp-header-button.js +9 -4
- package/dist/header/esp-header.d.ts +1 -0
- package/dist/header/esp-header.js +7 -4
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/shared/configured-brand.d.ts +46 -0
- package/dist/shared/configured-brand.js +8 -4
- package/dist/shared/theme-fit-report.d.ts +38 -2
- package/dist/shared/theme-fit-report.js +1 -1
- package/dist/shared/theme.d.ts +50 -0
- package/dist/shared/theme.js +1 -1
- package/espalier.css-data.json +8 -0
- package/espalier.token-manifest.json +12 -0
- package/package.json +1 -1
|
@@ -114,6 +114,19 @@ export interface ThemeFitToken {
|
|
|
114
114
|
* since a zone's unexpected value then traces to a root theme line.
|
|
115
115
|
*/
|
|
116
116
|
explicit?: "declared" | "inherited";
|
|
117
|
+
/**
|
|
118
|
+
* Present on a role-paired ink the role layer compiled (ESP0223).
|
|
119
|
+
* `"declared"` means the theme named the slot — a separate claim about
|
|
120
|
+
* this token's family. `"derived"` means it paired off another role,
|
|
121
|
+
* which for `action.ink` is the canvas: the token IS the page ground
|
|
122
|
+
* by contract, and its distance from the anchor it reports describes
|
|
123
|
+
* that contract rather than a theme that missed its brand.
|
|
124
|
+
*
|
|
125
|
+
* Absent when no such role is declared, and absent on a token an
|
|
126
|
+
* explicit mapping pinned — there the pin, not the role, chose the
|
|
127
|
+
* value, and {@link explicit} is the mark that says so.
|
|
128
|
+
*/
|
|
129
|
+
pairing?: "declared" | "derived";
|
|
117
130
|
}
|
|
118
131
|
/**
|
|
119
132
|
* A theme's fit report — the stable JSON shape the docs site renders.
|
|
@@ -184,7 +197,7 @@ export declare function printThemeFitReport(report: ThemeFitReport): void;
|
|
|
184
197
|
/** One cross-token finding over a single surface's emitted values. */
|
|
185
198
|
export interface ThemeFitLint {
|
|
186
199
|
/** Stable lint identifier. */
|
|
187
|
-
id: "action-canvas-separation" | "link-hover-ordering";
|
|
200
|
+
id: "action-anchor-inversion" | "action-canvas-separation" | "apca-target-unmet" | "link-hover-ordering";
|
|
188
201
|
/** Lints describe design-quality hazards, not validation failures. */
|
|
189
202
|
severity: "warning";
|
|
190
203
|
/** The tokens the finding is about, recommended retune target first. */
|
|
@@ -212,7 +225,7 @@ export interface ThemeFitDataPaletteLint {
|
|
|
212
225
|
message: string;
|
|
213
226
|
}
|
|
214
227
|
/** Runtime validation/comparison vocabulary used by the exported field descriptors. */
|
|
215
|
-
export type ThemeFitFieldKind = "anchor" | "anchor-record" | "apca" | "boolean" | "data-palette-record" | "explicit" | "fit-lint-id" | "lint-array" | "message" | "number" | "palette-lint-id" | "palette-lint-record" | "report-array" | "scheme" | "semantic" | "semantic-array" | "series-pair" | "simulation" | "string" | "string-array" | "token-array" | "warning";
|
|
228
|
+
export type ThemeFitFieldKind = "anchor" | "anchor-record" | "apca" | "boolean" | "data-palette-record" | "explicit" | "fit-lint-id" | "lint-array" | "message" | "number" | "pairing" | "palette-lint-id" | "palette-lint-record" | "report-array" | "scheme" | "semantic" | "semantic-array" | "series-pair" | "simulation" | "string" | "string-array" | "token-array" | "warning";
|
|
216
229
|
/** One runtime field descriptor used by fit-suite validation and comparison. */
|
|
217
230
|
export interface ThemeFitFieldDescriptor<Field extends PropertyKey = PropertyKey> {
|
|
218
231
|
readonly field: Field;
|
|
@@ -226,6 +239,8 @@ export declare const THEME_FIT_LINT_IDS: readonly ThemeFitLint["id"][];
|
|
|
226
239
|
export declare const THEME_FIT_DATA_PALETTE_LINT_IDS: readonly ThemeFitDataPaletteLint["id"][];
|
|
227
240
|
/** Every stable explicit-pin provenance value. */
|
|
228
241
|
export declare const THEME_FIT_EXPLICIT_VALUES: readonly NonNullable<ThemeFitToken["explicit"]>[];
|
|
242
|
+
/** Every stable role-paired-ink provenance value. */
|
|
243
|
+
export declare const THEME_FIT_PAIRING_VALUES: readonly NonNullable<ThemeFitToken["pairing"]>[];
|
|
229
244
|
type ThemeFitLintSeverity = ThemeFitLint["severity"] | ThemeFitDataPaletteLint["severity"];
|
|
230
245
|
/** Every stable fit-suite lint severity. */
|
|
231
246
|
export declare const THEME_FIT_LINT_SEVERITIES: readonly ThemeFitLintSeverity[];
|
|
@@ -256,6 +271,27 @@ export declare const THEME_FIT_DATA_PALETTE_LINT_FIELDS: readonly ThemeFitFieldD
|
|
|
256
271
|
* wash itself signals the state and the ink must clear the text tier
|
|
257
272
|
* there; when the wash equals the background (no visible wash), hover
|
|
258
273
|
* must not read weaker than rest — a dimming hover feels disabled.
|
|
274
|
+
* - **action-anchor-inversion** (ESP0223) — the filled action rendered
|
|
275
|
+
* the *opposite way round* from the swatches it names: a surface whose
|
|
276
|
+
* swatch wants dark ink took light ink instead, or a declared pair's
|
|
277
|
+
* rendered lightness order reversed. Anchor drift on its own is by
|
|
278
|
+
* design — a stop supplies lightness (ADR-015) — and a raw distance
|
|
279
|
+
* cannot tell "a deeper rose" from "the gold became brown": a coral
|
|
280
|
+
* action drifts ΔE 0.29 and reads correctly, while a gold one drifts
|
|
281
|
+
* 0.34 and reads as a different design. The sign does tell them
|
|
282
|
+
* apart, and needs no threshold. This is also the one anchor drift an
|
|
283
|
+
* author cannot chase down: the action's stop is chosen by the engine,
|
|
284
|
+
* so seating the ramp — the remedy the lightness-ramps guide gives for
|
|
285
|
+
* every other token — cannot move it, and the fix is a pin.
|
|
286
|
+
* - **apca-target-unmet** (ESP0223) — enforcement moved a text token as
|
|
287
|
+
* far as its ramp allows and the pair still misses the legibility
|
|
288
|
+
* floor. The per-token `apca` block has always carried the numbers;
|
|
289
|
+
* nothing read them, so a theme could pin a surface no ink can carry
|
|
290
|
+
* and check clean.
|
|
291
|
+
*
|
|
292
|
+
* The two ESP0223 lints read `anchor`, `pairing` and `apca` rather than
|
|
293
|
+
* only `resolved`, because both findings are about how a token got where
|
|
294
|
+
* it is, which a colour alone cannot say.
|
|
259
295
|
*/
|
|
260
296
|
export declare function themeFitLints(report: ThemeFitReport): ThemeFitLint[];
|
|
261
297
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{apcaContrast as g,deltaEOK as _,parseOklch as v,serializeOklch as I}from"./color-engine.js";import{DATA_SERIES_KEYS as A,auditDataPalette as j,describePaletteCollision as C}from"./data-colors.js";import{DEFAULT_DARK_THEME as D,DEFAULT_LIGHT_THEME as $,explicitMappingTokens as w,mergeTheme as F,parseAnchorSource as P,resolveContextTheme as N}from"./theme.js";import{computeThemeProperties as y}from"../root/helpers/compute-theme-properties.js";function te(e,t,r={}){return L(e,t,r).report}function L(e,t,r={}){let o=e,s=null;if(r.context!==void 0){const n=N(e,r.context);if(!n)throw new Error(`themeFitReport: context "${r.context}" is not defined by the theme.`);o=n,s=new Set(Object.keys(e.contexts[r.context]?.semanticMappings??{}))}const c=[],m=y(o,t,c),k=w(o),l=c.map(n=>{const a=Y(n);return k.has(a.token)&&(a.explicit=s===null||s.has(a.token)?"declared":"inherited"),a});return{properties:m,report:{scheme:t,seedColor:o.seedColor,anchors:G(o.anchors),tokens:l,adjustedTokens:l.filter(n=>n.adjusted).map(n=>n.token)}}}function B(e){return e.tokens.map(t=>({token:t.token,source:t.source,requested:t.requested,resolved:t.resolved,apca:X(t),anchor:W(t)}))}function re(e){const t=e.adjustedTokens.length>0?`APCA moved ${e.adjustedTokens.join(", ")}`:"APCA moved nothing";console.info(`Espalier theme fit \u2014 ${e.scheme} scheme, seed ${e.seedColor}. ${t}.`),console.table(B(e))}function E(e){const t=Object.entries(e).map(([r,o])=>Object.freeze({field:r,kind:o.kind,compared:o.compared}));return Object.freeze(t)}const V={"action-canvas-separation":!0,"link-hover-ordering":!0},oe=Object.freeze(Object.keys(V)),q={"data-palette-cvd-collision":!0},ne=Object.freeze(Object.keys(q)),z={declared:!0,inherited:!0},se=Object.freeze(Object.keys(z)),U={warning:!0},ae=Object.freeze(Object.keys(U)),ce=E({token:{kind:"semantic",compared:!0},property:{kind:"string",compared:!0},source:{kind:"string",compared:!0},lightness:{kind:"string",compared:!0},requested:{kind:"string",compared:!0},resolved:{kind:"string",compared:!0},adjusted:{kind:"boolean",compared:!0},sourceResolved:{kind:"boolean",compared:!0},anchor:{kind:"anchor",compared:!0},apca:{kind:"apca",compared:!0},explicit:{kind:"explicit",compared:!0}}),ie=E({reference:{kind:"string",compared:!0},color:{kind:"string",compared:!0},deltaE:{kind:"number",compared:!0}}),de=E({from:{kind:"string",compared:!0},to:{kind:"string",compared:!0},targetLc:{kind:"number",compared:!0},against:{kind:"semantic",compared:!0},againstColor:{kind:"string",compared:!0},fromLc:{kind:"number",compared:!0},toLc:{kind:"number",compared:!0}}),ue=E({id:{kind:"fit-lint-id",compared:!0},severity:{kind:"warning",compared:!0},tokens:{kind:"semantic-array",compared:!0},measured:{kind:"number",compared:!0},message:{kind:"message",compared:!0}}),le=E({id:{kind:"palette-lint-id",compared:!0},severity:{kind:"warning",compared:!0},series:{kind:"series-pair",compared:!0},simulation:{kind:"simulation",compared:!0},measured:{kind:"number",compared:!0},threshold:{kind:"number",compared:!0},message:{kind:"message",compared:!0}}),x=.045,O=.5,b=75,K=.045;function S(e){const t=[],r=new Map(e.tokens.map(n=>[n.token,n.resolved])),o=n=>{const a=r.get(n);return a===void 0?null:v(a)},s=o("background"),c=o("actionBackground");if(s&&c){const n=_(c,s);if(n<x){const a=u(n,4);t.push({id:"action-canvas-separation",severity:"warning",tokens:["actionBackground","background"],measured:a,message:`actionBackground sits \u0394E ${a} from background (floor ${x}) \u2014 filled actions vanish into this canvas. Retune the surface apart: move the background stop, or pin actionBackground to a separated stop.`})}}const m=o("link"),k=o("linkHover"),l=o("linkHoverBg");if(s&&m&&k&&l){const n=Math.abs(g(m,s)),a=Math.abs(g(k,l));_(l,s)>=K?a+O<b&&t.push({id:"link-hover-ordering",severity:"warning",tokens:["linkHoverBg","linkHover"],measured:u(b-a,1),message:`linkHover reaches only Lc ${u(a,1)} on the linkHoverBg wash it actually paints (tier ${b}) \u2014 retune linkHoverBg before changing linkHover; the wash has one consumer while the ink has many.`}):a+O<n&&t.push({id:"link-hover-ordering",severity:"warning",tokens:["linkHover","link"],measured:u(n-a,1),message:`linkHover reads weaker than link on the same canvas (Lc ${u(a,1)} vs ${u(n,1)}) \u2014 a dimming hover feels disabled. Retune linkHover toward more contrast than the resting link.`})}return t}const R=":root",pe=E({scheme:{kind:"scheme",compared:!0},seedColor:{kind:"string",compared:!0},anchors:{kind:"anchor-record",compared:!0},tokens:{kind:"token-array",compared:!0},adjustedTokens:{kind:"semantic-array",compared:!0},surface:{kind:"string",compared:!0},lints:{kind:"lint-array",compared:!0}}),me=E({surfaces:{kind:"string-array",compared:!0},dataPalette:{kind:"data-palette-record",compared:!0},paletteLints:{kind:"palette-lint-record",compared:!0},light:{kind:"report-array",compared:!0},dark:{kind:"report-array",compared:!0}});function ke(e,t){const r=F($,e),o=F(D,t),s=[R,...[...new Set([...Object.keys(r.contexts),...Object.keys(o.contexts)])].sort()],c=p=>{const i={};for(let d=0;d<A.length;d+=1){const f=A[d],h=`--esp-color-series-${d+1}`,T=p[h];if(T===void 0)throw new Error(`Theme fit report did not emit required property ${h}.`);i[f]=T}return i},m=p=>j(p).map(i=>{const d=u(i.distance,4);return{id:"data-palette-cvd-collision",severity:"warning",series:i.series,simulation:i.simulation,measured:d,threshold:i.threshold,message:C(i)}}),k=(p,i)=>{const d=L(p,i);if(Object.keys(d.properties).length===0)throw new Error(`themeFitReportSuite: ${i} root emitted no properties for seed "${p.seedColor}".`);const f=[{...d.report,surface:R,lints:S(d.report)}];for(const h of s){if(h===R||!(h in p.contexts))continue;const H=L(p,i,{context:h}).report;f.push({...H,surface:h,lints:S(H)})}return{dataPalette:c(d.properties),reports:f}},l=k(r,"light"),n=k(o,"dark"),a={light:l.dataPalette,dark:n.dataPalette};return{surfaces:s,dataPalette:a,paletteLints:{light:m(a.light),dark:m(a.dark)},light:l.reports,dark:n.reports}}function u(e,t){const r=Math.pow(10,t);return Math.round(e*r)/r}function M(e,t){return t===void 0?e:`${e}.${t}`}function G(e){const t={};for(const[r,o]of Object.entries(e)){if(typeof o=="string"){t[r]=o;continue}for(const[s,c]of Object.entries(o))t[s==="color"?r:M(r,s)]=c}return t}function Y(e){const t=v(e.resolved),r=e.requested===void 0?e.resolved:I(e.requested),o={token:e.token,property:e.property,source:e.source,lightness:e.lightness,requested:r,resolved:e.resolved,adjusted:r!==e.resolved,sourceResolved:e.sourceResolved},s=P(e.source);if(s&&e.sourceResolved&&(o.anchor={reference:M(s.name,s.slot),color:I(e.base),deltaE:u(_(e.base,t),4)}),e.contrast){const c=e.contrast.background;o.apca={from:r,to:e.resolved,targetLc:e.contrast.targetLc,against:e.contrast.against,againstColor:I(c),fromLc:u(Math.abs(g(v(r),c)),1),toLc:u(Math.abs(g(t,c)),1)}}return o}function X(e){if(!e.apca)return"";const{targetLc:t,against:r,fromLc:o,toLc:s}=e.apca;return e.adjusted?`Lc ${t} vs ${r} \u2014 pushed from Lc ${o} to Lc ${s}`:`Lc ${t} vs ${r} \u2014 met at Lc ${o}`}function W(e){return e.anchor?`${e.anchor.reference} \u0394E ${e.anchor.deltaE}`:e.sourceResolved?"":"unresolved \u2014 seed used"}export{R as ROOT_SURFACE,ie as THEME_FIT_ANCHOR_FIELDS,de as THEME_FIT_APCA_FIELDS,le as THEME_FIT_DATA_PALETTE_LINT_FIELDS,ne as THEME_FIT_DATA_PALETTE_LINT_IDS,se as THEME_FIT_EXPLICIT_VALUES,ue as THEME_FIT_LINT_FIELDS,oe as THEME_FIT_LINT_IDS,ae as THEME_FIT_LINT_SEVERITIES,pe as THEME_FIT_REPORT_FIELDS,me as THEME_FIT_SUITE_FIELDS,ce as THEME_FIT_TOKEN_FIELDS,re as printThemeFitReport,S as themeFitLints,te as themeFitReport,ke as themeFitReportSuite,B as themeFitRows};
|
|
1
|
+
import{apcaContrast as T,deltaEOK as x,parseOklch as _,serializeOklch as $}from"./color-engine.js";import{DATA_SERIES_KEYS as C,auditDataPalette as q,describePaletteCollision as K}from"./data-colors.js";import{DEFAULT_DARK_THEME as G,DEFAULT_LIGHT_THEME as Y,explicitMappingTokens as W,mergeTheme as j,parseAnchorSource as X,resolveContextTheme as J,roleInkProvenance as Q}from"./theme.js";import{computeThemeProperties as Z}from"../root/helpers/compute-theme-properties.js";function ke(e,t,o={}){return H(e,t,o).report}function H(e,t,o={}){let n=e,c=null;if(o.context!==void 0){const s=J(e,o.context);if(!s)throw new Error(`themeFitReport: context "${o.context}" is not defined by the theme.`);n=s,c=new Set(Object.keys(e.contexts[o.context]?.semanticMappings??{}))}const p=[],v=Z(n,t,p),L=W(n),f=Q(n.roles),E=p.map(s=>{const a=ie(s);if(L.has(a.token))a.explicit=c===null||c.has(a.token)?"declared":"inherited";else{const i=f[a.token];i!==void 0&&(a.pairing=i)}return a});return{properties:v,report:{scheme:t,seedColor:n.seedColor,anchors:ce(n.anchors),tokens:E,adjustedTokens:E.filter(s=>s.adjusted).map(s=>s.token)}}}function ee(e){return e.tokens.map(t=>({token:t.token,source:t.source,requested:t.requested,resolved:t.resolved,apca:de(t),anchor:le(t)}))}function ge(e){const t=e.adjustedTokens.length>0?`APCA moved ${e.adjustedTokens.join(", ")}`:"APCA moved nothing";console.info(`Espalier theme fit \u2014 ${e.scheme} scheme, seed ${e.seedColor}. ${t}.`),console.table(ee(e))}function I(e){const t=Object.entries(e).map(([o,n])=>Object.freeze({field:o,kind:n.kind,compared:n.compared}));return Object.freeze(t)}const te={"action-anchor-inversion":!0,"action-canvas-separation":!0,"apca-target-unmet":!0,"link-hover-ordering":!0},fe=Object.freeze(Object.keys(te)),re={"data-palette-cvd-collision":!0},Ee=Object.freeze(Object.keys(re)),ne={declared:!0,inherited:!0},Te=Object.freeze(Object.keys(ne)),oe={declared:!0,derived:!0},_e=Object.freeze(Object.keys(oe)),ae={warning:!0},ve=Object.freeze(Object.keys(ae)),Le=I({token:{kind:"semantic",compared:!0},property:{kind:"string",compared:!0},source:{kind:"string",compared:!0},lightness:{kind:"string",compared:!0},requested:{kind:"string",compared:!0},resolved:{kind:"string",compared:!0},adjusted:{kind:"boolean",compared:!0},sourceResolved:{kind:"boolean",compared:!0},anchor:{kind:"anchor",compared:!0},apca:{kind:"apca",compared:!0},explicit:{kind:"explicit",compared:!0},pairing:{kind:"pairing",compared:!0}}),Ie=I({reference:{kind:"string",compared:!0},color:{kind:"string",compared:!0},deltaE:{kind:"number",compared:!0}}),be=I({from:{kind:"string",compared:!0},to:{kind:"string",compared:!0},targetLc:{kind:"number",compared:!0},against:{kind:"semantic",compared:!0},againstColor:{kind:"string",compared:!0},fromLc:{kind:"number",compared:!0},toLc:{kind:"number",compared:!0}}),Re=I({id:{kind:"fit-lint-id",compared:!0},severity:{kind:"warning",compared:!0},tokens:{kind:"semantic-array",compared:!0},measured:{kind:"number",compared:!0},message:{kind:"message",compared:!0}}),Me=I({id:{kind:"palette-lint-id",compared:!0},severity:{kind:"warning",compared:!0},series:{kind:"series-pair",compared:!0},simulation:{kind:"simulation",compared:!0},measured:{kind:"number",compared:!0},threshold:{kind:"number",compared:!0},message:{kind:"message",compared:!0}}),D=.045,N=.045,M=75,y={l:0,c:0,h:0},P={l:1,c:0,h:0},B=.5,F=75,se=.045;function V(e){const t=[],o=new Map(e.tokens.map(r=>[r.token,r.resolved])),n=r=>{const d=o.get(r);return d===void 0?null:_(d)},c=n("background"),p=n("actionBackground");if(c&&p){const r=x(p,c);if(r<D){const d=u(r,4);t.push({id:"action-canvas-separation",severity:"warning",tokens:["actionBackground","background"],measured:d,message:`actionBackground sits \u0394E ${d} from background (floor ${D}) \u2014 filled actions vanish into this canvas. Retune the surface apart: move the background stop, or pin actionBackground to a separated stop.`})}}const v=n("link"),L=n("linkHover"),f=n("linkHoverBg");if(c&&v&&L&&f){const r=Math.abs(T(v,c)),d=Math.abs(T(L,f));x(f,c)>=se?d+B<F&&t.push({id:"link-hover-ordering",severity:"warning",tokens:["linkHoverBg","linkHover"],measured:u(F-d,1),message:`linkHover reaches only Lc ${u(d,1)} on the linkHoverBg wash it actually paints (tier ${F}) \u2014 retune linkHoverBg before changing linkHover; the wash has one consumer while the ink has many.`}):d+B<r&&t.push({id:"link-hover-ordering",severity:"warning",tokens:["linkHover","link"],measured:u(r-d,1),message:`linkHover reads weaker than link on the same canvas (Lc ${u(d,1)} vs ${u(r,1)}) \u2014 a dimming hover feels disabled. Retune linkHover toward more contrast than the resting link.`})}const E=r=>Math.abs(T(y,r))>=Math.abs(T(P,r))?"dark":"light",s=e.tokens.find(r=>r.token==="actionBackground"),a=e.tokens.find(r=>r.token==="actionText"),i=[],l=[];let m=0;const h=a?.anchor?_(a.anchor.color):null,g=a?_(a.resolved):null,k=s?.anchor?_(s.anchor.color):null,b=s?_(s.resolved):null,O=g&&b?g.l>b.l?"light":"dark":null;s?.anchor&&k&&b&&O&&s.anchor.deltaE>=N&&E(k)!==O&&(i.push("actionBackground"),m=Math.max(m,s.anchor.deltaE),l.push(`"${s.anchor.reference}" wants ${E(k)} ink but actionBackground renders carrying a ${O} label (\u0394E ${u(s.anchor.deltaE,4)})`)),a?.anchor&&a.pairing!=="derived"&&h&&g&&k&&b&&a.anchor.deltaE>=N&&k.l!==h.l&&Math.sign(k.l-h.l)!==Math.sign(b.l-g.l)&&(i.push("actionText"),m=Math.max(m,a.anchor.deltaE),l.push(`the declared pair puts "${s.anchor.reference}" ${k.l>h.l?"above":"below"} "${a.anchor.reference}" in lightness and the rendered pair puts it ${b.l>g.l?"above":"below"} (\u0394E ${u(a.anchor.deltaE,4)})`)),i.length>0&&t.push({id:"action-anchor-inversion",severity:"warning",tokens:i,measured:u(m,4),message:`The filled action renders the opposite way round from the swatches it names: ${l.join("; ")}. `+(s?.explicit===void 0?"A filled action's ramp stop is chosen by the engine near its mid-band target, so seating the ramp cannot move it the way it moves every other anchored token. Retune by pinning semanticMappings.actionBackground to a stop that carries the swatch":"semanticMappings.actionBackground is already pinned, so the engine did not place this \u2014 retune the stop that pin names")+" \u2014 and check the pair still clears its tier there, because a swatch this far off the band often cannot hold a label at its own lightness."});const A=e.tokens.filter(r=>r.apca!==void 0&&r.apca.toLc<Math.min(r.apca.targetLc,M)).sort((r,d)=>Math.min(d.apca.targetLc,M)-d.apca.toLc-(Math.min(r.apca.targetLc,M)-r.apca.toLc)||(r.token<d.token?-1:r.token>d.token?1:0));if(A.length>0){const r=A[0].apca,d=A.map(R=>`${R.token} reaches Lc ${u(R.apca.toLc,1)} on ${R.apca.against} (floor ${Math.min(R.apca.targetLc,M)})`),w=_(r.againstColor),U=w!==null&&Math.max(Math.abs(T(y,w)),Math.abs(T(P,w)))>=Math.min(r.targetLc,M);t.push({id:"apca-target-unmet",severity:"warning",tokens:A.map(R=>R.token),measured:u(Math.min(r.targetLc,M)-r.toLc,1),message:`${d.join(", ")} \u2014 enforcement moved the ink as far as this ramp allows and the pair still falls short. `+(U?"The opposite ink pole does clear the floor on that ground, so the emitted ink is on the weaker side rather than the ground being impossible \u2014 check the pairing before retuning the ground.":"No ink reaches the floor on that ground, so retune the ground each pair reads against toward a lightness that can carry it.")})}return t}const S=":root",Ae=I({scheme:{kind:"scheme",compared:!0},seedColor:{kind:"string",compared:!0},anchors:{kind:"anchor-record",compared:!0},tokens:{kind:"token-array",compared:!0},adjustedTokens:{kind:"semantic-array",compared:!0},surface:{kind:"string",compared:!0},lints:{kind:"lint-array",compared:!0}}),we=I({surfaces:{kind:"string-array",compared:!0},dataPalette:{kind:"data-palette-record",compared:!0},paletteLints:{kind:"palette-lint-record",compared:!0},light:{kind:"report-array",compared:!0},dark:{kind:"report-array",compared:!0}});function Oe(e,t){const o=j(Y,e),n=j(G,t),c=[S,...[...new Set([...Object.keys(o.contexts),...Object.keys(n.contexts)])].sort()],p=a=>{const i={};for(let l=0;l<C.length;l+=1){const m=C[l],h=`--esp-color-series-${l+1}`,g=a[h];if(g===void 0)throw new Error(`Theme fit report did not emit required property ${h}.`);i[m]=g}return i},v=a=>q(a).map(i=>{const l=u(i.distance,4);return{id:"data-palette-cvd-collision",severity:"warning",series:i.series,simulation:i.simulation,measured:l,threshold:i.threshold,message:K(i)}}),L=(a,i)=>{const l=H(a,i);if(Object.keys(l.properties).length===0)throw new Error(`themeFitReportSuite: ${i} root emitted no properties for seed "${a.seedColor}".`);const m=[{...l.report,surface:S,lints:V(l.report)}];for(const h of c){if(h===S||!(h in a.contexts))continue;const k=H(a,i,{context:h}).report;m.push({...k,surface:h,lints:V(k)})}return{dataPalette:p(l.properties),reports:m}},f=L(o,"light"),E=L(n,"dark"),s={light:f.dataPalette,dark:E.dataPalette};return{surfaces:c,dataPalette:s,paletteLints:{light:v(s.light),dark:v(s.dark)},light:f.reports,dark:E.reports}}function u(e,t){const o=Math.pow(10,t);return Math.round(e*o)/o}function z(e,t){return t===void 0?e:`${e}.${t}`}function ce(e){const t={};for(const[o,n]of Object.entries(e)){if(typeof n=="string"){t[o]=n;continue}for(const[c,p]of Object.entries(n))t[c==="color"?o:z(o,c)]=p}return t}function ie(e){const t=_(e.resolved),o=e.requested===void 0?e.resolved:$(e.requested),n={token:e.token,property:e.property,source:e.source,lightness:e.lightness,requested:o,resolved:e.resolved,adjusted:o!==e.resolved,sourceResolved:e.sourceResolved},c=X(e.source);if(c&&e.sourceResolved&&(n.anchor={reference:z(c.name,c.slot),color:$(e.base),deltaE:u(x(e.base,t),4)}),e.contrast){const p=e.contrast.background;n.apca={from:o,to:e.resolved,targetLc:e.contrast.targetLc,against:e.contrast.against,againstColor:$(p),fromLc:u(Math.abs(T(_(o),p)),1),toLc:u(Math.abs(T(t,p)),1)}}return n}function de(e){if(!e.apca)return"";const{targetLc:t,against:o,fromLc:n,toLc:c}=e.apca;return e.adjusted?`Lc ${t} vs ${o} \u2014 pushed from Lc ${n} to Lc ${c}`:`Lc ${t} vs ${o} \u2014 met at Lc ${n}`}function le(e){return e.anchor?`${e.anchor.reference} \u0394E ${e.anchor.deltaE}`:e.sourceResolved?"":"unresolved \u2014 seed used"}export{S as ROOT_SURFACE,Ie as THEME_FIT_ANCHOR_FIELDS,be as THEME_FIT_APCA_FIELDS,Me as THEME_FIT_DATA_PALETTE_LINT_FIELDS,Ee as THEME_FIT_DATA_PALETTE_LINT_IDS,Te as THEME_FIT_EXPLICIT_VALUES,Re as THEME_FIT_LINT_FIELDS,fe as THEME_FIT_LINT_IDS,ve as THEME_FIT_LINT_SEVERITIES,_e as THEME_FIT_PAIRING_VALUES,Ae as THEME_FIT_REPORT_FIELDS,we as THEME_FIT_SUITE_FIELDS,Le as THEME_FIT_TOKEN_FIELDS,ge as printThemeFitReport,V as themeFitLints,ke as themeFitReport,Oe as themeFitReportSuite,ee as themeFitRows};
|
package/dist/shared/theme.d.ts
CHANGED
|
@@ -269,6 +269,32 @@ export declare const ROLE_NAMES: readonly RoleName[];
|
|
|
269
269
|
* following `accent.text` exactly as before.
|
|
270
270
|
*/
|
|
271
271
|
export declare const ROLE_TOKEN_PLAN: Readonly<Record<RoleName, Readonly<Record<string, ReadonlyArray<[SemanticColorName, LightnessKey]>>>>>;
|
|
272
|
+
/**
|
|
273
|
+
* Role slots whose ink lightness is derived from the surface that role
|
|
274
|
+
* actually painted, rather than taken from {@link ROLE_TOKEN_PLAN}.
|
|
275
|
+
*
|
|
276
|
+
* {@link resolvePairedInkStop} used to run only for a slot the theme
|
|
277
|
+
* left *undeclared*, so naming `action.ink` took the plan's `surface`
|
|
278
|
+
* stop verbatim. In a light ramp both rules answer `surface` and the
|
|
279
|
+
* difference never showed. In a dark ramp the plan's stop is the
|
|
280
|
+
* near-black page ground, which is the wrong side of a mid-dark action
|
|
281
|
+
* surface: enforcement had to walk the label the whole way across the
|
|
282
|
+
* ramp and stopped at the first value that cleared the target, emitting
|
|
283
|
+
* a weaker ink than the ramp could give. ADR-016 is explicit that the
|
|
284
|
+
* model's job is to hand enforcement the strongest available starting
|
|
285
|
+
* point on the correct side, so the derivation now runs for a declared
|
|
286
|
+
* slot too (ESP0223).
|
|
287
|
+
*
|
|
288
|
+
* The source still comes from the theme: naming `action.ink` chooses
|
|
289
|
+
* the family, exactly as ADR-015 says an anchor supplies hue and chroma
|
|
290
|
+
* while the ramp supplies lightness.
|
|
291
|
+
*
|
|
292
|
+
* Every entry here must also appear in {@link ROLE_PAIRED_INK}: the
|
|
293
|
+
* compile branch is gated on `paired` first, and
|
|
294
|
+
* {@link roleInkProvenance} walks the pairing table, so an entry in only
|
|
295
|
+
* this set would be silently inert in both.
|
|
296
|
+
*/
|
|
297
|
+
export declare const ROLE_DERIVED_INK: ReadonlySet<string>;
|
|
272
298
|
/**
|
|
273
299
|
* Ink slots that derive from another role when the theme does not
|
|
274
300
|
* declare them.
|
|
@@ -293,6 +319,8 @@ interface CompileRoleOptions {
|
|
|
293
319
|
actionSurfaceContrast?: (source: MappingSource, stop: LightnessKey) => number;
|
|
294
320
|
/** ΔE-OK between an action surface candidate and the theme's background. */
|
|
295
321
|
actionSurfaceSeparation?: (source: MappingSource, stop: LightnessKey) => number;
|
|
322
|
+
/** Which ink pole reads better on a finished action surface at a lightness. */
|
|
323
|
+
actionSurfacePole?: (source: MappingSource, lightness: number) => "dark" | "light";
|
|
296
324
|
}
|
|
297
325
|
/**
|
|
298
326
|
* Compile roles into semantic mappings.
|
|
@@ -304,6 +332,23 @@ interface CompileRoleOptions {
|
|
|
304
332
|
* reach.
|
|
305
333
|
*/
|
|
306
334
|
export declare function compileRoles(roles: ThemeRoles, lightness: LightnessMap, baseMappings: SemanticMappings, options?: CompileRoleOptions): Partial<SemanticMappings>;
|
|
335
|
+
/**
|
|
336
|
+
* Whether each role-paired ink token's *source* was named by the theme
|
|
337
|
+
* or paired off another role (ESP0223).
|
|
338
|
+
*
|
|
339
|
+
* The distinction matters to anything judging how far a token landed
|
|
340
|
+
* from the swatch it names. `action.ink` defaults to the canvas colour,
|
|
341
|
+
* so an undeclared ink IS the page ground by contract — it is re-lit to
|
|
342
|
+
* the opposite end of the ramp on purpose, and the large anchor ΔE that
|
|
343
|
+
* follows describes the contract working, not a theme missing its
|
|
344
|
+
* brand. A theme that names the slot has made a separate claim about
|
|
345
|
+
* the label's family, and the same ΔE then describes a claim that did
|
|
346
|
+
* not survive.
|
|
347
|
+
*
|
|
348
|
+
* A pure read of `roles`: the compile is not re-run, and a role the
|
|
349
|
+
* theme never declared reports nothing rather than guessing.
|
|
350
|
+
*/
|
|
351
|
+
export declare function roleInkProvenance(roles: ThemeRoles): Partial<Record<SemanticColorName, "declared" | "derived">>;
|
|
307
352
|
/** The complete, resolved Espalier theme. */
|
|
308
353
|
export interface EspalierTheme {
|
|
309
354
|
/**
|
|
@@ -665,6 +710,11 @@ export declare const DEFAULT_DARK_LIGHTNESS: Readonly<LightnessMap>;
|
|
|
665
710
|
*
|
|
666
711
|
* Each entry tells the color engine which variant supplies the
|
|
667
712
|
* hue and which lightness key sets the perceived brightness.
|
|
713
|
+
*
|
|
714
|
+
* `actionBackground` carries the **light** scheme's stop; the dark
|
|
715
|
+
* theme overrides it through {@link buildDefaultSemanticMappings}. See
|
|
716
|
+
* {@link DEFAULT_ACTION_BACKGROUND_STOP} for why that one mapping
|
|
717
|
+
* cannot share a name across schemes.
|
|
668
718
|
*/
|
|
669
719
|
export declare const DEFAULT_SEMANTIC_MAPPINGS: Readonly<SemanticMappings>;
|
|
670
720
|
/** Built-in authored stack for body and UI text. */
|
package/dist/shared/theme.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{UNSAFE_KEYS as dt,isSafeKey as M}from"./unsafe-keys.js";import{ACCEPTED_COLOR_FORMS as oe,apcaContrast as mt,clampChannel as ge,deltaEOK as gt,deriveSemantic as ae,gamutMapToSRGB as he,linearRgbToOklab as ht,oklchToSRGB as yt,parseCssColor as W,parseOklch as bt,serializeOklch as ce,srgbToLinearRGB as $t}from"./color-engine.js";import{computeVariants as ye,parseAnchorSource as xt,resolveAnchorColor as kt,resolveMappingSource as ue}from"./variant-engine.js";import{auditColorDistances as Fe,auditDataPalette as St,describePaletteCollision as At,DATA_SERIES_KEYS as fe,DEFAULT_DATA_PALETTE as be,DEFAULT_DATA_RAMP_STEPS as Mt,MAX_DATA_RAMP_STEPS as $e,MIN_DATA_RAMP_LIGHTNESS_STEP as We,MIN_DATA_RAMP_STEPS as xe}from"./data-colors.js";const j=/^[a-z][a-z0-9-]*$/;function ke(e){return xt(e)}function je(e,n){return kt(e,n)}function Ot(e,n){const t=ke(e);if(t){const o=je(n,t);return o&&W(o)?o:null}return W(e)?e:null}const se=["canvas","ink","accent","action","structure"],Se={canvas:{color:[["background","surface"],["layer1","raised1"],["layer2","raised2"],["layer3","raised3"],["layer4","raised4"]]},ink:{color:[["text","text"],["typeOverline","text"],["typeLabel","text"],["typeLead","text"],["typeCaption","text"],["inputSelection","text"]],heading:[["headings","muted"],["headingsHover","ink"]]},accent:{color:[["linkHoverBg","raised2"],["inputSelectionBg","raised2"],["inputCaret","ink"]],text:[["link","accent"]],hover:[["linkHover","text"]]},action:{color:[["actionBackground","muted"]],ink:[["actionText","surface"]]},structure:{color:[["border","border"],["shadow","shadow"]]}},Tt=new Set(["action.color"]),Ct={canvas:"background",ink:"text",accent:"link",action:"actionBackground",structure:"border"},Rt={"action.ink":{role:"canvas",slot:"color"}},vt=.45,Et=.045;function ze(e,n,t){const o=Ue.actionText,i=[...U].sort((y,T)=>e[y]-e[T]||U.indexOf(y)-U.indexOf(T)),a=n?i.filter(y=>n(y)>=o.targetLc):i,u=t?a.filter(y=>t(y)>=Et):a,d=u.length>0?u:a,m=d.length>0?d:i;let A,k=1/0;for(const y of m){const T=Math.abs(e[y]-vt);T<k&&(k=T,A=y)}return A??"muted"}function wt(e,n,t){const o=Oe(n,t,e)>.5;let i=U[0];for(const a of U)(o?n[a]<n[i]:n[a]>n[i])&&(i=a);return i}const Bt={"accent.hover":"text"};function _t(e,n){const t=new Map;try{const o=de(n,e),i=(a,u,d,m)=>{const A=ke(u),k=A?je(m,A):null,y=k===null?null:W(k),T=t.get(a)??[];T.some(_=>_.source===u&&_.chroma===y?.c)||(T.push({source:u,where:d,chroma:y?.c}),t.set(a,T))};for(const[a,u]of Object.entries(o.semanticMappings))u.source.startsWith("anchor:")&&i(a,u.source,"the root table",o.anchors);for(const a of Object.keys(o.contexts)){const u=it(o,a);if(u)for(const[d,m]of Object.entries(u.semanticMappings))m.source.startsWith("anchor:")&&i(d,m.source,`contexts.${a}`,u.anchors)}}catch{return new Map}return t}function X(e,n){if(e===void 0)return;if(typeof e=="string")return n==="color"?e:void 0;const t=e[n];return typeof t=="string"?t:void 0}function Ke(e,n,t,o={}){const i={},a={};for(const[u,d]of Object.entries(o.explicitMappings??{}))d!==void 0&&(a[u]=d.lightness);for(const u of se){const d=e[u];if(d!==void 0)for(const[m,A]of Object.entries(Se[u])){const k=Rt[`${u}.${m}`];let y=X(d,m),T=!1;if(y===void 0){k&&(y=X(e[k.role],k.slot),y??=t[Ct[k.role]]?.source,T=y!==void 0);const _=Bt[`${u}.${m}`];_!==void 0&&(y??=X(d,_)),y??=X(d,"color")}if(y!==void 0)for(const[_,z]of A){let H=z;if(Tt.has(`${u}.${m}`))H=ze(n,o.actionSurfaceContrast?s=>o.actionSurfaceContrast(y,s):void 0,o.actionSurfaceSeparation?s=>o.actionSurfaceSeparation(y,s):void 0);else if(T&&k){const s=Ue[_],r=(s&&a[s.bg])??ze(n,o.actionSurfaceContrast?c=>o.actionSurfaceContrast(X(d,"color"),c):void 0,o.actionSurfaceSeparation?c=>o.actionSurfaceSeparation(X(d,"color"),c):void 0);H=wt(r,n,o.tones??{})}i[_]={source:y,lightness:H}}}}return i}const Ue={text:{bg:"background",targetLc:75},typeOverline:{bg:"background",targetLc:90},typeLabel:{bg:"background",targetLc:75},typeLead:{bg:"background",targetLc:75},typeCaption:{bg:"background",targetLc:90},dangerText:{bg:"background",targetLc:75},headings:{bg:"background",targetLc:60},headingsHover:{bg:"background",targetLc:60},link:{bg:"background",targetLc:75},linkHover:{bg:"linkHoverBg",targetLc:75},actionText:{bg:"actionBackground",targetLc:75},inputCaret:{bg:"layer2",targetLc:60},inputSelection:{bg:"inputSelectionBg",targetLc:60}},K=["background","layer1","layer2","layer3","layer4","actionBackground","actionText","border","shadow","text","typeOverline","typeLabel","typeLead","typeCaption","dangerText","headings","headingsHover","link","linkHover","linkHoverBg","inputCaret","inputSelection","inputSelectionBg"];function cn(e){return typeof e=="string"&&K.includes(e)}const Lt=["typeOverline","typeLabel","typeLead","typeCaption"],Ae=["primary","analogous-left","analogous-right","complementary","split-complementary-left","split-complementary-right","triadic-left","triadic-right","danger","success","warning","info"],ee=["danger","success","warning","info"],It=["analogous-left","analogous-right","complementary","split-complementary-left","split-complementary-right","triadic-left","triadic-right","danger","success","warning","info"],U=["surface","raised1","raised2","raised3","raised4","accent","muted","text","border","ink","shadow"],Ge="tone:";function Me(e){if(typeof e!="string"||!e.startsWith(Ge))return null;const n=e.slice(Ge.length);return M(n)&&j.test(n)?n:null}function te(e){return typeof e!="string"?!1:U.includes(e)}function Oe(e,n,t){if(te(t))return e[t];const o=Me(t);return o===null?e.surface:n?.[o]??e.surface}const Nt={surface:.99,raised1:.97,raised2:.9,raised3:.8,raised4:.72,accent:.5,muted:.45,text:.35,border:.3,ink:.25,shadow:.2},Ht={surface:.15,raised1:.2,raised2:.3,raised3:.4,raised4:.36,accent:.6,muted:.75,text:.85,border:.7,ink:.95,shadow:.6},Te={background:{source:"primary",lightness:"surface"},layer1:{source:"primary",lightness:"raised1"},layer2:{source:"primary",lightness:"raised2"},layer3:{source:"primary",lightness:"raised3"},layer4:{source:"primary",lightness:"raised4"},actionBackground:{source:"primary",lightness:"raised3"},actionText:{source:"primary",lightness:"ink"},border:{source:"primary",lightness:"border"},shadow:{source:"primary",lightness:"shadow"},text:{source:"primary",lightness:"text"},typeOverline:{source:"primary",lightness:"text"},typeLabel:{source:"primary",lightness:"text"},typeLead:{source:"primary",lightness:"text"},typeCaption:{source:"primary",lightness:"text"},dangerText:{source:"danger",lightness:"text"},headings:{source:"primary",lightness:"muted"},headingsHover:{source:"primary",lightness:"text"},link:{source:"complementary",lightness:"accent"},linkHover:{source:"complementary",lightness:"text"},linkHoverBg:{source:"triadic-left",lightness:"raised2"},inputCaret:{source:"triadic-right",lightness:"ink"},inputSelection:{source:"complementary",lightness:"text"},inputSelectionBg:{source:"triadic-left",lightness:"raised2"}},Y=.4;function Ce(){const e={};for(const n of K)e[n]={min:0,max:Y};return e}const Ve="system-ui, sans-serif",Je="monospace",Ye={seedColor:"oklch(0.7 0.125 216)",fontBody:Ve,fontHeadings:"",fontBrand:"",fontMenu:"",fontMonospace:Je,fontWeightBody:"normal",fontWeightHeadings:"bold",fontWeightBrand:"bold",fontWeightMenu:"bold",fontWeightMonospace:"normal",stylesheets:[],rootFontSize:16,typeRatio:1.25,spaceRatio:1.618,borderRadius:.2,viewportMin:320,viewportMax:1200,angles:{analogous:30,complementary:180,splitComplementary:30,triadic:120},semanticHues:{danger:27,success:150,warning:90,info:244},variantChroma:{},intents:{},tones:{},chroma:Ce(),semanticMappings:{...Te},explicitMappingTokens:[],anchors:{},roles:{},contexts:{},dataPalette:{...be},dataRamps:{}},Re={...Ye,chroma:Ce(),semanticMappings:{...Te},anchors:{},roles:{},contexts:{},tones:{},dataPalette:{...be},dataRamps:{},lightness:{...Nt}},qe={...Ye,chroma:Ce(),semanticMappings:{...Te},anchors:{},roles:{},contexts:{},tones:{},dataPalette:{...be},dataRamps:{},lightness:{...Ht}},le=new WeakMap;le.set(Re,new Set),le.set(qe,new Set);function Pt(e,n){return dt.has(e)?void 0:n}function pe(e){const n=e.explicitMappingTokens;if(!Array.isArray(n)||n.some(o=>typeof o!="string"||!K.includes(o)))return;const t=new Set(n);if(t.size===n.length&&!(t.size>0&&(!L(e.semanticMappings)||[...t].some(o=>!Object.prototype.hasOwnProperty.call(e.semanticMappings,o)))))return t}function Xe(e){return K.filter(n=>e.has(n))}function un(e){return`--esp-color-${e.replace(/([A-Z])/g,"-$1").replace(/(\d)/g,"-$1").toLowerCase()}`}function Dt(e){try{const n=Ze(e),t=JSON.parse(n,Pt);return typeof t!="object"||t===null||Array.isArray(t)?null:t}catch{return null}}const ve="\xEF\xBB\xBF";function Ft(e){if(/^[\u0000-\u007f]*$/.test(e))return btoa(e);const n=new TextEncoder().encode(e);let t=ve;for(const o of n)t+=String.fromCharCode(o);return btoa(t)}function Ze(e){const n=atob(e);if(!n.startsWith(ve))return n;const t=Uint8Array.from(n.slice(ve.length),o=>o.charCodeAt(0));return new TextDecoder("utf-8",{fatal:!0}).decode(t)}function Ee(e){return Ft(JSON.stringify(e))}function Wt(e){const n={};for(const t of ee){const o=e[t];typeof o=="string"&&(n[t]=o.startsWith("anchor:")?o:re(o))}return n}function re(e){if(bt(e))return e;const n=W(e);return n?ce(n):e}function Qe(e,n){const t={};for(const[o,i]of Object.entries(e))M(o)&&(t[o]=i);if(!n)return t;for(const[o,i]of Object.entries(n)){if(i===void 0||!M(o))continue;const a=t[o];if(a!==void 0&&typeof i=="object"&&i!==null){const u={};if(typeof a=="string")u.color=a;else for(const[d,m]of Object.entries(a))M(d)&&(u[d]=m);for(const[d,m]of Object.entries(i))m!==void 0&&M(d)&&(u[d]=m);t[o]=u;continue}t[o]=i}return t}function we(e){const n={};if(!L(e))return n;for(const[t,o]of Object.entries(e))M(t)&&j.test(t)&&!te(t)&&typeof o=="number"&&Number.isFinite(o)&&o>=0&&o<=1&&(n[t]=o);return n}function jt(e,n){return{...we(e),...we(n)}}function zt(e,n){const t={...e};if(!L(n))return t;for(const o of U){const i=n[o];typeof i=="number"&&Number.isFinite(i)&&i>=0&&i<=1&&(t[o]=i)}return t}function et(e){if(typeof e!="object"||e===null||Array.isArray(e))return null;const n=e,t={};for(const o of se){const i=n[o];i!==void 0&&(t[o]=i)}if(typeof n.lightness=="object"&&n.lightness!==null&&!Array.isArray(n.lightness)){const o={};for(const i of U){const a=n.lightness[i];a!==void 0&&(o[i]=a)}t.lightness=o}if(n.tones!==void 0){const o=we(n.tones);Object.keys(o).length>0&&(t.tones=o)}if(typeof n.semanticMappings=="object"&&n.semanticMappings!==null&&!Array.isArray(n.semanticMappings)){const o={};for(const[i,a]of Object.entries(n.semanticMappings)){if(!M(i)||!K.includes(i)||typeof a!="object"||a===null||Array.isArray(a))continue;const{source:u,lightness:d}=a;typeof u=="string"&&(typeof d!="string"||!te(d)&&Me(d)===null||(o[i]={source:u,lightness:d}))}Object.keys(o).length>0&&(t.semanticMappings=o)}return t}function Kt(e,n){const t={};for(const[o,i]of Object.entries(e)){if(!M(o)||!j.test(o))continue;const a=et(i);a&&(t[o]=a)}if(!n)return t;for(const[o,i]of Object.entries(n)){if(!M(o)||!j.test(o)||i===void 0)continue;const a=et(i);if(!a)continue;const u=t[o];t[o]={...u??{},...a,...u?.lightness||a.lightness?{lightness:{...u?.lightness,...a.lightness}}:{},...u?.tones||a.tones?{tones:{...u?.tones,...a.tones}}:{},...u?.semanticMappings||a.semanticMappings?{semanticMappings:{...u?.semanticMappings,...a.semanticMappings}}:{}}}return t}function L(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function F(e){const n={};for(const[t,o]of Object.entries(e))o!==void 0&&M(t)&&(n[t]=o);return n}function tt(e){if(!L(e))return e;const n=F(e);return L(e.lightness)&&(n.lightness=F(e.lightness)),L(e.tones)&&(n.tones=F(e.tones)),n}function Ut(e,n){const t={};for(const[o,i]of Object.entries(e))M(o)&&(t[o]=tt(i));if(!n)return t;for(const[o,i]of Object.entries(n)){if(!M(o)||i===void 0)continue;const a=t[o];if(!L(a)||!L(i)){t[o]=tt(i);continue}const u={...F(a),...F(i)};L(a.lightness)&&L(i.lightness)?u.lightness={...F(a.lightness),...F(i.lightness)}:L(i.lightness)&&(u.lightness=F(i.lightness)),L(a.tones)&&L(i.tones)?u.tones={...F(a.tones),...F(i.tones)}:L(i.tones)&&(u.tones=F(i.tones)),L(a.semanticMappings)&&L(i.semanticMappings)?u.semanticMappings={...F(a.semanticMappings),...F(i.semanticMappings)}:L(i.semanticMappings)&&(u.semanticMappings=F(i.semanticMappings)),t[o]=u}return t}function Gt(e){const n={};for(const[t,o]of Object.entries(e)){if(!M(t))continue;if(typeof o=="string"){n[t]=re(o);continue}const i={};for(const[a,u]of Object.entries(o))M(a)&&(i[a]=typeof u=="string"?re(u):u);n[t]=i}return n}function ie(e){return typeof e!="string"?"":e.startsWith("anchor:")?e:re(e)}function Vt(e){const n={};for(const t of fe)n[t]=ie(e[t]);return n}function nt(e,n){const t={};for(const[o,i]of Object.entries(e))M(o)&&j.test(o)&&i&&typeof i=="object"&&!Array.isArray(i)&&(t[o]={...i});if(!n)return t;for(const[o,i]of Object.entries(n)){if(!M(o)||!j.test(o)||!i||typeof i!="object"||Array.isArray(i))continue;const a=t[o],u=a!==void 0&&i.type!==void 0&&i.type!==a.type;t[o]={...u?{}:a??{},...i}}return t}function Jt(e){const n={};for(const[t,o]of Object.entries(e))if(M(t)){if(o.type==="sequential"&&typeof o.source=="string"){n[t]={...o,source:ie(o.source)};continue}if(o.type==="diverging"&&typeof o.start=="string"&&typeof o.end=="string"){n[t]={...o,start:ie(o.start),end:ie(o.end),...typeof o.neutral=="string"?{neutral:ie(o.neutral)}:{}};continue}n[t]={...o}}return n}function ot(e){const n=W(e.seedColor);if(!n)return;const t=ye(n,e);return(o,i)=>{const a=ue(o,t,e.anchors)??t.primary,u=e.chroma.actionBackground,d=ae(a,e.lightness[i],u.min,u.max),m={l:d.l>.5?0:1,c:0,h:0};return Math.abs(mt(m,d))}}function Yt(e,n,t){if(n?.background)return n.background;const o=X(e.canvas,"color");if(o!==void 0){const i=Se.canvas.color?.find(([a])=>a==="background");if(i)return{source:o,lightness:i[1]}}return t.background}function st(e,n){const t=W(e.seedColor);if(!t||!n)return;const o=ye(t,e),i=ue(n.source,o,e.anchors)??o.primary,a=e.chroma.background,u=ae(i,Oe(e.lightness,e.tones,n.lightness),a.min,a.max);return(d,m)=>{const A=ue(d,o,e.anchors)??o.primary,k=e.chroma.actionBackground,y=ae(A,e.lightness[m],k.min,k.max);return gt(y,u)}}function qt(e){const n=le.get(e);if(n)return new Set(n);const t=pe(e);if(t)return t;const o=new Set,i=Ke(e.roles,e.lightness,e.semanticMappings,{tones:e.tones,actionSurfaceContrast:ot(e),actionSurfaceSeparation:st(e,e.semanticMappings.background)});for(const[a,u]of Object.entries(i)){const d=e.semanticMappings[a];(d.source!==u.source||d.lightness!==u.lightness)&&o.add(a)}return o}function de(e,n){const t={...e.roles,...n.roles},o=Kt(e.contexts,n.contexts),i=zt(e.lightness,n.lightness),a=jt(e.tones,n.tones),u=Gt(Qe(e.anchors,n.anchors)),d=typeof n.seedColor=="string"?re(n.seedColor):e.seedColor,m=n.semanticMappings,A={...e.angles,...n.angles},k={...e.semanticHues,...n.semanticHues},y={...e.variantChroma,...n.variantChroma},T=Wt({...e.intents,...n.intents}),_=n.chroma,z=ne(e.chroma,_),H=Vt(ne(e.dataPalette,n.dataPalette)),s=Jt(nt(e.dataRamps,n.dataRamps)),r=qt(e),c=new Set(r),l=pe(n),p={};for(const x of r)p[x]=e.semanticMappings[x];for(const[x,O]of Object.entries(m??{}))O!==void 0&&(l===void 0||l.has(x)?(c.add(x),p[x]=O):(c.delete(x),delete p[x]));const g=ne(e.semanticMappings,m),f={angles:A,anchors:u,chroma:z,intents:T,lightness:i,tones:a,seedColor:d,semanticHues:k,variantChroma:y},h=ot(f),$=st(f,Yt(t,p,g)),b=Ke(t,i,g,{explicitMappings:p,tones:a,actionSurfaceContrast:h,actionSurfaceSeparation:$}),R={};for(const[x,O]of Object.entries(b))c.has(x)||(R[x]=O);const C={};for(const x of Lt)!c.has(x)&&R[x]===void 0&&(C[x]={source:g.text.source,lightness:g.text.lightness},_?.text!==void 0&&_[x]===void 0&&(z[x]={...z.text}));const w=ne(ne(ne(e.semanticMappings,C),R),m),S={...e,seedColor:d,fontBody:n.fontBody||e.fontBody||Ve,fontHeadings:n.fontHeadings??e.fontHeadings,fontBrand:n.fontBrand??e.fontBrand,fontMenu:n.fontMenu??e.fontMenu,fontMonospace:n.fontMonospace||e.fontMonospace||Je,fontWeightBody:String(n.fontWeightBody??e.fontWeightBody),fontWeightHeadings:String(n.fontWeightHeadings??e.fontWeightHeadings),fontWeightBrand:String(n.fontWeightBrand??e.fontWeightBrand),fontWeightMenu:String(n.fontWeightMenu??e.fontWeightMenu),fontWeightMonospace:String(n.fontWeightMonospace??e.fontWeightMonospace),stylesheets:n.stylesheets??[...e.stylesheets],rootFontSize:n.rootFontSize??e.rootFontSize,typeRatio:n.typeRatio??e.typeRatio,spaceRatio:n.spaceRatio??e.spaceRatio,borderRadius:n.borderRadius??e.borderRadius,viewportMin:n.viewportMin??e.viewportMin,viewportMax:n.viewportMax??e.viewportMax,angles:A,semanticHues:k,variantChroma:y,intents:T,lightness:i,tones:a,chroma:z,semanticMappings:w,explicitMappingTokens:Xe(c),anchors:u,roles:t,contexts:o,dataPalette:H,dataRamps:s};return n.pageBackgroundImage!==void 0&&(S.pageBackgroundImage=n.pageBackgroundImage),n.pageBackgroundImageOpacity!==void 0&&(S.pageBackgroundImageOpacity=n.pageBackgroundImageOpacity),n.boxBackgroundImage!==void 0&&(S.boxBackgroundImage=n.boxBackgroundImage),n.boxBackgroundImageOpacity!==void 0&&(S.boxBackgroundImageOpacity=n.boxBackgroundImageOpacity),n.vellumOpacity!==void 0&&(S.vellumOpacity=n.vellumOpacity),n.vellumBackgroundImage!==void 0&&(S.vellumBackgroundImage=n.vellumBackgroundImage),n.vellumBackgroundImageOpacity!==void 0&&(S.vellumBackgroundImageOpacity=n.vellumBackgroundImageOpacity),le.set(S,new Set(c)),S}const rt=new WeakMap;function it(e,n){const t=e.contexts&&Object.prototype.hasOwnProperty.call(e.contexts,n)?e.contexts[n]:void 0;if(!t)return null;let o=rt.get(e);const i=o?.get(n);if(i)return i;const a={};for(const d of se){const m=t[d];m!==void 0&&(a[d]=m)}const u=de(e,{lightness:t.lightness,tones:t.tones,roles:a,semanticMappings:t.semanticMappings});return o||(o=new Map,rt.set(e,o)),o.set(n,u),u}function ne(e,n){if(!n)return{...e};const t={...e};for(const o of Object.keys(n)){const i=n[o];i!==void 0&&(t[o]=i)}return t}function Be(e){let n;try{n=Ze(e)}catch{return{error:"Failed to decode Base64 string."}}let t;try{t=JSON.parse(n)}catch{return{error:"Decoded string is not valid JSON."}}return typeof t!="object"||t===null||Array.isArray(t)?{error:"Theme must be a JSON object."}:{value:t}}function fn(e){const n=Be(e);return n.error!==void 0?{valid:!1,errors:[n.error],warnings:[]}:_e(n.value)}function _e(e,n=Re){const t=[],o=[];"seedColor"in e&&(typeof e.seedColor!="string"?t.push("seedColor must be a string."):W(e.seedColor)||t.push(`seedColor is not a valid CSS color: "${e.seedColor}". Accepted forms: ${oe}.`));for(const s of["fontBody","fontHeadings","fontBrand","fontMenu","fontMonospace"])s in e&&typeof e[s]!="string"&&t.push(`${s} must be a string.`);const i=["normal","bold","lighter","bolder"],a=["inherit","initial","unset","revert","revert-layer"];for(const s of["fontWeightBody","fontWeightHeadings","fontWeightBrand","fontWeightMenu","fontWeightMonospace"])if(s in e){const r=e[s];if(typeof r=="number")(r<1||r>1e3)&&t.push(`${s} numeric value must be 1\u20131000 (got ${r}).`);else if(typeof r=="string"){const c=i.includes(r)||a.includes(r);if(/^\d+$/.test(r)){const p=Number(r);(p<1||p>1e3)&&t.push(`${s} numeric value must be 1\u20131000 (got "${r}").`)}else c||o.push(`${s} = "${r}" is not a standard font-weight value.`)}else t.push(`${s} must be a string or number.`)}"stylesheets"in e&&(Array.isArray(e.stylesheets)?e.stylesheets.some(s=>typeof s!="string")&&t.push("Every entry in stylesheets must be a string."):t.push("stylesheets must be an array of strings."));const u=[["rootFontSize",1,100],["borderRadius",0,10],["viewportMin",100,1e4],["viewportMax",200,1e4]];for(const[s,r,c]of u)if(s in e)if(typeof e[s]!="number"||!isFinite(e[s]))t.push(`${s} must be a finite number.`);else{const l=e[s];r!==void 0&&l<r&&t.push(`${s} must be \u2265 ${r} (got ${l}).`),c!==void 0&&l>c&&o.push(`${s} = ${l} is unusually high (max ${c}).`)}for(const s of["typeRatio","spaceRatio"])if(s in e)if(typeof e[s]!="number"||!isFinite(e[s]))t.push(`${s} must be a finite number.`);else{const r=e[s];r<=1&&t.push(`${s} must be > 1 (got ${r}).`);const c=s==="typeRatio"?1.3:2;r>c&&o.push(`${s} = ${r} is very high (max ${c}); scales may be extreme.`)}if("viewportMin"in e&&"viewportMax"in e){const s=e.viewportMin,r=e.viewportMax;typeof s=="number"&&typeof r=="number"&&s>=r&&t.push(`viewportMin (${s}) must be less than viewportMax (${r}).`)}if("angles"in e)if(typeof e.angles!="object"||e.angles===null)t.push("angles must be an object.");else{const s=e.angles;for(const r of["analogous","complementary","splitComplementary","triadic"])if(r in s)if(typeof s[r]!="number"||!isFinite(s[r]))t.push(`angles.${r} must be a finite number.`);else{const c=s[r];(c<0||c>360)&&o.push(`angles.${r} = ${c} is outside 0\u2013360.`)}}if("semanticHues"in e)if(typeof e.semanticHues!="object"||e.semanticHues===null)t.push("semanticHues must be an object.");else{const s=e.semanticHues;for(const r of["danger","success","warning","info"])if(r in s)if(typeof s[r]!="number"||!isFinite(s[r]))t.push(`semanticHues.${r} must be a finite number.`);else{const c=s[r];(c<0||c>360)&&o.push(`semanticHues.${r} = ${c} is outside 0\u2013360.`)}}if("variantChroma"in e)if(typeof e.variantChroma!="object"||e.variantChroma===null)t.push("variantChroma must be an object.");else{const s=e.variantChroma;for(const r of It)if(r in s)if(typeof s[r]!="number"||!isFinite(s[r]))t.push(`variantChroma["${r}"] must be a finite number.`);else{const c=s[r];c<0&&t.push(`variantChroma["${r}"] must be \u2265 0 (got ${c}).`),c>Y&&o.push(`variantChroma["${r}"] = ${c} exceeds ${Y}.`)}}function d(s,r){if(typeof s!="object"||s===null||Array.isArray(s)){t.push(`${r} must be an object.`);return}const c=s;for(const l of Object.keys(c))(!M(l)||!te(l))&&t.push(`${r}.${l} is not a built-in lightness stop; expected one of: ${U.join(", ")}.`);for(const l of U)if(l in c)if(typeof c[l]!="number"||!isFinite(c[l]))t.push(`${r}.${l} must be a finite number.`);else{const p=c[l];(p<0||p>1)&&t.push(`${r}.${l} must be 0\u20131 (got ${p}).`)}}"lightness"in e&&d(e.lightness,"lightness");function m(s,r){const c=new Set;if(!L(s))return t.push(`${r} must be an object.`),c;for(const[l,p]of Object.entries(s)){if(!M(l)||!j.test(l)){t.push(`${r}.${l} must be a lowercase slug matching ${j.source}.`);continue}if(te(l)){t.push(`${r}.${l} conflicts with the built-in "${l}" lightness stop; choose a distinct custom tone name.`);continue}c.add(l),typeof p!="number"||!Number.isFinite(p)?t.push(`${r}.${l} must be a finite number.`):(p<0||p>1)&&t.push(`${r}.${l} must be 0\u20131 (got ${p}).`)}return c}const A=new Set(Object.keys(n.tones??{}));if("tones"in e)for(const s of m(e.tones,"tones"))A.add(s);if("chroma"in e)if(typeof e.chroma!="object"||e.chroma===null)t.push("chroma must be an object.");else{const s=e.chroma,r=_t(e,n);for(const c of K)if(c in s){const l=s[c];if(typeof l!="object"||l===null){t.push(`chroma.${c} must be { min, max }.`);continue}const p=l;for(const f of r.get(c)??[])f.chroma!==void 0&&typeof p.min=="number"&&typeof p.max=="number"&&(f.chroma<p.min-1e-9||f.chroma>p.max+1e-9)&&o.push(`chroma.${c} clamps the anchor-sourced token ${c} ("${f.source}", effective in ${f.where}) and moves it off its declared swatch. Remove the band if that is unintended \u2014 anchors otherwise keep their own chroma.`);const g=l;(typeof g.min!="number"||g.min<0)&&t.push(`chroma.${c}.min must be \u2265 0.`),(typeof g.max!="number"||g.max<0||g.max>Y)&&t.push(`chroma.${c}.max must be 0\u2013${Y}.`),typeof g.min=="number"&&typeof g.max=="number"&&g.min>g.max&&t.push(`chroma.${c}.min (${g.min}) must be \u2264 max (${g.max}).`)}}if("anchors"in e)if(typeof e.anchors!="object"||e.anchors===null||Array.isArray(e.anchors))t.push("anchors must be an object of named colors.");else for(const[s,r]of Object.entries(e.anchors))if(M(s)?j.test(s)||t.push(`anchors: "${s}" is not a valid anchor name; use a lowercase slug (letters, digits, hyphens).`):t.push(`anchors: "${s}" is a reserved JavaScript property name and cannot be an anchor name; rename it.`),Ae.includes(s)&&t.push(`anchors: "${s}" collides with a reserved color source name.`),typeof r=="string")W(r)||t.push(`anchors.${s} is not a valid CSS color: "${r}". Accepted forms: ${oe}.`);else if(typeof r=="object"&&r!==null&&!Array.isArray(r)){const c=r;typeof c.color!="string"&&t.push(`anchors.${s} must declare its base "color".`);for(const[l,p]of Object.entries(c))M(l)?l!=="color"&&!j.test(l)&&t.push(`anchors.${s}: "${l}" is not a valid slot name; use a lowercase slug.`):t.push(`anchors.${s}: "${l}" is a reserved JavaScript property name and cannot be a slot name; rename it.`),typeof p!="string"?t.push(`anchors.${s}.${l} must be a CSS color string.`):W(p)||t.push(`anchors.${s}.${l} is not a valid CSS color: "${p}". Accepted forms: ${oe}.`)}else t.push(`anchors.${s} must be a color string or a { color, \u2026slots } object.`);const k=new Map;if("anchors"in e&&typeof e.anchors=="object"&&e.anchors!==null&&!Array.isArray(e.anchors))for(const[s,r]of Object.entries(e.anchors))k.set(s,r);function y(s,r){const c=ke(s);if(!c){t.push(`${r} "${s}" is not valid anchor syntax; use anchor:<name> or anchor:<name>.<slot>.`);return}if(!k.has(c.name)){const l=[...k.keys()];t.push(`${r} references undeclared anchor "${c.name}". Declared anchors: ${l.length>0?l.join(", "):"(none)"}.`);return}if(c.slot!==void 0){const l=k.get(c.name);if(typeof(typeof l=="object"&&l!==null&&!Array.isArray(l)?l[c.slot]:void 0)!="string"){const g=typeof l=="object"&&l!==null?Object.keys(l).filter(f=>f!=="color"):[];t.push(`${r} references unknown slot "${c.slot}" on anchor "${c.name}". Declared slots: ${g.length>0?g.join(", "):"(none)"}.`)}}}function T(s,r){if(s.startsWith("anchor:")){y(s,r);return}Ae.includes(s)||t.push(`${r} must be one of: ${Ae.join(", ")}, or a declared anchor as anchor:<name> / anchor:<name>.<slot>.`)}if("intents"in e)if(typeof e.intents!="object"||e.intents===null||Array.isArray(e.intents))t.push("intents must be an object.");else for(const[s,r]of Object.entries(e.intents)){const c=`intents.${s}`;if(!ee.includes(s)){t.push(`${c} is not a status family; expected one of: ${ee.join(", ")}.`);continue}if(typeof r!="string"){t.push(`${c} must be a string (a CSS color or an anchor: reference).`);continue}if(r.startsWith("anchor:")){y(r,c);continue}W(r)||t.push(`${c} "${r}" is not a supported color form or anchor: reference. Accepted forms: ${oe}, or anchor:<name> / anchor:<name>.<slot>. An override retunes a family with a declared color; it never points one family at another \u2014 retune, never reassign.`)}function _(s,r){if(s.startsWith("anchor:")){y(s,r);return}W(s)||t.push(`${r} is not a valid CSS color: "${s}". Accepted forms: ${oe}, or a declared anchor as anchor:<name> / anchor:<name>.<slot>.`)}if("dataPalette"in e)if(typeof e.dataPalette!="object"||e.dataPalette===null||Array.isArray(e.dataPalette))t.push("dataPalette must be an object with series1\u2013series8 color values.");else{const s=e.dataPalette;for(const[r,c]of Object.entries(s)){if(!fe.includes(r)){t.push(`dataPalette.${r} is not a series slot; expected one of: ${fe.join(", ")}.`);continue}typeof c!="string"?t.push(`dataPalette.${r} must be a CSS color or anchor reference string.`):_(c,`dataPalette.${r}`)}}if("dataRamps"in e)if(typeof e.dataRamps!="object"||e.dataRamps===null||Array.isArray(e.dataRamps))t.push("dataRamps must be an object of named ramp declarations.");else for(const[s,r]of Object.entries(e.dataRamps)){if(M(s)?j.test(s)||t.push(`dataRamps: "${s}" is not a valid ramp name; use a lowercase slug (letters, digits, hyphens).`):t.push(`dataRamps: "${s}" is a reserved JavaScript property name and cannot be a ramp name; rename it.`),typeof r!="object"||r===null||Array.isArray(r)){t.push(`dataRamps.${s} must be a sequential or diverging ramp object.`);continue}const c=r,l=c.steps??Mt;if((typeof l!="number"||!Number.isInteger(l)||l<xe||l>$e)&&t.push(`dataRamps.${s}.steps must be an integer from ${xe} through ${$e}.`),c.type==="sequential"){typeof c.source!="string"?t.push(`dataRamps.${s}.source must be a CSS color or anchor reference string.`):_(c.source,`dataRamps.${s}.source`);const p=c.lightnessStart??.95,g=c.lightnessEnd??.25;for(const[f,h]of[["lightnessStart",p],["lightnessEnd",g]])(typeof h!="number"||!Number.isFinite(h)||h<0||h>1)&&t.push(`dataRamps.${s}.${f} must be a finite number from 0 through 1.`);typeof p=="number"&&typeof g=="number"&&p<=g?t.push(`dataRamps.${s}.lightnessStart must be greater than lightnessEnd.`):typeof p=="number"&&Number.isFinite(p)&&typeof g=="number"&&Number.isFinite(g)&&typeof l=="number"&&Number.isInteger(l)&&l>=xe&&l<=$e&&(p-g)/(l-1)<=We&&t.push(`dataRamps.${s} lightness bounds must leave more than ${We} lightness between serialized stops.`);continue}if(c.type==="diverging"){typeof l=="number"&&Number.isInteger(l)&&l%2===0&&t.push(`dataRamps.${s}.steps must be odd so the neutral is the exact midpoint.`);for(const p of["start","end"])typeof c[p]!="string"?t.push(`dataRamps.${s}.${p} must be a CSS color or anchor reference string.`):_(c[p],`dataRamps.${s}.${p}`);"neutral"in c&&(typeof c.neutral!="string"?t.push(`dataRamps.${s}.neutral must be a CSS color or anchor reference string.`):_(c.neutral,`dataRamps.${s}.neutral`));continue}t.push(`dataRamps.${s}.type must be "sequential" or "diverging".`)}if("dataPalette"in e&&t.length===0){const s=de(Re,e),r={};let c=!0;for(const l of fe){const p=Ot(s.dataPalette[l],s.anchors);if(!p){c=!1;break}r[l]=p}if(c)for(const l of St(r))o.push(At(l))}function z(s,r){if(typeof s!="object"||s===null||Array.isArray(s)){t.push(`${r} must be an object.`);return}const c=s;for(const[l,p]of Object.entries(c)){const g=`${r}.${l}`;if(!se.includes(l)){t.push(`${g} is not a role; expected one of: ${se.join(", ")}. (The status family is reserved and is not a role.)`);continue}const f=l,h=Se[f];if(typeof p=="string"){T(p,g);continue}if(typeof p!="object"||p===null||Array.isArray(p)){t.push(`${g} must be a color source or a { color, \u2026slots } object.`);continue}const $=p;typeof $.color!="string"&&t.push(`${g} must declare its base "color".`);for(const[b,R]of Object.entries($)){if(!Object.prototype.hasOwnProperty.call(h,b)||!M(b)){const C=Object.keys(h).filter(w=>w!=="color");t.push(`${g}.${b} is not a slot of the ${f} role. Declared slots: ${C.length>0?C.join(", "):"(none)"}.`);continue}typeof R!="string"?t.push(`${g}.${b} must be a color source string.`):T(R,`${g}.${b}`)}}}if("roles"in e&&z(e.roles,"roles"),"contexts"in e)if(typeof e.contexts!="object"||e.contexts===null||Array.isArray(e.contexts))t.push("contexts must be an object.");else for(const[s,r]of Object.entries(e.contexts)){if(!M(s)||!j.test(s)){t.push(`contexts.${s} must be a lowercase slug matching ${j.source}.`);continue}if(typeof r!="object"||r===null||Array.isArray(r)){z(r,`contexts.${s}`);continue}const c=r,l=Object.fromEntries(Object.entries(c).filter(([g])=>g!=="lightness"&&g!=="tones"&&g!=="semanticMappings"));z(l,`contexts.${s}`),"lightness"in c&&d(c.lightness,`contexts.${s}.lightness`);const p=new Set(A);if("tones"in c)for(const g of m(c.tones,`contexts.${s}.tones`))p.add(g);"semanticMappings"in c&&H(c.semanticMappings,`contexts.${s}.semanticMappings`,p)}function H(s,r,c){if(typeof s!="object"||s===null||Array.isArray(s)){t.push(`${r} must be an object.`);return}const l=s;for(const p of Object.keys(l))K.includes(p)||t.push(`${r}.${p} is not a semantic token; expected one of: ${K.join(", ")}.`);for(const p of K)if(p in l){const g=l[p];if(typeof g!="object"||g===null){t.push(`${r}.${p} must be { source, lightness }.`);continue}const f=g;if(typeof f.source!="string"?t.push(`${r}.${p}.source must be a string.`):T(f.source,`${r}.${p}.source`),typeof f.lightness!="string")t.push(`${r}.${p}.lightness must be one of: ${U.join(", ")}, or a declared tone:<name>.`);else if(!te(f.lightness)){const h=Me(f.lightness);if(h===null)t.push(`${r}.${p}.lightness must be one of: ${U.join(", ")}, or a declared tone:<name>.`);else if(!c.has(h)){const $=[...c].sort();t.push(`${r}.${p}.lightness references undeclared tone "${h}". Declared tones: ${$.length>0?$.join(", "):"(none)"}.`)}}}}if("semanticMappings"in e&&H(e.semanticMappings,"semanticMappings",A),"explicitMappingTokens"in e)if(!Array.isArray(e.explicitMappingTokens))t.push("explicitMappingTokens must be an array of semantic token names.");else{const s=new Set,r=L(e.semanticMappings)?e.semanticMappings:void 0;for(const c of e.explicitMappingTokens){if(typeof c!="string"||!K.includes(c)){t.push(`explicitMappingTokens entries must be one of: ${K.join(", ")}.`);continue}s.has(c)&&t.push(`explicitMappingTokens contains duplicate token "${c}".`),s.add(c),(!r||!Object.prototype.hasOwnProperty.call(r,c))&&t.push(`explicitMappingTokens names "${c}" without a semanticMappings entry.`)}}for(const s of["pageBackgroundImage","boxBackgroundImage","vellumBackgroundImage"])s in e&&typeof e[s]!="string"&&t.push(`${s} must be a string.`);for(const s of["pageBackgroundImageOpacity","boxBackgroundImageOpacity","vellumOpacity","vellumBackgroundImageOpacity"])if(s in e)if(typeof e[s]!="number"||!isFinite(e[s]))t.push(`${s} must be a finite number.`);else{const r=e[s];(r<0||r>1)&&t.push(`${s} must be 0\u20131 (got ${r}).`)}return o.push(...Xt(e,n)),{valid:t.length===0,errors:t,warnings:o}}const B=.045;function Xt(e,n){try{return Zt(e,n)}catch{return[]}}function Zt(e,n){const t=de(n,e),o=ut(t),i=[...o],a=new Set(o);for(const u of Object.keys(t.contexts)){const d=it(t,u);if(d)for(const m of ut(d))a.has(m)||i.push(`contexts.${u}: ${m}`)}return i}function Qt(e){const n=yt(he(e)),t=$t(n);return ht({r:ge(t.r),g:ge(t.g),b:ge(t.b)})}function Z(e,n){return Math.hypot(e.L-n.L,e.a-n.a,e.b-n.b)}function q(e){return Qt(W(ce(he(e))))}function at(e){return(Math.floor(e*1e4)/1e4).toFixed(4)}const Q=2,ct=1e-4;function ut(e){const n=W(e.seedColor);if(!n)return[];const t=ye(n,e),o=e.semanticMappings.actionBackground,i=e.chroma.actionBackground,a=Oe(e.lightness,e.tones,o.lightness),u=(f,h,$,b)=>he(ae(f,h,$,b)),d=ee.map(f=>({name:f,base:t[f]})),m=[];if(ee.includes(o.source))m.push(`actionBackground is sourced from the "${o.source}" status family: ordinary and ${o.source}-intent action surfaces render identically (their labels may still differ). Remap the action to a non-status source \u2014 retuning "${o.source}" via intents moves both colors together.`);else{const f=ue(o.source,t,e.anchors);f&&d.push({name:"action",base:f})}const A=Fe(d.map(({name:f,base:h})=>[f,ce(u(h,a,i.min,i.max))]),B,["normal"]);if(A.length===0)return m;const k=new Map,y=(f,h)=>{const $=`${f}:${h}`;let b=k.get($);if(!b){b=[];for(let R=0;R<360;R+=Q)b.push(q({l:f,c:h,h:R}));k.set($,b)}return b},T=B-.002,_=(f,h,$,b)=>{const R=Math.hypot(f.a,f.b),C=Math.atan2(f.b,f.a)*180/Math.PI+180;let w=0;for(const S of $===b?[b]:[$,b]){if(S+R<B-1e-4)continue;let x=C,O=Z(q({l:h,c:S,h:C}),f);if(O>=B)return O;const D=y(h,S);for(let E=0;E<D.length;E+=1){const v=Z(D[E],f);if(v>=B)return v;v>O&&(O=v,x=E*Q)}let P=x;for(let E=x-Q;E<=x+Q;E+=.1){const v=Z(q({l:h,c:S,h:E}),f);if(v>=B)return v;v>O&&(O=v,P=E)}if(O>=T)for(let E=P-.1;E<=P+.1;E+=.001){const v=Z(q({l:h,c:S,h:E}),f);if(v>=B)return v;v>O&&(O=v)}O>w&&(w=O)}return w},z=(f,h,$)=>{const b=h===$?[$]:[h,$];let R=0;for(const C of b)for(const w of b){if(C+w<B-1e-4)continue;const S=y(f,C),x=y(f,w);let O=0,D=0,P=-1;for(let N=0;N<S.length;N+=1)for(let G=0;G<x.length;G+=1){const V=Z(S[N],x[G]);if(V>=B)return V;V>P&&(P=V,O=N*Q,D=G*Q)}const E=(N,G,V,Le)=>{const Ie=[];for(let J=G-V;J<=G+V;J+=Le)Ie.push({h:J,lab:q({l:f,c:w,h:J})});let me=-1,Ne=N,He=G;for(let J=N-V;J<=N+V;J+=Le){const pt=q({l:f,c:C,h:J});for(const Pe of Ie){const De=Z(pt,Pe.lab);De>me&&(me=De,Ne=J,He=Pe.h)}}return{distance:me,hueA:Ne,hueB:He}},v=E(O,D,Q,.1);if(v.distance>=B)return v.distance;let I=Math.max(P,v.distance);if(I>=T){const N=E(v.hueA,v.hueB,.1,.001);if(N.distance>I&&(I=N.distance),I>=B)return I}I>R&&(R=I)}return R},H=f=>ee.includes(f),s=(f,h,$,b,R)=>{const C=q(u(f.base,$,b,R)),w=q(u(h.base,$,b,R));if(Z(C,w)>=B)return{outcome:"direct"};const S=H(f.name)&&H(h.name),x=[f,h].filter(P=>H(P.name)),O=S?"one of them":`"${H(f.name)?f.name:h.name}"`;let D;for(const P of x){const E=_(P===f?w:C,$,b,R);if(E>=B)return{outcome:"retune",target:O};E>=B-ct&&(D=D??O)}if(S){const P=z($,b,R);if(P>=B)return{outcome:"retune",target:"both"};P>=B-ct&&(D=D??"both")}return D!==void 0?{outcome:"near",target:D}:{outcome:"no"}},r=f=>f.outcome==="direct"?4:f.outcome==="retune"?f.target==="both"?2:3:f.outcome==="near"?1:0,c=f=>[...f].sort().join("|"),l=new Set(Fe(d.map(({name:f,base:h})=>[f,ce(u(h,a,0,Y))]),B,["normal"]).map(f=>c(f.pair))),p=new Map(d.map(f=>[f.name,f])),g=new Map;for(const{pair:f,distance:h}of A){const $=p.get(f[0]),b=p.get(f[1]),R=H($.name)&&H(b.name),C=s($,b,a,i.min,i.max);if(C.outcome==="direct"||C.outcome==="retune"){const I=C.target??(R?"one of them":`"${H($.name)?$.name:b.name}"`);l.has(c(f))?m.push(`Status colors "${f[0]}" and "${f[1]}" are hard to distinguish under normal vision (distance ${at(h)} < ${B}); status meanings must stay distinguishable \u2014 retune ${I} via intents.`):m.push(`Status colors "${f[0]}" and "${f[1]}" are hard to distinguish as rendered (distance ${at(h)} < ${B}); the actionBackground chroma band ({ min: ${i.min}, max: ${i.max} }) pushes them together \u2014 widen the band, or retune ${I} via intents.`);continue}const w=s($,b,a,0,Y);let S={outcome:"no"};for(let I=1;I<=19&&S.outcome!=="direct";I+=1){const N=I*.05;if(Math.abs(N-a)<.001)continue;const G=s($,b,N,i.min,i.max);r(G)>r(S)&&(S=G)}let x={outcome:"no"};const O=w.outcome==="direct"||w.outcome==="retune",D=S.outcome==="direct"||S.outcome==="retune";if(!O&&!D)for(let I=1;I<=19&&x.outcome!=="direct";I+=1){const N=s($,b,I*.05,0,Y);r(N)>r(x)&&(x=N)}const P=en(w,S,x),E=`${C.outcome}|${P}`;let v=g.get(E);v||(v=[],g.set(E,v)),v.push(f)}for(const[f,h]of g){const $=f.indexOf("|"),b=f.slice(0,$),R=f.slice($+1),C=h.map(([x,O])=>`"${x}"/"${O}"`),w=C.length>1?`${C.slice(0,-1).join(", ")} and ${C[C.length-1]}`:C[0],S=b==="near"?`Status colors ${w} may not separate by retuning as rendered: at the action stop's lightness (${a}) with the actionBackground chroma band ({ min: ${i.min}, max: ${i.max} }), the closest reachable retune found comes within the audit's search margin of the ${B} threshold`:`Status colors ${w} cannot be separated as rendered: at the action stop's lightness (${a}) with the actionBackground chroma band ({ min: ${i.min}, max: ${i.max} }), no intent retuning can pull ${h.length>1?"these pairs":"the pair"} ${B} apart`;m.push(S+R)}return m}function en(e,n,t){if(e.outcome==="direct"&&n.outcome==="direct")return" \u2014 widen the chroma band or move the action lightness stop.";if(e.outcome==="direct")return n.outcome==="no"?"; no other action lightness stop can help while the band holds \u2014 widen the chroma band.":" \u2014 widen the chroma band.";if(n.outcome==="direct")return e.outcome==="no"?"; no wider chroma band can help at this lightness \u2014 move the action lightness stop.":" \u2014 move the action lightness stop.";if(e.outcome==="retune"&&n.outcome==="retune")return` \u2014 widen the chroma band or move the action lightness stop, then retune ${e.target} via intents.`;if(e.outcome==="retune")return n.outcome==="no"?`; no other action lightness stop can help while the band holds \u2014 widen the chroma band, then retune ${e.target} via intents.`:` \u2014 widen the chroma band, then retune ${e.target} via intents.`;if(n.outcome==="retune")return e.outcome==="no"?`; no wider chroma band can help at this lightness \u2014 move the action lightness stop, then retune ${n.target} via intents.`:` \u2014 move the action lightness stop, then retune ${n.target} via intents.`;const o=e.outcome==="no"&&n.outcome==="no"?"; neither a wider chroma band alone nor another stop alone can help":"; neither a wider chroma band alone nor another stop alone provably helps";return t.outcome==="direct"?`${o} \u2014 change the band and the stop together.`:t.outcome==="retune"?`${o} \u2014 change the band and the stop together, then retune ${t.target} via intents.`:"; no explored band or stop change provably separates this pair."}function ln(e,n){const t=Be(e),o=Be(n),i=t.error!==void 0?{valid:!1,errors:[t.error],warnings:[]}:_e(t.value),a=o.error!==void 0?{valid:!1,errors:[o.error],warnings:[]}:_e(o.value,qe),u=[...i.errors.map(m=>`light: ${m}`),...a.errors.map(m=>`dark: ${m}`)],d=[...i.warnings.map(m=>`light: ${m}`),...a.warnings.map(m=>`dark: ${m}`)];if(i.valid&&a.valid){const m=new Set(Object.keys(t.value?.contexts??{})),A=new Set(Object.keys(o.value?.contexts??{})),k=[...A].filter(T=>!m.has(T)).sort(),y=[...m].filter(T=>!A.has(T)).sort();(k.length>0||y.length>0)&&u.push(`contexts must declare the same names in both schemes. Missing from light: ${k.join(", ")||"(none)"}. Missing from dark: ${y.join(", ")||"(none)"}.`)}return{valid:u.length===0,errors:u,warnings:d}}const tn=["anchors","angles","contexts","dataPalette","dataRamps","intents","roles","chroma","lightness","tones","semanticHues","semanticMappings","variantChroma"];function nn(e,n){const t={};for(const[a,u]of Object.entries(e))M(a)&&(t[a]=u);for(const[a,u]of Object.entries(n))u!==void 0&&M(a)&&(t[a]=u);for(const a of tn){const u=e[a],d=n[a];if(u&&typeof u=="object"&&!Array.isArray(u)&&d&&typeof d=="object"&&!Array.isArray(d)){if(a==="anchors"){t[a]=Qe(u,d);continue}if(a==="contexts"){t[a]=Ut(u,d);continue}if(a==="dataRamps"){t[a]=nt(u,d);continue}const m={};for(const[A,k]of Object.entries(u))M(A)&&(m[A]=k);for(const[A,k]of Object.entries(d))k!==void 0&&M(A)&&(m[A]=k);t[a]=m}}const o=pe(e),i=pe(n);if(o!==void 0||i!==void 0){const a=o??new Set(Object.keys(e.semanticMappings??{}).filter(u=>K.includes(u)));for(const u of Object.keys(n.semanticMappings??{}))i===void 0||i.has(u)?a.add(u):a.delete(u);t.explicitMappingTokens=Xe(a)}return t}function pn(...e){let n={};for(const t of e){if(!t)continue;const o=Dt(t);o&&(n=nn(n,o))}return Ee(n)}function ft(e){return e.replace(/\\/g,"\\\\").replace(/"/g,'\\"').replace(/\n/g,"\\n").replace(/\r/g,"\\r")}const lt={borderRadius:.1,fontBody:'"Noto Sans", sans-serif',fontWeightBody:"normal",fontHeadings:'"Inika", serif',fontWeightHeadings:"normal",fontBrand:'"Inika", serif',fontWeightBrand:"normal",fontMonospace:'"JetBrains Mono", monospace',fontWeightMonospace:"normal",seedColor:"oklch(.07 0.15 216)"};function dn(e){return Ee({...lt,pageBackgroundImage:`url("${ft(e)}")`,pageBackgroundImageOpacity:.5})}function mn(e){return Ee({...lt,pageBackgroundImage:`url("${ft(e)}")`,pageBackgroundImageOpacity:.55})}export{j as ANCHOR_SLUG_PATTERN,Ae as COLOR_SOURCES,Ve as DEFAULT_BODY_FONT_FAMILY,Ht as DEFAULT_DARK_LIGHTNESS,qe as DEFAULT_DARK_THEME,Nt as DEFAULT_LIGHT_LIGHTNESS,Re as DEFAULT_LIGHT_THEME,Je as DEFAULT_MONOSPACE_FONT_FAMILY,Te as DEFAULT_SEMANTIC_MAPPINGS,U as LIGHTNESS_KEYS,tn as NESTED_THEME_KEYS,se as ROLE_NAMES,Rt as ROLE_PAIRED_INK,Se as ROLE_TOKEN_PLAN,K as SEMANTIC_COLOR_NAMES,ee as STATUS_COLOR_SOURCES,Ue as TOKEN_PAIRINGS,It as VARIANT_COLOR_SOURCES,mn as buildTaprootDarkTheme,dn as buildTaprootLightTheme,Ke as compileRoles,Ee as encodeTheme,qt as explicitMappingTokens,te as isLightnessKey,L as isObjectRecord,cn as isSemanticColorName,pn as layerThemes,nn as mergePartials,de as mergeTheme,ke as parseAnchorSource,Dt as parseTheme,je as resolveAnchorColor,it as resolveContextTheme,Ot as resolveDataColorSource,Oe as resolveLightnessReference,un as semanticToCSS,Me as toneReferenceName,fn as validateTheme,ln as validateThemePair};
|
|
1
|
+
import{UNSAFE_KEYS as yt,isSafeKey as M}from"./unsafe-keys.js";import{ACCEPTED_COLOR_FORMS as oe,apcaContrast as se,clampChannel as be,deltaEOK as bt,deriveSemantic as re,gamutMapToSRGB as $e,linearRgbToOklab as $t,oklchToSRGB as kt,parseCssColor as W,parseOklch as xt,serializeOklch as fe,srgbToLinearRGB as St}from"./color-engine.js";import{computeVariants as le,parseAnchorSource as At,resolveAnchorColor as Mt,resolveMappingSource as ie}from"./variant-engine.js";import{auditColorDistances as Fe,auditDataPalette as Ot,describePaletteCollision as Tt,DATA_SERIES_KEYS as pe,DEFAULT_DATA_PALETTE as ke,DEFAULT_DATA_RAMP_STEPS as Ct,MAX_DATA_RAMP_STEPS as xe,MIN_DATA_RAMP_LIGHTNESS_STEP as We,MIN_DATA_RAMP_STEPS as Se}from"./data-colors.js";const K=/^[a-z][a-z0-9-]*$/;function Ae(e){return At(e)}function je(e,n){return Mt(e,n)}function Rt(e,n){const t=Ae(e);if(t){const o=je(n,t);return o&&W(o)?o:null}return W(e)?e:null}const ae=["canvas","ink","accent","action","structure"],de={canvas:{color:[["background","surface"],["layer1","raised1"],["layer2","raised2"],["layer3","raised3"],["layer4","raised4"]]},ink:{color:[["text","text"],["typeOverline","text"],["typeLabel","text"],["typeLead","text"],["typeCaption","text"],["inputSelection","text"]],heading:[["headings","muted"],["headingsHover","ink"]]},accent:{color:[["linkHoverBg","raised2"],["inputSelectionBg","raised2"],["inputCaret","ink"]],text:[["link","accent"]],hover:[["linkHover","text"]]},action:{color:[["actionBackground","muted"]],ink:[["actionText","surface"]]},structure:{color:[["border","border"],["shadow","shadow"]]}},vt=new Set(["action.color"]),Et=new Set(["action.ink"]),wt={canvas:"background",ink:"text",accent:"link",action:"actionBackground",structure:"border"},Ke={"action.ink":{role:"canvas",slot:"color"}},Bt=.45,_t=.045;function ze(e,n,t){const o=Ge.actionText,i=[...U].sort((S,A)=>e[S]-e[A]||U.indexOf(S)-U.indexOf(A)),a=n?i.filter(S=>n(S)>=o.targetLc):i,u=t?a.filter(S=>t(S)>=_t):a,d=u.length>0?u:a,m=d.length>0?d:i;let x,b=1/0;for(const S of m){const A=Math.abs(e[S]-Bt);A<b&&(b=A,x=S)}return x??"muted"}function Lt(e){const n={l:e,c:0,h:0};return Math.abs(se({l:0,c:0,h:0},n))>=Math.abs(se({l:1,c:0,h:0},n))?"dark":"light"}function It(e,n,t,o){const i=Te(n,t,e),a=(o??Lt)(i)==="dark";let u=U[0];for(const d of U)(a?n[d]<n[u]:n[d]>n[u])&&(u=d);return u}const Nt={"accent.hover":"text"};function Pt(e,n){const t=new Map;try{const o=he(n,e),i=(a,u,d,m)=>{const x=Ae(u),b=x?je(m,x):null,S=b===null?null:W(b),A=t.get(a)??[];A.some(D=>D.source===u&&D.chroma===S?.c)||(A.push({source:u,where:d,chroma:S?.c}),t.set(a,A))};for(const[a,u]of Object.entries(o.semanticMappings))u.source.startsWith("anchor:")&&i(a,u.source,"the root table",o.anchors);for(const a of Object.keys(o.contexts)){const u=ft(o,a);if(u)for(const[d,m]of Object.entries(u.semanticMappings))m.source.startsWith("anchor:")&&i(d,m.source,`contexts.${a}`,u.anchors)}}catch{return new Map}return t}function Y(e,n){if(e===void 0)return;if(typeof e=="string")return n==="color"?e:void 0;const t=e[n];return typeof t=="string"?t:void 0}function Ue(e,n,t,o={}){const i={};for(const a of ae){const u=e[a];if(u!==void 0)for(const[d,m]of Object.entries(de[a])){const x=Ke[`${a}.${d}`];let b=Y(u,d),S=!1;if(b===void 0){x&&(b=Y(e[x.role],x.slot),b??=t[wt[x.role]]?.source,S=b!==void 0);const A=Nt[`${a}.${d}`];A!==void 0&&(b??=Y(u,A)),b??=Y(u,"color")}if(b!==void 0)for(const[A,D]of m){let F=D;if(vt.has(`${a}.${d}`))F=ze(n,o.actionSurfaceContrast?L=>o.actionSurfaceContrast(b,L):void 0,o.actionSurfaceSeparation?L=>o.actionSurfaceSeparation(b,L):void 0);else if(x&&(S||Et.has(`${a}.${d}`))){const L=Ge[A],s=L?o.explicitMappings?.[L.bg]:void 0,r=s?.lightness??ze(n,o.actionSurfaceContrast?f=>o.actionSurfaceContrast(Y(u,"color"),f):void 0,o.actionSurfaceSeparation?f=>o.actionSurfaceSeparation(Y(u,"color"),f):void 0),c=s?.source??Y(u,"color");F=It(r,n,o.tones??{},o.actionSurfacePole&&c!==void 0?f=>o.actionSurfacePole(c,f):void 0)}i[A]={source:b,lightness:F}}}}return i}function dn(e){const n={};for(const t of Object.keys(Ke)){const o=t.indexOf("."),i=t.slice(0,o),a=t.slice(o+1),u=e[i];if(u===void 0)continue;const d=Y(u,a)!==void 0?"declared":"derived";for(const[m]of de[i][a]??[])n[m]=d}return n}const Ge={text:{bg:"background",targetLc:75},typeOverline:{bg:"background",targetLc:90},typeLabel:{bg:"background",targetLc:75},typeLead:{bg:"background",targetLc:75},typeCaption:{bg:"background",targetLc:90},dangerText:{bg:"background",targetLc:75},headings:{bg:"background",targetLc:60},headingsHover:{bg:"background",targetLc:60},link:{bg:"background",targetLc:75},linkHover:{bg:"linkHoverBg",targetLc:75},actionText:{bg:"actionBackground",targetLc:75},inputCaret:{bg:"layer2",targetLc:60},inputSelection:{bg:"inputSelectionBg",targetLc:60}},z=["background","layer1","layer2","layer3","layer4","actionBackground","actionText","border","shadow","text","typeOverline","typeLabel","typeLead","typeCaption","dangerText","headings","headingsHover","link","linkHover","linkHoverBg","inputCaret","inputSelection","inputSelectionBg"];function mn(e){return typeof e=="string"&&z.includes(e)}const Ht=["typeOverline","typeLabel","typeLead","typeCaption"],Me=["primary","analogous-left","analogous-right","complementary","split-complementary-left","split-complementary-right","triadic-left","triadic-right","danger","success","warning","info"],ee=["danger","success","warning","info"],Dt=["analogous-left","analogous-right","complementary","split-complementary-left","split-complementary-right","triadic-left","triadic-right","danger","success","warning","info"],U=["surface","raised1","raised2","raised3","raised4","accent","muted","text","border","ink","shadow"],Ve="tone:";function Oe(e){if(typeof e!="string"||!e.startsWith(Ve))return null;const n=e.slice(Ve.length);return M(n)&&K.test(n)?n:null}function te(e){return typeof e!="string"?!1:U.includes(e)}function Te(e,n,t){if(te(t))return e[t];const o=Oe(t);return o===null?e.surface:n?.[o]??e.surface}const Ft={surface:.99,raised1:.97,raised2:.9,raised3:.8,raised4:.72,accent:.5,muted:.45,text:.35,border:.3,ink:.25,shadow:.2},Wt={surface:.15,raised1:.2,raised2:.3,raised3:.4,raised4:.36,accent:.6,muted:.75,text:.85,border:.7,ink:.95,shadow:.6},Je={background:{source:"primary",lightness:"surface"},layer1:{source:"primary",lightness:"raised1"},layer2:{source:"primary",lightness:"raised2"},layer3:{source:"primary",lightness:"raised3"},layer4:{source:"primary",lightness:"raised4"},actionBackground:{source:"primary",lightness:"muted"},actionText:{source:"primary",lightness:"ink"},border:{source:"primary",lightness:"border"},shadow:{source:"primary",lightness:"shadow"},text:{source:"primary",lightness:"text"},typeOverline:{source:"primary",lightness:"text"},typeLabel:{source:"primary",lightness:"text"},typeLead:{source:"primary",lightness:"text"},typeCaption:{source:"primary",lightness:"text"},dangerText:{source:"danger",lightness:"text"},headings:{source:"primary",lightness:"muted"},headingsHover:{source:"primary",lightness:"text"},link:{source:"complementary",lightness:"accent"},linkHover:{source:"complementary",lightness:"text"},linkHoverBg:{source:"triadic-left",lightness:"raised2"},inputCaret:{source:"triadic-right",lightness:"ink"},inputSelection:{source:"complementary",lightness:"text"},inputSelectionBg:{source:"triadic-left",lightness:"raised2"}},jt={light:"muted",dark:"raised3"};function Ye(e){return{...Je,actionBackground:{source:"primary",lightness:jt[e]}}}const q=.4;function Ce(){const e={};for(const n of z)e[n]={min:0,max:q};return e}const qe="system-ui, sans-serif",Xe="monospace",Ze={seedColor:"oklch(0.7 0.125 216)",fontBody:qe,fontHeadings:"",fontBrand:"",fontMenu:"",fontMonospace:Xe,fontWeightBody:"normal",fontWeightHeadings:"bold",fontWeightBrand:"bold",fontWeightMenu:"bold",fontWeightMonospace:"normal",stylesheets:[],rootFontSize:16,typeRatio:1.25,spaceRatio:1.618,borderRadius:.2,viewportMin:320,viewportMax:1200,angles:{analogous:30,complementary:180,splitComplementary:30,triadic:120},semanticHues:{danger:27,success:150,warning:90,info:244},variantChroma:{},intents:{},tones:{},chroma:Ce(),semanticMappings:{...Je},explicitMappingTokens:[],anchors:{},roles:{},contexts:{},dataPalette:{...ke},dataRamps:{}},Re={...Ze,chroma:Ce(),semanticMappings:Ye("light"),anchors:{},roles:{},contexts:{},tones:{},dataPalette:{...ke},dataRamps:{},lightness:{...Ft}},Qe={...Ze,chroma:Ce(),semanticMappings:Ye("dark"),anchors:{},roles:{},contexts:{},tones:{},dataPalette:{...ke},dataRamps:{},lightness:{...Wt}},me=new WeakMap;me.set(Re,new Set),me.set(Qe,new Set);function Kt(e,n){return yt.has(e)?void 0:n}function ge(e){const n=e.explicitMappingTokens;if(!Array.isArray(n)||n.some(o=>typeof o!="string"||!z.includes(o)))return;const t=new Set(n);if(t.size===n.length&&!(t.size>0&&(!I(e.semanticMappings)||[...t].some(o=>!Object.prototype.hasOwnProperty.call(e.semanticMappings,o)))))return t}function et(e){return z.filter(n=>e.has(n))}function gn(e){return`--esp-color-${e.replace(/([A-Z])/g,"-$1").replace(/(\d)/g,"-$1").toLowerCase()}`}function zt(e){try{const n=tt(e),t=JSON.parse(n,Kt);return typeof t!="object"||t===null||Array.isArray(t)?null:t}catch{return null}}const ve="\xEF\xBB\xBF";function Ut(e){if(/^[\u0000-\u007f]*$/.test(e))return btoa(e);const n=new TextEncoder().encode(e);let t=ve;for(const o of n)t+=String.fromCharCode(o);return btoa(t)}function tt(e){const n=atob(e);if(!n.startsWith(ve))return n;const t=Uint8Array.from(n.slice(ve.length),o=>o.charCodeAt(0));return new TextDecoder("utf-8",{fatal:!0}).decode(t)}function Ee(e){return Ut(JSON.stringify(e))}function Gt(e){const n={};for(const t of ee){const o=e[t];typeof o=="string"&&(n[t]=o.startsWith("anchor:")?o:ce(o))}return n}function ce(e){if(xt(e))return e;const n=W(e);return n?fe(n):e}function nt(e,n){const t={};for(const[o,i]of Object.entries(e))M(o)&&(t[o]=i);if(!n)return t;for(const[o,i]of Object.entries(n)){if(i===void 0||!M(o))continue;const a=t[o];if(a!==void 0&&typeof i=="object"&&i!==null){const u={};if(typeof a=="string")u.color=a;else for(const[d,m]of Object.entries(a))M(d)&&(u[d]=m);for(const[d,m]of Object.entries(i))m!==void 0&&M(d)&&(u[d]=m);t[o]=u;continue}t[o]=i}return t}function we(e){const n={};if(!I(e))return n;for(const[t,o]of Object.entries(e))M(t)&&K.test(t)&&!te(t)&&typeof o=="number"&&Number.isFinite(o)&&o>=0&&o<=1&&(n[t]=o);return n}function Vt(e,n){return{...we(e),...we(n)}}function Jt(e,n){const t={...e};if(!I(n))return t;for(const o of U){const i=n[o];typeof i=="number"&&Number.isFinite(i)&&i>=0&&i<=1&&(t[o]=i)}return t}function ot(e){if(typeof e!="object"||e===null||Array.isArray(e))return null;const n=e,t={};for(const o of ae){const i=n[o];i!==void 0&&(t[o]=i)}if(typeof n.lightness=="object"&&n.lightness!==null&&!Array.isArray(n.lightness)){const o={};for(const i of U){const a=n.lightness[i];a!==void 0&&(o[i]=a)}t.lightness=o}if(n.tones!==void 0){const o=we(n.tones);Object.keys(o).length>0&&(t.tones=o)}if(typeof n.semanticMappings=="object"&&n.semanticMappings!==null&&!Array.isArray(n.semanticMappings)){const o={};for(const[i,a]of Object.entries(n.semanticMappings)){if(!M(i)||!z.includes(i)||typeof a!="object"||a===null||Array.isArray(a))continue;const{source:u,lightness:d}=a;typeof u=="string"&&(typeof d!="string"||!te(d)&&Oe(d)===null||(o[i]={source:u,lightness:d}))}Object.keys(o).length>0&&(t.semanticMappings=o)}return t}function Yt(e,n){const t={};for(const[o,i]of Object.entries(e)){if(!M(o)||!K.test(o))continue;const a=ot(i);a&&(t[o]=a)}if(!n)return t;for(const[o,i]of Object.entries(n)){if(!M(o)||!K.test(o)||i===void 0)continue;const a=ot(i);if(!a)continue;const u=t[o];t[o]={...u??{},...a,...u?.lightness||a.lightness?{lightness:{...u?.lightness,...a.lightness}}:{},...u?.tones||a.tones?{tones:{...u?.tones,...a.tones}}:{},...u?.semanticMappings||a.semanticMappings?{semanticMappings:{...u?.semanticMappings,...a.semanticMappings}}:{}}}return t}function I(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function j(e){const n={};for(const[t,o]of Object.entries(e))o!==void 0&&M(t)&&(n[t]=o);return n}function st(e){if(!I(e))return e;const n=j(e);return I(e.lightness)&&(n.lightness=j(e.lightness)),I(e.tones)&&(n.tones=j(e.tones)),n}function qt(e,n){const t={};for(const[o,i]of Object.entries(e))M(o)&&(t[o]=st(i));if(!n)return t;for(const[o,i]of Object.entries(n)){if(!M(o)||i===void 0)continue;const a=t[o];if(!I(a)||!I(i)){t[o]=st(i);continue}const u={...j(a),...j(i)};I(a.lightness)&&I(i.lightness)?u.lightness={...j(a.lightness),...j(i.lightness)}:I(i.lightness)&&(u.lightness=j(i.lightness)),I(a.tones)&&I(i.tones)?u.tones={...j(a.tones),...j(i.tones)}:I(i.tones)&&(u.tones=j(i.tones)),I(a.semanticMappings)&&I(i.semanticMappings)?u.semanticMappings={...j(a.semanticMappings),...j(i.semanticMappings)}:I(i.semanticMappings)&&(u.semanticMappings=j(i.semanticMappings)),t[o]=u}return t}function Xt(e){const n={};for(const[t,o]of Object.entries(e)){if(!M(t))continue;if(typeof o=="string"){n[t]=ce(o);continue}const i={};for(const[a,u]of Object.entries(o))M(a)&&(i[a]=typeof u=="string"?ce(u):u);n[t]=i}return n}function ue(e){return typeof e!="string"?"":e.startsWith("anchor:")?e:ce(e)}function Zt(e){const n={};for(const t of pe)n[t]=ue(e[t]);return n}function rt(e,n){const t={};for(const[o,i]of Object.entries(e))M(o)&&K.test(o)&&i&&typeof i=="object"&&!Array.isArray(i)&&(t[o]={...i});if(!n)return t;for(const[o,i]of Object.entries(n)){if(!M(o)||!K.test(o)||!i||typeof i!="object"||Array.isArray(i))continue;const a=t[o],u=a!==void 0&&i.type!==void 0&&i.type!==a.type;t[o]={...u?{}:a??{},...i}}return t}function Qt(e){const n={};for(const[t,o]of Object.entries(e))if(M(t)){if(o.type==="sequential"&&typeof o.source=="string"){n[t]={...o,source:ue(o.source)};continue}if(o.type==="diverging"&&typeof o.start=="string"&&typeof o.end=="string"){n[t]={...o,start:ue(o.start),end:ue(o.end),...typeof o.neutral=="string"?{neutral:ue(o.neutral)}:{}};continue}n[t]={...o}}return n}function it(e){const n=W(e.seedColor);if(!n)return;const t=le(n,e);return(o,i)=>{const a=ie(o,t,e.anchors)??t.primary,u=e.chroma.actionBackground,d=re(a,e.lightness[i],u.min,u.max),m={l:d.l>.5?0:1,c:0,h:0};return Math.abs(se(m,d))}}function at(e){const n=W(e.seedColor);if(!n)return;const t=le(n,e);return(o,i)=>{const a=ie(o,t,e.anchors)??t.primary,u=e.chroma.actionBackground,d=re(a,i,u.min,u.max);return Math.abs(se({l:0,c:0,h:0},d))>=Math.abs(se({l:1,c:0,h:0},d))?"dark":"light"}}function en(e,n,t){if(n?.background)return n.background;const o=Y(e.canvas,"color");if(o!==void 0){const i=de.canvas.color?.find(([a])=>a==="background");if(i)return{source:o,lightness:i[1]}}return t.background}function ct(e,n){const t=W(e.seedColor);if(!t||!n)return;const o=le(t,e),i=ie(n.source,o,e.anchors)??o.primary,a=e.chroma.background,u=re(i,Te(e.lightness,e.tones,n.lightness),a.min,a.max);return(d,m)=>{const x=ie(d,o,e.anchors)??o.primary,b=e.chroma.actionBackground,S=re(x,e.lightness[m],b.min,b.max);return bt(S,u)}}function tn(e){const n=me.get(e);if(n)return new Set(n);const t=ge(e);if(t)return t;const o=new Set,i=Ue(e.roles,e.lightness,e.semanticMappings,{tones:e.tones,actionSurfaceContrast:it(e),actionSurfacePole:at(e),actionSurfaceSeparation:ct(e,e.semanticMappings.background)});for(const[a,u]of Object.entries(i)){const d=e.semanticMappings[a];(d.source!==u.source||d.lightness!==u.lightness)&&o.add(a)}return o}function he(e,n){const t={...e.roles,...n.roles},o=Yt(e.contexts,n.contexts),i=Jt(e.lightness,n.lightness),a=Vt(e.tones,n.tones),u=Xt(nt(e.anchors,n.anchors)),d=typeof n.seedColor=="string"?ce(n.seedColor):e.seedColor,m=n.semanticMappings,x={...e.angles,...n.angles},b={...e.semanticHues,...n.semanticHues},S={...e.variantChroma,...n.variantChroma},A=Gt({...e.intents,...n.intents}),D=n.chroma,F=ne(e.chroma,D),L=Zt(ne(e.dataPalette,n.dataPalette)),s=Qt(rt(e.dataRamps,n.dataRamps)),r=tn(e),c=new Set(r),f=ge(n),p={};for(const y of r)p[y]=e.semanticMappings[y];for(const[y,_]of Object.entries(m??{}))_!==void 0&&(f===void 0||f.has(y)?(c.add(y),p[y]=_):(c.delete(y),delete p[y]));const g=ne(e.semanticMappings,p),l={angles:x,anchors:u,chroma:F,intents:A,lightness:i,tones:a,seedColor:d,semanticHues:b,variantChroma:S},h=it(l),k=at(l),$=ct(l,en(t,p,g)),R=Ue(t,i,g,{explicitMappings:p,tones:a,actionSurfaceContrast:h,actionSurfacePole:k,actionSurfaceSeparation:$}),O={};for(const[y,_]of Object.entries(R))c.has(y)||(O[y]=_);const v={};for(const y of Ht)!c.has(y)&&O[y]===void 0&&(v[y]={source:g.text.source,lightness:g.text.lightness},D?.text!==void 0&&D[y]===void 0&&(F[y]={...F.text}));const E=ne(ne(ne(e.semanticMappings,v),O),p),T={...e,seedColor:d,fontBody:n.fontBody||e.fontBody||qe,fontHeadings:n.fontHeadings??e.fontHeadings,fontBrand:n.fontBrand??e.fontBrand,fontMenu:n.fontMenu??e.fontMenu,fontMonospace:n.fontMonospace||e.fontMonospace||Xe,fontWeightBody:String(n.fontWeightBody??e.fontWeightBody),fontWeightHeadings:String(n.fontWeightHeadings??e.fontWeightHeadings),fontWeightBrand:String(n.fontWeightBrand??e.fontWeightBrand),fontWeightMenu:String(n.fontWeightMenu??e.fontWeightMenu),fontWeightMonospace:String(n.fontWeightMonospace??e.fontWeightMonospace),stylesheets:n.stylesheets??[...e.stylesheets],rootFontSize:n.rootFontSize??e.rootFontSize,typeRatio:n.typeRatio??e.typeRatio,spaceRatio:n.spaceRatio??e.spaceRatio,borderRadius:n.borderRadius??e.borderRadius,viewportMin:n.viewportMin??e.viewportMin,viewportMax:n.viewportMax??e.viewportMax,angles:x,semanticHues:b,variantChroma:S,intents:A,lightness:i,tones:a,chroma:F,semanticMappings:E,explicitMappingTokens:et(c),anchors:u,roles:t,contexts:o,dataPalette:L,dataRamps:s};return n.pageBackgroundImage!==void 0&&(T.pageBackgroundImage=n.pageBackgroundImage),n.pageBackgroundImageOpacity!==void 0&&(T.pageBackgroundImageOpacity=n.pageBackgroundImageOpacity),n.boxBackgroundImage!==void 0&&(T.boxBackgroundImage=n.boxBackgroundImage),n.boxBackgroundImageOpacity!==void 0&&(T.boxBackgroundImageOpacity=n.boxBackgroundImageOpacity),n.vellumOpacity!==void 0&&(T.vellumOpacity=n.vellumOpacity),n.vellumBackgroundImage!==void 0&&(T.vellumBackgroundImage=n.vellumBackgroundImage),n.vellumBackgroundImageOpacity!==void 0&&(T.vellumBackgroundImageOpacity=n.vellumBackgroundImageOpacity),me.set(T,new Set(c)),T}const ut=new WeakMap;function ft(e,n){const t=e.contexts&&Object.prototype.hasOwnProperty.call(e.contexts,n)?e.contexts[n]:void 0;if(!t)return null;let o=ut.get(e);const i=o?.get(n);if(i)return i;const a={};for(const d of ae){const m=t[d];m!==void 0&&(a[d]=m)}const u=he(e,{lightness:t.lightness,tones:t.tones,roles:a,semanticMappings:t.semanticMappings});return o||(o=new Map,ut.set(e,o)),o.set(n,u),u}function ne(e,n){if(!n)return{...e};const t={...e};for(const o of Object.keys(n)){const i=n[o];i!==void 0&&(t[o]=i)}return t}function Be(e){let n;try{n=tt(e)}catch{return{error:"Failed to decode Base64 string."}}let t;try{t=JSON.parse(n)}catch{return{error:"Decoded string is not valid JSON."}}return typeof t!="object"||t===null||Array.isArray(t)?{error:"Theme must be a JSON object."}:{value:t}}function hn(e){const n=Be(e);return n.error!==void 0?{valid:!1,errors:[n.error],warnings:[]}:_e(n.value)}function _e(e,n=Re){const t=[],o=[];"seedColor"in e&&(typeof e.seedColor!="string"?t.push("seedColor must be a string."):W(e.seedColor)||t.push(`seedColor is not a valid CSS color: "${e.seedColor}". Accepted forms: ${oe}.`));for(const s of["fontBody","fontHeadings","fontBrand","fontMenu","fontMonospace"])s in e&&typeof e[s]!="string"&&t.push(`${s} must be a string.`);const i=["normal","bold","lighter","bolder"],a=["inherit","initial","unset","revert","revert-layer"];for(const s of["fontWeightBody","fontWeightHeadings","fontWeightBrand","fontWeightMenu","fontWeightMonospace"])if(s in e){const r=e[s];if(typeof r=="number")(r<1||r>1e3)&&t.push(`${s} numeric value must be 1\u20131000 (got ${r}).`);else if(typeof r=="string"){const c=i.includes(r)||a.includes(r);if(/^\d+$/.test(r)){const p=Number(r);(p<1||p>1e3)&&t.push(`${s} numeric value must be 1\u20131000 (got "${r}").`)}else c||o.push(`${s} = "${r}" is not a standard font-weight value.`)}else t.push(`${s} must be a string or number.`)}"stylesheets"in e&&(Array.isArray(e.stylesheets)?e.stylesheets.some(s=>typeof s!="string")&&t.push("Every entry in stylesheets must be a string."):t.push("stylesheets must be an array of strings."));const u=[["rootFontSize",1,100],["borderRadius",0,10],["viewportMin",100,1e4],["viewportMax",200,1e4]];for(const[s,r,c]of u)if(s in e)if(typeof e[s]!="number"||!isFinite(e[s]))t.push(`${s} must be a finite number.`);else{const f=e[s];r!==void 0&&f<r&&t.push(`${s} must be \u2265 ${r} (got ${f}).`),c!==void 0&&f>c&&o.push(`${s} = ${f} is unusually high (max ${c}).`)}for(const s of["typeRatio","spaceRatio"])if(s in e)if(typeof e[s]!="number"||!isFinite(e[s]))t.push(`${s} must be a finite number.`);else{const r=e[s];r<=1&&t.push(`${s} must be > 1 (got ${r}).`);const c=s==="typeRatio"?1.3:2;r>c&&o.push(`${s} = ${r} is very high (max ${c}); scales may be extreme.`)}if("viewportMin"in e&&"viewportMax"in e){const s=e.viewportMin,r=e.viewportMax;typeof s=="number"&&typeof r=="number"&&s>=r&&t.push(`viewportMin (${s}) must be less than viewportMax (${r}).`)}if("angles"in e)if(typeof e.angles!="object"||e.angles===null)t.push("angles must be an object.");else{const s=e.angles;for(const r of["analogous","complementary","splitComplementary","triadic"])if(r in s)if(typeof s[r]!="number"||!isFinite(s[r]))t.push(`angles.${r} must be a finite number.`);else{const c=s[r];(c<0||c>360)&&o.push(`angles.${r} = ${c} is outside 0\u2013360.`)}}if("semanticHues"in e)if(typeof e.semanticHues!="object"||e.semanticHues===null)t.push("semanticHues must be an object.");else{const s=e.semanticHues;for(const r of["danger","success","warning","info"])if(r in s)if(typeof s[r]!="number"||!isFinite(s[r]))t.push(`semanticHues.${r} must be a finite number.`);else{const c=s[r];(c<0||c>360)&&o.push(`semanticHues.${r} = ${c} is outside 0\u2013360.`)}}if("variantChroma"in e)if(typeof e.variantChroma!="object"||e.variantChroma===null)t.push("variantChroma must be an object.");else{const s=e.variantChroma;for(const r of Dt)if(r in s)if(typeof s[r]!="number"||!isFinite(s[r]))t.push(`variantChroma["${r}"] must be a finite number.`);else{const c=s[r];c<0&&t.push(`variantChroma["${r}"] must be \u2265 0 (got ${c}).`),c>q&&o.push(`variantChroma["${r}"] = ${c} exceeds ${q}.`)}}function d(s,r){if(typeof s!="object"||s===null||Array.isArray(s)){t.push(`${r} must be an object.`);return}const c=s;for(const f of Object.keys(c))(!M(f)||!te(f))&&t.push(`${r}.${f} is not a built-in lightness stop; expected one of: ${U.join(", ")}.`);for(const f of U)if(f in c)if(typeof c[f]!="number"||!isFinite(c[f]))t.push(`${r}.${f} must be a finite number.`);else{const p=c[f];(p<0||p>1)&&t.push(`${r}.${f} must be 0\u20131 (got ${p}).`)}}"lightness"in e&&d(e.lightness,"lightness");function m(s,r){const c=new Set;if(!I(s))return t.push(`${r} must be an object.`),c;for(const[f,p]of Object.entries(s)){if(!M(f)||!K.test(f)){t.push(`${r}.${f} must be a lowercase slug matching ${K.source}.`);continue}if(te(f)){t.push(`${r}.${f} conflicts with the built-in "${f}" lightness stop; choose a distinct custom tone name.`);continue}c.add(f),typeof p!="number"||!Number.isFinite(p)?t.push(`${r}.${f} must be a finite number.`):(p<0||p>1)&&t.push(`${r}.${f} must be 0\u20131 (got ${p}).`)}return c}const x=new Set(Object.keys(n.tones??{}));if("tones"in e)for(const s of m(e.tones,"tones"))x.add(s);if("chroma"in e)if(typeof e.chroma!="object"||e.chroma===null)t.push("chroma must be an object.");else{const s=e.chroma,r=Pt(e,n);for(const c of z)if(c in s){const f=s[c];if(typeof f!="object"||f===null){t.push(`chroma.${c} must be { min, max }.`);continue}const p=f;for(const l of r.get(c)??[])l.chroma!==void 0&&typeof p.min=="number"&&typeof p.max=="number"&&(l.chroma<p.min-1e-9||l.chroma>p.max+1e-9)&&o.push(`chroma.${c} clamps the anchor-sourced token ${c} ("${l.source}", effective in ${l.where}) and moves it off its declared swatch. Remove the band if that is unintended \u2014 anchors otherwise keep their own chroma.`);const g=f;(typeof g.min!="number"||g.min<0)&&t.push(`chroma.${c}.min must be \u2265 0.`),(typeof g.max!="number"||g.max<0||g.max>q)&&t.push(`chroma.${c}.max must be 0\u2013${q}.`),typeof g.min=="number"&&typeof g.max=="number"&&g.min>g.max&&t.push(`chroma.${c}.min (${g.min}) must be \u2264 max (${g.max}).`)}}if("anchors"in e)if(typeof e.anchors!="object"||e.anchors===null||Array.isArray(e.anchors))t.push("anchors must be an object of named colors.");else for(const[s,r]of Object.entries(e.anchors))if(M(s)?K.test(s)||t.push(`anchors: "${s}" is not a valid anchor name; use a lowercase slug (letters, digits, hyphens).`):t.push(`anchors: "${s}" is a reserved JavaScript property name and cannot be an anchor name; rename it.`),Me.includes(s)&&t.push(`anchors: "${s}" collides with a reserved color source name.`),typeof r=="string")W(r)||t.push(`anchors.${s} is not a valid CSS color: "${r}". Accepted forms: ${oe}.`);else if(typeof r=="object"&&r!==null&&!Array.isArray(r)){const c=r;typeof c.color!="string"&&t.push(`anchors.${s} must declare its base "color".`);for(const[f,p]of Object.entries(c))M(f)?f!=="color"&&!K.test(f)&&t.push(`anchors.${s}: "${f}" is not a valid slot name; use a lowercase slug.`):t.push(`anchors.${s}: "${f}" is a reserved JavaScript property name and cannot be a slot name; rename it.`),typeof p!="string"?t.push(`anchors.${s}.${f} must be a CSS color string.`):W(p)||t.push(`anchors.${s}.${f} is not a valid CSS color: "${p}". Accepted forms: ${oe}.`)}else t.push(`anchors.${s} must be a color string or a { color, \u2026slots } object.`);const b=new Map;if("anchors"in e&&typeof e.anchors=="object"&&e.anchors!==null&&!Array.isArray(e.anchors))for(const[s,r]of Object.entries(e.anchors))b.set(s,r);function S(s,r){const c=Ae(s);if(!c){t.push(`${r} "${s}" is not valid anchor syntax; use anchor:<name> or anchor:<name>.<slot>.`);return}if(!b.has(c.name)){const f=[...b.keys()];t.push(`${r} references undeclared anchor "${c.name}". Declared anchors: ${f.length>0?f.join(", "):"(none)"}.`);return}if(c.slot!==void 0){const f=b.get(c.name);if(typeof(typeof f=="object"&&f!==null&&!Array.isArray(f)?f[c.slot]:void 0)!="string"){const g=typeof f=="object"&&f!==null?Object.keys(f).filter(l=>l!=="color"):[];t.push(`${r} references unknown slot "${c.slot}" on anchor "${c.name}". Declared slots: ${g.length>0?g.join(", "):"(none)"}.`)}}}function A(s,r){if(s.startsWith("anchor:")){S(s,r);return}Me.includes(s)||t.push(`${r} must be one of: ${Me.join(", ")}, or a declared anchor as anchor:<name> / anchor:<name>.<slot>.`)}if("intents"in e)if(typeof e.intents!="object"||e.intents===null||Array.isArray(e.intents))t.push("intents must be an object.");else for(const[s,r]of Object.entries(e.intents)){const c=`intents.${s}`;if(!ee.includes(s)){t.push(`${c} is not a status family; expected one of: ${ee.join(", ")}.`);continue}if(typeof r!="string"){t.push(`${c} must be a string (a CSS color or an anchor: reference).`);continue}if(r.startsWith("anchor:")){S(r,c);continue}W(r)||t.push(`${c} "${r}" is not a supported color form or anchor: reference. Accepted forms: ${oe}, or anchor:<name> / anchor:<name>.<slot>. An override retunes a family with a declared color; it never points one family at another \u2014 retune, never reassign.`)}function D(s,r){if(s.startsWith("anchor:")){S(s,r);return}W(s)||t.push(`${r} is not a valid CSS color: "${s}". Accepted forms: ${oe}, or a declared anchor as anchor:<name> / anchor:<name>.<slot>.`)}if("dataPalette"in e)if(typeof e.dataPalette!="object"||e.dataPalette===null||Array.isArray(e.dataPalette))t.push("dataPalette must be an object with series1\u2013series8 color values.");else{const s=e.dataPalette;for(const[r,c]of Object.entries(s)){if(!pe.includes(r)){t.push(`dataPalette.${r} is not a series slot; expected one of: ${pe.join(", ")}.`);continue}typeof c!="string"?t.push(`dataPalette.${r} must be a CSS color or anchor reference string.`):D(c,`dataPalette.${r}`)}}if("dataRamps"in e)if(typeof e.dataRamps!="object"||e.dataRamps===null||Array.isArray(e.dataRamps))t.push("dataRamps must be an object of named ramp declarations.");else for(const[s,r]of Object.entries(e.dataRamps)){if(M(s)?K.test(s)||t.push(`dataRamps: "${s}" is not a valid ramp name; use a lowercase slug (letters, digits, hyphens).`):t.push(`dataRamps: "${s}" is a reserved JavaScript property name and cannot be a ramp name; rename it.`),typeof r!="object"||r===null||Array.isArray(r)){t.push(`dataRamps.${s} must be a sequential or diverging ramp object.`);continue}const c=r,f=c.steps??Ct;if((typeof f!="number"||!Number.isInteger(f)||f<Se||f>xe)&&t.push(`dataRamps.${s}.steps must be an integer from ${Se} through ${xe}.`),c.type==="sequential"){typeof c.source!="string"?t.push(`dataRamps.${s}.source must be a CSS color or anchor reference string.`):D(c.source,`dataRamps.${s}.source`);const p=c.lightnessStart??.95,g=c.lightnessEnd??.25;for(const[l,h]of[["lightnessStart",p],["lightnessEnd",g]])(typeof h!="number"||!Number.isFinite(h)||h<0||h>1)&&t.push(`dataRamps.${s}.${l} must be a finite number from 0 through 1.`);typeof p=="number"&&typeof g=="number"&&p<=g?t.push(`dataRamps.${s}.lightnessStart must be greater than lightnessEnd.`):typeof p=="number"&&Number.isFinite(p)&&typeof g=="number"&&Number.isFinite(g)&&typeof f=="number"&&Number.isInteger(f)&&f>=Se&&f<=xe&&(p-g)/(f-1)<=We&&t.push(`dataRamps.${s} lightness bounds must leave more than ${We} lightness between serialized stops.`);continue}if(c.type==="diverging"){typeof f=="number"&&Number.isInteger(f)&&f%2===0&&t.push(`dataRamps.${s}.steps must be odd so the neutral is the exact midpoint.`);for(const p of["start","end"])typeof c[p]!="string"?t.push(`dataRamps.${s}.${p} must be a CSS color or anchor reference string.`):D(c[p],`dataRamps.${s}.${p}`);"neutral"in c&&(typeof c.neutral!="string"?t.push(`dataRamps.${s}.neutral must be a CSS color or anchor reference string.`):D(c.neutral,`dataRamps.${s}.neutral`));continue}t.push(`dataRamps.${s}.type must be "sequential" or "diverging".`)}if("dataPalette"in e&&t.length===0){const s=he(Re,e),r={};let c=!0;for(const f of pe){const p=Rt(s.dataPalette[f],s.anchors);if(!p){c=!1;break}r[f]=p}if(c)for(const f of Ot(r))o.push(Tt(f))}function F(s,r){if(typeof s!="object"||s===null||Array.isArray(s)){t.push(`${r} must be an object.`);return}const c=s;for(const[f,p]of Object.entries(c)){const g=`${r}.${f}`;if(!ae.includes(f)){t.push(`${g} is not a role; expected one of: ${ae.join(", ")}. (The status family is reserved and is not a role.)`);continue}const l=f,h=de[l];if(typeof p=="string"){A(p,g);continue}if(typeof p!="object"||p===null||Array.isArray(p)){t.push(`${g} must be a color source or a { color, \u2026slots } object.`);continue}const k=p;typeof k.color!="string"&&t.push(`${g} must declare its base "color".`);for(const[$,R]of Object.entries(k)){if(!Object.prototype.hasOwnProperty.call(h,$)||!M($)){const O=Object.keys(h).filter(v=>v!=="color");t.push(`${g}.${$} is not a slot of the ${l} role. Declared slots: ${O.length>0?O.join(", "):"(none)"}.`);continue}typeof R!="string"?t.push(`${g}.${$} must be a color source string.`):A(R,`${g}.${$}`)}}}if("roles"in e&&F(e.roles,"roles"),"contexts"in e)if(typeof e.contexts!="object"||e.contexts===null||Array.isArray(e.contexts))t.push("contexts must be an object.");else for(const[s,r]of Object.entries(e.contexts)){if(!M(s)||!K.test(s)){t.push(`contexts.${s} must be a lowercase slug matching ${K.source}.`);continue}if(typeof r!="object"||r===null||Array.isArray(r)){F(r,`contexts.${s}`);continue}const c=r,f=Object.fromEntries(Object.entries(c).filter(([g])=>g!=="lightness"&&g!=="tones"&&g!=="semanticMappings"));F(f,`contexts.${s}`),"lightness"in c&&d(c.lightness,`contexts.${s}.lightness`);const p=new Set(x);if("tones"in c)for(const g of m(c.tones,`contexts.${s}.tones`))p.add(g);"semanticMappings"in c&&L(c.semanticMappings,`contexts.${s}.semanticMappings`,p)}function L(s,r,c){if(typeof s!="object"||s===null||Array.isArray(s)){t.push(`${r} must be an object.`);return}const f=s;for(const p of Object.keys(f))z.includes(p)||t.push(`${r}.${p} is not a semantic token; expected one of: ${z.join(", ")}.`);for(const p of z)if(p in f){const g=f[p];if(typeof g!="object"||g===null){t.push(`${r}.${p} must be { source, lightness }.`);continue}const l=g;if(typeof l.source!="string"?t.push(`${r}.${p}.source must be a string.`):A(l.source,`${r}.${p}.source`),typeof l.lightness!="string")t.push(`${r}.${p}.lightness must be one of: ${U.join(", ")}, or a declared tone:<name>.`);else if(!te(l.lightness)){const h=Oe(l.lightness);if(h===null)t.push(`${r}.${p}.lightness must be one of: ${U.join(", ")}, or a declared tone:<name>.`);else if(!c.has(h)){const k=[...c].sort();t.push(`${r}.${p}.lightness references undeclared tone "${h}". Declared tones: ${k.length>0?k.join(", "):"(none)"}.`)}}}}if("semanticMappings"in e&&L(e.semanticMappings,"semanticMappings",x),"explicitMappingTokens"in e)if(!Array.isArray(e.explicitMappingTokens))t.push("explicitMappingTokens must be an array of semantic token names.");else{const s=new Set,r=I(e.semanticMappings)?e.semanticMappings:void 0;for(const c of e.explicitMappingTokens){if(typeof c!="string"||!z.includes(c)){t.push(`explicitMappingTokens entries must be one of: ${z.join(", ")}.`);continue}s.has(c)&&t.push(`explicitMappingTokens contains duplicate token "${c}".`),s.add(c),(!r||!Object.prototype.hasOwnProperty.call(r,c))&&t.push(`explicitMappingTokens names "${c}" without a semanticMappings entry.`)}}for(const s of["pageBackgroundImage","boxBackgroundImage","vellumBackgroundImage"])s in e&&typeof e[s]!="string"&&t.push(`${s} must be a string.`);for(const s of["pageBackgroundImageOpacity","boxBackgroundImageOpacity","vellumOpacity","vellumBackgroundImageOpacity"])if(s in e)if(typeof e[s]!="number"||!isFinite(e[s]))t.push(`${s} must be a finite number.`);else{const r=e[s];(r<0||r>1)&&t.push(`${s} must be 0\u20131 (got ${r}).`)}return o.push(...nn(e,n)),{valid:t.length===0,errors:t,warnings:o}}const B=.045;function nn(e,n){try{return on(e,n)}catch{return[]}}function on(e,n){const t=he(n,e),o=dt(t),i=[...o],a=new Set(o);for(const u of Object.keys(t.contexts)){const d=ft(t,u);if(d)for(const m of dt(d))a.has(m)||i.push(`contexts.${u}: ${m}`)}return i}function sn(e){const n=kt($e(e)),t=St(n);return $t({r:be(t.r),g:be(t.g),b:be(t.b)})}function Z(e,n){return Math.hypot(e.L-n.L,e.a-n.a,e.b-n.b)}function X(e){return sn(W(fe($e(e))))}function lt(e){return(Math.floor(e*1e4)/1e4).toFixed(4)}const Q=2,pt=1e-4;function dt(e){const n=W(e.seedColor);if(!n)return[];const t=le(n,e),o=e.semanticMappings.actionBackground,i=e.chroma.actionBackground,a=Te(e.lightness,e.tones,o.lightness),u=(l,h,k,$)=>$e(re(l,h,k,$)),d=ee.map(l=>({name:l,base:t[l]})),m=[];if(ee.includes(o.source))m.push(`actionBackground is sourced from the "${o.source}" status family: ordinary and ${o.source}-intent action surfaces render identically (their labels may still differ). Remap the action to a non-status source \u2014 retuning "${o.source}" via intents moves both colors together.`);else{const l=ie(o.source,t,e.anchors);l&&d.push({name:"action",base:l})}const x=Fe(d.map(({name:l,base:h})=>[l,fe(u(h,a,i.min,i.max))]),B,["normal"]);if(x.length===0)return m;const b=new Map,S=(l,h)=>{const k=`${l}:${h}`;let $=b.get(k);if(!$){$=[];for(let R=0;R<360;R+=Q)$.push(X({l,c:h,h:R}));b.set(k,$)}return $},A=B-.002,D=(l,h,k,$)=>{const R=Math.hypot(l.a,l.b),O=Math.atan2(l.b,l.a)*180/Math.PI+180;let v=0;for(const E of k===$?[$]:[k,$]){if(E+R<B-1e-4)continue;let T=O,y=Z(X({l:h,c:E,h:O}),l);if(y>=B)return y;const _=S(h,E);for(let w=0;w<_.length;w+=1){const C=Z(_[w],l);if(C>=B)return C;C>y&&(y=C,T=w*Q)}let H=T;for(let w=T-Q;w<=T+Q;w+=.1){const C=Z(X({l:h,c:E,h:w}),l);if(C>=B)return C;C>y&&(y=C,H=w)}if(y>=A)for(let w=H-.1;w<=H+.1;w+=.001){const C=Z(X({l:h,c:E,h:w}),l);if(C>=B)return C;C>y&&(y=C)}y>v&&(v=y)}return v},F=(l,h,k)=>{const $=h===k?[k]:[h,k];let R=0;for(const O of $)for(const v of $){if(O+v<B-1e-4)continue;const E=S(l,O),T=S(l,v);let y=0,_=0,H=-1;for(let P=0;P<E.length;P+=1)for(let G=0;G<T.length;G+=1){const V=Z(E[P],T[G]);if(V>=B)return V;V>H&&(H=V,y=P*Q,_=G*Q)}const w=(P,G,V,Le)=>{const Ie=[];for(let J=G-V;J<=G+V;J+=Le)Ie.push({h:J,lab:X({l,c:v,h:J})});let ye=-1,Ne=P,Pe=G;for(let J=P-V;J<=P+V;J+=Le){const ht=X({l,c:O,h:J});for(const He of Ie){const De=Z(ht,He.lab);De>ye&&(ye=De,Ne=J,Pe=He.h)}}return{distance:ye,hueA:Ne,hueB:Pe}},C=w(y,_,Q,.1);if(C.distance>=B)return C.distance;let N=Math.max(H,C.distance);if(N>=A){const P=w(C.hueA,C.hueB,.1,.001);if(P.distance>N&&(N=P.distance),N>=B)return N}N>R&&(R=N)}return R},L=l=>ee.includes(l),s=(l,h,k,$,R)=>{const O=X(u(l.base,k,$,R)),v=X(u(h.base,k,$,R));if(Z(O,v)>=B)return{outcome:"direct"};const E=L(l.name)&&L(h.name),T=[l,h].filter(H=>L(H.name)),y=E?"one of them":`"${L(l.name)?l.name:h.name}"`;let _;for(const H of T){const w=D(H===l?v:O,k,$,R);if(w>=B)return{outcome:"retune",target:y};w>=B-pt&&(_=_??y)}if(E){const H=F(k,$,R);if(H>=B)return{outcome:"retune",target:"both"};H>=B-pt&&(_=_??"both")}return _!==void 0?{outcome:"near",target:_}:{outcome:"no"}},r=l=>l.outcome==="direct"?4:l.outcome==="retune"?l.target==="both"?2:3:l.outcome==="near"?1:0,c=l=>[...l].sort().join("|"),f=new Set(Fe(d.map(({name:l,base:h})=>[l,fe(u(h,a,0,q))]),B,["normal"]).map(l=>c(l.pair))),p=new Map(d.map(l=>[l.name,l])),g=new Map;for(const{pair:l,distance:h}of x){const k=p.get(l[0]),$=p.get(l[1]),R=L(k.name)&&L($.name),O=s(k,$,a,i.min,i.max);if(O.outcome==="direct"||O.outcome==="retune"){const N=O.target??(R?"one of them":`"${L(k.name)?k.name:$.name}"`);f.has(c(l))?m.push(`Status colors "${l[0]}" and "${l[1]}" are hard to distinguish under normal vision (distance ${lt(h)} < ${B}); status meanings must stay distinguishable \u2014 retune ${N} via intents.`):m.push(`Status colors "${l[0]}" and "${l[1]}" are hard to distinguish as rendered (distance ${lt(h)} < ${B}); the actionBackground chroma band ({ min: ${i.min}, max: ${i.max} }) pushes them together \u2014 widen the band, or retune ${N} via intents.`);continue}const v=s(k,$,a,0,q);let E={outcome:"no"};for(let N=1;N<=19&&E.outcome!=="direct";N+=1){const P=N*.05;if(Math.abs(P-a)<.001)continue;const G=s(k,$,P,i.min,i.max);r(G)>r(E)&&(E=G)}let T={outcome:"no"};const y=v.outcome==="direct"||v.outcome==="retune",_=E.outcome==="direct"||E.outcome==="retune";if(!y&&!_)for(let N=1;N<=19&&T.outcome!=="direct";N+=1){const P=s(k,$,N*.05,0,q);r(P)>r(T)&&(T=P)}const H=rn(v,E,T),w=`${O.outcome}|${H}`;let C=g.get(w);C||(C=[],g.set(w,C)),C.push(l)}for(const[l,h]of g){const k=l.indexOf("|"),$=l.slice(0,k),R=l.slice(k+1),O=h.map(([T,y])=>`"${T}"/"${y}"`),v=O.length>1?`${O.slice(0,-1).join(", ")} and ${O[O.length-1]}`:O[0],E=$==="near"?`Status colors ${v} may not separate by retuning as rendered: at the action stop's lightness (${a}) with the actionBackground chroma band ({ min: ${i.min}, max: ${i.max} }), the closest reachable retune found comes within the audit's search margin of the ${B} threshold`:`Status colors ${v} cannot be separated as rendered: at the action stop's lightness (${a}) with the actionBackground chroma band ({ min: ${i.min}, max: ${i.max} }), no intent retuning can pull ${h.length>1?"these pairs":"the pair"} ${B} apart`;m.push(E+R)}return m}function rn(e,n,t){if(e.outcome==="direct"&&n.outcome==="direct")return" \u2014 widen the chroma band or move the action lightness stop.";if(e.outcome==="direct")return n.outcome==="no"?"; no other action lightness stop can help while the band holds \u2014 widen the chroma band.":" \u2014 widen the chroma band.";if(n.outcome==="direct")return e.outcome==="no"?"; no wider chroma band can help at this lightness \u2014 move the action lightness stop.":" \u2014 move the action lightness stop.";if(e.outcome==="retune"&&n.outcome==="retune")return` \u2014 widen the chroma band or move the action lightness stop, then retune ${e.target} via intents.`;if(e.outcome==="retune")return n.outcome==="no"?`; no other action lightness stop can help while the band holds \u2014 widen the chroma band, then retune ${e.target} via intents.`:` \u2014 widen the chroma band, then retune ${e.target} via intents.`;if(n.outcome==="retune")return e.outcome==="no"?`; no wider chroma band can help at this lightness \u2014 move the action lightness stop, then retune ${n.target} via intents.`:` \u2014 move the action lightness stop, then retune ${n.target} via intents.`;const o=e.outcome==="no"&&n.outcome==="no"?"; neither a wider chroma band alone nor another stop alone can help":"; neither a wider chroma band alone nor another stop alone provably helps";return t.outcome==="direct"?`${o} \u2014 change the band and the stop together.`:t.outcome==="retune"?`${o} \u2014 change the band and the stop together, then retune ${t.target} via intents.`:"; no explored band or stop change provably separates this pair."}function yn(e,n){const t=Be(e),o=Be(n),i=t.error!==void 0?{valid:!1,errors:[t.error],warnings:[]}:_e(t.value),a=o.error!==void 0?{valid:!1,errors:[o.error],warnings:[]}:_e(o.value,Qe),u=[...i.errors.map(m=>`light: ${m}`),...a.errors.map(m=>`dark: ${m}`)],d=[...i.warnings.map(m=>`light: ${m}`),...a.warnings.map(m=>`dark: ${m}`)];if(i.valid&&a.valid){const m=new Set(Object.keys(t.value?.contexts??{})),x=new Set(Object.keys(o.value?.contexts??{})),b=[...x].filter(A=>!m.has(A)).sort(),S=[...m].filter(A=>!x.has(A)).sort();(b.length>0||S.length>0)&&u.push(`contexts must declare the same names in both schemes. Missing from light: ${b.join(", ")||"(none)"}. Missing from dark: ${S.join(", ")||"(none)"}.`)}return{valid:u.length===0,errors:u,warnings:d}}const an=["anchors","angles","contexts","dataPalette","dataRamps","intents","roles","chroma","lightness","tones","semanticHues","semanticMappings","variantChroma"];function cn(e,n){const t={};for(const[a,u]of Object.entries(e))M(a)&&(t[a]=u);for(const[a,u]of Object.entries(n))u!==void 0&&M(a)&&(t[a]=u);for(const a of an){const u=e[a],d=n[a];if(u&&typeof u=="object"&&!Array.isArray(u)&&d&&typeof d=="object"&&!Array.isArray(d)){if(a==="anchors"){t[a]=nt(u,d);continue}if(a==="contexts"){t[a]=qt(u,d);continue}if(a==="dataRamps"){t[a]=rt(u,d);continue}const m={};for(const[x,b]of Object.entries(u))M(x)&&(m[x]=b);for(const[x,b]of Object.entries(d))b!==void 0&&M(x)&&(m[x]=b);t[a]=m}}const o=ge(e),i=ge(n);if(o!==void 0||i!==void 0){const a=o??new Set(Object.keys(e.semanticMappings??{}).filter(u=>z.includes(u)));for(const u of Object.keys(n.semanticMappings??{}))i===void 0||i.has(u)?a.add(u):a.delete(u);t.explicitMappingTokens=et(a)}return t}function bn(...e){let n={};for(const t of e){if(!t)continue;const o=zt(t);o&&(n=cn(n,o))}return Ee(n)}function mt(e){return e.replace(/\\/g,"\\\\").replace(/"/g,'\\"').replace(/\n/g,"\\n").replace(/\r/g,"\\r")}const gt={borderRadius:.1,fontBody:'"Noto Sans", sans-serif',fontWeightBody:"normal",fontHeadings:'"Inika", serif',fontWeightHeadings:"normal",fontBrand:'"Inika", serif',fontWeightBrand:"normal",fontMonospace:'"JetBrains Mono", monospace',fontWeightMonospace:"normal",seedColor:"oklch(.07 0.15 216)"};function $n(e){return Ee({...gt,pageBackgroundImage:`url("${mt(e)}")`,pageBackgroundImageOpacity:.5})}function kn(e){return Ee({...gt,pageBackgroundImage:`url("${mt(e)}")`,pageBackgroundImageOpacity:.55})}export{K as ANCHOR_SLUG_PATTERN,Me as COLOR_SOURCES,qe as DEFAULT_BODY_FONT_FAMILY,Wt as DEFAULT_DARK_LIGHTNESS,Qe as DEFAULT_DARK_THEME,Ft as DEFAULT_LIGHT_LIGHTNESS,Re as DEFAULT_LIGHT_THEME,Xe as DEFAULT_MONOSPACE_FONT_FAMILY,Je as DEFAULT_SEMANTIC_MAPPINGS,U as LIGHTNESS_KEYS,an as NESTED_THEME_KEYS,Et as ROLE_DERIVED_INK,ae as ROLE_NAMES,Ke as ROLE_PAIRED_INK,de as ROLE_TOKEN_PLAN,z as SEMANTIC_COLOR_NAMES,ee as STATUS_COLOR_SOURCES,Ge as TOKEN_PAIRINGS,Dt as VARIANT_COLOR_SOURCES,kn as buildTaprootDarkTheme,$n as buildTaprootLightTheme,Ue as compileRoles,Ee as encodeTheme,tn as explicitMappingTokens,te as isLightnessKey,I as isObjectRecord,mn as isSemanticColorName,bn as layerThemes,cn as mergePartials,he as mergeTheme,Ae as parseAnchorSource,zt as parseTheme,je as resolveAnchorColor,ft as resolveContextTheme,Rt as resolveDataColorSource,Te as resolveLightnessReference,dn as roleInkProvenance,gn as semanticToCSS,Oe as toneReferenceName,hn as validateTheme,yn as validateThemePair};
|
package/espalier.css-data.json
CHANGED
|
@@ -621,6 +621,10 @@
|
|
|
621
621
|
"name": "--esp-footer-border",
|
|
622
622
|
"description": "Block-start footer border. Defaults to `1px solid var(--esp-color-border)`."
|
|
623
623
|
},
|
|
624
|
+
{
|
|
625
|
+
"name": "--esp-footer-brand-logo-aspect-ratio",
|
|
626
|
+
"description": "The ratio the configured logo's box is reserved at while the image is still loading or has failed, so alt text never decides the brand region's width. A logo that loads is always laid out at its own ratio, whatever this is set to. Defaults to `3 / 1`."
|
|
627
|
+
},
|
|
624
628
|
{
|
|
625
629
|
"name": "--esp-footer-brand-logo-max-width",
|
|
626
630
|
"description": "Configured logo maximum inline size. Defaults to `12rem`."
|
|
@@ -857,6 +861,10 @@
|
|
|
857
861
|
"name": "--esp-header-brand-inline-placement",
|
|
858
862
|
"description": "The CSS `justify-content` value for the brand container. Defaults to `start`."
|
|
859
863
|
},
|
|
864
|
+
{
|
|
865
|
+
"name": "--esp-header-brand-logo-aspect-ratio",
|
|
866
|
+
"description": "The ratio the configured logo's box is reserved at while the image is still loading or has failed, so alt text never decides the brand region's width. A logo that loads is always laid out at its own ratio, whatever this is set to. Defaults to `3 / 1`."
|
|
867
|
+
},
|
|
860
868
|
{
|
|
861
869
|
"name": "--esp-header-brand-logo-max-width",
|
|
862
870
|
"description": "The configured logo maximum inline size. Defaults to `12rem`."
|
|
@@ -846,6 +846,12 @@
|
|
|
846
846
|
"component": "esp-footer",
|
|
847
847
|
"description": "Block-start footer border. Defaults to `1px solid var(--esp-color-border)`."
|
|
848
848
|
},
|
|
849
|
+
{
|
|
850
|
+
"name": "--esp-footer-brand-logo-aspect-ratio",
|
|
851
|
+
"category": "component",
|
|
852
|
+
"component": "esp-footer",
|
|
853
|
+
"description": "The ratio the configured logo's box is reserved at while the image is still loading or has failed, so alt text never decides the brand region's width. A logo that loads is always laid out at its own ratio, whatever this is set to. Defaults to `3 / 1`."
|
|
854
|
+
},
|
|
849
855
|
{
|
|
850
856
|
"name": "--esp-footer-brand-logo-max-width",
|
|
851
857
|
"category": "component",
|
|
@@ -1200,6 +1206,12 @@
|
|
|
1200
1206
|
"component": "esp-header",
|
|
1201
1207
|
"description": "The CSS `justify-content` value for the brand container. Defaults to `start`."
|
|
1202
1208
|
},
|
|
1209
|
+
{
|
|
1210
|
+
"name": "--esp-header-brand-logo-aspect-ratio",
|
|
1211
|
+
"category": "component",
|
|
1212
|
+
"component": "esp-header",
|
|
1213
|
+
"description": "The ratio the configured logo's box is reserved at while the image is still loading or has failed, so alt text never decides the brand region's width. A logo that loads is always laid out at its own ratio, whatever this is set to. Defaults to `3 / 1`."
|
|
1214
|
+
},
|
|
1203
1215
|
{
|
|
1204
1216
|
"name": "--esp-header-brand-logo-max-width",
|
|
1205
1217
|
"category": "component",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@taprootio/espalier",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.19.0",
|
|
4
4
|
"packageManager": "bun@1.3.12",
|
|
5
5
|
"description": "Espalier — a themeable, accessible, framework-agnostic, enterprise-grade design system built on web standards and love.",
|
|
6
6
|
"customElements": "custom-elements.json",
|