const SAMPLES=SAMPLES_J, CATS=CATS_J, UI_FACES=UIFACES_J, APPS=APPS_J; const COLOR_NAMES=COLOR_NAMES_J; let MAP=MAP_J, PALETTE=PALETTE_J, SYNTAX=SYNTAX_J, UIMAP=UIMAP_J; let LOCKED=new Set(LOCKS_J); // rows whose choice is decided (controls disabled, skipped by erase/reset batch actions) const DELTAE_MIN=0.02; // OKLab ΔE below this = colors too close to tell apart (perceptual-metrics spec) const DEFAULT_UIMAP=JSON.parse(JSON.stringify(UIMAP)); function syntaxBlank(k){return {fg:MAP[k]||null,bg:null,bold:false,italic:false,underline:false,strike:false,box:null};} function syncSyntaxCache(k){const s=SYNTAX[k]||syntaxBlank(k);MAP[k]=s.fg||'';} function syncAllSyntaxCache(){CATS.forEach(c=>syncSyntaxCache(c[0]));} function syncSyntaxFromCache(){CATS.forEach(c=>{const k=c[0];syntaxFace(k).fg=MAP[k]||null;});} function syntaxFace(k){if(!SYNTAX[k])SYNTAX[k]=syntaxBlank(k);return SYNTAX[k];} function setSyntaxFg(k,hex){syntaxFace(k).fg=hex||null;syncSyntaxCache(k);} syncAllSyntaxCache(); const DEFAULT_SYNTAX=JSON.parse(JSON.stringify(SYNTAX)); // --- tier-3 package faces: pure state helpers (Phase 1) --- // Thin wrappers over the pure logic in app-core.js (inlined further down), // passing the live module state. packagesForExport / mergePackagesInto live in // the core verbatim and are used by name. function pname(n){return nameToHex(n,PALETTE);} function seedPkgmap(){return buildPkgmap(APPS,PALETTE);} let PKGMAP=seedPkgmap(); function esc(t){return t.replace(/&/g,'&').replace(//g,'>');} // Pure color-math core (lin/rl/contrast/rating/hsv2rgb/rgb2hsv/hex2rgb/rgb2hex, // plus OKLab/OKLCH/APCA/deltaE), inlined verbatim from colormath.js. COLORMATH_J // Pure package-model + dropdown logic, inlined verbatim from app-core.js. The // wrappers above (pname/seedPkgmap/ddList/pkgEffFg/pkgEffBg) delegate here. APP_CORE_J // Pure color/UI-boundary helpers (normHex, ratingColor, textOn), inlined from // app-util.js. textOn uses rl from the colormath core above. APP_UTIL_J // Pure palette-generator planner and browser-side generator panel. PALETTE_GENERATOR_CORE_J PALETTE_GENERATOR_UI_J // The contrast-cell readout shared by every table: a WCAG ratio colored by its // table verdict. Callers compute r for their own fg/bg. function verdictFor(r,target=4.5){return r>=target?'PASS':'FAIL';} function crHtml(r,target=4.5){const v=verdictFor(r,target);return `${r.toFixed(1)} ${v}`;} // Effective fg/bg with the standard fallback: an unset foreground reads as the // default fg (MAP['p']), an unset background as the ground (MAP['bg']). All three // tiers resolve their raw value through these before measuring or rendering. function effFg(v){return v||MAP['p'];} function effBg(v){return v||MAP['bg'];} // The ground pair (background + default foreground), passed to every app-core // helper that needs to resolve ground roles. Was the literal {bg:MAP['bg'], // fg:MAP['p']} repeated across app.js, palette-actions.js, and the browser gates. function groundPair(){return {bg:MAP['bg'],fg:MAP['p']};} function cid(l){return l.replace(/\W/g,'');} function buildLangSel(){const s=document.getElementById('langsel');s.innerHTML='';for(const lang in SAMPLES){const o=document.createElement('option');o.value=lang;o.textContent=lang;s.appendChild(o);}} function renderCode(){ const lang=document.getElementById('langsel').value;let html=''; for(const line of SAMPLES[lang]){ if(line.length===0){html+='\n';continue;} for(const [k,t] of line)html+=`${esc(t)}`; html+='\n';} const cp=document.getElementById('codepre');cp.innerHTML=html; cp.onclick=(e)=>{const s=e.target.closest('[data-k]');if(s)flashAssign(s.dataset.k);}; buildMockFrame(); } // Custom color dropdown: a real swatch + name + hex per row, since native //