Initial commit

This commit is contained in:
2026-04-23 21:38:24 -04:00
commit 63e12a9636
1762 changed files with 1672620 additions and 0 deletions
@@ -0,0 +1,359 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=1440" />
<title>Powder Coating Logix — Design Review</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=IBM+Plex+Mono:wght@400;500;600&family=Fraunces:opsz,wght@9..144,500;9..144,600&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.css">
<script src="https://unpkg.com/react@18.3.1/umd/react.development.js" integrity="sha384-hD6/rw4ppMLGNu3tX5cjIb+uRZ7UkRJ6BPkLpg4hAu/6onKUg4lLsHAs9EBPT82L" crossorigin="anonymous"></script>
<script src="https://unpkg.com/react-dom@18.3.1/umd/react-dom.development.js" integrity="sha384-u6aeetuaXnQ38mYT8rp6sbXaQe3NL9t+IBXmnYxwkUI2Hw4bsp2Wvmx4yRQF1uAm" crossorigin="anonymous"></script>
<script src="https://unpkg.com/@babel/standalone@7.29.0/babel.min.js" integrity="sha384-m08KidiNqLdpJqLq95G/LEi8Qvjl/xUYll3QILypMoQ65QorJ9Lvtp2RXYGBFj1y" crossorigin="anonymous"></script>
<style>
:root{
--ink:#0F0F10;
--graphite:#1A1A1C;
--slate:#3A3A3E;
--steel:#6B6B70;
--mute:#9A9A9F;
--rule:#E4E2DC;
--rule-soft:#EFEDE7;
--paper:#FAFAF7;
--paper-2:#F3F1EB;
--card:#FFFFFF;
--ember:oklch(0.68 0.17 50);
--ember-tint:oklch(0.95 0.04 55);
--ember-ink:oklch(0.42 0.15 40);
--ok:oklch(0.62 0.11 155);
--ok-tint:oklch(0.95 0.04 155);
--warn:oklch(0.76 0.13 80);
--warn-tint:oklch(0.96 0.05 85);
--bad:oklch(0.60 0.19 25);
--bad-tint:oklch(0.95 0.04 25);
--cool:oklch(0.58 0.09 240);
--cool-tint:oklch(0.95 0.03 240);
}
*{box-sizing:border-box}
html,body{margin:0;padding:0}
body{
font-family:'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;
background:var(--paper);
color:var(--ink);
font-size:14px;
line-height:1.5;
-webkit-font-smoothing:antialiased;
font-feature-settings:"ss01","cv11";
}
.mono{font-family:'IBM Plex Mono',ui-monospace,monospace;font-feature-settings:"zero"}
.serif{font-family:'Fraunces',Georgia,serif;font-variation-settings:"opsz" 144}
/* ────────── Document shell ────────── */
.doc{max-width:1320px;margin:0 auto;padding:56px 48px 120px}
.doc-head{
display:grid;grid-template-columns:1fr auto;gap:32px;align-items:end;
padding-bottom:28px;border-bottom:1px solid var(--rule);margin-bottom:40px;
}
.kicker{
font-family:'IBM Plex Mono',monospace;
font-size:11px;letter-spacing:0.14em;text-transform:uppercase;
color:var(--steel);display:flex;align-items:center;gap:10px;
}
.kicker::before{content:"";width:18px;height:1px;background:var(--ember)}
h1.doc-title{
font-family:'Fraunces',Georgia,serif;
font-weight:500;
font-size:64px;
line-height:1.02;
letter-spacing:-0.02em;
margin:14px 0 10px;
color:var(--ink);
}
h1.doc-title em{font-style:italic;color:var(--ember-ink)}
.doc-sub{max-width:640px;color:var(--slate);font-size:16px;line-height:1.55}
.doc-meta{
text-align:right;font-size:12px;color:var(--steel);
display:flex;flex-direction:column;gap:4px;
}
.doc-meta b{color:var(--ink);font-weight:600}
/* ────────── Section ────────── */
section.chapter{margin:88px 0 0}
.chap-head{
display:grid;grid-template-columns:120px 1fr;gap:32px;
padding-bottom:20px;margin-bottom:28px;
border-bottom:1px solid var(--rule);
}
.chap-num{
font-family:'IBM Plex Mono',monospace;font-size:12px;letter-spacing:0.1em;
color:var(--ember-ink);padding-top:6px;
}
.chap-title{
font-family:'Fraunces',Georgia,serif;
font-weight:500;font-size:32px;line-height:1.15;letter-spacing:-0.01em;
margin:0 0 8px;color:var(--ink);
}
.chap-lede{color:var(--slate);max-width:720px;font-size:15px}
/* ────────── Critique list ────────── */
.findings{display:grid;grid-template-columns:repeat(3,1fr);gap:1px;background:var(--rule);border:1px solid var(--rule);border-radius:2px}
.finding{background:var(--card);padding:22px 22px 24px}
.finding-tag{
font-family:'IBM Plex Mono',monospace;font-size:10px;letter-spacing:0.12em;
color:var(--steel);text-transform:uppercase;display:flex;align-items:center;gap:8px;
}
.finding-tag .sev{
width:8px;height:8px;border-radius:50%;
}
.sev.hi{background:var(--bad)}
.sev.md{background:var(--warn)}
.sev.lo{background:var(--cool)}
.finding h4{margin:10px 0 6px;font-size:15px;font-weight:600;letter-spacing:-0.01em}
.finding p{margin:0;color:var(--slate);font-size:13px;line-height:1.55}
/* ────────── Before/After stage ────────── */
.stage{
display:grid;grid-template-columns:1fr 1fr;gap:24px;margin-top:24px;
}
.stage.single{grid-template-columns:1fr}
.mock{
background:var(--card);
border:1px solid var(--rule);
border-radius:8px;
overflow:hidden;
position:relative;
}
.mock-head{
display:flex;align-items:center;justify-content:space-between;
padding:10px 14px;border-bottom:1px solid var(--rule);
background:var(--paper-2);
}
.mock-label{
font-family:'IBM Plex Mono',monospace;font-size:10px;letter-spacing:0.14em;
text-transform:uppercase;color:var(--steel);
}
.mock-label b{color:var(--ink);font-weight:600}
.mock-label.after b{color:var(--ember-ink)}
.mock-tag{
font-family:'IBM Plex Mono',monospace;font-size:10px;letter-spacing:0.1em;
text-transform:uppercase;color:var(--steel);padding:3px 7px;
border:1px solid var(--rule);border-radius:99px;background:var(--card);
}
.mock-body{
position:relative;
overflow:hidden;
/* content is a fake app at ~1280px wide, scaled to fit column */
}
.scaler{
width:1280px;
transform-origin:top left;
/* transform scale is applied by component based on container width */
}
/* small callout strip under before/after */
.delta{
display:grid;grid-template-columns:1fr 1fr;gap:24px;margin-top:14px;
}
.delta-col{
font-size:12.5px;color:var(--slate);line-height:1.6;
}
.delta-col h5{
font-family:'IBM Plex Mono',monospace;font-size:10px;letter-spacing:0.14em;
text-transform:uppercase;color:var(--steel);margin:0 0 6px;font-weight:500;
}
.delta-col ul{margin:0;padding-left:16px}
.delta-col li{margin:3px 0}
.delta-col li::marker{color:var(--ember)}
/* ────────── System tokens strip ────────── */
.sys{
display:grid;grid-template-columns:repeat(4,1fr);gap:1px;
background:var(--rule);border:1px solid var(--rule);border-radius:2px;
margin-top:28px;
}
.sys-cell{background:var(--card);padding:22px}
.sys-cell h5{
font-family:'IBM Plex Mono',monospace;font-size:10px;letter-spacing:0.14em;
text-transform:uppercase;color:var(--steel);margin:0 0 14px;font-weight:500;
}
.swatch-row{display:flex;flex-direction:column;gap:8px}
.swatch{display:flex;align-items:center;gap:10px;font-size:12px}
.swatch .chip{width:24px;height:24px;border-radius:4px;border:1px solid rgba(0,0,0,0.08);flex-shrink:0}
.swatch .lbl{color:var(--ink);font-weight:500}
.swatch .hex{margin-left:auto;font-family:'IBM Plex Mono',monospace;color:var(--steel);font-size:11px}
.type-sample{margin-bottom:12px}
.type-sample:last-child{margin-bottom:0}
.type-meta{font-family:'IBM Plex Mono',monospace;font-size:10px;color:var(--steel);letter-spacing:0.1em;text-transform:uppercase;margin-bottom:2px}
.type-val{color:var(--ink);line-height:1.1}
/* ────────── Tweaks panel ────────── */
.tweaks{
position:fixed;right:20px;bottom:20px;width:280px;
background:var(--card);border:1px solid var(--rule);border-radius:10px;
box-shadow:0 20px 40px -20px rgba(0,0,0,0.25), 0 2px 4px rgba(0,0,0,0.04);
padding:14px 14px 10px;z-index:9999;font-size:12px;
display:none;
}
.tweaks.on{display:block}
.tweaks h5{
font-family:'IBM Plex Mono',monospace;font-size:10px;letter-spacing:0.14em;
text-transform:uppercase;color:var(--steel);margin:0 0 10px;
display:flex;align-items:center;justify-content:space-between;
}
.tweak-row{margin-bottom:10px}
.tweak-row label{display:block;font-size:11px;color:var(--steel);margin-bottom:4px;text-transform:uppercase;letter-spacing:0.06em}
.tweak-opts{display:flex;gap:4px;flex-wrap:wrap}
.tweak-opt{
flex:1;min-width:0;padding:6px 8px;border:1px solid var(--rule);
background:var(--card);border-radius:5px;cursor:pointer;font-size:12px;
color:var(--ink);font-weight:500;transition:all .15s;
}
.tweak-opt:hover{border-color:var(--slate)}
.tweak-opt.on{background:var(--ink);color:var(--paper);border-color:var(--ink)}
.tweak-dot{display:flex;gap:6px}
.tweak-dot button{
width:22px;height:22px;border-radius:50%;border:2px solid transparent;
cursor:pointer;padding:0;
}
.tweak-dot button.on{border-color:var(--ink)}
</style>
</head>
<body>
<div class="doc">
<header class="doc-head">
<div>
<div class="kicker">Design critique · April 2026</div>
<h1 class="doc-title">Powder Coating Logix <em>wants to grow up.</em></h1>
<p class="doc-sub">
The app is functionally dense — billing, jobs, inventory, shop floor, accounting. Visually
it reads as a generic Bootstrap admin: rainbow KPIs, decorative icon bubbles, gradient
welcome banners, duplicated stat strips. Here's what's holding the look back, and a
direction that feels like a tool, not a template.
</p>
</div>
<div class="doc-meta">
<span>File · <b>Design Review.html</b></span>
<span>Screens analyzed · <b>Dashboard · Jobs · Board</b></span>
<span>Source · <b>PowderCoating.Web</b></span>
</div>
</header>
<!-- Mount points -->
<div id="critique-root"></div>
<div id="system-root"></div>
<div id="screen1-root"></div>
<div id="screen2-root"></div>
<div id="screen3-root"></div>
<div id="wrap-root"></div>
<div class="tweaks" id="tweaksPanel">
<h5>Tweaks <span class="mono" style="color:var(--mute)">· v1</span></h5>
<div class="tweak-row">
<label>Accent hue</label>
<div class="tweak-dot" id="tw-accent"></div>
</div>
<div class="tweak-row">
<label>Density</label>
<div class="tweak-opts" id="tw-density">
<button class="tweak-opt" data-v="comfortable">Comfortable</button>
<button class="tweak-opt on" data-v="compact">Compact</button>
</div>
</div>
<div class="tweak-row">
<label>Surface</label>
<div class="tweak-opts" id="tw-surface">
<button class="tweak-opt on" data-v="paper">Paper</button>
<button class="tweak-opt" data-v="white">White</button>
<button class="tweak-opt" data-v="ink">Ink</button>
</div>
</div>
</div>
</div>
<script type="application/json" id="tweak-defaults">/*EDITMODE-BEGIN*/{
"accent": "ember",
"density": "comfortable",
"surface": "ink"
}/*EDITMODE-END*/</script>
<script type="text/babel" src="mock_components.jsx"></script>
<script type="text/babel" src="screens_before.jsx"></script>
<script type="text/babel" src="screens_after.jsx"></script>
<script type="text/babel" src="review_app.jsx"></script>
<script>
// Tweaks wiring — accent hue swatches
const ACCENTS = {
ember: {h:50, c:0.17, label:'Ember'},
signal: {h:25, c:0.19, label:'Signal'},
cobalt: {h:245, c:0.15, label:'Cobalt'},
moss: {h:145, c:0.11, label:'Moss'},
ink: {h:280, c:0.04, label:'Graphite'},
};
const accentWrap = document.getElementById('tw-accent');
Object.entries(ACCENTS).forEach(([k,v])=>{
const b = document.createElement('button');
b.style.background = `oklch(0.68 ${v.c} ${v.h})`;
b.title = v.label;
b.dataset.v = k;
b.addEventListener('click',()=>applyAccent(k));
accentWrap.appendChild(b);
});
function applyAccent(k){
const v = ACCENTS[k];
document.documentElement.style.setProperty('--ember', `oklch(0.68 ${v.c} ${v.h})`);
document.documentElement.style.setProperty('--ember-tint', `oklch(0.95 ${v.c*0.3} ${v.h})`);
document.documentElement.style.setProperty('--ember-ink', `oklch(0.42 ${v.c*0.9} ${v.h-10})`);
[...accentWrap.children].forEach(b=>b.classList.toggle('on',b.dataset.v===k));
post({accent:k});
}
applyAccent('ember');
document.querySelectorAll('#tw-density .tweak-opt').forEach(b=>{
b.addEventListener('click',()=>{
document.querySelectorAll('#tw-density .tweak-opt').forEach(x=>x.classList.remove('on'));
b.classList.add('on');
document.documentElement.dataset.density = b.dataset.v;
post({density:b.dataset.v});
});
});
document.querySelectorAll('#tw-surface .tweak-opt').forEach(b=>{
b.addEventListener('click',()=>{
document.querySelectorAll('#tw-surface .tweak-opt').forEach(x=>x.classList.remove('on'));
b.classList.add('on');
applySurface(b.dataset.v);
post({surface:b.dataset.v});
});
});
function applySurface(v){
const s = document.documentElement.style;
if(v==='paper'){ s.setProperty('--paper','#FAFAF7'); s.setProperty('--paper-2','#F3F1EB'); s.setProperty('--card','#FFFFFF'); s.setProperty('--ink','#0F0F10'); }
if(v==='white'){ s.setProperty('--paper','#FFFFFF'); s.setProperty('--paper-2','#F6F6F6'); s.setProperty('--card','#FFFFFF'); s.setProperty('--ink','#0F0F10'); }
if(v==='ink'){ s.setProperty('--paper','#0E0E10'); s.setProperty('--paper-2','#17171A'); s.setProperty('--card','#1C1C20'); s.setProperty('--ink','#F4F2EC'); s.setProperty('--slate','#C2C0BA'); s.setProperty('--steel','#8A8883'); s.setProperty('--rule','#2B2B2F'); s.setProperty('--rule-soft','#232327'); }
}
// Edit mode protocol
window.addEventListener('message',(e)=>{
if(e.data?.type==='__activate_edit_mode') document.getElementById('tweaksPanel').classList.add('on');
if(e.data?.type==='__deactivate_edit_mode') document.getElementById('tweaksPanel').classList.remove('on');
});
function post(edits){
try{ window.parent.postMessage({type:'__edit_mode_set_keys',edits},'*'); }catch(e){}
}
try{ window.parent.postMessage({type:'__edit_mode_available'},'*'); }catch(e){}
</script>
</body>
</html>