@apollion-dsi/tokens 5.3.0 → 5.5.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/lib/cli.mjs CHANGED
@@ -1,9 +1,14 @@
1
1
  #!/usr/bin/env node
2
- var un=Object.defineProperty;var i=(e,n)=>un(e,"name",{value:n,configurable:!0}),pn=(e=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(e,{get:(n,o)=>(typeof require<"u"?require:n)[o]}):e)(function(e){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+e+'" is not supported')});import{readFile as mo}from"node:fs/promises";import{resolve as le}from"node:path";import{mkdir as tn,mkdtemp as eo,readFile as no,rename as oo,rm as on,writeFile as rn}from"node:fs/promises";import{tmpdir as to}from"node:os";import{dirname as sn,join as z}from"node:path";import{defaultInputBorder as F}from"@apollion-dsi/core/themes/border";import{createReadableTextLayer as mn}from"@apollion-dsi/core/themes/colors";import{createDeth as gn,levelValues as hn}from"@apollion-dsi/core/themes/depth";import{createFont as yn,defaultInputFont as v}from"@apollion-dsi/core/themes/font";import{defaultInputSpacing as de}from"@apollion-dsi/core/themes/spacing";import{converter as bn,formatHex as Rn,parse as kn}from"culori";import{DIMENSION_MULTIPLIERS as fn}from"@apollion-dsi/core/themes/dimension";function G({multiplier:e=.25,alias:n},o){let t=o!==void 0?fn[o]:e;return(...r)=>r.map(s=>{let a=typeof s=="string"?n[s]:s;return`${t*a}rem`}).join(" ")}i(G,"createSpacing");var K={"bg.primary":{description:"Primary action surface \u2014 the brand\u2019s dominant call-to-action background."},"bg.secondary":{description:"Secondary action surface \u2014 supporting actions paired with the primary."},"bg.danger":{description:"Destructive / error surface \u2014 irreversible or failing actions."},"bg.success":{description:"Positive confirmation surface \u2014 completed or healthy states."},"bg.info":{description:"Informational surface \u2014 neutral, non-blocking notices.",deprecated:"Use bg.information once the foundation role is renamed (tracked for S6)."},"text.on-primary":{description:"Text/icon colour with guaranteed contrast over bg.primary."},"text.on-danger":{description:"Text/icon colour with guaranteed contrast over bg.danger."},"space.medium":{description:"Base spacing step (1rem at normal density) \u2014 the layout rhythm unit."},"space.large":{description:"Comfortable spacing step \u2014 section padding and card gutters."},"spacing.md":{description:"Medium foundation spacing alias \u2014 references the space.medium primitive."},"spacing.lg":{description:"Large foundation spacing alias \u2014 references the space.large primitive."},"border.radius.md":{description:"Default card corner radius."},"border.width.thin":{description:"Hairline border \u2014 dividers and default input outlines."},"border.width.regular":{description:"Standard emphasis border \u2014 focused/active controls."}};function Z(e){let n=Object.keys(K).filter(o=>!e.has(o));if(n.length>0)throw new Error(`token-meta: ${n.length} stale TOKEN_META key(s) resolve to no IR node: ${n.join(", ")}. Update src/token-meta.ts to match the current IR paths.`)}i(Z,"assertTokenMetaResolves");var In=bn("oklch");function b(e){return typeof e.type=="string"&&"value"in e}i(b,"isToken");function k(e){return e.replace(/([a-z])([A-Z])/g,"$1-$2").toLowerCase()}i(k,"kebab");function ue(e){return e.split(".").map(k).join(".")}i(ue,"kebabPath");function $(e){return e.kind==="ref"?e.resolved.raw:e.raw}i($,"rawValue");function P(e,n){return Number(e.toFixed(n))||0}i(P,"round");function ee(e){let n=In(kn(e));if(!n)return{kind:"color",raw:e,components:[0,0,0],hex:"#000000"};let o=[P(n.l,4),P(n.c,4),P(n.h??0,2)],t=Rn(n)??"#000000";return n.alpha!==void 0&&n.alpha!==1?{kind:"color",raw:e,components:o,alpha:P(n.alpha,4),hex:t}:{kind:"color",raw:e,components:o,hex:t}}i(ee,"toColorValue");var pe=/^(-?(?:\d+\.?\d*|\.\d+))(px|rem)$/;function T(e){let n=pe.exec(e.trim());if(n)return{kind:"dimension",raw:e,value:Number(n[1]),unit:n[2]};let o=Number.parseFloat(e);return{kind:"dimension",raw:e,value:Number.isFinite(o)?o:0,unit:"rem"}}i(T,"toDimensionValue");function h(e){return{type:"color",value:ee(e)}}i(h,"colorToken");function Q(e){let n={};for(let[o,t]of Object.entries(e))n[o]=h(t);return n}i(Q,"recordColorGroup");function fe(e){let n=mn(e),o={};for(let[t,r]of Object.entries(n.palettes))o[t]=h(r);return o.neutral=Q(n.neutral),o}i(fe,"buildReadableTextGroup");var Sn=["main","opposite","complementary","primary","secondary","tertiary","success","danger","warning","information"];function me(e){let n={};for(let o of Sn){let t=e[o];n[o]={base:h(t.base),dark:h(t.dark),action:h(t.action),active:h(t.active),light:h(t.light),onLight:h(t.onLight)}}return n.grayscale=Q(e.grayscale),n.neutral=Q(e.neutral),n.baseDark=h(e.baseDark??"#000000"),n.baseLight=h(e.baseLight??"#ffffff"),n.deepDark=h(e.deepDark??"#000000"),n.deepLight=h(e.deepLight??"#ffffff"),n}i(me,"buildColorPrimitives");function ge(e){let n=G(de,e),o={};for(let t of Object.keys(de.alias))o[t]={type:"dimension",value:T(n(t))};return o}i(ge,"buildSpacePrimitives");function he(){let e={};for(let[n,o]of Object.entries(F.borderWidth))e[n]={type:"dimension",value:T(o)};return e}i(he,"buildBorderWidthPrimitives");function xn(e,n){return{color:me(e),space:ge(n),borderWidth:he()}}i(xn,"buildPrimitives");var ye={primary:"color.primary.base",secondary:"color.secondary.base",tertiary:"color.tertiary.base",success:"color.success.base",danger:"color.danger.base",warning:"color.warning.base",info:"color.information.base"},be={onPrimary:"color.baseLight",onSecondary:"color.baseLight",onTertiary:"color.baseDark",onSuccess:"color.baseLight",onDanger:"color.baseLight",onWarning:"color.baseDark",onInfo:"color.baseLight"};function wn(e,n){let o=e;for(let t of n.split(".").slice(1))if(o&&typeof o=="object"&&t in o)o=o[t];else return;return typeof o=="string"?o:void 0}i(wn,"lookupPrimitive");function M(e,n,o){let t={};for(let[r,s]of Object.entries(e)){let a=o[r],c=a?wn(n,a):void 0;t[r]=a&&c===s?{type:"color",value:{kind:"ref",path:a,resolved:ee(s)}}:h(s)}return t}i(M,"colorRefGroup");var Re={xs:"space.xs",sm:"space.small",md:"space.medium",lg:"space.large",xl:"space.xl",xxl:"space.xxl"},Dn={none:"border-width.none",thin:"border-width.thin",regular:"border-width.regular",great:"border-width.great",bold:"border-width.bold"};function vn(e,n){let o=n.split("."),t=o[0]==="border-width"?"borderWidth":o[0],r=e[t];for(let s of o.slice(1))if(r&&!b(r)&&s in r)r=r[s];else return;return r&&b(r)&&r.value.kind==="dimension"?r.value.raw:void 0}i(vn,"lookupDimensionPrimitive");function ne(e,n,o){let t={};for(let[r,s]of Object.entries(e)){let a=o[r],c=a?vn(n,a):void 0;t[r]=a&&c===s?{type:"dimension",value:{kind:"ref",path:a,resolved:T(s)}}:{type:"dimension",value:T(s)}}return t}i(ne,"dimensionRefGroup");function ke(e){let n={},o={};for(let[s,a]of Object.entries(F.borderRadius))pe.test(a)?n[s]={type:"dimension",value:T(a)}:o[s]=a;let t=ne(F.borderWidth,e,Dn),r={};for(let[s,a]of Object.entries(F.borderStyle))r[s]={type:"strokeStyle",value:{kind:"strokeStyle",raw:a,style:a}};return{group:{radius:n,width:t,style:r},extensions:o}}i(ke,"buildBorder");function Ie(e){let n=yn(v,e),o={};for(let[c,l]of Object.entries(v.fontFamily)){let p=l.replace(/;\s*$/,"").trim();o[c]={type:"fontFamily",value:{kind:"fontFamily",raw:p,family:p}}}let t={};for(let[c,l]of Object.entries(n.fontSize))t[c]={type:"dimension",value:T(l)};let r={};for(let[c,l]of Object.entries(v.fontWeight))r[c]={type:"fontWeight",value:{kind:"fontWeight",raw:`${l}`,weight:l}};let s={};for(let[c,l]of Object.entries(v.lineHeight))s[c]={type:"number",value:{kind:"number",raw:`${l}`,number:l}};let a={letterSpacing:v.letterSpacing,textTransform:v.textTransform,fontStyle:v.fontStyle};return{group:{family:o,size:t,weight:r,lineHeight:s},extensions:a}}i(Ie,"buildFont");var Tn=/rgba?\([^)]*\)|#[0-9a-fA-F]+|[a-zA-Z]+$/;function Cn(e){let n=e.trim(),o=n.startsWith("inset");o&&(n=n.slice(5).trim());let t=n.match(Tn),r=t?t[0]:"#000000",a=(t?n.slice(0,t.index).trim():n).split(/\s+/).filter(Boolean),c=i(l=>T(a[l]??"0px"),"dim");return{kind:"shadow",raw:e,shadow:{color:ee(r),offsetX:c(0),offsetY:c(1),blur:c(2),spread:c(3),inset:o}}}i(Cn,"parseShadow");function Se(e){let n=gn(e),o={};for(let t of Object.keys(hn))o[t]={type:"shadow",value:Cn(n(t))};return o}i(Se,"buildShadow");function L(e,n,o){let t={};for(let[r,s]of Object.entries(e)){let a=n?`${n}.${k(r)}`:k(r);if(b(s)){o.add(a);let c=K[a];t[r]=c&&(c.description!==void 0||c.deprecated!==void 0)?{...s,...c.description!==void 0?{description:c.description}:{},...c.deprecated!==void 0?{deprecated:c.deprecated}:{}}:s}else t[r]=L(s,a,o)}return t}i(L,"decorateGroup");function $n(e){let n=new Set,o=L(e.primitives,"",n),t=L(e.groups,"",n);return Z(n),{...e,primitives:o,groups:t}}i($n,"decorateMeta");function N(e,n){return L(e,"",n)}i(N,"decorateSlice");function xe(e,n,o){for(let[t,r]of Object.entries(e)){let s=n?`${n}.${k(t)}`:k(t);b(r)?o.add(s):xe(r,s,o)}}i(xe,"collectPaths");function we(e){let n=new Set;for(let o of e)xe(o.groups,"",n);Z(n)}i(we,"assertSlicesMetaComplete");function De(){let e=he(),o=ke({borderWidth:e}),t={};Object.keys(o.extensions).length>0&&(t["com.apollion.border"]={radius:o.extensions});let r=new Set;return{groups:N({"border-width":e,border:o.group},r),extensions:t}}i(De,"buildBaseIR");function ve(e){let n=Ie(e),o=new Set;return{groups:N({font:n.group},o),extensions:{"com.apollion.font":n.extensions}}}i(ve,"buildFontIR");function Te(e,n){let o=me(n),t=new Set;return{groups:N({color:o,bg:M(e.bg,n,ye),text:M(e.text,n,be),tx:fe(n),shadow:Se(n)},t),extensions:{}}}i(Te,"buildColorIR");function Ce(e,n){let o=ge(n),t={space:o},r=new Set;return{groups:N({space:o,spacing:ne(e.spacing,t,Re)},r),extensions:{}}}i(Ce,"buildSpacingIR");function Vn(e,n,o){let t={brand:o.brand,mode:o.mode,surface:o.surface,dimension:o.dimension},r=xn(n,o.dimension),s=ke(r),a=Ie(o.dimension),c={"com.apollion.variant":t,"com.apollion.font":a.extensions};Object.keys(s.extensions).length>0&&(c["com.apollion.border"]={radius:s.extensions});let l={description:`Apollion DS tokens \u2014 DTCG 2025.10. Variant: ${t.brand}/${t.mode}/${t.surface}/${t.dimension}.`,meta:t,primitives:r,groups:{bg:M(e.bg,n,ye),text:M(e.text,n,be),tx:fe(n),spacing:ne(e.spacing,r,Re),border:s.group,font:a.group,shadow:Se(n)},extensions:c};return $n(l)}i(Vn,"buildIR");var $e=Vn;var An="/* Generated by apollion-tokens build \u2014 DO NOT EDIT. See apollion.config.mjs. */";function Ve(e,n,o){for(let[t,r]of Object.entries(e)){let s=[...n,k(t)];b(r)?o.push(` --apollion-${s.join("-")}: ${$(r.value)};`):Ve(r,s,o)}}i(Ve,"emitVars");function Ae(e,n,o){for(let[t,r]of Object.entries(e)){let s=[...n,k(t)];b(r)?r.type==="color"&&o.push(` @property --apollion-${s.join("-")} { syntax: '<color>'; inherits: true; initial-value: ${$(r.value)}; }`):Ae(r,s,o)}}i(Ae,"emitProperties");function Oe(e){let{brand:n,mode:o,surface:t,dimension:r}=e.meta,s=[An,""];return s.push(`/* Variant: brand=${n} mode=${o} surface=${t} dimension=${r} */`,"",":root {"),Ve(e.groups,[],s),s.push("}",""),s.push("@supports (background: paint(squircle)) or (color: oklch(0% 0 0)) {"),Ae(e.groups,[],s),s.push("}",""),s.join(`
3
- `)}i(Oe,"renderCss");function Ee(e){return e.alpha!==void 0?{colorSpace:"oklch",components:[...e.components],alpha:e.alpha,hex:e.hex}:{colorSpace:"oklch",components:[...e.components],hex:e.hex}}i(Ee,"colorValue");function V(e){return{value:e.value,unit:e.unit}}i(V,"dimensionValue");function On(e){let n=e.shadow,o={color:Ee(n.color),offsetX:V(n.offsetX),offsetY:V(n.offsetY),blur:V(n.blur),spread:V(n.spread)};return n.inset&&(o.inset=!0),o}i(On,"shadowValue");function En(e){switch(e.kind){case"ref":return`{${ue(e.path)}}`;case"color":return Ee(e);case"dimension":return V(e);case"fontFamily":return e.family;case"fontWeight":return e.weight;case"number":return e.number;case"strokeStyle":return e.style;case"shadow":return On(e)}}i(En,"projectValue");function jn(e){let n={$value:En(e.value),$type:e.type};return e.description!==void 0&&(n.$description=e.description),e.deprecated!==void 0&&(n.$deprecated=e.deprecated),n}i(jn,"projectToken");function oe(e){let n={};for(let[o,t]of Object.entries(e))n[k(o)]=b(t)?jn(t):oe(t);return n}i(oe,"projectGroup");function _(e,n){let o={$description:n,...oe(e.groups)};return Object.keys(e.extensions).length>0&&(o.$extensions=e.extensions),`${JSON.stringify(o,null,2)}
4
- `}i(_,"renderSet");function je(e){return _(e,"Apollion DS \u2014 base set (axis-invariant: border). DTCG 2025.10.")}i(je,"renderBaseSet");function Ge(e,n,o,t){return _(e,`Apollion DS \u2014 colour set. brand=${n} mode=${o} surface=${t}. DTCG 2025.10.`)}i(Ge,"renderColorSet");function Pe(e,n){return _(e,`Apollion DS \u2014 spacing set. dimension=${n}. DTCG 2025.10.`)}i(Pe,"renderSpacingSet");function Fe(e,n){return _(e,`Apollion DS \u2014 font set. dimension=${n}. DTCG 2025.10.`)}i(Fe,"renderFontSet");function Me(e,n){let{modifiers:o}=n,t=[{name:"brand",values:[...o.brand],default:o.brand[0]},{name:"mode",values:[...o.mode],default:o.mode[0]},{name:"surface",values:[...o.surface],default:o.surface[0]},{name:"dimension",values:[...o.dimension],default:o.dimension[0]}],s={name:"apollion-tokens",description:"Apollion DS token resolver \u2014 DTCG 2025.10. Compose the base set with the colour set for the chosen brand/mode/surface and the spacing + font sets for the chosen dimension. NOTE: mode is a topology placeholder in this release (dark resolves identically to light until S6).",sets:[{name:n.base.name,source:n.base.file},...n.spacing.map(a=>({name:a.name,source:a.file})),...n.font.map(a=>({name:a.name,source:a.file})),...n.color.map(a=>({name:a.name,source:a.file}))],modifiers:t,$extensions:{"com.apollion.resolver":{composition:{always:[n.base.name],byModifier:{color:"${brand}.color.${mode}.${surface}",spacing:"spacing.${dimension}",font:"font.${dimension}"}},modeIsPlaceholder:!0}}};return`${JSON.stringify(s,null,2)}
5
- `}i(Me,"renderResolver");var Gn="// Generated by apollion-tokens build \u2014 DO NOT EDIT. See apollion.config.mjs.";function Le(e,n,o){let t=" ".repeat(n);for(let[r,s]of Object.entries(e))b(s)?o.push(`${t}${JSON.stringify(r)}: ${JSON.stringify($(s.value))},`):(o.push(`${t}${r}: {`),Le(s,n+1,o),o.push(`${t}},`))}i(Le,"emitGroup");function Ne(e){let{brand:n,mode:o,surface:t,dimension:r}=e.meta,s=[Gn,`// Variant: brand=${n} mode=${o} surface=${t} dimension=${r}`,"","export const tokens = {"];return Le(e.groups,1,s),s.push("} as const;","","export type Tokens = typeof tokens;",""),s.join(`
6
- `)}i(Ne,"renderTs");var Pn=["light","dark"],Fn=["positive","negative"],Mn=["compact","normal","spacious"];function B(e){let n=e.modes??Pn,o=e.surfaces??Fn,t=e.dimensions??Mn,r=Object.entries(e.brands).sort(([a],[c])=>a.localeCompare(c)),s=[];for(let[a,c]of r)for(let l of n)for(let p of o)for(let D of t)s.push({brand:a,colors:c,mode:l,surface:p,dimension:D});return s}i(B,"expandVariants");function _e(e){return`${e.brand}.${e.mode}.${e.surface}.${e.dimension}`}i(_e,"variantName");import{createHash as Ln}from"node:crypto";function re(e){return Ln("sha256").update(e).digest("hex")}i(re,"sha256");function ie(e){return re(te(e))}i(ie,"hashConfig");function te(e){return e===null||typeof e!="object"?JSON.stringify(e):Array.isArray(e)?`[${e.map(te).join(",")}]`:`{${Object.keys(e).sort().map(t=>`${JSON.stringify(t)}:${te(e[t])}`).join(",")}}`}i(te,"stableStringify");function Be(e){try{let{execSync:n}=pn("node:child_process");return n("git rev-parse --short HEAD",{cwd:e,stdio:["ignore","pipe","ignore"],encoding:"utf8"}).trim()}catch{return""}}i(Be,"detectGitCommit");function He(){return{node:process.version,platform:`${process.platform}-${process.arch}`}}i(He,"buildEnv");function We(e){let n=[...e.files].sort((t,r)=>t.path.localeCompare(r.path)),o={configHash:e.configHash,files:n,gitCommit:e.gitCommit,buildEnv:e.buildEnv};return`${JSON.stringify(o,null,2)}
7
- `}i(We,"serializeManifest");var Nn="json/sets",Ue="json/resolver.json";function H(e){return`${Nn}/${e}.json`}i(H,"setFile");function _n(e,n,o){return`${e}.color.${n}.${o}`}i(_n,"colorSetName");function Bn(e){return`spacing.${e}`}i(Bn,"spacingSetName");function Hn(e){return`font.${e}`}i(Hn,"fontSetName");function W(e,n){e.includes(n)||e.push(n)}i(W,"pushUnique");function Je(e){let n=B(e),o=[],t=[],r=[],s=[],a=new Set,c=[],l=new Set,p=[],D=new Set,O=[];for(let u of n){W(o,u.brand),W(t,u.mode),W(r,u.surface),W(s,u.dimension);let g=_n(u.brand,u.mode,u.surface);a.has(g)||(a.add(g),c.push({kind:"color",name:g,file:H(g),brand:u.brand,mode:u.mode,surface:u.surface}));let S=Bn(u.dimension);l.has(S)||(l.add(S),p.push({kind:"spacing",name:S,file:H(S),dimension:u.dimension}));let f=Hn(u.dimension);D.has(f)||(D.add(f),O.push({kind:"font",name:f,file:H(f),dimension:u.dimension}))}return{base:{kind:"base",name:"base",file:H("base")},spacing:p,font:O,color:c,modifiers:{brand:o,mode:t,surface:r,dimension:s}}}i(Je,"planSets");import{createFoundation as nn}from"@apollion-dsi/core/themes/foundation";import{createSemantic as Yn}from"@apollion-dsi/core/themes/semantic";import{defaultInputSpacing as Kn}from"@apollion-dsi/core/themes/spacing";import{invertForSurface as Zn}from"@apollion-dsi/core/themes/surface";import{converter as Wn,formatHex as A,interpolate as Un,parse as I,wcagContrast as Ze}from"culori";var ae=Wn("oklch");function d(e,n,o){let t=I(e),r=I(n);if(!t||!r)return e;let s=Un([t,r],"oklch");return A(s(o))??e}i(d,"mixOklch");function Jn(e){return e?typeof e=="string"?e:e.base:"#000"}i(Jn,"coerceToHex");var U=1.3,zn=.05,ze=.04,w=i((e,n)=>{let o=I(e),t=I(n);return!o||!t?1:Ze(o,t)},"contrastRatio"),se=i(e=>{let n=ae(I(e));return n?n.l??0:null},"oklchLightness"),Xn=4.5;function Xe(e,n,o=Xn){let t=I(n),r=ae(I(e));if(!t||!r)return e;let s=w("#fff",n)>=w("#000",n)?.04:-.04;for(let a=0;a<25;a+=1){let c=A(r)??e,l=I(c);if(l&&Ze(l,t)>=o)return c;let p=Math.min(1,Math.max(0,(r.l??0)+s));if(p===(r.l??0))break;r={...r,l:p}}return A(r)??e}i(Xe,"readableColor");var qe=i((e,n)=>{if(w(e,n)>=U)return!0;let o=se(e),t=se(n);return o!==null&&t!==null&&Math.abs(o-t)>=zn},"isPerceptibleState"),qn=i(e=>e?w("#fff",e)>w("#000",e):!1,"isDarkSurface");function Ye(e,n,o){let t=ae(I(e));if(!t)return null;let r={...t,l:o??t.l??0},s=n?ze:-ze;for(let a=0;a<25;a+=1){let c=Math.min(1,Math.max(0,(r.l??0)+s));if(c===(r.l??0))break;r={...r,l:c};let l=A(r);if(l&&w(e,l)>=U)return l}return A(r)??null}i(Ye,"derivePerceptibleState");function Ke(e,n,o){let t=Ye(e,n,o);if(t&&w(e,t)>=U)return t;let r=Ye(e,!n);return r&&w(e,r)>=U?r:t??r}i(Ke,"perceptibleStateFor");function R(e,n){let o=typeof e=="object"&&e!==null?e:void 0,t=Jn(e),r=n.deepDark,s=n.deepLight,a={base:t,dark:d(t,r,.6),action:d(t,r,.2),active:d(t,s,.6),light:d(t,s,.9),onLight:t};if(I(t)){let c=qn(n.baseLight),l=qe(t,a.action);if(l||(a.action=Ke(t,c)??a.action),!qe(t,a.active)){let p=l?void 0:se(a.action)??void 0;a.active=Ke(t,c,p)??a.active}}if(a.onLight=Xe(a.action,a.light),o){let c=o.action??a.action,l=o.light??a.light;return{base:t,dark:o.dark??a.dark,action:c,active:o.active??a.active,light:l,onLight:o.onLight??Xe(c,l)}}return a}i(R,"mountSingleColor");function Qe(e){let n=e.deepLight,o=e.deepDark;return{0:n,5:d(n,o,.05),10:d(n,o,.1),20:d(n,o,.2),30:d(n,o,.3),40:d(n,o,.4),50:d(n,o,.5),60:d(n,o,.6),70:d(n,o,.7),80:d(n,o,.8),90:d(n,o,.9),100:d(n,o,1)}}i(Qe,"mountGreyscaleColors");function en(e){let n=e.deepLight,o=e.deepDark,t=typeof e.primary=="object"&&e.primary?e.primary.base:e.primary,r=i(a=>1/17*(a-1),"interpolation"),s=d(t,o,.5);return{0:d(s,n,r(18)),5:d(s,n,r(17.5)),10:d(s,n,r(17)),20:d(s,n,r(16)),30:d(s,n,r(15)),40:d(s,n,r(14)),50:d(s,n,r(13)),60:d(s,n,r(12)),70:d(s,n,r(11)),80:d(s,n,r(10)),90:d(s,n,r(9)),100:d(s,n,r(8)),110:d(s,n,r(7)),120:d(s,n,r(6)),130:d(s,n,r(5)),140:d(s,n,r(4)),150:d(s,n,r(3)),160:d(s,n,r(2)),170:s,180:d(s,o,.25)}}i(en,"mountNeutralColors");function Qn(e){return{baseDark:e.baseDark,baseLight:e.baseLight,deepDark:e.deepDark,deepLight:e.deepLight,transparent:e.transparent??"transparent",neutral:en(e),grayscale:Qe(e),main:R(e.main,e),opposite:R(e.opposite,e),complementary:R(e.complementary,e),danger:R(e.danger,e),information:R(e.information,e),success:R(e.success,e),warning:R(e.warning,e),primary:R(e.primary,e),secondary:R(e.secondary,e),tertiary:R(e.tertiary,e)}}i(Qn,"composeColors");function J(e,n=Kn){let o=Qn(e.colors),t=G(n,e.dimension),r=Yn({colors:o,spacing:t}),s=nn(r);return e.surface==="negative"&&(s=nn(Zn({semantic:r,colors:o},"negative").semantic)),{foundation:s,colors:o}}i(J,"buildVariantThemes");async function an(e){let{config:n,outDir:o,cwd:t=process.cwd(),verbose:r=!1}=e,s=B(n),a=n.output??{};if(s.length===0)throw new Error("apollion-tokens build: no variants (config.brands is empty)");let c=await eo(z(to(),"apollion-tokens-"));try{let l=[],p=i(async(u,g)=>{await ro(c,u,g),l.push({path:u,sha256:re(g)}),r&&console.log(` \u2713 ${u}`)},"emit");if(a.json){let u=Je(n),g=[],S=De();g.push(S),await p(u.base.file,je(S));for(let f of u.spacing){let x=s.find(j=>j.dimension===f.dimension),{foundation:q}=J(x),E=Ce(q,f.dimension);g.push(E),await p(f.file,Pe(E,f.dimension))}for(let f of u.font){let x=ve(f.dimension);g.push(x),await p(f.file,Fe(x,f.dimension))}for(let f of u.color){let x=s.find(Y=>Y.brand===f.brand&&Y.mode===f.mode&&Y.surface===f.surface),{foundation:q,colors:E}=J(x),j=Te(q,E);g.push(j),await p(f.file,Ge(j,f.brand,f.mode,f.surface))}we(g),await p(Ue,Me(n,u))}if(a.css||a.ts)for(let u of s){let{foundation:g,colors:S}=J(u),f=$e(g,S,u),x=_e(u);a.css&&await p(`css/${x}.css`,Oe(f)),a.ts&&await p(`ts/${x}.d.ts`,Ne(f))}let D={configHash:ie(n),files:l,gitCommit:Be(t),buildEnv:He()},O=We(D);return await rn(z(c,"manifest.json"),O),await on(o,{recursive:!0,force:!0}),await tn(sn(o),{recursive:!0}),await oo(c,o),r&&console.log(`\u2713 ${l.length} files \u2192 ${o}`),{manifest:D,outDir:o}}catch(l){throw await on(c,{recursive:!0,force:!0}).catch(()=>{}),l}}i(an,"build");async function cn(e){let{config:n,outDir:o}=e,t;try{t=JSON.parse(await no(z(o,"manifest.json"),"utf8"))}catch{return!1}return t.configHash===ie(n)}i(cn,"check");async function ro(e,n,o){let t=z(e,n);await tn(sn(t),{recursive:!0}),await rn(t,o)}i(ro,"writeAt");import{readFile as so}from"node:fs/promises";import{resolve as ao}from"node:path";import{createContext as co,Script as lo}from"node:vm";import{z as m}from"zod";var y=m.string().regex(/^#([0-9a-fA-F]{3}){1,2}$|^transparent$|^rgb\(.*\)$|^oklch\(.*\)$/,{message:'Must be hex, rgb(), oklch(), or "transparent"'}),io=m.object({baseDark:m.string().optional(),baseLight:m.string().optional(),deepDark:y,deepLight:y,transparent:m.string().optional(),main:y.optional(),opposite:y.optional(),complementary:y.optional(),information:y.optional(),success:y.optional(),danger:y.optional(),warning:y.optional(),primary:y.optional(),secondary:y.optional(),tertiary:y.optional()}).passthrough(),ln=m.object({brands:m.record(m.string(),io).refine(e=>Object.keys(e).length>0,{message:"apollion.config.mjs: brands must contain at least 1 entry"}),modes:m.array(m.enum(["light","dark"])).optional(),surfaces:m.array(m.enum(["positive","negative"])).optional(),dimensions:m.array(m.enum(["compact","normal","spacious"])).optional(),output:m.object({runtime:m.boolean().optional(),css:m.boolean().optional(),json:m.boolean().optional(),ts:m.boolean().optional()}).passthrough().optional()}).passthrough();var uo=[/\brequire\s*\(/,/\bimport\s*\(/,/^\s*import\s+/m],po=1e3;var ce=class ce extends Error{constructor(o,t){super(o);this.configPath=t;this.name="ConfigLoadError"}};i(ce,"ConfigLoadError");var C=ce;async function dn(e){let n=ao(e.configPath),o=await so(n,"utf8");for(let l of uo)if(l.test(o))throw new C(`apollion.config: dynamic require/import not allowed (matched ${l}). Declarative config only \u2014 see ADR-006 \xA73.8 B3.`,n);let t=o.replace(/(^|\n)\s*export\s+default\s+/,(l,p)=>`${p}__apollion_config_export = `);if(t===o)throw new C("apollion.config: missing `export default <object>;` \u2014 config must export a default object literal.",n);let r={__apollion_config_export:void 0,console:fo(),Symbol,Number,String,Boolean,Array,Object,JSON,Math,defineConfig:i(l=>l,"defineConfig")},s=co(r);try{new lo(t,{filename:n}).runInContext(s,{timeout:po})}catch(l){throw new C(`apollion.config: evaluation failed \u2014 ${l instanceof Error?l.message:String(l)}`,n)}let a=r.__apollion_config_export;if(a===void 0)throw new C("apollion.config: `export default` produced undefined.",n);let c=ln.safeParse(a);if(!c.success){let l=c.error.issues.map(p=>` ${p.path.join(".")||"(root)"}: ${p.message}`).join(`
8
- `);throw new C(`apollion.config: schema validation failed \u2014
9
- ${l}`,n)}return c.data}i(dn,"loadConfig");function fo(){return{log:i((...e)=>console.log("[apollion.config]",...e),"log"),warn:i((...e)=>console.warn("[apollion.config]",...e),"warn"),error:i((...e)=>console.error("[apollion.config]",...e),"error")}}i(fo,"makeReadOnlyConsole");function go(e){let n=e.slice(2),o=n[0];o!=="build"&&X(`Unknown command "${o??""}". Usage: apollion-tokens build [--check] [--verbose] --config <path> [--out <dir>]`);let t="apollion.config.mjs",r="dist",s=!1,a=!1;for(let c=1;c<n.length;c++){let l=n[c];switch(l){case"--config":t=n[++c]??X("--config needs a path");break;case"--out":r=n[++c]??X("--out needs a path");break;case"--check":s=!0;break;case"--verbose":a=!0;break;default:X(`Unknown flag "${l}"`)}}return{command:o,configPath:t,outDir:r,check:s,verbose:a}}i(go,"parseArgs");function X(e){console.error(`apollion-tokens: ${e}`),process.exit(2)}i(X,"fail");async function ho(e){let n=le(e);if(n.endsWith(".json")){let o=await mo(n,"utf8");return JSON.parse(o)}return dn({configPath:n})}i(ho,"loadConfigFromPath");async function yo(){let e=go(process.argv),n=await ho(e.configPath);if(e.check){await cn({config:n,outDir:le(e.outDir)})||(console.error("apollion-tokens: dist/ is stale or missing (configHash mismatch). Re-run `apollion-tokens build` without --check."),process.exit(1)),console.log("apollion-tokens: dist/ is up-to-date with config.");return}let{manifest:o}=await an({config:n,outDir:le(e.outDir),verbose:e.verbose});console.log(`apollion-tokens: wrote ${o.files.length} file(s) \u2014 configHash=${o.configHash.slice(0,12)}\u2026`)}i(yo,"main");yo().catch(e=>{console.error(`apollion-tokens: ${e instanceof Error?e.message:String(e)}`),process.exit(1)});
2
+ var Dn=Object.defineProperty;var i=(e,n)=>Dn(e,"name",{value:n,configurable:!0}),Tn=(e=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(e,{get:(n,o)=>(typeof require<"u"?require:n)[o]}):e)(function(e){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+e+'" is not supported')});import{readFile as Mo}from"node:fs/promises";import{resolve as ye}from"node:path";import{mkdir as Rn,mkdtemp as wo,readFile as yn,rename as vo,rm as bn,writeFile as kn}from"node:fs/promises";import{tmpdir as Do}from"node:os";import{dirname as In,join as F}from"node:path";import{converter as zn,parse as qn}from"culori";import{defaultInputBorder as H}from"@apollion-dsi/core/themes/border";import{createReadableTextLayer as Cn}from"@apollion-dsi/core/themes/colors";import{createDeth as Vn,levelValues as On}from"@apollion-dsi/core/themes/depth";import{createFont as En,defaultInputFont as V}from"@apollion-dsi/core/themes/font";import{defaultInputSpacing as be}from"@apollion-dsi/core/themes/spacing";import{converter as An,formatHex as jn,parse as Gn}from"culori";import{DIMENSION_MULTIPLIERS as $n}from"@apollion-dsi/core/themes/dimension";function _({multiplier:e=.25,alias:n},o){let t=o!==void 0?$n[o]:e;return(...r)=>r.map(s=>{let a=typeof s=="string"?n[s]:s;return`${t*a}rem`}).join(" ")}i(_,"createSpacing");var te={"bg.primary":{description:"Primary action surface \u2014 the brand\u2019s dominant call-to-action background."},"bg.secondary":{description:"Secondary action surface \u2014 supporting actions paired with the primary."},"bg.danger":{description:"Destructive / error surface \u2014 irreversible or failing actions."},"bg.success":{description:"Positive confirmation surface \u2014 completed or healthy states."},"bg.info":{description:"Informational surface \u2014 neutral, non-blocking notices.",deprecated:"Use bg.information once the foundation role is renamed (tracked for S6)."},"text.on-primary":{description:"Text/icon colour with guaranteed contrast over bg.primary."},"text.on-danger":{description:"Text/icon colour with guaranteed contrast over bg.danger."},"space.medium":{description:"Base spacing step (1rem at normal density) \u2014 the layout rhythm unit."},"space.large":{description:"Comfortable spacing step \u2014 section padding and card gutters."},"spacing.md":{description:"Medium foundation spacing alias \u2014 references the space.medium primitive."},"spacing.lg":{description:"Large foundation spacing alias \u2014 references the space.large primitive."},"border.radius.md":{description:"Default card corner radius."},"border.width.thin":{description:"Hairline border \u2014 dividers and default input outlines."},"border.width.regular":{description:"Standard emphasis border \u2014 focused/active controls."}};function re(e){let n=Object.keys(te).filter(o=>!e.has(o));if(n.length>0)throw new Error(`token-meta: ${n.length} stale TOKEN_META key(s) resolve to no IR node: ${n.join(", ")}. Update src/token-meta.ts to match the current IR paths.`)}i(re,"assertTokenMetaResolves");var Mn=An("oklch");function h(e){return typeof e.type=="string"&&"value"in e}i(h,"isToken");function I(e){return e.replace(/([a-z])([A-Z])/g,"$1-$2").toLowerCase()}i(I,"kebab");function Re(e){return e.split(".").map(I).join(".")}i(Re,"kebabPath");function E(e){return e.kind==="ref"?e.resolved.raw:e.raw}i(E,"rawValue");function B(e,n){return Number(e.toFixed(n))||0}i(B,"round");function se(e){let n=Mn(Gn(e));if(!n)return{kind:"color",raw:e,components:[0,0,0],hex:"#000000"};let o=[B(n.l,4),B(n.c,4),B(n.h??0,2)],t=jn(n)??"#000000";return n.alpha!==void 0&&n.alpha!==1?{kind:"color",raw:e,components:o,alpha:B(n.alpha,4),hex:t}:{kind:"color",raw:e,components:o,hex:t}}i(se,"toColorValue");var ke=/^(-?(?:\d+\.?\d*|\.\d+))(px|rem)$/;function O(e){let n=ke.exec(e.trim());if(n)return{kind:"dimension",raw:e,value:Number(n[1]),unit:n[2]};let o=Number.parseFloat(e);return{kind:"dimension",raw:e,value:Number.isFinite(o)?o:0,unit:"rem"}}i(O,"toDimensionValue");function k(e){return{type:"color",value:se(e)}}i(k,"colorToken");function ie(e){let n={};for(let[o,t]of Object.entries(e))n[o]=k(t);return n}i(ie,"recordColorGroup");function Ie(e){let n=Cn(e),o={};for(let[t,r]of Object.entries(n.palettes))o[t]=k(r);return o.neutral=ie(n.neutral),o}i(Ie,"buildReadableTextGroup");var Pn=["main","opposite","complementary","primary","secondary","tertiary","success","danger","warning","information"];function xe(e){let n={};for(let o of Pn){let t=e[o];n[o]={base:k(t.base),dark:k(t.dark),action:k(t.action),active:k(t.active),light:k(t.light),onLight:k(t.onLight)}}return n.grayscale=ie(e.grayscale),n.neutral=ie(e.neutral),n.baseDark=k(e.baseDark??"#000000"),n.baseLight=k(e.baseLight??"#ffffff"),n.deepDark=k(e.deepDark??"#000000"),n.deepLight=k(e.deepLight??"#ffffff"),n}i(xe,"buildColorPrimitives");function Se(e){let n=_(be,e),o={};for(let t of Object.keys(be.alias))o[t]={type:"dimension",value:O(n(t))};return o}i(Se,"buildSpacePrimitives");function we(){let e={};for(let[n,o]of Object.entries(H.borderWidth))e[n]={type:"dimension",value:O(o)};return e}i(we,"buildBorderWidthPrimitives");function Nn(e,n){return{color:xe(e),space:Se(n),borderWidth:we()}}i(Nn,"buildPrimitives");var ve={primary:"color.primary.base",secondary:"color.secondary.base",tertiary:"color.tertiary.base",success:"color.success.base",danger:"color.danger.base",warning:"color.warning.base",info:"color.information.base"},De={onPrimary:"color.baseLight",onSecondary:"color.baseLight",onTertiary:"color.baseDark",onSuccess:"color.baseLight",onDanger:"color.baseLight",onWarning:"color.baseDark",onInfo:"color.baseLight"};function Fn(e,n){let o=e;for(let t of n.split(".").slice(1))if(o&&typeof o=="object"&&t in o)o=o[t];else return;return typeof o=="string"?o:void 0}i(Fn,"lookupPrimitive");function W(e,n,o){let t={};for(let[r,s]of Object.entries(e)){let a=o[r],c=a?Fn(n,a):void 0;t[r]=a&&c===s?{type:"color",value:{kind:"ref",path:a,resolved:se(s)}}:k(s)}return t}i(W,"colorRefGroup");var Te={xs:"space.xs",sm:"space.small",md:"space.medium",lg:"space.large",xl:"space.xl",xxl:"space.xxl"},Ln={none:"border-width.none",thin:"border-width.thin",regular:"border-width.regular",great:"border-width.great",bold:"border-width.bold"};function _n(e,n){let o=n.split("."),t=o[0]==="border-width"?"borderWidth":o[0],r=e[t];for(let s of o.slice(1))if(r&&!h(r)&&s in r)r=r[s];else return;return r&&h(r)&&r.value.kind==="dimension"?r.value.raw:void 0}i(_n,"lookupDimensionPrimitive");function ae(e,n,o){let t={};for(let[r,s]of Object.entries(e)){let a=o[r],c=a?_n(n,a):void 0;t[r]=a&&c===s?{type:"dimension",value:{kind:"ref",path:a,resolved:O(s)}}:{type:"dimension",value:O(s)}}return t}i(ae,"dimensionRefGroup");function $e(e){let n={},o={};for(let[s,a]of Object.entries(H.borderRadius))ke.test(a)?n[s]={type:"dimension",value:O(a)}:o[s]=a;let t=ae(H.borderWidth,e,Ln),r={};for(let[s,a]of Object.entries(H.borderStyle))r[s]={type:"strokeStyle",value:{kind:"strokeStyle",raw:a,style:a}};return{group:{radius:n,width:t,style:r},extensions:o}}i($e,"buildBorder");function Ce(e){let n=En(V,e),o={};for(let[c,l]of Object.entries(V.fontFamily)){let p=l.replace(/;\s*$/,"").trim();o[c]={type:"fontFamily",value:{kind:"fontFamily",raw:p,family:p}}}let t={};for(let[c,l]of Object.entries(n.fontSize))t[c]={type:"dimension",value:O(l)};let r={};for(let[c,l]of Object.entries(V.fontWeight))r[c]={type:"fontWeight",value:{kind:"fontWeight",raw:`${l}`,weight:l}};let s={};for(let[c,l]of Object.entries(V.lineHeight))s[c]={type:"number",value:{kind:"number",raw:`${l}`,number:l}};let a={letterSpacing:V.letterSpacing,textTransform:V.textTransform,fontStyle:V.fontStyle};return{group:{family:o,size:t,weight:r,lineHeight:s},extensions:a}}i(Ce,"buildFont");var Bn=/rgba?\([^)]*\)|#[0-9a-fA-F]+|[a-zA-Z]+$/;function Hn(e){let n=e.trim(),o=n.startsWith("inset");o&&(n=n.slice(5).trim());let t=n.match(Bn),r=t?t[0]:"#000000",a=(t?n.slice(0,t.index).trim():n).split(/\s+/).filter(Boolean),c=i(l=>O(a[l]??"0px"),"dim");return{kind:"shadow",raw:e,shadow:{color:se(r),offsetX:c(0),offsetY:c(1),blur:c(2),spread:c(3),inset:o}}}i(Hn,"parseShadow");function Ve(e){let n=Vn(e),o={};for(let t of Object.keys(On))o[t]={type:"shadow",value:Hn(n(t))};return o}i(Ve,"buildShadow");function J(e,n,o){let t={};for(let[r,s]of Object.entries(e)){let a=n?`${n}.${I(r)}`:I(r);if(h(s)){o.add(a);let c=te[a];t[r]=c&&(c.description!==void 0||c.deprecated!==void 0)?{...s,...c.description!==void 0?{description:c.description}:{},...c.deprecated!==void 0?{deprecated:c.deprecated}:{}}:s}else t[r]=J(s,a,o)}return t}i(J,"decorateGroup");function Wn(e){let n=new Set,o=J(e.primitives,"",n),t=J(e.groups,"",n);return re(n),{...e,primitives:o,groups:t}}i(Wn,"decorateMeta");function z(e,n){return J(e,"",n)}i(z,"decorateSlice");function Oe(e,n,o){for(let[t,r]of Object.entries(e)){let s=n?`${n}.${I(t)}`:I(t);h(r)?o.add(s):Oe(r,s,o)}}i(Oe,"collectPaths");function Ee(e){let n=new Set;for(let o of e)Oe(o.groups,"",n);re(n)}i(Ee,"assertSlicesMetaComplete");function Ae(){let e=we(),o=$e({borderWidth:e}),t={};Object.keys(o.extensions).length>0&&(t["com.apollion.border"]={radius:o.extensions});let r=new Set;return{groups:z({"border-width":e,border:o.group},r),extensions:t}}i(Ae,"buildBaseIR");function je(e){let n=Ce(e),o=new Set;return{groups:z({font:n.group},o),extensions:{"com.apollion.font":n.extensions}}}i(je,"buildFontIR");function Ge(e,n){let o=xe(n),t=new Set;return{groups:z({color:o,bg:W(e.bg,n,ve),text:W(e.text,n,De),tx:Ie(n),shadow:Ve(n)},t),extensions:{}}}i(Ge,"buildColorIR");function Me(e,n){let o=Se(n),t={space:o},r=new Set;return{groups:z({space:o,spacing:ae(e.spacing,t,Te)},r),extensions:{}}}i(Me,"buildSpacingIR");function Jn(e,n,o){let t={brand:o.brand,mode:o.mode,surface:o.surface,dimension:o.dimension},r=Nn(n,o.dimension),s=$e(r),a=Ce(o.dimension),c={"com.apollion.variant":t,"com.apollion.font":a.extensions};Object.keys(s.extensions).length>0&&(c["com.apollion.border"]={radius:s.extensions});let l={description:`Apollion DS tokens \u2014 DTCG 2025.10. Variant: ${t.brand}/${t.mode}/${t.surface}/${t.dimension}.`,meta:t,primitives:r,groups:{bg:W(e.bg,n,ve),text:W(e.text,n,De),tx:Ie(n),spacing:ae(e.spacing,r,Te),border:s.group,font:a.group,shadow:Ve(n)},extensions:c};return Wn(l)}i(Jn,"buildIR");var q=Jn;var Un=zn("rgb"),Pe="// Generated by apollion-tokens build \u2014 DO NOT EDIT. See apollion.config.mjs.";function ce(e){if(e.value.kind==="color")return e.value;if(e.value.kind==="ref"&&e.value.resolved.kind==="color")return e.value.resolved}i(ce,"colorPayload");function le(e){return e.alpha===void 0}i(le,"isOpaqueColor");function Ne(e){let n=Un(qn(e.hex));if(!n)return"0 0 0";let o=i(t=>Math.min(255,Math.max(0,Math.round(t*255))),"channel");return`${o(n.r)} ${o(n.g)} ${o(n.b)}`}i(Ne,"rgbTriplet");function U(e,n=[]){let o=new Map;for(let[t,r]of Object.entries(e)){let s=[...n,I(t)];if(h(r))o.set(s.join("-"),r);else for(let[a,c]of U(r,s))o.set(a,c)}return o}i(U,"flatTokens");function y(e,...n){let o=e[n[0]];for(let t of n.slice(1)){if(!o||h(o))return{};o=o[t]}return o&&!h(o)?o:{}}i(y,"groupAt");function Fe(e){let n=[];for(let o of["bg","text","tx"])for(let[t,r]of U(y(e.groups,o),[o])){let s=ce(r);s&&n.push({key:t,cssVar:`--apollion-${t}`,opaque:le(s)})}return n}i(Fe,"colorEntries");function T(e,n){return[...U(e)].map(([o])=>[o,`var(--apollion-${[...n,o].join("-")})`])}i(T,"varEntries");function $(e,n,o){if(o.length!==0){e.push(` ${n}: {`);for(let[t,r]of o)e.push(` ${JSON.stringify(t)}: ${JSON.stringify(r)},`);e.push(" },")}}i($,"pushScale");function Le(e){let n=[Pe,"// Tailwind preset over the Apollion foundation tokens \u2014 requires dist/css/ vars in scope.","","const preset = {"," theme: {"," extend: {"],o=Fe(e);n.push(" colors: {");for(let{key:t,cssVar:r,opaque:s}of o)s?n.push(` ${JSON.stringify(t)}: ${JSON.stringify(`rgb(var(${r}-rgb) / <alpha-value>)`)},`):(n.push(` // ${t} carries its own alpha \u2014 excluded from the <alpha-value> modifier form.`),n.push(` ${JSON.stringify(t)}: ${JSON.stringify(`var(${r})`)},`));return n.push(" },"),$(n,"spacing",T(y(e.groups,"spacing"),["spacing"])),$(n,"borderRadius",T(y(e.groups,"border","radius"),["border","radius"])),$(n,"borderWidth",T(y(e.groups,"border","width"),["border","width"])),$(n,"fontFamily",T(y(e.groups,"font","family"),["font","family"])),$(n,"fontSize",T(y(e.groups,"font","size"),["font","size"])),$(n,"fontWeight",T(y(e.groups,"font","weight"),["font","weight"])),$(n,"lineHeight",T(y(e.groups,"font","lineHeight"),["font","line-height"])),$(n,"boxShadow",T(y(e.groups,"shadow"),["shadow"])),n.push(" },"," },","};","","export default preset;",""),n.join(`
3
+ `)}i(Le,"renderTailwindPreset");function _e(e){let n=i(r=>[...U(r).keys()],"keys"),o=i(r=>`[${r.map(s=>JSON.stringify(s)).join(", ")}]`,"list");return[Pe,"// tailwind-merge extension for the generated preset \u2014 pass to extendTailwindMerge().","","export const twMergeExtension = {"," extend: {"," theme: {",` colors: ${o(Fe(e).map(r=>r.key))},`,` spacing: ${o(n(y(e.groups,"spacing")))},`,` borderRadius: ${o(n(y(e.groups,"border","radius")))},`,` borderWidth: ${o(n(y(e.groups,"border","width")))},`," },"," classGroups: {",` 'font-family': [{ font: ${o(n(y(e.groups,"font","family")))} }],`,` 'font-size': [{ text: ${o(n(y(e.groups,"font","size")))} }],`,` 'font-weight': [{ font: ${o(n(y(e.groups,"font","weight")))} }],`,` leading: [{ leading: ${o(n(y(e.groups,"font","lineHeight")))} }],`,` shadow: [{ shadow: ${o(n(y(e.groups,"shadow")))} }],`," },"," },","};",""].join(`
4
+ `)}i(_e,"renderTwMergeExtension");var Xn="/* Generated by apollion-tokens build \u2014 DO NOT EDIT. See apollion.config.mjs. */";function Be(e,n,o){for(let[t,r]of Object.entries(e)){let s=[...n,I(t)];h(r)?o.push(` --apollion-${s.join("-")}: ${E(r.value)};`):Be(r,s,o)}}i(Be,"emitVars");function He(e,n,o){for(let[t,r]of Object.entries(e)){let s=[...n,I(t)];if(!h(r)){He(r,s,o);continue}let a=ce(r);a&&le(a)&&o.push(` --apollion-${s.join("-")}-rgb: ${Ne(a)};`)}}i(He,"emitRgbVars");function We(e,n,o){for(let[t,r]of Object.entries(e)){let s=[...n,I(t)];h(r)?r.type==="color"&&o.push(` @property --apollion-${s.join("-")} { syntax: '<color>'; inherits: true; initial-value: ${E(r.value)}; }`):We(r,s,o)}}i(We,"emitProperties");function Je(e,n={}){let{brand:o,mode:t,surface:r,dimension:s}=e.meta,a=[Xn,""];return a.push(`/* Variant: brand=${o} mode=${t} surface=${r} dimension=${s} */`,"",":root {"),Be(e.groups,[],a),n.rgbCompanions&&(a.push(""," /* -rgb channel triplets \u2014 Tailwind <alpha-value> companions (opaque colour tokens only). */"),He(e.groups,[],a)),a.push("}",""),a.push("@supports (background: paint(squircle)) or (color: oklch(0% 0 0)) {"),We(e.groups,[],a),a.push("}",""),a.join(`
5
+ `)}i(Je,"renderCss");var Yn="<!-- Generated by apollion-tokens build \u2014 DO NOT EDIT. See apollion.config.mjs. -->";function ue(e,n,o){for(let[t,r]of Object.entries(e)){let s=n?`${n}.${t}`:t;h(r)?o.push([s,E(r.value)]):ue(r,s,o)}}i(ue,"flatten");function Kn(e){return typeof e=="number"?String(e):`'${String(e).replace(/'/g,"''")}'`}i(Kn,"yamlEscape");function Zn(e){let{mode:n,surface:o,dimension:t}=e.meta;return`${n}.${o}.${t}`}i(Zn,"variantKey");function ze(e,n){if(n.length===0)throw new Error(`renderDesignMd: no variants for brand "${e}"`);let o=["---",`brand: '${e}'`,"generator: apollion-tokens","variants:"];for(let r of n){let s=[];ue(r.groups,"",s),o.push(` ${Zn(r)}:`);for(let[a,c]of s)o.push(` ${a}: ${Kn(c)}`)}o.push("---");let t=["",Yn,"",`# Design.md \u2014 ${e}`,"","Resolved design-token values for this brand, one section per variant.","Consumption rules (which token to reach for, layer boundaries) live in the","package `llms.txt`; this file carries the values those rules reference.","Regenerate with `apollion-tokens build` \u2014 never edit.",""];for(let r of n){let{mode:s,surface:a,dimension:c}=r.meta;t.push(`## Variant \`${s} \xB7 ${a} \xB7 ${c}\``,"");let l=[];ue(r.groups,"",l);let p=new Map;for(let[R,D]of l){let u=R.split(".")[0]??R,g=p.get(u)??[];g.push([R,D]),p.set(u,g)}for(let[R,D]of p){t.push(`### ${R}`,"","| Token | Value |","| --- | --- |");for(let[u,g]of D)t.push(`| \`${u}\` | \`${g}\` |`);t.push("")}}return`${o.join(`
6
+ `)}
7
+ ${t.join(`
8
+ `)}`}i(ze,"renderDesignMd");function qe(e){return e.alpha!==void 0?{colorSpace:"oklch",components:[...e.components],alpha:e.alpha,hex:e.hex}:{colorSpace:"oklch",components:[...e.components],hex:e.hex}}i(qe,"colorValue");function P(e){return{value:e.value,unit:e.unit}}i(P,"dimensionValue");function Qn(e){let n=e.shadow,o={color:qe(n.color),offsetX:P(n.offsetX),offsetY:P(n.offsetY),blur:P(n.blur),spread:P(n.spread)};return n.inset&&(o.inset=!0),o}i(Qn,"shadowValue");function eo(e){switch(e.kind){case"ref":return`{${Re(e.path)}}`;case"color":return qe(e);case"dimension":return P(e);case"fontFamily":return e.family;case"fontWeight":return e.weight;case"number":return e.number;case"strokeStyle":return e.style;case"shadow":return Qn(e)}}i(eo,"projectValue");function no(e){let n={$value:eo(e.value),$type:e.type};return e.description!==void 0&&(n.$description=e.description),e.deprecated!==void 0&&(n.$deprecated=e.deprecated),n}i(no,"projectToken");function de(e){let n={};for(let[o,t]of Object.entries(e))n[I(o)]=h(t)?no(t):de(t);return n}i(de,"projectGroup");function X(e,n){let o={$description:n,...de(e.groups)};return Object.keys(e.extensions).length>0&&(o.$extensions=e.extensions),`${JSON.stringify(o,null,2)}
9
+ `}i(X,"renderSet");function Ue(e){return X(e,"Apollion DS \u2014 base set (axis-invariant: border). DTCG 2025.10.")}i(Ue,"renderBaseSet");function Xe(e,n,o,t){return X(e,`Apollion DS \u2014 colour set. brand=${n} mode=${o} surface=${t}. DTCG 2025.10.`)}i(Xe,"renderColorSet");function Ye(e,n){return X(e,`Apollion DS \u2014 spacing set. dimension=${n}. DTCG 2025.10.`)}i(Ye,"renderSpacingSet");function Ke(e,n){return X(e,`Apollion DS \u2014 font set. dimension=${n}. DTCG 2025.10.`)}i(Ke,"renderFontSet");function Ze(e,n){let{modifiers:o}=n,t=[{name:"brand",values:[...o.brand],default:o.brand[0]},{name:"mode",values:[...o.mode],default:o.mode[0]},{name:"surface",values:[...o.surface],default:o.surface[0]},{name:"dimension",values:[...o.dimension],default:o.dimension[0]}],s={name:"apollion-tokens",description:"Apollion DS token resolver \u2014 DTCG 2025.10. Compose the base set with the colour set for the chosen brand/mode/surface and the spacing + font sets for the chosen dimension. NOTE: mode is a topology placeholder in this release (dark resolves identically to light until S6).",sets:[{name:n.base.name,source:n.base.file},...n.spacing.map(a=>({name:a.name,source:a.file})),...n.font.map(a=>({name:a.name,source:a.file})),...n.color.map(a=>({name:a.name,source:a.file}))],modifiers:t,$extensions:{"com.apollion.resolver":{composition:{always:[n.base.name],byModifier:{color:"${brand}.color.${mode}.${surface}",spacing:"spacing.${dimension}",font:"font.${dimension}"}},modeIsPlaceholder:!0}}};return`${JSON.stringify(s,null,2)}
10
+ `}i(Ze,"renderResolver");var oo="// Generated by apollion-tokens build \u2014 DO NOT EDIT. See apollion.config.mjs.";function to(e,n,o){let t=[];if(e.description!==void 0&&t.push(e.description),e.deprecated===!0?t.push("@deprecated"):typeof e.deprecated=="string"&&t.push(`@deprecated ${e.deprecated}`),t.length!==0){o.push(`${n}/**`);for(let r of t)o.push(`${n} * ${r.replace(/\*\//g,"*\\/")}`);o.push(`${n} */`)}}i(to,"emitDoc");function Qe(e,n,o){let t=" ".repeat(n);for(let[r,s]of Object.entries(e))h(s)?(to(s,t,o),o.push(`${t}${JSON.stringify(r)}: ${JSON.stringify(E(s.value))},`)):(o.push(`${t}${r}: {`),Qe(s,n+1,o),o.push(`${t}},`))}i(Qe,"emitGroup");function en(e){let{brand:n,mode:o,surface:t,dimension:r}=e.meta,s=[oo,`// Variant: brand=${n} mode=${o} surface=${t} dimension=${r}`,"","export const tokens = {"];return Qe(e.groups,1,s),s.push("} as const;","","export type Tokens = typeof tokens;",""),s.join(`
11
+ `)}i(en,"renderTs");var ro=["light","dark"],io=["positive","negative"],so=["compact","normal","spacious"];function Y(e){let n=e.modes??ro,o=e.surfaces??io,t=e.dimensions??so,r=Object.entries(e.brands).sort(([a],[c])=>a.localeCompare(c)),s=[];for(let[a,c]of r)for(let l of n)for(let p of o)for(let R of t)s.push({brand:a,colors:c,mode:l,surface:p,dimension:R});return s}i(Y,"expandVariants");function nn(e){return`${e.brand}.${e.mode}.${e.surface}.${e.dimension}`}i(nn,"variantName");import{createHash as ao}from"node:crypto";function K(e){return ao("sha256").update(e).digest("hex")}i(K,"sha256");function fe(e){return K(pe(e))}i(fe,"hashConfig");function pe(e){return e===null||typeof e!="object"?JSON.stringify(e):Array.isArray(e)?`[${e.map(pe).join(",")}]`:`{${Object.keys(e).sort().map(t=>`${JSON.stringify(t)}:${pe(e[t])}`).join(",")}}`}i(pe,"stableStringify");function on(e){try{let{execSync:n}=Tn("node:child_process");return n("git rev-parse --short HEAD",{cwd:e,stdio:["ignore","pipe","ignore"],encoding:"utf8"}).trim()}catch{return""}}i(on,"detectGitCommit");function tn(){return{node:process.version,platform:`${process.platform}-${process.arch}`}}i(tn,"buildEnv");function rn(e){let n=[...e.files].sort((t,r)=>t.path.localeCompare(r.path)),o={configHash:e.configHash,files:n,gitCommit:e.gitCommit,buildEnv:e.buildEnv};return`${JSON.stringify(o,null,2)}
12
+ `}i(rn,"serializeManifest");var co="json/sets",sn="json/resolver.json";function Z(e){return`${co}/${e}.json`}i(Z,"setFile");function lo(e,n,o){return`${e}.color.${n}.${o}`}i(lo,"colorSetName");function uo(e){return`spacing.${e}`}i(uo,"spacingSetName");function po(e){return`font.${e}`}i(po,"fontSetName");function Q(e,n){e.includes(n)||e.push(n)}i(Q,"pushUnique");function an(e){let n=Y(e),o=[],t=[],r=[],s=[],a=new Set,c=[],l=new Set,p=[],R=new Set,D=[];for(let u of n){Q(o,u.brand),Q(t,u.mode),Q(r,u.surface),Q(s,u.dimension);let g=lo(u.brand,u.mode,u.surface);a.has(g)||(a.add(g),c.push({kind:"color",name:g,file:Z(g),brand:u.brand,mode:u.mode,surface:u.surface}));let x=uo(u.dimension);l.has(x)||(l.add(x),p.push({kind:"spacing",name:x,file:Z(x),dimension:u.dimension}));let f=po(u.dimension);R.has(f)||(R.add(f),D.push({kind:"font",name:f,file:Z(f),dimension:u.dimension}))}return{base:{kind:"base",name:"base",file:Z("base")},spacing:p,font:D,color:c,modifiers:{brand:o,mode:t,surface:r,dimension:s}}}i(an,"planSets");import{createFoundation as hn}from"@apollion-dsi/core/themes/foundation";import{createSemantic as Ro}from"@apollion-dsi/core/themes/semantic";import{defaultInputSpacing as ko}from"@apollion-dsi/core/themes/spacing";import{invertForSurface as Io}from"@apollion-dsi/core/themes/surface";import{converter as fo,formatHex as N,interpolate as go,parse as v,wcagContrast as fn}from"culori";var me=fo("oklch");function d(e,n,o){let t=v(e),r=v(n);if(!t||!r)return e;let s=go([t,r],"oklch");return N(s(o))??e}i(d,"mixOklch");function mo(e){return e?typeof e=="string"?e:e.base:"#000"}i(mo,"coerceToHex");var ee=1.3,ho=.05,cn=.04,C=i((e,n)=>{let o=v(e),t=v(n);return!o||!t?1:fn(o,t)},"contrastRatio"),ge=i(e=>{let n=me(v(e));return n?n.l??0:null},"oklchLightness"),yo=4.5;function ln(e,n,o=yo){let t=v(n),r=me(v(e));if(!t||!r)return e;let s=C("#fff",n)>=C("#000",n)?.04:-.04;for(let a=0;a<25;a+=1){let c=N(r)??e,l=v(c);if(l&&fn(l,t)>=o)return c;let p=Math.min(1,Math.max(0,(r.l??0)+s));if(p===(r.l??0))break;r={...r,l:p}}return N(r)??e}i(ln,"readableColor");var un=i((e,n)=>{if(C(e,n)>=ee)return!0;let o=ge(e),t=ge(n);return o!==null&&t!==null&&Math.abs(o-t)>=ho},"isPerceptibleState"),bo=i(e=>e?C("#fff",e)>C("#000",e):!1,"isDarkSurface");function dn(e,n,o){let t=me(v(e));if(!t)return null;let r={...t,l:o??t.l??0},s=n?cn:-cn;for(let a=0;a<25;a+=1){let c=Math.min(1,Math.max(0,(r.l??0)+s));if(c===(r.l??0))break;r={...r,l:c};let l=N(r);if(l&&C(e,l)>=ee)return l}return N(r)??null}i(dn,"derivePerceptibleState");function pn(e,n,o){let t=dn(e,n,o);if(t&&C(e,t)>=ee)return t;let r=dn(e,!n);return r&&C(e,r)>=ee?r:t??r}i(pn,"perceptibleStateFor");function w(e,n){let o=typeof e=="object"&&e!==null?e:void 0,t=mo(e),r=n.deepDark,s=n.deepLight,a={base:t,dark:d(t,r,.6),action:d(t,r,.2),active:d(t,s,.6),light:d(t,s,.9),onLight:t};if(v(t)){let c=bo(n.baseLight),l=un(t,a.action);if(l||(a.action=pn(t,c)??a.action),!un(t,a.active)){let p=l?void 0:ge(a.action)??void 0;a.active=pn(t,c,p)??a.active}}if(a.onLight=ln(a.action,a.light),o){let c=o.action??a.action,l=o.light??a.light;return{base:t,dark:o.dark??a.dark,action:c,active:o.active??a.active,light:l,onLight:o.onLight??ln(c,l)}}return a}i(w,"mountSingleColor");function gn(e){let n=e.deepLight,o=e.deepDark;return{0:n,5:d(n,o,.05),10:d(n,o,.1),20:d(n,o,.2),30:d(n,o,.3),40:d(n,o,.4),50:d(n,o,.5),60:d(n,o,.6),70:d(n,o,.7),80:d(n,o,.8),90:d(n,o,.9),100:d(n,o,1)}}i(gn,"mountGreyscaleColors");function mn(e){let n=e.deepLight,o=e.deepDark,t=typeof e.primary=="object"&&e.primary?e.primary.base:e.primary,r=i(a=>1/17*(a-1),"interpolation"),s=d(t,o,.5);return{0:d(s,n,r(18)),5:d(s,n,r(17.5)),10:d(s,n,r(17)),20:d(s,n,r(16)),30:d(s,n,r(15)),40:d(s,n,r(14)),50:d(s,n,r(13)),60:d(s,n,r(12)),70:d(s,n,r(11)),80:d(s,n,r(10)),90:d(s,n,r(9)),100:d(s,n,r(8)),110:d(s,n,r(7)),120:d(s,n,r(6)),130:d(s,n,r(5)),140:d(s,n,r(4)),150:d(s,n,r(3)),160:d(s,n,r(2)),170:s,180:d(s,o,.25)}}i(mn,"mountNeutralColors");function xo(e){return{...e,baseDark:e.baseLight,baseLight:e.baseDark,deepDark:e.deepLight,deepLight:e.deepDark}}i(xo,"toCanonicalDarkInput");function So(e){return{baseDark:e.baseDark,baseLight:e.baseLight,deepDark:e.deepDark,deepLight:e.deepLight,transparent:e.transparent??"transparent",neutral:mn(e),grayscale:gn(e),main:w(e.main,e),opposite:w(e.opposite,e),complementary:w(e.complementary,e),danger:w(e.danger,e),information:w(e.information,e),success:w(e.success,e),warning:w(e.warning,e),primary:w(e.primary,e),secondary:w(e.secondary,e),tertiary:w(e.tertiary,e)}}i(So,"composeColors");function G(e,n=ko){let o=e.mode==="dark"?xo(e.colors):e.colors,t=So(o),r=_(n,e.dimension),s=Ro({colors:t,spacing:r}),a=hn(s);return e.surface==="negative"&&(a=hn(Io({semantic:s,colors:t},"negative").semantic)),{foundation:a,colors:t}}i(G,"buildVariantThemes");async function xn(e){let{config:n,outDir:o,cwd:t=process.cwd(),verbose:r=!1}=e,s=Y(n),a=n.output??{};if(s.length===0)throw new Error("apollion-tokens build: no variants (config.brands is empty)");let c=await wo(F(Do(),"apollion-tokens-"));try{let l=[],p=i(async(u,g)=>{await To(c,u,g),l.push({path:u,sha256:K(g)}),r&&console.log(` \u2713 ${u}`)},"emit");if(a.json){let u=an(n),g=[],x=Ae();g.push(x),await p(u.base.file,Ue(x));for(let f of u.spacing){let b=s.find(L=>L.dimension===f.dimension),{foundation:M}=G(b),j=Me(M,f.dimension);g.push(j),await p(f.file,Ye(j,f.dimension))}for(let f of u.font){let b=je(f.dimension);g.push(b),await p(f.file,Ke(b,f.dimension))}for(let f of u.color){let b=s.find(oe=>oe.brand===f.brand&&oe.mode===f.mode&&oe.surface===f.surface),{foundation:M,colors:j}=G(b),L=Ge(M,j);g.push(L),await p(f.file,Xe(L,f.brand,f.mode,f.surface))}Ee(g),await p(sn,Ze(n,u))}if(a.css||a.ts)for(let u of s){let{foundation:g,colors:x}=G(u),f=q(g,x,u),b=nn(u);a.css&&await p(`css/${b}.css`,Je(f,{rgbCompanions:a.tailwind})),a.ts&&await p(`ts/${b}.d.ts`,en(f))}if(a.tailwind){let u=s[0],{foundation:g,colors:x}=G(u),f=q(g,x,u);await p("tailwind/preset.mjs",Le(f)),await p("tailwind/tw-merge.mjs",_e(f))}if(a.designMd){let u=[...new Set(s.map(g=>g.brand))];for(let g of u){let f=s.filter(b=>b.brand===g).map(b=>{let{foundation:M,colors:j}=G(b);return q(M,j,b)});await p(`design/${g}.design.md`,ze(g,f))}}let R={configHash:fe(n),files:l,gitCommit:on(t),buildEnv:tn()},D=rn(R);return await kn(F(c,"manifest.json"),D),await bn(o,{recursive:!0,force:!0}),await Rn(In(o),{recursive:!0}),await vo(c,o),r&&console.log(`\u2713 ${l.length} files \u2192 ${o}`),{manifest:R,outDir:o}}catch(l){throw await bn(c,{recursive:!0,force:!0}).catch(()=>{}),l}}i(xn,"build");async function Sn(e){let{config:n,outDir:o}=e,t;try{t=JSON.parse(await yn(F(o,"manifest.json"),"utf8"))}catch{return!1}if(t.configHash!==fe(n))return!1;for(let r of t.files){let s;try{s=await yn(F(o,r.path))}catch{return!1}if(K(s)!==r.sha256)return!1}return!0}i(Sn,"check");async function To(e,n,o){let t=F(e,n);await Rn(In(t),{recursive:!0}),await kn(t,o)}i(To,"writeAt");import{readFile as Co}from"node:fs/promises";import{resolve as Vo}from"node:path";import{createContext as Oo,Script as Eo}from"node:vm";import{z as m}from"zod";var S=m.string().regex(/^#([0-9a-fA-F]{3}){1,2}$|^transparent$|^rgb\(.*\)$|^oklch\(.*\)$/,{message:'Must be hex, rgb(), oklch(), or "transparent"'}),$o=m.object({baseDark:m.string().optional(),baseLight:m.string().optional(),deepDark:S,deepLight:S,transparent:m.string().optional(),main:S.optional(),opposite:S.optional(),complementary:S.optional(),information:S.optional(),success:S.optional(),danger:S.optional(),warning:S.optional(),primary:S.optional(),secondary:S.optional(),tertiary:S.optional()}).passthrough(),wn=m.object({brands:m.record(m.string(),$o).refine(e=>Object.keys(e).length>0,{message:"apollion.config.mjs: brands must contain at least 1 entry"}),modes:m.array(m.enum(["light","dark"])).optional(),surfaces:m.array(m.enum(["positive","negative"])).optional(),dimensions:m.array(m.enum(["compact","normal","spacious"])).optional(),output:m.object({runtime:m.boolean().optional(),css:m.boolean().optional(),json:m.boolean().optional(),ts:m.boolean().optional(),designMd:m.boolean().optional(),tailwind:m.boolean().optional()}).passthrough().optional()}).passthrough();var Ao=[/\brequire\s*\(/,/\bimport\s*\(/,/^\s*import\s+/m],jo=1e3;var he=class he extends Error{constructor(o,t){super(o);this.configPath=t;this.name="ConfigLoadError"}};i(he,"ConfigLoadError");var A=he;async function vn(e){let n=Vo(e.configPath),o=await Co(n,"utf8");for(let l of Ao)if(l.test(o))throw new A(`apollion.config: dynamic require/import not allowed (matched ${l}). Declarative config only \u2014 see ADR-006 \xA73.8 B3.`,n);let t=o.replace(/(^|\n)\s*export\s+default\s+/,(l,p)=>`${p}__apollion_config_export = `);if(t===o)throw new A("apollion.config: missing `export default <object>;` \u2014 config must export a default object literal.",n);let r={__apollion_config_export:void 0,console:Go(),Symbol,Number,String,Boolean,Array,Object,JSON,Math,defineConfig:i(l=>l,"defineConfig")},s=Oo(r);try{new Eo(t,{filename:n}).runInContext(s,{timeout:jo})}catch(l){throw new A(`apollion.config: evaluation failed \u2014 ${l instanceof Error?l.message:String(l)}`,n)}let a=r.__apollion_config_export;if(a===void 0)throw new A("apollion.config: `export default` produced undefined.",n);let c=wn.safeParse(a);if(!c.success){let l=c.error.issues.map(p=>` ${p.path.join(".")||"(root)"}: ${p.message}`).join(`
13
+ `);throw new A(`apollion.config: schema validation failed \u2014
14
+ ${l}`,n)}return c.data}i(vn,"loadConfig");function Go(){return{log:i((...e)=>console.log("[apollion.config]",...e),"log"),warn:i((...e)=>console.warn("[apollion.config]",...e),"warn"),error:i((...e)=>console.error("[apollion.config]",...e),"error")}}i(Go,"makeReadOnlyConsole");function Po(e){let n=e.slice(2),o=n[0];o!=="build"&&ne(`Unknown command "${o??""}". Usage: apollion-tokens build [--check] [--verbose] --config <path> [--out <dir>]`);let t="apollion.config.mjs",r="dist",s=!1,a=!1;for(let c=1;c<n.length;c++){let l=n[c];switch(l){case"--config":t=n[++c]??ne("--config needs a path");break;case"--out":r=n[++c]??ne("--out needs a path");break;case"--check":s=!0;break;case"--verbose":a=!0;break;default:ne(`Unknown flag "${l}"`)}}return{command:o,configPath:t,outDir:r,check:s,verbose:a}}i(Po,"parseArgs");function ne(e){console.error(`apollion-tokens: ${e}`),process.exit(2)}i(ne,"fail");async function No(e){let n=ye(e);if(n.endsWith(".json")){let o=await Mo(n,"utf8");return JSON.parse(o)}return vn({configPath:n})}i(No,"loadConfigFromPath");async function Fo(){let e=Po(process.argv),n=await No(e.configPath);if(e.check){await Sn({config:n,outDir:ye(e.outDir)})||(console.error("apollion-tokens: dist/ is stale, missing, or has drifted from its manifest. Re-run `apollion-tokens build` without --check."),process.exit(1)),console.log("apollion-tokens: dist/ is up-to-date with config.");return}let{manifest:o}=await xn({config:n,outDir:ye(e.outDir),verbose:e.verbose});console.log(`apollion-tokens: wrote ${o.files.length} file(s) \u2014 configHash=${o.configHash.slice(0,12)}\u2026`)}i(Fo,"main");Fo().catch(e=>{console.error(`apollion-tokens: ${e instanceof Error?e.message:String(e)}`),process.exit(1)});
@@ -1,3 +1,3 @@
1
- "use strict";var f=Object.defineProperty;var y=Object.getOwnPropertyDescriptor;var C=Object.getOwnPropertyNames;var _=Object.prototype.hasOwnProperty;var a=(o,n)=>f(o,"name",{value:n,configurable:!0});var k=(o,n)=>{for(var r in n)f(o,r,{get:n[r],enumerable:!0})},j=(o,n,r,p)=>{if(n&&typeof n=="object"||typeof n=="function")for(let s of C(n))!_.call(o,s)&&s!==r&&f(o,s,{get:()=>n[s],enumerable:!(p=y(n,s))||p.enumerable});return o};var A=o=>j(f({},"__esModule",{value:!0}),o);var v={};k(v,{ConfigLoadError:()=>l,defineConfig:()=>P,loadConfig:()=>D});module.exports=A(v);var b=require("node:fs/promises"),w=require("node:path"),g=require("node:vm");var t=require("zod"),i=t.z.string().regex(/^#([0-9a-fA-F]{3}){1,2}$|^transparent$|^rgb\(.*\)$|^oklch\(.*\)$/,{message:'Must be hex, rgb(), oklch(), or "transparent"'}),S=t.z.object({baseDark:t.z.string().optional(),baseLight:t.z.string().optional(),deepDark:i,deepLight:i,transparent:t.z.string().optional(),main:i.optional(),opposite:i.optional(),complementary:i.optional(),information:i.optional(),success:i.optional(),danger:i.optional(),warning:i.optional(),primary:i.optional(),secondary:i.optional(),tertiary:i.optional()}).passthrough(),h=t.z.object({brands:t.z.record(t.z.string(),S).refine(o=>Object.keys(o).length>0,{message:"apollion.config.mjs: brands must contain at least 1 entry"}),modes:t.z.array(t.z.enum(["light","dark"])).optional(),surfaces:t.z.array(t.z.enum(["positive","negative"])).optional(),dimensions:t.z.array(t.z.enum(["compact","normal","spacious"])).optional(),output:t.z.object({runtime:t.z.boolean().optional(),css:t.z.boolean().optional(),json:t.z.boolean().optional(),ts:t.z.boolean().optional()}).passthrough().optional()}).passthrough();var $=[/\brequire\s*\(/,/\bimport\s*\(/,/^\s*import\s+/m],O=1e3;function P(o){return o}a(P,"defineConfig");var u=class u extends Error{constructor(r,p){super(r);this.configPath=p;this.name="ConfigLoadError"}};a(u,"ConfigLoadError");var l=u;async function D(o){let n=(0,w.resolve)(o.configPath),r=await(0,b.readFile)(n,"utf8");for(let e of $)if(e.test(r))throw new l(`apollion.config: dynamic require/import not allowed (matched ${e}). Declarative config only \u2014 see ADR-006 \xA73.8 B3.`,n);let p=r.replace(/(^|\n)\s*export\s+default\s+/,(e,c)=>`${c}__apollion_config_export = `);if(p===r)throw new l("apollion.config: missing `export default <object>;` \u2014 config must export a default object literal.",n);let s={__apollion_config_export:void 0,console:T(),Symbol,Number,String,Boolean,Array,Object,JSON,Math,defineConfig:a(e=>e,"defineConfig")},x=(0,g.createContext)(s);try{new g.Script(p,{filename:n}).runInContext(x,{timeout:O})}catch(e){throw new l(`apollion.config: evaluation failed \u2014 ${e instanceof Error?e.message:String(e)}`,n)}let d=s.__apollion_config_export;if(d===void 0)throw new l("apollion.config: `export default` produced undefined.",n);let m=h.safeParse(d);if(!m.success){let e=m.error.issues.map(c=>` ${c.path.join(".")||"(root)"}: ${c.message}`).join(`
1
+ "use strict";var f=Object.defineProperty;var y=Object.getOwnPropertyDescriptor;var C=Object.getOwnPropertyNames;var _=Object.prototype.hasOwnProperty;var a=(n,t)=>f(n,"name",{value:t,configurable:!0});var k=(n,t)=>{for(var r in t)f(n,r,{get:t[r],enumerable:!0})},j=(n,t,r,p)=>{if(t&&typeof t=="object"||typeof t=="function")for(let s of C(t))!_.call(n,s)&&s!==r&&f(n,s,{get:()=>t[s],enumerable:!(p=y(t,s))||p.enumerable});return n};var A=n=>j(f({},"__esModule",{value:!0}),n);var v={};k(v,{ConfigLoadError:()=>l,defineConfig:()=>P,loadConfig:()=>D});module.exports=A(v);var b=require("node:fs/promises"),w=require("node:path"),g=require("node:vm");var o=require("zod"),i=o.z.string().regex(/^#([0-9a-fA-F]{3}){1,2}$|^transparent$|^rgb\(.*\)$|^oklch\(.*\)$/,{message:'Must be hex, rgb(), oklch(), or "transparent"'}),S=o.z.object({baseDark:o.z.string().optional(),baseLight:o.z.string().optional(),deepDark:i,deepLight:i,transparent:o.z.string().optional(),main:i.optional(),opposite:i.optional(),complementary:i.optional(),information:i.optional(),success:i.optional(),danger:i.optional(),warning:i.optional(),primary:i.optional(),secondary:i.optional(),tertiary:i.optional()}).passthrough(),h=o.z.object({brands:o.z.record(o.z.string(),S).refine(n=>Object.keys(n).length>0,{message:"apollion.config.mjs: brands must contain at least 1 entry"}),modes:o.z.array(o.z.enum(["light","dark"])).optional(),surfaces:o.z.array(o.z.enum(["positive","negative"])).optional(),dimensions:o.z.array(o.z.enum(["compact","normal","spacious"])).optional(),output:o.z.object({runtime:o.z.boolean().optional(),css:o.z.boolean().optional(),json:o.z.boolean().optional(),ts:o.z.boolean().optional(),designMd:o.z.boolean().optional(),tailwind:o.z.boolean().optional()}).passthrough().optional()}).passthrough();var $=[/\brequire\s*\(/,/\bimport\s*\(/,/^\s*import\s+/m],O=1e3;function P(n){return n}a(P,"defineConfig");var u=class u extends Error{constructor(r,p){super(r);this.configPath=p;this.name="ConfigLoadError"}};a(u,"ConfigLoadError");var l=u;async function D(n){let t=(0,w.resolve)(n.configPath),r=await(0,b.readFile)(t,"utf8");for(let e of $)if(e.test(r))throw new l(`apollion.config: dynamic require/import not allowed (matched ${e}). Declarative config only \u2014 see ADR-006 \xA73.8 B3.`,t);let p=r.replace(/(^|\n)\s*export\s+default\s+/,(e,c)=>`${c}__apollion_config_export = `);if(p===r)throw new l("apollion.config: missing `export default <object>;` \u2014 config must export a default object literal.",t);let s={__apollion_config_export:void 0,console:T(),Symbol,Number,String,Boolean,Array,Object,JSON,Math,defineConfig:a(e=>e,"defineConfig")},x=(0,g.createContext)(s);try{new g.Script(p,{filename:t}).runInContext(x,{timeout:O})}catch(e){throw new l(`apollion.config: evaluation failed \u2014 ${e instanceof Error?e.message:String(e)}`,t)}let d=s.__apollion_config_export;if(d===void 0)throw new l("apollion.config: `export default` produced undefined.",t);let m=h.safeParse(d);if(!m.success){let e=m.error.issues.map(c=>` ${c.path.join(".")||"(root)"}: ${c.message}`).join(`
2
2
  `);throw new l(`apollion.config: schema validation failed \u2014
3
- ${e}`,n)}return m.data}a(D,"loadConfig");function T(){return{log:a((...o)=>console.log("[apollion.config]",...o),"log"),warn:a((...o)=>console.warn("[apollion.config]",...o),"warn"),error:a((...o)=>console.error("[apollion.config]",...o),"error")}}a(T,"makeReadOnlyConsole");0&&(module.exports={ConfigLoadError,defineConfig,loadConfig});
3
+ ${e}`,t)}return m.data}a(D,"loadConfig");function T(){return{log:a((...n)=>console.log("[apollion.config]",...n),"log"),warn:a((...n)=>console.warn("[apollion.config]",...n),"warn"),error:a((...n)=>console.error("[apollion.config]",...n),"error")}}a(T,"makeReadOnlyConsole");0&&(module.exports={ConfigLoadError,defineConfig,loadConfig});
@@ -1,3 +1,3 @@
1
- var h=Object.defineProperty;var r=(n,i)=>h(n,"name",{value:i,configurable:!0});import{readFile as w}from"node:fs/promises";import{resolve as x}from"node:path";import{createContext as y,Script as C}from"node:vm";import{z as o}from"zod";var e=o.string().regex(/^#([0-9a-fA-F]{3}){1,2}$|^transparent$|^rgb\(.*\)$|^oklch\(.*\)$/,{message:'Must be hex, rgb(), oklch(), or "transparent"'}),b=o.object({baseDark:o.string().optional(),baseLight:o.string().optional(),deepDark:e,deepLight:e,transparent:o.string().optional(),main:e.optional(),opposite:e.optional(),complementary:e.optional(),information:e.optional(),success:e.optional(),danger:e.optional(),warning:e.optional(),primary:e.optional(),secondary:e.optional(),tertiary:e.optional()}).passthrough(),u=o.object({brands:o.record(o.string(),b).refine(n=>Object.keys(n).length>0,{message:"apollion.config.mjs: brands must contain at least 1 entry"}),modes:o.array(o.enum(["light","dark"])).optional(),surfaces:o.array(o.enum(["positive","negative"])).optional(),dimensions:o.array(o.enum(["compact","normal","spacious"])).optional(),output:o.object({runtime:o.boolean().optional(),css:o.boolean().optional(),json:o.boolean().optional(),ts:o.boolean().optional()}).passthrough().optional()}).passthrough();var _=[/\brequire\s*\(/,/\bimport\s*\(/,/^\s*import\s+/m],k=1e3;function v(n){return n}r(v,"defineConfig");var f=class f extends Error{constructor(s,p){super(s);this.configPath=p;this.name="ConfigLoadError"}};r(f,"ConfigLoadError");var a=f;async function I(n){let i=x(n.configPath),s=await w(i,"utf8");for(let t of _)if(t.test(s))throw new a(`apollion.config: dynamic require/import not allowed (matched ${t}). Declarative config only \u2014 see ADR-006 \xA73.8 B3.`,i);let p=s.replace(/(^|\n)\s*export\s+default\s+/,(t,l)=>`${l}__apollion_config_export = `);if(p===s)throw new a("apollion.config: missing `export default <object>;` \u2014 config must export a default object literal.",i);let g={__apollion_config_export:void 0,console:j(),Symbol,Number,String,Boolean,Array,Object,JSON,Math,defineConfig:r(t=>t,"defineConfig")},d=y(g);try{new C(p,{filename:i}).runInContext(d,{timeout:k})}catch(t){throw new a(`apollion.config: evaluation failed \u2014 ${t instanceof Error?t.message:String(t)}`,i)}let m=g.__apollion_config_export;if(m===void 0)throw new a("apollion.config: `export default` produced undefined.",i);let c=u.safeParse(m);if(!c.success){let t=c.error.issues.map(l=>` ${l.path.join(".")||"(root)"}: ${l.message}`).join(`
1
+ var h=Object.defineProperty;var r=(n,i)=>h(n,"name",{value:i,configurable:!0});import{readFile as w}from"node:fs/promises";import{resolve as x}from"node:path";import{createContext as y,Script as C}from"node:vm";import{z as o}from"zod";var e=o.string().regex(/^#([0-9a-fA-F]{3}){1,2}$|^transparent$|^rgb\(.*\)$|^oklch\(.*\)$/,{message:'Must be hex, rgb(), oklch(), or "transparent"'}),b=o.object({baseDark:o.string().optional(),baseLight:o.string().optional(),deepDark:e,deepLight:e,transparent:o.string().optional(),main:e.optional(),opposite:e.optional(),complementary:e.optional(),information:e.optional(),success:e.optional(),danger:e.optional(),warning:e.optional(),primary:e.optional(),secondary:e.optional(),tertiary:e.optional()}).passthrough(),u=o.object({brands:o.record(o.string(),b).refine(n=>Object.keys(n).length>0,{message:"apollion.config.mjs: brands must contain at least 1 entry"}),modes:o.array(o.enum(["light","dark"])).optional(),surfaces:o.array(o.enum(["positive","negative"])).optional(),dimensions:o.array(o.enum(["compact","normal","spacious"])).optional(),output:o.object({runtime:o.boolean().optional(),css:o.boolean().optional(),json:o.boolean().optional(),ts:o.boolean().optional(),designMd:o.boolean().optional(),tailwind:o.boolean().optional()}).passthrough().optional()}).passthrough();var _=[/\brequire\s*\(/,/\bimport\s*\(/,/^\s*import\s+/m],k=1e3;function v(n){return n}r(v,"defineConfig");var f=class f extends Error{constructor(s,p){super(s);this.configPath=p;this.name="ConfigLoadError"}};r(f,"ConfigLoadError");var a=f;async function I(n){let i=x(n.configPath),s=await w(i,"utf8");for(let t of _)if(t.test(s))throw new a(`apollion.config: dynamic require/import not allowed (matched ${t}). Declarative config only \u2014 see ADR-006 \xA73.8 B3.`,i);let p=s.replace(/(^|\n)\s*export\s+default\s+/,(t,l)=>`${l}__apollion_config_export = `);if(p===s)throw new a("apollion.config: missing `export default <object>;` \u2014 config must export a default object literal.",i);let g={__apollion_config_export:void 0,console:j(),Symbol,Number,String,Boolean,Array,Object,JSON,Math,defineConfig:r(t=>t,"defineConfig")},d=y(g);try{new C(p,{filename:i}).runInContext(d,{timeout:k})}catch(t){throw new a(`apollion.config: evaluation failed \u2014 ${t instanceof Error?t.message:String(t)}`,i)}let m=g.__apollion_config_export;if(m===void 0)throw new a("apollion.config: `export default` produced undefined.",i);let c=u.safeParse(m);if(!c.success){let t=c.error.issues.map(l=>` ${l.path.join(".")||"(root)"}: ${l.message}`).join(`
2
2
  `);throw new a(`apollion.config: schema validation failed \u2014
3
3
  ${t}`,i)}return c.data}r(I,"loadConfig");function j(){return{log:r((...n)=>console.log("[apollion.config]",...n),"log"),warn:r((...n)=>console.warn("[apollion.config]",...n),"warn"),error:r((...n)=>console.error("[apollion.config]",...n),"error")}}r(j,"makeReadOnlyConsole");export{a as ConfigLoadError,v as defineConfig,I as loadConfig};
@@ -1 +1 @@
1
- "use strict";var t=Object.defineProperty;var u=Object.getOwnPropertyDescriptor;var f=Object.getOwnPropertyNames;var b=Object.prototype.hasOwnProperty;var c=(o,n)=>t(o,"name",{value:n,configurable:!0});var D=(o,n)=>{for(var s in n)t(o,s,{get:n[s],enumerable:!0})},S=(o,n,s,r)=>{if(n&&typeof n=="object"||typeof n=="function")for(let e of f(n))!b.call(o,e)&&e!==s&&t(o,e,{get:()=>n[e],enumerable:!(r=u(n,e))||r.enumerable});return o};var g=o=>S(t({},"__esModule",{value:!0}),o);var F={};D(F,{expandVariants:()=>C,variantName:()=>E});module.exports=g(F);var x=["light","dark"],A=["positive","negative"],y=["compact","normal","spacious"];function C(o){let n=o.modes??x,s=o.surfaces??A,r=o.dimensions??y,e=Object.entries(o.brands).sort(([i],[a])=>i.localeCompare(a)),d=[];for(let[i,a]of e)for(let l of n)for(let p of s)for(let m of r)d.push({brand:i,colors:a,mode:l,surface:p,dimension:m});return d}c(C,"expandVariants");function E(o){return`${o.brand}.${o.mode}.${o.surface}.${o.dimension}`}c(E,"variantName");0&&(module.exports={expandVariants,variantName});
1
+ "use strict";var t=Object.defineProperty;var u=Object.getOwnPropertyDescriptor;var f=Object.getOwnPropertyNames;var b=Object.prototype.hasOwnProperty;var c=(o,n)=>t(o,"name",{value:n,configurable:!0});var g=(o,n)=>{for(var s in n)t(o,s,{get:n[s],enumerable:!0})},D=(o,n,s,r)=>{if(n&&typeof n=="object"||typeof n=="function")for(let e of f(n))!b.call(o,e)&&e!==s&&t(o,e,{get:()=>n[e],enumerable:!(r=u(n,e))||r.enumerable});return o};var S=o=>D(t({},"__esModule",{value:!0}),o);var M={};g(M,{expandVariants:()=>C,variantName:()=>E});module.exports=S(M);var x=["light","dark"],A=["positive","negative"],y=["compact","normal","spacious"];function C(o){let n=o.modes??x,s=o.surfaces??A,r=o.dimensions??y,e=Object.entries(o.brands).sort(([i],[a])=>i.localeCompare(a)),d=[];for(let[i,a]of e)for(let l of n)for(let p of s)for(let m of r)d.push({brand:i,colors:a,mode:l,surface:p,dimension:m});return d}c(C,"expandVariants");function E(o){return`${o.brand}.${o.mode}.${o.surface}.${o.dimension}`}c(E,"variantName");0&&(module.exports={expandVariants,variantName});
@@ -1 +1 @@
1
- var m=Object.defineProperty;var r=(o,n)=>m(o,"name",{value:n,configurable:!0});var u=["light","dark"],f=["positive","negative"],b=["compact","normal","spacious"];function S(o){let n=o.modes??u,i=o.surfaces??f,a=o.dimensions??b,c=Object.entries(o.brands).sort(([e],[s])=>e.localeCompare(s)),t=[];for(let[e,s]of c)for(let d of n)for(let l of i)for(let p of a)t.push({brand:e,colors:s,mode:d,surface:l,dimension:p});return t}r(S,"expandVariants");function g(o){return`${o.brand}.${o.mode}.${o.surface}.${o.dimension}`}r(g,"variantName");export{S as expandVariants,g as variantName};
1
+ var m=Object.defineProperty;var r=(o,n)=>m(o,"name",{value:n,configurable:!0});var u=["light","dark"],f=["positive","negative"],b=["compact","normal","spacious"];function D(o){let n=o.modes??u,i=o.surfaces??f,a=o.dimensions??b,c=Object.entries(o.brands).sort(([e],[s])=>e.localeCompare(s)),t=[];for(let[e,s]of c)for(let d of n)for(let l of i)for(let p of a)t.push({brand:e,colors:s,mode:d,surface:l,dimension:p});return t}r(D,"expandVariants");function S(o){return`${o.brand}.${o.mode}.${o.surface}.${o.dimension}`}r(S,"variantName");export{D as expandVariants,S as variantName};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@apollion-dsi/tokens",
3
- "version": "5.3.0",
3
+ "version": "5.5.0",
4
4
  "description": "Apollion Design System — Framework-agnostic design tokens",
5
5
  "homepage": "https://www.apollion.com.br",
6
6
  "license": "MIT",
@@ -37,6 +37,7 @@
37
37
  "./dist/json/sets/*": "./dist/json/sets/*",
38
38
  "./dist/json/*": "./dist/json/*",
39
39
  "./dist/ts/*": "./dist/ts/*",
40
+ "./dist/tailwind/*": "./dist/tailwind/*",
40
41
  "./dist/manifest.json": "./dist/manifest.json"
41
42
  },
42
43
  "sideEffects": false,
@@ -66,7 +67,7 @@
66
67
  },
67
68
  "devDependencies": {
68
69
  "@apollion-dsi/core": "workspace:*",
69
- "@apollion-dsi/eslint-config": "0.9.0",
70
+ "@apollion-dsi/eslint-config": "0.9.1",
70
71
  "@types/culori": "4.0.1",
71
72
  "@types/jest": "30.0.0",
72
73
  "@types/node": "25.7.0",
package/src/build.ts CHANGED
@@ -19,8 +19,11 @@
19
19
  * Verified by `__tests__/build.test.ts`.
20
20
  *
21
21
  * **`--check` mode (CI gate):** read existing `manifest.json`, recompute
22
- * the expected manifest from current config, compare. Exit 1 on drift.
23
- * Never writes anything. Suitable for pre-push hook or local lint.
22
+ * `configHash` from current config, then re-hash every file the manifest
23
+ * lists and compare against its recorded sha256 — `configHash` alone only
24
+ * proves "the input didn't change", not "dist/ still reflects it" (a file
25
+ * can be hand-edited or corrupted without touching config). Exit 1 on
26
+ * drift. Never writes anything. Suitable for pre-push hook or local lint.
24
27
  *
25
28
  * @see ADR-006 §3.5 (atomic+idempotent build)
26
29
  * @see PRD-002 §S5 acceptance (rerun byte-identical, --check blocks drift)
@@ -31,7 +34,9 @@ import { tmpdir } from 'node:os';
31
34
  import { dirname, join } from 'node:path';
32
35
 
33
36
  import { renderCss } from './renderers/css';
37
+ import { renderDesignMd } from './renderers/design-md';
34
38
  import { renderBaseSet, renderColorSet, renderFontSet, renderResolver, renderSpacingSet } from './renderers/resolver';
39
+ import { renderTailwindPreset, renderTwMergeExtension } from './renderers/tailwind';
35
40
  import { renderTs } from './renderers/ts';
36
41
  import type { ApollionConfig, Variant } from './config-schema';
37
42
  import { expandVariants, variantName } from './config-schema';
@@ -127,11 +132,37 @@ export async function build(opts: BuildOptions): Promise<BuildResult> {
127
132
  const ir = buildFullIR(foundation, colors, variant);
128
133
  const baseName = variantName(variant);
129
134
 
130
- if (output.css) await emit(`css/${baseName}.css`, renderCss(ir));
135
+ if (output.css) await emit(`css/${baseName}.css`, renderCss(ir, { rgbCompanions: output.tailwind }));
131
136
  if (output.ts) await emit(`ts/${baseName}.d.ts`, renderTs(ir));
132
137
  }
133
138
  }
134
139
 
140
+ // ── Tailwind surface: preset + tw-merge extension (naming layer) ─────────
141
+ // Token *topology* is variant-invariant (same groups/keys across the axes),
142
+ // and every entry maps through `var(--apollion-*)` indirection — so one
143
+ // preset serves all variants. The first expanded variant is the
144
+ // representative (deterministic: `expandVariants` ordering is stable).
145
+ if (output.tailwind) {
146
+ const variant = variants[0];
147
+ const { foundation, colors } = buildVariantThemes(variant);
148
+ const ir = buildFullIR(foundation, colors, variant);
149
+ await emit('tailwind/preset.mjs', renderTailwindPreset(ir));
150
+ await emit('tailwind/tw-merge.mjs', renderTwMergeExtension(ir));
151
+ }
152
+
153
+ // ── Design.md surface: resolved-values AI context, one doc per brand ─────
154
+ if (output.designMd) {
155
+ const brands = [...new Set(variants.map((v) => v.brand))];
156
+ for (const brand of brands) {
157
+ const brandVariants = variants.filter((v) => v.brand === brand);
158
+ const irs = brandVariants.map((variant) => {
159
+ const { foundation, colors } = buildVariantThemes(variant);
160
+ return buildFullIR(foundation, colors, variant);
161
+ });
162
+ await emit(`design/${brand}.design.md`, renderDesignMd(brand, irs));
163
+ }
164
+ }
165
+
135
166
  const manifest: BuildManifest = {
136
167
  configHash: hashConfig(config),
137
168
  files,
@@ -170,7 +201,22 @@ export async function check(opts: { config: ApollionConfig; outDir: string }): P
170
201
  } catch {
171
202
  return false; // no manifest = needs build
172
203
  }
173
- return current.configHash === hashConfig(config);
204
+ if (current.configHash !== hashConfig(config)) return false;
205
+
206
+ // configHash only proves the input didn't change — re-verify each emitted
207
+ // file's bytes still match what the manifest recorded, so a hand-edited or
208
+ // corrupted dist/ file (config untouched) is still caught as drift.
209
+ for (const entry of current.files) {
210
+ let content: Buffer;
211
+ try {
212
+ content = await readFile(join(outDir, entry.path));
213
+ } catch {
214
+ return false; // file missing
215
+ }
216
+ if (sha256(content) !== entry.sha256) return false;
217
+ }
218
+
219
+ return true;
174
220
  }
175
221
 
176
222
  async function writeAt(root: string, relativePath: string, content: string): Promise<void> {
@@ -67,13 +67,13 @@ export function getOppositeColor(color: AcceptColorType): string {
67
67
  return formatHex(rotated) ?? hex;
68
68
  }
69
69
 
70
- /** Piso perceptual base↔estado de interação (razão WCAG) — espelho do core (ADR-012). */
70
+ /** Perceptual state floor between base and interaction state (WCAG ratio) — mirror of the core (ADR-012). */
71
71
  const MIN_STATE_CONTRAST = 1.3;
72
72
 
73
- /** ΔL OKLch JND — critério alternativo onde a razão WCAG satura (quase-preto). */
73
+ /** ΔL OKLch JND — alternative criterion where the WCAG ratio saturates (near-black). */
74
74
  const STATE_DELTA_L_JND = 0.05;
75
75
 
76
- /** Passo de L por iteração na correção de estado. */
76
+ /** L step per iteration during state correction. */
77
77
  const STATE_L_STEP = 0.04;
78
78
 
79
79
  const contrastRatio = (a: string, b: string): number => {
@@ -88,13 +88,13 @@ const oklchLightness = (color: string): number | null => {
88
88
  return parsed ? (parsed.l ?? 0) : null;
89
89
  };
90
90
 
91
- /** Piso de contraste WCAG AA (texto normal) — espelho do core. */
91
+ /** WCAG AA contrast floor (normal text) — mirror of the core. */
92
92
  const MIN_CONTRAST_AA = 4.5;
93
93
 
94
94
  /**
95
- * Ajusta o L OKLch de `color` até passar `minRatio` contra `background`,
96
- * preservando hue/croma — **espelho byte-a-byte** de `readableColor` do core
97
- * (`Colors.helpers.ts`; parity.test.ts). Usado para derivar o ink tonal
95
+ * Adjusts the OKLch L of `color` until it passes `minRatio` against `background`,
96
+ * preserving hue/chroma — **byte-for-byte mirror** of the core's `readableColor`
97
+ * (`Colors.helpers.ts`; parity.test.ts). Used to derive the tonal ink
98
98
  * `onLight` (APOLLION-CONTRAST-GUARANTEE).
99
99
  */
100
100
  function readableColor(color: string, background: string, minRatio = MIN_CONTRAST_AA): string {
@@ -157,9 +157,9 @@ function perceptibleStateFor(base: string, surfaceIsDark: boolean, startL?: numb
157
157
  }
158
158
 
159
159
  /**
160
- * Derive `{ base, dark, action, active, light }` via OKLch lerp, com piso
161
- * perceptual mode-aware nos estados de interação — espelho byte-a-byte do
162
- * core (ADR-012; parity.test.ts). Overrides por slot passam verbatim.
160
+ * Derive `{ base, dark, action, active, light }` via OKLch lerp, with a
161
+ * mode-aware perceptual state floor on the interaction states — byte-for-byte
162
+ * mirror of the core (ADR-012; parity.test.ts). Per-slot overrides pass through verbatim.
163
163
  */
164
164
  export function mountSingleColor(
165
165
  color: AcceptColorType | ColorPalleteOverrideInterface,
@@ -176,7 +176,7 @@ export function mountSingleColor(
176
176
  action: mixOklch(base, darken!, 0.2),
177
177
  active: mixOklch(base, lighten!, 0.6),
178
178
  light: mixOklch(base, lighten!, 0.9),
179
- // Placeholder — recalculado do `action` FINAL abaixo (espelho do core).
179
+ // Placeholder — recomputed from the FINAL `action` below (mirror of the core).
180
180
  onLight: base,
181
181
  };
182
182
 
@@ -194,7 +194,7 @@ export function mountSingleColor(
194
194
  }
195
195
  }
196
196
 
197
- // Ink tonal AA por construção (APOLLION-CONTRAST-GUARANTEE) — espelho do core.
197
+ // Tonal ink AA by construction (APOLLION-CONTRAST-GUARANTEE) — mirror of the core.
198
198
  derived.onLight = readableColor(derived.action, derived.light);
199
199
 
200
200
  if (override) {
@@ -238,7 +238,7 @@ export function mountGreyscaleColors(colors: ColorsInput): Record<GrayscaleColor
238
238
  export function mountNeutralColors(colors: ColorsInput): Record<NeutralColorsType, string> {
239
239
  const lighter = colors.deepLight!;
240
240
  const darker = colors.deepDark!;
241
- // Slot pode ser override por slot (ADR-012) — a rampa ancora só no seed.
241
+ // The slot may be overridden per slot (ADR-012) — the ramp anchors on the seed only.
242
242
  const primary =
243
243
  typeof colors.primary === 'object' && colors.primary ? colors.primary.base : (colors.primary as string);
244
244
 
package/src/cli.ts CHANGED
@@ -103,7 +103,7 @@ async function main(): Promise<void> {
103
103
  const ok = await check({ config, outDir: resolve(args.outDir) });
104
104
  if (!ok) {
105
105
  console.error(
106
- `apollion-tokens: dist/ is stale or missing (configHash mismatch). Re-run \`apollion-tokens build\` without --check.`,
106
+ `apollion-tokens: dist/ is stale, missing, or has drifted from its manifest. Re-run \`apollion-tokens build\` without --check.`,
107
107
  );
108
108
  process.exit(1);
109
109
  }
@@ -57,6 +57,8 @@ export const ApollionConfigSchema = z
57
57
  css: z.boolean().optional(),
58
58
  json: z.boolean().optional(),
59
59
  ts: z.boolean().optional(),
60
+ designMd: z.boolean().optional(),
61
+ tailwind: z.boolean().optional(),
60
62
  })
61
63
  .passthrough()
62
64
  .optional(),
@@ -36,6 +36,15 @@ export interface ApollionOutputFlags {
36
36
  css?: boolean;
37
37
  json?: boolean;
38
38
  ts?: boolean;
39
+ /** `dist/design/<brand>.design.md` — resolved-values AI context per brand
40
+ * (YAML frontmatter + markdown body). See `renderers/design-md.ts`. */
41
+ designMd?: boolean;
42
+ /** `dist/tailwind/{preset,tw-merge}.mjs` — generated Tailwind preset mapping
43
+ * foundation tokens to theme keys (`var(--apollion-*)` indirection) plus a
44
+ * tailwind-merge extension derived from the same IR. Also adds `-rgb`
45
+ * channel-triplet companion vars to `dist/css/` so opaque colour tokens
46
+ * support Tailwind's alpha modifier. See `renderers/tailwind.ts`. */
47
+ tailwind?: boolean;
39
48
  }
40
49
 
41
50
  export interface ApollionConfig {
@@ -102,7 +111,7 @@ export function expandVariants(config: ApollionConfig): Variant[] {
102
111
  }
103
112
 
104
113
  /**
105
- * Stable variant filename (sem extension).
114
+ * Stable variant filename (without extension).
106
115
  * Format: `<brand>.<mode>.<surface>.<dimension>` — kebab where needed.
107
116
  */
108
117
  export function variantName(v: Variant): string {
package/src/ir.ts CHANGED
@@ -258,8 +258,8 @@ function buildColorPrimitives(colors: ColorsThemeInterface): IRGroup {
258
258
  action: colorToken(palette.action),
259
259
  active: colorToken(palette.active),
260
260
  light: colorToken(palette.light),
261
- // Par tonal AA (APOLLION-CONTRAST-GUARANTEE): ink legível sobre `light`,
262
- // emitido como `--apollion-color-<paleta>-on-light`.
261
+ // AA tonal pair (APOLLION-CONTRAST-GUARANTEE): ink legible over `light`,
262
+ // emitted as `--apollion-color-<palette>-on-light`.
263
263
  onLight: colorToken(palette.onLight),
264
264
  };
265
265
  }
package/src/manifest.ts CHANGED
@@ -8,7 +8,7 @@
8
8
  *
9
9
  * **Threat-model fields (ADR-006 §3.9):** `gitCommit` and `buildEnv` give
10
10
  * provenance without requiring CI/SLSA-3 (decision Q-G9 — single-user org,
11
- * sem CI). `signedBy` slot reserved for sigstore in future PRD-003.
11
+ * no CI). `signedBy` slot reserved for sigstore in future PRD-003.
12
12
  *
13
13
  * @see ADR-006 §3.9 + §8.5 risk T1/R2
14
14
  * @see PRD-002 §S5
@@ -13,6 +13,8 @@
13
13
  * @see ../ir.ts (source of truth) · ADR-006 §3.3 + §3.10 · tech-radar R3
14
14
  */
15
15
 
16
+ import { colorPayload, isOpaqueColor, rgbTriplet } from './tailwind';
17
+
16
18
  import type { IRDocument, IRGroup } from '../ir';
17
19
  import { isToken, kebab, rawValue } from '../ir';
18
20
 
@@ -26,6 +28,28 @@ function emitVars(group: IRGroup, prefix: string[], lines: string[]): void {
26
28
  }
27
29
  }
28
30
 
31
+ /**
32
+ * `-rgb` channel-triplet companions for opaque colour tokens (Tailwind
33
+ * `<alpha-value>` support — `output.tailwind` only). Projection rule shared
34
+ * with the preset renderer ({@link colorPayload}/{@link isOpaqueColor}/
35
+ * {@link rgbTriplet}) so preset entries and companions cannot drift.
36
+ *
37
+ * NEVER mirrored into the `@property` blocks — `syntax: '<color>'` is invalid
38
+ * for a channel triplet (`emitProperties` walks tokens, companions are not
39
+ * tokens, so the exclusion is structural).
40
+ */
41
+ function emitRgbVars(group: IRGroup, prefix: string[], lines: string[]): void {
42
+ for (const [key, node] of Object.entries(group)) {
43
+ const path = [...prefix, kebab(key)];
44
+ if (!isToken(node)) {
45
+ emitRgbVars(node, path, lines);
46
+ continue;
47
+ }
48
+ const color = colorPayload(node);
49
+ if (color && isOpaqueColor(color)) lines.push(` --apollion-${path.join('-')}-rgb: ${rgbTriplet(color)};`);
50
+ }
51
+ }
52
+
29
53
  function emitProperties(group: IRGroup, prefix: string[], lines: string[]): void {
30
54
  for (const [key, node] of Object.entries(group)) {
31
55
  const path = [...prefix, kebab(key)];
@@ -39,13 +63,24 @@ function emitProperties(group: IRGroup, prefix: string[], lines: string[]): void
39
63
  }
40
64
  }
41
65
 
42
- export function renderCss(ir: IRDocument): string {
66
+ export interface RenderCssOptions {
67
+ /** Emit `-rgb` channel-triplet companions for opaque colour tokens
68
+ * (`output.tailwind` — see {@link emitRgbVars}). Default false: the byte
69
+ * output without the flag is unchanged. */
70
+ rgbCompanions?: boolean;
71
+ }
72
+
73
+ export function renderCss(ir: IRDocument, options: RenderCssOptions = {}): string {
43
74
  const { brand, mode, surface, dimension } = ir.meta;
44
75
  const lines: string[] = [HEADER_LINE, ''];
45
76
 
46
77
  // Variant marker as a comment (NOT a var — keep cascade clean).
47
78
  lines.push(`/* Variant: brand=${brand} mode=${mode} surface=${surface} dimension=${dimension} */`, '', ':root {');
48
79
  emitVars(ir.groups, [], lines);
80
+ if (options.rgbCompanions) {
81
+ lines.push('', ' /* -rgb channel triplets — Tailwind <alpha-value> companions (opaque colour tokens only). */');
82
+ emitRgbVars(ir.groups, [], lines);
83
+ }
49
84
  lines.push('}', '');
50
85
 
51
86
  // @property declarations for color tokens — opt-in via @supports.