diff --git a/templates/roll_calculator.html b/templates/roll_calculator.html
index b38ddc1..5463d08 100644
--- a/templates/roll_calculator.html
+++ b/templates/roll_calculator.html
@@ -297,9 +297,23 @@
font-size: 13px;
}
.lo-summary-item:last-child { margin-bottom: 0; }
+ .lo-summary-item.lo-governing-summary {
+ background: #eef8f2;
+ border-left: 3px solid #2BAC70;
+ padding: 8px 10px;
+ border-radius: 4px;
+ }
.lo-value-highlight { color: #2BAC70; font-weight: bold; font-size: 16px; }
.lo-value-number { color: #1F5438; font-weight: bold; }
.lo-util-group { display: flex; flex-direction: column; gap: 4px; text-align: right; }
+ .lo-reserve-note {
+ margin-top: 4px;
+ color: #666;
+ font-size: 12px;
+ line-height: 1.35;
+ text-align: right;
+ max-width: 300px;
+ }
.lo-results-table {
background: white;
padding: 16px;
@@ -315,10 +329,15 @@
font-weight: 600;
color: #333;
border-bottom: 2px solid #2BAC70;
+ white-space: normal;
}
.lo-results-table td { padding: 8px; border-bottom: 1px solid #e0e0e0; }
.lo-results-table tbody tr:hover { background: #f9f9f9; }
- .lo-results-table tbody tr.lo-recommended { background: #fffacd; font-weight: bold; }
+ .lo-results-table tbody tr.lo-governing {
+ background: #eef8f2;
+ font-weight: 600;
+ border-left: 3px solid #2BAC70;
+ }
.lo-warning {
background: #fff8e1;
border: 1px solid #f0b429;
@@ -807,9 +826,9 @@
-
Results:
-
-
Limiting Factor:
+
Capacity Summary:
+
+ Governing Constraint:
–
@@ -827,18 +846,27 @@
Product: – m²
+
+
Remaining Capacity:
+
+
Payload: – kg
+
Unused Payload: – %
+
Unused Volume: – %
+
+
+
-
Comparison Table:
+
Capacity Analysis:
- | Scenario |
- Rolls |
- kg |
- m² |
- Util. % |
+ Constraint |
+ Theoretical Max Rolls |
+ Theoretical Total Weight |
+ Transported Area [m²] |
+ Payload Util. % |
@@ -1350,6 +1378,14 @@ class LoadOptimizerUI {
showResults(res, maxW) {
const m2PerRoll = this.optimizer.state.m2PerRoll || 0;
+ const remainingPayload = Math.max(0, maxW - res.finalWeight);
+ const unusedPayload = Math.max(0, 100 - res.utilizationWeight);
+ const unusedVolume = Math.max(0, 100 - res.utilizationVolume);
+ const interpretations = {
+ geometry: 'Payload remains available; no additional roll fits geometrically.',
+ weight: 'Payload limit is reached before volume or geometry.',
+ volume: 'Volume capacity is reached before payload or geometry.'
+ };
document.getElementById('limitingFactorValue').textContent = res.limiting.name;
document.getElementById('totalRollsValue').textContent = res.finalRolls;
document.getElementById('rollsDetailValue').textContent =
@@ -1357,16 +1393,21 @@ class LoadOptimizerUI {
document.getElementById('weightUtilValue').textContent = this.optimizer.fmt(res.utilizationWeight);
document.getElementById('volumeUtilValue').textContent = this.optimizer.fmt(res.utilizationVolume);
document.getElementById('productM2Value').textContent = this.optimizer.fmt(res.finalM2, 0);
+ document.getElementById('remainingPayloadValue').textContent = this.optimizer.fmt(remainingPayload, 0);
+ document.getElementById('unusedPayloadValue').textContent = this.optimizer.fmt(unusedPayload);
+ document.getElementById('unusedVolumeValue').textContent = this.optimizer.fmt(unusedVolume);
+ document.getElementById('capacityInterpretationValue').textContent =
+ interpretations[res.limiting.type] || '';
const tbody = document.querySelector('#comparisonTable tbody');
tbody.innerHTML = '';
res.scenarios.forEach(sc => {
const tr = document.createElement('tr');
const lim = (sc.type === res.limiting.type);
- if (lim) tr.classList.add('lo-recommended');
+ if (lim) tr.classList.add('lo-governing');
const util = maxW > 0 ? (sc.weight / maxW * 100).toFixed(1) : '–';
const scM2 = isFinite(sc.rolls) && m2PerRoll > 0 ? Math.round(sc.rolls * m2PerRoll) : '–';
tr.innerHTML =
- ''+ sc.name +(lim?' ★':'')+' | '+
+ ''+ sc.name +(lim?' → Governing Constraint':'')+' | '+
''+ (sc.rolls === Infinity ? '–' : sc.rolls) +' | '+
''+ (isFinite(sc.weight) ? Math.round(sc.weight) : '–') +' | '+
''+ scM2 +' | '+