diff --git a/docs/fleet-calculator.html b/docs/fleet-calculator.html
index 1611af7..cd6c215 100644
--- a/docs/fleet-calculator.html
+++ b/docs/fleet-calculator.html
@@ -5,6 +5,11 @@
D1 08:00:00sim clock
@@ -204,18 +267,18 @@ footer{flex:0 0 clamp(150px,26vh,210px);display:grid;grid-template-columns:1.1fr
Legend
-
Saturated steam 10 bar
-
Condensate return
-
Press cooling water
-
Cooling water return
-
Hydraulic oil 180 bar
-
Galvanics cooling 12 to 20 °C
-
DI water
-
PVC granulate
-
Regrind
-
Colour compound
-
Stamper sets to presses
-
Edge trim and rejects
+
Saturated steam 10 bar
+
Condensate return
+
Press cooling water
+
Cooling water return
+
Hydraulic oil 180 bar
+
Galvanics cooling 12 to 20 °C
+
DI water
+
PVC granulate
+
Regrind
+
Colour compound
+
Stamper sets to presses
+
Edge trim and rejects
Lamps: green run · grey idle · amber hold, change or waiting · red alarm. Yellow diamonds are the three artist approval gates, with the number of titles waiting at each. Two shifts, 06:00 to 22:00: presses and operator steps stop at night, plating already in the bath finishes. Discs on the metal path: gold lacquer, silver silvered lacquer, grey father or mother, ringed stamper.
@@ -593,7 +656,7 @@ function drawPress(m){const g=el('g',{class:'machine',id:'m_'+m.id});const {x,y,
m.topSt=el('rect',{x:px+8,y:y+54,width:pw-16,height:3,fill:'#b9c2cc'},g);
m.cake=el('g',{visibility:'hidden'},g);el('circle',{cx:x+w/2,cy:y+90,r:7,fill:'#3d3a33',stroke:'#8a7a55'},m.cake);
m.pY=[y+38,y+80];
- m.stateEl=el('text',{x:x+w/2,y:y+138,class:'mtag','text-anchor':'middle',style:'font-weight:700;fill:#e6ecf7'},g,'OFF');
+ m.stateEl=el('text',{x:x+w/2,y:y+138,class:'mtag','text-anchor':'middle',style:'font-weight:700;fill:var(--ink)'},g,'OFF');
m.tagEls=[0,1,2].map(i=>el('text',{x:x+7,y:y+154+i*13,class:'mtag'},g,''));
m.g=g;g.addEventListener('click',()=>select(m.id));}
function drawVex(m){const g=el('g',{class:'machine',id:'m_'+m.id});const {x,y,w,h}=m;
@@ -606,7 +669,7 @@ function drawVex(m){const g=el('g',{class:'machine',id:'m_'+m.id});const {x,y,w,
el('path',{d:`M${x+56},${y+50} H${x+84} V${y+60} L${x+76},${y+74} H${x+64} L${x+56},${y+60} Z`,class:'hopper'},g);
el('text',{x:x+8,y:y+82,class:'small'},g,'◀ cake A');
el('text',{x:x+w-8,y:y+82,class:'small','text-anchor':'end'},g,'cake B ▶');
- m.zoneEls=[0,1,2].map(i=>el('rect',{x:x+10+i*40,y:y+88,width:38,height:26,class:'zone',fill:'#1b2438'},g));
+ m.zoneEls=[0,1,2].map(i=>el('rect',{x:x+10+i*40,y:y+88,width:38,height:26,class:'zone',style:'fill:var(--z0)'},g));
m.zoneT=[0,1,2].map(i=>el('text',{x:x+29+i*40,y:y+105,class:'ctxt','text-anchor':'middle'},g,''));
el('line',{x1:x+10,y1:y+120,x2:x+w-10,y2:y+120,class:'screw'},g);
m.g=g;g.addEventListener('click',()=>select(m.id));}
@@ -788,7 +851,7 @@ function renderTags(){
m.fillEl.setAttribute('y',(m.y+m.h-30-hh).toFixed(1));m.fillEl.setAttribute('height',hh.toFixed(1));m.lvlEl.textContent=f0(l*100)+' %';m.lamp.setAttribute('class','lamp '+(l<0.1?'alarm':l<0.25?'warn':'run'));});
PRESS.forEach(P=>{const m=M[P.id];const T=P.set&&P.set.T;
m.stateEl.textContent=pressLabel(P);const amber=P.waiting||['CHANGE','UNMOUNT'].includes(P.state)||P.mode==='tp';
- m.stateEl.style.fill=P.state==='NOPVC'||P.state==='STOP'?'#ff3b3b':amber?'#ffbf1f':(P.state==='IDLE'||P.state==='OFF')?'#8a97b0':'#e6ecf7';
+ m.stateEl.style.fill=P.state==='NOPVC'||P.state==='STOP'?'var(--alarm)':amber?'var(--warn)':(P.state==='IDLE'||P.state==='OFF')?'var(--mute)':'var(--ink)';
m.tagEls[0].textContent=running(P)?'F '+f0(P.force)+' t · '+f0(P.moldT)+' °C':P.state==='STOP'?P.stopWhy:P.state==='OFF'?'night: shift 06:00':'mould '+f0(P.moldT)+' °C';
m.tagEls[1].textContent=T?T.id+' · '+P.set.k:(P.state==='OFF'?'':'waiting for a set');
m.tagEls[2].textContent=!T?'':P.mode==='tp'?'test press '+(TP_N-P.tpLeft)+'/'+TP_N:P.mode==='fa'?'first article':'run '+T.cycles+'/'+T.target;
@@ -796,7 +859,7 @@ function renderTags(){
['tA','tB','tC1','tC2'].forEach((id,i)=>lampSet(id,running(PRESS[i])?'run':'idle'));
const dRun=PRESS.slice(0,2).some(running);
M.vex.zoneT.forEach((t,i)=>t.textContent=f0(dRun?jit([132,146,156][i],1):[92,96,98][i])+'°');
- M.vex.zoneEls.forEach((z,i)=>z.setAttribute('fill',dRun?['#3a2a1c','#4a2e1a','#5a301a'][i]:'#1b2438'));lampSet('vex',dRun?'run':'idle');lampSet('ex35',S.ex35?'run':'idle');
+ M.vex.zoneEls.forEach((z,i)=>{z.style.fill=dRun?'var(--z'+(i+1)+')':'var(--z0)';});lampSet('vex',dRun?'run':'idle');lampSet('ex35',S.ex35?'run':'idle');
M.pppu.pos.forEach((p,i)=>{const w=ST.pppu.slots[i];p.r.setAttribute('class','pos'+(w?' on':''));p.a.textContent=w?w.it.T.sid+w.it.side+' 20 A':'free';p.b.textContent=w?dur(w.end-S.t):'';});
lampSet('pppu',ST.pppu.slots.some(Boolean)?'run':ST.pppu.q.length?'warn':'idle');
[0,1].forEach(u=>{const m=M['pdpu'+(u+1)];let any=false,done=false;
@@ -957,6 +1020,15 @@ function frame(now){const dt=Math.min(0.1,(now-last)/1000);last=now;
requestAnimationFrame(frame);
window.__plant={S,TITLES,RACK,PRESS,CELLS,ST,PLATEQ,M,tick};
})();
+(function(){
+ var b=document.getElementById("themeBtn"),de=document.documentElement;
+ function set(t,save){de.setAttribute("data-theme",t);if(save){try{localStorage.setItem("cnx-theme",t)}catch(e){}}
+ b.textContent=t==="light"?"☾":"☀";b.title="Switch to "+(t==="light"?"dark":"light")+" mode";}
+ set(de.getAttribute("data-theme")||"dark",false);
+ b.addEventListener("click",function(){set(de.getAttribute("data-theme")==="light"?"dark":"light",true);b.blur();});
+ var mq=window.matchMedia&&matchMedia("(prefers-color-scheme: light)");
+ if(mq&&mq.addEventListener)mq.addEventListener("change",function(e){var s=null;try{s=localStorage.getItem("cnx-theme")}catch(_){}if(!s)set(e.matches?"light":"dark",false);});
+})();