{"id":15371,"date":"2026-10-17T02:57:26","date_gmt":"2026-10-17T02:57:26","guid":{"rendered":"https:\/\/hondellighting.com\/?page_id=15371"},"modified":"2026-10-17T03:51:54","modified_gmt":"2026-10-17T03:51:54","slug":"elementor-15371","status":"publish","type":"page","link":"https:\/\/hondellighting.com\/ar\/elementor-15371.html","title":{"rendered":"Elementor #15371"},"content":{"rendered":"<div data-elementor-type=\"wp-page\" data-elementor-id=\"15371\" class=\"elementor elementor-15371\">\n\t\t\t\t<div class=\"elementor-element elementor-element-ae6c13c e-flex e-con-boxed e-con e-parent\" data-id=\"ae6c13c\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-4731415 elementor-widget elementor-widget-html\" data-id=\"4731415\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n  <meta charset=\"UTF-8\">\r\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\r\n  <title>DIALux Architectural Lighting Simulator & Lux Calculator<\/title>\r\n\r\n  <!-- Tailwind CSS CDN -->\r\n  <script src=\"https:\/\/cdn.tailwindcss.com\"><\/script>\r\n  \r\n  <!-- Font Awesome Icons -->\r\n  <link rel=\"stylesheet\" href=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/font-awesome\/6.5.1\/css\/all.min.css\">\r\n  \r\n  <!-- Inter & JetBrains Mono Fonts -->\r\n  <link rel=\"preconnect\" href=\"https:\/\/fonts.googleapis.com\">\r\n  <link rel=\"preconnect\" href=\"https:\/\/fonts.gstatic.com\" crossorigin>\r\n  <link href=\"https:\/\/fonts.googleapis.com\/css2?family=Inter:wght@300;400;500;600;700;800&family=JetBrains+Mono:wght@400;600;700&display=swap\" rel=\"stylesheet\">\r\n\r\n  <!-- jsPDF & html2canvas for PDF Report Generation -->\r\n  <script src=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/jspdf\/2.5.1\/jspdf.umd.min.js\"><\/script>\r\n  <script src=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/html2canvas\/1.4.1\/html2canvas.min.js\"><\/script>\r\n\r\n  <style>\r\n    body {\r\n      font-family: 'Inter', sans-serif;\r\n      user-select: none;\r\n      -webkit-user-select: none;\r\n    }\r\n    .font-mono {\r\n      font-family: 'JetBrains Mono', monospace;\r\n    }\r\n    ::-webkit-scrollbar {\r\n      width: 6px;\r\n      height: 6px;\r\n    }\r\n    ::-webkit-scrollbar-track {\r\n      background: #020617;\r\n    }\r\n    ::-webkit-scrollbar-thumb {\r\n      background: #1e293b;\r\n      border-radius: 4px;\r\n    }\r\n    ::-webkit-scrollbar-thumb:hover {\r\n      background: #334155;\r\n    }\r\n    input[type=range] {\r\n      accent-color: #f59e0b;\r\n    }\r\n  <\/style>\r\n<\/head>\r\n<body class=\"bg-[#030712] text-slate-100 min-h-screen flex flex-col overflow-x-hidden antialiased\">\r\n\r\n  <header class=\"bg-slate-950\/95 backdrop-blur-md border-b border-slate-800\/80 px-4 py-2.5 sticky top-0 z-40 flex items-center justify-between gap-4\">\r\n    <div class=\"flex items-center gap-3\">\r\n      <div class=\"w-9 h-9 rounded-xl bg-gradient-to-tr from-amber-500 to-amber-300 flex items-center justify-center text-slate-950 shadow-lg shadow-amber-500\/20\">\r\n        <i class=\"fa-solid fa-lightbulb text-lg\"><\/i>\r\n      <\/div>\r\n      <div>\r\n        <h1 class=\"text-sm md:text-base font-bold text-white tracking-tight flex items-center gap-2\">\r\n          DIALux Lighting Simulator\r\n          <span class=\"text-[10px] uppercase font-mono px-2 py-0.5 rounded-full bg-amber-500\/20 text-amber-300 border border-amber-500\/40\">CIE \/ EN 12464-1<\/span>\r\n        <\/h1>\r\n        <p class=\"text-[11px] text-slate-400\">Architectural Photometric Engine \u00b7 2BHK Layout \u00b7 Workplane (0.8m AFF)<\/p>\r\n      <\/div>\r\n    <\/div>\r\n\r\n    <!-- Quick Stats Bar -->\r\n    <div class=\"hidden lg:flex items-center gap-6 text-xs bg-slate-900\/90 px-4 py-1.5 rounded-xl border border-slate-800 font-mono\">\r\n      <div class=\"flex items-center gap-2\">\r\n        <span class=\"w-2 h-2 rounded-full bg-amber-400 animate-pulse\"><\/span>\r\n        <span class=\"text-slate-400\">Luminaires:<\/span>\r\n        <span class=\"text-white font-bold\" id=\"statFixtureCount\">10<\/span>\r\n      <\/div>\r\n      <div class=\"w-px h-4 bg-slate-800\"><\/div>\r\n      <div>\r\n        <span class=\"text-slate-400\">Connected Load:<\/span>\r\n        <span class=\"text-amber-400 font-bold\" id=\"statTotalWatts\">109 W<\/span>\r\n      <\/div>\r\n      <div class=\"w-px h-4 bg-slate-800\"><\/div>\r\n      <div>\r\n        <span class=\"text-slate-400\">Total Flux:<\/span>\r\n        <span class=\"text-emerald-400 font-bold\" id=\"statTotalLumens\">10,540 lm<\/span>\r\n      <\/div>\r\n    <\/div>\r\n\r\n    <!-- Actions -->\r\n    <div class=\"flex items-center gap-2\">\r\n      <select id=\"presetSceneSelect\" class=\"bg-slate-900 border border-slate-700 text-xs rounded-lg px-2.5 py-1.5 text-slate-200 outline-none focus:border-amber-500\">\r\n        <option value=\"modern\">Preset: Balanced Architectural (Default)<\/option>\r\n        <option value=\"cozy\">Preset: Warm & Intimate 2700K<\/option>\r\n        <option value=\"task\">Preset: High Lux Work Task 4000K<\/option>\r\n      <\/select>\r\n\r\n      <button id=\"exportPdfBtn\" class=\"bg-amber-500 hover:bg-amber-400 text-slate-950 font-semibold px-3 py-1.5 rounded-lg text-xs flex items-center gap-1.5 shadow-md shadow-amber-500\/20 transition active:scale-95\">\r\n        <i class=\"fa-solid fa-file-pdf\"><\/i>\r\n        <span>PDF Report<\/span>\r\n      <\/button>\r\n    <\/div>\r\n  <\/header>\r\n\r\n  <main class=\"flex-1 grid grid-cols-1 xl:grid-cols-12 gap-0 overflow-hidden\">\r\n    \r\n    <!-- Canvas Interactive Viewport (Cols 1-9) -->\r\n    <div class=\"xl:col-span-8 2xl:col-span-9 bg-[#030712] flex flex-col border-b xl:border-b-0 xl:border-r border-slate-800\/80 relative\">\r\n      \r\n      <!-- Toolbar Over Canvas -->\r\n      <div class=\"bg-slate-950\/90 backdrop-blur-md px-4 py-2 border-b border-slate-800\/80 flex flex-wrap items-center justify-between gap-3 text-xs z-20\">\r\n        <div class=\"flex items-center gap-1.5 bg-slate-900 p-1 rounded-lg border border-slate-800\">\r\n          <button id=\"viewRealisticBtn\" class=\"px-3 py-1.5 rounded-md font-medium transition flex items-center gap-1.5 bg-slate-800 text-amber-300 shadow-sm\">\r\n            <i class=\"fa-solid fa-eye\"><\/i> Realistic Render\r\n          <\/button>\r\n          <button id=\"viewHeatmapBtn\" class=\"px-3 py-1.5 rounded-md font-medium text-slate-400 hover:text-white transition flex items-center gap-1.5\">\r\n            <i class=\"fa-solid fa-fire\"><\/i> DIALux False Color\r\n          <\/button>\r\n        <\/div>\r\n\r\n        <!-- Toggles: Isolux Curves, Furniture Outlines, Grid -->\r\n        <div class=\"flex items-center gap-2\">\r\n          <button id=\"toggleIsoluxBtn\" class=\"px-2.5 py-1.5 rounded-lg bg-amber-500\/15 hover:bg-amber-500\/25 text-amber-300 border border-amber-500\/40 transition flex items-center gap-1.5 font-medium\" title=\"Toggle Live DIALux Isolux Contour Lines\">\r\n            <i class=\"fa-solid fa-chart-line\"><\/i> <span>Isolux Curves<\/span>\r\n          <\/button>\r\n          <button id=\"toggleFurnitureBtn\" class=\"px-2.5 py-1.5 rounded-lg bg-slate-900 hover:bg-slate-800 text-white border border-slate-700 transition flex items-center gap-1.5\" title=\"Toggle Furniture Outlines\">\r\n            <i class=\"fa-solid fa-couch\"><\/i> <span>Furniture<\/span>\r\n          <\/button>\r\n          <button id=\"toggleGridBtn\" class=\"px-2.5 py-1.5 rounded-lg bg-slate-900 hover:bg-slate-800 text-slate-400 border border-slate-800 transition flex items-center gap-1.5\" title=\"Toggle 1-Meter CAD Grid\">\r\n            <i class=\"fa-solid fa-border-all\"><\/i> <span>Grid<\/span>\r\n          <\/button>\r\n        <\/div>\r\n\r\n        <!-- Real-Time Cursor Lux Probe Display -->\r\n        <div class=\"flex items-center gap-2 bg-slate-900 px-3 py-1 rounded-lg border border-slate-800 font-mono text-[11px]\">\r\n          <span class=\"text-slate-400\"><i class=\"fa-solid fa-crosshairs text-amber-400 mr-1\"><\/i>Probe:<\/span>\r\n          <span id=\"probeLuxValue\" class=\"text-white font-bold\">185 lx<\/span>\r\n          <span class=\"text-slate-600\">|<\/span>\r\n          <span id=\"probeRoom\" class=\"text-white font-medium\">Master Suite<\/span>\r\n        <\/div>\r\n      <\/div>\r\n\r\n      <!-- Canvas Render Area -->\r\n      <div class=\"relative flex-1 flex items-center justify-center p-3 bg-[#020617] overflow-auto\">\r\n        <canvas id=\"lightingCanvas\" width=\"1200\" height=\"800\" class=\"rounded-xl shadow-2xl border border-slate-800 cursor-crosshair max-w-full h-auto object-contain\"><\/canvas>\r\n        \r\n        <!-- Live Full-Spectrum DIALux False Color Legend Bar -->\r\n        <div id=\"heatmapLegendBar\" class=\"hidden absolute bottom-6 right-6 bg-slate-950\/95 backdrop-blur-md p-3.5 rounded-xl border border-slate-700\/80 shadow-2xl z-20 font-mono text-[10px] space-y-1.5\">\r\n          <div class=\"text-[11px] font-bold text-white mb-1 flex items-center justify-between\">\r\n            <span class=\"flex items-center gap-1.5\"><i class=\"fa-solid fa-palette text-amber-400\"><\/i> DIALux False Color Scale<\/span>\r\n            <span class=\"text-slate-300\">Lux (lx)<\/span>\r\n          <\/div>\r\n          <!-- Complete calibrated 8-color DIALux spectrum -->\r\n          <div class=\"w-56 h-4 rounded-md border border-slate-600 shadow-inner\" style=\"background: linear-gradient(to right, #110038 0%, #1e3a8a 12%, #0284c7 25%, #059669 40%, #84cc16 55%, #facc15 70%, #f97316 85%, #dc2626 95%, #f43f5e 100%);\"><\/div>\r\n          <div class=\"flex justify-between text-white font-semibold text-[10px] pt-0.5\">\r\n            <span>&lt;20<\/span>\r\n            <span>50<\/span>\r\n            <span>100<\/span>\r\n            <span>150<\/span>\r\n            <span>250<\/span>\r\n            <span>350<\/span>\r\n            <span>500+<\/span>\r\n          <\/div>\r\n        <\/div>\r\n\r\n        <!-- Interactive Drag Tip -->\r\n        <div class=\"absolute bottom-5 left-5 bg-slate-950\/90 backdrop-blur-md px-3 py-1.5 rounded-lg border border-slate-800 text-[11px] text-white pointer-events-none hidden sm:flex items-center gap-2\">\r\n          <i class=\"fa-solid fa-hand-pointer text-amber-400\"><\/i>\r\n          <span>Click & drag lights \u2014 isolux contours and photometrics calculate live<\/span>\r\n        <\/div>\r\n      <\/div>\r\n    <\/div>\r\n\r\n    <div class=\"xl:col-span-4 2xl:col-span-3 bg-slate-950 flex flex-col h-full border-slate-800 overflow-y-auto\">\r\n      \r\n      <!-- Tabs Switcher -->\r\n      <div class=\"flex border-b border-slate-800 p-2 gap-1 bg-slate-950 sticky top-0 z-10 text-xs\">\r\n        <button id=\"tabFixturesBtn\" class=\"flex-1 py-2 font-medium rounded-md text-amber-300 bg-slate-900 flex items-center justify-center gap-2 shadow-sm border border-slate-800\">\r\n          <i class=\"fa-solid fa-sliders\"><\/i> Luminaire Control\r\n        <\/button>\r\n        <button id=\"tabRoomsBtn\" class=\"flex-1 py-2 font-medium rounded-md text-slate-400 hover:text-white flex items-center justify-center gap-2\">\r\n          <i class=\"fa-solid fa-chart-pie\"><\/i> Lux Compliance\r\n        <\/button>\r\n      <\/div>\r\n\r\n      <!-- Tab Content: Fixture Controls -->\r\n      <div id=\"tabContentFixtures\" class=\"p-4 space-y-4\">\r\n        \r\n        <!-- Add Architectural Fixture -->\r\n        <div class=\"bg-slate-900\/80 p-3 rounded-xl border border-slate-800 space-y-2\">\r\n          <div class=\"text-xs font-semibold text-white flex items-center justify-between\">\r\n            <span class=\"flex items-center gap-1.5\">\r\n              <i class=\"fa-solid fa-circle-plus text-amber-400\"><\/i>\r\n              Add Architectural Luminaire\r\n            <\/span>\r\n            <span class=\"text-[10px] text-slate-400\">Click to deploy<\/span>\r\n          <\/div>\r\n          <div class=\"grid grid-cols-2 gap-2 text-xs\">\r\n            <button onclick=\"addNewFixture('downlight')\" class=\"p-2 bg-slate-950 hover:bg-slate-800 border border-slate-800 hover:border-amber-500\/50 rounded-lg text-left transition\">\r\n              <div class=\"font-medium text-amber-300 flex items-center gap-1.5\">\r\n                <i class=\"fa-regular fa-circle-dot text-xs\"><\/i> Recessed Downlight\r\n              <\/div>\r\n              <div class=\"text-[10px] text-slate-400\">12W \u00b7 100 lm\/W \u00b7 3000K<\/div>\r\n            <\/button>\r\n\r\n            <button onclick=\"addNewFixture('bedside')\" class=\"p-2 bg-slate-950 hover:bg-slate-800 border border-slate-800 hover:border-amber-500\/50 rounded-lg text-left transition\">\r\n              <div class=\"font-medium text-amber-300 flex items-center gap-1.5\">\r\n                <i class=\"fa-solid fa-lamp text-xs\"><\/i> Bedside Table Lamp\r\n              <\/div>\r\n              <div class=\"text-[10px] text-slate-400\">5W \u00b7 70 lm\/W \u00b7 2700K<\/div>\r\n            <\/button>\r\n\r\n            <button onclick=\"addNewFixture('spotlight')\" class=\"p-2 bg-slate-950 hover:bg-slate-800 border border-slate-800 hover:border-amber-500\/50 rounded-lg text-left transition\">\r\n              <div class=\"font-medium text-amber-300 flex items-center gap-1.5\">\r\n                <i class=\"fa-solid fa-bullseye text-xs\"><\/i> Accent Spotlight\r\n              <\/div>\r\n              <div class=\"text-[10px] text-slate-400\">8W \u00b7 85 lm\/W \u00b7 24\u00b0 Spot<\/div>\r\n            <\/button>\r\n\r\n            <button onclick=\"addNewFixture('pendant')\" class=\"p-2 bg-slate-950 hover:bg-slate-800 border border-slate-800 hover:border-amber-500\/50 rounded-lg text-left transition\">\r\n              <div class=\"font-medium text-amber-300 flex items-center gap-1.5\">\r\n                <i class=\"fa-solid fa-ring text-xs\"><\/i> Dining Chandelier\r\n              <\/div>\r\n              <div class=\"text-[10px] text-slate-400\">24W \u00b7 95 lm\/W \u00b7 3000K<\/div>\r\n            <\/button>\r\n\r\n            <button onclick=\"addNewFixture('surface')\" class=\"p-2 bg-slate-950 hover:bg-slate-800 border border-slate-800 hover:border-amber-500\/50 rounded-lg text-left transition\">\r\n              <div class=\"font-medium text-amber-300 flex items-center gap-1.5\">\r\n                <i class=\"fa-solid fa-circle text-xs\"><\/i> Surface Flush Panel\r\n              <\/div>\r\n              <div class=\"text-[10px] text-slate-400\">18W \u00b7 110 lm\/W \u00b7 4000K<\/div>\r\n            <\/button>\r\n\r\n            <button onclick=\"addNewFixture('wallwasher')\" class=\"p-2 bg-slate-950 hover:bg-slate-800 border border-slate-800 hover:border-amber-500\/50 rounded-lg text-left transition\">\r\n              <div class=\"font-medium text-amber-300 flex items-center gap-1.5\">\r\n                <i class=\"fa-solid fa-water text-xs\"><\/i> Linear Wall Washer\r\n              <\/div>\r\n              <div class=\"text-[10px] text-slate-400\">15W \u00b7 120 lm\/W \u00b7 120\u00b0 Cove<\/div>\r\n            <\/button>\r\n          <\/div>\r\n        <\/div>\r\n\r\n        <!-- Selected Fixture Settings Card -->\r\n        <div id=\"selectedFixturePanel\" class=\"bg-slate-900\/90 p-4 rounded-xl border border-amber-500\/50 space-y-3.5 shadow-xl hidden\">\r\n          <div class=\"flex items-center justify-between border-b border-slate-800 pb-2.5\">\r\n            <span class=\"text-xs font-bold text-amber-300 flex items-center gap-1.5\">\r\n              <i class=\"fa-solid fa-sliders\"><\/i>\r\n              <span id=\"selectedFixtureTitle\">Luminaire #1<\/span>\r\n            <\/span>\r\n            <div class=\"flex items-center gap-1.5\">\r\n              <button id=\"toggleLightPowerBtn\" class=\"text-xs px-2.5 py-1 rounded bg-slate-800 hover:bg-slate-700 text-slate-200 border border-slate-700 transition\" title=\"Toggle Power\">\r\n                <i class=\"fa-solid fa-power-off text-xs text-emerald-400\"><\/i>\r\n              <\/button>\r\n              <button id=\"deleteFixtureBtn\" class=\"text-rose-400 hover:text-rose-300 text-xs px-2.5 py-1 rounded bg-rose-950\/40 border border-rose-900\/50 flex items-center gap-1 transition\">\r\n                <i class=\"fa-solid fa-trash-can text-xs\"><\/i> Delete\r\n              <\/button>\r\n            <\/div>\r\n          <\/div>\r\n\r\n          <!-- Wattage Slider + Direct Number Input -->\r\n          <div class=\"space-y-1\">\r\n            <div class=\"flex justify-between items-center text-xs\">\r\n              <span class=\"text-slate-300\">Wattage & Consumption:<\/span>\r\n              <div class=\"flex items-center gap-1\">\r\n                <input type=\"number\" id=\"numWattage\" min=\"1\" max=\"150\" class=\"w-14 bg-slate-950 border border-slate-700 rounded px-1.5 py-0.5 text-right font-mono text-white text-xs focus:border-amber-500 outline-none\">\r\n                <span class=\"text-slate-400 font-mono\">\u062f\u0628\u0644\u064a\u0648<\/span>\r\n              <\/div>\r\n            <\/div>\r\n            <input type=\"range\" id=\"inputWattage\" min=\"2\" max=\"60\" step=\"1\" value=\"12\" class=\"w-full accent-amber-500 bg-slate-800 rounded-lg h-2 cursor-pointer\">\r\n          <\/div>\r\n\r\n          <!-- Per-Fixture Editable Luminous Efficacy (lm\/W) -->\r\n          <div class=\"space-y-1\">\r\n            <div class=\"flex justify-between items-center text-xs\">\r\n              <span class=\"text-slate-300 flex items-center gap-1\">\r\n                <span>Luminous Efficacy:<\/span>\r\n                <i class=\"fa-solid fa-circle-info text-[10px] text-slate-400\" title=\"LED chip & optical transmission efficiency (lm\/W)\"><\/i>\r\n              <\/span>\r\n              <div class=\"flex items-center gap-1\">\r\n                <input type=\"number\" id=\"numEfficacy\" min=\"30\" max=\"220\" class=\"w-14 bg-slate-950 border border-slate-700 rounded px-1.5 py-0.5 text-right font-mono text-amber-300 text-xs focus:border-amber-500 outline-none\">\r\n                <span class=\"text-slate-400 font-mono text-[10px]\">lm\/W<\/span>\r\n              <\/div>\r\n            <\/div>\r\n            <input type=\"range\" id=\"inputEfficacy\" min=\"30\" max=\"180\" step=\"1\" value=\"100\" class=\"w-full accent-amber-400 bg-slate-800 rounded-lg h-2 cursor-pointer\">\r\n          <\/div>\r\n\r\n          <!-- Calculated Photometrics Output -->\r\n          <div class=\"grid grid-cols-2 gap-2 text-xs bg-slate-950 p-2.5 rounded-lg border border-slate-800\">\r\n            <div>\r\n              <span class=\"text-slate-400 block text-[10px]\">Total Lumens Output<\/span>\r\n              <span class=\"font-mono font-bold text-emerald-400 text-sm\" id=\"valLumens\">1,200 lm<\/span>\r\n            <\/div>\r\n            <div>\r\n              <span class=\"text-slate-400 block text-[10px]\">Peak Intensity (I_0)<\/span>\r\n              <span class=\"font-mono font-semibold text-amber-300\" id=\"valIntensity\">~1,600 cd<\/span>\r\n            <\/div>\r\n          <\/div>\r\n\r\n          <!-- Beam Angle -->\r\n          <div class=\"space-y-1.5\">\r\n            <div class=\"flex justify-between text-xs\">\r\n              <span class=\"text-slate-300\">Beam Spread (FWHM):<\/span>\r\n              <span class=\"font-mono text-white font-semibold\" id=\"valBeamAngle\">60\u00b0<\/span>\r\n            <\/div>\r\n            <div class=\"grid grid-cols-5 gap-1\">\r\n              <button onclick=\"setBeamAngle(15)\" class=\"beam-btn py-1 text-[11px] rounded bg-slate-800 hover:bg-slate-700 text-slate-300\">15\u00b0<\/button>\r\n              <button onclick=\"setBeamAngle(24)\" class=\"beam-btn py-1 text-[11px] rounded bg-slate-800 hover:bg-slate-700 text-slate-300\">24\u00b0<\/button>\r\n              <button onclick=\"setBeamAngle(36)\" class=\"beam-btn py-1 text-[11px] rounded bg-slate-800 hover:bg-slate-700 text-slate-300\">36\u00b0<\/button>\r\n              <button onclick=\"setBeamAngle(60)\" class=\"beam-btn py-1 text-[11px] rounded bg-amber-600 text-white font-semibold\">60\u00b0<\/button>\r\n              <button onclick=\"setBeamAngle(120)\" class=\"beam-btn py-1 text-[11px] rounded bg-slate-800 hover:bg-slate-700 text-slate-300\">120 \u062f\u0631\u062c\u0629<\/button>\r\n            <\/div>\r\n          <\/div>\r\n\r\n          <!-- CCT Color Temp -->\r\n          <div class=\"space-y-1.5\">\r\n            <div class=\"flex justify-between text-xs\">\r\n              <span class=\"text-slate-300\">Color Temperature:<\/span>\r\n              <span class=\"font-mono text-amber-300 font-semibold\" id=\"valCCT\">3000K Warm<\/span>\r\n            <\/div>\r\n            <div class=\"grid grid-cols-4 gap-1 text-[10px]\">\r\n              <button onclick=\"setCCT(2700)\" class=\"cct-btn py-1 rounded bg-[#ff9329]\/20 border border-[#ff9329]\/40 text-[#ffb066] font-medium\">2700 \u0623\u0644\u0641<\/button>\r\n              <button onclick=\"setCCT(3000)\" class=\"cct-btn py-1 rounded bg-[#ffb46b]\/20 border border-[#ffb46b]\/40 text-[#ffc694] font-medium ring-1 ring-amber-400\">3000K<\/button>\r\n              <button onclick=\"setCCT(4000)\" class=\"cct-btn py-1 rounded bg-[#d8ecff]\/20 border border-[#d8ecff]\/40 text-[#d8ecff] font-medium\">4000 \u0643<\/button>\r\n              <button onclick=\"setCCT(6000)\" class=\"cct-btn py-1 rounded bg-[#a4d2ff]\/20 border border-[#a4d2ff]\/40 text-[#bce0ff] font-medium\">6000K<\/button>\r\n            <\/div>\r\n          <\/div>\r\n\r\n          <!-- Mounting Height -->\r\n          <div class=\"space-y-1\">\r\n            <div class=\"flex justify-between text-xs\">\r\n              <span class=\"text-slate-300\">Mounting Height above floor:<\/span>\r\n              <span class=\"font-mono text-white font-semibold\" id=\"valHeight\">2.8 m<\/span>\r\n            <\/div>\r\n            <input type=\"range\" id=\"inputHeight\" min=\"0.5\" max=\"3.6\" step=\"0.1\" value=\"2.8\" class=\"w-full accent-amber-500 bg-slate-800 rounded-lg h-2 cursor-pointer\">\r\n          <\/div>\r\n        <\/div>\r\n\r\n        <div id=\"noSelectionNotice\" class=\"p-6 rounded-xl border border-dashed border-slate-800 text-center text-slate-400 text-xs\">\r\n          <i class=\"fa-regular fa-hand-pointer text-2xl mb-2 text-slate-500 block\"><\/i>\r\n          Select any luminaire or bedside lamp on the floor plan to inspect photometrics and adjust specifications.\r\n        <\/div>\r\n\r\n        <!-- Fixtures Installed List -->\r\n        <div class=\"space-y-2\">\r\n          <div class=\"flex items-center justify-between text-xs font-semibold text-white\">\r\n            <span>Deployed Luminaires<\/span>\r\n            <span class=\"text-[10px] font-mono text-slate-400\" id=\"listSummaryText\">10 installed<\/span>\r\n          <\/div>\r\n          <div id=\"fixtureListContainer\" class=\"space-y-1.5 max-h-56 overflow-y-auto pr-1\"><\/div>\r\n        <\/div>\r\n      <\/div>\r\n\r\n      <!-- Tab Content: Room Compliance Metrics -->\r\n      <div id=\"tabContentRooms\" class=\"p-4 space-y-3 hidden\">\r\n        <div class=\"text-xs text-slate-300 bg-slate-900 p-3 rounded-lg border border-slate-800\">\r\n          <span class=\"font-semibold text-white block mb-1 flex items-center gap-1.5\">\r\n            <i class=\"fa-solid fa-shield-halved text-amber-400\"><\/i> EN 12464-1 Residential Standards\r\n          <\/span>\r\n          Photometrics evaluated on workplane ($h = 0.80\\text{ m}$ AFF). Displays average illuminance ($E_{\\text{avg}}$), minimum ($E_{\\text{min}}$), maximum ($E_{\\text{max}}$), and Uniformity ratio ($U_0 = E_{\\text{min}} \/ E_{\\text{avg}}$).\r\n        <\/div>\r\n        <div id=\"roomMetricsContainer\" class=\"space-y-2.5\"><\/div>\r\n      <\/div>\r\n    <\/div>\r\n  <\/main>\r\n\r\n  <div id=\"pdfExportContainer\" class=\"hidden bg-slate-950 text-white p-8 max-w-4xl mx-auto space-y-6\">\r\n    <div class=\"border-b-2 border-amber-500 pb-4 flex justify-between items-end\">\r\n      <div>\r\n        <h1 class=\"text-2xl font-bold text-white\">DIALux Photometric Engineering Report<\/h1>\r\n        <p class=\"text-xs text-slate-400\">2BHK Residential Flat \u00b7 Architectural Lighting Calculation (CIE \/ EN 12464-1)<\/p>\r\n      <\/div>\r\n      <div class=\"text-right text-xs text-slate-400 font-mono\">\r\n        <div>Date: <span id=\"reportDate\"><\/span><\/div>\r\n        <div>Workplane: 0.80 m AFF<\/div>\r\n      <\/div>\r\n    <\/div>\r\n\r\n    <!-- Render Canvas Image in PDF -->\r\n    <div class=\"border border-slate-800 rounded-lg overflow-hidden bg-[#030712] p-2\">\r\n      <div id=\"pdfCanvasImageContainer\" class=\"w-full flex justify-center\"><\/div>\r\n    <\/div>\r\n\r\n    <!-- Room Compliance Table -->\r\n    <div class=\"space-y-2\">\r\n      <h3 class=\"text-sm font-bold text-amber-400 border-b border-slate-800 pb-1\">Room Illuminance Compliance Summary<\/h3>\r\n      <table class=\"w-full text-xs text-left border border-slate-800\">\r\n        <thead class=\"bg-slate-900 text-slate-300 border-b border-slate-800\">\r\n          <tr>\r\n            <th class=\"p-2 border-r border-slate-800\">Room \/ Zone<\/th>\r\n            <th class=\"p-2 border-r border-slate-800\">Target (lx)<\/th>\r\n            <th class=\"p-2 border-r border-slate-800\">E_avg (lx)<\/th>\r\n            <th class=\"p-2 border-r border-slate-800\">E_min<\/th>\r\n            <th class=\"p-2 border-r border-slate-800\">E_max<\/th>\r\n            <th class=\"p-2 border-r border-slate-800\">Uniformity (U0)<\/th>\r\n            <th class=\"p-2\">Status<\/th>\r\n          <\/tr>\r\n        <\/thead>\r\n        <tbody id=\"pdfRoomTableBody\"><\/tbody>\r\n      <\/table>\r\n    <\/div>\r\n\r\n    <!-- Fixture Schedule in PDF -->\r\n    <div class=\"space-y-2\">\r\n      <h3 class=\"text-sm font-bold text-amber-400 border-b border-slate-800 pb-1\">Luminaire & Lamp Schedule<\/h3>\r\n      <table class=\"w-full text-xs text-left border border-slate-800\">\r\n        <thead class=\"bg-slate-900 text-slate-300 border-b border-slate-800\">\r\n          <tr>\r\n            <th class=\"p-2 border-r border-slate-800\">Tag<\/th>\r\n            <th class=\"p-2 border-r border-slate-800\">Luminaire Type<\/th>\r\n            <th class=\"p-2 border-r border-slate-800\">Watts<\/th>\r\n            <th class=\"p-2 border-r border-slate-800\">Efficacy<\/th>\r\n            <th class=\"p-2 border-r border-slate-800\">Flux<\/th>\r\n            <th class=\"p-2 border-r border-slate-800\">Beam<\/th>\r\n            <th class=\"p-2 border-r border-slate-800\">\u0627\u0644\u062a\u062d\u0648\u064a\u0644 \u0627\u0644\u0646\u0642\u062f\u064a \u0627\u0644\u0645\u0648\u062d\u062f<\/th>\r\n            <th class=\"p-2\">Height<\/th>\r\n          <\/tr>\r\n        <\/thead>\r\n        <tbody id=\"pdfFixtureTableBody\"><\/tbody>\r\n      <\/table>\r\n    <\/div>\r\n  <\/div>\r\n\r\n  <script>\r\n    const CANVAS_WIDTH = 1200;\r\n    const CANVAS_HEIGHT = 800;\r\n    const PIXELS_PER_METER = 40; \/\/ 40px = 1m\r\n    const WORK_PLANE_HEIGHT = 0.8; \/\/ standard 0.8m AFF\r\n\r\n    const ROOMS = [\r\n      { id: 'master_bed', name: 'Master Suite', x: 60, y: 60, w: 460, h: 330, targetMin: 120, targetMax: 200 },\r\n      { id: 'bed2', name: 'Bedroom 2', x: 520, y: 60, w: 370, h: 330, targetMin: 120, targetMax: 200 },\r\n      { id: 'foyer', name: 'Foyer & Gallery', x: 890, y: 60, w: 250, h: 330, targetMin: 100, targetMax: 180 },\r\n      { id: 'living', name: 'Living Room', x: 60, y: 390, w: 460, h: 350, targetMin: 150, targetMax: 300 },\r\n      { id: 'dining', name: 'Dining Hall', x: 520, y: 390, w: 350, h: 350, targetMin: 200, targetMax: 350 },\r\n      { id: 'kitchen', name: 'Kitchen & Bar', x: 870, y: 390, w: 270, h: 350, targetMin: 250, targetMax: 450 }\r\n    ];\r\n\r\n    const DOORWAYS = [\r\n      { id: 'd_master', x: 230, y: 390, width: 60, orientation: 'horizontal', connect: ['master_bed', 'living'] },\r\n      { id: 'd_bed2', x: 640, y: 390, width: 60, orientation: 'horizontal', connect: ['bed2', 'dining'] },\r\n      { id: 'd_foyer', x: 960, y: 390, width: 65, orientation: 'horizontal', connect: ['foyer', 'kitchen'] },\r\n      { id: 'd_arch', x: 520, y: 470, height: 180, orientation: 'vertical', connect: ['living', 'dining'] },\r\n      { id: 'd_kitchen', x: 870, y: 480, height: 75, orientation: 'vertical', connect: ['dining', 'kitchen'] }\r\n    ];\r\n\r\n    const WALL_SEGMENTS = [\r\n      { p1: { x: 60, y: 60 }, p2: { x: 1140, y: 60 } },\r\n      { p1: { x: 1140, y: 60 }, p2: { x: 1140, y: 740 } },\r\n      { p1: { x: 1140, y: 740 }, p2: { x: 60, y: 740 } },\r\n      { p1: { x: 60, y: 740 }, p2: { x: 60, y: 60 } },\r\n      { p1: { x: 60, y: 390 }, p2: { x: 230, y: 390 } },\r\n      { p1: { x: 290, y: 390 }, p2: { x: 520, y: 390 } },\r\n      { p1: { x: 520, y: 390 }, p2: { x: 640, y: 390 } },\r\n      { p1: { x: 700, y: 390 }, p2: { x: 890, y: 390 } },\r\n      { p1: { x: 890, y: 390 }, p2: { x: 960, y: 390 } },\r\n      { p1: { x: 1025, y: 390 }, p2: { x: 1140, y: 390 } },\r\n      { p1: { x: 520, y: 60 }, p2: { x: 520, y: 390 } },\r\n      { p1: { x: 520, y: 390 }, p2: { x: 520, y: 470 } },\r\n      { p1: { x: 520, y: 650 }, p2: { x: 520, y: 740 } },\r\n      { p1: { x: 890, y: 60 }, p2: { x: 890, y: 390 } },\r\n      { p1: { x: 870, y: 390 }, p2: { x: 870, y: 480 } },\r\n      { p1: { x: 870, y: 555 }, p2: { x: 870, y: 740 } }\r\n    ];\r\n\r\n    const FURNITURE_ITEMS = [\r\n      { type: 'rug', x: 120, y: 460, w: 320, h: 230, label: 'Loomed Wool Rug' },\r\n      { type: 'sectional_sofa', x: 130, y: 480, w: 220, h: 90, label: 'Modern Sectional' },\r\n      { type: 'armchair', x: 370, y: 500, w: 56, h: 56, angle: -0.2, label: 'Lounge Chair' },\r\n      { type: 'armchair', x: 350, y: 590, w: 56, h: 56, angle: -1.2, label: 'Lounge Chair' },\r\n      { type: 'coffee_table', x: 210, y: 585, w: 105, h: 55, label: 'Marble Coffee Table' },\r\n      { type: 'media_wall', x: 75, y: 480, w: 30, h: 180, label: 'Media Wall' },\r\n      { type: 'dining_set', x: 620, y: 505, w: 155, h: 110, label: '6-Seater Oak Dining Table' },\r\n      { type: 'sideboard', x: 540, y: 700, w: 120, h: 30, label: 'Dining Console' },\r\n      { type: 'bed_king', x: 120, y: 95, w: 180, h: 210, label: 'King Bed' },\r\n      { type: 'nightstand', x: 74, y: 105, w: 38, h: 42, label: 'Nightstand L' },\r\n      { type: 'nightstand', x: 308, y: 105, w: 38, h: 42, label: 'Nightstand R' },\r\n      { type: 'rug', x: 95, y: 155, w: 230, h: 180, label: 'Silk Rug' },\r\n      { type: 'wardrobe', x: 390, y: 75, w: 110, h: 48, label: 'Fitted Wardrobe' },\r\n      { type: 'study_desk', x: 390, y: 310, w: 105, h: 45, label: 'Vanity Desk' },\r\n      { type: 'bed_queen', x: 590, y: 95, w: 150, h: 190, label: 'Queen Bed' },\r\n      { type: 'nightstand', x: 545, y: 105, w: 38, h: 42, label: 'Nightstand' },\r\n      { type: 'wardrobe', x: 760, y: 75, w: 115, h: 48, label: 'Wardrobe' },\r\n      { type: 'study_desk', x: 760, y: 315, w: 110, h: 45, label: 'Workstation' },\r\n      { type: 'kitchen_island', x: 895, y: 410, w: 220, h: 50, label: 'Quartz Island Counter' },\r\n      { type: 'kitchen_counter', x: 1075, y: 460, w: 45, h: 200, label: 'Kitchen Counter' },\r\n      { type: 'bench', x: 940, y: 100, w: 120, h: 40, label: 'Entry Bench' }\r\n    ];\r\n\r\n    const SCENE_PRESETS = {\r\n      modern: [\r\n        { id: 1, type: 'wallwasher', x: 130, y: 435, watts: 15, efficacy: 110, beamAngle: 120, cct: 3000, height: 2.8, enabled: true, name: 'Living Feature Wash' },\r\n        { id: 2, type: 'downlight', x: 260, y: 530, watts: 12, efficacy: 100, beamAngle: 60, cct: 3000, height: 2.8, enabled: true, name: 'Living Ambient 1' },\r\n        { id: 3, type: 'downlight', x: 370, y: 530, watts: 12, efficacy: 100, beamAngle: 60, cct: 3000, height: 2.8, enabled: true, name: 'Living Ambient 2' },\r\n        { id: 4, type: 'pendant', x: 695, y: 560, watts: 24, efficacy: 95, beamAngle: 90, cct: 3000, height: 2.4, enabled: true, name: 'Dining Chandelier' },\r\n        { id: 5, type: 'bedside', x: 93, y: 126, watts: 5, efficacy: 70, beamAngle: 60, cct: 2700, height: 0.75, enabled: true, name: 'Master Bedside Left' },\r\n        { id: 6, type: 'bedside', x: 327, y: 126, watts: 5, efficacy: 70, beamAngle: 60, cct: 2700, height: 0.75, enabled: true, name: 'Master Bedside Right' },\r\n        { id: 7, type: 'downlight', x: 260, y: 240, watts: 12, efficacy: 95, beamAngle: 60, cct: 2700, height: 2.8, enabled: true, name: 'Master Ambient Downlight' },\r\n        { id: 8, type: 'bedside', x: 564, y: 126, watts: 5, efficacy: 70, beamAngle: 60, cct: 2700, height: 0.75, enabled: true, name: 'Bed 2 Reading Lamp' },\r\n        { id: 9, type: 'downlight', x: 670, y: 220, watts: 14, efficacy: 100, beamAngle: 60, cct: 3000, height: 2.8, enabled: true, name: 'Bed 2 Ambient' },\r\n        { id: 10, type: 'downlight', x: 990, y: 520, watts: 18, efficacy: 110, beamAngle: 90, cct: 3500, height: 2.8, enabled: true, name: 'Kitchen Task Downlight' }\r\n      ],\r\n      cozy: [\r\n        { id: 1, type: 'wallwasher', x: 130, y: 435, watts: 10, efficacy: 90, beamAngle: 120, cct: 2700, height: 2.8, enabled: true, name: 'Living Warm Wash' },\r\n        { id: 2, type: 'spotlight', x: 260, y: 600, watts: 8, efficacy: 85, beamAngle: 36, cct: 2700, height: 2.8, enabled: true, name: 'Coffee Table Accent' },\r\n        { id: 3, type: 'pendant', x: 695, y: 560, watts: 18, efficacy: 90, beamAngle: 90, cct: 2700, height: 2.4, enabled: true, name: 'Dining Amber' },\r\n        { id: 4, type: 'bedside', x: 93, y: 126, watts: 4, efficacy: 65, beamAngle: 60, cct: 2700, height: 0.75, enabled: true, name: 'Master Bedside Left' },\r\n        { id: 5, type: 'bedside', x: 327, y: 126, watts: 4, efficacy: 65, beamAngle: 60, cct: 2700, height: 0.75, enabled: true, name: 'Master Bedside Right' },\r\n        { id: 6, type: 'bedside', x: 564, y: 126, watts: 4, efficacy: 65, beamAngle: 60, cct: 2700, height: 0.75, enabled: true, name: 'Bed 2 Reading Lamp' }\r\n      ],\r\n      task: [\r\n        { id: 1, type: 'downlight', x: 220, y: 520, watts: 20, efficacy: 110, beamAngle: 90, cct: 4000, height: 2.8, enabled: true, name: 'Living Center 1' },\r\n        { id: 2, type: 'downlight', x: 380, y: 520, watts: 20, efficacy: 110, beamAngle: 90, cct: 4000, height: 2.8, enabled: true, name: 'Living Center 2' },\r\n        { id: 3, type: 'pendant', x: 695, y: 560, watts: 32, efficacy: 105, beamAngle: 90, cct: 4000, height: 2.4, enabled: true, name: 'Dining Task' },\r\n        { id: 4, type: 'downlight', x: 260, y: 220, watts: 18, efficacy: 105, beamAngle: 60, cct: 4000, height: 2.8, enabled: true, name: 'Master Bright' },\r\n        { id: 5, type: 'bedside', x: 93, y: 126, watts: 6, efficacy: 80, beamAngle: 36, cct: 3000, height: 0.75, enabled: true, name: 'Master Task Reading L' },\r\n        { id: 6, type: 'bedside', x: 327, y: 126, watts: 6, efficacy: 80, beamAngle: 36, cct: 3000, height: 0.75, enabled: true, name: 'Master Task Reading R' },\r\n        { id: 7, type: 'downlight', x: 680, y: 220, watts: 18, efficacy: 105, beamAngle: 60, cct: 4000, height: 2.8, enabled: true, name: 'Bed 2 Bright' },\r\n        { id: 8, type: 'downlight', x: 990, y: 520, watts: 24, efficacy: 115, beamAngle: 90, cct: 4000, height: 2.8, enabled: true, name: 'Kitchen Prep' }\r\n      ]\r\n    };\r\n\r\n    let fixtures = JSON.parse(JSON.stringify(SCENE_PRESETS.modern));\r\n    let nextFixtureId = 16;\r\n    let selectedFixtureId = 5; \/\/ Default focused on Bedside Lamp\r\n    let viewMode = 'realistic'; \/\/ 'realistic' | 'heatmap'\r\n    let showFurniture = true;\r\n    let showGrid = false;\r\n    let showIsolux = true; \/\/ Live DIALux isolux curves default ON\r\n\r\n    let canvas = null;\r\n    let ctx = null;\r\n    let isDragging = false;\r\n    let draggedFixture = null;\r\n    let dragOffset = { x: 0, y: 0 };\r\n\r\n    function ensureCanvasContext() {\r\n      if (!canvas) canvas = document.getElementById('lightingCanvas');\r\n      if (canvas && !ctx) ctx = canvas.getContext('2d');\r\n      return !!(canvas && ctx);\r\n    }\r\n\r\n    function getRoomForPoint(x, y) {\r\n      for (let i = 0; i < ROOMS.length; i++) {\r\n        const r = ROOMS[i];\r\n        if (x >= r.x && x <= r.x + r.w && y >= r.y && y <= r.y + r.h) {\r\n          return r;\r\n        }\r\n      }\r\n      return null;\r\n    }\r\n\r\n    function getOcclusionFactor(fix, targetX, targetY) {\r\n      const sourceRoom = getRoomForPoint(fix.x, fix.y);\r\n      const targetRoom = getRoomForPoint(targetX, targetY);\r\n\r\n      if (!sourceRoom || !targetRoom) return 0;\r\n      if (sourceRoom.id === targetRoom.id) return 1.0;\r\n\r\n      \/\/ Bedside lamps are local task lamps and don't spill through solid walls\r\n      if (fix.type === 'bedside') return 0;\r\n\r\n      let bestApertureTransmission = 0;\r\n      for (let i = 0; i < DOORWAYS.length; i++) {\r\n        const d = DOORWAYS[i];\r\n        const connects = (d.connect[0] === sourceRoom.id && d.connect[1] === targetRoom.id) ||\r\n                         (d.connect[1] === sourceRoom.id && d.connect[0] === targetRoom.id);\r\n\r\n        if (connects) {\r\n          const doorCenterX = d.orientation === 'horizontal' ? d.x + d.width \/ 2 : d.x;\r\n          const doorCenterY = d.orientation === 'horizontal' ? d.y : d.y + (d.height || 60) \/ 2;\r\n          const d2 = Math.hypot(targetX - doorCenterX, targetY - doorCenterY);\r\n\r\n          const isWideArch = d.id === 'd_arch';\r\n          const maxSpillDist = isWideArch ? 400 : 200;\r\n\r\n          if (d2 < maxSpillDist) {\r\n            const apertureSize = isWideArch ? 0.90 : 0.60;\r\n            const trans = apertureSize * Math.max(0, 1 - (d2 \/ maxSpillDist));\r\n            if (trans > bestApertureTransmission) {\r\n              bestApertureTransmission = trans;\r\n            }\r\n          }\r\n        }\r\n      }\r\n      return bestApertureTransmission;\r\n    }\r\n\r\n    function cctToRgb(kelvin) {\r\n      const temp = kelvin \/ 100;\r\n      let r, g, b;\r\n      if (temp <= 66) {\r\n        r = 255;\r\n        g = Math.min(255, Math.max(0, 99.4708025861 * Math.log(temp) - 161.1195681661));\r\n        b = temp <= 19 ? 0 : Math.min(255, Math.max(0, 138.5177312231 * Math.log(temp - 10) - 305.0447927307));\r\n      } else {\r\n        r = Math.min(255, Math.max(0, 329.698727446 * Math.pow(temp - 60, -0.1332047592)));\r\n        g = Math.min(255, Math.max(0, 288.1221695283 * Math.pow(temp - 60, -0.0755148492)));\r\n        b = 255;\r\n      }\r\n      return { r: Math.round(r), g: Math.round(g), b: Math.round(b) };\r\n    }\r\n\r\n    \/* Full-Spectrum 8-color DIALux calibrated false color map *\/\r\n    function luxToHeatmapColor(lux) {\r\n      if (lux <= 10) return 'rgb(17, 0, 56)';\r\n      if (lux < 50) {\r\n        const t = (lux - 10) \/ 40;\r\n        return `rgb(${Math.round(17 + 13 * t)}, ${Math.round(0 + 58 * t)}, ${Math.round(56 + 82 * t)})`; \/\/ to deep blue\r\n      } else if (lux < 100) {\r\n        const t = (lux - 50) \/ 50;\r\n        return `rgb(${Math.round(30 - 28 * t)}, ${Math.round(58 + 74 * t)}, ${Math.round(138 + 61 * t)})`; \/\/ to sky cyan\r\n      } else if (lux < 150) {\r\n        const t = (lux - 100) \/ 50;\r\n        return `rgb(${Math.round(2 + 3 * t)}, ${Math.round(132 + 18 * t)}, ${Math.round(199 - 94 * t)})`; \/\/ to emerald\r\n      } else if (lux < 250) {\r\n        const t = (lux - 150) \/ 100;\r\n        return `rgb(${Math.round(5 + 127 * t)}, ${Math.round(150 + 54 * t)}, ${Math.round(105 - 83 * t)})`; \/\/ to lime yellow\r\n      } else if (lux < 350) {\r\n        const t = (lux - 250) \/ 100;\r\n        return `rgb(${Math.round(132 + 117 * t)}, ${Math.round(204 - 89 * t)}, ${Math.round(22 - 1 * t)})`; \/\/ to amber orange\r\n      } else if (lux < 500) {\r\n        const t = (lux - 350) \/ 150;\r\n        return `rgb(${Math.round(249 - 29 * t)}, ${Math.round(115 - 77 * t)}, ${Math.round(21 + 17 * t)})`; \/\/ to vibrant red\r\n      } else {\r\n        const t = Math.min(1, (lux - 500) \/ 350);\r\n        return `rgb(${Math.round(220 + 24 * t)}, ${Math.round(38 + 25 * t)}, ${Math.round(38 + 56 * t)})`; \/\/ to hot magenta\r\n      }\r\n    }\r\n\r\n    \/* International point-by-point calculation: E_h = (I(theta) * cos(theta)) \/ d^2 *\/\r\n    function calculateLuxAtPoint(px, py) {\r\n      let totalLux = 0;\r\n\r\n      for (let i = 0; i < fixtures.length; i++) {\r\n        const fix = fixtures[i];\r\n        if (fix.enabled === false) continue;\r\n\r\n        const occlusion = getOcclusionFactor(fix, px, py);\r\n        if (occlusion <= 0) continue;\r\n\r\n        const dx_px = px - fix.x;\r\n        const dy_px = py - fix.y;\r\n        const dist2D_m = Math.hypot(dx_px, dy_px) \/ PIXELS_PER_METER;\r\n\r\n        const fixH = (fix.height !== undefined) ? fix.height : 2.8;\r\n        const effectiveH = fix.type === 'bedside' ? Math.max(0.20, Math.abs(fixH - 0.6)) : Math.max(0.3, fixH - WORK_PLANE_HEIGHT);\r\n        const actualDist_m = Math.sqrt(dist2D_m * dist2D_m + effectiveH * effectiveH);\r\n        const cosTheta = effectiveH \/ actualDist_m;\r\n\r\n        \/\/ Total lumens & candela peak\r\n        const totalLumens = fix.watts * fix.efficacy;\r\n        const beamRad = (fix.beamAngle * Math.PI) \/ 180;\r\n        const halfAngle = beamRad \/ 2;\r\n        const solidAngle = Math.max(0.15, 2 * Math.PI * (1 - Math.cos(halfAngle)));\r\n        const centralIntensity_cd = (totalLumens \/ solidAngle) * 0.95;\r\n\r\n        \/\/ Gaussian FWHM falloff matching international optical polar graphs\r\n        const thetaAngle = Math.atan2(dist2D_m, effectiveH);\r\n        const relAngle = thetaAngle \/ halfAngle;\r\n        let factor = Math.exp(-Math.pow(relAngle, 2) * 1.386);\r\n\r\n        if (thetaAngle > halfAngle * 1.3) {\r\n          factor *= Math.max(0, 1 - (thetaAngle - halfAngle * 1.3) \/ (halfAngle * 0.4));\r\n        }\r\n\r\n        const intensity_cd = centralIntensity_cd * factor;\r\n        const directLux = (intensity_cd * cosTheta) \/ (actualDist_m * actualDist_m);\r\n        const indirectLux = (totalLumens \/ 200) * Math.max(0, 1 - dist2D_m \/ 4.8);\r\n\r\n        totalLux += (directLux + indirectLux) * occlusion;\r\n      }\r\n\r\n      return Math.round(totalLux);\r\n    }\r\n\r\n    function drawLiveIsoluxCurves() {\r\n      if (!showIsolux) return;\r\n\r\n      const step = 20;\r\n      const cols = Math.floor(CANVAS_WIDTH \/ step);\r\n      const rows = Math.floor(CANVAS_HEIGHT \/ step);\r\n\r\n      \/\/ 1. Compute grid lux field\r\n      const grid = new Float32Array((cols + 1) * (rows + 1));\r\n      for (let r = 0; r <= rows; r++) {\r\n        const y = r * step;\r\n        for (let c = 0; c <= cols; c++) {\r\n          const x = c * step;\r\n          grid[r * (cols + 1) + c] = calculateLuxAtPoint(x, y);\r\n        }\r\n      }\r\n\r\n      \/\/ Standard DIALux isolux threshold levels\r\n      const isoLevels = [30, 50, 100, 150, 200, 300, 500];\r\n\r\n      ctx.save();\r\n      ctx.lineWidth = 1.3;\r\n\r\n      isoLevels.forEach((level, levelIdx) => {\r\n        \/\/ Subtle level color with high contrast\r\n        ctx.strokeStyle = 'rgba(255, 255, 255, 0.72)';\r\n        ctx.beginPath();\r\n\r\n        const segments = [];\r\n\r\n        \/\/ Marching squares segment extraction per cell\r\n        for (let r = 0; r < rows; r++) {\r\n          const y0 = r * step;\r\n          const y1 = y0 + step;\r\n\r\n          for (let c = 0; c < cols; c++) {\r\n            const x0 = c * step;\r\n            const x1 = x0 + step;\r\n\r\n            const idx = r * (cols + 1) + c;\r\n            const vBL = grid[idx + (cols + 1)];\r\n            const vBR = grid[idx + (cols + 1) + 1];\r\n            const vTR = grid[idx + 1];\r\n            const vTL = grid[idx];\r\n\r\n            let cellMask = 0;\r\n            if (vBL >= level) cellMask |= 1;\r\n            if (vBR >= level) cellMask |= 2;\r\n            if (vTR >= level) cellMask |= 4;\r\n            if (vTL >= level) cellMask |= 8;\r\n\r\n            if (cellMask === 0 || cellMask === 15) continue;\r\n\r\n            const getX = (v1, v2, xA, xB) => xA + (xB - xA) * ((level - v1) \/ (v2 - v1 || 1e-5));\r\n            const getY = (v1, v2, yA, yB) => yA + (yB - yA) * ((level - v1) \/ (v2 - v1 || 1e-5));\r\n\r\n            const edgeBottom = { x: getX(vBL, vBR, x0, x1), y: y1 };\r\n            const edgeRight  = { x: x1, y: getY(vBR, vTR, y1, y0) };\r\n            const edgeTop    = { x: getX(vTL, vTR, x0, x1), y: y0 };\r\n            const edgeLeft   = { x: x0, y: getY(vBL, vTL, y1, y0) };\r\n\r\n            const addSeg = (p1, p2) => {\r\n              segments.push({ p1, p2 });\r\n              ctx.moveTo(p1.x, p1.y);\r\n              ctx.lineTo(p2.x, p2.y);\r\n            };\r\n\r\n            switch (cellMask) {\r\n              case 1:  case 14: addSeg(edgeLeft, edgeBottom); break;\r\n              case 2:  case 13: addSeg(edgeBottom, edgeRight); break;\r\n              case 3:  case 12: addSeg(edgeLeft, edgeRight); break;\r\n              case 4:  case 11: addSeg(edgeRight, edgeTop); break;\r\n              case 5:           addSeg(edgeLeft, edgeTop); addSeg(edgeBottom, edgeRight); break;\r\n              case 6:  case 9:  addSeg(edgeBottom, edgeTop); break;\r\n              case 7:  case 8:  addSeg(edgeLeft, edgeTop); break;\r\n              case 10:          addSeg(edgeLeft, edgeBottom); addSeg(edgeRight, edgeTop); break;\r\n            }\r\n          }\r\n        }\r\n        ctx.stroke();\r\n\r\n        \/\/ 2. Draw crisp white lux numbers along isolux curves (as shown in user DIALux diagram)\r\n        if (segments.length > 8) {\r\n          const labelInterval = Math.max(12, Math.floor(segments.length \/ 4));\r\n          for (let s = Math.floor(labelInterval \/ 2); s < segments.length; s += labelInterval) {\r\n            const seg = segments[s];\r\n            const mx = (seg.p1.x + seg.p2.x) \/ 2;\r\n            const my = (seg.p1.y + seg.p2.y) \/ 2;\r\n\r\n            if (mx < 80 || mx > 1120 || my < 80 || my > 720) continue;\r\n\r\n            const textStr = `${level} lx`;\r\n            ctx.font = '700 9px JetBrains Mono';\r\n            ctx.textAlign = 'center';\r\n            ctx.textBaseline = 'middle';\r\n\r\n            \/\/ Background pill for label contrast\r\n            const txtWidth = ctx.measureText(textStr).width;\r\n            ctx.fillStyle = '#020617';\r\n            ctx.fillRect(mx - txtWidth \/ 2 - 3, my - 6, txtWidth + 6, 12);\r\n\r\n            ctx.strokeStyle = 'rgba(255, 255, 255, 0.4)';\r\n            ctx.lineWidth = 0.8;\r\n            ctx.strokeRect(mx - txtWidth \/ 2 - 3, my - 6, txtWidth + 6, 12);\r\n\r\n            \/\/ White text label\r\n            ctx.fillStyle = '#ffffff';\r\n            ctx.fillText(textStr, mx, my);\r\n          }\r\n        }\r\n      });\r\n\r\n      ctx.restore();\r\n    }\r\n\r\n    function resizeCanvas() {\r\n      if (!ensureCanvasContext()) return;\r\n      canvas.width = CANVAS_WIDTH;\r\n      canvas.height = CANVAS_HEIGHT;\r\n      renderScene();\r\n    }\r\n\r\n    function renderScene() {\r\n      if (!ensureCanvasContext()) return;\r\n      ctx.clearRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);\r\n\r\n      if (viewMode === 'heatmap') {\r\n        renderHeatmapMode();\r\n      } else {\r\n        renderRealisticMode();\r\n      }\r\n\r\n      \/\/ Draw white CAD furniture\r\n      if (showFurniture) {\r\n        drawWhiteFurniture();\r\n      }\r\n\r\n      \/\/ Draw Live DIALux Isolux Contour lines with white values\r\n      drawLiveIsoluxCurves();\r\n\r\n      \/\/ Walls, fixtures, labels\r\n      drawWallsAndApertures();\r\n      drawFixtures();\r\n    }\r\n\r\n    function renderRealisticMode() {\r\n      \/\/ 1. Dark room base as requested\r\n      ctx.fillStyle = '#060a12';\r\n      ctx.fillRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);\r\n\r\n      \/\/ Room subtle floor tints with distinct borders\r\n      ROOMS.forEach(r => {\r\n        ctx.fillStyle = '#0a0f1d';\r\n        ctx.fillRect(r.x, r.y, r.w, r.h);\r\n\r\n        ctx.strokeStyle = 'rgba(255, 255, 255, 0.04)';\r\n        ctx.lineWidth = 1;\r\n        ctx.strokeRect(r.x, r.y, r.w, r.h);\r\n      });\r\n\r\n      if (showGrid) {\r\n        drawArchitecturalGrid('rgba(255, 255, 255, 0.08)');\r\n      }\r\n\r\n      \/\/ 2. Realistic additive lighting pass\r\n      renderCleanLightingPass();\r\n    }\r\n\r\n    function renderCleanLightingPass() {\r\n      const lightCanvas = document.createElement('canvas');\r\n      lightCanvas.width = CANVAS_WIDTH;\r\n      lightCanvas.height = CANVAS_HEIGHT;\r\n      const lCtx = lightCanvas.getContext('2d');\r\n\r\n      \/\/ Darkness depth\r\n      lCtx.fillStyle = 'rgba(2, 6, 23, 0.82)';\r\n      lCtx.fillRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);\r\n\r\n      lCtx.globalCompositeOperation = 'lighter';\r\n\r\n      fixtures.forEach(fix => {\r\n        if (fix.enabled === false) return;\r\n\r\n        const hostRoom = getRoomForPoint(fix.x, fix.y);\r\n        if (!hostRoom) return;\r\n\r\n        const rgb = cctToRgb(fix.cct);\r\n        const radius = fix.type === 'bedside'\r\n          ? Math.min(200, (fix.watts * 28) * (fix.beamAngle \/ 50))\r\n          : Math.min(460, (fix.watts * 18) * (fix.beamAngle \/ 50));\r\n        \r\n        const alpha = Math.min(0.92, 0.45 + (fix.watts \/ 35) * 0.45);\r\n\r\n        lCtx.save();\r\n        lCtx.beginPath();\r\n        lCtx.rect(hostRoom.x, hostRoom.y, hostRoom.w, hostRoom.h);\r\n        lCtx.clip();\r\n\r\n        const grad = lCtx.createRadialGradient(fix.x, fix.y, 2, fix.x, fix.y, radius);\r\n        grad.addColorStop(0, `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${alpha})`);\r\n        grad.addColorStop(0.25, `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${alpha * 0.65})`);\r\n        grad.addColorStop(0.55, `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${alpha * 0.28})`);\r\n        grad.addColorStop(0.85, `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${alpha * 0.06})`);\r\n        grad.addColorStop(1, `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 0)`);\r\n\r\n        lCtx.fillStyle = grad;\r\n        lCtx.fillRect(hostRoom.x, hostRoom.y, hostRoom.w, hostRoom.h);\r\n\r\n        if (fix.type !== 'bedside') {\r\n          drawWallScallopHighlight(lCtx, fix, rgb, hostRoom);\r\n        }\r\n\r\n        lCtx.restore();\r\n\r\n        \/\/ Light spill through doorways\r\n        if (fix.type !== 'bedside') {\r\n          DOORWAYS.forEach(d => {\r\n            const isConnected = d.connect.includes(hostRoom.id);\r\n            if (!isConnected) return;\r\n\r\n            const neighborRoomId = d.connect[0] === hostRoom.id ? d.connect[1] : d.connect[0];\r\n            const neighborRoom = ROOMS.find(r => r.id === neighborRoomId);\r\n            if (!neighborRoom) return;\r\n\r\n            const doorCenterX = d.orientation === 'horizontal' ? d.x + d.width \/ 2 : d.x;\r\n            const doorCenterY = d.orientation === 'horizontal' ? d.y : d.y + (d.height || 60) \/ 2;\r\n            const distToDoor = Math.hypot(fix.x - doorCenterX, fix.y - doorCenterY);\r\n\r\n            const threshold = d.id === 'd_arch' ? 380 : 250;\r\n            if (distToDoor < threshold) {\r\n              lCtx.save();\r\n              lCtx.beginPath();\r\n              lCtx.rect(neighborRoom.x, neighborRoom.y, neighborRoom.w, neighborRoom.h);\r\n              lCtx.clip();\r\n\r\n              const spillStrength = (1 - distToDoor \/ threshold) * (d.id === 'd_arch' ? 0.75 : 0.45);\r\n              const spillRadius = radius * 0.85;\r\n\r\n              const spillGrad = lCtx.createRadialGradient(fix.x, fix.y, distToDoor * 0.7, fix.x, fix.y, spillRadius);\r\n              spillGrad.addColorStop(0, `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${alpha * spillStrength})`);\r\n              spillGrad.addColorStop(0.5, `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${alpha * spillStrength * 0.35})`);\r\n              spillGrad.addColorStop(1, `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 0)`);\r\n\r\n              lCtx.fillStyle = spillGrad;\r\n              lCtx.fillRect(neighborRoom.x, neighborRoom.y, neighborRoom.w, neighborRoom.h);\r\n              lCtx.restore();\r\n            }\r\n          });\r\n        }\r\n      });\r\n\r\n      ctx.drawImage(lightCanvas, 0, 0);\r\n    }\r\n\r\n    function drawWallScallopHighlight(targetCtx, fix, rgb, room) {\r\n      const distToTop = Math.abs(fix.y - room.y);\r\n      const distToBottom = Math.abs(fix.y - (room.y + room.h));\r\n      const distToLeft = Math.abs(fix.x - room.x);\r\n      const distToRight = Math.abs(fix.x - (room.x + room.w));\r\n      const minDist = Math.min(distToTop, distToBottom, distToLeft, distToRight);\r\n\r\n      if (minDist < 50 && fix.beamAngle <= 90) {\r\n        targetCtx.save();\r\n        targetCtx.fillStyle = `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 0.32)`;\r\n        targetCtx.beginPath();\r\n        targetCtx.arc(fix.x, fix.y, 48, 0, Math.PI * 2);\r\n        targetCtx.fill();\r\n        targetCtx.restore();\r\n      }\r\n    }\r\n\r\n    function renderHeatmapMode() {\r\n      const step = 14;\r\n      const cols = Math.floor(CANVAS_WIDTH \/ step);\r\n      const rows = Math.floor(CANVAS_HEIGHT \/ step);\r\n\r\n      ctx.fillStyle = '#030718';\r\n      ctx.fillRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);\r\n\r\n      for (let r = 0; r < rows; r++) {\r\n        const y = r * step + step \/ 2;\r\n        if (y < 60 || y > 740) continue;\r\n\r\n        for (let c = 0; c < cols; c++) {\r\n          const x = c * step + step \/ 2;\r\n          if (x < 60 || x > 1140) continue;\r\n\r\n          const lux = calculateLuxAtPoint(x, y);\r\n          ctx.fillStyle = luxToHeatmapColor(lux);\r\n          ctx.fillRect(c * step, r * step, step, step);\r\n        }\r\n      }\r\n    }\r\n\r\n    function drawArchitecturalGrid(color) {\r\n      ctx.save();\r\n      ctx.strokeStyle = color;\r\n      ctx.lineWidth = 0.5;\r\n      for (let x = 60; x <= 1140; x += 40) {\r\n        ctx.beginPath();\r\n        ctx.moveTo(x, 60);\r\n        ctx.lineTo(x, 740);\r\n        ctx.stroke();\r\n      }\r\n      for (let y = 60; y <= 740; y += 40) {\r\n        ctx.beginPath();\r\n        ctx.moveTo(60, y);\r\n        ctx.lineTo(1140, y);\r\n        ctx.stroke();\r\n      }\r\n      ctx.restore();\r\n    }\r\n\r\n    function drawWhiteFurniture() {\r\n      ctx.save();\r\n\r\n      FURNITURE_ITEMS.forEach(item => {\r\n        ctx.save();\r\n        ctx.translate(item.x, item.y);\r\n        if (item.angle) ctx.rotate(item.angle);\r\n\r\n        \/\/ Dark translucent fill + crisp white CAD outline\r\n        ctx.strokeStyle = '#ffffff';\r\n        ctx.lineWidth = 1.6;\r\n        ctx.fillStyle = 'rgba(15, 23, 42, 0.55)';\r\n\r\n        if (item.type === 'rug') {\r\n          ctx.fillStyle = 'rgba(255, 255, 255, 0.04)';\r\n          ctx.strokeStyle = 'rgba(255, 255, 255, 0.45)';\r\n          ctx.lineWidth = 1.2;\r\n          ctx.setLineDash([4, 4]);\r\n          ctx.fillRect(0, 0, item.w, item.h);\r\n          ctx.strokeRect(0, 0, item.w, item.h);\r\n          ctx.setLineDash([]);\r\n\r\n        } else if (item.type === 'bed_king' || item.type === 'bed_queen') {\r\n          \/\/ Padded Headboard\r\n          ctx.fillStyle = 'rgba(255, 255, 255, 0.15)';\r\n          ctx.fillRect(0, 0, item.w, 32);\r\n          ctx.strokeRect(0, 0, item.w, 32);\r\n\r\n          \/\/ Mattress\r\n          ctx.fillStyle = 'rgba(30, 41, 59, 0.65)';\r\n          ctx.beginPath();\r\n          ctx.roundRect(6, 28, item.w - 12, item.h - 34, 6);\r\n          ctx.fill();\r\n          ctx.stroke();\r\n\r\n          \/\/ Bed Runner \/ Throw\r\n          ctx.fillStyle = 'rgba(255, 255, 255, 0.1)';\r\n          ctx.fillRect(6, item.h - 60, item.w - 12, 54);\r\n          ctx.strokeRect(6, item.h - 60, item.w - 12, 54);\r\n\r\n          \/\/ Pillows\r\n          const pilW = (item.w - 32) \/ 2;\r\n          ctx.fillStyle = 'rgba(255, 255, 255, 0.2)';\r\n          ctx.fillRect(10, 36, pilW, 30);\r\n          ctx.strokeRect(10, 36, pilW, 30);\r\n          ctx.fillRect(22 + pilW, 36, pilW, 30);\r\n          ctx.strokeRect(22 + pilW, 36, pilW, 30);\r\n\r\n        } else if (item.type === 'sectional_sofa') {\r\n          ctx.beginPath();\r\n          ctx.roundRect(0, 0, item.w, item.h, 18);\r\n          ctx.fill();\r\n          ctx.stroke();\r\n\r\n          \/\/ Cushions\r\n          const cW = (item.w - 24) \/ 3;\r\n          for (let c = 0; c < 3; c++) {\r\n            ctx.beginPath();\r\n            ctx.roundRect(8 + c * (cW + 4), 8, cW, item.h - 16, 8);\r\n            ctx.stroke();\r\n          }\r\n\r\n        } else if (item.type === 'armchair') {\r\n          ctx.beginPath();\r\n          ctx.roundRect(0, 0, item.w, item.h, 14);\r\n          ctx.fill();\r\n          ctx.stroke();\r\n\r\n          ctx.beginPath();\r\n          ctx.arc(item.w \/ 2, item.h \/ 2, item.w * 0.32, 0, Math.PI * 2);\r\n          ctx.stroke();\r\n\r\n        } else if (item.type === 'coffee_table') {\r\n          ctx.beginPath();\r\n          ctx.ellipse(item.w \/ 2, item.h \/ 2, item.w \/ 2, item.h \/ 2, 0, 0, Math.PI * 2);\r\n          ctx.fill();\r\n          ctx.stroke();\r\n\r\n        } else if (item.type === 'dining_set') {\r\n          \/\/ Tabletop\r\n          ctx.beginPath();\r\n          ctx.roundRect(0, 0, item.w, item.h, 10);\r\n          ctx.fill();\r\n          ctx.stroke();\r\n\r\n          \/\/ 6 Dining Chairs with white outlines\r\n          const chW = 34, chH = 14;\r\n          [0.25, 0.75].forEach(r => {\r\n            ctx.fillRect(item.w * r - chW \/ 2, -18, chW, chH);\r\n            ctx.strokeRect(item.w * r - chW \/ 2, -18, chW, chH);\r\n            ctx.fillRect(item.w * r - chW \/ 2, item.h + 4, chW, chH);\r\n            ctx.strokeRect(item.w * r - chW \/ 2, item.h + 4, chW, chH);\r\n          });\r\n          ctx.fillRect(-18, item.h \/ 2 - chW \/ 2, chH, chW);\r\n          ctx.strokeRect(-18, item.h \/ 2 - chW \/ 2, chH, chW);\r\n          ctx.fillRect(item.w + 4, item.h \/ 2 - chW \/ 2, chH, chW);\r\n          ctx.strokeRect(item.w + 4, item.h \/ 2 - chW \/ 2, chH, chW);\r\n\r\n        } else if (item.type === 'kitchen_island') {\r\n          ctx.fillRect(0, 0, item.w, item.h);\r\n          ctx.strokeRect(0, 0, item.w, item.h);\r\n\r\n          \/\/ Induction and sink outlines\r\n          ctx.strokeRect(20, 10, 60, 30);\r\n          ctx.beginPath();\r\n          ctx.roundRect(item.w - 75, 10, 50, 30, 4);\r\n          ctx.stroke();\r\n\r\n        } else {\r\n          \/\/ Nightstands, wardrobes & consoles\r\n          ctx.fillRect(0, 0, item.w, item.h);\r\n          ctx.strokeRect(0, 0, item.w, item.h);\r\n        }\r\n\r\n        \/\/ Crisp White Typography Label\r\n        ctx.fillStyle = '#ffffff';\r\n        ctx.font = '600 10px Inter';\r\n        ctx.textAlign = 'center';\r\n        ctx.fillText(item.label, item.w \/ 2, item.h \/ 2 + 3);\r\n\r\n        ctx.restore();\r\n      });\r\n\r\n      ctx.restore();\r\n    }\r\n\r\n    function drawWallsAndApertures() {\r\n      ctx.save();\r\n\r\n      \/\/ Room Dimensions & Names in Crisp White\r\n      ROOMS.forEach(r => {\r\n        ctx.fillStyle = '#ffffff';\r\n        ctx.font = '700 13px Inter';\r\n        ctx.textAlign = 'left';\r\n        ctx.fillText(r.name.toUpperCase(), r.x + 18, r.y + 26);\r\n\r\n        const dimStr = `${(r.w \/ PIXELS_PER_METER).toFixed(1)}m \u00d7 ${(r.h \/ PIXELS_PER_METER).toFixed(1)}m`;\r\n        ctx.fillStyle = '#94a3b8';\r\n        ctx.font = '10px JetBrains Mono';\r\n        ctx.fillText(dimStr, r.x + 18, r.y + 40);\r\n      });\r\n\r\n      \/\/ Outer Perimeter & Partition Walls with Architectural Thickness\r\n      ctx.strokeStyle = '#020617';\r\n      ctx.lineWidth = 14;\r\n      ctx.lineCap = 'square';\r\n      ctx.beginPath();\r\n      WALL_SEGMENTS.forEach(w => {\r\n        ctx.moveTo(w.p1.x, w.p1.y);\r\n        ctx.lineTo(w.p2.x, w.p2.y);\r\n      });\r\n      ctx.stroke();\r\n\r\n      ctx.strokeStyle = '#334155';\r\n      ctx.lineWidth = 6;\r\n      ctx.beginPath();\r\n      WALL_SEGMENTS.forEach(w => {\r\n        ctx.moveTo(w.p1.x, w.p1.y);\r\n        ctx.lineTo(w.p2.x, w.p2.y);\r\n      });\r\n      ctx.stroke();\r\n\r\n      \/\/ Sharp white wall edge line\r\n      ctx.strokeStyle = '#ffffff';\r\n      ctx.lineWidth = 1.4;\r\n      ctx.beginPath();\r\n      WALL_SEGMENTS.forEach(w => {\r\n        ctx.moveTo(w.p1.x, w.p1.y);\r\n        ctx.lineTo(w.p2.x, w.p2.y);\r\n      });\r\n      ctx.stroke();\r\n\r\n      \/\/ Architectural Door Swings\r\n      ctx.strokeStyle = 'rgba(245, 158, 11, 0.9)';\r\n      ctx.lineWidth = 1.5;\r\n      ctx.setLineDash([4, 4]);\r\n      const doors = [\r\n        { x: 230, y: 390, r: 60, s: 0, e: Math.PI \/ 2 },\r\n        { x: 640, y: 390, r: 60, s: 0, e: Math.PI \/ 2 },\r\n        { x: 870, y: 480, r: 75, s: Math.PI \/ 2, e: Math.PI }\r\n      ];\r\n      doors.forEach(d => {\r\n        ctx.beginPath();\r\n        ctx.arc(d.x, d.y, d.r, d.s, d.e);\r\n        ctx.stroke();\r\n      });\r\n\r\n      ctx.restore();\r\n    }\r\n\r\n    function drawFixtures() {\r\n      fixtures.forEach(fix => {\r\n        const isSelected = fix.id === selectedFixtureId;\r\n        const rgb = cctToRgb(fix.cct);\r\n        const isOn = fix.enabled !== false;\r\n\r\n        ctx.save();\r\n        ctx.translate(fix.x, fix.y);\r\n\r\n        \/\/ Selection Halo\r\n        if (isSelected) {\r\n          ctx.beginPath();\r\n          ctx.arc(0, 0, 20, 0, Math.PI * 2);\r\n          ctx.strokeStyle = '#f59e0b';\r\n          ctx.lineWidth = 2.5;\r\n          ctx.setLineDash([4, 3]);\r\n          ctx.stroke();\r\n          ctx.setLineDash([]);\r\n        }\r\n\r\n        if (fix.type === 'bedside') {\r\n          \/\/ Bedside Table Lamp CAD Representation\r\n          ctx.beginPath();\r\n          ctx.roundRect(-9, -9, 18, 18, 4);\r\n          ctx.fillStyle = '#0f172a';\r\n          ctx.fill();\r\n          ctx.strokeStyle = isSelected ? '#f59e0b' : '#ffffff';\r\n          ctx.lineWidth = 1.5;\r\n          ctx.stroke();\r\n\r\n          \/\/ Conical Lampshade\r\n          ctx.beginPath();\r\n          ctx.moveTo(-11, 7);\r\n          ctx.lineTo(11, 7);\r\n          ctx.lineTo(7, -8);\r\n          ctx.lineTo(-7, -8);\r\n          ctx.closePath();\r\n          ctx.fillStyle = isOn ? `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 0.95)` : '#334155';\r\n          if (isOn) {\r\n            ctx.shadowColor = `rgb(${rgb.r}, ${rgb.g}, ${rgb.b})`;\r\n            ctx.shadowBlur = 12;\r\n          }\r\n          ctx.fill();\r\n          ctx.strokeStyle = '#ffffff';\r\n          ctx.lineWidth = 1;\r\n          ctx.stroke();\r\n\r\n          \/\/ Lamp Finial\r\n          ctx.beginPath();\r\n          ctx.arc(0, -9, 2.5, 0, Math.PI * 2);\r\n          ctx.fillStyle = '#fbbf24';\r\n          ctx.fill();\r\n\r\n        } else {\r\n          \/\/ Standard Downlight \/ Pendant \/ Spotlight\r\n          ctx.beginPath();\r\n          ctx.arc(0, 0, 11, 0, Math.PI * 2);\r\n          ctx.fillStyle = '#020617';\r\n          ctx.fill();\r\n          ctx.strokeStyle = isSelected ? '#f59e0b' : '#ffffff';\r\n          ctx.lineWidth = 2;\r\n          ctx.stroke();\r\n\r\n          ctx.beginPath();\r\n          ctx.arc(0, 0, 5.5, 0, Math.PI * 2);\r\n          if (isOn) {\r\n            ctx.fillStyle = `rgb(${rgb.r}, ${rgb.g}, ${rgb.b})`;\r\n            ctx.shadowColor = `rgb(${rgb.r}, ${rgb.g}, ${rgb.b})`;\r\n            ctx.shadowBlur = 12;\r\n          } else {\r\n            ctx.fillStyle = '#475569';\r\n            ctx.shadowBlur = 0;\r\n          }\r\n          ctx.fill();\r\n        }\r\n\r\n        \/\/ White Tag Label\r\n        ctx.shadowBlur = 0;\r\n        ctx.font = '700 11px JetBrains Mono';\r\n        ctx.fillStyle = isSelected ? '#f59e0b' : '#ffffff';\r\n        ctx.textAlign = 'center';\r\n        ctx.fillText(`L${fix.id}`, 0, -16);\r\n\r\n        ctx.restore();\r\n      });\r\n    }\r\n\r\n    function calculateRoomMetrics() {\r\n      const roomStats = {};\r\n      const sampleSpacing = 20;\r\n\r\n      ROOMS.forEach(room => {\r\n        let sumLux = 0;\r\n        let minLux = Infinity;\r\n        let maxLux = -Infinity;\r\n        let count = 0;\r\n\r\n        for (let y = room.y + 16; y < room.y + room.h - 16; y += sampleSpacing) {\r\n          for (let x = room.x + 16; x < room.x + room.w - 16; x += sampleSpacing) {\r\n            const lux = calculateLuxAtPoint(x, y);\r\n            sumLux += lux;\r\n            if (lux < minLux) minLux = lux;\r\n            if (lux > maxLux) maxLux = lux;\r\n            count++;\r\n          }\r\n        }\r\n\r\n        const avgLux = count > 0 ? Math.round(sumLux \/ count) : 0;\r\n        minLux = minLux === Infinity ? 0 : minLux;\r\n        maxLux = maxLux === -Infinity ? 0 : maxLux;\r\n        const uniformity = avgLux > 0 ? (minLux \/ avgLux).toFixed(2) : '0.00';\r\n        const isCompliant = avgLux >= room.targetMin;\r\n\r\n        roomStats[room.id] = {\r\n          name: room.name,\r\n          targetMin: room.targetMin,\r\n          targetMax: room.targetMax,\r\n          avgLux,\r\n          minLux,\r\n          maxLux,\r\n          uniformity,\r\n          isCompliant\r\n        };\r\n      });\r\n\r\n      return roomStats;\r\n    }\r\n\r\n    function updateMetricsUI() {\r\n      const activeFixtures = fixtures.filter(f => f.enabled !== false);\r\n      const totalWatts = activeFixtures.reduce((acc, f) => acc + f.watts, 0);\r\n      const totalLumens = activeFixtures.reduce((acc, f) => acc + (f.watts * f.efficacy), 0);\r\n\r\n      document.getElementById('statFixtureCount').textContent = fixtures.length;\r\n      document.getElementById('statTotalWatts').textContent = `${totalWatts} W`;\r\n      document.getElementById('statTotalLumens').textContent = `${totalLumens.toLocaleString()} lm`;\r\n      document.getElementById('listSummaryText').textContent = `${fixtures.length} installed`;\r\n\r\n      const metrics = calculateRoomMetrics();\r\n      const container = document.getElementById('roomMetricsContainer');\r\n      container.innerHTML = '';\r\n\r\n      Object.keys(metrics).forEach(key => {\r\n        const m = metrics[key];\r\n        const card = document.createElement('div');\r\n        card.className = `p-3 rounded-xl border text-xs space-y-2 transition ${\r\n          m.isCompliant ? 'bg-slate-900 border-emerald-500\/40' : 'bg-slate-900 border-amber-500\/40'\r\n        }`;\r\n\r\n        card.innerHTML = `\r\n          <div class=\"flex items-center justify-between\">\r\n            <span class=\"font-bold text-white\">${m.name}<\/span>\r\n            <span class=\"px-2 py-0.5 rounded text-[10px] font-semibold ${\r\n              m.isCompliant ? 'bg-emerald-950\/80 text-emerald-300 border border-emerald-700' : 'bg-amber-950\/80 text-amber-300 border border-amber-700'\r\n            }\">\r\n              ${m.isCompliant ? 'Compliant' : 'Target ' + m.targetMin + ' lx'}\r\n            <\/span>\r\n          <\/div>\r\n          <div class=\"grid grid-cols-3 gap-2 bg-slate-950 p-2 rounded-lg border border-slate-800 font-mono text-[11px]\">\r\n            <div>\r\n              <span class=\"text-[9px] text-slate-400 block\">E_avg<\/span>\r\n              <span class=\"font-bold ${m.isCompliant ? 'text-emerald-400' : 'text-amber-400'}\">${m.avgLux} lx<\/span>\r\n            <\/div>\r\n            <div>\r\n              <span class=\"text-[9px] text-slate-400 block\">E_min \/ max<\/span>\r\n              <span class=\"text-white\">${m.minLux} \/ ${m.maxLux}<\/span>\r\n            <\/div>\r\n            <div>\r\n              <span class=\"text-[9px] text-slate-400 block\">Uniformity (U0)<\/span>\r\n              <span class=\"text-white\">${m.uniformity}<\/span>\r\n            <\/div>\r\n          <\/div>\r\n        `;\r\n        container.appendChild(card);\r\n      });\r\n\r\n      updateFixtureListUI();\r\n    }\r\n\r\n    function updateFixtureListUI() {\r\n      const container = document.getElementById('fixtureListContainer');\r\n      container.innerHTML = '';\r\n\r\n      fixtures.forEach(fix => {\r\n        const isSelected = fix.id === selectedFixtureId;\r\n        const isOn = fix.enabled !== false;\r\n        const isLamp = fix.type === 'bedside';\r\n\r\n        const div = document.createElement('div');\r\n        div.className = `p-2 rounded-lg border text-xs flex items-center justify-between cursor-pointer transition ${\r\n          isSelected ? 'bg-amber-500\/20 border-amber-500\/60 text-amber-200' : 'bg-slate-900 border-slate-800 text-slate-300 hover:bg-slate-850'\r\n        }`;\r\n        div.onclick = () => selectFixture(fix.id);\r\n\r\n        div.innerHTML = `\r\n          <div class=\"flex items-center gap-2\">\r\n            <span class=\"w-5 h-5 rounded-full ${isOn ? (isLamp ? 'bg-amber-500\/30 text-amber-300 border-amber-400' : 'bg-slate-800 text-amber-300') : 'bg-slate-950 text-slate-600'} border border-slate-700 flex items-center justify-center font-mono text-[10px] font-bold\">\r\n              ${isLamp ? '<i class=\"fa-solid fa-lamp text-[9px]\"><\/i>' : fix.id}\r\n            <\/span>\r\n            <div>\r\n              <div class=\"font-medium text-white flex items-center gap-1.5\">\r\n                <span>${fix.name}<\/span>\r\n                ${isLamp ? '<span class=\"text-[9px] bg-amber-500\/25 text-amber-300 px-1 rounded font-normal\">Bedside<\/span>' : ''}\r\n              <\/div>\r\n              <div class=\"text-[10px] text-slate-400 font-mono\">${fix.watts}W \u00b7 ${fix.efficacy} lm\/W \u00b7 ${fix.beamAngle}\u00b0 \u00b7 ${fix.cct}K<\/div>\r\n            <\/div>\r\n          <\/div>\r\n          <div class=\"text-right font-mono text-[11px] ${isOn ? 'text-white' : 'text-slate-600'}\">\r\n            ${isOn ? (fix.watts * fix.efficacy) + ' lm' : 'OFF'}\r\n          <\/div>\r\n        `;\r\n        container.appendChild(div);\r\n      });\r\n    }\r\n\r\n    function selectFixture(id) {\r\n      selectedFixtureId = id;\r\n      const fix = fixtures.find(f => f.id === id);\r\n      const panel = document.getElementById('selectedFixturePanel');\r\n      const notice = document.getElementById('noSelectionNotice');\r\n\r\n      if (!fix) {\r\n        panel.classList.add('hidden');\r\n        notice.classList.remove('hidden');\r\n        renderScene();\r\n        return;\r\n      }\r\n\r\n      panel.classList.remove('hidden');\r\n      notice.classList.add('hidden');\r\n\r\n      const isBedside = fix.type === 'bedside';\r\n      document.getElementById('selectedFixtureTitle').innerHTML = `\r\n        <span>L${fix.id}: ${fix.name}<\/span>\r\n        ${isBedside ? '<span class=\"ml-1 text-[10px] bg-amber-500\/20 text-amber-300 px-1.5 py-0.5 rounded font-normal\">Bedside Table Lamp<\/span>' : ''}\r\n      `;\r\n\r\n      \/\/ Sync Wattage\r\n      document.getElementById('inputWattage').value = fix.watts;\r\n      document.getElementById('numWattage').value = fix.watts;\r\n\r\n      \/\/ Sync Editable Efficacy\r\n      document.getElementById('inputEfficacy').value = fix.efficacy;\r\n      document.getElementById('numEfficacy').value = fix.efficacy;\r\n\r\n      \/\/ Calculated Total Lumens & Peak Intensity\r\n      const lumens = fix.watts * fix.efficacy;\r\n      document.getElementById('valLumens').textContent = `${lumens.toLocaleString()} lm`;\r\n\r\n      const beamRad = (fix.beamAngle * Math.PI) \/ 180;\r\n      const halfAngle = beamRad \/ 2;\r\n      const solidAngle = Math.max(0.15, 2 * Math.PI * (1 - Math.cos(halfAngle)));\r\n      const cd = Math.round((lumens \/ solidAngle) * 0.95);\r\n      document.getElementById('valIntensity').textContent = `~${cd.toLocaleString()} cd`;\r\n\r\n      \/\/ Beam, CCT, Height\r\n      document.getElementById('valBeamAngle').textContent = `${fix.beamAngle}\u00b0`;\r\n      document.getElementById('valCCT').textContent = `${fix.cct}K`;\r\n      document.getElementById('inputHeight').value = fix.height;\r\n      document.getElementById('valHeight').textContent = `${fix.height} m`;\r\n\r\n      \/\/ Power toggle status\r\n      const pwrBtn = document.getElementById('toggleLightPowerBtn');\r\n      const isOn = fix.enabled !== false;\r\n      pwrBtn.innerHTML = `<i class=\"fa-solid fa-power-off text-xs ${isOn ? 'text-emerald-400' : 'text-slate-500'}\"><\/i>`;\r\n\r\n      document.querySelectorAll('.beam-btn').forEach(btn => {\r\n        if (btn.textContent.trim() === `${fix.beamAngle}\u00b0`) {\r\n          btn.className = 'beam-btn py-1 text-[11px] rounded bg-amber-600 text-white font-semibold';\r\n        } else {\r\n          btn.className = 'beam-btn py-1 text-[11px] rounded bg-slate-800 hover:bg-slate-700 text-slate-300';\r\n        }\r\n      });\r\n\r\n      renderScene();\r\n      updateMetricsUI();\r\n    }\r\n\r\n    function addNewFixture(type) {\r\n      let watts = 12, efficacy = 100, beamAngle = 60, cct = 3000, height = 2.8, name = 'Recessed Downlight';\r\n      let targetX = 350 + (Math.random() * 80 - 40);\r\n      let targetY = 490 + (Math.random() * 80 - 40);\r\n\r\n      if (type === 'bedside') {\r\n        watts = 5;\r\n        efficacy = 70;\r\n        beamAngle = 60;\r\n        cct = 2700;\r\n        height = 0.75;\r\n        name = 'Bedside Table Lamp';\r\n        targetX = 93 + (Math.random() * 20 - 10);\r\n        targetY = 126 + (Math.random() * 20 - 10);\r\n      } else if (type === 'spotlight') {\r\n        watts = 8;\r\n        efficacy = 85;\r\n        beamAngle = 24;\r\n        cct = 2700;\r\n        name = 'Accent Spotlight';\r\n      } else if (type === 'pendant') {\r\n        watts = 24;\r\n        efficacy = 95;\r\n        beamAngle = 90;\r\n        cct = 3000;\r\n        height = 2.4;\r\n        name = 'Dining Chandelier';\r\n      } else if (type === 'surface') {\r\n        watts = 18;\r\n        efficacy = 110;\r\n        beamAngle = 100;\r\n        cct = 4000;\r\n        height = 2.8;\r\n        name = 'Ceiling Flush Panel';\r\n      } else if (type === 'wallwasher') {\r\n        watts = 15;\r\n        efficacy = 120;\r\n        beamAngle = 120;\r\n        cct = 3000;\r\n        name = 'Linear Wall Washer';\r\n      }\r\n\r\n      const newF = {\r\n        id: nextFixtureId++,\r\n        type,\r\n        x: targetX,\r\n        y: targetY,\r\n        watts,\r\n        efficacy,\r\n        beamAngle,\r\n        cct,\r\n        height,\r\n        enabled: true,\r\n        name: `${name} ${nextFixtureId}`\r\n      };\r\n\r\n      fixtures.push(newF);\r\n      selectFixture(newF.id);\r\n    }\r\n\r\n    function setBeamAngle(angle) {\r\n      const fix = fixtures.find(f => f.id === selectedFixtureId);\r\n      if (!fix) return;\r\n      fix.beamAngle = angle;\r\n      selectFixture(fix.id);\r\n    }\r\n\r\n    function setCCT(kelvin) {\r\n      const fix = fixtures.find(f => f.id === selectedFixtureId);\r\n      if (!fix) return;\r\n      fix.cct = kelvin;\r\n      selectFixture(fix.id);\r\n    }\r\n\r\n    function getCanvasCoords(evt) {\r\n      if (!ensureCanvasContext()) return { x: 0, y: 0 };\r\n      const rect = canvas.getBoundingClientRect();\r\n      const clientX = evt.clientX || (evt.touches && evt.touches[0].clientX);\r\n      const clientY = evt.clientY || (evt.touches && evt.touches[0].clientY);\r\n      const scaleX = CANVAS_WIDTH \/ rect.width;\r\n      const scaleY = CANVAS_HEIGHT \/ rect.height;\r\n      return {\r\n        x: (clientX - rect.left) * scaleX,\r\n        y: (clientY - rect.top) * scaleY\r\n      };\r\n    }\r\n\r\n    function onPointerDown(e) {\r\n      const pos = getCanvasCoords(e);\r\n      for (let i = fixtures.length - 1; i >= 0; i--) {\r\n        const fix = fixtures[i];\r\n        if (Math.hypot(fix.x - pos.x, fix.y - pos.y) <= 24) {\r\n          isDragging = true;\r\n          draggedFixture = fix;\r\n          dragOffset.x = pos.x - fix.x;\r\n          dragOffset.y = pos.y - fix.y;\r\n          selectFixture(fix.id);\r\n          return;\r\n        }\r\n      }\r\n    }\r\n\r\n    function onPointerMove(e) {\r\n      const pos = getCanvasCoords(e);\r\n\r\n      if (isDragging && draggedFixture) {\r\n        draggedFixture.x = Math.max(75, Math.min(1125, pos.x - dragOffset.x));\r\n        draggedFixture.y = Math.max(75, Math.min(725, pos.y - dragOffset.y));\r\n        renderScene();\r\n        return;\r\n      }\r\n\r\n      const lux = calculateLuxAtPoint(pos.x, pos.y);\r\n      const room = getRoomForPoint(pos.x, pos.y);\r\n      document.getElementById('probeLuxValue').textContent = `${lux} lx`;\r\n      document.getElementById('probeRoom').textContent = room ? `${room.name}` : 'Outside Perimeter';\r\n    }\r\n\r\n    function onPointerUp() {\r\n      if (isDragging) {\r\n        isDragging = false;\r\n        draggedFixture = null;\r\n        renderScene();\r\n        updateMetricsUI();\r\n      }\r\n    }\r\n\r\n    function setupCanvasEventListeners() {\r\n      if (!ensureCanvasContext()) return;\r\n      canvas.addEventListener('mousedown', onPointerDown);\r\n      window.addEventListener('mousemove', onPointerMove);\r\n      window.addEventListener('mouseup', onPointerUp);\r\n\r\n      canvas.addEventListener('touchstart', (e) => { e.preventDefault(); onPointerDown(e); }, { passive: false });\r\n      window.addEventListener('touchmove', (e) => { onPointerMove(e); }, { passive: false });\r\n      window.addEventListener('touchend', onPointerUp);\r\n    }\r\n\r\n    function safeAddListener(id, event, handler) {\r\n      const el = document.getElementById(id);\r\n      if (el) el.addEventListener(event, handler);\r\n    }\r\n\r\n    function handleWattageChange(newWatts) {\r\n      const fix = fixtures.find(f => f.id === selectedFixtureId);\r\n      if (!fix) return;\r\n      fix.watts = Math.max(1, Math.min(200, parseInt(newWatts) || 1));\r\n      selectFixture(fix.id);\r\n    }\r\n\r\n    function handleEfficacyChange(newEff) {\r\n      const fix = fixtures.find(f => f.id === selectedFixtureId);\r\n      if (!fix) return;\r\n      fix.efficacy = Math.max(10, Math.min(300, parseInt(newEff) || 30));\r\n      selectFixture(fix.id);\r\n    }\r\n\r\n    function setupUIEventListeners() {\r\n      safeAddListener('inputWattage', 'input', (e) => handleWattageChange(e.target.value));\r\n      safeAddListener('numWattage', 'change', (e) => handleWattageChange(e.target.value));\r\n\r\n      safeAddListener('inputEfficacy', 'input', (e) => handleEfficacyChange(e.target.value));\r\n      safeAddListener('numEfficacy', 'change', (e) => handleEfficacyChange(e.target.value));\r\n\r\n      safeAddListener('inputHeight', 'input', (e) => {\r\n        const fix = fixtures.find(f => f.id === selectedFixtureId);\r\n        if (!fix) return;\r\n        fix.height = parseFloat(e.target.value);\r\n        const valH = document.getElementById('valHeight');\r\n        if (valH) valH.textContent = `${fix.height} m`;\r\n        renderScene();\r\n        updateMetricsUI();\r\n      });\r\n\r\n      safeAddListener('toggleLightPowerBtn', 'click', () => {\r\n        const fix = fixtures.find(f => f.id === selectedFixtureId);\r\n        if (!fix) return;\r\n        fix.enabled = (fix.enabled === false) ? true : false;\r\n        selectFixture(fix.id);\r\n      });\r\n\r\n      safeAddListener('deleteFixtureBtn', 'click', () => {\r\n        if (!selectedFixtureId) return;\r\n        fixtures = fixtures.filter(f => f.id !== selectedFixtureId);\r\n        selectedFixtureId = fixtures.length > 0 ? fixtures[0].id : null;\r\n        selectFixture(selectedFixtureId);\r\n        renderScene();\r\n        updateMetricsUI();\r\n      });\r\n\r\n      safeAddListener('presetSceneSelect', 'change', (e) => {\r\n        const val = e.target.value;\r\n        if (SCENE_PRESETS[val]) {\r\n          fixtures = JSON.parse(JSON.stringify(SCENE_PRESETS[val]));\r\n          nextFixtureId = 18;\r\n          selectFixture(fixtures[0].id);\r\n        }\r\n      });\r\n\r\n      safeAddListener('viewRealisticBtn', 'click', () => {\r\n        viewMode = 'realistic';\r\n        const rBtn = document.getElementById('viewRealisticBtn');\r\n        const hBtn = document.getElementById('viewHeatmapBtn');\r\n        const leg = document.getElementById('heatmapLegendBar');\r\n        if (rBtn) rBtn.className = 'px-3 py-1.5 rounded-md font-medium transition flex items-center gap-1.5 bg-slate-800 text-amber-300 shadow-sm';\r\n        if (hBtn) hBtn.className = 'px-3 py-1.5 rounded-md font-medium text-slate-400 hover:text-white transition flex items-center gap-1.5';\r\n        if (leg) leg.classList.add('hidden');\r\n        renderScene();\r\n      });\r\n\r\n      safeAddListener('viewHeatmapBtn', 'click', () => {\r\n        viewMode = 'heatmap';\r\n        const hBtn = document.getElementById('viewHeatmapBtn');\r\n        const rBtn = document.getElementById('viewRealisticBtn');\r\n        const leg = document.getElementById('heatmapLegendBar');\r\n        if (hBtn) hBtn.className = 'px-3 py-1.5 rounded-md font-medium transition flex items-center gap-1.5 bg-amber-600 text-white shadow-sm';\r\n        if (rBtn) rBtn.className = 'px-3 py-1.5 rounded-md font-medium text-slate-400 hover:text-white transition flex items-center gap-1.5';\r\n        if (leg) leg.classList.remove('hidden');\r\n        renderScene();\r\n      });\r\n\r\n      safeAddListener('toggleIsoluxBtn', 'click', () => {\r\n        showIsolux = !showIsolux;\r\n        const btn = document.getElementById('toggleIsoluxBtn');\r\n        if (btn) {\r\n          btn.className = showIsolux\r\n            ? 'px-2.5 py-1.5 rounded-lg bg-amber-500\/20 text-amber-300 border border-amber-500\/50 transition flex items-center gap-1.5 font-medium'\r\n            : 'px-2.5 py-1.5 rounded-lg bg-slate-900 text-slate-400 border border-slate-800 transition flex items-center gap-1.5';\r\n        }\r\n        renderScene();\r\n      });\r\n\r\n      safeAddListener('toggleFurnitureBtn', 'click', () => {\r\n        showFurniture = !showFurniture;\r\n        const btn = document.getElementById('toggleFurnitureBtn');\r\n        if (btn) btn.classList.toggle('text-amber-400', showFurniture);\r\n        renderScene();\r\n      });\r\n\r\n      safeAddListener('toggleGridBtn', 'click', () => {\r\n        showGrid = !showGrid;\r\n        const btn = document.getElementById('toggleGridBtn');\r\n        if (btn) btn.classList.toggle('text-amber-400', showGrid);\r\n        renderScene();\r\n      });\r\n\r\n      safeAddListener('tabFixturesBtn', 'click', () => {\r\n        const fBtn = document.getElementById('tabFixturesBtn');\r\n        const rBtn = document.getElementById('tabRoomsBtn');\r\n        const fTab = document.getElementById('tabContentFixtures');\r\n        const rTab = document.getElementById('tabContentRooms');\r\n        if (fBtn) fBtn.className = 'flex-1 py-2 font-medium rounded-md text-amber-300 bg-slate-900 flex items-center justify-center gap-2 shadow-sm border border-slate-800';\r\n        if (rBtn) rBtn.className = 'flex-1 py-2 font-medium rounded-md text-slate-400 hover:text-white flex items-center justify-center gap-2';\r\n        if (fTab) fTab.classList.remove('hidden');\r\n        if (rTab) rTab.classList.add('hidden');\r\n      });\r\n\r\n      safeAddListener('tabRoomsBtn', 'click', () => {\r\n        const rBtn = document.getElementById('tabRoomsBtn');\r\n        const fBtn = document.getElementById('tabFixturesBtn');\r\n        const rTab = document.getElementById('tabContentRooms');\r\n        const fTab = document.getElementById('tabContentFixtures');\r\n        if (rBtn) rBtn.className = 'flex-1 py-2 font-medium rounded-md text-amber-300 bg-slate-900 flex items-center justify-center gap-2 shadow-sm border border-slate-800';\r\n        if (fBtn) fBtn.className = 'flex-1 py-2 font-medium rounded-md text-slate-400 hover:text-white flex items-center justify-center gap-2';\r\n        if (rTab) rTab.classList.remove('hidden');\r\n        if (fTab) fTab.classList.add('hidden');\r\n        updateMetricsUI();\r\n      });\r\n\r\n      safeAddListener('exportPdfBtn', 'click', exportPdfHandler);\r\n    }\r\n\r\n    async function exportPdfHandler() {\r\n      const btn = document.getElementById('exportPdfBtn');\r\n      if (!btn) return;\r\n      const originalHTML = btn.innerHTML;\r\n      btn.innerHTML = `<i class=\"fa-solid fa-spinner fa-spin\"><\/i> Generating PDF...`;\r\n      btn.disabled = true;\r\n\r\n      try {\r\n        const { jsPDF } = window.jspdf || {};\r\n        if (!jsPDF) return;\r\n\r\n        const metrics = calculateRoomMetrics();\r\n        const exportContainer = document.getElementById('pdfExportContainer');\r\n\r\n        const dateEl = document.getElementById('reportDate');\r\n        if (dateEl) {\r\n          dateEl.textContent = new Date().toLocaleDateString('en-US', {\r\n            year: 'numeric', month: 'short', day: 'numeric'\r\n          });\r\n        }\r\n\r\n        const imgContainer = document.getElementById('pdfCanvasImageContainer');\r\n        if (imgContainer && canvas) {\r\n          imgContainer.innerHTML = '';\r\n          const img = document.createElement('img');\r\n          img.src = canvas.toDataURL('image\/png');\r\n          img.className = 'w-full h-full object-contain';\r\n          imgContainer.appendChild(img);\r\n        }\r\n\r\n        const roomTbody = document.getElementById('pdfRoomTableBody');\r\n        if (roomTbody) {\r\n          roomTbody.innerHTML = '';\r\n          Object.keys(metrics).forEach(k => {\r\n            const m = metrics[k];\r\n            const tr = document.createElement('tr');\r\n            tr.className = 'border-b border-slate-800';\r\n            tr.innerHTML = `\r\n              <td class=\"p-2 font-medium text-white border-r border-slate-800\">${m.name}<\/td>\r\n              <td class=\"p-2 border-r border-slate-800 font-mono text-slate-300\">${m.targetMin}-${m.targetMax} lx<\/td>\r\n              <td class=\"p-2 border-r border-slate-800 font-mono font-bold text-amber-300\">${m.avgLux} lx<\/td>\r\n              <td class=\"p-2 border-r border-slate-800 font-mono text-slate-300\">${m.minLux}<\/td>\r\n              <td class=\"p-2 border-r border-slate-800 font-mono text-slate-300\">${m.maxLux}<\/td>\r\n              <td class=\"p-2 border-r border-slate-800 font-mono text-slate-300\">${m.uniformity}<\/td>\r\n              <td class=\"p-2 font-bold ${m.isCompliant ? 'text-emerald-400' : 'text-amber-400'}\">\r\n                ${m.isCompliant ? 'PASSED' : 'LOW LUX'}\r\n              <\/td>\r\n            `;\r\n            roomTbody.appendChild(tr);\r\n          });\r\n        }\r\n\r\n        const fixTbody = document.getElementById('pdfFixtureTableBody');\r\n        if (fixTbody) {\r\n          fixTbody.innerHTML = '';\r\n          fixtures.forEach(f => {\r\n            const tr = document.createElement('tr');\r\n            tr.className = 'border-b border-slate-800';\r\n            tr.innerHTML = `\r\n              <td class=\"p-2 font-mono font-bold border-r border-slate-800 text-amber-300\">L${f.id}<\/td>\r\n              <td class=\"p-2 border-r border-slate-800 text-white\">${f.name}<\/td>\r\n              <td class=\"p-2 border-r border-slate-800 font-mono text-slate-300\">${f.watts} W<\/td>\r\n              <td class=\"p-2 border-r border-slate-800 font-mono text-slate-300\">${f.efficacy} lm\/W<\/td>\r\n              <td class=\"p-2 border-r border-slate-800 font-mono font-bold text-emerald-400\">${f.watts * f.efficacy} lm<\/td>\r\n              <td class=\"p-2 border-r border-slate-800 font-mono text-slate-300\">${f.beamAngle}\u00b0<\/td>\r\n              <td class=\"p-2 border-r border-slate-800 font-mono text-slate-300\">${f.cct}K<\/td>\r\n              <td class=\"p-2 font-mono text-slate-300\">${f.height}m<\/td>\r\n            `;\r\n            fixTbody.appendChild(tr);\r\n          });\r\n        }\r\n\r\n        if (exportContainer) {\r\n          exportContainer.classList.remove('hidden');\r\n          const renderedCanvas = await html2canvas(exportContainer, {\r\n            scale: 2,\r\n            useCORS: true,\r\n            backgroundColor: '#020617'\r\n          });\r\n          exportContainer.classList.add('hidden');\r\n\r\n          const pdf = new jsPDF('p', 'mm', 'a4');\r\n          const imgData = renderedCanvas.toDataURL('image\/jpeg', 0.95);\r\n          const pdfWidth = pdf.internal.pageSize.getWidth();\r\n          const pdfHeight = (renderedCanvas.height * pdfWidth) \/ renderedCanvas.width;\r\n\r\n          pdf.addImage(imgData, 'JPEG', 0, 0, pdfWidth, pdfHeight);\r\n          pdf.save(`DIALux_Lighting_Report_${Date.now()}.pdf`);\r\n        }\r\n\r\n      } catch (err) {\r\n        console.error('PDF generation error:', err);\r\n      } finally {\r\n        btn.innerHTML = originalHTML;\r\n        btn.disabled = false;\r\n      }\r\n    }\r\n\r\n    function initializeApp() {\r\n      if (!ensureCanvasContext()) {\r\n        setTimeout(initializeApp, 50);\r\n        return;\r\n      }\r\n      setupCanvasEventListeners();\r\n      setupUIEventListeners();\r\n      resizeCanvas();\r\n      selectFixture(5); \/\/ Default focus on bedside lamp\r\n      updateMetricsUI();\r\n    }\r\n\r\n    if (document.readyState === 'loading') {\r\n      document.addEventListener('DOMContentLoaded', initializeApp);\r\n    } else {\r\n      initializeApp();\r\n    }\r\n\r\n    window.addEventListener('resize', () => {\r\n      resizeCanvas();\r\n    });\r\n  <\/script>\r\n<\/body>\r\n<\/html>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>","protected":false},"excerpt":{"rendered":"<p>DIALux Architectural Lighting Simulator &#038; Lux Calculator DIALux Lighting Simulator CIE \/ EN 12464-1 Architectural Photometric Engine \u00b7 2BHK Layout \u00b7 Workplane (0.8m AFF) Luminaires: 10 Connected Load: 109 W Total Flux: 10,540 lm Preset: Balanced Architectural (Default)Preset: Warm &#038; Intimate 2700KPreset: High Lux Work Task 4000K PDF Report Realistic Render DIALux False Color Isolux [&hellip;]<\/p>","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"_acf_changed":false,"footnotes":""},"class_list":["post-15371","page","type-page","status-publish","hentry"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v27.6 (Yoast SEO v28.5) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Elementor #15371 - Hondel Lighting Limited<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/hondellighting.com\/ar\/elementor-15371.html\/\" \/>\n<meta property=\"og:locale\" content=\"ar_AR\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Elementor #15371\" \/>\n<meta property=\"og:description\" content=\"DIALux Architectural Lighting Simulator &#038; Lux Calculator DIALux Lighting Simulator CIE \/ EN 12464-1 Architectural Photometric Engine \u00b7 2BHK Layout \u00b7 Workplane (0.8m AFF) Luminaires: 10 Connected Load: 109 W Total Flux: 10,540 lm Preset: Balanced Architectural (Default)Preset: Warm &#038; Intimate 2700KPreset: High Lux Work Task 4000K PDF Report Realistic Render DIALux False Color Isolux [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/hondellighting.com\/ar\/elementor-15371.html\/\" \/>\n<meta property=\"og:site_name\" content=\"Hondel Lighting Limited\" \/>\n<meta property=\"article:modified_time\" content=\"2026-10-17T03:51:54+00:00\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"\u0648\u0642\u062a \u0627\u0644\u0642\u0631\u0627\u0621\u0629 \u0627\u0644\u0645\u064f\u0642\u062f\u0651\u0631\" \/>\n\t<meta name=\"twitter:data1\" content=\"\u062f\u0642\u064a\u0642\u062a\u0627\u0646\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/hondellighting.com\\\/elementor-15371.html\",\"url\":\"https:\\\/\\\/hondellighting.com\\\/elementor-15371.html\",\"name\":\"Elementor #15371 - Hondel Lighting Limited\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/hondellighting.com\\\/#website\"},\"datePublished\":\"2026-10-17T02:57:26+00:00\",\"dateModified\":\"2026-10-17T03:51:54+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/hondellighting.com\\\/elementor-15371.html#breadcrumb\"},\"inLanguage\":\"ar\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/hondellighting.com\\\/elementor-15371.html\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/hondellighting.com\\\/elementor-15371.html#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/hondellighting.com\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Elementor #15371\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/hondellighting.com\\\/#website\",\"url\":\"https:\\\/\\\/hondellighting.com\\\/\",\"name\":\"Hondel Lighting\",\"description\":\"Facade Lighting Manufacturer\",\"publisher\":{\"@id\":\"https:\\\/\\\/hondellighting.com\\\/#organization\"},\"alternateName\":\"Hondel\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/hondellighting.com\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"ar\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/hondellighting.com\\\/#organization\",\"name\":\"Hondel Lighting Limited\",\"url\":\"https:\\\/\\\/hondellighting.com\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"ar\",\"@id\":\"https:\\\/\\\/hondellighting.com\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/hondellighting.com\\\/wp-content\\\/uploads\\\/2023\\\/10\\\/hondel-logo-black-png.png\",\"contentUrl\":\"https:\\\/\\\/hondellighting.com\\\/wp-content\\\/uploads\\\/2023\\\/10\\\/hondel-logo-black-png.png\",\"width\":86,\"height\":40,\"caption\":\"Hondel Lighting Limited\"},\"image\":{\"@id\":\"https:\\\/\\\/hondellighting.com\\\/#\\\/schema\\\/logo\\\/image\\\/\"}}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Elementor #15371 - Hondel Lighting Limited","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/hondellighting.com\/ar\/elementor-15371.html\/","og_locale":"ar_AR","og_type":"article","og_title":"Elementor #15371","og_description":"DIALux Architectural Lighting Simulator &#038; Lux Calculator DIALux Lighting Simulator CIE \/ EN 12464-1 Architectural Photometric Engine \u00b7 2BHK Layout \u00b7 Workplane (0.8m AFF) Luminaires: 10 Connected Load: 109 W Total Flux: 10,540 lm Preset: Balanced Architectural (Default)Preset: Warm &#038; Intimate 2700KPreset: High Lux Work Task 4000K PDF Report Realistic Render DIALux False Color Isolux [&hellip;]","og_url":"https:\/\/hondellighting.com\/ar\/elementor-15371.html\/","og_site_name":"Hondel Lighting Limited","article_modified_time":"2026-10-17T03:51:54+00:00","twitter_card":"summary_large_image","twitter_misc":{"\u0648\u0642\u062a \u0627\u0644\u0642\u0631\u0627\u0621\u0629 \u0627\u0644\u0645\u064f\u0642\u062f\u0651\u0631":"\u062f\u0642\u064a\u0642\u062a\u0627\u0646"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/hondellighting.com\/elementor-15371.html","url":"https:\/\/hondellighting.com\/elementor-15371.html","name":"Elementor #15371 - Hondel Lighting Limited","isPartOf":{"@id":"https:\/\/hondellighting.com\/#website"},"datePublished":"2026-10-17T02:57:26+00:00","dateModified":"2026-10-17T03:51:54+00:00","breadcrumb":{"@id":"https:\/\/hondellighting.com\/elementor-15371.html#breadcrumb"},"inLanguage":"ar","potentialAction":[{"@type":"ReadAction","target":["https:\/\/hondellighting.com\/elementor-15371.html"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/hondellighting.com\/elementor-15371.html#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/hondellighting.com\/"},{"@type":"ListItem","position":2,"name":"Elementor #15371"}]},{"@type":"WebSite","@id":"https:\/\/hondellighting.com\/#website","url":"https:\/\/hondellighting.com\/","name":"Hondel Lighting","description":"Facade Lighting Manufacturer","publisher":{"@id":"https:\/\/hondellighting.com\/#organization"},"alternateName":"Hondel","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/hondellighting.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"ar"},{"@type":"Organization","@id":"https:\/\/hondellighting.com\/#organization","name":"Hondel Lighting Limited","url":"https:\/\/hondellighting.com\/","logo":{"@type":"ImageObject","inLanguage":"ar","@id":"https:\/\/hondellighting.com\/#\/schema\/logo\/image\/","url":"https:\/\/hondellighting.com\/wp-content\/uploads\/2023\/10\/hondel-logo-black-png.png","contentUrl":"https:\/\/hondellighting.com\/wp-content\/uploads\/2023\/10\/hondel-logo-black-png.png","width":86,"height":40,"caption":"Hondel Lighting Limited"},"image":{"@id":"https:\/\/hondellighting.com\/#\/schema\/logo\/image\/"}}]}},"_links":{"self":[{"href":"https:\/\/hondellighting.com\/ar\/wp-json\/wp\/v2\/pages\/15371","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/hondellighting.com\/ar\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/hondellighting.com\/ar\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/hondellighting.com\/ar\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/hondellighting.com\/ar\/wp-json\/wp\/v2\/comments?post=15371"}],"version-history":[{"count":8,"href":"https:\/\/hondellighting.com\/ar\/wp-json\/wp\/v2\/pages\/15371\/revisions"}],"predecessor-version":[{"id":15380,"href":"https:\/\/hondellighting.com\/ar\/wp-json\/wp\/v2\/pages\/15371\/revisions\/15380"}],"wp:attachment":[{"href":"https:\/\/hondellighting.com\/ar\/wp-json\/wp\/v2\/media?parent=15371"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}