prishasinghai's picture
Update index.html
c8e151f verified
Raw
History Blame Contribute Delete
30.2 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Silverstone British GP β€” Crowd Flow Optimiser</title>
<style>
/* ================================================================== */
/* 1. STYLING & DASHBOARD LAYOUT (CSS) */
/* ================================================================== */
* {
box-sizing: border-box;
margin: 0;
padding: 0;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
body {
background-color: #121212;
color: #ffffff;
padding: 20px;
}
header {
text-align: center;
margin-bottom: 20px;
}
header h1 {
color: #e10600; /* F1 Red Color */
font-size: 24px;
margin-bottom: 5px;
}
header p {
color: #aaa;
font-size: 14px;
}
/* Two-column responsive grid layout */
.dashboard {
display: flex;
flex-wrap: wrap;
gap: 20px;
max-width: 1450px;
margin: 0 auto;
}
/* Left Panel: Sliders & Controls */
.controls-panel {
flex: 1;
min-width: 320px;
background-color: #1e1e1e;
padding: 20px;
border-radius: 10px;
border: 1px solid #333;
}
.controls-panel h2 {
font-size: 18px;
margin-bottom: 15px;
color: #00cc66;
}
.slider-group {
margin-bottom: 15px;
}
.slider-group label {
display: block;
font-size: 13px;
margin-bottom: 6px;
color: #ddd;
}
.slider-group input[type="range"] {
width: 100%;
cursor: pointer;
}
.value-badge {
color: #e10600;
font-weight: bold;
}
/* Online Ordering Section inside Controls Panel */
.order-btn {
width: 100%;
padding: 12px;
background-color: #e10600;
color: white;
border: none;
border-radius: 6px;
font-weight: bold;
font-size: 14px;
cursor: pointer;
margin-top: 10px;
transition: background 0.2s;
}
.order-btn:hover {
background-color: #ff1e1e;
}
.active-orders-list {
margin-top: 15px;
max-height: 180px;
overflow-y: auto;
background: #141414;
padding: 10px;
border-radius: 6px;
border: 1px solid #333;
}
.order-card {
background: #252525;
padding: 8px;
margin-bottom: 8px;
border-radius: 4px;
border-left: 3px solid #f39c12;
font-size: 12px;
}
.order-card.ready {
border-left-color: #00cc66;
}
/* Modal Overlay */
.modal {
display: none;
position: fixed;
z-index: 1000;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.8);
justify-content: center;
align-items: center;
}
.modal-content {
background-color: #1e1e1e;
padding: 25px;
border-radius: 10px;
border: 1px solid #444;
width: 400px;
max-width: 90%;
}
.modal-content h3 {
color: #e10600;
margin-bottom: 15px;
}
.form-group {
margin-bottom: 12px;
}
.form-group label {
display: block;
font-size: 13px;
margin-bottom: 5px;
color: #ccc;
}
.form-group select, .form-group input {
width: 100%;
padding: 8px;
background: #2b2b2b;
border: 1px solid #444;
color: white;
border-radius: 4px;
}
.modal-actions {
display: flex;
gap: 10px;
margin-top: 20px;
}
.btn-submit {
flex: 1;
background: #00cc66;
color: black;
padding: 10px;
border: none;
border-radius: 4px;
font-weight: bold;
cursor: pointer;
}
.btn-cancel {
flex: 1;
background: #444;
color: white;
padding: 10px;
border: none;
border-radius: 4px;
cursor: pointer;
}
/* Right Panel: Interactive Canvas Map & Report */
.map-panel {
flex: 2;
min-width: 450px;
background-color: #1e1e1e;
padding: 20px;
border-radius: 10px;
border: 1px solid #333;
}
canvas {
width: 100%;
height: auto;
background-color: #181818;
border-radius: 8px;
border: 1px solid #444;
display: block;
}
/* Report Box Styling */
.report-box {
margin-top: 15px;
padding: 15px;
background-color: #252525;
border-radius: 8px;
border-left: 5px solid #00cc66;
font-size: 14px;
line-height: 1.5;
}
.report-box.alert {
border-left-color: #ff4444;
background-color: #2a1a1a;
}
.report-box h3 {
margin-bottom: 8px;
font-size: 16px;
}
.badge {
display: inline-block;
padding: 3px 8px;
border-radius: 4px;
font-size: 12px;
font-weight: bold;
}
.badge-red { background-color: #ff4444; color: white; }
.badge-green { background-color: #00cc66; color: black; }
.badge-purple { background-color: #a020f0; color: white; }
</style>
</head>
<body>
<header>
<h1>🏎️ SILVERSTONE BRITISH GP β€” CROWD FLOW OPTIMISER</h1>
<p>Real-time interconnected crowd routing, dynamic bottleneck propagation & online ordering integration</p>
</header>
<div class="dashboard">
<!-- ============================================================== -->
<!-- LEFT PANEL: USER SLIDER INPUTS & ONLINE ORDERING -->
<!-- ============================================================== -->
<div class="controls-panel">
<h2>βš™οΈ Grandstand Crowd Inputs</h2>
<div class="slider-group">
<label for="hamilton">Hamilton Straight GS: <span id="hamilton-val" class="value-badge">65</span> fans/min</label>
<input type="range" id="hamilton" min="10" max="100" value="65" oninput="updateSimulation()">
</div>
<div class="slider-group">
<label for="becketts">Becketts GS: <span id="becketts-val" class="value-badge">60</span> fans/min</label>
<input type="range" id="becketts" min="10" max="100" value="60" oninput="updateSimulation()">
</div>
<div class="slider-group">
<label for="stowe">Stowe GS: <span id="stowe-val" class="value-badge">40</span> fans/min</label>
<input type="range" id="stowe" min="10" max="100" value="40" oninput="updateSimulation()">
</div>
<div class="slider-group">
<label for="village">Village GS: <span id="village-val" class="value-badge">55</span> fans/min</label>
<input type="range" id="village" min="10" max="100" value="55" oninput="updateSimulation()">
</div>
<div class="slider-group">
<label for="club">Club GS: <span id="club-val" class="value-badge">50</span> fans/min</label>
<input type="range" id="club" min="10" max="100" value="50" oninput="updateSimulation()">
</div>
<hr style="border-color: #333; margin: 15px 0;">
<!-- ONLINE ORDERING SECTION -->
<h2 style="color: #f39c12;">πŸ” Click & Collect Food and Merch Express</h2>
<button class="order-btn" onclick="openOrderModal()">πŸ›’ Place Express Food/Merch Order</button>
<div style="margin-top: 15px;">
<span style="font-size: 13px; font-weight: bold; color: #aaa;">Active Mobile Orders:</span>
<div id="ordersContainer" class="active-orders-list">
<p style="color: #666; font-size: 12px; text-align: center;">No active mobile orders</p>
</div>
</div>
<hr style="border-color: #333; margin: 15px 0;">
<div style="font-size: 12px; color: #aaa; line-height: 1.4;">
<p><strong>πŸ’‘ Dynamic Flow Rules:</strong></p>
<p>β€’ <strong>Gate 1 Threshold:</strong> 50 fans/min</p>
<p>β€’ <strong>Gate 3 Threshold:</strong> 45 fans/min</p>
<p>β€’ Bottlenecks cause cascading <span class="badge badge-red">RED</span> corridor congestions.</p>
<p>β€’ Active rerouting renders complex multi-node <span class="badge badge-purple">PURPLE</span> Google Maps detours.</p>
</div>
</div>
<!-- ============================================================== -->
<!-- RIGHT PANEL: HTML5 CANVAS MAP & TEXT ANALYSIS REPORT -->
<!-- ============================================================== -->
<div class="map-panel">
<canvas id="silverstoneCanvas" width="900" height="520"></canvas>
<div id="reportBox" class="report-box">
<!-- Dynamic Text Report Injected Here -->
</div>
</div>
</div>
<!-- ONLINE ORDER MODAL DIALOG -->
<div id="orderModal" class="modal">
<div class="modal-content">
<h3>πŸ” Place Online Pickup Order</h3>
<div class="form-group">
<label for="pickupLocation">Select Pickup Location:</label>
<select id="pickupLocation">
<option value="Main Fan Zone">Main Fan Zone</option>
<option value="Becketts Food">Becketts Food</option>
<option value="Village Plaza">Village Plaza</option>
<option value="Club Eats">Club Eats</option>
</select>
</div>
<div class="form-group">
<label for="itemSelect">Select Express Menu Item:</label>
<select id="itemSelect">
<option value="F1 Burger & Chips Combo (Β£14.00)">F1 Burger & Chips Combo (Β£14.00)</option>
<option value="Woodfired Pizza Slices (Β£11.50)">Woodfired Pizza Slices (Β£11.50)</option>
<option value="Grid Soft Drink & Fries (Β£7.00)">Grid Soft Drink & Fries (Β£7.00)</option>
<option value="Silverstone Official Cap (Β£30.00)">Silverstone Official Cap (Β£30.00)</option>
</select>
</div>
<div class="form-group">
<label for="custName">Customer Name / Ticket ID:</label>
<input type="text" id="custName" placeholder="e.g. John - Row C" value="Seat 14B">
</div>
<div class="modal-actions">
<button class="btn-submit" onclick="submitOrder()">Confirm Order</button>
<button class="btn-cancel" onclick="closeOrderModal()">Cancel</button>
</div>
</div>
</div>
<!-- ================================================================== -->
<!-- 2. JAVASCRIPT SIMULATION & CANVAS DRAWING LOGIC -->
<!-- ================================================================== -->
<script>
// Gate Capacity Limits
const GATE_1_CAPACITY = 50;
const GATE_3_CAPACITY = 45;
// Active Orders State Management
let activeOrders = [];
let orderCounter = 101;
function updateSimulation() {
// 1. READ SLIDER VALUES FROM HTML INPUTS
const hamiltonCrowd = parseInt(document.getElementById('hamilton').value);
const beckettsCrowd = parseInt(document.getElementById('becketts').value);
const stoweCrowd = parseInt(document.getElementById('stowe').value);
const villageCrowd = parseInt(document.getElementById('village').value);
const clubCrowd = parseInt(document.getElementById('club').value);
// Update UI slider text badges
document.getElementById('hamilton-val').innerText = hamiltonCrowd;
document.getElementById('becketts-val').innerText = beckettsCrowd;
document.getElementById('stowe-val').innerText = stoweCrowd;
document.getElementById('village-val').innerText = villageCrowd;
document.getElementById('club-val').innerText = clubCrowd;
// 2. MATHEMATICAL TRAFFIC LOAD CALCULATIONS
const gate1Load = Math.round(hamiltonCrowd * 0.5 + beckettsCrowd * 0.3 + villageCrowd * 0.3);
const gate2Load = Math.round(hamiltonCrowd * 0.2 + clubCrowd * 0.4);
const gate3Load = Math.round(stoweCrowd * 0.6 + beckettsCrowd * 0.4);
const gate4Load = Math.round(villageCrowd * 0.4 + hamiltonCrowd * 0.2);
// Bottleneck flags
const isGate1Bottleneck = gate1Load > GATE_1_CAPACITY;
const isGate3Bottleneck = gate3Load > GATE_3_CAPACITY;
const excessGate1 = isGate1Bottleneck ? (gate1Load - GATE_1_CAPACITY) : 0;
const excessGate3 = isGate3Bottleneck ? (gate3Load - GATE_3_CAPACITY) : 0;
// 3. DRAW MAP ON HTML5 CANVAS
drawCanvasMap(
hamiltonCrowd, beckettsCrowd, stoweCrowd, villageCrowd, clubCrowd,
gate1Load, gate3Load, isGate1Bottleneck, isGate3Bottleneck
);
// 4. UPDATE TEXT REPORT
updateReport(gate1Load, gate2Load, gate3Load, gate4Load, isGate1Bottleneck, isGate3Bottleneck, excessGate1, excessGate3);
}
/* --- ONLINE ORDERING FUNCTIONS --- */
function openOrderModal() {
document.getElementById('orderModal').style.display = 'flex';
}
function closeOrderModal() {
document.getElementById('orderModal').style.display = 'none';
}
function submitOrder() {
const location = document.getElementById('pickupLocation').value;
const item = document.getElementById('itemSelect').value;
const customer = document.getElementById('custName').value || 'Guest';
const newOrder = {
id: `#ORD-${orderCounter++}`,
location: location,
item: item,
customer: customer,
status: 'Preparing'
};
activeOrders.push(newOrder);
closeOrderModal();
renderOrdersUI();
updateSimulation(); // Refresh Canvas Map Badges
// Automatically transition order status to Ready after 8 seconds
setTimeout(() => {
newOrder.status = 'Ready for Pickup';
renderOrdersUI();
updateSimulation();
}, 8000);
}
function completeOrder(orderId) {
activeOrders = activeOrders.filter(o => o.id !== orderId);
renderOrdersUI();
updateSimulation();
}
function renderOrdersUI() {
const container = document.getElementById('ordersContainer');
if (activeOrders.length === 0) {
container.innerHTML = `<p style="color: #666; font-size: 12px; text-align: center;">No active mobile orders</p>`;
return;
}
container.innerHTML = activeOrders.map(o => `
<div class="order-card ${o.status === 'Ready for Pickup' ? 'ready' : ''}">
<div style="display:flex; justify-space-between; font-weight:bold;">
<span>${o.id} - ${o.customer}</span>
<span style="color: ${o.status === 'Ready for Pickup' ? '#00cc66' : '#f39c12'}">${o.status}</span>
</div>
<div style="color: #aaa; margin-top:3px;">πŸ“ ${o.location}</div>
<div style="color: #ddd;">πŸ” ${o.item}</div>
${o.status === 'Ready for Pickup' ? `<button onclick="completeOrder('${o.id}')" style="margin-top:5px; background:#00cc66; color:black; border:none; padding:2px 6px; border-radius:3px; cursor:pointer; font-size:10px; font-weight:bold;">Collect Order</button>` : ''}
</div>
`).join('');
}
function drawCanvasMap(hamilton, becketts, stowe, village, club, gate1Load, gate3Load, isGate1Bottleneck, isGate3Bottleneck) {
const canvas = document.getElementById('silverstoneCanvas');
const ctx = canvas.getContext('2d');
// Clear canvas background
ctx.fillStyle = '#181818';
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Map coordinate converter
function toCanvas(x, y) {
return {
x: x * 65 + 430,
y: -y * 48 + 260
};
}
// Helper function to draw multi-point paths
function drawPath(points, color, isDashed = false) {
ctx.beginPath();
if (isDashed) ctx.setLineDash([8, 6]);
points.forEach((ptKey, idx) => {
const pos = typeof ptKey === 'string' ? nodes[ptKey].pos : toCanvas(ptKey.x, ptKey.y);
if (idx === 0) ctx.moveTo(pos.x, pos.y);
else ctx.lineTo(pos.x, pos.y);
});
ctx.strokeStyle = color;
ctx.lineWidth = isDashed ? 5 : 4;
ctx.stroke();
if (isDashed) ctx.setLineDash([]);
}
// -------------------------------------------------------------
// A. DRAW F1 CIRCUIT TRACK
// -------------------------------------------------------------
const trackPoints = [
{x: -1, y: 0}, {x: 1, y: -2}, {x: 3, y: -3}, {x: 2, y: -4},
{x: -1, y: -3}, {x: -2, y: -1}, {x: -3, y: 1}, {x: -1, y: 3},
{x: 1, y: 4}, {x: 3, y: 4}, {x: 4, y: 2}, {x: 2, y: 0}, {x: -1, y: 0}
];
// Outer track border
ctx.beginPath();
trackPoints.forEach((pt, idx) => {
const c = toCanvas(pt.x, pt.y);
if (idx === 0) ctx.moveTo(c.x, c.y);
else ctx.lineTo(c.x, c.y);
});
ctx.strokeStyle = '#333333';
ctx.lineWidth = 14;
ctx.stroke();
// Racing line
ctx.beginPath();
ctx.setLineDash([6, 6]);
trackPoints.forEach((pt, idx) => {
const c = toCanvas(pt.x, pt.y);
if (idx === 0) ctx.moveTo(c.x, c.y);
else ctx.lineTo(c.x, c.y);
});
ctx.strokeStyle = '#aaaaaa';
ctx.lineWidth = 1.5;
ctx.stroke();
ctx.setLineDash([]); // Reset dash
// -------------------------------------------------------------
// B. DEFINE MAP NODES (Grandstands, Food, Hubs, Gates)
// Shifted safely outside the track boundary
// -------------------------------------------------------------
const nodes = {
// Grandstands
"Hamilton GS": { pos: toCanvas(-2.2, -2.5), type: "gs", label: `Hamilton (${hamilton})` },
"Becketts GS": { pos: toCanvas(1, 4.8), type: "gs", label: `Becketts (${becketts})` },
"Stowe GS": { pos: toCanvas(4.8, 1.5), type: "gs", label: `Stowe (${stowe})` },
"Village GS": { pos: toCanvas(-4.2, 1.2), type: "gs", label: `Village (${village})` },
"Club GS": { pos: toCanvas(2.8, -4.5), type: "gs", label: `Club (${club})` },
// Food Stalls & Arenas
"Main Fan Zone": { pos: toCanvas(-4.2, -1.0), type: "food", label: "πŸ” Main Fan Zone" },
"Becketts Food": { pos: toCanvas(2.8, 4.2), type: "food", label: "🌭 Becketts Food" },
"Village Plaza": { pos: toCanvas(-3.2, 3.2), type: "food", label: "πŸ• Village Plaza" },
"Club Eats": { pos: toCanvas(-0.5, -4.5), type: "food", label: "🍦 Club Eats" },
// Intermediate Junction Hubs
"Arena Crossroad": { pos: toCanvas(-3.5, -2.2), type: "hub", label: "πŸ“ Arena Hub" },
"Becketts Interchange": { pos: toCanvas(-1.0, 4.2), type: "hub", label: "πŸ“ Becketts Hub" },
"South Bypass": { pos: toCanvas(-2.2, -3.8), type: "hub", label: "πŸ“ South Hub" },
// Gates
"Main Gate 1": { pos: toCanvas(-4.8, -2.2), type: "gate", label: "πŸšͺ Main Gate 1" },
"South Gate 2": { pos: toCanvas(1.5, -4.8), type: "gate", label: "πŸšͺ South Gate 2" },
"East Gate 3": { pos: toCanvas(5.2, -1.5), type: "gate", label: "πŸšͺ East Gate 3" },
"West Gate 4": { pos: toCanvas(-4.8, 3.2), type: "gate", label: "πŸšͺ West Gate 4" }
};
// -------------------------------------------------------------
// C. INTERCONNECTED STANDARD PEDESTRIAN PATHS (GREEN / RED)
// Explicit waypoint routing around track perimeter
// -------------------------------------------------------------
const pathColorG1 = isGate1Bottleneck ? "#ff4444" : "#00cc66";
const pathColorG3 = isGate3Bottleneck ? "#ff4444" : "#00cc66";
// Gate 1 Network
drawPath(["Hamilton GS", "Arena Crossroad"], pathColorG1);
drawPath(["Arena Crossroad", "Main Fan Zone"], pathColorG1);
drawPath(["Main Fan Zone", "Main Gate 1"], pathColorG1);
drawPath(["Village GS", "Main Fan Zone"], pathColorG1);
// Gate 3 & Becketts Network
drawPath(["Becketts GS", "Becketts Interchange"], pathColorG3);
drawPath(["Becketts GS", "Becketts Food"], pathColorG3);
drawPath(["Becketts Food", "Stowe GS"], pathColorG3);
drawPath(["Stowe GS", "East Gate 3"], pathColorG3);
// Outer Northern Connection (Becketts Hub <-> Village Plaza <-> Fan Zone around top/left)
drawPath(["Becketts Interchange", "Village Plaza"], pathColorG1);
drawPath(["Village Plaza", "Village GS"], "#00cc66");
drawPath(["Village Plaza", "West Gate 4"], "#00cc66");
// Outer Southern Connection (Hamilton <-> South Bypass <-> Club Eats <-> South Gate 2 around bottom)
drawPath(["Hamilton GS", "South Bypass"], "#00cc66");
drawPath(["South Bypass", "Club Eats"], "#00cc66");
drawPath(["Club GS", "Club Eats"], "#00cc66");
drawPath(["Club Eats", "South Gate 2"], "#00cc66");
// -------------------------------------------------------------
// D. EXPANDED GOOGLE MAPS MULTI-NODE DETOURS (PURPLE)
// Detours routed cleanly along the outer perimeter
// -------------------------------------------------------------
if (isGate1Bottleneck) {
// Fan Zone -> South Hub -> Club Eats -> South Gate 2
drawPath(["Main Fan Zone", "Arena Crossroad", "South Bypass", "Club Eats", "South Gate 2"], "#a020f0", true);
// Arena Hub -> West Gate 4
drawPath(["Arena Crossroad", "Village GS", "West Gate 4"], "#a020f0", true);
}
if (isGate3Bottleneck) {
// Becketts Hub -> Village Plaza -> Main Fan Zone -> South Hub -> South Gate 2
drawPath(["Becketts Interchange", "Village Plaza", "Main Fan Zone", "South Bypass", "South Gate 2"], "#a020f0", true);
}
// -------------------------------------------------------------
// E. DRAW NODE BOXES, LABELS & ORDER BADGES
// -------------------------------------------------------------
for (let key in nodes) {
const n = nodes[key];
ctx.font = "bold 11px Arial";
const textWidth = ctx.measureText(n.label).width;
const boxPadding = 7;
let boxColor = "#3498db"; // Blue for Grandstands
if (n.type === "food") boxColor = "#f39c12"; // Orange for Food
if (n.type === "hub") boxColor = "#7f8c8d"; // Grey for Hubs
if (n.type === "gate") {
if ((key === "Main Gate 1" && isGate1Bottleneck) || (key === "East Gate 3" && isGate3Bottleneck)) {
boxColor = "#ff4444";
} else {
boxColor = "#00cc66";
}
}
// Draw background rounded box
ctx.fillStyle = boxColor;
ctx.beginPath();
ctx.roundRect(
n.pos.x - textWidth / 2 - boxPadding,
n.pos.y - 12,
textWidth + boxPadding * 2,
24,
6
);
ctx.fill();
ctx.strokeStyle = "#ffffff";
ctx.lineWidth = 1;
ctx.stroke();
// Draw label text
ctx.fillStyle = "#ffffff";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillText(n.label, n.pos.x, n.pos.y);
// DRAW PENDING ORDERS OVERLAY BADGE FOR FOOD STALLS
if (n.type === "food") {
const pendingCount = activeOrders.filter(o => o.location === key).length;
if (pendingCount > 0) {
ctx.fillStyle = "#e10600";
ctx.beginPath();
ctx.arc(n.pos.x + textWidth / 2 + 5, n.pos.y - 10, 10, 0, Math.PI * 2);
ctx.fill();
ctx.strokeStyle = "#ffffff";
ctx.lineWidth = 1.5;
ctx.stroke();
ctx.fillStyle = "#ffffff";
ctx.font = "bold 10px Arial";
ctx.fillText(pendingCount, n.pos.x + textWidth / 2 + 5, n.pos.y - 10);
}
}
}
// Draw Legend
ctx.font = "11px Arial";
ctx.fillStyle = "#ffffff";
ctx.textAlign = "left";
ctx.fillText("🟒 Clear Pathway", 20, 25);
ctx.fillText("πŸ”΄ Congested Network Segment", 140, 25);
ctx.fillText("🟣 Google Maps Active Multi-Leg Detour", 330, 25);
}
function updateReport(gate1, gate2, gate3, gate4, isG1Alert, isG3Alert, excess1, excess3) {
const reportDiv = document.getElementById('reportBox');
if (isG1Alert || isG3Alert) {
reportDiv.className = "report-box alert";
let alertsHtml = `<h3 style="color: #ff4444;">πŸ”΄ NETWORK BOTTLENECK ALERT ACTIVATED</h3>`;
if (isG1Alert) {
alertsHtml += `<p>β€’ <strong>Main Gate 1 Bottleneck:</strong> Load <code>${gate1}</code> fans/min (Max limit: ${GATE_1_CAPACITY}). Overflow: <code>${excess1}</code> fans.</p>`;
}
if (isG3Alert) {
alertsHtml += `<p>β€’ <strong>East Gate 3 Bottleneck:</strong> Load <code>${gate3}</code> fans/min (Max limit: ${GATE_3_CAPACITY}). Overflow: <code>${excess3}</code> fans.</p>`;
}
alertsHtml += `
<hr style="border-color: #552222; margin: 10px 0;">
<h4 style="color: #a020f0;">πŸ”„ Dynamic Rerouting Protocol:</h4>
<p>β€’ Activating interconnected <span class="badge badge-purple">PURPLE DETOURS</span> across <strong>Arena Hub</strong>, <strong>South Bypass</strong>, and <strong>Becketts Interchange</strong>.</p>
<p>β€’ Directing overflow pedestrian traffic to under-utilized exit points at <strong>South Gate 2</strong> and <strong>West Gate 4</strong>.</p>
`;
reportDiv.innerHTML = alertsHtml;
} else {
reportDiv.className = "report-box";
reportDiv.innerHTML = `
<h3 style="color: #00cc66;">🟒 ALL INTERCONNECTED PATHWAYS OPTIMAL</h3>
<p>β€’ <strong>Main Gate 1 Load:</strong> <code>${gate1}</code> / ${GATE_1_CAPACITY} fans/min (Safe)</p>
<p>β€’ <strong>South Gate 2 Load:</strong> <code>${gate2}</code> / 50 fans/min (Safe)</p>
<p>β€’ <strong>East Gate 3 Load:</strong> <code>${gate3}</code> / ${GATE_3_CAPACITY} fans/min (Safe)</p>
<p>β€’ <strong>West Gate 4 Load:</strong> <code>${gate4}</code> / 45 fans/min (Safe)</p>
<p style="margin-top: 5px; color: #aaa;"><em>Status: Grid flow is balanced across all junctions. No purple detour routing required.</em></p>
`;
}
}
// Initialize simulation on initial page load
window.onload = updateSimulation;
</script>
</body>
</html>