{"id":13788,"date":"2025-11-25T19:42:09","date_gmt":"2025-11-25T19:42:09","guid":{"rendered":"https:\/\/lumepix.eu\/?page_id=13788"},"modified":"2026-03-24T11:04:48","modified_gmt":"2026-03-24T11:04:48","slug":"aluspinna-moodu-tooriist","status":"publish","type":"page","link":"https:\/\/lumepix.eu\/en\/aluspinna-moodu-tooriist\/","title":{"rendered":"Aluspinna m\u00f5\u00f5du t\u00f6\u00f6riist"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-page\" data-elementor-id=\"13788\" class=\"elementor elementor-13788\">\n\t\t\t\t<div class=\"elementor-element elementor-element-b80db28 e-flex e-con-boxed e-con e-parent\" data-id=\"b80db28\" 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-3bb3193 elementor-widget elementor-widget-html\" data-id=\"3bb3193\" 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=\"et\">\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>Ekraani t\u00fc\u00fcbi ja suuruse valimise t\u00f6\u00f6riist<\/title>\r\n<\/head>\r\n<body>\r\n\r\n<section class=\"lp-tools\">\r\n\r\n  <!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\r\n       P\u00c4IS\r\n  \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\r\n  <div class=\"lp-tools-header\">\r\n    <div class=\"lp-tools-logo\">\r\n      <span class=\"lp-tools-logo-text\">Ekraani t\u00fc\u00fcbi ja suuruse valimise t\u00f6\u00f6riist<\/span>\r\n    <\/div>\r\n    <p class=\"lp-tools-intro\">\r\n      Sobiva ekraani m\u00f5\u00f5du ja tehnoloogia valimine t\u00f6\u00f6- ja \u00e4rikeskkonda aitab planeerida Lumepix-i loodud t\u00f6\u00f6riist. T\u00f6ida vajalikud lahtrid ja saada tulemus endale E-mailile. \r\n    <\/p>\r\n  <\/div>\r\n\r\n  <!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\r\n       VIISARD \u2013 SAMMUDE INDIKAATOR\r\n  \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\r\n  <div class=\"lp-wizard-bar\">\r\n    <div class=\"lp-wizard-step lp-ws-active\" id=\"ws-1\">\r\n      <div class=\"lp-ws-num\">1<\/div>\r\n      <div class=\"lp-ws-label\">Keskkond &amp; kaugus<\/div>\r\n    <\/div>\r\n    <div class=\"lp-wizard-connector\"><\/div>\r\n    <div class=\"lp-wizard-step\" id=\"ws-2\">\r\n      <div class=\"lp-ws-num\">2<\/div>\r\n      <div class=\"lp-ws-label\">M\u00f5\u00f5dud &amp; pitch<\/div>\r\n    <\/div>\r\n    <div class=\"lp-wizard-connector\"><\/div>\r\n    <div class=\"lp-wizard-step\" id=\"ws-3\">\r\n      <div class=\"lp-ws-num\">3<\/div>\r\n      <div class=\"lp-ws-label\">Tulemused<\/div>\r\n    <\/div>\r\n  <\/div>\r\n\r\n  <!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\r\n       EELSEADISTUSED\r\n  \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\r\n  <div class=\"lp-presets\" id=\"lp-presets\">\r\n    <p class=\"lp-presets-label\">Kiirstart \u2013 vali kasutusala:<\/p>\r\n    <div class=\"lp-presets-row\">\r\n      <button class=\"lp-preset-btn\" data-preset=\"mall\">\r\n        <span class=\"lp-preset-icon\">\ud83c\udfec<\/span>\r\n        <span>Kaubanduskeskus<\/span>\r\n      <\/button>\r\n      <button class=\"lp-preset-btn\" data-preset=\"conf\">\r\n        <span class=\"lp-preset-icon\">\ud83c\udfa4<\/span>\r\n        <span>Konverentsisaal<\/span>\r\n      <\/button>\r\n      <button class=\"lp-preset-btn\" data-preset=\"confsmall\">\r\n        <span class=\"lp-preset-icon\">\ud83d\udccb<\/span>\r\n        <span>Koosolekuruum<\/span>\r\n      <\/button>\r\n      <button class=\"lp-preset-btn\" data-preset=\"outdoor\">\r\n        <span class=\"lp-preset-icon\">\ud83c\udf06<\/span>\r\n        <span>V\u00e4lireklaam<\/span>\r\n      <\/button>\r\n      <button class=\"lp-preset-btn\" data-preset=\"resto\">\r\n        <span class=\"lp-preset-icon\">\ud83c\udf7d\ufe0f<\/span>\r\n        <span>Restoran \/ men\u00fc\u00fctahvel<\/span>\r\n      <\/button>\r\n    <\/div>\r\n  <\/div>\r\n\r\n  <!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\r\n       SAMM 1 \u2013 KESKKOND & KAUGUS\r\n  \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\r\n  <div class=\"lp-tool-card lp-step\" id=\"step-1\">\r\n    <h2 class=\"lp-tool-title\">Samm 1 \u2013 M\u00e4\u00e4ra  keskkond ja vaatekaugus<\/h2>\r\n\r\n    <!-- Pikslisammu visuaal -->\r\n    <div class=\"pp-view-visual\" id=\"pp-visual-avixa\">\r\n      <div class=\"pp-view-screen\">\r\n        <div class=\"pp-view-screen-inner\">\r\n          <div class=\"pp-view-art\">\r\n            <span class=\"pp-art-bar pp-art-bar-1\"><\/span>\r\n            <span class=\"pp-art-bar pp-art-bar-2\"><\/span>\r\n            <span class=\"pp-art-bar pp-art-bar-3\"><\/span>\r\n            <span class=\"pp-art-dot\"><\/span>\r\n          <\/div>\r\n        <\/div>\r\n        <span class=\"pp-view-screen-label\">Ekraan<\/span>\r\n      <\/div>\r\n      <div class=\"pp-view-ground\">\r\n        <div class=\"pp-view-ground-line\">\r\n          <div class=\"pp-view-distance-line\" id=\"pp-distance-line-avixa\"><\/div>\r\n          <div class=\"pp-view-person\" id=\"pp-person-avixa\">\r\n            <div class=\"pp-view-person-inner\">\r\n              <div class=\"pp-view-head\"><\/div>\r\n              <div class=\"pp-view-body\"><\/div>\r\n            <\/div>\r\n          <\/div>\r\n        <\/div>\r\n        <div class=\"pp-view-scale\" id=\"pp-scale-avixa\"><\/div>\r\n      <\/div>\r\n      <div class=\"pp-view-distance-label\" id=\"pp-distance-label-avixa\">0,0 m<\/div>\r\n    <\/div>\r\n\r\n    <form class=\"lp-form lp-form-pitch\" id=\"lp-pitch-form-avixa\">\r\n      <div class=\"lp-form-row\">\r\n        <label for=\"view-distance-avixa\">Vaatekaugus (m)<\/label>\r\n        <input type=\"number\" id=\"view-distance-avixa\" min=\"0.5\" step=\"0.1\" placeholder=\"nt 7\">\r\n      <\/div>\r\n      <div class=\"lp-form-row\">\r\n        <label for=\"content-type-avixa\">Sisu t\u00fc\u00fcp<\/label>\r\n        <select id=\"content-type-avixa\">\r\n          <option value=\"detail\">Detailne sisu (Excel, CAD, v\u00e4ike tekst)<\/option>\r\n          <option value=\"mix\">Reklaamsisu \u2013 pilt\/video\/suurem tekst<\/option>\r\n          <option value=\"branding\">Visuaalne taust &amp; br\u00e4nding (suured s\u00fcmbolid)<\/option>\r\n        <\/select>\r\n      <\/div>\r\n      <div class=\"lp-form-row\">\r\n        <label for=\"env-type-avixa\">Keskkonna heledus<\/label>\r\n        <select id=\"env-type-avixa\">\r\n          <option value=\"indoor-normal\">Sisekeskkond<\/option>\r\n          <option value=\"indoor-bright\">Tugevalt valgustatud ruum v\u00f5i v\u00e4lja suunatud<\/option>\r\n          <option value=\"outdoor\">V\u00e4litingimused<\/option>\r\n        <\/select>\r\n      <\/div>\r\n      <div class=\"lp-form-row lp-form-row-button\">\r\n        <label class=\"lp-label-hidden\">&nbsp;<\/label>\r\n        <button type=\"submit\" class=\"lp-btn\">EDASI \u2192<\/button>\r\n      <\/div>\r\n    <\/form>\r\n\r\n    <div class=\"lp-result lp-result-hidden\" id=\"lp-pitch-result-avixa\"><\/div>\r\n  <\/div>\r\n\r\n  <!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\r\n       SAMM 2 \u2013 M\u00d5\u00d5DUD & PITCH\r\n  \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\r\n  <div class=\"lp-tool-card lp-step lp-step-locked\" id=\"step-2\">\r\n    <h2 class=\"lp-tool-title\">Samm 2 \u2013 Maksimaalne ekraani kasutatav m\u00f5\u00f5t <\/h2>\r\n\r\n    <form class=\"lp-form lp-form-size\" id=\"lp-size-form\">\r\n      <div class=\"lp-form-row\">\r\n        <label for=\"base-width\">Aluspinna laius (mm)<\/label>\r\n        <input type=\"number\" id=\"base-width\" min=\"100\" step=\"1\" placeholder=\"nt 1200\">\r\n      <\/div>\r\n      <div class=\"lp-form-row\">\r\n        <label for=\"base-height\">Aluspinna k\u00f5rgus (mm)<\/label>\r\n        <input type=\"number\" id=\"base-height\" min=\"100\" step=\"1\" placeholder=\"nt 1900\">\r\n      <\/div>\r\n      <div class=\"lp-form-row\">\r\n        <label for=\"env\">Keskkond<\/label>\r\n        <select id=\"env\">\r\n          <option value=\"indoor\">Siseruum (indoor)<\/option>\r\n          <option value=\"outdoor\">V\u00e4litingimused (outdoor)<\/option>\r\n        <\/select>\r\n      <\/div>\r\n      <div class=\"lp-form-row\">\r\n        <label for=\"led-pitch\">LED pixel pitch<\/label>\r\n        <select id=\"led-pitch\"><\/select>\r\n      <\/div>\r\n      <div class=\"lp-form-row\">\r\n        <label for=\"lcd-orient\">LCD orientatsioon<\/label>\r\n        <select id=\"lcd-orient\">\r\n          <option value=\"auto\">Automaatne<\/option>\r\n          <option value=\"portrait\">Portree (vertikaalne)<\/option>\r\n          <option value=\"landscape\">Maastik (horisontaalne)<\/option>\r\n        <\/select>\r\n      <\/div>\r\n      <div class=\"lp-form-row lp-form-row-button\">\r\n        <label class=\"lp-label-hidden\">&nbsp;<\/label>\r\n        <button type=\"submit\" class=\"lp-btn\">ARVUTA \u2192<\/button>\r\n      <\/div>\r\n    <\/form>\r\n  <\/div>\r\n\r\n  <!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\r\n       SAMM 3 \u2013 TULEMUSED\r\n  \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\r\n  <div class=\"lp-tool-card lp-step lp-step-locked\" id=\"step-3\">\r\n    <h2 class=\"lp-tool-title\">Samm 3 \u2013 Tulemused ja lahendused<\/h2>\r\n\r\n    <!-- Visuaalne v\u00f5rdlus -->\r\n    <div class=\"lp-visual-wrapper\">\r\n      <div class=\"lp-visual-header\">\r\n        <span>Visuaalne v\u00f5rdlus<\/span>\r\n        <span class=\"lp-visual-legend\">\r\n          <span class=\"lp-leg lp-leg-base\"><\/span> aluspind\r\n          <span class=\"lp-leg lp-leg-led\"><\/span> LED\r\n          <span class=\"lp-leg lp-leg-lcd\"><\/span> LCD\r\n          <span class=\"lp-leg lp-leg-wall\"><\/span> LCD videosein\r\n        <\/span>\r\n      <\/div>\r\n      <div class=\"lp-visual-inner\" id=\"lp-visual-inner\">\r\n        <div class=\"lp-visual-base\" id=\"vis-base\"><\/div>\r\n        <div class=\"lp-visual-led\"  id=\"vis-led\"><\/div>\r\n        <div class=\"lp-visual-lcd\"  id=\"vis-lcd\"><\/div>\r\n        <div class=\"lp-visual-wall\" id=\"vis-wall\"><\/div>\r\n      <\/div>\r\n      <div class=\"lp-visual-toggles-row\">\r\n        <label class=\"lp-toggle-big\" for=\"toggle-led\">\r\n          <input type=\"checkbox\" id=\"toggle-led\" class=\"lp-cb\" checked>\r\n          <span class=\"lp-cb-box\" aria-hidden=\"true\"><\/span>\r\n          <span class=\"lp-cb-label\">LED ekraan<\/span>\r\n        <\/label>\r\n        <label class=\"lp-toggle-big\" for=\"toggle-lcd\">\r\n          <input type=\"checkbox\" id=\"toggle-lcd\" class=\"lp-cb\" checked>\r\n          <span class=\"lp-cb-box\" aria-hidden=\"true\"><\/span>\r\n          <span class=\"lp-cb-label\">LCD ekraan<\/span>\r\n        <\/label>\r\n        <label class=\"lp-toggle-big\" for=\"toggle-wall\">\r\n          <input type=\"checkbox\" id=\"toggle-wall\" class=\"lp-cb\">\r\n          <span class=\"lp-cb-box\" aria-hidden=\"true\"><\/span>\r\n          <span class=\"lp-cb-label\">LCD videosein<\/span>\r\n        <\/label>\r\n      <\/div>\r\n    <\/div>\r\n\r\n    <!-- Tekstilised tulemused -->\r\n    <div class=\"lp-result lp-result-hidden\" id=\"lp-size-result\"><\/div>\r\n\r\n    <!-- \u2500\u2500 RUUMIPLAAN \u2500\u2500 -->\r\n    <div class=\"lp-room-section lp-result-hidden\" id=\"lp-room-section\">\r\n      <h3 class=\"lp-section-subtitle\">Ruumiplaan ja n\u00e4htavustsoon <span style=\"font-size:11px;font-weight:400;color:#9ca3af;\">(valikuline)<\/span><\/h3>\r\n      <div class=\"lp-room-inputs\">\r\n        <div class=\"lp-form-row\">\r\n          <label for=\"room-w\">Ruumi laius (m)<\/label>\r\n          <input type=\"number\" id=\"room-w\" min=\"1\" step=\"0.5\" placeholder=\"nt 12\">\r\n        <\/div>\r\n        <div class=\"lp-form-row\">\r\n          <label for=\"room-d\">Ruumi s\u00fcgavus \/ pikkus (m)<\/label>\r\n          <input type=\"number\" id=\"room-d\" min=\"1\" step=\"0.5\" placeholder=\"nt 20\">\r\n        <\/div>\r\n        <div class=\"lp-form-row\">\r\n          <label for=\"room-h\">Ekraani alumine serv p\u00f5randast (m)<\/label>\r\n          <input type=\"number\" id=\"room-h\" min=\"0\" step=\"0.1\" placeholder=\"nt 1.2\">\r\n        <\/div>\r\n        <div class=\"lp-form-row lp-form-row-button\">\r\n          <label class=\"lp-label-hidden\">&nbsp;<\/label>\r\n          <button type=\"button\" class=\"lp-btn lp-btn-secondary\" id=\"btn-room\">KUVA PLAAN<\/button>\r\n        <\/div>\r\n      <\/div>\r\n      <canvas id=\"lp-room-canvas\" class=\"lp-room-canvas\"><\/canvas>\r\n      <div class=\"lp-visual-toggles-row\" style=\"margin-top:10px;\">\r\n        <label class=\"lp-toggle-big\" for=\"toggle-30deg\">\r\n          <input type=\"checkbox\" id=\"toggle-30deg\" class=\"lp-cb\">\r\n          <span class=\"lp-cb-box\" aria-hidden=\"true\"><\/span>\r\n          <span class=\"lp-cb-label\">30\u00b0 vaatenurk<\/span>\r\n        <\/label>\r\n        <label class=\"lp-toggle-big\" for=\"toggle-45deg\">\r\n          <input type=\"checkbox\" id=\"toggle-45deg\" class=\"lp-cb\">\r\n          <span class=\"lp-cb-box\" aria-hidden=\"true\"><\/span>\r\n          <span class=\"lp-cb-label\">45\u00b0 vaatenurk<\/span>\r\n        <\/label>\r\n        <label class=\"lp-toggle-big\" for=\"toggle-60deg\">\r\n          <input type=\"checkbox\" id=\"toggle-60deg\" class=\"lp-cb\" checked>\r\n          <span class=\"lp-cb-box\" aria-hidden=\"true\"><\/span>\r\n          <span class=\"lp-cb-label\">DISCAS 60\u00b0<\/span>\r\n        <\/label>\r\n      <\/div>\r\n      <p class=\"lp-room-hint\" id=\"lp-room-hint\"><\/p>\r\n    <\/div>\r\n\r\n    <!-- \u2500\u2500 KONTAKTVORM + PDF \u2500\u2500 -->\r\n    <div class=\"lp-export-section lp-result-hidden\" id=\"lp-export-section\">\r\n      <h3 class=\"lp-section-subtitle\">Saada tulemused ja lae alla PDF<\/h3>\r\n      <p class=\"lp-export-note\">T\u00e4ida vorm \u2013 Lumepix saab sinu p\u00e4ringu ja brauser laadib PDF-kokkuv\u00f5tte alla automaatselt.<\/p>\r\n\r\n      <!-- Peidetud CF7 andmev\u00e4ljad \u2013 t\u00e4idetakse JS-ga automaatselt -->\r\n      <form id=\"lp-cf7-form\" class=\"lp-cf7-wrap\" novalidate>\r\n        <input type=\"hidden\" name=\"_wpcf7\"              value=\"14410\">\r\n        <input type=\"hidden\" name=\"_wpcf7_version\"      value=\"5\">\r\n        <input type=\"hidden\" name=\"_wpcf7_locale\"       value=\"et\">\r\n        <input type=\"hidden\" name=\"_wpcf7_unit_tag\"     id=\"lp-unit-tag\" value=\"\">\r\n        <input type=\"hidden\" name=\"_wpcf7_container_post\" value=\"0\">\r\n\r\n        <!-- Kalkulaatori tulemused \u2013 t\u00e4idetakse JS-ga -->\r\n        <input type=\"hidden\" name=\"calc-pitch\" id=\"cf7-pitch\" value=\"\">\r\n        <input type=\"hidden\" name=\"calc-led\"   id=\"cf7-led\"   value=\"\">\r\n        <input type=\"hidden\" name=\"calc-lcd\"   id=\"cf7-lcd\"   value=\"\">\r\n        <input type=\"hidden\" name=\"calc-env\"   id=\"cf7-env\"   value=\"\">\r\n        <input type=\"hidden\" name=\"calc-dims\"  id=\"cf7-dims\"  value=\"\">\r\n\r\n        <!-- Kasutaja sisestab -->\r\n        <div class=\"lp-export-row\">\r\n          <input type=\"text\"  name=\"calc-name\"  id=\"cf7-name\"  placeholder=\"Sinu nimi\"       class=\"lp-export-input\" required>\r\n          <input type=\"email\" name=\"calc-email\" id=\"cf7-email\" placeholder=\"sinu@email.com\"  class=\"lp-export-input\" required>\r\n          <button type=\"submit\" class=\"lp-btn\" id=\"btn-export\">SAADA JA LAE PDF<\/button>\r\n        <\/div>\r\n      <\/form>\r\n\r\n      <div class=\"lp-export-status\" id=\"export-status\"><\/div>\r\n    <\/div>\r\n\r\n\r\n\r\n    <!-- Tagasi algusesse -->\r\n    <div class=\"lp-restart-row\">\r\n      <button type=\"button\" class=\"lp-btn lp-btn-ghost\" id=\"btn-restart\">\u2190 Alusta uuesti<\/button>\r\n    <\/div>\r\n  <\/div>\r\n\r\n<\/section>\r\n\r\n<!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\r\n     CSS\r\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\r\n<style>\r\n:root {\r\n  --lumepix-accent:      #DCE900;\r\n  --lumepix-accent-soft: #F4F8CC;\r\n  --lumepix-dark:        #141414;\r\n  --lumepix-grey:        #f5f5f7;\r\n  --lumepix-border:      #dcdde3;\r\n  --lumepix-radius-lg:   18px;\r\n  --lumepix-radius-xl:   24px;\r\n  --lumepix-shadow-soft: 0 18px 35px rgba(0,0,0,0.06);\r\n  --lp-field-height:     52px;\r\n}\r\n\r\n.lp-tools {\r\n  max-width: 900px; margin: 0 auto; padding: 40px 20px 60px;\r\n  font-family: system-ui,-apple-system,BlinkMacSystemFont,\"Segoe UI\",sans-serif;\r\n  color: var(--lumepix-dark);\r\n}\r\n\r\n\/* \u2500\u2500 P\u00c4IS \u2500\u2500 *\/\r\n.lp-tools-header { margin-bottom: 24px; }\r\n.lp-tools-logo   { display:flex; align-items:center; gap:10px; margin-bottom:6px; }\r\n.lp-tools-logo-text {\r\n  font-size:18px; font-weight:700; color:var(--lumepix-accent);\r\n  letter-spacing:.06em; text-transform:uppercase;\r\n}\r\n.lp-tools-intro { font-size:15px; max-width:620px; color:#555866; margin:0; }\r\n\r\n\/* \u2500\u2500 VIISARD SAMMUDE RIBA \u2500\u2500 *\/\r\n.lp-wizard-bar {\r\n  display: flex; align-items: center; gap: 0;\r\n  margin-bottom: 24px; padding: 0 4px;\r\n}\r\n.lp-wizard-step {\r\n  display: flex; align-items: center; gap: 10px;\r\n  flex-shrink: 0;\r\n}\r\n.lp-ws-num {\r\n  width: 32px; height: 32px; border-radius: 50%;\r\n  display: flex; align-items: center; justify-content: center;\r\n  font-size: 13px; font-weight: 700;\r\n  background: #e5e7eb; color: #9ca3af;\r\n  transition: background .3s, color .3s;\r\n  flex-shrink: 0;\r\n}\r\n.lp-ws-label {\r\n  font-size: 13px; font-weight: 600; color: #9ca3af;\r\n  transition: color .3s; white-space: nowrap;\r\n}\r\n.lp-wizard-connector {\r\n  flex: 1; height: 2px; background: #e5e7eb; margin: 0 10px;\r\n  min-width: 20px;\r\n  transition: background .3s;\r\n}\r\n.lp-wizard-step.lp-ws-active .lp-ws-num {\r\n  background: #111827; color: #fff;\r\n}\r\n.lp-wizard-step.lp-ws-active .lp-ws-label { color: #111827; }\r\n.lp-wizard-step.lp-ws-done .lp-ws-num {\r\n  background: var(--lumepix-accent); color: #111;\r\n}\r\n.lp-wizard-step.lp-ws-done .lp-ws-label { color: #374151; }\r\n.lp-wizard-step.lp-ws-done + .lp-wizard-connector { background: var(--lumepix-accent); }\r\n\r\n\/* \u2500\u2500 EELSEADISTUSED \u2500\u2500 *\/\r\n.lp-presets {\r\n  background: #fff; border-radius: var(--lumepix-radius-xl);\r\n  border: 1px solid var(--lumepix-border); padding: 16px 20px;\r\n  margin-bottom: 16px; box-shadow: var(--lumepix-shadow-soft);\r\n}\r\n.lp-presets-label { font-size:13px; font-weight:600; color:#484b57; margin:0 0 10px; }\r\n.lp-presets-row { display:flex; gap:10px; flex-wrap:wrap; }\r\n.lp-preset-btn {\r\n  display: flex; align-items: center; gap: 8px;\r\n  padding: 8px 16px; border-radius: 999px;\r\n  border: 1px solid var(--lumepix-border);\r\n  background: var(--lumepix-grey);\r\n  font-size: 13px; font-weight: 500; cursor: pointer; color: #374151;\r\n  transition: border-color .15s, background .15s, transform .06s;\r\n}\r\n.lp-preset-btn:hover {\r\n  border-color: #111827; background: #f0f0f0; transform: translateY(-1px);\r\n}\r\n.lp-preset-btn.lp-preset-active {\r\n  border-color: #111827; background: #111827; color: #fff;\r\n}\r\n.lp-preset-icon { font-size: 16px; }\r\n\r\n\/* \u2500\u2500 KAARDID \u2500\u2500 *\/\r\n.lp-tool-card {\r\n  background: #fff; border-radius: var(--lumepix-radius-xl);\r\n  padding: 22px 22px 24px; margin-bottom: 16px;\r\n  box-shadow: var(--lumepix-shadow-soft); border: 1px solid var(--lumepix-border);\r\n  transition: opacity .3s, filter .3s;\r\n}\r\n.lp-step-locked {\r\n  opacity: .45; pointer-events: none; filter: grayscale(.3);\r\n}\r\n.lp-step-locked .lp-tool-title::after {\r\n  content: \" \ud83d\udd12\"; font-size: 14px;\r\n}\r\n\r\n.lp-tool-title {\r\n  font-size: 20px; margin: 0 0 16px;\r\n  display: flex; align-items: center; gap: 10px;\r\n}\r\n.lp-tool-title::before {\r\n  content: \"\"; display:inline-block; width:11px; height:11px;\r\n  border-radius:999px; background:var(--lumepix-accent); flex-shrink:0;\r\n}\r\n\r\n\/* \u2500\u2500 VORM \u2500\u2500 *\/\r\n.lp-form { display:grid; gap:12px 16px; align-items:flex-start; margin-top:8px; }\r\n.lp-form-pitch { grid-template-columns: repeat(3, minmax(0,1fr)); }\r\n.lp-form-size  { grid-template-columns: repeat(4, minmax(0,1fr)); }\r\n.lp-form-row   { display:flex; flex-direction:column; gap:6px; }\r\n.lp-form-row label { font-size:13px; font-weight:600; color:#484b57; line-height:1.3; }\r\n.lp-label-hidden { visibility:hidden; }\r\n\r\n.lp-form-row input,\r\n.lp-form-row select {\r\n  font-size:14px; padding:0 14px; border-radius:999px;\r\n  border:1px solid var(--lumepix-border); background:var(--lumepix-grey);\r\n  outline:none; height:var(--lp-field-height); box-sizing:border-box;\r\n  transition:border-color .15s, background .15s;\r\n}\r\n.lp-form-row input:focus,\r\n.lp-form-row select:focus { border-color:var(--lumepix-accent); background:#fff; }\r\n.lp-form-row-button { grid-column:1\/-1; max-width:260px; }\r\n\r\n.lp-btn {\r\n  margin:0; width:100%; border-radius:999px; border:1px solid #111827;\r\n  background:#111827; color:#f9fafb; font-size:14px; font-weight:600;\r\n  cursor:pointer; height:var(--lp-field-height); box-sizing:border-box;\r\n  text-transform:uppercase; letter-spacing:.08em;\r\n  display:inline-flex; align-items:center; justify-content:center;\r\n  transition:background .12s, border-color .12s, transform .06s;\r\n}\r\n.lp-btn:hover  { background:#020617; border-color:#020617; transform:translateY(-1px); }\r\n.lp-btn:active { transform:translateY(0); }\r\n\r\n.lp-btn-secondary {\r\n  background: var(--lumepix-accent); border-color: var(--lumepix-accent); color: #111;\r\n}\r\n.lp-btn-secondary:hover { background:#c5d200; border-color:#c5d200; }\r\n\r\n.lp-btn-ghost {\r\n  background: transparent; border-color: var(--lumepix-border); color: #374151;\r\n}\r\n.lp-btn-ghost:hover { background: #f5f5f7; border-color:#9ca3af; }\r\n\r\n\/* \u2500\u2500 TULEMUS \u2500\u2500 *\/\r\n.lp-result {\r\n  margin-top:16px; padding:12px 14px; border-radius:var(--lumepix-radius-lg);\r\n  background:var(--lumepix-accent-soft); border:1px dashed rgba(220,233,0,.55);\r\n  font-size:13px; line-height:1.6; color:#1f2333;\r\n}\r\n.lp-result-hidden { display:none; }\r\n.lp-result strong { font-weight:700; }\r\n.lp-result small  { display:block; margin-top:2px; font-size:11px; color:#626678; }\r\n\r\n\/* \u2500\u2500 PIKSLISAMMU VISUAAL \u2500\u2500 *\/\r\n.pp-view-visual {\r\n  margin-bottom:16px; padding:20px 18px 14px; border-radius:18px;\r\n  background:linear-gradient(180deg,#fff 0%,#f5f5f7 55%,#e1e3eb 100%);\r\n  border:1px solid var(--lumepix-border); position:relative;\r\n}\r\n.pp-view-screen {\r\n  width:120px; height:72px; position:relative; margin:8px 0 10px;\r\n  border-radius:18px; background:#050816;\r\n  box-shadow:0 0 0 3px #020617,0 16px 26px rgba(15,23,42,.55); overflow:hidden;\r\n}\r\n.pp-view-screen-inner {\r\n  position:absolute; inset:6px; border-radius:14px;\r\n  background:radial-gradient(circle at 10% 0%,rgba(220,233,0,.35),transparent 60%),\r\n             radial-gradient(circle at 90% 100%,rgba(148,163,184,.4),transparent 55%),\r\n             linear-gradient(135deg,#020617,#020617);\r\n  display:flex; align-items:flex-end; padding:6px 8px;\r\n}\r\n.pp-view-art { width:100%; height:100%; position:relative; }\r\n.pp-art-bar { position:absolute; bottom:4px; width:18%; border-radius:999px 999px 0 0; background:linear-gradient(180deg,rgba(220,233,0,.9),rgba(132,148,0,.95)); opacity:.9; }\r\n.pp-art-bar-1 { left:4%;  height:18px; }\r\n.pp-art-bar-2 { left:30%; height:10px; opacity:.6; }\r\n.pp-art-bar-3 { left:56%; height:22px; opacity:.75; }\r\n.pp-art-dot { position:absolute; top:10px; right:8px; width:7px; height:7px; border-radius:999px; background:var(--lumepix-accent); box-shadow:0 0 0 2px rgba(220,233,0,.25); }\r\n.pp-view-screen-label { position:absolute; bottom:-18px; left:50%; transform:translateX(-50%); font-size:11px; font-weight:600; color:#4b5563; }\r\n.pp-view-ground { position:relative; margin-top:0; padding-left:140px; padding-right:20px; }\r\n.pp-view-ground-line { position:relative; margin-top:-40px; height:40px; }\r\n.pp-view-distance-line { position:absolute; left:0; bottom:0; height:2px; width:0%; background:var(--lumepix-accent); transition:width .4s ease-out; }\r\n.pp-view-ground-line::before { content:\"\"; position:absolute; left:0; right:0; bottom:0; height:2px; background:linear-gradient(90deg,#9ca3af,#d1d5db 40%,#e5e7eb); }\r\n.pp-view-person { position:absolute; bottom:0; left:0; transform:translateX(-50%); transition:left .4s ease-out; }\r\n.pp-view-person-inner { display:flex; flex-direction:column; align-items:center; }\r\n.pp-view-head { width:16px; height:16px; border-radius:999px; background:var(--lumepix-accent); box-shadow:0 0 0 1px #fff,0 0 10px rgba(220,233,0,.5); }\r\n.pp-view-body { width:4px; height:30px; border-radius:999px; margin-top:3px; background:linear-gradient(180deg,var(--lumepix-accent),#8ea100); }\r\n@keyframes pp-walk-bob { 0%,100%{transform:translateY(0)} 50%{transform:translateY(-4px)} }\r\n.pp-view-person.is-walking .pp-view-person-inner { animation:pp-walk-bob .5s ease-in-out 3; }\r\n.pp-view-scale { position:relative; margin-top:18px; height:24px; }\r\n.pp-view-scale-mark { position:absolute; bottom:0; transform:translateX(-50%); font-size:10px; color:#6b7280; text-align:center; white-space:nowrap; }\r\n.pp-view-scale-mark::before { content:\"\"; position:absolute; top:-12px; left:50%; transform:translateX(-50%); width:1px; height:10px; background:#9ca3af; }\r\n.pp-view-distance-label { margin-top:8px; font-size:12px; font-weight:600; color:#111827; text-align:right; }\r\n\r\n\/* \u2500\u2500 EKRAANIDE VISUAAL \u2500\u2500 *\/\r\n.lp-visual-wrapper { margin-top:4px; }\r\n.lp-visual-header { display:flex; align-items:center; justify-content:space-between; font-size:12px; color:#4b5563; margin-bottom:6px; gap:12px; }\r\n.lp-visual-legend { display:flex; align-items:center; gap:10px; font-size:11px; flex-wrap:wrap; }\r\n.lp-leg { display:inline-block; width:14px; height:8px; border-radius:999px; margin-right:4px; }\r\n.lp-leg-base { border:1px dashed #9ca3af; background:transparent; }\r\n.lp-leg-led  { background:rgba(220,233,0,.7); }\r\n.lp-leg-lcd  { background:#020617; }\r\n.lp-leg-wall { background:rgba(2,6,23,.25); border:1px dashed #020617; }\r\n\r\n.lp-visual-inner {\r\n  position:relative; width:100%; height:clamp(230px,32vw,320px);\r\n  border-radius:24px;\r\n  background:linear-gradient(135deg,#f9fafb,#e5e7eb 50%,#f3f4f6);\r\n  border:1px solid var(--lumepix-border); overflow:hidden;\r\n}\r\n.lp-visual-base,.lp-visual-led,.lp-visual-lcd,.lp-visual-wall {\r\n  position:absolute; transform:translate(-50%,-50%); display:none; border-radius:0;\r\n}\r\n.lp-visual-base { z-index:1; border:1px dashed #9ca3af; background:rgba(148,163,184,.05); }\r\n.lp-visual-led  { z-index:3; background-color:rgba(220,233,0,.35);\r\n  background-image:repeating-linear-gradient(to right,rgba(0,0,0,.25) 0px,rgba(0,0,0,.25) 1px,transparent 1px,transparent 100%),\r\n                   repeating-linear-gradient(to bottom,rgba(0,0,0,.25) 0px,rgba(0,0,0,.25) 1px,transparent 1px,transparent 100%);\r\n}\r\n.lp-visual-lcd {\r\n  z-index:2; border-style:solid; border-color:#020617;\r\n  background:linear-gradient(135deg,#4b5563,#111827 45%,#020617);\r\n  box-shadow:0 0 0 1px rgba(255,255,255,.1),0 4px 10px rgba(0,0,0,.45),inset 0 0 18px rgba(0,0,0,.65);\r\n}\r\n.lp-visual-lcd::after {\r\n  content:\"\"; position:absolute; inset:0; pointer-events:none;\r\n  background:linear-gradient(135deg,rgba(255,255,255,.14),rgba(255,255,255,.06) 25%,rgba(255,255,255,0) 55%),\r\n             radial-gradient(circle at 80% 10%,rgba(255,255,255,.18),rgba(255,255,255,0) 40%);\r\n  mix-blend-mode:screen;\r\n}\r\n.lp-visual-wall {\r\n  z-index:4; border:2px solid rgba(2,6,23,.5); background-color:rgba(2,6,23,.08);\r\n}\r\n\r\n.lp-visual-toggles-row { margin-top:10px; display:flex; gap:20px; font-size:14px; color:#1f2937; flex-wrap:wrap; align-items:center; }\r\n.lp-toggle-big { display:inline-flex; align-items:center; gap:8px; cursor:pointer; user-select:none; }\r\n.lp-cb { position:absolute; opacity:0; width:0; height:0; pointer-events:none; }\r\n.lp-cb-box {\r\n  display:inline-flex; align-items:center; justify-content:center; flex-shrink:0;\r\n  width:18px; height:18px; border-radius:4px; border:2px solid #9ca3af;\r\n  background:#fff; box-sizing:border-box; transition:border-color .15s, background .15s;\r\n}\r\n.lp-cb-box::after {\r\n  content:\"\"; display:block; width:10px; height:7px;\r\n  border-left:2px solid #fff; border-bottom:2px solid #fff;\r\n  transform:rotate(-45deg) translateY(-1px); opacity:0; transition:opacity .1s;\r\n}\r\n.lp-cb:checked + .lp-cb-box { background:#111827; border-color:#111827; }\r\n.lp-cb:checked + .lp-cb-box::after { opacity:1; }\r\n.lp-cb:focus-visible + .lp-cb-box { outline:2px solid var(--lumepix-accent); outline-offset:2px; }\r\n.lp-cb-label { cursor:pointer; font-weight:500; }\r\n\r\n\/* \u2500\u2500 SEKTSIOONID (ruumiplaan, eksport, QR) \u2500\u2500 *\/\r\n.lp-section-subtitle {\r\n  font-size:15px; font-weight:700; color:#111827;\r\n  margin:20px 0 12px; padding-top:16px;\r\n  border-top:1px solid var(--lumepix-border);\r\n  display:flex; align-items:center; gap:8px;\r\n}\r\n.lp-section-subtitle::before {\r\n  content:\"\"; display:inline-block; width:8px; height:8px;\r\n  border-radius:50%; background:var(--lumepix-accent); flex-shrink:0;\r\n}\r\n\r\n\/* Ruumiplaan *\/\r\n.lp-room-section { margin-top:4px; }\r\n.lp-room-inputs {\r\n  display:grid; grid-template-columns:repeat(3,minmax(0,1fr)) auto;\r\n  gap:12px 14px; align-items:flex-start; margin-bottom:16px;\r\n}\r\n.lp-room-canvas {\r\n  display:block; width:100%; height:clamp(420px, 70vw, 600px); border-radius:18px;\r\n  border:1px solid var(--lumepix-border);\r\n  background:linear-gradient(135deg,#f9fafb,#e5e7eb 50%,#f3f4f6);\r\n}\r\n@media (max-width: 600px) {\r\n  .lp-room-canvas { height: 90vw; min-height: 400px; }\r\n}\r\n.lp-room-hint { font-size:12px; color:#6b7280; margin:8px 0 0; text-align:center; }\r\n\r\n\/* CF7 vormi wrapper *\/\r\n.lp-cf7-wrap { margin: 0; }\r\n\r\n\/* E-mail eksport *\/\r\n.lp-export-section { margin-top:4px; }\r\n.lp-export-row { display:flex; gap:10px; flex-wrap:wrap; align-items:stretch; margin-bottom:8px; }\r\n.lp-export-input {\r\n  flex:1; min-width:180px; font-size:14px; padding:0 14px;\r\n  border-radius:999px; border:1px solid var(--lumepix-border);\r\n  background:var(--lumepix-grey); outline:none;\r\n  height:var(--lp-field-height); box-sizing:border-box;\r\n  transition:border-color .15s, background .15s;\r\n}\r\n.lp-export-input:focus { border-color:var(--lumepix-accent); background:#fff; }\r\n.lp-export-row .lp-btn { flex:0 0 auto; width:auto; padding:0 24px; }\r\n.lp-export-note { font-size:11px; color:#6b7280; margin:0; }\r\n.lp-export-status {\r\n  margin-top:10px; font-size:13px; font-weight:600;\r\n  min-height:20px; transition:color .2s;\r\n}\r\n.lp-export-status.ok    { color:#16a34a; }\r\n.lp-export-status.error { color:#dc2626; }\r\n\r\n\r\n\r\n\/* Taask\u00e4ivitus *\/\r\n.lp-restart-row { margin-top:20px; padding-top:16px; border-top:1px solid var(--lumepix-border); }\r\n.lp-restart-row .lp-btn { width:auto; padding:0 24px; }\r\n\r\n\/* \u2500\u2500 RESPONSIVE \u2500\u2500 *\/\r\n@media (max-width:1024px) {\r\n  .lp-form-pitch { grid-template-columns:repeat(2,minmax(0,1fr)); }\r\n  .lp-form-size  { grid-template-columns:repeat(2,minmax(0,1fr)); }\r\n  .lp-room-inputs { grid-template-columns:repeat(2,minmax(0,1fr)); }\r\n}\r\n@media (max-width:768px) {\r\n  .lp-tools        { padding-inline:12px; }\r\n  .lp-tool-card    { padding:18px 16px 20px; }\r\n  .pp-view-visual  { padding:12px 12px 10px; }\r\n  .pp-view-ground  { padding-left:118px; padding-right:12px; }\r\n  .lp-form, .lp-room-inputs { grid-template-columns:1fr; }\r\n  .lp-form-row-button { max-width:none; }\r\n  .lp-visual-header { flex-direction:column; align-items:flex-start; }\r\n  .lp-wizard-bar { overflow-x:auto; padding-bottom:4px; }\r\n  .lp-ws-label { display:none; }\r\n}\r\n<\/style>\r\n\r\n<!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\r\n     JAVASCRIPT\r\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\r\n<script>\r\n(function () {\r\n\"use strict\";\r\n\r\n\/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\r\n   ANDMED\r\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 *\/\r\nconst LED_PITCHES = [0.6,0.79,0.9,1.25,1.5,1.75,2,2.5,2.9,3.9,5,6,6.66,8,10,16];\r\nconst VAD_FACTOR = 3.44;\r\nconst ACD_FACTOR = 1.72;\r\n\r\nconst INDOOR_LCD_SIZES = [\r\n  {inch:13,w:310,h:195},{inch:24,w:556,h:327},{inch:32,w:726,h:419},\r\n  {inch:43,w:968,h:558},{inch:46,w:1021,h:576},{inch:50,w:1124,h:648},\r\n  {inch:55,w:1235,h:708},{inch:65,w:1451,h:831},{inch:75,w:1678,h:959},\r\n  {inch:85,w:1904,h:1082},{inch:98,w:2193,h:1250},{inch:110,w:2440,h:1375}\r\n];\r\n\r\nconst OUTDOOR_LCD_SIZES = [\r\n  {inch:22,w:573.0,h:342.4},{inch:46,w:1069.0,h:623.6},\r\n  {inch:55,w:1260.6,h:731.4},{inch:75,w:1774.8,h:1053.4}\r\n];\r\n\r\nconst INDOOR_VIDEO_WALL_PANELS  = [{inch:46,w:1022,h:577},{inch:55,w:1213.5,h:684.3}];\r\nconst OUTDOOR_VIDEO_WALL_PANELS = [\r\n  {inch:22,w:573.0,h:342.4},{inch:46,w:1069.0,h:623.6},\r\n  {inch:55,w:1260.6,h:731.4},{inch:75,w:1774.8,h:1053.4}\r\n];\r\n\r\n\/* Eelseadistused *\/\r\nconst PRESETS = {\r\n  mall:      {dist:5,  content:\"mix\",      envAvixa:\"indoor-normal\", env:\"indoor\",  w:3000, h:1800, orient:\"auto\",     label:\"Kaubanduskeskus\"},\r\n  conf:      {dist:12, content:\"detail\",   envAvixa:\"indoor-normal\", env:\"indoor\",  w:5000, h:3000, orient:\"landscape\", label:\"Suur konverentsisaal\"},\r\n  confsmall: {dist:4,  content:\"detail\",   envAvixa:\"indoor-normal\", env:\"indoor\",  w:2000, h:1200, orient:\"landscape\", label:\"V\u00e4ike koosolekuruum\"},\r\n  outdoor:   {dist:15, content:\"mix\",      envAvixa:\"outdoor\",       env:\"outdoor\", w:4000, h:2500, orient:\"landscape\", label:\"V\u00e4lireklaam\"},\r\n  resto:     {dist:3,  content:\"mix\",      envAvixa:\"indoor-normal\", env:\"indoor\",  w:1200, h:900,  orient:\"landscape\", label:\"Restoran \/ men\u00fc\u00fctahvel\"}\r\n};\r\n\r\n\/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\r\n   OLEKUHOIDLA\r\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 *\/\r\nconst state = {\r\n  baseW:null, baseH:null, ledSize:null, lcdSingle:null,\r\n  wallSize:null, ledStep:250,\r\n  pitchMm:null, envAvixa:null, env:null,\r\n  dist:null, content:null, lcdOrient:null,\r\n  ledText:\"\", lcdText:\"\", pitchText:\"\"\r\n};\r\n\r\n\r\n\/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\r\n   MATEMAATIKA\r\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 *\/\r\nfunction nearestPitch(t) {\r\n  return LED_PITCHES.reduce((b,p)=>Math.abs(p-t)<Math.abs(b-t)?p:b, LED_PITCHES[0]);\r\n}\r\nfunction formatMm(v) { return parseFloat(v.toFixed(2)).toString().replace(\".\",\",\"); }\r\nfunction formatPitch(mm) { return \"P\"+formatMm(mm); }\r\nfunction isPortrait(w,h) { return h>=w; }\r\nfunction getLcdBezel(inch) {\r\n  if(inch<=24)return 10; if(inch<=43)return 8; if(inch<=65)return 6; if(inch<=85)return 5; return 4;\r\n}\r\n\r\nfunction applyOrientation(w,h,choice,bw,bh) {\r\n  let sw=w,sh=h;\r\n  const bp=isPortrait(bw,bh);\r\n  if(choice===\"portrait\"  && sw>sh){[sw,sh]=[sh,sw];}\r\n  else if(choice===\"landscape\" && sh>sw){[sw,sh]=[sh,sw];}\r\n  else if(choice===\"auto\"){\r\n    if(bp&&sw>sh){[sw,sh]=[sh,sw];}\r\n    if(!bp&&sh>sw){[sw,sh]=[sh,sw];}\r\n  }\r\n  return {w:sw,h:sh};\r\n}\r\n\r\nfunction calcLedSize(bw,bh,step) {\r\n  const min=step*2;\r\n  if(bw<min||bh<min)return null;\r\n  const lw=Math.floor(bw\/step)*step, lh=Math.floor(bh\/step)*step;\r\n  if(lw<min||lh<min)return null;\r\n  return {w:lw,h:lh};\r\n}\r\nfunction calcLedRes(lw,lh,pitch){ return {wPx:Math.round(lw\/pitch),hPx:Math.round(lh\/pitch)}; }\r\n\r\nfunction calcLcdSize(bw,bh,choice,env) {\r\n  const sizes=env===\"outdoor\"?OUTDOOR_LCD_SIZES:INDOOR_LCD_SIZES;\r\n  let best=null;\r\n  for(const lcd of sizes){\r\n    for(const {w,h} of [\r\n      applyOrientation(lcd.w,lcd.h,choice,bw,bh),\r\n      ...(choice!==\"auto\"?[applyOrientation(lcd.h,lcd.w,choice,bw,bh)]:[])\r\n    ]){\r\n      if(w<=bw&&h<=bh&&(!best||lcd.inch>best.inch)) best={inch:lcd.inch,w,h};\r\n    }\r\n  }\r\n  return best;\r\n}\r\n\r\nfunction calcVideoWall(bw,bh,choice,env) {\r\n  const panels=env===\"outdoor\"?OUTDOOR_VIDEO_WALL_PANELS:INDOOR_VIDEO_WALL_PANELS;\r\n  let best=null;\r\n  for(const panel of panels){\r\n    for(const {pw,ph} of [{pw:panel.w,ph:panel.h},{pw:panel.h,ph:panel.w}]){\r\n      for(let cols=1;cols<=8;cols++){\r\n        for(let rows=1;rows<=8;rows++){\r\n          if(cols*rows<2)continue;\r\n          const o=applyOrientation(pw*cols,ph*rows,choice,bw,bh);\r\n          const sw=o.w!==pw*cols;\r\n          if(o.w<=bw&&o.h<=bh){\r\n            const area=o.w*o.h;\r\n            if(!best||area>best.area)\r\n              best={inch:panel.inch,cols:sw?rows:cols,rows:sw?cols:rows,w:o.w,h:o.h,area};\r\n          }\r\n        }\r\n      }\r\n    }\r\n  }\r\n  if(!best)return null;\r\n  return {inch:best.inch,cols:best.cols,rows:best.rows,w:best.w,h:best.h};\r\n}\r\n\r\nfunction getEnvText(env) {\r\n  return ({\r\n    \"indoor-normal\":{title:\"Tavaline sisekeskkond\",text:\"Soovituslik LED heledus umbes 600\u2013800 nit. LCD signage-ekraanidel piisab tavaliselt 350\u2013500 nit tasemest.\"},\r\n    \"indoor-bright\":{title:\"Hele sisekeskkond \/ klaasfassaad\",text:\"Soovituslik LED heledus ligikaudu 1500\u20133000 nit. LCD puhul kasutada k\u00f5rge heledusklassiga (700\u20132500 nit) mudeleid.\"},\r\n    \"outdoor\":{title:\"V\u00e4litingimused\",text:\"V\u00e4liekraanidel soovitatakse alates 4000 nit heledusest, praktikas 5000\u20136000 nit ja enam, et pilt oleks p\u00e4ikesevalguses selgelt n\u00e4htav.\"}\r\n  })[env]||{title:\"\",text:\"\"};\r\n}\r\n\r\n\/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\r\n   VIISARD \u2013 SAMMUDE HALDUS\r\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 *\/\r\nfunction setWizardStep(n) {\r\n  for(let i=1;i<=3;i++){\r\n    const ws=document.getElementById(\"ws-\"+i);\r\n    const step=document.getElementById(\"step-\"+i);\r\n    ws.classList.remove(\"lp-ws-active\",\"lp-ws-done\");\r\n    if(step){ step.classList.remove(\"lp-step-locked\"); }\r\n    if(i<n){\r\n      ws.classList.add(\"lp-ws-done\");\r\n    } else if(i===n){\r\n      ws.classList.add(\"lp-ws-active\");\r\n    } else {\r\n      if(step) step.classList.add(\"lp-step-locked\");\r\n    }\r\n  }\r\n  \/\/ Kerib aktiivse sammu juurde\r\n  const activeStep=document.getElementById(\"step-\"+n);\r\n  if(activeStep && n>1){\r\n    setTimeout(()=>activeStep.scrollIntoView({behavior:\"smooth\",block:\"start\"}),100);\r\n  }\r\n}\r\n\r\n\/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\r\n   VISUAALI UUENDAMINE (ekraanide v\u00f5rdlus)\r\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 *\/\r\nfunction updateVisual(bw,bh,ledSize,lcdSingle,wall,ledStepMm) {\r\n  const cont=document.getElementById(\"lp-visual-inner\");\r\n  const baseEl=document.getElementById(\"vis-base\");\r\n  const ledEl =document.getElementById(\"vis-led\");\r\n  const lcdEl =document.getElementById(\"vis-lcd\");\r\n  const wallEl=document.getElementById(\"vis-wall\");\r\n  if(!cont||!baseEl)return;\r\n\r\n  const showLed  = document.getElementById(\"toggle-led\")?.checked  ??true;\r\n  const showLcd  = document.getElementById(\"toggle-lcd\")?.checked  ??true;\r\n  const showWall = document.getElementById(\"toggle-wall\")?.checked ??true;\r\n\r\n  if(!bw||!bh){ [baseEl,ledEl,lcdEl,wallEl].forEach(e=>e.style.display=\"none\"); return; }\r\n\r\n  const rect=cont.getBoundingClientRect();\r\n  if(rect.width===0||rect.height===0)return;\r\n\r\n  const pad=18, scale=Math.min((rect.width-pad*2)\/bw,(rect.height-pad*2)\/bh);\r\n\r\n  function applyRect(el,w,h){\r\n    el.style.display=\"block\"; el.style.width=(w*scale)+\"px\"; el.style.height=(h*scale)+\"px\";\r\n    el.style.left=\"50%\"; el.style.top=\"50%\";\r\n  }\r\n  applyRect(baseEl,bw,bh);\r\n\r\n  if(ledSize&&showLed){\r\n    applyRect(ledEl,ledSize.w,ledSize.h);\r\n    const gp=(ledStepMm||250)*scale;\r\n    ledEl.style.backgroundSize=gp+\"px \"+gp+\"px\";\r\n  } else ledEl.style.display=\"none\";\r\n\r\n  if(lcdSingle&&showLcd){\r\n    applyRect(lcdEl,lcdSingle.w,lcdSingle.h);\r\n    lcdEl.style.borderWidth=getLcdBezel(lcdSingle.inch||55)+\"px\";\r\n  } else lcdEl.style.display=\"none\";\r\n\r\n  if(wall&&showWall){\r\n    applyRect(wallEl,wall.w,wall.h);\r\n    const tw=(wall.w*scale)\/wall.cols, th=(wall.h*scale)\/wall.rows;\r\n    wallEl.style.backgroundImage=\r\n      \"repeating-linear-gradient(to right,rgba(2,6,23,.55) 0px,rgba(2,6,23,.55) 2px,transparent 2px,transparent \"+tw+\"px),\"+\r\n      \"repeating-linear-gradient(to bottom,rgba(2,6,23,.55) 0px,rgba(2,6,23,.55) 2px,transparent 2px,transparent \"+th+\"px)\";\r\n    wallEl.style.backgroundSize=(wall.w*scale)+\"px \"+(wall.h*scale)+\"px\";\r\n  } else wallEl.style.display=\"none\";\r\n}\r\n\r\nfunction redrawVisual(){\r\n  updateVisual(state.baseW,state.baseH,state.ledSize,state.lcdSingle,state.wallSize,state.ledStep);\r\n}\r\n\r\n\/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\r\n   PIKSLISAMMU VISUAAL\r\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 *\/\r\nfunction initPitchScale() {\r\n  const scale=document.getElementById(\"pp-scale-avixa\");\r\n  if(!scale||scale.dataset.init===\"1\")return;\r\n  [1,5,10,15,20].forEach(v=>{\r\n    const m=document.createElement(\"div\");\r\n    m.className=\"pp-view-scale-mark\"; m.style.left=(v\/20*100)+\"%\";\r\n    const s=document.createElement(\"span\");\r\n    s.textContent=v===20?\"20 m+\":v+\" m\"; m.appendChild(s); scale.appendChild(m);\r\n  });\r\n  scale.dataset.init=\"1\";\r\n}\r\n\r\nfunction updatePitchVisual(dist) {\r\n  const person=document.getElementById(\"pp-person-avixa\");\r\n  const label =document.getElementById(\"pp-distance-label-avixa\");\r\n  const line  =document.getElementById(\"pp-distance-line-avixa\");\r\n  if(!person||!label||!line)return;\r\n  const c=Math.min(Math.max(dist||0,0),20), t=c\/20;\r\n  person.style.left=(t*100)+\"%\"; line.style.width=(t*100)+\"%\";\r\n  label.textContent=c.toFixed(1).replace(\".\",\",\")+\"\\u00a0m\";\r\n  if(dist>0){\r\n    person.classList.remove(\"is-walking\"); void person.offsetWidth;\r\n    person.classList.add(\"is-walking\");\r\n  }\r\n}\r\n\r\n\/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\r\n   PITCH DROPDOWN\r\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 *\/\r\nfunction fillPitchDropdown(env) {\r\n  const sel=document.getElementById(\"led-pitch\");\r\n  if(!sel)return;\r\n  const prev=parseFloat(sel.value);\r\n  sel.innerHTML=\"\";\r\n  LED_PITCHES.forEach(p=>{\r\n    if(env===\"outdoor\"&&p<2.5)return;\r\n    const o=document.createElement(\"option\");\r\n    o.value=String(p);\r\n    o.textContent=\"P\"+String(p).replace(\".\",\",\")+\" (\"+p+\" mm)\";\r\n    sel.appendChild(o);\r\n  });\r\n  if(!isNaN(prev)&&Array.from(sel.options).some(o=>parseFloat(o.value)===prev))\r\n    sel.value=String(prev);\r\n}\r\n\r\nfunction syncPitchDropdown(mm) {\r\n  if(!mm)return;\r\n  const sel=document.getElementById(\"led-pitch\");\r\n  if(!sel||!sel.options.length)return;\r\n  let best=sel.options[0], diff=Math.abs(parseFloat(best.value)-mm);\r\n  for(const o of sel.options){\r\n    const d=Math.abs(parseFloat(o.value)-mm);\r\n    if(d<diff){diff=d;best=o;}\r\n  }\r\n  sel.value=best.value;\r\n}\r\n\r\n\/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\r\n   RUUMIPLAAN (samm 3)\r\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 *\/\r\n\/\/ Ruumiplaan \u2013 vaade \u00dcLEVALT (2D linnuplaan)\r\n\/\/ Laius = X (horisontaalne), S\u00fcgavus = Y (vertikaalne, ekraanist eemale)\r\nfunction drawRoomPlan(roomW, roomD, screenH, show30 = true, show45 = true) {\r\n  const canvas = document.getElementById(\"lp-room-canvas\");\r\n  const hint   = document.getElementById(\"lp-room-hint\");\r\n  if (!canvas) return;\r\n\r\n  const CW = canvas.offsetWidth || 800;\r\n  const CH = canvas.offsetHeight || 420;\r\n  canvas.width        = CW * devicePixelRatio;\r\n  canvas.height       = CH * devicePixelRatio;\r\n  \/\/ height already set by CSS \u2013 don't override\r\n  const ctx = canvas.getContext(\"2d\");\r\n  ctx.scale(devicePixelRatio, devicePixelRatio);\r\n  ctx.clearRect(0, 0, CW, CH);\r\n\r\n  \/\/ Veerised:\r\n  \/\/ padL = LED siltide jaoks (vasakul, tekstAlign right)\r\n  \/\/ padR = LCD sildi + \"p\u00f5randast\" teksti jaoks\r\n  \/\/ padT = ekraaniribade + siltide jaoks\r\n  \/\/ padB = legendi jaoks\r\n  \/\/ Mobiilil v\u00e4iksemad veerised\r\n  const isMobile = CW < 520;\r\n  const padL = isMobile ? 80 : 96;\r\n  const padR = isMobile ? 84 : 110;\r\n  const padT = isMobile ? 52 : 62;\r\n  const padB = isMobile ? 58 : 42;  \/\/ desktopil 1 rida legendile\r\n  const availW = CW - padL - padR;\r\n  const availH = CH - padT - padB;\r\n  const scale  = Math.min(availW \/ roomW, availH \/ roomD);\r\n  const rW = roomW * scale;\r\n  const rD = roomD * scale;\r\n  const ox = padL + (availW - rW) \/ 2;\r\n  const oy = padT;\r\n\r\n  \/\/ \u2500\u2500 RUUM \u2500\u2500\r\n  ctx.fillStyle = \"#f0f4f8\";\r\n  ctx.strokeStyle = \"#d1d5db\"; ctx.lineWidth = 1;\r\n  ctx.beginPath(); ctx.rect(ox, oy, rW, rD); ctx.fill(); ctx.stroke();\r\n\r\n  \/\/ Ekraanisein \u2013 \u00fclemine sein\r\n  \/\/ Sein \u2013 sama \u00f5huke hall joon kui teised seinad\r\n  ctx.strokeStyle = \"#d1d5db\"; ctx.lineWidth = 1;\r\n  ctx.beginPath(); ctx.moveTo(ox, oy); ctx.lineTo(ox + rW, oy); ctx.stroke();\r\n\r\n  \/\/ \u2500\u2500 RUUMI M\u00d5\u00d5DUD \u2500\u2500\r\n  \/\/ Laius: \u00fclevalpool ruumi, horisontaalselt keskel\r\n  ctx.fillStyle = \"#6b7280\"; ctx.font = (isMobile?\"9px\":\"11px\") + \" system-ui\"; ctx.textAlign = \"center\";\r\n  ctx.fillText(roomW + \" m\", ox + rW \/ 2, oy - 44);\r\n\r\n  \/\/ S\u00fcgavus: vasakul ruumist, vertikaalselt \u2013 paigutatakse LED siltide VASAKULE\r\n  \/\/ Kasutame cx = padL\/2 = 48px \u2013 ruumi serva ja LED siltide vahele\r\n  ctx.save();\r\n  ctx.translate(padL \/ 2 - 4, oy + rD \/ 2);\r\n  ctx.rotate(-Math.PI \/ 2);\r\n  ctx.textAlign = \"center\"; ctx.font = \"11px system-ui\"; ctx.fillStyle = \"#6b7280\";\r\n  ctx.fillText(roomD + \" m\", 0, 0);\r\n  ctx.restore();\r\n\r\n  \/\/ \u2500\u2500 EKRAANID \u00fclemise seina peal \u2500\u2500\r\n  const scrLedWm  = ((state.ledSize && state.ledSize.w) ? state.ledSize.w : (state.baseW || 2000)) \/ 1000;\r\n  const scrLedPxW = Math.min(scrLedWm * scale, rW);\r\n  const scrLedPxH = 7;\r\n  const scrLedX   = ox + rW \/ 2 - scrLedPxW \/ 2;\r\n  const scrLedY   = oy - scrLedPxH;\r\n\r\n  const scrLcdW   = (state.lcdSingle && state.lcdSingle.w) ? state.lcdSingle.w : 0;\r\n  const scrLcdPxW = scrLcdW ? Math.min(scrLcdW \/ 1000 * scale, rW) : 0;\r\n  const scrLcdPxH = 4;\r\n  const scrLcdX   = ox + rW \/ 2 - scrLcdPxW \/ 2;\r\n  const scrLcdY   = oy - scrLedPxH - scrLcdPxH;  \/\/ LCD vahetult LED riba peal\r\n\r\n  \/\/ LED riba (must)\r\n  ctx.fillStyle = \"#111827\";\r\n  ctx.fillRect(scrLedX, scrLedY, scrLedPxW, scrLedPxH);\r\n\r\n  \/\/ LCD riba (sinine) \u2013 kui olemas\r\n  if (scrLcdPxW > 0) {\r\n    ctx.fillStyle = \"rgba(59,130,246,0.65)\";\r\n    ctx.fillRect(scrLcdX, scrLcdY, scrLcdPxW, scrLcdPxH);\r\n  }\r\n\r\n  \/\/ Ekraani alumine serv k\u00f5rgus \u2013 paremal\r\n  if (screenH > 0) {\r\n    ctx.fillStyle = \"#9ca3af\"; ctx.font = \"10px system-ui\"; ctx.textAlign = \"left\";\r\n    ctx.fillText(screenH + \" m p\u00f5randast\", ox + rW + 6, oy + 12);\r\n  }\r\n\r\n  \/\/ \u2500\u2500 VAATEKAUGUSTE LOOGIKA \u2500\u2500\r\n  const pitchMm   = state.pitchMm || (state.dist ? state.dist \/ VAD_FACTOR : 2);\r\n  const userDistM = state.dist || 0;\r\n\r\n  \/\/ LED m\u00f5\u00f5dud \u2013 kasutame arvutatud ledSize m\u00f5\u00f5te (mm \u2192 m)\r\n  const ledWm   = ((state.ledSize && state.ledSize.w) ? state.ledSize.w : (state.baseW || 2000)) \/ 1000;\r\n  const ledHm   = ((state.ledSize && state.ledSize.h) ? state.ledSize.h : (state.baseH || 1500)) \/ 1000;\r\n  \/\/ Diagonaal on orientatsioonist s\u00f5ltumatu alus (6\u00d73 = 3\u00d76 = sama diagonaal)\r\n  const ledDiagM = Math.sqrt(ledWm * ledWm + ledHm * ledHm);\r\n\r\n  \/\/ LED vaatekaugused:\r\n  \/\/   min = pitchMm \u00d7 1.0        (l\u00e4him kaugus \u2013 piksleid enam ei erista)\r\n  \/\/   max = 5 \u00d7 diagonaal        (Lmax = k\u00d7diag, k=5 konservatiivne)\r\n  \/\/   opt = min(pitchMm\u00d73.44, max) (AVIXA VAD, kuid ei \u00fcleta max-i)\r\n  const ledMinM  = pitchMm * 1.0;\r\n  const ledMaxM  = 4 * ledDiagM;\r\n  const ledOptM  = Math.min(pitchMm * VAD_FACTOR, ledMaxM);\r\n\r\n  \/\/ LCD m\u00f5\u00f5dud \u2013 kasutame arvutatud lcdSingle m\u00f5\u00f5te (mm \u2192 m)\r\n  const lcdInch  = (state.lcdSingle && state.lcdSingle.inch) ? state.lcdSingle.inch : 55;\r\n  \/\/ LCD diagonaal: arvutatud lcdSingle.w ja .h p\u00f5hjal (kui olemas), muidu inch \u00d7 0.0254\r\n  const lcdWm    = (state.lcdSingle && state.lcdSingle.w) ? state.lcdSingle.w \/ 1000 : lcdInch * 0.0254 * 16 \/ Math.sqrt(256 + 81);\r\n  const lcdHm    = (state.lcdSingle && state.lcdSingle.h) ? state.lcdSingle.h \/ 1000 : lcdInch * 0.0254 * 9  \/ Math.sqrt(256 + 81);\r\n  const lcdDiagM = Math.sqrt(lcdWm * lcdWm + lcdHm * lcdHm);\r\n  \/\/ LCD vaatekaugused (16:9 ekraan, H = diag \u00d7 0.4903):\r\n  \/\/   opt = 3 \u00d7 H = 3 \u00d7 0.4903 \u00d7 diag \u2248 1.47 \u00d7 diag  (SMPTE soovituslik)\r\n  \/\/   max = 8 \u00d7 H = 8 \u00d7 0.4903 \u00d7 diag \u2248 3.92 \u00d7 diag  (Lmax = k\u00d7H, k=8)\r\n  \/\/ Kordajad teisendavad 8\u00d7H valemi diagonaali p\u00f5hjal, tulemused identsed\r\n  const LCD_H_RATIO = 9 \/ Math.sqrt(16*16 + 9*9);  \/\/ \u2248 0.4903\r\n  const lcdOptM  = lcdDiagM * 3.0 * LCD_H_RATIO;   \/\/ \u2248 diag \u00d7 1.47\r\n  const lcdMaxM  = lcdDiagM * 8.0 * LCD_H_RATIO;   \/\/ \u2248 diag \u00d7 3.92\r\n\r\n  function toPx(m) { return Math.min(Math.max(m * scale, 2), rD - 2); }\r\n\r\n  const ledMinY = oy + toPx(ledMinM);\r\n  const ledOptY = oy + toPx(ledOptM);\r\n  const ledMaxY = oy + toPx(ledMaxM);\r\n  const lcdOptY = oy + toPx(lcdOptM);\r\n  const lcdMaxY = oy + toPx(lcdMaxM);\r\n\r\n  \/\/ \u2500\u2500 LED TSOON \u2500\u2500\r\n  \/\/ min \u2192 max: kollane ala\r\n  ctx.fillStyle = \"rgba(220,233,0,0.18)\";\r\n  ctx.fillRect(ox, ledMinY, rW, Math.min(ledMaxY, oy + rD) - ledMinY);\r\n\r\n  \/\/ LED opt joon \u2013 katkendlik kollane\r\n  ctx.save(); ctx.setLineDash([6, 4]);\r\n  ctx.strokeStyle = \"#b8c200\"; ctx.lineWidth = 1.5;\r\n  ctx.beginPath(); ctx.moveTo(ox, ledOptY); ctx.lineTo(ox + rW, ledOptY); ctx.stroke();\r\n  ctx.restore();\r\n\r\n  \/\/ LED max joon \u2013 t\u00e4isjoon tumedam\r\n  if (ledMaxY < oy + rD - 2) {\r\n    ctx.strokeStyle = \"#8a9900\"; ctx.lineWidth = 2;\r\n    ctx.beginPath(); ctx.moveTo(ox, ledMaxY); ctx.lineTo(ox + rW, ledMaxY); ctx.stroke();\r\n  }\r\n\r\n  \/\/ LED min joon \u2013 \u00f5huke hall katkendlik\r\n  ctx.save(); ctx.setLineDash([3, 3]);\r\n  ctx.strokeStyle = \"rgba(150,150,150,0.50)\"; ctx.lineWidth = 1;\r\n  ctx.beginPath(); ctx.moveTo(ox, ledMinY); ctx.lineTo(ox + rW, ledMinY); ctx.stroke();\r\n  ctx.restore();\r\n\r\n  \/\/ \u2500\u2500 LCD TSOON \u2500\u2500\r\n  ctx.fillStyle = \"rgba(59,130,246,0.07)\";\r\n  ctx.fillRect(ox, oy, rW, Math.min(toPx(lcdMaxM), rD));\r\n\r\n  if (lcdMaxY < oy + rD - 4) {\r\n    ctx.save(); ctx.setLineDash([2, 4]);\r\n    ctx.strokeStyle = \"rgba(59,130,246,0.35)\"; ctx.lineWidth = 1;\r\n    ctx.beginPath(); ctx.moveTo(ox, lcdMaxY); ctx.lineTo(ox + rW, lcdMaxY); ctx.stroke();\r\n    ctx.restore();\r\n  }\r\n\r\n  \/\/ \u2500\u2500 DISCAS 60\u00b0 KOONUS (toggle-iga) \u2500\u2500\r\n  \/\/ Linnuplaani vaates: kaks joont ekraani vasakust ja paremast servast,\r\n  \/\/ l\u00e4hevad 60\u00b0 nurgaga ruumi s\u00fcgavusse kuni ruumi seina\/p\u00f5hjani.\r\n  \/\/ Ei kuvata min joont \u2013 ainult koonuse jooned.\r\n\r\n  const TAN60      = Math.tan(60 * Math.PI \/ 180);  \/\/ \u2248 1.732\r\n  const discasLedH = (ledWm \/ 2) \/ TAN60;\r\n  const discasLedV = (ledHm \/ 2) \/ TAN60;\r\n  const discasLedM = Math.max(discasLedH, discasLedV);\r\n  const discasLedY = oy + toPx(discasLedM);\r\n\r\n  const show60 = document.getElementById(\"toggle-60deg\")?.checked ?? true;\r\n\r\n  if (show60) {\r\n    const discasScrLeft  = scrLedX;\r\n    const discasScrRight = scrLedX + scrLedPxW;\r\n    const discasCx       = scrLedX + scrLedPxW \/ 2;  \/\/ ekraani keskpunkt\r\n\r\n    \/\/ DISCAS 60\u00b0: vasak joon algab PAREMAST servast ja l\u00e4heb VASAKULE 60\u00b0 all\r\n    \/\/             parem joon algab VASAKUST servast ja l\u00e4heb PAREMALE 60\u00b0 all\r\n    \/\/ Jooned ristuvad ekraani ees discasLedM kaugusel (cx-s)\r\n    \/\/ P\u00e4rast ristumist j\u00e4tkuvad sama nurgaga edasi kuni ruumi seina\/p\u00f5hjani\r\n\r\n    \/\/ Abifunktsioon: joon algab startX, liigub dir suunas tan60 nurgaga\r\n    \/\/ Tagastab l\u00f5pp-punkti (ruumi sein v\u00f5i p\u00f5hi) ja kauguse meetrites\r\n    function discasLine(startX, dir) {\r\n      \/\/ dx\/dy = dir * TAN60  \u2192 iga ruumipiksel alla = TAN60 pikslit k\u00fclgsuunas\r\n      \/\/ L\u00f5peb vasakul seinal (x=ox) v\u00f5i paremal (x=ox+rW) v\u00f5i p\u00f5hjas (y=oy+rD)\r\n      let tWall, endXWall;\r\n      if (dir < 0) {\r\n        tWall    = (startX - ox) \/ (TAN60 * 1);  \/\/ pikslid kuni vasaku seinani\r\n        endXWall = ox;\r\n      } else {\r\n        tWall    = (ox + rW - startX) \/ (TAN60 * 1);\r\n        endXWall = ox + rW;\r\n      }\r\n      const tFloor = rD;  \/\/ pikslid kuni p\u00f5hjani\r\n      const t      = Math.min(tWall, tFloor);\r\n      const endX   = t < tFloor ? endXWall : startX + dir * TAN60 * rD;\r\n      const endY   = oy + t;\r\n      const distM  = (t \/ scale);  \/\/ meetrites ekraanist\r\n      return { x: endX, y: endY, distM, hitsWall: t < tFloor };\r\n    }\r\n\r\n    \/\/ Vasak joon: algab paremast servast, l\u00e4heb vasakule\r\n    const dL = discasLine(discasScrRight, -1);\r\n    \/\/ Parem joon: algab vasakust servast, l\u00e4heb paremale\r\n    const dR = discasLine(discasScrLeft,  +1);\r\n\r\n    \/\/ Joonista jooned\r\n    ctx.strokeStyle = \"rgba(59,130,246,0.35)\"; ctx.lineWidth = 1.5;\r\n    ctx.beginPath(); ctx.moveTo(discasScrRight, oy); ctx.lineTo(dL.x, dL.y); ctx.stroke();\r\n    ctx.beginPath(); ctx.moveTo(discasScrLeft,  oy); ctx.lineTo(dR.x, dR.y); ctx.stroke();\r\n\r\n    \/\/ Ristumispunkt \u2013 v\u00e4ike ring\r\n    const crossY  = oy + toPx(discasLedM);\r\n    ctx.beginPath();\r\n    ctx.arc(discasCx, crossY, 4, 0, Math.PI * 2);\r\n    ctx.fillStyle = \"rgba(59,130,246,0.35)\"; ctx.fill();\r\n\r\n    \/\/ Seinajoone kaugus siltidena l\u00f5pp-punktides\r\n    ctx.font = \"10px system-ui\";\r\n    \/\/ DISCAS silt ainult paremal\r\n    if (dR.hitsWall) {\r\n      ctx.fillStyle = \"rgba(59,130,246,0.43)\"; ctx.textAlign = \"left\";\r\n      ctx.fillText(\"60\u00b0  \" + dR.distM.toFixed(1) + \" m\", dR.x + 4, dR.y - 3);\r\n    }\r\n  }\r\n\r\n  \/\/ \u2500\u2500 VAATENURGAD \u2013 30\u00b0 ja 45\u00b0 \u2500\u2500\r\n  \/\/ Alguspunkt: ekraani KESKPUNKT (cx, oy)\r\n  \/\/ Joon l\u00f5peb RUUMI K\u00dcLGSEINAL (x=ox v\u00f5i x=ox+rW) v\u00f5i p\u00f5hjas (y=oy+rD)\r\n  \/\/ kumb tuleb ette. L\u00f5ikumispunkt m\u00e4rgitakse kaugusena ekraanist.\r\n\r\n  const tan30 = Math.tan(30 * Math.PI \/ 180);\r\n  const tan45 = Math.tan(45 * Math.PI \/ 180);\r\n  const cx = ox + rW \/ 2;\r\n\r\n  \/\/ Abifunktsioon: leiab joonel\u00f5pu ja kauguse meetrites\r\n  \/\/ dir: +1 paremale, -1 vasakule\r\n  function coneEnd(tanA, dir) {\r\n    \/\/ Parameeter t \u2208 [0,1] kus t=1 on ruumi p\u00f5hi\r\n    \/\/ K\u00fclgsein: cx + dir*t*rD*tanA = (dir>0 ? ox+rW : ox)\r\n    const wallX   = dir > 0 ? ox + rW : ox;\r\n    const tWall   = (wallX - cx) \/ (dir * rD * tanA);\r\n    const tFloor  = 1.0;\r\n    const t       = Math.min(tWall, tFloor);\r\n    const endX    = cx + dir * t * rD * tanA;\r\n    const endY    = oy + t * rD;\r\n    const distM   = t * roomD;  \/\/ kaugus meetrites\r\n    const hitsWall = tWall <= tFloor;\r\n    return { x: endX, y: endY, distM, hitsWall };\r\n  }\r\n\r\n  const end30L = coneEnd(tan30, -1);\r\n  const end30R = coneEnd(tan30, +1);\r\n  const end45L = coneEnd(tan45, -1);\r\n  const end45R = coneEnd(tan45, +1);\r\n\r\n  if (show45) {\r\n  \/\/ 45\u00b0 t\u00e4idetud ala\r\n  ctx.beginPath();\r\n  ctx.moveTo(cx, oy);\r\n  ctx.lineTo(end45L.x, end45L.y);\r\n  if (end45L.hitsWall && end45R.hitsWall) {\r\n    ctx.lineTo(ox, oy + rD); ctx.lineTo(ox + rW, oy + rD);\r\n  }\r\n  ctx.lineTo(end45R.x, end45R.y);\r\n  ctx.closePath();\r\n  ctx.fillStyle = \"rgba(251,146,60,0.04)\"; ctx.fill();\r\n\r\n  \/\/ 45\u00b0 jooned\r\n  ctx.save(); ctx.setLineDash([5, 3]);\r\n  ctx.strokeStyle = \"rgba(251,146,60,0.28)\"; ctx.lineWidth = 1;\r\n  ctx.beginPath(); ctx.moveTo(cx, oy); ctx.lineTo(end45L.x, end45L.y); ctx.stroke();\r\n  ctx.beginPath(); ctx.moveTo(cx, oy); ctx.lineTo(end45R.x, end45R.y); ctx.stroke();\r\n  ctx.restore();\r\n\r\n  } \/\/ end show45\r\n\r\n  if (show30) {\r\n  \/\/ 30\u00b0 t\u00e4idetud ala\r\n  ctx.beginPath();\r\n  ctx.moveTo(cx, oy);\r\n  ctx.lineTo(end30L.x, end30L.y);\r\n  if (end30L.hitsWall && end30R.hitsWall) {\r\n    ctx.lineTo(ox, oy + rD); ctx.lineTo(ox + rW, oy + rD);\r\n  }\r\n  ctx.lineTo(end30R.x, end30R.y);\r\n  ctx.closePath();\r\n  ctx.fillStyle = \"rgba(251,146,60,0.07)\"; ctx.fill();\r\n\r\n  \/\/ 30\u00b0 jooned\r\n  ctx.strokeStyle = \"rgba(234,88,12,0.35)\"; ctx.lineWidth = 1.5;\r\n  ctx.beginPath(); ctx.moveTo(cx, oy); ctx.lineTo(end30L.x, end30L.y); ctx.stroke();\r\n  ctx.beginPath(); ctx.moveTo(cx, oy); ctx.lineTo(end30R.x, end30R.y); ctx.stroke();\r\n\r\n  } \/\/ end show30\r\n\r\n  \/\/ \u2500\u2500 KAUGUSE SILDID l\u00f5ikumispunktides \u2500\u2500\r\n  ctx.font = \"bold \" + (isMobile?\"9px\":\"10px\") + \" system-ui\";\r\n\r\n  if (show30) {\r\n  \/\/ 30\u00b0 silt \u2013 ainult paremal\r\n  ctx.fillStyle = \"rgba(200,70,10,0.43)\";\r\n  ctx.textAlign = end30R.hitsWall ? \"left\" : \"center\";\r\n  ctx.fillText(\"30\u00b0  \" + end30R.distM.toFixed(1) + \" m\", end30R.x + 4, end30R.y - 4);\r\n\r\n  } \/\/ end show30 labels\r\n\r\n  if (show45) {\r\n  \/\/ 45\u00b0 silt \u2013 ainult paremal\r\n  ctx.fillStyle = \"rgba(251,146,60,0.43)\";\r\n  ctx.textAlign = end45R.hitsWall ? \"left\" : \"center\";\r\n  ctx.fillText(\"45\u00b0  \" + end45R.distM.toFixed(1) + \" m\", end45R.x + 4, end45R.y + 12);\r\n\r\n  } \/\/ end show45 labels\r\n\r\n  \/\/ \u2500\u2500 SILDID \u2013 LED vasakul, LCD paremal \u2500\u2500\r\n  \/\/ Resolve overlaps: sorteeri Y, nihuta kattuvad\r\n  function resolveY(items, gap) {\r\n    items.sort((a, b) => a.y - b.y);\r\n    for (let i = 1; i < items.length; i++) {\r\n      if (items[i].y < items[i-1].y + gap) items[i].y = items[i-1].y + gap;\r\n    }\r\n    return items;\r\n  }\r\n\r\n  \/\/ LED sildid \u2013 paigutatakse ox ja padL vahele (piisavalt ruumi)\r\n  const ledLbls = [\r\n    { y: ledMinY,    text: \"LED min  \" + ledMinM.toFixed(1) + \" m\",    color: \"#9ca3af\" },\r\n    { y: ledOptY,    text: \"LED opt  \" + ledOptM.toFixed(1) + \" m\",    color: \"#6b7280\" },\r\n    { y: ledMaxY,    text: \"LED max  \" + ledMaxM.toFixed(1) + \" m\",    color: \"#374151\" },\r\n\r\n  ];\r\n  ctx.font = (isMobile?\"9px\":\"10px\") + \" system-ui\";\r\n  resolveY(ledLbls, isMobile ? 11 : 13).forEach(item => {\r\n    \/\/ L\u00fchike \u00fchendav joon\r\n    ctx.save(); ctx.setLineDash([1, 3]);\r\n    ctx.strokeStyle = \"rgba(160,160,160,0.4)\"; ctx.lineWidth = 1;\r\n    ctx.beginPath(); ctx.moveTo(ox - 4, item.y); ctx.lineTo(ox, item.y); ctx.stroke();\r\n    ctx.restore();\r\n    ctx.fillStyle = item.color; ctx.textAlign = \"right\";\r\n    ctx.fillText(item.text, ox - 6, item.y + 3);\r\n  });\r\n\r\n  \/\/ LCD max silt paremal\r\n  const lcdLbls = [];\r\n  if (lcdMaxY < oy + rD - 3) {\r\n    lcdLbls.push({ y: lcdMaxY, text: \"LCD max  \" + lcdMaxM.toFixed(1) + \" m\", color: \"rgba(59,130,246,0.75)\" });\r\n  }\r\n  resolveY(lcdLbls, isMobile ? 11 : 13).forEach(item => {\r\n    ctx.save(); ctx.setLineDash([1, 3]);\r\n    ctx.strokeStyle = \"rgba(160,160,160,0.4)\"; ctx.lineWidth = 1;\r\n    ctx.beginPath(); ctx.moveTo(ox + rW, item.y); ctx.lineTo(ox + rW + 4, item.y); ctx.stroke();\r\n    ctx.restore();\r\n    ctx.fillStyle = item.color; ctx.textAlign = \"left\";\r\n    ctx.fillText(item.text, ox + rW + 6, item.y + 3);\r\n  });\r\n\r\n  \/\/ \u2500\u2500 LEGEND \u2013 horisontaalselt KESKEL, canvas allosas \u2500\u2500\r\n  const legY  = oy + rD + 18;\r\n  ctx.font    = (isMobile?\"9px\":\"10px\") + \" system-ui\";\r\n\r\n  \/\/ Kogu legendi laius arvutus\r\n  const items = [\r\n    { type: \"box\",  color: \"rgba(220,233,0,0.40)\",  stroke: \"rgba(180,200,0,0.6)\",   label: \"LED optimaalne tsoon\" },\r\n    { type: \"dash\", color: \"#b8c200\",                label: \"LED opt kaugus\" },\r\n    { type: \"line\", color: \"#8a9900\",                label: \"LED max kaugus\" },\r\n    { type: \"box\",  color: \"rgba(59,130,246,0.18)\",  stroke: \"rgba(59,130,246,0.4)\", label: \"LCD kasutatav ala\" },\r\n    { type: \"box\",  color: \"rgba(251,146,60,0.20)\",  stroke: \"rgba(251,146,60,0.6)\", label: \"30\u00b0 vaatenurk\" },\r\n    { type: \"dbox\", color: \"rgba(251,146,60,0.10)\",  stroke: \"rgba(251,146,60,0.4)\", label: \"45\u00b0 vaatenurk\" },\r\n    { type: \"box\",  color: \"rgba(59,130,246,0.12)\",  stroke: \"rgba(59,130,246,0.55)\", label: \"DISCAS 60\u00b0\" },\r\n  ];\r\n\r\n  \/\/ M\u00f5\u00f5da iga elemendi laius: 14px s\u00fcmbol + 4px vahe + tekst + 16px item-vahe\r\n  \/\/ Legend \u2013 desktopil k\u00f5ik \u00fchel real, mobiilil 2 elementi reas\r\n  const legRowH    = isMobile ? 16 : 18;\r\n  const itemsPerRow = isMobile ? 2 : items.length;  \/\/ desktop: 1 rida, mobil: 2\/reas\r\n  const legColW    = Math.floor((CW - padL - 8) \/ itemsPerRow);\r\n\r\n  items.forEach((it, i) => {\r\n    const legRow = Math.floor(i \/ itemsPerRow);\r\n    const legCol = i % itemsPerRow;\r\n    const lx = padL + legCol * legColW;\r\n    const currentLegY = legY + legRow * legRowH;\r\n    const symW = 14;\r\n    if (it.type === \"box\" || it.type === \"dbox\") {\r\n      ctx.fillStyle = it.color;\r\n      ctx.fillRect(lx, currentLegY, symW, 10);\r\n      if (it.type === \"dbox\") {\r\n        ctx.save(); ctx.setLineDash([3,2]);\r\n        ctx.strokeStyle = it.stroke; ctx.lineWidth = 1;\r\n        ctx.strokeRect(lx, currentLegY, symW, 10);\r\n        ctx.restore();\r\n      } else {\r\n        ctx.strokeStyle = it.stroke; ctx.lineWidth = 1;\r\n        ctx.strokeRect(lx, legY, symW, 10);\r\n      }\r\n    } else if (it.type === \"dash\") {\r\n      ctx.save(); ctx.setLineDash([5, 3]);\r\n      ctx.strokeStyle = it.color; ctx.lineWidth = 1.5;\r\n      ctx.beginPath(); ctx.moveTo(lx, currentLegY + 5); ctx.lineTo(lx + symW, currentLegY + 5); ctx.stroke();\r\n      ctx.restore();\r\n    } else {\r\n      ctx.strokeStyle = it.color; ctx.lineWidth = 2;\r\n      ctx.beginPath(); ctx.moveTo(lx, currentLegY + 5); ctx.lineTo(lx + symW, currentLegY + 5); ctx.stroke();\r\n    }\r\n    ctx.fillStyle = \"#6b7280\"; ctx.textAlign = \"left\";\r\n    ctx.fillText(it.label, lx + symW + 4, currentLegY + 8);\r\n  });  \/\/ end legend forEach\r\n\r\n  \/\/ \u2500\u2500 HINT \u2500\u2500\r\n  if (hint) {\r\n    hint.textContent =\r\n      \"LED: min \" + ledMinM.toFixed(1) + \" m  \u00b7  opt \" + ledOptM.toFixed(1) + \" m  \u00b7  max \" + ledMaxM.toFixed(1) + \" m  (P\" + pitchMm + \" mm)    \" +\r\n      \"LCD \" + lcdInch + \"\\\": kasutatav kuni \" + lcdMaxM.toFixed(1) + \" m    \" +\r\n      \"\";\r\n  }\r\n}\r\n\r\n\/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\r\n   QR KOOD\r\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 *\/\r\nfunction buildParamURL() {\r\n  const base = window.location.href.split(\"?\")[0].split(\"#\")[0];\r\n  const p = new URLSearchParams();\r\n  if(state.dist)      p.set(\"dist\",    state.dist);\r\n  if(state.content)   p.set(\"content\", state.content);\r\n  if(state.envAvixa)  p.set(\"env1\",    state.envAvixa);\r\n  if(state.env)       p.set(\"env2\",    state.env);\r\n  if(state.baseW)     p.set(\"w\",       state.baseW);\r\n  if(state.baseH)     p.set(\"h\",       state.baseH);\r\n  if(state.pitchMm)   p.set(\"pitch\",   state.pitchMm);\r\n  if(state.lcdOrient) p.set(\"orient\",  state.lcdOrient);\r\n  return base + \"?\" + p.toString();\r\n}\r\n\r\n\r\n\/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\r\n   E-MAIL EKSPORT (EmailJS)\r\n   NB: asenda PUBLIC_KEY, SERVICE_ID ja TEMPLATE_ID\r\n       oma EmailJS konto v\u00e4\u00e4rtustega\r\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 *\/\r\nconst EMAILJS_PUBLIC_KEY  = \"YOUR_PUBLIC_KEY\";   \/\/ \u2190 asenda\r\nconst EMAILJS_SERVICE_ID  = \"YOUR_SERVICE_ID\";   \/\/ \u2190 asenda\r\n\r\nfunction loadEmailJS(cb) {\r\n  if(window.emailjs){ cb(); return; }\r\n  const s = document.createElement(\"script\");\r\n  s.src = \"https:\/\/cdn.jsdelivr.net\/npm\/@emailjs\/browser@4\/dist\/email.min.js\";\r\n  s.onload = () => { emailjs.init(EMAILJS_PUBLIC_KEY); cb(); };\r\n  s.onerror = () => cb(new Error(\"EmailJS laadimine eba\u00f5nnestus\"));\r\n  document.head.appendChild(s);\r\n}\r\n\r\n\/\/ Kliendile l\u00e4heb kokkuv\u00f5te, Lumepixile l\u00e4heb lead + kontaktandmed\r\n\/\/ Kasuta kahte eraldi EmailJS malli:\r\n\/\/   EMAILJS_TEMPLATE_CLIENT  \u2013 kliendile (to_email = kliendi aadress)\r\n\/\/   EMAILJS_TEMPLATE_LEAD    \u2013 Lumepixile (to_email = LUMEPIX_EMAIL)\r\nconst LUMEPIX_EMAIL           = \"info@lumepix.ee\";          \/\/ \u2190 Lumepix'i sisend-email\r\nconst EMAILJS_TEMPLATE_CLIENT = \"YOUR_TEMPLATE_CLIENT\";     \/\/ \u2190 asenda: mall kliendile\r\nconst EMAILJS_TEMPLATE_LEAD   = \"YOUR_TEMPLATE_LEAD\";       \/\/ \u2190 asenda: mall Lumepixile\r\n\r\nfunction sendExportEmail(email, name) {\r\n  return new Promise((resolve, reject) => {\r\n    loadEmailJS((err) => {\r\n      if(err){ reject(err); return; }\r\n\r\n      const sharedParams = {\r\n        client_name:  name || \"\u2013\",\r\n        client_email: email,\r\n        pitch_text:   state.pitchText || \"\u2013\",\r\n        led_text:     state.ledText   || \"\u2013\",\r\n        lcd_text:     state.lcdText   || \"\u2013\",\r\n        env:          state.env       || \"\u2013\",\r\n        base_w:       state.baseW     || \"\u2013\",\r\n        base_h:       state.baseH     || \"\u2013\",\r\n      };\r\n\r\n      \/\/ Kliendile \u2013 personaliseerin\r\n      const clientParams = { ...sharedParams, to_email: email, to_name: name || \"Lugupeetud klient\" };\r\n      \/\/ Lumepixile \u2013 lead-teade\r\n      const leadParams   = { ...sharedParams, to_email: LUMEPIX_EMAIL, to_name: \"Lumepix meeskond\" };\r\n\r\n      \/\/ Saadame m\u00f5lemad paralleelselt\r\n      Promise.all([\r\n        emailjs.send(EMAILJS_SERVICE_ID, EMAILJS_TEMPLATE_CLIENT, clientParams),\r\n        emailjs.send(EMAILJS_SERVICE_ID, EMAILJS_TEMPLATE_LEAD,   leadParams)\r\n      ]).then(() => resolve()).catch(reject);\r\n    });\r\n  });\r\n}\r\n\r\n\/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\r\n   URL PARAMEETRITE LUGEMINE (eelt\u00e4itmine)\r\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 *\/\r\nfunction readURLParams() {\r\n  const p = new URLSearchParams(window.location.search);\r\n  if(p.has(\"dist\")){\r\n    const inp = document.getElementById(\"view-distance-avixa\");\r\n    if(inp) inp.value = p.get(\"dist\");\r\n  }\r\n  if(p.has(\"content\")){\r\n    const sel = document.getElementById(\"content-type-avixa\");\r\n    if(sel) sel.value = p.get(\"content\");\r\n  }\r\n  if(p.has(\"env1\")){\r\n    const sel = document.getElementById(\"env-type-avixa\");\r\n    if(sel) sel.value = p.get(\"env1\");\r\n  }\r\n  if(p.has(\"env2\")){\r\n    const sel = document.getElementById(\"env\");\r\n    if(sel) sel.value = p.get(\"env2\");\r\n    fillPitchDropdown(p.get(\"env2\"));\r\n  }\r\n  if(p.has(\"w\")){\r\n    const inp = document.getElementById(\"base-width\");\r\n    if(inp) inp.value = p.get(\"w\");\r\n  }\r\n  if(p.has(\"h\")){\r\n    const inp = document.getElementById(\"base-height\");\r\n    if(inp) inp.value = p.get(\"h\");\r\n  }\r\n  if(p.has(\"pitch\")){\r\n    const sel = document.getElementById(\"led-pitch\");\r\n    if(sel) sel.value = p.get(\"pitch\");\r\n  }\r\n  if(p.has(\"orient\")){\r\n    const sel = document.getElementById(\"lcd-orient\");\r\n    if(sel) sel.value = p.get(\"orient\");\r\n  }\r\n}\r\n\r\n\/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\r\n   TULEMUSTE KUVAMINE (samm 3)\r\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 *\/\r\nfunction showResult(el,html){ if(!el)return; el.classList.remove(\"lp-result-hidden\"); el.innerHTML=html; }\r\nfunction showSection(id){ const el=document.getElementById(id); if(el)el.classList.remove(\"lp-result-hidden\"); }\r\n\r\n\/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\r\n   INIT\r\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 *\/\r\ndocument.addEventListener(\"DOMContentLoaded\", function () {\r\n  initPitchScale();\r\n  updatePitchVisual(0);\r\n  fillPitchDropdown(\"indoor\");\r\n  setWizardStep(1);\r\n  readURLParams();\r\n\r\n  const pitchForm   = document.getElementById(\"lp-pitch-form-avixa\");\r\n  const pitchResult = document.getElementById(\"lp-pitch-result-avixa\");\r\n  const distInput   = document.getElementById(\"view-distance-avixa\");\r\n  const contentSel  = document.getElementById(\"content-type-avixa\");\r\n  const envSelAvixa = document.getElementById(\"env-type-avixa\");\r\n\r\n  const sizeForm    = document.getElementById(\"lp-size-form\");\r\n  const sizeResult  = document.getElementById(\"lp-size-result\");\r\n  const envSelect   = document.getElementById(\"env\");\r\n\r\n  \/* \u2500\u2500 EELSEADISTUSED \u2500\u2500 *\/\r\n  document.querySelectorAll(\".lp-preset-btn\").forEach(btn => {\r\n    btn.addEventListener(\"click\", function () {\r\n      document.querySelectorAll(\".lp-preset-btn\").forEach(b=>b.classList.remove(\"lp-preset-active\"));\r\n      btn.classList.add(\"lp-preset-active\");\r\n\r\n      const pr = PRESETS[btn.dataset.preset];\r\n      if(!pr)return;\r\n\r\n      if(distInput)      distInput.value    = pr.dist;\r\n      if(contentSel)     contentSel.value   = pr.content;\r\n      if(envSelAvixa)    envSelAvixa.value  = pr.envAvixa;\r\n      if(envSelect)      envSelect.value    = pr.env;\r\n\r\n      const bwEl=document.getElementById(\"base-width\");\r\n      const bhEl=document.getElementById(\"base-height\");\r\n      const orEl=document.getElementById(\"lcd-orient\");\r\n      if(bwEl) bwEl.value = pr.w;\r\n      if(bhEl) bhEl.value = pr.h;\r\n      if(orEl) orEl.value = pr.orient;\r\n\r\n      fillPitchDropdown(pr.env);\r\n      updatePitchVisual(pr.dist);\r\n    });\r\n  });\r\n\r\n  \/* \u2500\u2500 PIKSLISAMMU VISUAAL REALTIME \u2500\u2500 *\/\r\n  if(distInput){\r\n    distInput.addEventListener(\"input\", function(){\r\n      const v=parseFloat(distInput.value);\r\n      updatePitchVisual(v>0?v:0);\r\n    });\r\n  }\r\n\r\n  \/* \u2500\u2500 ENV S\u00dcNKRONISEERIMINE \u2500\u2500 *\/\r\n  if(envSelAvixa&&envSelect){\r\n    envSelAvixa.addEventListener(\"change\", function(){\r\n      const mapped=envSelAvixa.value===\"outdoor\"?\"outdoor\":\"indoor\";\r\n      envSelect.value=mapped; fillPitchDropdown(mapped);\r\n    });\r\n  }\r\n  if(envSelect){\r\n    envSelect.addEventListener(\"change\", function(){ fillPitchDropdown(envSelect.value); });\r\n  }\r\n\r\n  \/* \u2500\u2500 SAMM 1: PIKSLISAMMU ARVUTUS \u2500\u2500 *\/\r\n  if(pitchForm&&pitchResult){\r\n    pitchForm.addEventListener(\"submit\", function(e){\r\n      e.preventDefault();\r\n      const dist=parseFloat(distInput.value);\r\n      if(!dist||dist<=0){\r\n        showResult(pitchResult,\"Palun sisesta vaatekaugus meetrites (nt 7).\");\r\n        updatePitchVisual(0); return;\r\n      }\r\n      updatePitchVisual(dist);\r\n\r\n      const contentType = contentSel.value;\r\n      const envType     = envSelAvixa.value;\r\n      const vadMm       = nearestPitch(dist\/VAD_FACTOR);\r\n      const acdMm       = nearestPitch(dist\/ACD_FACTOR);\r\n      const affordMm    = nearestPitch(dist);\r\n      const envText     = getEnvText(envType);\r\n\r\n      let mainBlock=\"\", chosenMm=null;\r\n      if(contentType===\"detail\"){\r\n        chosenMm=vadMm;\r\n        mainBlock=\"<p><strong>AVIXA Visual Acuity Distance \u2013 maksimaalne detailsus<\/strong><br>Soovituslik pikslisamm detailse sisu jaoks: <strong>\"+formatPitch(vadMm)+\"<\/strong> (\"+formatMm(vadMm)+\" mm).<\/p>\";\r\n      } else if(contentType===\"mix\"){\r\n        chosenMm=acdMm;\r\n        mainBlock=\"<p><strong>AVIXA Average Comfortable Viewing Distance \u2013 segasisu<\/strong><br>Soovituslik pikslisamm (video + tekst): <strong>\"+formatPitch(acdMm)+\"<\/strong> (\"+formatMm(acdMm)+\" mm).<\/p>\";\r\n      } else {\r\n        chosenMm=affordMm;\r\n        mainBlock=\"<p><strong>Minimaalne vaatamiskaugus (br\u00e4nding)<\/strong><br>Pikslisamm: <strong>\"+formatPitch(affordMm)+\"<\/strong> (\"+formatMm(affordMm)+\" mm). Sobib logode, suurte s\u00fcmbolite kuvamiseks.<\/p>\";\r\n      }\r\n\r\n      const html=\"<h3 style='margin:0 0 8px;font-size:14px;'>Soovituslik pikslisamm<\/h3>\"+mainBlock+\r\n        \"<hr style='border:none;border-top:1px dashed rgba(0,0,0,.15);margin:10px 0;'>\"+\r\n        \"<p><strong>Keskkonna heledus:<\/strong> \"+envText.title+\"<\/p><p>\"+envText.text+\"<\/p>\"+\r\n        \"<small>Arvutused p\u00f5hinevad AVIXA juhistel ja Lumepix'i praktilistel kogemustel. \"+\r\n        \"L\u00f5plik pitch s\u00f5ltub ka ekraani suurusest, sisust ja eelarvest \u2013 sobivaima lahenduse leiame koos.<\/small>\";\r\n\r\n      showResult(pitchResult, html);\r\n\r\n      \/\/ Olek\r\n      state.dist=dist; state.content=contentType; state.envAvixa=envType;\r\n      state.pitchMm = chosenMm;\r\n      state.pitchText = formatPitch(chosenMm)+\" (\"+formatMm(chosenMm)+\" mm) \u2013 \"+envText.title;\r\n\r\n      \/\/ Sync env + pitch dropdown\r\n      if(envSelect){\r\n        const mapped=envType===\"outdoor\"?\"outdoor\":\"indoor\";\r\n        envSelect.value=mapped; fillPitchDropdown(mapped);\r\n      }\r\n      syncPitchDropdown(chosenMm);\r\n\r\n      \/\/ Samm 2 avaneb\r\n      setWizardStep(2);\r\n    });\r\n  }\r\n\r\n  \/* \u2500\u2500 SAMM 2: M\u00d5\u00d5DUSOBIVUSE ARVUTUS \u2500\u2500 *\/\r\n  if(sizeForm&&sizeResult){\r\n    sizeForm.addEventListener(\"submit\", function(e){\r\n      e.preventDefault();\r\n      const bw     = parseFloat(document.getElementById(\"base-width\").value);\r\n      const bh     = parseFloat(document.getElementById(\"base-height\").value);\r\n      const pitch  = parseFloat(document.getElementById(\"led-pitch\").value);\r\n      const orient = document.getElementById(\"lcd-orient\").value;\r\n      const env    = envSelect?envSelect.value:\"indoor\";\r\n\r\n      if(!bw||!bh||bw<=0||bh<=0){\r\n        showResult(sizeResult,\"Palun sisesta korrektsed aluspinna m\u00f5\u00f5dud millimeetrites.\"); return;\r\n      }\r\n      if(!pitch||pitch<=0){\r\n        showResult(sizeResult,\"Palun vali LED pixel pitch.\"); return;\r\n      }\r\n      if(env===\"outdoor\"&&pitch<2.5){\r\n        showResult(sizeResult,\"V\u00e4liekraani puhul on minimaalne pikslisamm P2.5.\"); return;\r\n      }\r\n\r\n      const ledStep    = env===\"outdoor\"?320:250;\r\n      const envLabel   = env===\"outdoor\"?\"v\u00e4litingimused\":\"siseruum\";\r\n      const ledSize    = calcLedSize(bw,bh,ledStep);\r\n      const lcdSingle  = calcLcdSize(bw,bh,orient,env);\r\n      const videoWall  = calcVideoWall(bw,bh,orient,env);\r\n\r\n      \/* LED tekst *\/\r\n      let ledText;\r\n      if(!ledSize){\r\n        const min=ledStep*2;\r\n        ledText=\"<strong>LED ekraan (\"+envLabel+\"):<\/strong> Pind on v\u00e4iksem kui minimaalne moodulite kombinatsioon (\"+min+\"\u00d7\"+min+\" mm, samm \"+ledStep+\" mm).\";\r\n      } else {\r\n        const res=calcLedRes(ledSize.w,ledSize.h,pitch);\r\n        const ol=isPortrait(ledSize.w,ledSize.h)?\" (vertikaalne)\":\" (horisontaalne)\";\r\n        ledText=\"<strong>LED ekraan (\"+envLabel+\"):<\/strong> \"+ledSize.w+\"\u00d7\"+ledSize.h+\" mm\"+ol+\r\n          \", moodulisamm \"+ledStep+\" mm, pitch P\"+String(pitch).replace(\".\",\",\")+\r\n          \"<br>Ligikaudne resolutsioon: \"+res.wPx+\"\u00d7\"+res.hPx+\" px.\";\r\n      }\r\n\r\n      \/* LCD tekst *\/\r\n      let lcdText;\r\n      if(!lcdSingle&&!videoWall){\r\n        lcdText=env===\"outdoor\"\r\n          ?\"<strong>V\u00e4liekraan (LCD):<\/strong> \u00dckski saadaolev v\u00e4liekraan (22\\\", 46\\\", 55\\\", 75\\\") ega videosein ei mahu antud m\u00f5\u00f5tudesse.\"\r\n          :\"<strong>LCD lahendus (siseruum):<\/strong> \u00dckski standardne siseekraan ei mahu antud m\u00f5\u00f5tudesse valitud orientatsiooniga.\";\r\n      } else {\r\n        const parts=[];\r\n        if(lcdSingle){\r\n          const ol=isPortrait(lcdSingle.w,lcdSingle.h)?\" (vertikaalne)\":\" (horisontaalne)\";\r\n          parts.push(\"<strong>\"+(env===\"outdoor\"?\"\u00dcksik v\u00e4liekraan\":\"\u00dcksik LCD ekraan (siseruum)\")+\":<\/strong> \"+\r\n            lcdSingle.inch+\"\\\" (\"+Math.round(lcdSingle.w)+\"\u00d7\"+Math.round(lcdSingle.h)+\" mm\"+ol+\").\");\r\n        }\r\n        if(videoWall){\r\n          const ol=isPortrait(videoWall.w,videoWall.h)?\" (vertikaalne)\":\" (horisontaalne)\";\r\n          const wl=env===\"outdoor\"?\"<strong>Alternatiiv \u2013 v\u00e4liekraanide videosein:<\/strong>\":\"<strong>Alternatiiv \u2013 LCD videosein:<\/strong>\";\r\n          const wn=env===\"outdoor\"?\"Videoseina moodustame raamideta v\u00e4liekraanidest Lumepix'i lahendusest.\":\"Videoseina moodustame raamideta LCD ekraanidest Lumepix'i lahendusest.\";\r\n          parts.push(wl+\" \"+videoWall.cols+\"\u00d7\"+videoWall.rows+\" paneeli, paneeli diagonaal u \"+videoWall.inch+\"\\\"; kogum\u00f5\u00f5t \"+\r\n            Math.round(videoWall.w)+\"\u00d7\"+Math.round(videoWall.h)+\" mm\"+ol+\r\n            \".<br><em style='font-size:11px;'>\"+wn+\"<\/em>\");\r\n        }\r\n        lcdText=parts.join(\"<br><br>\");\r\n      }\r\n\r\n      \/\/ Olek\r\n      state.baseW=bw; state.baseH=bh; state.ledSize=ledSize;\r\n      state.lcdSingle=lcdSingle; state.wallSize=videoWall; state.ledStep=ledStep;\r\n      state.env=env; state.pitchMm=pitch; state.lcdOrient=orient;\r\n      state.ledText=ledText.replace(\/<[^>]+>\/g,\" \").replace(\/\\s+\/g,\" \").trim();\r\n      state.lcdText=lcdText.replace(\/<[^>]+>\/g,\" \").replace(\/\\s+\/g,\" \").trim();\r\n\r\n      \/\/ Kuva\r\n      redrawVisual();\r\n      showResult(sizeResult, ledText+\"<br><br>\"+lcdText);\r\n\r\n      \/\/ Uuenda ruumiplaan automaatselt kui ruumi m\u00f5\u00f5dud on t\u00e4idetud\r\n      const rwEl = document.getElementById(\"room-w\");\r\n      const rdEl = document.getElementById(\"room-d\");\r\n      const rhEl = document.getElementById(\"room-h\");\r\n      if (rwEl && rdEl && parseFloat(rwEl.value) > 0 && parseFloat(rdEl.value) > 0) {\r\n        drawRoomPlan(parseFloat(rwEl.value), parseFloat(rdEl.value), parseFloat(rhEl?.value)||0, document.getElementById('toggle-30deg')?.checked ?? true, document.getElementById('toggle-45deg')?.checked ?? true);\r\n      }\r\n\r\n      \/\/ Sektsioonid\r\n      showSection(\"lp-room-section\");\r\n      showSection(\"lp-export-section\");\r\n\r\n      \/\/ Samm 3\r\n      setWizardStep(3);\r\n    });\r\n  }\r\n\r\n  \/* \u2500\u2500 TOGGLE'ID \u2500\u2500 *\/\r\n  [\"toggle-led\",\"toggle-lcd\",\"toggle-wall\"].forEach(id=>{\r\n    const el=document.getElementById(id);\r\n    if(el)el.addEventListener(\"change\",redrawVisual);\r\n  });\r\n\r\n  \/\/ Vaatenurga toggle'id \u2013 uuendavad ruumiplaani\r\n  [\"toggle-30deg\",\"toggle-45deg\",\"toggle-60deg\"].forEach(function(id){\r\n    const el = document.getElementById(id);\r\n    if (!el) return;\r\n    el.addEventListener(\"change\", function() {\r\n      const rwEl = document.getElementById(\"room-w\");\r\n      const rdEl = document.getElementById(\"room-d\");\r\n      const rhEl = document.getElementById(\"room-h\");\r\n      if (rwEl && rdEl && parseFloat(rwEl.value) > 0 && parseFloat(rdEl.value) > 0) {\r\n        drawRoomPlan(\r\n          parseFloat(rwEl.value), parseFloat(rdEl.value), parseFloat(rhEl?.value)||0,\r\n          document.getElementById(\"toggle-30deg\")?.checked ?? true,\r\n          document.getElementById(\"toggle-45deg\")?.checked ?? true\r\n        );\r\n      }\r\n    });\r\n  });\r\n\r\n  \/* \u2500\u2500 RUUMIPLAAN \u2500\u2500 *\/\r\n  document.getElementById(\"btn-room\")?.addEventListener(\"click\", function(){\r\n    const rw=parseFloat(document.getElementById(\"room-w\").value);\r\n    const rd=parseFloat(document.getElementById(\"room-d\").value);\r\n    const rh=parseFloat(document.getElementById(\"room-h\").value)||0;\r\n    if(!rw||!rd||rw<=0||rd<=0){\r\n      const hint=document.getElementById(\"lp-room-hint\");\r\n      if(hint)hint.textContent=\"Palun sisesta ruumi laius ja s\u00fcgavus meetrites.\";\r\n      return;\r\n    }\r\n    drawRoomPlan(rw, rd, rh,\r\n      document.getElementById('toggle-30deg')?.checked ?? true,\r\n      document.getElementById('toggle-45deg')?.checked ?? true);\r\n  });\r\n\r\n  \/* \u2500\u2500 E-MAIL EKSPORT \u2500\u2500 *\/\r\n  \/\/ \u2500\u2500 CF7 VORM + PDF GENEREERIMINE \u2500\u2500\r\n  document.getElementById(\"lp-cf7-form\")?.addEventListener(\"submit\", function(e) {\r\n    e.preventDefault();\r\n\r\n    const statusEl = document.getElementById(\"export-status\");\r\n    const btn      = document.getElementById(\"btn-export\");\r\n    const name     = document.getElementById(\"cf7-name\")?.value.trim();\r\n    const email    = document.getElementById(\"cf7-email\")?.value.trim();\r\n\r\n    \/\/ Valideerimine\r\n    if (!name) {\r\n      statusEl.textContent = \"Palun sisesta oma nimi.\";\r\n      statusEl.className   = \"lp-export-status error\"; return;\r\n    }\r\n    if (!email || !\/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$\/.test(email)) {\r\n      statusEl.textContent = \"Palun sisesta korrektne e-posti aadress.\";\r\n      statusEl.className   = \"lp-export-status error\"; return;\r\n    }\r\n    if (!state.baseW) {\r\n      statusEl.textContent = \"Palun arvuta esmalt tulemused (samm 2).\";\r\n      statusEl.className   = \"lp-export-status error\"; return;\r\n    }\r\n\r\n    \/\/ T\u00e4ida peidetud CF7 v\u00e4ljad kalkulaatori tulemusandmetega\r\n    document.getElementById(\"cf7-pitch\").value = state.pitchText  || \"\u2013\";\r\n    document.getElementById(\"cf7-led\").value   = state.ledText    || \"\u2013\";\r\n    document.getElementById(\"cf7-lcd\").value   = state.lcdText    || \"\u2013\";\r\n    document.getElementById(\"cf7-env\").value   = state.env        || \"\u2013\";\r\n    document.getElementById(\"cf7-dims\").value  = (state.baseW || \"\u2013\") + \" \u00d7 \" + (state.baseH || \"\u2013\") + \" mm\";\r\n\r\n    \/\/ CF7 unit tag (unikaalne iga saatmise jaoks)\r\n    document.getElementById(\"lp-unit-tag\").value = \"wpcf7-f14410-p0-o\" + Date.now();\r\n\r\n    btn.disabled    = true;\r\n    btn.textContent = \"Saadan...\";\r\n    statusEl.textContent = \"\";\r\n    statusEl.className   = \"lp-export-status\";\r\n\r\n    \/\/ Saada CF7 REST API kaudu (CF7 v5+)\r\n    \/\/ Endpoint: \/wp-json\/contact-form-7\/v1\/contact-forms\/{id}\/feedback\r\n    const formData = new FormData(document.getElementById(\"lp-cf7-form\"));\r\n\r\n    \/\/ CF7 saatmine \u2013 kasuta CF7 enda wpcf7 globaalset objekti kui olemas\r\n    \/\/ CF7 lisab window.wpcf7 automaatselt kui plugin on aktiivne\r\n    \/\/ functions.php snippet seadistab window.lp_cf7_rest ja window.lp_cf7_nonce\r\n\r\n    \/\/ Proovi URL j\u00e4rgmises j\u00e4rjekorras:\r\n    \/\/ 1. window.lp_cf7_rest (functions.php snippet)\r\n    \/\/ 2. window.wpcf7 objekt (CF7 enda global)\r\n    \/\/ 3. Suhteline URL \/wp-json\/...\r\n    let cf7Url = window.lp_cf7_rest || null;\r\n    if (!cf7Url && window.wpcf7) {\r\n      cf7Url = window.wpcf7.apiSettings?.root + \"contact-form-7\/v1\/contact-forms\/14410\/feedback\";\r\n    }\r\n    if (!cf7Url) {\r\n      cf7Url = \"\/wp-json\/contact-form-7\/v1\/contact-forms\/14410\/feedback\";\r\n    }\r\n\r\n    const cf7Nonce = window.lp_cf7_nonce\r\n      || (window.wpApiSettings && window.wpApiSettings.nonce)\r\n      || \"\";\r\n\r\n    \/\/ DEBUG \u2013 n\u00e4htav brauseri konsoolis (F12 \u2192 Console)\r\n    console.log(\"LP Debug:\", {\r\n      cf7Url,\r\n      cf7Nonce: cf7Nonce ? \"OK (\"+cf7Nonce.length+\"chars)\" : \"PUUDUB\",\r\n      lp_cf7_rest:  window.lp_cf7_rest  || \"pole seadistatud\",\r\n      lp_cf7_nonce: window.lp_cf7_nonce || \"pole seadistatud\",\r\n      wpcf7: window.wpcf7 ? \"olemas\" : \"puudub\",\r\n      wpApiSettings: window.wpApiSettings ? \"olemas\" : \"puudub\"\r\n    });\r\n\r\n    fetch(cf7Url, {\r\n      method: \"POST\",\r\n      body: formData,\r\n      credentials: \"same-origin\",\r\n      headers: {\r\n        \"X-WP-Nonce\": cf7Nonce\r\n      }\r\n    })\r\n    .then(r => {\r\n      if (!r.ok && r.status !== 200) throw new Error(\"HTTP \" + r.status);\r\n      return r.json();\r\n    })\r\n    .then(data => {\r\n      if (data.status === \"mail_sent\") {\r\n        statusEl.textContent = \"\u2713 Saadetud! PDF laaditakse alla...\";\r\n        statusEl.className   = \"lp-export-status ok\";\r\n        btn.disabled    = false;\r\n        btn.textContent = \"SAADA JA LAE PDF\";\r\n        setTimeout(() => generatePDF(name, email), 400);\r\n\r\n      } else if (data.status === \"mail_failed\") {\r\n        \/\/ CF7 sai p\u00e4ringu aga mail eba\u00f5nnestus \u2013 PDF ikkagi alla\r\n        statusEl.textContent = \"\u26a0\ufe0f E-kirja saatmine eba\u00f5nnestus, kuid PDF laaditakse alla. V\u00f5ta Lumepixiga \u00fchendust.\";\r\n        statusEl.className   = \"lp-export-status error\";\r\n        btn.disabled    = false;\r\n        btn.textContent = \"SAADA JA LAE PDF\";\r\n        setTimeout(() => generatePDF(name, email), 400);\r\n\r\n      } else if (data.status === \"validation_failed\") {\r\n        const msgs = data.invalid_fields\r\n          ? data.invalid_fields.map(f => f.message).join(\", \")\r\n          : \"Kontrolli v\u00e4lju.\";\r\n        statusEl.textContent = \"Viga: \" + msgs;\r\n        statusEl.className   = \"lp-export-status error\";\r\n        btn.disabled    = false;\r\n        btn.textContent = \"SAADA JA LAE PDF\";\r\n\r\n      } else {\r\n        statusEl.textContent = \"Teadmata viga (status: \" + data.status + \"). PDF laaditakse alla.\";\r\n        statusEl.className   = \"lp-export-status error\";\r\n        btn.disabled    = false;\r\n        btn.textContent = \"SAADA JA LAE PDF\";\r\n        setTimeout(() => generatePDF(name, email), 400);\r\n      }\r\n    })\r\n    .catch(err => {\r\n      console.warn(\"CF7 viga:\", err);\r\n      statusEl.textContent = \"\u26a0\ufe0f \u00dchenduse viga. PDF laaditakse alla \u2013 saada k\u00fcsimus info@lumepix.ee\";\r\n      statusEl.className   = \"lp-export-status error\";\r\n      btn.disabled    = false;\r\n      btn.textContent = \"SAADA JA LAE PDF\";\r\n      setTimeout(() => generatePDF(name, email), 400);\r\n    });\r\n  });\r\n\r\n  \/\/ \u2500\u2500 PDF GENEREERIMINE (jsPDF) \u2500\u2500\r\n  function generatePDF(clientName, clientEmail) {\r\n    \/\/ Lae jsPDF d\u00fcnaamiliselt\r\n    function doGenerate(jsPDF) {\r\n      const doc  = new jsPDF({ orientation: \"portrait\", unit: \"mm\", format: \"a4\" });\r\n      const pw   = doc.internal.pageSize.getWidth();\r\n      const ph   = doc.internal.pageSize.getHeight();\r\n      const m    = 18;  \/\/ marginaal\r\n\r\n      \/\/ \u2500\u2500 P\u00c4IS \u2500\u2500\r\n      const d = new Date();\r\n      doc.setFillColor(220, 233, 0);\r\n      doc.rect(0, 0, pw, 24, \"F\");\r\n\r\n      \/\/ Logo \u2013 base64 PNG\r\n      const logoB64 = \"\/9j\/4AAQSkZJRgABAQAAAQABAAD\/4gHYSUNDX1BST0ZJTEUAAQEAAAHIAAAAAAQwAABtbnRyUkdCIFhZWiAH4AABAAEAAAAAAABhY3NwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAA9tYAAQAAAADTLQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlkZXNjAAAA8AAAACRyWFlaAAABFAAAABRnWFlaAAABKAAAABRiWFlaAAABPAAAABR3dHB0AAABUAAAABRyVFJDAAABZAAAAChnVFJDAAABZAAAAChiVFJDAAABZAAAAChjcHJ0AAABjAAAADxtbHVjAAAAAAAAAAEAAAAMZW5VUwAAAAgAAAAcAHMAUgBHAEJYWVogAAAAAAAAb6IAADj1AAADkFhZWiAAAAAAAABimQAAt4UAABjaWFlaIAAAAAAAACSgAAAPhAAAts9YWVogAAAAAAAA9tYAAQAAAADTLXBhcmEAAAAAAAQAAAACZmYAAPKnAAANWQAAE9AAAApbAAAAAAAAAABtbHVjAAAAAAAAAAEAAAAMZW5VUwAAACAAAAAcAEcAbwBvAGcAbABlACAASQBuAGMALgAgADIAMAAxADb\/2wBDAAUDBAQEAwUEBAQFBQUGBwwIBwcHBw8LCwkMEQ8SEhEPERETFhwXExQaFRERGCEYGh0dHx8fExciJCIeJBweHx7\/2wBDAQUFBQcGBw4ICA4eFBEUHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh7\/wAARCABpAdQDASIAAhEBAxEB\/8QAHAABAAMBAQEBAQAAAAAAAAAAAAYHCAUEAwEC\/8QAURAAAQIFAgMDBAsMBwgDAQAAAQIDAAQFBhEHIRIxQQgTURQiYYEWMjY3QnF0lLGy0RUXIzRSU1ZzkaGzwSRVg5KTwtIzQ1RicnXh8DVEgrT\/xAAbAQEBAAMBAQEAAAAAAAAAAAAAAQIDBQQGB\/\/EADQRAAIBAwMCBAMHAwUAAAAAAAABAgMEEQUhMRJBBlFhcRMUIjJCgZGxwfBSoeEVIzPR8f\/aAAwDAQACEQMRAD8AxlCEIAQhCAOlbNDqtyVyVotFk3Jyeml8DTSB+0k8gANyTsAI2rptolZtq2W5QLgZkqpU6033U487gFZA4u7ZzuAnHFkbkp4jjAAqDs76laUafW1MuzkrVRcbrRMzMrlkrDuN0stFKjwpyB7bGTuTgDFYakaoXPel6N3K9OOyKpNziprLDhAkwDkcJ6q2BKuZPgAAPiNUoaprVzK2pZo0Yb9T5lLtj0z\/ANvfCPTBwprL3Z79dNKKrprXf95OUOaWfIp3h9fduY2CwPURuOoFbxqSn9oWzLj0yeo2pVFm56fWjuX2ZVhJRM7ea6klQDas77ciMjwGY6iZMz8waeHxJlxXcB8guBGdgojYnHPEdnQbq\/qU5Ub+m1OG3V2l6r9+36LXVjFPMWeeEIR3jUIQhACEIQAhCEAIQhACEIQAhCEAIQhACEIQAhCEAIQhACEIQAhCEAIQhACEIQAhCEAIQhACEIQAhCEAIQhACEIQAhCEAIQhACEIQAhCEAIQhACJXaunF9XRwKodrVOaaX7V4s92yf7ReE\/vjX9g0zTS2dJZG\/5O1JFppNMbnH3Wpfv5hB4RxgKWSrZWevSK4vTtWNOysxKWrbL6FOIUhE3PPhKkEjHEG0Z3HP20fER8Tahf1JU9Otc9Lw3JpJP1X+T0\/BjFZnIpLSnT6bvrUNNpCcTJcAdVMzKUB4NJb5kAEBWVYSDnrmOhplc0vprftRp1y0CRrFOU6qQqcvMSyHVpCFkFSOIcwR7Xkrrvgj39mfUGiaeXtOVKvsTC5WckjLB1hsLW2rjQrJBI808JzjJyBtHF15qFu1nVCqVu1p5M3TajwTIUG1IKXFJHeJIUAc8YUfXHWqO4ur+rZ3EH8FwWHjbqzvuuHvtv22NaxGKkuSwu1Hb+msjbltXFY0tLsLrK3FpMos9y6ykDJKD7RQUpIwMY84EZG1BrSpCilaSlQ5gjBEemUdS49Ky89MPiRQ6CoJPF3aVEcZSnlnA9eBG4K7pNptqZO0K85NSVSgQgr8jPC3PMpThKF9QUkAE7KwCk8hw+KtqVPw1RpULqUqkX1fVy1h5in7rbnt5cZKDrNuOxlHQK36FdGq9Godx94ZGYUsltKuEOqSgrShR5gHhxtv02zmLR7R982XRaZN6cWFQKK1xEIqc2xKN4QUkHu0nHnLBG6t8chvnEK7S0zR6frXNzVnTzbRYZZQ4ZI92mWfbR3ZQgpwBhKU+15EkcwYqgbq3PM8zHqpWK1StR1Gq5KPSmoPhS5y\/PG2PbJHLoTgvzJtcenc9RtKrev12ZK2Kw+4yZctYLOCrgPFnfiCFHkMYHPO3nl9M76m7ZlLkp9tzlQpU2grafkwHzgKKVZSglScEEHI6Ra2tOqdhVPSCR07tdE5PrkkSzbc4qX7plIaABUOIhRURkbp+EY4mievk9p5bqLcm6E3Vach5bjakzBadb4jkgbEEZycbczvGilfazOydanRzPrf0y2bh27rDWy38iuNPqw3sUzMMPSz62Jhlxl1BwpDiSlST4EHlHzjethXZYGt1Nne8tjynyHgS+iqSTauAr4scC8n8k8sEeuMe62y1BkdVK\/T7ZkUSVMk5oy7bKFqUAtACXDlRJ3WFbchG7RvEM7+5naVqDp1ILLy0129uc5W3BKlLpXUnlEMhCEfSmkQhFz6b6ZW5cFl0+rz654TMx3nGG3gE+a4pIwOE9AIApiEdu+qXLUW7qjSpMuGXlneBHeHKsYB3PrjiQAhCEAIRpLs76J2bfmnSa\/XF1RM2Zt1nEvMJQjhTjGxSd94qjXq06XZOp1RtyjGYMlLNsqQX1ha8raSo5IA6k9I4trr1rdX1Sxp564Zztts0ufxNkqUoxUnwQSEIR2jWIQi7LA0vtquWfTqtOrnxMTDZUvu3gE5CiNhw+iAKThHWvKnS9Juqp0yVKyxLTK22+M5VgHbJj3WA1a01VxJXR5Syy8QlqZadCUtq\/58g7Hx6dduQEbhGhJvRm1XZNxMpMT7TykHu3C6FpSehIxuPXFH3RQajblXdplTZ7t1G6VD2rieiknqD\/AO7xcA5cIQiAQhCAEIt\/TfSRFSpn3SuczMuHkgy8s2rgWE\/lKyDjPQftj91Gs+wLQpfeOKqD8+8D5NLeUjKj+Urzdkj9\/IRcDJT8IROtHLTpd2VaelaoqYDbDAcR3Kwk54sb5BiAgsI0T95m0PzlT\/x0\/wCmH3mbQ\/OVP\/HT\/pi4JkztCJDqPRpS370qFIkC6ZaXLfB3isq85tKjk\/GTGi9INALEurTWiXDVHKuJydYLjoZmUpRniUNgUHHKOTq+s22k0lVuM4bxss78\/sbKdN1HhGU4RIdSqPKW9qBXqHIFwykhPuy7JcVxK4UqIGTtkxy6DKtT1dkJJ7i7qYmW2l8JweFSgDj9sdGjVjWpxqR4aT\/Mxaw8HihGifvM2h+cqf8Ajp\/0w+8zaH5yp\/46f9MbcGOTO0I0T95m0PzlT\/x0\/wCmPhN6KWw42RLT1UYc6EuIWPWOH+cMDJn2ETPUHTyr2iBNLWmdpylcImW044T0C0\/B\/ePTEMiFEIvLsv6VWxqPI1164V1BKpF1lLPkzwQMLCyc5Sc+1EcjtN6eUDTq5qVTrfVOKZmpMvOeUuhZ4uMp2IA2wI4sNetZ6i9OWfiL024zz7Gz4Uujr7FSQjuWOzQJq4WJS41PtyT\/AOD71pwI7pZ5E5B83ofDOekXDWtF6CqlTH3ImJ1E9wEsF50KQVeB80bHlnpHbwaygoR9ZyWfk5p2VmmlNPsrKHEKGClQOCDHyiAQiV6Z2e\/d9eEueNuQYwubeTzSnokf8x6es9Isq6tNbCtyhzFWn36mGmk+agTCeJxR5JHm8z\/5i4BRUI\/pwpLiihPCkk4TnOB4ZhEBsXsmVGVufQuqWrUnB3UkuYk3Qo8pd5JVk56ZU4PVGPZtnyebel+8bd7pakcbauJKsHGQeoPjHds+pXUWJy0rZdmleyBTTL8tLjzpjhKuFOeg8455bZztmLiuXsxVulafKrMvWG52uMNh6YkEoCW+HGVJQsnzlD0gA746Z+Ro\/KaFf1p3FZJV5Jxj5ebfllt+nr5b31VIrC4KLtz7neyGnCsIUummabE2Eq4VFriHHg9Dw53i5O0fopS9O6JJV+gVCempGYmvJ3WpnhUWiUlSSFJAyPNI3HhvH17O+oWmFtUp+WvO2ZFqpy2XJapCSMw4\/v7Q5yULHQjCSOeCN7gpGumlF\/PzFsVuWXKycxhDf3YYQGH\/AFhSgg55FWOmDnaPFrGq6pQv41KFCfwqeerupJ917fn54wZU4QccN7sxNG3uyPQ6xStFnG6jKOyq5+cemZRLmxU0ptCUqxzAJSSM9MHkY+VI7OFh02+G7kQ8+\/Smh3rdLfIWylzOQorJypAG\/Cc+kkbRFNTO0wmlXzK0+0pWXqNGkXSJ95X\/ANvoUtH4KRzCupA+D7bm6zqs\/E1NWemQcsfVJvbGOI+7\/ndrOnD4L6psy\/X6TUqFWZqkViUdlJ+VcKHmnB5yT\/MHmCNiDkRKNErITqDqHJW4++9Lyi0OPTLzIBWhtCSds7bq4U+uNXXdZNh6+2zTblps+qWfSQkTrLYLyUg5Ww6knmMnGeRORkHf5TtW0j7P9JMjKMpVVnGxxMs4enpjqC4o44E9d+EeAj2VPGM7i2dvQpS+aeV0pfZfGd+3f9fMxVvh5b+kzp2k7PtWw7sp9tWyiaUtqSD04\/MPca1rWo8IOAEjCUg7Ae2iq41veWuWjNy2pNTlRtn7qVRDeJeRn5BPeKUdhh4cQSkdSFA45DpFR6JaPz2qc\/P1Rx5uiURpahxsoKz3h3DbaVKzwpyMknltknOOppGr1LbT3PU4Sp\/D2cpb9Tfl3f5Y7J7GFSmnL6N8l2dlfyC0+z3U7rccZcKnJqemOFYJSGU8IbOOR8zIHPzx4xj6dmXp2dfnJlZcffcU64o\/CUo5J\/aYsfUKhXxpBMVi0XJ100WttBIeQn8DNtpUCFAHPCsYwRzAJG4IJrKPVoVjCFavfRqKarNNNf09l+GWvw\/AxqS2UccCEIR9GahGndEfevo\/9t\/GcjMUad0R96+j\/wBt\/GciojKL1Z98at\/KP8oiLRKdWffGrfyj\/KIi0QohCEAWDYWsV82RQBQ7fnpVmSDqnQlyVQ4eJWM7keiIze10Ve8bjmLgrrzbs\/MJQlxbbYQCEpCRsNuQEWbo9Ytr3BZyahVqcZiZMw4jjD7iNhjAwlQEQDVakU+hXzPUymMFiVaS0UI41KxltJO6iTzJjyU9PtaNZ14U0py5aW7z5syc21jJFoQhHrMRGpNH\/e2ov6pX11RluNSaP+9tRf1SvrqiojM+6l++BXPlrn0xHYkWpfvgVz5a59MR2IU0N2eqpPT9ozEvOTCnkScx3THFuUo4QeHPgOnhEpvu06ddtIMnOJ7t9GTLzCRlTSv5g9R1+PBiE9mr3NVT5YPqCJLX76lKDfsvQKqEMyc1KIdbmT\/u3CtacK\/5Twjfp125ZdiGdbnoNRtyru0yps926jdKh7VxPRST1B\/93jlxq6+7Tpt3Ucyk2Ah5AKpaZSMqaV\/MHqOvx4MZluehVG3Ku7TKmz3byN0qG6XE9FJPUH\/3eI1gpy4uvRzTXg7m4ril\/P2XKSjg5eC1jx8B6zH5o5prw9zcVxS\/nbLlJRY5eC1j6B6zE81HvWQtCl94vhfqDwPk0tndR\/KV4JH7+QgkQlUZBuepT1Xrs3PVCYW++txQKldADgADoB4RrSkPuTVJk5l3HeOsIWrAwMlIJjIE\/wDj0x+tV9JisI+EWz2afdFVfkifriKmi2ezT7oqr8kT9cREVkx1tuytWsxSl0d5pozKnQ5xtheeEJxz+MxWf33b2\/42W+bI+yJf2m\/xWhf9b\/0IikoNkPfcFWna7V36rUVpXNP8PeKSkJBwkJGw9AET61ddNQ7Zt6ToNJqEm3IyaO7ZSuTQogZJ3JGTuTFZQjyXVlb3kVC4gpJb7rJlGTjwz33DVp2vV2drVRWlc5OvqffUlISCtRySAOW8fW0fdZR\/lzH8RMcuOpaPuso\/y5j+ImPRCEYRUYrCRDU94T0xTLVqlRlSlL8tKOOtlQyApKSRtFCffevT\/ipT5smLy1F9wVd+QPfUMZNjYyIsD7796f8AFSnzZMeyk6z3PLzKFVBiSnWM+egN92oj0EHA9YMVnH9sNOvvIZYbW66shKEIGSonoBEyU13inXNbQ4k99IVGWBwoYJQtOfURn1GMl1aTXT6pNyDpyuWfWyo+lKiD9EausmnPUm0aVTpnZ9iVQlwZzhWNxn0HaMuXfMtzt2VecZILb8884gjqkrJH7orIjvacam3bp8zOs21Ny7CJ1SFP97LpcyUggYzy9sY8uot+3Hf9Rlp+5Jhl9+WZ7lotMpbATknkOe5iU6G2lQLmlaqutSJmVS62g0Q8tHCCFZ9qRnkI52t9t0a2q3IS1GlDLNOyxWtJdUvKuIjPnEx4lp9qq\/zKpr4j+9jfy59jPreOnOxX0X\/oVev3Wpwt2pO5n5RH9HWo7vNDp6VJ\/eMeBigI9NLn5qmVFioSLymZmXWFtrHQj+Xoj2IxLr15snyyWVdNMZzMMp\/praR\/tED4fxp6+j4opih0udrVWl6ZT2i7MzC+FA6DxJ8ABuT6I1HYdyyd2241UGglLmO7mWOfdrxuPiPMegx57Qsai2zV6jUpBslybX+DChsw3zKE+jO\/xYHTe4IeuzbfkLStxunsKSEtpLkw+rbvF485Z8Bt6gBFB6uXmu6653UqtQpUoopl08u8PVwj09PAfGYmmvV78CV2pS3vOUB5e4k8h0a\/mfUPGKUiMIQhCIU7+nztzs3hIO2amZVXUFZlBLthbmeBXFhJBB83i6R6b9qt+zc8WL2nK+ZjOQxUi4nh+JCsAeoR8rKTddLW9elsNzTf3CdaU\/NsjIY7ziCeIdUq4VA523wecXrdHabkqzp25T\/YshVwPIDa\/KWkPSSDjznEpVkk+CVDG+5OMH5\/UK1zTvITt7eNVfZbylKL53eHth5\/9Rtik47vBmeLV7MNJsmr6lS8veT44kgKp0q6kdxMv52Ssn9oTyUdifgq7fZ30ktq\/pean7muOXZK+JuWp0lNtJmuLO7ikkHhT4Dh357DGbetrs66e2dPv3DcVVdqUlKkONpqCkMsMgfCcIwF7+OB4gxzde8S2NOFayc5RqYx9K3y\/J\/rx6PJnSoybUux8+2TVb2p1msS1CYLVvTGW6pNsKPejJwltQ+C2epHM+acDZWNY3hRda9N7wu1+x23jMNTTZZbemWQJWcUcgtDi3ORyyAFbgdM0tqh2ba5L3xKtWU2H6JUniAp1f8A8f1IcPMoAzg7n4J3wVcnwpqtPS6XyN9T+DLHUm9upeue6\/xyZ14Ob6ovJFeytWL2kdSGJC02DOSk0R905ZxRSwGQd3FHfhUnOx55OMHODcvbQpFkLtVir1R8StzA93Tu5SC5MpB85Cx+QM54j7U8s5wZI2\/p\/wBnSxJaWfU4\/NTa094WkJM1PLHtl4JACEgnAzgctyd\/hdNoaZ6+0hNcpNWAqTTQbTOS5\/CsjchDzKsbZJ54PgrEcq51WFfVqeq\/DlToJ460vtY\/q9O3DeNueM1DFNwzlmII9dJnalITrb9Jm5uVms4QuWcUhzPoKd405eHZotOiWTNTCbwXLVdCeJmZqTzTEqoj4BGMpB8eI429cB7PmrtM03cnabX6EzOSxKlNTkiw0qZQvqgryONB6Hi26ZB2+6h4gpX1pUq2EHVcdul\/Tn2ytzzOk4ySk8EO1CqWptQoFJ9nKq2unIW55A5UWCkrUQniIUoBS9gNyT1x1iDxa2r193VrBUZ2oSdNmG7eobRfTLo3TLoJCe8cVyK1E8ugzjkSapjo6V1\/LJVIRhLvGPCzvj3w8v1MZ87PIhCEdIwEad0R96+j\/wBt\/GcjMUad0R96+j\/238ZyKiMovVn3xq38o\/yiItEp1Z98at\/KP8oiLRCiEIQBo3s+e96n5W7\/ACiqtdPfMqX\/AEM\/wkxaPZ3dDlgrQObc84k\/3UH+cVpr4wtnUeZcUCA+w04n0jh4fpSYyfBCAwhCMSiNSaP+9tRf1SvrqjLcap0pYXLad0RtwEKMsF4PgolQ\/cRFRGZ41L98CufLXPpiOx3tRHQ9fldWOXl7yf2LI\/lHBiFL57NXuaqnywfUERPtH+7qU\/7a3\/EciTdnKblJe3KmmYmmGVGcBAW4EkjgHjEV7RD7Exe8quXebdSKcgFSFBQz3jm20ZdiHS0d1JMgWbeuB\/MmcIlZpZ\/2PghR\/J8D0+LlclVotJq70o\/UZFiaXKOd6wpYzwq\/mOWx22HhGQIsuwtVp236E9TKhLrqAabxIqKt0HohR6oHTqMY5YxEwW3qNekhaFL7xzhfn3gfJpbO6j+UrwSP38hGZ65VZ+t1R6pVKYU\/MvHKlHkB0AHQDoIV2rT9bqj1SqUwp+ZeOVKPIDoAOgHQR4YN5KbCt33P075K19QRkSf\/AB6Y\/Wq+kxru3fc\/TvkrX1BGRJ\/8emP1qvpMGRHwi2ezT7oqr8kT9cRU0Wz2afdFVfkifriCKy9HG2nMd4hC8cuIAx\/Hk8r+YZ\/uCKi7Tf4pQv1j\/wBCIpKK2TBsryeV\/MM\/3BGV9SwlN\/1tKQAkTi8AcucR2ERsCOpaPuso\/wAuY\/iJjlx1LR91lH+XMfxExCmuJlhmZl3JeZZbeZcSUrbcSFJUDzBB5iOR7EbU\/RmjfMW\/sj8v911iyK28y4tpxEi6pC0KIUkhJwQRyjL3shr\/APXlT+dr+2MmyGovYhan6M0b5i39keun0SiUxffSFIp8msA+ezLobP7QIyl7Ia\/\/AF5U\/na\/tj4TdVqk2gtzdSnJhB5pdfUofvMMjBeurOpNPptMmKPQ5tE1Un0ltbrSsol0nYniHwvADlzPgc\/QhGLZS7+zL+I1z9az9C44\/aV90tL+Rn65jsdmX8Rrn61n6Fxx+0r7paX8jP1zF7EKohCJJp3bjVyXA3Lzc01KyDWHJl1bgT5v5Kc9Ty9G56RCljdnOg1NnyuvuvOMSD6O5bZ6PkH259CdwD4k+u5HkqW0tCXFNqUkgLTjKT4jO0cOer9uW9QFvJnJNErJsgIZZcSTgDCUpAPPkIrjTPVGaqF2TMjXnEol6g7mUOfNYVyDfxEAD4\/jMZcEKuvai1GgXLNyFUUp1\/jLgeVn8MlRyF59P05EcWNPar2a3dlBPk6UpqcqCuVWduLxbJ8D+449MZkeacZeWy8hTbiFFK0qGCkjYgjxiNFP4hCEQGxuyvS5K29AqtctXl23JefMzNvpcSCFy7SCjhIPMeY5z\/KjHj6w68twIS2FqKuFIwE5PIeiN62nJ2TdmjsrYNJuiVmGDTG5R9VOmm+\/GEjjPCQSOIg5ynkTFJ372W6nSaZO1S3bkZn2pZlb5lppgtulKUklKVJ4gpRxtkJGY\/NtA120oX91K7m4TqT2TT4Wce3PfyPZVpScY9PYoyx5enTV40dirzbUpTlTjRm3nDhKGgoFZ\/ug+uLu7V2rVt3rR6Zb1qT7s5LszSpibd7lTaCpKeFAHEAT7ZfTGw5xA+z\/AKYN6nXDPSMzVlU2WkZdLzim2wtbmVYCQCRjqc79Nt44Gr1Dots6iVW3qA9MvyVPcSx3swtKlrcCR3meEAbL4hjHSPpq1OyvNYgpSbqUU3j7qzjd7c7rGH2NCco035MiiVKSoKSSlQOQQcEGN19mC8a3dekaqjXXxNTlPmXZRLyvbuoQ2hSSs9VedgnrgE75Jw3TWpd6oyzM4+WJZx5CXnQnJQgkBSgOuBkxvWUremmkbNDsITzFPM4cNhR4iSR\/tn1dOIgDiO3hhI24nj1xq29O3jTcqjbaws4Uftft\/MG212bedjD183XW70uSYr1emi\/NPHAA2Q0gckIHRI8PWckkxI+z\/eUrY2qFOrdReW1TSlxidKElR7taSAcDc4Vwnbwj2dpWhW\/b+r1TpVsy5Yl0obdeYScoadWnjUlA6JwUnHTJ6YArSPqaFO21DTYwjHppzhxxhNfzBobcJ57ourtaVm17ouukXNa9blakzNSRYfQ0ohba21ZBUhWFJylYAyBnhPgYpWLq1N0Zo9v6WyeodDuV5+Rm2ZdxuTmmQXD3wBwHEkAkZORwjkY52kGhVyaiUZNdZqUhTKWXlNBx4KW6spxkpQBgjO26huI52majp1jpkWqv+3BuOZJp5XbGN2vRGc4TlPjdl09lKVpNzaA1m2\/JmGXnXZmTnVpQOJzvEZQ4o9cBfCP+iMhzss9Jzj8nMoLbzDim3EnmlSTgj9ojeGkGmtE0dpdSffudx9E73ZmXZwtsMJKOLBSCfNPnHOVHp4RkLXsUZWrlwTNv1CVqFPmpnylt6WcC0FTgClgEbHCyrlHG8L6hTuNVu\/gNypzxJPD57rf329EbK0GoRzyQaEIR9+eURp3RH3r6P\/bfxnIzFGh9ILlt6Q06pcpPVymy0w33vG07MoSpOXlkZBORsQYqIystUKFW5m\/6w\/LUaovNLfylxuWWpKhwjkQN4jXsbuL+oKr8zc+yNP8AsxtP9JaR88b+2HsxtP8ASWkfPG\/ti4BmD2N3F\/UFV+ZufZHzmaFW5Vhb8zR6iwygZU45LLSlI9JIwI1H7MbT\/SWkfPG\/tiNan3Pbk7YVXlZOvUyYfcZAQ23NIUpR4hyAO8TAyQvs415qVqc7b8wvh8sAel8nYrSDxD4ynB\/\/ADE51esVV209qakChFUlAQ3xHAdQdygnoc7g+k+ORm+WfelphuYl3VtPNKC0LQcFKhuCDF6WJrDT5qXbk7n\/AKJNDCfKkIJac9KgN0n93xcoJgpar0WrUl9TNTp01KrTz7xsgeo8iPSI8Tba3FhDaFLUeQSMkxsCn1ik1FvjkKnJTaT1aeSv6DHoAlZVJVhlgHcnZOYuBkzpp7ppWa\/PMzFTlXpClpIU4t1JQt0fkoB338eXx8ovu46pJWzbUzUXUpQxJs4bbGwJAwhA+M4Ecy4tQLTojSlTFWYmHRyYlVB1ZPhscD1kRQ+o991C8JxKVo8lp7KiWJcKzv8AlKPVX0ftJcAikw85MTDj7yipxxZWtR6knJMfOEIxKdCl0OtVVpbtLo9Qnm0K4VqlpZbgSfAlIODHyqdNqNLmEy9TkJqReUnjDcwyptRTkjOFAHGQd\/RGmexndVsW\/Z1cl67cVIpbztQSttE5ONsqWnuwMgKIyMxBe2LW6NX9TqfOUOrSFUlkUZppT0nMJeQlYeeJSSkkZwQcekR81Q1u4q6vOwdHEF97ffZPyx\/c3OmlT6slKwhCPpTSIQhAGwrd9z9O+StfUEZEn\/x6Y\/Wq+kxqKhXXa7VDkG3LjpCFolm0qSqdbBBCRkEZjLk6QqcfUkgguKII67xWRHxi2ezT7oqr8kT9cRU0Wb2fqrTKVXak7U6hKySFyoShT7qUBR4hsMwRSVdounVCoS1FEhITU2ULe4wwypfDkIxnA25RTvsbuL+oKr8zc+yNP+zG0\/0lpHzxv7YezG0\/0lpHzxv7YuCGYPY3cX9QVX5m59kPY3cX9QVX5m59kaf9mNp\/pLSPnjf2w9mNp\/pLSPnjf2xMDJlaoUypU8IM\/T5uUC88BfZUjixzxkbx6bR91lH+XMfxExZXaGrVIq0tRk0uqSc6WlvFwMPJXw5CMZwduRisrXdbYualvPOJbbbnGVLWo4CQFgkk9BApqHUX3BV35A99Qxk2NM35dVszVl1mWlrgpbzzsk6httE0hSlKKTgAA7mMzQZEIQhEKIQhAF39mX8Rrn61n6Fxx+0r7paX8jP1zHo7Pdbo9Ik6wmqVSTki640UB95KOLAVnGTvzEcvtAVWmVav052mT8tOtolSlSmHQsJPGdjiL2IVpCEIhRH6CQcg4Ij8hAGj9GL1Fy0f7nT7uarJIAWSd3m+QX8fQ+nB6xGde7JzxXXS2fAT7aR6g7\/I+o+Jipbeq87QqxLVWnucEwwviHgodUn0EbGNK0m+7SrFEZmJmrU6W8oaw9KzMwhKkk7KSoE7jn8YjLkhluES29rbp8pcL6bfq9Lm6c5+EZInmstg58w5V0+jEIxKRRta21pcbWpC0nKVJOCDE7tfWHUi3QluRuqdfYAx3E6RMox4YczgfFiIFCPPcWlC5j01oKS9Un+pVJrgn+h2on3ub6XX3JBc3Kvy7ku\/Lsr4DwqIUMZzyKR6oacWTcGrl+zYZUGkOvqm6nPLGUMBaion0qJzhPX0AEiAR9WJiYYQ6hl91pLqeBwIWQFp54OOYjz1rD6qla3ajVmkuprPHG2V5\/pngyUuE+C9u1LQNP7ct+1qLaM9IKnZAvNTLTLqXHlpUEnvHlJ5K4k9ce22GBtR1UqE9VJ5yeqM29NzLmON11ZUo4AAGT0AAA9Ai8NE9D7W1EtF6qovSYE+hJQ7JtSqUmUdIPDx5UStJ5gjhyMjIIOKlvqz67ZlzvW9W5RTc22fwZQCUPoJ81aD8JJ\/8HBBEcvQ7m1puVgqrnVp5y5Jp7vLxntn37ehnUUn9WNmSrs71Ois6z0apXbUAiXRxpQ9MniQXC2UNhajySMjc7DA6ROu0too1Q23r3sxpDlDcPeTcq0QRK5Pt0Y5tknl8H4va\/tsdmmYmLAXcF2XIm25vuzMd06wFol2QM5dJUnhV1x8HrvkCi5ycmZMTlIkazMzFMU6QQha22pgJV5qy2T6ARkZEeejKnqGpfM6fcf8eIzj0txay+Hss7vDWfy5rzCGJLkl1y6jP1jR23LAUy6PuTNOPOvKUMOJyrukgc\/NDih6hH9UrWO\/aPaMla1CqrdJp0ohSU+SsJDi+JRUVFasqySonYiK+hHc\/wBKs+jolTTXU5Yaz9Tzl7+\/4Grrlzk91ZrFWrU0ZqsVSdqL5\/3k0+p1X7VEx4YQj3RjGC6YrCMRCEIyAhCEAIQhACEIQAhCEAIEkwhACEIQAhCEAIQhACEIQAhCEAIQhACEIQAhCEAIQhACEIQAhCEAIQhACEIQAhCEAIQhACEIQAhCEAIQhACEIQAhCEASLT28a5Y1ysV6hTPdPt+a42rdt9vqhY6g\/tBwRggRtqzLu0+1Lt2TvWbl5BEzQiX3ROcPeU1zh84kn4O2QrkcA7KTtgOJRaHuVvD\/ALcz\/wD1Mx8t4j8P0NRUaqbhUTS6lzhvDT89n\/EbqVVw27E+7RetE1f08uh0Nx2WtmXXsN0qnVA7LWOifyU+s74ApmEI7mn6fQ0+hGhQjiK\/v6v1NcpOTyxCEI9piIQhACEIQAhCEAIQhACEIQAhCEAIQhACEBCAEIQgBCEIAQhCAEIQgBCEIAQhCAEIQgBCEIAQhCAEIQgBCEIAQhCAEIQgBCEIAQhCAEIQgBCEIA\/\/2Q==\";\r\n      try {\r\n        \/\/ Logo suurus: 468\u00d7105px \u2192 sobiv k\u00f5rgus PDF p\u00e4isesse ~14mm\r\n        const logoW = 45, logoH = 45 * (105\/468);\r\n        doc.addImage(\"data:image\/jpeg;base64,\" + logoB64, \"JPEG\", m, 4, logoW, logoH);\r\n      } catch(e) {\r\n        \/\/ Fallback tekst\r\n        doc.setTextColor(20, 20, 20);\r\n        doc.setFont(\"helvetica\", \"bold\"); doc.setFontSize(13);\r\n        doc.text(\"LUMEPIX\", m, 15);\r\n      }\r\n\r\n      doc.setTextColor(20, 20, 20);\r\n      doc.setFont(\"helvetica\", \"normal\"); doc.setFontSize(9);\r\n      doc.text(\"Ekraanikalkulaatori kokkuv\u00f5te\", m + 50, 13);\r\n      doc.text(d.toLocaleDateString(\"et-EE\"), pw - m, 13, { align: \"right\" });\r\n\r\n      \/\/ \u2500\u2500 KLIENDI ANDMED \u2500\u2500\r\n      let y = 34;\r\n      doc.setFontSize(10);\r\n      doc.setFont(\"helvetica\", \"bold\");\r\n      doc.setTextColor(20, 20, 20);\r\n      doc.text(\"Kliendi andmed\", m, y); y += 6;\r\n      doc.setFont(\"helvetica\", \"normal\");\r\n      doc.setFontSize(9);\r\n      doc.text(\"Nimi:    \" + (clientName  || \"\u2013\"), m, y); y += 5;\r\n      doc.text(\"E-mail:  \" + (clientEmail || \"\u2013\"), m, y); y += 10;\r\n\r\n      \/\/ \u2500\u2500 TULEMUSED \u2500\u2500\r\n      doc.setFont(\"helvetica\", \"bold\"); doc.setFontSize(10);\r\n      doc.text(\"Kalkulaatori tulemused\", m, y); y += 6;\r\n      doc.setFont(\"helvetica\", \"normal\"); doc.setFontSize(9);\r\n\r\n      const rows = [\r\n        [\"Keskkond\",       state.env       || \"\u2013\"],\r\n        [\"Aluspind\",       (state.baseW||\"\u2013\") + \" \u00d7 \" + (state.baseH||\"\u2013\") + \" mm\"],\r\n        [\"Pikslisamm\",     state.pitchText || \"\u2013\"],\r\n        [\"LED ekraan\",     state.ledText   || \"\u2013\"],\r\n        [\"LCD lahendus\",   state.lcdText   || \"\u2013\"],\r\n      ];\r\n\r\n      rows.forEach(([label, val]) => {\r\n        doc.setFont(\"helvetica\", \"bold\");\r\n        doc.text(label + \":\", m, y);\r\n        doc.setFont(\"helvetica\", \"normal\");\r\n        \/\/ Wrap pikk tekst\r\n        const lines = doc.splitTextToSize(val, pw - m - 55);\r\n        doc.text(lines, m + 35, y);\r\n        y += 5 * lines.length + 2;\r\n      });\r\n\r\n      \/\/ \u2500\u2500 EKRAANIDE VISUAALNE V\u00d5RDLUS \u2500\u2500\r\n      \/\/ lp-visual-inner on div, mitte canvas \u2013 joonistame uue offscreen canvas-i\r\n      const visDiv = document.getElementById(\"lp-visual-inner\");\r\n      if (visDiv && state.baseW) {\r\n        y += 4;\r\n        doc.setFont(\"helvetica\", \"bold\"); doc.setFontSize(10);\r\n        doc.text(\"Ekraanide visuaalne v\u00f5rdlus\", m, y); y += 5;\r\n\r\n        try {\r\n          \/\/ Kasuta html2canvas-i v\u00f5i joonista div CSS-pilti\r\n          \/\/ Lihtne lahendus: tee offscreen canvas sama loogikaga mis updateVisual\r\n          const oc  = document.createElement(\"canvas\");\r\n          const ocW = 700, ocH = 320;\r\n          oc.width  = ocW * devicePixelRatio;\r\n          oc.height = ocH * devicePixelRatio;\r\n          oc.style.width  = ocW + \"px\";\r\n          oc.style.height = ocH + \"px\";\r\n          const octx = oc.getContext(\"2d\");\r\n          octx.scale(devicePixelRatio, devicePixelRatio);\r\n\r\n          \/\/ Taust\r\n          octx.fillStyle = \"#f3f4f6\";\r\n          octx.fillRect(0, 0, ocW, ocH);\r\n\r\n          const pad = 16;\r\n          const availW = ocW - pad*2, availH = ocH - pad*2;\r\n          const bw = state.baseW, bh = state.baseH;\r\n          const sc = Math.min(availW\/bw, availH\/bh);\r\n          const rw = bw*sc, rh = bh*sc;\r\n          const ox2 = pad + (availW-rw)\/2, oy2 = pad + (availH-rh)\/2;\r\n\r\n          \/\/ Aluspind\r\n          octx.strokeStyle = \"#9ca3af\"; octx.lineWidth = 1;\r\n          octx.setLineDash([4,3]);\r\n          octx.strokeRect(ox2, oy2, rw, rh);\r\n          octx.setLineDash([]);\r\n\r\n          \/\/ LED\r\n          if (state.ledSize) {\r\n            const lw = state.ledSize.w*sc, lh = state.ledSize.h*sc;\r\n            const lx = ox2 + rw\/2 - lw\/2, ly = oy2 + rh\/2 - lh\/2;\r\n            octx.fillStyle = \"rgba(220,233,0,0.35)\";\r\n            octx.fillRect(lx, ly, lw, lh);\r\n            const gp = (state.ledStep||250)*sc;\r\n            octx.strokeStyle = \"rgba(0,0,0,0.2)\"; octx.lineWidth = 0.5;\r\n            for (let xi = lx; xi < lx+lw; xi += gp) {\r\n              octx.beginPath(); octx.moveTo(xi, ly); octx.lineTo(xi, ly+lh); octx.stroke();\r\n            }\r\n            for (let yi = ly; yi < ly+lh; yi += gp) {\r\n              octx.beginPath(); octx.moveTo(lx, yi); octx.lineTo(lx+lw, yi); octx.stroke();\r\n            }\r\n            octx.strokeStyle = \"rgba(180,200,0,0.6)\"; octx.lineWidth = 1;\r\n            octx.strokeRect(lx, ly, lw, lh);\r\n            octx.fillStyle = \"#374151\"; octx.font = \"bold 11px sans-serif\"; octx.textAlign = \"center\";\r\n            octx.fillText(\"LED \" + state.ledSize.w + \"\u00d7\" + state.ledSize.h + \" mm\", lx+lw\/2, ly-4);\r\n          }\r\n\r\n          \/\/ LCD\r\n          if (state.lcdSingle) {\r\n            const cw2 = state.lcdSingle.w*sc, ch2 = state.lcdSingle.h*sc;\r\n            const cx2 = ox2 + rw\/2 - cw2\/2, cy2 = oy2 + rh\/2 - ch2\/2;\r\n            octx.fillStyle = \"#111827\";\r\n            octx.fillRect(cx2, cy2, cw2, ch2);\r\n            octx.fillStyle = \"#DCE900\"; octx.font = \"10px sans-serif\"; octx.textAlign = \"center\";\r\n            octx.fillText(\"LCD \" + state.lcdSingle.inch + '\"', cx2+cw2\/2, cy2+ch2\/2+4);\r\n          }\r\n\r\n          const visImg = oc.toDataURL(\"image\/png\");\r\n          const visW   = pw - m*2;\r\n          const visH   = visW * (ocH \/ ocW);\r\n          const maxVis = ph - y - 50;\r\n          const fvH    = Math.min(visH, maxVis);\r\n          const fvW    = fvH * (ocW \/ ocH);\r\n          doc.addImage(visImg, \"PNG\", m, y, fvW, fvH);\r\n          y += fvH + 8;\r\n        } catch(e) {\r\n          doc.setFont(\"helvetica\", \"normal\"); doc.setFontSize(8);\r\n          doc.text(\"(visuaal ei ole saadaval)\", m, y); y += 6;\r\n        }\r\n      }\r\n\r\n      \/\/ \u2500\u2500 RUUMIPLAAN \u2013 alati uuel lehel, landscape formaadis \u2500\u2500\r\n      const roomCanvas = document.getElementById(\"lp-room-canvas\");\r\n      if (roomCanvas && roomCanvas.width > 0) {\r\n        doc.addPage(\"a4\", \"landscape\");\r\n        const lw = doc.internal.pageSize.getWidth();\r\n        const lh = doc.internal.pageSize.getHeight();\r\n\r\n        \/\/ P\u00e4is\r\n        doc.setFillColor(220, 233, 0);\r\n        doc.rect(0, 0, lw, 16, \"F\");\r\n        doc.setTextColor(20, 20, 20);\r\n        try {\r\n          const logoW2 = 36, logoH2 = 36 * (105\/468);\r\n          doc.addImage(\"data:image\/jpeg;base64,\" + logoB64, \"JPEG\", m, 3, logoW2, logoH2);\r\n        } catch(e) {\r\n          doc.setFont(\"helvetica\", \"bold\"); doc.setFontSize(10);\r\n          doc.text(\"LUMEPIX\", m, 10);\r\n        }\r\n        doc.setFont(\"helvetica\", \"normal\"); doc.setFontSize(8);\r\n        doc.text(\"Ruumiplaan ja n\u00e4htavustsoon\", m + 42, 10);\r\n        doc.text(clientName + \"  \u00b7  \" + clientEmail, lw - m, 10, { align: \"right\" });\r\n\r\n        try {\r\n          const imgData = roomCanvas.toDataURL(\"image\/png\");\r\n          const availW2 = lw - m * 2;\r\n          const availH2 = lh - 24;  \/\/ p\u00e4is 14 + vahe 10\r\n          const ratio   = roomCanvas.width \/ roomCanvas.height;\r\n          let fw = availW2, fh = availW2 \/ ratio;\r\n          if (fh > availH2) { fh = availH2; fw = fh * ratio; }\r\n          const fx = m + (availW2 - fw) \/ 2;\r\n          doc.addImage(imgData, \"PNG\", fx, 18, fw, fh);\r\n        } catch(e) {\r\n          doc.setFont(\"helvetica\", \"normal\"); doc.setFontSize(9);\r\n          doc.text(\"(ruumiplaani pilt ei ole saadaval)\", m, 30);\r\n        }\r\n      }\r\n\r\n      \/\/ \u2500\u2500 JALUS \u2500\u2500\r\n      doc.setDrawColor(220, 233, 0);\r\n      doc.setLineWidth(0.8);\r\n      doc.line(m, ph - 16, pw - m, ph - 16);\r\n      doc.setFont(\"helvetica\", \"normal\"); doc.setFontSize(8);\r\n      doc.setTextColor(100, 100, 100);\r\n      doc.text(\"Lumepix O\u00dc  \u00b7  www.lumepix.eu  \u00b7  info@lumepix.ee\", m, ph - 9);\r\n      doc.text(\"Dokument genereeritud \" + d.toLocaleDateString(\"et-EE\"), pw - m, ph - 9, { align: \"right\" });\r\n\r\n      \/\/ Salvesta\r\n      doc.save(\"Lumepix_ekraanikalkulaator_\" + d.toISOString().slice(0,10) + \".pdf\");\r\n    }\r\n\r\n    if (window.jspdf && window.jspdf.jsPDF) {\r\n      doGenerate(window.jspdf.jsPDF);\r\n    } else {\r\n      const s = document.createElement(\"script\");\r\n      s.src = \"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/jspdf\/2.5.1\/jspdf.umd.min.js\";\r\n      s.onload = () => doGenerate(window.jspdf.jsPDF);\r\n      s.onerror = () => {\r\n        const st = document.getElementById(\"export-status\");\r\n        if (st) { st.textContent = \"PDF teek ei laadinud. Kontrolli interneti\u00fchendust.\"; st.className = \"lp-export-status error\"; }\r\n      };\r\n      document.head.appendChild(s);\r\n    }\r\n  }\r\n\r\n  \/* \u2500\u2500 TAASK\u00c4IVITUS \u2500\u2500 *\/\r\n  document.getElementById(\"btn-restart\")?.addEventListener(\"click\", function(){\r\n    \/\/ L\u00e4htesta vormid\r\n    document.getElementById(\"lp-pitch-form-avixa\")?.reset();\r\n    document.getElementById(\"lp-size-form\")?.reset();\r\n    document.getElementById(\"room-w\") && (document.getElementById(\"room-w\").value=\"\");\r\n    document.getElementById(\"room-d\") && (document.getElementById(\"room-d\").value=\"\");\r\n    document.getElementById(\"room-h\") && (document.getElementById(\"room-h\").value=\"\");\r\n    document.getElementById(\"export-email\") && (document.getElementById(\"export-email\").value=\"\");\r\n    document.getElementById(\"export-name\")  && (document.getElementById(\"export-name\").value=\"\");\r\n\r\n    \/\/ L\u00e4htesta olek\r\n    Object.assign(state,{baseW:null,baseH:null,ledSize:null,lcdSingle:null,wallSize:null,ledStep:250,pitchMm:null,envAvixa:null,env:null,dist:null,content:null,lcdOrient:null,ledText:\"\",lcdText:\"\",pitchText:\"\"});\r\n\r\n    \/\/ Peida tulemused\r\n    [\"lp-pitch-result-avixa\",\"lp-size-result\",\"lp-room-section\",\"lp-export-section\"].forEach(id=>{\r\n      const el=document.getElementById(id); if(el)el.classList.add(\"lp-result-hidden\");\r\n    });\r\n\r\n    \/\/ Ruumiplaan t\u00fchjendus\r\n    const canvas=document.getElementById(\"lp-room-canvas\");\r\n    if(canvas){ const ctx=canvas.getContext(\"2d\"); ctx.clearRect(0,0,canvas.width,canvas.height); }\r\n    const hint=document.getElementById(\"lp-room-hint\"); if(hint)hint.textContent=\"\";\r\n\r\n    \/\/ Export status\r\n    const st=document.getElementById(\"export-status\"); if(st){ st.textContent=\"\"; st.className=\"lp-export-status\"; }\r\n\r\n    \/\/ Visuaal t\u00fchjendus\r\n    updateVisual(null,null,null,null,null,null);\r\n    updatePitchVisual(0);\r\n    fillPitchDropdown(\"indoor\");\r\n    document.querySelectorAll(\".lp-preset-btn\").forEach(b=>b.classList.remove(\"lp-preset-active\"));\r\n\r\n    setWizardStep(1);\r\n    window.scrollTo({top:0,behavior:\"smooth\"});\r\n    \/\/ Eemalda URL parameetrid\r\n    history.replaceState(null,\"\",window.location.pathname);\r\n  });\r\n\r\n});\r\n\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>\n\t\t","protected":false},"excerpt":{"rendered":"<p>Ekraani t\u00fc\u00fcbi ja suuruse valimise t\u00f6\u00f6riist Ekraani t\u00fc\u00fcbi ja suuruse valimise t\u00f6\u00f6riist Sobiva ekraani m\u00f5\u00f5du ja tehnoloogia valimine t\u00f6\u00f6- ja \u00e4rikeskkonda aitab planeerida Lumepix-i loodud t\u00f6\u00f6riist. T\u00f6ida vajalikud lahtrid ja saada tulemus endale E-mailile. 1 Keskkond &amp; kaugus 2 M\u00f5\u00f5dud &amp; pitch 3 Tulemused Kiirstart \u2013 vali kasutusala: \ud83c\udfec Kaubanduskeskus \ud83c\udfa4 Konverentsisaal \ud83d\udccb Koosolekuruum \ud83c\udf06 [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-13788","page","type-page","status-publish","hentry"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.4 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Aluspinna m\u00f5\u00f5du t\u00f6\u00f6riist - Lumepix<\/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:\/\/lumepix.eu\/en\/aluspinna-moodu-tooriist\/\" \/>\n<meta property=\"og:locale\" content=\"en_GB\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Aluspinna m\u00f5\u00f5du t\u00f6\u00f6riist - Lumepix\" \/>\n<meta property=\"og:description\" content=\"Ekraani t\u00fc\u00fcbi ja suuruse valimise t\u00f6\u00f6riist Ekraani t\u00fc\u00fcbi ja suuruse valimise t\u00f6\u00f6riist Sobiva ekraani m\u00f5\u00f5du ja tehnoloogia valimine t\u00f6\u00f6- ja \u00e4rikeskkonda aitab planeerida Lumepix-i loodud t\u00f6\u00f6riist. T\u00f6ida vajalikud lahtrid ja saada tulemus endale E-mailile. 1 Keskkond &amp; kaugus 2 M\u00f5\u00f5dud &amp; pitch 3 Tulemused Kiirstart \u2013 vali kasutusala: \ud83c\udfec Kaubanduskeskus \ud83c\udfa4 Konverentsisaal \ud83d\udccb Koosolekuruum \ud83c\udf06 [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/lumepix.eu\/en\/aluspinna-moodu-tooriist\/\" \/>\n<meta property=\"og:site_name\" content=\"Lumepix\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/people\/Lumepix\/61584204856868\/\" \/>\n<meta property=\"article:modified_time\" content=\"2026-03-24T11:04:48+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/lumepix.eu\/wp-content\/uploads\/2024\/10\/Artboard-1.png\" \/>\n\t<meta property=\"og:image:width\" content=\"416\" \/>\n\t<meta property=\"og:image:height\" content=\"93\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Estimated reading time\" \/>\n\t<meta name=\"twitter:data1\" content=\"2 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/lumepix.eu\\\/aluspinna-moodu-tooriist\\\/\",\"url\":\"https:\\\/\\\/lumepix.eu\\\/aluspinna-moodu-tooriist\\\/\",\"name\":\"Aluspinna m\u00f5\u00f5du t\u00f6\u00f6riist - Lumepix\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/lumepix.eu\\\/#website\"},\"datePublished\":\"2025-11-25T19:42:09+00:00\",\"dateModified\":\"2026-03-24T11:04:48+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/lumepix.eu\\\/aluspinna-moodu-tooriist\\\/#breadcrumb\"},\"inLanguage\":\"en-GB\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/lumepix.eu\\\/aluspinna-moodu-tooriist\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/lumepix.eu\\\/aluspinna-moodu-tooriist\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/lumepix.eu\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Aluspinna m\u00f5\u00f5du t\u00f6\u00f6riist\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/lumepix.eu\\\/#website\",\"url\":\"https:\\\/\\\/lumepix.eu\\\/\",\"name\":\"Lumepix\",\"description\":\"Audiovideo lahenduste m\u00fc\u00fck ja paigaldus\",\"publisher\":{\"@id\":\"https:\\\/\\\/lumepix.eu\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/lumepix.eu\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-GB\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/lumepix.eu\\\/#organization\",\"name\":\"Lumepix\",\"alternateName\":\"Lumepix\",\"url\":\"https:\\\/\\\/lumepix.eu\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-GB\",\"@id\":\"https:\\\/\\\/lumepix.eu\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/lumepix.eu\\\/wp-content\\\/uploads\\\/2024\\\/10\\\/Artboard-1-2.png\",\"contentUrl\":\"https:\\\/\\\/lumepix.eu\\\/wp-content\\\/uploads\\\/2024\\\/10\\\/Artboard-1-2.png\",\"width\":100,\"height\":100,\"caption\":\"Lumepix\"},\"image\":{\"@id\":\"https:\\\/\\\/lumepix.eu\\\/#\\\/schema\\\/logo\\\/image\\\/\"},\"sameAs\":[\"https:\\\/\\\/www.facebook.com\\\/people\\\/Lumepix\\\/61584204856868\\\/\",\"https:\\\/\\\/www.linkedin.com\\\/company\\\/106633848\"]}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Aluspinna m\u00f5\u00f5du t\u00f6\u00f6riist - Lumepix","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:\/\/lumepix.eu\/en\/aluspinna-moodu-tooriist\/","og_locale":"en_GB","og_type":"article","og_title":"Aluspinna m\u00f5\u00f5du t\u00f6\u00f6riist - Lumepix","og_description":"Ekraani t\u00fc\u00fcbi ja suuruse valimise t\u00f6\u00f6riist Ekraani t\u00fc\u00fcbi ja suuruse valimise t\u00f6\u00f6riist Sobiva ekraani m\u00f5\u00f5du ja tehnoloogia valimine t\u00f6\u00f6- ja \u00e4rikeskkonda aitab planeerida Lumepix-i loodud t\u00f6\u00f6riist. T\u00f6ida vajalikud lahtrid ja saada tulemus endale E-mailile. 1 Keskkond &amp; kaugus 2 M\u00f5\u00f5dud &amp; pitch 3 Tulemused Kiirstart \u2013 vali kasutusala: \ud83c\udfec Kaubanduskeskus \ud83c\udfa4 Konverentsisaal \ud83d\udccb Koosolekuruum \ud83c\udf06 [&hellip;]","og_url":"https:\/\/lumepix.eu\/en\/aluspinna-moodu-tooriist\/","og_site_name":"Lumepix","article_publisher":"https:\/\/www.facebook.com\/people\/Lumepix\/61584204856868\/","article_modified_time":"2026-03-24T11:04:48+00:00","og_image":[{"width":416,"height":93,"url":"https:\/\/lumepix.eu\/wp-content\/uploads\/2024\/10\/Artboard-1.png","type":"image\/png"}],"twitter_card":"summary_large_image","twitter_misc":{"Estimated reading time":"2 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/lumepix.eu\/aluspinna-moodu-tooriist\/","url":"https:\/\/lumepix.eu\/aluspinna-moodu-tooriist\/","name":"Aluspinna m\u00f5\u00f5du t\u00f6\u00f6riist - Lumepix","isPartOf":{"@id":"https:\/\/lumepix.eu\/#website"},"datePublished":"2025-11-25T19:42:09+00:00","dateModified":"2026-03-24T11:04:48+00:00","breadcrumb":{"@id":"https:\/\/lumepix.eu\/aluspinna-moodu-tooriist\/#breadcrumb"},"inLanguage":"en-GB","potentialAction":[{"@type":"ReadAction","target":["https:\/\/lumepix.eu\/aluspinna-moodu-tooriist\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/lumepix.eu\/aluspinna-moodu-tooriist\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/lumepix.eu\/"},{"@type":"ListItem","position":2,"name":"Aluspinna m\u00f5\u00f5du t\u00f6\u00f6riist"}]},{"@type":"WebSite","@id":"https:\/\/lumepix.eu\/#website","url":"https:\/\/lumepix.eu\/","name":"Lumepix","description":"Audiovideo lahenduste m\u00fc\u00fck ja paigaldus","publisher":{"@id":"https:\/\/lumepix.eu\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/lumepix.eu\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-GB"},{"@type":"Organization","@id":"https:\/\/lumepix.eu\/#organization","name":"Lumepix","alternateName":"Lumepix","url":"https:\/\/lumepix.eu\/","logo":{"@type":"ImageObject","inLanguage":"en-GB","@id":"https:\/\/lumepix.eu\/#\/schema\/logo\/image\/","url":"https:\/\/lumepix.eu\/wp-content\/uploads\/2024\/10\/Artboard-1-2.png","contentUrl":"https:\/\/lumepix.eu\/wp-content\/uploads\/2024\/10\/Artboard-1-2.png","width":100,"height":100,"caption":"Lumepix"},"image":{"@id":"https:\/\/lumepix.eu\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/people\/Lumepix\/61584204856868\/","https:\/\/www.linkedin.com\/company\/106633848"]}]}},"_links":{"self":[{"href":"https:\/\/lumepix.eu\/en\/wp-json\/wp\/v2\/pages\/13788","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/lumepix.eu\/en\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/lumepix.eu\/en\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/lumepix.eu\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/lumepix.eu\/en\/wp-json\/wp\/v2\/comments?post=13788"}],"version-history":[{"count":230,"href":"https:\/\/lumepix.eu\/en\/wp-json\/wp\/v2\/pages\/13788\/revisions"}],"predecessor-version":[{"id":14588,"href":"https:\/\/lumepix.eu\/en\/wp-json\/wp\/v2\/pages\/13788\/revisions\/14588"}],"wp:attachment":[{"href":"https:\/\/lumepix.eu\/en\/wp-json\/wp\/v2\/media?parent=13788"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}