revert: rollback to version before Anggaran & Decision Dashboard (commit 45fc0b7)
Browse files- frontend/app.js +15 -320
- frontend/index.html +123 -484
- frontend/style.css +3 -822
frontend/app.js
CHANGED
|
@@ -117,34 +117,12 @@ const timelineList = document.getElementById("timeline-list");
|
|
| 117 |
const hourlySection = document.getElementById("hourly-section");
|
| 118 |
const hourlyGrid = document.getElementById("hourly-grid");
|
| 119 |
|
| 120 |
-
// Decision Dashboard UI Elements
|
| 121 |
-
const decLocationSelect = document.getElementById("dec-location-select");
|
| 122 |
-
const decTotalVol = document.getElementById("dec-total-vol");
|
| 123 |
-
const decVolStatus = document.getElementById("dec-vol-status");
|
| 124 |
-
const decCostVal = document.getElementById("dec-cost-val");
|
| 125 |
-
const decEfficiencyVal = document.getElementById("dec-efficiency-val");
|
| 126 |
-
const decSavedVal = document.getElementById("dec-saved-val");
|
| 127 |
-
const decWorkloadGrid = document.getElementById("dec-workload-grid");
|
| 128 |
-
const decTruckLarge = document.getElementById("dec-truck-large");
|
| 129 |
-
const decTruckSmall = document.getElementById("dec-truck-small");
|
| 130 |
-
const decCriticalTitle = document.getElementById("dec-critical-title");
|
| 131 |
-
const decCriticalList = document.getElementById("dec-critical-list");
|
| 132 |
-
|
| 133 |
-
// Weather Modal UI Elements
|
| 134 |
-
const weatherModal = document.getElementById("weather-modal");
|
| 135 |
-
const modalWeatherLoc = document.getElementById("modal-weather-loc");
|
| 136 |
-
const modalSumTotal = document.getElementById("modal-sum-total");
|
| 137 |
-
const modalSumAvg = document.getElementById("modal-sum-avg");
|
| 138 |
-
const modalSumBadge = document.getElementById("modal-sum-badge");
|
| 139 |
-
const weatherModalList = document.getElementById("weather-modal-list");
|
| 140 |
-
|
| 141 |
// State
|
| 142 |
let selectedLocation = "Menteng";
|
| 143 |
let rainValue = 0; // 0 means Auto (Open-Meteo)
|
| 144 |
let map;
|
| 145 |
let mapMarkers = {};
|
| 146 |
let routeLine = null;
|
| 147 |
-
let lastPredictionData = null;
|
| 148 |
|
| 149 |
// ==========================================
|
| 150 |
// SPA MULTIPAGE ROUTING
|
|
@@ -173,11 +151,8 @@ function switchPage(pageId) {
|
|
| 173 |
loadAlertsFeed();
|
| 174 |
} else if (pageId === "page-autopilot") {
|
| 175 |
loadAutopilotFeed();
|
| 176 |
-
} else if (pageId === "page-predictor") {
|
| 177 |
-
|
| 178 |
-
if (lastPredictionData) {
|
| 179 |
-
updateDecisionDashboard(lastPredictionData, selectedLocation);
|
| 180 |
-
}
|
| 181 |
}
|
| 182 |
}
|
| 183 |
|
|
@@ -414,41 +389,38 @@ async function fetchLiveWeather(loc) {
|
|
| 414 |
const precipList = dailyData.precipitation_sum || [];
|
| 415 |
const precipToday = precipList[2] || 0;
|
| 416 |
|
| 417 |
-
let cond = "
|
| 418 |
-
if (code === 0
|
| 419 |
-
else if (code
|
| 420 |
-
else if (code
|
| 421 |
-
else if (
|
| 422 |
-
else if (precipToday >= 5.0) cond = "Hujan Sedang";
|
| 423 |
-
else if (precipToday >= 0.5) cond = "Hujan Ringan";
|
| 424 |
-
else cond = "Berawan";
|
| 425 |
|
| 426 |
if (weatherForecastText) weatherForecastText.textContent = `${temp}°C - ${cond}`;
|
| 427 |
if (weatherLocationText) weatherLocationText.textContent = `${loc} (${coord.city})`;
|
| 428 |
if (weatherPrecip) weatherPrecip.textContent = `${precipToday.toFixed(1)} mm`;
|
| 429 |
|
| 430 |
if (weatherAlert) {
|
| 431 |
-
if (precipToday >
|
| 432 |
-
weatherAlert.textContent = "FLOOD DANGER 🔴";
|
| 433 |
-
weatherAlert.className = "highlight text-red";
|
| 434 |
-
} else if (precipToday >= 20) {
|
| 435 |
weatherAlert.textContent = "HEAVY RAIN 🟡";
|
| 436 |
weatherAlert.className = "highlight text-warning";
|
|
|
|
|
|
|
|
|
|
| 437 |
} else {
|
| 438 |
-
weatherAlert.textContent = "Normal
|
| 439 |
weatherAlert.className = "highlight";
|
| 440 |
}
|
| 441 |
}
|
| 442 |
} catch (err) {
|
| 443 |
console.warn("Weather fetch timed out/failed. Using fallback forecast.", err);
|
| 444 |
// Instant Fallback Weather Data
|
| 445 |
-
const fallbackTemp =
|
| 446 |
const fallbackPrecip = 0.0;
|
| 447 |
-
if (weatherForecastText) weatherForecastText.textContent = `${fallbackTemp.toFixed(1)}°C -
|
| 448 |
if (weatherLocationText) weatherLocationText.textContent = `${loc} (${coord.city})`;
|
| 449 |
if (weatherPrecip) weatherPrecip.textContent = `${fallbackPrecip.toFixed(1)} mm`;
|
| 450 |
if (weatherAlert) {
|
| 451 |
-
weatherAlert.textContent = "Normal
|
| 452 |
weatherAlert.className = "highlight";
|
| 453 |
}
|
| 454 |
}
|
|
@@ -603,285 +575,8 @@ function updateDashboardData(data, confScore, message) {
|
|
| 603 |
} else {
|
| 604 |
if (hourlySection) hourlySection.style.display = "none";
|
| 605 |
}
|
| 606 |
-
|
| 607 |
-
// Save and update Decision Dashboard
|
| 608 |
-
lastPredictionData = data;
|
| 609 |
-
updateDecisionDashboard(data, selectedLocation);
|
| 610 |
-
}
|
| 611 |
-
|
| 612 |
-
// ==========================================
|
| 613 |
-
// DECISION DASHBOARD (EXECUTIVE LOGISTICS & COST OPTIMIZER)
|
| 614 |
-
// ==========================================
|
| 615 |
-
function updateDecisionDashboard(data, location) {
|
| 616 |
-
if (!data || !data.prediction_results || data.prediction_results.length === 0) return;
|
| 617 |
-
|
| 618 |
-
const results = data.prediction_results;
|
| 619 |
-
const weekResults = results.slice(0, 7);
|
| 620 |
-
const totalVolume = weekResults.reduce((acc, curr) => acc + curr.total_volume_ton, 0);
|
| 621 |
-
const totalTrucks = weekResults.reduce((acc, curr) => acc + curr.recommended_trucks, 0);
|
| 622 |
-
const config = KECAMATAN_DATABASE[location] || KECAMATAN_DATABASE["Menteng"];
|
| 623 |
-
|
| 624 |
-
// 1. Total Volume Prediksi
|
| 625 |
-
if (decTotalVol) decTotalVol.textContent = totalVolume.toFixed(1);
|
| 626 |
-
if (decVolStatus) decVolStatus.innerHTML = `<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#00F0FF" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg> Berhasil diprediksi (${weekResults.length} hari)`;
|
| 627 |
-
|
| 628 |
-
// 2. Estimasi Biaya Operasional (Pergub DKI & Standar DLH: Rp 95.000/ton + SDM Rp 504.000/truk/hari)
|
| 629 |
-
const costProactive = Math.round(((totalVolume * 95000) + (totalTrucks * 504000)) / 100000) * 100000;
|
| 630 |
-
const costReactive = Math.round((costProactive * 2.048) / 100000) * 100000;
|
| 631 |
-
const costSaved = costReactive - costProactive;
|
| 632 |
-
const efficiencyPct = ((costSaved / costReactive) * 100).toFixed(1);
|
| 633 |
-
|
| 634 |
-
if (decCostVal) decCostVal.textContent = `Rp ${costProactive.toLocaleString('id-ID')}`;
|
| 635 |
-
if (decEfficiencyVal) decEfficiencyVal.textContent = `${efficiencyPct}%`;
|
| 636 |
-
if (decSavedVal) decSavedVal.innerHTML = `<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#4ade80" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="23 18 13.5 8.5 8.5 13.5 1 6"/><polyline points="17 18 23 18 23 12"/></svg> Hemat Rp ${costSaved.toLocaleString('id-ID')} dibanding Reaktif`;
|
| 637 |
-
|
| 638 |
-
// 3. Alokasi Armada Spesifik (Dump Truck 60% vs Pick-up 40% pemukiman padat)
|
| 639 |
-
const dumpTruckUnits = Math.ceil(totalTrucks * 0.60);
|
| 640 |
-
const pickupUnits = Math.ceil(totalTrucks * 0.40 * 1.75);
|
| 641 |
-
if (decTruckLarge) decTruckLarge.textContent = dumpTruckUnits;
|
| 642 |
-
if (decTruckSmall) decTruckSmall.textContent = pickupUnits;
|
| 643 |
-
|
| 644 |
-
// 4. Peta Beban Kerja Harian (7 Hari Horizon)
|
| 645 |
-
if (decWorkloadGrid) {
|
| 646 |
-
decWorkloadGrid.innerHTML = "";
|
| 647 |
-
const dayAbbrsIndo = ["MIN", "SEN", "SEL", "RAB", "KAM", "JUM", "SAB"];
|
| 648 |
-
|
| 649 |
-
weekResults.forEach(day => {
|
| 650 |
-
const dateObj = new Date(day.date);
|
| 651 |
-
const dayAbbr = dayAbbrsIndo[dateObj.getDay()] || "HARI";
|
| 652 |
-
const isCritical = day.risk_status === "CRITICAL" || day.total_volume_ton > (config.normal_avg * 1.18);
|
| 653 |
-
const isWarning = day.risk_status === "WARNING";
|
| 654 |
-
|
| 655 |
-
let badgeClass = "normal";
|
| 656 |
-
if (isCritical) badgeClass = "peak-critical";
|
| 657 |
-
else if (isWarning || dateObj.getDay() === 0 || dateObj.getDay() === 5 || dateObj.getDay() === 6) badgeClass = "warning";
|
| 658 |
-
|
| 659 |
-
const card = document.createElement("div");
|
| 660 |
-
card.className = `workload-day-card ${isCritical ? "critical" : ""}`;
|
| 661 |
-
|
| 662 |
-
// Shift schedule: S1 & S2 always active, S3 active on peak/critical days
|
| 663 |
-
const showShift3 = isCritical || day.total_volume_ton > (config.normal_avg * 1.10);
|
| 664 |
-
|
| 665 |
-
card.innerHTML = `
|
| 666 |
-
<div class="workload-day-badge ${badgeClass}">${dayAbbr}</div>
|
| 667 |
-
<div class="workload-ton-val">${day.total_volume_ton.toFixed(1)}</div>
|
| 668 |
-
<div class="workload-ton-label">TON</div>
|
| 669 |
-
<div class="workload-trucks-count">
|
| 670 |
-
<span>🚚</span> <span>${day.recommended_trucks}</span>
|
| 671 |
-
</div>
|
| 672 |
-
<div class="workload-shifts-list">
|
| 673 |
-
<span class="workload-shift-pill s1">S1: 04:00-10:00</span>
|
| 674 |
-
<span class="workload-shift-pill s2">S2: 10:00-16:00</span>
|
| 675 |
-
${showShift3 ? '<span class="workload-shift-pill s3">S3: 19:00-01:00</span>' : ''}
|
| 676 |
-
</div>
|
| 677 |
-
`;
|
| 678 |
-
decWorkloadGrid.appendChild(card);
|
| 679 |
-
});
|
| 680 |
-
}
|
| 681 |
-
|
| 682 |
-
// 5. Rencana Aksi Kritis
|
| 683 |
-
const peakDay = weekResults.reduce((max, d) => d.total_volume_ton > max.total_volume_ton ? d : max, weekResults[0]);
|
| 684 |
-
if (peakDay) {
|
| 685 |
-
const peakDateObj = new Date(peakDay.date);
|
| 686 |
-
const dayAbbrsIndo = ["MIN", "SEN", "SEL", "RAB", "KAM", "JUM", "SAB"];
|
| 687 |
-
const peakDayName = dayAbbrsIndo[peakDateObj.getDay()] || "HARI";
|
| 688 |
-
|
| 689 |
-
let situationTag = "BEBAN PUNCAK & KEPADATAN RUTIN";
|
| 690 |
-
if (peakDay.event_info) {
|
| 691 |
-
situationTag = peakDay.event_info.toUpperCase();
|
| 692 |
-
} else if (peakDay.risk_status === "CRITICAL") {
|
| 693 |
-
situationTag = "HUJAN LEBAT & BEBAN PUNCAK";
|
| 694 |
-
}
|
| 695 |
-
|
| 696 |
-
if (decCriticalTitle) {
|
| 697 |
-
decCriticalTitle.textContent = `AKSI HARI ${peakDayName} (${situationTag})`;
|
| 698 |
-
}
|
| 699 |
-
|
| 700 |
-
if (decCriticalList) {
|
| 701 |
-
decCriticalList.innerHTML = `
|
| 702 |
-
<li>Aktifkan <strong>Shift 3 (19:00 - 01:00 WIB)</strong> untuk evakuasi cepat TPS permukiman ${location} guna mencegah penumpukan sampah malam.</li>
|
| 703 |
-
<li>Prioritaskan dispatch <strong>${Math.ceil(peakDay.recommended_trucks * 0.60)} unit Dump Truck 15T</strong> via jalur bebas hambatan untuk mitigasi antrean gerbang timbang TPST Bantargebang.</li>
|
| 704 |
-
<li>Siagakan <strong>pompa portabel penyedot lindi</strong> dan armada sapu bersih di titik TPS transfer point.</li>
|
| 705 |
-
<li>Kerahkan <strong>${Math.ceil(peakDay.recommended_trucks * 0.40 * 1.75)} armada Pick-up</strong> untuk penyisiran lorong pemukiman padat sebelum jam sibuk warga (pukul 06:00 WIB).</li>
|
| 706 |
-
`;
|
| 707 |
-
}
|
| 708 |
-
}
|
| 709 |
-
}
|
| 710 |
-
|
| 711 |
-
// ==========================================
|
| 712 |
-
// 7-DAY WEATHER FORECAST MODAL CONTROLLER
|
| 713 |
-
// ==========================================
|
| 714 |
-
async function openWeatherModal(loc) {
|
| 715 |
-
const targetLoc = loc || selectedLocation;
|
| 716 |
-
const coord = KECAMATAN_DATABASE[targetLoc];
|
| 717 |
-
if (!coord) return;
|
| 718 |
-
|
| 719 |
-
if (modalWeatherLoc) modalWeatherLoc.textContent = targetLoc;
|
| 720 |
-
if (weatherModal) {
|
| 721 |
-
weatherModal.classList.add("open");
|
| 722 |
-
}
|
| 723 |
-
|
| 724 |
-
if (weatherModalList) {
|
| 725 |
-
weatherModalList.innerHTML = '<div class="weather-modal-loading">Mengambil data cuaca 7 hari dari Open-Meteo API...</div>';
|
| 726 |
-
}
|
| 727 |
-
|
| 728 |
-
try {
|
| 729 |
-
const url = `https://api.open-meteo.com/v1/forecast?latitude=${coord.coords[0]}&longitude=${coord.coords[1]}&daily=weathercode,temperature_2m_max,temperature_2m_min,precipitation_sum,precipitation_hours&timezone=Asia/Jakarta&forecast_days=7`;
|
| 730 |
-
|
| 731 |
-
const timeoutPromise = new Promise((_, reject) =>
|
| 732 |
-
setTimeout(() => reject(new Error("Timeout")), 2000)
|
| 733 |
-
);
|
| 734 |
-
const fetchPromise = fetch(url).then(res => {
|
| 735 |
-
if (!res.ok) throw new Error("HTTP Error");
|
| 736 |
-
return res.json();
|
| 737 |
-
});
|
| 738 |
-
|
| 739 |
-
const data = await Promise.race([fetchPromise, timeoutPromise]);
|
| 740 |
-
const daily = data.daily || {};
|
| 741 |
-
const dates = daily.time || [];
|
| 742 |
-
const codes = daily.weathercode || [];
|
| 743 |
-
const tempMax = daily.temperature_2m_max || [];
|
| 744 |
-
const tempMin = daily.temperature_2m_min || [];
|
| 745 |
-
const precipSum = daily.precipitation_sum || [];
|
| 746 |
-
const precipHours = daily.precipitation_hours || [];
|
| 747 |
-
|
| 748 |
-
let totalPrecip = 0;
|
| 749 |
-
let totalHours = 0;
|
| 750 |
-
precipSum.forEach(p => totalPrecip += (p || 0));
|
| 751 |
-
precipHours.forEach(h => totalHours += (h || 0));
|
| 752 |
-
|
| 753 |
-
const avgHr = totalHours > 0 ? (totalPrecip / totalHours) : (totalPrecip / 7);
|
| 754 |
-
|
| 755 |
-
if (modalSumTotal) modalSumTotal.textContent = `${totalPrecip.toFixed(1)}mm`;
|
| 756 |
-
if (modalSumAvg) modalSumAvg.textContent = `${avgHr.toFixed(1)}mm/hr`;
|
| 757 |
-
|
| 758 |
-
// BMKG Weather Category badge
|
| 759 |
-
if (modalSumBadge) {
|
| 760 |
-
if (totalPrecip < 20.0) {
|
| 761 |
-
modalSumBadge.textContent = "KERING";
|
| 762 |
-
modalSumBadge.className = "weather-dryness-badge dry";
|
| 763 |
-
} else if (totalPrecip < 50.0) {
|
| 764 |
-
modalSumBadge.textContent = "LEMBAP";
|
| 765 |
-
modalSumBadge.className = "weather-dryness-badge wet";
|
| 766 |
-
} else {
|
| 767 |
-
modalSumBadge.textContent = "HUJAN LEBAT";
|
| 768 |
-
modalSumBadge.className = "weather-dryness-badge heavy";
|
| 769 |
-
}
|
| 770 |
-
}
|
| 771 |
-
|
| 772 |
-
const dayNamesIndo = ["Min", "Sen", "Sel", "Rab", "Kam", "Jum", "Sab"];
|
| 773 |
-
|
| 774 |
-
if (weatherModalList) {
|
| 775 |
-
weatherModalList.innerHTML = "";
|
| 776 |
-
dates.forEach((dStr, idx) => {
|
| 777 |
-
const dateObj = new Date(dStr);
|
| 778 |
-
const dayName = dayNamesIndo[dateObj.getDay()] || "Hari";
|
| 779 |
-
const wCode = codes[idx] || 0;
|
| 780 |
-
const pVal = precipSum[idx] || 0.0;
|
| 781 |
-
const tMax = Math.round(tempMax[idx] || 33);
|
| 782 |
-
const tMin = Math.round(tempMin[idx] || 25);
|
| 783 |
-
|
| 784 |
-
let icon = "☀️";
|
| 785 |
-
let condition = "Cerah";
|
| 786 |
-
|
| 787 |
-
// BMKG Meteorological Standard Interpretation
|
| 788 |
-
if (wCode >= 95 || (wCode >= 80 && pVal >= 20.0)) {
|
| 789 |
-
icon = "⛈️";
|
| 790 |
-
condition = "Badai Petir";
|
| 791 |
-
} else if (pVal >= 20.0) {
|
| 792 |
-
icon = "🌧️";
|
| 793 |
-
condition = "Hujan Lebat";
|
| 794 |
-
} else if (pVal >= 5.0) {
|
| 795 |
-
icon = "🌧️";
|
| 796 |
-
condition = "Hujan Sedang";
|
| 797 |
-
} else if (pVal >= 1.5) {
|
| 798 |
-
icon = "🌦️";
|
| 799 |
-
condition = "Hujan Ringan";
|
| 800 |
-
} else if (pVal >= 0.5) {
|
| 801 |
-
icon = "⛅";
|
| 802 |
-
condition = "Berawan";
|
| 803 |
-
} else {
|
| 804 |
-
// Under 0.5mm is non-rainy (Cerah / Cerah Berawan)
|
| 805 |
-
if (wCode === 0) {
|
| 806 |
-
icon = "☀️";
|
| 807 |
-
condition = "Cerah";
|
| 808 |
-
} else if (wCode <= 2) {
|
| 809 |
-
icon = "🌤️";
|
| 810 |
-
condition = "Cerah Berawan";
|
| 811 |
-
} else {
|
| 812 |
-
icon = "⛅";
|
| 813 |
-
condition = "Berawan";
|
| 814 |
-
}
|
| 815 |
-
}
|
| 816 |
-
|
| 817 |
-
const precipDisplay = pVal >= 0.5 ? `${pVal.toFixed(1)}mm` : '';
|
| 818 |
-
|
| 819 |
-
const row = document.createElement("div");
|
| 820 |
-
row.className = "weather-forecast-row";
|
| 821 |
-
row.innerHTML = `
|
| 822 |
-
<span class="w-row-day">${dayName}</span>
|
| 823 |
-
<span class="w-row-icon">${icon}</span>
|
| 824 |
-
<span class="w-row-cond">${condition}</span>
|
| 825 |
-
<span class="w-row-precip">${precipDisplay}</span>
|
| 826 |
-
<div class="w-row-temp">
|
| 827 |
-
<span class="w-temp-max">${tMax}°</span>
|
| 828 |
-
<span class="w-temp-min">${tMin}°</span>
|
| 829 |
-
</div>
|
| 830 |
-
`;
|
| 831 |
-
weatherModalList.appendChild(row);
|
| 832 |
-
});
|
| 833 |
-
}
|
| 834 |
-
|
| 835 |
-
} catch (err) {
|
| 836 |
-
console.warn("Open-Meteo weather modal fallback:", err);
|
| 837 |
-
// Fallback matching real Jakarta climate baseline
|
| 838 |
-
const fallbackData = [
|
| 839 |
-
{ day: "Kam", icon: "🌦️", cond: "Hujan Ringan", precip: "1.3mm", max: 33, min: 25 },
|
| 840 |
-
{ day: "Jum", icon: "⛅", cond: "Berawan", precip: "", max: 35, min: 25 },
|
| 841 |
-
{ day: "Sab", icon: "🌤️", cond: "Cerah Berawan", precip: "", max: 36, min: 25 },
|
| 842 |
-
{ day: "Min", icon: "☀️", cond: "Cerah", precip: "", max: 34, min: 26 },
|
| 843 |
-
{ day: "Sen", icon: "🌦️", cond: "Hujan Ringan", precip: "1.5mm", max: 33, min: 26 },
|
| 844 |
-
{ day: "Sel", icon: "🌤️", cond: "Cerah Berawan", precip: "", max: 35, min: 26 },
|
| 845 |
-
{ day: "Rab", icon: "🌧️", cond: "Hujan Sedang", precip: "3.6mm", max: 35, min: 27 }
|
| 846 |
-
];
|
| 847 |
-
|
| 848 |
-
if (modalSumTotal) modalSumTotal.textContent = "6.4mm";
|
| 849 |
-
if (modalSumAvg) modalSumAvg.textContent = "0.9mm/hr";
|
| 850 |
-
if (modalSumBadge) {
|
| 851 |
-
modalSumBadge.textContent = "KERING";
|
| 852 |
-
modalSumBadge.className = "weather-dryness-badge dry";
|
| 853 |
-
}
|
| 854 |
-
|
| 855 |
-
if (weatherModalList) {
|
| 856 |
-
weatherModalList.innerHTML = "";
|
| 857 |
-
fallbackData.forEach(item => {
|
| 858 |
-
const row = document.createElement("div");
|
| 859 |
-
row.className = "weather-forecast-row";
|
| 860 |
-
row.innerHTML = `
|
| 861 |
-
<span class="w-row-day">${item.day}</span>
|
| 862 |
-
<span class="w-row-icon">${item.icon}</span>
|
| 863 |
-
<span class="w-row-cond">${item.cond}</span>
|
| 864 |
-
<span class="w-row-precip">${item.precip}</span>
|
| 865 |
-
<div class="w-row-temp">
|
| 866 |
-
<span class="w-temp-max">${item.max}°</span>
|
| 867 |
-
<span class="w-temp-min">${item.min}°</span>
|
| 868 |
-
</div>
|
| 869 |
-
`;
|
| 870 |
-
weatherModalList.appendChild(row);
|
| 871 |
-
});
|
| 872 |
-
}
|
| 873 |
-
}
|
| 874 |
}
|
| 875 |
|
| 876 |
-
function closeWeatherModal() {
|
| 877 |
-
if (weatherModal) {
|
| 878 |
-
weatherModal.classList.remove("open");
|
| 879 |
-
}
|
| 880 |
-
}
|
| 881 |
-
|
| 882 |
-
window.openWeatherModal = openWeatherModal;
|
| 883 |
-
window.closeWeatherModal = closeWeatherModal;
|
| 884 |
-
|
| 885 |
// Request CSV from Backend API and download it
|
| 886 |
async function runExport() {
|
| 887 |
if (!exportBtn) return;
|
|
|
|
| 117 |
const hourlySection = document.getElementById("hourly-section");
|
| 118 |
const hourlyGrid = document.getElementById("hourly-grid");
|
| 119 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 120 |
// State
|
| 121 |
let selectedLocation = "Menteng";
|
| 122 |
let rainValue = 0; // 0 means Auto (Open-Meteo)
|
| 123 |
let map;
|
| 124 |
let mapMarkers = {};
|
| 125 |
let routeLine = null;
|
|
|
|
| 126 |
|
| 127 |
// ==========================================
|
| 128 |
// SPA MULTIPAGE ROUTING
|
|
|
|
| 151 |
loadAlertsFeed();
|
| 152 |
} else if (pageId === "page-autopilot") {
|
| 153 |
loadAutopilotFeed();
|
| 154 |
+
} else if (pageId === "page-predictor" && map) {
|
| 155 |
+
setTimeout(() => { map.invalidateSize(); }, 200);
|
|
|
|
|
|
|
|
|
|
| 156 |
}
|
| 157 |
}
|
| 158 |
|
|
|
|
| 389 |
const precipList = dailyData.precipitation_sum || [];
|
| 390 |
const precipToday = precipList[2] || 0;
|
| 391 |
|
| 392 |
+
let cond = "Cloudy";
|
| 393 |
+
if (code === 0) cond = "Clear Sky";
|
| 394 |
+
else if (code > 0 && code < 4) cond = "Partly Cloudy";
|
| 395 |
+
else if (code >= 51 && code <= 67) cond = "Rainy";
|
| 396 |
+
else if (code >= 80 && code <= 82) cond = "Showers";
|
|
|
|
|
|
|
|
|
|
| 397 |
|
| 398 |
if (weatherForecastText) weatherForecastText.textContent = `${temp}°C - ${cond}`;
|
| 399 |
if (weatherLocationText) weatherLocationText.textContent = `${loc} (${coord.city})`;
|
| 400 |
if (weatherPrecip) weatherPrecip.textContent = `${precipToday.toFixed(1)} mm`;
|
| 401 |
|
| 402 |
if (weatherAlert) {
|
| 403 |
+
if (precipToday > 30) {
|
|
|
|
|
|
|
|
|
|
| 404 |
weatherAlert.textContent = "HEAVY RAIN 🟡";
|
| 405 |
weatherAlert.className = "highlight text-warning";
|
| 406 |
+
} else if (precipToday > 50) {
|
| 407 |
+
weatherAlert.textContent = "FLOOD DANGER 🔴";
|
| 408 |
+
weatherAlert.className = "highlight text-red";
|
| 409 |
} else {
|
| 410 |
+
weatherAlert.textContent = "Normal conditions";
|
| 411 |
weatherAlert.className = "highlight";
|
| 412 |
}
|
| 413 |
}
|
| 414 |
} catch (err) {
|
| 415 |
console.warn("Weather fetch timed out/failed. Using fallback forecast.", err);
|
| 416 |
// Instant Fallback Weather Data
|
| 417 |
+
const fallbackTemp = 28.5 + Math.random() * 3.0;
|
| 418 |
const fallbackPrecip = 0.0;
|
| 419 |
+
if (weatherForecastText) weatherForecastText.textContent = `${fallbackTemp.toFixed(1)}°C - Partly Cloudy`;
|
| 420 |
if (weatherLocationText) weatherLocationText.textContent = `${loc} (${coord.city})`;
|
| 421 |
if (weatherPrecip) weatherPrecip.textContent = `${fallbackPrecip.toFixed(1)} mm`;
|
| 422 |
if (weatherAlert) {
|
| 423 |
+
weatherAlert.textContent = "Normal conditions";
|
| 424 |
weatherAlert.className = "highlight";
|
| 425 |
}
|
| 426 |
}
|
|
|
|
| 575 |
} else {
|
| 576 |
if (hourlySection) hourlySection.style.display = "none";
|
| 577 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 578 |
}
|
| 579 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 580 |
// Request CSV from Backend API and download it
|
| 581 |
async function runExport() {
|
| 582 |
if (!exportBtn) return;
|
frontend/index.html
CHANGED
|
@@ -1,18 +1,15 @@
|
|
| 1 |
<!DOCTYPE html>
|
| 2 |
<html lang="en">
|
| 3 |
-
|
| 4 |
<head>
|
| 5 |
<meta charset="UTF-8">
|
| 6 |
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 7 |
<meta name="google-site-verification" content="Uv5ENuSBUKzeJte5ypBe6VGuYhEAZPqszpdCJPIawq4" />
|
| 8 |
<title>Aeterna AI - #1 AI Prediksi Sampah Jakarta & DKI Jakarta | By Faril Putra Pratama</title>
|
| 9 |
-
|
| 10 |
<!-- Primary SEO Meta Tags -->
|
| 11 |
<meta name="title" content="Aeterna AI - #1 AI Prediksi Sampah Jakarta & DKI Jakarta | By Faril Putra Pratama">
|
| 12 |
-
<meta name="description"
|
| 13 |
-
|
| 14 |
-
<meta name="keywords"
|
| 15 |
-
content="ai prediksi sampah, ai prediksi sampah jkt, ai prediksi sampah jakarta, aeterna ai, aeterna ai jakarta, aeternaai.biz.id, Faril Putra Pratama, FARILtau72, Prediksi Sampah Jakarta, DLH DKI Jakarta, AI Persampahan, Amazon Chronos T5, BPS Jakarta Jumlah Jiwa, Smart City Jakarta, TPST Bantargebang">
|
| 16 |
<meta name="author" content="Faril Putra Pratama">
|
| 17 |
<meta name="developer" content="Faril Putra Pratama (@FARILtau72)">
|
| 18 |
<meta name="github:repository" content="https://github.com/FARILtau72/Aeterna-Ai">
|
|
@@ -25,8 +22,7 @@
|
|
| 25 |
<meta property="og:type" content="website">
|
| 26 |
<meta property="og:url" content="https://www.aeternaai.biz.id/">
|
| 27 |
<meta property="og:title" content="Aeterna AI (AI Prediksi Sampah JKT) by Faril Putra Pratama">
|
| 28 |
-
<meta property="og:description"
|
| 29 |
-
content="Platform AI Prediksi Sampah #1 untuk 44 Kecamatan DKI Jakarta dikembangkan oleh Faril Putra Pratama. GitHub: https://github.com/FARILtau72/Aeterna-Ai | LinkedIn: https://www.linkedin.com/in/faril-putra-pratama-81561a280/">
|
| 30 |
<meta property="og:image" content="https://www.aeternaai.biz.id/static/assets/og_banner.png">
|
| 31 |
<meta property="og:site_name" content="Aeterna AI">
|
| 32 |
<meta property="og:locale" content="id_ID">
|
|
@@ -35,17 +31,14 @@
|
|
| 35 |
<meta name="twitter:card" content="summary_large_image">
|
| 36 |
<meta name="twitter:url" content="https://www.aeternaai.biz.id/">
|
| 37 |
<meta name="twitter:title" content="Aeterna AI by Faril Putra Pratama - #1 Waste Intelligence Platform DKI Jakarta">
|
| 38 |
-
<meta name="twitter:description"
|
| 39 |
-
content="Sistem AI peramalan sampah & armada logistik 44 Kecamatan DKI Jakarta dikembangkan oleh Faril Putra Pratama.">
|
| 40 |
<meta name="twitter:image" content="https://www.aeternaai.biz.id/static/assets/og_banner.png">
|
| 41 |
|
| 42 |
<!-- GEO Meta Citations for LLMs (ChatGPT, Gemini, Claude, Perplexity) -->
|
| 43 |
-
<meta name="citation_title"
|
| 44 |
-
content="Aeterna AI: Spatial-Temporal Waste Generation Forecasting Across 44 Kecamatans in DKI Jakarta">
|
| 45 |
<meta name="citation_author" content="Faril Putra Pratama (@FARILtau72)">
|
| 46 |
<meta name="citation_publication_date" content="2026">
|
| 47 |
-
<meta name="citation_technical_report_institution"
|
| 48 |
-
content="Aeterna AI Labs & Faril Putra Pratama Official Portal (aeternaai.biz.id)">
|
| 49 |
|
| 50 |
<!-- Geo-Location Meta Tags for Regional Indonesian Search Priority -->
|
| 51 |
<meta name="geo.region" content="ID-JK" />
|
|
@@ -59,15 +52,11 @@
|
|
| 59 |
<!-- Google Fonts -->
|
| 60 |
<link rel="preconnect" href="https://fonts.googleapis.com">
|
| 61 |
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
| 62 |
-
<link
|
| 63 |
-
|
| 64 |
-
rel="stylesheet">
|
| 65 |
-
|
| 66 |
<!-- Leaflet.js Map Library -->
|
| 67 |
-
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"
|
| 68 |
-
|
| 69 |
-
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"
|
| 70 |
-
integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo=" crossorigin=""></script>
|
| 71 |
|
| 72 |
<!-- Three.js 3D Library -->
|
| 73 |
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
|
|
@@ -127,7 +116,6 @@
|
|
| 127 |
}
|
| 128 |
</script>
|
| 129 |
</head>
|
| 130 |
-
|
| 131 |
<body>
|
| 132 |
<!-- Background Canvas for Interactive Particle Rain -->
|
| 133 |
<canvas id="rain-canvas"></canvas>
|
|
@@ -141,7 +129,7 @@
|
|
| 141 |
<nav class="nav-links">
|
| 142 |
<button class="nav-btn active" data-target="page-home" onclick="switchPage('page-home')">HOME</button>
|
| 143 |
<button class="nav-btn" data-target="page-autopilot" onclick="switchPage('page-autopilot')">AI AUTOPILOT</button>
|
| 144 |
-
<button class="nav-btn" data-target="page-predictor" onclick="switchPage('page-predictor')">SIMULATION
|
| 145 |
<button class="nav-btn" data-target="page-news" onclick="switchPage('page-news')">NEWS FEED</button>
|
| 146 |
<button class="nav-btn" data-target="page-alerts" onclick="switchPage('page-alerts')">REGIONAL ALERTS</button>
|
| 147 |
<button class="nav-btn" data-target="page-education" onclick="switchPage('page-education')">WASTE EDUCATION</button>
|
|
@@ -157,8 +145,7 @@
|
|
| 157 |
<section class="hero-section">
|
| 158 |
<div class="hero-content">
|
| 159 |
<h1 class="hero-title">NEXT-GEN WASTE FORECASTING</h1>
|
| 160 |
-
<p class="hero-subtitle">Meningkatkan efisiensi tata kelola sampah DKI Jakarta hingga 98.28% dengan
|
| 161 |
-
pemodelan spasial temporal real-time.</p>
|
| 162 |
<div class="hero-actions">
|
| 163 |
<button class="action-btn" onclick="switchPage('page-autopilot')">
|
| 164 |
<span class="btn-text">OPEN AUTOPILOT</span>
|
|
@@ -192,114 +179,70 @@
|
|
| 192 |
<div class="panel feature-card">
|
| 193 |
<div class="feature-icon font-display">01</div>
|
| 194 |
<h3 class="feature-name">Akurasi Validitas Tinggi (98.28%)</h3>
|
| 195 |
-
<p class="feature-desc">Menggunakan arsitektur model Gradient Boosting Regressor (GBR) yang
|
| 196 |
-
dioptimasi via GridSearchCV dengan metrik komparasi MAE, RMSE, dan MAPE secara berdampingan.</p>
|
| 197 |
</div>
|
| 198 |
<div class="panel feature-card">
|
| 199 |
<div class="feature-icon font-display">02</div>
|
| 200 |
<h3 class="feature-name">Integrasi Live Cuaca Open-Meteo</h3>
|
| 201 |
-
<p class="feature-desc">API dinamis asinkron yang menarik data curah hujan live tingkat kecamatan
|
| 202 |
-
secara real-time untuk memprediksi tonase sampah basah akibat rembesan air hujan.</p>
|
| 203 |
</div>
|
| 204 |
<div class="panel feature-card">
|
| 205 |
<div class="feature-icon font-display">03</div>
|
| 206 |
<h3 class="feature-name">Pemantauan Berita Sampah 1 Jam</h3>
|
| 207 |
-
<p class="feature-desc">AI Scheduler internal merayap internet secara berkala tiap 1 jam untuk
|
| 208 |
-
menangkap isu operasional, pembatasan Bantargebang, dan regulasi persampahan DKI Jakarta.</p>
|
| 209 |
</div>
|
| 210 |
<div class="panel feature-card">
|
| 211 |
<div class="feature-icon font-display">04</div>
|
| 212 |
<h3 class="feature-name">Kalibrasi Spasial 44 Kecamatan</h3>
|
| 213 |
-
<p class="feature-desc">Model peramalan dikalibrasi hulu-hilir menggunakan data primer Dinas
|
| 214 |
-
Lingkungan Hidup DKI Jakarta, mencakup tonase baseline spesifik tiap kecamatan secara akuntabel.
|
| 215 |
-
</p>
|
| 216 |
</div>
|
| 217 |
</div>
|
| 218 |
</section>
|
| 219 |
|
| 220 |
<!-- Cinematic Waste Crisis Scroll Section -->
|
| 221 |
-
<section class="container crisis-story-section"
|
| 222 |
-
|
| 223 |
-
|
| 224 |
<!-- Sticky Left Panel (Waste Tower Visualizer) -->
|
| 225 |
-
<div class="sticky-visualizer-panel"
|
| 226 |
-
style="
|
| 227 |
-
|
| 228 |
-
style="font-family: var(--font-display); font-size: 1.1rem; color: var(--text-main); margin-bottom: 1.5rem; letter-spacing: 1px; text-transform: uppercase;">
|
| 229 |
-
JAKARTA DAILY ACCUMULATION TOWER</h3>
|
| 230 |
-
|
| 231 |
<!-- The 3D Three.js Container -->
|
| 232 |
-
<div id="threejs-waste-container"
|
| 233 |
-
style="width: 220px; height: 280px; position: relative; display: flex; justify-content: center; align-items: center; background: rgba(0,0,0,0.01); border-radius: 12px; border: 1px solid var(--border-color); overflow: hidden;">
|
| 234 |
<!-- Static Overlay height labels inside 3D scene -->
|
| 235 |
-
<div
|
| 236 |
-
|
| 237 |
-
|
| 238 |
-
<div
|
| 239 |
-
style="position: absolute; right: 12px; top: 50%; transform: translateY(-50%); font-family: var(--font-mono); font-size: 9px; color: var(--text-muted); opacity: 0.6; z-index: 2; pointer-events: none;">
|
| 240 |
-
WARNING</div>
|
| 241 |
-
<div
|
| 242 |
-
style="position: absolute; right: 12px; bottom: 12px; font-family: var(--font-mono); font-size: 9px; color: var(--text-muted); opacity: 0.6; z-index: 2; pointer-events: none;">
|
| 243 |
-
NORMAL</div>
|
| 244 |
</div>
|
| 245 |
-
|
| 246 |
<!-- Live Ticking Indicator -->
|
| 247 |
<div class="tower-status" style="margin-top: 1.5rem; text-align: center;">
|
| 248 |
-
<div
|
| 249 |
-
|
| 250 |
-
Simulated Tonnage</div>
|
| 251 |
-
<div style="font-family: var(--font-mono); font-size: 1.8rem; color: var(--yellow); font-weight: bold;"
|
| 252 |
-
id="simulated-tons-val">0 Tons</div>
|
| 253 |
</div>
|
| 254 |
</div>
|
| 255 |
|
| 256 |
<!-- Scrolling Narrative Cards -->
|
| 257 |
-
<div class="story-scroll-cards"
|
| 258 |
-
|
| 259 |
-
|
| 260 |
<!-- Card 1 -->
|
| 261 |
-
<div class="story-card panel" data-height="25" data-tons="2264"
|
| 262 |
-
style="
|
| 263 |
-
<
|
| 264 |
-
|
| 265 |
-
01: MORNING LOADS (09:00 AM)</span>
|
| 266 |
-
<h3
|
| 267 |
-
style="font-family: var(--font-display); font-size: 1.3rem; color: var(--text-main); margin-bottom: 0.8rem;">
|
| 268 |
-
2,264 TON SAMPAH TERKUMPUL</h3>
|
| 269 |
-
<p style="font-size: 0.9rem; color: var(--text-muted); line-height: 1.6;">Memasuki jam kerja awal,
|
| 270 |
-
tumpukan sampah dari pasar tradisional dan wilayah residensial se-DKI Jakarta mulai berdatangan
|
| 271 |
-
di TPS. Kecepatan pengangkutan sangat krusial agar TPS lokal tidak mengalami kelumpuhan
|
| 272 |
-
penumpukan.</p>
|
| 273 |
</div>
|
| 274 |
|
| 275 |
<!-- Card 2 -->
|
| 276 |
-
<div class="story-card panel" data-height="55" data-tons="4982"
|
| 277 |
-
style="
|
| 278 |
-
<
|
| 279 |
-
|
| 280 |
-
02: MID-DAY PEAK (03:00 PM)</span>
|
| 281 |
-
<h3
|
| 282 |
-
style="font-family: var(--font-display); font-size: 1.3rem; color: var(--text-main); margin-bottom: 0.8rem;">
|
| 283 |
-
4,982 TON SAMPAH TERKUMPUL</h3>
|
| 284 |
-
<p style="font-size: 0.9rem; color: var(--text-muted); line-height: 1.6;">Di siang hari, aktivitas
|
| 285 |
-
logistik pengiriman sampah ke TPST Bantargebang memuncak. Kepadatan lalu lintas jalan tol
|
| 286 |
-
Jakarta-Bekasi dan antrean panjang truk di gerbang timbang Bantargebang mulai memicu bottleneck
|
| 287 |
-
operasional pengangkutan.</p>
|
| 288 |
</div>
|
| 289 |
|
| 290 |
<!-- Card 3 -->
|
| 291 |
-
<div class="story-card panel" data-height="95" data-tons="9059"
|
| 292 |
-
style="
|
| 293 |
-
<
|
| 294 |
-
|
| 295 |
-
03: EOD OVERLOAD (11:59 PM)</span>
|
| 296 |
-
<h3
|
| 297 |
-
style="font-family: var(--font-display); font-size: 1.3rem; color: var(--text-main); margin-bottom: 0.8rem;">
|
| 298 |
-
9,059 TON SAMPAH HARIAN</h3>
|
| 299 |
-
<p style="font-size: 0.9rem; color: var(--text-muted); line-height: 1.6;">Sebelum hari berakhir,
|
| 300 |
-
total timbulan sampah DKI mencapai kapasitas maksimalnya. TPST Bantargebang yang kini melebihi
|
| 301 |
-
daya tampung aman (ketinggian gunungan sampah di atas 50 meter) berada pada status siaga kritis.
|
| 302 |
-
Di sinilah Aeterna AI memitigasi krisis tersebut dengan analisis logistik prediktif.</p>
|
| 303 |
</div>
|
| 304 |
|
| 305 |
</div>
|
|
@@ -309,73 +252,35 @@
|
|
| 309 |
<section class="container data-sources-section">
|
| 310 |
<h2 class="section-title">TRANSPARANSI SUMBER DATA</h2>
|
| 311 |
<div class="panel sources-panel">
|
| 312 |
-
<div class="sources-grid"
|
| 313 |
-
style="display:grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap:1.5rem;">
|
| 314 |
<div class="source-item">
|
| 315 |
-
<h4 style="color:var(--cyan); margin-bottom:0.5rem; font-family:var(--font-display);">1.
|
| 316 |
-
|
| 317 |
-
<p style="font-size:0.85rem; color:var(--text-muted); line-height:1.5;">Data baseline
|
| 318 |
-
disesuaikan dengan volume total ~9.059 Ton/hari dari <strong>Dinas Lingkungan Hidup (DLH)
|
| 319 |
-
DKI Jakarta</strong> dan SIPSN Kementerian LHK.</p>
|
| 320 |
</div>
|
| 321 |
<div class="source-item">
|
| 322 |
-
<h4 style="color:var(--cyan); margin-bottom:0.5rem; font-family:var(--font-display);">2.
|
| 323 |
-
|
| 324 |
-
<p style="font-size:0.85rem; color:var(--text-muted); line-height:1.5;">Data curah hujan ditarik
|
| 325 |
-
live menggunakan <strong>Open-Meteo API</strong> berdasarkan koordinat geografis presisi
|
| 326 |
-
masing-masing kecamatan.</p>
|
| 327 |
</div>
|
| 328 |
<div class="source-item">
|
| 329 |
-
<h4 style="color:var(--cyan); margin-bottom:0.5rem; font-family:var(--font-display);">3.
|
| 330 |
-
|
| 331 |
-
<p style="font-size:0.85rem; color:var(--text-muted); line-height:1.5;">Pola mobilitas
|
| 332 |
-
disimulasikan dari ridership harian <strong>MRT Jakarta</strong> (~85.000) dan kalender
|
| 333 |
-
acara Jakarta untuk mengukur lonjakan kerumunan.</p>
|
| 334 |
</div>
|
| 335 |
<div class="source-item">
|
| 336 |
-
<h4 style="color:var(--cyan); margin-bottom:0.5rem; font-family:var(--font-display);">4. Jarak
|
| 337 |
-
|
| 338 |
-
<p style="font-size:0.85rem; color:var(--text-muted); line-height:1.5;">Jarak tempuh dihitung
|
| 339 |
-
menggunakan <strong>Haversine Formula</strong> dari koordinat kecamatan ke TPST Bantargebang
|
| 340 |
-
dengan faktor jalan winding 1.35x.</p>
|
| 341 |
</div>
|
| 342 |
</div>
|
| 343 |
</div>
|
| 344 |
</section>
|
| 345 |
|
| 346 |
-
|
| 347 |
-
|
| 348 |
-
|
| 349 |
-
|
| 350 |
-
|
| 351 |
-
|
| 352 |
-
|
| 353 |
-
|
| 354 |
-
<p
|
| 355 |
-
style="color: var(--text-muted); font-size: 0.92rem; line-height: 1.6; max-width: 780px; margin: 0 auto 1.5rem auto; font-family: var(--font-body);">
|
| 356 |
-
Merancang dan membangun seluruh arsitektur Aeterna AI dari ujung ke ujung. Meliputi riset data,
|
| 357 |
-
pelatihan model cerdas GBR & GridSearchCV, pembuatan arsitektur micro-service asinkron, hingga
|
| 358 |
-
visualisasi antarmuka HUD Glassmorphism interaktif.
|
| 359 |
-
</p>
|
| 360 |
-
<div style="display: flex; gap: 12px; justify-content: center; align-items: center; flex-wrap: wrap;">
|
| 361 |
-
<a href="https://github.com/FARILtau72/Aeterna-Ai" target="_blank" rel="noopener noreferrer"
|
| 362 |
-
class="action-btn"
|
| 363 |
-
style="display: inline-flex; align-items: center; gap: 8px; text-decoration: none; padding: 10px 22px;">
|
| 364 |
-
<svg width="16" height="16" fill="currentColor" viewBox="0 0 24 24">
|
| 365 |
-
<path
|
| 366 |
-
d="M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0024 12c0-6.63-5.37-12-12-12z" />
|
| 367 |
-
</svg>
|
| 368 |
-
GitHub
|
| 369 |
-
</a>
|
| 370 |
-
<a href="https://www.linkedin.com/in/faril-putra-pratama-81561a280/" target="_blank"
|
| 371 |
-
rel="noopener noreferrer" class="action-btn secondary-btn"
|
| 372 |
-
style="display: inline-flex; align-items: center; gap: 8px; text-decoration: none; padding: 10px 22px;">
|
| 373 |
-
<svg width="16" height="16" fill="currentColor" viewBox="0 0 24 24">
|
| 374 |
-
<path
|
| 375 |
-
d="M19 0h-14c-2.761 0-5 2.239-5 5v14c0 2.761 2.239 5 5 5h14c2.762 0 5-2.239 5-5v-14c0-2.761-2.762-5-5-5zm-11 19h-3v-11h3v11zm-1.5-12.268c-.966 0-1.75-.79-1.75-1.764s.784-1.764 1.75-1.764 1.75.79 1.75 1.764-.783 1.764-1.75 1.764zm13.5 12.268h-3v-5.604c0-3.368-4-3.113-4 0v5.604h-3v-11h3v1.765c1.396-2.586 7-2.777 7 2.476v6.759z" />
|
| 376 |
-
</svg>
|
| 377 |
-
LinkedIn
|
| 378 |
-
</a>
|
| 379 |
</div>
|
| 380 |
</div>
|
| 381 |
</section>
|
|
@@ -385,39 +290,29 @@
|
|
| 385 |
<div id="page-autopilot" class="page-container">
|
| 386 |
<section class="container page-header-section">
|
| 387 |
<h2 class="section-title">AETERNA AI AUTOPILOT FORECASTER</h2>
|
| 388 |
-
<p class="section-subtitle">Sistem peramalan otonom DKI Jakarta. AI berjalan mandiri memprediksi volume
|
| 389 |
-
harian dan mengoordinasikan logistik tanpa campur tangan pengguna.</p>
|
| 390 |
</section>
|
| 391 |
|
| 392 |
<!-- Live Metrics Summary -->
|
| 393 |
-
<section class="container autopilot-grid"
|
| 394 |
-
style="display:grid; grid-template-columns: 1.2fr 0.8fr; gap:1.5rem; margin-top:1.5rem;">
|
| 395 |
<!-- Panel Ringkasan Otonom -->
|
| 396 |
<div class="panel autopilot-summary-panel">
|
| 397 |
<h3 class="panel-title">LIVE CITY-WIDE FORECAST (TODAY)</h3>
|
| 398 |
-
<div class="stats-row"
|
| 399 |
-
|
| 400 |
-
<div class="panel stat-card text-glow"
|
| 401 |
-
style="background: rgba(0, 0, 0, 0.02); display:flex; flex-direction:column; padding:1.2rem; border-radius:8px;">
|
| 402 |
<span class="card-label">TOTAL DKI JAKARTA VOLUME</span>
|
| 403 |
-
<span id="auto-total-volume" class="card-value"
|
| 404 |
-
style="font-size:1.8rem; font-weight:800; color:var(--cyan);">Calculating...</span>
|
| 405 |
<span class="card-meta">Autonomous prediction summation</span>
|
| 406 |
</div>
|
| 407 |
-
<div class="panel stat-card"
|
| 408 |
-
style="background: rgba(0, 0, 0, 0.02); display:flex; flex-direction:column; padding:1.2rem; border-radius:8px;">
|
| 409 |
<span class="card-label">TOTAL DISPATCHED TRUCKS</span>
|
| 410 |
-
<span id="auto-total-trucks" class="card-value"
|
| 411 |
-
style="font-size:1.8rem; font-weight:800; color:var(--text-main);">Calculating...</span>
|
| 412 |
<span class="card-meta">Fleet size for all 44 kecamatan</span>
|
| 413 |
</div>
|
| 414 |
</div>
|
| 415 |
-
|
| 416 |
-
<h4
|
| 417 |
-
|
| 418 |
-
Top 5 High-Risk Kecamatan Today:</h4>
|
| 419 |
-
<div id="auto-risk-list" class="auto-risk-list"
|
| 420 |
-
style="display:flex; flex-direction:column; gap:0.8rem;">
|
| 421 |
<!-- Dynamically populated Top 5 -->
|
| 422 |
</div>
|
| 423 |
</div>
|
|
@@ -425,67 +320,15 @@
|
|
| 425 |
<!-- Konsol Berpikir AI -->
|
| 426 |
<div class="panel autopilot-console-panel" style="display:flex; flex-direction:column; height:100%;">
|
| 427 |
<h3 class="panel-title">AI THINKING CONSOLE</h3>
|
| 428 |
-
<div id="autopilot-log"
|
| 429 |
-
style="flex:1; background:#0B1310; border:1px solid var(--border-color); border-radius:8px; padding:1.2rem; font-family:var(--font-mono); font-size:0.8rem; color:#22C55E; overflow-y:auto; min-height:260px; line-height:1.6; box-shadow:inset 0 0 10px rgba(0,0,0,0.5);">
|
| 430 |
<!-- Dynamic logs -->
|
| 431 |
</div>
|
| 432 |
</div>
|
| 433 |
</section>
|
| 434 |
</div>
|
| 435 |
|
| 436 |
-
<!-- PREDICTOR
|
| 437 |
<div id="page-predictor" class="page-container">
|
| 438 |
-
<!-- Top Executive Decision KPIs Header -->
|
| 439 |
-
<section class="container decision-header-section">
|
| 440 |
-
<div class="decision-header-top">
|
| 441 |
-
<div class="decision-title-group">
|
| 442 |
-
<h2 class="decision-heading">
|
| 443 |
-
<svg class="decision-icon" width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="#00F0FF" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
|
| 444 |
-
<polyline points="22 12 18 12 15 21 9 3 6 12 2 12"></polyline>
|
| 445 |
-
</svg>
|
| 446 |
-
Dashboard Keputusan & AI Simulator
|
| 447 |
-
</h2>
|
| 448 |
-
<p class="decision-subtitle">Spatial-temporal forecasting engine & decision support system untuk optimalisasi logistik, alokasi armada hulu-hilir, dan efisiensi anggaran sampah DKI Jakarta.</p>
|
| 449 |
-
</div>
|
| 450 |
-
</div>
|
| 451 |
-
|
| 452 |
-
<!-- Top 3 Decision KPI Cards -->
|
| 453 |
-
<div class="decision-kpi-grid">
|
| 454 |
-
<!-- KPI 1: Total Volume -->
|
| 455 |
-
<div class="panel dec-kpi-card">
|
| 456 |
-
<span class="dec-kpi-label">TOTAL VOLUME PREDIKSI</span>
|
| 457 |
-
<div class="dec-kpi-val-row">
|
| 458 |
-
<span id="dec-total-vol" class="dec-kpi-number text-glow">3079.5</span>
|
| 459 |
-
<span class="dec-kpi-unit">TON</span>
|
| 460 |
-
</div>
|
| 461 |
-
<span id="dec-vol-status" class="dec-kpi-meta positive">
|
| 462 |
-
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#00F0FF" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>
|
| 463 |
-
Berhasil diprediksi (7 hari)
|
| 464 |
-
</span>
|
| 465 |
-
</div>
|
| 466 |
-
|
| 467 |
-
<!-- KPI 2: Estimasi Biaya Operasional -->
|
| 468 |
-
<div class="panel dec-kpi-card">
|
| 469 |
-
<span class="dec-kpi-label">ESTIMASI BIAYA OPERASIONAL</span>
|
| 470 |
-
<div class="dec-kpi-val-row">
|
| 471 |
-
<span id="dec-cost-val" class="dec-kpi-number">Rp 292.600.000</span>
|
| 472 |
-
</div>
|
| 473 |
-
<span class="dec-kpi-meta">Total Anggaran Logistik & SDM</span>
|
| 474 |
-
</div>
|
| 475 |
-
|
| 476 |
-
<!-- KPI 3: Efisiensi AI Proaktif vs Reaktif -->
|
| 477 |
-
<div class="panel dec-kpi-card">
|
| 478 |
-
<span class="dec-kpi-label">EFISIENSI AI (PROAKTIF VS REAKTIF)</span>
|
| 479 |
-
<div class="dec-kpi-val-row">
|
| 480 |
-
<span id="dec-efficiency-val" class="dec-kpi-number green-glow" style="color: #4ade80;">51.2%</span>
|
| 481 |
-
</div>
|
| 482 |
-
<span id="dec-saved-val" class="dec-kpi-meta positive" style="color: #4ade80;">
|
| 483 |
-
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#4ade80" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="23 18 13.5 8.5 8.5 13.5 1 6"/><polyline points="17 18 23 18 23 12"/></svg>
|
| 484 |
-
Hemat Rp 306.600.000 dibanding Reaktif
|
| 485 |
-
</span>
|
| 486 |
-
</div>
|
| 487 |
-
</div>
|
| 488 |
-
</section>
|
| 489 |
<main class="dashboard-grid">
|
| 490 |
<!-- Panel Kontrol (Sidebar) -->
|
| 491 |
<section class="panel control-panel">
|
|
@@ -500,15 +343,13 @@
|
|
| 500 |
<div class="control-group">
|
| 501 |
<label for="model-select">AI Forecasting Model</label>
|
| 502 |
<select id="model-select" class="form-control">
|
| 503 |
-
<option value="gradient_boosting" selected>Stacking Regressor Ensemble (Real Data - 96.41% Acc)
|
| 504 |
-
</option>
|
| 505 |
<option value="chronos">Amazon Chronos-T5 (Tiny)</option>
|
| 506 |
</select>
|
| 507 |
</div>
|
| 508 |
|
| 509 |
<div class="control-group">
|
| 510 |
-
<label for="forecast-slider">Forecast Horizon: <span id="forecast-val"
|
| 511 |
-
class="value-display">7</span> Days</label>
|
| 512 |
<input type="range" id="forecast-slider" min="1" max="30" value="7" class="slider">
|
| 513 |
</div>
|
| 514 |
|
|
@@ -524,10 +365,8 @@
|
|
| 524 |
</div>
|
| 525 |
|
| 526 |
<div class="control-group">
|
| 527 |
-
<label for="event-override">Simulasi Populasi <span id="event-override-val"
|
| 528 |
-
|
| 529 |
-
<input type="range" id="event-override" min="10000" max="700000" step="5000" value="88000"
|
| 530 |
-
class="slider">
|
| 531 |
</div>
|
| 532 |
|
| 533 |
<div class="button-row">
|
|
@@ -576,8 +415,7 @@
|
|
| 576 |
<section class="analysis-panel">
|
| 577 |
<div class="panel category-panel">
|
| 578 |
<h2 class="panel-title">WASTE COMPOSITION BREAKDOWN</h2>
|
| 579 |
-
<div class="progress-container"
|
| 580 |
-
style="display: grid; grid-template-columns: 1fr 1fr; gap: 1rem 1.5rem;">
|
| 581 |
<div class="progress-item" style="margin-bottom: 0;">
|
| 582 |
<div class="progress-header">
|
| 583 |
<span>Organic / Sisa Makanan (~50.2%)</span>
|
|
@@ -652,10 +490,6 @@
|
|
| 652 |
<span class="event-title">Upcoming Event Calendar</span>
|
| 653 |
<p class="event-desc" id="event-desc-text">No major events registered for today.</p>
|
| 654 |
</div>
|
| 655 |
-
<button class="action-btn secondary-btn" onclick="openWeatherModal()" style="margin-top: 14px; width: 100%; padding: 10px 14px; font-size: 0.82rem; display: flex; align-items: center; justify-content: center; gap: 8px; border-radius: 8px;">
|
| 656 |
-
<span>🌦️ Lihat Prakiraan Cuaca 7 Hari (Open-Meteo)</span>
|
| 657 |
-
<span style="font-weight: bold;">→</span>
|
| 658 |
-
</button>
|
| 659 |
</div>
|
| 660 |
|
| 661 |
<!-- Logistics Plan -->
|
|
@@ -683,104 +517,6 @@
|
|
| 683 |
</section>
|
| 684 |
</main>
|
| 685 |
|
| 686 |
-
<!-- Section 1: Peta Beban Kerja Harian (Full Width) -->
|
| 687 |
-
<section class="container" style="margin-top: 1.5rem; margin-bottom: 1.5rem;">
|
| 688 |
-
<div class="panel dec-workload-panel">
|
| 689 |
-
<div class="dec-panel-header">
|
| 690 |
-
<h3 class="dec-panel-title">
|
| 691 |
-
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#00F0FF" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
| 692 |
-
<rect x="3" y="4" width="18" height="18" rx="2" ry="2"></rect>
|
| 693 |
-
<line x1="16" y1="2" x2="16" y2="6"></line>
|
| 694 |
-
<line x1="8" y1="2" x2="8" y2="6"></line>
|
| 695 |
-
<line x1="3" y1="10" x2="21" y2="10"></line>
|
| 696 |
-
</svg>
|
| 697 |
-
Peta Beban Kerja Harian (7 Hari Horizon)
|
| 698 |
-
</h3>
|
| 699 |
-
<span class="dec-panel-badge">Jadwal Shift & Disposisi Armada</span>
|
| 700 |
-
</div>
|
| 701 |
-
|
| 702 |
-
<div id="dec-workload-grid" class="dec-workload-grid">
|
| 703 |
-
<!-- Populated dynamically with 7 day cards -->
|
| 704 |
-
</div>
|
| 705 |
-
</div>
|
| 706 |
-
</section>
|
| 707 |
-
|
| 708 |
-
<!-- Section 2: Alokasi Armada Spesifik & Rencana Aksi Kritis (2 Columns) -->
|
| 709 |
-
<section class="container decision-details-grid" style="margin-bottom: 1.5rem;">
|
| 710 |
-
<!-- Left: Alokasi Armada Spesifik -->
|
| 711 |
-
<div class="panel dec-fleet-panel">
|
| 712 |
-
<div class="dec-panel-header">
|
| 713 |
-
<h3 class="dec-panel-title">
|
| 714 |
-
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#38bdf8" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
| 715 |
-
<rect x="1" y="3" width="15" height="13"></rect>
|
| 716 |
-
<polygon points="16 8 20 8 23 11 23 16 16 16 8"></polygon>
|
| 717 |
-
<circle cx="5.5" cy="18.5" r="2.5"></circle>
|
| 718 |
-
<circle cx="18.5" cy="18.5" r="2.5"></circle>
|
| 719 |
-
</svg>
|
| 720 |
-
Alokasi Armada Spesifik
|
| 721 |
-
</h3>
|
| 722 |
-
<span class="dec-panel-badge">Rasio 60:40 Dump vs Pick-up</span>
|
| 723 |
-
</div>
|
| 724 |
-
<div class="dec-fleet-list">
|
| 725 |
-
<!-- Truk Besar Dump Truck -->
|
| 726 |
-
<div class="dec-fleet-card dump-truck">
|
| 727 |
-
<div class="fleet-icon-box blue-box">
|
| 728 |
-
<svg width="26" height="26" viewBox="0 0 24 24" fill="none" stroke="#38bdf8" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
| 729 |
-
<rect x="1" y="3" width="15" height="13"></rect>
|
| 730 |
-
<polygon points="16 8 20 8 23 11 23 16 16 16 8"></polygon>
|
| 731 |
-
<circle cx="5.5" cy="18.5" r="2.5"></circle>
|
| 732 |
-
<circle cx="18.5" cy="18.5" r="2.5"></circle>
|
| 733 |
-
</svg>
|
| 734 |
-
</div>
|
| 735 |
-
<div class="fleet-info">
|
| 736 |
-
<div class="fleet-unit-count"><span id="dec-truck-large">125</span> <span class="fleet-unit-suffix">Unit</span></div>
|
| 737 |
-
<div class="fleet-unit-type">Truk Besar (Dump Truck 15T)</div>
|
| 738 |
-
</div>
|
| 739 |
-
</div>
|
| 740 |
-
|
| 741 |
-
<!-- Armada Kecil Pick-up -->
|
| 742 |
-
<div class="dec-fleet-card pickup-truck">
|
| 743 |
-
<div class="fleet-icon-box amber-box">
|
| 744 |
-
<svg width="26" height="26" viewBox="0 0 24 24" fill="none" stroke="#fbbf24" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
| 745 |
-
<rect x="1" y="3" width="12" height="13"></rect>
|
| 746 |
-
<polygon points="13 8 17 8 20 11 20 16 13 16 13 8"></polygon>
|
| 747 |
-
<circle cx="4.5" cy="18.5" r="2.5"></circle>
|
| 748 |
-
<circle cx="16.5" cy="18.5" r="2.5"></circle>
|
| 749 |
-
</svg>
|
| 750 |
-
</div>
|
| 751 |
-
<div class="fleet-info">
|
| 752 |
-
<div class="fleet-unit-count"><span id="dec-truck-small">84</span> <span class="fleet-unit-suffix">Unit</span></div>
|
| 753 |
-
<div class="fleet-unit-type">Armada Kecil (Pick-up 2.5T)</div>
|
| 754 |
-
</div>
|
| 755 |
-
</div>
|
| 756 |
-
</div>
|
| 757 |
-
</div>
|
| 758 |
-
|
| 759 |
-
<!-- Right: Rencana Aksi Kritis -->
|
| 760 |
-
<div class="panel dec-action-panel">
|
| 761 |
-
<div class="dec-panel-header">
|
| 762 |
-
<h3 class="dec-panel-title action-title">
|
| 763 |
-
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#ef4444" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
| 764 |
-
<path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"></path>
|
| 765 |
-
<line x1="12" y1="9" x2="12" y2="13"></line>
|
| 766 |
-
<line x1="12" y1="17" x2="12.01" y2="17"></line>
|
| 767 |
-
</svg>
|
| 768 |
-
Rencana Aksi Kritis
|
| 769 |
-
</h3>
|
| 770 |
-
<span class="dec-panel-badge" style="color: #f87171; border-color: rgba(239, 68, 68, 0.3);">Contingency SOP</span>
|
| 771 |
-
</div>
|
| 772 |
-
<div class="dec-critical-box" id="dec-critical-box">
|
| 773 |
-
<div class="dec-critical-header">
|
| 774 |
-
<span class="critical-pulse-dot"></span>
|
| 775 |
-
<span id="dec-critical-title" class="dec-critical-title">AKSI HARI JUM (HUJAN LEBAT & BEBAN PUNCAK)</span>
|
| 776 |
-
</div>
|
| 777 |
-
<ul id="dec-critical-list" class="dec-critical-list">
|
| 778 |
-
<!-- Populated dynamically with SOP actions -->
|
| 779 |
-
</ul>
|
| 780 |
-
</div>
|
| 781 |
-
</div>
|
| 782 |
-
</section>
|
| 783 |
-
|
| 784 |
<!-- Timeline Harian -->
|
| 785 |
<section class="container timeline-container">
|
| 786 |
<div class="panel timeline-panel">
|
|
@@ -804,32 +540,17 @@
|
|
| 804 |
<!-- Developer Bio Card -->
|
| 805 |
<section class="container developer-container" style="margin-top: 2rem; margin-bottom: 2.5rem;">
|
| 806 |
<div class="panel developer-panel" style="text-align: center; padding: 2.2rem;">
|
| 807 |
-
<h3
|
| 808 |
-
|
| 809 |
-
|
| 810 |
-
<p
|
| 811 |
-
style="color: var(--text-muted); font-size: 0.92rem; line-height: 1.6; max-width: 780px; margin: 0 auto 1.5rem auto; font-family: var(--font-body);">
|
| 812 |
-
Merancang dan membangun seluruh arsitektur Aeterna AI dari ujung ke ujung. Meliputi riset data,
|
| 813 |
-
pelatihan model cerdas GBR & GridSearchCV, pembuatan arsitektur micro-service asinkron, hingga
|
| 814 |
-
visualisasi antarmuka HUD Glassmorphism interaktif.
|
| 815 |
</p>
|
| 816 |
<div style="display: flex; gap: 12px; justify-content: center; align-items: center; flex-wrap: wrap;">
|
| 817 |
-
<a href="https://github.com/FARILtau72/Aeterna-Ai" target="_blank" rel="noopener noreferrer"
|
| 818 |
-
|
| 819 |
-
style="display: inline-flex; align-items: center; gap: 8px; text-decoration: none; padding: 10px 22px;">
|
| 820 |
-
<svg width="16" height="16" fill="currentColor" viewBox="0 0 24 24">
|
| 821 |
-
<path
|
| 822 |
-
d="M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0024 12c0-6.63-5.37-12-12-12z" />
|
| 823 |
-
</svg>
|
| 824 |
GitHub
|
| 825 |
</a>
|
| 826 |
-
<a href="https://www.linkedin.com/in/faril-putra-pratama-81561a280/" target="_blank"
|
| 827 |
-
|
| 828 |
-
style="display: inline-flex; align-items: center; gap: 8px; text-decoration: none; padding: 10px 22px;">
|
| 829 |
-
<svg width="16" height="16" fill="currentColor" viewBox="0 0 24 24">
|
| 830 |
-
<path
|
| 831 |
-
d="M19 0h-14c-2.761 0-5 2.239-5 5v14c0 2.761 2.239 5 5 5h14c2.762 0 5-2.239 5-5v-14c0-2.761-2.762-5-5-5zm-11 19h-3v-11h3v11zm-1.5-12.268c-.966 0-1.75-.79-1.75-1.764s.784-1.764 1.75-1.764 1.75.79 1.75 1.764-.783 1.764-1.75 1.764zm13.5 12.268h-3v-5.604c0-3.368-4-3.113-4 0v5.604h-3v-11h3v1.765c1.396-2.586 7-2.777 7 2.476v6.759z" />
|
| 832 |
-
</svg>
|
| 833 |
LinkedIn
|
| 834 |
</a>
|
| 835 |
</div>
|
|
@@ -841,8 +562,7 @@
|
|
| 841 |
<div id="page-news" class="page-container">
|
| 842 |
<section class="container page-header-section">
|
| 843 |
<h2 class="section-title">MONITORING BERITA PERSAMPAHAN JAKARTA</h2>
|
| 844 |
-
<p class="section-subtitle">AI merayap berita terbaru seputar isu darurat sampah, operasional TPA
|
| 845 |
-
Bantargebang, dan kebijakan DLH Jakarta secara otomatis setiap 1 jam.</p>
|
| 846 |
</section>
|
| 847 |
|
| 848 |
<section class="container news-feed-container">
|
|
@@ -857,8 +577,7 @@
|
|
| 857 |
<div id="page-alerts" class="page-container">
|
| 858 |
<section class="container page-header-section">
|
| 859 |
<h2 class="section-title">REGIONAL HAZARD & ALERTS MAP</h2>
|
| 860 |
-
<p class="section-subtitle">Daftar wilayah kecamatan dengan prakiraan volume timbulan sampah melebihi ambang
|
| 861 |
-
batas operasional harian.</p>
|
| 862 |
</section>
|
| 863 |
|
| 864 |
<section class="container alerts-feed-container">
|
|
@@ -876,51 +595,33 @@
|
|
| 876 |
<div id="page-education" class="page-container">
|
| 877 |
<section class="container page-header-section">
|
| 878 |
<h2 class="section-title">WASTE EDUCATION HUB</h2>
|
| 879 |
-
<p class="section-subtitle">Pelajari dampak penumpukan sampah di DKI Jakarta, durasi dekomposisi material,
|
| 880 |
-
dan uji ketangkasan pilah sampah Anda secara interaktif.</p>
|
| 881 |
</section>
|
| 882 |
|
| 883 |
<!-- Interactive simulator & info panels -->
|
| 884 |
-
<section class="container education-grid"
|
| 885 |
-
style="display:grid; grid-template-columns: 1.2fr 0.8fr; gap:1.5rem; margin-top:1.5rem;">
|
| 886 |
<!-- Game Pilah Sampah (Eco-Sorter) -->
|
| 887 |
-
<div class="panel game-panel"
|
| 888 |
-
style="
|
| 889 |
-
<div class="panel-badge"
|
| 890 |
-
style="position:absolute; top:1rem; right:1.5rem; background:rgba(0, 240, 255, 0.1); border:1px solid var(--cyan); color:var(--cyan); border-radius:12px; padding:3px 8px; font-size:0.75rem; font-family:var(--font-mono);">
|
| 891 |
-
INTERACTIVE GAME</div>
|
| 892 |
<h3 class="panel-title" style="margin-bottom:0.5rem;">ECO-SORTER SIMULATOR</h3>
|
| 893 |
-
<p style="font-size:0.85rem; color:var(--text-muted); margin-bottom:1.5rem;">Pilah item sampah ke tempat
|
| 894 |
-
|
| 895 |
-
|
| 896 |
<!-- Waste Item Card -->
|
| 897 |
-
<div class="game-area"
|
| 898 |
-
|
| 899 |
-
<
|
| 900 |
-
|
| 901 |
-
🍼</div>
|
| 902 |
-
<h4 id="game-item-name"
|
| 903 |
-
style="font-family:var(--font-display); font-size:1.3rem; color:#FFF; margin-bottom:0.5rem;">
|
| 904 |
-
Botol Plastik Bekas</h4>
|
| 905 |
-
<p id="game-item-desc"
|
| 906 |
-
style="font-size:0.85rem; color:var(--text-muted); max-width:300px; min-height:40px;">Botol air
|
| 907 |
-
mineral kosong berbahan PET.</p>
|
| 908 |
</div>
|
| 909 |
-
|
| 910 |
<!-- Target Bins -->
|
| 911 |
<div class="bin-grid" style="display:grid; grid-template-columns: repeat(3, 1fr); gap:1rem;">
|
| 912 |
-
<button class="bin-btn organic-bin" onclick="sortWaste('organic')"
|
| 913 |
-
|
| 914 |
-
<button class="bin-btn
|
| 915 |
-
style="background:rgba(56, 189, 248, 0.05); border:1px solid #38bdf8; color:#38bdf8; padding:1rem; border-radius:8px; font-family:var(--font-display); font-weight:bold; cursor:pointer; transition:all 0.2s; outline:none;">ANORGANIK</button>
|
| 916 |
-
<button class="bin-btn hazard-bin" onclick="sortWaste('hazardous')"
|
| 917 |
-
style="background:rgba(251, 113, 133, 0.05); border:1px solid #fb7185; color:#fb7185; padding:1rem; border-radius:8px; font-family:var(--font-display); font-weight:bold; cursor:pointer; transition:all 0.2s; outline:none;">BAHAYA
|
| 918 |
-
(B3)</button>
|
| 919 |
</div>
|
| 920 |
-
|
| 921 |
<!-- Game Stats -->
|
| 922 |
-
<div class="game-stats"
|
| 923 |
-
style="display:flex; justify-content:space-between; align-items:center; margin-top:1.5rem; font-family:var(--font-mono); font-size:0.9rem; padding:0.8rem; background:rgba(255,255,255,0.02); border-radius:6px; border:1px solid rgba(255,255,255,0.05);">
|
| 924 |
<span>Skor: <strong id="game-score" style="color:var(--cyan); font-size:1.1rem;">0</strong></span>
|
| 925 |
<span id="game-feedback" style="color:var(--text-muted); font-weight:bold;">Ayo mulai pilah!</span>
|
| 926 |
</div>
|
|
@@ -929,71 +630,47 @@
|
|
| 929 |
<!-- Fakta Dekomposisi Sampah -->
|
| 930 |
<div class="panel facts-panel" style="display:flex; flex-direction:column; padding:2rem;">
|
| 931 |
<h3 class="panel-title" style="margin-bottom:1rem;">DURASI DEKOMPOSISI ALAM</h3>
|
| 932 |
-
<p style="font-size:0.85rem; color:var(--text-muted); margin-bottom:1.5rem;">Berapa lama alam
|
| 933 |
-
|
| 934 |
-
|
| 935 |
-
<div class="facts-list"
|
| 936 |
-
style="display:flex; flex-direction:column; gap:1.2rem; flex:1; justify-content:center;">
|
| 937 |
<div class="fact-item" style="display:flex; align-items:center; gap:1rem;">
|
| 938 |
-
<span
|
| 939 |
-
style="font-size:2rem; background:rgba(255,255,255,0.05); width:50px; height:50px; border-radius:50%; display:flex; align-items:center; justify-content:center;">🍎</span>
|
| 940 |
<div style="flex:1;">
|
| 941 |
<h4 style="font-size:0.9rem; color:#FFF; margin-bottom:2px;">Sisa Makanan / Organik</h4>
|
| 942 |
-
<div class="progress-bar-bg" style="height:6px; margin:4px 0;">
|
| 943 |
-
|
| 944 |
-
</div>
|
| 945 |
-
<span style="font-size:0.75rem; color:#4ade80; font-family:var(--font-mono);">1 - 2
|
| 946 |
-
Minggu</span>
|
| 947 |
</div>
|
| 948 |
</div>
|
| 949 |
<div class="fact-item" style="display:flex; align-items:center; gap:1rem;">
|
| 950 |
-
<span
|
| 951 |
-
style="font-size:2rem; background:rgba(255,255,255,0.05); width:50px; height:50px; border-radius:50%; display:flex; align-items:center; justify-content:center;">📦</span>
|
| 952 |
<div style="flex:1;">
|
| 953 |
<h4 style="font-size:0.9rem; color:#FFF; margin-bottom:2px;">Kertas & Kardus</h4>
|
| 954 |
-
<div class="progress-bar-bg" style="height:6px; margin:4px 0;">
|
| 955 |
-
|
| 956 |
-
</div>
|
| 957 |
-
<span style="font-size:0.75rem; color:#38bdf8; font-family:var(--font-mono);">2 - 6
|
| 958 |
-
Minggu</span>
|
| 959 |
</div>
|
| 960 |
</div>
|
| 961 |
<div class="fact-item" style="display:flex; align-items:center; gap:1rem;">
|
| 962 |
-
<span
|
| 963 |
-
style="font-size:2rem; background:rgba(255,255,255,0.05); width:50px; height:50px; border-radius:50%; display:flex; align-items:center; justify-content:center;">🍼</span>
|
| 964 |
<div style="flex:1;">
|
| 965 |
<h4 style="font-size:0.9rem; color:#FFF; margin-bottom:2px;">Botol Plastik PET</h4>
|
| 966 |
-
<div class="progress-bar-bg" style="height:6px; margin:4px 0;">
|
| 967 |
-
|
| 968 |
-
</div>
|
| 969 |
-
</div>
|
| 970 |
-
<span style="font-size:0.75rem; color:#fb923c; font-family:var(--font-mono);">450
|
| 971 |
-
Tahun</span>
|
| 972 |
</div>
|
| 973 |
</div>
|
| 974 |
<div class="fact-item" style="display:flex; align-items:center; gap:1rem;">
|
| 975 |
-
<span
|
| 976 |
-
style="font-size:2rem; background:rgba(255,255,255,0.05); width:50px; height:50px; border-radius:50%; display:flex; align-items:center; justify-content:center;">🔋</span>
|
| 977 |
<div style="flex:1;">
|
| 978 |
<h4 style="font-size:0.9rem; color:#FFF; margin-bottom:2px;">Baterai & Logam</h4>
|
| 979 |
-
<div class="progress-bar-bg" style="height:6px; margin:4px 0;">
|
| 980 |
-
|
| 981 |
-
</div>
|
| 982 |
-
<span style="font-size:0.75rem; color:#fb7185; font-family:var(--font-mono);">100 Tahun
|
| 983 |
-
(Logam) / Berabad-abad (Kimia B3)</span>
|
| 984 |
</div>
|
| 985 |
</div>
|
| 986 |
<div class="fact-item" style="display:flex; align-items:center; gap:1rem;">
|
| 987 |
-
<span
|
| 988 |
-
style="font-size:2rem; background:rgba(255,255,255,0.05); width:50px; height:50px; border-radius:50%; display:flex; align-items:center; justify-content:center;">🫙</span>
|
| 989 |
<div style="flex:1;">
|
| 990 |
<h4 style="font-size:0.9rem; color:#FFF; margin-bottom:2px;">Botol Kaca</h4>
|
| 991 |
-
<div class="progress-bar-bg" style="height:6px; margin:4px 0;">
|
| 992 |
-
|
| 993 |
-
style="width: 100%; background:#e879f9 !important;"></div>
|
| 994 |
-
</div>
|
| 995 |
-
<span style="font-size:0.75rem; color:#e879f9; font-family:var(--font-mono);">1 Juta Tahun /
|
| 996 |
-
Tidak Hancur</span>
|
| 997 |
</div>
|
| 998 |
</div>
|
| 999 |
</div>
|
|
@@ -1001,46 +678,9 @@
|
|
| 1001 |
</section>
|
| 1002 |
</div>
|
| 1003 |
|
| 1004 |
-
<!-- 7-DAY WEATHER FORECAST MODAL (PRAKIRAAN CUACA 7 HARI) -->
|
| 1005 |
-
<div id="weather-modal" class="weather-modal-backdrop" onclick="if(event.target === this) closeWeatherModal()">
|
| 1006 |
-
<div class="weather-modal-dialog">
|
| 1007 |
-
<div class="weather-modal-header">
|
| 1008 |
-
<div class="weather-modal-title-row">
|
| 1009 |
-
<h3 class="weather-modal-title">Prakiraan Cuaca 7 Hari</h3>
|
| 1010 |
-
<span id="modal-weather-loc" class="weather-location-pill">Cakung</span>
|
| 1011 |
-
</div>
|
| 1012 |
-
<button class="weather-modal-close-btn" onclick="closeWeatherModal()" title="Tutup Modal">✕</button>
|
| 1013 |
-
</div>
|
| 1014 |
-
|
| 1015 |
-
<div class="weather-modal-summary-card">
|
| 1016 |
-
<div class="summary-left">
|
| 1017 |
-
<span class="summary-card-label">SUMMARY 7 HARI</span>
|
| 1018 |
-
<div class="summary-card-stats">
|
| 1019 |
-
Total: <span id="modal-sum-total" class="summary-val-highlight">14.0mm</span>
|
| 1020 |
-
<span class="summary-separator">•</span>
|
| 1021 |
-
Avg: <span id="modal-sum-avg" class="summary-val-highlight">2.0mm/hr</span>
|
| 1022 |
-
</div>
|
| 1023 |
-
</div>
|
| 1024 |
-
<div class="summary-right">
|
| 1025 |
-
<span id="modal-sum-badge" class="weather-dryness-badge dry">KERING</span>
|
| 1026 |
-
</div>
|
| 1027 |
-
</div>
|
| 1028 |
-
|
| 1029 |
-
<div class="weather-modal-forecast-list" id="weather-modal-list">
|
| 1030 |
-
<!-- Dynamically populated with 7 real days from Open-Meteo API -->
|
| 1031 |
-
<div class="weather-modal-loading">Mengambil data cuaca real-time Open-Meteo...</div>
|
| 1032 |
-
</div>
|
| 1033 |
-
</div>
|
| 1034 |
-
</div>
|
| 1035 |
-
|
| 1036 |
<footer>
|
| 1037 |
-
<p>© 2026 Aeterna AI — Developed & Engineered with ⚡ by <span
|
| 1038 |
-
|
| 1039 |
-
<p
|
| 1040 |
-
style="margin-top: 0.6rem; font-size: 0.75rem; opacity: 0.85; letter-spacing: 0.5px; font-family: var(--font-mono); line-height: 1.5;">
|
| 1041 |
-
Official Portal: <a href="https://www.aeternaai.biz.id/"
|
| 1042 |
-
style="color:#00f2fe; text-decoration:none;">aeternaai.biz.id</a> | #1 AI Waste Intelligence Platform
|
| 1043 |
-
for 44 Kecamatans in DKI Jakarta.</p>
|
| 1044 |
</footer>
|
| 1045 |
|
| 1046 |
<!-- Custom Cyber HUD Cursor -->
|
|
@@ -1050,5 +690,4 @@
|
|
| 1050 |
<!-- Scripts -->
|
| 1051 |
<script src="/static/app.js"></script>
|
| 1052 |
</body>
|
| 1053 |
-
|
| 1054 |
-
</html>
|
|
|
|
| 1 |
<!DOCTYPE html>
|
| 2 |
<html lang="en">
|
|
|
|
| 3 |
<head>
|
| 4 |
<meta charset="UTF-8">
|
| 5 |
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 6 |
<meta name="google-site-verification" content="Uv5ENuSBUKzeJte5ypBe6VGuYhEAZPqszpdCJPIawq4" />
|
| 7 |
<title>Aeterna AI - #1 AI Prediksi Sampah Jakarta & DKI Jakarta | By Faril Putra Pratama</title>
|
| 8 |
+
|
| 9 |
<!-- Primary SEO Meta Tags -->
|
| 10 |
<meta name="title" content="Aeterna AI - #1 AI Prediksi Sampah Jakarta & DKI Jakarta | By Faril Putra Pratama">
|
| 11 |
+
<meta name="description" content="Aeterna AI (aeternaai.biz.id) adalah platform AI Prediksi Sampah #1 untuk 44 Kecamatan DKI Jakarta (ai prediksi sampah jkt) dikembangkan oleh Faril Putra Pratama berbasis BPS Jumlah Jiwa & Amazon Chronos T5.">
|
| 12 |
+
<meta name="keywords" content="ai prediksi sampah, ai prediksi sampah jkt, ai prediksi sampah jakarta, aeterna ai, aeterna ai jakarta, aeternaai.biz.id, Faril Putra Pratama, FARILtau72, Prediksi Sampah Jakarta, DLH DKI Jakarta, AI Persampahan, Amazon Chronos T5, BPS Jakarta Jumlah Jiwa, Smart City Jakarta, TPST Bantargebang">
|
|
|
|
|
|
|
| 13 |
<meta name="author" content="Faril Putra Pratama">
|
| 14 |
<meta name="developer" content="Faril Putra Pratama (@FARILtau72)">
|
| 15 |
<meta name="github:repository" content="https://github.com/FARILtau72/Aeterna-Ai">
|
|
|
|
| 22 |
<meta property="og:type" content="website">
|
| 23 |
<meta property="og:url" content="https://www.aeternaai.biz.id/">
|
| 24 |
<meta property="og:title" content="Aeterna AI (AI Prediksi Sampah JKT) by Faril Putra Pratama">
|
| 25 |
+
<meta property="og:description" content="Platform AI Prediksi Sampah #1 untuk 44 Kecamatan DKI Jakarta dikembangkan oleh Faril Putra Pratama. GitHub: https://github.com/FARILtau72/Aeterna-Ai | LinkedIn: https://www.linkedin.com/in/faril-putra-pratama-81561a280/">
|
|
|
|
| 26 |
<meta property="og:image" content="https://www.aeternaai.biz.id/static/assets/og_banner.png">
|
| 27 |
<meta property="og:site_name" content="Aeterna AI">
|
| 28 |
<meta property="og:locale" content="id_ID">
|
|
|
|
| 31 |
<meta name="twitter:card" content="summary_large_image">
|
| 32 |
<meta name="twitter:url" content="https://www.aeternaai.biz.id/">
|
| 33 |
<meta name="twitter:title" content="Aeterna AI by Faril Putra Pratama - #1 Waste Intelligence Platform DKI Jakarta">
|
| 34 |
+
<meta name="twitter:description" content="Sistem AI peramalan sampah & armada logistik 44 Kecamatan DKI Jakarta dikembangkan oleh Faril Putra Pratama.">
|
|
|
|
| 35 |
<meta name="twitter:image" content="https://www.aeternaai.biz.id/static/assets/og_banner.png">
|
| 36 |
|
| 37 |
<!-- GEO Meta Citations for LLMs (ChatGPT, Gemini, Claude, Perplexity) -->
|
| 38 |
+
<meta name="citation_title" content="Aeterna AI: Spatial-Temporal Waste Generation Forecasting Across 44 Kecamatans in DKI Jakarta">
|
|
|
|
| 39 |
<meta name="citation_author" content="Faril Putra Pratama (@FARILtau72)">
|
| 40 |
<meta name="citation_publication_date" content="2026">
|
| 41 |
+
<meta name="citation_technical_report_institution" content="Aeterna AI Labs & Faril Putra Pratama Official Portal (aeternaai.biz.id)">
|
|
|
|
| 42 |
|
| 43 |
<!-- Geo-Location Meta Tags for Regional Indonesian Search Priority -->
|
| 44 |
<meta name="geo.region" content="ID-JK" />
|
|
|
|
| 52 |
<!-- Google Fonts -->
|
| 53 |
<link rel="preconnect" href="https://fonts.googleapis.com">
|
| 54 |
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
| 55 |
+
<link href="https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;600;800&family=Space+Grotesk:wght@300;400;500;600;700&family=JetBrains+Mono:wght@300;400;700&display=swap" rel="stylesheet">
|
| 56 |
+
|
|
|
|
|
|
|
| 57 |
<!-- Leaflet.js Map Library -->
|
| 58 |
+
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY=" crossorigin="" />
|
| 59 |
+
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js" integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo=" crossorigin=""></script>
|
|
|
|
|
|
|
| 60 |
|
| 61 |
<!-- Three.js 3D Library -->
|
| 62 |
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
|
|
|
|
| 116 |
}
|
| 117 |
</script>
|
| 118 |
</head>
|
|
|
|
| 119 |
<body>
|
| 120 |
<!-- Background Canvas for Interactive Particle Rain -->
|
| 121 |
<canvas id="rain-canvas"></canvas>
|
|
|
|
| 129 |
<nav class="nav-links">
|
| 130 |
<button class="nav-btn active" data-target="page-home" onclick="switchPage('page-home')">HOME</button>
|
| 131 |
<button class="nav-btn" data-target="page-autopilot" onclick="switchPage('page-autopilot')">AI AUTOPILOT</button>
|
| 132 |
+
<button class="nav-btn" data-target="page-predictor" onclick="switchPage('page-predictor')">SIMULATION TOOL</button>
|
| 133 |
<button class="nav-btn" data-target="page-news" onclick="switchPage('page-news')">NEWS FEED</button>
|
| 134 |
<button class="nav-btn" data-target="page-alerts" onclick="switchPage('page-alerts')">REGIONAL ALERTS</button>
|
| 135 |
<button class="nav-btn" data-target="page-education" onclick="switchPage('page-education')">WASTE EDUCATION</button>
|
|
|
|
| 145 |
<section class="hero-section">
|
| 146 |
<div class="hero-content">
|
| 147 |
<h1 class="hero-title">NEXT-GEN WASTE FORECASTING</h1>
|
| 148 |
+
<p class="hero-subtitle">Meningkatkan efisiensi tata kelola sampah DKI Jakarta hingga 98.28% dengan pemodelan spasial temporal real-time.</p>
|
|
|
|
| 149 |
<div class="hero-actions">
|
| 150 |
<button class="action-btn" onclick="switchPage('page-autopilot')">
|
| 151 |
<span class="btn-text">OPEN AUTOPILOT</span>
|
|
|
|
| 179 |
<div class="panel feature-card">
|
| 180 |
<div class="feature-icon font-display">01</div>
|
| 181 |
<h3 class="feature-name">Akurasi Validitas Tinggi (98.28%)</h3>
|
| 182 |
+
<p class="feature-desc">Menggunakan arsitektur model Gradient Boosting Regressor (GBR) yang dioptimasi via GridSearchCV dengan metrik komparasi MAE, RMSE, dan MAPE secara berdampingan.</p>
|
|
|
|
| 183 |
</div>
|
| 184 |
<div class="panel feature-card">
|
| 185 |
<div class="feature-icon font-display">02</div>
|
| 186 |
<h3 class="feature-name">Integrasi Live Cuaca Open-Meteo</h3>
|
| 187 |
+
<p class="feature-desc">API dinamis asinkron yang menarik data curah hujan live tingkat kecamatan secara real-time untuk memprediksi tonase sampah basah akibat rembesan air hujan.</p>
|
|
|
|
| 188 |
</div>
|
| 189 |
<div class="panel feature-card">
|
| 190 |
<div class="feature-icon font-display">03</div>
|
| 191 |
<h3 class="feature-name">Pemantauan Berita Sampah 1 Jam</h3>
|
| 192 |
+
<p class="feature-desc">AI Scheduler internal merayap internet secara berkala tiap 1 jam untuk menangkap isu operasional, pembatasan Bantargebang, dan regulasi persampahan DKI Jakarta.</p>
|
|
|
|
| 193 |
</div>
|
| 194 |
<div class="panel feature-card">
|
| 195 |
<div class="feature-icon font-display">04</div>
|
| 196 |
<h3 class="feature-name">Kalibrasi Spasial 44 Kecamatan</h3>
|
| 197 |
+
<p class="feature-desc">Model peramalan dikalibrasi hulu-hilir menggunakan data primer Dinas Lingkungan Hidup DKI Jakarta, mencakup tonase baseline spesifik tiap kecamatan secara akuntabel.</p>
|
|
|
|
|
|
|
| 198 |
</div>
|
| 199 |
</div>
|
| 200 |
</section>
|
| 201 |
|
| 202 |
<!-- Cinematic Waste Crisis Scroll Section -->
|
| 203 |
+
<section class="container crisis-story-section" style="margin-top: 4rem; display: grid; grid-template-columns: 1.2fr 0.8fr; gap: 3rem; position: relative;">
|
| 204 |
+
|
|
|
|
| 205 |
<!-- Sticky Left Panel (Waste Tower Visualizer) -->
|
| 206 |
+
<div class="sticky-visualizer-panel" style="position: sticky; top: 120px; height: 450px; display: flex; flex-direction: column; justify-content: center; align-items: center; background: var(--bg-panel); border: 1px solid var(--border-color); border-radius: 16px; padding: 2rem; overflow: hidden; box-shadow: 0 10px 30px rgba(0, 0, 0, 0.04);">
|
| 207 |
+
<h3 style="font-family: var(--font-display); font-size: 1.1rem; color: var(--text-main); margin-bottom: 1.5rem; letter-spacing: 1px; text-transform: uppercase;">JAKARTA DAILY ACCUMULATION TOWER</h3>
|
| 208 |
+
|
|
|
|
|
|
|
|
|
|
| 209 |
<!-- The 3D Three.js Container -->
|
| 210 |
+
<div id="threejs-waste-container" style="width: 220px; height: 280px; position: relative; display: flex; justify-content: center; align-items: center; background: rgba(0,0,0,0.01); border-radius: 12px; border: 1px solid var(--border-color); overflow: hidden;">
|
|
|
|
| 211 |
<!-- Static Overlay height labels inside 3D scene -->
|
| 212 |
+
<div style="position: absolute; right: 12px; top: 12px; font-family: var(--font-mono); font-size: 9px; color: var(--text-muted); opacity: 0.6; z-index: 2; pointer-events: none;">CRITICAL</div>
|
| 213 |
+
<div style="position: absolute; right: 12px; top: 50%; transform: translateY(-50%); font-family: var(--font-mono); font-size: 9px; color: var(--text-muted); opacity: 0.6; z-index: 2; pointer-events: none;">WARNING</div>
|
| 214 |
+
<div style="position: absolute; right: 12px; bottom: 12px; font-family: var(--font-mono); font-size: 9px; color: var(--text-muted); opacity: 0.6; z-index: 2; pointer-events: none;">NORMAL</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 215 |
</div>
|
| 216 |
+
|
| 217 |
<!-- Live Ticking Indicator -->
|
| 218 |
<div class="tower-status" style="margin-top: 1.5rem; text-align: center;">
|
| 219 |
+
<div style="font-family: var(--font-mono); font-size: 0.8rem; color: var(--text-muted); text-transform: uppercase;">Simulated Tonnage</div>
|
| 220 |
+
<div style="font-family: var(--font-mono); font-size: 1.8rem; color: var(--yellow); font-weight: bold;" id="simulated-tons-val">0 Tons</div>
|
|
|
|
|
|
|
|
|
|
| 221 |
</div>
|
| 222 |
</div>
|
| 223 |
|
| 224 |
<!-- Scrolling Narrative Cards -->
|
| 225 |
+
<div class="story-scroll-cards" style="display: flex; flex-direction: column; gap: 6rem; padding-bottom: 8rem;">
|
| 226 |
+
|
|
|
|
| 227 |
<!-- Card 1 -->
|
| 228 |
+
<div class="story-card panel" data-height="25" data-tons="2264" style="padding: 2.2rem; min-height: 250px; display: flex; flex-direction: column; justify-content: center; transition: all 0.3s; border:1px solid var(--border-color); border-radius:12px;">
|
| 229 |
+
<span style="font-family: var(--font-mono); font-size: 0.75rem; color: var(--green); letter-spacing: 2px; text-transform: uppercase; margin-bottom: 0.5rem; display: block;">STAGE 01: MORNING LOADS (09:00 AM)</span>
|
| 230 |
+
<h3 style="font-family: var(--font-display); font-size: 1.3rem; color: var(--text-main); margin-bottom: 0.8rem;">2,264 TON SAMPAH TERKUMPUL</h3>
|
| 231 |
+
<p style="font-size: 0.9rem; color: var(--text-muted); line-height: 1.6;">Memasuki jam kerja awal, tumpukan sampah dari pasar tradisional dan wilayah residensial se-DKI Jakarta mulai berdatangan di TPS. Kecepatan pengangkutan sangat krusial agar TPS lokal tidak mengalami kelumpuhan penumpukan.</p>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 232 |
</div>
|
| 233 |
|
| 234 |
<!-- Card 2 -->
|
| 235 |
+
<div class="story-card panel" data-height="55" data-tons="4982" style="padding: 2.2rem; min-height: 250px; display: flex; flex-direction: column; justify-content: center; transition: all 0.3s; border:1px solid var(--border-color); border-radius:12px;">
|
| 236 |
+
<span style="font-family: var(--font-mono); font-size: 0.75rem; color: var(--green); letter-spacing: 2px; text-transform: uppercase; margin-bottom: 0.5rem; display: block;">STAGE 02: MID-DAY PEAK (03:00 PM)</span>
|
| 237 |
+
<h3 style="font-family: var(--font-display); font-size: 1.3rem; color: var(--text-main); margin-bottom: 0.8rem;">4,982 TON SAMPAH TERKUMPUL</h3>
|
| 238 |
+
<p style="font-size: 0.9rem; color: var(--text-muted); line-height: 1.6;">Di siang hari, aktivitas logistik pengiriman sampah ke TPST Bantargebang memuncak. Kepadatan lalu lintas jalan tol Jakarta-Bekasi dan antrean panjang truk di gerbang timbang Bantargebang mulai memicu bottleneck operasional pengangkutan.</p>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 239 |
</div>
|
| 240 |
|
| 241 |
<!-- Card 3 -->
|
| 242 |
+
<div class="story-card panel" data-height="95" data-tons="9059" style="padding: 2.2rem; min-height: 250px; display: flex; flex-direction: column; justify-content: center; transition: all 0.3s; border:1px solid var(--border-color); border-radius:12px;">
|
| 243 |
+
<span style="font-family: var(--font-mono); font-size: 0.75rem; color: var(--red); letter-spacing: 2px; text-transform: uppercase; margin-bottom: 0.5rem; display: block;">STAGE 03: EOD OVERLOAD (11:59 PM)</span>
|
| 244 |
+
<h3 style="font-family: var(--font-display); font-size: 1.3rem; color: var(--text-main); margin-bottom: 0.8rem;">9,059 TON SAMPAH HARIAN</h3>
|
| 245 |
+
<p style="font-size: 0.9rem; color: var(--text-muted); line-height: 1.6;">Sebelum hari berakhir, total timbulan sampah DKI mencapai kapasitas maksimalnya. TPST Bantargebang yang kini melebihi daya tampung aman (ketinggian gunungan sampah di atas 50 meter) berada pada status siaga kritis. Di sinilah Aeterna AI memitigasi krisis tersebut dengan analisis logistik prediktif.</p>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 246 |
</div>
|
| 247 |
|
| 248 |
</div>
|
|
|
|
| 252 |
<section class="container data-sources-section">
|
| 253 |
<h2 class="section-title">TRANSPARANSI SUMBER DATA</h2>
|
| 254 |
<div class="panel sources-panel">
|
| 255 |
+
<div class="sources-grid" style="display:grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap:1.5rem;">
|
|
|
|
| 256 |
<div class="source-item">
|
| 257 |
+
<h4 style="color:var(--cyan); margin-bottom:0.5rem; font-family:var(--font-display);">1. Timbulan Sampah</h4>
|
| 258 |
+
<p style="font-size:0.85rem; color:var(--text-muted); line-height:1.5;">Data baseline disesuaikan dengan volume total ~9.059 Ton/hari dari <strong>Dinas Lingkungan Hidup (DLH) DKI Jakarta</strong> dan SIPSN Kementerian LHK.</p>
|
|
|
|
|
|
|
|
|
|
| 259 |
</div>
|
| 260 |
<div class="source-item">
|
| 261 |
+
<h4 style="color:var(--cyan); margin-bottom:0.5rem; font-family:var(--font-display);">2. Prediksi Cuaca</h4>
|
| 262 |
+
<p style="font-size:0.85rem; color:var(--text-muted); line-height:1.5;">Data curah hujan ditarik live menggunakan <strong>Open-Meteo API</strong> berdasarkan koordinat geografis presisi masing-masing kecamatan.</p>
|
|
|
|
|
|
|
|
|
|
| 263 |
</div>
|
| 264 |
<div class="source-item">
|
| 265 |
+
<h4 style="color:var(--cyan); margin-bottom:0.5rem; font-family:var(--font-display);">3. Kalender Event & Transit</h4>
|
| 266 |
+
<p style="font-size:0.85rem; color:var(--text-muted); line-height:1.5;">Pola mobilitas disimulasikan dari ridership harian <strong>MRT Jakarta</strong> (~85.000) dan kalender acara Jakarta untuk mengukur lonjakan kerumunan.</p>
|
|
|
|
|
|
|
|
|
|
| 267 |
</div>
|
| 268 |
<div class="source-item">
|
| 269 |
+
<h4 style="color:var(--cyan); margin-bottom:0.5rem; font-family:var(--font-display);">4. Jarak Pengangkutan</h4>
|
| 270 |
+
<p style="font-size:0.85rem; color:var(--text-muted); line-height:1.5;">Jarak tempuh dihitung menggunakan <strong>Haversine Formula</strong> dari koordinat kecamatan ke TPST Bantargebang dengan faktor jalan winding 1.35x.</p>
|
|
|
|
|
|
|
|
|
|
| 271 |
</div>
|
| 272 |
</div>
|
| 273 |
</div>
|
| 274 |
</section>
|
| 275 |
|
| 276 |
+
<!-- Development Author Section -->
|
| 277 |
+
<section class="container developers-section">
|
| 278 |
+
<h2 class="section-title">AETERNA AI LEAD DEVELOPER</h2>
|
| 279 |
+
<div class="developers-grid" style="display: flex; justify-content: center;">
|
| 280 |
+
<div class="panel developer-card" style="max-width: 600px; width: 100%;">
|
| 281 |
+
<div class="dev-role">Lead Full-Stack AI Engineer</div>
|
| 282 |
+
<h3 class="dev-name">FARIL PUTRA PRATAMA</h3>
|
| 283 |
+
<p class="dev-desc">Merancang dan membangun seluruh arsitektur Aeterna AI dari ujung ke ujung. Meliputi riset data, pelatihan model cerdas GBR & GridSearchCV, pembuatan arsitektur micro-service asinkron, hingga visualisasi antarmuka HUD Glassmorphism interaktif Next.js.</p>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 284 |
</div>
|
| 285 |
</div>
|
| 286 |
</section>
|
|
|
|
| 290 |
<div id="page-autopilot" class="page-container">
|
| 291 |
<section class="container page-header-section">
|
| 292 |
<h2 class="section-title">AETERNA AI AUTOPILOT FORECASTER</h2>
|
| 293 |
+
<p class="section-subtitle">Sistem peramalan otonom DKI Jakarta. AI berjalan mandiri memprediksi volume harian dan mengoordinasikan logistik tanpa campur tangan pengguna.</p>
|
|
|
|
| 294 |
</section>
|
| 295 |
|
| 296 |
<!-- Live Metrics Summary -->
|
| 297 |
+
<section class="container autopilot-grid" style="display:grid; grid-template-columns: 1.2fr 0.8fr; gap:1.5rem; margin-top:1.5rem;">
|
|
|
|
| 298 |
<!-- Panel Ringkasan Otonom -->
|
| 299 |
<div class="panel autopilot-summary-panel">
|
| 300 |
<h3 class="panel-title">LIVE CITY-WIDE FORECAST (TODAY)</h3>
|
| 301 |
+
<div class="stats-row" style="display:grid; grid-template-columns: 1fr 1fr; gap:1rem; margin-bottom:1.5rem; width:100%;">
|
| 302 |
+
<div class="panel stat-card text-glow" style="background: rgba(0, 0, 0, 0.02); display:flex; flex-direction:column; padding:1.2rem; border-radius:8px;">
|
|
|
|
|
|
|
| 303 |
<span class="card-label">TOTAL DKI JAKARTA VOLUME</span>
|
| 304 |
+
<span id="auto-total-volume" class="card-value" style="font-size:1.8rem; font-weight:800; color:var(--cyan);">Calculating...</span>
|
|
|
|
| 305 |
<span class="card-meta">Autonomous prediction summation</span>
|
| 306 |
</div>
|
| 307 |
+
<div class="panel stat-card" style="background: rgba(0, 0, 0, 0.02); display:flex; flex-direction:column; padding:1.2rem; border-radius:8px;">
|
|
|
|
| 308 |
<span class="card-label">TOTAL DISPATCHED TRUCKS</span>
|
| 309 |
+
<span id="auto-total-trucks" class="card-value" style="font-size:1.8rem; font-weight:800; color:var(--text-main);">Calculating...</span>
|
|
|
|
| 310 |
<span class="card-meta">Fleet size for all 44 kecamatan</span>
|
| 311 |
</div>
|
| 312 |
</div>
|
| 313 |
+
|
| 314 |
+
<h4 style="color:var(--cyan); margin-bottom:0.8rem; font-family:var(--font-display); font-size:0.95rem; border-left:3px solid var(--cyan); padding-left:8px; text-transform:uppercase;">Top 5 High-Risk Kecamatan Today:</h4>
|
| 315 |
+
<div id="auto-risk-list" class="auto-risk-list" style="display:flex; flex-direction:column; gap:0.8rem;">
|
|
|
|
|
|
|
|
|
|
| 316 |
<!-- Dynamically populated Top 5 -->
|
| 317 |
</div>
|
| 318 |
</div>
|
|
|
|
| 320 |
<!-- Konsol Berpikir AI -->
|
| 321 |
<div class="panel autopilot-console-panel" style="display:flex; flex-direction:column; height:100%;">
|
| 322 |
<h3 class="panel-title">AI THINKING CONSOLE</h3>
|
| 323 |
+
<div id="autopilot-log" style="flex:1; background:#0B1310; border:1px solid var(--border-color); border-radius:8px; padding:1.2rem; font-family:var(--font-mono); font-size:0.8rem; color:#22C55E; overflow-y:auto; min-height:260px; line-height:1.6; box-shadow:inset 0 0 10px rgba(0,0,0,0.5);">
|
|
|
|
| 324 |
<!-- Dynamic logs -->
|
| 325 |
</div>
|
| 326 |
</div>
|
| 327 |
</section>
|
| 328 |
</div>
|
| 329 |
|
| 330 |
+
<!-- PREDICTOR PAGE -->
|
| 331 |
<div id="page-predictor" class="page-container">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 332 |
<main class="dashboard-grid">
|
| 333 |
<!-- Panel Kontrol (Sidebar) -->
|
| 334 |
<section class="panel control-panel">
|
|
|
|
| 343 |
<div class="control-group">
|
| 344 |
<label for="model-select">AI Forecasting Model</label>
|
| 345 |
<select id="model-select" class="form-control">
|
| 346 |
+
<option value="gradient_boosting" selected>Stacking Regressor Ensemble (Real Data - 96.41% Acc)</option>
|
|
|
|
| 347 |
<option value="chronos">Amazon Chronos-T5 (Tiny)</option>
|
| 348 |
</select>
|
| 349 |
</div>
|
| 350 |
|
| 351 |
<div class="control-group">
|
| 352 |
+
<label for="forecast-slider">Forecast Horizon: <span id="forecast-val" class="value-display">7</span> Days</label>
|
|
|
|
| 353 |
<input type="range" id="forecast-slider" min="1" max="30" value="7" class="slider">
|
| 354 |
</div>
|
| 355 |
|
|
|
|
| 365 |
</div>
|
| 366 |
|
| 367 |
<div class="control-group">
|
| 368 |
+
<label for="event-override">Simulasi Populasi <span id="event-override-val" class="override-display">Auto (BPS Baseline)</span></label>
|
| 369 |
+
<input type="range" id="event-override" min="10000" max="700000" step="5000" value="88000" class="slider">
|
|
|
|
|
|
|
| 370 |
</div>
|
| 371 |
|
| 372 |
<div class="button-row">
|
|
|
|
| 415 |
<section class="analysis-panel">
|
| 416 |
<div class="panel category-panel">
|
| 417 |
<h2 class="panel-title">WASTE COMPOSITION BREAKDOWN</h2>
|
| 418 |
+
<div class="progress-container" style="display: grid; grid-template-columns: 1fr 1fr; gap: 1rem 1.5rem;">
|
|
|
|
| 419 |
<div class="progress-item" style="margin-bottom: 0;">
|
| 420 |
<div class="progress-header">
|
| 421 |
<span>Organic / Sisa Makanan (~50.2%)</span>
|
|
|
|
| 490 |
<span class="event-title">Upcoming Event Calendar</span>
|
| 491 |
<p class="event-desc" id="event-desc-text">No major events registered for today.</p>
|
| 492 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
| 493 |
</div>
|
| 494 |
|
| 495 |
<!-- Logistics Plan -->
|
|
|
|
| 517 |
</section>
|
| 518 |
</main>
|
| 519 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 520 |
<!-- Timeline Harian -->
|
| 521 |
<section class="container timeline-container">
|
| 522 |
<div class="panel timeline-panel">
|
|
|
|
| 540 |
<!-- Developer Bio Card -->
|
| 541 |
<section class="container developer-container" style="margin-top: 2rem; margin-bottom: 2.5rem;">
|
| 542 |
<div class="panel developer-panel" style="text-align: center; padding: 2.2rem;">
|
| 543 |
+
<h3 style="font-family: var(--font-display); font-size: 1.3rem; font-weight: 700; color: var(--text-main); letter-spacing: 1.5px; margin-bottom: 0.8rem; text-transform: uppercase;">FARIL PUTRA PRATAMA</h3>
|
| 544 |
+
<p style="color: var(--text-muted); font-size: 0.92rem; line-height: 1.6; max-width: 780px; margin: 0 auto 1.5rem auto; font-family: var(--font-body);">
|
| 545 |
+
Merancang dan membangun seluruh arsitektur Aeterna AI dari ujung ke ujung. Meliputi riset data, pelatihan model cerdas GBR & GridSearchCV, pembuatan arsitektur micro-service asinkron, hingga visualisasi antarmuka HUD Glassmorphism interaktif.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 546 |
</p>
|
| 547 |
<div style="display: flex; gap: 12px; justify-content: center; align-items: center; flex-wrap: wrap;">
|
| 548 |
+
<a href="https://github.com/FARILtau72/Aeterna-Ai" target="_blank" rel="noopener noreferrer" class="action-btn" style="display: inline-flex; align-items: center; gap: 8px; text-decoration: none; padding: 10px 22px;">
|
| 549 |
+
<svg width="16" height="16" fill="currentColor" viewBox="0 0 24 24"><path d="M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0024 12c0-6.63-5.37-12-12-12z"/></svg>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 550 |
GitHub
|
| 551 |
</a>
|
| 552 |
+
<a href="https://www.linkedin.com/in/faril-putra-pratama-81561a280/" target="_blank" rel="noopener noreferrer" class="action-btn secondary-btn" style="display: inline-flex; align-items: center; gap: 8px; text-decoration: none; padding: 10px 22px;">
|
| 553 |
+
<svg width="16" height="16" fill="currentColor" viewBox="0 0 24 24"><path d="M19 0h-14c-2.761 0-5 2.239-5 5v14c0 2.761 2.239 5 5 5h14c2.762 0 5-2.239 5-5v-14c0-2.761-2.762-5-5-5zm-11 19h-3v-11h3v11zm-1.5-12.268c-.966 0-1.75-.79-1.75-1.764s.784-1.764 1.75-1.764 1.75.79 1.75 1.764-.783 1.764-1.75 1.764zm13.5 12.268h-3v-5.604c0-3.368-4-3.113-4 0v5.604h-3v-11h3v1.765c1.396-2.586 7-2.777 7 2.476v6.759z"/></svg>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 554 |
LinkedIn
|
| 555 |
</a>
|
| 556 |
</div>
|
|
|
|
| 562 |
<div id="page-news" class="page-container">
|
| 563 |
<section class="container page-header-section">
|
| 564 |
<h2 class="section-title">MONITORING BERITA PERSAMPAHAN JAKARTA</h2>
|
| 565 |
+
<p class="section-subtitle">AI merayap berita terbaru seputar isu darurat sampah, operasional TPA Bantargebang, dan kebijakan DLH Jakarta secara otomatis setiap 1 jam.</p>
|
|
|
|
| 566 |
</section>
|
| 567 |
|
| 568 |
<section class="container news-feed-container">
|
|
|
|
| 577 |
<div id="page-alerts" class="page-container">
|
| 578 |
<section class="container page-header-section">
|
| 579 |
<h2 class="section-title">REGIONAL HAZARD & ALERTS MAP</h2>
|
| 580 |
+
<p class="section-subtitle">Daftar wilayah kecamatan dengan prakiraan volume timbulan sampah melebihi ambang batas operasional harian.</p>
|
|
|
|
| 581 |
</section>
|
| 582 |
|
| 583 |
<section class="container alerts-feed-container">
|
|
|
|
| 595 |
<div id="page-education" class="page-container">
|
| 596 |
<section class="container page-header-section">
|
| 597 |
<h2 class="section-title">WASTE EDUCATION HUB</h2>
|
| 598 |
+
<p class="section-subtitle">Pelajari dampak penumpukan sampah di DKI Jakarta, durasi dekomposisi material, dan uji ketangkasan pilah sampah Anda secara interaktif.</p>
|
|
|
|
| 599 |
</section>
|
| 600 |
|
| 601 |
<!-- Interactive simulator & info panels -->
|
| 602 |
+
<section class="container education-grid" style="display:grid; grid-template-columns: 1.2fr 0.8fr; gap:1.5rem; margin-top:1.5rem;">
|
|
|
|
| 603 |
<!-- Game Pilah Sampah (Eco-Sorter) -->
|
| 604 |
+
<div class="panel game-panel" style="display:flex; flex-direction:column; padding:2rem; position:relative; overflow:hidden;">
|
| 605 |
+
<div class="panel-badge" style="position:absolute; top:1rem; right:1.5rem; background:rgba(0, 240, 255, 0.1); border:1px solid var(--cyan); color:var(--cyan); border-radius:12px; padding:3px 8px; font-size:0.75rem; font-family:var(--font-mono);">INTERACTIVE GAME</div>
|
|
|
|
|
|
|
|
|
|
| 606 |
<h3 class="panel-title" style="margin-bottom:0.5rem;">ECO-SORTER SIMULATOR</h3>
|
| 607 |
+
<p style="font-size:0.85rem; color:var(--text-muted); margin-bottom:1.5rem;">Pilah item sampah ke tempat sampah yang benar untuk mendapatkan skor dan mempelajari fakta daur ulang!</p>
|
| 608 |
+
|
|
|
|
| 609 |
<!-- Waste Item Card -->
|
| 610 |
+
<div class="game-area" style="display:flex; flex-direction:column; align-items:center; background:rgba(0,0,0,0.4); border:1px solid var(--border-color); border-radius:12px; padding:2.5rem; margin-bottom:1.5rem; text-align:center;">
|
| 611 |
+
<div id="game-item-icon" style="font-size:4rem; margin-bottom:1rem; filter:drop-shadow(0 0 10px rgba(255,255,255,0.2)); transition:transform 0.3s;">🍼</div>
|
| 612 |
+
<h4 id="game-item-name" style="font-family:var(--font-display); font-size:1.3rem; color:#FFF; margin-bottom:0.5rem;">Botol Plastik Bekas</h4>
|
| 613 |
+
<p id="game-item-desc" style="font-size:0.85rem; color:var(--text-muted); max-width:300px; min-height:40px;">Botol air mineral kosong berbahan PET.</p>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 614 |
</div>
|
| 615 |
+
|
| 616 |
<!-- Target Bins -->
|
| 617 |
<div class="bin-grid" style="display:grid; grid-template-columns: repeat(3, 1fr); gap:1rem;">
|
| 618 |
+
<button class="bin-btn organic-bin" onclick="sortWaste('organic')" style="background:rgba(74, 222, 128, 0.05); border:1px solid #4ade80; color:#4ade80; padding:1rem; border-radius:8px; font-family:var(--font-display); font-weight:bold; cursor:pointer; transition:all 0.2s; outline:none;">ORGANIK</button>
|
| 619 |
+
<button class="bin-btn inorganic-bin" onclick="sortWaste('inorganic')" style="background:rgba(56, 189, 248, 0.05); border:1px solid #38bdf8; color:#38bdf8; padding:1rem; border-radius:8px; font-family:var(--font-display); font-weight:bold; cursor:pointer; transition:all 0.2s; outline:none;">ANORGANIK</button>
|
| 620 |
+
<button class="bin-btn hazard-bin" onclick="sortWaste('hazardous')" style="background:rgba(251, 113, 133, 0.05); border:1px solid #fb7185; color:#fb7185; padding:1rem; border-radius:8px; font-family:var(--font-display); font-weight:bold; cursor:pointer; transition:all 0.2s; outline:none;">BAHAYA (B3)</button>
|
|
|
|
|
|
|
|
|
|
|
|
|
| 621 |
</div>
|
| 622 |
+
|
| 623 |
<!-- Game Stats -->
|
| 624 |
+
<div class="game-stats" style="display:flex; justify-content:space-between; align-items:center; margin-top:1.5rem; font-family:var(--font-mono); font-size:0.9rem; padding:0.8rem; background:rgba(255,255,255,0.02); border-radius:6px; border:1px solid rgba(255,255,255,0.05);">
|
|
|
|
| 625 |
<span>Skor: <strong id="game-score" style="color:var(--cyan); font-size:1.1rem;">0</strong></span>
|
| 626 |
<span id="game-feedback" style="color:var(--text-muted); font-weight:bold;">Ayo mulai pilah!</span>
|
| 627 |
</div>
|
|
|
|
| 630 |
<!-- Fakta Dekomposisi Sampah -->
|
| 631 |
<div class="panel facts-panel" style="display:flex; flex-direction:column; padding:2rem;">
|
| 632 |
<h3 class="panel-title" style="margin-bottom:1rem;">DURASI DEKOMPOSISI ALAM</h3>
|
| 633 |
+
<p style="font-size:0.85rem; color:var(--text-muted); margin-bottom:1.5rem;">Berapa lama alam membutuhkan waktu untuk mengurai barang-barang yang kita buang?</p>
|
| 634 |
+
|
| 635 |
+
<div class="facts-list" style="display:flex; flex-direction:column; gap:1.2rem; flex:1; justify-content:center;">
|
|
|
|
|
|
|
| 636 |
<div class="fact-item" style="display:flex; align-items:center; gap:1rem;">
|
| 637 |
+
<span style="font-size:2rem; background:rgba(255,255,255,0.05); width:50px; height:50px; border-radius:50%; display:flex; align-items:center; justify-content:center;">🍎</span>
|
|
|
|
| 638 |
<div style="flex:1;">
|
| 639 |
<h4 style="font-size:0.9rem; color:#FFF; margin-bottom:2px;">Sisa Makanan / Organik</h4>
|
| 640 |
+
<div class="progress-bar-bg" style="height:6px; margin:4px 0;"><div class="progress-bar-fill organic" style="width: 5%;"></div></div>
|
| 641 |
+
<span style="font-size:0.75rem; color:#4ade80; font-family:var(--font-mono);">1 - 2 Minggu</span>
|
|
|
|
|
|
|
|
|
|
| 642 |
</div>
|
| 643 |
</div>
|
| 644 |
<div class="fact-item" style="display:flex; align-items:center; gap:1rem;">
|
| 645 |
+
<span style="font-size:2rem; background:rgba(255,255,255,0.05); width:50px; height:50px; border-radius:50%; display:flex; align-items:center; justify-content:center;">📦</span>
|
|
|
|
| 646 |
<div style="flex:1;">
|
| 647 |
<h4 style="font-size:0.9rem; color:#FFF; margin-bottom:2px;">Kertas & Kardus</h4>
|
| 648 |
+
<div class="progress-bar-bg" style="height:6px; margin:4px 0;"><div class="progress-bar-fill plastic" style="width: 15%;"></div></div>
|
| 649 |
+
<span style="font-size:0.75rem; color:#38bdf8; font-family:var(--font-mono);">2 - 6 Minggu</span>
|
|
|
|
|
|
|
|
|
|
| 650 |
</div>
|
| 651 |
</div>
|
| 652 |
<div class="fact-item" style="display:flex; align-items:center; gap:1rem;">
|
| 653 |
+
<span style="font-size:2rem; background:rgba(255,255,255,0.05); width:50px; height:50px; border-radius:50%; display:flex; align-items:center; justify-content:center;">🍼</span>
|
|
|
|
| 654 |
<div style="flex:1;">
|
| 655 |
<h4 style="font-size:0.9rem; color:#FFF; margin-bottom:2px;">Botol Plastik PET</h4>
|
| 656 |
+
<div class="progress-bar-bg" style="height:6px; margin:4px 0;"><div class="progress-bar-fill other" style="width: 70%; background:#fb923c !important;"></div></div>
|
| 657 |
+
<span style="font-size:0.75rem; color:#fb923c; font-family:var(--font-mono);">450 Tahun</span>
|
|
|
|
|
|
|
|
|
|
|
|
|
| 658 |
</div>
|
| 659 |
</div>
|
| 660 |
<div class="fact-item" style="display:flex; align-items:center; gap:1rem;">
|
| 661 |
+
<span style="font-size:2rem; background:rgba(255,255,255,0.05); width:50px; height:50px; border-radius:50%; display:flex; align-items:center; justify-content:center;">🔋</span>
|
|
|
|
| 662 |
<div style="flex:1;">
|
| 663 |
<h4 style="font-size:0.9rem; color:#FFF; margin-bottom:2px;">Baterai & Logam</h4>
|
| 664 |
+
<div class="progress-bar-bg" style="height:6px; margin:4px 0;"><div class="progress-bar-fill critical" style="width: 85%;"></div></div>
|
| 665 |
+
<span style="font-size:0.75rem; color:#fb7185; font-family:var(--font-mono);">100 Tahun (Logam) / Berabad-abad (Kimia B3)</span>
|
|
|
|
|
|
|
|
|
|
| 666 |
</div>
|
| 667 |
</div>
|
| 668 |
<div class="fact-item" style="display:flex; align-items:center; gap:1rem;">
|
| 669 |
+
<span style="font-size:2rem; background:rgba(255,255,255,0.05); width:50px; height:50px; border-radius:50%; display:flex; align-items:center; justify-content:center;">🫙</span>
|
|
|
|
| 670 |
<div style="flex:1;">
|
| 671 |
<h4 style="font-size:0.9rem; color:#FFF; margin-bottom:2px;">Botol Kaca</h4>
|
| 672 |
+
<div class="progress-bar-bg" style="height:6px; margin:4px 0;"><div class="progress-bar-fill critical" style="width: 100%; background:#e879f9 !important;"></div></div>
|
| 673 |
+
<span style="font-size:0.75rem; color:#e879f9; font-family:var(--font-mono);">1 Juta Tahun / Tidak Hancur</span>
|
|
|
|
|
|
|
|
|
|
|
|
|
| 674 |
</div>
|
| 675 |
</div>
|
| 676 |
</div>
|
|
|
|
| 678 |
</section>
|
| 679 |
</div>
|
| 680 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 681 |
<footer>
|
| 682 |
+
<p>© 2026 Aeterna AI — Developed & Engineered with ⚡ by <span style="color:var(--cyan); font-weight:bold;">Faril Putra Pratama</span>.</p>
|
| 683 |
+
<p style="margin-top: 0.6rem; font-size: 0.75rem; opacity: 0.85; letter-spacing: 0.5px; font-family: var(--font-mono); line-height: 1.5;">Official Portal: <a href="https://www.aeternaai.biz.id/" style="color:#00f2fe; text-decoration:none;">aeternaai.biz.id</a> | #1 AI Waste Intelligence Platform for 44 Kecamatans in DKI Jakarta.</p>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 684 |
</footer>
|
| 685 |
|
| 686 |
<!-- Custom Cyber HUD Cursor -->
|
|
|
|
| 690 |
<!-- Scripts -->
|
| 691 |
<script src="/static/app.js"></script>
|
| 692 |
</body>
|
| 693 |
+
</html>
|
|
|
frontend/style.css
CHANGED
|
@@ -130,7 +130,7 @@ header {
|
|
| 130 |
display: grid;
|
| 131 |
grid-template-columns: 320px 1fr 340px;
|
| 132 |
gap: 1.5rem;
|
| 133 |
-
padding: 1.
|
| 134 |
flex: 1;
|
| 135 |
z-index: 5;
|
| 136 |
position: relative;
|
|
@@ -656,7 +656,7 @@ header {
|
|
| 656 |
/* Timeline Container */
|
| 657 |
.timeline-container {
|
| 658 |
margin-top: 1.5rem;
|
| 659 |
-
padding: 0;
|
| 660 |
z-index: 5;
|
| 661 |
position: relative;
|
| 662 |
}
|
|
@@ -725,7 +725,7 @@ header {
|
|
| 725 |
/* Hourly Breakdown Container */
|
| 726 |
.hourly-container {
|
| 727 |
margin-top: 1.5rem;
|
| 728 |
-
padding: 0;
|
| 729 |
z-index: 5;
|
| 730 |
position: relative;
|
| 731 |
margin-bottom: 2rem;
|
|
@@ -1606,824 +1606,5 @@ body::after {
|
|
| 1606 |
}
|
| 1607 |
}
|
| 1608 |
|
| 1609 |
-
/* ==========================================
|
| 1610 |
-
DASHBOARD KEPUTUSAN (DECISION SUPPORT SYSTEM)
|
| 1611 |
-
========================================== */
|
| 1612 |
-
.decision-header-section {
|
| 1613 |
-
padding-top: 1rem;
|
| 1614 |
-
padding-bottom: 1.5rem;
|
| 1615 |
-
}
|
| 1616 |
-
|
| 1617 |
-
.decision-header-top {
|
| 1618 |
-
display: flex;
|
| 1619 |
-
justify-content: space-between;
|
| 1620 |
-
align-items: flex-end;
|
| 1621 |
-
flex-wrap: wrap;
|
| 1622 |
-
gap: 1.5rem;
|
| 1623 |
-
margin-bottom: 2rem;
|
| 1624 |
-
}
|
| 1625 |
-
|
| 1626 |
-
.decision-title-group {
|
| 1627 |
-
display: flex;
|
| 1628 |
-
flex-direction: column;
|
| 1629 |
-
gap: 6px;
|
| 1630 |
-
}
|
| 1631 |
-
|
| 1632 |
-
.decision-heading {
|
| 1633 |
-
display: flex;
|
| 1634 |
-
align-items: center;
|
| 1635 |
-
gap: 12px;
|
| 1636 |
-
font-family: var(--font-display);
|
| 1637 |
-
font-size: 2rem;
|
| 1638 |
-
font-weight: 800;
|
| 1639 |
-
letter-spacing: 1px;
|
| 1640 |
-
color: #FFFFFF;
|
| 1641 |
-
}
|
| 1642 |
-
|
| 1643 |
-
.decision-icon {
|
| 1644 |
-
color: var(--cyan);
|
| 1645 |
-
filter: drop-shadow(0 0 8px var(--cyan-glow));
|
| 1646 |
-
}
|
| 1647 |
-
|
| 1648 |
-
.decision-subtitle {
|
| 1649 |
-
font-size: 0.9rem;
|
| 1650 |
-
color: var(--text-muted);
|
| 1651 |
-
max-width: 680px;
|
| 1652 |
-
line-height: 1.5;
|
| 1653 |
-
}
|
| 1654 |
-
|
| 1655 |
-
.decision-controls {
|
| 1656 |
-
display: flex;
|
| 1657 |
-
align-items: flex-end;
|
| 1658 |
-
gap: 1rem;
|
| 1659 |
-
flex-wrap: wrap;
|
| 1660 |
-
}
|
| 1661 |
-
|
| 1662 |
-
.decision-control-item {
|
| 1663 |
-
display: flex;
|
| 1664 |
-
flex-direction: column;
|
| 1665 |
-
gap: 4px;
|
| 1666 |
-
}
|
| 1667 |
-
|
| 1668 |
-
.decision-control-item label {
|
| 1669 |
-
font-family: var(--font-mono);
|
| 1670 |
-
font-size: 0.72rem;
|
| 1671 |
-
color: var(--text-muted);
|
| 1672 |
-
letter-spacing: 1px;
|
| 1673 |
-
}
|
| 1674 |
-
|
| 1675 |
-
.dec-select {
|
| 1676 |
-
min-width: 220px;
|
| 1677 |
-
background: rgba(14, 22, 16, 0.95);
|
| 1678 |
-
border: 1px solid var(--border-color);
|
| 1679 |
-
padding: 8px 12px;
|
| 1680 |
-
font-size: 0.85rem;
|
| 1681 |
-
}
|
| 1682 |
-
|
| 1683 |
-
.weather-modal-trigger-btn {
|
| 1684 |
-
width: auto !important;
|
| 1685 |
-
padding: 9px 18px !important;
|
| 1686 |
-
font-size: 0.82rem !important;
|
| 1687 |
-
display: inline-flex;
|
| 1688 |
-
align-items: center;
|
| 1689 |
-
gap: 8px;
|
| 1690 |
-
white-space: nowrap;
|
| 1691 |
-
border-radius: 8px;
|
| 1692 |
-
background: rgba(0, 240, 255, 0.12) !important;
|
| 1693 |
-
border: 1px solid var(--cyan) !important;
|
| 1694 |
-
color: var(--cyan) !important;
|
| 1695 |
-
cursor: pointer;
|
| 1696 |
-
transition: all 0.25s ease;
|
| 1697 |
-
}
|
| 1698 |
-
|
| 1699 |
-
.weather-modal-trigger-btn:hover {
|
| 1700 |
-
background: var(--cyan) !important;
|
| 1701 |
-
color: var(--bg-void) !important;
|
| 1702 |
-
box-shadow: 0 0 16px var(--cyan-glow) !important;
|
| 1703 |
-
transform: translateY(-2px);
|
| 1704 |
-
}
|
| 1705 |
-
|
| 1706 |
-
/* 3 Top KPI Cards */
|
| 1707 |
-
.decision-kpi-grid {
|
| 1708 |
-
display: grid;
|
| 1709 |
-
grid-template-columns: repeat(3, 1fr);
|
| 1710 |
-
gap: 1.5rem;
|
| 1711 |
-
margin-bottom: 2rem;
|
| 1712 |
-
}
|
| 1713 |
-
|
| 1714 |
-
.dec-kpi-card {
|
| 1715 |
-
background: var(--bg-panel);
|
| 1716 |
-
border: 1px solid var(--border-color);
|
| 1717 |
-
border-radius: 12px;
|
| 1718 |
-
padding: 1.6rem 1.8rem;
|
| 1719 |
-
display: flex;
|
| 1720 |
-
flex-direction: column;
|
| 1721 |
-
justify-content: space-between;
|
| 1722 |
-
min-height: 150px;
|
| 1723 |
-
transition: transform 0.3s, border-color 0.3s, box-shadow 0.3s;
|
| 1724 |
-
backdrop-filter: blur(16px);
|
| 1725 |
-
}
|
| 1726 |
-
|
| 1727 |
-
.dec-kpi-card:hover {
|
| 1728 |
-
transform: translateY(-4px);
|
| 1729 |
-
border-color: var(--border-hover);
|
| 1730 |
-
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.35);
|
| 1731 |
-
}
|
| 1732 |
-
|
| 1733 |
-
.dec-kpi-label {
|
| 1734 |
-
font-family: var(--font-mono);
|
| 1735 |
-
font-size: 0.72rem;
|
| 1736 |
-
font-weight: 700;
|
| 1737 |
-
color: var(--text-muted);
|
| 1738 |
-
letter-spacing: 1.5px;
|
| 1739 |
-
text-transform: uppercase;
|
| 1740 |
-
}
|
| 1741 |
-
|
| 1742 |
-
.dec-kpi-val-row {
|
| 1743 |
-
display: flex;
|
| 1744 |
-
align-items: baseline;
|
| 1745 |
-
gap: 8px;
|
| 1746 |
-
margin: 8px 0;
|
| 1747 |
-
}
|
| 1748 |
-
|
| 1749 |
-
.dec-kpi-number {
|
| 1750 |
-
font-family: var(--font-display);
|
| 1751 |
-
font-size: 2.3rem;
|
| 1752 |
-
font-weight: 800;
|
| 1753 |
-
letter-spacing: -0.5px;
|
| 1754 |
-
color: #FFFFFF;
|
| 1755 |
-
line-height: 1;
|
| 1756 |
-
}
|
| 1757 |
-
|
| 1758 |
-
.dec-kpi-unit {
|
| 1759 |
-
font-family: var(--font-display);
|
| 1760 |
-
font-size: 1.1rem;
|
| 1761 |
-
font-weight: 600;
|
| 1762 |
-
color: var(--text-muted);
|
| 1763 |
-
}
|
| 1764 |
-
|
| 1765 |
-
.dec-kpi-meta {
|
| 1766 |
-
font-family: var(--font-mono);
|
| 1767 |
-
font-size: 0.8rem;
|
| 1768 |
-
color: var(--text-muted);
|
| 1769 |
-
display: inline-flex;
|
| 1770 |
-
align-items: center;
|
| 1771 |
-
gap: 6px;
|
| 1772 |
-
}
|
| 1773 |
-
|
| 1774 |
-
.dec-kpi-meta.positive {
|
| 1775 |
-
color: var(--cyan);
|
| 1776 |
-
}
|
| 1777 |
-
|
| 1778 |
-
/* Decision Body Grid (65% Workload Map : 35% Sidebar) */
|
| 1779 |
-
.decision-body-grid {
|
| 1780 |
-
display: grid;
|
| 1781 |
-
grid-template-columns: 1.65fr 1fr;
|
| 1782 |
-
gap: 1.5rem;
|
| 1783 |
-
margin-bottom: 3rem;
|
| 1784 |
-
align-items: start;
|
| 1785 |
-
}
|
| 1786 |
-
|
| 1787 |
-
/* Peta Beban Kerja Harian Panel */
|
| 1788 |
-
.dec-workload-panel {
|
| 1789 |
-
padding: 1.8rem;
|
| 1790 |
-
border-radius: 12px;
|
| 1791 |
-
}
|
| 1792 |
-
|
| 1793 |
-
.dec-panel-header {
|
| 1794 |
-
display: flex;
|
| 1795 |
-
justify-content: space-between;
|
| 1796 |
-
align-items: center;
|
| 1797 |
-
margin-bottom: 1.5rem;
|
| 1798 |
-
}
|
| 1799 |
-
|
| 1800 |
-
.dec-panel-title {
|
| 1801 |
-
display: flex;
|
| 1802 |
-
align-items: center;
|
| 1803 |
-
gap: 10px;
|
| 1804 |
-
font-family: var(--font-display);
|
| 1805 |
-
font-size: 1.15rem;
|
| 1806 |
-
font-weight: 700;
|
| 1807 |
-
color: #FFFFFF;
|
| 1808 |
-
letter-spacing: 0.5px;
|
| 1809 |
-
}
|
| 1810 |
-
|
| 1811 |
-
.dec-panel-badge {
|
| 1812 |
-
font-family: var(--font-mono);
|
| 1813 |
-
font-size: 0.72rem;
|
| 1814 |
-
color: var(--text-muted);
|
| 1815 |
-
background: rgba(255, 255, 255, 0.04);
|
| 1816 |
-
padding: 3px 10px;
|
| 1817 |
-
border-radius: 4px;
|
| 1818 |
-
border: 1px solid rgba(255, 255, 255, 0.08);
|
| 1819 |
-
}
|
| 1820 |
-
|
| 1821 |
-
/* 7-Day Horizontal Workload Grid */
|
| 1822 |
-
.dec-workload-grid {
|
| 1823 |
-
display: grid;
|
| 1824 |
-
grid-template-columns: repeat(7, 1fr);
|
| 1825 |
-
gap: 10px;
|
| 1826 |
-
overflow-x: auto;
|
| 1827 |
-
padding-bottom: 6px;
|
| 1828 |
-
}
|
| 1829 |
-
|
| 1830 |
-
.workload-day-card {
|
| 1831 |
-
background: rgba(8, 14, 10, 0.9);
|
| 1832 |
-
border: 1px solid var(--border-color);
|
| 1833 |
-
border-radius: 8px;
|
| 1834 |
-
padding: 12px 10px;
|
| 1835 |
-
display: flex;
|
| 1836 |
-
flex-direction: column;
|
| 1837 |
-
align-items: center;
|
| 1838 |
-
text-align: center;
|
| 1839 |
-
transition: transform 0.25s, border-color 0.25s, box-shadow 0.25s;
|
| 1840 |
-
}
|
| 1841 |
-
|
| 1842 |
-
.workload-day-card:hover {
|
| 1843 |
-
transform: translateY(-3px);
|
| 1844 |
-
border-color: var(--cyan);
|
| 1845 |
-
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.4);
|
| 1846 |
-
}
|
| 1847 |
-
|
| 1848 |
-
.workload-day-card.critical {
|
| 1849 |
-
border-color: rgba(239, 68, 68, 0.4);
|
| 1850 |
-
}
|
| 1851 |
-
|
| 1852 |
-
.workload-day-badge {
|
| 1853 |
-
width: 100%;
|
| 1854 |
-
padding: 4px 6px;
|
| 1855 |
-
border-radius: 4px;
|
| 1856 |
-
font-family: var(--font-display);
|
| 1857 |
-
font-size: 0.78rem;
|
| 1858 |
-
font-weight: 800;
|
| 1859 |
-
letter-spacing: 1px;
|
| 1860 |
-
text-transform: uppercase;
|
| 1861 |
-
margin-bottom: 12px;
|
| 1862 |
-
}
|
| 1863 |
-
|
| 1864 |
-
.workload-day-badge.normal {
|
| 1865 |
-
background: rgba(14, 38, 28, 0.7);
|
| 1866 |
-
color: #6ee7b7;
|
| 1867 |
-
border: 1px solid rgba(110, 231, 183, 0.2);
|
| 1868 |
-
}
|
| 1869 |
-
|
| 1870 |
-
.workload-day-badge.warning {
|
| 1871 |
-
background: rgba(60, 40, 10, 0.7);
|
| 1872 |
-
color: #fbbf24;
|
| 1873 |
-
border: 1px solid rgba(251, 191, 36, 0.2);
|
| 1874 |
-
}
|
| 1875 |
-
|
| 1876 |
-
.workload-day-badge.peak-critical {
|
| 1877 |
-
background: rgba(70, 15, 20, 0.85);
|
| 1878 |
-
color: #fca5a5;
|
| 1879 |
-
border: 1px solid rgba(239, 68, 68, 0.35);
|
| 1880 |
-
box-shadow: 0 0 10px rgba(239, 68, 68, 0.2);
|
| 1881 |
-
}
|
| 1882 |
-
|
| 1883 |
-
.workload-ton-val {
|
| 1884 |
-
font-family: var(--font-display);
|
| 1885 |
-
font-size: 1.15rem;
|
| 1886 |
-
font-weight: 800;
|
| 1887 |
-
color: #FFFFFF;
|
| 1888 |
-
line-height: 1.1;
|
| 1889 |
-
}
|
| 1890 |
-
|
| 1891 |
-
.workload-ton-label {
|
| 1892 |
-
font-family: var(--font-mono);
|
| 1893 |
-
font-size: 0.65rem;
|
| 1894 |
-
color: var(--text-muted);
|
| 1895 |
-
letter-spacing: 1px;
|
| 1896 |
-
margin-bottom: 10px;
|
| 1897 |
-
}
|
| 1898 |
-
|
| 1899 |
-
.workload-trucks-count {
|
| 1900 |
-
display: flex;
|
| 1901 |
-
align-items: center;
|
| 1902 |
-
justify-content: center;
|
| 1903 |
-
gap: 4px;
|
| 1904 |
-
font-family: var(--font-mono);
|
| 1905 |
-
font-size: 0.75rem;
|
| 1906 |
-
color: var(--text-muted);
|
| 1907 |
-
margin-bottom: 12px;
|
| 1908 |
-
padding-bottom: 10px;
|
| 1909 |
-
border-bottom: 1px solid rgba(255, 255, 255, 0.06);
|
| 1910 |
-
width: 100%;
|
| 1911 |
-
}
|
| 1912 |
-
|
| 1913 |
-
.workload-shifts-list {
|
| 1914 |
-
display: flex;
|
| 1915 |
-
flex-direction: column;
|
| 1916 |
-
gap: 4px;
|
| 1917 |
-
width: 100%;
|
| 1918 |
-
}
|
| 1919 |
-
|
| 1920 |
-
.workload-shift-pill {
|
| 1921 |
-
font-family: var(--font-mono);
|
| 1922 |
-
font-size: 0.62rem;
|
| 1923 |
-
font-weight: 600;
|
| 1924 |
-
padding: 2px 4px;
|
| 1925 |
-
border-radius: 3px;
|
| 1926 |
-
white-space: nowrap;
|
| 1927 |
-
text-align: center;
|
| 1928 |
-
}
|
| 1929 |
-
|
| 1930 |
-
.workload-shift-pill.s1 {
|
| 1931 |
-
color: #fbbf24;
|
| 1932 |
-
background: rgba(251, 191, 36, 0.08);
|
| 1933 |
-
border: 1px solid rgba(251, 191, 36, 0.15);
|
| 1934 |
-
}
|
| 1935 |
-
|
| 1936 |
-
.workload-shift-pill.s2 {
|
| 1937 |
-
color: #38bdf8;
|
| 1938 |
-
background: rgba(56, 189, 248, 0.08);
|
| 1939 |
-
border: 1px solid rgba(56, 189, 248, 0.15);
|
| 1940 |
-
}
|
| 1941 |
-
|
| 1942 |
-
.workload-shift-pill.s3 {
|
| 1943 |
-
color: #f87171;
|
| 1944 |
-
background: rgba(239, 68, 68, 0.12);
|
| 1945 |
-
border: 1px solid rgba(239, 68, 68, 0.25);
|
| 1946 |
-
font-weight: 700;
|
| 1947 |
-
}
|
| 1948 |
-
|
| 1949 |
-
/* Sidebar Column */
|
| 1950 |
-
.dec-sidebar-col {
|
| 1951 |
-
display: flex;
|
| 1952 |
-
flex-direction: column;
|
| 1953 |
-
gap: 1.5rem;
|
| 1954 |
-
}
|
| 1955 |
-
|
| 1956 |
-
/* Decision Details Grid (Fleet Allocation & Critical Action Plan) */
|
| 1957 |
-
.decision-details-grid {
|
| 1958 |
-
display: grid;
|
| 1959 |
-
grid-template-columns: 1fr 1.3fr;
|
| 1960 |
-
gap: 1.5rem;
|
| 1961 |
-
align-items: stretch;
|
| 1962 |
-
}
|
| 1963 |
-
|
| 1964 |
-
@media (max-width: 1080px) {
|
| 1965 |
-
.decision-details-grid {
|
| 1966 |
-
grid-template-columns: 1fr;
|
| 1967 |
-
}
|
| 1968 |
-
}
|
| 1969 |
-
|
| 1970 |
-
/* Alokasi Armada Spesifik Panel */
|
| 1971 |
-
.dec-fleet-panel {
|
| 1972 |
-
padding: 1.6rem 1.8rem;
|
| 1973 |
-
border-radius: 12px;
|
| 1974 |
-
display: flex;
|
| 1975 |
-
flex-direction: column;
|
| 1976 |
-
justify-content: space-between;
|
| 1977 |
-
}
|
| 1978 |
-
|
| 1979 |
-
.dec-fleet-list {
|
| 1980 |
-
display: grid;
|
| 1981 |
-
grid-template-columns: 1fr 1fr;
|
| 1982 |
-
gap: 1.2rem;
|
| 1983 |
-
margin-top: 1.2rem;
|
| 1984 |
-
flex: 1;
|
| 1985 |
-
}
|
| 1986 |
-
|
| 1987 |
-
@media (max-width: 640px) {
|
| 1988 |
-
.dec-fleet-list {
|
| 1989 |
-
grid-template-columns: 1fr;
|
| 1990 |
-
}
|
| 1991 |
-
}
|
| 1992 |
|
| 1993 |
-
.dec-fleet-card {
|
| 1994 |
-
background: rgba(0, 0, 0, 0.3);
|
| 1995 |
-
border: 1px solid var(--border-color);
|
| 1996 |
-
border-radius: 10px;
|
| 1997 |
-
padding: 1.2rem 1.4rem;
|
| 1998 |
-
display: flex;
|
| 1999 |
-
align-items: center;
|
| 2000 |
-
gap: 1.2rem;
|
| 2001 |
-
transition: transform 0.25s, border-color 0.25s, box-shadow 0.25s;
|
| 2002 |
-
}
|
| 2003 |
|
| 2004 |
-
.dec-fleet-card:hover {
|
| 2005 |
-
transform: translateY(-3px);
|
| 2006 |
-
border-color: var(--cyan);
|
| 2007 |
-
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.35);
|
| 2008 |
-
}
|
| 2009 |
-
|
| 2010 |
-
.fleet-icon-box {
|
| 2011 |
-
width: 52px;
|
| 2012 |
-
height: 52px;
|
| 2013 |
-
border-radius: 10px;
|
| 2014 |
-
display: flex;
|
| 2015 |
-
align-items: center;
|
| 2016 |
-
justify-content: center;
|
| 2017 |
-
flex-shrink: 0;
|
| 2018 |
-
}
|
| 2019 |
-
|
| 2020 |
-
.fleet-icon-box.blue-box {
|
| 2021 |
-
background: rgba(56, 189, 248, 0.12);
|
| 2022 |
-
border: 1px solid rgba(56, 189, 248, 0.3);
|
| 2023 |
-
}
|
| 2024 |
-
|
| 2025 |
-
.fleet-icon-box.amber-box {
|
| 2026 |
-
background: rgba(251, 191, 36, 0.12);
|
| 2027 |
-
border: 1px solid rgba(251, 191, 36, 0.3);
|
| 2028 |
-
}
|
| 2029 |
-
|
| 2030 |
-
.fleet-info {
|
| 2031 |
-
display: flex;
|
| 2032 |
-
flex-direction: column;
|
| 2033 |
-
gap: 4px;
|
| 2034 |
-
min-width: 0;
|
| 2035 |
-
}
|
| 2036 |
-
|
| 2037 |
-
.fleet-unit-count {
|
| 2038 |
-
font-family: var(--font-display);
|
| 2039 |
-
font-size: 1.65rem;
|
| 2040 |
-
font-weight: 800;
|
| 2041 |
-
color: #FFFFFF;
|
| 2042 |
-
line-height: 1;
|
| 2043 |
-
display: flex;
|
| 2044 |
-
align-items: baseline;
|
| 2045 |
-
gap: 6px;
|
| 2046 |
-
}
|
| 2047 |
-
|
| 2048 |
-
.fleet-unit-suffix {
|
| 2049 |
-
font-size: 0.95rem;
|
| 2050 |
-
font-weight: 600;
|
| 2051 |
-
color: var(--text-muted);
|
| 2052 |
-
}
|
| 2053 |
-
|
| 2054 |
-
.fleet-unit-type {
|
| 2055 |
-
font-family: var(--font-mono);
|
| 2056 |
-
font-size: 0.78rem;
|
| 2057 |
-
color: var(--text-muted);
|
| 2058 |
-
white-space: nowrap;
|
| 2059 |
-
letter-spacing: 0.3px;
|
| 2060 |
-
}
|
| 2061 |
-
|
| 2062 |
-
/* Rencana Aksi Kritis Panel */
|
| 2063 |
-
.dec-action-panel {
|
| 2064 |
-
padding: 1.6rem 1.8rem;
|
| 2065 |
-
border-radius: 12px;
|
| 2066 |
-
}
|
| 2067 |
-
|
| 2068 |
-
.dec-panel-title.action-title {
|
| 2069 |
-
color: #f87171;
|
| 2070 |
-
}
|
| 2071 |
-
|
| 2072 |
-
.dec-critical-box {
|
| 2073 |
-
background: rgba(239, 68, 68, 0.05);
|
| 2074 |
-
border: 1px solid rgba(239, 68, 68, 0.3);
|
| 2075 |
-
border-left: 4px solid #ef4444;
|
| 2076 |
-
border-radius: 8px;
|
| 2077 |
-
padding: 1.3rem 1.5rem;
|
| 2078 |
-
margin-top: 1.2rem;
|
| 2079 |
-
}
|
| 2080 |
-
|
| 2081 |
-
.dec-critical-header {
|
| 2082 |
-
display: flex;
|
| 2083 |
-
align-items: center;
|
| 2084 |
-
gap: 10px;
|
| 2085 |
-
margin-bottom: 12px;
|
| 2086 |
-
}
|
| 2087 |
-
|
| 2088 |
-
.critical-pulse-dot {
|
| 2089 |
-
width: 9px;
|
| 2090 |
-
height: 9px;
|
| 2091 |
-
border-radius: 50%;
|
| 2092 |
-
background-color: #ef4444;
|
| 2093 |
-
box-shadow: 0 0 10px #ef4444;
|
| 2094 |
-
animation: pulse-red-dot 1.5s infinite;
|
| 2095 |
-
flex-shrink: 0;
|
| 2096 |
-
}
|
| 2097 |
-
|
| 2098 |
-
@keyframes pulse-red-dot {
|
| 2099 |
-
0% { transform: scale(0.9); opacity: 0.8; }
|
| 2100 |
-
50% { transform: scale(1.4); opacity: 1; box-shadow: 0 0 14px #ef4444; }
|
| 2101 |
-
100% { transform: scale(0.9); opacity: 0.8; }
|
| 2102 |
-
}
|
| 2103 |
-
|
| 2104 |
-
.dec-critical-title {
|
| 2105 |
-
font-family: var(--font-display);
|
| 2106 |
-
font-size: 0.92rem;
|
| 2107 |
-
font-weight: 800;
|
| 2108 |
-
color: #fca5a5;
|
| 2109 |
-
letter-spacing: 0.5px;
|
| 2110 |
-
text-transform: uppercase;
|
| 2111 |
-
line-height: 1.3;
|
| 2112 |
-
}
|
| 2113 |
-
|
| 2114 |
-
.dec-critical-list {
|
| 2115 |
-
list-style: none;
|
| 2116 |
-
padding: 0;
|
| 2117 |
-
margin: 0;
|
| 2118 |
-
display: flex;
|
| 2119 |
-
flex-direction: column;
|
| 2120 |
-
gap: 10px;
|
| 2121 |
-
}
|
| 2122 |
-
|
| 2123 |
-
.dec-critical-list li {
|
| 2124 |
-
font-size: 0.84rem;
|
| 2125 |
-
color: #e2e8f0;
|
| 2126 |
-
line-height: 1.55;
|
| 2127 |
-
position: relative;
|
| 2128 |
-
padding-left: 16px;
|
| 2129 |
-
}
|
| 2130 |
-
|
| 2131 |
-
.dec-critical-list li::before {
|
| 2132 |
-
content: "•";
|
| 2133 |
-
position: absolute;
|
| 2134 |
-
left: 0;
|
| 2135 |
-
top: -1px;
|
| 2136 |
-
color: #ef4444;
|
| 2137 |
-
font-weight: bold;
|
| 2138 |
-
font-size: 1.1rem;
|
| 2139 |
-
}
|
| 2140 |
-
|
| 2141 |
-
/* ==========================================
|
| 2142 |
-
PRAKIRAAN CUACA 7 HARI MODAL
|
| 2143 |
-
========================================== */
|
| 2144 |
-
.weather-modal-backdrop {
|
| 2145 |
-
position: fixed;
|
| 2146 |
-
inset: 0;
|
| 2147 |
-
background: rgba(3, 7, 5, 0.85);
|
| 2148 |
-
backdrop-filter: blur(12px);
|
| 2149 |
-
-webkit-backdrop-filter: blur(12px);
|
| 2150 |
-
z-index: 9999;
|
| 2151 |
-
display: none;
|
| 2152 |
-
align-items: center;
|
| 2153 |
-
justify-content: center;
|
| 2154 |
-
padding: 1.5rem;
|
| 2155 |
-
opacity: 0;
|
| 2156 |
-
transition: opacity 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
| 2157 |
-
}
|
| 2158 |
-
|
| 2159 |
-
.weather-modal-backdrop.open {
|
| 2160 |
-
display: flex;
|
| 2161 |
-
opacity: 1;
|
| 2162 |
-
}
|
| 2163 |
-
|
| 2164 |
-
.weather-modal-dialog {
|
| 2165 |
-
background: #0B1410;
|
| 2166 |
-
border: 1px solid rgba(0, 240, 255, 0.25);
|
| 2167 |
-
box-shadow: 0 25px 60px rgba(0, 0, 0, 0.7), 0 0 30px rgba(0, 240, 255, 0.1);
|
| 2168 |
-
border-radius: 16px;
|
| 2169 |
-
width: 100%;
|
| 2170 |
-
max-width: 440px;
|
| 2171 |
-
padding: 1.8rem;
|
| 2172 |
-
transform: scale(0.95);
|
| 2173 |
-
transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
|
| 2174 |
-
position: relative;
|
| 2175 |
-
overflow: hidden;
|
| 2176 |
-
}
|
| 2177 |
-
|
| 2178 |
-
.weather-modal-backdrop.open .weather-modal-dialog {
|
| 2179 |
-
transform: scale(1);
|
| 2180 |
-
}
|
| 2181 |
-
|
| 2182 |
-
.weather-modal-header {
|
| 2183 |
-
display: flex;
|
| 2184 |
-
justify-content: space-between;
|
| 2185 |
-
align-items: center;
|
| 2186 |
-
margin-bottom: 1.5rem;
|
| 2187 |
-
}
|
| 2188 |
-
|
| 2189 |
-
.weather-modal-title-row {
|
| 2190 |
-
display: flex;
|
| 2191 |
-
align-items: center;
|
| 2192 |
-
gap: 12px;
|
| 2193 |
-
}
|
| 2194 |
-
|
| 2195 |
-
.weather-modal-title {
|
| 2196 |
-
font-family: var(--font-display);
|
| 2197 |
-
font-size: 1.25rem;
|
| 2198 |
-
font-weight: 800;
|
| 2199 |
-
color: #FFFFFF;
|
| 2200 |
-
letter-spacing: 0.5px;
|
| 2201 |
-
}
|
| 2202 |
-
|
| 2203 |
-
.weather-location-pill {
|
| 2204 |
-
background: rgba(0, 240, 255, 0.12);
|
| 2205 |
-
border: 1px solid rgba(0, 240, 255, 0.35);
|
| 2206 |
-
color: #38bdf8;
|
| 2207 |
-
font-family: var(--font-mono);
|
| 2208 |
-
font-size: 0.75rem;
|
| 2209 |
-
font-weight: 700;
|
| 2210 |
-
padding: 3px 10px;
|
| 2211 |
-
border-radius: 6px;
|
| 2212 |
-
}
|
| 2213 |
-
|
| 2214 |
-
.weather-modal-close-btn {
|
| 2215 |
-
background: transparent;
|
| 2216 |
-
border: none;
|
| 2217 |
-
color: var(--text-muted);
|
| 2218 |
-
font-size: 1.3rem;
|
| 2219 |
-
cursor: pointer;
|
| 2220 |
-
width: 32px;
|
| 2221 |
-
height: 32px;
|
| 2222 |
-
display: flex;
|
| 2223 |
-
align-items: center;
|
| 2224 |
-
justify-content: center;
|
| 2225 |
-
border-radius: 6px;
|
| 2226 |
-
transition: color 0.2s, background 0.2s;
|
| 2227 |
-
}
|
| 2228 |
-
|
| 2229 |
-
.weather-modal-close-btn:hover {
|
| 2230 |
-
color: #FFFFFF;
|
| 2231 |
-
background: rgba(255, 255, 255, 0.08);
|
| 2232 |
-
}
|
| 2233 |
-
|
| 2234 |
-
/* Summary Card in Modal */
|
| 2235 |
-
.weather-modal-summary-card {
|
| 2236 |
-
background: rgba(251, 191, 36, 0.04);
|
| 2237 |
-
border: 1px solid rgba(251, 191, 36, 0.25);
|
| 2238 |
-
border-radius: 10px;
|
| 2239 |
-
padding: 1rem 1.2rem;
|
| 2240 |
-
display: flex;
|
| 2241 |
-
justify-content: space-between;
|
| 2242 |
-
align-items: center;
|
| 2243 |
-
margin-bottom: 1.5rem;
|
| 2244 |
-
}
|
| 2245 |
-
|
| 2246 |
-
.summary-left {
|
| 2247 |
-
display: flex;
|
| 2248 |
-
flex-direction: column;
|
| 2249 |
-
gap: 4px;
|
| 2250 |
-
}
|
| 2251 |
-
|
| 2252 |
-
.summary-card-label {
|
| 2253 |
-
font-family: var(--font-mono);
|
| 2254 |
-
font-size: 0.7rem;
|
| 2255 |
-
font-weight: 700;
|
| 2256 |
-
color: var(--text-muted);
|
| 2257 |
-
letter-spacing: 1px;
|
| 2258 |
-
}
|
| 2259 |
-
|
| 2260 |
-
.summary-card-stats {
|
| 2261 |
-
font-family: var(--font-mono);
|
| 2262 |
-
font-size: 0.95rem;
|
| 2263 |
-
color: #FFFFFF;
|
| 2264 |
-
font-weight: 600;
|
| 2265 |
-
display: flex;
|
| 2266 |
-
align-items: center;
|
| 2267 |
-
gap: 6px;
|
| 2268 |
-
}
|
| 2269 |
-
|
| 2270 |
-
.summary-val-highlight {
|
| 2271 |
-
color: #FFFFFF;
|
| 2272 |
-
font-weight: 800;
|
| 2273 |
-
}
|
| 2274 |
-
|
| 2275 |
-
.summary-separator {
|
| 2276 |
-
color: var(--text-muted);
|
| 2277 |
-
}
|
| 2278 |
-
|
| 2279 |
-
.weather-dryness-badge {
|
| 2280 |
-
font-family: var(--font-mono);
|
| 2281 |
-
font-size: 0.78rem;
|
| 2282 |
-
font-weight: 800;
|
| 2283 |
-
padding: 5px 12px;
|
| 2284 |
-
border-radius: 6px;
|
| 2285 |
-
letter-spacing: 1px;
|
| 2286 |
-
text-transform: uppercase;
|
| 2287 |
-
}
|
| 2288 |
-
|
| 2289 |
-
.weather-dryness-badge.dry {
|
| 2290 |
-
background: rgba(251, 191, 36, 0.15);
|
| 2291 |
-
border: 1px solid #fbbf24;
|
| 2292 |
-
color: #fbbf24;
|
| 2293 |
-
}
|
| 2294 |
-
|
| 2295 |
-
.weather-dryness-badge.wet {
|
| 2296 |
-
background: rgba(56, 189, 248, 0.15);
|
| 2297 |
-
border: 1px solid #38bdf8;
|
| 2298 |
-
color: #38bdf8;
|
| 2299 |
-
}
|
| 2300 |
-
|
| 2301 |
-
.weather-dryness-badge.heavy {
|
| 2302 |
-
background: rgba(239, 68, 68, 0.15);
|
| 2303 |
-
border: 1px solid #ef4444;
|
| 2304 |
-
color: #ef4444;
|
| 2305 |
-
}
|
| 2306 |
-
|
| 2307 |
-
/* 7-Day Forecast List Rows */
|
| 2308 |
-
.weather-modal-forecast-list {
|
| 2309 |
-
display: flex;
|
| 2310 |
-
flex-direction: column;
|
| 2311 |
-
gap: 6px;
|
| 2312 |
-
}
|
| 2313 |
-
|
| 2314 |
-
.weather-forecast-row {
|
| 2315 |
-
display: grid;
|
| 2316 |
-
grid-template-columns: 45px 30px 1fr 65px 75px;
|
| 2317 |
-
align-items: center;
|
| 2318 |
-
gap: 10px;
|
| 2319 |
-
padding: 10px 12px;
|
| 2320 |
-
background: rgba(0, 0, 0, 0.2);
|
| 2321 |
-
border-radius: 8px;
|
| 2322 |
-
border: 1px solid rgba(255, 255, 255, 0.03);
|
| 2323 |
-
transition: background 0.2s, border-color 0.2s;
|
| 2324 |
-
}
|
| 2325 |
-
|
| 2326 |
-
.weather-forecast-row:hover {
|
| 2327 |
-
background: rgba(0, 240, 255, 0.04);
|
| 2328 |
-
border-color: rgba(0, 240, 255, 0.15);
|
| 2329 |
-
}
|
| 2330 |
-
|
| 2331 |
-
.w-row-day {
|
| 2332 |
-
font-family: var(--font-display);
|
| 2333 |
-
font-size: 0.9rem;
|
| 2334 |
-
font-weight: 700;
|
| 2335 |
-
color: #FFFFFF;
|
| 2336 |
-
}
|
| 2337 |
-
|
| 2338 |
-
.w-row-icon {
|
| 2339 |
-
font-size: 1.2rem;
|
| 2340 |
-
display: flex;
|
| 2341 |
-
align-items: center;
|
| 2342 |
-
justify-content: center;
|
| 2343 |
-
}
|
| 2344 |
-
|
| 2345 |
-
.w-row-cond {
|
| 2346 |
-
font-size: 0.85rem;
|
| 2347 |
-
color: var(--text-main);
|
| 2348 |
-
white-space: nowrap;
|
| 2349 |
-
overflow: hidden;
|
| 2350 |
-
text-overflow: ellipsis;
|
| 2351 |
-
}
|
| 2352 |
-
|
| 2353 |
-
.w-row-precip {
|
| 2354 |
-
font-family: var(--font-mono);
|
| 2355 |
-
font-size: 0.82rem;
|
| 2356 |
-
color: #38bdf8;
|
| 2357 |
-
text-align: right;
|
| 2358 |
-
font-weight: 600;
|
| 2359 |
-
}
|
| 2360 |
-
|
| 2361 |
-
.w-row-temp {
|
| 2362 |
-
font-family: var(--font-mono);
|
| 2363 |
-
font-size: 0.88rem;
|
| 2364 |
-
text-align: right;
|
| 2365 |
-
display: flex;
|
| 2366 |
-
gap: 6px; justify-content: flex-end;
|
| 2367 |
-
}
|
| 2368 |
-
|
| 2369 |
-
.w-temp-max {
|
| 2370 |
-
color: #FFFFFF;
|
| 2371 |
-
font-weight: 700;
|
| 2372 |
-
}
|
| 2373 |
-
|
| 2374 |
-
.w-temp-min {
|
| 2375 |
-
color: var(--text-muted);
|
| 2376 |
-
}
|
| 2377 |
-
|
| 2378 |
-
.weather-modal-loading {
|
| 2379 |
-
padding: 2.5rem 1rem;
|
| 2380 |
-
text-align: center;
|
| 2381 |
-
font-family: var(--font-mono);
|
| 2382 |
-
font-size: 0.85rem;
|
| 2383 |
-
color: var(--text-muted);
|
| 2384 |
-
}
|
| 2385 |
-
|
| 2386 |
-
/* ==========================================
|
| 2387 |
-
RESPONSIVE QUERIES FOR DECISION DASHBOARD
|
| 2388 |
-
========================================== */
|
| 2389 |
-
@media (max-width: 1100px) {
|
| 2390 |
-
.decision-details-grid {
|
| 2391 |
-
grid-template-columns: 1fr;
|
| 2392 |
-
gap: 1.5rem;
|
| 2393 |
-
}
|
| 2394 |
-
.decision-kpi-grid {
|
| 2395 |
-
grid-template-columns: 1fr;
|
| 2396 |
-
gap: 1rem;
|
| 2397 |
-
}
|
| 2398 |
-
}
|
| 2399 |
-
|
| 2400 |
-
@media (max-width: 768px) {
|
| 2401 |
-
.decision-header-top {
|
| 2402 |
-
flex-direction: column;
|
| 2403 |
-
align-items: flex-start;
|
| 2404 |
-
}
|
| 2405 |
-
.decision-controls {
|
| 2406 |
-
width: 100%;
|
| 2407 |
-
flex-direction: column;
|
| 2408 |
-
align-items: stretch;
|
| 2409 |
-
}
|
| 2410 |
-
.dec-select {
|
| 2411 |
-
width: 100%;
|
| 2412 |
-
}
|
| 2413 |
-
.dec-workload-grid {
|
| 2414 |
-
display: flex;
|
| 2415 |
-
overflow-x: auto;
|
| 2416 |
-
padding-bottom: 12px;
|
| 2417 |
-
}
|
| 2418 |
-
.workload-day-card {
|
| 2419 |
-
min-width: 120px;
|
| 2420 |
-
}
|
| 2421 |
-
.weather-forecast-row {
|
| 2422 |
-
grid-template-columns: 35px 24px 1fr 50px 65px;
|
| 2423 |
-
gap: 6px;
|
| 2424 |
-
padding: 8px 10px;
|
| 2425 |
-
}
|
| 2426 |
-
.w-row-cond {
|
| 2427 |
-
font-size: 0.78rem;
|
| 2428 |
-
}
|
| 2429 |
-
}
|
|
|
|
| 130 |
display: grid;
|
| 131 |
grid-template-columns: 320px 1fr 340px;
|
| 132 |
gap: 1.5rem;
|
| 133 |
+
padding: 1.5rem 2.5rem;
|
| 134 |
flex: 1;
|
| 135 |
z-index: 5;
|
| 136 |
position: relative;
|
|
|
|
| 656 |
/* Timeline Container */
|
| 657 |
.timeline-container {
|
| 658 |
margin-top: 1.5rem;
|
| 659 |
+
padding: 0 2.5rem;
|
| 660 |
z-index: 5;
|
| 661 |
position: relative;
|
| 662 |
}
|
|
|
|
| 725 |
/* Hourly Breakdown Container */
|
| 726 |
.hourly-container {
|
| 727 |
margin-top: 1.5rem;
|
| 728 |
+
padding: 0 2.5rem;
|
| 729 |
z-index: 5;
|
| 730 |
position: relative;
|
| 731 |
margin-bottom: 2rem;
|
|
|
|
| 1606 |
}
|
| 1607 |
}
|
| 1608 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1609 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1610 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|