Turntable Conveyor Configurator | SALECNC.net

:root {
–bg-primary: #f8fafc;
–bg-card: #ffffff;
–text-primary: #0f172a;
–text-secondary: #475569;
–text-muted: #94a3b8;
–primary: #2563eb;
–primary-light: #eff6ff;
–primary-hover: #1d4ed8;
–accent: #f97316;
–accent-light: #fff7ed;
–success: #10b981;
–border-color: #e2e8f0;
–border-hover: #cbd5e1;
–shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05);
–shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
–shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
–radius-lg: 16px;
–radius-md: 12px;
–radius-sm: 8px;
}
* { box-sizing: border-box; margin: 0; padding: 0; }
body { font-family: ‘Inter’, sans-serif; background: var(–bg-primary); color: var(–text-primary); line-height: 1.5; min-height: 100vh; }
.app-container { max-width: 1440px; margin: 0 auto; padding: 24px; }
header { display: flex; align-items: center; justify-content: space-between; background: var(–bg-card); padding: 16px 28px; border-radius: var(–radius-lg); box-shadow: var(–shadow-sm); border: 1px solid var(–border-color); margin-bottom: 24px; }
.logo-group { display: flex; align-items: center; gap: 16px; }
.logo-cnc { font-family: ‘Outfit’, sans-serif; font-size: 28px; font-weight: 800; font-style: italic; letter-spacing: -0.5px; }
.logo-cnc span.orange { color: var(–accent); }
.logo-cnc span.dark { color: #1e293b; }
.logo-cnc span.net { font-size: 16px; font-weight: 500; color: var(–text-secondary); }
.header-title { text-align: right; }
.header-title h1 { font-family: ‘Outfit’, sans-serif; font-size: 1.25rem; font-weight: 700; color: var(–text-primary); }
.header-title p { font-size: 0.85rem; color: var(–text-secondary); }
.workspace-grid { display: grid; grid-template-columns: 420px 1fr; gap: 24px; }
.sidebar { display: flex; flex-direction: column; gap: 20px; }
.card { background: var(–bg-card); border: 1px solid var(–border-color); border-radius: var(–radius-lg); padding: 24px; box-shadow: var(–shadow-sm); }
.card-title { font-family: ‘Outfit’, sans-serif; font-size: 1.1rem; font-weight: 700; margin-bottom: 18px; display: flex; align-items: center; gap: 8px; color: var(–text-primary); border-bottom: 2px solid var(–primary-light); padding-bottom: 8px; }
.card-title .icon { color: var(–primary); }
.form-group { margin-bottom: 18px; }
.form-group:last-child { margin-bottom: 0; }
.label-row { display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px; }
.control-label { font-size: 0.875rem; font-weight: 600; color: var(–text-primary); }
.control-value { font-family: ‘Outfit’, sans-serif; font-size: 0.9rem; font-weight: 700; color: var(–primary); background: var(–primary-light); padding: 2px 8px; border-radius: var(–radius-sm); }
input[type=”range”] { -webkit-appearance: none; width: 100%; height: 6px; background: #e2e8f0; border-radius: 9999px; outline: none; transition: background 0.2s; }
input[type=”range”]::-webkit-slider-thumb { -webkit-appearance: none; appearance: none; width: 18px; height: 18px; border-radius: 50%; background: var(–primary); cursor: pointer; border: 2px solid #ffffff; box-shadow: var(–shadow-sm); transition: background-color 0.15s, transform 0.15s; }
input[type=”range”]::-webkit-slider-thumb:hover { background: var(–primary-hover); transform: scale(1.1); }
.slider-limits { display: flex; justify-content: space-between; font-size: 0.75rem; color: var(–text-muted); margin-top: 4px; }
select { width: 100%; padding: 10px 14px; border-radius: var(–radius-sm); border: 1px solid var(–border-color); background-color: var(–bg-card); font-family: inherit; font-size: 0.9rem; color: var(–text-primary); outline: none; cursor: pointer; transition: border-color 0.2s, box-shadow 0.2s; appearance: none; background-image: url(“data:image/svg+xml;charset=UTF-8,%3Csvg xmlns=’http://www.w3.org/2000/svg’ width=’24’ height=’24’ viewBox=’0 0 24 24′ fill=’none’ stroke=’%23475569′ stroke-width=’2′ stroke-linecap=’round’ stroke-linejoin=’round’%3E%3Cpolyline points=’6 9 12 15 18 9’%3E%3C/polyline%3E%3C/svg%3E”); background-repeat: no-repeat; background-position: right 12px center; background-size: 16px; }
select:focus { border-color: var(–primary); box-shadow: 0 0 0 3px rgba(37,99,235,0.15); }
.static-badge { background: #f1f5f9; color: var(–text-secondary); border: 1px solid var(–border-color); padding: 10px 14px; border-radius: var(–radius-sm); font-size: 0.9rem; font-weight: 500; display: flex; align-items: center; justify-content: space-between; }
.static-badge-lock { color: var(–text-muted); font-size: 0.75rem; display: flex; align-items: center; gap: 4px; }
.color-selector { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; }
.color-pill { display: flex; align-items: center; justify-content: center; gap: 8px; padding: 8px; border: 1px solid var(–border-color); border-radius: var(–radius-sm); cursor: pointer; transition: all 0.2s; background: var(–bg-card); }
.color-pill:hover { border-color: var(–border-hover); background: var(–bg-primary); }
.color-pill.active { border-color: var(–primary); background: var(–primary-light); box-shadow: 0 0 0 1px var(–primary); }
.color-dot { width: 14px; height: 14px; border-radius: 50%; border: 1px solid rgba(0,0,0,0.1); }
.color-dot.gold { background: #ffd700; }
.color-dot.silver { background: #e2e8f0; }
.color-dot.black { background: #0f172a; }
.color-label { font-size: 0.85rem; font-weight: 500; color: var(–text-primary); }
.price-card { background: linear-gradient(135deg, #1e293b 0%, #0f172a 100%); color: #ffffff; border: none; }
.price-card .card-title { color: #ffffff; border-bottom: 2px solid rgba(255,255,255,0.1); }
.price-row { display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px; }
.price-row.total { margin-top: 16px; border-top: 1px dashed rgba(255,255,255,0.2); padding-top: 16px; }
.price-row .label { font-size: 0.85rem; color: #cbd5e1; }
.price-row .val { font-family: ‘Outfit’, sans-serif; font-size: 0.95rem; font-weight: 600; }
.price-row.total .label { font-size: 1.1rem; font-weight: 700; color: #ffffff; }
.price-row.total .val-group { text-align: right; }
.price-row.total .thb-val { font-family: ‘Outfit’, sans-serif; font-size: 1.6rem; font-weight: 800; color: var(–accent); line-height: 1.2; }
.price-row.total .usd-val { font-size: 0.9rem; color: #94a3b8; }
.btn { display: flex; align-items: center; justify-content: center; gap: 8px; width: 100%; padding: 14px; border-radius: var(–radius-md); font-family: ‘Outfit’, sans-serif; font-size: 1rem; font-weight: 700; cursor: pointer; transition: all 0.2s; border: none; }
.btn-primary { background: var(–primary); color: #ffffff; box-shadow: 0 4px 6px -1px rgba(37,99,235,0.2); }
.btn-primary:hover { background: var(–primary-hover); transform: translateY(-1px); box-shadow: 0 6px 8px -1px rgba(37,99,235,0.25); }
.diagram-area { display: flex; flex-direction: column; gap: 24px; }
.diagram-panel { background: var(–bg-card); border: 1px solid var(–border-color); border-radius: var(–radius-lg); padding: 24px; box-shadow: var(–shadow-sm); display: flex; flex-direction: column; position: relative; min-height: 380px; }
.diagram-panel.large { min-height: 480px; }
.diagram-panel-title { font-family: ‘Outfit’, sans-serif; font-size: 0.95rem; font-weight: 700; color: var(–text-secondary); text-transform: uppercase; letter-spacing: 0.05em; margin-bottom: 16px; display: flex; align-items: center; justify-content: space-between; }
.diagram-canvas-container { flex: 1; display: flex; align-items: center; justify-content: center; overflow: hidden; border: 1px solid #f1f5f9; border-radius: var(–radius-md); background-color: #fafbfc; position: relative; }
.diagram-canvas-container svg { width: 100%; height: 100%; display: block; }
.diagrams-bottom-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 24px; }
.print-quote-page { display: none; }
@media (max-width: 1100px) {
.workspace-grid { grid-template-columns: 1fr; }
.sidebar { order: 2; }
.diagram-area { order: 1; }
}
@media (max-width: 768px) {
.diagrams-bottom-grid { grid-template-columns: 1fr; }
}
@media print {
@page { size: landscape; margin: 0; }
body { margin: 0; background: #ffffff !important; }
.no-print { display: none !important; }
.print-quote-page { display: block !important; position: relative; width: 297mm; height: 210mm; margin: 0 auto; padding: 0; box-sizing: border-box; background: #ffffff; page-break-after: avoid; overflow: hidden; }
* { -webkit-print-color-adjust: exact !important; print-color-adjust: exact !important; }
}

/* —- แก้ URL รูปภาพตรงนี้ที่เดียว —- */
var IMG = {
tg: ‘https://www.salecnc.net/wp-content/uploads/tg.jpg’,
ts: ‘https://www.salecnc.net/wp-content/uploads/ts.jpg’,
tb: ‘https://www.salecnc.net/wp-content/uploads/tb.jpg’,
logo: ‘https://www.salecnc.net/wp-content/uploads/logo-turn.png’,
top_con: ‘https://www.salecnc.net/wp-content/uploads/top_con.png’,
cnc_plate: ‘https://www.salecnc.net/wp-content/uploads/cnc-plate.png’,
template: ‘https://www.salecnc.net/wp-content/uploads/turn-template.jpg’
};

SALECNC.net

Turntable Conveyor Configurator

Interactive Customization & Quotation System

Figure 1 — Top View (ภาพด้านบน)
Centrally Anchored

Figure 2 — Side View (ภาพด้านข้าง)
Base Anchored

Figure 3 — Isometric View (ภาพ ISO)

/* ======================================================
STATE
====================================================== */
var state = {
width: 560, length: 1400, color: ‘gold’,
spacing: 200, height: 300, material: ‘marble’, diameter: 150
};

/* ======================================================
SET DEFAULT IMAGES (ใช้ IMG object ที่กำหนดไว้ด้านบน)
====================================================== */
document.getElementById(‘iso-image’).src = IMG.tg;
document.getElementById(‘print-iso-img’).src = IMG.tg;
document.getElementById(‘print-bg’).src = IMG.template;

/* ======================================================
EVENT LISTENERS
====================================================== */
document.getElementById(‘input-length’).addEventListener(‘input’, function(e) {
state.length = parseInt(e.target.value);
document.getElementById(‘val-length’).textContent = state.length.toLocaleString() + ‘ mm’;
updateAll();
});
document.getElementById(‘input-spacing’).addEventListener(‘input’, function(e) {
state.spacing = parseInt(e.target.value);
document.getElementById(‘val-spacing’).textContent = state.spacing + ‘ mm’;
updateAll();
});
document.getElementById(‘input-height’).addEventListener(‘input’, function(e) {
state.height = parseInt(e.target.value);
document.getElementById(‘val-height’).textContent = state.height + ‘ mm’;
updateAll();
});
document.getElementById(‘input-material’).addEventListener(‘change’, function(e) {
state.material = e.target.value;
updateAll();
});
document.getElementById(‘input-diameter’).addEventListener(‘input’, function(e) {
state.diameter = parseInt(e.target.value);
document.getElementById(‘val-diameter’).textContent = state.diameter + ‘ mm’;
updateAll();
});

function setColor(color) {
state.color = color;
document.querySelectorAll(‘.color-pill’).forEach(function(pill) {
pill.classList.remove(‘active’);
if (pill.getAttribute(‘onclick’).indexOf(color) !== -1) pill.classList.add(‘active’);
});
updateAll();
}

/* ======================================================
PRICING
====================================================== */
var USD_RATE = 35.0;
var baseCostTHB = 45000;

function calculatePrice() {
var lengthSurcharge = Math.max(0, (state.length – 1400) * 1.5);
var heightSurcharge = Math.max(0, (state.height – 300) * 4);
var discSurcharge = Math.max(0, (state.diameter – 150) * 10);
var extraCharges = 0;
if (state.material === ‘marble’) extraCharges += 8000;
else if (state.material === ‘stainless’) extraCharges += 5000;
else if (state.material === ‘aluminum’) extraCharges += 3500;
else if (state.material === ‘acrylic’) extraCharges += 2000;
else if (state.material === ‘pvc’) extraCharges += 1000;
if (state.color === ‘gold’) extraCharges += 1500;
else if (state.color === ‘silver’) extraCharges += 800;
var totalTHB = baseCostTHB + lengthSurcharge + heightSurcharge + discSurcharge + extraCharges;
var totalUSD = totalTHB / USD_RATE;
document.getElementById(‘price-total-thb’).textContent = ‘฿’ + totalTHB.toLocaleString(‘en-US’, {minimumFractionDigits:2});
document.getElementById(‘price-total-usd’).textContent = ‘$’ + totalUSD.toLocaleString(‘en-US’, {minimumFractionDigits:2}) + ‘ USD’;
return { totalTHB: totalTHB, totalUSD: totalUSD };
}

/* ======================================================
TOP VIEW SVG
====================================================== */
function renderTopView(svg, targetWidth) {
svg = svg || document.getElementById(‘svg1’);
svg.innerHTML = ”;
var L = state.length;
var W = L – 560;
var Spacing = state.spacing;
var hBlue = 560 + (Spacing – 20) * 2;
var hPink = 560 + Spacing * 2;
var L_outer = L + Spacing * 2;
var containerWidth = targetWidth || svg.clientWidth || (svg.parentNode ? svg.parentNode.clientWidth : 0);
if (!containerWidth || containerWidth < 50) containerWidth = 800;
var scale = L_outer / (containerWidth – 260);
var marginX = 130 * scale;
var marginY = 100 * scale;
var viewBoxWidth = L_outer + marginX * 2;
var viewBoxHeight = hPink + marginY * 2;
svg.setAttribute('viewBox', (-viewBoxWidth/2) + ' ' + (-viewBoxHeight/2) + ' ' + viewBoxWidth + ' ' + viewBoxHeight);

var beltColor = '#cbd5e1';
if (state.color === 'gold') beltColor = '#d8bc7e';
else if (state.color === 'silver') beltColor = '#cbd5e1';
else if (state.color === 'black') beltColor = '#0f172a';

var goldColor = '#d8bc7e';
var lightGrey = '#e2e8f0';

var layers = [
{ h: hPink, r: hPink/2, rectFill: goldColor, arcFill: goldColor },
{ h: hBlue, r: hBlue/2, rectFill: lightGrey, arcFill: lightGrey },
{ h: 560, r: 280, rectFill: beltColor, arcFill: beltColor },
{ h: 530, r: 265, rectFill: beltColor, arcFill: beltColor },
{ h: 105, r: 52.5, rectFill: beltColor, arcFill: beltColor }
];

layers.forEach(function(layer) {
var rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
rect.setAttribute('x', -W/2); rect.setAttribute('y', -layer.h/2);
rect.setAttribute('width', W); rect.setAttribute('height', layer.h);
rect.setAttribute('fill', layer.rectFill);
svg.appendChild(rect);

var la = document.createElementNS('http://www.w3.org/2000/svg', 'path');
la.setAttribute('d', 'M ' + (-W/2) + ' ' + (-layer.h/2) + ' A ' + layer.r + ' ' + layer.r + ' 0 0 0 ' + (-W/2) + ' ' + (layer.h/2) + ' Z');
la.setAttribute('fill', layer.arcFill); svg.appendChild(la);

var ra = document.createElementNS('http://www.w3.org/2000/svg', 'path');
ra.setAttribute('d', 'M ' + (W/2) + ' ' + (-layer.h/2) + ' A ' + layer.r + ' ' + layer.r + ' 0 0 1 ' + (W/2) + ' ' + (layer.h/2) + ' Z');
ra.setAttribute('fill', layer.arcFill); svg.appendChild(ra);
});

/* Logo */
var logoImg = document.createElementNS('http://www.w3.org/2000/svg', 'image');
logoImg.setAttribute('href', IMG.logo);
logoImg.setAttribute('x', -90); logoImg.setAttribute('y', -40);
logoImg.setAttribute('width', 180); logoImg.setAttribute('height', 80);
logoImg.setAttribute('preserveAspectRatio', 'xMidYMid meet');
svg.appendChild(logoImg);

/* Dark green square + top_con */
var sqSize = 110;
var sqX = W/2 – 107.50 – sqSize;
var sqY = -sqSize/2;

var sq = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
sq.setAttribute('x', sqX); sq.setAttribute('y', sqY);
sq.setAttribute('width', sqSize); sq.setAttribute('height', sqSize);
sq.setAttribute('fill', beltColor);
svg.appendChild(sq);

var topConImg = document.createElementNS('http://www.w3.org/2000/svg', 'image');
topConImg.setAttribute('href', IMG.top_con);
topConImg.setAttribute('x', sqX); topConImg.setAttribute('y', sqY);
topConImg.setAttribute('width', sqSize); topConImg.setAttribute('height', sqSize);
svg.appendChild(topConImg);

/* Conveyor plates */
var R_path = 158.75;
var Perimeter = 2 * W + 2 * Math.PI * R_path;
var NumPlates = Math.round(Perimeter / 40);
var actual_pitch = Perimeter / NumPlates;

var plateFillColor = goldColor;
if (state.color === 'silver') plateFillColor = '#cbd5e1';
else if (state.color === 'black') plateFillColor = '#0f172a';

for (var i = 0; i < NumPlates; i++) {
var dist = i * actual_pitch;
var x = 0, y = 0, theta = 0;
if (dist <= W) {
x = -W/2 + dist; y = -R_path; theta = 0;
} else if (dist <= W + Math.PI * R_path) {
var arc_dist = dist – W;
var alpha = -Math.PI/2 + arc_dist/R_path;
x = W/2 + R_path * Math.cos(alpha); y = R_path * Math.sin(alpha);
theta = (alpha + Math.PI/2) * 180 / Math.PI;
} else if (dist <= 2*W + Math.PI*R_path) {
var line_dist = dist – (W + Math.PI*R_path);
x = W/2 – line_dist; y = R_path; theta = 180;
} else {
var arc_dist2 = dist – (2*W + Math.PI*R_path);
var alpha2 = Math.PI/2 + arc_dist2/R_path;
x = -W/2 + R_path * Math.cos(alpha2); y = R_path * Math.sin(alpha2);
theta = (alpha2 + Math.PI/2) * 180 / Math.PI;
}
var pg = document.createElementNS('http://www.w3.org/2000/svg', 'g');
pg.setAttribute('transform', 'translate(' + x + ',' + y + ') rotate(' + theta + ')');
var pr = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
pr.setAttribute('x','-25'); pr.setAttribute('y','-87.5');
pr.setAttribute('width','50'); pr.setAttribute('height','175');
pr.setAttribute('fill', plateFillColor); pr.setAttribute('stroke','#475569'); pr.setAttribute('stroke-width','1');
pg.appendChild(pr);
var pe = document.createElementNS('http://www.w3.org/2000/svg', 'path');
pe.setAttribute('d','M -25 -87.5 A 73 87.5 0 0 0 -25 87.5 Z');
pe.setAttribute('fill', plateFillColor); pe.setAttribute('stroke','#475569'); pe.setAttribute('stroke-width','1');
pg.appendChild(pe);
svg.appendChild(pg);
}

/* Plate image */
var plateSize = state.diameter;
var plateY = 280 + Spacing/2;
var plateImg = document.createElementNS('http://www.w3.org/2000/svg', 'image');
plateImg.setAttribute('href', IMG.cnc_plate);
plateImg.setAttribute('x', -plateSize/2); plateImg.setAttribute('y', plateY – plateSize/2);
plateImg.setAttribute('width', plateSize); plateImg.setAttribute('height', plateSize);
plateImg.setAttribute('preserveAspectRatio', 'xMidYMid meet');
svg.appendChild(plateImg);

addTopViewDimensionLines(svg, L, Spacing, scale);
}

function addTopViewDimensionLines(svg, L, Spacing, scale) {
var dimColor = '#475569';
var tickSize = 8*scale, arrowLength = 12*scale, arrowWidth = 4*scale;
var fontSize = 16*scale, textOffset = 8*scale;
var W = L – 560;
var hPink = 560 + Spacing*2;

function drawDimLine(x1,y1,x2,y2,projX1,projY1,projX2,projY2,textVal,isVertical,textOffsetSide) {
textOffsetSide = textOffsetSide || -1;
function line(ax1,ay1,ax2,ay2,dashed) {
var el = document.createElementNS('http://www.w3.org/2000/svg','line');
el.setAttribute('x1',ax1); el.setAttribute('y1',ay1);
el.setAttribute('x2',ax2); el.setAttribute('y2',ay2);
el.setAttribute('stroke',dimColor); el.setAttribute('stroke-width', dashed ? 1.5*scale : 2*scale);
if (dashed) el.setAttribute('stroke-dasharray', (4*scale)+' '+(4*scale));
svg.appendChild(el);
}
function poly(pts) {
var el = document.createElementNS('http://www.w3.org/2000/svg','polygon');
el.setAttribute('points',pts); el.setAttribute('fill',dimColor); svg.appendChild(el);
}
function txt(tx,ty,val,rotate) {
var el = document.createElementNS('http://www.w3.org/2000/svg','text');
el.setAttribute('x',tx); el.setAttribute('y',ty);
el.setAttribute('fill',dimColor); el.setAttribute('font-family','Outfit');
el.setAttribute('font-size', fontSize+'px'); el.setAttribute('font-weight','700');
el.setAttribute('text-anchor','middle');
if (rotate) el.setAttribute('transform','rotate(-90,'+tx+','+ty+')');
el.textContent = val; svg.appendChild(el);
}
if (isVertical) {
line(projX1,projY1, x1+textOffsetSide*tickSize, y1, true);
line(projX2,projY2, x2+textOffsetSide*tickSize, y2, true);
line(x1,y1,x2,y2);
poly(x1+','+(y1)+' '+(x1-arrowWidth)+','+(y1+arrowLength)+' '+(x1+arrowWidth)+','+(y1+arrowLength));
poly(x2+','+(y2)+' '+(x2-arrowWidth)+','+(y2-arrowLength)+' '+(x2+arrowWidth)+','+(y2-arrowLength));
var tx = x1 + textOffsetSide*(textOffset+12*scale);
txt(tx,(y1+y2)/2,textVal,true);
} else {
line(projX1,projY1, x1, y1-tickSize, true);
line(projX2,projY2, x2, y2-tickSize, true);
line(x1,y1,x2,y2);
poly(x1+','+y1+' '+(x1+arrowLength)+','+(y1-arrowWidth)+' '+(x1+arrowLength)+','+(y1+arrowWidth));
poly(x2+','+y2+' '+(x2-arrowLength)+','+(y2-arrowWidth)+' '+(x2-arrowLength)+','+(y2+arrowWidth));
txt((x1+x2)/2, y1-textOffset, textVal, false);
}
}

var lengthDimY = (280+Spacing)+40*scale;
drawDimLine(-L/2,lengthDimY,L/2,lengthDimY,-L/2,280+Spacing,L/2,280+Spacing, L.toLocaleString()+' mm', false);
var L_outer = L + Spacing*2;
var topDimY = -(hPink/2)-40*scale;
drawDimLine(-L_outer/2,topDimY,L_outer/2,topDimY,-L_outer/2,-hPink/2,L_outer/2,-hPink/2, L_outer.toLocaleString()+' mm', false);
var rightDimX = L/2+Spacing+40*scale;
drawDimLine(rightDimX,-hPink/2,rightDimX,hPink/2,W/2,-hPink/2,W/2,hPink/2, hPink.toLocaleString()+' mm', true, 1);
var leftDimX = -L/2-Spacing-60*scale;
drawDimLine(leftDimX,-(280+Spacing),leftDimX,-280,-W/2,-(280+Spacing),-W/2,-280, Spacing+' mm', true, -1);
var yPlateTop = 280+Spacing/2-state.diameter/2;
var valGap = Math.round(Spacing/2-state.diameter/2);
drawDimLine(leftDimX,280,leftDimX,yPlateTop,-W/2,280,-state.diameter/2,yPlateTop, valGap+' mm', true, -1);
var yPlateBottom = 280+Spacing/2+state.diameter/2;
drawDimLine(leftDimX,yPlateBottom,leftDimX,280+Spacing,-state.diameter/2,yPlateBottom,-W/2,280+Spacing, valGap+' mm', true, -1);
}

/* ======================================================
SIDE VIEW SVG
====================================================== */
function renderSideView(svg, targetWidth) {
svg = svg || document.getElementById('svg2');
svg.innerHTML = '';
var TableHeight = state.height;
var Spacing = state.spacing;
var wOrange = 705, hOrange = TableHeight – 60;
var wLBlue = 560 + Spacing*2, hLBlue = 60;
var wPink = 110, hPink = 230;
var wTotal = wLBlue, hTotal = TableHeight + hPink;
var containerWidth = targetWidth || svg.clientWidth || (svg.parentNode ? svg.parentNode.clientWidth : 0);
if (!containerWidth || containerWidth < 50) containerWidth = 400;
var scale = (wTotal+200)/containerWidth;
var marginX = 100*scale, marginY = 80*scale;
var viewBoxWidth = wTotal + marginX*2;
var viewBoxHeight = hTotal + marginY*2;
svg.setAttribute('viewBox', (-viewBoxWidth/2)+' '+(-viewBoxHeight+marginY)+' '+viewBoxWidth+' '+viewBoxHeight);

function rect(x,y,w,h,fill,stroke,sw) {
var el = document.createElementNS('http://www.w3.org/2000/svg','rect');
el.setAttribute('x',x); el.setAttribute('y',y);
el.setAttribute('width',w); el.setAttribute('height',h);
el.setAttribute('fill',fill);
if (stroke) { el.setAttribute('stroke',stroke); el.setAttribute('stroke-width',sw||1); }
svg.appendChild(el);
}

rect(-wOrange/2, -hOrange, wOrange, hOrange, '#0f172a');
rect(-wLBlue/2, -TableHeight, wLBlue, hLBlue, '#d8bc7e');

var pinkFillColor = '#d8bc7e';
if (state.color === 'silver') pinkFillColor = '#cbd5e1';
else if (state.color === 'black') pinkFillColor = '#334155';
rect(-wPink/2, -TableHeight-hPink, wPink, hPink, pinkFillColor, '#ffffff', 1);

var ground = document.createElementNS('http://www.w3.org/2000/svg','line');
ground.setAttribute('x1',-wTotal/2-50*scale); ground.setAttribute('y1',0);
ground.setAttribute('x2', wTotal/2+50*scale); ground.setAttribute('y2',0);
ground.setAttribute('stroke','#475569'); ground.setAttribute('stroke-width',3*scale);
svg.appendChild(ground);

addSideViewDimensionLines(svg, wTotal, wLBlue, TableHeight, -TableHeight-hPink, hPink, scale, wOrange);
}

function addSideViewDimensionLines(svg, wTotal, wLBlue, TableHeight, pinkY, pinkH, scale, wOrange) {
var dimColor = '#475569';
var arrowLength = 12*scale, arrowWidth = 4*scale;
var fontSize = 16*scale, textOffset = 8*scale;
var heightDimX = -wLBlue/2-50*scale;

function line(x1,y1,x2,y2,w,dashed) {
var el = document.createElementNS('http://www.w3.org/2000/svg','line');
el.setAttribute('x1',x1); el.setAttribute('y1',y1); el.setAttribute('x2',x2); el.setAttribute('y2',y2);
el.setAttribute('stroke',dimColor); el.setAttribute('stroke-width',w||2*scale);
if (dashed) el.setAttribute('stroke-dasharray',(4*scale)+' '+(4*scale));
svg.appendChild(el);
}
function poly(pts) {
var el = document.createElementNS('http://www.w3.org/2000/svg','polygon');
el.setAttribute('points',pts); el.setAttribute('fill',dimColor); svg.appendChild(el);
}
function txt(x,y,val,rotate) {
var el = document.createElementNS('http://www.w3.org/2000/svg','text');
el.setAttribute('x',x); el.setAttribute('y',y); el.setAttribute('fill',dimColor);
el.setAttribute('font-family','Outfit'); el.setAttribute('font-size',fontSize+'px');
el.setAttribute('font-weight','700'); el.setAttribute('text-anchor','middle');
if (rotate) el.setAttribute('transform','rotate(-90,'+x+','+y+')');
el.textContent = val; svg.appendChild(el);
}

line(heightDimX,0,heightDimX,-TableHeight);
line(-wOrange/2,0,heightDimX-8*scale,0,1.5*scale,true);
line(-wLBlue/2,-TableHeight,heightDimX-8*scale,-TableHeight,1.5*scale,true);
poly(heightDimX+','+(-TableHeight)+' '+(heightDimX-arrowWidth)+','+(-TableHeight+arrowLength)+' '+(heightDimX+arrowWidth)+','+(-TableHeight+arrowLength));
poly(heightDimX+',0 '+(heightDimX-arrowWidth)+','+(-arrowLength)+' '+(heightDimX+arrowWidth)+','+(-arrowLength));
var tx = heightDimX-(textOffset+12*scale);
txt(tx,-TableHeight/2,'H = '+TableHeight+' mm',true);

var widthDimY = 40*scale;
line(-wLBlue/2,widthDimY,wLBlue/2,widthDimY);
line(-wLBlue/2,-TableHeight,-wLBlue/2,widthDimY+8*scale,1.5*scale,true);
line(wLBlue/2,-TableHeight,wLBlue/2,widthDimY+8*scale,1.5*scale,true);
poly((-wLBlue/2)+','+widthDimY+' '+(-wLBlue/2+arrowLength)+','+(widthDimY-arrowWidth)+' '+(-wLBlue/2+arrowLength)+','+(widthDimY+arrowWidth));
poly((wLBlue/2)+','+widthDimY+' '+(wLBlue/2-arrowLength)+','+(widthDimY-arrowWidth)+' '+(wLBlue/2-arrowLength)+','+(widthDimY+arrowWidth));
txt(0, widthDimY+textOffset+16*scale, 'Width Span = '+wLBlue.toLocaleString()+' mm', false);
}

/* ======================================================
UPDATE ALL
====================================================== */
function updateAll() {
calculatePrice();
renderTopView();
renderSideView();
var isoImg = document.getElementById('iso-image');
if (isoImg) {
if (state.color === 'gold') isoImg.src = IMG.tg;
else if (state.color === 'silver') isoImg.src = IMG.ts;
else if (state.color === 'black') isoImg.src = IMG.tb;
}
}

/* ======================================================
PRINT
====================================================== */
function printQuote() {
var bgImg = document.getElementById('print-bg');
var isoImg = document.getElementById('print-iso-img');

document.getElementById('print-val-width').textContent = '560 mm';
document.getElementById('print-val-length').textContent = state.length.toLocaleString() + ' mm';
document.getElementById('print-val-color').textContent = state.color.charAt(0).toUpperCase() + state.color.slice(1);
document.getElementById('print-val-tbl-width').textContent = (560+state.spacing*2).toLocaleString() + ' mm';
document.getElementById('print-val-tbl-length').textContent= (state.length+state.spacing*2).toLocaleString() + ' mm';
document.getElementById('print-val-tbl-height').textContent= state.height.toLocaleString() + ' mm';
document.getElementById('print-val-material').textContent = 'Marble';

if (state.color === 'gold') isoImg.src = IMG.tg;
else if (state.color === 'silver') isoImg.src = IMG.ts;
else if (state.color === 'black') isoImg.src = IMG.tb;

renderTopView(document.getElementById('svg1-print'), 673.5);
renderSideView(document.getElementById('svg2-print'), 404.1);

var loaded = 0;
[bgImg, isoImg].forEach(function(img) {
if (img.complete) { loaded++; if (loaded === 2) setTimeout(function(){ window.print(); }, 400); }
else { img.onload = img.onerror = function() { loaded++; if (loaded === 2) setTimeout(function(){ window.print(); }, 400); }; }
});
}

/* ======================================================
INIT
====================================================== */
window.onload = function() { updateAll(); };
window.addEventListener('resize', function() { updateAll(); });