1import { r as reactExports, j as jsxRuntimeExports } from "./vendor-react-Bay9Y7Lb.js"; 2import { a as api } from "./index-w5lXls15.js"; 3import { cg as Activity, bs as Zap, fL as Snowflake, fM as Wind, dW as Thermometer, a$ as Shield, dh as SlidersVertical, cM as RefreshCw, a_ as CircleCheck, aY as TriangleAlert, dZ as Server, eu as Power, c4 as RotateCcw, cj as Cpu, cu as TrendingUp, eC as Terminal, ct as BookOpen, fN as Wifi, b9 as Settings, de as Flame, fO as Droplets, cB as ChevronUp, cC as ChevronDown, bM as Clock, e9 as Radio, cF as Key, bz as EyeOff, bA as Eye, bG as CircleQuestionMark, dO as Calendar, ci as Database, ba as Info, ch as Gauge, bj as CreditCard, aW as X } from "./vendor-D0P4XgNj.js"; 4import "./vendor-i18n-BC7ZMXWQ.js"; 5const AC_MODES = [ 6 { id: 0, name: "Cool", icon: Snowflake, color: "text-cyan-400" }, 7 { id: 1, name: "Heat", icon: Flame, color: "text-rose-400" }, 8 { id: 2, name: "Auto", icon: Activity, color: "text-emerald-400" }, 9 { id: 3, name: "Fan Only", icon: Wind, color: "text-blue-400" }, 10 { id: 4, name: "Dry (Dehum)", icon: Droplets, color: "text-indigo-400" } 11]; 12const FAN_SPEEDS = [ 13 { id: 0, name: "Auto" }, 14 { id: 1, name: "Low" }, 15 { id: 2, name: "Medium" }, 16 { id: 3, name: "High" } 17]; 18const PRESETS = [ 19 { label: "ð¿ Eco", temp: 26, fan: 1, desc: "Power Saver" }, 20 { label: "â¡ Optimal (Rec.)", temp: 24, fan: 0, desc: "Best Efficiency" }, 21 { label: "âï¸ Cool", temp: 22, fan: 2, desc: "High Worker Load" }, 22 { label: "ð Turbo", temp: 19, fan: 3, desc: "Emergency Chill" } 23]; 24const TIME_RANGES = [ 25 { id: "1h", label: "1 Hour" }, 26 { id: "6h", label: "6 Hours" }, 27 { id: "24h", label: "24 Hours" }, 28 { id: "7d", label: "7 Days" }, 29 { id: "30d", label: "30 Days" } 30]; 31const OCTOPUS_RANGE_OPTIONS = [ 32 { id: "24h", label: "24h", fullLabel: "24 Hours" }, 33 { id: "7d", label: "7d", fullLabel: "7 Days" }, 34 { id: "30d", label: "30d", fullLabel: "30 Days" }, 35 { id: "3m", label: "3m", fullLabel: "3 Months" }, 36 { id: "6m", label: "6m", fullLabel: "6 Months" }, 37 { id: "1y", label: "1y", fullLabel: "1 Year" }, 38 { id: "3y", label: "3y", fullLabel: "3 Years" }, 39 { id: "10y", label: "10y", fullLabel: "10 Years" } 40]; 41const OPERATIONAL_PROFILES = [ 42 { 43 id: "balanced", 44 name: "Balanced Efficiency", 45 badge: "Recommended Standard", 46 description: "Cruises comfortably at 24°C; turns off below 20°C for free-cooling; wakes up at 25°C. Best overall balance of power savings and hardware protection.", 47 icon: Activity, 48 color: "text-emerald-400", 49 bgGradient: "from-emerald-950/40 via-zinc-950 to-zinc-950", 50 borderColor: "border-emerald-500/40", 51 targetInlet: "22°C â 25°C", 52 coldCutoff: 20, 53 warmWakeup: 25, 54 cpuWakeup: 88, 55 optimalTemp: 24, 56 fanName: "Auto (0)", 57 config: { 58 cold_cutoff_temp: 20, 59 warm_wakeup_temp: 25, 60 emergency_wakeup_cpu_temp: 88, 61 temp_thresholds: { 62 optimal: { inlet_temp: 22, target_ac_temp: 24, fan: 0 }, 63 warm: { inlet_temp: 26, cpu_temp: 85, target_ac_temp: 22, fan: 2 }, 64 emergency_high: { inlet_temp: 28, cpu_temp: 92, target_ac_temp: 19, fan: 3 }, 65 cool: { inlet_temp: 20, target_ac_temp: 26, fan: 1 } 66 } 67 } 68 }, 69 { 70 id: "performance", 71 name: "High-Compute Performance", 72 badge: "Heavy Worker Load", 73 description: "Tighter thermal envelope with earlier fan ramp-up (21°C target). Recommended during intense worker render batches or parallel model compile runs.", 74 icon: Zap, 75 color: "text-rose-400", 76 bgGradient: "from-rose-950/40 via-zinc-950 to-zinc-950", 77 borderColor: "border-rose-500/40", 78 targetInlet: "20°C â 23°C", 79 coldCutoff: 18, 80 warmWakeup: 23, 81 cpuWakeup: 82, 82 optimalTemp: 21, 83 fanName: "Low (1)", 84 config: { 85 cold_cutoff_temp: 18, 86 warm_wakeup_temp: 23, 87 emergency_wakeup_cpu_temp: 82, 88 temp_thresholds: { 89 optimal: { inlet_temp: 20, target_ac_temp: 21, fan: 1 }, 90 warm: { inlet_temp: 24, cpu_temp: 80, target_ac_temp: 19, fan: 2 }, 91 emergency_high: { inlet_temp: 26, cpu_temp: 88, target_ac_temp: 18, fan: 3 }, 92 cool: { inlet_temp: 18, target_ac_temp: 24, fan: 1 } 93 } 94 } 95 }, 96 { 97 id: "winter_saver", 98 name: "Max Winter Power Saver", 99 badge: "Tokyo Cold Ambient", 100 description: "Maximizes 0W standby sleep by leveraging cold Japanese winter ambient air. Server radiates heat naturally up to 28°C before AC compressor re-engages.", 101 icon: Snowflake, 102 color: "text-cyan-400", 103 bgGradient: "from-blue-950/40 via-cyan-950/20 to-zinc-950", 104 borderColor: "border-cyan-500/40", 105 targetInlet: "24°C â 27°C", 106 coldCutoff: 22, 107 warmWakeup: 28, 108 cpuWakeup: 88, 109 optimalTemp: 24, 110 fanName: "Auto (0)", 111 config: { 112 cold_cutoff_temp: 22, 113 warm_wakeup_temp: 28, 114 emergency_wakeup_cpu_temp: 88, 115 temp_thresholds: { 116 optimal: { inlet_temp: 24, target_ac_temp: 24, fan: 0 }, 117 warm: { inlet_temp: 28, cpu_temp: 85, target_ac_temp: 24, fan: 2 }, 118 emergency_high: { inlet_temp: 30, cpu_temp: 92, target_ac_temp: 21, fan: 3 }, 119 cool: { inlet_temp: 22, target_ac_temp: 26, fan: 1 } 120 } 121 } 122 }, 123 { 124 id: "continuous", 125 name: "Continuous Gentle Airflow", 126 badge: "Humidity & Dust Guard", 127 description: "Lowers auto-cutoff so AC stays ON with gentle continuous cir
127culation. Prevents room moisture accumulation and ensures steady face filtration.", 128 icon: Wind, 129 color: "text-amber-400", 130 bgGradient: "from-amber-950/40 via-zinc-950 to-zinc-950", 131 borderColor: "border-amber-500/40", 132 targetInlet: "22°C â 26°C", 133 coldCutoff: 16, 134 warmWakeup: 22, 135 cpuWakeup: 88, 136 optimalTemp: 24, 137 fanName: "Low (1)", 138 config: { 139 cold_cutoff_temp: 16, 140 warm_wakeup_temp: 22, 141 emergency_wakeup_cpu_temp: 88, 142 temp_thresholds: { 143 optimal: { inlet_temp: 22, target_ac_temp: 24, fan: 1 }, 144 warm: { inlet_temp: 26, cpu_temp: 85, target_ac_temp: 22, fan: 2 }, 145 emergency_high: { inlet_temp: 28, cpu_temp: 92, target_ac_temp: 19, fan: 3 }, 146 cool: { inlet_temp: 20, target_ac_temp: 26, fan: 1 } 147 } 148 } 149 } 150]; 151const getActiveProfileId = (cfg) => { 152 var _a, _b, _c, _d, _e, _f; 153 if (!cfg) return "winter_saver"; 154 for (const p of OPERATIONAL_PROFILES) { 155 const t = cfg.temp_thresholds; 156 const pt = p.config.temp_thresholds; 157 if (cfg.cold_cutoff_temp === p.config.cold_cutoff_temp && cfg.warm_wakeup_temp === p.config.warm_wakeup_temp && cfg.emergency_wakeup_cpu_temp === p.config.emergency_wakeup_cpu_temp && ((_a = t == null ? void 0 : t.optimal) == null ? void 0 : _a.inlet_temp) === pt.optimal.inlet_temp && ((_b = t == null ? void 0 : t.optimal) == null ? void 0 : _b.target_ac_temp) === pt.optimal.target_ac_temp && ((_c = t == null ? void 0 : t.optimal) == null ? void 0 : _c.fan) === pt.optimal.fan && ((_d = t == null ? void 0 : t.warm) == null ? void 0 : _d.inlet_temp) === pt.warm.inlet_temp && ((_e = t == null ? void 0 : t.warm) == null ? void 0 : _e.target_ac_temp) === pt.warm.target_ac_temp && ((_f = t == null ? void 0 : t.emergency_high) == null ? void 0 : _f.inlet_temp) === pt.emergency_high.inlet_temp) { 158 return p.id; 159 } 160 } 161 return "custom"; 162}; 163function ClimateControl() { 164 var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G, _H, _I, _J, _K, _L, _M, _N, _O, _P, _Q, _R, _S, _T, _U, _V, _W, _X, _Y, _Z, __, _$, _aa, _ba, _ca, _da, _ea, _fa, _ga, _ha, _ia, _ja, _ka, _la, _ma, _na, _oa, _pa, _qa, _ra, _sa, _ta, _ua, _va, _wa, _xa; 165 const [serversData, setServersData] = reactExports.useState(null); 166 const [selectedServer, setSelectedServer] = reactExports.useState("xc640"); 167 const [powerActionLoading, setPowerActionLoading] = reactExports.useState(false); 168 const [serverData, setServerData] = reactExports.useState(null); 169 const [acData, setAcData] = reactExports.useState(null); 170 const [guardianMode, setGuardianMode] = reactExports.useState("auto"); 171 const [config, setConfig] = reactExports.useState(null); 172 const [activeTier, setActiveTier] = reactExports.useState(null); 173 const [showAdvancedTuning, setShowAdvancedTuning] = reactExports.useState(false); 174 const [isConfigDirty, setIsConfigDirty] = reactExports.useState(false); 175 const configDirtyRef = reactExports.useRef(false); 176 const netModalOpenRef = reactExports.useRef(false); 177 const [logs, setLogs] = reactExports.useState([]); 178 const [loading, setLoading] = reactExports.useState(true); 179 const [saving, setSaving] = reactExports.useState(false); 180 const [autoRefresh, setAutoRefresh] = reactExports.useState(true); 181 const [feedback, setFeedback] = reactExports.useState(null); 182 const [activeTab, setActiveTab] = reactExports.useState("control"); 183 const [octopusStatus, setOctopusStatus] = reactExports.useState(null); 184 const [octopusReadings, setOctopusReadings] = reactExports.useState(null); 185 const [octopusRange, setOctopusRange] = reactExports.useState("24h"); 186 const [octopusViewMode, setOctopusViewMode] = reactExports.useState("intervals"); 187 const [octopusChartType, setOctopusChartType] = reactExports.useState("line"); 188 const [chartShowPower, setChartShowPower] = reactExports.useState(true); 189 const [chartShowCost, setChartShowCost] = reactExports.useState(true); 190 const [octopusLoading, setOctopusLoading] = reactExports.useState(false); 191 const [octopusSyncing, setOctopusSyncing] = reactExports.useState(false); 192 const [octopusModalOpen, setOctopusModalOpen] = reactExports.useState(false); 193 const [hoveredReading, setHoveredReading] = reactExports.useState(null); 194 const [hoveredReadingIndex, setHoveredReadingIndex] = reactExports.useState(null); 195 const [octAcctNumber, setOctAcctNumber] = reactExports.useState("A-277BFC94"); 196 const [octEmail, setOctEmail] = reactExports.useState("[email protected]"); 197 const [octPassword, setOctPassword] = reactExports.useState("64a2n~LnSFYU.T}"); 198 const [octShowPassword, setOctShowPassword] = reactExports.useState(false); 199 const [octTesting, setOctTesting] = reactExports.useState(false); 200 const [octTestResult, setOctTestResult] = reactExports.useState(null); 201 const [octSaving, setOctSaving] = reactExports.useState(false); 202 const [netModalOpen, setNetModalOpen] = reactExports.useState(false); 203 reactExports.useEffect(() => { 204 netModalOpenRef.current = netModalOpen; 205 }, [netModalOpen]); 206 const [netIp, setNetIp] = reactExports.useState("192.168.40.190"); 207 const [netPort, setNetPort] = reactExports.useState(54321); 208 const [netMac, setNetMac] = reactExports.useState("34:FA:1C:84:C8:8E"); 209 const [netToken, setNetToken] = reactExports.useState("a1d46a441e3724e023c36a9120249781"); 210 const [netDid, setNetDid] = reactExports.useState("2049601204"); 211 const [showToken, setShowToken] = reactExports.useState(false); 212 const [netTesting, setNetTesting] = reactExports.useState(false); 213 const [netTestResult, setNetTestResult] = reactExports.useState(null); 214 const [netSaving, setNetSaving] = reactExports.useState(false); 215 const [historyRange, setHistoryRange] = reactExports.useState("24h"); 216 const [historyData, setHistoryData] = reactExports.useState(null); 217 const [historyLoading, setHistoryLoading] = reactExports.useState(false); 218 const [hoveredIndex, setHoveredIndex] = reactExports.useState(null); 219 const [visibleSeries, setVisibleSeries] = reactExports.useState({ 220 inlet: true, 221 t440: true, 222 roomTemp: true, 223 roomHumidity: false, 224 exhaust: true, 225 cpu1: true, 226 cpu2: true, 227 target: true 228 }); 229 const fetchStatus = async () => { 230 try { 231 const rawRes = await api.get("/admin/climate/status"); 232 const data = (rawRes == null ? void 0 : rawRes.data) || rawRes; 233 if (data) { 234 if (data.servers) setServersData(data.servers); 235 if (data.server) setServerData(data.server); 236 if (data.ac) {
237 setAcData(data.ac); 238 if (!netModalOpenRef.current) { 239 if (data.ac.device_ip) setNetIp(data.ac.device_ip); 240 if (data.ac.device_port) setNetPort(data.ac.device_port); 241 if (data.ac.device_mac) setNetMac(data.ac.device_mac); 242 if (data.ac.device_did) setNetDid(data.ac.device_did); 243 } 244 } 245 if (data.guardian) { 246 setGuardianMode(data.guardian.mode || "auto"); 247 if (data.guardian.active_tier) { 248 setActiveTier(data.guardian.active_tier); 249 } 250 if (data.guardian.config && !configDirtyRef.current) { 251 setConfig(data.guardian.config); 252 if (data.guardian.config.device_token && !netModalOpenRef.current) { 253 setNetToken(data.guardian.config.device_token); 254 } 255 } 256 } 257 } 258 } catch (err) { 259 console.error("Failed to fetch climate status:", err); 260 } finally { 261 setLoading(false); 262 } 263 }; 264 const handleServerPower = async (serverId, action) => { 265 var _a2, _b2, _c2; 266 const actionLabels = { 267 on: "Power ON", 268 graceful_off: "Gracefully Shut Down", 269 cycle: "Reboot / Power Cycle" 270 }; 271 const srvName = ((_a2 = serversData == null ? void 0 : serversData[serverId]) == null ? void 0 : _a2.name) || (serverId === "xc640" ? "Dell XC640 (Node 2)" : "Dell T440 (Node 2B)"); 272 const isPrimary = serverId === "xc640";
273 let confirmMsg = `Are you sure you want to ${actionLabels[action]} ${srvName} via iDRAC?`; 274 if (isPrimary && (action === "graceful_off" || action === "cycle")) { 275 confirmMsg = `â ï¸ CRITICAL LIVE PRODUCTION WARNING! 276 277${srvName} is the PRIMARY LIVE PRODUCTION SERVER hosting the HamieNET website, PostgreSQL database, and Docker cluster. 278 279Executing '${actionLabels[action]}' will IMMEDIATELY disconnect your web session! 280 281` + (action === "graceful_off" ? `To power the server back on, you will need to access Dell iDRAC directly at https://192.168.40.10 or press the physical power button on the server chassis. 282 283` : `The server will reboot and services will resume once boot completes (~3-5 minutes). 284 285`) + `Do you want to proceed with ${actionLabels[action]}?`; 286 } 287 if (!window.confirm(confirmMsg)) { 288 return; 289 } 290 setPowerActionLoading(true); 291 try { 292 const res = await api.post("/admin/climate/server-power", { server_id: serverId, action }); 293 if (res == null ? void 0 : res.success) { 294 setFeedback({ 295 type: "success", 296 message: `iDRAC command '${actionLabels[action]}' sent to ${srvName}.` 297 }); 298 setTimeout(fetchStatus, 4e3); 299 } else { 300 setFeedback({ 301 type: "error", 302 message: (res == null ? void 0 : res.error) || "Failed to execute power action" 303 }); 304 } 305 } catch (err) { 306 setFeedback({ 307 type: "error", 308 message: ((_c2 = (_b2 = err == null ? void 0 : err.response) == null ? void 0 : _b2.data) == null ? void 0 : _c2.error) || err.message || "Power action failed" 309 }); 310 } finally { 311 setPowerActionLoading(false); 312 } 313 }; 314 const fetchHistory = async (rangeOverride) => { 315 const targetRange = rangeOverride || historyRange; 316 setHistoryLoading(true); 317 try { 318 const rawRes = await api.get(`/admin/climate/history?range=${targetRange}`); 319 const data = (rawRes == null ? void 0 : rawRes.data) || rawRes; 320 if (data && data.points) { 321 setHistoryData(data); 322 } 323 } catch (err) { 324 console.error("Failed to fetch climate history:", err); 325 } finally { 326 setHistoryLoading(false); 327 } 328 }; 329 const fetchLogs = async () => { 330 try { 331 const rawRes = await api.get("/admin/climate/logs?lines=40"); 332 const data = (rawRes == null ? void 0 : rawRes.data) || rawRes; 333 if (data == null ? void 0 : data.logs) { 334 setLogs(data.logs); 335 } 336 } catch (err) { 337 console.error("Failed to fetch climate logs:", err); 338 } 339 }; 340 const fetchOctopusStatus = async (force = false) => { 341 var _a2; 342 try { 343 const rawRes = await api.get(`/admin/climate/octopus/status${force ? "?force=true" : ""}`); 344 const data = (rawRes == null ? void 0 : rawRes.data) || rawRes; 345 if (data && data.success) { 346 setOctopusStatus(data); 347 if ((_a2 = data.account) == null ? void 0 : _a2.number) setOctAcctNumber(data.account.number); 348 } 349 } catch (err) { 350 console.error("Failed to fetch Octopus status:", err); 351 } 352 }; 353 const fetchOctopusReadings = async (range = octopusRange, force = false) => { 354 setOctopusLoading(true); 355 try { 356 const rawRes = await api.get(`/admin/climate/octopus/readings?range=${range}${force ? "&force=true" : ""}`); 357 const data = (rawRes == null ? void 0 : rawRes.data) || rawRes; 358 if (data && data.success) { 359 setOctopusReadings(data); 360 } 361 } catch (err) { 362 console.error("Failed to fetch Octopus readings:", err); 363 } finally { 364 setOctopusLoading(false); 365 } 366 }; 367 const handleOctopusSync = async () => { 368 setOctopusSyncing(true); 369 try { 370 const rawRes = await api.post("/admin/climate/octopus/refresh", { range: octopusRange }); 371 const data = (rawRes == null ? void 0 : rawRes.data) || rawRes; 372 if (data == null ? void 0 : data.status) setOctopusStatus(data.status); 373 if (data == null ? void 0 : data.readings) setOctopusReadings(data.readings); 374 showFeedback("success", "Smart meter telemetry synced from Octopus Energy"); 375 } catch (err) { 376 showFeedback("error", "Failed to sync with Octopus Energy"); 377 } finally { 378 setOctopusSyncing(false); 379 } 380 }; 381 const handleSaveOctopusConfig = async () => { 382 var _a2, _b2; 383 setOctSaving(true); 384 try { 385 await api.post("/admin/climate/octopus/config", { 386 accountNumber: octAcctNumber, 387 email: octEmail, 388 password: octPassword 389 }); 390 showFeedback("success", "Octopus Energy credentials saved successfully"); 391 setOctopusModalOpen(false); 392 fetchOctopusStatus(true); 393 fetchOctopusReadings(octopusRange, true); 394 } catch (err) { 395 showFeedback("error", ((_b2 = (_a2 = err.response) == null ? void 0 : _a2.data) == null ? void 0 : _b2.error) || "Failed to save Octopus credentials"); 396 } finally { 397 setOctSaving(false); 398 } 399 }; 400 const handleTestOctopusConnection = async () => { 401 setOctTesting(true); 402 setOctTestResult(null); 403 try { 404 const rawRes = await api.post("/admin/climate/octopus/test-connection", { 405 accountNumber: octAcctNumber, 406 email: octEmail, 407 password: octPassword 408 }); 409 const data = (rawRes == null ? void 0 : rawRes.data) || rawRes; 410 setOctTestResult(data); 411 if (data == null ? void 0 : data.success) { 412 showFeedback("success", `Handshake verified in ${data.latencyMs}ms!`); 413 } else { 414 showFeedback("error", (data == null ? void 0 : data.error) || "Connection test failed"); 415 } 416 } catch (err) { 417 setOctTestResult({ success: false, error: err.message }); 418 showFeedback("error", "Connection test request failed"); 419 } finally { 420 setOctTesting(false); 421 } 422 }; 423 reactExports.useEffect(() => { 424 const handleKeyDown = (e) => { 425 if (e.key === "Escape") { 426 if (netModalOpen) setNetModalOpen(false); 427 if (octopusModalOpen) setOctopusModalOpen(false); 428 } 429 }; 430 window.addEventListener("keydown", handleKeyDown); 431 return () => window.removeEventListener("keydown", handleKeyDown); 432 }, [netModalOpen, octopusModalOpen]); 433 reactExports.useEffect(() => { 434 fetchStatus(); 435 fetchHistory(historyRange); 436 if (activeTab === "logs") fetchLogs(); 437 if (activeTab === "octopus") { 438 fetchOctopusStatus(); 439 fetchOctopusReadings(octopusRange); 440 } 441 let interval = null; 442 if (autoRefresh) { 443 interval = setInterval(() => { 444 fetchStatus(); 445 if (activeTab === "history") fetchHistory(); 446 if (activeTab === "logs") fetchLogs(); 447 if (activeTab === "octopus") fetchOctopusStatus(); 448 }, 6e3); 449 } 450 return () => { 451 if (interval) clearInterval(interval); 452 }; 453 }, [autoRefresh, activeTab, historyRange, octopusRange]); 454 const showFeedback = (type, message) => { 455 setFeedback({ type, message }); 456 setTimeout(() => setFeedback(null), 4e3); 457 }; 458 const handleAcControl = async (payload) => { 459 var _a2, _b2; 460 setSaving(true); 461 try { 462 const rawRes = await api.post("/admin/climate/control", payload); 463 const data = (rawRes == null ? void 0 : rawRes.data) || rawRes; 464 if (data == null ? void 0 : data.ac) {
465 setAcData(data.ac); 466 } 467 showFeedback("success", "Air conditioner setting applied successfully"); 468 fetchStatus(); 469 } catch (err) { 470 showFeedback("error", ((_b2 = (_a2 = err.response) == null ? void 0 : _a2.data) == null ? void 0 : _b2.error) || err.message || "Failed to apply setting"); 471 } finally { 472 setSaving(false); 473 } 474 }; 475 const handleModeSwitch = async (newMode) => { 476 setSaving(true); 477 try { 478 await api.post("/admin/climate/mode", { mode: newMode }); 479 setGuardianMode(newMode); 480 showFeedback("success", `Guardian mode switched to ${newMode.toUpperCase()}`); 481 fetchStatus(); 482 } catch (err) { 483 showFeedback("error", "Failed to change guardian mode"); 484 } finally { 485 setSaving(false); 486 } 487 }; 488 const handleSaveConfig = async () => { 489 if (!config) return; 490 setSaving(true); 491 try { 492 await api.post("/admin/climate/config", { config }); 493 setIsConfigDirty(false); 494 configDirtyRef.current = false; 495 showFeedback("success", "Guardian thresholds updated & service restarted"); 496 fetchStatus(); 497 } catch (err) { 498 showFeedback("error", "Failed to update guardian configuration"); 499 } finally { 500 setSaving(false); 501 } 502 }; 503 const handleDiscardConfig = () => { 504 setIsConfigDirty(false); 505 configDirtyRef.current = false; 506 fetchStatus(); 507 showFeedback("success", "Changes discarded. Reverted to server configuration."); 508 }; 509 const handleRestartService = async () => { 510 setSaving(true); 511 try { 512 await api.post("/admin/climate/daemon/restart", {}); 513 showFeedback("success", "Thermal Guardian service restarted"); 514 fetchLogs(); 515 } catch (err) { 516 showFeedback("error", "Failed to restart guardian service"); 517 } finally { 518 setSaving(false); 519 } 520 }; 521 const handleTestConnection = async () => { 522 var _a2, _b2; 523 setNetTesting(true); 524 setNetTestResult(null); 525 try { 526 const rawRes = await api.post("/admin/climate/test-connection", { 527 ip: netIp, 528 port: netPort, 529 token: netToken 530 }); 531 const data = (rawRes == null ? void 0 : rawRes.data) || rawRes; 532 if (data == null ? void 0 : data.success) { 533 setNetTestResult({ 534 success: true, 535 message: `Verified! Model: ${data.model || "lmkj.acpartner.wsd001"}, DID: ${data.did}`, 536 latency_ms: data.latency_ms, 537 mac: data.mac 538 }); 539 if (data.mac) setNetMac(data.mac); 540 if (data.did) setNetDid(data.did); 541 showFeedback("success", `Local miIO handshake verified in ${data.latency_ms}ms!`); 542 } else { 543 setNetTestResult({ 544 success: false, 545 message: (data == null ? void 0 : data.error) || `Device at ${netIp}:${netPort} did not respond` 546 }); 547 showFeedback("error", `Handshake failed: ${(data == null ? void 0 : data.error) || "Device unreachable"}`); 548 } 549 } catch (err) { 550 setNetTestResult({ 551 success: false, 552 message: ((_b2 = (_a2 = err.response) == null ? void 0 : _a2.data) == null ? void 0 : _b2.error) || err.message || "Connection test failed" 553 }); 554 showFeedback("error", "Connection test failed"); 555 } finally { 556 setNetTesting(false); 557 } 558 }; 559 const handleSaveNetworkConfig = async () => { 560 var _a2, _b2; 561 setNetSaving(true); 562 try { 563 const rawRes = await api.post("/admin/climate/network-config", { 564 device_ip: netIp, 565 device_port: netPort, 566 device_mac: netMac, 567 device_token: netToken, 568 did: netDid 569 }); 570 const data = (rawRes == null ? void 0 : rawRes.data) || rawRes; 571 if (data == null ? void 0 : data.success) { 572 showFeedback("success", "Controller network settings saved & guardian restarted!"); 573 setNetModalOpen(false); 574 fetchStatus(); 575 } else { 576 showFeedback("error", (data == null ? void 0 : data.error) || "Failed to update network settings"); 577 } 578 } catch (err) { 579 showFeedback("error", ((_b2 = (_a2 = err.response) == null ? void 0 : _a2.data) == null ? void 0 : _b2.error) || err.message || "Save failed"); 580 } finally { 581 setNetSaving(false); 582 } 583 }; 584 const handleThresholdChange = (tier, field, val) => { 585 if (!(config == null ? void 0 : config.temp_thresholds)) return; 586 setConfig({ 587 ...config, 588 temp_thresholds: { 589 ...config.temp_thresholds, 590 [tier]: { 591 ...config.temp_thresholds[tier], 592 [field]: isNaN(val) ? 0 : val 593 } 594 } 595 }); 596 setIsConfigDirty(true); 597 configDirtyRef.current = true; 598 }; 599 const handleHysteresisChange = (field, val) => { 600 if (!config) return; 601 setConfig({ 602 ...config, 603 [field]: isNaN(val) ? 0 : val 604 }); 605 setIsConfigDirty(true); 606 configDirtyRef.current = true; 607 }; 608 const handleApplyProfile = (profileId) => {
609 const profile = OPERATIONAL_PROFILES.find((p) => p.id === profileId); 610 if (!profile || !config) return; 611 setConfig({ 612 ...config, 613 profile: profile.id, 614 cold_cutoff_temp: profile.config.cold_cutoff_temp, 615 warm_wakeup_temp: profile.config.warm_wakeup_temp, 616 emergency_wakeup_cpu_temp: profile.config.emergency_wakeup_cpu_temp, 617 temp_thresholds: { 618 ...config.temp_thresholds, 619 optimal: { ...profile.config.temp_thresholds.optimal }, 620 warm: { ...profile.config.temp_thresholds.warm }, 621 emergency_high: { ...profile.config.temp_thresholds.emergency_high }, 622 cool: { ...profile.config.temp_thresholds.cool } 623 } 624 }); 625 setIsConfigDirty(true); 626 configDirtyRef.current = true; 627 showFeedback("success", `Applied '${profile.name}' profile. Click 'Save & Apply' to commit to server.`); 628 }; 629 const handleResetProfile = () => { 630 const activeId = getActiveProfileId(config); 631 const targetId = activeId === "custom" ? "winter_saver" : activeId; 632 handleApplyProfile(targetId); 633 }; 634 const getInletColor = (temp) => { 635 if (temp === null) return "text-zinc-400"; 636 if (temp < 25) return "text-emerald-400"; 637 if (temp <= 27) return "text-amber-400"; 638 return "text-rose-400"; 639 }; 640 const getCpuColor = (temp) => { 641 if (temp === null) return "text-zinc-400"; 642 if (temp < 80) return "text-emerald-400"; 643 if (temp <= 88) return "text-amber-400"; 644 return "text-rose-400"; 645 }; 646 return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-6 max-w-7xl mx-auto pb-16", children: [ 647 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col md:flex-row md:items-center justify-between gap-4 bg-zinc-900/80 border border-zinc-800/80 p-5 rounded-2xl backdrop-blur-xl shadow-xl", children: [
648 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-4", children: [ 649 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "p-3 bg-cyan-500/10 border border-cyan-500/20 rounded-xl text-cyan-400", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Thermometer, { className: "w-8 h-8" }) }), 650 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 651 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3", children: [ 652 /* @__PURE__ */ jsxRuntimeExports.jsx("h1", { className: "text-xl font-bold text-white tracking-wide", children: "Server Room Climate & Thermal Guardian" }), 653 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "px-2.5 py-0.5 rounded-full text-xs font-semibold bg-cyan-500/10 text-cyan-400 border border-cyan-500/20", children: "JP Node (Dell XC640)" }) 654 ] }), 655 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-zinc-400 mt-1", children: "Real-time Dell iDRAC thermal telemetry linked to Xiaomi BOFON Smart AC controller" }) 656 ] }) 657 ] }),
658 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-wrap items-center gap-3 self-end md:self-center", children: [ 659 /* @__PURE__ */ jsxRuntimeExports.jsx( 660 "div", 661 { 662 className: `px-3.5 py-1.5 rounded-xl text-xs font-black flex items-center gap-2 border shadow-sm transition-all ${(acData == null ? void 0 : acData.power) ? "bg-emerald-500/15 border-emerald-500/40 text-emerald-300 shadow-emerald-950/40" : "bg-zinc-950/80 border-zinc-700/80 text-zinc-300"}`, 663 title: (acData == null ? void 0 : acData.power) ? "Air conditioner compressor is currently running" : "Air conditioner is currently powered off", 664 children: (acData == null ? void 0 : acData.power) ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [ 665 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "relative flex h-2.5 w-2.5", children: [ 666 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "animate-ping absolute inline-flex h-full w-full rounded-full bg-emerald-400 opacity-75" }),
667 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "relative inline-flex rounded-full h-2.5 w-2.5 bg-emerald-500" }) 668 ] }), 669 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "tracking-wide", children: [ 670 "AC: RUNNING (", 671 acData.target_temp ?? 22, 672 "°C ", 673 acData.mode_name || "Cool", 674 ")" 675 ] }) 676 ] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [ 677 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "w-2.5 h-2.5 rounded-full bg-zinc-500" }), 678 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-zinc-400 font-semibold tracking-wide", children: [ 679 "AC: ", 680 /* @__PURE__ */ jsxRuntimeExports.jsx("b", { className: "text-amber-400", children: "OFF" }), 681 " (STANDBY)" 682 ] }) 683 ] }) 684 } 685 ), 686 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center bg-zinc-950 p-1 rounded-xl border border-zinc-800", children: [
687 /* @__PURE__ */ jsxRuntimeExports.jsxs( 688 "button", 689 { 690 onClick: () => handleModeSwitch("auto"), 691 disabled: saving, 692 className: `px-3 py-1.5 rounded-lg text-xs font-semibold transition-all flex items-center gap-1.5 ${guardianMode === "auto" ? "bg-emerald-500/20 text-emerald-400 border border-emerald-500/40 shadow-sm" : "text-zinc-400 hover:text-zinc-200"}`, 693 children: [ 694 /* @__PURE__ */ jsxRuntimeExports.jsx(Shield, { className: "w-3.5 h-3.5" }), 695 "AI Auto Guardian" 696 ] 697 } 698 ), 699 /* @__PURE__ */ jsxRuntimeExports.jsxs( 700 "button", 701 { 702 onClick: () => handleModeSwitch("manual"), 703 disabled: saving, 704 className: `px-3 py-1.5 rounded-lg text-xs font-semibold transition-all flex items-center gap-1.5 ${guardianMode === "manual" ? "bg-amber-500/20 text-amber-400 border border-amber-500/40 shadow-sm" : "text-zinc-400 hover:text-zinc-200"}`, 705 children: [
706 /* @__PURE__ */ jsxRuntimeExports.jsx(SlidersVertical, { className: "w-3.5 h-3.5" }), 707 "Manual Override" 708 ] 709 } 710 ) 711 ] }), 712 /* @__PURE__ */ jsxRuntimeExports.jsx( 713 "button", 714 { 715 onClick: fetchStatus, 716 disabled: loading || saving, 717 className: "p-2.5 rounded-xl bg-zinc-800/80 hover:bg-zinc-700 text-zinc-300 border border-zinc-700/60 transition", 718 title: "Refresh Telemetry", 719 children: /* @__PURE__ */ jsxRuntimeExports.jsx(RefreshCw, { className: `w-4 h-4 ${loading ? "animate-spin text-cyan-400" : ""}` }) 720 } 721 ) 722 ] }) 723 ] }), 724 feedback && /* @__PURE__ */ jsxRuntimeExports.jsxs( 725 "div", 726 { 727 className: `p-4 rounded-xl border flex items-center gap-3 transition-all ${feedback.type === "success" ? "bg-emerald-950/40 border-emerald-500/30 text-emerald-300" : "bg-rose-950/40 border-rose-500/30 text-rose-300"}`, 728 children: [ 729 feedback.type === "success" ? /* @__P
729URE__ */ jsxRuntimeExports.jsx(CircleCheck, { className: "w-5 h-5 flex-shrink-0 text-emerald-400" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(TriangleAlert, { className: "w-5 h-5 flex-shrink-0 text-rose-400" }), 730 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm font-medium", children: feedback.message }) 731 ] 732 } 733 ), 734 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3 bg-zinc-900/80 border border-zinc-800 p-3.5 rounded-2xl shadow-md", children: [ 735 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [ 736 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-xs font-bold text-zinc-400 uppercase tracking-wider pl-1 flex items-center gap-1.5", children: [ 737 /* @__PURE__ */ jsxRuntimeExports.jsx(Server, { className: "w-3.5 h-3.5 text-cyan-400" }), 738 "Monitored Nodes:" 739 ] }), 740 /* @__PURE__ */ jsxRuntimeExports.jsxs( 741 "button", 742 { 743 onClick: () => setSelectedServer("xc640"), 744 className: `px-3.5 py-2 rounded-xl text-xs font-bold transition-all flex items-center gap-2.5 border ${selectedServer === "xc640" ? "bg-zinc-800 border-cyan-500/60 text-white shadow-md shadow-cyan-500/10" : "bg-zinc-950/40 border-zinc-800 text-zinc-400 hover:text-zinc-200"}`, 745 children: [
746 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: `w-2 h-2 rounded-full ${((_a = serversData == null ? void 0 : serversData.xc640) == null ? void 0 : _a.power_state) === "On" ? "bg-emerald-400 animate-pulse" : "bg-zinc-500"}` }), 747 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Node 2 (Dell XC640)" }), 748 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "px-1.5 py-0.5 text-[10px] rounded bg-emerald-500/20 text-emerald-300 font-mono", children: ((_b = serversData == null ? void 0 : serversData.xc640) == null ? void 0 : _b.power_watts) !== void 0 ? `${serversData.xc640.power_watts}W` : (serverData == null ? void 0 : serverData.power_watts) ? `${serverData.power_watts}W` : "Active" }) 749 ] 750 } 751 ), 752 /* @__PURE__ */ jsxRuntimeExports.jsxs( 753 "button", 754 { 755 onClick: () => setSelectedServer("t440"), 756 className: `px-3.5 py-2 rounded-xl text-xs font-bold transition-all flex items-center gap-2.5 border ${selectedServer === "t440" ? "bg-zinc-800 border-purple-500/60 text-white shadow-md shadow-purple-500/10" : "bg-zinc-950/40 border-zinc-800 text-zinc-400 hover:text-zinc-200"}`, 757 children: [
758 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: `w-2 h-2 rounded-full ${((_c = serversData == null ? void 0 : serversData.t440) == null ? void 0 : _c.power_state) === "On" ? "bg-emerald-400 animate-pulse" : "bg-amber-500"}` }), 759 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Node 2B (Dell T440)" }), 760 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "px-1.5 py-0.5 text-[10px] rounded bg-amber-500/20 text-amber-300 font-mono", children: ((_d = serversData == null ? void 0 : serversData.t440) == null ? void 0 : _d.power_state) === "On" ? `${serversData.t440.power_watts}W` : ((_e = serversData == null ? void 0 : serversData.t440) == null ? void 0 : _e.power_watts) !== void 0 ? `Standby ${serversData.t440.power_watts}W` : "Standby 8W" }) 761 ] 762 } 763 ) 764 ] }), 765 selectedServer === "t440" ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3", children: [ 766 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-xs text-zinc-400 font-medium", children: [ 767 "Service Tag: ",
768 /* @__PURE__ */ jsxRuntimeExports.jsx("b", { className: "text-zinc-200 font-mono", children: ((_f = serversData == null ? void 0 : serversData.t440) == null ? void 0 : _f.service_tag) || "BGN9BQ2" }) 769 ] }), 770 ((_g = serversData == null ? void 0 : serversData.t440) == null ? void 0 : _g.power_state) === "Off" ? /* @__PURE__ */ jsxRuntimeExports.jsxs( 771 "button", 772 { 773 onClick: () => handleServerPower("t440", "on"), 774 disabled: powerActionLoading, 775 className: "px-3.5 py-1.5 rounded-xl bg-emerald-600 hover:bg-emerald-500 text-white text-xs font-bold transition flex items-center gap-1.5 shadow-sm shadow-emerald-500/20", 776 children: [ 777 /* @__PURE__ */ jsxRuntimeExports.jsx(Power, { className: "w-3.5 h-3.5" }), 778 powerActionLoading ? "Sending Command..." : "Power On T440 (iDRAC)" 779 ] 780 } 781 ) : /* @__PURE__ */ jsxRuntimeExports.jsxs( 782 "button", 783 { 784 onClick: () => handleServerPower("t440", "graceful_off"), 785 disabled: powerActionLoading, 786 className: "px-3.5 py-1.5 rounded-xl bg-rose-600 hover:bg-rose-500 text-white text-xs font-bold transition flex items-center gap-1.5 shadow-sm shadow-rose-500/20", 787 children: [
788 /* @__PURE__ */ jsxRuntimeExports.jsx(Power, { className: "w-3.5 h-3.5" }), 789 powerActionLoading ? "Shutting down..." : "Graceful Shutdown (iDRAC)" 790 ] 791 } 792 ) 793 ] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-wrap items-center gap-3 text-xs text-zinc-400 font-medium", children: [ 794 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [ 795 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [ 796 "Service Tag: ", 797 /* @__PURE__ */ jsxRuntimeExports.jsx("b", { className: "text-zinc-200 font-mono", children: ((_h = serversData == null ? void 0 : serversData.xc640) == null ? void 0 : _h.service_tag) || "2CTM0R2" }) 798 ] }), 799 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "â¢" }), 800 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-emerald-400 font-semibold flex items-center gap-1", children: [ 801 /* @__P
801URE__ */ jsxRuntimeExports.jsx(CircleCheck, { className: "w-3.5 h-3.5" }), 802 " Primary Live Compute" 803 ] }) 804 ] }), 805 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center gap-2", children: ((_i = serversData == null ? void 0 : serversData.xc640) == null ? void 0 : _i.power_state) === "Off" ? /* @__PURE__ */ jsxRuntimeExports.jsxs( 806 "button", 807 { 808 onClick: () => handleServerPower("xc640", "on"), 809 disabled: powerActionLoading, 810 className: "px-3.5 py-1.5 rounded-xl bg-emerald-600 hover:bg-emerald-500 text-white text-xs font-bold transition flex items-center gap-1.5 shadow-sm shadow-emerald-500/20", 811 children: [ 812 /* @__PURE__ */ jsxRuntimeExports.jsx(Power, { className: "w-3.5 h-3.5" }), 813 powerActionLoading ? "Sending Command..." : "Power On XC640 (iDRAC)" 814 ] 815 } 816 ) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [ 817 /* @__P
817URE__ */ jsxRuntimeExports.jsxs( 818 "button", 819 { 820 onClick: () => handleServerPower("xc640", "cycle"), 821 disabled: powerActionLoading, 822 className: "px-3 py-1.5 rounded-xl bg-amber-600/80 hover:bg-amber-600 text-amber-100 text-xs font-bold transition flex items-center gap-1.5 shadow-sm border border-amber-500/40 cursor-pointer", 823 title: "Hardware Graceful Restart via Dell iDRAC", 824 children: [ 825 /* @__PURE__ */ jsxRuntimeExports.jsx(RotateCcw, { className: "w-3.5 h-3.5" }), 826 powerActionLoading ? "Processing..." : "Reboot (iDRAC)" 827 ] 828 } 829 ), 830 /* @__PURE__ */ jsxRuntimeExports.jsxs( 831 "button", 832 { 833 onClick: () => handleServerPower("xc640", "graceful_off"), 834 disabled: powerActionLoading, 835 className: "px-3 py-1.5 rounded-xl bg-rose-600/80 hover:bg-rose-600 text-white text-xs font-bold transition flex items-center gap-1.5 shadow-sm shadow-rose-500/20 border border-rose-500/40 cursor-pointer", 836 title: "Graceful Shutdown via Dell iDRAC (Halts web server and database)", 837 children: [
838 /* @__PURE__ */ jsxRuntimeExports.jsx(Power, { className: "w-3.5 h-3.5" }), 839 powerActionLoading ? "Shutting down..." : "Graceful Shutdown (iDRAC)" 840 ] 841 } 842 ) 843 ] }) }) 844 ] }) 845 ] }), 846 (() => { 847 const activeSrv = (serversData == null ? void 0 : serversData[selectedServer]) || (selectedServer === "xc640" ? { 848 power_state: "On", 849 inlet_temp: (serverData == null ? void 0 : serverData.inlet_temp) ?? null, 850 cpu1_temp: (serverData == null ? void 0 : serverData.cpu1_temp) ?? null, 851 cpu2_temp: (serverData == null ? void 0 : serverData.cpu2_temp) ?? null, 852 exhaust_temp: (serverData == null ? void 0 : serverData.exhaust_temp) ?? null, 853 power_watts: (serverData == null ? void 0 : serverData.power_watts) ?? null 854 } : { 855 power_state: "Off", 856 inlet_temp: 26, 857 cpu1_temp: 67, 858 cpu2_temp: null, 859 exhaust_temp: null, 860 power_watts: 8 861 }); 862 return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-2 md:grid-cols-4 gap-4", children: [
863 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-zinc-900/70 border border-zinc-800 p-4 rounded-2xl relative overflow-hidden", children: [ 864 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between", children: [ 865 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs font-medium text-zinc-400 uppercase tracking-wider", children: "Inlet Temp" }), 866 /* @__PURE__ */ jsxRuntimeExports.jsx(Thermometer, { className: `w-4 h-4 ${selectedServer === "t440" ? "text-purple-400" : "text-cyan-400"}` }) 867 ] }), 868 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-2 flex items-baseline gap-2", children: [ 869 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `text-3xl font-extrabold ${getInletColor(activeSrv.inlet_temp)}`, children: activeSrv.inlet_temp !== null && activeSrv.inlet_temp !== void 0 ? `${activeSrv.inlet_temp}°C` : "--" }), 870 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs text-zinc-500", children: "Optimal: 22-25°C" }) 871 ] }),
872 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-2 w-full bg-zinc-800 h-1.5 rounded-full overflow-hidden", children: /* @__PURE__ */ jsxRuntimeExports.jsx( 873 "div", 874 { 875 className: `h-full rounded-full transition-all duration-500 ${selectedServer === "t440" ? "bg-purple-400" : "bg-cyan-400"}`, 876 style: { width: `${Math.min(100, Math.max(0, ((activeSrv.inlet_temp || 20) - 15) * 5))}%` } 877 } 878 ) }) 879 ] }), 880 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-zinc-900/70 border border-zinc-800 p-4 rounded-2xl relative overflow-hidden", children: [ 881 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between", children: [ 882 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs font-medium text-zinc-400 uppercase tracking-wider", children: "CPU Temps" }), 883 /* @__PURE__ */ jsxRuntimeExports.jsx(Cpu, { className: "w-4 h-4 text-amber-400" }) 884 ] }),
885 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-2 flex items-baseline gap-3", children: [ 886 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-baseline gap-1", children: [ 887 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs text-zinc-400 font-mono", children: "C1:" }), 888 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `text-2xl font-bold ${getCpuColor(activeSrv.cpu1_temp)}`, children: activeSrv.cpu1_temp !== null && activeSrv.cpu1_temp !== void 0 ? `${activeSrv.cpu1_temp}°C` : "--" }) 889 ] }), 890 activeSrv.cpu2_temp !== null && activeSrv.cpu2_temp !== void 0 ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-baseline gap-1", children: [ 891 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs text-zinc-400 font-mono", children: "C2:" }), 892 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `text-2xl font-bold ${getCpuColor(activeSrv.cpu2_temp)}`, children: `${activeSrv.cpu2_temp}°C` }) 893 ] }) : /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[11px] text-zinc-500 font-medium", children: "Single Socket" }) 894 ] }),
895 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "mt-1 text-xs text-zinc-500", children: activeSrv.power_state === "Off" ? "Standby Thermal Sensor" : "Throttle limit: 96°C" }) 896 ] }), 897 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-zinc-900/70 border border-zinc-800 p-4 rounded-2xl relative overflow-hidden", children: [ 898 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between", children: [ 899 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs font-medium text-zinc-400 uppercase tracking-wider", children: "Exhaust Temp" }), 900 /* @__PURE__ */ jsxRuntimeExports.jsx(Wind, { className: "w-4 h-4 text-orange-400" }) 901 ] }), 902 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-2 flex items-baseline gap-2", children: [ 903 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-3xl font-extrabold text-zinc-200", children: activeSrv.exhaust_temp !== null && activeSrv.exhaust_temp !== void 0 ? `${activeSrv.exhaust_temp}°C` : "Standby" }),
904 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs text-zinc-500", children: activeSrv.exhaust_temp ? "Chassis Rear" : "Passive Air" }) 905 ] }), 906 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "mt-1 text-xs text-zinc-500", children: selectedServer === "t440" ? "Tower / Rack Airflow" : "16x Fans Active" }) 907 ] }), 908 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-zinc-900/70 border border-zinc-800 p-4 rounded-2xl relative overflow-hidden", children: [ 909 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between", children: [ 910 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs font-medium text-zinc-400 uppercase tracking-wider", children: "Chassis Power" }), 911 /* @__PURE__ */ jsxRuntimeExports.jsx(Zap, { className: "w-4 h-4 text-yellow-400" }) 912 ] }), 913 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-2 flex items-baseline gap-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-3xl font-extrabold text-yellow-400 font-mono", children: activeSrv.power_watts !== null && activeSrv.power_watts !== void 0 ? `${activeSrv.power_watts} W` : "--" }) }),
914 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "mt-1 text-xs text-zinc-500", children: activeSrv.power_state === "Off" ? "Standby Idle (iDRAC9 Active)" : "PSU 750W (100V AC)" }) 915 ] }) 916 ] }); 917 })(), 918 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 border-b border-zinc-800 pb-1", children: [ 919 /* @__PURE__ */ jsxRuntimeExports.jsxs( 920 "button", 921 { 922 onClick: () => setActiveTab("control"), 923 className: `px-4 py-2 text-sm font-semibold rounded-t-xl transition-all flex items-center gap-2 border-b-2 ${activeTab === "control" ? "text-cyan-400 border-cyan-400 bg-zinc-900/60" : "text-zinc-400 border-transparent hover:text-zinc-200"}`, 924 children: [ 925 /* @__PURE__ */ jsxRuntimeExports.jsx(Snowflake, { className: "w-4 h-4" }), 926 "AC Remote Console" 927 ] 928 } 929 ), 930 /* @__PURE__ */ jsxRuntimeExports.jsxs( 931 "button", 932 { 933 onClick: () => { 934 setActiveTab("history"); 935 fetchHistory(); 936 }, 937 className: `px-4 py-2 text-sm font-semibold rounded-t-xl transition-all flex items-center gap-2 border-b-2 ${activeTab === "history" ? "text-cyan-400 border-cyan-400 bg-zinc-900/60" : "text-zinc-400 border-transparent hover:text-zinc-200"}`, 938 children: [
939 /* @__PURE__ */ jsxRuntimeExports.jsx(TrendingUp, { className: "w-4 h-4" }), 940 "Thermal & Power History" 941 ] 942 } 943 ), 944 /* @__PURE__ */ jsxRuntimeExports.jsxs( 945 "button", 946 { 947 onClick: () => { 948 setActiveTab("octopus"); 949 fetchOctopusStatus(); 950 fetchOctopusReadings(octopusRange); 951 }, 952 className: `px-4 py-2 text-sm font-semibold rounded-t-xl transition-all flex items-center gap-2 border-b-2 ${activeTab === "octopus" ? "text-amber-400 border-amber-400 bg-zinc-900/60" : "text-zinc-400 border-transparent hover:text-zinc-200"}`, 953 children: [ 954 /* @__PURE__ */ jsxRuntimeExports.jsx(Zap, { className: "w-4 h-4 text-amber-400" }), 955 "Octopus Energy" 956 ] 957 } 958 ), 959 /* @__PURE__ */ jsxRuntimeExports.jsxs( 960 "button", 961 { 962 onClick: () => setActiveTab("guardian"), 963 className: `px-4 py-2 text-sm font-semibold rounded-t-xl transition-all flex items-center gap-2 border-b-2 ${activeTab === "guardian" ? "text-cyan-400 border-cyan-400 bg-zinc-900/60" : "text-zinc-400 border-transparent hover:text-zinc-200"}`, 964 children: [
965 /* @__PURE__ */ jsxRuntimeExports.jsx(Shield, { className: "w-4 h-4" }), 966 "Guardian Thresholds & Policy" 967 ] 968 } 969 ), 970 /* @__PURE__ */ jsxRuntimeExports.jsxs( 971 "button", 972 { 973 onClick: () => { 974 setActiveTab("logs"); 975 fetchLogs(); 976 }, 977 className: `px-4 py-2 text-sm font-semibold rounded-t-xl transition-all flex items-center gap-2 border-b-2 ${activeTab === "logs" ? "text-cyan-400 border-cyan-400 bg-zinc-900/60" : "text-zinc-400 border-transparent hover:text-zinc-200"}`, 978 children: [ 979 /* @__PURE__ */ jsxRuntimeExports.jsx(Terminal, { className: "w-4 h-4" }), 980 "Thermal Audit Logs" 981 ] 982 } 983 ), 984 /* @__PURE__ */ jsxRuntimeExports.jsxs( 985 "button", 986 { 987 onClick: () => setActiveTab("docs"), 988 className: `px-4 py-2 text-sm font-semibold rounded-t-xl transition-all flex items-center gap-2 border-b-2 ${activeTab === "docs" ? "text-cyan-400 border-cyan-400 bg-zinc-900/60" : "text-zinc-400 border-transparent hover:text-zinc-200"}`, 989 children: [
990 /* @__PURE__ */ jsxRuntimeExports.jsx(BookOpen, { className: "w-4 h-4" }), 991 "Policy Guide & Docs" 992 ] 993 } 994 ) 995 ] }), 996 activeTab === "control" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-1 lg:grid-cols-3 gap-6", children: [ 997 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "lg:col-span-2 bg-zinc-900/80 border border-zinc-800 p-6 rounded-2xl shadow-xl space-y-6", children: [ 998 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex flex-col sm:flex-row sm:items-center justify-between gap-4", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-start gap-3", children: [ 999 /* @__PURE__ */ jsxRuntimeExports.jsx( 1000 "div", 1001 { 1002 className: `w-3.5 h-3.5 mt-1 rounded-full ${(acData == null ? void 0 : acData.power) ? "bg-emerald-400 animate-pulse" : "bg-zinc-600"}` 1003 } 1004 ), 1005 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1.5", children: [
1006 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [ 1007 /* @__PURE__ */ jsxRuntimeExports.jsx("h2", { className: "text-base font-bold text-white", children: "BOFON Air Conditioner Console" }), 1008 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "px-2 py-0.5 rounded-full text-[10px] font-bold bg-emerald-500/20 text-emerald-400 border border-emerald-500/30 flex items-center gap-1", children: [ 1009 /* @__PURE__ */ jsxRuntimeExports.jsx(Wifi, { className: "w-2.5 h-2.5" }), 1010 (acData == null ? void 0 : acData.connection_mode) || "Local LAN Direct (miIO UDP)" 1011 ] }), 1012 (acData == null ? void 0 : acData.latency_ms) !== null && (acData == null ? void 0 : acData.latency_ms) !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "px-2 py-0.5 rounded-full text-[10px] font-mono text-cyan-400 bg-cyan-950/60 border border-cyan-800/40", children: [ 1013 acData.latency_ms, 1014 "ms" 1015 ] }) 1016 ] }),
1017 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-wrap items-center gap-x-3 gap-y-1 text-xs text-zinc-400", children: [ 1018 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1 font-mono", children: [ 1019 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-zinc-500 text-[11px]", children: "IP:" }), 1020 /* @__PURE__ */ jsxRuntimeExports.jsx("b", { className: "text-zinc-200", children: (acData == null ? void 0 : acData.device_ip) || (config == null ? void 0 : config.device_ip) || "192.168.40.190" }) 1021 ] }), 1022 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-zinc-700", children: "â¢" }), 1023 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1 font-mono", children: [ 1024 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-zinc-500 text-[11px]", children: "Port:" }), 1025 /* @__PURE__ */ jsxRuntimeExports.jsxs("b", { className: "text-zinc-200", children: [ 1026 (acData == null ? void 0 : acData.device_port) || (config == null ? void 0 : config.device_port) || 54321, 1027 " (UDP)" 1028 ] }) 1029 ] }),
1030 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-zinc-700", children: "â¢" }), 1031 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1 font-mono", children: [ 1032 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-zinc-500 text-[11px]", children: "MAC:" }), 1033 /* @__PURE__ */ jsxRuntimeExports.jsx("b", { className: "text-zinc-300", children: (acData == null ? void 0 : acData.device_mac) || (config == null ? void 0 : config.device_mac) || "34:FA:1C:84:C8:8E" }) 1034 ] }), 1035 /* @__PURE__ */ jsxRuntimeExports.jsxs( 1036 "button", 1037 { 1038 onClick: () => { 1039 setNetIp((acData == null ? void 0 : acData.device_ip) || (config == null ? void 0 : config.device_ip) || "192.168.40.190"); 1040 setNetPort((acData == null ? void 0 : acData.device_port) || (config == null ? void 0 : config.device_port) || 54321); 1041 setNetMac((acData == null ? void 0 : acData.device_mac) || (config == null ? void 0 : config.device_mac) || "34:FA:1C:84:C8:8E"); 1042 setNetToken((config == null ? void 0 : config.device_token) || "a1d46a441e3724e023c36a9120249781"); 1043 setNetDid((acData == null ? void 0 : acData.device_did) || (config == null ? void 0 : config.did) || "2049601204"); 1044 setNetTestResult(null); 1045 setNetModalOpen(true); 1046 }, 1047 className: "ml-1 text-[11px] font-semibold text-cyan-400 hover:text-cyan-300 underline underline-offset-2 flex items-center gap-1 cursor-pointer transition", 1048 children: [
1049 /* @__PURE__ */ jsxRuntimeExports.jsx(Settings, { className: "w-3 h-3" }), 1050 "Configure Network" 1051 ] 1052 } 1053 ) 1054 ] }) 1055 ] }) 1056 ] }) }), 1057 /* @__PURE__ */ jsxRuntimeExports.jsxs( 1058 "div", 1059 { 1060 className: `p-4 rounded-2xl border transition-all flex flex-col sm:flex-row sm:items-center justify-between gap-4 shadow-xl ${(acData == null ? void 0 : acData.power) ? "bg-gradient-to-r from-emerald-950/70 via-zinc-900 to-emerald-950/40 border-emerald-500/50 shadow-emerald-950/30" : "bg-gradient-to-r from-zinc-950 via-zinc-900 to-amber-950/20 border-zinc-700/80 shadow-black/40"}`, 1061 children: [ 1062 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3.5", children: [ 1063 /* @__PURE__ */ jsxRuntimeExports.jsx( 1064 "div", 1065 { 1066 className: `p-3 rounded-2xl border ${(acData == null ? void 0 : acData.power) ? "bg-emerald-500/20 border-emerald-500/40 text-emerald-300" : "bg-zinc-800/80 border-zinc-700 text-zinc-400"}`, 1067 children: /* @__PURE__ */ jsxRuntimeExports.jsx(Power, { className: `w-6 h-6 ${(acData == null ? void 0 : acData.power) ? "animate-pulse" : ""}` }) 1068 } 1069 ),
1070 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-0.5", children: [ 1071 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [ 1072 /* @__PURE__ */ jsxRuntimeExports.jsx( 1073 "span", 1074 { 1075 className: `text-base font-black tracking-wide ${(acData == null ? void 0 : acData.power) ? "text-emerald-400" : "text-zinc-200"}`, 1076 children: (acData == null ? void 0 : acData.power) ? "AIR CONDITIONER IS RUNNING" : "AIR CONDITIONER IS OFF (STANDBY)" 1077 } 1078 ), 1079 /* @__PURE__ */ jsxRuntimeExports.jsx( 1080 "span", 1081 { 1082 className: `px-2 py-0.5 rounded-full text-[10px] font-extrabold uppercase ${(acData == null ? void 0 : acData.power) ? "bg-emerald-500/20 text-emerald-300 border border-emerald-500/40" : "bg-zinc-800 text-zinc-400 border border-zinc-700"}`, 1083 children: (acData == null ? void 0 : acData.power) ? "Active Cooling" : "Standby Mode" 1084 } 1085 ) 1086 ] }),
1087 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-zinc-400", children: (acData == null ? void 0 : acData.power) ? /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [ 1088 "Cooling to ", 1089 /* @__PURE__ */ jsxRuntimeExports.jsxs("b", { className: "text-white", children: [ 1090 acData.target_temp ?? 22, 1091 "°C" 1092 ] }), 1093 " ⢠Fan:", 1094 " ", 1095 /* @__PURE__ */ jsxRuntimeExports.jsx("b", { className: "text-white", children: acData.fan_name || "Medium" }), 1096 " ⢠Room Ambient:", 1097 " ", 1098 /* @__PURE__ */ jsxRuntimeExports.jsx("b", { className: "text-emerald-300", children: acData.room_temp != null ? `${acData.room_temp}°C` : "--" }) 1099 ] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [ 1100 "Compressor is stopped (Power Saver) ⢠Guardian will auto-start AC if inlet reaches", 1101 " ",
1102 /* @__PURE__ */ jsxRuntimeExports.jsxs("b", { className: "text-amber-300", children: [ 1103 (config == null ? void 0 : config.warm_wakeup_temp) ?? 25, 1104 "°C" 1105 ] }) 1106 ] }) }) 1107 ] }) 1108 ] }), 1109 /* @__PURE__ */ jsxRuntimeExports.jsxs( 1110 "button", 1111 { 1112 onClick: () => handleAcControl({ power: !(acData == null ? void 0 : acData.power) }), 1113 disabled: saving, 1114 className: `px-5 py-2.5 rounded-xl text-sm font-black transition-all flex items-center justify-center gap-2 shadow-xl cursor-pointer shrink-0 ${(acData == null ? void 0 : acData.power) ? "bg-rose-950/70 hover:bg-rose-900 border border-rose-500/50 text-rose-200 shadow-rose-950/40" : "bg-emerald-500 hover:bg-emerald-400 text-zinc-950 font-black shadow-emerald-500/30"}`, 1115 children: [ 1116 /* @__PURE__ */ jsxRuntimeExports.jsx(Power, { className: "w-4 h-4" }), 1117 (acData == null ? void 0 : acData.power) ? "TURN AC OFF" : "TURN AC ON NOW" 1118 ] 1119 } 1120 ) 1121 ] 1122 } 1123 ),
1124 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-zinc-950/60 border border-zinc-800/80 p-6 rounded-2xl flex flex-col md:flex-row items-center justify-between gap-6", children: [ 1125 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-6", children: [ 1126 /* @__PURE__ */ jsxRuntimeExports.jsx( 1127 "div", 1128 { 1129 className: `relative flex flex-col items-center justify-center w-36 h-36 rounded-full border-4 shadow-inner transition-all ${(acData == null ? void 0 : acData.power) ? "border-cyan-500/40 bg-cyan-950/20 shadow-cyan-950/50" : "border-zinc-700/80 bg-zinc-950/80 opacity-80"}`, 1130 children: (acData == null ? void 0 : acData.power) ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [ 1131 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-4xl font-extrabold text-white tracking-tight", children: [ 1132 (acData == null ? void 0 : acData.target_temp) ?? 24, 1133 "°" 1134 ] }),
1135 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] uppercase font-bold text-cyan-400 tracking-wider mt-0.5", children: "Active Cooling" }) 1136 ] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [ 1137 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "px-2 py-0.5 rounded-md text-[10px] font-black uppercase bg-zinc-800 border border-zinc-600 text-zinc-300 mb-1", children: "OFF / STANDBY" }), 1138 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-3xl font-bold text-zinc-400", children: [ 1139 (acData == null ? void 0 : acData.target_temp) ?? 24, 1140 "°" 1141 ] }), 1142 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[9px] uppercase font-bold text-zinc-500 tracking-wider", children: "Set Target" }) 1143 ] }) 1144 } 1145 ), 1146 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-2", children: [
1147 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [ 1148 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs font-semibold text-zinc-400", children: "Set Temperature" }), 1149 !(acData == null ? void 0 : acData.power) && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] text-zinc-500 font-medium", children: "(Pre-set)" }) 1150 ] }), 1151 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [ 1152 /* @__PURE__ */ jsxRuntimeExports.jsx( 1153 "button", 1154 { 1155 onClick: () => handleAcControl({ target_temp: Math.max(16, ((acData == null ? void 0 : acData.target_temp) || 24) - 1) }), 1156 disabled: saving || ((acData == null ? void 0 : acData.target_temp) || 24) <= 16, 1157 className: "w-10 h-10 rounded-xl bg-zinc-800 hover:bg-zinc-700 text-zinc-100 font-bold text-lg border border-zinc-700/80 transition flex items-center justify-center", 1158 children: "-" 1159 } 1160 ),
1161 /* @__PURE__ */ jsxRuntimeExports.jsx( 1162 "input", 1163 { 1164 type: "range", 1165 min: "16", 1166 max: "30", 1167 step: "1", 1168 value: (acData == null ? void 0 : acData.target_temp) || 24, 1169 onChange: (e) => handleAcControl({ target_temp: parseInt(e.target.value, 10) }), 1170 className: "w-32 md:w-44 accent-cyan-400 cursor-pointer" 1171 } 1172 ), 1173 /* @__PURE__ */ jsxRuntimeExports.jsx( 1174 "button", 1175 { 1176 onClick: () => handleAcControl({ target_temp: Math.min(30, ((acData == null ? void 0 : acData.target_temp) || 24) + 1) }), 1177 disabled: saving || ((acData == null ? void 0 : acData.target_temp) || 24) >= 30, 1178 className: "w-10 h-10 rounded-xl bg-zinc-800 hover:bg-zinc-700 text-zinc-100 font-bold text-lg border border-zinc-700/80 transition flex items-center justify-center", 1179 children: "+" 1180 } 1181 ) 1182 ] }) 1183 ] }) 1184 ] }),
1185 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "grid grid-cols-2 gap-2 w-full md:w-auto", children: PRESETS.map((p) => /* @__PURE__ */ jsxRuntimeExports.jsxs( 1186 "button", 1187 { 1188 onClick: () => handleAcControl({ power: true, mode: 0, target_temp: p.temp, fan: p.fan }), 1189 disabled: saving, 1190 className: `p-2.5 rounded-xl border text-left transition-all ${(acData == null ? void 0 : acData.target_temp) === p.temp && (acData == null ? void 0 : acData.power) ? "bg-cyan-500/20 border-cyan-500/50 text-cyan-300 shadow-md" : "bg-zinc-900 border-zinc-800 text-zinc-300 hover:bg-zinc-800/80"}`, 1191 children: [ 1192 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-xs font-bold", children: p.label }), 1193 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[10px] text-zinc-400 mt-0.5", children: p.desc }) 1194 ] 1195 }, 1196 p.label 1197 )) }) 1198 ] }), 1199 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4", children: [
1200 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-zinc-950/40 border border-zinc-800/80 p-4 rounded-xl space-y-3", children: [ 1201 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs font-semibold text-zinc-400 uppercase tracking-wider", children: "Operating Mode" }), 1202 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "grid grid-cols-3 gap-2", children: AC_MODES.slice(0, 3).map((m) => { 1203 const Icon = m.icon; 1204 const isSelected = (acData == null ? void 0 : acData.mode) === m.id; 1205 return /* @__PURE__ */ jsxRuntimeExports.jsxs( 1206 "button", 1207 { 1208 onClick: () => handleAcControl({ mode: m.id }), 1209 disabled: saving, 1210 className: `p-3 rounded-xl border flex flex-col items-center gap-1.5 transition-all ${isSelected ? "bg-cyan-500/20 border-cyan-500 text-cyan-300 font-bold" : "bg-zinc-900 border-zinc-800/80 text-zinc-400 hover:bg-zinc-800/60"}`, 1211 children: [
1212 /* @__PURE__ */ jsxRuntimeExports.jsx(Icon, { className: `w-5 h-5 ${m.color}` }), 1213 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs", children: m.name }) 1214 ] 1215 }, 1216 m.id 1217 ); 1218 }) }) 1219 ] }), 1220 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-zinc-950/40 border border-zinc-800/80 p-4 rounded-xl space-y-3", children: [ 1221 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs font-semibold text-zinc-400 uppercase tracking-wider", children: "Fan Airflow Speed" }), 1222 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "grid grid-cols-4 gap-2", children: FAN_SPEEDS.map((f) => { 1223 const isSelected = (acData == null ? void 0 : acData.fan) === f.id; 1224 return /* @__PURE__ */ jsxRuntimeExports.jsxs( 1225 "button", 1226 { 1227 onClick: () => handleAcControl({ fan: f.id }), 1228 disabled: saving, 1229 className: `p-3 rounded-xl border flex flex-col items-center gap-1.5 transition-all ${isSelected ? "bg-cyan-500/20 border-cyan-500 text-cyan-300 font-bold" : "bg-zinc-900 border-zinc-800/80 text-zinc-400 hover:bg-zinc-800/60"}`, 1230 children: [
1231 /* @__PURE__ */ jsxRuntimeExports.jsx(Wind, { className: "w-5 h-5 text-blue-400" }), 1232 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs", children: f.name }) 1233 ] 1234 }, 1235 f.id 1236 ); 1237 }) }) 1238 ] }) 1239 ] }) 1240 ] }), 1241 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-6", children: [ 1242 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-zinc-900/80 border border-zinc-800 p-6 rounded-2xl shadow-xl space-y-4", children: [ 1243 /* @__PURE__ */ jsxRuntimeExports.jsxs("h3", { className: "text-sm font-bold text-white flex items-center gap-2", children: [ 1244 /* @__PURE__ */ jsxRuntimeExports.jsx(Droplets, { className: "w-4 h-4 text-cyan-400" }), 1245 "Room Ambient Environment" 1246 ] }), 1247 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-2 gap-4", children: [ 1248 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-zinc-950 p-4 rounded-xl border border-zinc-800 text-center", children: [
1249 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs text-zinc-400", children: "Room Ambient" }), 1250 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-2xl font-bold text-white mt-1", children: (acData == null ? void 0 : acData.room_temp) != null ? `${acData.room_temp}°C` : "--" }) 1251 ] }), 1252 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-zinc-950 p-4 rounded-xl border border-zinc-800 text-center", children: [ 1253 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs text-zinc-400", children: "Humidity" }), 1254 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-2xl font-bold text-white mt-1", children: (acData == null ? void 0 : acData.room_humidity) != null ? `${acData.room_humidity}%` : "--" }) 1255 ] }) 1256 ] }), 1257 (() => { 1258 var _a2; 1259 const pts = ((_a2 = historyData == null ? void 0 : historyData.points) == null ? void 0 : _a2.filter((p) => p.room_temp != null)) || []; 1260 if (pts.length < 2) return null; 1261 const w = 320; 1262 const h = 64; 1263 const temps = pts.map((p) => p.room_temp); 1264 const minT = Math.floor(Math.min(...temps) - 1); 1265 const maxT = Math.ceil(Math.max(...temps) + 1); 1266 const span = Math.max(1, maxT - minT); 1267 const getMiniX = (idx) => idx / (pts.length - 1) * w; 1268 const getMiniY = (temp) => h - (temp - minT) / span * (h - 12) - 6; 1269 const linePath = pts.map((p, i) => `${i === 0 ? "M" : "L"} ${getMiniX(i).toFixed(1)},${getMiniY(p.room_temp).toFixed(1)}`).join(" "); 1270 const areaPath = `${linePath} L ${w},${h} L 0,${h} Z`; 1271 return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-zinc-950 p-3 rounded-xl border border-zinc-800 space-y-1.5", children: [
1272 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between text-[11px] text-zinc-400", children: [ 1273 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-semibold text-zinc-300 flex items-center gap-1.5", children: [ 1274 /* @__PURE__ */ jsxRuntimeExports.jsx(TrendingUp, { className: "w-3.5 h-3.5 text-emerald-400" }), 1275 "24h Room Ambient Trend" 1276 ] }), 1277 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono text-[10px] text-zinc-500", children: [ 1278 "Min: ", 1279 /* @__PURE__ */ jsxRuntimeExports.jsxs("b", { className: "text-emerald-400", children: [ 1280 Math.min(...temps), 1281 "°C" 1282 ] }), 1283 " · Max: ", 1284 /* @__PURE__ */ jsxRuntimeExports.jsxs("b", { className: "text-rose-400", children: [ 1285 Math.max(...temps), 1286 "°C" 1287 ] }) 1288 ] }) 1289 ] }),
1290 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-full h-14 relative", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("svg", { viewBox: `0 0 ${w} ${h}`, className: "w-full h-full overflow-hidden", preserveAspectRatio: "none", children: [ 1291 /* @__PURE__ */ jsxRuntimeExports.jsx("defs", { children: /* @__PURE__ */ jsxRuntimeExports.jsxs("linearGradient", { id: "miniRoomGrad", x1: "0", y1: "0", x2: "0", y2: "1", children: [ 1292 /* @__PURE__ */ jsxRuntimeExports.jsx("stop", { offset: "0%", stopColor: "#10b981", stopOpacity: "0.35" }), 1293 /* @__PURE__ */ jsxRuntimeExports.jsx("stop", { offset: "100%", stopColor: "#10b981", stopOpacity: "0.0" }) 1294 ] }) }), 1295 /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: areaPath, fill: "url(#miniRoomGrad)" }), 1296 /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: linePath, fill: "none", stroke: "#10b981", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) 1297 ] }) }) 1298 ] }); 1299 })(),
1300 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-3 bg-zinc-950/80 rounded-xl border border-zinc-800 text-xs text-zinc-400 space-y-2", children: [ 1301 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between items-center pb-1.5 border-b border-zinc-800/80", children: [ 1302 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-semibold text-zinc-300", children: "AC Hardware Power:" }), 1303 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: `font-black flex items-center gap-1.5 ${(acData == null ? void 0 : acData.power) ? "text-emerald-400" : "text-amber-400"}`, children: [ 1304 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `w-2 h-2 rounded-full ${(acData == null ? void 0 : acData.power) ? "bg-emerald-400 animate-pulse" : "bg-amber-400"}` }), 1305 (acData == null ? void 0 : acData.power) ? "RUNNING (Cooling)" : "OFF (Standby)" 1306 ] }) 1307 ] }), 1308 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between", children: [
1309 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Thermal Differential:" }), 1310 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-semibold text-zinc-200", children: (serverData == null ? void 0 : serverData.inlet_temp) && (acData == null ? void 0 : acData.room_temp) ? `${(serverData.inlet_temp - acData.room_temp).toFixed(1)}°C` : "0°C" }) 1311 ] }), 1312 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between", children: [ 1313 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Guardian Daemon:" }), 1314 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-semibold text-emerald-400", children: "Active (Systemd)" }) 1315 ] }) 1316 ] }) 1317 ] }), 1318 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-zinc-900/80 border border-zinc-800 p-5 rounded-2xl space-y-3", children: [ 1319 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs font-semibold text-zinc-400 uppercase tracking-wider", children: "Service Maintenance" }),
1320 /* @__PURE__ */ jsxRuntimeExports.jsxs( 1321 "button", 1322 { 1323 onClick: handleRestartService, 1324 disabled: saving, 1325 className: "w-full p-2.5 rounded-xl bg-zinc-800 hover:bg-zinc-700 text-zinc-200 text-xs font-semibold border border-zinc-700 flex items-center justify-center gap-2 transition", 1326 children: [ 1327 /* @__PURE__ */ jsxRuntimeExports.jsx(RefreshCw, { className: "w-3.5 h-3.5" }), 1328 "Restart Thermal Guardian Service" 1329 ] 1330 } 1331 ) 1332 ] }) 1333 ] }) 1334 ] }), 1335 activeTab === "history" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-6", children: [ 1336 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-zinc-900/80 border border-zinc-800 p-6 rounded-2xl shadow-xl flex flex-col md:flex-row md:items-center justify-between gap-4", children: [ 1337 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 1338 /* @__PURE__ */ jsxRuntimeExports.jsxs("h2", { className: "text-base font-bold text-white flex items-center gap-2", children: [
1339 /* @__PURE__ */ jsxRuntimeExports.jsx(TrendingUp, { className: "w-5 h-5 text-cyan-400" }), 1340 "Environmental & Power Historical Trends" 1341 ] }), 1342 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-zinc-400 mt-0.5", children: "Continuous telemetry recorded via Dell Redfish & BOFON AC Partner" }) 1343 ] }), 1344 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3", children: [ 1345 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center bg-zinc-950 p-1 rounded-xl border border-zinc-800", children: TIME_RANGES.map((r) => /* @__PURE__ */ jsxRuntimeExports.jsx( 1346 "button", 1347 { 1348 onClick: () => { 1349 setHistoryRange(r.id); 1350 fetchHistory(r.id); 1351 }, 1352 className: `px-3 py-1.5 rounded-lg text-xs font-semibold transition ${historyRange === r.id ? "bg-cyan-500 text-white shadow-md shadow-cyan-500/20" : "text-zinc-400 hover:text-zinc-200"}`, 1353 children: r.label 1354 }, 1355 r.id 1356 )) }),
1357 /* @__PURE__ */ jsxRuntimeExports.jsx( 1358 "button", 1359 { 1360 onClick: () => fetchHistory(), 1361 disabled: historyLoading, 1362 className: "p-2 rounded-xl bg-zinc-800 hover:bg-zinc-700 text-zinc-300 border border-zinc-700 transition flex items-center justify-center", 1363 title: "Refresh Telemetry History", 1364 children: /* @__PURE__ */ jsxRuntimeExports.jsx(RefreshCw, { className: `w-4 h-4 ${historyLoading ? "animate-spin text-cyan-400" : ""}` }) 1365 } 1366 ) 1367 ] }) 1368 ] }), 1369 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-2 md:grid-cols-4 gap-4", children: [ 1370 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-zinc-900/80 border border-zinc-800 p-4 rounded-2xl", children: [ 1371 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between", children: [ 1372 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs font-semibold text-zinc-400 uppercase tracking-wider", children: "Inlet Temp" }),
1373 /* @__PURE__ */ jsxRuntimeExports.jsx(Thermometer, { className: "w-4 h-4 text-cyan-400" }) 1374 ] }), 1375 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-2 flex items-baseline gap-2", children: [ 1376 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-2xl font-bold text-white", children: ((_j = historyData == null ? void 0 : historyData.stats) == null ? void 0 : _j.avg_inlet) ? `${historyData.stats.avg_inlet}°C` : "--" }), 1377 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[11px] text-zinc-500", children: "avg" }) 1378 ] }), 1379 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-1 flex items-center gap-2 text-[11px] text-zinc-400", children: [ 1380 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [ 1381 "Min: ", 1382 /* @__PURE__ */ jsxRuntimeExports.jsxs("b", { className: "text-zinc-200", children: [ 1383 ((_k = historyData == null ? void 0 : historyData.stats) == null ? void 0 : _k.min_inlet) ?? "--", 1384 "°C" 1385 ] }) 1386 ] }),
1387 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "â¢" }), 1388 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [ 1389 "Max: ", 1390 /* @__PURE__ */ jsxRuntimeExports.jsxs("b", { className: "text-zinc-200", children: [ 1391 ((_l = historyData == null ? void 0 : historyData.stats) == null ? void 0 : _l.max_inlet) ?? "--", 1392 "°C" 1393 ] }) 1394 ] }) 1395 ] }) 1396 ] }), 1397 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-zinc-900/80 border border-zinc-800 p-4 rounded-2xl", children: [ 1398 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between", children: [ 1399 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs font-semibold text-zinc-400 uppercase tracking-wider", children: "Dual Xeon CPUs" }), 1400 /* @__PURE__ */ jsxRuntimeExports.jsx(Cpu, { className: "w-4 h-4 text-amber-400" }) 1401 ] }), 1402 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-2 flex items-baseline gap-2", children: [
1403 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-2xl font-bold text-amber-300", children: (serverData == null ? void 0 : serverData.cpu1_temp) ? `${serverData.cpu1_temp}°C` : "--" }), 1404 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[11px] text-zinc-500", children: "current peak" }) 1405 ] }), 1406 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-1 flex items-center gap-2 text-[11px] text-zinc-400", children: [ 1407 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [ 1408 "C1: ", 1409 /* @__PURE__ */ jsxRuntimeExports.jsxs("b", { className: "text-zinc-200", children: [ 1410 (serverData == null ? void 0 : serverData.cpu1_temp) ?? "--", 1411 "°C" 1412 ] }) 1413 ] }), 1414 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "â¢" }), 1415 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [ 1416 "C2: ", 1417 /* @__PURE__ */ jsxRuntimeExports.jsxs("b", { className: "text-zinc-200", children: [ 1418 (serverData == null ? void 0 : serverData.cpu2_temp) ?? "--", 1419 "°C" 1420 ] }) 1421 ] }) 1422 ] }) 1423 ] }),
1424 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-zinc-900/80 border border-zinc-800 p-4 rounded-2xl", children: [ 1425 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between", children: [ 1426 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs font-semibold text-zinc-400 uppercase tracking-wider", children: "Avg Power" }), 1427 /* @__PURE__ */ jsxRuntimeExports.jsx(Zap, { className: "w-4 h-4 text-yellow-400" }) 1428 ] }), 1429 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-2 flex items-baseline gap-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-2xl font-bold text-yellow-400 font-mono", children: ((_m = historyData == null ? void 0 : historyData.stats) == null ? void 0 : _m.avg_power) ? `${historyData.stats.avg_power} W` : "--" }) }), 1430 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-1 text-[11px] text-zinc-400", children: [ 1431 "Est: ",
1432 /* @__PURE__ */ jsxRuntimeExports.jsx("b", { className: "text-zinc-200", children: ((_n = historyData == null ? void 0 : historyData.stats) == null ? void 0 : _n.avg_power) ? `${(historyData.stats.avg_power * 24 / 1e3).toFixed(1)} kWh/day` : "--" }) 1433 ] }) 1434 ] }), 1435 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-zinc-900/80 border border-zinc-800 p-4 rounded-2xl", children: [ 1436 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between", children: [ 1437 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs font-semibold text-zinc-400 uppercase tracking-wider", children: "AC Duty Cycle" }), 1438 /* @__PURE__ */ jsxRuntimeExports.jsx(Activity, { className: "w-4 h-4 text-emerald-400" }) 1439 ] }), 1440 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-2 flex items-baseline gap-2", children: [ 1441 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-2xl font-bold text-emerald-400", children: ((_o = historyData == null ? void 0 : historyData.stats) == null ? void 0 : _o.duty_cycle_percent) !== void 0 ? `${historyData.stats.duty_cycle_percent}%` : "--" }),
1442 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[11px] text-zinc-500", children: "running" }) 1443 ] }), 1444 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-1 text-[11px] text-zinc-400", children: [ 1445 "Compressor: ", 1446 /* @__PURE__ */ jsxRuntimeExports.jsx("b", { className: "text-emerald-300", children: (acData == null ? void 0 : acData.power) ? "Active" : "Standby" }) 1447 ] }) 1448 ] }) 1449 ] }), 1450 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-zinc-900/80 border border-zinc-800 p-6 rounded-2xl shadow-xl space-y-4", children: [ 1451 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col sm:flex-row sm:items-center justify-between gap-3", children: [ 1452 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [ 1453 /* @__PURE__ */ jsxRuntimeExports.jsx(Thermometer, { className: "w-4 h-4 text-cyan-400" }), 1454 /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "text-sm font-bold text-white", children: "Temperature History (°C)" }) 1455 ] }),
1456 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-wrap items-center gap-2 text-xs", children: [ 1457 /* @__PURE__ */ jsxRuntimeExports.jsxs( 1458 "button", 1459 { 1460 onClick: () => setVisibleSeries((prev) => ({ ...prev, inlet: !prev.inlet })), 1461 className: `px-2.5 py-1 rounded-lg border flex items-center gap-1.5 transition ${visibleSeries.inlet ? "bg-cyan-500/20 border-cyan-500/60 text-cyan-300 font-semibold" : "bg-zinc-950 border-zinc-800 text-zinc-500"}`, 1462 children: [ 1463 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "w-2 h-2 rounded-full bg-cyan-400" }), 1464 "XC640 Inlet" 1465 ] 1466 } 1467 ), 1468 /* @__PURE__ */ jsxRuntimeExports.jsxs( 1469 "button", 1470 { 1471 onClick: () => setVisibleSeries((prev) => ({ ...prev, t440: !prev.t440 })), 1472 className: `px-2.5 py-1 rounded-lg border flex items-center gap-1.5 transition ${visibleSeries.t440 ? "bg-purple-500/20 border-purple-500/60 text-purple-300 font-semibold" : "bg-zinc-950 border-zinc-800 text-zinc-500"}`, 1473 children: [
1474 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "w-2 h-2 rounded-full bg-purple-400" }), 1475 "T440 Inlet (Standby)" 1476 ] 1477 } 1478 ), 1479 /* @__PURE__ */ jsxRuntimeExports.jsxs( 1480 "button", 1481 { 1482 onClick: () => setVisibleSeries((prev) => ({ ...prev, roomTemp: !prev.roomTemp })), 1483 className: `px-2.5 py-1 rounded-lg border flex items-center gap-1.5 transition ${visibleSeries.roomTemp ? "bg-emerald-500/20 border-emerald-500/60 text-emerald-300 font-semibold" : "bg-zinc-950 border-zinc-800 text-zinc-500"}`, 1484 children: [ 1485 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "w-2 h-2 rounded-full bg-emerald-400" }), 1486 "Room Ambient" 1487 ] 1488 } 1489 ), 1490 /* @__PURE__ */ jsxRuntimeExports.jsxs( 1491 "button", 1492 { 1493 onClick: () => setVisibleSeries((prev) => ({ ...prev, roomHumidity: !prev.roomHumidity })), 1494 className: `px-2.5 py-1 rounded-lg border flex items-center gap-1.5 transition ${visibleSeries.roomHumidity ? "bg-teal-500/20 border-teal-500/60 text-teal-300 font-semibold" : "bg-zinc-950 border-zinc-800 text-zinc-500"}`, 1495 children: [
1496 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "w-2 h-2 rounded-full bg-teal-400" }), 1497 "Room Humidity" 1498 ] 1499 } 1500 ), 1501 /* @__PURE__ */ jsxRuntimeExports.jsxs( 1502 "button", 1503 { 1504 onClick: () => setVisibleSeries((prev) => ({ ...prev, exhaust: !prev.exhaust })), 1505 className: `px-2.5 py-1 rounded-lg border flex items-center gap-1.5 transition ${visibleSeries.exhaust ? "bg-orange-500/20 border-orange-500/60 text-orange-300 font-semibold" : "bg-zinc-950 border-zinc-800 text-zinc-500"}`, 1506 children: [ 1507 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "w-2 h-2 rounded-full bg-orange-400" }), 1508 "XC640 Exhaust" 1509 ] 1510 } 1511 ), 1512 /* @__PURE__ */ jsxRuntimeExports.jsxs( 1513 "button", 1514 { 1515 onClick: () => setVisibleSeries((prev) => ({ ...prev, cpu1: !prev.cpu1 })), 1516 className: `px-2.5 py-1 rounded-lg border flex items-center gap-1.5 transition ${visibleSeries.cpu1 ? "bg-yellow-500/20 border-yellow-500/60 text-yellow-300 font-semibold" : "bg-zinc-950 border-zinc-800 text-zinc-500"}`, 1517 children: [
1518 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "w-2 h-2 rounded-full bg-yellow-400" }), 1519 "CPU 1" 1520 ] 1521 } 1522 ), 1523 /* @__PURE__ */ jsxRuntimeExports.jsxs( 1524 "button", 1525 { 1526 onClick: () => setVisibleSeries((prev) => ({ ...prev, cpu2: !prev.cpu2 })), 1527 className: `px-2.5 py-1 rounded-lg border flex items-center gap-1.5 transition ${visibleSeries.cpu2 ? "bg-fuchsia-500/20 border-fuchsia-500/60 text-fuchsia-300 font-semibold" : "bg-zinc-950 border-zinc-800 text-zinc-500"}`, 1528 children: [ 1529 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "w-2 h-2 rounded-full bg-fuchsia-400" }), 1530 "CPU 2" 1531 ] 1532 } 1533 ), 1534 /* @__PURE__ */ jsxRuntimeExports.jsxs( 1535 "button", 1536 { 1537 onClick: () => setVisibleSeries((prev) => ({ ...prev, target: !prev.target })), 1538 className: `px-2.5 py-1 rounded-lg border flex items-center gap-1.5 transition ${visibleSeries.target ? "bg-blue-500/20 border-blue-500/60 text-blue-300 font-semibold" : "bg-zinc-950 border-zinc-800 text-zinc-500"}`, 1539 children: [
1540 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "w-2 h-2 rounded-full bg-blue-400" }), 1541 "AC Target" 1542 ] 1543 } 1544 ) 1545 ] }) 1546 ] }), 1547 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "relative w-full h-72 bg-zinc-950/60 rounded-xl border border-zinc-800/80 p-3 select-none", children: !(historyData == null ? void 0 : historyData.points) || historyData.points.length === 0 ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "h-full flex items-center justify-center text-zinc-500 text-xs", children: historyLoading ? "Loading telemetry time-series..." : "No historical data points logged yet." }) : (() => { 1548 const points = historyData.points; 1549 const width = 800; 1550 const height = 240; 1551 const padLeft = 45; 1552 const padRight = 20; 1553 const padTop = 20; 1554 const padBottom = 30; 1555 const plotW = width - padLeft - padRight; 1556 const plotH = height - padTop - padBottom; 1557 const activeValues = []; 1558 points.forEach((p) => { 1559 if (visibleSeries.inlet && p.inlet_temp != null) activeValues.push(p.inlet_temp); 1560 if (visibleSeries.t440 && p.t440_inlet != null) activeValues.push(p.t440_inlet); 1561 if (visibleSeries.roomTemp && p.room_temp != null) activeValues.push(p.room_temp); 1562 if (visibleSeries.roomHumidity && p.room_humidity != null) activeValues.push(p.room_humidity); 1563 if (visibleSeries.exhaust && p.exhaust_temp != null) activeValues.push(p.exhaust_temp); 1564 if (visibleSeries.cpu1 && p.cpu1_temp != null) activeValues.push(p.cpu1_temp); 1565 if (visibleSeries.cpu2 && p.cpu2_temp != null) activeValues.push(p.cpu2_temp); 1566 if (visibleSeries.target && p.ac_target_temp != null) activeValues.push(p.ac_target_temp); 1567 }); 1568 const rawMin = activeValues.length > 0 ? Math.min(...activeValues) : 18; 1569 const rawMax = activeValues.length > 0 ? Math.max(...activeValues) : 32; 1570 const span = Math.max(2, rawMax - rawMin); 1571 const pad = Math.max(1.5, Math.ceil(span * 0.12)); 1572 const minTemp = Math.max(0, Math.floor(rawMin - pad)); 1573 const maxTemp = Math.ceil(rawMax + pad); 1574 const tempRange = Math.max(1, maxTemp - minTemp); 1575 const getY = (temp) => { 1576 if (temp === null || temp === void 0) return padTop + plotH; 1577 const clamped = Math.max(minTemp, Math.min(maxTemp, temp)); 1578 return padTop + plotH - (clamped - minTemp) / tempRange * plotH; 1579 }; 1580 const getX = (idx) => { 1581 return padLeft + idx / Math.max(1, points.length - 1) * plotW; 1582 }; 1583 const buildPath = (key) => { 1584 return points.map((p, i) => `${i === 0 ? "M" : "L"} ${getX(i).toFixed(1)},${getY(p[key]).toFixed(1)}`).join(" "); 1585 }; 1586 const step = (maxTemp - minTemp) / 4; 1587 const gridTemps = [ 1588 minTemp, 1589 Math.round(minTemp + step), 1590 Math.round(minTemp + step * 2), 1591 Math.round(minTemp + step * 3), 1592 maxTemp 1593 ]; 1594 const hoveredPoint = hoveredIndex !== null && hoveredIndex >= 0 && hoveredIndex < points.length ? points[hoveredIndex] : null; 1595 return /* @__PURE__ */ jsxRuntimeExports.jsxs( 1596 "div", 1597 { 1598 className: "relative w-full h-full cursor-crosshair", 1599 onMouseMove: (e) => { 1600 const rect = e.currentTarget.getBoundingClientRect(); 1601 if (!rect.width) return; 1602 const mouseX = e.clientX - rect.left; 1603 const svgX = mouseX / rect.width * width; 1604 if (svgX < padLeft - 10 || svgX > width - padRight + 10) { 1605 setHoveredIndex(null); 1606 return; 1607 } 1608 const plotRatio = (svgX - padLeft) / plotW; 1609 const clampedRatio = Math.max(0, Math.min(1, plotRatio)); 1610 const denom = Math.max(1, points.length - 1); 1611 const idx = Math.min( 1612 points.length - 1, 1613 Math.max(0, Math.round(clampedRatio * denom)) 1614 ); 1615 setHoveredIndex(idx); 1616 }, 1617 onMouseLeave: () => setHoveredIndex(null), 1618 children: [
1619 /* @__PURE__ */ jsxRuntimeExports.jsxs("svg", { viewBox: `0 0 ${width} ${height}`, className: "w-full h-full overflow-visible", children: [ 1620 gridTemps.map((gt) => { 1621 const yPos = getY(gt); 1622 return /* @__PURE__ */ jsxRuntimeExports.jsxs("g", { children: [ 1623 /* @__PURE__ */ jsxRuntimeExports.jsx( 1624 "line", 1625 { 1626 x1: padLeft, 1627 y1: yPos, 1628 x2: width - padRight, 1629 y2: yPos, 1630 stroke: "#27272a", 1631 strokeDasharray: "3 3" 1632 } 1633 ), 1634 /* @__PURE__ */ jsxRuntimeExports.jsxs( 1635 "text", 1636 { 1637 x: padLeft - 8, 1638 y: yPos + 3, 1639 fill: "#71717a", 1640 fontSize: "10", 1641 textAnchor: "end", 1642 fontFamily: "monospace", 1643 children: [ 1644 gt, 1645 "°C" 1646 ] 1647 } 1648 ) 1649 ] }, gt); 1650 }), 1651 points.filter((_, i) => i % Math.max(1, Math.floor(points.length / 6)) === 0).map((p, i, arr) => { 1652 const origIdx = points.indexOf(p); 1653 const xPos = getX(origIdx); 1654 return /* @__PURE__ */ jsxRuntimeExports.jsx( 1655 "text", 1656 { 1657 x: xPos, 1658 y: height - 8, 1659 fill: "#71717a", 1660 fontSize: "10", 1661 textAnchor: origIdx === 0 ? "start" : origIdx === points.length - 1 ? "end" : "middle", 1662 fontFamily: "monospace", 1663 children: historyRange === "7d" || historyRange === "30d" ? `${p.date} ${p.time}` : p.time 1664 }, 1665 p.timestamp 1666 ); 1667 }), 1668 visibleSeries.roomHumidity && /* @__PURE__ */ jsxRuntimeExports.jsx( 1669 "path", 1670 { 1671 d: buildPath("room_humidity"), 1672 fill: "none", 1673 stroke: "#14b8a6", 1674 strokeWidth: "1.5", 1675 strokeDasharray: "2 2", 1676 opacity: "0.8" 1677 } 1678 ), 1679 visibleSeries.target && /* @__PURE__ */ jsxRuntimeExports.jsx( 1680 "path", 1681 { 1682 d: buildPath("ac_target_temp"), 1683 fill: "none", 1684 stroke: "#60a5fa", 1685 strokeWidth: "1.5", 1686 strokeDasharray: "4 4", 1687 opacity: "0.8" 1688 } 1689 ), 1690 visibleSeries.cpu2 && /* @__PURE__ */ jsxRuntimeExports.jsx( 1691 "path", 1692 { 1693 d: buildPath("cpu2_temp"), 1694 fill: "none", 1695 stroke: "#e879f9", 1696 strokeWidth: "1.5" 1697 } 1698 ), 1699 visibleSeries.cpu1 && /* @__PURE__ */ jsxRuntimeExports.jsx( 1700 "path", 1701 { 1702 d: buildPath("cpu1_temp"), 1703 fill: "none", 1704 stroke: "#facc15", 1705 strokeWidth: "1.5" 1706 } 1707 ), 1708 visibleSeries.exhaust && /* @__PURE__ */ jsxRuntimeExports.jsx( 1709 "path", 1710 { 1711 d: buildPath("exhaust_temp"), 1712 fill: "none", 1713 stroke: "#fb923c", 1714 strokeWidth: "2" 1715 } 1716 ),
1717 visibleSeries.t440 && /* @__PURE__ */ jsxRuntimeExports.jsx( 1718 "path", 1719 { 1720 d: buildPath("t440_inlet"), 1721 fill: "none", 1722 stroke: "#c084fc", 1723 strokeWidth: "2", 1724 strokeDasharray: "4 3", 1725 opacity: "0.9" 1726 } 1727 ), 1728 visibleSeries.roomTemp && /* @__PURE__ */ jsxRuntimeExports.jsx( 1729 "path", 1730 { 1731 d: buildPath("room_temp"), 1732 fill: "none", 1733 stroke: "#10b981", 1734 strokeWidth: "2", 1735 opacity: "0.95" 1736 } 1737 ), 1738 visibleSeries.inlet && /* @__PURE__ */ jsxRuntimeExports.jsx( 1739 "path", 1740 { 1741 d: buildPath("inlet_temp"), 1742 fill: "none", 1743 stroke: "#22d3ee", 1744 strokeWidth: "2.5" 1745 } 1746 ), 1747 hoveredPoint && hoveredIndex !== null && (() => { 1748 const hX = getX(hoveredIndex); 1749 const isRightSide = hX > width * 0.52; 1750 const activeSeries = []; 1751 if (visibleSeries.inlet && hoveredPoint.inlet_temp != null) { 1752 activeSeries.push({ id: "inlet", label: "Inlet", val: hoveredPoint.inlet_temp, unit: "°C", color: "#22d3ee", y: getY(hoveredPoint.inlet_temp) }); 1753 } 1754 if (visibleSeries.roomTemp && hoveredPoint.room_temp != null) { 1755 activeSeries.push({ id: "roomTemp", label: "Room", val: hoveredPoint.room_temp, unit: "°C", color: "#10b981", y: getY(hoveredPoint.room_temp) }); 1756 } 1757 if (visibleSeries.t440 && hoveredPoint.t440_inlet != null) { 1758 activeSeries.push({ id: "t440", label: "T440", val: hoveredPoint.t440_inlet, unit: "°C", color: "#c084fc", y: getY(hoveredPoint.t440_inlet) }); 1759 } 1760 if (visibleSeries.exhaust && hoveredPoint.exhaust_temp != null) { 1761 activeSeries.push({ id: "exhaust", label: "Exhaust", val: hoveredPoint.exhaust_temp, unit: "°C", color: "#fb923c", y: getY(hoveredPoint.exhaust_temp) }); 1762 } 1763 if (visibleSeries.cpu1 && hoveredPoint.cpu1_temp != null) { 1764 activeSeries.push({ id: "cpu1", label: "CPU1", val: hoveredPoint.cpu1_temp, unit: "°C", color: "#facc15", y: getY(hoveredPoint.cpu1_temp) }); 1765 } 1766 if (visibleSeries.cpu2 && hoveredPoint.cpu2_temp != null) { 1767 activeSeries.push({ id: "cpu2", label: "CPU2", val: hoveredPoint.cpu2_temp, unit: "°C", color: "#e879f9", y: getY(hoveredPoint.cpu2_temp) }); 1768 } 1769 if (visibleSeries.target && hoveredPoint.ac_target_temp != null) { 1770 activeSeries.push({ id: "target", label: "Target", val: hoveredPoint.ac_target_temp, unit: "°C", color: "#60a5fa", y: getY(hoveredPoint.ac_target_temp) }); 1771 } 1772 if (visibleSeries.roomHumidity && hoveredPoint.room_humidity != null) { 1773 activeSeries.push({ id: "roomHumidity", label: "Humidity", val: hoveredPoint.room_humidity, unit: "%", color: "#14b8a6", y: getY(hoveredPoint.room_humidity) }); 1774 } 1775 const sortedItems = [...activeSeries].sort((a, b) => a.y - b.y); 1776 const adjustedItems = []; 1777 sortedItems.forEach((s, idx) => { 1778 let bY = s.y; 1779 if (idx > 0) { 1780 const prevY = adjustedItems[idx - 1].badgeY; 1781 if (bY < prevY + 15) { 1782 bY = prevY + 15; 1783 } 1784 } 1785 adjustedItems.push({ item: s, badgeY: bY }); 1786 }); 1787 const maxBadgeY = height - padBottom - 8; 1788 for (let i = adjustedItems.length - 1; i >= 0; i--) { 1789 if (adjustedItems[i].badgeY > maxBadgeY) { 1790 adjustedItems[i].badgeY = maxBadgeY - (adjustedItems.length - 1 - i) * 15; 1791 } 1792 } 1793 const badgeW = 42; 1794 const badgeH = 14.5; 1795 const badgeX = isRightSide ? Math.min(width - padRight - badgeW, hX + 8) : Math.max(padLeft, hX - badgeW - 8); 1796 return /* @__PURE__ */ jsxRuntimeExports.jsxs("g", { children: [
1797 /* @__PURE__ */ jsxRuntimeExports.jsx( 1798 "line", 1799 { 1800 x1: hX, 1801 y1: padTop, 1802 x2: hX, 1803 y2: height - padBottom, 1804 stroke: "#71717a", 1805 strokeWidth: "1.2", 1806 strokeDasharray: "2 2" 1807 } 1808 ), 1809 /* @__PURE__ */ jsxRuntimeExports.jsxs("g", { children: [ 1810 /* @__PURE__ */ jsxRuntimeExports.jsx( 1811 "rect", 1812 { 1813 x: Math.max(padLeft, Math.min(width - padRight - 52, hX - 26)), 1814 y: 3, 1815 width: "52", 1816 height: "14", 1817 rx: "3", 1818 fill: "#18181b", 1819 stroke: "#52525b", 1820 strokeWidth: "1" 1821 } 1822 ),
1823 /* @__PURE__ */ jsxRuntimeExports.jsx( 1824 "text", 1825 { 1826 x: Math.max(padLeft + 26, Math.min(width - padRight - 26, hX)), 1827 y: 13.5, 1828 fill: "#f4f4f5", 1829 fontSize: "8.5", 1830 fontWeight: "bold", 1831 textAnchor: "middle", 1832 fontFamily: "monospace", 1833 children: hoveredPoint.time 1834 } 1835 ) 1836 ] }), 1837 adjustedItems.map(({ item, badgeY }) => { 1838 const isConnectorNeeded = Math.abs(item.y - badgeY) > 3; 1839 return /* @__PURE__ */ jsxRuntimeExports.jsxs("g", { children: [ 1840 isConnectorNeeded && /* @__PURE__ */ jsxRuntimeExports.jsx( 1841 "line", 1842 { 1843 x1: isRightSide ? hX + 4 : hX - 4, 1844 y1: item.y, 1845 x2: isRightSide ? badgeX : badgeX + badgeW, 1846 y2: badgeY, 1847 stroke: item.color, 1848 strokeWidth: "0.8", 1849 opacity: "0.6" 1850 } 1851 ),
1852 /* @__PURE__ */ jsxRuntimeExports.jsx( 1853 "rect", 1854 { 1855 x: badgeX, 1856 y: badgeY - badgeH / 2, 1857 width: badgeW, 1858 height: badgeH, 1859 rx: "3", 1860 fill: "#09090b", 1861 stroke: item.color, 1862 strokeWidth: "1", 1863 opacity: "0.95" 1864 } 1865 ), 1866 /* @__PURE__ */ jsxRuntimeExports.jsxs( 1867 "text", 1868 { 1869 x: badgeX + badgeW / 2, 1870 y: badgeY + 3.2, 1871 fill: item.color, 1872 fontSize: "9", 1873 fontWeight: "bold", 1874 textAnchor: "middle", 1875 fontFamily: "monospace", 1876 children: [ 1877 item.val, 1878 item.unit 1879 ] 1880 } 1881 ),
1882 /* @__PURE__ */ jsxRuntimeExports.jsx( 1883 "circle", 1884 { 1885 cx: hX, 1886 cy: item.y, 1887 r: "3.5", 1888 fill: item.color, 1889 stroke: "#09090b", 1890 strokeWidth: "1.5" 1891 } 1892 ) 1893 ] }, item.id); 1894 }) 1895 ] }); 1896 })() 1897 ] }), 1898 hoveredPoint && hoveredIndex !== null && (() => { 1899 const hX = getX(hoveredIndex); 1900 const isRightSide = hX > width * 0.52; 1901 return /* @__PURE__ */ jsxRuntimeExports.jsxs( 1902 "div", 1903 { 1904 className: "absolute top-2 bg-zinc-900/95 border border-zinc-700/80 p-3 rounded-xl shadow-2xl backdrop-blur-md text-xs pointer-events-none space-y-1.5 z-20 min-w-48 transition-transform duration-75", 1905 style: { 1906 left: `${hX / width * 100}%`, 1907 transform: isRightSide ? "translateX(calc(-100% - 18px))" : "translateX(18px)" 1908 }, 1909 children: [
1910 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between items-center border-b border-zinc-800 pb-1 font-mono text-zinc-400 text-[11px]", children: [ 1911 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [ 1912 hoveredPoint.date, 1913 " ", 1914 hoveredPoint.time 1915 ] }), 1916 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `px-1.5 py-0.5 rounded text-[10px] font-bold ${hoveredPoint.ac_power ? "bg-emerald-500/20 text-emerald-400" : "bg-zinc-800 text-zinc-400"}`, children: hoveredPoint.ac_power ? "AC ON" : "AC OFF" }) 1917 ] }), 1918 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1", children: [ 1919 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between text-cyan-400 font-semibold", children: [ 1920 /* @__P
1920URE__ */ jsxRuntimeExports.jsx("span", { children: "XC640 Inlet:" }), 1921 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [ 1922 hoveredPoint.inlet_temp ?? "--", 1923 "°C" 1924 ] }) 1925 ] }), 1926 hoveredPoint.room_temp !== null && hoveredPoint.room_temp !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between text-emerald-400 font-semibold", children: [ 1927 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Room Ambient:" }), 1928 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [ 1929 hoveredPoint.room_temp, 1930 "°C" 1931 ] }) 1932 ] }), 1933 hoveredPoint.room_humidity !== null && hoveredPoint.room_humidity !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between text-teal-400 font-semibold", children: [
1934 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Room Humidity:" }), 1935 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [ 1936 hoveredPoint.room_humidity, 1937 "% RH" 1938 ] }) 1939 ] }), 1940 hoveredPoint.t440_inlet !== null && hoveredPoint.t440_inlet !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between text-purple-400 font-semibold", children: [ 1941 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "T440 Inlet:" }), 1942 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [ 1943 hoveredPoint.t440_inlet, 1944 "°C (", 1945 hoveredPoint.t440_power ?? 8, 1946 "W)" 1947 ] }) 1948 ] }),
1949 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between text-orange-400 font-semibold", children: [ 1950 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "XC640 Exhaust:" }), 1951 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [ 1952 hoveredPoint.exhaust_temp ?? "--", 1953 "°C" 1954 ] }) 1955 ] }), 1956 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between text-yellow-400", children: [ 1957 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "CPU 1 Core:" }), 1958 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [ 1959 hoveredPoint.cpu1_temp ?? "--", 1960 "°C" 1961 ] }) 1962 ] }), 1963 /* @__P
1963URE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between text-fuchsia-400", children: [ 1964 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "CPU 2 Core:" }), 1965 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [ 1966 hoveredPoint.cpu2_temp ?? "--", 1967 "°C" 1968 ] }) 1969 ] }), 1970 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between text-blue-400", children: [ 1971 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "AC Target Setting:" }), 1972 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [ 1973 hoveredPoint.ac_target_temp ?? "--", 1974 "°C" 1975 ] }) 1976 ] }), 1977 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between text-emerald-400 border-t border-zinc-800 pt-1", children: [
1978 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "XC640 Power:" }), 1979 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono", children: [ 1980 hoveredPoint.power_watts ?? "--", 1981 " W" 1982 ] }) 1983 ] }) 1984 ] }) 1985 ] 1986 } 1987 ); 1988 })() 1989 ] 1990 } 1991 ); 1992 })() }) 1993 ] }), 1994 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-zinc-900/80 border border-zinc-800 p-6 rounded-2xl shadow-xl space-y-4", children: [ 1995 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between", children: [ 1996 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [ 1997 /* @__PURE__ */ jsxRuntimeExports.jsx(Zap, { className: "w-4 h-4 text-emerald-400" }),
1998 /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "text-sm font-bold text-white", children: "Chassis Power Consumption & AC Duty Cycle" }) 1999 ] }), 2000 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs text-zinc-400 font-mono", children: "Redfish PSU Telemetry" }) 2001 ] }), 2002 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "relative w-full h-44 bg-zinc-950/60 rounded-xl border border-zinc-800/80 p-3 select-none", children: !(historyData == null ? void 0 : historyData.points) || historyData.points.length === 0 ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "h-full flex items-center justify-center text-zinc-500 text-xs", children: "No power data available." }) : (() => { 2003 const points = historyData.points; 2004 const width = 800; 2005 const height = 140; 2006 const padLeft = 40; 2007 const padRight = 20; 2008 const padTop = 15; 2009 const padBottom = 25; 2010 const plotW = width - padLeft - padRight; 2011 const plotH = height - padTop - padBottom; 2012 const minP = 300; 2013 const maxP = 600; 2014 const pRange = maxP - minP; 2015 const getY = (p) => { 2016 if (p === null || p === void 0) return padTop + plotH; 2017 const clamped = Math.max(minP, Math.min(maxP, p)); 2018 return padTop + plotH - (clamped - minP) / pRange * plotH; 2019 }; 2020 const getX = (idx) => { 2021 return padLeft + idx / Math.max(1, points.length - 1) * plotW; 2022 }; 2023 const linePath = points.map((p, i) => `${i === 0 ? "M" : "L"} ${getX(i).toFixed(1)},${getY(p.power_watts).toFixed(1)}`).join(" "); 2024 const areaPath = `${linePath} L ${getX(points.length - 1)},${padTop + plotH} L ${getX(0)},${padTop + plotH} Z`; 2025 return /* @__PURE__ */ jsxRuntimeExports.jsxs("svg", { viewBox: `0 0 ${width} ${height}`, className: "w-full h-full overflow-visible", children: [
2026 /* @__PURE__ */ jsxRuntimeExports.jsx("defs", { children: /* @__PURE__ */ jsxRuntimeExports.jsxs("linearGradient", { id: "powerGrad", x1: "0", y1: "0", x2: "0", y2: "1", children: [ 2027 /* @__PURE__ */ jsxRuntimeExports.jsx("stop", { offset: "0%", stopColor: "#10b981", stopOpacity: "0.3" }), 2028 /* @__PURE__ */ jsxRuntimeExports.jsx("stop", { offset: "100%", stopColor: "#10b981", stopOpacity: "0.0" }) 2029 ] }) }), 2030 [350, 450, 550].map((pw) => { 2031 const yPos = getY(pw); 2032 return /* @__PURE__ */ jsxRuntimeExports.jsxs("g", { children: [ 2033 /* @__PURE__ */ jsxRuntimeExports.jsx( 2034 "line", 2035 { 2036 x1: padLeft, 2037 y1: yPos, 2038 x2: width - padRight, 2039 y2: yPos, 2040 stroke: "#27272a", 2041 strokeDasharray: "3 3" 2042 } 2043 ), 2044 /* @__PURE__ */ jsxRuntimeExports.jsxs( 2045 "text", 2046 { 2047 x: padLeft - 8, 2048 y: yPos + 3, 2049 fill: "#71717a", 2050 fontSize: "9", 2051 textAnchor: "end", 2052 fontFamily: "monospace", 2053 children: [ 2054 pw, 2055 "W" 2056 ] 2057 } 2058 ) 2059 ] }, pw); 2060 }),
2061 /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: areaPath, fill: "url(#powerGrad)" }), 2062 /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: linePath, fill: "none", stroke: "#10b981", strokeWidth: "2" }) 2063 ] }); 2064 })() }), 2065 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1.5 pt-1", children: [ 2066 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between items-center text-xs", children: [ 2067 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-zinc-400 font-semibold flex items-center gap-1.5", children: [ 2068 /* @__PURE__ */ jsxRuntimeExports.jsx(Power, { className: "w-3.5 h-3.5 text-emerald-400" }), 2069 "AC Compressor State Timeline" 2070 ] }), 2071 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3 text-[11px]", children: [ 2072 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1 text-emerald-400", children: [
2073 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "w-2.5 h-2.5 rounded bg-emerald-500 inline-block" }), 2074 "Compressor ON" 2075 ] }), 2076 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1 text-zinc-500", children: [ 2077 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "w-2.5 h-2.5 rounded bg-zinc-800 inline-block" }), 2078 "Compressor Standby" 2079 ] }) 2080 ] }) 2081 ] }), 2082 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-full h-5 bg-zinc-950 rounded-lg overflow-hidden flex border border-zinc-800", children: (historyData == null ? void 0 : historyData.points) && historyData.points.map((p, idx) => /* @__PURE__ */ jsxRuntimeExports.jsx( 2083 "div", 2084 { 2085 className: `h-full flex-1 transition-colors ${p.ac_power ? "bg-emerald-500/80 hover:bg-emerald-400" : "bg-zinc-800/60 hover:bg-zinc-700"}`, 2086 title: `${p.time}: AC ${p.ac_power ? "Running" : "Standby"} (Inlet: ${p.inlet_temp}°C)` 2087 }, 2088 idx 2089 )) }) 2090 ] }) 2091 ] }) 2092 ] }), 2093 activeTab === "guardian" && (() => { 2094 var _a2, _b2, _c2, _d2, _e2, _f2, _g2, _h2, _i2, _j2, _k2, _l2, _m2, _n2, _o2, _p2, _q2, _r2, _s2; 2095 const currentInlet = ((_a2 = serversData == null ? void 0 : serversData.xc640) == null ? void 0 : _a2.inlet_temp) ?? (serverData == null ? void 0 : serverData.inlet_temp) ?? 24; 2096 const currentCpu = Math.max(((_b2 = serversData == null ? void 0 : serversData.xc640) == null ? void 0 : _b2.cpu1_temp) ?? 0, ((_c2 = serversData == null ? void 0 : serversData.xc640) == null ? void 0 : _c2.cpu2_temp) ?? 0, (serverData == null ? void 0 : serverData.cpu1_temp) ?? 0, 70); 2097 const activeProfileId = getActiveProfileId(config); 2098 const activeProfile = OPERATIONAL_PROFILES.find((p) => p.id === activeProfileId); 2099 const isCustom = activeProfileId === "custom"; 2100 const pinPercent = Math.max(3, Math.min(97, (currentInlet - 16) / (34 - 16) * 100)); 2101 const coldCutoff = (config == null ? void 0 : config.cold_cutoff_temp) ?? 20; 2102 const warmWakeup = (config == null ? void 0 : config.warm_wakeup_temp) ?? 25; 2103 const optimalInlet = ((_e2 = (_d2 = config == null ? void 0 : config.temp_thresholds) == null ? void 0 : _d2.optimal) == null ? void 0 : _e2.inlet_temp) ?? 22; 2104 const warmInlet = ((_g2 = (_f2 = config == null ? void 0 : config.temp_thresholds) == null ? void 0 : _f2.warm) == null ? void 0 : _g2.inlet_temp) ?? 26; 2105 const emergencyInlet = ((_i2 = (_h2 = config == null ? void 0 : config.temp_thresholds) == null ? void 0 : _h2.emergency_high) == null ? void 0 : _i2.inlet_temp) ?? 28; 2106 const severityStyles = { 2107 info: "from-blue-950/40 via-cyan-950/20 to-zinc-950 border-cyan-500/40 text-cyan-300", 2108 success: "from-emerald-950/40 via-zinc-950 to-zinc-950 border-emerald-500/40 text-emerald-300", 2109 warning: "from-amber-950/40 via-zinc-950 to-zinc-950 border-amber-500/40 text-amber-300", 2110 danger: "from-rose-950/40 via-zinc-950 to-zinc-950 border-rose-500/40 text-rose-300" 2111 }; 2112 const activeSeverity = (activeTier == null ? void 0 : activeTier.severity) || ((acData == null ? void 0 : acData.power) ? "success" : "info"); 2113 return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-zinc-900/80 border border-zinc-800 p-6 rounded-2xl shadow-xl space-y-6", children: [
2114 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col sm:flex-row sm:items-center justify-between gap-4", children: [ 2115 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 2116 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3", children: [ 2117 /* @__PURE__ */ jsxRuntimeExports.jsxs("h2", { className: "text-base font-bold text-white flex items-center gap-2", children: [ 2118 /* @__PURE__ */ jsxRuntimeExports.jsx(Shield, { className: "w-5 h-5 text-emerald-400" }), 2119 "Automated AI Guardian Thermal Regulation Strategy" 2120 ] }), 2121 isConfigDirty && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "px-2.5 py-0.5 rounded-full text-[11px] font-black bg-amber-500/20 text-amber-300 border border-amber-500/40 animate-pulse flex items-center gap-1.5 shadow-sm", children: [ 2122 /* @__PURE__ */ jsxRuntimeExports.jsx(TriangleAlert, { className: "w-3.5 h-3.5" }), 2123 "Unsaved Changes" 2124 ] }) 2125 ] }),
2126 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-zinc-400 mt-0.5", children: "Cascading temperature regulation ladder evaluated every minute across Tokyo server nodes" }) 2127 ] }), 2128 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2.5 self-start sm:self-center", children: [ 2129 isConfigDirty && /* @__PURE__ */ jsxRuntimeExports.jsxs( 2130 "button", 2131 { 2132 onClick: handleDiscardConfig, 2133 disabled: saving, 2134 className: "px-4 py-2 rounded-xl bg-zinc-800 hover:bg-zinc-700 text-zinc-300 text-xs font-bold border border-zinc-700 transition flex items-center gap-1.5 cursor-pointer shadow-sm", 2135 title: "Discard unsaved edits and reload current values from server", 2136 children: [ 2137 /* @__PURE__ */ jsxRuntimeExports.jsx(RefreshCw, { className: "w-3.5 h-3.5" }), 2138 "Discard Changes" 2139 ] 2140 } 2141 ),
2142 /* @__PURE__ */ jsxRuntimeExports.jsxs( 2143 "button", 2144 { 2145 onClick: handleSaveConfig, 2146 disabled: saving, 2147 className: `px-5 py-2 rounded-xl text-xs font-black transition flex items-center gap-2 shadow-lg cursor-pointer ${isConfigDirty ? "bg-emerald-500 hover:bg-emerald-400 text-zinc-950 shadow-emerald-500/30" : "bg-cyan-500 hover:bg-cyan-600 text-white shadow-cyan-500/20"}`, 2148 children: [ 2149 /* @__PURE__ */ jsxRuntimeExports.jsx(Settings, { className: "w-4 h-4" }), 2150 saving ? "Saving..." : "Save & Apply Policies" 2151 ] 2152 } 2153 ) 2154 ] }) 2155 ] }), 2156 /* @__PURE__ */ jsxRuntimeExports.jsxs( 2157 "div", 2158 { 2159 className: `p-5 rounded-2xl border bg-gradient-to-r transition-all shadow-xl space-y-3 ${severityStyles[activeSeverity] || severityStyles.info}`, 2160 children: [ 2161 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col md:flex-row md:items-center justify-between gap-3 pb-2 border-b border-white/10", children: [
2162 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3", children: [ 2163 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "relative flex h-3 w-3", children: [ 2164 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "animate-ping absolute inline-flex h-full w-full rounded-full bg-current opacity-75" }), 2165 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "relative inline-flex rounded-full h-3 w-3 bg-current" }) 2166 ] }), 2167 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 2168 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[11px] font-bold uppercase tracking-wider text-zinc-400", children: "Currently Active Regulation Tier" }), 2169 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-base font-black text-white flex items-center gap-2", children: [ 2170 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: (activeTier == null ? void 0 : activeTier.tier_name) || ((acData == null ? void 0 : acData.power) ? "Optimal Cruising (Standard)" : "Passive Free-Cooling (Standby OFF)") }),
2171 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs font-mono font-bold px-2 py-0.5 rounded-full bg-black/40 border border-white/20", children: (activeTier == null ? void 0 : activeTier.tier_id) || ((acData == null ? void 0 : acData.power) ? "OPTIMAL_COOL" : "STANDBY_OFF") }) 2172 ] }) 2173 ] }) 2174 ] }), 2175 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3 self-start md:self-center", children: [ 2176 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-right", children: [ 2177 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[10px] text-zinc-400 font-semibold uppercase", children: "Hardware Response" }), 2178 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-xs font-bold text-white", children: (acData == null ? void 0 : acData.power) ? `Cooling to ${acData.target_temp ?? 24}°C ⢠Fan ${acData.fan_name || "Auto"}` : "Compressor Stopped (0W Draw)" }) 2179 ] }),
2180 /* @__PURE__ */ jsxRuntimeExports.jsx( 2181 "span", 2182 { 2183 className: `px-2.5 py-1 rounded-lg text-xs font-black uppercase border ${(acData == null ? void 0 : acData.power) ? "bg-emerald-500/20 text-emerald-300 border-emerald-500/40" : "bg-zinc-800 text-zinc-400 border-zinc-700"}`, 2184 children: (acData == null ? void 0 : acData.power) ? "AC: ON" : "AC: OFF" 2185 } 2186 ) 2187 ] }) 2188 ] }), 2189 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-3 text-xs", children: [ 2190 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1", children: [ 2191 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-zinc-400 font-semibold block", children: "Decision Reasoning:" }), 2192 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-zinc-200 leading-relaxed font-medium", children: (activeTier == null ? void 0 : activeTier.tier_reason) || ((acData == null ? void 0 : acData.power) ? `Inlet (${currentInlet}°C) is in cruising sweet spot. AC running at ${acData.target_temp ?? 24}°C.` : `Server inlet is ${currentInlet}°C (below ${warmWakeup}°C wakeup threshold). Compressor resting at 0W power draw.`) }) 2193 ] }),
2194 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1", children: [ 2195 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-zinc-400 font-semibold block", children: "Next State Transition:" }), 2196 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-zinc-300 leading-relaxed font-mono text-[11px]", children: (activeTier == null ? void 0 : activeTier.next_transition) || ((acData == null ? void 0 : acData.power) ? `Will power OFF if inlet drops ⤠${coldCutoff}°C; switches to High Load if inlet ⥠${warmInlet}°C.` : `Wakes up and turns ON when inlet reaches ⥠${warmWakeup}°C or CPU reaches ⥠${(config == null ? void 0 : config.emergency_wakeup_cpu_temp) ?? 88}°C.`) }) 2197 ] }) 2198 ] }) 2199 ] 2200 } 2201 ), 2202 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-zinc-950 p-5 rounded-xl border border-zinc-800/90 space-y-5", children: [ 2203 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col sm:flex-row sm:items-center justify-between gap-2", children: [
2204 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 2205 /* @__PURE__ */ jsxRuntimeExports.jsxs("h3", { className: "text-sm font-bold text-white flex items-center gap-2", children: [ 2206 /* @__PURE__ */ jsxRuntimeExports.jsx(Thermometer, { className: "w-4 h-4 text-cyan-400" }), 2207 "Cascading Regulation Spectrum & Thermal Decision Points" 2208 ] }), 2209 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-zinc-400 mt-0.5", children: "The AI Guardian walks down this temperature spectrum from right to left to pick the exact tier" }) 2210 ] }), 2211 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 text-xs", children: [ 2212 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-zinc-400", children: "Live Dell XC640:" }), 2213 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono font-bold text-cyan-300 bg-cyan-950/60 px-2 py-0.5 rounded border border-cyan-800/50", children: [ 2214 "Inlet ", 2215 currentInlet, 2216 "°C" 2217 ] }),
2218 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono font-bold text-amber-300 bg-amber-950/60 px-2 py-0.5 rounded border border-amber-800/50", children: [ 2219 "CPU ", 2220 currentCpu, 2221 "°C" 2222 ] }) 2223 ] }) 2224 ] }), 2225 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "pt-7 pb-2 px-3", children: [ 2226 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "relative w-full h-4 rounded-full bg-zinc-900 border border-zinc-800 overflow-visible flex shadow-inner", children: [ 2227 /* @__PURE__ */ jsxRuntimeExports.jsxs( 2228 "div", 2229 { 2230 style: { left: `${pinPercent}%` }, 2231 className: "absolute -top-7 transform -translate-x-1/2 flex flex-col items-center z-20 transition-all duration-700", 2232 children: [ 2233 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "px-2 py-0.5 rounded-full text-[10px] font-black bg-white text-zinc-950 shadow-lg whitespace-nowrap flex items-center gap-1 border border-zinc-300", children: [
2234 /* @__PURE__ */ jsxRuntimeExports.jsx(Thermometer, { className: "w-3 h-3 text-cyan-600" }), 2235 " ", 2236 currentInlet, 2237 "°C Now" 2238 ] }), 2239 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-0 h-0 border-l-[4px] border-l-transparent border-r-[4px] border-r-transparent border-t-[5px] border-t-white" }) 2240 ] 2241 } 2242 ), 2243 /* @__PURE__ */ jsxRuntimeExports.jsx( 2244 "div", 2245 { 2246 style: { width: `${Math.max(10, (coldCutoff - 16) / 18 * 100)}%` }, 2247 className: "h-full bg-gradient-to-r from-blue-600 to-cyan-500 rounded-l-full relative", 2248 title: `0W Standby Cutoff Zone: ⤠${coldCutoff}°C` 2249 } 2250 ), 2251 /* @__PURE__ */ jsxRuntimeExports.jsx( 2252 "div", 2253 { 2254 style: { width: `${Math.max(10, (warmInlet - coldCutoff) / 18 * 100)}%` }, 2255 className: "h-full bg-emerald-500 relative", 2256 title: `Optimal Cruising Sweet Spot: ${coldCutoff}°C â ${warmInlet}°C` 2257 } 2258 ),
2259 /* @__PURE__ */ jsxRuntimeExports.jsx( 2260 "div", 2261 { 2262 style: { width: `${Math.max(10, (emergencyInlet - warmInlet) / 18 * 100)}%` }, 2263 className: "h-full bg-amber-500 relative", 2264 title: `High Load Active Cooling: ${warmInlet}°C â ${emergencyInlet}°C` 2265 } 2266 ), 2267 /* @__PURE__ */ jsxRuntimeExports.jsx( 2268 "div", 2269 { 2270 style: { width: `${Math.max(10, (34 - emergencyInlet) / 18 * 100)}%` }, 2271 className: "h-full bg-rose-500 rounded-r-full relative", 2272 title: `Emergency Chill: ⥠${emergencyInlet}°C` 2273 } 2274 ) 2275 ] }), 2276 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "relative w-full h-4 mt-1.5 text-[10px] font-mono text-zinc-500", children: [ 2277 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "absolute left-0", children: "16°C" }), 2278 /* @__P
2278URE__ */ jsxRuntimeExports.jsxs("span", { style: { left: `${(coldCutoff - 16) / 18 * 100}%` }, className: "absolute transform -translate-x-1/2 text-cyan-400 font-bold", children: [ 2279 "Cutoff ", 2280 coldCutoff, 2281 "°C" 2282 ] }), 2283 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { style: { left: `${(warmInlet - 16) / 18 * 100}%` }, className: "absolute transform -translate-x-1/2 text-amber-400 font-bold", children: [ 2284 "Warm ", 2285 warmInlet, 2286 "°C" 2287 ] }), 2288 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { style: { left: `${(emergencyInlet - 16) / 18 * 100}%` }, className: "absolute transform -translate-x-1/2 text-rose-400 font-bold", children: [ 2289 "Emerg ", 2290 emergencyInlet, 2291 "°C" 2292 ] }), 2293 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "absolute right-0", children: "34°C+" }) 2294 ] }) 2295 ] }),
2296 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-3 text-xs pt-1", children: [ 2297 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-3 bg-zinc-900/60 rounded-xl border border-blue-500/30 space-y-1", children: [ 2298 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between", children: [ 2299 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-bold text-blue-400 flex items-center gap-1.5", children: [ 2300 /* @__PURE__ */ jsxRuntimeExports.jsx(Snowflake, { className: "w-3.5 h-3.5" }), 2301 " 1. Free-Cooling" 2302 ] }), 2303 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] px-1.5 py-0.2 rounded bg-blue-950 text-blue-300 font-mono", children: "0W" }) 2304 ] }), 2305 /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-[11px] text-zinc-400", children: [ 2306 "Trigger: ",
2307 /* @__PURE__ */ jsxRuntimeExports.jsxs("b", { children: [ 2308 "Inlet ⤠", 2309 coldCutoff, 2310 "°C" 2311 ] }) 2312 ] }), 2313 /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-[11px] text-zinc-500", children: [ 2314 "Turns AC ", 2315 /* @__PURE__ */ jsxRuntimeExports.jsx("b", { children: "Power: OFF" }), 2316 ". Sleeps until heat reaches ⥠", 2317 warmWakeup, 2318 "°C." 2319 ] }) 2320 ] }), 2321 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-3 bg-zinc-900/60 rounded-xl border border-emerald-500/30 space-y-1", children: [ 2322 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between", children: [ 2323 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-bold text-emerald-400 flex items-center gap-1.5", children: [ 2324 /* @__PURE__ */ jsxRuntimeExports.jsx(Activity, { className: "w-3.5 h-3.5" }), 2325 " 2. Optimal Cruising" 2326 ] }),
2327 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] px-1.5 py-0.2 rounded bg-emerald-950 text-emerald-300 font-mono", children: "Auto" }) 2328 ] }), 2329 /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-[11px] text-zinc-400", children: [ 2330 "Trigger: ", 2331 /* @__PURE__ */ jsxRuntimeExports.jsxs("b", { children: [ 2332 "Inlet ", 2333 optimalInlet, 2334 "°C â ", 2335 warmInlet - 1, 2336 "°C" 2337 ] }) 2338 ] }), 2339 /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-[11px] text-zinc-500", children: [ 2340 "Runs AC at ", 2341 /* @__PURE__ */ jsxRuntimeExports.jsxs("b", { children: [ 2342 ((_k2 = (_j2 = config == null ? void 0 : config.temp_thresholds) == null ? void 0 : _j2.optimal) == null ? void 0 : _k2.target_ac_temp) ?? 24, 2343 "°C" 2344 ] }), 2345 " with Fan Auto." 2346 ] }) 2347 ] }),
2348 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-3 bg-zinc-900/60 rounded-xl border border-amber-500/30 space-y-1", children: [ 2349 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between", children: [ 2350 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-bold text-amber-400 flex items-center gap-1.5", children: [ 2351 /* @__PURE__ */ jsxRuntimeExports.jsx(Flame, { className: "w-3.5 h-3.5" }), 2352 " 3. High Load Warm" 2353 ] }), 2354 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] px-1.5 py-0.2 rounded bg-amber-950 text-amber-300 font-mono", children: "Med" }) 2355 ] }), 2356 /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-[11px] text-zinc-400", children: [ 2357 "Trigger: ", 2358 /* @__PURE__ */ jsxRuntimeExports.jsxs("b", { children: [ 2359 "Inlet ⥠", 2360 warmInlet, 2361 "°C or CPU ⥠", 2362 ((_m2 = (_l2 = config == null ? void 0 : config.temp_thresholds) == null ? void 0 : _l2.warm) == null ? void 0 : _m2.cpu_temp) ?? 85, 2363 "°C" 2364 ] }) 2365 ] }),
2366 /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-[11px] text-zinc-500", children: [ 2367 "Drops AC to ", 2368 /* @__PURE__ */ jsxRuntimeExports.jsxs("b", { children: [ 2369 ((_o2 = (_n2 = config == null ? void 0 : config.temp_thresholds) == null ? void 0 : _n2.warm) == null ? void 0 : _o2.target_ac_temp) ?? 22, 2370 "°C" 2371 ] }), 2372 " with Fan 2." 2373 ] }) 2374 ] }), 2375 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-3 bg-zinc-900/60 rounded-xl border border-rose-500/30 space-y-1", children: [ 2376 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between", children: [ 2377 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-bold text-rose-400 flex items-center gap-1.5", children: [ 2378 /* @__PURE__ */ jsxRuntimeExports.jsx(Zap, { className: "w-3.5 h-3.5" }), 2379 " 4. Emergency Chill" 2380 ] }),
2381 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] px-1.5 py-0.2 rounded bg-rose-950 text-rose-300 font-mono", children: "High" }) 2382 ] }), 2383 /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-[11px] text-zinc-400", children: [ 2384 "Trigger: ", 2385 /* @__PURE__ */ jsxRuntimeExports.jsxs("b", { children: [ 2386 "Inlet ⥠", 2387 emergencyInlet, 2388 "°C or CPU ⥠", 2389 ((_q2 = (_p2 = config == null ? void 0 : config.temp_thresholds) == null ? void 0 : _p2.emergency_high) == null ? void 0 : _q2.cpu_temp) ?? 92, 2390 "°C" 2391 ] }) 2392 ] }), 2393 /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-[11px] text-zinc-500", children: [ 2394 "Immediate chill at ", 2395 /* @__PURE__ */ jsxRuntimeExports.jsxs("b", { children: [ 2396 ((_s2 = (_r2 = config == null ? void 0 : config.temp_thresholds) == null ? void 0 : _r2.emergency_high) == null ? void 0 : _s2.target_ac_temp) ?? 19, 2397 "°C" 2398 ] }), 2399 ", Fan 3 (bypasses holds)." 2400 ] }) 2401 ] }) 2402 ] }) 2403 ] }),
2404 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-4", children: [ 2405 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col sm:flex-row sm:items-center justify-between gap-2", children: [ 2406 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 2407 /* @__PURE__ */ jsxRuntimeExports.jsxs("h3", { className: "text-sm font-bold text-white flex items-center gap-2", children: [ 2408 /* @__PURE__ */ jsxRuntimeExports.jsx(SlidersVertical, { className: "w-4 h-4 text-cyan-400" }), 2409 "Operational Strategy Profiles (1-Click Optimization)" 2410 ] }), 2411 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-zinc-400 mt-0.5", children: "Select an operating profile to automatically harmonize all 14+ trigger and timing parameters" }) 2412 ] }), 2413 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center gap-2", children: isCustom ? /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "px-2.5 py-1 rounded-full text-xs font-bold bg-amber-500/20 text-amber-300 border border-amber-500/40 flex items-center gap-1.5", children: [
2414 /* @__PURE__ */ jsxRuntimeExports.jsx(Settings, { className: "w-3.5 h-3.5" }), 2415 "Custom Tuning Active" 2416 ] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "px-2.5 py-1 rounded-full text-xs font-bold bg-emerald-500/20 text-emerald-300 border border-emerald-500/40 flex items-center gap-1.5", children: [ 2417 /* @__PURE__ */ jsxRuntimeExports.jsx(CircleCheck, { className: "w-3.5 h-3.5" }), 2418 "Preset: ", 2419 (activeProfile == null ? void 0 : activeProfile.name) || "Standard" 2420 ] }) }) 2421 ] }), 2422 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4", children: OPERATIONAL_PROFILES.map((prof) => { 2423 const IconComp = prof.icon; 2424 const isSelected = activeProfileId === prof.id; 2425 return /* @__PURE__ */ jsxRuntimeExports.jsxs( 2426 "div", 2427 { 2428 onClick: () => handleApplyProfile(prof.id), 2429 className: `p-4 rounded-xl border transition-all cursor-pointer relative overflow-hidden flex flex-col justify-between space-y-3 ${isSelected ? `bg-gradient-to-r ${prof.bgGradient} ${prof.borderColor} ring-2 ring-cyan-500/50 shadow-lg` : "bg-zinc-950/70 border-zinc-800 hover:border-zinc-700 hover:bg-zinc-950"}`, 2430 children: [
2431 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1.5", children: [ 2432 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between", children: [ 2433 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: `text-sm font-bold flex items-center gap-2 ${prof.color}`, children: [ 2434 /* @__PURE__ */ jsxRuntimeExports.jsx(IconComp, { className: "w-4 h-4" }), 2435 prof.name 2436 ] }), 2437 isSelected ? /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "px-2 py-0.5 rounded-full text-[10px] font-black bg-emerald-500/20 text-emerald-400 border border-emerald-500/40 flex items-center gap-1", children: [ 2438 /* @__PURE__ */ jsxRuntimeExports.jsx(CircleCheck, { className: "w-3 h-3" }), 2439 " ACTIVE PROFILE" 2440 ] }) : /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] text-zinc-500 font-mono bg-zinc-900 px-2 py-0.5 rounded border border-zinc-800", children: prof.badge }) 2441 ] }),
2442 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-zinc-400 leading-relaxed", children: prof.description }) 2443 ] }), 2444 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "pt-2 border-t border-zinc-800/60 flex items-center justify-between text-[11px] font-mono", children: [ 2445 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-zinc-400", children: [ 2446 "Target: ", 2447 /* @__PURE__ */ jsxRuntimeExports.jsx("b", { className: "text-white", children: prof.targetInlet }) 2448 ] }), 2449 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-zinc-400", children: [ 2450 "Cutoff: ", 2451 /* @__PURE__ */ jsxRuntimeExports.jsxs("b", { className: "text-cyan-400", children: [ 2452 "⤠", 2453 prof.coldCutoff, 2454 "°C" 2455 ] }) 2456 ] }),
2457 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-zinc-400", children: [ 2458 "Wakeup: ", 2459 /* @__PURE__ */ jsxRuntimeExports.jsxs("b", { className: "text-amber-400", children: [ 2460 "⥠", 2461 prof.warmWakeup, 2462 "°C" 2463 ] }) 2464 ] }) 2465 ] }) 2466 ] 2467 }, 2468 prof.id 2469 ); 2470 }) }) 2471 ] }), 2472 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border border-zinc-800 rounded-xl overflow-hidden bg-zinc-950/40", children: [ 2473 /* @__PURE__ */ jsxRuntimeExports.jsxs( 2474 "button", 2475 { 2476 type: "button", 2477 onClick: () => setShowAdvancedTuning(!showAdvancedTuning), 2478 className: "w-full px-5 py-3.5 bg-zinc-900/90 hover:bg-zinc-850 flex items-center justify-between transition text-left cursor-pointer border-b border-zinc-800/80", 2479 children: [
2480 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2.5", children: [ 2481 /* @__PURE__ */ jsxRuntimeExports.jsx(Settings, { className: "w-4 h-4 text-indigo-400" }), 2482 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 2483 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs font-bold text-white block", children: "Advanced Thresholds & Engineering Fine-Tuning" }), 2484 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[11px] text-zinc-400", children: "Customize exact numeric triggers, fan speeds, CPU spike limits, and anti-cycling timers" }) 2485 ] }) 2486 ] }), 2487 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3", children: [ 2488 isCustom && /* @__PURE__ */ jsxRuntimeExports.jsx( 2489 "button", 2490 { 2491 type: "button", 2492 onClick: (e) => { 2493 e.stopPropagation(); 2494 handleResetProfile(); 2495 }, 2496 className: "px-2.5 py-1 text-[10px] font-bold rounded bg-zinc-800 hover:bg-zinc-700 text-zinc-300 border border-zinc-700 transition", 2497 children: "Reset to Preset Defaults" 2498 } 2499 ),
2500 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-xs text-zinc-400 font-semibold flex items-center gap-1", children: [ 2501 showAdvancedTuning ? "Collapse" : "Expand", 2502 showAdvancedTuning ? /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronUp, { className: "w-4 h-4" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronDown, { className: "w-4 h-4" }) 2503 ] }) 2504 ] }) 2505 ] 2506 } 2507 ), 2508 showAdvancedTuning && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-5 space-y-6", children: [ 2509 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-gradient-to-r from-blue-950/40 via-cyan-950/30 to-zinc-950 p-5 rounded-xl border border-cyan-500/30 space-y-4", children: [ 2510 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col md:flex-row md:items-center justify-between gap-2", children: [ 2511 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [
2512 /* @__PURE__ */ jsxRuntimeExports.jsx(Snowflake, { className: "w-5 h-5 text-cyan-400" }), 2513 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm font-bold text-white", children: "Winter & Cold Ambient Free-Cooling Hysteresis" }) 2514 ] }), 2515 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-xs text-cyan-400 font-mono bg-cyan-950/80 border border-cyan-800/60 px-2.5 py-1 rounded-full flex items-center gap-1.5", children: [ 2516 /* @__PURE__ */ jsxRuntimeExports.jsx(CircleCheck, { className: "w-3.5 h-3.5 text-cyan-400" }), 2517 "Auto-Cutoff Enabled (⤠", 2518 (config == null ? void 0 : config.cold_cutoff_temp) ?? 20, 2519 "°C)" 2520 ] }) 2521 ] }), 2522 /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-xs text-zinc-400", children: [ 2523 "When outdoor ambient in Tokyo is cold (e.g. 5°C winter) or room naturally dissipates heat, the AC is powered ",
2524 /* @__PURE__ */ jsxRuntimeExports.jsx("strong", { children: "completely OFF (0W draw)" }), 2525 ". It will remain off until the server inlet warms up to the wakeup threshold." 2526 ] }), 2527 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-1 md:grid-cols-3 gap-4 text-xs pt-1", children: [ 2528 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-zinc-950/60 p-4 rounded-xl border border-zinc-800 space-y-2", children: [ 2529 /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "text-cyan-300 font-semibold flex items-center justify-between gap-1", children: [ 2530 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "âï¸ Cold Cutoff Inlet (°C)" }), 2531 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] font-semibold text-cyan-400/90 bg-cyan-950/80 border border-cyan-800/50 px-1.5 py-0.5 rounded", children: "Rec: 20°C" }) 2532 ] }),
2533 /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-[11px] text-zinc-500", children: [ 2534 "If inlet falls ⤠this temp, AC turns ", 2535 /* @__PURE__ */ jsxRuntimeExports.jsx("strong", { children: "Power: OFF" }), 2536 "." 2537 ] }), 2538 /* @__PURE__ */ jsxRuntimeExports.jsx( 2539 "input", 2540 { 2541 type: "number", 2542 min: "16", 2543 max: "23", 2544 value: (config == null ? void 0 : config.cold_cutoff_temp) ?? 20, 2545 onChange: (e) => handleHysteresisChange("cold_cutoff_temp", parseInt(e.target.value, 10)), 2546 className: "w-full bg-zinc-900 border border-zinc-700 rounded-lg p-2.5 text-white font-bold" 2547 } 2548 ) 2549 ] }), 2550 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-zinc-950/60 p-4 rounded-xl border border-zinc-800 space-y-2", children: [
2551 /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "text-amber-300 font-semibold flex items-center justify-between gap-1", children: [ 2552 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "ð¥ Warm Wakeup Inlet (°C)" }), 2553 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] font-semibold text-amber-400/90 bg-amber-950/80 border border-amber-800/50 px-1.5 py-0.5 rounded", children: "Rec: 25°C" }) 2554 ] }), 2555 /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-[11px] text-zinc-500", children: [ 2556 "When OFF, wakes up and turns ", 2557 /* @__PURE__ */ jsxRuntimeExports.jsx("strong", { children: "Power: ON" }), 2558 " at ⥠this temp." 2559 ] }), 2560 /* @__PURE__ */ jsxRuntimeExports.jsx( 2561 "input", 2562 { 2563 type: "number", 2564 min: "22", 2565 max: "29", 2566 value: (config == null ? void 0 : config.warm_wakeup_temp) ?? 25, 2567 onChange: (e) => handleHysteresisChange("warm_wakeup_temp", parseInt(e.target.value, 10)), 2568 className: "w-full bg-zinc-900 border border-zinc-700 rounded-lg p-2.5 text-white font-bold" 2569 } 2570 ) 2571 ] }),
2572 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-zinc-950/60 p-4 rounded-xl border border-zinc-800 space-y-2", children: [ 2573 /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "text-rose-300 font-semibold flex items-center justify-between gap-1", children: [ 2574 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "⡠CPU Spike Wakeup (°C)" }), 2575 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] font-semibold text-rose-400/90 bg-rose-950/80 border border-rose-800/50 px-1.5 py-0.5 rounded", children: "Rec: 88°C" }) 2576 ] }), 2577 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[11px] text-zinc-500", children: "If CPU spikes ⥠this temp while OFF, immediately wake up AC." }), 2578 /* @__PURE__ */ jsxRuntimeExports.jsx( 2579 "input", 2580 { 2581 type: "number", 2582 min: "70", 2583 max: "95", 2584 value: (config == null ? void 0 : config.emergency_wakeup_cpu_temp) ?? 88, 2585 onChange: (e) => handleHysteresisChange("emergency_wakeup_cpu_temp", parseInt(e.target.value, 10)), 2586 className: "w-full bg-zinc-900 border border-zinc-700 rounded-lg p-2.5 text-white font-bold" 2587 } 2588 ) 2589 ] }) 2590 ] }) 2591 ] }), 2592 (config == null ? void 0 : config.temp_thresholds) && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4", children: [
2593 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-zinc-950 p-5 rounded-xl border border-zinc-800/80 space-y-4", children: [ 2594 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between flex-wrap gap-2", children: [ 2595 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm font-bold text-emerald-400 flex items-center gap-2", children: "â¡ Optimal Policy (Standard)" }), 2596 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-xs text-zinc-400 font-mono bg-zinc-900/80 border border-zinc-800 px-2 py-0.5 rounded", children: [ 2597 "Inlet: ", 2598 config.temp_thresholds.optimal.inlet_temp ?? 22, 2599 "°C â ", 2600 (config.temp_thresholds.warm.inlet_temp ?? 26) - 1, 2601 "°C" 2602 ] }) 2603 ] }), 2604 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-1 sm:grid-cols-3 gap-3 text-xs", children: [
2605 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 2606 /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "text-zinc-400 flex items-center justify-between mb-1", children: [ 2607 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Baseline Inlet (°C)" }), 2608 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] font-semibold text-emerald-400/90 bg-emerald-950/60 border border-emerald-800/40 px-1.5 py-0.2 rounded", children: "Rec: 22°C" }) 2609 ] }), 2610 /* @__PURE__ */ jsxRuntimeExports.jsx( 2611 "input", 2612 { 2613 type: "number", 2614 min: "18", 2615 max: "26", 2616 value: config.temp_thresholds.optimal.inlet_temp ?? 22, 2617 onChange: (e) => handleThresholdChange("optimal", "inlet_temp", parseInt(e.target.value, 10)), 2618 className: "w-full bg-zinc-900 border border-zinc-700 rounded-lg p-2 text-white font-bold" 2619 } 2620 ) 2621 ] }),
2622 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 2623 /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "text-zinc-400 flex items-center justify-between mb-1", children: [ 2624 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Target AC (°C)" }), 2625 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] font-semibold text-emerald-400/90 bg-emerald-950/60 border border-emerald-800/40 px-1.5 py-0.2 rounded", children: "Rec: 24°C" }) 2626 ] }), 2627 /* @__PURE__ */ jsxRuntimeExports.jsx( 2628 "input", 2629 { 2630 type: "number", 2631 min: "16", 2632 max: "30", 2633 value: config.temp_thresholds.optimal.target_ac_temp, 2634 onChange: (e) => handleThresholdChange("optimal", "target_ac_temp", parseInt(e.target.value, 10)), 2635 className: "w-full bg-zinc-900 border border-zinc-700 rounded-lg p-2 text-white font-bold" 2636 } 2637 ) 2638 ] }),
2639 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 2640 /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "text-zinc-400 flex items-center justify-between mb-1", children: [ 2641 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Fan (0=Auto..3)" }), 2642 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] font-semibold text-emerald-400/90 bg-emerald-950/60 border border-emerald-800/40 px-1.5 py-0.2 rounded", children: "Rec: 0 (Auto)" }) 2643 ] }), 2644 /* @__PURE__ */ jsxRuntimeExports.jsx( 2645 "input", 2646 { 2647 type: "number", 2648 min: "0", 2649 max: "3", 2650 value: config.temp_thresholds.optimal.fan, 2651 onChange: (e) => handleThresholdChange("optimal", "fan", parseInt(e.target.value, 10)), 2652 className: "w-full bg-zinc-900 border border-zinc-700 rounded-lg p-2 text-white font-bold" 2653 } 2654 ) 2655 ] }) 2656 ] }) 2657 ] }),
2658 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-zinc-950 p-5 rounded-xl border border-zinc-800/80 space-y-4", children: [ 2659 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between flex-wrap gap-2", children: [ 2660 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm font-bold text-amber-400 flex items-center gap-2", children: "ð¥ Warm Room Policy (High Load)" }), 2661 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-xs text-zinc-400 font-mono bg-zinc-900/80 border border-zinc-800 px-2 py-0.5 rounded", children: [ 2662 "Inlet ⥠", 2663 config.temp_thresholds.warm.inlet_temp ?? 26, 2664 "°C or CPU ⥠", 2665 config.temp_thresholds.warm.cpu_temp ?? 85, 2666 "°C" 2667 ] }) 2668 ] }), 2669 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-2 sm:grid-cols-4 gap-3 text-xs", children: [
2670 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 2671 /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "text-zinc-400 flex items-center justify-between mb-1", children: [ 2672 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Inlet (°C)" }), 2673 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] font-semibold text-amber-400/90 bg-amber-950/60 border border-amber-800/40 px-1 rounded", children: "Rec: 26°C" }) 2674 ] }), 2675 /* @__PURE__ */ jsxRuntimeExports.jsx( 2676 "input", 2677 { 2678 type: "number", 2679 min: "22", 2680 max: "32", 2681 value: config.temp_thresholds.warm.inlet_temp ?? 26, 2682 onChange: (e) => handleThresholdChange("warm", "inlet_temp", parseInt(e.target.value, 10)), 2683 className: "w-full bg-zinc-900 border border-zinc-700 rounded-lg p-2 text-white font-bold" 2684 } 2685 ) 2686 ] }),
2687 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 2688 /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "text-zinc-400 flex items-center justify-between mb-1", children: [ 2689 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "CPU (°C)" }), 2690 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] font-semibold text-amber-400/90 bg-amber-950/60 border border-amber-800/40 px-1 rounded", children: "Rec: 85°C" }) 2691 ] }), 2692 /* @__PURE__ */ jsxRuntimeExports.jsx( 2693 "input", 2694 { 2695 type: "number", 2696 min: "70", 2697 max: "95", 2698 value: config.temp_thresholds.warm.cpu_temp ?? 85, 2699 onChange: (e) => handleThresholdChange("warm", "cpu_temp", parseInt(e.target.value, 10)), 2700 className: "w-full bg-zinc-900 border border-zinc-700 rounded-lg p-2 text-white font-bold" 2701 } 2702 ) 2703 ] }),
2704 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 2705 /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "text-zinc-400 flex items-center justify-between mb-1", children: [ 2706 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Target (°C)" }), 2707 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] font-semibold text-amber-400/90 bg-amber-950/60 border border-amber-800/40 px-1 rounded", children: "Rec: 22°C" }) 2708 ] }), 2709 /* @__PURE__ */ jsxRuntimeExports.jsx( 2710 "input", 2711 { 2712 type: "number", 2713 min: "16", 2714 max: "30", 2715 value: config.temp_thresholds.warm.target_ac_temp, 2716 onChange: (e) => handleThresholdChange("warm", "target_ac_temp", parseInt(e.target.value, 10)), 2717 className: "w-full bg-zinc-900 border border-zinc-700 rounded-lg p-2 text-white font-bold" 2718 } 2719 ) 2720 ] }),
2721 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 2722 /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "text-zinc-400 flex items-center justify-between mb-1", children: [ 2723 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Fan (0..3)" }), 2724 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] font-semibold text-amber-400/90 bg-amber-950/60 border border-amber-800/40 px-1 rounded", children: "Rec: 2" }) 2725 ] }), 2726 /* @__PURE__ */ jsxRuntimeExports.jsx( 2727 "input", 2728 { 2729 type: "number", 2730 min: "0", 2731 max: "3", 2732 value: config.temp_thresholds.warm.fan, 2733 onChange: (e) => handleThresholdChange("warm", "fan", parseInt(e.target.value, 10)), 2734 className: "w-full bg-zinc-900 border border-zinc-700 rounded-lg p-2 text-white font-bold" 2735 } 2736 ) 2737 ] }) 2738 ] }) 2739 ] }),
2740 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-zinc-950 p-5 rounded-xl border border-zinc-800/80 space-y-4", children: [ 2741 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between flex-wrap gap-2", children: [ 2742 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm font-bold text-rose-400 flex items-center gap-2", children: "ð¨ Emergency Chill Policy" }), 2743 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-xs text-zinc-400 font-mono bg-zinc-900/80 border border-zinc-800 px-2 py-0.5 rounded", children: [ 2744 "Inlet ⥠", 2745 config.temp_thresholds.emergency_high.inlet_temp ?? 28, 2746 "°C or CPU ⥠", 2747 config.temp_thresholds.emergency_high.cpu_temp ?? 92, 2748 "°C" 2749 ] }) 2750 ] }), 2751 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-2 sm:grid-cols-4 gap-3 text-xs", children: [
2752 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 2753 /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "text-zinc-400 flex items-center justify-between mb-1", children: [ 2754 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Inlet (°C)" }), 2755 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] font-semibold text-rose-400/90 bg-rose-950/60 border border-rose-800/40 px-1 rounded", children: "Rec: 28°C" }) 2756 ] }), 2757 /* @__PURE__ */ jsxRuntimeExports.jsx( 2758 "input", 2759 { 2760 type: "number", 2761 min: "24", 2762 max: "35", 2763 value: config.temp_thresholds.emergency_high.inlet_temp ?? 28, 2764 onChange: (e) => handleThresholdChange("emergency_high", "inlet_temp", parseInt(e.target.value, 10)), 2765 className: "w-full bg-zinc-900 border border-zinc-700 rounded-lg p-2 text-white font-bold" 2766 } 2767 ) 2768 ] }),
2769 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 2770 /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "text-zinc-400 flex items-center justify-between mb-1", children: [ 2771 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "CPU (°C)" }), 2772 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] font-semibold text-rose-400/90 bg-rose-950/60 border border-rose-800/40 px-1 rounded", children: "Rec: 92°C" }) 2773 ] }), 2774 /* @__PURE__ */ jsxRuntimeExports.jsx( 2775 "input", 2776 { 2777 type: "number", 2778 min: "75", 2779 max: "98", 2780 value: config.temp_thresholds.emergency_high.cpu_temp ?? 92, 2781 onChange: (e) => handleThresholdChange("emergency_high", "cpu_temp", parseInt(e.target.value, 10)), 2782 className: "w-full bg-zinc-900 border border-zinc-700 rounded-lg p-2 text-white font-bold" 2783 } 2784 ) 2785 ] }),
2786 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 2787 /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "text-zinc-400 flex items-center justify-between mb-1", children: [ 2788 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Target (°C)" }), 2789 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] font-semibold text-rose-400/90 bg-rose-950/60 border border-rose-800/40 px-1 rounded", children: "Rec: 19°C" }) 2790 ] }), 2791 /* @__PURE__ */ jsxRuntimeExports.jsx( 2792 "input", 2793 { 2794 type: "number", 2795 min: "16", 2796 max: "30", 2797 value: config.temp_thresholds.emergency_high.target_ac_temp, 2798 onChange: (e) => handleThresholdChange("emergency_high", "target_ac_temp", parseInt(e.target.value, 10)), 2799 className: "w-full bg-zinc-900 border border-zinc-700 rounded-lg p-2 text-white font-bold" 2800 } 2801 ) 2802 ] }),
2803 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 2804 /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "text-zinc-400 flex items-center justify-between mb-1", children: [ 2805 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Fan (0..3)" }), 2806 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] font-semibold text-rose-400/90 bg-rose-950/60 border border-rose-800/40 px-1 rounded", children: "Rec: 3" }) 2807 ] }), 2808 /* @__PURE__ */ jsxRuntimeExports.jsx( 2809 "input", 2810 { 2811 type: "number", 2812 min: "0", 2813 max: "3", 2814 value: config.temp_thresholds.emergency_high.fan, 2815 onChange: (e) => handleThresholdChange("emergency_high", "fan", parseInt(e.target.value, 10)), 2816 className: "w-full bg-zinc-900 border border-zinc-700 rounded-lg p-2 text-white font-bold" 2817 } 2818 ) 2819 ] }) 2820 ] }) 2821 ] }),
2822 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-zinc-950 p-5 rounded-xl border border-zinc-800/80 space-y-4", children: [ 2823 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between flex-wrap gap-2", children: [ 2824 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm font-bold text-cyan-400 flex items-center gap-2", children: "ð¿ Cool / Eco Policy" }), 2825 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-xs text-zinc-400 font-mono bg-zinc-900/80 border border-zinc-800 px-2 py-0.5 rounded", children: [ 2826 "Inlet ⤠", 2827 config.temp_thresholds.cool.inlet_temp ?? 20, 2828 "°C" 2829 ] }) 2830 ] }), 2831 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-1 sm:grid-cols-3 gap-3 text-xs", children: [ 2832 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
2833 /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "text-zinc-400 flex items-center justify-between mb-1", children: [ 2834 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Trigger Low Inlet (°C)" }), 2835 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] font-semibold text-cyan-400/90 bg-cyan-950/60 border border-cyan-800/40 px-1.5 py-0.2 rounded", children: "Rec: 20°C" }) 2836 ] }), 2837 /* @__PURE__ */ jsxRuntimeExports.jsx( 2838 "input", 2839 { 2840 type: "number", 2841 min: "16", 2842 max: "23", 2843 value: config.temp_thresholds.cool.inlet_temp ?? 20, 2844 onChange: (e) => handleThresholdChange("cool", "inlet_temp", parseInt(e.target.value, 10)), 2845 className: "w-full bg-zinc-900 border border-zinc-700 rounded-lg p-2 text-white font-bold" 2846 } 2847 ) 2848 ] }),
2849 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 2850 /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "text-zinc-400 flex items-center justify-between mb-1", children: [ 2851 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Target AC (°C)" }), 2852 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] font-semibold text-cyan-400/90 bg-cyan-950/60 border border-cyan-800/40 px-1.5 py-0.2 rounded", children: "Rec: 26°C" }) 2853 ] }), 2854 /* @__PURE__ */ jsxRuntimeExports.jsx( 2855 "input", 2856 { 2857 type: "number", 2858 min: "16", 2859 max: "30", 2860 value: config.temp_thresholds.cool.target_ac_temp, 2861 onChange: (e) => handleThresholdChange("cool", "target_ac_temp", parseInt(e.target.value, 10)), 2862 className: "w-full bg-zinc-900 border border-zinc-700 rounded-lg p-2 text-white font-bold" 2863 } 2864 ) 2865 ] }),
2866 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 2867 /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "text-zinc-400 flex items-center justify-between mb-1", children: [ 2868 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Fan (0..3)" }), 2869 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] font-semibold text-cyan-400/90 bg-cyan-950/60 border border-cyan-800/40 px-1.5 py-0.2 rounded", children: "Rec: 1 (Low)" }) 2870 ] }), 2871 /* @__PURE__ */ jsxRuntimeExports.jsx( 2872 "input", 2873 { 2874 type: "number", 2875 min: "0", 2876 max: "3", 2877 value: config.temp_thresholds.cool.fan, 2878 onChange: (e) => handleThresholdChange("cool", "fan", parseInt(e.target.value, 10)), 2879 className: "w-full bg-zinc-900 border border-zinc-700 rounded-lg p-2 text-white font-bold" 2880 } 2881 ) 2882 ] }) 2883 ] }) 2884 ] }) 2885 ] }),
2886 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-zinc-950 p-5 rounded-xl border border-zinc-800 space-y-4", children: [ 2887 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between", children: [ 2888 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [ 2889 /* @__PURE__ */ jsxRuntimeExports.jsx(Clock, { className: "w-5 h-5 text-indigo-400" }), 2890 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm font-bold text-white", children: "Guardian Protection & Anti-Cycling Timing" }) 2891 ] }), 2892 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs text-indigo-400/80 font-mono bg-indigo-950/60 border border-indigo-800/50 px-2.5 py-1 rounded-full", children: "Hardware Protection" }) 2893 ] }), 2894 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-zinc-400", children: "Safeguards the physical compressor from rapid on/off cycling wear and configures Redfish telemetry polling rate." }),
2895 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4 text-xs", children: [ 2896 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-zinc-900/50 p-4 rounded-xl border border-zinc-800 space-y-2", children: [ 2897 /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "text-indigo-300 font-semibold flex items-center justify-between", children: [ 2898 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "â±ï¸ Telemetry Polling Interval (Seconds)" }), 2899 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] font-semibold text-indigo-400/90 bg-indigo-950/80 border border-indigo-800/50 px-2 py-0.5 rounded", children: "Rec: 60s" }) 2900 ] }), 2901 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[11px] text-zinc-500", children: "How often the Guardian daemon queries server iDRAC and evaluates thermal rules." }), 2902 /* @__P
2902URE__ */ jsxRuntimeExports.jsx( 2903 "input", 2904 { 2905 type: "number", 2906 min: "15", 2907 max: "300", 2908 value: (config == null ? void 0 : config.poll_interval_seconds) ?? 60, 2909 onChange: (e) => handleHysteresisChange("poll_interval_seconds", parseInt(e.target.value, 10)), 2910 className: "w-full bg-zinc-900 border border-zinc-700 rounded-lg p-2.5 text-white font-bold" 2911 } 2912 ) 2913 ] }), 2914 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-zinc-900/50 p-4 rounded-xl border border-zinc-800 space-y-2", children: [ 2915 /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "text-indigo-300 font-semibold flex items-center justify-between", children: [ 2916 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "ð¡ï¸ Compressor Anti-Cycle Hold (Seconds)" }), 2917 /* @__P
2917URE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] font-semibold text-indigo-400/90 bg-indigo-950/80 border border-indigo-800/50 px-2 py-0.5 rounded", children: "Rec: 180s" }) 2918 ] }), 2919 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[11px] text-zinc-500", children: "Minimum elapsed time between AC power switches to prevent compressor damage." }), 2920 /* @__PURE__ */ jsxRuntimeExports.jsx( 2921 "input", 2922 { 2923 type: "number", 2924 min: "60", 2925 max: "600", 2926 value: (config == null ? void 0 : config.min_switch_interval_seconds) ?? 180, 2927 onChange: (e) => handleHysteresisChange("min_switch_interval_seconds", parseInt(e.target.value, 10)), 2928 className: "w-full bg-zinc-900 border border-zinc-700 rounded-lg p-2.5 text-white font-bold" 2929 } 2930 ) 2931 ] }) 2932 ] }) 2933 ] }) 2934 ] }) 2935 ] }),
2936 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-gradient-to-r from-zinc-950 via-zinc-900 to-zinc-950 p-6 rounded-xl border border-zinc-700/80 space-y-5", children: [ 2937 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col md:flex-row md:items-center justify-between gap-3 pb-3 border-b border-zinc-800", children: [ 2938 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2.5", children: [ 2939 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "p-2 rounded-lg bg-cyan-500/10 border border-cyan-500/20 text-cyan-400", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Wifi, { className: "w-5 h-5" }) }), 2940 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 2941 /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "text-sm font-bold text-white flex items-center gap-2", children: "BOFON AC Controller Local LAN Configuration (miIO UDP)" }), 2942 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-zinc-400 mt-0.5", children: "Direct socket communication on Tokyo subnet without cloud dependency" }) 2943 ] }) 2944 ] }),
2945 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [ 2946 /* @__PURE__ */ jsxRuntimeExports.jsxs( 2947 "button", 2948 { 2949 type: "button", 2950 onClick: handleTestConnection, 2951 disabled: netTesting || netSaving, 2952 className: "px-4 py-2 rounded-xl text-xs font-bold bg-zinc-800 hover:bg-zinc-700 text-zinc-200 border border-zinc-700 transition flex items-center gap-1.5 shadow-sm", 2953 children: [ 2954 /* @__PURE__ */ jsxRuntimeExports.jsx(RefreshCw, { className: `w-3.5 h-3.5 ${netTesting ? "animate-spin text-cyan-400" : ""}` }), 2955 netTesting ? "Testing Handshake..." : "Test Handshake" 2956 ] 2957 } 2958 ), 2959 /* @__PURE__ */ jsxRuntimeExports.jsxs( 2960 "button", 2961 { 2962 type: "button", 2963 onClick: handleSaveNetworkConfig, 2964 disabled: netSaving || netTesting, 2965 className: "px-4 py-2 rounded-xl text-xs font-bold bg-cyan-500 hover:bg-cyan-600 text-white transition flex items-center gap-1.5 shadow-lg shadow-cyan-500/20", 2966 children: [
2967 /* @__PURE__ */ jsxRuntimeExports.jsx(Settings, { className: "w-3.5 h-3.5" }), 2968 netSaving ? "Saving..." : "Save Network Settings" 2969 ] 2970 } 2971 ) 2972 ] }) 2973 ] }), 2974 netTestResult && /* @__PURE__ */ jsxRuntimeExports.jsxs( 2975 "div", 2976 { 2977 className: `p-3.5 rounded-xl text-xs flex items-center justify-between gap-3 border ${netTestResult.success ? "bg-emerald-950/40 border-emerald-500/40 text-emerald-300" : "bg-rose-950/40 border-rose-500/40 text-rose-300"}`, 2978 children: [ 2979 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [ 2980 netTestResult.success ? /* @__PURE__ */ jsxRuntimeExports.jsx(CircleCheck, { className: "w-4 h-4 text-emerald-400 shrink-0" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(TriangleAlert, { className: "w-4 h-4 text-rose-400 shrink-0" }), 2981 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: netTestResult.message }) 2982 ] }), 2983 netTestResult.latency_ms !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono text-[11px] px-2 py-0.5 rounded bg-black/40 border border-current font-bold", children: [ 2984 netTestResult.latency_ms, 2985 "ms latency" 2986 ] }) 2987 ] 2988 } 2989 ),
2990 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-1 md:grid-cols-3 gap-4 text-xs", children: [ 2991 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1.5", children: [ 2992 /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "text-zinc-300 font-semibold flex items-center gap-1.5", children: [ 2993 /* @__PURE__ */ jsxRuntimeExports.jsx(Wifi, { className: "w-3.5 h-3.5 text-cyan-400" }), 2994 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Controller IP Address" }) 2995 ] }), 2996 /* @__PURE__ */ jsxRuntimeExports.jsx( 2997 "input", 2998 { 2999 type: "text", 3000 value: netIp, 3001 onChange: (e) => setNetIp(e.target.value), 3002 placeholder: "192.168.40.190", 3003 className: "w-full bg-zinc-950 border border-zinc-800 rounded-lg p-2.5 text-white font-mono font-medium focus:border-cyan-500 focus:outline-none" 3004 } 3005 ),
3006 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[11px] text-zinc-500", children: "Local LAN IP of the BOFON AC partner" }) 3007 ] }), 3008 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1.5", children: [ 3009 /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "text-zinc-300 font-semibold flex items-center gap-1.5", children: [ 3010 /* @__PURE__ */ jsxRuntimeExports.jsx(Radio, { className: "w-3.5 h-3.5 text-cyan-400" }), 3011 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "miIO UDP Port" }) 3012 ] }), 3013 /* @__PURE__ */ jsxRuntimeExports.jsx( 3014 "input", 3015 { 3016 type: "number", 3017 value: netPort, 3018 onChange: (e) => setNetPort(parseInt(e.target.value, 10)), 3019 placeholder: "54321", 3020 className: "w-full bg-zinc-950 border border-zinc-800 rounded-lg p-2.5 text-white font-mono font-medium focus:border-cyan-500 focus:outline-none" 3021 } 3022 ),
3023 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[11px] text-zinc-500", children: "Standard miIO port (default 54321)" }) 3024 ] }), 3025 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1.5", children: [ 3026 /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "text-zinc-300 font-semibold flex items-center gap-1.5", children: [ 3027 /* @__PURE__ */ jsxRuntimeExports.jsx(SlidersVertical, { className: "w-3.5 h-3.5 text-cyan-400" }), 3028 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Device MAC Address" }) 3029 ] }), 3030 /* @__PURE__ */ jsxRuntimeExports.jsx( 3031 "input", 3032 { 3033 type: "text", 3034 value: netMac, 3035 onChange: (e) => setNetMac(e.target.value), 3036 placeholder: "34:FA:1C:84:C8:8E", 3037 className: "w-full bg-zinc-950 border border-zinc-800 rounded-lg p-2.5 text-white font-mono font-medium focus:border-cyan-500 focus:outline-none" 3038 } 3039 ),
3040 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[11px] text-zinc-500", children: "Hardware BSSID / MAC for reference" }) 3041 ] }), 3042 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1.5 md:col-span-2", children: [ 3043 /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "text-zinc-300 font-semibold flex items-center justify-between", children: [ 3044 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1.5", children: [ 3045 /* @__PURE__ */ jsxRuntimeExports.jsx(Key, { className: "w-3.5 h-3.5 text-cyan-400" }), 3046 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "AES-128 Encryption Token (32 Hex Characters)" }) 3047 ] }), 3048 /* @__PURE__ */ jsxRuntimeExports.jsxs( 3049 "button", 3050 { 3051 type: "button", 3052 onClick: () => setShowToken(!showToken), 3053 className: "text-[11px] text-cyan-400 hover:text-cyan-300 flex items-center gap-1", 3054 children: [ 3055 showToken ? /* @__PURE__ */ jsxRuntimeExports.jsx(EyeOff, { className: "w-3 h-3" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Eye, { className: "w-3 h-3" }), 3056 showToken ? "Hide Token" : "Show Token" 3057 ] 3058 } 3059 ) 3060 ] }),
3061 /* @__PURE__ */ jsxRuntimeExports.jsx( 3062 "input", 3063 { 3064 type: showToken ? "text" : "password", 3065 value: netToken, 3066 onChange: (e) => setNetToken(e.target.value), 3067 placeholder: "a1d46a441e3724e023c36a9120249781", 3068 className: "w-full bg-zinc-950 border border-zinc-800 rounded-lg p-2.5 text-white font-mono text-xs focus:border-cyan-500 focus:outline-none tracking-wider" 3069 } 3070 ), 3071 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[11px] text-zinc-500", children: "Cryptographic token extracted from pairing session for zero-cloud LAN miIO" }) 3072 ] }), 3073 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1.5", children: [ 3074 /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "text-zinc-300 font-semibold flex items-center gap-1.5", children: [ 3075 /* @__PURE__ */ jsxRuntimeExports.jsx(Shield, { className: "w-3.5 h-3.5 text-cyan-400" }),
3076 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Device ID (DID)" }) 3077 ] }), 3078 /* @__PURE__ */ jsxRuntimeExports.jsx( 3079 "input", 3080 { 3081 type: "text", 3082 value: netDid, 3083 onChange: (e) => setNetDid(e.target.value), 3084 placeholder: "2049601204", 3085 className: "w-full bg-zinc-950 border border-zinc-800 rounded-lg p-2.5 text-white font-mono font-medium focus:border-cyan-500 focus:outline-none" 3086 } 3087 ), 3088 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[11px] text-zinc-500", children: "Numerical device identifier" }) 3089 ] }) 3090 ] }) 3091 ] }) 3092 ] }); 3093 })(), 3094 activeTab === "logs" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-zinc-900/80 border border-zinc-800 p-6 rounded-2xl shadow-xl space-y-4", children: [ 3095 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between", children: [
3096 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [ 3097 /* @__PURE__ */ jsxRuntimeExports.jsx(Terminal, { className: "w-5 h-5 text-cyan-400" }), 3098 /* @__PURE__ */ jsxRuntimeExports.jsx("h2", { className: "text-base font-bold text-white", children: "Live Thermal Audit & Regulation Logs" }) 3099 ] }), 3100 /* @__PURE__ */ jsxRuntimeExports.jsxs( 3101 "button", 3102 { 3103 onClick: fetchLogs, 3104 className: "px-3 py-1.5 rounded-lg bg-zinc-800 hover:bg-zinc-700 text-xs text-zinc-300 flex items-center gap-1.5 transition", 3105 children: [ 3106 /* @__PURE__ */ jsxRuntimeExports.jsx(RefreshCw, { className: "w-3.5 h-3.5" }), 3107 "Refresh Logs" 3108 ] 3109 } 3110 ) 3111 ] }), 3112 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "bg-black/80 border border-zinc-800 p-4 rounded-xl font-mono text-xs text-zinc-300 max-h-96 overflow-y-auto space-y-1.5 shadow-inner", children: logs.length > 0 ? logs.map((line, idx) => /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "leading-relaxed hover:bg-zinc-900/50 px-1 rounded", children: line }, idx)) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-zinc-600 italic", children: "No logs recorded yet." }) }) 3113 ] }), 3114 activeTab === "docs" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-6 animate-fadeIn", children: [
3115 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-gradient-to-r from-cyan-950/40 via-indigo-950/30 to-zinc-950 p-6 rounded-2xl border border-cyan-500/30 shadow-xl space-y-3", children: [ 3116 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col sm:flex-row sm:items-center justify-between gap-3", children: [ 3117 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3", children: [ 3118 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "p-2.5 rounded-xl bg-cyan-500/10 border border-cyan-500/30 text-cyan-400", children: /* @__PURE__ */ jsxRuntimeExports.jsx(BookOpen, { className: "w-6 h-6" }) }), 3119 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 3120 /* @__PURE__ */ jsxRuntimeExports.jsx("h2", { className: "text-lg font-bold text-white tracking-tight", children: "Guardian Thermal Regulation Architecture & Policy Guide" }), 3121 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-zinc-400 mt-0.5", children: "How HamieNet AI Guardian safeguards enterprise server hardware with an autonomous multi-tier thermal ladder." }) 3122 ] }) 3123 ] }),
3124 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs text-cyan-400 font-mono bg-cyan-950/70 border border-cyan-800/60 px-3 py-1.5 rounded-full self-start sm:self-auto", children: "Autonomous Decision Tree" }) 3125 ] }), 3126 /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-xs text-zinc-300 leading-relaxed pt-1 border-t border-zinc-800/80", children: [ 3127 "Instead of a primitive home thermostat that only turns on/off at a single fixed temperature, the AI Guardian continuously polls server telemetry every 60 seconds (Dell iDRAC9 Out-Of-Band controller for chassis air intake and Dual Xeon CPU temperatures). It evaluates a ", 3128 /* @__PURE__ */ jsxRuntimeExports.jsx("strong", { children: "top-down priority ladder" }), 3129 " to select the exact target temperature and fan speed needed to protect the silicon while conserving power." 3130 ] }) 3131 ] }), 3132 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-zinc-900/80 border border-zinc-800 p-6 rounded-2xl shadow-xl space-y-5", children: [
3133 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between", children: [ 3134 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [ 3135 /* @__PURE__ */ jsxRuntimeExports.jsx(SlidersVertical, { className: "w-5 h-5 text-cyan-400" }), 3136 /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "text-sm font-bold text-white uppercase tracking-wider", children: "The Priority Thermal Ladder (Top-Down Evaluation)" }) 3137 ] }), 3138 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs text-zinc-500 font-mono", children: "Evaluated Every 60s" }) 3139 ] }), 3140 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-3", children: [ 3141 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-gradient-to-r from-rose-950/40 via-zinc-950 to-zinc-950 p-4 rounded-xl border border-rose-500/40 flex flex-col md:flex-row md:items-center justify-between gap-4", children: [
3142 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1", children: [ 3143 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [ 3144 /* @__PURE__ */ jsxRuntimeExports.jsx(Flame, { className: "w-4 h-4 text-rose-400" }), 3145 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm font-bold text-white", children: "Tier 1: Emergency Chill Policy" }), 3146 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "px-2 py-0.5 rounded-full text-[10px] font-extrabold uppercase bg-rose-950/80 text-rose-400 border border-rose-800/60", children: "Highest Priority ⢠Safety Override" }) 3147 ] }), 3148 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-xs text-zinc-400 flex flex-wrap items-center gap-2", children: [ 3149 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Trigger:" }), 3150 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono text-rose-300 font-bold bg-rose-950/40 px-2 py-0.5 rounded border border-rose-900/50", children: [ 3151 "Inlet ⥠", 3152 ((_q = (_p = config == null ? void 0 : config.temp_thresholds) == null ? void 0 : _p.emergency_high) == null ? void 0 : _q.inlet_temp) ?? 28, 3153 "°C" 3154 ] }),
3155 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "OR" }), 3156 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono text-rose-300 font-bold bg-rose-950/40 px-2 py-0.5 rounded border border-rose-900/50", children: [ 3157 "CPU ⥠", 3158 ((_s = (_r = config == null ? void 0 : config.temp_thresholds) == null ? void 0 : _r.emergency_high) == null ? void 0 : _s.cpu_temp) ?? 92, 3159 "°C" 3160 ] }) 3161 ] }) 3162 ] }), 3163 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3 shrink-0 bg-zinc-900/80 px-3.5 py-2 rounded-xl border border-zinc-800", children: [ 3164 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-right", children: [ 3165 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[10px] text-zinc-400 uppercase font-semibold", children: "AC Command" }), 3166 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-sm font-bold text-rose-300", children: [ 3167 ((_u = (_t = config == null ? void 0 : config.temp_thresholds) == null ? void 0 : _t.emergency_high) == null ? void 0 : _u.target_ac_temp) ?? 19, 3168 "°C ⢠Fan ", 3169 ((_w = (_v = config == null ? void 0 : config.temp_thresholds) == null ? void 0 : _v.emergency_high) == null ? void 0 : _w.fan) ?? 3, 3170 " (Max)" 3171 ] }) 3172 ] }),
3173 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] font-bold text-rose-400 bg-rose-950/90 border border-rose-700/50 px-2 py-1 rounded", children: "Power: ON" }) 3174 ] }) 3175 ] }), 3176 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-gradient-to-r from-amber-950/40 via-zinc-950 to-zinc-950 p-4 rounded-xl border border-amber-500/40 flex flex-col md:flex-row md:items-center justify-between gap-4", children: [ 3177 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1", children: [ 3178 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [ 3179 /* @__PURE__ */ jsxRuntimeExports.jsx(Zap, { className: "w-4 h-4 text-amber-400" }), 3180 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm font-bold text-white", children: "Tier 2: Warm Room Active Cooling" }), 3181 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "px-2 py-0.5 rounded-full text-[10px] font-extrabold uppercase bg-amber-950/80 text-amber-400 border border-amber-800/60", children: "High Compute Load" }) 3182 ] }),
3183 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-xs text-zinc-400 flex flex-wrap items-center gap-2", children: [ 3184 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Trigger:" }), 3185 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono text-amber-300 font-bold bg-amber-950/40 px-2 py-0.5 rounded border border-amber-900/50", children: [ 3186 "Inlet ⥠", 3187 ((_y = (_x = config == null ? void 0 : config.temp_thresholds) == null ? void 0 : _x.warm) == null ? void 0 : _y.inlet_temp) ?? 26, 3188 "°C" 3189 ] }), 3190 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "OR" }), 3191 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono text-amber-300 font-bold bg-amber-950/40 px-2 py-0.5 rounded border border-amber-900/50", children: [ 3192 "CPU ⥠", 3193 ((_A = (_z = config == null ? void 0 : config.temp_thresholds) == null ? void 0 : _z.warm) == null ? void 0 : _A.cpu_temp) ?? 85, 3194 "°C" 3195 ] }),
3196 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "OR" }), 3197 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono text-amber-300 font-bold bg-amber-950/40 px-2 py-0.5 rounded border border-amber-900/50", children: [ 3198 "Wakeup ⥠", 3199 (config == null ? void 0 : config.warm_wakeup_temp) ?? 25, 3200 "°C" 3201 ] }) 3202 ] }) 3203 ] }), 3204 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3 shrink-0 bg-zinc-900/80 px-3.5 py-2 rounded-xl border border-zinc-800", children: [ 3205 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-right", children: [ 3206 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[10px] text-zinc-400 uppercase font-semibold", children: "AC Command" }), 3207 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-sm font-bold text-amber-300", children: [ 3208 ((_C = (_B = config == null ? void 0 : config.temp_thresholds) == null ? void 0 : _B.warm) == null ? void 0 : _C.target_ac_temp) ?? 22, 3209 "°C ⢠Fan ", 3210 ((_E = (_D = config == null ? void 0 : config.temp_thresholds) == null ? void 0 : _D.warm) == null ? void 0 : _E.fan) ?? 2, 3211 " (Med)" 3212 ] }) 3213 ] }),
3214 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] font-bold text-emerald-400 bg-emerald-950/90 border border-emerald-700/50 px-2 py-1 rounded", children: "Power: ON" }) 3215 ] }) 3216 ] }), 3217 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-gradient-to-r from-emerald-950/40 via-zinc-950 to-zinc-950 p-4 rounded-xl border border-emerald-500/40 flex flex-col md:flex-row md:items-center justify-between gap-4", children: [ 3218 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1", children: [ 3219 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [ 3220 /* @__PURE__ */ jsxRuntimeExports.jsx(Activity, { className: "w-4 h-4 text-emerald-400" }), 3221 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm font-bold text-white", children: "Tier 3: Optimal Standard Policy" }), 3222 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "px-2 py-0.5 rounded-full text-[10px] font-extrabold uppercase bg-emerald-950/80 text-emerald-400 border border-emerald-800/60", children: "Cruising Sweet Spot" }) 3223 ] }),
3224 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-xs text-zinc-400 flex flex-wrap items-center gap-2", children: [ 3225 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Trigger:" }), 3226 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono text-emerald-300 font-bold bg-emerald-950/40 px-2 py-0.5 rounded border border-emerald-900/50", children: [ 3227 "Inlet ", 3228 ((_G = (_F = config == null ? void 0 : config.temp_thresholds) == null ? void 0 : _F.optimal) == null ? void 0 : _G.inlet_temp) ?? 22, 3229 "°C â 25°C" 3230 ] }), 3231 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-zinc-500", children: "(Normal operating window while AC is running)" }) 3232 ] }) 3233 ] }), 3234 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3 shrink-0 bg-zinc-900/80 px-3.5 py-2 rounded-xl border border-zinc-800", children: [
3235 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-right", children: [ 3236 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[10px] text-zinc-400 uppercase font-semibold", children: "AC Command" }), 3237 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-sm font-bold text-emerald-300", children: [ 3238 ((_I = (_H = config == null ? void 0 : config.temp_thresholds) == null ? void 0 : _H.optimal) == null ? void 0 : _I.target_ac_temp) ?? 24, 3239 "°C ⢠Fan ", 3240 ((_K = (_J = config == null ? void 0 : config.temp_thresholds) == null ? void 0 : _J.optimal) == null ? void 0 : _K.fan) ?? 0, 3241 " (Auto)" 3242 ] }) 3243 ] }), 3244 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] font-bold text-emerald-400 bg-emerald-950/90 border border-emerald-700/50 px-2 py-1 rounded", children: "Power: ON" }) 3245 ] }) 3246 ] }), 3247 /* @__P
3247URE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-gradient-to-r from-cyan-950/40 via-zinc-950 to-zinc-950 p-4 rounded-xl border border-cyan-500/40 flex flex-col md:flex-row md:items-center justify-between gap-4", children: [ 3248 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1", children: [ 3249 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [ 3250 /* @__PURE__ */ jsxRuntimeExports.jsx(Wind, { className: "w-4 h-4 text-cyan-400" }), 3251 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm font-bold text-white", children: "Tier 4: Cool / Eco Policy" }), 3252 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "px-2 py-0.5 rounded-full text-[10px] font-extrabold uppercase bg-cyan-950/80 text-cyan-400 border border-cyan-800/60", children: "Gentle Airflow ⢠Power Saver" }) 3253 ] }), 3254 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-xs text-zinc-400 flex flex-wrap items-center gap-2", children: [
3255 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Trigger:" }), 3256 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono text-cyan-300 font-bold bg-cyan-950/40 px-2 py-0.5 rounded border border-cyan-900/50", children: [ 3257 "Inlet ⤠", 3258 ((_M = (_L = config == null ? void 0 : config.temp_thresholds) == null ? void 0 : _L.cool) == null ? void 0 : _M.inlet_temp) ?? 20, 3259 "°C" 3260 ] }), 3261 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-zinc-500", children: "(When AC remains powered rather than shut down)" }) 3262 ] }) 3263 ] }), 3264 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3 shrink-0 bg-zinc-900/80 px-3.5 py-2 rounded-xl border border-zinc-800", children: [ 3265 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-right", children: [ 3266 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[10px] text-zinc-400 uppercase font-semibold", children: "AC Command" }),
3267 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-sm font-bold text-cyan-300", children: [ 3268 ((_O = (_N = config == null ? void 0 : config.temp_thresholds) == null ? void 0 : _N.cool) == null ? void 0 : _O.target_ac_temp) ?? 26, 3269 "°C ⢠Fan ", 3270 ((_Q = (_P = config == null ? void 0 : config.temp_thresholds) == null ? void 0 : _P.cool) == null ? void 0 : _Q.fan) ?? 1, 3271 " (Low)" 3272 ] }) 3273 ] }), 3274 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] font-bold text-cyan-400 bg-cyan-950/90 border border-cyan-700/50 px-2 py-1 rounded", children: "Power: ON" }) 3275 ] }) 3276 ] }), 3277 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-gradient-to-r from-blue-950/40 via-zinc-950 to-zinc-950 p-4 rounded-xl border border-blue-500/40 flex flex-col md:flex-row md:items-center justify-between gap-4", children: [ 3278 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1", children: [
3279 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [ 3280 /* @__PURE__ */ jsxRuntimeExports.jsx(Snowflake, { className: "w-4 h-4 text-blue-400" }), 3281 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm font-bold text-white", children: "Tier 5: Winter & Cold Ambient Auto-Off" }), 3282 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "px-2 py-0.5 rounded-full text-[10px] font-extrabold uppercase bg-blue-950/80 text-blue-400 border border-blue-800/60", children: "Passive Free-Cooling ⢠0W Draw" }) 3283 ] }), 3284 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-xs text-zinc-400 flex flex-wrap items-center gap-2", children: [ 3285 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Trigger:" }), 3286 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono text-blue-300 font-bold bg-blue-950/40 px-2 py-0.5 rounded border border-blue-900/50", children: [ 3287 "Inlet ⤠", 3288 (config == null ? void 0 : config.cold_cutoff_temp) ?? 20, 3289 "°C" 3290 ] }),
3291 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-zinc-500", children: [ 3292 "(Sleeps until inlet warms up to ", 3293 (config == null ? void 0 : config.warm_wakeup_temp) ?? 25, 3294 "°C)" 3295 ] }) 3296 ] }) 3297 ] }), 3298 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3 shrink-0 bg-zinc-900/80 px-3.5 py-2 rounded-xl border border-zinc-800", children: [ 3299 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-right", children: [ 3300 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[10px] text-zinc-400 uppercase font-semibold", children: "AC Command" }), 3301 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-sm font-bold text-zinc-400", children: "Compressor Stopped ⢠Standby" }) 3302 ] }), 3303 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] font-bold text-zinc-400 bg-zinc-800 border border-zinc-700 px-2 py-1 rounded", children: "Power: OFF (0W)" }) 3304 ] }) 3305 ] }) 3306 ] }) 3307 ] }),
3308 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-zinc-900/80 border border-cyan-500/30 p-6 rounded-2xl shadow-xl space-y-4", children: [ 3309 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2.5", children: [ 3310 /* @__PURE__ */ jsxRuntimeExports.jsx(CircleQuestionMark, { className: "w-5 h-5 text-cyan-400" }), 3311 /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "text-base font-bold text-white", children: 'Deep Dive: When is the "Cool / Eco Policy" Used Over Other Policies?' }) 3312 ] }), 3313 /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-xs text-zinc-300 leading-relaxed", children: [ 3314 "A common question is why the system offers both ", 3315 /* @__PURE__ */ jsxRuntimeExports.jsx("strong", { children: "Winter Auto-Off" }), 3316 " and ", 3317 /* @__PURE__ */ jsxRuntimeExports.jsx("strong", { children: "Cool / Eco Policy" }), 3318 " when server temperatures are low. They serve two distinct operating philosophies:" 3319 ] }),
3320 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4 text-xs pt-2", children: [ 3321 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-zinc-950 p-4 rounded-xl border border-blue-500/30 space-y-2.5", children: [ 3322 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between", children: [ 3323 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-bold text-blue-300 flex items-center gap-1.5", children: [ 3324 /* @__PURE__ */ jsxRuntimeExports.jsx(Snowflake, { className: "w-4 h-4" }), 3325 "Winter Auto-Off (Free-Cooling)" 3326 ] }), 3327 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "px-2 py-0.5 rounded bg-blue-950 text-blue-300 border border-blue-800/50 text-[10px] font-bold", children: "0 Watt Power Draw" }) 3328 ] }), 3329 /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-zinc-400 leading-relaxed", children: [ 3330 "Completely turns the air conditioner ",
3331 /* @__PURE__ */ jsxRuntimeExports.jsx("strong", { children: "OFF" }), 3332 ". This is designed for cold seasons (such as Tokyo winter where outdoor ambient is 5°C). The server heat naturally radiates through the walls and ventilation, so running an active compressor is a waste of electricity. The AC remains fully powered off until the room warms up to 25°C." 3333 ] }) 3334 ] }), 3335 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-zinc-950 p-4 rounded-xl border border-cyan-500/30 space-y-2.5", children: [ 3336 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between", children: [ 3337 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-bold text-cyan-300 flex items-center gap-1.5", children: [ 3338 /* @__PURE__ */ jsxRuntimeExports.jsx(Wind, { className: "w-4 h-4" }), 3339 "Cool / Eco Policy" 3340 ] }), 3341 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "px-2 py-0.5 rounded bg-cyan-950 text-cyan-300 border border-cyan-800/50 text-[10px] font-bold", children: "Continuous Gentle Airflow" }) 3342 ] }),
3343 /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-zinc-400 leading-relaxed", children: [ 3344 "Keeps the air conditioner ", 3345 /* @__PURE__ */ jsxRuntimeExports.jsx("strong", { children: "ON" }), 3346 ", but backs off the compressor to ", 3347 /* @__PURE__ */ jsxRuntimeExports.jsx("strong", { children: "26°C with Low Fan" }), 3348 ". This is designed for spring, autumn, or humid periods where you want continuous air circulation and air filtration across the server face without shocking the compressor with on/off power cycles." 3349 ] }) 3350 ] }) 3351 ] }), 3352 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-zinc-950/80 p-4 rounded-xl border border-zinc-800 space-y-3 mt-2", children: [ 3353 /* @__PURE__ */ jsxRuntimeExports.jsxs("h4", { className: "text-xs font-bold text-white uppercase tracking-wider flex items-center gap-2", children: [ 3354 /* @__PURE__ */ jsxRuntimeExports.jsx(SlidersVertical, { className: "w-4 h-4 text-indigo-400" }), 3355 "Configuration Recipes: Choosing Between Auto-Off and Cool/Eco" 3356 ] }),
3357 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-3 text-xs text-zinc-400", children: [ 3358 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-3 bg-zinc-900/60 rounded-lg border border-zinc-800", children: [ 3359 /* @__PURE__ */ jsxRuntimeExports.jsx("b", { className: "text-white block mb-1", children: "Recipe 1: Maximum Power Savings (Recommended)" }), 3360 "Keep Cold Cutoff at ", 3361 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-cyan-400 font-mono font-bold", children: "20°C" }), 3362 ". As soon as server inlet falls to ⤠20°C, the AC turns completely OFF. It will sleep for several hours until heat reaches 25°C, providing maximum power savings." 3363 ] }), 3364 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-3 bg-zinc-900/60 rounded-lg border border-zinc-800", children: [ 3365 /* @__PURE__ */ jsxRuntimeExports.jsx("b", { className: "text-white block mb-1", children: "Recipe 2: Gentle Continuous Circulation" }), 3366 "Lower Cold Cutoff to ",
3367 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-cyan-400 font-mono font-bold", children: "18°C" }), 3368 " and set Cool/Eco to ", 3369 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-cyan-400 font-mono font-bold", children: "21°C" }), 3370 ". Between 18°C and 21°C, the AC cruises gently in Cool/Eco mode (26°C, Low Fan). It only powers off completely if the room drops below 18°C." 3371 ] }) 3372 ] }) 3373 ] }) 3374 ] }), 3375 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-zinc-900/80 border border-zinc-800 p-6 rounded-2xl shadow-xl space-y-4", children: [ 3376 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [ 3377 /* @__PURE__ */ jsxRuntimeExports.jsx(Clock, { className: "w-5 h-5 text-indigo-400" }), 3378 /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "text-sm font-bold text-white uppercase tracking-wider", children: "Hardware Safety Protections & Anti-Cycling Architecture" }) 3379 ] }),
3380 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-1 md:grid-cols-3 gap-4 text-xs", children: [ 3381 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-zinc-950 p-4 rounded-xl border border-zinc-800 space-y-2", children: [ 3382 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-bold text-indigo-300 flex items-center gap-1.5", children: [ 3383 /* @__PURE__ */ jsxRuntimeExports.jsx(Shield, { className: "w-4 h-4 text-indigo-400" }), 3384 "Compressor Anti-Cycle Hold (180s)" 3385 ] }), 3386 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-zinc-400 leading-relaxed", children: "AC compressors can be damaged if turned on and off repeatedly without time for internal refrigerant oil pressure to equalize. The Guardian enforces a strict 3-minute minimum hold between power changes." }) 3387 ] }), 3388 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-zinc-950 p-4 rounded-xl border border-zinc-800 space-y-2", children: [
3389 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-bold text-rose-300 flex items-center gap-1.5", children: [ 3390 /* @__PURE__ */ jsxRuntimeExports.jsx(TriangleAlert, { className: "w-4 h-4 text-rose-400" }), 3391 "Emergency Override Bypass" 3392 ] }), 3393 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-zinc-400 leading-relaxed", children: "If server inlet hits ⥠28°C or CPU hits ⥠92°C, safety holds are immediately overridden. Hardware survival takes precedence, commanding emergency chill instantly without waiting for timers." }) 3394 ] }), 3395 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-zinc-950 p-4 rounded-xl border border-zinc-800 space-y-2", children: [ 3396 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-bold text-amber-300 flex items-center gap-1.5", children: [ 3397 /* @__PURE__ */ jsxRuntimeExports.jsx(Cpu, { className: "w-4 h-4 text-amber-400" }), 3398 "CPU Spike Wakeup (88°C)" 3399 ] }),
3400 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-zinc-400 leading-relaxed", children: "When the AC is sleeping in Winter Auto-Off, a sudden burst of worker transcoding or compile jobs will heat the CPU silicon before the room air warms up. If CPU spikes ⥠88°C, the AC wakes up immediately." }) 3401 ] }) 3402 ] }) 3403 ] }) 3404 ] }), 3405 activeTab === "octopus" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-6", children: [ 3406 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-zinc-900/80 border border-zinc-800 p-6 rounded-2xl shadow-xl space-y-4", children: [ 3407 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col lg:flex-row lg:items-center justify-between gap-4", children: [ 3408 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-start gap-3.5", children: [ 3409 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "p-3 bg-amber-500/10 border border-amber-500/20 rounded-xl text-amber-400 mt-0.5 shrink-0", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Zap, { className: "w-6 h-6" }) }),
3410 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1", children: [ 3411 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [ 3412 /* @__PURE__ */ jsxRuntimeExports.jsx("h2", { className: "text-lg font-bold text-white tracking-wide", children: "Octopus Energy Grid Monitor" }), 3413 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "px-2.5 py-0.5 rounded-full text-xs font-bold bg-amber-500/15 text-amber-300 border border-amber-500/30 flex items-center gap-1.5", children: [ 3414 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "w-2 h-2 rounded-full bg-emerald-400 animate-pulse" }), 3415 ((_R = octopusStatus == null ? void 0 : octopusStatus.plan) == null ? void 0 : _R.name) || "Simple Octopus", 3416 " (", 3417 ((_S = octopusStatus == null ? void 0 : octopusStatus.grid) == null ? void 0 : _S.contractCapacity) || "50A", 3418 ")" 3419 ] }), 3420 (octopusStatus == null ? void 0 : octopusStatus.isCached) && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "px-2 py-0.5 rounded-full text-[10px] font-mono text-zinc-400 bg-zinc-800/80 border border-zinc-700/60", title: "Short-term cache active to prevent Kraken API rate limiting", children: "15m Cache Active" }) 3421 ] }),
3422 /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-xs text-zinc-400", children: [ 3423 "Live smart meter feed from TEPCO Power Grid via Octopus Energy Japan Kraken GraphQL API (Account: ", 3424 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono text-zinc-300 font-semibold", children: ((_T = octopusStatus == null ? void 0 : octopusStatus.account) == null ? void 0 : _T.number) || "A-277BFC94" }), 3425 ")" 3426 ] }) 3427 ] }) 3428 ] }), 3429 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-wrap items-center gap-2.5 self-end lg:self-center", children: [ 3430 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center bg-zinc-950 p-1 rounded-xl border border-zinc-800 text-xs font-semibold", children: [ 3431 /* @__PURE__ */ jsxRuntimeExports.jsx( 3432 "button", 3433 { 3434 onClick: () => setOctopusViewMode("intervals"), 3435 className: `px-3 py-1.5 rounded-lg transition-all ${octopusViewMode === "intervals" ? "bg-amber-500/20 text-amber-300 border border-amber-500/30 shadow-sm" : "text-zinc-400 hover:text-zinc-200"}`, 3436 children: "30-Min Intervals" 3437 } 3438 ),
3439 /* @__PURE__ */ jsxRuntimeExports.jsx( 3440 "button", 3441 { 3442 onClick: () => setOctopusViewMode("daily"), 3443 className: `px-3 py-1.5 rounded-lg transition-all ${octopusViewMode === "daily" ? "bg-amber-500/20 text-amber-300 border border-amber-500/30 shadow-sm" : "text-zinc-400 hover:text-zinc-200"}`, 3444 children: "Daily Totals" 3445 } 3446 ) 3447 ] }), 3448 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center bg-zinc-950 p-1 rounded-xl border border-zinc-800 text-xs font-semibold", children: OCTOPUS_RANGE_OPTIONS.map((opt) => /* @__PURE__ */ jsxRuntimeExports.jsx( 3449 "button", 3450 { 3451 onClick: () => { 3452 setOctopusRange(opt.id); 3453 fetchOctopusReadings(opt.id); 3454 }, 3455 className: `px-2.5 py-1.5 rounded-lg transition-all ${octopusRange === opt.id ? "bg-zinc-800 text-white font-bold" : "text-zinc-400 hover:text-zinc-200"}`, 3456 title: opt.fullLabel, 3457 children: opt.label 3458 }, 3459 opt.id 3460 )) }),
3461 /* @__PURE__ */ jsxRuntimeExports.jsxs( 3462 "button", 3463 { 3464 onClick: handleOctopusSync, 3465 disabled: octopusSyncing || octopusLoading, 3466 className: "p-2.5 rounded-xl bg-zinc-800/80 hover:bg-zinc-700 text-zinc-200 border border-zinc-700/60 transition flex items-center gap-1.5 text-xs font-bold cursor-pointer", 3467 title: "Invalidate cache and sync fresh smart meter telemetry", 3468 children: [ 3469 /* @__PURE__ */ jsxRuntimeExports.jsx(RefreshCw, { className: `w-4 h-4 ${octopusSyncing ? "animate-spin text-amber-400" : ""}` }), 3470 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "hidden sm:inline", children: "Sync" }) 3471 ] 3472 } 3473 ), 3474 /* @__PURE__ */ jsxRuntimeExports.jsxs( 3475 "button", 3476 { 3477 onClick: () => { 3478 setOctTestResult(null); 3479 setOctopusModalOpen(true); 3480 }, 3481 className: "p-2.5 rounded-xl bg-zinc-800/80 hover:bg-zinc-700 text-zinc-200 border border-zinc-700/60 transition flex items-center gap-1.5 text-xs font-bold cursor-pointer", 3482 title: "Configure Octopus Account Credentials", 3483 children: [
3484 /* @__PURE__ */ jsxRuntimeExports.jsx(Settings, { className: "w-4 h-4 text-cyan-400" }), 3485 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "hidden sm:inline", children: "Config" }) 3486 ] 3487 } 3488 ) 3489 ] }) 3490 ] }), 3491 (octopusStatus == null ? void 0 : octopusStatus.warning) && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-3.5 bg-amber-950/40 border border-amber-500/40 rounded-xl text-amber-300 text-xs flex items-center gap-2", children: [ 3492 /* @__PURE__ */ jsxRuntimeExports.jsx(TriangleAlert, { className: "w-4 h-4 shrink-0 text-amber-400" }), 3493 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: octopusStatus.warning }) 3494 ] }) 3495 ] }), 3496 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4", children: [ 3497 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-zinc-900/80 border border-zinc-800 p-4 rounded-2xl relative overflow-hidden shadow-lg", children: [
3498 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between", children: [ 3499 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs font-semibold text-zinc-400 uppercase tracking-wider", children: "Today's Usage" }), 3500 /* @__PURE__ */ jsxRuntimeExports.jsx(Zap, { className: "w-4 h-4 text-amber-400" }) 3501 ] }), 3502 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-2 flex items-baseline gap-2", children: [ 3503 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-3xl font-extrabold text-white", children: ((_V = (_U = octopusStatus == null ? void 0 : octopusStatus.metrics) == null ? void 0 : _U.today) == null ? void 0 : _V.kwh) !== void 0 ? `${octopusStatus.metrics.today.kwh.toFixed(2)}` : "--" }), 3504 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm font-bold text-amber-400", children: "kWh" }) 3505 ] }), 3506 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-2 flex items-center justify-between text-xs text-zinc-400 pt-2 border-t border-zinc-800/60", children: [
3507 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Yesterday:" }), 3508 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono font-bold text-zinc-200", children: ((_X = (_W = octopusStatus == null ? void 0 : octopusStatus.metrics) == null ? void 0 : _W.yesterday) == null ? void 0 : _X.kwh) !== void 0 ? `${octopusStatus.metrics.yesterday.kwh.toFixed(2)} kWh` : "--" }) 3509 ] }) 3510 ] }), 3511 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-zinc-900/80 border border-zinc-800 p-4 rounded-2xl relative overflow-hidden shadow-lg", children: [ 3512 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between", children: [ 3513 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs font-semibold text-zinc-400 uppercase tracking-wider", children: "Today's Cost" }), 3514 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-xs font-mono font-bold px-2 py-0.5 rounded bg-emerald-500/20 text-emerald-300 border border-emerald-500/30", children: [ 3515 "Â¥", 3516 ((_Z = (_Y = octopusStatus == null ? void 0 : octopusStatus.metrics) == null ? void 0 : _Y.today) == null ? void 0 : _Z.effectiveRate) ? `${octopusStatus.metrics.today.effectiveRate}/kWh` : "34.5/kWh" 3517 ] }) 3518 ] }),
3519 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-2 flex items-baseline gap-2", children: [ 3520 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-3xl font-extrabold text-emerald-400", children: ((_$ = (__ = octopusStatus == null ? void 0 : octopusStatus.metrics) == null ? void 0 : __.today) == null ? void 0 : _$.costYen) !== void 0 ? `Â¥${octopusStatus.metrics.today.costYen.toLocaleString()}` : "--" }), 3521 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs text-zinc-400", children: "estimated" }) 3522 ] }), 3523 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-2 flex items-center justify-between text-xs text-zinc-400 pt-2 border-t border-zinc-800/60", children: [ 3524 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Yesterday Cost:" }), 3525 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono font-bold text-emerald-300", children: ((_ba = (_aa = octopusStatus == null ? void 0 : octopusStatus.metrics) == null ? void 0 : _aa.yesterday) == null ? void 0 : _ba.costYen) !== void 0 ? `Â¥${octopusStatus.metrics.yesterday.costYen.toLocaleString()}` : "--" }) 3526 ] }) 3527 ] }), 3528 (() => { 3529 var _a2, _b2, _c2; 3530 const latestWatts = ((_b2 = (_a2 = octopusStatus == null ? void 0 : octopusStatus.metrics) == null ? void 0 : _a2.latestReading) == null ? void 0 : _b2.avgWatts) || 600; 3531 const peakWatts = ((_c2 = octopusReadings == null ? void 0 : octopusReadings.stats) == null ? void 0 : _c2.maxReadingWatts) || 800; 3532 const breakerWatts = 5e3; 3533 const pct = Math.min(100, Math.round(latestWatts / breakerWatts * 100)); 3534 return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-zinc-900/80 border border-zinc-800 p-4 rounded-2xl relative overflow-hidden shadow-lg", children: [
3535 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between", children: [ 3536 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs font-semibold text-zinc-400 uppercase tracking-wider", children: "Recent Grid Draw" }), 3537 /* @__PURE__ */ jsxRuntimeExports.jsx(Activity, { className: "w-4 h-4 text-cyan-400" }) 3538 ] }), 3539 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-2 flex items-baseline gap-2", children: [ 3540 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-3xl font-extrabold text-cyan-400", children: latestWatts }), 3541 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm font-bold text-zinc-400", children: "Watts" }), 3542 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-xs font-mono text-zinc-500 ml-auto", children: [ 3543 "Peak: ", 3544 peakWatts, 3545 "W" 3546 ] }) 3547 ] }),
3548 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-2 w-full bg-zinc-800 h-1.5 rounded-full overflow-hidden", children: /* @__PURE__ */ jsxRuntimeExports.jsx( 3549 "div", 3550 { 3551 className: `h-full rounded-full transition-all duration-500 ${pct < 40 ? "bg-emerald-400" : pct < 70 ? "bg-amber-400" : "bg-rose-400"}`, 3552 style: { width: `${Math.max(5, pct)}%` } 3553 } 3554 ) }), 3555 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-1.5 flex items-center justify-between text-[11px] text-zinc-500", children: [ 3556 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [ 3557 "Breaker Load: ", 3558 pct, 3559 "%" 3560 ] }), 3561 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono", children: "50A Breaker (5kW)" }) 3562 ] }) 3563 ] }); 3564 })(), 3565 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-zinc-900/80 border border-zinc-800 p-4 rounded-2xl relative overflow-hidden shadow-lg", children: [
3566 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between", children: [ 3567 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs font-semibold text-zinc-400 uppercase tracking-wider", children: "Billing Period" }), 3568 /* @__PURE__ */ jsxRuntimeExports.jsx(Calendar, { className: "w-4 h-4 text-purple-400" }) 3569 ] }), 3570 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-2 flex items-baseline gap-2", children: [ 3571 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-2xl font-bold text-white", children: [ 3572 "Day ", 3573 ((_ca = octopusStatus == null ? void 0 : octopusStatus.billing) == null ? void 0 : _ca.cutoffDay) || 1 3574 ] }), 3575 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs text-zinc-400", children: "monthly cutoff" }) 3576 ] }), 3577 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-2 flex items-center justify-between text-xs text-zinc-400 pt-2 border-t border-zinc-800/60", children: [
3578 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Next Read Date:" }), 3579 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono font-bold text-purple-300", children: [ 3580 ((_da = octopusStatus == null ? void 0 : octopusStatus.billing) == null ? void 0 : _da.nextReadingDate) || "Sep 2", 3581 ((_ea = octopusStatus == null ? void 0 : octopusStatus.billing) == null ? void 0 : _ea.daysRemaining) !== null && ((_fa = octopusStatus == null ? void 0 : octopusStatus.billing) == null ? void 0 : _fa.daysRemaining) !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-[10px] text-zinc-400 ml-1", children: [ 3582 "(", 3583 octopusStatus.billing.daysRemaining, 3584 "d left)" 3585 ] }) 3586 ] }) 3587 ] }) 3588 ] }) 3589 ] }), 3590 (() => { 3591 var _a2, _b2, _c2; 3592 const gridWatts = ((_b2 = (_a2 = octopusStatus == null ? void 0 : octopusStatus.metrics) == null ? void 0 : _a2.latestReading) == null ? void 0 : _b2.avgWatts) || 600; 3593 const serverWatts = ((_c2 = serversData == null ? void 0 : serversData.xc640) == null ? void 0 : _c2.power_watts) || (serverData == null ? void 0 : serverData.power_watts) || 182; 3594 const acRunning = acData == null ? void 0 : acData.power; 3595 const estimatedAcWatts = acRunning ? 350 : 0; 3596 const serverPct = Math.min(100, Math.round(serverWatts / gridWatts * 100)); 3597 const acPct = Math.min(100 - serverPct, Math.round(estimatedAcWatts / gridWatts * 100)); 3598 const otherPct = Math.max(0, 100 - serverPct - acPct); 3599 return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-zinc-900/80 border border-zinc-800 p-5 rounded-2xl shadow-xl space-y-4", children: [
3600 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col sm:flex-row sm:items-center justify-between gap-2", children: [ 3601 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2.5", children: [ 3602 /* @__PURE__ */ jsxRuntimeExports.jsx(Server, { className: "w-5 h-5 text-cyan-400" }), 3603 /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "text-sm font-bold text-white tracking-wide", children: "Server Room & Climate Grid Power Correlation" }) 3604 ] }), 3605 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3 text-xs", children: [ 3606 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-zinc-400", children: [ 3607 "Total Grid Draw: ", 3608 /* @__PURE__ */ jsxRuntimeExports.jsxs("b", { className: "text-white font-mono", children: [ 3609 gridWatts, 3610 "W" 3611 ] }) 3612 ] }), 3613 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "px-2 py-0.5 rounded bg-cyan-950/60 border border-cyan-800/40 text-cyan-300 font-mono text-[11px]", children: [ 3614 "Server: ", 3615 serverWatts, 3616 "W (", 3617 serverPct, 3618 "%)" 3619 ] }) 3620 ] }) 3621 ] }),
3622 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "w-full bg-zinc-950 h-5 rounded-xl overflow-hidden p-1 flex items-center gap-1 border border-zinc-800", children: [ 3623 /* @__PURE__ */ jsxRuntimeExports.jsx( 3624 "div", 3625 { 3626 className: "h-full bg-gradient-to-r from-cyan-500 to-blue-500 rounded-lg transition-all duration-500 flex items-center justify-center text-[10px] font-extrabold text-white shadow-sm", 3627 style: { width: `${Math.max(8, serverPct)}%` }, 3628 title: `Dell XC640 Server: ${serverWatts}W (${serverPct}% of grid)`, 3629 children: serverPct > 15 && `Server ${serverWatts}W` 3630 } 3631 ), 3632 acRunning && /* @__PURE__ */ jsxRuntimeExports.jsx( 3633 "div", 3634 { 3635 className: "h-full bg-gradient-to-r from-emerald-500 to-teal-500 rounded-lg transition-all duration-500 flex items-center justify-center text-[10px] font-extrabold text-white shadow-sm", 3636 style: { width: `${Math.max(8, acPct)}%` }, 3637 title: `Air Conditioner: ~${estimatedAcWatts}W (${acPct}% of grid)`, 3638 children: acPct > 15 && `AC ~${estimatedAcWatts}W` 3639 } 3640 ),
3641 /* @__PURE__ */ jsxRuntimeExports.jsx( 3642 "div", 3643 { 3644 className: "h-full bg-zinc-800 rounded-lg transition-all duration-500 flex items-center justify-center text-[10px] font-semibold text-zinc-400", 3645 style: { width: `${Math.max(8, otherPct)}%` }, 3646 title: `Other Premise Load: ~${Math.max(0, gridWatts - serverWatts - estimatedAcWatts)}W (${otherPct}% of grid)`, 3647 children: otherPct > 15 && `Other ~${Math.max(0, gridWatts - serverWatts - estimatedAcWatts)}W` 3648 } 3649 ) 3650 ] }), 3651 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-1 sm:grid-cols-3 gap-3 text-xs pt-1", children: [ 3652 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 p-2.5 rounded-xl bg-zinc-950/60 border border-zinc-800/80", children: [ 3653 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-3 h-3 rounded-full bg-cyan-400 shrink-0" }), 3654 /* @__P
3654URE__ */ jsxRuntimeExports.jsxs("div", { children: [ 3655 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "font-bold text-zinc-200", children: "Dell XC640 (JP Node)" }), 3656 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-[11px] text-zinc-400 font-mono", children: [ 3657 serverWatts, 3658 "W ⢠", 3659 serverPct, 3660 "% total load" 3661 ] }) 3662 ] }) 3663 ] }), 3664 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 p-2.5 rounded-xl bg-zinc-950/60 border border-zinc-800/80", children: [ 3665 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: `w-3 h-3 rounded-full shrink-0 ${acRunning ? "bg-emerald-400 animate-pulse" : "bg-zinc-600"}` }), 3666 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 3667 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "font-bold text-zinc-200", children: "BOFON Air Conditioner" }),
3668 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[11px] text-zinc-400", children: acRunning ? `Compressor Active (~${estimatedAcWatts}W)` : "Standby Mode (0W Compressor)" }) 3669 ] }) 3670 ] }), 3671 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 p-2.5 rounded-xl bg-zinc-950/60 border border-zinc-800/80", children: [ 3672 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-3 h-3 rounded-full bg-zinc-700 shrink-0" }), 3673 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 3674 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "font-bold text-zinc-200", children: "Base / Other Equipment" }), 3675 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-[11px] text-zinc-400 font-mono", children: [ 3676 "~", 3677 Math.max(0, gridWatts - serverWatts - estimatedAcWatts), 3678 "W ⢠", 3679 otherPct, 3680 "% of grid" 3681 ] }) 3682 ] }) 3683 ] }) 3684 ] }) 3685 ] }); 3686 })(),
3687 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-zinc-900/80 border border-zinc-800 p-6 rounded-2xl shadow-xl space-y-4", children: [ 3688 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col lg:flex-row lg:items-center justify-between gap-4 pb-3 border-b border-zinc-800", children: [ 3689 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1", children: [ 3690 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-wrap items-center gap-2.5", children: [ 3691 /* @__PURE__ */ jsxRuntimeExports.jsx(Activity, { className: "w-4 h-4 text-amber-400" }), 3692 /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "text-base font-bold text-white tracking-wide", children: octopusRange === "10y" ? "10-Year Energy & Cost History" : octopusRange === "3y" ? "3-Year Energy & Cost History" : octopusRange === "1y" ? "1-Year Energy & Cost History" : octopusRange === "6m" ? "6-Month Energy & Cost History" : octopusRange === "3m" ? "3-Month Energy & Cost History" : octopusRange === "30d" ? "30-Day Smart Meter Power & Cost Timeline" : octopusRange === "7d" ? "7-Day Smart Meter Power & Cost Timeline" : "24-Hour Smart Meter Power & Cost Timeline" }), 3693 (octopusReadings == null ? void 0 : octopusReadings.isOffline) && /* @__P
3693URE__ */ jsxRuntimeExports.jsxs("span", { className: "px-2 py-0.5 rounded-md bg-amber-500/20 border border-amber-500/40 text-amber-300 font-mono text-[10px] flex items-center gap-1 font-bold", children: [ 3694 /* @__PURE__ */ jsxRuntimeExports.jsx(Database, { className: "w-3 h-3" }), 3695 " Offline Archive" 3696 ] }) 3697 ] }), 3698 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-zinc-400", children: ["3m", "6m", "1y", "3y", "10y"].includes(octopusRange) ? `${octopusRange === "3y" || octopusRange === "10y" ? "Continuous monthly" : "Continuous daily"} aggregation (${((_ga = octopusReadings == null ? void 0 : octopusReadings.points) == null ? void 0 : _ga.length) || 0} ${octopusRange === "3y" || octopusRange === "10y" ? "months" : "days"}) stored persistently on local storage` : `Half-hourly smart meter telemetry (${((_ha = octopusReadings == null ? void 0 : octopusReadings.points) == null ? void 0 : _ha.length) || 0} time blocks) with real-time cost calculation` }) 3699 ] }),
3700 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-wrap items-center gap-2.5", children: [ 3701 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center bg-zinc-950 p-1 rounded-xl border border-zinc-800 text-xs font-semibold", children: [ 3702 /* @__PURE__ */ jsxRuntimeExports.jsxs( 3703 "button", 3704 { 3705 type: "button", 3706 onClick: () => setChartShowPower(!chartShowPower), 3707 className: `px-2.5 py-1.5 rounded-lg transition-all flex items-center gap-1.5 ${chartShowPower ? "bg-amber-500/20 text-amber-300 border border-amber-500/40 shadow-sm" : "text-zinc-500 hover:text-zinc-300 opacity-60"}`, 3708 title: "Toggle Power (Watts) / Energy (kWh) curve", 3709 children: [ 3710 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `w-2 h-2 rounded-full ${chartShowPower ? "bg-amber-400 shadow-sm shadow-amber-400/50" : "bg-zinc-600"}` }), 3711 /* @__P
3711URE__ */ jsxRuntimeExports.jsx("span", { children: ["3m", "6m", "1y", "3y", "10y"].includes(octopusRange) ? "Energy (kWh)" : "Power (W)" }) 3712 ] 3713 } 3714 ), 3715 /* @__PURE__ */ jsxRuntimeExports.jsxs( 3716 "button", 3717 { 3718 type: "button", 3719 onClick: () => setChartShowCost(!chartShowCost), 3720 className: `px-2.5 py-1.5 rounded-lg transition-all flex items-center gap-1.5 ${chartShowCost ? "bg-emerald-500/20 text-emerald-300 border border-emerald-500/40 shadow-sm" : "text-zinc-500 hover:text-zinc-300 opacity-60"}`, 3721 title: "Toggle Cost (Â¥) curve", 3722 children: [ 3723 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `w-2 h-2 rounded-full ${chartShowCost ? "bg-emerald-400 shadow-sm shadow-emerald-400/50" : "bg-zinc-600"}` }), 3724 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Cost (Â¥)" }) 3725 ] 3726 } 3727 ) 3728 ] }),
3729 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center bg-zinc-950 p-1 rounded-xl border border-zinc-800 text-xs font-semibold", children: [ 3730 /* @__PURE__ */ jsxRuntimeExports.jsx( 3731 "button", 3732 { 3733 type: "button", 3734 onClick: () => setOctopusChartType("line"), 3735 className: `px-2.5 py-1.5 rounded-lg transition-all ${octopusChartType === "line" ? "bg-zinc-800 text-white font-bold shadow-sm" : "text-zinc-400 hover:text-zinc-200"}`, 3736 title: "Continuous Line & Area Chart", 3737 children: "Line" 3738 } 3739 ), 3740 /* @__PURE__ */ jsxRuntimeExports.jsx( 3741 "button", 3742 { 3743 type: "button", 3744 onClick: () => setOctopusChartType("bar"), 3745 className: `px-2.5 py-1.5 rounded-lg transition-all ${octopusChartType === "bar" ? "bg-zinc-800 text-white font-bold shadow-sm" : "text-zinc-400 hover:text-zinc-200"}`, 3746 title: "Discrete Column Bar Chart", 3747 children: "Bar" 3748 } 3749 ) 3750 ] }),
3751 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center bg-zinc-950 p-1 rounded-xl border border-zinc-800 text-xs font-semibold", children: OCTOPUS_RANGE_OPTIONS.map((opt) => /* @__PURE__ */ jsxRuntimeExports.jsx( 3752 "button", 3753 { 3754 type: "button", 3755 onClick: () => { 3756 setOctopusRange(opt.id); 3757 fetchOctopusReadings(opt.id); 3758 }, 3759 className: `px-2.5 py-1.5 rounded-lg transition-all ${octopusRange === opt.id ? "bg-amber-500/20 text-amber-300 border border-amber-500/40 font-bold shadow-sm" : "text-zinc-400 hover:text-zinc-200"}`, 3760 title: opt.fullLabel, 3761 children: opt.label 3762 }, 3763 opt.id 3764 )) }) 3765 ] }) 3766 ] }), 3767 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3 text-xs font-mono pt-1", children: [ 3768 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-wrap items-center gap-4", children: [
3769 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1.5 text-amber-300 font-bold", children: [ 3770 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "w-2.5 h-2.5 rounded-sm bg-amber-400" }), 3771 "Total Energy: ", 3772 ((_ia = octopusReadings == null ? void 0 : octopusReadings.stats) == null ? void 0 : _ia.totalKwh) !== void 0 ? `${octopusReadings.stats.totalKwh.toLocaleString()} kWh` : "--" 3773 ] }), 3774 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1.5 text-emerald-300 font-bold", children: [ 3775 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "w-2.5 h-2.5 rounded-sm bg-emerald-400" }), 3776 "Total Cost: ¥", 3777 ((_ja = octopusReadings == null ? void 0 : octopusReadings.stats) == null ? void 0 : _ja.totalCostYen) !== void 0 ? octopusReadings.stats.totalCostYen.toLocaleString() : "--" 3778 ] }) 3779 ] }), 3780 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-wrap items-center gap-4 text-zinc-400", children: [
3781 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [ 3782 "Avg Power: ", 3783 /* @__PURE__ */ jsxRuntimeExports.jsxs("b", { className: "text-zinc-200", children: [ 3784 ((_ka = octopusReadings == null ? void 0 : octopusReadings.stats) == null ? void 0 : _ka.avgWatts) ?? "--", 3785 "W" 3786 ] }) 3787 ] }), 3788 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [ 3789 "Peak Draw: ", 3790 /* @__PURE__ */ jsxRuntimeExports.jsxs("b", { className: "text-amber-300", children: [ 3791 ((_la = octopusReadings == null ? void 0 : octopusReadings.stats) == null ? void 0 : _la.maxReadingWatts) ?? "--", 3792 "W" 3793 ] }) 3794 ] }), 3795 (octopusReadings == null ? void 0 : octopusReadings.archiveCount) ? /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-zinc-500 hidden sm:inline", title: "Persistently saved offline intervals", children: [ 3796 "Archive: ", 3797 octopusReadings.archiveCount.toLocaleString(), 3798 " records" 3799 ] }) : null 3800 ] }) 3801 ] }),
3802 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "relative pt-2 pb-2", children: octopusLoading ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "h-64 flex flex-col items-center justify-center gap-3 text-zinc-400", children: [ 3803 /* @__PURE__ */ jsxRuntimeExports.jsx(RefreshCw, { className: "w-6 h-6 animate-spin text-amber-400" }), 3804 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs", children: "Loading smart meter telemetry from Octopus Energy..." }) 3805 ] }) : !((_ma = octopusReadings == null ? void 0 : octopusReadings.points) == null ? void 0 : _ma.length) ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "h-64 flex flex-col items-center justify-center gap-2 text-zinc-500", children: [ 3806 /* @__PURE__ */ jsxRuntimeExports.jsx(Info, { className: "w-8 h-8 text-zinc-600" }), 3807 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs", children: "No smart meter readings found for this time range." }) 3808 ] }) : octopusChartType === "line" ? ( 3809 /* Full-Width Responsive SVG Line Chart (No Horizontal Scrolling) */ 3810 (() => { 3811 const points = octopusReadings.points; 3812 const isMonthly = octopusRange === "3y" || octopusRange === "10y"; 3813 const isDaily = ["3m", "6m", "1y"].includes(octopusRange); 3814 const isAggregated = isDaily || isMonthly; 3815 const svgW = 1e3; 3816 const svgH = 260; 3817 const padL = 60; 3818 const padR = 60; 3819 const padT = 20; 3820 const padB = 35; 3821 const plotW = svgW - padL - padR; 3822 const plotH = svgH - padT - padB; 3823 const powerValues = points.map((p) => isAggregated ? p.kwh : p.avgWatts); 3824 const maxPowerRaw = Math.max(1, ...powerValues); 3825 const maxPower = maxPowerRaw * 1.15; 3826 const costValues = points.map((p) => p.costYen); 3827 const maxCostRaw = Math.max(1, ...costValues); 3828 const maxCost = maxCostRaw * 1.15; 3829 const coordsPower = points.map((p, i) => { 3830 const x = points.length === 1 ? padL + plotW / 2 : padL + i / (points.length - 1) * plotW; 3831 const val = isAggregated ? p.kwh : p.avgWatts; 3832 const y = padT + plotH - val / maxPower * plotH; 3833 return { x, y, val }; 3834 }); 3835 const coordsCost = points.map((p, i) => { 3836 const x = points.length === 1 ? padL + plotW / 2 : padL + i / (points.length - 1) * plotW; 3837 const val = p.costYen; 3838 const y = padT + plotH - val / maxCost * plotH; 3839 return { x, y, val }; 3840 }); 3841 const powerLinePath = coordsPower.map((c, i) => `${i === 0 ? "M" : "L"} ${c.x.toFixed(1)},${c.y.toFixed(1)}`).join(" "); 3842 const powerAreaPath = `${powerLinePath} L ${coordsPower[coordsPower.length - 1].x.toFixed(1)},${padT + plotH} L ${coordsPower[0].x.toFixed(1)},${padT + plotH} Z`; 3843 const costLinePath = coordsCost.map((c, i) => `${i === 0 ? "M" : "L"} ${c.x.toFixed(1)},${c.y.toFixed(1)}`).join(" "); 3844 const costAreaPath = `${costLinePath} L ${coordsCost[coordsCost.length - 1].x.toFixed(1)},${padT + plotH} L ${coordsCost[0].x.toFixed(1)},${padT + plotH} Z`; 3845 const gridTiers = [0, 0.25, 0.5, 0.75, 1]; 3846 const tickCount = Math.min(points.length, isAggregated ? 12 : 7); 3847 const tickIndices = []; 3848 for (let t = 0; t < tickCount; t++) { 3849 tickIndices.push(Math.round(t / (tickCount - 1) * (points.length - 1))); 3850 } 3851 const activeIdx = hoveredReadingIndex !== null && hoveredReadingIndex >= 0 && hoveredReadingIndex < points.length ? hoveredReadingIndex : null; 3852 const activePoint = activeIdx !== null ? points[activeIdx] : null; 3853 const activePowerCoord = activeIdx !== null ? coordsPower[activeIdx] : null; 3854 const activeCostCoord = activeIdx !== null ? coordsCost[activeIdx] : null; 3855 return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-3", children: [
3856 /* @__PURE__ */ jsxRuntimeExports.jsx( 3857 "div", 3858 { 3859 className: "relative w-full overflow-hidden select-none cursor-crosshair rounded-xl bg-zinc-950/60 border border-zinc-800/80 p-1", 3860 onMouseMove: (e) => { 3861 const rect = e.currentTarget.getBoundingClientRect(); 3862 const clientX = e.clientX - rect.left; 3863 const relativeX = clientX / rect.width * svgW; 3864 const boundedX = Math.max(padL, Math.min(padL + plotW, relativeX)); 3865 const pct = (boundedX - padL) / plotW; 3866 const idx = Math.min(points.length - 1, Math.max(0, Math.round(pct * (points.length - 1)))); 3867 setHoveredReadingIndex(idx); 3868 setHoveredReading(points[idx]); 3869 }, 3870 onMouseLeave: () => { 3871 setHoveredReadingIndex(null); 3872 setHoveredReading(null); 3873 }, 3874 children: /* @__PURE__ */ jsxRuntimeExports.jsxs( 3875 "svg", 3876 {
3877 viewBox: `0 0 ${svgW} ${svgH}`, 3878 className: "w-full h-64 sm:h-72", 3879 preserveAspectRatio: "none", 3880 children: [ 3881 /* @__PURE__ */ jsxRuntimeExports.jsxs("defs", { children: [ 3882 /* @__PURE__ */ jsxRuntimeExports.jsxs("linearGradient", { id: "octPowerGrad", x1: "0", y1: "0", x2: "0", y2: "1", children: [ 3883 /* @__PURE__ */ jsxRuntimeExports.jsx("stop", { offset: "0%", stopColor: "#f59e0b", stopOpacity: "0.35" }), 3884 /* @__PURE__ */ jsxRuntimeExports.jsx("stop", { offset: "100%", stopColor: "#f59e0b", stopOpacity: "0.0" }) 3885 ] }), 3886 /* @__PURE__ */ jsxRuntimeExports.jsxs("linearGradient", { id: "octCostGrad", x1: "0", y1: "0", x2: "0", y2: "1", children: [ 3887 /* @__PURE__ */ jsxRuntimeExports.jsx("stop", { offset: "0%", stopColor: "#10b981", stopOpacity: "0.30" }),
3888 /* @__PURE__ */ jsxRuntimeExports.jsx("stop", { offset: "100%", stopColor: "#10b981", stopOpacity: "0.0" }) 3889 ] }) 3890 ] }), 3891 gridTiers.map((tier, idx) => { 3892 const y = padT + plotH - tier * plotH; 3893 const powerVal = Math.round(tier * maxPower); 3894 const costVal = Math.round(tier * maxCost); 3895 return /* @__PURE__ */ jsxRuntimeExports.jsxs("g", { children: [ 3896 /* @__PURE__ */ jsxRuntimeExports.jsx( 3897 "line", 3898 { 3899 x1: padL, 3900 y1: y, 3901 x2: padL + plotW, 3902 y2: y, 3903 stroke: "#27272a", 3904 strokeDasharray: "3 3", 3905 strokeWidth: "1" 3906 } 3907 ), 3908 chartShowPower && /* @__PURE__ */ jsxRuntimeExports.jsxs( 3909 "text", 3910 { 3911 x: padL - 8, 3912 y: y + 3, 3913 textAnchor: "end", 3914 fill: "#f59e0b", 3915 fontSize: "10", 3916 fontFamily: "monospace", 3917 className: "opacity-75", 3918 children: [ 3919 powerVal, 3920 isAggregated ? "kWh" : "W" 3921 ] 3922 } 3923 ), 3924 chartShowCost && /* @__PURE__ */ jsxRuntimeExports.jsxs( 3925 "text", 3926 { 3927 x: padL + plotW + 8, 3928 y: y + 3, 3929 textAnchor: "start", 3930 fill: "#10b981", 3931 fontSize: "10", 3932 fontFamily: "monospace", 3933 className: "opacity-75", 3934 children: [ 3935 "Â¥", 3936 costVal 3937 ] 3938 } 3939 ) 3940 ] }, idx); 3941 }), 3942 chartShowCost && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
3943 /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: costAreaPath, fill: "url(#octCostGrad)" }), 3944 /* @__PURE__ */ jsxRuntimeExports.jsx( 3945 "path", 3946 { 3947 d: costLinePath, 3948 fill: "none", 3949 stroke: "#10b981", 3950 strokeWidth: "2", 3951 strokeLinecap: "round", 3952 strokeLinejoin: "round" 3953 } 3954 ) 3955 ] }), 3956 chartShowPower && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [ 3957 /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: powerAreaPath, fill: "url(#octPowerGrad)" }), 3958 /* @__PURE__ */ jsxRuntimeExports.jsx( 3959 "path", 3960 { 3961 d: powerLinePath, 3962 fill: "none", 3963 stroke: "#f59e0b", 3964 strokeWidth: "2", 3965 strokeLinecap: "round", 3966 strokeLinejoin: "round" 3967 } 3968 ) 3969 ] }), 3970 points.length <= 48 && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [ 3971 chartShowPower && coordsPower.map((c, i) => /* @__PURE__ */ jsxRuntimeExports.jsx( 3972 "circle", 3973 { 3974 cx: c.x, 3975 cy: c.y, 3976 r: activeIdx === i ? 5 : 2.5, 3977 fill: "#f59e0b", 3978 stroke: "#18181b", 3979 strokeWidth: "1.5" 3980 }, 3981 `p-dot-${i}` 3982 )), 3983 chartShowCost && coordsCost.map((c, i) => /* @__PURE__ */ jsxRuntimeExports.jsx( 3984 "circle", 3985 { 3986 cx: c.x, 3987 cy: c.y, 3988 r: activeIdx === i ? 5 : 2.5, 3989 fill: "#10b981", 3990 stroke: "#18181b", 3991 strokeWidth: "1.5" 3992 }, 3993 `c-dot-${i}` 3994 )) 3995 ] }), 3996 tickIndices.map((ptIdx, k) => { 3997 var _a2; 3998 const pt = points[ptIdx]; 3999 const x = ((_a2 = coordsPower[ptIdx]) == null ? void 0 : _a2.x) || padL + ptIdx / (points.length - 1) * plotW; 4000 return /* @__PURE__ */ jsxRuntimeExports.jsx( 4001 "text", 4002 { 4003 x, 4004 y: padT + plotH + 18, 4005 textAnchor: "middle", 4006 fill: "#71717a", 4007 fontSize: "10", 4008 fontFamily: "monospace", 4009 children: pt.label 4010 }, 4011 k 4012 ); 4013 }), 4014 activePoint && activePowerCoord && activeCostCoord && /* @__P
4014URE__ */ jsxRuntimeExports.jsxs("g", { children: [ 4015 /* @__PURE__ */ jsxRuntimeExports.jsx( 4016 "line", 4017 { 4018 x1: activePowerCoord.x, 4019 y1: padT, 4020 x2: activePowerCoord.x, 4021 y2: padT + plotH, 4022 stroke: "#e4e4e7", 4023 strokeDasharray: "2 2", 4024 strokeWidth: "1.2" 4025 } 4026 ), 4027 chartShowPower && /* @__PURE__ */ jsxRuntimeExports.jsx( 4028 "circle", 4029 { 4030 cx: activePowerCoord.x, 4031 cy: activePowerCoord.y, 4032 r: "6", 4033 fill: "#f59e0b", 4034 stroke: "#ffffff", 4035 strokeWidth: "2.5" 4036 } 4037 ), 4038 chartShowCost && /* @__PURE__ */ jsxRuntimeExports.jsx( 4039 "circle", 4040 { 4041 cx: activeCostCoord.x, 4042 cy: activeCostCoord.y, 4043 r: "6", 4044 fill: "#10b981", 4045 stroke: "#ffffff", 4046 strokeWidth: "2.5" 4047 } 4048 ) 4049 ] }) 4050 ] 4051 } 4052 ) 4053 } 4054 ),
4055 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "min-h-[52px] p-3 rounded-xl bg-zinc-950 border border-zinc-800 flex flex-wrap items-center justify-between gap-3 text-xs", children: hoveredReading ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [ 4056 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [ 4057 /* @__PURE__ */ jsxRuntimeExports.jsx(Clock, { className: "w-4 h-4 text-amber-400 shrink-0" }), 4058 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono font-bold text-white", children: [ 4059 hoveredReading.date, 4060 " ", 4061 hoveredReading.time !== "00:00" ? hoveredReading.time : "", 4062 isMonthly ? " (Monthly Total)" : isDaily ? " (Daily Total)" : " (30-Minute Window)" 4063 ] }) 4064 ] }), 4065 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-wrap items-center gap-3 sm:gap-4 font-mono", children: [
4066 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1.5 px-2.5 py-1 rounded-lg bg-amber-500/10 border border-amber-500/30 text-amber-300 font-bold", children: [ 4067 /* @__PURE__ */ jsxRuntimeExports.jsx(Zap, { className: "w-3.5 h-3.5 text-amber-400" }), 4068 isAggregated ? `Energy: ${hoveredReading.kwh.toFixed(2)} kWh` : `Usage: ${hoveredReading.kwh.toFixed(3)} kWh` 4069 ] }), 4070 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1.5 px-2.5 py-1 rounded-lg bg-cyan-500/10 border border-cyan-500/30 text-cyan-300 font-bold", children: [ 4071 /* @__PURE__ */ jsxRuntimeExports.jsx(Activity, { className: "w-3.5 h-3.5 text-cyan-400" }), 4072 isAggregated ? `Avg Load: ${hoveredReading.avgWatts} W` : `Avg Power: ${hoveredReading.avgWatts} W` 4073 ] }), 4074 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1.5 px-2.5 py-1 rounded-lg bg-emerald-500/10 border border-emerald-500/30 text-emerald-300 font-bold", children: [
4075 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "¥" }), 4076 "Cost: ¥", 4077 hoveredReading.costYen.toFixed(2) 4078 ] }) 4079 ] }) 4080 ] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between w-full text-zinc-500", children: [ 4081 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "italic flex items-center gap-1.5", children: [ 4082 /* @__PURE__ */ jsxRuntimeExports.jsx(Info, { className: "w-3.5 h-3.5 text-zinc-600" }), 4083 "Hover anywhere over the line chart to inspect exact power draw in Watts, energy consumed, and electricity cost." 4084 ] }), 4085 points.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono text-[11px] text-zinc-400 hidden sm:inline", children: [ 4086 "Recent: ", 4087 points[points.length - 1].avgWatts, 4088 "W ⢠¥", 4089 points[points.length - 1].costYen 4090 ] }) 4091 ] }) }) 4092 ] }); 4093 })() 4094 ) : ( 4095 /* Column Bar Chart View */
4096 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-3", children: [ 4097 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "h-56 flex items-end gap-1.5 sm:gap-2 overflow-x-auto pb-4 pt-6 px-2 scrollbar-thin", children: (() => { 4098 const points = octopusReadings.points; 4099 const maxKwh = Math.max(0.5, ...points.map((p) => p.kwh) || [1]); 4100 return points.map((pt, idx) => { 4101 const heightPct = Math.max(8, Math.min(100, Math.round(pt.kwh / maxKwh * 100))); 4102 const isPeak = pt.avgWatts >= 1e3; 4103 const isHovered = (hoveredReading == null ? void 0 : hoveredReading.startAt) === pt.startAt; 4104 return /* @__PURE__ */ jsxRuntimeExports.jsx( 4105 "div", 4106 { 4107 className: "flex-1 min-w-[12px] sm:min-w-[16px] max-w-[28px] h-full flex flex-col justify-end items-center group relative cursor-pointer", 4108 onMouseEnter: () => setHoveredReading(pt), 4109 onMouseLeave: () => setHoveredReading(null), 4110 children: /* @__PURE__ */ jsxRuntimeExports.jsx( 4111 "div", 4112 { 4113 className: `w-full rounded-t-md transition-all duration-200 ${isHovered ? "bg-amber-300 ring-2 ring-amber-400 shadow-lg shadow-amber-500/30" : isPeak ? "bg-gradient-to-t from-rose-500 to-amber-500 hover:from-rose-400 hover:to-amber-400" : "bg-gradient-to-t from-amber-600/80 to-amber-400/90 hover:from-amber-500 hover:to-amber-300"}`, 4114 style: { height: `${heightPct}%` } 4115 } 4116 ) 4117 }, 4118 idx 4119 ); 4120 }); 4121 })() }),
4122 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "min-h-[50px] p-3 rounded-xl bg-zinc-950 border border-zinc-800 flex flex-wrap items-center justify-between gap-3 text-xs", children: hoveredReading ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [ 4123 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [ 4124 /* @__PURE__ */ jsxRuntimeExports.jsx(Clock, { className: "w-4 h-4 text-amber-400" }), 4125 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono font-bold text-white", children: [ 4126 hoveredReading.date, 4127 " ", 4128 hoveredReading.time, 4129 " (", 4130 octopusRange === "1y" ? "Daily" : "30m window", 4131 ")" 4132 ] }) 4133 ] }), 4134 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-4 font-mono", children: [ 4135 /* @__P
4135URE__ */ jsxRuntimeExports.jsxs("span", { className: "text-amber-300 font-bold", children: [ 4136 "Usage: ", 4137 hoveredReading.kwh.toFixed(3), 4138 " kWh" 4139 ] }), 4140 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-cyan-300 font-bold", children: [ 4141 "Avg Power: ", 4142 hoveredReading.avgWatts, 4143 " W" 4144 ] }), 4145 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-emerald-400 font-bold", children: [ 4146 "Cost: ¥", 4147 hoveredReading.costYen.toFixed(2) 4148 ] }) 4149 ] }) 4150 ] }) : /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-zinc-500 italic", children: "Hover over any bar above to view exact consumption, power draw in Watts, and cost breakdown." }) }) 4151 ] }) 4152 ) }) 4153 ] }), 4154 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-1 md:grid-cols-3 gap-5 text-xs", children: [
4155 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-zinc-900/80 border border-zinc-800 p-5 rounded-2xl shadow-lg space-y-3.5", children: [ 4156 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-bold text-amber-300 flex items-center gap-2 pb-2 border-b border-zinc-800 text-sm", children: [ 4157 /* @__PURE__ */ jsxRuntimeExports.jsx(Gauge, { className: "w-4 h-4 text-amber-400" }), 4158 "Hardware & Supply Point" 4159 ] }), 4160 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-2 text-zinc-400", children: [ 4161 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between", children: [ 4162 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Supply Point (SPIN):" }), 4163 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono text-zinc-200 font-bold", children: ((_na = octopusStatus == null ? void 0 : octopusStatus.grid) == null ? void 0 : _na.spin) || "0300111001301609017252" }) 4164 ] }),
4165 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between", children: [ 4166 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Smart Meter Serial:" }), 4167 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono text-cyan-300 font-bold", children: ((_oa = octopusStatus == null ? void 0 : octopusStatus.grid) == null ? void 0 : _oa.meterSerial) || "F24G468872" }) 4168 ] }), 4169 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between", children: [ 4170 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Contract Capacity:" }), 4171 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono text-emerald-400 font-bold", children: [ 4172 ((_pa = octopusStatus == null ? void 0 : octopusStatus.grid) == null ? void 0 : _pa.contractCapacity) || "50A", 4173 " (Single-Phase)" 4174 ] }) 4175 ] }), 4176 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between", children: [
4177 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Regional Grid Operator:" }), 4178 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-zinc-300", children: "TEPCO Power Grid" }) 4179 ] }), 4180 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between pt-1", children: [ 4181 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Service Premise:" }), 4182 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-zinc-300 text-right truncate max-w-[180px]", title: (_qa = octopusStatus == null ? void 0 : octopusStatus.account) == null ? void 0 : _qa.address, children: ((_ra = octopusStatus == null ? void 0 : octopusStatus.account) == null ? void 0 : _ra.address) || "Tokyo, Ota-ku" }) 4183 ] }) 4184 ] }) 4185 ] }), 4186 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-zinc-900/80 border border-zinc-800 p-5 rounded-2xl shadow-lg space-y-3.5", children: [ 4187 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-bold text-emerald-300 flex items-center gap-2 pb-2 border-b border-zinc-800 text-sm", children: [
4188 /* @__PURE__ */ jsxRuntimeExports.jsx(CreditCard, { className: "w-4 h-4 text-emerald-400" }), 4189 "Tariff & Rate Breakdown" 4190 ] }), 4191 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-2 text-zinc-400", children: [ 4192 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between", children: [ 4193 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Active Energy Plan:" }), 4194 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-bold text-zinc-200", children: ((_sa = octopusStatus == null ? void 0 : octopusStatus.plan) == null ? void 0 : _sa.name) || "ã·ã³ãã«ãªã¯ããã¹" }) 4195 ] }), 4196 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between", children: [ 4197 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Daily Standing Charge:" }), 4198 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono text-emerald-400 font-bold", children: [ 4199 "Â¥", 4200 ((_ta = octopusStatus == null ? void 0 : octopusStatus.plan) == null ? void 0 : _ta.standingChargePerDay) ?? 0, 4201 " / day" 4202 ] }) 4203 ] }),
4204 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between", children: [ 4205 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Renewable Energy Levy:" }), 4206 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono text-amber-300 font-bold", children: [ 4207 "Â¥", 4208 ((_ua = octopusStatus == null ? void 0 : octopusStatus.plan) == null ? void 0 : _ua.renewableEnergyLevy) ?? 4.18, 4209 " / kWh" 4210 ] }) 4211 ] }), 4212 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between", children: [ 4213 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Fuel Cost Adjustment:" }), 4214 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono text-zinc-300 font-bold", children: [ 4215 "Â¥", 4216 ((_va = octopusStatus == null ? void 0 : octopusStatus.plan) == null ? void 0 : _va.fuelCostAdjustment) ?? 0, 4217 " / kWh" 4218 ] }) 4219 ] }), 4220 ((_wa = octopusStatus == null ? void 0 : octopusStatus.plan) == null ? void 0 : _wa.upcomingPlan) && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between pt-1 border-t border-zinc-800/80", children: [
4221 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Scheduled Next Plan:" }), 4222 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-purple-300 font-bold", children: octopusStatus.plan.upcomingPlan.name }) 4223 ] }) 4224 ] }) 4225 ] }), 4226 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-zinc-900/80 border border-zinc-800 p-5 rounded-2xl shadow-lg space-y-3.5", children: [ 4227 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-bold text-cyan-300 flex items-center gap-2 pb-2 border-b border-zinc-800 text-sm", children: [ 4228 /* @__PURE__ */ jsxRuntimeExports.jsx(Shield, { className: "w-4 h-4 text-cyan-400" }), 4229 "API & Caching Specs" 4230 ] }), 4231 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-2 text-zinc-400", children: [ 4232 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between", children: [ 4233 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Backend Engine:" }),
4234 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono text-zinc-200", children: "Kraken GraphQL API" }) 4235 ] }), 4236 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between", children: [ 4237 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Short-Term Cache:" }), 4238 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-bold text-emerald-400", children: "15-Minute TTL (In-Memory)" }) 4239 ] }), 4240 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between", children: [ 4241 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Token Rotation:" }), 4242 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono text-zinc-300", children: "50m Auto-Refresh" }) 4243 ] }), 4244 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between", children: [ 4245 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Rate-Limit Safety:" }),
4246 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-zinc-300", children: "Full Anti-Throttle Guard" }) 4247 ] }), 4248 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between pt-1", children: [ 4249 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Account Status:" }), 4250 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "px-2 py-0.5 rounded bg-emerald-500/20 text-emerald-300 font-bold text-[10px]", children: [ 4251 ((_xa = octopusStatus == null ? void 0 : octopusStatus.account) == null ? void 0 : _xa.status) || "ACTIVE", 4252 " (Â¥0 Overdue)" 4253 ] }) 4254 ] }) 4255 ] }) 4256 ] }) 4257 ] }) 4258 ] }), 4259 netModalOpen && /* @__PURE__ */ jsxRuntimeExports.jsx( 4260 "div", 4261 { 4262 className: "fixed inset-0 z-50 flex items-center justify-center p-4 bg-black/75 backdrop-blur-sm animate-fadeIn cursor-pointer", 4263 onClick: () => setNetModalOpen(false), 4264 children: /* @__PURE__ */ jsxRuntimeExports.jsxs( 4265 "div", 4266 { 4267 className: "bg-zinc-900 border border-zinc-700/80 rounded-2xl p-6 max-w-lg w-full shadow-2xl space-y-5 cursor-default", 4268 onClick: (e) => e.stopPropagation(), 4269 children: [
4270 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between pb-3 border-b border-zinc-800", children: [ 4271 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2.5", children: [ 4272 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "p-2 rounded-xl bg-cyan-500/10 border border-cyan-500/20 text-cyan-400", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Wifi, { className: "w-5 h-5" }) }), 4273 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 4274 /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "text-base font-bold text-white", children: "BOFON Controller Network Settings" }), 4275 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-zinc-400 mt-0.5", children: "Local LAN Direct Control (miIO UDP)" }) 4276 ] }) 4277 ] }), 4278 /* @__PURE__ */ jsxRuntimeExports.jsx( 4279 "button", 4280 { 4281 type: "button", 4282 onClick: () => setNetModalOpen(false), 4283 className: "p-1.5 rounded-lg text-zinc-400 hover:text-white hover:bg-zinc-800 transition cursor-pointer", 4284 children: /* @__PURE__ */ jsxRuntimeExports.jsx(X, { className: "w-5 h-5" }) 4285 } 4286 ) 4287 ] }), 4288 netTestResult && /* @__PURE__ */ jsxRuntimeExports.jsxs( 4289 "div", 4290 { 4291 className: `p-3.5 rounded-xl text-xs flex items-center justify-between gap-3 border ${netTestResult.success ? "bg-emerald-950/40 border-emerald-500/40 text-emerald-300" : "bg-rose-950/40 border-rose-500/40 text-rose-300"}`, 4292 children: [
4293 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [ 4294 netTestResult.success ? /* @__PURE__ */ jsxRuntimeExports.jsx(CircleCheck, { className: "w-4 h-4 text-emerald-400 shrink-0" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(TriangleAlert, { className: "w-4 h-4 text-rose-400 shrink-0" }), 4295 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: netTestResult.message }) 4296 ] }), 4297 netTestResult.latency_ms !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono text-[11px] px-2 py-0.5 rounded bg-black/40 border border-current font-bold", children: [ 4298 netTestResult.latency_ms, 4299 "ms latency" 4300 ] }) 4301 ] 4302 } 4303 ), 4304 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-4 text-xs", children: [ 4305 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-2 gap-3", children: [
4306 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 4307 /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-zinc-300 font-semibold block mb-1", children: "Controller IP Address" }), 4308 /* @__PURE__ */ jsxRuntimeExports.jsx( 4309 "input", 4310 { 4311 type: "text", 4312 value: netIp, 4313 onChange: (e) => setNetIp(e.target.value), 4314 placeholder: "192.168.40.190", 4315 className: "w-full bg-zinc-950 border border-zinc-800 rounded-lg p-2.5 text-white font-mono focus:border-cyan-500 focus:outline-none" 4316 } 4317 ) 4318 ] }), 4319 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 4320 /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-zinc-300 font-semibold block mb-1", children: "miIO UDP Port" }), 4321 /* @__PURE__ */ jsxRuntimeExports.jsx( 4322 "input", 4323 { 4324 type: "number", 4325 value: netPort, 4326 onChange: (e) => setNetPort(parseInt(e.target.value, 10)), 4327 placeholder: "54321", 4328 className: "w-full bg-zinc-950 border border-zinc-800 rounded-lg p-2.5 text-white font-mono focus:border-cyan-500 focus:outline-none" 4329 } 4330 ) 4331 ] }) 4332 ] }),
4333 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-2 gap-3", children: [ 4334 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 4335 /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-zinc-300 font-semibold block mb-1", children: "MAC Address" }), 4336 /* @__PURE__ */ jsxRuntimeExports.jsx( 4337 "input", 4338 { 4339 type: "text", 4340 value: netMac, 4341 onChange: (e) => setNetMac(e.target.value), 4342 placeholder: "34:FA:1C:84:C8:8E", 4343 className: "w-full bg-zinc-950 border border-zinc-800 rounded-lg p-2.5 text-white font-mono focus:border-cyan-500 focus:outline-none" 4344 } 4345 ) 4346 ] }), 4347 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 4348 /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-zinc-300 font-semibold block mb-1", children: "Device ID (did)" }),
4349 /* @__PURE__ */ jsxRuntimeExports.jsx( 4350 "input", 4351 { 4352 type: "text", 4353 value: netDid, 4354 onChange: (e) => setNetDid(e.target.value), 4355 placeholder: "2049601204", 4356 className: "w-full bg-zinc-950 border border-zinc-800 rounded-lg p-2.5 text-white font-mono focus:border-cyan-500 focus:outline-none" 4357 } 4358 ) 4359 ] }) 4360 ] }), 4361 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 4362 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between mb-1", children: [ 4363 /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-zinc-300 font-semibold", children: "AES-128 Encryption Token" }), 4364 /* @__PURE__ */ jsxRuntimeExports.jsxs( 4365 "button", 4366 { 4367 type: "button", 4368 onClick: () => setShowToken(!showToken), 4369 className: "text-[11px] text-cyan-400 hover:text-cyan-300 flex items-center gap-1 cursor-pointer", 4370 children: [ 4371 showToken ? /* @__PURE__ */ jsxRuntimeExports.jsx(EyeOff, { className: "w-3 h-3" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Eye, { className: "w-3 h-3" }), 4372 showToken ? "Hide" : "Show" 4373 ] 4374 } 4375 ) 4376 ] }),
4377 /* @__PURE__ */ jsxRuntimeExports.jsx( 4378 "input", 4379 { 4380 type: showToken ? "text" : "password", 4381 value: netToken, 4382 onChange: (e) => setNetToken(e.target.value), 4383 placeholder: "a1d46a441e3724e023c36a9120249781", 4384 className: "w-full bg-zinc-950 border border-zinc-800 rounded-lg p-2.5 text-white font-mono tracking-wider focus:border-cyan-500 focus:outline-none" 4385 } 4386 ) 4387 ] }) 4388 ] }), 4389 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between pt-3 border-t border-zinc-800", children: [ 4390 /* @__PURE__ */ jsxRuntimeExports.jsxs( 4391 "button", 4392 { 4393 type: "button", 4394 onClick: handleTestConnection, 4395 disabled: netTesting || netSaving, 4396 className: "px-4 py-2 rounded-xl text-xs font-bold bg-zinc-800 hover:bg-zinc-700 text-zinc-200 border border-zinc-700 transition flex items-center gap-1.5 cursor-pointer", 4397 children: [
4398 /* @__PURE__ */ jsxRuntimeExports.jsx(RefreshCw, { className: `w-3.5 h-3.5 ${netTesting ? "animate-spin text-cyan-400" : ""}` }), 4399 netTesting ? "Testing Handshake..." : "Test Handshake" 4400 ] 4401 } 4402 ), 4403 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [ 4404 /* @__PURE__ */ jsxRuntimeExports.jsx( 4405 "button", 4406 { 4407 type: "button", 4408 onClick: () => setNetModalOpen(false), 4409 className: "px-4 py-2 rounded-xl text-xs font-semibold text-zinc-400 hover:text-white hover:bg-zinc-800 transition cursor-pointer", 4410 children: "Cancel" 4411 } 4412 ), 4413 /* @__PURE__ */ jsxRuntimeExports.jsx( 4414 "button", 4415 { 4416 type: "button", 4417 onClick: handleSaveNetworkConfig, 4418 disabled: netSaving || netTesting, 4419 className: "px-4 py-2 rounded-xl text-xs font-bold bg-cyan-500 hover:bg-cyan-600 text-white transition flex items-center gap-1.5 shadow-lg shadow-cyan-500/20 cursor-pointer", 4420 children: netSaving ? "Saving..." : "Save & Apply" 4421 } 4422 ) 4423 ] }) 4424 ] }) 4425 ] 4426 } 4427 ) 4428 } 4429 ), 4430 octopusModalOpen && /* @__PURE__ */ jsxRuntimeExports.jsx( 4431 "div", 4432 { 4433 className: "fixed inset-0 z-50 flex items-center justify-center p-4 bg-black/75 backdrop-blur-sm animate-fadeIn cursor-pointer", 4434 onClick: () => setOctopusModalOpen(false), 4435 children: /* @__PURE__ */ jsxRuntimeExports.jsxs( 4436 "div", 4437 { 4438 className: "bg-zinc-900 border border-zinc-700/80 rounded-2xl p-6 max-w-lg w-full shadow-2xl space-y-5 cursor-default", 4439 onClick: (e) => e.stopPropagation(), 4440 children: [
4441 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between pb-3 border-b border-zinc-800", children: [ 4442 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2.5", children: [ 4443 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "p-2 rounded-xl bg-amber-500/10 border border-amber-500/20 text-amber-400", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Zap, { className: "w-5 h-5" }) }), 4444 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 4445 /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "text-base font-bold text-white", children: "Octopus Energy Account Configuration" }), 4446 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-zinc-400 mt-0.5", children: "Kraken GraphQL API Authentication (Japan)" }) 4447 ] }) 4448 ] }), 4449 /* @__PURE__ */ jsxRuntimeExports.jsx( 4450 "button", 4451 { 4452 type: "button", 4453 onClick: () => setOctopusModalOpen(false), 4454 className: "p-1.5 rounded-lg text-zinc-400 hover:text-white hover:bg-zinc-800 transition cursor-pointer", 4455 children: /* @__PURE__ */ jsxRuntimeExports.jsx(X, { className: "w-5 h-5" }) 4456 } 4457 ) 4458 ] }), 4459 octTestResult && /* @__PURE__ */ jsxRuntimeExports.jsxs( 4460 "div", 4461 { 4462 className: `p-3.5 rounded-xl text-xs flex items-center justify-between gap-3 border ${octTestResult.success ? "bg-emerald-950/40 border-emerald-500/40 text-emerald-300" : "bg-rose-950/40 border-rose-500/40 text-rose-300"}`, 4463 children: [
4464 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [ 4465 octTestResult.success ? /* @__PURE__ */ jsxRuntimeExports.jsx(CircleCheck, { className: "w-4 h-4 text-emerald-400 shrink-0" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(TriangleAlert, { className: "w-4 h-4 text-rose-400 shrink-0" }), 4466 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: octTestResult.success ? `Verified! Status: ${octTestResult.status} (${octTestResult.capacity})` : octTestResult.error || "Verification failed" }) 4467 ] }), 4468 octTestResult.latencyMs !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono text-[11px] px-2 py-0.5 rounded bg-black/40 border border-current font-bold", children: [ 4469 octTestResult.latencyMs, 4470 "ms" 4471 ] }) 4472 ] 4473 } 4474 ), 4475 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-4 text-xs", children: [
4476 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 4477 /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-zinc-300 font-semibold block mb-1", children: "Octopus Account Number" }), 4478 /* @__PURE__ */ jsxRuntimeExports.jsx( 4479 "input", 4480 { 4481 type: "text", 4482 value: octAcctNumber, 4483 onChange: (e) => setOctAcctNumber(e.target.value), 4484 placeholder: "A-277BFC94", 4485 className: "w-full bg-zinc-950 border border-zinc-800 rounded-lg p-2.5 text-white font-mono focus:border-amber-500 focus:outline-none" 4486 } 4487 ) 4488 ] }), 4489 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 4490 /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-zinc-300 font-semibold block mb-1", children: "Login Email Address" }), 4491 /* @__PURE__ */ jsxRuntimeExports.jsx( 4492 "input", 4493 { 4494 type: "email", 4495 value: octEmail, 4496 onChange: (e) => setOctEmail(e.target.value), 4497 placeholder: "[email protected]", 4498 className: "w-full bg-zinc-950 border border-zinc-800 rounded-lg p-2.5 text-white focus:border-amber-500 focus:outline-none" 4499 } 4500 ) 4501 ] }),
4502 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 4503 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between mb-1", children: [ 4504 /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-zinc-300 font-semibold", children: "Account Password" }), 4505 /* @__PURE__ */ jsxRuntimeExports.jsxs( 4506 "button", 4507 { 4508 type: "button", 4509 onClick: () => setOctShowPassword(!octShowPassword), 4510 className: "text-[11px] text-amber-400 hover:text-amber-300 flex items-center gap-1 cursor-pointer", 4511 children: [ 4512 octShowPassword ? /* @__PURE__ */ jsxRuntimeExports.jsx(EyeOff, { className: "w-3 h-3" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Eye, { className: "w-3 h-3" }), 4513 octShowPassword ? "Hide" : "Show" 4514 ] 4515 } 4516 ) 4517 ] }),
4518 /* @__PURE__ */ jsxRuntimeExports.jsx( 4519 "input", 4520 { 4521 type: octShowPassword ? "text" : "password", 4522 value: octPassword, 4523 onChange: (e) => setOctPassword(e.target.value), 4524 placeholder: "Enter Octopus password", 4525 className: "w-full bg-zinc-950 border border-zinc-800 rounded-lg p-2.5 text-white font-mono tracking-wider focus:border-amber-500 focus:outline-none" 4526 } 4527 ) 4528 ] }) 4529 ] }), 4530 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between pt-3 border-t border-zinc-800", children: [ 4531 /* @__PURE__ */ jsxRuntimeExports.jsxs( 4532 "button", 4533 { 4534 type: "button", 4535 onClick: handleTestOctopusConnection, 4536 disabled: octTesting || octSaving, 4537 className: "px-4 py-2 rounded-xl text-xs font-bold bg-zinc-800 hover:bg-zinc-700 text-zinc-200 border border-zinc-700 transition flex items-center gap-1.5 cursor-pointer", 4538 children: [
4539 /* @__PURE__ */ jsxRuntimeExports.jsx(RefreshCw, { className: `w-3.5 h-3.5 ${octTesting ? "animate-spin text-amber-400" : ""}` }), 4540 octTesting ? "Testing Handshake..." : "Test Handshake" 4541 ] 4542 } 4543 ), 4544 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [ 4545 /* @__PURE__ */ jsxRuntimeExports.jsx( 4546 "button", 4547 { 4548 type: "button", 4549 onClick: () => setOctopusModalOpen(false), 4550 className: "px-4 py-2 rounded-xl text-xs font-semibold text-zinc-400 hover:text-white hover:bg-zinc-800 transition cursor-pointer", 4551 children: "Cancel" 4552 } 4553 ), 4554 /* @__PURE__ */ jsxRuntimeExports.jsx( 4555 "button", 4556 { 4557 type: "button", 4558 onClick: handleSaveOctopusConfig, 4559 disabled: octSaving || octTesting, 4560 className: "px-4 py-2 rounded-xl text-xs font-bold bg-amber-500 hover:bg-amber-600 text-black transition flex items-center gap-1.5 shadow-lg shadow-amber-500/20 cursor-pointer", 4561 children: octSaving ? "Saving..." : "Save & Reconnect" 4562 } 4563 ) 4564 ] }) 4565 ] }) 4566 ] 4567 } 4568 ) 4569 } 4570 ) 4571 ] }); 4572} 4573export { 4574 OPERATIONAL_PROFILES, 4575 ClimateControl as default, 4576 getActiveProfileId 4577};
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.