<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>The Cubinator - Container Load Estimator</title>
<!-- Tailwind CSS -->
<script src="https://cdn.tailwindcss.com"></script>
<!-- Font Awesome Icons -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<!-- Google Font Inter -->
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&display=swap" rel="stylesheet">
<script>
tailwind.config = {
theme: {
extend: {
colors: {
brand: {
50: '#f0f7ff',
100: '#e0effe',
500: '#0284c7',
600: '#0369a1',
700: '#035482',
800: '#075985',
900: '#0c4a6e',
}
},
fontFamily: {
sans: ['Inter', 'sans-serif'],
}
}
}
}
</script>
<style>
body { font-family: 'Inter', sans-serif; }
.custom-scrollbar::-webkit-scrollbar { width: 6px; height: 6px; }
.custom-scrollbar::-webkit-scrollbar-track { background: #f1f5f9; }
.custom-scrollbar::-webkit-scrollbar-thumb { background: #cbd5e1; border-radius: 4px; }
.custom-scrollbar::-webkit-scrollbar-thumb:hover { background: #94a3b8; }
</style>
</head>
<body class="bg-slate-100 text-slate-800 min-h-screen flex flex-col justify-between">
<!-- Navigation Header -->
<header class="bg-slate-900 text-white shadow-lg sticky top-0 z-50 border-b border-slate-800">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 h-16 flex items-center justify-between">
<div class="flex items-center space-x-3">
<div class="bg-sky-500 text-slate-900 p-2 rounded-lg font-black text-xl tracking-wider flex items-center">
<i class="fa-solid fa-cubes mr-2"></i>CUBINATOR
</div>
<span class="text-xs bg-slate-800 text-sky-400 px-2 py-1 rounded font-mono border border-slate-700">v2.0 Logic Fixed</span>
</div>
<div class="text-xs text-slate-400 hidden sm:block">
Precision Container Load Calculator
</div>
</div>
</header>
<!-- Main Container -->
<main class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8 w-full flex-grow">
<div class="grid grid-cols-1 lg:grid-cols-12 gap-8">
<!-- Input Form Column -->
<div class="lg:col-span-5 space-y-6">
<div class="bg-white rounded-xl shadow-sm border border-slate-200 p-6">
<h2 class="text-lg font-bold text-slate-900 mb-4 flex items-center">
<i class="fa-solid fa-box text-sky-600 mr-2"></i> Cargo Specifications
</h2>
<form id="calcForm" onsubmit="event.preventDefault(); calculate();" class="space-y-4">
<!-- Unit Selector -->
<div>
<label class="block text-xs font-semibold text-slate-600 uppercase mb-1">Measurement Unit</label>
<div class="grid grid-cols-2 gap-2">
<button type="button" id="unitCm" onclick="setUnit('cm')" class="py-2 px-3 text-sm font-medium rounded-lg border border-sky-500 bg-sky-50 text-sky-700 font-semibold">
Metric (CM / KG)
</button>
<button type="button" id="unitIn" onclick="setUnit('in')" class="py-2 px-3 text-sm font-medium rounded-lg border border-slate-200 text-slate-600 hover:bg-slate-50">
Imperial (IN / LBS)
</button>
</div>
</div>
<!-- Dimensions Inputs -->
<div class="grid grid-cols-3 gap-3">
<div>
<label class="block text-xs font-medium text-slate-600 mb-1">Length (<span class="unitDim">cm</span>)</label>
<input type="number" id="cLength" step="any" min="0.1" required class="w-full px-3 py-2 border border-slate-300 rounded-lg focus:ring-2 focus:ring-sky-500 focus:outline-none text-slate-900 font-semibold" placeholder="100">
</div>
<div>
<label class="block text-xs font-medium text-slate-600 mb-1">Width (<span class="unitDim">cm</span>)</label>
<input type="number" id="cWidth" step="any" min="0.1" required class="w-full px-3 py-2 border border-slate-300 rounded-lg focus:ring-2 focus:ring-sky-500 focus:outline-none text-slate-900 font-semibold" placeholder="100">
</div>
<div>
<label class="block text-xs font-medium text-slate-600 mb-1">Height (<span class="unitDim">cm</span>)</label>
<input type="number" id="cHeight" step="any" min="0.1" required class="w-full px-3 py-2 border border-slate-300 rounded-lg focus:ring-2 focus:ring-sky-500 focus:outline-none text-slate-900 font-semibold" placeholder="100">
</div>
</div>
<!-- Quantity and Weight -->
<div class="grid grid-cols-2 gap-3">
<div>
<label class="block text-xs font-medium text-slate-600 mb-1">Total Quantity (Pcs)</label>
<input type="number" id="cQty" min="1" step="1" required value="192" class="w-full px-3 py-2 border border-slate-300 rounded-lg focus:ring-2 focus:ring-sky-500 focus:outline-none text-slate-900 font-semibold">
</div>
<div>
<label class="block text-xs font-medium text-slate-600 mb-1">Unit Weight (<span class="unitWeight">kg</span>)</label>
<input type="number" id="cWeight" step="any" min="0" value="10" class="w-full px-3 py-2 border border-slate-300 rounded-lg focus:ring-2 focus:ring-sky-500 focus:outline-none text-slate-900 font-semibold">
</div>
</div>
<hr class="border-slate-100 my-2">
<!-- Options -->
<div class="space-y-3">
<div>
<label class="block text-xs font-semibold text-slate-600 uppercase mb-1">Target Container Type</label>
<select id="containerType" class="w-full px-3 py-2 border border-slate-300 rounded-lg focus:ring-2 focus:ring-sky-500 focus:outline-none text-slate-900 font-semibold bg-white">
<option value="40GP">40' General Purpose (40GP)</option>
<option value="40HC">40' High Cube (40HC)</option>
<option value="20GP">20' General Purpose (20GP)</option>
</select>
</div>
<!-- Double Stacking Toggle -->
<div class="bg-slate-50 p-3 rounded-lg border border-slate-200 flex items-center justify-between">
<div>
<div class="text-sm font-semibold text-slate-800">Double Stacking Allowed</div>
<div class="text-xs text-slate-500">Allow items to stack on top of each other</div>
</div>
<label class="relative inline-flex items-center cursor-pointer">
<input type="checkbox" id="canStack" checked class="sr-only peer">
<div class="w-11 h-6 bg-slate-300 peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-slate-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-sky-600"></div>
</label>
</div>
</div>
<button type="submit" class="w-full py-3 bg-sky-600 hover:bg-sky-700 text-white font-bold rounded-lg shadow transition flex items-center justify-center space-x-2">
<i class="fa-solid fa-calculator"></i>
<span>Calculate Containers</span>
</button>
</form>
</div>
</div>
<!-- Results Output Column -->
<div class="lg:col-span-7 space-y-6">
<!-- Primary Result Box -->
<div class="bg-slate-900 text-white rounded-xl p-6 shadow-xl relative overflow-hidden">
<div class="absolute -right-6 -bottom-6 opacity-10 text-9xl font-black text-sky-400 pointer-events-none">
<i class="fa-solid fa-truck-ramp-box"></i>
</div>
<div class="text-xs text-sky-400 font-mono uppercase tracking-wider mb-1">Calculation Results</div>
<div class="flex items-baseline space-x-3 my-2">
<span id="resContainers" class="text-5xl font-black text-white">0</span>
<span id="resContainerType" class="text-xl font-bold text-sky-300">x 40GP Containers</span>
</div>
<div id="resSummaryText" class="text-sm text-slate-300 border-t border-slate-800 pt-3 mt-3">
Enter cargo parameters and click Calculate.
</div>
</div>
<!-- Breakdown Cards -->
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<!-- Single Container Breakdown -->
<div class="bg-white rounded-xl p-5 shadow-sm border border-slate-200">
<h3 class="text-xs font-bold text-slate-400 uppercase tracking-wider mb-3">Capacity Per Single Container</h3>
<div class="space-y-3">
<div class="flex justify-between items-center">
<span class="text-sm text-slate-600">Max Cargo Pcs / Container:</span>
<span id="resFitPerContainer" class="text-base font-bold text-slate-900">0 pcs</span>
</div>
<div class="flex justify-between items-center">
<span class="text-sm text-slate-600">Volumetric Utilization:</span>
<span id="resVolUtil" class="text-base font-bold text-sky-600">0%</span>
</div>
<div class="flex justify-between items-center">
<span class="text-sm text-slate-600">Weight Utilization:</span>
<span id="resWeightUtil" class="text-base font-bold text-slate-800">0%</span>
</div>
</div>
</div>
<!-- Total Shipment Metrics -->
<div class="bg-white rounded-xl p-5 shadow-sm border border-slate-200">
<h3 class="text-xs font-bold text-slate-400 uppercase tracking-wider mb-3">Total Shipment Totals</h3>
<div class="space-y-3">
<div class="flex justify-between items-center">
<span class="text-sm text-slate-600">Total Total Cargo Volume:</span>
<span id="resTotalCbm" class="text-base font-bold text-slate-900">0 CBM</span>
</div>
<div class="flex justify-between items-center">
<span class="text-sm text-slate-600">Total Total Gross Weight:</span>
<span id="resTotalWeight" class="text-base font-bold text-slate-900">0 KG</span>
</div>
<div class="flex justify-between items-center">
<span class="text-sm text-slate-600">Formula Check:</span>
<span id="resFormulaCheck" class="text-xs font-mono text-slate-500">Total / PcsPerContainer</span>
</div>
</div>
</div>
</div>
<!-- Container Specifications Table -->
<div class="bg-white rounded-xl p-5 shadow-sm border border-slate-200">
<h3 class="text-xs font-bold text-slate-400 uppercase tracking-wider mb-3">Container Internal Specs Reference</h3>
<div class="overflow-x-auto">
<table class="w-full text-left text-xs">
<thead>
<tr class="border-b border-slate-200 text-slate-500">
<th class="pb-2">Type</th>
<th class="pb-2">Inner Dim (L × W × H)</th>
<th class="pb-2">Volume</th>
<th class="pb-2">Max Payload</th>
</tr>
</thead>
<tbody class="divide-y divide-slate-100 text-slate-700">
<tr>
<td class="py-2 font-bold text-sky-700">20GP</td>
<td class="py-2">5.89m × 2.35m × 2.39m</td>
<td class="py-2">33.2 CBM</td>
<td class="py-2">28,200 kg</td>
</tr>
<tr>
<td class="py-2 font-bold text-sky-700">40GP</td>
<td class="py-2">12.03m × 2.35m × 2.39m</td>
<td class="py-2">67.7 CBM</td>
<td class="py-2">26,700 kg</td>
</tr>
<tr>
<td class="py-2 font-bold text-sky-700">40HC</td>
<td class="py-2">12.03m × 2.35m × 2.69m</td>
<td class="py-2">76.3 CBM</td>
<td class="py-2">26,500 kg</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</main>
<footer class="bg-slate-900 text-slate-400 text-xs py-4 text-center border-t border-slate-800">
© The Cubinator Container Load Calculator. All Rights Reserved.
</footer>
<script>
// Container Specs (Dimensions in CM, Vol in CBM, Payload in KG)
const CONTAINERS = {
'20GP': { l: 589, w: 235, h: 239, maxCbm: 33.2, maxWeightKg: 28200 },
'40GP': { l: 1203, w: 235, h: 239, maxCbm: 67.7, maxWeightKg: 26700 },
'40HC': { l: 1203, w: 235, h: 269, maxCbm: 76.3, maxWeightKg: 26500 }
};
let currentUnit = 'cm'; // 'cm' or 'in'
function setUnit(unit) {
currentUnit = unit;
const isCm = unit === 'cm';
document.querySelectorAll('.unitDim').forEach(el => el.textContent = isCm ? 'cm' : 'in');
document.querySelectorAll('.unitWeight').forEach(el => el.textContent = isCm ? 'kg' : 'lbs');
document.getElementById('unitCm').className = isCm
? 'py-2 px-3 text-sm font-medium rounded-lg border border-sky-500 bg-sky-50 text-sky-700 font-semibold'
: 'py-2 px-3 text-sm font-medium rounded-lg border border-slate-200 text-slate-600 hover:bg-slate-50';
document.getElementById('unitIn').className = !isCm
? 'py-2 px-3 text-sm font-medium rounded-lg border border-sky-500 bg-sky-50 text-sky-700 font-semibold'
: 'py-2 px-3 text-sm font-medium rounded-lg border border-slate-200 text-slate-600 hover:bg-slate-50';
calculate();
}
function calculate() {
const lengthInput = parseFloat(document.getElementById('cLength').value);
const widthInput = parseFloat(document.getElementById('cWidth').value);
const heightInput = parseFloat(document.getElementById('cHeight').value);
const totalQty = parseInt(document.getElementById('cQty').value);
const unitWeightInput = parseFloat(document.getElementById('cWeight').value) || 0;
const containerType = document.getElementById('containerType').value;
const canStack = document.getElementById('canStack').checked;
if (!lengthInput || !widthInput || !heightInput || !totalQty) return;
// Convert dimensions to CM and KG internally
let lengthCm = currentUnit === 'in' ? lengthInput * 2.54 : lengthInput;
let widthCm = currentUnit === 'in' ? widthInput * 2.54 : widthInput;
let heightCm = currentUnit === 'in' ? heightInput * 2.54 : heightInput;
let unitWeightKg = currentUnit === 'in' ? unitWeightInput * 0.453592 : unitWeightInput;
const container = CONTAINERS[containerType];
// 1. Calculate how many fit along length, width, height
let fitLength = Math.floor(container.l / lengthCm);
let fitWidth = Math.floor(container.w / widthCm);
let fitHeight = Math.floor(container.h / heightCm);
// If stacking is turned off, limit vertical fit to 1 tier max
if (!canStack) {
fitHeight = Math.min(fitHeight, 1);
}
let pcsPerContainer = fitLength * fitWidth * fitHeight;
// Check if cargo is too large to fit even one piece
if (pcsPerContainer < 1) {
document.getElementById('resContainers').textContent = "0";
document.getElementById('resContainerType').textContent = `x ${containerType}`;
document.getElementById('resSummaryText').textContent = "Cargo item dimensions exceed single container dimensions.";
document.getElementById('resFitPerContainer').textContent = "0 pcs";
document.getElementById('resVolUtil').textContent = "0%";
document.getElementById('resWeightUtil').textContent = "0%";
return;
}
// 2. Check container payload weight limit constraints
if (unitWeightKg > 0) {
let maxByWeight = Math.floor(container.maxWeightKg / unitWeightKg);
pcsPerContainer = Math.min(pcsPerContainer, maxByWeight);
}
// 3. Exact division calculation: Total Qty / Capacity Per Container (rounded up)
const containersRequired = Math.ceil(totalQty / pcsPerContainer);
// Volume & Weight Totals
const singleItemCbm = (lengthCm * widthCm * heightCm) / 1000000;
const totalShipmentCbm = singleItemCbm * totalQty;
const totalShipmentKg = unitWeightKg * totalQty;
const cbmPerContainer = pcsPerContainer * singleItemCbm;
const volUtilPercent = ((cbmPerContainer / container.maxCbm) * 100).toFixed(1);
const weightUtilPercent = (((pcsPerContainer * unitWeightKg) / container.maxWeightKg) * 100).toFixed(1);
// Update UI
document.getElementById('resContainers').textContent = containersRequired;
document.getElementById('resContainerType').textContent = `x ${containerType} Container${containersRequired > 1 ? 's' : ''}`;
document.getElementById('resSummaryText').textContent =
`To transport ${totalQty.toLocaleString()} pieces, you need ${containersRequired} ${containerType} container(s). Each container holds up to ${pcsPerContainer} pieces (${canStack ? 'stacking enabled' : 'single layer only'}).`;
document.getElementById('resFitPerContainer').textContent = `${pcsPerContainer} pcs / container`;
document.getElementById('resVolUtil').textContent = `${volUtilPercent}%`;
document.getElementById('resWeightUtil').textContent = `${weightUtilPercent}%`;
document.getElementById('resTotalCbm').textContent = `${totalShipmentCbm.toFixed(2)} CBM`;
document.getElementById('resTotalWeight').textContent = currentUnit === 'in'
? `${(totalShipmentKg / 0.453592).toFixed(1)} LBS`
: `${totalShipmentKg.toFixed(1)} KG`;
document.getElementById('resFormulaCheck').textContent = `${totalQty} total ÷ ${pcsPerContainer} per cont. = ${containersRequired}`;
}
// Run initial calculation on load
window.onload = calculate;
</script>
</body>
</html>