{"id":3149,"date":"2026-02-08T18:19:06","date_gmt":"2026-02-08T17:19:06","guid":{"rendered":"https:\/\/www.papaya.events\/?page_id=3149"},"modified":"2026-02-17T03:26:07","modified_gmt":"2026-02-17T02:26:07","slug":"majstor-13","status":"publish","type":"page","link":"https:\/\/www.papaya.events\/hr\/master-13\/","title":{"rendered":"M-13"},"content":{"rendered":"<div class=\"wpb-content-wrapper\"><div class=\"vc_row wpb_row vc_row-fluid\"><div class=\"wpb_column vc_column_container vc_col-sm-12 sc_layouts_column_icons_position_left\"><div class=\"vc_column-inner\"><div class=\"wpb_wrapper\">\n\t<div class=\"wpb_raw_code wpb_raw_html wpb_content_element\" >\n\t\t<div class=\"wpb_wrapper\">\n\t\t\t<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no\">\r\n    <title>Sonic Lab v1.10 - Modular<\/title>\r\n    \r\n    <style>\r\n        @import url('https:\/\/fonts.googleapis.com\/css2?family=Orbitron:wght@400..900&display=swap');\r\n@import url('https:\/\/fonts.googleapis.com\/css2?family=Rajdhani:wght@500;600;700&display=swap');\r\n\r\n\/* --- SCOPED THEME & WP RESET --- *\/\r\n#sonic-lab-v25 {\r\n    \/* Lokalne varijable *\/\r\n    --metal-base: #1e293b;\r\n    --neon-blue: #38bdf8;\r\n    --neon-red: #ef4444;\r\n    --screen-bg: #38bdf8;    \r\n    --screen-ink: #0f172a;\r\n    --glass-bg: rgba(2, 6, 23, 0.6); \r\n\r\n    all: initial; \r\n    display: block;\r\n    touch-action: manipulation; \r\n    \r\n    background-color: var(--metal-base) !important;\r\n    background-image: \r\n        repeating-linear-gradient(90deg, transparent 0, transparent 1px, rgba(255,255,255,0.03) 1px, rgba(255,255,255,0.03) 2px),\r\n        linear-gradient(180deg, #334155 0%, #0f172a 100%) !important;\r\n    color: #94a3b8 !important;\r\n    font-family: 'Rajdhani', system-ui, -apple-system, sans-serif !important;\r\n    padding: 35px 10px 45px 10px;\r\n    border-radius: 16px !important;\r\n    max-width: 1050px !important; \r\n    margin: 0px auto !important;\r\n    border: 2px solid #475569 !important;\r\n    box-shadow: 0 0 0 2px #020617, 0 30px 70px rgba(0,0,0,0.8), inset 0 2px 1px rgba(255,255,255,0.15) !important; \r\n    box-sizing: border-box !important;\r\n    position: relative;\r\n    line-height: normal !important;\r\n    transition: border-color 0.5s;\r\n    -webkit-tap-highlight-color: transparent; \r\n}\r\n\r\n#sonic-lab-v25 * { \r\n    box-sizing: border-box !important; \r\n    font-family: 'Rajdhani', sans-serif !important; \r\n    margin: 0; padding: 0; \r\n    -webkit-tap-highlight-color: transparent;\r\n}\r\n\r\n\/* --- SYSTEM OFF STATE STYLES --- *\/\r\n#sonic-lab-v25.sys-off { border-color: #334155 !important; }\r\n\r\n#sonic-lab-v25.sys-off .pan-side-val,\r\n#sonic-lab-v25.sys-off .pan-side-label,\r\n#sonic-lab-v25.sys-off .lab-title span,\r\n#sonic-lab-v25.sys-off .panel-head,\r\n#sonic-lab-v25.sys-off .pan-display-row,\r\n#sonic-lab-v25.sys-off .pan-display-row span,\r\n#sonic-lab-v25.sys-off .meter-label,\r\n#sonic-lab-v25.sys-off .meter-scale-half span,\r\n#sonic-lab-v25.sys-off #sub-status, \r\n#sonic-lab-v25.sys-off #iso-status,\r\n#sonic-lab-v25.sys-off .text-glow-white,\r\n#sonic-lab-v25.sys-off #kick-btn-val,\r\n#sonic-lab-v25.sys-off .knob-val-display\r\n{\r\n    color: #475569 !important;\r\n    border-color: #475569 !important;\r\n    text-shadow: none !important;\r\n    transition: color 0.5s, border-color 0.5s;\r\n}\r\n\r\n#sonic-lab-v25.sys-off .knob-ring { background: #334155 !important; box-shadow: none !important; }\r\n#sonic-lab-v25.sys-off .knob-cap { background: #1e293b !important; border-color: #334155 !important; }\r\n#sonic-lab-v25.sys-off .knob-indicator { background: #475569 !important; box-shadow: none !important; }\r\n\r\n#sonic-lab-v25.sys-off button.sub-toggle,\r\n#sonic-lab-v25.sys-off button.sub-toggle.sub-ready {\r\n    color: #475569 !important;\r\n    border-color: #334155 !important;\r\n    text-shadow: none !important;\r\n    cursor: not-allowed !important;\r\n    transition: color 0.5s;\r\n}\r\n\r\n#sonic-lab-v25.sys-off .tick,\r\n#sonic-lab-v25.sys-off .vol-tick { color: #475569 !important; text-shadow: none !important; }\r\n\r\n#sonic-lab-v25.sys-off .mus-screen,\r\n#sonic-lab-v25.sys-off .rta-screen,\r\n#sonic-lab-v25.sys-off .sub-screen,\r\n#sonic-lab-v25.sys-off .digital-screen-container {\r\n    background: #000 !important;\r\n    box-shadow: inset 0 0 10px #000 !important;\r\n    border-color: #1e293b !important;\r\n}\r\n\r\n#sonic-lab-v25.sys-off canvas,\r\n#sonic-lab-v25.sys-off .mus-grid-display,\r\n#sonic-lab-v25.sys-off #sub-hz-val,\r\n#sonic-lab-v25.sys-off #iso-hz-val,\r\n#sonic-lab-v25.sys-off #freq-mini-disp,\r\n#sonic-lab-v25.sys-off #warning-overlay {\r\n    opacity: 0 !important;\r\n    transition: opacity 0.3s;\r\n}\r\n\r\n#sonic-lab-v25.sys-off #btn-stop {\r\n    color: #ffffff4a !important; \r\n    text-shadow: none !important;\r\n    border-color: #334155 !important;\r\n}\r\n\r\n#sonic-lab-v25.sys-off #btn-sine {\r\n    background: linear-gradient(180deg, #aebcd1 0%, #334155 50%, #1e293b 51%, #334155 100%) !important;\r\n    border: 2px solid #0f172a !important; \r\n    border-top: 2px solid #64748b !important;\r\n    color: #fff !important;\r\n    box-shadow: 0 4px 6px rgba(0,0,0,0.5), inset 0 1px 0 rgba(255,255,255,0.1) !important;\r\n    text-shadow: 0 -1px 0 #000 !important;\r\n    transform: none !important;\r\n}\r\n\r\n#sonic-lab-v25.sys-off .piano-wrapper::before { background: #475569 !important; box-shadow: none !important; }\r\n\r\n\/* FONTS & BASE *\/\r\n#sonic-lab-v25 .modal-header-bar,\r\n#sonic-lab-v25 h2,\r\n#sonic-lab-v25 #screen-input,\r\n#sonic-lab-v25 #warning-overlay,\r\n#sonic-lab-v25 .meter-label,\r\n#sonic-lab-v25 .mus-cell,\r\n#sonic-lab-v25 #sub-hz-val, \r\n#sonic-lab-v25 #iso-hz-val,\r\n#sonic-lab-v25 .help-btn,\r\n#sonic-lab-v25 .knob-label {\r\n    font-family: 'Orbitron', monospace !important;\r\n}\r\n\r\n#sonic-lab-v25 button { all: unset; cursor: pointer !important; }\r\n#sonic-lab-v25 input { all: unset; }\r\n\r\n\/* --- KNOB STYLES --- *\/\r\n#sonic-lab-v25 .knob-wrapper {\r\n    display: flex; flex-direction: column; align-items: center; gap: 5px; position: relative; width: 16%;\r\n    touch-action: none !important; \r\n}\r\n#sonic-lab-v25 .knob-container {\r\n    width: 55px; height: 55px; position: relative; cursor: ns-resize;\r\n    border-radius: 50%;\r\n    box-shadow: inset 0 2px 5px rgba(0,0,0,0.8), 0 1px 0 rgba(255,255,255,0.1);\r\n    background: #0f172a;\r\n    touch-action: none !important; \r\n}\r\n#sonic-lab-v25 .knob-ring {\r\n    position: absolute; top: 0; left: 0; width: 100%; height: 100%; border-radius: 50%;\r\n    background: conic-gradient(var(--neon-blue) 0%, #334155 0%);\r\n    box-shadow: 0 0 10px rgba(56, 189, 248, 0.2);\r\n    transition: box-shadow 0.3s;\r\n    pointer-events: none; \r\n}\r\n#sonic-lab-v25 .knob-cap {\r\n    position: absolute; top: 5px; left: 5px; width: 45px; height: 45px;\r\n    border-radius: 50%;\r\n    background: linear-gradient(135deg, #475569 0%, #1e293b 100%);\r\n    border: 1px solid #64748b; border-bottom: 2px solid #0f172a;\r\n    box-shadow: 0 4px 5px rgba(0,0,0,0.5), inset 0 1px 1px rgba(255,255,255,0.3);\r\n    transform: rotate(0deg); \r\n    z-index: 2;\r\n    pointer-events: none; \r\n}\r\n#sonic-lab-v25 .knob-indicator {\r\n    position: absolute; top: 3px; left: 50%; width: 2px; height: 8px;\r\n    background: var(--neon-blue); transform: translateX(-50%);\r\n    box-shadow: 0 0 5px var(--neon-blue); border-radius: 1px;\r\n}\r\n#sonic-lab-v25 .knob-label {\r\n    font-size: 8px; color: #94a3b8; font-weight: bold; letter-spacing: 1px; white-space: nowrap;\r\n}\r\n#sonic-lab-v25 .knob-val-display {\r\n    font-size: 9px; color: #fff; font-weight: bold; margin-top: -2px; text-shadow: 0 0 5px rgba(255,255,255,0.5); white-space: nowrap;\r\n}\r\n\r\n\/* MOBILE POPUP SLIDER *\/\r\n#sonic-lab-v25 #mobile-knob-editor {\r\n    display: none; \r\n    position: fixed; \r\n    top: 50%; \r\n    left: 50%; \r\n    transform: translate(-50%, -50%); \r\n    width: 80%; \r\n    max-width: 300px;\r\n    background: rgba(15, 23, 42, 0.98);\r\n    border: 2px solid var(--neon-blue); \r\n    border-radius: 12px;\r\n    padding: 20px; \r\n    z-index: 9999; \r\n    backdrop-filter: blur(10px);\r\n    box-shadow: 0 0 50px rgba(0,0,0,0.9);\r\n    flex-direction: column; gap: 15px; text-align: center;\r\n    animation: popUp 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275);\r\n}\r\n@keyframes popUp { from { transform: translate(-50%, -40%); opacity: 0; } to { transform: translate(-50%, -50%); opacity: 1; } }\r\n\r\n#sonic-lab-v25 #mobile-knob-title { color: var(--neon-blue); font-weight: 900; font-size: 14px; letter-spacing: 2px; margin-bottom: 5px; font-family: 'Orbitron'; }\r\n#sonic-lab-v25 #mobile-knob-val { color: #fff; font-weight: bold; font-size: 24px; margin-bottom: 10px; text-shadow: 0 0 10px rgba(255,255,255,0.5); font-family: 'Orbitron'; }\r\n#sonic-lab-v25 .close-popup-area { position: fixed; top:0; left:0; width:100%; height:100%; z-index: 9998; display:none; background: rgba(0,0,0,0.5); backdrop-filter: blur(2px); }\r\n\r\n\/* SCREWS *\/\r\n#sonic-lab-v25 .screw {\r\n    width: 18px; height: 18px;\r\n    background: linear-gradient(135deg, #94a3b8, #475569);\r\n    border-radius: 50%;\r\n    box-shadow: 0 2px 4px rgba(0,0,0,0.8), inset 0 1px 0 rgba(255,255,255,0.4);\r\n    position: absolute; z-index: 10;\r\n    display: flex; justify-content: center; align-items: center;\r\n    border: 1px solid #334155;\r\n}\r\n#sonic-lab-v25 .screw::after {\r\n    content: ''; width: 8px; height: 8px; background: #1e293b;\r\n    clip-path: polygon(50% 0%, 100% 25%, 100% 75%, 50% 100%, 0% 75%, 0% 25%);\r\n    box-shadow: inset 0 1px 2px #000;\r\n}\r\n#sonic-lab-v25 .tl { top: 12px; left: 12px; } #sonic-lab-v25 .tr { top: 12px; right: 12px; }\r\n#sonic-lab-v25 .bl { bottom: 12px; left: 12px; } #sonic-lab-v25 .br { bottom: 12px; right: 12px; }\r\n\r\n\/* HELP BUTTON *\/\r\n#sonic-lab-v25 .help-btn {\r\n    position: absolute; bottom: 5px; left: 50%; transform: translateX(-50%);\r\n    width: 35px; height: 35px; border-radius: 50%;\r\n    background: linear-gradient(145deg, #1e293b, #0f172a) !important; \r\n    color: #64748b;\r\n    font-weight: 900; font-size: 22px; text-align: center; line-height: 24px;\r\n    box-shadow: 0 4px 10px rgba(0,0,0,0.8), inset 0 1px 0 rgba(255,255,255,0.1);\r\n    border: 2px solid #334155; cursor: pointer; z-index: 20;\r\n    transition: all 0.2s;\r\n}\r\n#sonic-lab-v25 .help-btn:hover { color: #94a3b8; border-color: #475569; }\r\n#sonic-lab-v25 .help-btn:active { transform: translateX(-50%) scale(0.95); background: #020617; color: var(--neon-blue); border-color: var(--neon-blue); box-shadow: 0 0 10px rgba(56, 189, 248, 0.3); }\r\n\r\n\/* MODALS *\/\r\n#sonic-lab-v25 #safety-modal, #sonic-lab-v25 #help-modal {\r\n    display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%;\r\n    background: rgba(2, 6, 23, 0.95); z-index: 9999; \r\n    justify-content: center; align-items: center; backdrop-filter: blur(8px);\r\n}\r\n#sonic-lab-v25 .modal-box {\r\n    background: #1e293b; border: 4px solid #334155; border-radius: 12px;\r\n    width: 750px; \r\n    max-width: 95%; height: 600px; max-height: 90vh; text-align: left; \r\n    box-shadow: 0 0 60px rgba(0, 0, 0, 0.8);\r\n    animation: modalPop 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);\r\n    overflow: hidden; padding: 0; display: flex; flex-direction: column;\r\n}\r\n#sonic-lab-v25 .modal-box.danger { \r\n    border-color: #b91c1c; \r\n    width: 400px !important; \r\n    height: auto !important; \r\n    text-align: center; \r\n    padding-bottom: 20px;\r\n}\r\n  \r\n#sonic-lab-v25 .modal-header-bar {\r\n    background: linear-gradient(180deg, #334155, #1e293b);\r\n    color: white; padding: 15px; font-weight: 900; letter-spacing: 2px;\r\n    text-shadow: 0 1px 2px rgba(0,0,0,0.5); border-bottom: 2px solid #0f172a;\r\n    display: flex; align-items: center; justify-content: space-between; font-size: 16px;\r\n}\r\n#sonic-lab-v25 .modal-header-bar.danger { background: linear-gradient(180deg, #ef4444, #b91c1c); border-bottom: 2px solid #7f1d1d; justify-content: center; font-size: 20px;}\r\n\r\n#sonic-lab-v25 .help-layout-grid {\r\n    display: grid; grid-template-columns: 180px 1fr; height: 100%; overflow: hidden;\r\n}\r\n#sonic-lab-v25 .help-menu {\r\n    background: #0f172a; border-right: 1px solid #334155; padding: 15px;\r\n    overflow-y: auto; display: flex; flex-direction: column; gap: 5px;\r\n}\r\n#sonic-lab-v25 .help-content {\r\n    padding: 25px;\r\n    overflow-y: scroll; \/* Osigurava skrolanje *\/\r\n    height: 100%;       \/* Uzima punu visinu modala *\/\r\n    display: block;     \/* Sprje\u010dava sa\u017eimanje elemenata *\/\r\n}\r\n\r\n#sonic-lab-v25 .menu-item {\r\n    color: #94a3b8; font-size: 11px; font-weight: bold; cursor: pointer;\r\n    padding: 8px 10px; border-radius: 4px; transition: all 0.2s;\r\n    text-transform: uppercase; letter-spacing: 1px;\r\n}\r\n#sonic-lab-v25 .menu-item:hover { background: #1e293b; color: #cbd5e1; }\r\n#sonic-lab-v25 .menu-item.active { background: rgba(56, 189, 248, 0.1); color: var(--neon-blue); border-left: 2px solid var(--neon-blue); }\r\n\r\n@media (max-width: 800px) {\r\n    #sonic-lab-v25 .modal-box { width: 98% !important; height: 85vh !important; }\r\n    #sonic-lab-v25 .help-layout-grid { display: flex !important; flex-direction: column !important; }\r\n    #sonic-lab-v25 .help-menu { width: 100% !important; border-right: none !important; border-bottom: 2px solid #334155; flex-direction: row !important; flex-wrap: wrap !important; gap: 5px !important; padding: 10px !important; min-height: auto; flex-shrink: 0; }\r\n    #sonic-lab-v25 .menu-item { width: calc(50% - 5px) !important; text-align: center !important; border: 1px solid #334155; margin-bottom: 0 !important; background: #020617; padding: 10px 5px !important; }\r\n    #sonic-lab-v25 .menu-item.active { border-left: 1px solid #334155 !important; border-color: var(--neon-blue) !important; background: rgba(56, 189, 248, 0.15) !important; box-shadow: inset 0 0 10px rgba(56, 189, 248, 0.1); }\r\n    #sonic-lab-v25 .help-content { flex: 1; padding: 20px 15px !important; }\r\n    #sonic-lab-v25 .modal-actions .modal-btn { height: 55px !important; font-size: 12px !important; }\r\n}\r\n\r\n#sonic-lab-v25 .modal-section { margin-bottom: 40px; border-bottom: 1px solid #334155; padding-bottom: 20px; }\r\n#sonic-lab-v25 .modal-section:last-child { border: none; }\r\n\r\n#sonic-lab-v25 .modal-h3 { \r\n    color: var(--neon-blue); font-family: 'Orbitron'; font-size: 16px; \r\n    margin-bottom: 15px; display: block; font-weight: bold; \r\n    text-transform: uppercase !important; \r\n}\r\n\r\n#sonic-lab-v25 .modal-text { \r\n    font-size: 13px; color: #cbd5e1; line-height: 1.7; margin-bottom: 15px; \r\n    text-transform: none !important; \r\n    text-align: justify !important; \r\n    font-family: 'Rajdhani', sans-serif !important;\r\n}\r\n#sonic-lab-v25 .modal-text strong { color: #fff; font-weight: bold; }\r\n\r\n#sonic-lab-v25 .help-list { \r\n    padding-left: 20px; color: #94a3b8; font-size: 12px; line-height: 1.6; margin-bottom: 15px; \r\n    text-transform: none !important; \r\n    text-align: justify !important; \r\n    font-family: 'Rajdhani', sans-serif !important;\r\n}\r\n#sonic-lab-v25 .help-list li { margin-bottom: 5px; }\r\n\r\n@keyframes modalPop { from { transform: scale(0.9); opacity: 0; } to { transform: scale(1); opacity: 1; } }\r\n#sonic-lab-v25 .modal-actions { display: flex; gap: 15px; justify-content: center; margin-top: 20px;}\r\n\r\n#sonic-lab-v25 .lab-header {\r\n    display: flex; justify-content: space-between; align-items: center;\r\n    margin-bottom: 5px; border-bottom: 0px groove #334155; padding-bottom: 0px; margin-top: -29px;\r\n}\r\n#sonic-lab-v25 h2 { \r\n    margin-left: 30px !important; font-size: 14px !important; font-weight: 900 !important; letter-spacing: 1px !important; color: #e2e8f0 !important; \r\n    text-shadow: 0 2px 4px rgba(0,0,0,0.5) !important; \r\n    background: transparent !important; padding: 0 !important; line-height: 1.2 !important;\r\n}\r\n#sonic-lab-v25 .lab-title span { color: var(--neon-blue); font-size: 11px; font-weight: bold; letter-spacing: 3px; text-transform: uppercase; text-shadow: 0 0 5px rgba(56,189,248,0.5); margin-left: 0px; margin-left: 30px; transition: color 0.5s; }\r\n    \r\n#sonic-lab-v25 .status-panel {\r\n    font-size: 09px!important; font-weight: bold; color: #94a3b8; display: flex; align-items: center; gap: 10px;\r\n    background: #0f172a; padding: 5px 5px; border-radius: 4px; border: 1px solid #334155;\r\n    box-shadow: inset 0 2px 5px rgba(0,0,0,0.8); margin-right: 28px;\r\n}\r\n#sonic-lab-v25 .led-ind { width: 8px; height: 8px; background: #334155; border-radius: 50%; transition: 0.3s; box-shadow: inset 0 1px 1px rgba(0,0,0,1); }\r\n#sonic-lab-v25 .led-ind.active { background: var(--neon-blue); box-shadow: 0 0 10px var(--neon-blue); animation: pulseBlue 2s infinite; }\r\n@keyframes pulseBlue { 0% { opacity: 1; } 50% { opacity: 0.5; } 100% { opacity: 1; } }\r\n\r\n#sonic-lab-v25 .digital-screen-container {\r\n    background: #020617; padding: 6px; border-radius: 8px; margin-bottom: 10px; height: 296px; \r\n    box-shadow: inset 0 0 0 2px #0f172a, inset 0 0 0 5px #334155, inset 0 1px 0 5px rgba(255,255,255,0.1), 0 10px 30px rgba(0,0,0,0.7); \r\n    border: 1px solid #1e293b; position: relative;\r\n    transition: background 0.5s;\r\n}\r\n#sonic-lab-v25 .screen-inner {\r\n    width: 100%; height: 100%; background: #000; transform-origin: center;\r\n    position: relative; border-radius: 2px; overflow: hidden; border: 1px solid #0f172a;\r\n}\r\n#sonic-lab-v25 .screen-inner::after {\r\n    content: ''; position: absolute; top:0; left:0; width:100%; height:100%;\r\n    background: linear-gradient(135deg, rgba(255,255,255,0.05) 0%, transparent 40%, rgba(0,0,0,0.1) 100%);\r\n    pointer-events: none; z-index: 10;\r\n}\r\n#sonic-lab-v25 .screen-inner.crt-on {\r\n    background: radial-gradient(circle at center, var(--screen-bg) 40%, #0ea5e9 150%);\r\n    box-shadow: inset 0 0 30px rgba(0 0 0 \/ 75%);\r\n    animation: turnOn 0.4s linear forwards;\r\n}\r\n@keyframes turnOn {\r\n    0% { transform: scale(1, 0.002); opacity: 0; filter: brightness(0); background: #000;}\r\n    20% { transform: scale(1, 0.002); opacity: 1; filter: brightness(5); background: #fff; }\r\n    50% { transform: scale(1, 1); opacity: 1; filter: brightness(1.5); background: radial-gradient(circle at center, var(--screen-bg) 40%, #0ea5e9 150%); }\r\n    100% { transform: scale(1, 1); opacity: 1; filter: brightness(1); background: radial-gradient(circle at center, var(--screen-bg) 40%, #0ea5e9 150%); }\r\n}\r\n#sonic-lab-v25 .screen-inner.crt-off { background: #000 !important; transition: background 0.1s; }\r\n#sonic-lab-v25 canvas#scope { width: 100%; height: 100%; display: block; opacity: 1; transition: opacity 0.5s; }\r\n\r\n#sonic-lab-v25 #hz-overlay { position: absolute; top: 10px; right: 5px; display: none; text-align: right; z-index: 9; pointer-events: auto; }\r\n#sonic-lab-v25 .crt-on #hz-overlay { display: block; animation: fadeIn 1s forwards 0.5s; opacity: 0; }\r\n@keyframes fadeIn { to { opacity: 1; } }\r\n\r\n#sonic-lab-v25 #screen-input {\r\n    background: transparent !important; border: none !important; outline: none !important;\r\n    font-size: 30px !important; font-weight: 600 !important;\r\n    color: var(--screen-ink) !important; text-align: right !important; width: 400px !important;\r\n    margin: 0 !important; padding: 0 !important; pointer-events: auto !important; text-transform: none !important;\r\n    text-shadow: 0 0 3px rgba(15, 23, 42, 0.6), 0 0 1px var(--screen-ink) !important;\r\n    box-shadow: none !important;\r\n}\r\n#sonic-lab-v25 #screen-input:focus { border-bottom: 2px solid var(--screen-ink) !important; }\r\n\r\n#sonic-lab-v25 #warning-overlay {\r\n    position: absolute; top: 85%; left: 50%; transform: translate(-50%, -50%);\r\n    font-weight: 900; font-size: 10px;\r\n    color: var(--screen-ink); text-align: center; display: none; z-index: 20;\r\n    text-shadow: 0 0 2px rgba(255,255,255,0.3); width: 90%; letter-spacing: 1px;\r\n}\r\n#sonic-lab-v25 .crt-on #warning-overlay.show { display: block; animation: flashWarn 0.5s infinite alternate; color: var(--screen-ink);}\r\n@keyframes flashWarn { 0% { opacity: 1; } 100% { opacity: 0.3; } }\r\n\r\n\/* METERS *\/\r\n#sonic-lab-v25 .meter-bridge {\r\n    background: #0f172a; border: 1px solid #334155; border-radius: 6px; padding: 10px;\r\n    margin-bottom: 10px; box-shadow: inset 0 2px 10px rgba(0,0,0,0.8);\r\n    border-bottom: 1px solid #475569; position: relative; overflow: hidden; \r\n}\r\n#sonic-lab-v25 .meter-bridge::after {\r\n    content: ''; position: absolute; top: 0; left: 0; width: 100%; height: 100%;\r\n    background: linear-gradient(135deg, rgba(255,255,255,0.06) 0%, transparent 40%, rgba(0,0,0,0.3) 100%);\r\n    box-shadow: inset 0 0 25px rgba(2, 6, 23, 0.95), inset 0 0 10px rgba(2, 6, 23, 0.7);\r\n    pointer-events: none; z-index: 10;\r\n}\r\n#sonic-lab-v25 .meter-row { display: flex; flex-direction: row; gap: 20px; align-items: center; position: relative; z-index: 2; }\r\n#sonic-lab-v25 .meter-channel { display: flex; align-items: center; gap: 8px; flex: 1; }\r\n#sonic-lab-v25 .meter-label { \r\n    font-size: 11px; color: #e0f2fe; \r\n    font-weight: 900; width: 15px; text-shadow: 0 0 6px var(--neon-blue), 0 0 2px var(--neon-blue);\r\n    transition: color 0.5s;\r\n}\r\n#sonic-lab-v25 .led-strip { flex: 1; display: flex; gap: 3px; height: 10px; background: #020617; padding: 2px; border-radius: 2px; box-shadow: inset 0 1px 3px #000; }\r\n#sonic-lab-v25 .led-seg { flex: 1; background: #1e293b; border-radius: 1px; transition: background 0.05s; }\r\n#sonic-lab-v25 .led-seg.on-green { background: var(--neon-blue); box-shadow: 0 0 8px var(--neon-blue); }\r\n#sonic-lab-v25 .led-seg.on-yellow { background: #eab308; box-shadow: 0 0 8px #eab308; }\r\n#sonic-lab-v25 .led-seg.on-red { background: #ef4444; box-shadow: 0 0 10px #ef4444; }\r\n#sonic-lab-v25 .meter-scale-row { display: flex; flex-direction: row; gap: 20px; margin-top: 4px; position: relative; z-index: 2;}\r\n#sonic-lab-v25 .meter-scale-half { flex: 1; display: flex; justify-content: space-between; font-family: monospace; font-size: 9px; padding-left: 23px; }\r\n#sonic-lab-v25 .meter-scale-half span { color: #e0f2fe; text-shadow: 0 0 6px var(--neon-blue), 0 0 2px var(--neon-blue); font-weight: bold; transition: color 0.5s; }\r\n\r\n#sonic-lab-v25 .controls-grid { display: grid; grid-template-columns: 1fr 1.3fr; gap: 10px; } \r\n@media (max-width: 900px) { #sonic-lab-v25 .controls-grid { grid-template-columns: 1fr; } }\r\n#sonic-lab-v25 .right-column-wrap { display: flex; flex-direction: column; gap: 10px; }\r\n\r\n#sonic-lab-v25 .panel-card { \r\n    background: linear-gradient(135deg, #253045, #1e293b);\r\n    border: 1px solid #475569; border-top: 1px solid #64748b; border-bottom: 1px solid #0f172a;\r\n    border-radius: 8px; padding: 5px; box-shadow: 0 10px 20px rgba(0,0,0,0.3), inset 0 1px 0 rgba(255,255,255,0.05);\r\n    position: relative;\r\n}\r\n#sonic-lab-v25 .panel-card::before { content:''; position:absolute; top:8px; left:8px; width:8px; height:8px; background:#0f172a; border-radius:50%; box-shadow:inset 0 1px 1px rgba(255,255,255,0.2); opacity:0.0; }\r\n#sonic-lab-v25 .panel-card::after { content:''; position:absolute; top:8px; right:8px; width:8px; height:8px; background:#0f172a; border-radius:50%; box-shadow:inset 0 1px 1px rgba(255,255,255,0.2); opacity:0.0; }\r\n\r\n#sonic-lab-v25 .panel-head {\r\n    font-size: 11px; font-weight: 800; text-transform: uppercase; \r\n    letter-spacing: 1px; margin-bottom: 20px; display: block; \r\n    padding-bottom: 10px; color: var(--neon-blue); \r\n    border-bottom: 1px solid var(--neon-blue); text-shadow: 0 0 8px rgba(56,189,248,0.5);\r\n    transition: color 0.5s, border-color 0.5s;\r\n}\r\n#sonic-lab-v25 .tech-sub { display: block; font-size: 9px; color: #64748b !important; margin-top: -15px; margin-bottom: 20px; letter-spacing: 1px; font-family: monospace; }\r\n#sonic-lab-v25 .wave-row { display: grid; grid-template-columns: repeat(5, 1fr); gap: 8px; margin-bottom: 20px; }\r\n\r\n#sonic-lab-v25 button.tech-btn, #sonic-lab-v25 button.modal-btn, #sonic-lab-v25 button.pan-side-btn {\r\n    background: linear-gradient(180deg, #aebcd1 0%, #334155 50%, #1e293b 51%, #334155 100%) !important;\r\n    border: 2px solid #0f172a !important; border-top: 2px solid #64748b !important;\r\n    color: #cbd5e1 !important; text-shadow: 0 -1px 0 #000 !important;\r\n    padding: 0 !important; height: 48px !important; border-radius: 4px !important; \r\n    font-size: 10px !important; font-weight: 700 !important; \r\n    transition: all 0.1s ease-out !important; text-align: center !important; margin: 0 !important;\r\n    width: 100%; display: flex !important; justify-content: center !important; align-items: center !important; gap: 6px !important; \r\n    box-shadow: 0 4px 6px rgba(0,0,0,0.5), inset 0 1px 0 rgba(255,255,255,0.1) !important;\r\n    position: relative; z-index: 1;\r\n}\r\n#sonic-lab-v25 button.tech-btn:hover { background: linear-gradient(180deg, #576880 0%, #3f4f66 50%, #29354a 51%, #3f4f66 100%) !important; color: #fff !important; }\r\n#sonic-lab-v25 button.tech-btn:active, #sonic-lab-v25 button.tech-btn.active { \r\n    background: #0f172a !important; color: var(--neon-blue) !important; border: 2px solid var(--neon-blue) !important;\r\n    box-shadow: inset 0 0 10px rgba(56,189,248,0.3), 0 0 8px rgba(56,189,248,0.4) !important;\r\n    text-shadow: 0 0 5px var(--neon-blue) !important; transform: translateY(1px); \r\n}\r\n#sonic-lab-v25 button.noise-btn { flex-direction: column !important; justify-content: center !important; gap: 3px !important; }\r\n\r\n#sonic-lab-v25 button.pan-side-btn { \r\n    width: 62px !important; \r\n    height: 50px !important; \r\n    flex-shrink: 0; \r\n    flex-direction: column !important; \r\n    gap: 2px !important;\r\n    line-height: 1 !important;\r\n}\r\n#sonic-lab-v25 .pan-side-label { font-size: 15px; font-weight: 900; color: #e2e8f0; transition: color 0.5s; }\r\n#sonic-lab-v25 .pan-side-val { font-size: 9px; color: var(--neon-blue); font-weight: bold; transition: color 0.5s; }\r\n\r\n#sonic-lab-v25 button.pan-side-btn:active .pan-side-label,\r\n#sonic-lab-v25 button.pan-side-btn:active .pan-side-val { color: var(--neon-blue) !important; }\r\n\r\n#sonic-lab-v25 button.modal-btn { width: 120px !important; height: 38px !important; font-size: 11px !important; }\r\n\r\n#sonic-lab-v25 .btn-icon, #sonic-lab-v25 .noise-icon { \r\n    width: 20px; height: 16px; fill: none; stroke: currentColor; stroke-width: 1.5px; \r\n    stroke-linecap: round; stroke-linejoin: round; filter: drop-shadow(0 1px 1px rgba(0,0,0,0.5));\r\n}\r\n#sonic-lab-v25 button.noise-white.active { color: #ffffff !important; border-color: #ffffff !important; text-shadow: 0 0 5px #ffffff !important; box-shadow: inset 0 0 10px rgba(255,255,255,0.4), 0 0 8px rgba(255,255,255,0.4) !important; }\r\n#sonic-lab-v25 button.noise-pink.active { color: #f472b6 !important; border-color: #ec4899 !important; text-shadow: 0 0 5px #ec4899 !important; box-shadow: inset 0 0 10px rgba(236, 72, 153, 0.4), 0 0 8px rgba(236, 72, 153, 0.4) !important; }\r\n#sonic-lab-v25 button.noise-blue.active { color: #60a5fa !important; border-color: #3b82f6 !important; text-shadow: 0 0 5px #3b82f6 !important; box-shadow: inset 0 0 10px rgba(59, 130, 246, 0.4), 0 0 8px rgba(59, 130, 246, 0.4) !important; }\r\n#sonic-lab-v25 button.noise-grey.active { color: #cbd5e1 !important; border-color: #94a3b8 !important; text-shadow: 0 0 5px #94a3b8 !important; box-shadow: inset 0 0 10px rgba(148, 163, 184, 0.4), 0 0 8px rgba(148, 163, 184, 0.4) !important; }\r\n#sonic-lab-v25 button.noise-red.active { color: #f87171 !important; border-color: #ef4444 !important; text-shadow: 0 0 5px #ef4444 !important; box-shadow: inset 0 0 10px rgba(239, 68, 68, 0.4), 0 0 8px rgba(239, 68, 68, 0.4) !important; }\r\n#sonic-lab-v25 button.btn-confirm { background: linear-gradient(180deg, #ef4444, #991b1b) !important; color: white !important; border: 1px solid #7f1d1d !important; border-bottom: 3px solid #450a0a !important; }\r\n\r\n\/* MUSICAL DISPLAY *\/\r\n#sonic-lab-v25 .mus-screen {\r\n    background: radial-gradient(circle at center, var(--screen-bg) 20%, #0369a1 150%); height: 48px; margin-bottom: 8px; \r\n    border: 2px solid #0f172a; border-radius: 4px; position: relative; overflow: hidden; display: flex; align-items: center; justify-content: center;\r\n    box-shadow: inset 0 0 15px rgba(2, 6, 23, 0.8), inset 0 0 5px rgba(2, 6, 23, 0.5);\r\n    transition: background 0.5s;\r\n}\r\n#sonic-lab-v25 .mus-grid-display { display: grid; grid-template-columns: 1fr 1fr 1.5fr; gap: 6px; width: 100%; padding: 0 10px; z-index: 2; opacity: 0.85; filter: blur(0.4px); transition: opacity 0.5s;}\r\n#sonic-lab-v25 .mus-cell {\r\n    border: 1px solid rgba(15, 23, 42, 0.3); border-radius: 2px; text-align: center;\r\n    font-size: 12px; font-weight: 900; color: var(--screen-ink); padding: 4px 0;\r\n    background: rgba(255,255,255,0.05); text-shadow: 0 0 3px rgba(15, 23, 42, 0.6); white-space: nowrap;\r\n}\r\n\r\n\/* RTA ANALYZER *\/\r\n#sonic-lab-v25 .rta-screen {\r\n    background: #020617; height: 100px; margin-bottom: 8px; border: 2px solid #334155; border-radius: 6px;\r\n    position: relative; overflow: hidden; display: flex; align-items: flex-end; justify-content: center; box-shadow: inset 0 0 15px rgba(0,0,0,1); padding: 0 4px 4px 4px;\r\n    transition: background 0.5s;\r\n}\r\n#sonic-lab-v25 #iso-status { position: absolute; top: 6px; left: 10px; font-size: 9px; color: #64748b; font-weight: bold; letter-spacing: 1px; z-index: 2; opacity: 0.8; }\r\n\r\n\/* ADVANCED SUBWOOFER MATRIX *\/\r\n#sonic-lab-v25 .sub-unit {\r\n    background: linear-gradient(135deg, #1e293b, #0f172a); border: 1px solid #334155; border-radius: 8px; padding: 5px;\r\n    display: flex; flex-direction: column; gap: 12px; box-shadow: inset 0 0 20px rgba(0,0,0,0.5);\r\n}\r\n#sonic-lab-v25 .sub-screen {\r\n    background: #020617; border: 2px solid #334155; border-radius: 6px; position: relative; overflow: hidden; display: flex; align-items: center; justify-content: center; box-shadow: inset 0 0 15px rgba(0,0,0,1);\r\n    transition: background 0.5s;\r\n}\r\n#sonic-lab-v25 canvas#sub-scope-canvas { position: absolute; top:0; left:0; width:100%; height:100%; opacity: 0.8; }\r\n#sonic-lab-v25 #sub-status { position: absolute; top: 6px; left: 10px; font-size: 9px; color: #64748b; font-weight: bold; letter-spacing: 1px; z-index: 2; opacity: 0.8; }\r\n#sonic-lab-v25 #sub-invert-status { position: absolute; top: 6px; right: 10px; font-size: 9px; color: #eab308; font-weight: bold; letter-spacing: 1px; z-index: 2; display: none; text-shadow: 0 0 5px rgba(234, 179, 8, 0.5); }\r\n\r\n#sonic-lab-v25 #sub-hz-val, #sonic-lab-v25 #iso-hz-val {\r\n    font-size: 14px!important; color: var(--screen-ink); font-weight: 900;\r\n    text-shadow: 0 0 4px rgba(15, 23, 42, 0.7), 0 0 1px rgba(15, 23, 42, 0.9); filter: blur(0.4px); z-index: 2; opacity: 0.85; transition: opacity 0.5s;\r\n}\r\n#sonic-lab-v25 button.sub-phase.active { color: #fbbf24 !important; border-color: #fbbf24 !important; text-shadow: 0 0 10px #fbbf24; }\r\n\r\n#sonic-lab-v25 button.sub-toggle.sub-ready { \r\n    color: var(--neon-blue) !important;\r\n    border-color: #475569 !important;\r\n    text-shadow: 0 0 5px rgba(56, 189, 248, 0.4) !important;\r\n    transition: color 0.5s, text-shadow 0.5s;\r\n}\r\n#sonic-lab-v25 button.sub-toggle.sub-active { color: #ef4444 !important; border-color: #ef4444 !important; text-shadow: 0 0 10px #ef4444; }\r\n\r\n\/* SLIDERS *\/\r\n#sonic-lab-v25 .slider-track-container { position: relative; margin: 10px 0 30px 0; }\r\n#sonic-lab-v25 input[type=range].magnet-slider { width: 100%; -webkit-appearance: none; background: transparent; cursor: pointer; margin: 0; position: relative; z-index: 5; }\r\n#sonic-lab-v25 input[type=range].magnet-slider:focus { outline: none; }\r\n#sonic-lab-v25 input[type=range].magnet-slider::-webkit-slider-runnable-track {\r\n    height: 10px; background: #0f172a; border-radius: 5px; border: 2px solid #334155; box-shadow: inset 0 2px 5px rgba(0,0,0,0.9);\r\n}\r\n#sonic-lab-v25 input[type=range].magnet-slider::-webkit-slider-thumb {\r\n    -webkit-appearance: none; height: 26px; width: 14px; background: linear-gradient(180deg, #e2e8f0 0%, #94a3b8 50%, #64748b 100%); \r\n    border-radius: 3px; margin-top: -10px; border: 1px solid #fff; box-shadow: 0 2px 5px rgba(0,0,0,0.7);\r\n}\r\n\r\n#sonic-lab-v25 .scale-container { position: relative; height: 20px; margin-top: 15px; font-family: monospace; font-size: 9px; color: #64748b; padding: 0 15px; width: 95% !important; margin-left: 9px !important; }\r\n#sonic-lab-v25 .scale-ruler { display: none; width: 100%; justify-content: space-between; position: absolute; top: 0; left: 0; }\r\n#sonic-lab-v25 .scale-ruler.active { display: block; }\r\n#sonic-lab-v25 .tick { position: absolute; text-align: center; transform: translateX(-50%); }\r\n#sonic-lab-v25 .tick::before { content:'|'; display: block; font-size: 10px; margin-bottom: 5px; color: #475569; font-weight:bold; }\r\n#sonic-lab-v25 .vol-scale-wrapper { position: relative; width: 100%; height: 30px; margin-top: 10px; font-family: monospace; font-size: 9px; color: #64748b; }\r\n#sonic-lab-v25 .vol-tick { position: absolute; transform: translateX(-50%); }\r\n#sonic-lab-v25 .pan-display-row { display: flex; justify-content: space-between; font-size: 11px; color: #38bdf8; font-weight: bold; margin-bottom: 8px; font-family: monospace; transition: color 0.5s; }\r\n#sonic-lab-v25 .big-actions { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; margin-bottom: 0px; padding: 0px 8px; }\r\n\r\n#sonic-lab-v25 #freq-mini-disp {\r\n    filter: blur(0.5px);\r\n    text-shadow: 0 0 2px rgba(15, 23, 42, 0.6);\r\n    cursor: pointer;\r\n    display: flex; align-items: center; justify-content: center; height: 100%; width: 100%;\r\n    transition: opacity 0.5s;\r\n}\r\n\r\n\/* SMOKED GLASS STYLE FOR SLIDERS *\/\r\n#sonic-lab-v25 .smoked-glass {\r\n    background: var(--glass-bg);\r\n    border: 1px solid #334155;\r\n    border-radius: 6px;\r\n    padding: 15px 15px 10px 15px; \r\n    box-shadow: inset 0 2px 10px rgba(0,0,0,0.8);\r\n    margin-top: 5px;\r\n    display: flex; flex-direction: column; justify-content: center;\r\n    min-height: 87px; \r\n}\r\n#sonic-lab-v25 .text-glow-white {\r\n    color: #ffffff !important;\r\n    text-shadow: 0 0 5px rgba(255, 255, 255, 0.6), 0 0 10px rgba(255, 255, 255, 0.3);\r\n    font-weight: 700 !important;\r\n    opacity: 0.95;\r\n}\r\n#sonic-lab-v25 .smoked-glass .tick { color: #fff; text-shadow: 0 0 6px rgba(255,255,255,0.7); }\r\n#sonic-lab-v25 .smoked-glass .tick::before { color: #64748b; }\r\n\r\n#sonic-lab-v25 .pan-wrapper {\r\n    display: flex; align-items: center; gap: 8px; width: 100%; justify-content: space-between;\r\n}\r\n#sonic-lab-v25 .pan-slider-container {\r\n    position: relative; flex: 1; margin: 0 10px; display: flex; align-items: center; justify-content: center;\r\n}\r\n#sonic-lab-v25 .pan-center-marker {\r\n    position: absolute; left: 50%; height: 12px; width: 2px; background: #64748b; \r\n    transform: translateX(-50%); pointer-events: none; z-index: 1; top: 50%; margin-top: -6px;\r\n    box-shadow: 0 0 2px #000;\r\n}\r\n\r\n#sonic-lab-v25 button.pwr-btn {\r\n    padding: 0 !important; height: 40px !important; font-size: 14px !important; letter-spacing: 2px !important; border-radius: 6px; font-weight: 900 !important;\r\n    background: linear-gradient(180deg, #aebcd1 0%, #1e293b 100%) !important; border: 2px solid #0f172a !important; border-top: 2px solid #94a3b8 !important;\r\n    box-shadow: 0 8px 15px rgba(0,0,0,0.5), inset 0 1px 0 rgba(255,255,255,0.2) !important; transition: background 0.1s, color 0.1s, box-shadow 0.1s; text-align: center; margin-top: 5px;\r\n}\r\n#sonic-lab-v25 button.pwr-btn:active { transform: none !important; }\r\n\r\n@keyframes pulseBlueGray { \r\n    0% { box-shadow: 0 0 5px var(--neon-blue); border-color: var(--neon-blue); color: var(--neon-blue); text-shadow: 0 0 5px var(--neon-blue); } \r\n    50% { box-shadow: none; border-color: #ffffff; color: #ffffff; text-shadow: none; } \r\n    100% { box-shadow: 0 0 5px var(--neon-blue); border-color: var(--neon-blue); color: var(--neon-blue); text-shadow: 0 0 5px var(--neon-blue); } \r\n}\r\n\r\n#sonic-lab-v25 button.btn-ready { \r\n    animation: pulseBlueGray 2s infinite ease-in-out;\r\n}\r\n\r\n#sonic-lab-v25 button.btn-on { \r\n    color: #38bdf8 !important; \r\n    text-shadow: 0 0 8px rgba(56, 189, 248, 0.6) !important; \r\n    border-color: #334155; \r\n    animation: none !important; \r\n}\r\n\r\n#sonic-lab-v25 button.btn-mute { \r\n    background: #0f172a !important; color: #ef4444 !important; border: 2px solid #ef4444 !important;\r\n    box-shadow: inset 0 0 10px rgba(239, 68, 68, 0.2), 0 0 8px rgba(239, 68, 68, 0.4) !important;\r\n    text-shadow: 0 0 5px #ef4444 !important;\r\n    animation: none !important;\r\n}\r\n#sonic-lab-v25 button.btn-off { color: #38bdf8 !important; text-shadow: 0 0px 8px #38bdf899 !important; }\r\n#sonic-lab-v25 button.btn-off:active, #sonic-lab-v25 button.btn-off.active { \r\n    background: linear-gradient(180deg, #991b1b 0%, #7f1d1d 100%) !important; color: white !important; border-color: #ef4444 !important; \r\n    box-shadow: inset 0 0 20px rgba(0,0,0,0.8) !important; transform: none !important; \r\n}\r\n\r\n#sonic-lab-v25 .piano-wrapper {\r\n    position: relative; height: 180px; background: #0d1117; border-radius: 8px; overflow: hidden; margin-bottom: 20px; \r\n    border: 4px solid #1e293b; border-top: 15px solid #1e293b; display: flex; justify-content: center; box-shadow: 0 20px 40px rgba(0,0,0,0.7), inset 0 0 20px rgba(0,0,0,0.8);\r\n}\r\n#sonic-lab-v25 .piano-wrapper::before { content: ''; position: absolute; top:0; left:0; width:100%; height:4px; background: #38bdf8; z-index: 20; box-shadow: 0 1px 15px rgb(56 189 248); }\r\n\r\n#sonic-lab-v25 .key {\r\n    position: relative; float: left; width: 14.28%; height: 100%; \r\n    background: linear-gradient(to bottom, #f1f5f9 0%, #cbd5e1 85%, #94a3b8 100%);\r\n    border: 1px solid #1e293b; border-top: none; border-radius: 0 0 4px 4px; z-index: 1; cursor: pointer; transition: transform 0.05s, background 0.1s; \r\n    display: flex; align-items: flex-end; justify-content: center; padding-bottom: 10px; font-family: 'Segoe UI', sans-serif; font-size: 10px; font-weight: bold; color: #475569;\r\n    box-shadow: inset 2px 0 3px rgba(255,255,255,0.7), inset -2px 0 3px rgba(0,0,0,0.2), 0 4px 6px rgba(0,0,0,0.6);\r\n    border-bottom: 5px solid #475569; \r\n}\r\n#sonic-lab-v25 .key:active, #sonic-lab-v25 .key.active { \r\n    background: linear-gradient(180deg, #94a3b8 0%, #cbd5e1 100%); \r\n    box-shadow: inset 0 0 15px rgba(0,0,0,0.3); transform: translateY(2px); border-bottom: 2px solid #475569; color: #1e293b;\r\n}\r\n\r\n#sonic-lab-v25 .key.black {\r\n    position: absolute; top: 0; height: 65%; width: 10%; \r\n    background: linear-gradient(180deg, #1e293b 0%, #020617 90%, #000 100%);\r\n    z-index: 10; border-radius: 0 0 3px 3px; border: 1px solid #334155; border-top: none; color: #64748b; padding-bottom: 8px; font-size: 8px;\r\n    box-shadow: 2px 2px 5px rgba(0,0,0,0.8), inset 1px 1px 2px rgba(255,255,255,0.2);\r\n}\r\n#sonic-lab-v25 .key.black:active, #sonic-lab-v25 .key.black.active { \r\n    background: linear-gradient(180deg, #334155 0%, #1e293b 100%); color: #fff; transform: translateY(1px); box-shadow: 1px 1px 3px rgba(0,0,0,0.8), inset 0 0 5px rgba(0,0,0,0.5);\r\n}\r\n#sonic-lab-v25 button.oct-btn { width: 35px !important; font-size: 11px !important; }\r\n\/* --- NOVI STILOVI ZA KUTNE NATPISE --- *\/\r\n.slider-corner-lbl {\r\n    position: absolute;\r\n    bottom: 5px; \/* Odmak od dna *\/\r\n    font-size: 9px;\r\n    font-weight: 900;\r\n    font-family: 'Rajdhani', sans-serif !important;\r\n    letter-spacing: 1px;\r\n    pointer-events: none; \/* Da ne smeta klikanju *\/\r\n    z-index: 5;\r\n}\r\n\r\n\/* Lijevo dolje: LOG *\/\r\n.slider-corner-lbl.left {\r\n    left: 10px;\r\n    color: #ef4444; \/* Crvena *\/\r\n    display: none; \/* Skriveno po defaultu, JS pali *\/\r\n    text-shadow: 0 0 5px rgba(239, 68, 68, 0.3);\r\n}\r\n\r\n\/* Desno dolje: SELECT FREQUENCY *\/\r\n.slider-corner-lbl.right {\r\n    right: 10px;\r\n    color: #ef4444; \/* Crvena *\/\r\n    display: none; \/* Skriveno ako nije 0 Hz *\/\r\n    animation: textPulse 1.5s infinite; \/* Pulsiranje za upozorenje *\/\r\n}\r\n\r\n@keyframes textPulse {\r\n    0% { opacity: 1; text-shadow: 0 0 5px rgba(239, 68, 68, 0.5); }\r\n    50% { opacity: 0.4; text-shadow: none; }\r\n    100% { opacity: 1; text-shadow: 0 0 5px rgba(239, 68, 68, 0.5); }\r\n}\r\n\/* Plava pulsiraju\u0107a to\u010dka *\/\r\n.freq-dot {\r\n    position: absolute;\r\n    bottom: 8px; \/* Pozicionirano isto kao i tekst upozorenja *\/\r\n    right: 10px;\r\n    width: 8px;\r\n    height: 8px;\r\n    background-color: #38bdf8; \/* Neon Blue *\/\r\n    border-radius: 50%;\r\n    box-shadow: 0 0 8px #38bdf8;\r\n    display: none; \/* Skriveno na 0Hz *\/\r\n    pointer-events: none;\r\n    z-index: 6;\r\n}\r\n\r\n\/* Definiramo klju\u010dne to\u010dke animacije, ali trajanje (duration) \u0107emo mijenjati kroz JS *\/\r\n@keyframes dotPulse {\r\n    0% { opacity: 0.2; transform: scale(0.8); }\r\n    50% { opacity: 1; transform: scale(1.2); box-shadow: 0 0 12px #38bdf8; }\r\n    100% { opacity: 0.2; transform: scale(0.8); }\r\n}\r\n\/* Plava pulsiraju\u0107a to\u010dka *\/\r\n.freq-dot {\r\n    position: absolute;\r\n    bottom: 8px; \/* Pozicionirano isto kao i tekst upozorenja *\/\r\n    right: 10px;\r\n    width: 8px;\r\n    height: 8px;\r\n    background-color: #38bdf8; \/* Neon Blue *\/\r\n    border-radius: 50%;\r\n    box-shadow: 0 0 8px #38bdf8;\r\n    display: none; \/* Skriveno na 0Hz *\/\r\n    pointer-events: none;\r\n    z-index: 6;\r\n}\r\n\r\n\/* Definiramo klju\u010dne to\u010dke animacije, ali trajanje (duration) \u0107emo mijenjati kroz JS *\/\r\n@keyframes dotPulse {\r\n    0% { opacity: 0.2; transform: scale(0.8); }\r\n    50% { opacity: 1; transform: scale(1.2); box-shadow: 0 0 12px #38bdf8; }\r\n    100% { opacity: 0.2; transform: scale(0.8); }\r\n}\r\n\/* --- NOVI STILOVI ZA LIN\/LOG --- *\/\r\n.mode-indicator-wrap {\r\n    position: absolute;\r\n    bottom: 5px;\r\n    left: 10px;\r\n    display: flex;\r\n    gap: 8px; \/* Razmak izme\u0111u LIN i LOG *\/\r\n    z-index: 5;\r\n    pointer-events: none;\r\n}\r\n\r\n.mode-lbl {\r\n    font-size: 9px;\r\n    font-weight: 900;\r\n    font-family: 'Rajdhani', sans-serif !important;\r\n    letter-spacing: 1px;\r\n    color: #1e293b; \/* Tamna boja kad nije aktivno *\/\r\n    transition: color 0.3s, text-shadow 0.3s, opacity 0.5s;\r\n}\r\n\r\n.mode-lbl.active {\r\n    color: #38bdf8; \/* Plava aktivna *\/\r\n    text-shadow: 0 0 5px rgba(56, 189, 248, 0.6);\r\n}\r\n\r\n\/* --- STARI STILOVI ZA DESNI KUT (Ostavljamo Warning crvenim) --- *\/\r\n.slider-corner-lbl {\r\n    position: absolute; bottom: 5px;\r\n    font-size: 9px; font-weight: 900; font-family: 'Rajdhani', sans-serif !important; letter-spacing: 1px; pointer-events: none; z-index: 5;\r\n    transition: opacity 0.5s;\r\n}\r\n.slider-corner-lbl.right {\r\n    right: 10px; color: #ef4444; display: none; animation: textPulse 1.5s infinite;\r\n}\r\n\r\n\/* --- TO\u010cKA --- *\/\r\n.freq-dot {\r\n    position: absolute; bottom: 8px; right: 10px;\r\n    width: 8px; height: 8px; background-color: #38bdf8; border-radius: 50%;\r\n    box-shadow: 0 0 8px #38bdf8; display: none; pointer-events: none; z-index: 6;\r\n    transition: opacity 0.5s;\r\n}\r\n\r\n@keyframes textPulse { 0% { opacity: 1; text-shadow: 0 0 5px rgba(239, 68, 68, 0.5); } 50% { opacity: 0.4; text-shadow: none; } 100% { opacity: 1; text-shadow: 0 0 5px rgba(239, 68, 68, 0.5); } }\r\n\r\n\/* --- GLOBALNO SKRIVANJE KAD JE SYSTEM OFF --- *\/\r\n\/* Ovo rje\u0161ava zahtjev da sve nestane kad se ugasi sistem *\/\r\n#sonic-lab-v25.sys-off .mode-lbl,\r\n#sonic-lab-v25.sys-off .slider-corner-lbl,\r\n#sonic-lab-v25.sys-off .freq-dot {\r\n    opacity: 0 !important;\r\n    animation: none !important;\r\n}\r\n\/* Sakrij odre\u0111ene brojeve na malim ekranima radi \u010ditljivosti *\/\r\n@media (max-width: 600px) {\r\n    .hide-mobile {\r\n        display: none;\r\n    }\r\n}\r\n\r\n\/* Osiguraj da tickovi budu to\u010dno centrirani ispod slider to\u010dke *\/\r\n.tick {\r\n    position: absolute;\r\n    transform: translateX(-50%); \/* Klju\u010dno za preciznost *\/\r\n    text-align: center;\r\n    white-space: nowrap;\r\n}\r\n\/* OKVIR ZA BROJEVE *\/\r\n.knob-scale-nums {\r\n    position: absolute;\r\n    top: 0; left: 0;\r\n    width: 100%; height: 100%;\r\n    pointer-events: none;\r\n    z-index: 0;\r\n}\r\n\r\n\/* OKVIR ZA BROJEVE *\/\r\n.knob-scale-nums {\r\n    position: absolute;\r\n    top: 0; left: 0;\r\n    width: 100%; height: 100%;\r\n    pointer-events: none;\r\n    z-index: 0;\r\n}\r\n\r\n\/* SAMI BROJEVI - MATEMATI\u010cKI CENTRIRANI *\/\r\n.knob-scale-nums span {\r\n    position: absolute;\r\n    \/* Klju\u010dno: \u0160irina i visina 0 osiguravaju da je 'left\/top' to\u010dno u centru elementa *\/\r\n    width: 0; \r\n    height: 0;\r\n    \r\n    \/* Postavi u centar roditelja *\/\r\n    left: 50%; \r\n    top: 50%;\r\n    \r\n    \/* Flex za centriranje samog teksta oko nulte to\u010dke *\/\r\n    display: flex;\r\n    align-items: center;\r\n    justify-content: center;\r\n    \r\n    font-size: 9px;\r\n    font-weight: bold;\r\n    color: #64748b;\r\n    font-family: 'Rajdhani', sans-serif;\r\n    white-space: nowrap; \/* Sprje\u010dava prelazak u novi red *\/\r\n} \r\n\/* DRIVE MONITOR (Sada Dolje Desno) *\/\r\n#sonic-lab-v25 #drive-monitor {\r\n    position: absolute;\r\n    bottom: 5px;       \r\n    right: 8px;        \/* Promijenjeno iz left u right *\/\r\n    left: auto;        \/* Poni\u0161tava left positioning *\/\r\n    text-align: right; \/* Poravnanje teksta desno *\/\r\n    \r\n    color: #ef4444;    \r\n    font-family: 'Orbitron', monospace;\r\n    font-weight: 900;\r\n    font-size: 9px;    \r\n    letter-spacing: 1px;\r\n    text-shadow: 0 0 5px rgba(239, 68, 68, 0.6);\r\n    display: none;     \r\n    z-index: 20;\r\n    pointer-events: none;\r\n    animation: drivePulse 0.5s infinite alternate;\r\n}\r\n\r\n@keyframes drivePulse {\r\n    0% { opacity: 0.7; text-shadow: 0 0 2px rgba(239, 68, 68, 0.4); }\r\n    100% { opacity: 1; text-shadow: 0 0 8px rgba(239, 68, 68, 0.9); }\r\n}\r\n    <\/style>\r\n<\/head>\r\n<body>\r\n\r\n<div id=\"sonic-lab-v25\" class=\"sys-off\">\r\n    <div class=\"screw tl\"><\/div><div class=\"screw tr\"><\/div><div class=\"screw bl\"><\/div><div class=\"screw br\"><\/div>\r\n    \r\n    <button class=\"help-btn\" onclick=\"openHelp()\">?<\/button>\r\n\r\n    <div class=\"close-popup-area\" id=\"popup-closer\" onclick=\"closePopup()\"><\/div>\r\n    \r\n    <div id=\"mobile-knob-editor\">\r\n        <div id=\"mobile-knob-title\">PARAMETER<\/div>\r\n        <div id=\"mobile-knob-val\">50%<\/div>\r\n        <input type=\"range\" class=\"magnet-slider\" id=\"mobile-slider\" style=\"width:100%; height:40px;\">\r\n        <button class=\"tech-btn\" onclick=\"closePopup()\" style=\"height:30px !important; margin-top:10px;\">DONE<\/button>\r\n    <\/div>\r\n\r\n    <div id=\"safety-modal\">\r\n        <div class=\"modal-box danger\">\r\n            <div class=\"modal-header-bar danger\">\u26a0\ufe0f HIGH GAIN WARNING<\/div>\r\n            <div class=\"modal-content-body\" style=\"padding: 20px;\">\r\n                <p class=\"modal-text\" style=\"text-align:center !important; margin-bottom: 20px;\">\r\n                    Pushing volume above <b>-6dB (50%)<\/b> can damage equipment.<br>Are you sure?\r\n                <\/p>\r\n                <div class=\"modal-actions\">\r\n                    <button class=\"modal-btn\" onclick=\"cancelSafe()\">CANCEL<\/button>\r\n                    <button class=\"modal-btn btn-confirm\" onclick=\"confirmSafe()\">PROCEED<\/button>\r\n                <\/div>\r\n            <\/div>\r\n        <\/div>\r\n    <\/div>\r\n\r\n    <div id=\"help-modal\">\r\n        <div class=\"modal-box\">\r\n            <div class=\"modal-header-bar\">\r\n                <span>SONIC LAB MANUAL <span style=\"color:#94a3b8; font-weight:300; margin-left:10px;\">V1.10<\/span><\/span>\r\n                <span onclick=\"closeHelp()\" style=\"cursor:pointer; color:#ef4444; font-size:24px;\">\u2715<\/span>\r\n            <\/div>\r\n            \r\n            <div class=\"help-layout-grid\">\r\n                <div class=\"help-menu\">\r\n                    <div class=\"menu-item active\" onclick=\"scrollToSection('sec-intro', this)\">01. Intro<\/div>\r\n                    <div class=\"menu-item\" onclick=\"scrollToSection('sec-master', this)\">02. Master I\/O<\/div>\r\n                    <div class=\"menu-item\" onclick=\"scrollToSection('sec-wave', this)\">03. Oscillators<\/div>\r\n                    <div class=\"menu-item\" onclick=\"scrollToSection('sec-noise', this)\">04. Noise Gen<\/div>\r\n                    <div class=\"menu-item\" onclick=\"scrollToSection('sec-sweep', this)\">05. Freq Sweep<\/div>\r\n                    <div class=\"menu-item\" onclick=\"scrollToSection('sec-piano', this)\">06. Musical<\/div>\r\n                    <div class=\"menu-item\" onclick=\"scrollToSection('sec-rta', this)\">07. ISO & RTA<\/div>\r\n                    <div class=\"menu-item\" onclick=\"scrollToSection('sec-sub', this)\">08. LFE Matrix<\/div>\r\n                <\/div>\r\n\r\n                <div class=\"help-content\" id=\"help-content-area\" style=\"overflow-y: auto; height: 530px; padding: 25px; scroll-behavior: smooth; position: relative;\">\r\n                    \r\n                    <div id=\"sec-intro\" class=\"modal-section\">\r\n                        <span class=\"modal-h3\">01. ENGINE ARCHITECTURE (32-BIT FLOAT)<\/span>\r\n                        <p class=\"modal-text\">\r\n                            <strong>Sonic Lab v1.10<\/strong> is powered by a <strong>32-bit floating-point<\/strong> audio engine. This provides a theoretical dynamic range of over <strong>1,500 dB<\/strong>, ensuring that signal generation is mathematically perfect even at extreme attenuation.\r\n                        <\/p>\r\n                        <ul class=\"help-list\">\r\n                            <li><strong>Anti-Aliasing:<\/strong> Advanced algorithms suppress digital artifacts during high-frequency generation.<\/li>\r\n                            <li><strong>Sample Accuracy:<\/strong> Real-time interpolation at 44.1kHz prevents \"zipper noise\" when changing parameters.<\/li>\r\n                        <\/ul>\r\n                    <\/div>\r\n\r\n                    <div id=\"sec-master\" class=\"modal-section\">\r\n                        <span class=\"modal-h3\">02. MASTER I\/O & CALIBRATION<\/span>\r\n                        <p class=\"modal-text\">The Master stage acts as the final safety and routing barrier for the signal chain.<\/p>\r\n                        <ul class=\"help-list\">\r\n                            <li><strong>Safety Lock:<\/strong> The system triggers a warning at <strong>-6dB (50%)<\/strong> to prevent DAC saturation and hearing fatigue.<\/li>\r\n                            <li><strong>Panning:<\/strong> Adjusts the stereo image. Use 100% L or R to test for <strong>Cross-talk<\/strong> and isolation between channels.<\/li>\r\n                            <li><strong>System Off:<\/strong> Terminates the WebAudio context to simulate a hardware power-down (CRT discharge).<\/li>\r\n                        <\/ul>\r\n                    <\/div>\r\n\r\n                    <div id=\"sec-wave\" class=\"modal-section\">\r\n                        <span class=\"modal-h3\">03. WAVEFORM HARMONIC PROFILES<\/span>\r\n                        <p class=\"modal-text\">Waveforms are defined by their harmonic content:<\/p>\r\n                        <ul class=\"help-list\">\r\n                            <li><strong>Sine:<\/strong> Pure fundamental tone. Used for detecting physical resonances in structures.<\/li>\r\n                            <li><strong>Square:<\/strong> Odd harmonics only. Excellent for testing the <strong>Transient Response<\/strong> of amplifiers.<\/li>\r\n                            <li><strong>Sawtooth:<\/strong> Contains all harmonics. The most aggressive signal for broad-band stress tests.<\/li>\r\n                            <li><strong>Triangle:<\/strong> Ideal for checking the crossover transition between mid-drivers and tweeters.<\/li>\r\n                        <\/ul>\r\n                    <\/div>\r\n\r\n                    <div id=\"sec-noise\" class=\"modal-section\">\r\n                        <span class=\"modal-h3\">04. NOISE SPECTRUM ANALYSIS<\/span>\r\n                        <ul class=\"help-list\">\r\n                            <li><strong>White Noise:<\/strong> Equal energy per frequency. Standard for electronic hardware testing.<\/li>\r\n                            <li><strong>Pink Noise:<\/strong> Equal energy per <strong>octave<\/strong>. Calibrated to human hearing; industry standard for <strong>Room EQ Calibration<\/strong>.<\/li>\r\n                            <li><strong>Red\/Brown Noise:<\/strong> Low-frequency heavy. Used to test subwoofer excursion limits.<\/li>\r\n                        <\/ul>\r\n                    <\/div>\r\n\r\n                    <div id=\"sec-sweep\" class=\"modal-section\">\r\n                        <span class=\"modal-h3\">05. FREQUENCY SWEEPS (LIN vs LOG)<\/span>\r\n                        <p class=\"modal-text\">Sweeps identify \"nulls\" and \"peaks\" in room acoustics.<\/p>\r\n                        <ul class=\"help-list\">\r\n                            <li><strong>Linear (LIN):<\/strong> Moves through Hz at a fixed speed. Used for technical component data.<\/li>\r\n                            <li><strong>Logarithmic (LOG):<\/strong> Spends equal time in each musical octave. Preferred method for acoustic room mapping.<\/li>\r\n                        <\/ul>\r\n                    <\/div>\r\n\r\n                    <div id=\"sec-piano\" class=\"modal-section\">\r\n                        <span class=\"modal-h3\">06. MUSICAL SYNTHESIS & ADSR<\/span>\r\n                        <p class=\"modal-text\">This module tests the \"musicality\" and transient response of the audio chain.<\/p>\r\n                        <ul class=\"help-list\">\r\n                            <li><strong>Concert Pitch:<\/strong> Fully adjustable tuning (432Hz to 450Hz).<\/li>\r\n                            <li><strong>ADSR:<\/strong> Controls the Attack (sharpness) and Release (tail). Use long release to test room <strong>Reverb Time (RT60)<\/strong>.<\/li>\r\n                        <\/ul>\r\n                    <\/div>\r\n\r\n                    <div id=\"sec-rta\" class=\"modal-section\">\r\n                        <span class=\"modal-h3\">07. ISO STANDARDS & RTA ANALYZER<\/span>\r\n                        <p class=\"modal-text\"><strong>RTA (Real-Time Analyzer):<\/strong> A 72-band FFT visualizer monitors energy distribution.<\/p>\r\n                        <ul class=\"help-list\">\r\n                            <li><strong>ISO Frequencies:<\/strong> Pre-set industry points (31.5Hz, 125Hz, 1kHz) used for standardized documentation.<\/li>\r\n                        <\/ul>\r\n                    <\/div>\r\n\r\n                    <div id=\"sec-sub\" class=\"modal-section\">\r\n                        <span class=\"modal-h3\">08. LFE MATRIX & SUB-BASS CALIBRATION<\/span>\r\n                        <p class=\"modal-text\">Specialized unit for the 0Hz - 120Hz band (Subwoofer testing).<\/p>\r\n                        <ul class=\"help-list\">\r\n                            <li><strong>Phase Inversion (\u00d8):<\/strong> Fixes <strong>Phase Cancellation<\/strong>. If bass disappears when sub is ON, toggle this.<\/li>\r\n                            <li><strong>32-bit Drive:<\/strong> Adds controlled harmonic saturation to test woofer physical limits.<\/li>\r\n                            <li><strong>LFE Sweep:<\/strong> Dedicated low-end sweep to find mechanical rattles in cabinets.<\/li>\r\n                        <\/ul>\r\n                    <\/div>\r\n            <\/div>\r\n            <\/div>\r\n\t\t\t\r\n        <\/div>\r\n    <\/div>\r\n\r\n    <div id=\"hidden-inputs\" style=\"display:none;\">\r\n        <input type=\"number\" id=\"manual-input\" value=\"0\">\r\n    <\/div>\r\n\r\n    <div class=\"lab-header\">\r\n        <div class=\"lab-title\">\r\n            <span>Liquid Audio Engine<\/span>\r\n            <h2>SONIC LAB 32-bit<span style=\"color:#94a3b8; font-weight:300;\">v1.10<\/span><\/h2>\r\n        <\/div>\r\n        <div class=\"status-panel\">\r\n            <div class=\"led-ind\" id=\"led-indicator\"><\/div> <span id=\"status-text\">SYSTEM READY<\/span>\r\n        <\/div>\r\n    <\/div>\r\n\r\n    <div class=\"digital-screen-container\" id=\"screen-container\">\r\n        <div class=\"screen-inner crt-off\" id=\"screen-inner\">\r\n            <canvas id=\"scope\"><\/canvas>\r\n            <div id=\"warning-overlay\">SELECT NOISE, SWEEP, FREQUENCY OR ENTER MANUALLY VALUE<\/div>\r\n            <div id=\"hz-overlay\">\r\n                <input type=\"text\" inputmode=\"decimal\" id=\"screen-input\" value=\"0 Hz\" \r\n                       onfocus=\"onHzFocus(this)\" \r\n                       onblur=\"onHzBlur(this)\" \r\n                       onchange=\"manualEntry(this.value)\">\r\n            <\/div>\r\n        <\/div>\r\n    <\/div>\r\n\r\n    <div class=\"meter-bridge\">\r\n        <div class=\"meter-row\">\r\n            <div class=\"meter-channel\">\r\n                <div class=\"meter-label\">L<\/div>\r\n                <div class=\"led-strip\" id=\"meter-l-strip\"><\/div>\r\n            <\/div>\r\n            <div class=\"meter-channel\">\r\n                <div class=\"meter-label\">R<\/div>\r\n                <div class=\"led-strip\" id=\"meter-r-strip\"><\/div>\r\n            <\/div>\r\n        <\/div>\r\n        <div class=\"meter-scale-row\">\r\n            <div class=\"meter-scale-half\"><span>-\u221e<\/span><span>-12<\/span><span>-6<\/span><span>-3<\/span><span>0<\/span><\/div>\r\n            <div class=\"meter-scale-half\"><span>-\u221e<\/span><span>-12<\/span><span>-6<\/span><span>-3<\/span><span>0<\/span><\/div>\r\n        <\/div>\r\n    <\/div>\r\n\r\n    <div class=\"controls-grid\">\r\n        <div class=\"panel-card\">\r\n            <div class=\"big-actions\">\r\n                <button id=\"btn-main\" class=\"pwr-btn btn-ready\" onclick=\"handleMainButton()\">ACTIVATE<\/button>\r\n                <button id=\"btn-stop\" class=\"pwr-btn btn-off\" onclick=\"handleSystemOff()\">SYSTEM OFF<\/button>\r\n            <\/div>\r\n\r\n            <span class=\"panel-head\" style=\"margin-top:20px;\">STEREO & VOLUME<\/span>\r\n            \r\n            <div style=\"display: flex; flex-direction: column; gap: 15px;\">\r\n                <div class=\"smoked-glass\">\r\n    <div class=\"pan-display-row\" style=\"color:#38bdf8; font-weight:bold; margin-bottom: 2px;\"><span>MASTER GAIN dB<\/span><\/div>\r\n    <input type=\"range\" class=\"magnet-slider\" id=\"vol-slider\" min=\"0\" max=\"1\" step=\"0.001\" value=\"0.25\" oninput=\"updVol(this.value)\">\r\n    <div class=\"vol-scale-wrapper\" style=\"margin-top: 15px;\">\r\n         <span class=\"tick text-glow-white\" style=\"left:0%\">-\u221e<\/span>\r\n         <span class=\"tick text-glow-white\" style=\"left:25.1%\">-12<\/span>\r\n         <span class=\"tick text-glow-white\" style=\"left:50.1%\">-6<\/span>\r\n         <span class=\"tick text-glow-white\" style=\"left:75.1%\">-3<\/span>\r\n         <span class=\"tick text-glow-white\" style=\"left:98%\">0<\/span>\r\n    <\/div>\r\n<\/div>\r\n\r\n                <div class=\"smoked-glass\" style=\"min-height: auto; padding-bottom: 15px;\">\r\n                    <div class=\"pan-display-row\"><span>PANNING<\/span><\/div>\r\n                    <div class=\"pan-wrapper\">\r\n                        <button class=\"pan-side-btn\" id=\"btn-pan-l\" onclick=\"panJump('L')\">\r\n                            <span class=\"pan-side-label\">L<\/span>\r\n                            <span class=\"pan-side-val\" id=\"pan-l-val\">50%<\/span>\r\n                        <\/button>\r\n                        <div class=\"pan-slider-container\">\r\n                             <div class=\"pan-center-marker\"><\/div>\r\n                             <input type=\"range\" class=\"magnet-slider\" id=\"pan-slider\" min=\"-1\" max=\"1\" step=\"0.1\" value=\"0\" oninput=\"updPan(this.value)\" style=\"width: 100%;\">\r\n                        <\/div>\r\n                        <button class=\"pan-side-btn\" id=\"btn-pan-r\" onclick=\"panJump('R')\">\r\n                            <span class=\"pan-side-label\">R<\/span>\r\n                            <span class=\"pan-side-val\" id=\"pan-r-val\">50%<\/span>\r\n                        <\/button>\r\n                    <\/div>\r\n                <\/div>\r\n            <\/div>\r\n        <\/div>\r\n\r\n        <div class=\"right-column-wrap\">\r\n            <div class=\"panel-card\">\r\n     <span class=\"panel-head\" style=\"margin-bottom:10px; display:block; border-bottom: 1px solid var(--neon-blue); padding-bottom:5px;\">FREQUENCY TUNING<\/span>\r\n     <span class=\"tech-sub\" style=\"margin-bottom:15px; margin-top:5px;\">\/\/ TAP FREQUENCY ON MAIN DISPLAY TO EDIT<\/span>\r\n\r\n     <div style=\"display: flex; gap: 10px; align-items: stretch; margin-bottom: 25px; height: 96px; flex-wrap: nowrap;\">\r\n        \r\n        <div class=\"smoked-glass\" style=\"flex: 2; min-width: 0; position: relative; margin:0; padding: 0 5%; display: flex; flex-direction: column; justify-content: center;\">\r\n    \r\n    <div class=\"mode-indicator-wrap\">\r\n        <span id=\"lbl-lin\" class=\"mode-lbl\">LIN<\/span>\r\n        <span id=\"lbl-log\" class=\"mode-lbl active\">LOG<\/span>\r\n    <\/div>\r\n\r\n    <div id=\"lbl-freq-warning\" class=\"slider-corner-lbl right\">SELECT FREQUENCY<\/div>\r\n\r\n    <div id=\"freq-dot\" class=\"freq-dot\"><\/div>\r\n\r\n    <input type=\"range\" id=\"mag-slider\" class=\"magnet-slider\" min=\"0\" max=\"10000\" step=\"1\" value=\"0\" oninput=\"magnetSlide(this.value)\" style=\"width: 100%; margin: 0; z-index: 10;\">\r\n    \r\n    <div class=\"scale-container\" style=\"position: relative; width: 100%; height: 20px; margin-top: 10px; padding: 0;\">\r\n    \r\n    <div id=\"ruler-lin\" class=\"scale-ruler\">\r\n        <span class=\"tick\" style=\"left: 0%\">0<\/span>\r\n        <span class=\"tick\" style=\"left: 5%\">1k<\/span>\r\n        <span class=\"tick\" style=\"left: 25%\">5k<\/span>\r\n        <span class=\"tick\" style=\"left: 50%\">10k<\/span>\r\n        <span class=\"tick\" style=\"left: 75%\">15k<\/span>\r\n        <span class=\"tick\" style=\"left: 100%\">20k<\/span>\r\n    <\/div>\r\n    \r\n    <div id=\"ruler-log\" class=\"scale-ruler active\">\r\n        <span class=\"tick\" style=\"left: 0%\">0<\/span>\r\n        \r\n        <span class=\"tick\" style=\"left: 39.5%\">50<\/span>\r\n        \r\n        <span class=\"tick\" style=\"left: 46.5%\">100<\/span>\r\n        \r\n        <span class=\"tick hide-mobile\" style=\"left: 62.7%\">500<\/span>\r\n        \r\n        <span class=\"tick\" style=\"left: 69.7%\">1k<\/span>\r\n        \r\n        <span class=\"tick\" style=\"left: 86.0%\">5k<\/span>\r\n        \r\n        <span class=\"tick hide-mobile\" style=\"left: 93.0%\">10k<\/span>\r\n        \r\n        <span class=\"tick\" style=\"left: 100%\">20k<\/span>\r\n    <\/div>\r\n<\/div>\r\n<\/div>\r\n        \r\n        <div style=\"flex: 1; min-width: 110px; display: flex; flex-direction: column; gap: 4px;\">\r\n            \r\n            <div class=\"mus-screen\" style=\"width: 100%; height: 44px; margin: 0; font-size: 16px; font-weight: 900; color: var(--screen-ink);\" onclick=\"focusMainInput()\">\r\n                <div id=\"freq-mini-disp\" style=\"font-family: 'Orbitron', monospace !important;\">1.000 kHz<\/div>\r\n            <\/div>\r\n\r\n            <div style=\"display: flex; gap: 4px; height: 48px;\">\r\n                <button id=\"btn-scale-toggle\" class=\"tech-btn\" \r\n        style=\"width: 48px !important; min-width: 48px; height: 100% !important; font-size: 10px; padding:0; border-radius:4px; color: #cbd5e1; border-color: #0f172a; display:flex; justify-content:center; align-items:center;\" \r\n        onclick=\"toggleScaleMode()\">LIN<\/button>\r\n                \r\n                <button id=\"btn-freq-toggle\" class=\"tech-btn sub-toggle sub-ready\" \r\n                        onclick=\"toggleTone(this)\" \r\n                        style=\"flex-grow: 1; height: 100% !important; font-size: 13px; font-weight: 900; letter-spacing: 1px; margin:0; padding:0;\">SIGNAL<\/button>\r\n            <\/div>\r\n        <\/div>\r\n     <\/div>\r\n     <span class=\"panel-head\">WAVEFORM ENGINE<\/span>\r\n\t <span class=\"tech-sub\" style=\"margin-bottom:15px; margin-top:5px;\">\/\/ SOURCE TONE APPLIES TO ALL MODULES<\/span>\r\n     <div class=\"wave-row\">\r\n        <button class=\"tech-btn active w-btn\" id=\"btn-sine\" onclick=\"setWave('sine', this)\">\r\n            <svg class=\"btn-icon\" viewBox=\"0 0 24 24\"><path d=\"M2 12 Q 8 2 12 12 T 22 12\" stroke-width=\"1.5\"\/><\/svg> SIN\r\n        <\/button>\r\n        <button class=\"tech-btn w-btn\" onclick=\"setWave('square', this)\">\r\n            <svg class=\"btn-icon\" viewBox=\"0 0 24 24\"><path d=\"M2 20V4h9v16h9V4\" stroke-width=\"1.5\"\/><\/svg> SQR\r\n        <\/button>\r\n        <button class=\"tech-btn w-btn\" onclick=\"setWave('sawtooth', this)\">\r\n            <svg class=\"btn-icon\" viewBox=\"0 0 24 24\"><path d=\"M2 20L22 4v16\" stroke-width=\"1.5\"\/><\/svg> SAW\r\n        <\/button>\r\n        <button class=\"tech-btn w-btn\" onclick=\"setWave('triangle', this)\">\r\n            <svg class=\"btn-icon\" viewBox=\"0 0 24 24\"><path d=\"M2 20L12 4l10 16\" stroke-width=\"1.5\"\/><\/svg> TRI\r\n        <\/button>\r\n        <button id=\"btn-tone-toggle\" class=\"tech-btn sub-toggle sub-ready\" onclick=\"toggleTone(this)\" style=\"font-size: 10px !important; font-weight: 900 !important; letter-spacing: 1px;\">SIGNAL<\/button>\r\n    <\/div>\r\n\r\n     <div class=\"panel-header-row\" style=\"margin-top: 25px;\">\r\n         <span class=\"panel-head\">NOISE GENERATOR<\/span>\r\n     <\/div>\r\n     \r\n     <div style=\"display: grid; grid-template-columns: repeat(5, 0.8fr) 1fr; gap: 6px; margin-bottom: 0;\">\r\n        <button class=\"tech-btn noise-btn noise-white\" onclick=\"setWave('white', this)\">\r\n            <div>WHT<\/div>\r\n            <svg class=\"noise-icon\" viewBox=\"0 0 24 12\"><path d=\"M0,6 L2,9 L4,3 L6,8 L8,4 L10,7 L12,5 L14,9 L16,3 L18,8 L20,4 L22,7 L24,6\"\/><\/svg>\r\n        <\/button>\r\n        <button class=\"tech-btn noise-btn noise-pink\" onclick=\"setWave('pink', this)\">\r\n            <div>PNK<\/div>\r\n            <svg class=\"noise-icon\" viewBox=\"0 0 24 12\"><path d=\"M0,6 L2,9 L4,3 L6,8 L8,4 L10,7 L12,5 L14,9 L16,3 L18,8 L20,4 L22,7 L24,6\"\/><\/svg>\r\n        <\/button>\r\n        <button class=\"tech-btn noise-btn noise-blue\" onclick=\"setWave('blue', this)\">\r\n            <div>BLU<\/div>\r\n            <svg class=\"noise-icon\" viewBox=\"0 0 24 12\"><path d=\"M0,6 L2,9 L4,3 L6,8 L8,4 L10,7 L12,5 L14,9 L16,3 L18,8 L20,4 L22,7 L24,6\"\/><\/svg>\r\n        <\/button>\r\n        <button class=\"tech-btn noise-btn noise-grey\" onclick=\"setWave('grey', this)\">\r\n            <div>GRY<\/div>\r\n            <svg class=\"noise-icon\" viewBox=\"0 0 24 12\"><path d=\"M0,6 L2,9 L4,3 L6,8 L8,4 L10,7 L12,5 L14,9 L16,3 L18,8 L20,4 L22,7 L24,6\"\/><\/svg>\r\n        <\/button>\r\n        <button class=\"tech-btn noise-btn noise-red\" onclick=\"setWave('red', this)\">\r\n            <div>RED<\/div>\r\n            <svg class=\"noise-icon\" viewBox=\"0 0 24 12\"><path d=\"M0,6 L2,9 L4,3 L6,8 L8,4 L10,7 L12,5 L14,9 L16,3 L18,8 L20,4 L22,7 L24,6\"\/><\/svg>\r\n        <\/button>\r\n        <button id=\"btn-noise-toggle\" class=\"tech-btn sub-toggle sub-ready\" onclick=\"toggleNoise()\" style=\"font-size: 10px !important; font-weight: 900 !important; letter-spacing: 1px;\">SIGNAL<\/button>\r\n    <\/div>\r\n<\/div>\r\n\r\n            <div class=\"panel-card\">\r\n                <div class=\"panel-header-row\">\r\n                    <span class=\"panel-head\">SWEEP SIGNAL 20-20k Hz<\/span>\r\n                <\/div>\r\n                \r\n                <div style=\"display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; margin-bottom: 25px;\">\r\n                    <button id=\"btn-sweep-lin\" class=\"tech-btn w-btn-sweep\" onclick=\"armSweep('lin', this)\">\r\n                         <svg class=\"btn-icon\" viewBox=\"0 0 24 24\"><path d=\"M2 20 L22 4\" stroke-width=\"1.5\"\/><\/svg> LIN SWEEP\r\n                    <\/button>\r\n                    <button id=\"btn-sweep-log\" class=\"tech-btn w-btn-sweep\" onclick=\"armSweep('log', this)\">\r\n                         <svg class=\"btn-icon\" viewBox=\"0 0 24 24\"><path d=\"M4,20 Q12,20 20,4\" stroke-width=\"1.5\"\/><\/svg> LOG SWEEP\r\n                    <\/button>\r\n                    <button id=\"btn-sweep-toggle\" class=\"tech-btn sub-toggle sub-ready\" onclick=\"toggleSweep()\" style=\"font-size: 10px !important; font-weight: 900 !important; letter-spacing: 1px;\">SIGNAL<\/button>\r\n                <\/div>\r\n\r\n                <span class=\"panel-head\" style=\"margin-top: 25px;\">MUSICAL GENERATOR<\/span>\r\n                <div class=\"sub-unit\" style=\"border:1px solid #334155; margin-bottom:15px; padding:10px; background:linear-gradient(135deg, #1e293b, #0f172a);\">\r\n                    <div class=\"mus-screen\">\r\n                         <div class=\"mus-grid-display\">\r\n                             <div class=\"mus-cell\" id=\"mus-disp-oct\">OCT 4<\/div>\r\n                             <div class=\"mus-cell\" id=\"mus-disp-note\">READY<\/div>\r\n                             <div class=\"mus-cell\" id=\"mus-disp-freq\">0 Hz<\/div>\r\n                         <\/div>\r\n                    <\/div>\r\n                    <div style=\"display: grid; grid-template-columns: 1fr 1fr; gap:5px;\">\r\n                         <button class=\"tech-btn sub-nav\" onclick=\"stepOctave(-1)\">- OCT<\/button>\r\n                         <button class=\"tech-btn sub-nav\" onclick=\"stepOctave(1)\">+ OCT<\/button>\r\n                    <\/div>\r\n                <\/div>\r\n\r\n                <div class=\"piano-wrapper\">\r\n                    <div class=\"key\" onclick=\"playNote(0)\">C<\/div><div class=\"key\" onclick=\"playNote(2)\">D<\/div><div class=\"key\" onclick=\"playNote(4)\">E<\/div>\r\n                    <div class=\"key\" onclick=\"playNote(5)\">F<\/div><div class=\"key\" onclick=\"playNote(7)\">G<\/div><div class=\"key\" onclick=\"playNote(9)\">A<\/div><div class=\"key\" onclick=\"playNote(11)\">B<\/div>\r\n                    <div class=\"key black\" style=\"left: 10%;\" onclick=\"playNote(1)\"><\/div><div class=\"key black\" style=\"left: 24%;\" onclick=\"playNote(3)\"><\/div>\r\n                    <div class=\"key black\" style=\"left: 53%;\" onclick=\"playNote(6)\"><\/div><div class=\"key black\" style=\"left: 67%;\" onclick=\"playNote(8)\"><\/div><div class=\"key black\" style=\"left: 81%;\" onclick=\"playNote(10)\"><\/div>\r\n                <\/div>\r\n\r\n                <div class=\"panel-card\" style=\"margin-bottom: 25px; background: rgba(0,0,0,0.2);\">\r\n                    <div style=\"display:flex; justify-content: space-between; align-items: center; border-bottom: 1px solid #334155; padding-bottom: 5px; margin-bottom: 10px;\">\r\n                        <span class=\"panel-head\" style=\"margin:0; border:none; font-size: 10px;\">ENVELOPE & TUNING<\/span>\r\n                        <span class=\"tech-sub\" style=\"margin:0; font-size: 9px; color: var(--neon-blue);\">ADSR - GATE - TUNE<\/span>\r\n                    <\/div>\r\n\r\n                    <div style=\"display: flex; justify-content: space-around; gap: 2px; flex-wrap: wrap; margin-bottom: 10px;\">\r\n                        <div class=\"knob-wrapper\">\r\n                            <span class=\"knob-label\">ATTACK<\/span>\r\n                            <div class=\"knob-container\" id=\"knob-att\"><div class=\"knob-ring\" id=\"ring-att\"><\/div><div class=\"knob-cap\" id=\"cap-att\"><div class=\"knob-indicator\"><\/div><\/div><\/div>\r\n                            <span class=\"knob-val-display\" id=\"val-att\">0.05s<\/span>\r\n                        <\/div>\r\n                        <div class=\"knob-wrapper\">\r\n                            <span class=\"knob-label\">DECAY<\/span>\r\n                            <div class=\"knob-container\" id=\"knob-dec\"><div class=\"knob-ring\" id=\"ring-dec\"><\/div><div class=\"knob-cap\" id=\"cap-dec\"><div class=\"knob-indicator\"><\/div><\/div><\/div>\r\n                            <span class=\"knob-val-display\" id=\"val-dec\">0.1s<\/span>\r\n                        <\/div>\r\n                        <div class=\"knob-wrapper\">\r\n                            <span class=\"knob-label\">SUSTAIN<\/span>\r\n                            <div class=\"knob-container\" id=\"knob-sus\"><div class=\"knob-ring\" id=\"ring-sus\"><\/div><div class=\"knob-cap\" id=\"cap-sus\"><div class=\"knob-indicator\"><\/div><\/div><\/div>\r\n                            <span class=\"knob-val-display\" id=\"val-sus\">50%<\/span>\r\n                        <\/div>\r\n                        <div class=\"knob-wrapper\">\r\n                            <span class=\"knob-label\">RELEASE<\/span>\r\n                            <div class=\"knob-container\" id=\"knob-rel\"><div class=\"knob-ring\" id=\"ring-rel\"><\/div><div class=\"knob-cap\" id=\"cap-rel\"><div class=\"knob-indicator\"><\/div><\/div><\/div>\r\n                            <span class=\"knob-val-display\" id=\"val-rel\">0.5s<\/span>\r\n                        <\/div>\r\n                        <div class=\"knob-wrapper\">\r\n                            <span class=\"knob-label\">GATE<\/span>\r\n                            <div class=\"knob-container\" id=\"knob-gate\"><div class=\"knob-ring\" id=\"ring-gate\"><\/div><div class=\"knob-cap\" id=\"cap-gate\"><div class=\"knob-indicator\"><\/div><\/div><\/div>\r\n                            <span class=\"knob-val-display\" id=\"val-gate\">0.5s<\/span>\r\n                        <\/div>\r\n                        <div class=\"knob-wrapper\">\r\n                            <span class=\"knob-label\">TUNE<\/span>\r\n                            <div class=\"knob-container\" id=\"knob-tune\"><div class=\"knob-ring\" id=\"ring-tune\"><\/div><div class=\"knob-cap\" id=\"cap-tune\"><div class=\"knob-indicator\"><\/div><\/div><\/div>\r\n                            <span class=\"knob-val-display\" id=\"val-tune\">440Hz<\/span>\r\n                        <\/div>\r\n                    <\/div>\r\n                <\/div>\r\n\r\n                <span class=\"panel-head\">ISO STANDARDS & RTA ANALYZER<\/span>\r\n                <div class=\"sub-unit\" style=\"margin-bottom: 25px; padding: 10px;\">\r\n                    <div class=\"rta-screen\">\r\n                        <canvas id=\"iso-analyzer-canvas\" style=\"width: 100%; height: 100%;\"><\/canvas>\r\n                        <div id=\"iso-status\">RTA ANALYZER<\/div>\r\n                    <\/div>\r\n                    <div class=\"rta-controls-row\" style=\"display: grid; grid-template-columns: 1fr 2fr 1fr 2fr; gap: 8px;\">\r\n                        <button class=\"tech-btn sub-nav\" onclick=\"stepIso(-1)\" style=\"font-size: 26px !important; font-weight: 900 !important;\">-<\/button>\r\n                        <div class=\"mus-screen\" style=\"margin: 0; flex-direction: column; justify-content: center;\">\r\n                            <div id=\"iso-hz-val\" class=\"mus-text-ink\" style=\"font-size: 18px;\">1.000 kHz<\/div>\r\n                        <\/div>\r\n                        <button class=\"tech-btn sub-nav\" onclick=\"stepIso(1)\" style=\"font-size: 26px !important; font-weight: 900 !important;\">+<\/button>\r\n                        <button class=\"tech-btn sub-toggle sub-ready\" id=\"btn-iso-toggle\" onclick=\"toggleIso()\">SIGNAL<\/button>\r\n                    <\/div>\r\n                <\/div>\r\n\r\n                <span class=\"panel-head\">SUBWOOFER MATRIX<\/span>\r\n                <div class=\"sub-unit\">\r\n    <div style=\"display: grid; grid-template-columns: 1fr 2fr 1fr; gap: 8px; margin-bottom: 8px;\">\r\n        <div class=\"sub-screen\" style=\"grid-column: 1 \/ 3; height: 70px; margin-bottom: 0;\">\r\n            <canvas id=\"sub-scope-canvas\"><\/canvas>\r\n            <div id=\"sub-status\">LFE READY<\/div>\r\n            <div id=\"sub-invert-status\">INVERT PHASE<\/div>\r\n\t\t\t<div id=\"drive-monitor\">DRIVE LIMITER<\/div>\r\n        <\/div>\r\n        <div class=\"mus-screen\" style=\"grid-column: 3 \/ 4; height: 70px; margin-bottom: 0; flex-direction: column; justify-content: center;\">\r\n            <div id=\"sub-hz-val\">60 Hz<\/div>\r\n        <\/div>\r\n    <\/div>\r\n\r\n    <div class=\"sub-controls-row\" style=\"display: grid; grid-template-columns: 1fr 1fr 2fr; gap: 8px;\">\r\n        <button class=\"tech-btn sub-nav\" onclick=\"stepSub(-1)\" style=\"font-size: 26px !important; font-weight: 900 !important;\">-<\/button>\r\n        <button class=\"tech-btn sub-nav\" onclick=\"stepSub(1)\" style=\"font-size: 26px !important; font-weight: 900 !important;\">+<\/button>\r\n        <button class=\"tech-btn sub-toggle sub-ready\" id=\"btn-sub-toggle\" onclick=\"toggleSub()\">SIGNAL<\/button>\r\n    <\/div>\r\n\r\n    <div class=\"smoked-glass\" style=\"margin-bottom:8px; margin-top:5px; flex-direction: row; align-items: center; justify-content: space-between; padding: 10px 15px;\">\r\n        \r\n        <div style=\"flex: 1; display: flex; flex-direction: column; justify-content: center; margin-right: 25px;\">\r\n            <div class=\"pan-display-row\" style=\"color:#64748b; margin-bottom: 4px;\">\r\n                <span>SUB TRIM<\/span> \r\n                <span id=\"sub-trim-val\" class=\"text-glow-white\">0.0 dB<\/span>\r\n            <\/div>\r\n            \r\n            <div style=\"position:relative; width:100%;\">\r\n                <input type=\"range\" class=\"magnet-slider\" id=\"sub-trim-slider\" min=\"-12\" max=\"6\" step=\"1\" value=\"0\" oninput=\"updSubTrim(this.value)\" style=\"width: 100%;\">\r\n                <div class=\"vol-scale-wrapper\" style=\"margin-top: 5px; height: 15px; position: relative;\">\r\n                    <span class=\"tick\" style=\"left: 0%; transform: translateX(0%);\">-12<\/span>\r\n                    <span class=\"tick\" style=\"left: 66.6%; transform: translateX(-50%); color: #e2e8f0;\">0<\/span>\r\n                    <span class=\"tick\" style=\"left: 100%; transform: translateX(-100%);\">+6<\/span>\r\n                <\/div>\r\n            <\/div>\r\n        <\/div>\r\n\r\n        <div class=\"knob-wrapper\" style=\"width: 100px; flex-shrink: 0; margin-bottom: 5px; position: relative; display: flex; flex-direction: column; align-items: center;\">\r\n    <span class=\"knob-label\" style=\"margin-bottom: 5px; display:block; text-align:center;\">LPF FREQ<\/span>\r\n    \r\n    <div style=\"position: relative; width: 80px; height: 80px;\">\r\n        \r\n        <div class=\"knob-scale-nums\">\r\n            <span style=\"transform: translate(-50%, -50%) rotate(-135deg) translateY(-35px) rotate(135deg);\">0<\/span>\r\n            <span style=\"transform: translate(-50%, -50%) rotate(-90deg) translateY(-35px) rotate(90deg);\">20<\/span>\r\n            <span style=\"transform: translate(-50%, -50%) rotate(-45deg) translateY(-35px) rotate(45deg);\">40<\/span>\r\n            <span style=\"transform: translate(-50%, -50%) rotate(0deg) translateY(-35px) rotate(0deg);\">60<\/span>\r\n            <span style=\"transform: translate(-50%, -50%) rotate(45deg) translateY(-35px) rotate(-45deg);\">80<\/span>\r\n            <span style=\"transform: translate(-50%, -50%) rotate(90deg) translateY(-35px) rotate(-90deg);\">100<\/span>\r\n            <span style=\"transform: translate(-50%, -50%) rotate(135deg) translateY(-35px) rotate(-135deg);\">120<\/span>\r\n        <\/div>\r\n\r\n        <div class=\"knob-container\" id=\"knob-subFreq\" style=\"width: 50px; height: 50px; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); margin: 0; z-index: 10;\">\r\n            <div class=\"knob-ring\" id=\"ring-subFreq\"><\/div>\r\n            <div class=\"knob-cap\" id=\"cap-subFreq\" style=\"width: 40px; height: 40px; top: 5px; left: 5px;\">\r\n                <div class=\"knob-indicator\"><\/div>\r\n            <\/div>\r\n        <\/div>\r\n    <\/div>\r\n    \r\n    <span class=\"knob-val-display\" id=\"val-subFreq\" style=\"margin-top: 5px; display:block; text-align:center;\">60 Hz<\/span>\r\n<\/div>\r\n    <\/div>\r\n\r\n    <div style=\"display: grid; grid-template-columns: 1.2fr 1.2fr 0.8fr 0.8fr; gap: 6px; margin-top:0px;\">\r\n    <button class=\"tech-btn w-btn-sweep\" id=\"btn-sub-sweep\" onclick=\"armSubSweep()\">\r\n        <svg class=\"btn-icon\" viewBox=\"0 0 24 24\"><path d=\"M2 20 L22 4\" stroke-width=\"1.5\"\/><\/svg> LFE SWEEP\r\n    <\/button>\r\n    \r\n    <button class=\"tech-btn\" onclick=\"playSubKick()\">\r\n        <svg class=\"btn-icon\" viewBox=\"0 0 24 24\"><path d=\"M2 12 L 5 12 L 8 4 L 12 20 L 15 12 L 22 12\" stroke-width=\"1.5\" stroke-linejoin=\"round\"\/><\/svg>\r\n        KICK <span id=\"kick-btn-val\" style=\"margin-left:2px; font-size:9px; color:var(--neon-blue);\">60<\/span>\r\n    <\/button>\r\n    \r\n    <button class=\"tech-btn sub-phase\" id=\"btn-sub-phase\" onclick=\"togglePhase()\">\r\n        <span style=\"font-size: 14px; margin-right: 2px;\">\u00d8<\/span> INVERT\r\n    <\/button>\r\n    \r\n    <button class=\"tech-btn\" id=\"btn-sub-drive\" onclick=\"toggleSubDrive()\">\r\n        <svg class=\"btn-icon\" viewBox=\"0 0 24 24\"><path d=\"M22 12h-4l-3 9L9 3l-3 9H2\" stroke-width=\"1.5\" stroke-linejoin=\"round\"\/><\/svg>\r\n        DRIVE\r\n    <\/button>\r\n<\/div>\r\n<\/div>\r\n            <\/div>\r\n        <\/div>\r\n    <\/div>\r\n<\/div>\r\n\r\n<script src=\"script.js\"><\/script>\r\n\r\n\r\n\r\n<script>\r\n  const LED_COUNT = 20;\r\nconst SMOOTHING = 0.05; \r\n\r\nlet actx, osc, gain, pan, anal, noise;\r\nlet isSystemOn = false; \r\nlet isSignalOn = false; \r\nlet activeModule = 'none'; \r\n\r\nlet curWave = 'sine';\r\nlet safeVol = 0.25;\r\nlet highGainConfirmed = false;\r\nlet pendingVol = 0.25;\r\nlet sweepTimer = null;\r\nlet sweepMode = null;\r\nlet selectedSweepMode = null;\r\nlet moduleStopTimer = null; \r\n\r\nlet scaleMode = 'log'; \/\/ Default LOG\r\nlet currentOctave = 4;\r\nlet currentFreq = 0;\r\nlet concertPitch = 440; \r\nlet stopTimer;\r\n\r\nlet isTurningOff = false; \r\nlet offStartTime = 0;\r\n\r\nlet subFreq = 60;\r\nlet phasePolarity = 1;\r\nlet subTrim = 1.0;\r\nlet isSubDriveActive = false;\r\nlet subDriveNode = null;\r\n\r\nconst isoFreqs = [20, 32, 64, 125, 250, 500, 1000, 2000, 4000, 8000, 16000, 20000];\r\nlet isoIndex = 6; \r\n\r\nlet displayToast = null;\r\nlet toastTimer = null;\r\n\r\nlet rtaData; \r\nlet startupVuLevel = 0;\r\n\r\nlet adsr = {\r\n    a: 0.05, \r\n    d: 0.1,  \r\n    s: 0.5,  \r\n    r: 0.5   \r\n};\r\nlet activeVoices = []; \r\n\r\n\/\/ --- KNOB SETUP ---\r\nlet knobs = {\r\n    att: { val: 0.05, min: 0.01, max: 2, step: 0.01, unit: 's', param: 'a' },\r\n    dec: { val: 0.1, min: 0.01, max: 2, step: 0.01, unit: 's', param: 'd' },\r\n    sus: { val: 0.5, min: 0, max: 1, step: 0.05, unit: '%', param: 's' },\r\n    rel: { val: 0.5, min: 0.05, max: 5, step: 0.05, unit: 's', param: 'r' },\r\n    gate: { val: 0.5, min: 0.1, max: 5, step: 0.1, unit: 's', param: 'gate' },\r\n    tune: { val: 440, min: 430, max: 450, step: 1, unit: 'Hz', param: 'tune' },\r\n\t\/\/ Provjeri je li ovo dodano u let knobs = { ... }\r\n    subFreq: { val: 60, min: 0, max: 120, step: 10, unit: 'Hz', param: 'subFreq' }\r\n};\r\n\r\nlet activeKnobId = null;\r\n\r\nfunction initKnobs() {\r\n    ['att', 'dec', 'sus', 'rel', 'gate', 'tune'].forEach(id => {\r\n        let el = document.getElementById('knob-' + id);\r\n        el.addEventListener('mousedown', (e) => startKnobDrag(e, id));\r\n        el.addEventListener('touchstart', (e) => {\r\n            e.preventDefault(); \r\n            openKnobPopup(id);  \r\n        }, {passive: false});\r\n        updateKnobVisual(id);\r\n    });\r\n}\r\n\r\nlet knobStartY = 0;\r\nlet knobStartVal = 0;\r\nlet currentDragKnob = null;\r\n\r\nfunction startKnobDrag(e, id) {\r\n    if(!isSystemOn) return;\r\n    e.preventDefault(); \r\n    currentDragKnob = id;\r\n    knobStartY = e.clientY;\r\n    knobStartVal = knobs[id].val;\r\n    document.addEventListener('mousemove', handleKnobMove);\r\n    document.addEventListener('mouseup', endKnobDrag);\r\n}\r\n\r\nfunction handleKnobMove(e) {\r\n    if (!currentDragKnob) return;\r\n    let id = currentDragKnob;\r\n    let conf = knobs[id];\r\n    let delta = (knobStartY - e.clientY);\r\n    let range = conf.max - conf.min;\r\n    let change = (delta \/ 150) * range;\r\n    let newVal = knobStartVal + change;\r\n    if(newVal < conf.min) newVal = conf.min;\r\n    if(newVal > conf.max) newVal = conf.max;\r\n    newVal = Math.round(newVal \/ conf.step) * conf.step;\r\n    knobs[id].val = newVal;\r\n    if (['a','d','s','r'].includes(conf.param)) adsr[conf.param] = newVal;\r\n    else if (conf.param === 'tune') concertPitch = parseInt(newVal);\r\n    updateKnobVisual(id);\r\n}\r\n\r\nfunction endKnobDrag() {\r\n    currentDragKnob = null;\r\n    document.removeEventListener('mousemove', handleKnobMove);\r\n    document.removeEventListener('mouseup', endKnobDrag);\r\n}\r\n\r\nfunction updateKnobVisual(id) {\r\n    let conf = knobs[id];\r\n    let pct = (conf.val - conf.min) \/ (conf.max - conf.min);\r\n    let angle = -135 + (pct * 270);\r\n    document.getElementById('cap-' + id).style.transform = `rotate(${angle}deg)`;\r\n    let disp = conf.unit === '%' ? Math.round(conf.val * 100) : (conf.unit === 'Hz' ? Math.round(conf.val) : conf.val.toFixed(2));\r\n    document.getElementById('val-' + id).innerText = disp + conf.unit;\r\n}\r\n\r\n\/\/ --- MOBILE POPUP LOGIC ---\r\nfunction openKnobPopup(id) {\r\n    if(!isSystemOn || currentDragKnob) return; \r\n    if(window.innerWidth > 900) return; \r\n    \r\n    activeKnobId = id;\r\n    let conf = knobs[id];\r\n    let popup = document.getElementById('mobile-knob-editor');\r\n    let slider = document.getElementById('mobile-slider');\r\n    \r\n    document.getElementById('mobile-knob-title').innerText = id.toUpperCase();\r\n    \r\n    slider.min = conf.min; \r\n    slider.max = conf.max; \r\n    slider.step = conf.step; \r\n    slider.value = conf.val;\r\n    \r\n    slider.oninput = function() {\r\n        let v = parseFloat(this.value);\r\n        knobs[activeKnobId].val = v;\r\n        let p = conf.param;\r\n        \r\n        \/\/ --- OVO JE DODANO ZA SUBWOOFER ---\r\n        if (['a','d','s','r'].includes(p)) adsr[p] = v;\r\n        else if (p === 'tune') concertPitch = parseInt(v);\r\n        else if (p === 'subFreq') setSubHz(v); \/\/ <--- KLJU\u010cNI POPRAVAK\r\n        \r\n        updateKnobVisual(activeKnobId);\r\n        \r\n        let disp = conf.unit === '%' ? Math.round(v * 100) : (conf.unit === 'Hz' ? Math.round(v) : v.toFixed(2));\r\n        document.getElementById('mobile-knob-val').innerText = disp + conf.unit;\r\n    };\r\n    \r\n    let disp = conf.unit === '%' ? Math.round(conf.val * 100) : (conf.unit === 'Hz' ? Math.round(conf.val) : conf.val.toFixed(2));\r\n    document.getElementById('mobile-knob-val').innerText = disp + conf.unit;\r\n    \r\n    document.getElementById('popup-closer').style.display = 'block';\r\n    popup.style.display = 'flex';\r\n}\r\n\r\nfunction closePopup() {\r\n    document.getElementById('mobile-knob-editor').style.display = 'none';\r\n    document.getElementById('popup-closer').style.display = 'none';\r\n    activeKnobId = null;\r\n}\r\n\r\n\/\/ --- MAIN AUDIO LOGIC ---\r\nfunction buildMeters() {\r\n    const lStrip = document.getElementById('meter-l-strip');\r\n    const rStrip = document.getElementById('meter-r-strip');\r\n    lStrip.innerHTML = ''; rStrip.innerHTML = '';\r\n    for(let i=0; i<LED_COUNT; i++) {\r\n        let led = document.createElement('div');\r\n        led.className = 'led-seg';\r\n        lStrip.appendChild(led.cloneNode(true));\r\n        rStrip.appendChild(led.cloneNode(true));\r\n    }\r\n}\r\nbuildMeters();\r\n\r\nfunction makeDistortionCurve() {\r\n    let k = 100; let n_samples = 44100; let curve = new Float32Array(n_samples); let deg = Math.PI \/ 180;\r\n    for (let i = 0; i < n_samples; ++i ) {\r\n        let x = i * 2 \/ n_samples - 1;\r\n        curve[i] = ( 3 + k ) * x * 20 * deg \/ ( Math.PI + k * Math.abs(x) );\r\n    }\r\n    return curve;\r\n}\r\n\r\nfunction init() {\r\n    if (!actx) {\r\n        actx = new (window.AudioContext || window.webkitAudioContext)();\r\n        gain = actx.createGain();\r\n        pan = actx.createStereoPanner();\r\n        anal = actx.createAnalyser();\r\n        anal.fftSize = 4096; anal.smoothingTimeConstant = 0.8; \r\n        anal.minDecibels = -100; anal.maxDecibels = 0;       \r\n        rtaData = new Uint8Array(anal.frequencyBinCount);\r\n        subDriveNode = actx.createWaveShaper();\r\n        subDriveNode.curve = makeDistortionCurve(); \r\n        gain.connect(pan); pan.connect(anal); anal.connect(actx.destination);\r\n        loopVis();\r\n        initKnobs();\r\n    }\r\n    if (actx.state === 'suspended') actx.resume();\r\n}\r\n\r\nfunction isSubPlaying() { return activeModule === 'sub' || activeModule === 'sub-sweep-running' || activeModule === 'sub-kick'; }\r\nfunction isIsoPlaying() { return activeModule === 'iso'; }\r\nfunction getActualVol() { return safeVol * phasePolarity * (isSubPlaying() ? subTrim : 1.0); }\r\n\r\nfunction showToast(msg) {\r\n    displayToast = msg;\r\n    document.getElementById('screen-input').value = msg;\r\n    if(toastTimer) clearTimeout(toastTimer);\r\n    toastTimer = setTimeout(() => { displayToast = null; updateDisplay(); }, 1500); \r\n}\r\n\r\nfunction killCurrentAudio() {\r\n    clearTimeout(moduleStopTimer);\r\n    if(osc) { try{osc.stop();osc.disconnect();}catch(e){} osc=null; }\r\n    if(noise) { try{noise.stop();noise.disconnect();}catch(e){} noise=null; }\r\n}\r\n\r\nfunction resetSignalButtons() {\r\n    let toggles = ['btn-tone-toggle', 'btn-noise-toggle', 'btn-sweep-toggle', 'btn-iso-toggle', 'btn-sub-toggle', 'btn-freq-toggle'];\r\n    toggles.forEach(id => {\r\n        let btn = document.getElementById(id);\r\n        if(btn) {\r\n            btn.classList.remove('sub-active');\r\n            btn.classList.add('sub-ready');\r\n            btn.innerText = \"SIGNAL\";\r\n        }\r\n    });\r\n}\r\n\r\nfunction updateMasterButton() {\r\n    let mainBtn = document.getElementById('btn-main');\r\n    if (!isSystemOn) {\r\n        mainBtn.innerText = \"ACTIVATE\"; \r\n        mainBtn.classList.remove('btn-mute', 'btn-on');\r\n        mainBtn.classList.add('btn-ready'); \r\n    } else {\r\n        mainBtn.classList.remove('btn-ready');\r\n        if (isSignalOn) {\r\n            if (activeModule === 'iso') mainBtn.innerText = \"ISO & RTS\";\r\n            else if (isSubPlaying()) mainBtn.innerText = \"SUB\";\r\n            else mainBtn.innerText = \"MUTE\"; \r\n            mainBtn.classList.remove('btn-on');\r\n            mainBtn.classList.add('btn-mute'); \r\n        } else {\r\n            mainBtn.innerText = \"SIGNAL\"; \r\n            mainBtn.classList.remove('btn-mute');\r\n            mainBtn.classList.add('btn-on'); \r\n        }\r\n    }\r\n}\r\n\r\nfunction switchModuleTo(modName) {\r\n    killCurrentAudio();\r\n    clearInterval(sweepTimer);\r\n    clearTimeout(stopTimer);\r\n    activeModule = modName;\r\n    isSignalOn = true;\r\n    resetSignalButtons();\r\n}\r\n\r\nfunction silencePiano() {\r\n    if(osc) { try{osc.stop(); osc.disconnect();}catch(e){} osc=null; }\r\n    if(noise) { try{noise.stop(); noise.disconnect();}catch(e){} noise=null; }\r\n    isSignalOn = false;\r\n    changeFreq(0); \r\n    updateDisplay();\r\n    updateMasterButton();\r\n}\r\n\r\nfunction stopAllModules() {\r\n    if (!actx) return;\r\n    const now = actx.currentTime;\r\n    activeVoices.forEach(voice => {\r\n        try {\r\n            voice.gain.gain.cancelScheduledValues(now);\r\n            voice.gain.gain.setValueAtTime(voice.gain.gain.value, now);\r\n            voice.gain.gain.linearRampToValueAtTime(0, now + 0.1); \r\n            voice.osc.stop(now + 0.15);\r\n        } catch(e) {}\r\n    });\r\n    activeVoices = []; \r\n    clearInterval(sweepTimer); clearTimeout(stopTimer); clearTimeout(moduleStopTimer);\r\n    selectedSweepMode = null; \r\n    if (gain) {\r\n        gain.gain.cancelScheduledValues(now);\r\n        gain.gain.setValueAtTime(gain.gain.value, now);\r\n        gain.gain.linearRampToValueAtTime(0, now + 0.15); \r\n    }\r\n    isSignalOn = false; activeModule = 'none';\r\n    resetSignalButtons(); updateMasterButton(); \r\n    document.getElementById('status-text').innerText = \"SYSTEM ACTIVE\";\r\n    document.getElementById('status-text').style.color = \"#38bdf8\";\r\n    document.getElementById('sub-status').innerText = \"LFE READY\";\r\n    document.getElementById('sub-status').style.color = \"#64748b\";\r\n    document.getElementById('iso-status').innerText = \"RTA ANALYZER\";\r\n    document.getElementById('iso-status').style.color = \"#64748b\";\r\n    document.getElementById('btn-sub-sweep').classList.remove('active');\r\n    document.querySelectorAll('.w-btn-sweep:not(#btn-sub-sweep)').forEach(b => b.classList.remove('active'));\r\n    \r\n    \/\/ Na STOP vra\u0107amo na 0 Hz\r\n    changeFreq(0); \r\n    updateDisplay(); \r\n    \r\n    moduleStopTimer = setTimeout(() => {\r\n        if(osc) { try{osc.stop(); osc.disconnect();}catch(e){} osc=null; }\r\n        if(noise) { try{noise.stop(); noise.disconnect();}catch(e){} noise=null; }\r\n    }, 200);\r\n}\r\n\r\nfunction handleMainButton() {\r\n    init();\r\n    if (!isSystemOn) {\r\n        isSystemOn = true; isTurningOff = false; \r\n        document.getElementById('sonic-lab-v25').classList.remove('sys-off');\r\n        document.getElementById('screen-inner').classList.remove('crt-off'); \r\n        document.getElementById('screen-inner').classList.add('crt-on'); \r\n        document.getElementById('led-indicator').classList.add('active');\r\n        document.getElementById('status-text').innerText = \"SYSTEM ACTIVE\";\r\n        document.getElementById('status-text').style.color = \"#38bdf8\"; \r\n        document.getElementById('btn-stop').classList.remove('active');\r\n        document.getElementById('hz-overlay').style.display = ''; \r\n        \r\n        \/\/ KAD SE UPALI (ACTIVATE) IDE NA 1000 Hz\r\n        changeFreq(1000);\r\n\r\n        updateMasterButton(); updateDisplay();\r\n        startupVuLevel = 1.0;\r\n    } else if (!isSignalOn) {\r\n        if (selectedSweepMode) runSweepLogic(selectedSweepMode);\r\n        else if (activeModule === 'iso') toggleIso();\r\n        else if (activeModule === 'sub' || activeModule === 'sub-sweep-running' || activeModule === 'sub-sweep-armed' || activeModule === 'sub-kick') toggleSub();\r\n        else if (activeModule === 'noise' || isNoise(curWave)) toggleNoise();\r\n        else toggleTone();\r\n    } else {\r\n        stopAllModules(); \r\n    }\r\n}\r\n\r\nfunction showWarning() {\r\n    const warn = document.getElementById('warning-overlay');\r\n    warn.classList.add('show');\r\n    setTimeout(() => warn.classList.remove('show'), 4000);\r\n}\r\n\r\nfunction handleSystemOff() {\r\n    if (!isSystemOn) return; \r\n    stopAllModules(); isTurningOff = true; offStartTime = Date.now();\r\n    document.getElementById('screen-inner').classList.remove('crt-on'); \r\n    document.getElementById('hz-overlay').style.display = 'none'; \r\n    document.getElementById('sonic-lab-v25').classList.add('sys-off');\r\n    setTimeout(() => {\r\n        isSystemOn = false; isTurningOff = false;\r\n        resetSystemState(); \r\n        document.getElementById('led-indicator').classList.remove('active');\r\n        document.getElementById('status-text').innerText = \"SYSTEM READY\";\r\n        document.getElementById('status-text').style.color = \"#64748b\";\r\n        document.getElementById('btn-stop').classList.remove('active');\r\n        document.getElementById('hz-overlay').style.display = ''; \r\n        updateMasterButton(); \r\n    }, 3000); \r\n}\r\n\r\nfunction resetSystemState() {\r\n    curWave = 'sine'; \r\n    \/\/ RESET NA 0 Hz KOD GA\u0160ENJA\/RESETIRANJA\r\n    currentFreq = 0; \r\n    \r\n    selectedSweepMode = null; sweepMode = null; activeModule = 'none';\r\n    subFreq = 60;\r\n    document.getElementById('sub-hz-val').innerText = \"60 Hz\";\r\n    document.getElementById('kick-btn-val').innerText = \"60\";\r\n    document.getElementById('btn-sub-drive').classList.remove('active');\r\n    document.getElementById('sub-status').innerText = \"LFE READY\";\r\n    document.getElementById('sub-status').style.color = \"#64748b\";\r\n    isoIndex = 6;\r\n    document.getElementById('iso-hz-val').innerText = \"1.000 kHz\";\r\n    phasePolarity = 1;\r\n    document.getElementById('btn-sub-phase').classList.remove('active');\r\n    document.getElementById('sub-invert-status').style.display = 'none';\r\n    document.querySelectorAll('.w-btn').forEach(b => b.classList.remove('active'));\r\n    document.getElementById('btn-sine').classList.add('active'); \r\n    document.querySelectorAll('.w-btn-sweep').forEach(b => b.classList.remove('active'));\r\n    document.querySelectorAll('.noise-btn').forEach(b => b.classList.remove('active')); \r\n    \/\/ ... unutar resetSystemState ...\r\ndocument.getElementById('lbl-log-status').style.display = (scaleMode === 'log') ? 'block' : 'none';\r\ndocument.getElementById('lbl-freq-warning').style.display = 'block'; \/\/ Na reset je 0Hz, pa poka\u017ei warning\r\n    updateSliderPos(0);\r\n    document.getElementById('screen-input').value = \"0 Hz\";\r\n    \r\n    updateMusicalDisplay(-1); updateLEDs(0);\r\n    displayToast = null; updateDisplay(); \r\n    document.querySelector('#btn-pan-l .pan-side-label').innerText = \"L\";\r\n    document.querySelector('#btn-pan-r .pan-side-label').innerText = \"R\";\r\n    knobs.att.val = 0.05; updateKnobVisual('att');\r\n    knobs.dec.val = 0.1; updateKnobVisual('dec');\r\n    knobs.sus.val = 0.5; updateKnobVisual('sus');\r\n    knobs.rel.val = 0.5; updateKnobVisual('rel');\r\n    knobs.gate.val = 0.5; updateKnobVisual('gate');\r\n    knobs.tune.val = 440; updateKnobVisual('tune');\r\n    adsr = { a:0.05, d:0.1, s:0.5, r:0.5 }; concertPitch = 440;\r\n\t\/\/ ... unutar resetSystemState funkcije ...\r\nif(scaleMode === 'log') {\r\n    document.getElementById('lbl-log').classList.add('active');\r\n    document.getElementById('lbl-lin').classList.remove('active');\r\n} else {\r\n    document.getElementById('lbl-log').classList.remove('active');\r\n    document.getElementById('lbl-lin').classList.add('active');\r\n}\r\n\/\/ ... ostatak funkcije ...\r\n}\r\n\r\nfunction isNoise(w) { return ['white','pink','blue','grey','brown','red'].includes(w); }\r\n\r\nfunction createOsc() {\r\n    osc = actx.createOscillator();\r\n    osc.type = curWave;\r\n    osc.frequency.value = isSubPlaying() ? subFreq : (isIsoPlaying() ? isoFreqs[isoIndex] : currentFreq);\r\n    if (isSubPlaying() && isSubDriveActive) { osc.connect(subDriveNode); subDriveNode.connect(gain); } \r\n    else { osc.connect(gain); }\r\n}\r\n\r\nfunction createNoise() {\r\n    let bufSize = 2 * actx.sampleRate; let buf = actx.createBuffer(1, bufSize, actx.sampleRate);\r\n    let data = buf.getChannelData(0);\r\n    if (curWave === 'white') { for(let i=0; i<bufSize; i++) data[i] = Math.random() * 2 - 1; } \r\n    else if (curWave === 'pink') { \r\n        let b0=0,b1=0,b2=0,b3=0,b4=0,b5=0,b6=0;\r\n        for(let i=0; i<bufSize; i++) {\r\n            let w = Math.random()*2-1;\r\n            b0 = 0.99886*b0+w*0.0555179; b1 = 0.99332*b1+w*0.0750759; b2 = 0.96900*b2+w*0.1538520;\r\n            b3 = 0.86650*b3+w*0.3104856; b4 = 0.55000*b4+w*0.5329522; b5 = -0.7616*b5-w*0.0168980;\r\n            data[i] = b0+b1+b2+b3+b4+b5+b6+w*0.5362; data[i] *= 0.11; b6 = w*0.115926;\r\n        }\r\n    }\r\n    else if (curWave === 'red') { \r\n        let lastOut = 0;\r\n        for(let i=0; i<bufSize; i++) {\r\n            let white = Math.random() * 2 - 1;\r\n            lastOut = (lastOut + (0.02 * white)) \/ 1.02; \r\n            let out = lastOut * 3.0; \r\n            if(out > 1) out = 1; if(out < -1) out = -1;\r\n            data[i] = out * 0.5; \r\n        }\r\n    }\r\n    else if (curWave === 'blue') {\r\n            let lastIn = 0;\r\n            for(let i=0; i<bufSize; i++) {\r\n                let white = Math.random() * 2 - 1;\r\n                data[i] = (white - lastIn) * 0.5;\r\n                lastIn = white;\r\n            }\r\n    }\r\n    else if (curWave === 'grey') {\r\n        let lastOut = 0;\r\n        for(let i=0; i<bufSize; i++) {\r\n            let white = Math.random() * 2 - 1;\r\n            lastOut = (lastOut + (0.02 * white)) \/ 1.02;\r\n            data[i] = (white * 0.3) + (lastOut * 3.0);\r\n            data[i] *= 0.5; \r\n        }\r\n    }\r\n    noise = actx.createBufferSource();\r\n    noise.buffer = buf; noise.loop = true; noise.connect(gain);\r\n}\r\n\r\nfunction startSound() {\r\n    killCurrentAudio(); \r\n    const now = actx.currentTime;\r\n    gain.gain.cancelScheduledValues(now); gain.gain.setValueAtTime(0, now);\r\n    if (isNoise(curWave)) { createNoise(); noise.start(now); } \r\n    else { createOsc(); osc.start(now); }\r\n    gain.gain.linearRampToValueAtTime(getActualVol(), now + 0.05);\r\n    updateDisplay(); updateMasterButton(); \r\n}\r\n\r\nfunction toggleTone(caller) {\r\n    if (!isSystemOn) return;\r\n    if (activeModule === 'tone') stopAllModules();\r\n    else {\r\n        if (currentFreq === 0 && !isNoise(curWave)) { showWarning(); return; }\r\n        switchModuleTo('tone');\r\n        \r\n        \/\/ Palimo samo gumb koji je pozvao funkciju\r\n        if(caller) {\r\n            caller.classList.remove('sub-ready');\r\n            caller.classList.add('sub-active');\r\n            caller.innerText = \"STOP\";\r\n        } else {\r\n            \/\/ Fallback ako se pozove bez argumenta (npr enter)\r\n            let def = document.getElementById('btn-tone-toggle');\r\n            if(def) { def.classList.remove('sub-ready'); def.classList.add('sub-active'); def.innerText = \"STOP\"; }\r\n        }\r\n\r\n        document.getElementById('status-text').innerText = \"TONE LIVE\";\r\n        document.getElementById('status-text').style.color = \"#ef4444\";\r\n        if (isNoise(curWave)) setWave('sine', document.getElementById('btn-sine'));\r\n        startSound();\r\n    }\r\n}\r\n\r\nfunction toggleNoise() {\r\n    if (!isSystemOn) return;\r\n    if (activeModule === 'noise') stopAllModules();\r\n    else {\r\n        switchModuleTo('noise');\r\n        let btn = document.getElementById('btn-noise-toggle');\r\n        btn.classList.remove('sub-ready');\r\n        btn.classList.add('sub-active');\r\n        btn.innerText = \"STOP\";\r\n        document.getElementById('status-text').innerText = \"NOISE LIVE\";\r\n        document.getElementById('status-text').style.color = \"#ef4444\";\r\n        if (!isNoise(curWave)) setWave('white', document.querySelector('.noise-white'));\r\n        startSound();\r\n    }\r\n}\r\n\r\nfunction toggleSweep() {\r\n    if (!isSystemOn) return;\r\n    if (activeModule === 'sweep') stopAllModules();\r\n    else {\r\n        switchModuleTo('sweep');\r\n        let btn = document.getElementById('btn-sweep-toggle');\r\n        btn.classList.remove('sub-ready');\r\n        btn.classList.add('sub-active');\r\n        btn.innerText = \"STOP\";\r\n        document.getElementById('status-text').innerText = \"SWEEP LIVE\";\r\n        document.getElementById('status-text').style.color = \"#ef4444\";\r\n        if (!selectedSweepMode) {\r\n            selectedSweepMode = 'lin';\r\n            if(scaleMode !== 'lin') toggleScaleMode(); \r\n            document.getElementById('btn-sweep-lin').classList.add('active'); \r\n        }\r\n        if (isNoise(curWave)) setWave('sine', document.getElementById('btn-sine'));\r\n        runSweepLogic(selectedSweepMode);\r\n    }\r\n}\r\n\r\nfunction toggleIso() {\r\n    if(!isSystemOn) return; \r\n    if (activeModule === 'iso') stopAllModules();\r\n    else {\r\n        switchModuleTo('iso');\r\n        let btn = document.getElementById('btn-iso-toggle');\r\n        btn.classList.remove('sub-ready');\r\n        btn.classList.add('sub-active');\r\n        btn.innerText = \"STOP\";\r\n        let status = document.getElementById('iso-status');\r\n        status.innerText = \"ISO ACTIVE\";\r\n        status.style.color = \"var(--neon-blue)\";\r\n        document.getElementById('status-text').innerText = \"ISO ACTIVE\";\r\n        document.getElementById('status-text').style.color = \"#ef4444\";\r\n        showToast(\"ISO & RTA\"); \r\n        if (isNoise(curWave)) setWave('sine', document.getElementById('btn-sine'));\r\n        changeFreq(isoFreqs[isoIndex]); \r\n        startSound();\r\n    }\r\n    updateMasterButton();\r\n}\r\n\r\nfunction toggleSub() {\r\n    if(!isSystemOn) return;\r\n    if (activeModule === 'sub-sweep-running') { stopAllModules(); return; }\r\n    if (activeModule === 'sub' && isSignalOn) stopAllModules();\r\n    else {\r\n        if (activeModule === 'sub-sweep-armed') { runSubSweepLogic(); } \r\n        else {\r\n            switchModuleTo('sub');\r\n            let btn = document.getElementById('btn-sub-toggle');\r\n            btn.classList.remove('sub-ready');\r\n            btn.classList.add('sub-active');\r\n            btn.innerText = \"STOP\";\r\n            document.getElementById('status-text').innerText = \"SUBWOOFER ON\";\r\n            document.getElementById('status-text').style.color = \"#ef4444\";\r\n            let subStatus = document.getElementById('sub-status');\r\n            if (isSubDriveActive) { subStatus.innerText = \"LFE DRIVE ACTIVE\"; subStatus.style.color = \"#ef4444\"; } \r\n            else { subStatus.innerText = \"LFE ACTIVE\"; subStatus.style.color = \"var(--neon-blue)\"; }\r\n            showToast(\"SUB\"); \r\n            if (isNoise(curWave)) setWave('sine', document.getElementById('btn-sine'));\r\n            changeFreq(subFreq); \r\n            startSound();\r\n        }\r\n    }\r\n    updateMasterButton();\r\n}\r\n\r\nfunction formatHz(val) {\r\n    let v = Math.round(val); \/\/ Osiguraj cijeli broj\r\n    if (v === 0) return \"0 Hz\";\r\n    \r\n    if (v >= 1000) {\r\n        \/\/ Za kHz prikazujemo 3 decimale da se vidi to\u010dan Hz (npr. 1.234 kHz = 1234 Hz)\r\n        \/\/ Ako je to\u010dno 1000, 2000, bit \u0107e 1.000 kHz\r\n        return (v \/ 1000).toFixed(3) + \" kHz\";\r\n    }\r\n    \r\n    return v + \" Hz\";\r\n}\r\n\r\nfunction updateDisplay() {\r\n    document.getElementById('freq-mini-disp').innerText = formatHz(currentFreq);\r\n    if (displayToast) { document.getElementById('screen-input').value = displayToast; return; }\r\n    if (isNoise(curWave)) { document.getElementById('screen-input').value = curWave.toUpperCase() + \" N.\"; return; }\r\n    document.getElementById('screen-input').value = formatHz(currentFreq);\r\n}\r\n\r\nfunction onHzFocus(el) { if(!isSystemOn) return; el.value = currentFreq; }\r\nfunction onHzBlur(el) { if(!isSystemOn) { el.value = \"0 Hz\"; return; } updateDisplay(); }\r\nfunction focusMainInput() { if(!isSystemOn) return; document.getElementById('screen-input').focus(); }\r\n\r\nfunction manualEntry(val) {\r\n    if(!isSystemOn) return; \r\n    let clean = val.toLowerCase().replace(\/[^0-9.k]\/g, '');\r\n    let num = 0;\r\n    if(clean.includes('k')) num = parseFloat(clean.replace('k','')) * 1000; \r\n    else num = parseFloat(clean); \r\n    num = parseInt(num); \r\n    if(isNaN(num)) num = 0; if(num > 20000) num = 20000;\r\n    if (isNoise(curWave)) setWave('sine', document.getElementById('btn-sine'));\r\n    changeFreq(num);\r\n    document.getElementById('screen-input').blur(); \r\n}\r\n\r\nfunction toggleScaleMode() {\r\n    if(!isSystemOn) return;\r\n    \r\n    scaleMode = scaleMode === 'lin' ? 'log' : 'lin';\r\n    let btn = document.getElementById('btn-scale-toggle');\r\n    \r\n    \/\/ A\u017euriranje indikatora u slideru (LIN \/ LOG)\r\n    \/\/ Dodajemo klasu 'active' onom koji je odabran\r\n    if (scaleMode === 'log') {\r\n        document.getElementById('lbl-log').classList.add('active');\r\n        document.getElementById('lbl-lin').classList.remove('active');\r\n        \r\n        \/\/ Gumb logika (nudi suprotno)\r\n        btn.innerText = \"LIN\";\r\n        btn.style.color = '#cbd5e1'; \r\n        btn.style.borderColor = '#0f172a';\r\n        \r\n        document.getElementById('ruler-lin').classList.remove('active');\r\n        document.getElementById('ruler-log').classList.add('active');\r\n    } else {\r\n        document.getElementById('lbl-log').classList.remove('active');\r\n        document.getElementById('lbl-lin').classList.add('active');\r\n        \r\n        \/\/ Gumb logika (nudi suprotno)\r\n        btn.innerText = \"LOG\";\r\n        btn.style.color = '#ef4444'; \r\n        btn.style.borderColor = '#ef4444';\r\n        \r\n        document.getElementById('ruler-log').classList.remove('active');\r\n        document.getElementById('ruler-lin').classList.add('active');\r\n    }\r\n    \r\n    updateSliderPos(currentFreq);\r\n}\r\n\r\nfunction magnetSlide(rawVal) {\r\n    if(!isSystemOn) return; \r\n    \r\n    \/\/ Reset gumba za sweep\r\n    document.querySelectorAll('.w-btn-sweep:not(#btn-sub-sweep)').forEach(b => b.classList.remove('active'));\r\n    \r\n    let sliderMax = 10000; \r\n    let v = 0; \r\n    let minF = 1;      \/\/ Mora biti 1 da odgovara log(1)=0\r\n    let maxF = 20000;  \/\/ Max frekvencija\r\n    \r\n    if (scaleMode === 'lin') { \r\n        \/\/ Linearna formula: jednostavan postotak\r\n        v = (rawVal \/ sliderMax) * maxF;\r\n    } else { \r\n        \/\/ Logaritamska formula\r\n        if (rawVal == 0) {\r\n            v = 0; \/\/ Poseban slu\u010daj za 0 na slideru\r\n        } else {\r\n            \/\/ Formula: Freq = Min * (Max\/Min)^(Slider%)\r\n            \/\/ Ovdje Min mora biti 1 da bi matematika odgovarala HTML skali\r\n            v = minF * Math.pow((maxF \/ minF), (rawVal \/ sliderMax)); \r\n        }\r\n    }\r\n\r\n    \/\/ Zaokru\u017eivanje\r\n    v = Math.round(v);\r\n    if (v > 20000) v = 20000;\r\n    \r\n    \/\/ --- VIZUALNA LOGIKA (To\u010dka i Warning) ---\r\n    let dot = document.getElementById('freq-dot');\r\n    let warn = document.getElementById('lbl-freq-warning');\r\n    \r\n    if (v <= 0) {\r\n        if(dot) dot.style.display = 'none';\r\n        if(warn) warn.style.display = 'block';\r\n    } else {\r\n        if(warn) warn.style.display = 'none';\r\n        if(dot) {\r\n            dot.style.display = 'block';\r\n            let ratio = rawVal \/ sliderMax; \r\n            let blinkFreq = 1 + (ratio * 9); \r\n            dot.style.animation = `dotPulse ${1\/blinkFreq}s infinite`;\r\n        }\r\n    }\r\n    \r\n    changeFreq(v, false); \/\/ false = ne a\u017euriraj slider ponovno da ne trza\r\n}\r\n\r\nfunction updateSliderPos(hz) {\r\n    let slider = document.getElementById('mag-slider');\r\n    let warnLabel = document.getElementById('lbl-freq-warning');\r\n    let dot = document.getElementById('freq-dot');\r\n    \r\n    let sliderMax = 10000; \r\n    let pos = 0; \r\n    let minF = 1; \r\n    let maxF = 20000;\r\n\r\n    if (hz <= 0) {\r\n        pos = 0;\r\n        if(warnLabel) warnLabel.style.display = 'block';\r\n        if(dot) dot.style.display = 'none';\r\n    } else {\r\n        if(warnLabel) warnLabel.style.display = 'none';\r\n        if(dot) {\r\n            dot.style.display = 'block';\r\n            \/\/ A\u017euriraj animaciju to\u010dke i kod ru\u010dnog unosa frekvencije\r\n            let tempPosForAnim = 0;\r\n            if (scaleMode === 'lin') tempPosForAnim = (hz \/ maxF) * sliderMax;\r\n            else {\r\n                let sHz = hz < 1 ? 1 : hz;\r\n                tempPosForAnim = (Math.log(sHz \/ minF) \/ Math.log(maxF \/ minF)) * sliderMax;\r\n            }\r\n            let ratio = tempPosForAnim \/ sliderMax;\r\n            if(ratio > 1) ratio = 1;\r\n            let blinkFreq = 1 + (ratio * 9);\r\n            dot.style.animation = `dotPulse ${1\/blinkFreq}s infinite`;\r\n        }\r\n\r\n        \/\/ --- GLAVNA FORMULA ZA POZICIJU ---\r\n        if (scaleMode === 'lin') { \r\n            pos = (hz \/ maxF) * sliderMax; \r\n        } else { \r\n            \/\/ Log inverzija: Position = Log(Freq) \/ Log(Max)\r\n            \/\/ Koristimo safeHz jer log(0) nije mogu\u0107\r\n            let safeHz = hz < 1 ? 1 : hz;\r\n            \/\/ Math.log ra\u010duna prirodni logaritam, ali omjer je isti kao log10\r\n            pos = (Math.log(safeHz \/ minF) \/ Math.log(maxF \/ minF)) * sliderMax; \r\n        }\r\n    }\r\n    \r\n    if(pos < 0) pos = 0; \r\n    if(pos > sliderMax) pos = sliderMax;\r\n    \r\n    \/\/ A\u017euriraj slider samo ako nije trenutno u fokusu (da ne prekidamo drag)\r\n    if(document.activeElement !== slider) {\r\n        slider.value = pos;\r\n    }\r\n}\r\n\r\nfunction changeFreq(val, updateSlider = true) {\r\n    let v = parseFloat(val); currentFreq = v;\r\n    if (updateSlider) updateSliderPos(v);\r\n    updateDisplay();\r\n    if (osc && !noise && activeModule === 'tone') { osc.frequency.setTargetAtTime(v, actx.currentTime, SMOOTHING); }\r\n}\r\n\r\nfunction stepIso(step) {\r\n    if(!isSystemOn) return;\r\n    isoIndex += step;\r\n    if(isoIndex < 0) isoIndex = 0; if(isoIndex >= isoFreqs.length) isoIndex = isoFreqs.length - 1;\r\n    let f = isoFreqs[isoIndex];\r\n    document.getElementById('iso-hz-val').innerText = formatHz(f);\r\n    if(isIsoPlaying()) {\r\n        changeFreq(f); \r\n        if (osc && !noise) osc.frequency.setTargetAtTime(f, actx.currentTime, SMOOTHING);\r\n    }\r\n}\r\n\r\nfunction updSubTrim(val) {\r\n    let db = parseFloat(val);\r\n    let dispDB = db === -12 ? \"-12.0\" : (db > 0 ? \"+\" + db.toFixed(1) : db.toFixed(1));\r\n    document.getElementById('sub-trim-val').innerText = dispDB + \" dB\";\r\n    subTrim = Math.pow(10, db \/ 20);\r\n    if (isSubPlaying() && isSignalOn && gain) gain.gain.setTargetAtTime(getActualVol(), actx.currentTime, 0.1);\r\n}\r\n\r\nfunction toggleSubDrive() {\r\n    if(!isSystemOn) return;\r\n    isSubDriveActive = !isSubDriveActive;\r\n    \r\n    const btn = document.getElementById('btn-sub-drive');\r\n    const status = document.getElementById('sub-status'); \/\/ Dohva\u0107amo, ali ne mijenjamo tekst\r\n    const driveMonitor = document.getElementById('drive-monitor'); \r\n\r\n    if (isSubDriveActive) {\r\n        btn.classList.add('active');\r\n        \r\n        \/\/ --- PROMJENA: VI\u0160E NE MIJENJAMO TEKST GORE LIJEVO ---\r\n        \/\/ Samo palimo upozorenje dolje desno\r\n        if(driveMonitor) driveMonitor.style.display = 'block';\r\n        \r\n    } else {\r\n        btn.classList.remove('active');\r\n        \r\n        \/\/ Ako je sub aktivan, osiguraj da je boja plava (resetiraj eventualno crvenilo)\r\n        if (isSubPlaying()) { \r\n             status.style.color = \"var(--neon-blue)\"; \r\n        } else {\r\n             status.style.color = \"#64748b\";\r\n        }\r\n        \r\n        \/\/ Gasi upozorenje dolje desno\r\n        if(driveMonitor) driveMonitor.style.display = 'none';\r\n    }\r\n    \r\n    if (isSubPlaying() && isSignalOn) startSound(); \r\n}\r\n\r\nfunction togglePhase() {\r\n    if(!isSystemOn) return;\r\n    phasePolarity *= -1;\r\n    const btn = document.getElementById('btn-sub-phase');\r\n    const invStatus = document.getElementById('sub-invert-status');\r\n    if(phasePolarity === -1) { btn.classList.add('active'); invStatus.style.display = 'block'; } \r\n    else { btn.classList.remove('active'); invStatus.style.display = 'none'; }\r\n    if(isSignalOn && gain) gain.gain.setTargetAtTime(getActualVol(), actx.currentTime, 0.05);\r\n}\r\n\r\nfunction stepSub(step) {\r\n    if(!isSystemOn) return; \r\n    let newVal = subFreq + step;\r\n    setSubHz(newVal); \/\/ Ovo sada poziva glavnu funkciju koja sve rje\u0161ava\r\n}\r\n\r\nfunction setSubHz(val) {\r\n    if(!isSystemOn) return;\r\n    subFreq = val;\r\n    \r\n    \/\/ Limiteri\r\n    if(subFreq < 0) subFreq = 0;\r\n    if(subFreq > 120) subFreq = 120;\r\n\r\n    \/\/ Tekstualni update\r\n    document.getElementById('sub-hz-val').innerText = subFreq + \" Hz\";\r\n    document.getElementById('kick-btn-val').innerText = subFreq;\r\n    \r\n    \/\/ VIZUALNI UPDATE KNOBA (Povezivanje komandi)\r\n    if(knobs.subFreq) {\r\n        knobs.subFreq.val = subFreq;\r\n        updateKnobVisual('subFreq');\r\n    }\r\n\r\n    \/\/ Audio update\r\n    if(isSubPlaying() && osc) {\r\n        osc.frequency.setTargetAtTime(subFreq, actx.currentTime, 0.05);\r\n        currentFreq = subFreq; updateDisplay();\r\n    }\r\n}\r\n\r\nfunction armSubSweep() {\r\n    if(!isSystemOn) return;\r\n    activeModule = 'sub-sweep-armed'; resetSignalButtons();\r\n    document.getElementById('status-text').innerText = \"LFE SWEEP\";\r\n    document.getElementById('status-text').style.color = \"#ef4444\";\r\n    document.getElementById('sub-status').innerText = \"LFE ARMED\";\r\n    document.getElementById('sub-status').style.color = \"var(--neon-blue)\";\r\n    document.getElementById('btn-sub-sweep').classList.add('active');\r\n    if (isNoise(curWave)) setWave('sine', document.getElementById('btn-sine'));\r\n    showToast(\"LFE ARMED\"); updateMasterButton(); \r\n}\r\n\r\nfunction runSubSweepLogic() {\r\n    switchModuleTo('sub-sweep-running');\r\n    let btn = document.getElementById('btn-sub-toggle');\r\n    btn.classList.remove('sub-ready'); btn.classList.add('sub-active'); btn.innerText = \"STOP\";\r\n    document.getElementById('sub-status').innerText = \"SWEEP RUNNING\";\r\n    \r\n    createOsc(); const now = actx.currentTime; osc.start(now);\r\n    \r\n    gain.gain.cancelScheduledValues(now); gain.gain.setValueAtTime(0, now);\r\n    gain.gain.linearRampToValueAtTime(getActualVol(), now + 0.1);\r\n    \r\n    let dur = 10; \/\/ Trajanje sweepa\r\n    \r\n    \/\/ START OD 0 Hz DO 120 Hz\r\n    osc.frequency.cancelScheduledValues(now); \r\n    osc.frequency.setValueAtTime(0, now); \r\n    osc.frequency.linearRampToValueAtTime(120, now + dur); \r\n    \r\n    let start = Date.now();\r\n    clearInterval(sweepTimer);\r\n    \r\n    sweepTimer = setInterval(() => {\r\n        let el = (Date.now() - start) \/ 1000;\r\n        \r\n        \/\/ --- POPRAVAK ZA 120 HZ ---\r\n        if (el >= dur) { \r\n            \/\/ Forsiraj prikaz 120Hz na samom kraju prije ga\u0161enja\r\n            setSubHz(120); \r\n            clearInterval(sweepTimer); \r\n            stopAllModules(); \r\n            return; \r\n        }\r\n        \r\n        let p = el\/dur;\r\n        let hz = 0 + (120 * p);\r\n        \r\n        \/\/ Osigura\u010d da ne prelazi 120 tijekom sweepa\r\n        if(hz > 120) hz = 120;\r\n        \r\n        subFreq = Math.round(hz); \r\n        \r\n        \/\/ Update ekrana i knoba\r\n        document.getElementById('sub-hz-val').innerText = subFreq + \" Hz\";\r\n        document.getElementById('kick-btn-val').innerText = subFreq;\r\n        \r\n        if(knobs.subFreq) {\r\n            knobs.subFreq.val = subFreq;\r\n            updateKnobVisual('subFreq');\r\n        }\r\n        \r\n        currentFreq = subFreq; \r\n        updateDisplay(); \r\n    }, 50);\r\n}\r\n\r\nfunction playSubKick() {\r\n    if(!isSystemOn || isTurningOff) return;\r\n    switchModuleTo('sub-kick'); curWave = 'sine'; createOsc(); const now = actx.currentTime;\r\n    osc.frequency.setValueAtTime(150, now); osc.frequency.exponentialRampToValueAtTime(subFreq, now + 0.25);\r\n    gain.gain.cancelScheduledValues(now); gain.gain.setValueAtTime(0, now);\r\n    let aVol = getActualVol();\r\n    gain.gain.linearRampToValueAtTime(aVol, now + 0.01);\r\n    gain.gain.setValueAtTime(aVol, now + 0.02);\r\n    gain.gain.linearRampToValueAtTime(0, now + 0.25);\r\n    osc.start(now); osc.stop(now + 0.5); \r\n    document.getElementById('status-text').innerText = \"KICK TEST\";\r\n    document.getElementById('status-text').style.color = \"#ef4444\";\r\n    document.getElementById('sub-status').innerText = \"LFE KICK\";\r\n    document.getElementById('sub-status').style.color = \"var(--neon-blue)\";\r\n    showToast(\"KICK \" + subFreq + \"Hz\"); updateMasterButton(); \r\n    clearTimeout(stopTimer); stopTimer = setTimeout(() => { stopAllModules(); }, 600);\r\n}\r\n\r\nfunction setWave(w, btn) {\r\n    if(!isSystemOn) return; curWave = w;\r\n    activeVoices.forEach(v => { if(v.osc && !isNoise(w)) v.osc.type = w; });\r\n    if (isNoise(w)) {\r\n        document.querySelectorAll('.w-btn-sweep:not(#btn-sub-sweep)').forEach(b => b.classList.remove('active'));\r\n        if(scaleMode !== 'lin') toggleScaleMode();\r\n    }\r\n    document.querySelectorAll('.w-btn').forEach(b => b.classList.remove('active'));\r\n    document.querySelectorAll('.noise-btn').forEach(b => b.classList.remove('active'));\r\n    btn.classList.add('active');\r\n    let label = w.toUpperCase();\r\n    if (isNoise(w)) label = label + \" N.\"; else if (w === 'sine') label = \"SIN\"; else if (w === 'square') label = \"SQR\"; else if (w === 'sawtooth') label = \"SAW\"; else if (w === 'triangle') label = \"TRI\";\r\n    showToast(label);\r\n    if (isSignalOn) {\r\n        if (activeModule === 'noise' && !isNoise(w)) toggleTone(); \r\n        else if (activeModule === 'tone' && isNoise(w)) toggleNoise();\r\n        else {\r\n            if (osc && !isNoise(w)) osc.type = w;\r\n            if (isNoise(w) && activeModule === 'noise') startSound();\r\n        }\r\n    }\r\n}\r\n\r\nfunction updPan(val) {\r\n    if (!pan) return;\r\n    pan.pan.setTargetAtTime(val, actx.currentTime, 0.1);\r\n    let p = parseFloat(val); document.getElementById('pan-slider').value = p; \r\n    let lPct = Math.round(50 + (p * -50)); let rPct = Math.round(50 + (p * 50));\r\n    document.getElementById('pan-l-val').innerText = lPct + \"%\";\r\n    document.getElementById('pan-r-val').innerText = rPct + \"%\";\r\n    let lLabel = document.querySelector('#btn-pan-l .pan-side-label');\r\n    let rLabel = document.querySelector('#btn-pan-r .pan-side-label');\r\n    if (p === -1) { lLabel.innerText = \"C\"; rLabel.innerText = \"R\"; } else if (p === 1) { lLabel.innerText = \"L\"; rLabel.innerText = \"C\"; } else { lLabel.innerText = \"L\"; rLabel.innerText = \"R\"; }\r\n}\r\n\r\nfunction panJump(side) {\r\n    const current = parseFloat(document.getElementById('pan-slider').value);\r\n    if (side === 'L') { if (current === -1) updPan(0); else updPan(-1); } \r\n    else if (side === 'R') { if (current === 1) updPan(0); else updPan(1); }\r\n}\r\n\r\nfunction updVol(val, force=false) {\r\n    let v = parseFloat(val);\r\n    const targets = [0.25, 0.50, 0.75, 1.0]; const threshold = 0.025; \r\n    for(let t of targets) { if(Math.abs(v - t) < threshold) { v = t; document.getElementById('vol-slider').value = v; break; } }\r\n    if (v > 0.5 && !highGainConfirmed && !force) {\r\n        pendingVol = v; document.getElementById('vol-slider').value = 0.5;\r\n        document.getElementById('safety-modal').style.display = 'flex'; return;\r\n    }\r\n    safeVol = v; if (gain) gain.gain.setTargetAtTime(getActualVol(), actx.currentTime, 0.1);\r\n}\r\n\r\nfunction toggleRuler(mode) {\r\n    document.querySelectorAll('.scale-ruler').forEach(r => r.classList.remove('active'));\r\n    if (mode === 'log') document.getElementById('ruler-log').classList.add('active');\r\n    else document.getElementById('ruler-lin').classList.add('active');\r\n}\r\n\r\nfunction armSweep(mode, btn) {\r\n    if(!isSystemOn) return; selectedSweepMode = mode; \r\n    if (mode === 'lin' && scaleMode !== 'lin') toggleScaleMode();\r\n    if (mode === 'log' && scaleMode !== 'log') toggleScaleMode();\r\n    document.querySelectorAll('.w-btn-sweep:not(#btn-sub-sweep)').forEach(b => b.classList.remove('active'));\r\n    btn.classList.add('active');\r\n    if (isNoise(curWave)) setWave('sine', document.getElementById('btn-sine'));\r\n    showToast(mode === 'lin' ? \"LIN S.\" : \"LOG S.\");\r\n    if(activeModule === 'sweep') runSweepLogic(mode);\r\n}\r\n\r\nfunction runSweepLogic(mode) {\r\n    switchModuleTo('sweep'); \r\n    let btn = document.getElementById('btn-sweep-toggle');\r\n    btn.classList.remove('sub-ready'); btn.classList.add('sub-active'); btn.innerText = \"STOP\";\r\n    document.getElementById('status-text').innerText = \"SWEEP LIVE\";\r\n    document.getElementById('status-text').style.color = \"#ef4444\";\r\n    killCurrentAudio(); createOsc(); const now = actx.currentTime; osc.start(now);\r\n    gain.gain.cancelScheduledValues(now); gain.gain.setValueAtTime(0, now);\r\n    gain.gain.linearRampToValueAtTime(getActualVol(), now + 0.1); \r\n    sweepMode = mode === 'lin' ? 'LIN' : 'LOG';\r\n    let dur = mode === 'lin' ? 10 : 20;\r\n    osc.frequency.cancelScheduledValues(now); osc.frequency.setValueAtTime(20, now);\r\n    if (mode === 'log') osc.frequency.exponentialRampToValueAtTime(20000, now + dur);\r\n    else osc.frequency.linearRampToValueAtTime(20000, now + dur);\r\n    updateMasterButton(); \r\n    let start = Date.now();\r\n    clearInterval(sweepTimer);\r\n    sweepTimer = setInterval(() => {\r\n        let el = (Date.now() - start) \/ 1000;\r\n        if (el >= dur) { clearInterval(sweepTimer); stopAllModules(); return; }\r\n        let p = el\/dur;\r\n        let hz = mode === 'log' ? 20 * Math.pow(1000, p) : 20 + (19980*p);\r\n        if(hz > 20000) hz = 20000;\r\n        changeFreq(Math.round(hz));\r\n    }, 50);\r\n}\r\n\r\nfunction stepOctave(step) {\r\n        if(!isSystemOn) return; currentOctave += step;\r\n        if(currentOctave < 0) currentOctave = 0; if(currentOctave > 9) currentOctave = 9;\r\n        updateMusicalDisplay();\r\n}\r\n\r\nconst noteNames = [\"C\", \"C#\", \"D\", \"D#\", \"E\", \"F\", \"F#\", \"G\", \"G#\", \"A\", \"A#\", \"B\"];\r\nfunction updateMusicalDisplay(noteIndex = -1) {\r\n    document.getElementById('mus-disp-oct').innerText = \"OCT \" + currentOctave;\r\n    if(noteIndex === -1) {\r\n        document.getElementById('mus-disp-note').innerText = \"READY\";\r\n        document.getElementById('mus-disp-freq').innerText = \"0 Hz\";\r\n    } else {\r\n        let nName = noteNames[noteIndex];\r\n        document.getElementById('mus-disp-note').innerText = nName + currentOctave;\r\n        let baseNote = (currentOctave * 12) + 12; \r\n        let midiNote = baseNote + noteIndex;\r\n        let freq = concertPitch * Math.pow(2, (midiNote - 69) \/ 12);\r\n        document.getElementById('mus-disp-freq').innerText = formatHz(freq);\r\n    }\r\n}\r\n\r\nfunction updateTuning(val) { concertPitch = parseInt(val); document.getElementById('tuning-disp').innerText = concertPitch; }\r\n\r\nfunction updADSR(param, val) {\r\n    let v = parseFloat(val); adsr[param] = v;\r\n    if(param === 'a') document.getElementById('val-att').innerText = v + \"s\";\r\n    if(param === 'd') document.getElementById('val-dec').innerText = v + \"s\";\r\n    if(param === 's') document.getElementById('val-sus').innerText = Math.round(v * 100) + \"%\";\r\n    if(param === 'r') document.getElementById('val-rel').innerText = v + \"s\";\r\n}\r\n\r\nfunction playPolyNote(freq) {\r\n    if(!isSystemOn || isTurningOff) return;\r\n    isSignalOn = true; activeModule = 'piano';\r\n    document.getElementById('status-text').innerText = \"POLY SYNTH\";\r\n    document.getElementById('status-text').style.color = \"#ef4444\"; \r\n    const now = actx.currentTime; let gateTime = knobs.gate.val; \r\n    let vOsc = actx.createOscillator(); let vGain = actx.createGain();\r\n    if (isNoise(curWave)) vOsc.type = 'sawtooth'; else vOsc.type = curWave;\r\n    vOsc.frequency.value = freq;\r\n    vOsc.connect(vGain); vGain.connect(gain); \r\n    gain.gain.cancelScheduledValues(now); gain.gain.setValueAtTime(getActualVol(), now);\r\n    vGain.gain.setValueAtTime(0, now);\r\n    let peakGain = 0.5; let susLevel = peakGain * adsr.s;\r\n    vGain.gain.linearRampToValueAtTime(peakGain, now + adsr.a);\r\n    vGain.gain.linearRampToValueAtTime(susLevel, now + adsr.a + adsr.d);\r\n    vGain.gain.setValueAtTime(susLevel, now + gateTime);\r\n    vGain.gain.exponentialRampToValueAtTime(0.001, now + gateTime + adsr.r);\r\n    vGain.gain.linearRampToValueAtTime(0, now + gateTime + adsr.r + 0.05);\r\n    vOsc.start(now); vOsc.stop(now + gateTime + adsr.r + 0.1); \r\n    let voice = { osc: vOsc, gain: vGain }; activeVoices.push(voice);\r\n    setTimeout(() => {\r\n        let index = activeVoices.indexOf(voice);\r\n        if (index > -1) { activeVoices.splice(index, 1); }\r\n        if (activeVoices.length === 0) { changeFreq(0); }\r\n    }, (gateTime + adsr.r + 0.2) * 1000);\r\n    updateMasterButton();\r\n}\r\n\r\nfunction playNote(noteIndex) {\r\n    if(!isSystemOn || isTurningOff) return; \r\n    updateMusicalDisplay(noteIndex);\r\n    let baseNote = (currentOctave * 12) + 12; \r\n    let midiNote = baseNote + noteIndex;\r\n    let freq = concertPitch * Math.pow(2, (midiNote - 69) \/ 12);\r\n    currentFreq = freq; updateSliderPos(currentFreq); updateDisplay();\r\n    playPolyNote(freq);\r\n}\r\n\r\nfunction confirmSafe() { highGainConfirmed = true; document.getElementById('safety-modal').style.display = 'none'; updVol(pendingVol, true); }\r\nfunction cancelSafe() { highGainConfirmed = false; document.getElementById('safety-modal').style.display = 'none'; updVol(0.5, true); }\r\n\r\nfunction openHelp() { document.getElementById('help-modal').style.display = 'flex'; }\r\nfunction closeHelp() { document.getElementById('help-modal').style.display = 'none'; }\r\n\r\nfunction scrollToSection(id, btn) {\r\n    const el = document.getElementById(id);\r\n    const container = document.getElementById('help-content-area');\r\n    if(el && container) container.scrollTo({ top: el.offsetTop, behavior: 'smooth' });\r\n    const allBtns = document.querySelectorAll('.menu-item');\r\n    allBtns.forEach(b => b.classList.remove('active'));\r\n    if(btn) btn.classList.add('active');\r\n}\r\n\r\nfunction drawSnow(ctx, w, h, progress) {\r\n    ctx.fillStyle = \"#050a0f\"; ctx.fillRect(0,0,w,h);\r\n    ctx.shadowBlur = 5; ctx.shadowColor = \"rgba(200, 220, 255, 0.8)\";\r\n    for(let i=0; i<4000; i++) {\r\n        let x = Math.floor(Math.random() * w); let y = Math.floor(Math.random() * h); \r\n        let r = Math.random();\r\n        let rC = r > 0.8 ? 255 : (r > 0.4 ? 160 : 80);\r\n        let gC = r > 0.8 ? 255 : (r > 0.4 ? 170 : 90);\r\n        let bC = r > 0.8 ? 255 : (r > 0.4 ? 180 : 100);\r\n        ctx.fillStyle = `rgb(${rC},${gC},${bC})`; ctx.fillRect(x, y, 1.5, 1.5);\r\n    }\r\n    ctx.shadowBlur = 0;\r\n    let easeOut = progress * progress; \r\n    ctx.fillStyle = `rgba(0, 0, 0, ${easeOut})`; ctx.fillRect(0,0,w,h);\r\n}\r\n\r\nfunction drawSubScope(data) {\r\n    let cvs = document.getElementById('sub-scope-canvas');\r\n    let ctx = cvs.getContext('2d');\r\n    let w = cvs.width = cvs.clientWidth; let h = cvs.height = cvs.clientHeight;\r\n    ctx.clearRect(0,0,w,h);\r\n    if(!isSubPlaying()) {\r\n        ctx.lineWidth = 2; ctx.strokeStyle = '#38bdf8'; ctx.beginPath(); ctx.moveTo(0, h\/2); ctx.lineTo(w, h\/2); ctx.stroke(); return;\r\n    }\r\n    ctx.lineWidth = 2; ctx.strokeStyle = '#38bdf8'; ctx.beginPath();\r\n    let slice = w * 1.0 \/ data.length; let x = 0;\r\n    for(let i=0; i<data.length; i++) {\r\n        let v = data[i]\/128.0; let y = v * (h\/2); \r\n        if(i===0) ctx.moveTo(x,y); else ctx.lineTo(x,y); x += slice;\r\n    }\r\n    ctx.stroke();\r\n}\r\n\r\nfunction drawIsoAnalyzer() {\r\n    let cvs = document.getElementById('iso-analyzer-canvas');\r\n    if (!cvs || !actx) return;\r\n    let ctx = cvs.getContext('2d');\r\n    let w = cvs.width = cvs.clientWidth; let h = cvs.height = cvs.clientHeight;\r\n    ctx.clearRect(0, 0, w, h);\r\n    if (!isSystemOn) return;\r\n    let textH = 15; let graphH = h - textH;\r\n    ctx.strokeStyle = \"rgba(56, 189, 248, 0.1)\"; ctx.lineWidth = 1; ctx.beginPath();\r\n    ctx.moveTo(0, graphH * 0.25); ctx.lineTo(w, graphH * 0.25);\r\n    ctx.moveTo(0, graphH * 0.50); ctx.lineTo(w, graphH * 0.50);\r\n    ctx.moveTo(0, graphH * 0.75); ctx.lineTo(w, graphH * 0.75);\r\n    ctx.stroke();\r\n    let numBands = 72; let barW = (w \/ numBands) - 1; \r\n    if (!rtaData || !anal) return;\r\n    if (isSignalOn && (currentFreq > 0 || isSubPlaying() || isIsoPlaying() || isNoise(curWave) || activeVoices.length > 0)) {\r\n        anal.getByteFrequencyData(rtaData);\r\n    } else { for(let i=0; i<rtaData.length; i++) rtaData[i] = 0; }\r\n    let minLog = Math.log10(20); let maxLog = Math.log10(20000); let nyquist = actx.sampleRate \/ 2;\r\n    ctx.shadowBlur = 6; ctx.shadowColor = \"rgba(56, 189, 248, 0.8)\"; ctx.fillStyle = \"#38bdf8\"; \r\n    for(let i = 0; i < numBands; i++) {\r\n        let fStart = Math.pow(10, minLog + (i \/ numBands) * (maxLog - minLog));\r\n        let fEnd = Math.pow(10, minLog + ((i + 1) \/ numBands) * (maxLog - minLog));\r\n        let binStart = Math.floor((fStart \/ nyquist) * rtaData.length);\r\n        let binEnd = Math.floor((fEnd \/ nyquist) * rtaData.length);\r\n        if (binEnd <= binStart) binEnd = binStart + 1;\r\n        let maxVal = 0;\r\n        for(let b = binStart; b < binEnd && b < rtaData.length; b++) if(rtaData[b] > maxVal) maxVal = rtaData[b];\r\n        let valNorm = maxVal \/ 255.0; \r\n        let barH = Math.pow(valNorm, 1.2) * (graphH - 2); \r\n        if (barH < 2 && isSystemOn) barH = 2; \r\n        ctx.fillRect(i * (w \/ numBands), graphH - barH, barW, barH);\r\n    }\r\n    ctx.shadowBlur = 0;\r\n    ctx.fillStyle = \"#64748b\"; ctx.font = \"bold 8px monospace\"; ctx.textAlign = \"center\"; ctx.textBaseline = \"top\";\r\n    const labels = [20, 50, 100, 200, 500, 1000, 2000, 5000, 10000, 20000];\r\n    labels.forEach(freq => {\r\n        let p = (Math.log10(freq) - minLog) \/ (maxLog - minLog); let x = p * w;\r\n        let txt = freq >= 1000 ? (freq\/1000) + 'k' : freq;\r\n        if(x < 10) x = 10; if(x > w - 10) x = w - 10;\r\n        ctx.fillText(txt, x, graphH + 4);\r\n    });\r\n}\r\n\r\nfunction loopVis() {\r\n    requestAnimationFrame(loopVis);\r\n    let cvs = document.getElementById('scope'); let ctx = cvs.getContext('2d');\r\n    let w = cvs.width = cvs.clientWidth; let h = cvs.height = cvs.clientHeight;\r\n    if (isTurningOff) { \r\n        let p = (Date.now() - offStartTime) \/ 3000; if (p > 1) p = 1;\r\n        drawSnow(ctx, w, h, p); drawIsoAnalyzer(); return; \r\n    }\r\n    ctx.clearRect(0,0,w,h); \r\n    if (!isSystemOn) { ctx.fillStyle = '#000'; ctx.fillRect(0,0,w,h); drawIsoAnalyzer(); return; }\r\n    drawGrid(ctx, w, h);\r\n    let data = new Uint8Array(anal.fftSize);\r\n    if (isSignalOn && (currentFreq > 0 || isNoise(curWave) || isSubPlaying() || activeVoices.length > 0)) {\r\n        anal.getByteTimeDomainData(data);\r\n    } else { for(let i=0; i<data.length; i++) data[i] = 128; }\r\n    drawSubScope(data); drawIsoAnalyzer();\r\n    ctx.lineWidth = 3; ctx.strokeStyle = '#0f172a'; ctx.beginPath();\r\n    let slice = w * 1.0 \/ data.length; let x = 0;\r\n    for(let i=0; i<data.length; i++) {\r\n        let v = data[i]\/128.0; let y = v * (h\/2); y = (y * 0.8) + (h * 0.1); \r\n        if(i===0) ctx.moveTo(x,y); else ctx.lineTo(x,y); x += slice;\r\n    }\r\n    ctx.stroke();\r\n    drawKnob(ctx, 30, 35, 15); \r\n    ctx.font = \"bold 16px Orbitron\"; ctx.textAlign = \"left\"; ctx.fillStyle = \"#0f172a\";\r\n    ctx.shadowBlur = 1.5; ctx.shadowColor = \"rgba(15, 23, 42, 0.4)\"; \r\n    let volVal = parseFloat(document.getElementById('vol-slider').value);\r\n    let dispDB = \"-\u221e\";\r\n    if(Math.abs(volVal - 0.25) < 0.01) dispDB = \"-12.0\";\r\n    else if(Math.abs(volVal - 0.50) < 0.01) dispDB = \"-6.0\";\r\n    else if(Math.abs(volVal - 0.75) < 0.01) dispDB = \"-3.0\";\r\n    else if(Math.abs(volVal - 1.0) < 0.01) dispDB = \"0.0\";\r\n    else if(volVal > 0.01) { let db = 20 * Math.log10(volVal); dispDB = db.toFixed(1); }\r\n    ctx.fillText(dispDB + \" dB\", 60, 40); \r\n    drawStatusBar(ctx, w, h);\r\n    ctx.shadowBlur = 0; \r\n    if(startupVuLevel > 0) {\r\n        updateLEDs(startupVuLevel * LED_COUNT); startupVuLevel -= 0.02;\r\n        if(startupVuLevel < 0) startupVuLevel = 0;\r\n    } else if(isSignalOn && (currentFreq > 0 || isNoise(curWave) || isSubPlaying() || isIsoPlaying() || activeVoices.length > 0)) {\r\n        let sum=0; for(let i=0; i<data.length; i++) { let z=(data[i]-128)\/128; sum+=z*z; }\r\n        let jitter = (Math.random() - 0.5) * 0.05;\r\n        let gainVol = parseFloat(document.getElementById('vol-slider').value);\r\n        let signalStrength = gainVol + jitter;\r\n        if(signalStrength < 0) signalStrength = 0; if(signalStrength > 1) signalStrength = 1;\r\n        let baseLevel = Math.floor(signalStrength * LED_COUNT);\r\n        let pVal = parseFloat(document.getElementById('pan-slider').value);\r\n        let lMod = pVal < 0 ? 1 : 1 - pVal; let rMod = pVal > 0 ? 1 : 1 + pVal;\r\n        updateLEDs(baseLevel, lMod, rMod);\r\n    } else { updateLEDs(0); }\r\n}\r\n\r\nfunction drawGrid(ctx, w, h) {\r\n    ctx.lineWidth = 1; ctx.strokeStyle = 'rgba(255, 255, 255, 0.4)'; ctx.setLineDash([]); ctx.beginPath();\r\n    for (let x = 0; x <= w; x += 40) { ctx.moveTo(x, 0); ctx.lineTo(x, h); }\r\n    for (let y = 0; y <= h; y += 40) { ctx.moveTo(0, y); ctx.lineTo(w, y); }\r\n    ctx.stroke();\r\n    let centerY = (h * 0.15) + (h\/2 * 0.7); let scaleH = (h\/2 * 0.7);\r\n    ctx.strokeStyle = 'rgba(255, 255, 255, 0.8)'; ctx.lineWidth = 2; ctx.beginPath(); ctx.moveTo(0, centerY); ctx.lineTo(w, centerY); ctx.stroke();\r\n    ctx.lineWidth = 1; ctx.strokeStyle = 'rgba(255, 255, 255, 0.6)'; ctx.setLineDash([4, 4]); \r\n    let y3_top = centerY - (scaleH * 0.75); let y3_bot = centerY + (scaleH * 0.75);\r\n    ctx.moveTo(0, y3_top); ctx.lineTo(w, y3_top); ctx.moveTo(0, y3_bot); ctx.lineTo(w, y3_bot); ctx.stroke();\r\n    let y6_top = centerY - (scaleH * 0.50); let y6_bot = centerY + (scaleH * 0.50);\r\n    ctx.moveTo(0, y6_top); ctx.lineTo(w, y6_top); ctx.moveTo(0, y6_bot); ctx.lineTo(w, y6_bot); ctx.stroke();\r\n    let y12_top = centerY - (scaleH * 0.25); let y12_bot = centerY + (scaleH * 0.25);\r\n    ctx.moveTo(0, y12_top); ctx.lineTo(w, y12_top); ctx.moveTo(0, y12_bot); ctx.lineTo(w, y12_bot); ctx.stroke();\r\n    ctx.setLineDash([]);\r\n}\r\n\r\nfunction drawKnob(ctx, x, y, r) {\r\n    let pVal = parseFloat(document.getElementById('pan-slider').value);\r\n    let angle = pVal * (Math.PI * 0.75) - (Math.PI \/ 2); \r\n    ctx.font = \"8px Orbitron\"; ctx.textAlign = \"center\"; ctx.fillStyle = \"#0f172a\";\r\n    ctx.fillText(\"C\", x, y - r - 5);\r\n    ctx.beginPath(); ctx.arc(x, y, r, 0, 2 * Math.PI); ctx.lineWidth = 2; ctx.strokeStyle = '#0f172a'; ctx.stroke();\r\n    ctx.beginPath(); ctx.moveTo(x, y); ctx.lineTo(x + Math.cos(angle) * r, y + Math.sin(angle) * r); ctx.stroke();\r\n}\r\n\r\nfunction drawStatusBar(ctx, w, h) {\r\n    let labels = ['SINE', 'SQR', 'SAW', 'TRI', 'WHITE', 'PINK', 'BLUE', 'GREY', 'RED', 'LIN', 'LOG'];\r\n    let boxW = 26; let boxH = 12; let gap = 2; let startX = 20; let startY = h - 20; \r\n    let totalW = (labels.length * boxW) + ((labels.length - 1) * gap); startX = (w - totalW) \/ 2;\r\n    ctx.font = \"bold 7px 'Segoe UI'\"; ctx.textAlign = \"center\"; ctx.textBaseline = \"middle\";\r\n    labels.forEach((lbl, i) => {\r\n        let bx = startX + (i * (boxW + gap));\r\n        let isActive = false;\r\n        if (curWave.toUpperCase() === lbl) isActive = true;\r\n        if (curWave === 'sawtooth' && lbl === 'SAW') isActive = true;\r\n        if (curWave === 'square' && lbl === 'SQR') isActive = true;\r\n        if (curWave === 'triangle' && lbl === 'TRI') isActive = true;\r\n        if (isNoise(curWave) && curWave.toUpperCase() === lbl) isActive = true;\r\n        if(lbl === 'LIN' && selectedSweepMode === 'lin') isActive = true;\r\n        if(lbl === 'LOG' && selectedSweepMode === 'log') isActive = true;\r\n        ctx.fillStyle = isActive ? 'rgba(15, 23, 42, 0.1)' : 'rgba(255, 255, 255, 0.1)';\r\n        ctx.fillRect(bx, startY, boxW, boxH);\r\n        ctx.strokeStyle = '#0f172a'; ctx.lineWidth = 1; ctx.strokeRect(bx, startY, boxW, boxH);\r\n        ctx.fillStyle = isActive ? '#0f172a' : 'rgba(15, 23, 42, 0.4)'; ctx.fillText(lbl, bx + (boxW\/2), startY + (boxH\/2));\r\n    });\r\n}\r\n\r\nfunction updateLEDs(level, lMod = 1, rMod = 1) {\r\n    const lLeds = document.getElementById('meter-l-strip').children;\r\n    const rLeds = document.getElementById('meter-r-strip').children;\r\n    let lLevel = Math.floor(level * lMod); let rLevel = Math.floor(level * rMod);\r\n    for (let i = 0; i < LED_COUNT; i++) {\r\n        let color = 'green';\r\n        if(i >= 14) color = 'yellow'; if(i >= 17) color = 'red';    \r\n        let l = lLeds[i]; l.className = 'led-seg'; \r\n        if (i < lLevel) l.classList.add('on-' + color); else l.classList.remove('on-green', 'on-yellow', 'on-red');\r\n        let r = rLeds[i]; r.className = 'led-seg'; \r\n        if (i < rLevel) r.classList.add('on-' + color); else r.classList.remove('on-green', 'on-yellow', 'on-red');\r\n    }\r\n}\r\nfunction initKnobs() {\r\n    \/\/ Dodali smo 'subFreq' u listu ID-ova\r\n    ['att', 'dec', 'sus', 'rel', 'gate', 'tune', 'subFreq'].forEach(id => {\r\n        let el = document.getElementById('knob-' + id);\r\n        if(el) { \/\/ Provjera da element postoji\r\n            el.addEventListener('mousedown', (e) => startKnobDrag(e, id));\r\n            el.addEventListener('touchstart', (e) => {\r\n                e.preventDefault(); \r\n                openKnobPopup(id);  \r\n            }, {passive: false});\r\n            updateKnobVisual(id);\r\n        }\r\n    });\r\n}\r\nfunction handleKnobMove(e) {\r\n    if (!currentDragKnob) return;\r\n    let id = currentDragKnob;\r\n    let conf = knobs[id];\r\n    let delta = (knobStartY - e.clientY);\r\n    let range = conf.max - conf.min;\r\n    \r\n    \/\/ Smanjio sam osjetljivost (djelitelj 200) za precizniju kontrolu\r\n    let change = (delta \/ 200) * range; \r\n    let newVal = knobStartVal + change;\r\n    \r\n    if(newVal < conf.min) newVal = conf.min;\r\n    if(newVal > conf.max) newVal = conf.max;\r\n    \r\n    \/\/ Magnet\/Step logika\r\n    newVal = Math.round(newVal \/ conf.step) * conf.step;\r\n    \r\n    knobs[id].val = newVal;\r\n    \r\n    \/\/ --- OVDJE JE BILA GRE\u0160KA (nedostajao je subFreq) ---\r\n    if (['a','d','s','r'].includes(conf.param)) adsr[conf.param] = newVal;\r\n    else if (conf.param === 'tune') concertPitch = parseInt(newVal);\r\n    else if (conf.param === 'subFreq') {\r\n        \/\/ Pozivamo funkciju za promjenu frekvencije subwoofera\r\n        setSubHz(newVal);\r\n    }\r\n    \r\n    updateKnobVisual(id);\r\n}\r\nfunction setSubHz(val) {\r\n    if(!isSystemOn) return;\r\n    subFreq = val;\r\n    \r\n    \/\/ Limiteri\r\n    if(subFreq < 0) subFreq = 0;\r\n    if(subFreq > 120) subFreq = 120;\r\n\r\n    document.getElementById('sub-hz-val').innerText = subFreq + \" Hz\";\r\n    document.getElementById('kick-btn-val').innerText = subFreq;\r\n    \r\n    \/\/ --- NOVO: A\u017euriraj vizualnu poziciju knoba ---\r\n    if(knobs.subFreq) {\r\n        knobs.subFreq.val = subFreq;\r\n        updateKnobVisual('subFreq');\r\n    }\r\n\r\n    if(isSubPlaying() && osc) {\r\n        osc.frequency.setTargetAtTime(subFreq, actx.currentTime, 0.05);\r\n        currentFreq = subFreq; updateDisplay();\r\n    }\r\n}\r\n<\/script>\r\n\r\n<\/body>\r\n<\/html>\n\t\t<\/div>\n\t<\/div>\n<div class=\"vc_empty_space  height_large\"   style=\"height: 32px\"><span class=\"vc_empty_space_inner\"><\/span><\/div><div class=\"vc_btn3-container vc_btn3-center vc_do_btn\" ><a class=\"vc_general vc_btn3 vc_btn3-size-md vc_btn3-shape-square vc_btn3-style-outline vc_btn3-color-inverse\" href=\"\/master\" title=\"\">MENU<\/a><\/div><\/div><\/div><\/div><\/div>\n<\/div>","protected":false},"excerpt":{"rendered":"Sonic Lab v1.10 - Modular ? PARAMETER 50% DONE \u26a0\ufe0f HIGH GAIN WARNING Pushing volume above -6dB (50%) can damage equipment.Are you sure? CANCEL PROCEED SONIC LAB MANUAL V1.10 \u2715 01. Intro 02. Master I\/O 03. Oscillators 04. Noise Gen 05. Freq Sweep 06. Musical 07. ISO & RTA 08. LFE Matrix 01. ENGINE ARCHITECTURE (32-BIT FLOAT) Sonic Lab v1.10&hellip;","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"_price":"","_stock":"","_tribe_ticket_header":"","_tribe_default_ticket_provider":"TEC\\Tickets\\Commerce\\Module","_tribe_ticket_capacity":"0","_ticket_start_date":"","_ticket_end_date":"","_tribe_ticket_show_description":"","_tribe_ticket_show_not_going":false,"_tribe_ticket_use_global_stock":"","_tribe_ticket_global_stock_level":"","_global_stock_mode":"","_global_stock_cap":"","_tribe_rsvp_for_event":"","_tribe_ticket_going_count":"","_tribe_ticket_not_going_count":"","_tribe_tickets_list":"[]","_tribe_ticket_has_attendee_info_fields":false,"footnotes":"","_tec_slr_enabled":"","_tec_slr_layout":""},"class_list":["post-3149","page","type-page","status-publish","hentry"],"a3_pvc":{"activated":false,"total_views":0,"today_views":0},"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v24.6 (Yoast SEO v27.6) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>M-13 | papaya.events<\/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:\/\/www.papaya.events\/hr\/majstor-13\/\" \/>\n<meta property=\"og:locale\" content=\"hr_HR\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"M-13\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.papaya.events\/hr\/majstor-13\/\" \/>\n<meta property=\"og:site_name\" content=\"papaya.events\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/papaya.events.ls\" \/>\n<meta property=\"article:modified_time\" content=\"2026-02-17T02:26:07+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/cdn.papaya.events\/wp-content\/uploads\/2025\/02\/176-1-scaled.jpg?strip=all&quality=70&webp=65&sharp=1\" \/>\n\t<meta property=\"og:image:width\" content=\"2560\" \/>\n\t<meta property=\"og:image:height\" content=\"1695\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Procijenjeno vrijeme \u010ditanja\" \/>\n\t<meta name=\"twitter:data1\" content=\"1 minuta\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.papaya.events\\\/master-13\\\/\",\"url\":\"https:\\\/\\\/www.papaya.events\\\/master-13\\\/\",\"name\":\"M-13 | papaya.events\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.papaya.events\\\/#website\"},\"datePublished\":\"2026-02-08T17:19:06+00:00\",\"dateModified\":\"2026-02-17T02:26:07+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.papaya.events\\\/master-13\\\/#breadcrumb\"},\"inLanguage\":\"hr\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.papaya.events\\\/master-13\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.papaya.events\\\/master-13\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.papaya.events\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"M-13\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.papaya.events\\\/#website\",\"url\":\"https:\\\/\\\/www.papaya.events\\\/\",\"name\":\"papaya.events\",\"description\":\"Book the ultimate party event\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.papaya.events\\\/#organization\"},\"alternateName\":\"Unrivaled sounds, unforgettable light and FX for your events!\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.papaya.events\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"hr\"},{\"@type\":[\"Organization\",\"Place\",\"LocalBusiness\"],\"@id\":\"https:\\\/\\\/www.papaya.events\\\/#organization\",\"name\":\"papaya.events\",\"alternateName\":\"Unrivaled sounds, unforgettable light and FX for your events!\",\"url\":\"https:\\\/\\\/www.papaya.events\\\/\",\"logo\":{\"@id\":\"https:\\\/\\\/www.papaya.events\\\/master-13\\\/#local-main-organization-logo\"},\"image\":{\"@id\":\"https:\\\/\\\/www.papaya.events\\\/master-13\\\/#local-main-organization-logo\"},\"sameAs\":[\"https:\\\/\\\/www.facebook.com\\\/papaya.events.ls\",\"https:\\\/\\\/soundcloud.com\\\/papaya_events\",\"https:\\\/\\\/www.beatport.com\\\/artist\\\/drama\\\/170702\",\"https:\\\/\\\/www.youtube.com\\\/@papaya.events\",\"https:\\\/\\\/open.spotify.com\\\/user\\\/31m3wahhbsmph36a35fmzv45y344\",\"https:\\\/\\\/www.instagram.com\\\/papaya.events.ls\"],\"description\":\"Papaya Events is an event organization based in Umag, Croatia, run by three artists, specializing in open-air and club events that bring together music lovers through electronic sounds and an engaging atmosphere. The organization provides a complete experience, including its own production, sound, lighting, scene effects, and all essential elements for creating unforgettable moments. Their events range from intimate, small private parties to larger open-air gatherings, offering a diverse range of electronic music to suit every taste and setting. The focus is on crafting unforgettable experiences that leave lasting memories for all music enthusiasts and partygoers.\",\"legalName\":\"V.I.S.T.A. Ltd.\",\"foundingDate\":\"2006-04-07\",\"numberOfEmployees\":{\"@type\":\"QuantitativeValue\",\"minValue\":\"1\",\"maxValue\":\"10\"},\"publishingPrinciples\":\"https:\\\/\\\/www.papaya.events\\\/our-services\\\/\",\"ownershipFundingInfo\":\"https:\\\/\\\/www.papaya.events\\\/our-services\\\/\",\"address\":{\"@id\":\"https:\\\/\\\/www.papaya.events\\\/master-13\\\/#local-main-place-address\"},\"geo\":{\"@type\":\"GeoCoordinates\",\"latitude\":\"45.430166630509255\",\"longitude\":\"13.529640133684602\"},\"telephone\":[\"+385915127282\"],\"contactPoint\":{\"@type\":\"ContactPoint\",\"telephone\":\"+385915127282\",\"email\":\"info@papaya.events\"},\"openingHoursSpecification\":{\"@type\":\"OpeningHoursSpecification\",\"dayOfWeek\":[\"Monday\",\"Tuesday\",\"Wednesday\",\"Thursday\",\"Friday\",\"Saturday\",\"Sunday\"],\"opens\":\"00:00\",\"closes\":\"23:59\"},\"email\":\"info@papaya.events\",\"vatID\":\"HR93447560687\",\"priceRange\":\"$$$\"},{\"@type\":\"PostalAddress\",\"@id\":\"https:\\\/\\\/www.papaya.events\\\/master-13\\\/#local-main-place-address\",\"streetAddress\":\"Vladimir Nazor 5\",\"addressLocality\":\"Umag\",\"postalCode\":\"52470\",\"addressRegion\":\"Croatia\",\"addressCountry\":\"HR\"},{\"@type\":\"ImageObject\",\"inLanguage\":\"hr\",\"@id\":\"https:\\\/\\\/www.papaya.events\\\/master-13\\\/#local-main-organization-logo\",\"url\":\"https:\\\/\\\/cdn.papaya.events\\\/wp-content\\\/uploads\\\/2025\\\/02\\\/favicon-copy.png?strip=all&quality=70&webp=65&sharp=1\",\"contentUrl\":\"https:\\\/\\\/cdn.papaya.events\\\/wp-content\\\/uploads\\\/2025\\\/02\\\/favicon-copy.png?strip=all&quality=70&webp=65&sharp=1\",\"width\":1024,\"height\":1024,\"caption\":\"papaya.events\"}]}<\/script>\n<meta name=\"geo.placename\" content=\"Umag\" \/>\n<meta name=\"geo.position\" content=\"45.430166630509255;13.529640133684602\" \/>\n<meta name=\"geo.region\" content=\"Croatia\" \/>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"M-13 | papaya.events","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:\/\/www.papaya.events\/hr\/majstor-13\/","og_locale":"hr_HR","og_type":"article","og_title":"M-13","og_url":"https:\/\/www.papaya.events\/hr\/majstor-13\/","og_site_name":"papaya.events","article_publisher":"https:\/\/www.facebook.com\/papaya.events.ls","article_modified_time":"2026-02-17T02:26:07+00:00","og_image":[{"width":2560,"height":1695,"url":"https:\/\/cdn.papaya.events\/wp-content\/uploads\/2025\/02\/176-1-scaled.jpg?strip=all&quality=70&webp=65&sharp=1","type":"image\/jpeg"}],"twitter_card":"summary_large_image","twitter_misc":{"Procijenjeno vrijeme \u010ditanja":"1 minuta"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/www.papaya.events\/master-13\/","url":"https:\/\/www.papaya.events\/master-13\/","name":"M-13 | papaya.events","isPartOf":{"@id":"https:\/\/www.papaya.events\/#website"},"datePublished":"2026-02-08T17:19:06+00:00","dateModified":"2026-02-17T02:26:07+00:00","breadcrumb":{"@id":"https:\/\/www.papaya.events\/master-13\/#breadcrumb"},"inLanguage":"hr","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.papaya.events\/master-13\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.papaya.events\/master-13\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.papaya.events\/"},{"@type":"ListItem","position":2,"name":"M-13"}]},{"@type":"WebSite","@id":"https:\/\/www.papaya.events\/#website","url":"https:\/\/www.papaya.events\/","name":"papaya.events","description":"Rezervirajte vrhunski party doga\u0111aj","publisher":{"@id":"https:\/\/www.papaya.events\/#organization"},"alternateName":"Unrivaled sounds, unforgettable light and FX for your events!","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.papaya.events\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"hr"},{"@type":["Organization","Place","LocalBusiness"],"@id":"https:\/\/www.papaya.events\/#organization","name":"papaya.events","alternateName":"Unrivaled sounds, unforgettable light and FX for your events!","url":"https:\/\/www.papaya.events\/","logo":{"@id":"https:\/\/www.papaya.events\/master-13\/#local-main-organization-logo"},"image":{"@id":"https:\/\/www.papaya.events\/master-13\/#local-main-organization-logo"},"sameAs":["https:\/\/www.facebook.com\/papaya.events.ls","https:\/\/soundcloud.com\/papaya_events","https:\/\/www.beatport.com\/artist\/drama\/170702","https:\/\/www.youtube.com\/@papaya.events","https:\/\/open.spotify.com\/user\/31m3wahhbsmph36a35fmzv45y344","https:\/\/www.instagram.com\/papaya.events.ls"],"description":"Papaya Events je organizacija za doga\u0111aje sa sjedi\u0161tem u Umagu u Hrvatskoj, koju vode tri umjetnika, specijalizirana za doga\u0111aje na otvorenom i u klubovima koji okupljaju ljubitelje glazbe kroz elektroni\u010dke zvukove i zanimljivu atmosferu. Organizacija pru\u017ea cjelovito iskustvo, uklju\u010duju\u0107i vlastitu produkciju, zvuk, rasvjetu, scenske efekte i sve bitne elemente za stvaranje nezaboravnih trenutaka. Njihovi doga\u0111aji kre\u0107u se od intimnih, malih privatnih zabava do ve\u0107ih okupljanja na otvorenom, nude\u0107i raznolik raspon elektroni\u010dke glazbe za sva\u010diji ukus i okru\u017eenje. Fokus je na stvaranju nezaboravnih iskustava koja ostavljaju trajne uspomene za sve ljubitelje glazbe i ljubitelje zabave.","legalName":"V.I.S.T.A. Ltd.","foundingDate":"2006-04-07","numberOfEmployees":{"@type":"QuantitativeValue","minValue":"1","maxValue":"10"},"publishingPrinciples":"https:\/\/www.papaya.events\/our-services\/","ownershipFundingInfo":"https:\/\/www.papaya.events\/our-services\/","address":{"@id":"https:\/\/www.papaya.events\/master-13\/#local-main-place-address"},"geo":{"@type":"GeoCoordinates","latitude":"45.430166630509255","longitude":"13.529640133684602"},"telephone":["+385915127282"],"contactPoint":{"@type":"ContactPoint","telephone":"+385915127282","email":"info@papaya.events"},"openingHoursSpecification":{"@type":"OpeningHoursSpecification","dayOfWeek":["Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"],"opens":"00:00","closes":"23:59"},"email":"info@papaya.events","vatID":"HR93447560687","priceRange":"$$$"},{"@type":"PostalAddress","@id":"https:\/\/www.papaya.events\/master-13\/#local-main-place-address","streetAddress":"Vladimir Nazor 5","addressLocality":"Umag","postalCode":"52470","addressRegion":"Croatia","addressCountry":"HR"},{"@type":"ImageObject","inLanguage":"hr","@id":"https:\/\/www.papaya.events\/master-13\/#local-main-organization-logo","url":"https:\/\/cdn.papaya.events\/wp-content\/uploads\/2025\/02\/favicon-copy.png?strip=all&quality=70&webp=65&sharp=1","contentUrl":"https:\/\/cdn.papaya.events\/wp-content\/uploads\/2025\/02\/favicon-copy.png?strip=all&quality=70&webp=65&sharp=1","width":1024,"height":1024,"caption":"papaya.events"}]},"geo.placename":"Umag","geo.position":{"lat":"45.430166630509255","long":"13.529640133684602"},"geo.region":"Croatia"},"ticketed":false,"_links":{"self":[{"href":"https:\/\/www.papaya.events\/hr\/wp-json\/wp\/v2\/pages\/3149","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.papaya.events\/hr\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/www.papaya.events\/hr\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/www.papaya.events\/hr\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.papaya.events\/hr\/wp-json\/wp\/v2\/comments?post=3149"}],"version-history":[{"count":133,"href":"https:\/\/www.papaya.events\/hr\/wp-json\/wp\/v2\/pages\/3149\/revisions"}],"predecessor-version":[{"id":3316,"href":"https:\/\/www.papaya.events\/hr\/wp-json\/wp\/v2\/pages\/3149\/revisions\/3316"}],"wp:attachment":[{"href":"https:\/\/www.papaya.events\/hr\/wp-json\/wp\/v2\/media?parent=3149"}],"curies":[{"name":"radni list","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}