{"id":7064,"date":"2026-04-11T03:48:16","date_gmt":"2026-04-11T06:48:16","guid":{"rendered":"https:\/\/cube-vox.com\/?page_id=7064"},"modified":"2026-04-13T15:42:17","modified_gmt":"2026-04-13T18:42:17","slug":"home","status":"publish","type":"page","link":"https:\/\/cube-vox.com\/en\/home\/","title":{"rendered":"CubeVox"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-page\" data-elementor-id=\"7064\" class=\"elementor elementor-7064\" data-elementor-settings=\"{&quot;ha_cmc_init_switcher&quot;:&quot;no&quot;}\">\n\t\t\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-ac92af7 elementor-section-full_width elementor-section-height-min-height elementor-section-height-default elementor-section-items-middle elementor-invisible\" data-id=\"ac92af7\" data-element_type=\"section\" data-e-type=\"section\" id=\"home\" data-settings=\"{&quot;animation&quot;:&quot;fadeIn&quot;}\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-no\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-7ea319a\" data-id=\"7ea319a\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-85c4ef4 elementor-widget__width-inherit eael-hamburger--none eael-simple-menu-hamburger-align-right ha-has-bg-overlay elementor-invisible elementor-widget elementor-widget-eael-simple-menu\" data-id=\"85c4ef4\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;fadeIn&quot;}\" data-widget_type=\"eael-simple-menu.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t            <div data-hamburger-icon=\"&lt;i aria-hidden=&quot;true&quot; class=&quot;fas fa-bars&quot;&gt;&lt;\/i&gt;\" data-indicator-icon=\"\" data-dropdown-indicator-icon=\"&lt;i class=&quot;fas fa-angle-down&quot;&gt;&lt;\/i&gt;\" class=\"eael-simple-menu-container eael-simple-menu--loading eael-simple-menu-align-right eael-simple-menu--stretch eael-simple-menu-dropdown-align-left preset-1\" data-hamburger-breakpoints=\"{&quot;mobile&quot;:&quot;Mobile Portrait (&gt; 767px)&quot;,&quot;tablet&quot;:&quot;Tablet Portrait (&gt; 1024px)&quot;,&quot;desktop&quot;:&quot;Desktop (&gt; 2400px)&quot;,&quot;none&quot;:&quot;None&quot;}\" data-hamburger-device=\"none\">\n                <ul id=\"menu-main-menu\" class=\"eael-simple-menu eael-simple-menu-dropdown-animate-zoom-in eael-simple-menu-indicator eael-hamburger-left eael-simple-menu-horizontal\"><li id=\"menu-item-5910\" class=\"menu-item menu-item-type-custom menu-item-object-custom menu-item-5910\"><a href=\"#our-approach\">Nuestro Enfoque<\/a><\/li>\n<li id=\"menu-item-275\" class=\"menu-item menu-item-type-custom menu-item-object-custom menu-item-275\"><a href=\"#contact-us\">Cont\u00e1ctanos<\/a><\/li>\n<\/ul>                <button class=\"eael-simple-menu-toggle\">\n                    <span class=\"sr-only \">Hamburger Toggle Menu<\/span>\n                    <i aria-hidden=\"true\" class=\"fas fa-bars\"><\/i>                <\/button>\n            <\/div>\n            \t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-f753706 elementor-widget__width-auto elementor-absolute elementor-invisible elementor-widget elementor-widget-ha-site-logo happy-addon ha-site-logo\" data-id=\"f753706\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_position&quot;:&quot;absolute&quot;,&quot;_animation&quot;:&quot;fadeIn&quot;}\" data-widget_type=\"ha-site-logo.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<a href=\"https:\/\/cube-vox.com\/en\/\" class=\"custom-logo-link\" rel=\"home\"><img fetchpriority=\"high\" decoding=\"async\" width=\"1445\" height=\"368\" src=\"https:\/\/cube-vox.com\/wp-content\/uploads\/cubevox-logo-mark.webp\" class=\"custom-logo\" alt=\"Cubevox\" srcset=\"https:\/\/cube-vox.com\/wp-content\/uploads\/cubevox-logo-mark.webp 1445w, https:\/\/cube-vox.com\/wp-content\/uploads\/cubevox-logo-mark-600x153.webp 600w, https:\/\/cube-vox.com\/wp-content\/uploads\/cubevox-logo-mark-300x76.webp 300w, https:\/\/cube-vox.com\/wp-content\/uploads\/cubevox-logo-mark-1024x261.webp 1024w, https:\/\/cube-vox.com\/wp-content\/uploads\/cubevox-logo-mark-768x196.webp 768w, https:\/\/cube-vox.com\/wp-content\/uploads\/cubevox-logo-mark-18x5.webp 18w\" sizes=\"(max-width: 1445px) 100vw, 1445px\" \/><\/a>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-3e50e3e elementor-section-full_width she-header-yes she-header-transparent-yes elementor-section-height-default elementor-section-height-default elementor-invisible\" data-id=\"3e50e3e\" data-element_type=\"section\" data-e-type=\"section\" id=\"menuSpecs\" data-settings=\"{&quot;animation&quot;:&quot;fadeIn&quot;,&quot;scroll_distance&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:50,&quot;sizes&quot;:[]},&quot;transparent&quot;:&quot;yes&quot;,&quot;she_padding&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;top&quot;:&quot;0&quot;,&quot;right&quot;:&quot;0&quot;,&quot;bottom&quot;:&quot;0&quot;,&quot;left&quot;:&quot;0&quot;,&quot;isLinked&quot;:true},&quot;transparent_header_show&quot;:&quot;yes&quot;,&quot;_ha_eqh_enable&quot;:false,&quot;transparent_on&quot;:[&quot;desktop&quot;,&quot;tablet&quot;,&quot;mobile&quot;],&quot;scroll_distance_tablet&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;scroll_distance_mobile&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;she_offset_top&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:0,&quot;sizes&quot;:[]},&quot;she_offset_top_tablet&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;she_offset_top_mobile&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;she_width&quot;:{&quot;unit&quot;:&quot;%&quot;,&quot;size&quot;:100,&quot;sizes&quot;:[]},&quot;she_width_tablet&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;she_width_mobile&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;she_padding_tablet&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;top&quot;:&quot;&quot;,&quot;right&quot;:&quot;&quot;,&quot;bottom&quot;:&quot;&quot;,&quot;left&quot;:&quot;&quot;,&quot;isLinked&quot;:true},&quot;she_padding_mobile&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;top&quot;:&quot;&quot;,&quot;right&quot;:&quot;&quot;,&quot;bottom&quot;:&quot;&quot;,&quot;left&quot;:&quot;&quot;,&quot;isLinked&quot;:true}}\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-no\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-119d966\" data-id=\"119d966\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-0f5b1f2 eael-hamburger--mobile eael-simple-menu-hamburger-align-right ha-has-bg-overlay elementor-invisible elementor-widget elementor-widget-eael-simple-menu\" data-id=\"0f5b1f2\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;fadeIn&quot;}\" data-widget_type=\"eael-simple-menu.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<style>\n                        @media screen and (max-width: 767px) {\n                            .eael-hamburger--mobile {\n                                .eael-simple-menu-horizontal,\n                                .eael-simple-menu-vertical {\n                                    display: none;\n                                }\n                            }\n                            .eael-hamburger--mobile {\n                                .eael-simple-menu-container .eael-simple-menu-toggle {\n                                    display: block;\n                                }\n                            }\n                        }\n                        .eael-simple-menu-container.eael-simple-menu--loading > ul {\n                            display: -webkit-box !important;\n                            display: -ms-flexbox !important;\n                            display: flex !important;\n                            list-style: none !important;\n                        }\n                        .eael-simple-menu-container.eael-simple-menu--loading li ul {\n                            visibility: hidden !important;\n                            opacity: 0 !important;\n                        }\n                    <\/style>            <div data-hamburger-icon=\"&lt;i aria-hidden=&quot;true&quot; class=&quot;fas fa-bars&quot;&gt;&lt;\/i&gt;\" data-indicator-icon=\"&lt;i aria-hidden=&quot;true&quot; class=&quot;fas fa-angle-down&quot;&gt;&lt;\/i&gt;\" data-dropdown-indicator-icon=\"&lt;i class=&quot;fas fa-angle-down&quot;&gt;&lt;\/i&gt;\" class=\"eael-simple-menu-container eael-simple-menu--loading eael-simple-menu-align-left eael-simple-menu-dropdown-align-left preset-1\" data-hamburger-breakpoints=\"{&quot;mobile&quot;:&quot;Mobile Portrait (&gt; 767px)&quot;,&quot;tablet&quot;:&quot;Tablet Portrait (&gt; 1024px)&quot;,&quot;desktop&quot;:&quot;Desktop (&gt; 2400px)&quot;,&quot;none&quot;:&quot;None&quot;}\" data-hamburger-device=\"mobile\">\n                <ul id=\"menu-specs-menu\" class=\"eael-simple-menu eael-simple-menu-dropdown-animate-zoom-in eael-simple-menu-indicator eael-hamburger-left eael-simple-menu-horizontal\"><li id=\"menu-item-346\" class=\"menu-item menu-item-type-custom menu-item-object-custom menu-item-has-children menu-item-346\"><a href=\"#concept\">Concepto<\/a>\n<ul class=\"sub-menu\">\n\t<li id=\"menu-item-341\" class=\"menu-item menu-item-type-custom menu-item-object-custom menu-item-341\"><a href=\"#all-in-one\">Todo-en-Uno<\/a><\/li>\n<\/ul>\n<\/li>\n<li id=\"menu-item-260\" class=\"menu-item menu-item-type-custom menu-item-object-custom menu-item-has-children menu-item-260\"><a href=\"#uses\">\u00dasalo como quieras<\/a>\n<ul class=\"sub-menu\">\n\t<li id=\"menu-item-349\" class=\"menu-item menu-item-type-custom menu-item-object-custom menu-item-349\"><a href=\"#portableStudio\">Estudio Portable<\/a><\/li>\n\t<li id=\"menu-item-263\" class=\"menu-item menu-item-type-custom menu-item-object-custom menu-item-263\"><a href=\"#soundMixer\">Mezcladora<\/a><\/li>\n\t<li id=\"menu-item-262\" class=\"menu-item menu-item-type-custom menu-item-object-custom menu-item-262\"><a href=\"#audioInterface\">Interfaz de audio<\/a><\/li>\n\t<li id=\"menu-item-264\" class=\"menu-item menu-item-type-custom menu-item-object-custom menu-item-264\"><a href=\"#multiEffect\">Multi-efectos<\/a><\/li>\n\t<li id=\"menu-item-350\" class=\"menu-item menu-item-type-custom menu-item-object-custom menu-item-350\"><a href=\"#amplifier\">Amplificador de instrumentos<\/a><\/li>\n\t<li id=\"menu-item-261\" class=\"menu-item menu-item-type-custom menu-item-object-custom menu-item-261\"><a href=\"#bluetoothWifiSpeaker\">Speaker Inal\u00e1mbrico<\/a><\/li>\n<\/ul>\n<\/li>\n<li id=\"menu-item-352\" class=\"menu-item menu-item-type-custom menu-item-object-custom menu-item-has-children menu-item-352\"><a href=\"#composeCloud\">Compose &#038; Cloud<\/a>\n<ul class=\"sub-menu\">\n\t<li id=\"menu-item-353\" class=\"menu-item menu-item-type-custom menu-item-object-custom menu-item-353\"><a href=\"#compose\">Compose<\/a><\/li>\n\t<li id=\"menu-item-354\" class=\"menu-item menu-item-type-custom menu-item-object-custom menu-item-354\"><a href=\"#cloud\">En la nube<\/a><\/li>\n<\/ul>\n<\/li>\n<li id=\"menu-item-259\" class=\"menu-item menu-item-type-custom menu-item-object-custom menu-item-has-children menu-item-259\"><a href=\"#design\">Dise\u00f1o<\/a>\n<ul class=\"sub-menu\">\n\t<li id=\"menu-item-339\" class=\"menu-item menu-item-type-custom menu-item-object-custom menu-item-339\"><a href=\"#innovative\">Innovador<\/a><\/li>\n\t<li id=\"menu-item-340\" class=\"menu-item menu-item-type-custom menu-item-object-custom menu-item-340\"><a href=\"#compact\">Compacto<\/a><\/li>\n<\/ul>\n<\/li>\n<li id=\"menu-item-351\" class=\"menu-item menu-item-type-custom menu-item-object-custom menu-item-has-children menu-item-351\"><a href=\"#sonidoAcustica\">Caracteristicas<\/a>\n<ul class=\"sub-menu\">\n\t<li id=\"menu-item-1701\" class=\"menu-item menu-item-type-custom menu-item-object-custom menu-item-1701\"><a href=\"#sonidoAcustica\">Sonido \/ Ac\u00fastica<\/a><\/li>\n\t<li id=\"menu-item-250\" class=\"menu-item menu-item-type-custom menu-item-object-custom menu-item-250\"><a href=\"#specs\">Datos t\u00e9cnicos<\/a><\/li>\n<\/ul>\n<\/li>\n<li id=\"menu-item-249\" class=\"menu-item menu-item-type-custom menu-item-object-custom menu-item-249\"><a href=\"#faq\">FAQ<\/a><\/li>\n<\/ul>                <button class=\"eael-simple-menu-toggle\">\n                    <span class=\"sr-only \">Hamburger Toggle Menu<\/span>\n                    <i aria-hidden=\"true\" class=\"fas fa-bars\"><\/i>                <\/button>\n            <\/div>\n            \t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"ha-bg-parallax-wrap-hide elementor-section elementor-top-section elementor-element elementor-element-89a13f9 elementor-section-full_width elementor-section-height-min-height animated-slow ha-bg-parallax-yes elementor-section-items-stretch elementor-section-height-default elementor-invisible\" data-ha-bg-parallax=\"{&quot;type&quot;:&quot;scale-opacity&quot;,&quot;speed&quot;:0.5,&quot;android&quot;:0,&quot;ios&quot;:0,&quot;size&quot;:&quot;cover&quot;,&quot;repeat&quot;:&quot;no-repeat&quot;}\" data-id=\"89a13f9\" data-element_type=\"section\" data-e-type=\"section\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;,&quot;animation&quot;:&quot;fadeIn&quot;,&quot;animation_delay&quot;:400,&quot;ha_bg_parallax_switcher&quot;:&quot;yes&quot;,&quot;ha_bg_parallax_type&quot;:&quot;scale-opacity&quot;,&quot;ha_bg_parallax_speed&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:0,&quot;sizes&quot;:[]},&quot;ha_bg_parallax_enable_on_android&quot;:&quot;yes&quot;,&quot;ha_bg_parallax_enable_on_ios&quot;:&quot;yes&quot;,&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-55409e0\" data-id=\"55409e0\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-9873ecc animated-slow elementor-widget__width-initial elementor-invisible elementor-widget elementor-widget-text-editor\" data-id=\"9873ecc\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;fadeInUp&quot;}\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p><strong>CubeVox <span style=\"font-size: 0.34em; vertical-align: super; margin-left: 0.04em; opacity: 0.82; font-weight: 500; letter-spacing: 0.02em;\">HiFi<\/span><br \/><\/strong><\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-09b064d animated-slow elementor-widget__width-initial elementor-invisible elementor-widget elementor-widget-text-editor\" data-id=\"09b064d\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;fadeInDown&quot;,&quot;_animation_delay&quot;:500}\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Menos complicaciones. M\u00e1s m\u00fasica<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-e195ea7 animated-slow elementor-invisible elementor-widget elementor-widget-html\" data-id=\"e195ea7\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;fadeIn&quot;,&quot;_animation_delay&quot;:1000}\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<div class=\"cvxPillWrap\"\r\n     style=\"\r\n       \/* ===== ALINEACI\u00d3N POR BREAKPOINT (left | center | right) ===== *\/\r\n       --cvx-pill-align-desk: left;\r\n       --cvx-pill-align-tab:  left;\r\n       --cvx-pill-align-mob:  center;\r\n\r\n       \/* ===== COLOR \/ LOOK (ajustable) ===== *\/\r\n       --cvx-pill-bg: rgba(14,18,24,.40);\r\n       --cvx-pill-stroke: rgba(255,255,255,.18);\r\n       --cvx-pill-shadow: 0 18px 44px rgba(0,0,0,.52);\r\n       --cvx-pill-blur: 10px;\r\n\r\n       \/* ===== DESK (base) ===== *\/\r\n       --cvx-pill-w-desk:     clamp(320px, 40.5vw, 920px);\r\n       --cvx-pill-fs-desk:    clamp(12px, 0.90vw, 14px);\r\n       --cvx-pill-ls-desk:    clamp(0.16em, 0.22vw, 0.26em);\r\n       --cvx-pill-gap-desk:   clamp(8px, 0.9vw, 10px);\r\n       --cvx-pill-py-desk:    clamp(8px, 0.85vw, 10px);\r\n       --cvx-pill-px-desk:    clamp(12px, 1.1vw, 14px);\r\n       --cvx-pill-dot-desk:   clamp(10px, 0.85vw, 12px);\r\n\r\n       \/* ===== TABLET ===== *\/\r\n       --cvx-pill-w-tab:      clamp(320px, 46.5vw, 920px);\r\n       --cvx-pill-fs-tab:     clamp(10px, 1.30vw, 14px);\r\n       --cvx-pill-ls-tab:     clamp(0.16em, 0.22vw, 0.26em);\r\n       --cvx-pill-gap-tab:    clamp(8px, 0.9vw, 10px);\r\n       --cvx-pill-py-tab:     clamp(8px, 0.85vw, 10px);\r\n       --cvx-pill-px-tab:     clamp(12px, 1.1vw, 14px);\r\n       --cvx-pill-dot-tab:    clamp(10px, 0.85vw, 12px);\r\n\r\n       \/* ===== MOBILE ===== *\/\r\n       --cvx-pill-w-mob:      clamp(260px, 92vw, 380px);\r\n       --cvx-pill-fs-mob:     clamp(7px, 2.2vw, 10px);\r\n       --cvx-pill-ls-mob:     clamp(0.10em, 1.2vw, 0.18em);\r\n       --cvx-pill-gap-mob:    clamp(6px, 2.0vw, 10px);\r\n       --cvx-pill-py-mob:     clamp(8px, 2.3vw, 10px);\r\n       --cvx-pill-px-mob:     clamp(10px, 3.2vw, 14px);\r\n       --cvx-pill-dot-mob:    clamp(10px, 2.6vw, 12px);\r\n     \">\r\n  <div class=\"cvxPill\" aria-label=\"Capacidades\">\r\n    <span>REPRODUCCI\u00d3N<\/span><i aria-hidden=\"true\">\u2022<\/i>\r\n    <span>EFECTOS<\/span><i aria-hidden=\"true\">\u2022<\/i>\r\n    <span>MEZCLA<\/span><i aria-hidden=\"true\">\u2022<\/i>\r\n    <span>GRABACI\u00d3N<\/span>\r\n  <\/div>\r\n<\/div>\r\n\r\n<style>\r\n  .cvxPillWrap{\r\n    width: 100%;\r\n    display: block;\r\n    text-align: var(--cvx-pill-align-desk); \/* desk por defecto *\/\r\n  }\r\n\r\n  \/* ===== Mapeo efectivo (Desk por defecto) ===== *\/\r\n  .cvxPillWrap{\r\n    --cvx-pill-w:   var(--cvx-pill-w-desk);\r\n    --cvx-pill-fs:  var(--cvx-pill-fs-desk);\r\n    --cvx-pill-ls:  var(--cvx-pill-ls-desk);\r\n    --cvx-pill-gap: var(--cvx-pill-gap-desk);\r\n    --cvx-pill-py:  var(--cvx-pill-py-desk);\r\n    --cvx-pill-px:  var(--cvx-pill-px-desk);\r\n    --cvx-pill-dot: var(--cvx-pill-dot-desk);\r\n  }\r\n\r\n  \/* ===== Tablet ===== *\/\r\n  @media (max-width: 1024px){\r\n    .cvxPillWrap{\r\n      text-align: var(--cvx-pill-align-tab);\r\n\r\n      --cvx-pill-w:   var(--cvx-pill-w-tab);\r\n      --cvx-pill-fs:  var(--cvx-pill-fs-tab);\r\n      --cvx-pill-ls:  var(--cvx-pill-ls-tab);\r\n      --cvx-pill-gap: var(--cvx-pill-gap-tab);\r\n      --cvx-pill-py:  var(--cvx-pill-py-tab);\r\n      --cvx-pill-px:  var(--cvx-pill-px-tab);\r\n      --cvx-pill-dot: var(--cvx-pill-dot-tab);\r\n    }\r\n  }\r\n\r\n  \/* ===== Mobile ===== *\/\r\n  @media (max-width: 767px){\r\n    .cvxPillWrap{\r\n      text-align: var(--cvx-pill-align-mob);\r\n\r\n      --cvx-pill-w:   var(--cvx-pill-w-mob);\r\n      --cvx-pill-fs:  var(--cvx-pill-fs-mob);\r\n      --cvx-pill-ls:  var(--cvx-pill-ls-mob);\r\n      --cvx-pill-gap: var(--cvx-pill-gap-mob);\r\n      --cvx-pill-py:  var(--cvx-pill-py-mob);\r\n      --cvx-pill-px:  var(--cvx-pill-px-mob);\r\n      --cvx-pill-dot: var(--cvx-pill-dot-mob);\r\n    }\r\n  }\r\n\r\n  .cvxPill{\r\n    display: inline-flex;\r\n    align-items: center;\r\n    justify-content: center;\r\n    gap: var(--cvx-pill-gap);\r\n\r\n    width: min(var(--cvx-pill-w), 100%);\r\n    box-sizing: border-box;\r\n\r\n    padding: var(--cvx-pill-py) var(--cvx-pill-px);\r\n    border-radius: 999px;\r\n\r\n    border: 1px solid var(--cvx-pill-stroke);\r\n    background: var(--cvx-pill-bg);\r\n\r\n    -webkit-backdrop-filter: blur(var(--cvx-pill-blur));\r\n    backdrop-filter: blur(var(--cvx-pill-blur));\r\n\r\n    box-shadow: var(--cvx-pill-shadow);\r\n\r\n    font-family: var(--cvxFont, system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif);\r\n    font-size: var(--cvx-pill-fs);\r\n    letter-spacing: var(--cvx-pill-ls);\r\n    text-transform: uppercase;\r\n    color: rgba(255,255,255,.88);\r\n  }\r\n\r\n  .cvxPill i{\r\n    font-style: normal;\r\n    font-size: var(--cvx-pill-dot);\r\n    transform: translateY(-1px);\r\n    color: var(--cvxAccent, rgba(255,255,255,.9));\r\n  }\r\n\r\n  @supports (color: color-mix(in srgb, white, black)){\r\n    .cvxPill i{\r\n      color: color-mix(in srgb, var(--cvxAccent, #8ff) 70%, rgba(255,255,255,.9));\r\n    }\r\n  }\r\n\r\n  @media (max-width: 776px){\r\n    .cvxPill{\r\n      flex-wrap: wrap;\r\n      row-gap: 8px;\r\n      border-radius: 16px;\r\n    }\r\n  }\r\n<\/style>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-de249b3 animated-slow elementor-widget__width-initial cvx-lc-open-product elementor-invisible elementor-widget elementor-widget-ha-creative-button happy-addon ha-creative-button\" data-id=\"de249b3\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;fadeInRight&quot;}\" data-widget_type=\"ha-creative-button.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div data-magnetic=\"yes\" class=\"ha-creative-btn-wrap\">\n\t\t\t<a class=\"ha-creative-btn ha-stl--hermosa ha-eft--newbie\" href=\"#\" rel=\"nofollow\"><span><span>Quiero acceso anticipado<\/span><\/span><\/a>\n\t\t<\/div>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<section class=\"elementor-section elementor-inner-section elementor-element elementor-element-3dcb604 elementor-section-full_width elementor-section-content-top elementor-section-height-default elementor-section-height-default\" data-id=\"3dcb604\" data-element_type=\"section\" data-e-type=\"section\" data-settings=\"{&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-50 elementor-inner-column elementor-element elementor-element-2d0fefd\" data-id=\"2d0fefd\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-2adc55c elementor-widget elementor-widget-heading\" data-id=\"2adc55c\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h5 class=\"elementor-heading-title elementor-size-default\">Dej\u00e1 tu email y te avisamos antes de la preventa.<\/h5>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t<div class=\"elementor-column elementor-col-50 elementor-inner-column elementor-element elementor-element-236efe4\" data-id=\"236efe4\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-abed530 animated-slow elementor-widget__width-initial elementor-invisible elementor-widget elementor-widget-ha-creative-button happy-addon ha-creative-button\" data-id=\"abed530\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;fadeInRight&quot;}\" data-widget_type=\"ha-creative-button.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div data-magnetic=\"yes\" class=\"ha-creative-btn-wrap\">\n\t\t\t<a class=\"ha-creative-btn ha-stl--montino ha-eft--aylen\" href=\"#reservations-main\" rel=\"nofollow\">Reservar ahora<\/a>\n\t\t<\/div>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-ea65bb7 elementor-section-full_width elementor-section-height-min-height elementor-section-items-stretch elementor-section-height-default\" data-id=\"ea65bb7\" data-element_type=\"section\" data-e-type=\"section\" id=\"concept\" data-settings=\"{&quot;animation&quot;:&quot;none&quot;,&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-42cda07\" data-id=\"42cda07\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<section class=\"elementor-section elementor-inner-section elementor-element elementor-element-752b429 elementor-section-boxed elementor-section-height-default elementor-section-height-default\" data-id=\"752b429\" data-element_type=\"section\" data-e-type=\"section\" id=\"tituloAnimacion\" data-settings=\"{&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-no\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-inner-column elementor-element elementor-element-b787b49\" data-id=\"b787b49\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<section class=\"elementor-section elementor-inner-section elementor-element elementor-element-42cab83 elementor-section-boxed elementor-section-height-default elementor-section-height-default\" data-id=\"42cab83\" data-element_type=\"section\" data-e-type=\"section\" data-settings=\"{&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-inner-column elementor-element elementor-element-a2dc831\" data-id=\"a2dc831\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-bf7ee78 animated-slow elementor-invisible elementor-widget elementor-widget-heading\" data-id=\"bf7ee78\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;slideInDown&quot;}\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Concepto<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-bf303d4 elementor-invisible elementor-widget elementor-widget-ha-svg-draw happy-addon ha-svg-draw\" data-id=\"bf303d4\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;slideInLeft&quot;}\" data-widget_type=\"ha-svg-draw.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\n\t\t\t\t<div class=\"ha-svg-draw-container\">\n\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t\n  \n    \n      \n      \n    \n  \n  \n\n\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t<\/div>\n\n\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-inner-section elementor-element elementor-element-a873eb5 elementor-section-boxed elementor-section-height-default elementor-section-height-default\" data-id=\"a873eb5\" data-element_type=\"section\" data-e-type=\"section\" data-settings=\"{&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-inner-column elementor-element elementor-element-408965d\" data-id=\"408965d\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-08d9e42 animated-slow elementor-invisible elementor-widget elementor-widget-heading\" data-id=\"08d9e42\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;fadeInUp&quot;,&quot;_animation_delay&quot;:200}\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">\u00c1brete a una nueva experiencia<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-inner-section elementor-element elementor-element-21d639a elementor-section-full_width elementor-section-height-min-height elementor-section-height-default\" data-id=\"21d639a\" data-element_type=\"section\" data-e-type=\"section\" id=\"animacion\" data-settings=\"{&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-no\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-inner-column elementor-element elementor-element-324fda4\" data-id=\"324fda4\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-bac196b animated-slow elementor-invisible elementor-widget elementor-widget-html\" data-id=\"bac196b\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"aperturaWrap\" data-settings=\"{&quot;_animation&quot;:&quot;fadeIn&quot;,&quot;_animation_delay&quot;:500}\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<div class=\"cvxScope\">\r\n  <section\r\n    data-cvx-root=\"hero-scrub\"\r\n    style=\"\r\n      \/* PARAMETERS *\/\r\n      --cvx-hero-target-playback-x: 1;          \/* m\u00e1s alto = menos scroll para completar el clip *\/\r\n      --cvx-hero-sensitivity: 1;                \/* m\u00e1s alto = m\u00e1s sensible *\/\r\n      --cvx-hero-hold-px: 140;                  \/* tramo inicial visible en frame 0 antes del scrub *\/\r\n      --cvx-hero-fade-viewports: 0.8;             \/* largo del fade en m\u00faltiplos de viewport *\/\r\n      --cvx-hero-mobile-max: 767;               \/* viewport m\u00e1ximo para usar la fuente mobile *\/\r\n\r\n      \/* SEEK \/ RENDER *\/\r\n      --cvx-hero-max-seek-hz: 30;\r\n      --cvx-hero-time-alpha: 0.35;\r\n      --cvx-hero-activation-dead-px: 0;\r\n\r\n      \/* DEVICE TUNING *\/\r\n      --cvx-hero-fine-pointer-factor: 1.18;     \/* desktop con pointer fino: m\u00e1s scroll para completar *\/\r\n      --cvx-hero-touchpad-max-deltay: 18;\r\n\r\n      \/* WHEEL START REMAP *\/\r\n      --cvx-hero-wheel-start-frac: 0.14;        \/* tramo inicial del scrub afectado por el remap *\/\r\n      --cvx-hero-wheel-start-gain: 0.12;        \/* m\u00e1s bajo = primer avance de rueda m\u00e1s contenido *\/\r\n\r\n      \/* INPUT PROFILES *\/\r\n      --cvx-hero-wheel-line-alpha: 0.14;\r\n      --cvx-hero-wheel-line-step: 22;\r\n\r\n      --cvx-hero-wheel-pixel-alpha: 0.20;\r\n      --cvx-hero-wheel-pixel-step: 48;\r\n\r\n      --cvx-hero-touchpad-alpha: 0.34;\r\n      --cvx-hero-touchpad-step: 120;\r\n\r\n      --cvx-hero-touch-alpha: 0.42;\r\n      --cvx-hero-touch-step: 140;\r\n\r\n      --cvx-hero-key-alpha: 0.20;\r\n      --cvx-hero-key-step: 48;\r\n\r\n      --cvx-hero-default-alpha: 0.28;\r\n      --cvx-hero-default-step: 90;\r\n\r\n      \/* OVERLAY *\/\r\n      --cvx-hero-overlay-transition-ms: 250ms;\r\n      --cvx-hero-brightness-min: 0.15;\r\n    \"\r\n  >\r\n    <div class=\"cvxHeroScene\">\r\n      <video\r\n        class=\"cvxHeroVideo\"\r\n        data-cvx-src-desktop=\"\/wp-content\/uploads\/cubevox-hifi-hero-animation.mp4\"\r\n        data-cvx-src-mobile=\"\/wp-content\/uploads\/cubevox-hifi-hero-animation_9x16.mp4\"\r\n        preload=\"auto\"\r\n        playsinline\r\n        muted\r\n      ><\/video>\r\n    <\/div>\r\n  <\/section>\r\n<\/div>\r\n\r\n<script>\r\n(() => {\r\n  'use strict';\r\n\r\n  const ROOT_SELECTOR = '.cvxScope [data-cvx-root=\"hero-scrub\"]';\r\n  const INSTANCE_KEY = '__cvxHeroScrubInstance__';\r\n\r\n  const clamp = (x, a, b) => Math.max(a, Math.min(b, x));\r\n  const smoothstep01 = (t) => {\r\n    t = clamp(t, 0, 1);\r\n    return t * t * (3 - 2 * t);\r\n  };\r\n\r\n  function viewportH() {\r\n    return (window.visualViewport && window.visualViewport.height)\r\n      ? window.visualViewport.height\r\n      : window.innerHeight;\r\n  }\r\n\r\n  function isFinePointer() {\r\n    return !!(window.matchMedia && window.matchMedia('(pointer: fine)').matches);\r\n  }\r\n\r\n  function isMobileViewport(maxPx) {\r\n    const bp = Math.max(0, Math.round(maxPx || 0));\r\n    return !!(window.matchMedia && window.matchMedia(`(max-width: ${bp}px)`).matches);\r\n  }\r\n\r\n  function isCoarseWheelKind(kind) {\r\n    return kind === 'wheel-line' || kind === 'wheel-pixel' || kind === 'wheel-page';\r\n  }\r\n\r\n  function remapWheelStartProgress(p, startFrac, gain) {\r\n    const s = clamp(startFrac, 0.001, 0.9);\r\n    const g = clamp(gain, 0.001, 1);\r\n\r\n    if (p <= s) {\r\n      return (p \/ s) * (s * g);\r\n    }\r\n\r\n    return (s * g) + ((p - s) * ((1 - (s * g)) \/ (1 - s)));\r\n  }\r\n\r\n  function init(root) {\r\n    if (!root) return;\r\n    if (root[INSTANCE_KEY]?.destroy) root[INSTANCE_KEY].destroy();\r\n\r\n    const wrap = root.querySelector('.cvxHeroScene');\r\n    const vid = root.querySelector('.cvxHeroVideo');\r\n    if (!wrap || !vid) return;\r\n\r\n    let destroyed = false;\r\n    let raf = 0;\r\n    let lastFrameMs = 0;\r\n    let lastSeekMs = 0;\r\n\r\n    let tFiltered = 0;\r\n    let sVirtual = 0;\r\n    let primed = false;\r\n    let lastInputKind = 'default';\r\n\r\n    let resizeObserver = null;\r\n    let intersectionObserver = null;\r\n    let currentVideoSrc = '';\r\n\r\n    function readNumVar(name, fallback) {\r\n      const raw = getComputedStyle(root).getPropertyValue(name).trim();\r\n      const n = parseFloat(raw);\r\n      return Number.isFinite(n) ? n : fallback;\r\n    }\r\n\r\n    function buildConfig() {\r\n      return {\r\n        \/* CORE *\/\r\n        targetPlaybackX: readNumVar('--cvx-hero-target-playback-x', 2),\r\n        sensitivity: readNumVar('--cvx-hero-sensitivity', 1),\r\n        holdPx: readNumVar('--cvx-hero-hold-px', 0),\r\n        fadeViewports: readNumVar('--cvx-hero-fade-viewports', 1),\r\n        mobileMax: readNumVar('--cvx-hero-mobile-max', 767),\r\n\r\n        \/* SEEK *\/\r\n        maxSeekHz: readNumVar('--cvx-hero-max-seek-hz', 30),\r\n        timeSmoothingAlpha: readNumVar('--cvx-hero-time-alpha', 0.35),\r\n        activationDeadPx: readNumVar('--cvx-hero-activation-dead-px', 0),\r\n\r\n        \/* DEVICE *\/\r\n        finePointerScrubFactor: readNumVar('--cvx-hero-fine-pointer-factor', 1.18),\r\n        touchpadMaxDeltaY: readNumVar('--cvx-hero-touchpad-max-deltay', 18),\r\n\r\n        \/* VISUAL *\/\r\n        brightnessMin: readNumVar('--cvx-hero-brightness-min', 0.15),\r\n        overlayTransitionMs: readNumVar('--cvx-hero-overlay-transition-ms', 250),\r\n\r\n        \/* START REMAP *\/\r\n        wheelStartFraction: readNumVar('--cvx-hero-wheel-start-frac', 0.14),\r\n        wheelStartGain: readNumVar('--cvx-hero-wheel-start-gain', 0.12),\r\n\r\n        \/* PRIME *\/\r\n        primeOnFirstUserInput: true,\r\n\r\n        \/* INPUT PROFILES *\/\r\n        scrollProfiles: {\r\n          default: {\r\n            alpha: readNumVar('--cvx-hero-default-alpha', 0.28),\r\n            maxStepPxPerFrame: readNumVar('--cvx-hero-default-step', 90)\r\n          },\r\n          touch: {\r\n            alpha: readNumVar('--cvx-hero-touch-alpha', 0.42),\r\n            maxStepPxPerFrame: readNumVar('--cvx-hero-touch-step', 140)\r\n          },\r\n          touchpad: {\r\n            alpha: readNumVar('--cvx-hero-touchpad-alpha', 0.34),\r\n            maxStepPxPerFrame: readNumVar('--cvx-hero-touchpad-step', 120)\r\n          },\r\n          'wheel-line': {\r\n            alpha: readNumVar('--cvx-hero-wheel-line-alpha', 0.14),\r\n            maxStepPxPerFrame: readNumVar('--cvx-hero-wheel-line-step', 22)\r\n          },\r\n          'wheel-pixel': {\r\n            alpha: readNumVar('--cvx-hero-wheel-pixel-alpha', 0.20),\r\n            maxStepPxPerFrame: readNumVar('--cvx-hero-wheel-pixel-step', 48)\r\n          },\r\n          'wheel-page': {\r\n            alpha: readNumVar('--cvx-hero-wheel-pixel-alpha', 0.20),\r\n            maxStepPxPerFrame: readNumVar('--cvx-hero-wheel-pixel-step', 48)\r\n          },\r\n          key: {\r\n            alpha: readNumVar('--cvx-hero-key-alpha', 0.20),\r\n            maxStepPxPerFrame: readNumVar('--cvx-hero-key-step', 48)\r\n          }\r\n        }\r\n      };\r\n    }\r\n\r\n    let CFG = buildConfig();\r\n\r\n    function hasDuration() {\r\n      return Number.isFinite(vid.duration) && vid.duration > 0;\r\n    }\r\n\r\n    function detectWheelKind(e) {\r\n      if (e.deltaMode === 1) return 'wheel-line';\r\n      if (e.deltaMode === 2) return 'wheel-page';\r\n\r\n      const absY = Math.abs(e.deltaY);\r\n\r\n      if (isFinePointer() && absY >= 40) return 'wheel-line';\r\n      return absY <= CFG.touchpadMaxDeltaY ? 'touchpad' : 'wheel-pixel';\r\n    }\r\n\r\n    function getScrollProfile() {\r\n      return CFG.scrollProfiles[lastInputKind] || CFG.scrollProfiles.default;\r\n    }\r\n\r\n    function canMeasure() {\r\n      const rr = root.getBoundingClientRect();\r\n      const wr = wrap.getBoundingClientRect();\r\n      const vh = viewportH();\r\n\r\n      if (!vh || vh < 2) return false;\r\n      if (rr.width < 2) return false;\r\n      if (wr.width < 2) return false;\r\n      if (root.offsetParent === null && rr.height < 2 && wr.height < 2) return false;\r\n\r\n      return true;\r\n    }\r\n\r\n    function resolveVideoSrc() {\r\n      const desktopSrc = (vid.getAttribute('data-cvx-src-desktop') || '').trim();\r\n      const mobileSrc = (vid.getAttribute('data-cvx-src-mobile') || '').trim();\r\n      const fallbackSrc = (vid.getAttribute('src') || '').trim();\r\n\r\n      if (mobileSrc && isMobileViewport(CFG.mobileMax)) return mobileSrc;\r\n      return desktopSrc || mobileSrc || fallbackSrc;\r\n    }\r\n\r\n    function applyVideoSource() {\r\n      const nextSrc = resolveVideoSrc();\r\n      if (!nextSrc || nextSrc === currentVideoSrc) return false;\r\n\r\n      currentVideoSrc = nextSrc;\r\n\r\n      try { vid.pause(); } catch (_) {}\r\n\r\n      vid.setAttribute('src', nextSrc);\r\n      vid.load();\r\n\r\n      tFiltered = 0;\r\n      sVirtual = 0;\r\n      lastSeekMs = 0;\r\n      lastFrameMs = 0;\r\n      primed = false;\r\n\r\n      return true;\r\n    }\r\n\r\n    function primeVideo() {\r\n      if (!CFG.primeOnFirstUserInput || primed) return;\r\n      primed = true;\r\n\r\n      vid.muted = true;\r\n      vid.playsInline = true;\r\n\r\n      try {\r\n        const p = vid.play();\r\n        if (p && typeof p.then === 'function') {\r\n          p.then(() => {\r\n            try { vid.pause(); } catch (_) {}\r\n          }).catch(() => {});\r\n        }\r\n      } catch (_) {}\r\n    }\r\n\r\n    function schedule() {\r\n      if (destroyed || raf) return;\r\n      raf = requestAnimationFrame(update);\r\n    }\r\n\r\n    function applyBaseVideoStyles(vh) {\r\n      vid.style.position = 'fixed';\r\n      vid.style.left = '0';\r\n      vid.style.top = '0';\r\n      vid.style.width = '100%';\r\n      vid.style.height = `${vh}px`;\r\n      vid.style.objectFit = 'cover';\r\n      vid.style.pointerEvents = 'none';\r\n    }\r\n\r\n    function hideVideo() {\r\n      vid.style.opacity = '0';\r\n      vid.style.filter = 'brightness(1)';\r\n    }\r\n\r\n    function update() {\r\n      raf = 0;\r\n      if (destroyed) return;\r\n\r\n      CFG = buildConfig();\r\n\r\n      if (!canMeasure()) {\r\n        hideVideo();\r\n        return;\r\n      }\r\n\r\n      const now = performance.now();\r\n      const dt = lastFrameMs ? Math.max(1, now - lastFrameMs) : 16.667;\r\n      lastFrameMs = now;\r\n\r\n      const vh = viewportH();\r\n      const deviceScrubFactor = isFinePointer() ? CFG.finePointerScrubFactor : 1;\r\n      const holdPx = Math.max(0, CFG.holdPx);\r\n\r\n      const scrubDist = ((vh \/ CFG.targetPlaybackX) \/ CFG.sensitivity) * deviceScrubFactor;\r\n      const fadeDist = vh * CFG.fadeViewports;\r\n\r\n      const scrubStartPx = holdPx;\r\n      const scrubEndPx = holdPx + scrubDist;\r\n      const total = scrubEndPx + fadeDist;\r\n\r\n      \/* CALCULATED VARS *\/\r\n      wrap.style.height = `${Math.max(2, scrubEndPx)}px`;\r\n      root.style.setProperty('--cvx-hero-calc-hold-px', `${holdPx}px`);\r\n      root.style.setProperty('--cvx-hero-calc-scrub-start-px', `${scrubStartPx}px`);\r\n      root.style.setProperty('--cvx-hero-calc-scrub-end-px', `${scrubEndPx}px`);\r\n      root.style.setProperty('--cvx-hero-calc-scrub-dist-px', `${scrubDist}px`);\r\n      root.style.setProperty('--cvx-hero-calc-fade-dist-px', `${fadeDist}px`);\r\n\r\n      applyBaseVideoStyles(vh);\r\n\r\n      const r = wrap.getBoundingClientRect();\r\n      const sRaw = -r.top;\r\n\r\n      if (sRaw <= 0) {\r\n        sVirtual = 0;\r\n        tFiltered = 0;\r\n        hideVideo();\r\n        return;\r\n      }\r\n\r\n      if (sRaw >= total) {\r\n        sVirtual = scrubDist;\r\n        hideVideo();\r\n        return;\r\n      }\r\n\r\n      const inHold = sRaw < scrubStartPx;\r\n      const inScrub = sRaw >= scrubStartPx && sRaw <= scrubEndPx;\r\n\r\n      if (inHold) {\r\n        sVirtual = 0;\r\n      } else if (inScrub) {\r\n        const rawScrubPx = sRaw - scrubStartPx;\r\n        const profile = getScrollProfile();\r\n        const frameScale = dt \/ 16.667;\r\n        const maxStep = profile.maxStepPxPerFrame * frameScale;\r\n\r\n        const delta = rawScrubPx - sVirtual;\r\n        const stepped = clamp(delta * profile.alpha, -maxStep, maxStep);\r\n\r\n        sVirtual = Math.abs(delta) < 0.35 ? rawScrubPx : (sVirtual + stepped);\r\n      } else {\r\n        sVirtual = scrubDist;\r\n      }\r\n\r\n      let pScrub = 0;\r\n\r\n      if (!inHold) {\r\n        const sForScrub = clamp(sVirtual - CFG.activationDeadPx, 0, scrubDist);\r\n        const scrubUsable = Math.max(1, scrubDist - CFG.activationDeadPx);\r\n        pScrub = clamp(sForScrub \/ scrubUsable, 0, 1);\r\n\r\n        if (inScrub && isCoarseWheelKind(lastInputKind)) {\r\n          pScrub = remapWheelStartProgress(\r\n            pScrub,\r\n            CFG.wheelStartFraction,\r\n            CFG.wheelStartGain\r\n          );\r\n        }\r\n      }\r\n\r\n      let pFade = 0;\r\n      if (sRaw > scrubEndPx) {\r\n        pFade = clamp((sRaw - scrubEndPx) \/ fadeDist, 0, 1);\r\n      }\r\n      pFade = smoothstep01(pFade);\r\n\r\n      const opacity = 1 - pFade;\r\n      const br = 1 - (1 - CFG.brightnessMin) * pFade;\r\n\r\n      vid.style.opacity = String(opacity);\r\n      vid.style.filter = `brightness(${br})`;\r\n\r\n      if (hasDuration()) {\r\n        const eps = 0.001;\r\n        const maxT = Math.max(0, vid.duration - eps);\r\n        const tDesired = inHold ? 0 : (pScrub * maxT);\r\n\r\n        tFiltered = tFiltered + (tDesired - tFiltered) * CFG.timeSmoothingAlpha;\r\n\r\n        const minDt = 1000 \/ CFG.maxSeekHz;\r\n        if ((now - lastSeekMs) >= minDt) {\r\n          lastSeekMs = now;\r\n          try {\r\n            vid.currentTime = clamp(tFiltered, 0, maxT);\r\n          } catch (_) {}\r\n        }\r\n\r\n        const needsSeekCatchup = Math.abs(tDesired - tFiltered) > 0.002;\r\n        const needsScrollCatchup = inScrub && Math.abs((sRaw - scrubStartPx) - sVirtual) > 0.35;\r\n\r\n        if (needsSeekCatchup || needsScrollCatchup) schedule();\r\n      } else if (inScrub && Math.abs((sRaw - scrubStartPx) - sVirtual) > 0.35) {\r\n        schedule();\r\n      }\r\n    }\r\n\r\n    const onScroll = () => schedule();\r\n\r\n    const onResize = () => {\r\n      CFG = buildConfig();\r\n      applyVideoSource();\r\n      schedule();\r\n    };\r\n\r\n    const onWheelIntent = (e) => {\r\n      lastInputKind = detectWheelKind(e);\r\n      primeVideo();\r\n      schedule();\r\n    };\r\n\r\n    const onTouchIntent = () => {\r\n      lastInputKind = 'touch';\r\n      primeVideo();\r\n      schedule();\r\n    };\r\n\r\n    const onPointerIntent = () => {\r\n      primeVideo();\r\n    };\r\n\r\n    const onKeyIntent = (e) => {\r\n      switch (e.key) {\r\n        case 'ArrowDown':\r\n        case 'ArrowUp':\r\n        case 'PageDown':\r\n        case 'PageUp':\r\n        case 'Home':\r\n        case 'End':\r\n        case ' ':\r\n        case 'Spacebar':\r\n          lastInputKind = 'key';\r\n          primeVideo();\r\n          schedule();\r\n          break;\r\n      }\r\n    };\r\n\r\n    window.addEventListener('scroll', onScroll, { passive: true });\r\n    window.addEventListener('resize', onResize, { passive: true });\r\n    window.addEventListener('wheel', onWheelIntent, { passive: true, capture: true });\r\n    window.addEventListener('touchstart', onTouchIntent, { passive: true, capture: true });\r\n    window.addEventListener('pointerdown', onPointerIntent, true);\r\n    window.addEventListener('keydown', onKeyIntent, true);\r\n\r\n    if (window.visualViewport) {\r\n      window.visualViewport.addEventListener('resize', onResize, { passive: true });\r\n    }\r\n\r\n    if ('ResizeObserver' in window) {\r\n      resizeObserver = new ResizeObserver(() => {\r\n        if (destroyed) return;\r\n        CFG = buildConfig();\r\n        schedule();\r\n      });\r\n      resizeObserver.observe(root);\r\n    }\r\n\r\n    if ('IntersectionObserver' in window) {\r\n      intersectionObserver = new IntersectionObserver(() => {\r\n        if (destroyed) return;\r\n        schedule();\r\n      }, {\r\n        root: null,\r\n        rootMargin: '200% 0px 200% 0px',\r\n        threshold: 0\r\n      });\r\n      intersectionObserver.observe(root);\r\n    }\r\n\r\n    vid.addEventListener('loadedmetadata', () => {\r\n      try { vid.pause(); } catch (_) {}\r\n      tFiltered = 0;\r\n      sVirtual = 0;\r\n      schedule();\r\n    });\r\n\r\n    applyVideoSource();\r\n    try { vid.pause(); } catch (_) {}\r\n    schedule();\r\n\r\n    function destroy() {\r\n      destroyed = true;\r\n\r\n      if (raf) cancelAnimationFrame(raf);\r\n      raf = 0;\r\n\r\n      window.removeEventListener('scroll', onScroll);\r\n      window.removeEventListener('resize', onResize);\r\n      window.removeEventListener('wheel', onWheelIntent, true);\r\n      window.removeEventListener('touchstart', onTouchIntent, true);\r\n      window.removeEventListener('pointerdown', onPointerIntent, true);\r\n      window.removeEventListener('keydown', onKeyIntent, true);\r\n\r\n      if (window.visualViewport) {\r\n        window.visualViewport.removeEventListener('resize', onResize);\r\n      }\r\n\r\n      if (resizeObserver) resizeObserver.disconnect();\r\n      if (intersectionObserver) intersectionObserver.disconnect();\r\n\r\n      wrap.style.height = '';\r\n      vid.style.opacity = '';\r\n      vid.style.filter = '';\r\n      vid.style.position = '';\r\n      vid.style.top = '';\r\n      vid.style.left = '';\r\n      vid.style.width = '';\r\n      vid.style.height = '';\r\n      vid.style.objectFit = '';\r\n      vid.style.pointerEvents = '';\r\n\r\n      root.style.removeProperty('--cvx-hero-calc-hold-px');\r\n      root.style.removeProperty('--cvx-hero-calc-scrub-start-px');\r\n      root.style.removeProperty('--cvx-hero-calc-scrub-end-px');\r\n      root.style.removeProperty('--cvx-hero-calc-scrub-dist-px');\r\n      root.style.removeProperty('--cvx-hero-calc-fade-dist-px');\r\n\r\n      delete root[INSTANCE_KEY];\r\n    }\r\n\r\n    root[INSTANCE_KEY] = { destroy };\r\n  }\r\n\r\n  document.querySelectorAll(ROOT_SELECTOR).forEach(init);\r\n})();\r\n<\/script>\r\n\r\n<style>\r\n.cvxScope [data-cvx-root=\"hero-scrub\"] {\r\n  \/* COMPONENT *\/\r\n  position: relative;\r\n}\r\n\r\n.cvxScope [data-cvx-root=\"hero-scrub\"] .cvxHeroScene {\r\n  \/* COMPONENT *\/\r\n  position: relative;\r\n  height: 2px; \/* fallback; JS calcula hold + scrub *\/\r\n}\r\n\r\n.cvxScope [data-cvx-root=\"hero-scrub\"] .cvxHeroVideo {\r\n  \/* COMPONENT *\/\r\n  display: block;\r\n  border-radius: 0;\r\n  opacity: 0;\r\n  will-change: opacity, filter;\r\n  transition:\r\n    opacity var(--cvx-hero-overlay-transition-ms, 250ms) linear,\r\n    filter var(--cvx-hero-overlay-transition-ms, 250ms) linear;\r\n}\r\n\r\n@media (prefers-reduced-motion: reduce) {\r\n  .cvxScope [data-cvx-root=\"hero-scrub\"] .cvxHeroVideo {\r\n    transition: none;\r\n  }\r\n}\r\n<\/style>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"ha-bg-parallax-wrap-hide elementor-section elementor-top-section elementor-element elementor-element-e92a15c elementor-section-height-min-height elementor-section-items-stretch fx_section ha-bg-parallax-yes elementor-section-boxed elementor-section-height-default\" data-ha-bg-parallax=\"{&quot;type&quot;:&quot;opacity&quot;,&quot;speed&quot;:0.5,&quot;android&quot;:0,&quot;ios&quot;:0,&quot;size&quot;:&quot;cover&quot;,&quot;repeat&quot;:&quot;no-repeat&quot;}\" data-id=\"e92a15c\" data-element_type=\"section\" data-e-type=\"section\" id=\"all-in-one\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;,&quot;ha_bg_parallax_type&quot;:&quot;opacity&quot;,&quot;ha_bg_parallax_enable_on_android&quot;:&quot;yes&quot;,&quot;ha_bg_parallax_enable_on_ios&quot;:&quot;yes&quot;,&quot;ha_bg_parallax_switcher&quot;:&quot;yes&quot;,&quot;ha_bg_parallax_speed&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t\t<div class=\"elementor-background-overlay\"><\/div>\n\t\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-e0ee663\" data-id=\"e0ee663\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<section class=\"elementor-section elementor-inner-section elementor-element elementor-element-67df073c elementor-section-full_width elementor-section-height-default elementor-section-height-default\" data-id=\"67df073c\" data-element_type=\"section\" data-e-type=\"section\" data-settings=\"{&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-no\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-inner-column elementor-element elementor-element-364059b8\" data-id=\"364059b8\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-45127d48 animated-slow elementor-invisible elementor-widget elementor-widget-heading\" data-id=\"45127d48\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;slideInDown&quot;}\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Todo-en-uno<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-8f1f1f elementor-invisible elementor-widget elementor-widget-ha-svg-draw happy-addon ha-svg-draw\" data-id=\"8f1f1f\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;slideInLeft&quot;}\" data-widget_type=\"ha-svg-draw.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\n\t\t\t\t<div class=\"ha-svg-draw-container\">\n\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t\n  \n    \n      \n      \n    \n  \n  \n\n\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t<\/div>\n\n\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-inner-section elementor-element elementor-element-f8cdace elementor-section-full_width elementor-section-height-default elementor-section-height-default\" data-id=\"f8cdace\" data-element_type=\"section\" data-e-type=\"section\" data-settings=\"{&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-no\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-inner-column elementor-element elementor-element-1911f61\" data-id=\"1911f61\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-6ac5f1e4 animated-slow elementor-invisible elementor-widget elementor-widget-heading\" data-id=\"6ac5f1e4\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;fadeIn&quot;,&quot;_animation_delay&quot;:300}\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Ll\u00e9valo contigo<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-4495ddb6 elementor-invisible elementor-widget elementor-widget-heading\" data-id=\"4495ddb6\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;fadeInDown&quot;,&quot;_animation_delay&quot;:200}\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Un solo dispositivo, m\u00faltiples usos.<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-inner-section elementor-element elementor-element-24ea6c7 elementor-section-full_width elementor-section-content-space-evenly elementor-section-height-default elementor-section-height-default\" data-id=\"24ea6c7\" data-element_type=\"section\" data-e-type=\"section\" data-settings=\"{&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-no\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-inner-column elementor-element elementor-element-aaf1bff\" data-id=\"aaf1bff\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-f0e447c elementor-invisible elementor-widget elementor-widget-text-editor\" data-id=\"f0e447c\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;fadeInLeft&quot;}\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>CubeVox te acompa\u00f1a a donde vayas, listo para <span style=\"color: #ffffff;\"><strong>sonar por horas. <\/strong><\/span><\/p><p><span style=\"color: #ffffff;\"><strong><span style=\"color: #99ccff;\">Cerr\u00e1s \u2192 Llev\u00e1s \u2192 Abr\u00eds \u2192 Son\u00e1s.<\/span><br \/><\/strong><\/span><\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-69d4b89 elementor-invisible elementor-widget elementor-widget-ha-content-switcher happy-addon ha-content-switcher\" data-id=\"69d4b89\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;fadeInUp&quot;,&quot;_animation_delay&quot;:300}\" data-widget_type=\"ha-content-switcher.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"ha-content-switcher-wrapper ha-cs-design-button\" data-design-type=\"button\">\n\t\t\t<div class=\"ha-cs-switch-container\">\n\t\t\t\t<div class=\"ha-cs-switch-wrapper  desktop-horizontal horizontal\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<button class=\"ha-cs-button active ha-cs-icon-left\" data-content-id=\"77b8221\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<div class=\"ha-cs-icon-wrapper\"><i class=\"fas fa-tired\"><\/i><\/div>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<span>Otros<\/span>\n\t\t\t\t\t\t\t<\/button>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<button class=\"ha-cs-button  ha-cs-icon-left\" data-content-id=\"605a9af\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<div class=\"ha-cs-icon-wrapper\"><i class=\"fas fa-smile-beam\"><\/i><\/div>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<span>CubeVox<\/span>\n\t\t\t\t\t\t\t<\/button>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t<\/div>\n\t\t\t<div class=\"ha-cs-content-container\">\n\t\t\t\t<div class=\"ha-cs-content-wrapper  desktop-horizontal horizontal\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<div id=\"77b8221\" class=\"ha-cs-content-section active\">\n\t\t\t\t\t\t\t\t\t\t<div data-elementor-type=\"section\" data-elementor-id=\"1794\" class=\"elementor elementor-1794\" data-elementor-settings=\"{&quot;ha_cmc_init_switcher&quot;:&quot;no&quot;}\">\n\t\t\t\t\t\t<section class=\"elementor-section elementor-inner-section elementor-element elementor-element-40a2a306 elementor-section-full_width elementor-section-height-default elementor-section-height-default\" data-id=\"40a2a306\" data-element_type=\"section\" data-e-type=\"section\" data-settings=\"{&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-no\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-inner-column elementor-element elementor-element-e6c0539\" data-id=\"e6c0539\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-363a7e9b elementor-widget elementor-widget-ha-image-stack-group happy-addon ha-image-stack-group\" data-id=\"363a7e9b\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"ha-image-stack-group.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\n\t\t<div class=\"ha-cig\">\n\t\t\t<span class=\"ha-cig-item ha-cig-item-outline elementor-repeater-item-3cf5b4e\" tooltip=\"Speaker\" flow=\"up\"><img decoding=\"async\" src=\"https:\/\/cube-vox.com\/wp-content\/uploads\/bluetooth-speaker-card.webp\" alt=\"\"><\/span><span class=\"ha-cig-item ha-cig-item-outline elementor-repeater-item-168afa4\" tooltip=\"Mezcladora\" flow=\"up\"><img decoding=\"async\" src=\"https:\/\/cube-vox.com\/wp-content\/uploads\/audio-mixer-card.webp\" alt=\"\"><\/span><span class=\"ha-cig-item ha-cig-item-outline elementor-repeater-item-f44fa73\" tooltip=\"Multi-Efectos\" flow=\"up\"><img decoding=\"async\" src=\"https:\/\/cube-vox.com\/wp-content\/uploads\/multi-effects-processor-card.webp\" alt=\"\"><\/span><span class=\"ha-cig-item ha-cig-item-outline elementor-repeater-item-2ad74f0\" tooltip=\"Amplificador\" flow=\"up\"><img decoding=\"async\" src=\"https:\/\/cube-vox.com\/wp-content\/uploads\/instrument-amplifier-card.webp\" alt=\"\"><\/span><span class=\"ha-cig-item ha-cig-item-outline elementor-repeater-item-0ce1703\" tooltip=\"Interfaz de audio\" flow=\"up\"><img decoding=\"async\" src=\"https:\/\/cube-vox.com\/wp-content\/uploads\/audio-interface-card.webp\" alt=\"\"><\/span>\n\t\t<\/div>\n\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<\/div>\n\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<div id=\"605a9af\" class=\"ha-cs-content-section \">\n\t\t\t\t\t\t\t\t\t\t<div data-elementor-type=\"section\" data-elementor-id=\"1797\" class=\"elementor elementor-1797\" data-elementor-settings=\"{&quot;ha_cmc_init_switcher&quot;:&quot;no&quot;}\">\n\t\t\t\t\t\t<section class=\"elementor-section elementor-inner-section elementor-element elementor-element-57ea7994 elementor-section-full_width elementor-section-height-default elementor-section-height-default\" data-id=\"57ea7994\" data-element_type=\"section\" data-e-type=\"section\" data-settings=\"{&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-no\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-inner-column elementor-element elementor-element-514e6745\" data-id=\"514e6745\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-64a82ab5 elementor-widget elementor-widget-ha-image-stack-group happy-addon ha-image-stack-group\" data-id=\"64a82ab5\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"ha-image-stack-group.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\n\t\t<div class=\"ha-cig\">\n\t\t\t<span class=\"ha-cig-item ha-cig-item-outline elementor-repeater-item-2ad74f0\" tooltip=\"CubeVox\" flow=\"up\"><img decoding=\"async\" src=\"https:\/\/cube-vox.com\/wp-content\/uploads\/cubevox-portable-audio-studio-card.webp\" alt=\"\"><\/span>\n\t\t<\/div>\n\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<\/div>\n\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-inner-section elementor-element elementor-element-b8090bc elementor-section-full_width elementor-section-content-bottom elementor-section-height-default elementor-section-height-default\" data-id=\"b8090bc\" data-element_type=\"section\" data-e-type=\"section\" data-settings=\"{&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-no\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-inner-column elementor-element elementor-element-3e95e9c\" data-id=\"3e95e9c\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-548637aa elementor-icon-list--layout-inline elementor-align-center animated-slow elementor-list-item-link-full_width elementor-invisible elementor-widget elementor-widget-icon-list\" data-id=\"548637aa\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;fadeIn&quot;,&quot;_animation_delay&quot;:600}\" data-widget_type=\"icon-list.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<ul class=\"elementor-icon-list-items elementor-inline-items\">\n\t\t\t\t\t\t\t<li class=\"elementor-icon-list-item elementor-inline-item\">\n\t\t\t\t\t\t\t\t\t\t\t<span class=\"elementor-icon-list-icon\">\n\t\t\t\t\t\t\t<i aria-hidden=\"true\" class=\"fas fa-check\"><\/i>\t\t\t\t\t\t<\/span>\n\t\t\t\t\t\t\t\t\t\t<span class=\"elementor-icon-list-text\">facil de llevar.<\/span>\n\t\t\t\t\t\t\t\t\t<\/li>\n\t\t\t\t\t\t\t\t<li class=\"elementor-icon-list-item elementor-inline-item\">\n\t\t\t\t\t\t\t\t\t\t\t<span class=\"elementor-icon-list-icon\">\n\t\t\t\t\t\t\t<i aria-hidden=\"true\" class=\"fas fa-battery-full\"><\/i>\t\t\t\t\t\t<\/span>\n\t\t\t\t\t\t\t\t\t\t<span class=\"elementor-icon-list-text\">bateria duradera.<\/span>\n\t\t\t\t\t\t\t\t\t<\/li>\n\t\t\t\t\t\t\t\t<li class=\"elementor-icon-list-item elementor-inline-item\">\n\t\t\t\t\t\t\t\t\t\t\t<span class=\"elementor-icon-list-icon\">\n\t\t\t\t\t\t\t<i aria-hidden=\"true\" class=\"fas fa-plug\"><\/i>\t\t\t\t\t\t<\/span>\n\t\t\t\t\t\t\t\t\t\t<span class=\"elementor-icon-list-text\">sin cables extra.<\/span>\n\t\t\t\t\t\t\t\t\t<\/li>\n\t\t\t\t\t\t<\/ul>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-5b54097 elementor-section-height-min-height elementor-section-items-stretch fx_section elementor-section-boxed elementor-section-height-default\" data-id=\"5b54097\" data-element_type=\"section\" data-e-type=\"section\" id=\"uses\" data-settings=\"{&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-a7be758\" data-id=\"a7be758\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<section class=\"elementor-section elementor-inner-section elementor-element elementor-element-de85133 elementor-section-full_width elementor-section-height-default elementor-section-height-default\" data-id=\"de85133\" data-element_type=\"section\" data-e-type=\"section\" data-settings=\"{&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-no\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-inner-column elementor-element elementor-element-4bdec0e\" data-id=\"4bdec0e\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-3943fd8 animated-slow elementor-invisible elementor-widget elementor-widget-heading\" data-id=\"3943fd8\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"toHide\" data-settings=\"{&quot;_animation&quot;:&quot;slideInDown&quot;}\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">\u00dasalo como quieras<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-c2c7750 elementor-invisible elementor-widget elementor-widget-ha-svg-draw happy-addon ha-svg-draw\" data-id=\"c2c7750\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;slideInLeft&quot;}\" data-widget_type=\"ha-svg-draw.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\n\t\t\t\t<div class=\"ha-svg-draw-container\">\n\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t\n  \n    \n      \n      \n    \n  \n  \n\n\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t<\/div>\n\n\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-inner-section elementor-element elementor-element-0b59028 elementor-section-height-min-height elementor-section-full_width elementor-section-content-top elementor-section-height-default\" data-id=\"0b59028\" data-element_type=\"section\" data-e-type=\"section\" data-settings=\"{&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-no\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-inner-column elementor-element elementor-element-2ba77fe\" data-id=\"2ba77fe\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-956e9fe elementor-widget elementor-widget-eael-fancy-text\" data-id=\"956e9fe\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"eael-fancy-text.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\n\t<div  class=\"eael-fancy-text-container style-1\" data-fancy-text-id=\"956e9fe\" data-fancy-text=\"|un bluetooth speaker|una consola de mezcla|un equipo multi-efectos|un amplificador de instrumento|una interfaz de audio|un estudio portable\" data-fancy-text-transition-type=\"typing\" data-fancy-text-speed=\"50\" data-fancy-text-delay=\"2500\" data-fancy-text-cursor=\"yes\" data-fancy-text-loop=\"yes\" data-fancy-text-action=\"view_port\" >\n\t\t\t\t\t<span class=\"eael-fancy-text-prefix\">CubeVox es mas que  <\/span>\n\t\t\n\t\t\n\t\t\t\t\t<span id=\"eael-fancy-text-956e9fe\" class=\"eael-fancy-text-strings solid-color\">\n\t\t\t\t<noscript>\n\t\t\t\t\tun bluetooth speaker, una consola de mezcla, un equipo multi-efectos, un amplificador de instrumento, una interfaz de audio, un estudio portable\t\t\t\t<\/noscript>\n\t\t\t<\/span>\n\t\t\n\t\t\t<\/div><!-- close .eael-fancy-text-container -->\n\n\t<div class=\"clearfix\"><\/div>\n\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<div class=\"elementor-element elementor-element-90f4429 ha-image-accordion-hover ha-image-accordion-mobile-vertical ha-image-accordion-horizontal elementor-invisible elementor-widget elementor-widget-ha-image-accordion happy-addon ha-image-accordion\" data-id=\"90f4429\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;fadeIn&quot;}\" data-widget_type=\"ha-image-accordion.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t        <div class=\"ha-image-accordion-wrapper\">\n            <div class=\"ha-ia-container\">\n                <div class=\"ha-ia-gallery-wrap\">\n                                            <div style=\"background-image: url('https:\/\/cube-vox.com\/wp-content\/uploads\/recording-studio-banner.webp');\" class=\"ha-ia-item \">\n                            <div class=\"ha-overlay\">\n                                <div class=\"ha-ia-content-wrapper ha_fadeInUp\">\n                                                                                                            <div class=\"ha-ia-content-icon-title ha-ia-icon-left\">\n                                                                                <span class=\"ha-ia-content-title\">Estudio Portable<\/span>\n                                    <\/div>\n                                    <div class=\"ha-ia-content-description\">Graba, edita, mezcla y masteriza como un estudio profesional<\/div>                                                                            <a class=\"ha-ia-content-button\" href=\"#portableStudio\"  >\n                                            Ver m\u00e1s                                        <\/a>\n                                                                    <\/div>\n                            <\/div>\n                        <\/div>\n                                            <div style=\"background-image: url('https:\/\/cube-vox.com\/wp-content\/uploads\/digital-mixing-console-closeup.webp');\" class=\"ha-ia-item \">\n                            <div class=\"ha-overlay\">\n                                <div class=\"ha-ia-content-wrapper ha_fadeInUp\">\n                                                                                                            <div class=\"ha-ia-content-icon-title ha-ia-icon-left\">\n                                                                                <span class=\"ha-ia-content-title\">Sound Mixer<\/span>\n                                    <\/div>\n                                    <div class=\"ha-ia-content-description\">Multiplexa cada entrada y salida, nivela las se\u00f1ales y optimiza el rango din\u00e1mico<\/div>                                                                            <a class=\"ha-ia-content-button\" href=\"#soundMixer\"  >\n                                            Ver m\u00e1s                                        <\/a>\n                                                                    <\/div>\n                            <\/div>\n                        <\/div>\n                                            <div style=\"background-image: url('https:\/\/cube-vox.com\/wp-content\/uploads\/guitarist-adjusting-effects-live.webp');\" class=\"ha-ia-item \">\n                            <div class=\"ha-overlay\">\n                                <div class=\"ha-ia-content-wrapper ha_fadeInUp\">\n                                                                                                            <div class=\"ha-ia-content-icon-title ha-ia-icon-left\">\n                                                                                <span class=\"ha-ia-content-title\">Multi-Effect<\/span>\n                                    <\/div>\n                                    <div class=\"ha-ia-content-description\">Aplica efectos o conjuntos de efectos a cada canal, utiliza el ecualizador param\u00e9trico de 13 bandas para lograr un sonido \u00fanico!<\/div>                                                                            <a class=\"ha-ia-content-button\" href=\"#multiEffect\"  >\n                                            Ver m\u00e1s                                        <\/a>\n                                                                    <\/div>\n                            <\/div>\n                        <\/div>\n                                            <div style=\"background-image: url('https:\/\/cube-vox.com\/wp-content\/uploads\/desktop-audio-interface-closeup.webp');\" class=\"ha-ia-item \">\n                            <div class=\"ha-overlay\">\n                                <div class=\"ha-ia-content-wrapper ha_fadeInUp\">\n                                                                                                            <div class=\"ha-ia-content-icon-title ha-ia-icon-left\">\n                                                                                <span class=\"ha-ia-content-title\">Audio Interface<\/span>\n                                    <\/div>\n                                    <div class=\"ha-ia-content-description\">Con\u00e9ctate y exp\u00e1ndete a travez de Bluetooth MIDI o usando sus puertos USB \/ MIDI convencionales.\n\nDescubre una extrema calidad de sonido en 24 Bits y 192 kHz con amplio rango din\u00e1mico y baja distorsi\u00f3n harm\u00f3nica<\/div>                                                                            <a class=\"ha-ia-content-button\" href=\"#audioInterface\"  >\n                                            Ver m\u00e1s                                        <\/a>\n                                                                    <\/div>\n                            <\/div>\n                        <\/div>\n                                            <div style=\"background-image: url('https:\/\/cube-vox.com\/wp-content\/uploads\/guitarist-jumping-live-performance.webp');\" class=\"ha-ia-item \">\n                            <div class=\"ha-overlay\">\n                                <div class=\"ha-ia-content-wrapper ha_fadeInUp\">\n                                                                                                            <div class=\"ha-ia-content-icon-title ha-ia-icon-left\">\n                                                                                <span class=\"ha-ia-content-title\">Amplificador de Instrumentos<\/span>\n                                    <\/div>\n                                    <div class=\"ha-ia-content-description\">Conecta hasta 4 instrumentos de cualquier tipo y despreoc\u00fapate, CubeVox nivelar\u00e1 la gananancia e impedancia de manera \u00f3ptima<\/div>                                                                            <a class=\"ha-ia-content-button\" href=\"#amplifier\"  >\n                                            Ver m\u00e1s                                        <\/a>\n                                                                    <\/div>\n                            <\/div>\n                        <\/div>\n                                            <div style=\"background-image: url('https:\/\/cube-vox.com\/wp-content\/uploads\/friends-dancing-outdoors-night.webp');\" class=\"ha-ia-item \">\n                            <div class=\"ha-overlay\">\n                                <div class=\"ha-ia-content-wrapper ha_fadeInUp\">\n                                                                                                            <div class=\"ha-ia-content-icon-title ha-ia-icon-left\">\n                                                                                <span class=\"ha-ia-content-title\">Bluetooth | WiFi Speaker<\/span>\n                                    <\/div>\n                                    <div class=\"ha-ia-content-description\">Sonido sin interrupciones!\n\nCon\u00e9ctate a WiFi y contr\u00f3lalo donde estes, o reproduce audio de alta calidad y sin lags gracias a la tecnolog\u00eda Bluetooth 5.1 y AptX<\/div>                                                                            <a class=\"ha-ia-content-button\" href=\"#bluetoothWifiSpeaker\"  >\n                                            Ver m\u00e1s                                        <\/a>\n                                                                    <\/div>\n                            <\/div>\n                        <\/div>\n                                    <\/div>\n            <\/div>\n        <\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-40c6f9e elementor-section-height-min-height elementor-section-items-stretch fx_section elementor-section-boxed elementor-section-height-default\" data-id=\"40c6f9e\" data-element_type=\"section\" data-e-type=\"section\" id=\"portableStudio\" data-settings=\"{&quot;background_background&quot;:&quot;gradient&quot;,&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t\t<div class=\"elementor-background-overlay\"><\/div>\n\t\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-888e45c\" data-id=\"888e45c\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<section class=\"elementor-section elementor-inner-section elementor-element elementor-element-6712b64 elementor-section-full_width elementor-section-height-default elementor-section-height-default\" data-id=\"6712b64\" data-element_type=\"section\" data-e-type=\"section\" data-settings=\"{&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-no\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-inner-column elementor-element elementor-element-fdab6fb\" data-id=\"fdab6fb\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-a158f7e animated-slow elementor-invisible elementor-widget elementor-widget-heading\" data-id=\"a158f7e\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;slideInDown&quot;}\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Estudio Portable<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-3262db6 elementor-invisible elementor-widget elementor-widget-ha-svg-draw happy-addon ha-svg-draw\" data-id=\"3262db6\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;slideInLeft&quot;}\" data-widget_type=\"ha-svg-draw.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\n\t\t\t\t<div class=\"ha-svg-draw-container\">\n\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t\n  \n    \n      \n      \n    \n  \n  \n\n\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t<\/div>\n\n\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-inner-section elementor-element elementor-element-385bc9a elementor-section-full_width elementor-section-height-default elementor-section-height-default\" data-id=\"385bc9a\" data-element_type=\"section\" data-e-type=\"section\" data-settings=\"{&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-no\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-inner-column elementor-element elementor-element-cd08937\" data-id=\"cd08937\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-1999510 animated-slow elementor-invisible elementor-widget elementor-widget-heading\" data-id=\"1999510\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;fadeIn&quot;,&quot;_animation_delay&quot;:300}\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Producci\u00f3n profesional <\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-84acf97 elementor-invisible elementor-widget elementor-widget-heading\" data-id=\"84acf97\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;fadeInDown&quot;,&quot;_animation_delay&quot;:200}\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">donde est\u00e9s<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-inner-section elementor-element elementor-element-0b3fd6b elementor-section-full_width elementor-section-height-default elementor-section-height-default\" data-id=\"0b3fd6b\" data-element_type=\"section\" data-e-type=\"section\" data-settings=\"{&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-no\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-inner-column elementor-element elementor-element-e40c841\" data-id=\"e40c841\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-98ea30b elementor-widget elementor-widget-html\" data-id=\"98ea30b\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<!-- =========================================================\n     CVX SNIPPET STANDARD\n     1) HTML\n     2) CSS\n     3) JS\n========================================================= -->\n<section class=\"cvxScope\">\n\n    <section class=\"cvxPanel\" data-cvx-root=\"portable-studio\" data-ps-area=\"root\" data-ps-mode=\"capture\" style=\"\n    --cvx-ui-scale: clamp(0.89, 100vw \/ 360, 1);\n    --s: var(--cvx-ui-scale);\n    \n    \/* =====================================================\n       PORTABLE STUDIO\n       PARAMETRIZACION LOCAL DEL BLOQUE\n       Orden de lectura:\n       1) Scale\n       2) Content\n       3) Hero\n       4) Layout\n       5) Simulator \/ Toolbar\n       6) Stage \/ Overlay\n       7) Tour\n       8) Motion \/ Performance\n       9) Mobile overrides\n    ======================================================== *\/\n\n    \/* -------------------------\n       1) Scale\n    -------------------------- *\/\n\n    \/* -------------------------\n       8) Motion \/ Performance\n       Demo boot\n    -------------------------- *\/\n\n    \/* =====================================================\n    BASE CONFIG\n\n    --cvx-ps-track-seed: Vocal,Gtr,Bass,Drums,Synth,FX;\n\n    --cvx-ps-demo-xsteps: 6; \/* cu\u00e1ntas veces manda '+' (ZoomX) *\/\n    --cvx-ps-demo-autoprime-cooldown: 1400; \/* ms: anti-jitter; bajalo a 300\u2013600 si quer\u00e9s m\u00e1s agresivo *\/\n    \n    --cvx-ps-demo-seed-cooldown: 900;\n    \n    --cvx-ps-demo-autoprime: 1;\n    --cvx-ps-demo-pre-delay: 180;\n    --cvx-ps-demo-step-delay: 120;\n    ======================================================== *\/\n\n\/* -------------------------\n   2) Content\n   Hero copy\n-------------------------- *\/\n--cvx-ps-readout-gap: 14px;\n--cvx-ps-readout-pad-y: 12px;\n--cvx-ps-readout-pad-x: 12px;\n--cvx-ps-readout-mb: 10px;\n--cvx-ps-mode-title-fs: 12px;\n--cvx-ps-mode-title-lh: 1.1;\n--cvx-ps-mode-desc-mt: 6px;\n--cvx-ps-mode-desc-fs: 12px;\n--cvx-ps-mode-desc-lh: 1.35;\n--cvx-ps-badge-gap: 8px;\n--cvx-ps-badge-pad-y: 6px;\n--cvx-ps-badge-pad-x: 10px;\n--cvx-ps-badge-font: 11px;\n--cvx-ps-meta-mt: 8px;\n--cvx-ps-meta-gap-y: 6px;\n--cvx-ps-meta-gap-x: 10px;\n--cvx-ps-meta-font: 11px;\n\n--cvx-ps-desc-fs: 13px;\n--cvx-ps-desc-lh: 1.55;\n\n--cvx-ps-desc-fs-m: 12px;\n--cvx-ps-desc-lh-m: 1.48;\n\n--cvx-ps-mode-title-fs-m: 11px;\n--cvx-ps-mode-title-lh-m: 1.05;\n--cvx-ps-mode-desc-mt-m: 4px;\n--cvx-ps-mode-desc-fs-m: 10.5px;\n--cvx-ps-mode-desc-lh-m: 1.24;\n\n\/* -------------------------\n   3) Hero\n   Desktop\n-------------------------- *\/\n--cvx-ps-tag-fs: var(--cvx-ps-tag-fs-d, 11px);\n--cvx-ps-tag-pad-y: var(--cvx-ps-tag-pad-y-d, 7px);\n--cvx-ps-tag-pad-x: var(--cvx-ps-tag-pad-x-d, 10px);\n--cvx-ps-hero-tags-mt: var(--cvx-ps-hero-tags-mt-d, 12px);\n--cvx-ps-hero-tags-gap: var(--cvx-ps-hero-tags-gap-d, 10px);\n\n\/* -------------------------\n   3) Hero\n   Mobile\n-------------------------- *\/\n--cvx-ps-tag-fs-m: 10px;\n--cvx-ps-tag-pad-y-m: 6px;\n--cvx-ps-tag-pad-x-m: 9px;\n--cvx-ps-hero-tags-mt-m: 10px;\n--cvx-ps-hero-tags-gap-m: 6px;\n\n\/* HERO tags offsets *\/\n--cvx-ps-hero-tags-tx: var(--cvx-ps-hero-tags-tx-d, 0px);\n--cvx-ps-hero-tags-ty: var(--cvx-ps-hero-tags-ty-d, 0px);\n--cvx-ps-hero-tags-tx-m: 0px;\n--cvx-ps-hero-tags-ty-m: 0px;\n\n\/* -------------------------\n   4) Layout\n   Mobile\n-------------------------- *\/\n\n\/* Card padding *\/\n--cvx-ps-card-pad-y: 10px;\n--cvx-ps-card-pad-x: 12px;\n--cvx-ps-card-pad-y-m: 10px;\n--cvx-ps-card-pad-x-m: 8px;\n\n\/* Stage overlay card (left\/right) \u2014 \u201ccontra\u00edble\u201d en mobile *\/\n--cvx-ps-ov-inset: 14px;\n--cvx-ps-ov-pad: 12px;\n--cvx-ps-ov-gap: 10px;\n\n--cvx-ps-ov-inset-m: 8px;\n--cvx-ps-ov-pad-m: 7px;\n--cvx-ps-ov-gap-m: 6px;\n--cvx-ps-ov-maxw-m: 520px;       \/* bajalo (p.ej. 420px) para contraer en mobile *\/\n\n\/* Stage overlay (mobile) \u2014 tipograf\u00edas\/pills por lado *\/\n--cvx-ps-ovL-badge-fs-m: 10px;\n--cvx-ps-ovL-txt-fs-m: 10px;\n--cvx-ps-ovL-pill-fs-m: 7px;\n--cvx-ps-ovL-pill-py-m: 4px;\n--cvx-ps-ovL-pill-px-m: 8px;\n--cvx-ps-ovL-pill-gap-m: 4px;\n\n--cvx-ps-ovR-badge-fs-m: 10px;\n--cvx-ps-ovR-txt-fs-m: 10px;\n--cvx-ps-ovR-pill-fs-m: 7px;\n--cvx-ps-ovR-pill-py-m: 4px;\n--cvx-ps-ovR-pill-px-m: 8px;\n--cvx-ps-ovR-pill-gap-m: 4px;\n\n\/* -------------------------\n   5) Simulator \/ Toolbar\n   Mobile\n-------------------------- *\/\n--cvx-ps-bar-pad-m: 8px;\n--cvx-ps-bar-gap-m: 8px;\n--cvx-ps-bar-btn-h-m: 30px;\n--cvx-ps-bar-round-m: 30px;\n--cvx-ps-bar-btn-pad-x-m: 8px;\n--cvx-ps-bar-font-m: 10px;\n--cvx-ps-bar-font-round-m: 12px;\n\n\/* Demo block *\/\n--cvx-ps-demo-row-gap-m: 5px;\n--cvx-ps-demo-tip-fs-m: 9.5px;\n--cvx-ps-demo-tip-py-m: 6px;\n--cvx-ps-demo-tip-px-m: 12px;\n--cvx-ps-demo-tip-gap-m: 3px;\n--cvx-ps-demo-link-fs-m: 11px;\n\n\/* Readout \/ tabs \/ controls (mobile) *\/\n--cvx-ps-switch-pad-m: 5px;\n--cvx-ps-switch-gap-m: 4px;\n--cvx-ps-switch-radius-m: 18px;\n--cvx-ps-switch-btn-h-m: 34px;\n--cvx-ps-switch-btn-px-m: 8px;\n--cvx-ps-switch-btn-fs-m: 8.5px;\n--cvx-ps-bar-inner-gap-m: 6px;\n--cvx-ps-bar-nav-fs-m: 12px;\n\n\/* -------------------------\n   7) Tour\n   Mobile\n-------------------------- *\/\n--cvx-ps-guide-card-w-m: 290px;\n--cvx-ps-guide-card-maxw-m: 320px;\n--cvx-ps-guide-card-py-m: 9px;\n--cvx-ps-guide-card-px-m: 10px;\n--cvx-ps-guide-card-gap-m: 3px;\n--cvx-ps-guide-bar-pad-y-m: 6px;\n--cvx-ps-guide-bar-pad-x-m: 8px;\n--cvx-ps-guide-bar-gap-m: 6px;\n--cvx-ps-guide-bar-btn-gap-m: 6px;\n--cvx-ps-guide-bar-btn-h-m: 28px;\n--cvx-ps-guide-bar-btn-px-m: 9px;\n--cvx-ps-guide-bar-btn-fs-m: 10px;\n--cvx-ps-guide-cta-h-m: 32px;\n--cvx-ps-guide-cta-px-m: 12px;\n--cvx-ps-guide-cta-fs-m: 9px;\n\n--cvx-ps-guide-L-k-fs-m: 10px;\n--cvx-ps-guide-L-d-fs-m: 11px;\n--cvx-ps-guide-L-pill-fs-m: 10px;\n--cvx-ps-guide-L-pill-gap-m: 6px;\n\n--cvx-ps-guide-R-k-fs-m: 10px;\n--cvx-ps-guide-R-d-fs-m: 11px;\n--cvx-ps-guide-R-pill-fs-m: 10px;\n--cvx-ps-guide-R-pill-gap-m: 6px;\n\n--cvx-ps-hero-gap: 10px;\n--cvx-ps-hero-mb: 16px;\n\n\/* Hotkeys *\/\n--cvx-ps-hk-up: ArrowUp;\n--cvx-ps-hk-down: ArrowDown;\n--cvx-ps-hk-left: ArrowLeft;\n--cvx-ps-hk-right: ArrowRight;\n--cvx-ps-hk-enter: Enter;\n--cvx-ps-hk-back: Backspace;\n\n--cvx-ps-hk-xplus: +;\n--cvx-ps-hk-xminus: -;\n--cvx-ps-hk-yplus: PageDown;\n--cvx-ps-hk-yminus: PageUp;\n\n--cvx-ps-hk-gain-plus: 3;\n--cvx-ps-hk-gain-minus: 4;\n--cvx-ps-hk-vol-plus: 1;\n--cvx-ps-hk-vol-minus: 2;\n\n--cvx-ps-hk-shift: Shift;\n--cvx-ps-hk-cancel: .;\n--cvx-ps-hk-menu: e;\n--cvx-ps-hk-conf: w;\n\n--cvx-ps-hk-solo: s;\n--cvx-ps-hk-mute: m;\n--cvx-ps-hk-arm: q;\n\n\/* -------------------------\n   4) Layout\n   Desktop\n-------------------------- *\/\n\n\/* Breakpoints *\/\n--cvx-ps-bp-stack: 880px;\n\n\/* Layout *\/\n--cvx-ps-gap: 18px;\n--cvx-ps-hero-gap: 10px;\n\n\/* -------------------------\n   5) Simulator \/ Toolbar\n   Desktop\n-------------------------- *\/\n\n--cvx-ps-mini-py: 5px;                \/* ARM\/S\/M padding vertical *\/\n--cvx-ps-mini-px: 7px;                \/* ARM\/S\/M padding horizontal *\/\n--cvx-ps-mini-font: 10px;             \/* ARM\/S\/M font *\/\n--cvx-ps-mini-text-y: 0px;            \/* micro-ajuste texto mini *\/\n--cvx-ps-mini-hover-y: -1px;          \/* hover mini *\/\n--cvx-ps-mini-rad: 999px;             \/* radio mini *\/\n\n\/* Control bar \u00e2\u20ac\u201d label alignment\/offset *\/\n--cvx-ps-btn-justify: center;         \/* flex-start|center|flex-end *\/\n--cvx-ps-btn-align: center;           \/* flex-start|center|flex-end *\/\n--cvx-ps-btn-tx: 0px;                 \/* label X offset *\/\n--cvx-ps-btn-ty: 0px;                 \/* label Y offset *\/\n--cvx-ps-btn-fs: 8px;                 \/* label font-size *\/\n--cvx-ps-btn-lh: 1;                   \/* label line-height *\/\n--cvx-ps-btn-glyph-tx: 0px;           \/* offset X SOLO para + \/ \u2212 \/ flechas *\/\n--cvx-ps-btn-glyph-ty: 0px;           \/* offset Y SOLO para + \/ \u2212 \/ flechas *\/\n\n\/* Para \u201cal inicio\u201d (izquierda):\n   --cvx-ps-ctl-col-justify: flex-start;\n   --cvx-ps-ctl-col-pad: 2px;\n*\/\n\n\/* Control bar \u00e2\u20ac\u201d geometry *\/\n--cvx-ps-bar-gap: 10px;\n--cvx-ps-bar-pad: 10px;\n\n\/* Button geometry *\/\n--cvx-ps-bar-btn-h: 34px;             \/* altura base pill *\/\n--cvx-ps-bar-btn-pad-x: 6px;          \/* padding horizontal pill *\/\n--cvx-ps-bar-btn-rad: 999px;          \/* radio pill *\/\n--cvx-ps-bar-round: 34px;             \/* di\u00e1metro botones redondos *\/\n\n\/* Typography *\/\n--cvx-ps-bar-font: 11px;              \/* tama\u00f1o texto pills *\/\n--cvx-ps-bar-font-round: 13px;        \/* tama\u00f1o flechas *\/\n--cvx-ps-bar-letter: .08em;           \/* tracking pills *\/\n--cvx-ps-bar-text-y: 0px;             \/* micro-ajuste vertical del texto *\/\n\n\/* Motion *\/\n--cvx-ps-bar-hover-y: -1px;           \/* desplazamiento hover *\/\n--cvx-ps-bar-press-y: 0px;\n\n\/* Separators *\/\n--cvx-ps-bar-sep-h: 22px;\n--cvx-ps-bar-sep-alpha: .10;\n--cvx-ps-bar-sep-inner-alpha: .12;\n\n\/* -------------------------\n   6) Stage \/ Overlay\n   Desktop\n-------------------------- *\/\n\n\/* Mode assets\n   - Left = CubeVox screen \/ Compose Core (inside the simulator card)\n   - Right = Mobile app \/ proof (right column)\n*\/\n\n\/* Left stage: CubeVox screen \/ Compose Core *\/\n--cvx-ps-core-ar: 4 \/ 3;\n--cvx-ps-core-ar-m: 1;\n--cvx-ps-core-bg-pos: 10% 45%;\n--cvx-ps-core-overlay-alpha: .14;\n--cvx-ps-core-bg-size: 115% auto;\n\n\/* Core compositing (OLED photomontage)\n   - Use Z to temporarily place the render on top for alignment,\n     then push it behind to reveal the live OLED.\n*\/\n--cvx-ps-core-perspective: 100%;       \/* stage perspective for Z stacking *\/\n--cvx-ps-core-img-z: 30;               \/* px (negative = behind OLED) *\/\n--cvx-ps-core-img-alpha: 0.9;          \/* 0..1 *\/\n--cvx-ps-core-img-blend: screen;       \/* normal|screen|overlay|multiply *\/\n\n--cvx-ps-oled-z: 0;                    \/* px (OLED plane) *\/\n--cvx-ps-oled-shadow-z: 2;             \/* px (shadow pass above OLED) *\/\n\n\/* OLED emissive tuning (photomontage) *\/\n--cvx-ps-oled-emissive-blend: screen;  \/* screen|plus-lighter *\/\n--cvx-ps-oled-emissive-alpha: .92;     \/* 0..1 *\/\n--cvx-ps-oled-emissive-gain: 1.10;     \/* brightness() *\/\n--cvx-ps-oled-emissive-contrast: 1.05; \/* contrast() *\/\n--cvx-ps-oled-glow-1: 0px;             \/* inner bloom radius *\/\n--cvx-ps-oled-glow-a1: 0;              \/* inner bloom alpha *\/\n--cvx-ps-oled-glow-2: 0px;             \/* outer bloom radius *\/\n--cvx-ps-oled-glow-a2: 0;              \/* outer bloom alpha *\/\n\n\/* 4-corner warp (relative to CORE stage box)\n   p0 TL, p1 TR, p2 BR, p3 BL *\/\n--cvx-ps-oled-p0-x: 21%;\n--cvx-ps-oled-p0-y: 20.5%;\n--cvx-ps-oled-p1-x: 97.5%;\n--cvx-ps-oled-p1-y: 25%;\n--cvx-ps-oled-p2-x: 80%;\n--cvx-ps-oled-p2-y: 64%;\n--cvx-ps-oled-p3-x: 5.7%;\n--cvx-ps-oled-p3-y: 45.8%;\n--cvx-ps-oled-warp-on: 1;              \/* 0\/1 *\/\n--cvx-ps-warp-safe-on: 1;              \/* 0\/1 \u2014 clamp points + keep last good transform *\/\n\n\/* 4-corner warp (mobile overrides) *\/\n--cvx-ps-oled-p0-x-m: 21%;\n    --cvx-ps-oled-p0-y-m: 26.8%;\n    --cvx-ps-oled-p1-x-m: 97.2%;\n    --cvx-ps-oled-p1-y-m: 30%;\n    --cvx-ps-oled-p2-x-m: 79.7%;\n    --cvx-ps-oled-p2-y-m: 59%;\n    --cvx-ps-oled-p3-x-m: 6.2%;\n    --cvx-ps-oled-p3-y-m: 45%;\n\n\/* =====================================================\n   OLED SURFACE COMPOSITING (glass + shadow + clipping)\n   ===================================================== *\/\n\n\/* 1) OLED clipping (recorte + radio) *\/\n--cvx-ps-oled-clip-on: 1;              \/* 0\/1 *\/\n--cvx-ps-oled-clip-radius: 6px;        \/* a ojo: radio del marco en el render *\/\n--cvx-ps-oled-clip-radius-br: 11px;\n\n\/* 1-b) OLED edge feather (bordes suaves) *\/\n--cvx-ps-oled-feather-on: 1;           \/* 0\/1 *\/\n--cvx-ps-oled-feather-px: 2px;         \/* px *\/\n\n\/* 2) OLED glass (reflejo \/ highlight) *\/\n--cvx-ps-oled-glass-img: none;         \/* url(...) | none *\/\n--cvx-ps-oled-glass-alpha: .22;        \/* 0..1 *\/\n--cvx-ps-oled-glass-blend: screen;     \/* screen|overlay|soft-light *\/\n--cvx-ps-oled-glass-filter: none;      \/* e.g., blur(0.4px) contrast(1.05) *\/\n--cvx-ps-oled-glass-z: 1;              \/* px (arriba del canvas) *\/\n\n\/* 3) OLED shadow (sombra\/vignette del bisel) *\/\n--cvx-ps-oled-shadow-img: none;\n--cvx-ps-oled-shadow-alpha: 0;         \/* 0..1 *\/\n--cvx-ps-oled-shadow-blend: multiply;  \/* multiply|overlay|soft-light *\/\n--cvx-ps-oled-shadow-filter: none;     \/* e.g., blur(0.6px) *\/\n--cvx-ps-oled-shadow-z: 2;             \/* px (arriba del glass) *\/\n\n--cvx-ps-core-img-capture: url('\/wp-content\/uploads\/cubevox-hifi-display-detail-render.webp');\n\n\n--cvx-ps-core-img-edit: var(--cvx-ps-core-img-capture);\n--cvx-ps-core-img-mix: var(--cvx-ps-core-img-capture);\n--cvx-ps-core-img-share: var(--cvx-ps-core-img-capture);\n\n\/* Right stage: Mobile \/ Compose App *\/\n--cvx-ps-stage-ar: 4 \/ 4;\n--cvx-ps-stage-overlay-alpha: .14;\n\n--cvx-ps-stage-bg-pos-capture: 50% 100%;\n--cvx-ps-stage-bg-pos-edit:    50% 100%;\n--cvx-ps-stage-bg-pos-mix:     50% 100%;\n--cvx-ps-stage-bg-pos-sync:    85% 30%;\n\n--cvx-ps-stage-bg-size-capture: 180% auto;\n--cvx-ps-stage-bg-size-edit:    160% auto;\n--cvx-ps-stage-bg-size-mix:     150% auto;\n--cvx-ps-stage-bg-size-sync:    150% auto;\n\n--cvx-ps-stage-img-capture: url('\/wp-content\/uploads\/compose-app-waveform-smartphone.webp');\n--cvx-ps-stage-img-edit: url('\/wp-content\/uploads\/compose-app-effects-smartphone-over-shoulder.webp');\n--cvx-ps-stage-img-mix: url('\/wp-content\/uploads\/compose-app-control-smartphone.webp');\n--cvx-ps-stage-img-share: url('\/wp-content\/uploads\/compose-app-projects-smartphone.webp');\n\n\/* Simulator sizing *\/\n--cvx-ps-sim-pad: 0px;\n--cvx-ps-sim-radius: 18px;\n\n\/* Stage overlay card (info box over the stage) *\/\n--cvx-ps-overlaycard-on: 1;            \/* 0\/1 (global) *\/\n--cvx-ps-overlaycard-core-on: 1;       \/* 0\/1 (left core stage) *\/\n--cvx-ps-overlaycard-right-on: 1;      \/* 0\/1 (right stage) *\/\n--cvx-ps-overlaycard-hide-y: 10px;     \/* px *\/\n\n\/* Motion *\/\n--cvx-ps-ease: cubic-bezier(.2,.8,.2,1);\n--cvx-ps-dur: 200ms;\n\n\/* Meter animation (JS) *\/\n--cvx-ps-meter-fps: 26;\n--cvx-ps-meter-slew: .16;\n--cvx-ps-meter-floor: .06;\n--cvx-ps-meter-ceil: .96;\n\n\/* Accent tuning (optional) *\/\n--cvx-ps-accent-capture: var(--cvxAccent);\n--cvx-ps-accent-edit: #8B5CF6;\n--cvx-ps-accent-mix: #22C55E;\n--cvx-ps-accent-share: #38BDF8;\n\n\/* -------------------------\n   7) Tour\n   Desktop\n-------------------------- *\/\n\n\/* Guided tour UI anchor (relative to left image \/ .cvxPSStage--core) *\/\n--cvx-ps-guide-ui-inset: 14px; \/* padding interno desde el borde del stage *\/\n\n\n\">\n\n\n        <!-- =========================================================\n         HERO\n    ========================================================== -->\n        <header class=\"cvxPSHero\">\n            <div class=\"cvxPSHero__txt\">\n\n                <p class=\"cvxKicker\">De idea a sesi\u00f3n en minutos<\/p>\n\n                <p class=\"cvxDesc\">\n                    <strong>Captur\u00e1 ideas<\/strong> con calidad consistente y escal\u00e1 a una <strong>sesi\u00f3n multipista<\/strong> sin cambiar de herramienta.\n                    CubeVox + Compose Studio convierten el \u201csetup\u201d en un <strong>flujo continuo<\/strong>.\n                <\/p>\n                <ul class=\"cvxTags\" aria-label=\"Highlights\">\n                    <li class=\"cvxTag\">Grabaci\u00f3n multipista<\/li>\n                    <li class=\"cvxTag\">FX<\/li>\n                    <li class=\"cvxTag\">Sync + versiones<\/li>\n                <\/ul>\n            <\/div>\n\n        <\/header>\n\n        <!-- =========================================================\n         GRID\n    ========================================================== -->\n        <div class=\"cvxPSGrid\" data-ps-area=\"panel\">\n            <!-- =======================\n           LEFT: STUDIO SIMULATOR\n      ======================== -->\n            <div class=\"cvxCard cvxPSSim\">\n\n\n                <!-- Readout -->\n                <div class=\"cvxPSSim__readout\" aria-live=\"polite\">\n                    <div class=\"cvxPSSim__roL\">\n                        <div class=\"cvxPSSim__modeTitle\" data-ps-mode-title>CAPTURA \u00b7 Take r\u00e1pido<\/div>\n                        <div class=\"cvxPSSim__modeDesc\" data-ps-mode-desc>\n                            Problema: el setup te come la idea. Soluci\u00f3n: pistas listas, ganancia consistente y monitoreo con FX.\n                        <\/div>\n                    <\/div>\n\n                    <div class=\"cvxPSSim__roR\">\n                        <div class=\"cvxPSSim__badge\" data-ps-badge>\n                            <span class=\"dot\" aria-hidden=\"true\"><\/span>\n                            <span class=\"t\" data-ps-badge-text>LOCAL<\/span>\n                        <\/div>\n                        <div class=\"cvxPSSim__meta\">\n                            <span class=\"k\">Tracks<\/span><span class=\"v\" data-ps-tracks>0<\/span>\n                            <span class=\"k\">FX<\/span><span class=\"v\" data-ps-fx>LIVE<\/span>\n                        <\/div>\n                    <\/div>\n                <\/div>\n                <!-- Mode switch -->\n                <div class=\"cvxSwitch cvxPSSim__switch\" role=\"tablist\" aria-label=\"Modo de trabajo\">\n                    <button type=\"button\" class=\"on\" data-ps-mode-btn=\"capture\" role=\"tab\" aria-selected=\"true\">CAPTURA<\/button>\n                    <button type=\"button\" data-ps-mode-btn=\"edit\" role=\"tab\" aria-selected=\"false\">EDICI\u00d3N<\/button>\n                    <button type=\"button\" data-ps-mode-btn=\"mix\" role=\"tab\" aria-selected=\"false\">MEZCLA<\/button>\n                    <button type=\"button\" data-ps-mode-btn=\"share\" role=\"tab\" aria-selected=\"false\">SYNC<\/button>\n                <\/div>\n                <!-- =========================================================\n             CONTROL BAR (navigation + zoom + system) \u2014 replaces old Timeline\/Tracks\/Hint\n        ========================================================== -->\n                <div class=\"cvxPSCtrlBar\" role=\"group\" aria-label=\"Navegaci\u00f3n y controles\">\n                    <div class=\"grp grp--nav\" role=\"group\" aria-label=\"Navegaci\u00f3n\">\n                        <button type=\"button\" class=\"r\" data-ps-ctl=\"nav-up\" aria-label=\"Arriba\"><span class=\"cvxPSBtnTxt\">\u2191<\/span><\/button>\n                        <button type=\"button\" class=\"r\" data-ps-ctl=\"nav-left\" aria-label=\"Izquierda\"><span class=\"cvxPSBtnTxt\">\u2190<\/span><\/button>\n                        <button type=\"button\" class=\"r\" data-ps-ctl=\"nav-right\" aria-label=\"Derecha\"><span class=\"cvxPSBtnTxt\">\u2192<\/span><\/button>\n                        <button type=\"button\" class=\"r\" data-ps-ctl=\"nav-down\" aria-label=\"Abajo\"><span class=\"cvxPSBtnTxt\">\u2193<\/span><\/button>\n                    <\/div>\n\n                    <span class=\"sep sep--group\" aria-hidden=\"true\"><\/span>\n\n                    <div class=\"grp grp--zoom\" role=\"group\" aria-label=\"Zoom\">\n                        <button type=\"button\" class=\"pill\" data-ps-ctl=\"x+\"><span class=\"cvxPSBtnTxt\">X+<\/span><\/button>\n                        <button type=\"button\" class=\"pill\" data-ps-ctl=\"x-\"><span class=\"cvxPSBtnTxt\">X-<\/span><\/button>\n\n\n                        <button type=\"button\" class=\"pill\" data-ps-ctl=\"y+\"><span class=\"cvxPSBtnTxt\">Y+<\/span><\/button>\n                        <button type=\"button\" class=\"pill\" data-ps-ctl=\"y-\"><span class=\"cvxPSBtnTxt\">Y-<\/span><\/button>\n                    <\/div>\n\n                    <span class=\"sep sep--group\" aria-hidden=\"true\"><\/span>\n\n                    <div class=\"grp grp--sys\" role=\"group\" aria-label=\"Control\">\n                        <button type=\"button\" class=\"pill\" data-ps-tgl=\"shift\" aria-pressed=\"false\">SHIFT<\/button>\n\n\n                        <button type=\"button\" class=\"pill\" data-ps-ctl=\"cancel\">Cancel<\/button>\n                        <button type=\"button\" class=\"pill\" data-ps-ctl=\"menu\">Menu<\/button>\n                        <button type=\"button\" class=\"pill\" data-ps-ctl=\"conf\">Conf<\/button>\n                    <\/div>\n                <\/div>\n\n\n\n                <!-- Compose Core DEMO (photomontage target) -->\n                <div class=\"cvxStage cvxPSStage cvxPSStage--core\" style=\"\n            --stage-ar: var(--cvx-ps-core-ar);\n            --stage-img: var(--cvx-ps-core-img);\n            --stage-bg-pos: var(--cvx-ps-core-bg-pos);\n            --stage-overlay-alpha: var(--cvx-ps-core-overlay-alpha);\n          \" role=\"img\" aria-label=\"Compose Studio Core\"> <!-- CORE LAYERS (photomontage): image + live OLED + shadow pass -->\n                    <div class=\"cvxPSCoreLayers\" aria-hidden=\"true\">\n                        <div class=\"cvxPSCoreImg\" aria-hidden=\"true\"><\/div>\n\n                        <div class=\"cvxPSOledZ\" aria-hidden=\"true\">\n                            <div class=\"cvxPSOledWarp\" data-ps-oled-warp aria-hidden=\"true\">\n                                <!--\n                  OLED plane (warped)\n                  - Este contenedor es el \u201cPADRE\u201d del OLED en perspectiva.\n                  - Importante: el CLIP + FEATHER deben vivir ac\u00e1 (padre),\n                    as\u00ed tambi\u00e9n recortan el GLASS y el SHADOW.\n                -->\n                                <div class=\"cvxPSOledMask\" data-ps-oled-mask aria-hidden=\"true\">\n                                    <!-- Payload (canvas vivo \/ UI OLED real) -->\n                                    <div class=\"cvxPSOledMount\" data-ps-mount=\"oled\" aria-hidden=\"true\"><\/div>\n\n                                    <!-- Glass pass (reflejo\/vidrio) \u2014 va arriba del OLED -->\n                                    <div class=\"cvxPSOledGlass\" aria-hidden=\"true\"><\/div>\n\n                                    <!-- Shadow pass (bisel\/sombra) \u2014 va arriba del glass -->\n                                    <div class=\"cvxPSOledShadow\" aria-hidden=\"true\"><\/div>\n                                <\/div>\n                            <\/div>\n                        <\/div>\n                    <\/div>\n\n                    <div class=\"cvxPSStage__overlay\" data-ps-guide-card-target=\"left\">\n                        <p class=\"cvxBadge\" data-ps-guide-title>Compose Studio Core<\/p>\n                        <p class=\"cvxPSStage__txt\" data-ps-guide-desc>\n                            Control\u00e1, edit\u00e1 y sincroniz\u00e1 proyectos sin romper el flujo creativo.\n                        <\/p>\n\n                        <ul class=\"cvxPSStage__pills\" data-ps-guide-pills aria-label=\"Capabilities\">\n                            <li><span class=\"cvxPill\" style=\"--cvx-pill-accent: var(--cvxAccent);\">Multipista<\/span><\/li>\n                            <li><span class=\"cvxPill\" style=\"--cvx-pill-accent: #8B5CF6;\">No destructivo<\/span><\/li>\n                            <li><span class=\"cvxPill\" style=\"--cvx-pill-accent: #22C55E;\">FX<\/span><\/li>\n                            <li><span class=\"cvxPill\" style=\"--cvx-pill-accent: #38BDF8;\">Sync<\/span><\/li>\n                        <\/ul>\n                    <\/div>\n\n                <\/div>\n\n                <!-- Hint -->\n                <div class=\"cvxPSControlsGuideRow\">\n                    <div class=\"cvxTip cvxPSSim__tip\" role=\"note\" aria-label=\"Hint\">\n                        <span class=\"cvxTip__label\">Demo:<\/span>\n                        <span class=\"cvxTip__text\">muestra el flujo principal; la versi\u00f3n final suma ajustes por acci\u00f3n (p. ej., par\u00e1metros de FX) sin cambiar la l\u00f3gica.<\/span>\n                    <\/div>\n\n                    <button type=\"button\" class=\"cvxPSControlsGuideLink\" data-ps-controls-open>\n                        Gu\u00eda de controles\n                    <\/button>\n                <\/div>\n\n            <\/div>\n\n            <!-- =======================\n           RIGHT: STORY + PROOF\n      ======================== -->\n            <div class=\"cvxCard\">\n                <aside class=\"cvxPSAside\">\n                    <div class=\"cvxStage cvxPSStage\" style=\"\n            --stage-ar: var(--cvx-ps-stage-ar);\n            --stage-img: var(--cvx-ps-stage-img);\n            --stage-bg-pos: var(--cvx-ps-stage-bg-pos);\n            --stage-overlay-alpha: var(--cvx-ps-stage-overlay-alpha);\n          \" role=\"img\" aria-label=\"Compose Studio App\">\n                        <div class=\"cvxPSStage__overlay\" data-ps-guide-card-target=\"right\">\n                            <p class=\"cvxBadge\" data-ps-guide-title>Compose Studio App<\/p>\n                            <p class=\"cvxPSStage__txt\" data-ps-guide-desc>\n                                Control\u00e1, edit\u00e1 y sincroniz\u00e1 proyectos sin romper el flujo creativo.\n                            <\/p>\n\n                            <ul class=\"cvxPSStage__pills\" data-ps-guide-pills aria-label=\"Capabilities\">\n                                <li><span class=\"cvxPill\" style=\"--cvx-pill-accent: var(--cvxAccent);\">Multipista<\/span><\/li>\n                                <li><span class=\"cvxPill\" style=\"--cvx-pill-accent: #8B5CF6;\">No destructivo<\/span><\/li>\n                                <li><span class=\"cvxPill\" style=\"--cvx-pill-accent: #22C55E;\">FX<\/span><\/li>\n                                <li><span class=\"cvxPill\" style=\"--cvx-pill-accent: #38BDF8;\">Sync<\/span><\/li>\n                            <\/ul>\n                        <\/div>\n\n                    <\/div>\n\n                    <div class=\"cvxAcc cvxPSAcc\" aria-label=\"Detalles\">\n                        <div class=\"cvxAcc__item is-open\">\n                            <button class=\"cvxAcc__btn\" type=\"button\" aria-expanded=\"true\">\n                                <span class=\"cvxAcc__title\">Qu\u00e9 reemplaza en un home studio<\/span>\n                                <span class=\"cvxAcc__icon\" aria-hidden=\"true\"><\/span>\n                            <\/button>\n                            <div class=\"cvxAcc__body\">\n                                Unifica <b>grabadora<\/b>, <b>interfaz<\/b>, <b>efectos<\/b>, <b>mezcla<\/b> y <b>monitoreo<\/b> en un flujo coherente:\n                                menos cables, menos \u201csetups\u201d y menos puntos de falla.\n                            <\/div>\n                        <\/div>\n\n                        <div class=\"cvxAcc__item\">\n                            <button class=\"cvxAcc__btn\" type=\"button\" aria-expanded=\"false\">\n                                <span class=\"cvxAcc__title\">Del take al proyecto (sin migrar)<\/span>\n                                <span class=\"cvxAcc__icon\" aria-hidden=\"true\"><\/span>\n                            <\/button>\n                            <div class=\"cvxAcc__body\">\n                                Grab\u00e1s una idea y la convert\u00eds en sesi\u00f3n: edici\u00f3n multipista, mezcla y gesti\u00f3n del proyecto desde Compose\/Cloud,\n                                con estructura lista para escalar.\n                            <\/div>\n                        <\/div>\n\n                        <div class=\"cvxAcc__item\">\n                            <button class=\"cvxAcc__btn\" type=\"button\" aria-expanded=\"false\">\n                                <span class=\"cvxAcc__title\">Sync, versiones y colaboraci\u00f3n<\/span>\n                                <span class=\"cvxAcc__icon\" aria-hidden=\"true\"><\/span>\n                            <\/button>\n                            <div class=\"cvxAcc__body\">\n                                Manten\u00e9 proyectos <b>actualizados<\/b>, con <b>control de versiones<\/b> y trabajo colaborativo.\n                                Un estudio port\u00e1til que no se queda \u201caislado\u201d del resto del workflow.\n                            <\/div>\n                        <\/div>\n                    <\/div>\n                <\/aside>\n            <\/div>\n        <\/div>\n\n        <!-- =========================================================\n         GUIDED TOUR (optional onboarding overlay)\n         - All UI is scoped to this widget root\n         - Geometry is computed in JS from data-ps-area targets (post-transform for OLED)\n        ========================================================== -->\n        <div class=\"cvxPSGuide\" data-ps-guide aria-hidden=\"true\">\n            <div class=\"cvxPSGuideMask\" data-ps-guide-mask aria-hidden=\"true\">\n                <svg class=\"cvxPSGuideMaskSvg\" data-ps-guide-mask-svg aria-hidden=\"true\" focusable=\"false\" preserveAspectRatio=\"none\">\n                    <path data-ps-guide-mask-path fill-rule=\"evenodd\"><\/path>\n                <\/svg>\n            <\/div>\n\n            <div class=\"cvxPSGuideRadars\" data-ps-guide-radars aria-hidden=\"true\"><\/div>\n\n            <div class=\"cvxPSGuideCards\" aria-hidden=\"false\">\n                <article class=\"cvxPSGuideCard cvxPSGuideCard--left\" data-ps-guide-card=\"left\" aria-live=\"polite\">\n                    <p class=\"k\" data-ps-guide-title><\/p>\n                    <p class=\"d\" data-ps-guide-desc><\/p>\n                    <ul class=\"cvxPSGuidePills\" data-ps-guide-pills><\/ul>\n                <\/article>\n\n                <article class=\"cvxPSGuideCard cvxPSGuideCard--right\" data-ps-guide-card=\"right\" aria-live=\"polite\">\n                    <p class=\"k\" data-ps-guide-title><\/p>\n                    <p class=\"d\" data-ps-guide-desc><\/p>\n                    <ul class=\"cvxPSGuidePills\" data-ps-guide-pills><\/ul>\n                <\/article>\n            <\/div>\n\n            <div class=\"cvxPSGuideBar\" data-ps-guide-bar aria-hidden=\"false\">\n                <div class=\"cvxPSGuideBar__meta\" data-ps-guide-meta><\/div>\n\n                <div class=\"cvxPSGuideBar__btns\" role=\"group\" aria-label=\"Guided tour controls\">\n                    <button type=\"button\" class=\"b\" data-ps-guide-back>Back<\/button>\n                    <button type=\"button\" class=\"b b--pri\" data-ps-guide-next>Next<\/button>\n                    <span class=\"sep\" aria-hidden=\"true\"><\/span>\n                    <button type=\"button\" class=\"b\" data-ps-guide-reset>Exit<\/button>\n                <\/div>\n            <\/div>\n\n            <div class=\"cvxPSGuideCTA\" data-ps-guide-cta aria-hidden=\"false\">\n                <button type=\"button\" class=\"b b--pri\" data-ps-guide-start>Iniciar tour guiado<\/button>\n            <\/div>\n\n            <div class=\"cvxPSGuideCTA\" data-ps-guide-done hidden>\n                <div class=\"cvxPSGuideDone__msg\">Listo. Exploralo libremente.<\/div>\n                <button type=\"button\" class=\"b b--pri\" data-ps-guide-close>OK<\/button>\n            <\/div>\n\n            <div class=\"cvxPSToast\" data-ps-guide-toast role=\"status\" aria-live=\"polite\" aria-atomic=\"true\">\n                <div class=\"m\" data-ps-guide-toast-msg><\/div>\n            <\/div>\n\n        <\/div>\n        <script type=\"application\/json\" data-cvx-ps-guide>\n            {\n                \"version\": 1,\n                \"options\": {\n                    \"autoStart\": \"never\",\n                    \"startOnceKey\": \"cvx_ps_tour_v1_done\",\n                    \"modePolicy\": \"followUser\",\n                    \"respectReducedMotion\": true,\n                    \"motionMs\": 200,\n                    \"radarPulseMs\": 2200,\n                    \"zIndex\": 50,\n                    \"dim\": 0.2,\n                    \"featherPx\": 18\n                },\n                \"modes\": {\n                    \"capture\": [{\n                            \"id\": \"c2_create_track\",\n                            \"enabled\": true,\n                            \"cards\": {\n                                \"left\": {\n                                    \"title\": \"Arranquemos una toma\",\n                                    \"desc\": \"Empez\u00e1 con una pista base y dej\u00e1 el proyecto listo para sumar capas.\",\n                                    \"pills\": [\"En segundos\", \"Captura inmediata\"]\n                                },\n                                \"right\": {\n                                    \"title\": \"Compose Studio App\",\n                                    \"desc\": \"Lo que arm\u00e1s en CubeVox aparece en la app para revisar y continuar cuando quieras.\",\n                                    \"pills\": [\"Dispositivo \u2194 App\", \"Continuidad\"]\n                                }\n                            },\n                            \"ops\": {\n                                \"oledHotkeys\": [\"*\"],\n                                \"noSeedMs\": 1200\n                            },\n                            \"enter\": {\n                                \"hotkeys\": []\n                            },\n                            \"focus\": {\n                                \"radars\": [{\n                                    \"enabled\": true,\n                                    \"area\": \"oled\",\n                                    \"selector\": null,\n                                    \"anchor\": \"center\",\n                                    \"xN\": 0.18,\n                                    \"yN\": 0.28,\n                                    \"rN\": 0.18\n                                }]\n                            },\n                            \"advance\": {\n                                \"type\": \"tap\",\n                                \"tap\": {\n                                    \"area\": \"oled\",\n                                    \"xN\": 0.18,\n                                    \"yN\": 0.28,\n                                    \"rN\": 0.38,\n                                    \"swallow\": true\n                                }\n                            }\n                        },\n                        {\n                            \"id\": \"c3_mnu_open\",\n                            \"enabled\": true,\n                            \"cards\": {\n                                \"left\": {\n                                    \"title\": \"Configuraci\u00f3n de entrada del canal\",\n                                    \"desc\": \"Eleg\u00ed SRC; luego activ\u00e1 ARM para dejar el canal listo.\",\n                                    \"pills\": [\"SRC\", \"ARM\"]\n                                },\n                                \"right\": {}\n                            },\n                            \"enter\": {\n                                \"hotkeys\": [{\n                                    \"key\": \"a\",\n                                    \"preDelayMs\": 0\n                                }]\n                            },\n                            \"focus\": {\n                                \"radars\": [\n\n                                    {\n                                        \"enabled\": true,\n                                        \"area\": \"panel\",\n                                        \"selector\": \".cvxPSCtrlBar  [data-ps-ctl=\\\"conf\\\"]\",\n                                        \"anchor\": \"center\",\n                                        \"rPct\": 1\n                                    }\n                                ],\n                                \"mask\": {}\n                            },\n                            \"advance\": {\n                                \"type\": \"click\",\n                                \"click\": {\n                                    \"area\": \"panel\",\n                                    \"selector\": \".cvxPSCtrlBar [data-ps-ctl=\\\"conf\\\"]\",\n                                    \"swallow\": false\n                                }\n                            }\n                        },\n                        {\n                            \"id\": \"c4_mnu_ok\",\n                            \"enabled\": true,\n                            \"cards\": {\n                                \"left\": {},\n                                \"right\": {}\n                            },\n                            \"enter\": {\n                                \"hotkeys\": [{\n                                    \"key\": \"ArrowDown\",\n                                    \"preDelayMs\": 500\n                                }, {\n                                    \"key\": \"ArrowDown\",\n                                    \"preDelayMs\": 100\n                                }, {\n                                    \"key\": \"ArrowDown\",\n                                    \"preDelayMs\": 100\n                                }, {\n                                    \"key\": \"ArrowDown\",\n                                    \"preDelayMs\": 100\n                                }, {\n                                    \"key\": \"ArrowDown\",\n                                    \"preDelayMs\": 100\n                                }, {\n                                    \"key\": \"ArrowDown\",\n                                    \"preDelayMs\": 100\n                                }, {\n                                    \"key\": \"ArrowDown\",\n                                    \"preDelayMs\": 100\n                                }]\n                            },\n                            \"focus\": {\n                                \"radars\": [{\n                                    \"enabled\": true,\n                                    \"area\": \"oled\",\n                                    \"selector\": null,\n                                    \"anchor\": \"center\",\n                                    \"xN\": 0.8,\n                                    \"yN\": 0.6,\n                                    \"rN\": 0.04\n                                }],\n                                \"mask\": {\n                                    \"enabled\": true,\n                                    \"dim\": 0.38,\n                                    \"featherPx\": 14,\n                                    \"holes\": [{\n                                        \"enabled\": true,\n                                        \"area\": \"oled\",\n                                        \"selector\": null,\n                                        \"xN\": 0.8,\n                                        \"yN\": 0.6,\n                                        \"wN\": 0.34,\n                                        \"hN\": 0.54,\n                                        \"rN\": 0.05\n                                    }]\n                                }\n                            },\n\n                            \"advance\": {\n                                \"type\": \"tap\",\n                                \"tap\": {\n                                    \"area\": \"oled\",\n                                    \"xN\": 0.8,\n                                    \"yN\": 0.6,\n                                    \"rN\": 0.06\n                                }\n                            }\n\n                        },\n\n                        {\n                            \"id\": \"c5_arm_ready\",\n                            \"enabled\": true,\n                            \"cards\": {\n                                \"left\": {},\n                                \"right\": {}\n                            },\n                            \"enter\": {\n                                \"hotkeys\": [{\n                                    \"key\": \".\",\n                                    \"preDelayMs\": 0\n                                }]\n                            },\n                            \"focus\": {\n                                \"radars\": [{\n                                    \"enabled\": true,\n                                    \"area\": \"oled\",\n                                    \"selector\": null,\n                                    \"anchor\": \"center\",\n                                    \"xN\": 0.12,\n                                    \"yN\": 0.24,\n                                    \"rN\": 0.04\n                                }]\n                            },\n                            \"advance\": {\n                                \"type\": \"tap\",\n                                \"tap\": {\n                                    \"area\": \"oled\",\n                                    \"selector\": null,\n                                    \"anchor\": \"center\",\n                                    \"xN\": 0.12,\n                                    \"yN\": 0.24,\n                                    \"rN\": 0.05,\n                                    \"swallow\": false\n                                }\n                            }\n                        },\n\n                        {\n                            \"id\": \"c6_rec_loop\",\n                            \"enabled\": true,\n                            \"cards\": {\n                                \"left\": {\n                                    \"title\": \"Grab\u00e1 y repet\u00ed por regi\u00f3n\",\n                                    \"desc\": \"Listo el canal: ahora es tocar y registrar. REC arranca la pasada; para retakes, marc\u00e1 una regi\u00f3n y repet\u00ed solo ese tramo.\",\n                                    \"pills\": [\"REC\", \"STOP\", \"LOOP\"]\n                                },\n                                \"right\": {}\n                            },\n                            \"enter\": {\n                                \"hotkeys\": []\n                            },\n                            \"focus\": {\n                                \"radars\": [{\n                                    \"enabled\": true,\n                                    \"area\": \"oled\",\n                                    \"selector\": null,\n                                    \"anchor\": \"center\",\n                                    \"xN\": 0.517,\n                                    \"yN\": 0.1,\n                                    \"rN\": 0.08\n                                }],\n                                \"mask\": {\n                                    \"enabled\": true,\n                                    \"dim\": 0.38,\n                                    \"featherPx\": 14,\n                                    \"holes\": [{\n                                        \"enabled\": true,\n                                        \"area\": \"oled\",\n                                        \"selector\": null,\n                                        \"xN\": 0.517,\n                                        \"yN\": 0.1,\n                                        \"wN\": 0.34,\n                                        \"hN\": 0.54,\n                                        \"rN\": 0.08\n                                    }]\n                                }\n                            },\n                            \"advance\": {\n                                \"type\": \"tap\",\n                                \"tap\": {\n                                    \"area\": \"oled\",\n                                    \"selector\": null,\n                                    \"anchor\": \"center\",\n                                    \"xN\": 0.517,\n                                    \"yN\": 0.1,\n                                    \"rN\": 0.08,\n                                    \"swallow\": false\n                                }\n                            }\n                        },\n                        {\n                            \"id\": \"c7_set_gain\",\n                            \"enabled\": true,\n                            \"cards\": {\n                                \"left\": {\n                                    \"title\": \"Entrada consistente\",\n                                    \"desc\": \"Ajust\u00e1 la ganancia para optimizar el rango din\u00e1mico y evitar recortes. Cuando termines, hace clic en Next\",\n                                    \"pills\": [\"HEADROOM\", \"GAIN\"]\n                                },\n                                \"right\": {}\n                            },\n                            \"enter\": {\n                                \"hotkeys\": []\n                            },\n                            \"focus\": {\n                                \"radars\": [{\n                                    \"enabled\": true,\n                                    \"area\": \"oled\",\n                                    \"selector\": null,\n                                    \"anchor\": \"center\",\n                                    \"xN\": 0.18,\n                                    \"yN\": 0.22,\n                                    \"rN\": 0.1\n                                }],\n                                \"mask\": {\n                                    \"enabled\": false,\n                                    \"dim\": 0.38,\n                                    \"featherPx\": 14,\n                                    \"holes\": [{\n                                        \"enabled\": true,\n                                        \"area\": \"oled\",\n                                        \"selector\": null,\n                                        \"xN\": 0.517,\n                                        \"yN\": 0.135,\n                                        \"wN\": 0.34,\n                                        \"hN\": 0.54,\n                                        \"rN\": 0.08\n                                    }]\n                                }\n                            },\n                            \"advance\": {\n                                \"type\": \"tap\",\n                                \"tap\": {\n                                    \"area\": \"oled\",\n                                    \"selector\": null,\n                                    \"anchor\": \"center\",\n                                    \"xN\": 0.18,\n                                    \"yN\": 0.22,\n                                    \"rN\": 0.1,\n                                    \"swallow\": false\n                                }\n                            }\n                        },\n                        {\n                            \"id\": \"c8_mode_end\",\n                            \"enabled\": true,\n                            \"cards\": {\n                                \"left\": {},\n                                \"right\": {}\n                            },\n                            \"enter\": {\n                                \"hotkeys\": []\n                            },\n\n                            \"advance\": {\n                                \"type\": \"next\"\n                            }\n                        }\n                    ],\n\n                    \"edit\": [{\n                            \"id\": \"e1_add_all_track\",\n                            \"enabled\": true,\n                            \"cards\": {\n                                \"left\": {\n                                    \"title\": \"Expansi\u00f3n a multi-track\",\n                                    \"desc\": \"Perfecto!, ahora carguemos las pistas de nuestros otros instrumentos.\",\n                                    \"pills\": [\"Multitrack\", \"Expanci\u00f3n\"]\n\n                                },\n                                \"right\": {\n                                    \"title\": \"Compose Studio App\",\n                                    \"desc\": \"Edici\u00f3n no destructiva para ordenar y decidir r\u00e1pido dentro del proyecto.\",\n                                    \"pills\": [\"No destructivo\", \"Edici\u00f3n\"]\n\n                                }\n                            },\n                            \"enter\": {\n                                \"hotkeys\": [{\n                                    \"key\": \".\",\n                                    \"preDelayMs\": 0\n                                }, {\n                                    \"key\": \"PageUp\",\n                                    \"preDelayMs\": 500\n                                }]\n                            },\n                            \"focus\": {\n                                \"radars\": [{\n                                    \"enabled\": true,\n                                    \"area\": \"oled\",\n                                    \"selector\": null,\n                                    \"anchor\": \"center\",\n                                    \"xN\": 0.15,\n                                    \"yN\": 0.38,\n                                    \"rN\": 0.1\n                                }]\n                            },\n                            \"advance\": {\n                                \"type\": \"tap\",\n                                \"tap\": {\n                                    \"area\": \"oled\",\n                                    \"selector\": null,\n                                    \"anchor\": \"center\",\n                                    \"xN\": 0.15,\n                                    \"yN\": 0.38,\n                                    \"rN\": 0.1,\n                                    \"swallow\": true\n                                }\n                            }\n                        },\n                        {\n                            \"id\": \"e2_shift_multitrack\",\n                            \"enabled\": true,\n                            \"cards\": {\n                                \"left\": {\n                                    \"title\": \"Eleg\u00ed qu\u00e9 pistas editar\",\n                                    \"desc\": \"Con SHIFT seleccion\u00e1s varias pistas para editar de manera m\u00faltiple.\",\n                                    \"pills\": [\"SHIFT\", \"Multi-track\"]\n                                },\n                                \"right\": {}\n                            },\n                            \"enter\": {\n                                \"hotkeys\": [{\n                                    \"key\": \"z\",\n                                    \"preDelayMs\": 500\n                                }, {\n                                    \"key\": \"z\",\n                                    \"preDelayMs\": 100\n                                }, {\n                                    \"key\": \"z\",\n                                    \"preDelayMs\": 100\n                                }, {\n                                    \"key\": \"z\",\n                                    \"preDelayMs\": 100\n                                }, {\n                                    \"key\": \"PageUp\",\n                                    \"preDelayMs\": 100\n                                }, {\n                                    \"key\": \"PageUp\",\n                                    \"preDelayMs\": 100\n                                }]\n                            },\n                            \"focus\": {\n                                \"radars\": [\n\n                                    {\n                                        \"enabled\": true,\n                                        \"area\": \"panel\",\n                                        \"selector\": \".cvxPSCtrlBar  [data-ps-tgl=\\\"shift\\\"]\",\n                                        \"anchor\": \"center\",\n                                        \"rPct\": 1\n                                    }\n                                ],\n                                \"mask\": {}\n                            },\n                            \"advance\": {\n                                \"type\": \"click\",\n                                \"click\": {\n                                    \"area\": \"panel\",\n                                    \"selector\": \".cvxPSCtrlBar [data-ps-tgl=\\\"shift\\\"]\",\n                                    \"swallow\": false\n                                }\n                            }\n                        },\n                        {\n                            \"id\": \"e3_shift_multitrack_sel\",\n                            \"enabled\": true,\n                            \"cards\": {\n                                \"left\": {},\n                                \"right\": {}\n                            },\n                            \"enter\": {\n                                \"hotkeys\": []\n                            },\n                            \"focus\": {\n                                \"radars\": [{\n                                    \"enabled\": true,\n                                    \"area\": \"oled\",\n                                    \"selector\": null,\n                                    \"anchor\": \"center\",\n                                    \"xN\": 0.2,\n                                    \"yN\": 0.1,\n                                    \"rN\": 0.04\n                                }]\n                            },\n                            \"advance\": {\n                                \"type\": \"tap\",\n                                \"tap\": {\n                                    \"area\": \"oled\",\n                                    \"selector\": null,\n                                    \"anchor\": \"center\",\n                                    \"xN\": 0.2,\n                                    \"yN\": 0.1,\n                                    \"rN\": 0.04,\n                                    \"swallow\": false\n                                }\n                            }\n                        },\n                        {\n                            \"id\": \"e4_drag_region\",\n                            \"enabled\": true,\n                            \"cards\": {\n                                \"left\": {\n                                    \"title\": \"Marc\u00e1 una regi\u00f3n\",\n                                    \"desc\": \"Arrastr\u00e1 para definir el tramo a trabajar en las pistas seleccionadas.\",\n                                    \"pills\": [\"Regi\u00f3n\", \"Arrastrar\"]\n                                },\n                                \"right\": {}\n                            },\n                            \"enter\": {\n                                \"hotkeys\": []\n                            },\n                            \"focus\": {\n                                \"radars\": [{\n                                    \"enabled\": true,\n                                    \"area\": \"oled\",\n                                    \"selector\": null,\n                                    \"anchor\": \"center\",\n                                    \"xN\": 0.55,\n                                    \"yN\": 0.47,\n                                    \"rN\": 0.5\n                                }],\n                                \"mask\": {\n                                    \"enabled\": true,\n                                    \"dim\": 0.78,\n                                    \"featherPx\": 20,\n                                    \"delayMs\": 120,\n                                    \"holdMs\": 0,\n                                    \"holes\": [{\n                                        \"enabled\": true,\n                                        \"area\": \"oled\",\n                                        \"selector\": null,\n                                        \"paddingPx\": 0,\n                                        \"radiusPx\": 14,\n                                        \"xN\": 0.55,\n                                        \"yN\": 0.47,\n                                        \"wN\": 0.92,\n                                        \"hN\": 0.3\n                                    }]\n                                }\n                            },\n                            \"advance\": {\n                                \"type\": \"tap\",\n                                \"tap\": {\n                                    \"area\": \"oled\",\n                                    \"selector\": null,\n                                    \"anchor\": \"center\",\n                                    \"xN\": 0.55,\n                                    \"yN\": 0.47,\n                                    \"rN\": 0.5,\n                                    \"swallow\": false\n                                }\n                            }\n                        },\n                        {\n                            \"id\": \"e5_open_edit_menu\",\n                            \"enabled\": true,\n                            \"cards\": {\n                                \"left\": {\n                                    \"title\": \"Abr\u00ed el menu de edici\u00f3n\",\n                                    \"desc\": \"Desde EDIT pod\u00e9s aplicar varias acciones sobre la regi\u00f3n activa.\",\n                                    \"pills\": [\"EDIT\", \"Regi\u00f3n\"]\n                                },\n                                \"right\": {}\n                            },\n                            \"enter\": {\n                                \"hotkeys\": []\n                            },\n                            \"focus\": {\n                                \"radars\": [{\n                                    \"enabled\": true,\n                                    \"area\": \"panel\",\n                                    \"selector\": \".cvxPSCtrlBar  [data-ps-ctl=\\\"menu\\\"]\",\n                                    \"anchor\": \"center\",\n                                    \"rPct\": 0.85\n                                }],\n                                \"mask\": {\n                                    \"enabled\": false,\n                                    \"holes\": []\n                                }\n                            },\n                            \"advance\": {\n                                \"type\": \"click\",\n                                \"click\": {\n                                    \"area\": \"panel\",\n                                    \"selector\": \".cvxPSCtrlBar  [data-ps-ctl=\\\"menu\\\"]\",\n                                    \"swallow\": false\n                                }\n                            }\n                        },\n                        {\n                            \"id\": \"e6_apply_fx_or_fade\",\n                            \"enabled\": true,\n                            \"cards\": {\n                                \"left\": {\n                                    \"title\": \"Edici\u00f3n no destructiva\",\n                                    \"desc\": \"Eleg\u00ed CUT para quitar este tramo. Despu\u00e9s, si hace falta, aplic\u00e1s FADE o FX.\",\n                                    \"pills\": [\"CUT\/SPLIT\", \"FX\", \"FD IN\/OUT\"]\n                                },\n                                \"right\": {}\n                            },\n                            \"enter\": {\n                                \"hotkeys\": []\n                            },\n                            \"focus\": {\n                                \"radars\": [{\n                                    \"enabled\": true,\n                                    \"area\": \"panel\",\n                                    \"selector\": \".cvxPSCtrlBar  [data-ps-ctl=\\\"nav-down\\\"]\",\n                                    \"anchor\": \"center\",\n                                    \"rPct\": 0.85\n                                }, {\n                                    \"enabled\": true,\n                                    \"area\": \"panel\",\n                                    \"selector\": \".cvxPSCtrlBar  [data-ps-ctl=\\\"nav-up\\\"]\",\n                                    \"anchor\": \"center\",\n                                    \"rPct\": 0.85\n                                }, {\n                                    \"enabled\": true,\n                                    \"area\": \"oled\",\n                                    \"selector\": null,\n                                    \"anchor\": \"center\",\n                                    \"xN\": 0.42,\n                                    \"yN\": 0.4,\n                                    \"rN\": 0.5\n                                }]\n                            },\n                            \"advance\": {\n                                \"type\": \"tap\",\n                                \"tap\": {\n                                    \"area\": \"oled\",\n                                    \"selector\": null,\n                                    \"anchor\": \"center\",\n                                    \"xN\": 0.42,\n                                    \"yN\": 0.4,\n                                    \"rN\": 0.5,\n                                    \"swallow\": false\n                                }\n                            }\n                        }\n                    ],\n\n                    \"mix\": [{\n                            \"id\": \"m1_zoom_y\",\n                            \"enabled\": true,\n                            \"cards\": {\n                                \"left\": {\n                                    \"title\": \"De panorama a ajuste fino\",\n                                    \"desc\": \"Compar\u00e1 el arreglo completo, aisl\u00e1 lo que quer\u00e9s revisar y ajust\u00e1 VOL en x1.\",\n                                    \"pills\": [\"x1\", \"x2\", \"x4\"]\n                                },\n                                \"right\": {\n                                    \"title\": \"Compose Studio App\",\n                                    \"desc\": \"Mezcla y control del proyecto con continuidad entre dispositivo y app.\",\n                                    \"pills\": [\"Mezcla\", \"Control\"]\n                                }\n                            },\n                            \"enter\": {\n                                \"hotkeys\": []\n                            },\n                            \"focus\": {\n                                \"radars\": [{\n                                    \"enabled\": true,\n                                    \"area\": \"panel\",\n                                    \"selector\": \"[data-ps-ctl=\\\"y+\\\"]\",\n                                    \"anchor\": \"center\",\n                                    \"rPct\": 0.9\n                                }],\n                                \"mask\": {\n                                    \"enabled\": false,\n                                    \"holes\": []\n                                }\n                            },\n                            \"advance\": {\n                                \"type\": \"click\",\n                                \"click\": {\n                                    \"area\": \"panel\",\n                                    \"selector\": \".cvxPSCtrlBar  [data-ps-ctl=\\\"y+\\\"]\",\n                                    \"swallow\": false\n                                }\n                            }\n                        },\n                        {\n                            \"id\": \"m2_zoom_y\",\n                            \"enabled\": true,\n                            \"cards\": {\n                                \"left\": {},\n                                \"right\": {}\n                            },\n                            \"enter\": {\n                                \"hotkeys\": []\n                            },\n                            \"focus\": {\n                                \"radars\": [{\n                                    \"enabled\": true,\n                                    \"area\": \"panel\",\n                                    \"selector\": \"[data-ps-ctl=\\\"y+\\\"]\",\n                                    \"anchor\": \"center\",\n                                    \"rPct\": 0.9\n                                }]\n                            },\n                            \"advance\": {\n                                \"type\": \"click\",\n                                \"click\": {\n                                    \"area\": \"panel\",\n                                    \"selector\": \".cvxPSCtrlBar  [data-ps-ctl=\\\"y+\\\"]\",\n                                    \"swallow\": false\n                                }\n                            }\n                        },\n                        {\n                            \"id\": \"m3_track_nivel\",\n                            \"enabled\": true,\n                            \"cards\": {\n                                \"left\": {\n                                    \"title\": \"Ajuste de mezcla (x1)\",\n                                    \"desc\": \"En x1 ajust\u00e1s VOL para empujar o traer atr\u00e1s cada pista sin tocar el resto.\",\n                                    \"pills\": [\"Niveles\", \"Mezcla\"]\n                                },\n                                \"right\": {}\n                            },\n                            \"enter\": {\n                                \"hotkeys\": []\n                            },\n                            \"focus\": {\n                                \"radars\": [{\n                                    \"enabled\": true,\n                                    \"area\": \"oled\",\n                                    \"selector\": null,\n                                    \"anchor\": \"center\",\n                                    \"xN\": 0.17,\n                                    \"yN\": 0.3,\n                                    \"rN\": 0.1\n                                }]\n                            },\n                            \"advance\": {\n                                \"type\": \"tap\",\n                                \"tap\": {\n                                    \"area\": \"oled\",\n                                    \"selector\": null,\n                                    \"anchor\": \"center\",\n                                    \"xN\": 0.17,\n                                    \"yN\": 0.3,\n                                    \"rN\": 0.1,\n                                    \"swallow\": false\n                                }\n                            }\n                        },\n                        {\n                            \"id\": \"m4_solo_mute\",\n                            \"enabled\": true,\n                            \"cards\": {\n                                \"left\": {\n                                    \"title\": \"Compar\u00e1 sin perder el resto\",\n                                    \"desc\": \"Us\u00e1 SOLO\/MUTE para tomar decisiones de niveles y escena.\",\n                                    \"pills\": [\"SOLO\", \"MUTE\"]\n                                },\n                                \"right\": {}\n                            },\n                            \"enter\": {\n                                \"hotkeys\": []\n                            },\n                            \"focus\": {\n                                \"radars\": [{\n                                    \"enabled\": true,\n                                    \"area\": \"oled\",\n                                    \"selector\": null,\n                                    \"anchor\": \"center\",\n                                    \"xN\": 0.27,\n                                    \"yN\": 0.3,\n                                    \"rN\": 0.15\n                                }]\n                            },\n                            \"advance\": {\n                                \"type\": \"tap\",\n                                \"tap\": {\n                                    \"area\": \"oled\",\n                                    \"selector\": null,\n                                    \"anchor\": \"center\",\n                                    \"xN\": 0.27,\n                                    \"yN\": 0.3,\n                                    \"rN\": 0.15,\n                                    \"swallow\": false\n                                }\n                            }\n                        },\n                        {\n                            \"id\": \"m5_master_menu\",\n                            \"enabled\": true,\n                            \"cards\": {\n                                \"left\": {\n                                    \"title\": \"Monitoreo por pista\",\n                                    \"desc\": \"MASTER te deja elegir el OUT global (SPK\/HP\/EXP) y, por separado, el MON por track para armar escuchas diferentes sin tocar el mix.\",\n                                    \"pills\": [\"MASTER\", \"MON\/Track\", \"OUT\"]\n\n                                },\n                                \"right\": {}\n                            },\n                            \"enter\": {\n                                \"hotkeys\": []\n                            },\n                            \"focus\": {\n                                \"radars\": [{\n                                    \"enabled\": true,\n                                    \"area\": \"panel\",\n                                    \"selector\": \".cvxPSCtrlBar  [data-ps-ctl=\\\"conf\\\"]\",\n                                    \"anchor\": \"center\",\n                                    \"rPct\": 0.85\n                                }]\n                            },\n                            \"advance\": {\n                                \"type\": \"click\",\n                                \"click\": {\n                                    \"area\": \"panel\",\n                                    \"selector\": \".cvxPSCtrlBar  [data-ps-ctl=\\\"conf\\\"]\",\n                                    \"swallow\": false\n                                }\n                            }\n                        },\n                        {\n                            \"id\": \"m6_master_menu_sel\",\n                            \"enabled\": true,\n                            \"cards\": {\n                                \"left\": {},\n                                \"right\": {}\n                            },\n                            \"enter\": {\n                                \"hotkeys\": []\n                            },\n                            \"focus\": {\n                                \"radars\": [{\n                                    \"enabled\": true,\n                                    \"area\": \"oled\",\n                                    \"selector\": null,\n                                    \"anchor\": \"center\",\n                                    \"xN\": 0.7,\n                                    \"yN\": 0.5,\n                                    \"rN\": 0.4\n                                }, {\n                                    \"enabled\": true,\n                                    \"area\": \"panel\",\n                                    \"selector\": \".cvxPSCtrlBar  [data-ps-ctl=\\\"nav-down\\\"]\",\n                                    \"anchor\": \"center\",\n                                    \"rPct\": 0.85\n                                }, {\n                                    \"enabled\": true,\n                                    \"area\": \"panel\",\n                                    \"selector\": \".cvxPSCtrlBar  [data-ps-ctl=\\\"nav-up\\\"]\",\n                                    \"anchor\": \"center\",\n                                    \"rPct\": 0.85\n                                }]\n                            },\n\n                            \"advance\": {\n                                \"type\": \"tap\",\n                                \"tap\": {\n                                    \"area\": \"oled\",\n                                    \"xN\": 0.7,\n                                    \"yN\": 0.5,\n                                    \"rN\": 0.4,\n                                    \"swallow\": false\n                                }\n                            }\n                        }\n                    ],\n\n                    \"sync\": [{\n                            \"id\": \"s1_local_cloud\",\n                            \"enabled\": true,\n                            \"cards\": {\n                                \"left\": {\n                                    \"title\": \"Proyecto vivo\",\n                                    \"desc\": \"Decid\u00ed si el proyecto queda local o se sincroniza para continuarlo despu\u00e9s.\",\n                                    \"pills\": [\"Local\", \"Cloud\"]\n                                },\n                                \"right\": {\n                                    \"title\": \"Projects\",\n                                    \"desc\": \"Tus proyectos en la app, con sincronizaci\u00f3n y control de versiones.\",\n                                    \"pills\": [\"Sync\", \"Versiones\"]\n                                }\n                            },\n                            \"enter\": {\n                                \"hotkeys\": [{\n                                    \"key\": \".\",\n                                    \"preDelayMs\": 0\n                                }]\n                            },\n                            \"focus\": {\n                                \"radars\": [{\n                                    \"enabled\": true,\n                                    \"area\": \"panel\",\n                                    \"selector\": \".cvxPSCtrlBar  [data-ps-ctl=\\\"conf\\\"]\",\n                                    \"anchor\": \"center\",\n                                    \"rPct\": 0.85\n                                }]\n                            },\n                            \"advance\": {\n                                \"type\": \"click\",\n                                \"click\": {\n                                    \"area\": \"panel\",\n                                    \"selector\": \".cvxPSCtrlBar  [data-ps-ctl=\\\"conf\\\"]\",\n                                    \"swallow\": false\n                                }\n                            }\n                        },\n                        {\n                            \"id\": \"s2_local_cloud\",\n                            \"enabled\": true,\n                            \"cards\": {\n                                \"left\": {},\n                                \"right\": {}\n                            },\n                            \"enter\": {\n                                \"hotkeys\": [{\n                                    \"key\": \"ArrowDown\",\n                                    \"preDelayMs\": 100\n                                }, {\n                                    \"key\": \"ArrowDown\",\n                                    \"preDelayMs\": 100\n                                }, {\n                                    \"key\": \"ArrowDown\",\n                                    \"preDelayMs\": 100\n                                }, {\n                                    \"key\": \"ArrowDown\",\n                                    \"preDelayMs\": 100\n                                }, {\n                                    \"key\": \"ArrowDown\",\n                                    \"preDelayMs\": 100\n                                }]\n                            },\n                            \"focus\": {\n                                \"radars\": [{\n                                    \"enabled\": true,\n                                    \"area\": \"oled\",\n                                    \"selector\": null,\n                                    \"anchor\": \"center\",\n                                    \"xN\": 0.8,\n                                    \"yN\": 0.6,\n                                    \"rN\": 0.04\n                                }]\n                            },\n\n                            \"advance\": {\n                                \"type\": \"tap\",\n                                \"tap\": {\n                                    \"area\": \"oled\",\n                                    \"xN\": 0.8,\n                                    \"yN\": 0.6,\n                                    \"rN\": 0.06,\n                                    \"swallow\": false\n                                }\n                            }\n                        },\n                        {\n                            \"id\": \"s3_versions\",\n                            \"enabled\": true,\n                            \"cards\": {\n                                \"left\": {\n                                    \"title\": \"Guard\u00e1 un punto de control\",\n                                    \"desc\": \"Cerr\u00e1 una etapa como versi\u00f3n para seguir avanzando sin perder control.\",\n                                    \"pills\": [\"Versi\u00f3n\", \"Historial\"]\n                                },\n                                \"right\": {}\n                            },\n                            \"enter\": {\n                                \"hotkeys\": [{\n                                    \"key\": \"ArrowDown\",\n                                    \"preDelayMs\": 100\n                                }]\n                            },\n                            \"focus\": {\n                                \"radars\": [{\n                                    \"enabled\": true,\n                                    \"area\": \"oled\",\n                                    \"selector\": null,\n                                    \"anchor\": \"center\",\n                                    \"xN\": 0.8,\n                                    \"yN\": 0.6,\n                                    \"rN\": 0.04\n                                }]\n                            },\n\n                            \"advance\": {\n                                \"type\": \"tap\",\n                                \"tap\": {\n                                    \"area\": \"oled\",\n                                    \"xN\": 0.8,\n                                    \"yN\": 0.6,\n                                    \"rN\": 0.06,\n                                    \"swallow\": false\n                                }\n                            }\n                        },\n                        {\n                            \"id\": \"s4_versions\",\n                            \"enabled\": true,\n                            \"cards\": {\n                                \"left\": {},\n                                \"right\": {}\n                            },\n                            \"enter\": {\n                                \"hotkeys\": []\n                            },\n                            \"focus\": {\n                                \"radars\": [{\n                                    \"enabled\": true,\n                                    \"area\": \"oled\",\n                                    \"selector\": null,\n                                    \"anchor\": \"center\",\n                                    \"xN\": 0.27,\n                                    \"yN\": 0.53,\n                                    \"rN\": 0.17\n                                }]\n                            },\n\n                            \"advance\": {\n                                \"type\": \"tap\",\n                                \"tap\": {\n                                    \"area\": \"oled\",\n                                    \"xN\": 0.27,\n                                    \"yN\": 0.53,\n                                    \"rN\": 0.17,\n                                    \"swallow\": false\n                                }\n                            },\n                            \"toast\": {\n                                \"text\": \"Nuevo proyecto sincronizado\",\n                                \"tone\": \"success\",\n                                \"carrySteps\": 1\n                            }\n                        },\n                        {\n                            \"id\": \"s5_continue_anywhere\",\n                            \"enabled\": true,\n                            \"cards\": {\n                                \"left\": {\n                                    \"title\": \"Continuar donde est\u00e9s\",\n                                    \"desc\": \"Listo! ya tenemos nuestro proyecto sincronizado, ahora puedes trabajarlo desde AQA Cloud o en Compose Studio App.\",\n                                    \"pills\": [\"Projects\", \"Continuar\"]\n                                },\n                                \"right\": {}\n                            },\n                            \"enter\": {\n                                \"hotkeys\": []\n                            },\n                            \"focus\": {\n                                \"radars\": [{\n                                    \"enabled\": true,\n                                    \"area\": \"right\",\n                                    \"selector\": null,\n                                    \"anchor\": \"center\",\n                                    \"xN\": 0.5,\n                                    \"yN\": 0.25,\n                                    \"rN\": 0.3\n                                }]\n                            },\n                            \"advance\": {\n                                \"type\": \"tap\",\n                                \"tap\": {\n                                    \"area\": \"right\",\n                                    \"xN\": 0.5,\n                                    \"yN\": 0.25,\n                                    \"rN\": 0.3,\n                                    \"swallow\": false\n                                }\n                            }\n                        },\n                        {\n                            \"id\": \"s6_free_explore\",\n                            \"enabled\": true,\n                            \"cards\": {\n                                \"left\": {\n                                    \"title\": \"Cierra la demo y exploralo libremente\",\n                                    \"desc\": \"Hay m\u00e1s men\u00fas, atajos y combinaciones dentro de la sesi\u00f3n.\",\n                                    \"pills\": [\"Explorar\", \"M\u00e1s opciones\"]\n                                },\n                                \"right\": {}\n                            },\n                            \"enter\": {\n                                \"hotkeys\": []\n                            },\n                            \"focus\": {\n                                \"radars\": [{\n                                    \"enabled\": true,\n                                    \"area\": \"root\",\n                                    \"selector\": \"[data-ps-guide-reset]\",\n                                    \"anchor\": \"center\",\n                                    \"rPct\": 1.1\n                                }],\n                                \"mask\": {\n                                    \"enabled\": false,\n                                    \"holes\": []\n                                }\n                            },\n                            \"advance\": {\n                                \"type\": \"click\",\n                                \"click\": {\n                                    \"area\": \"root\",\n                                    \"selector\": \"[data-ps-guide-reset]\",\n                                    \"swallow\": false\n                                },\n                                \"next\": false\n                            }\n                        }\n                    ]\n                }\n\n\n\n\n\n\n            }\n        <\/script>\n\n    <\/section>\n    <!-- =========================================================\n    Controls Guide Modal (template + JS mount\/unmount)\n    - NOTE: inserted as sibling of [data-cvx-root=\"portable-studio\"]\n     ========================================================= -->\n    <section data-cvx-root=\"ps-controls-modal\">\n        <template id=\"cvxPSControlsGuideTpl\">\n            <section data-cvx-root=\"ps-controls-modal-live\">\n                <div class=\"cvxPSModal\" role=\"dialog\" aria-modal=\"true\" aria-labelledby=\"cvxPSControlsGuideTitle\">\n                    <button type=\"button\" class=\"cvxPSModal__backdrop\" data-ps-controls-close aria-label=\"Cerrar\"><\/button>\n\n                    <div class=\"cvxPSModal__panel\" role=\"document\">\n                        <header class=\"cvxPSModal__head\">\n                            <div class=\"cvxPSModal__kicker\">CubeVox \u2192 Compose Studio Core<\/div>\n                            <h3 class=\"cvxPSModal__title\" id=\"cvxPSControlsGuideTitle\">Gu\u00eda completa de controles<\/h3>\n                            <div class=\"cvxPSModal__headActions\">\n                                <button type=\"button\" class=\"cvxPSModal__close\" data-ps-controls-close aria-label=\"Cerrar\">\u2715<\/button>\n                            <\/div>\n                        <\/header>\n\n                        <div class=\"cvxPSModal__body\">\n                            <div class=\"cvxPSModal__grid\">\n\n                                <section class=\"cvxPSModal__card\" aria-label=\"MAIN\">\n                                    <div class=\"cvxPSModal__cardTitle\">MAIN<\/div>\n                                    <ul class=\"cvxPSModal__list\">\n                                        <li><b>Giro:<\/b> Navega por los controles al estilo tabulaci\u00f3n.<\/li>\n                                        <li><b>Clic:<\/b> Activa control (bot\u00f3n, chkbtn, etc) | selecciona control para cambiar valor (slider, arc, etc) | des-selecciona control<\/li>\n                                        <li><b>Doble Clic:<\/b> Alterna full screen<\/li>\n                                        <li><b>Pulsaci\u00f3n Larga:<\/b> Muestra popup de \u201cGuardar \/ Descartar \/ Cancelar\u201d | regresa a nivel superior de vista\/screen<\/li>\n                                    <\/ul>\n                                <\/section>\n\n                                <section class=\"cvxPSModal__card\" aria-label=\"MEDIA\">\n                                    <div class=\"cvxPSModal__cardTitle\">MEDIA<\/div>\n                                    <ul class=\"cvxPSModal__list\">\n                                        <li><b>Giro:<\/b> Desplaza la barra de tiempo | dimensiona regi\u00f3n | navega por opciones del Men\u00fa de Edici\u00f3n.<\/li>\n                                        <li><b>Clic:<\/b> Inicia regi\u00f3n | finaliza regi\u00f3n<\/li>\n                                        <li><b>Doble Clic:<\/b> Borra regi\u00f3n (de selecci\u00f3n, no regiones con FX)<\/li>\n                                        <li><b>Pulsaci\u00f3n Larga:<\/b> Muestra popup de Men\u00fa de Edici\u00f3n<\/li>\n                                    <\/ul>\n                                <\/section>\n\n                                <section class=\"cvxPSModal__card\" aria-label=\"CH1\">\n                                    <div class=\"cvxPSModal__cardTitle\">CH1<\/div>\n                                    <ul class=\"cvxPSModal__list\">\n                                        <li><b>Giro:<\/b> Zoom X +\/- | scroll en X<\/li>\n                                        <li><b>Clic:<\/b> Ajusta zoom al bloque | Ajusta vista a cursor (cursor centrado)<\/li>\n                                        <li><b>Doble Clic:<\/b> Alterna modo Zoom | Navegaci\u00f3n<\/li>\n                                        <li><b>Pulsaci\u00f3n Larga:<\/b> Ajusta zoom al proyecto | Alterna entre scroll al final y scroll al inicio<\/li>\n                                    <\/ul>\n                                <\/section>\n\n                                <section class=\"cvxPSModal__card\" aria-label=\"CH2\">\n                                    <div class=\"cvxPSModal__cardTitle\">CH2<\/div>\n                                    <ul class=\"cvxPSModal__list\">\n                                        <li><b>Giro:<\/b> Zoom Y +\/- | navegaci\u00f3n entre Tracks<\/li>\n                                        <li><b>Clic:<\/b> Ajusta zoom a 0 dB | Selecci\u00f3n de Tracks (m\u00faltiple permitido)<\/li>\n                                        <li><b>Doble Clic:<\/b> Alterna modo Zoom | Navegaci\u00f3n<\/li>\n                                        <li><b>Pulsaci\u00f3n Larga:<\/b> Ajusta zoom a Track | Limpia selecci\u00f3n de Tracks<\/li>\n                                    <\/ul>\n                                <\/section>\n\n                            <\/div>\n                        <\/div>\n                    <\/div>\n                <\/div>\n            <\/section>\n        <\/template>\n        <style>\n            \/* =========================================================\n       COMPONENT: Controls Guide Modal (scoped)\n       ========================================================= *\/\n\n            .cvxScope [data-cvx-root=\"ps-controls-modal\"] {\n                \/* PARAMETERS *\/\n                --cvx-psm-z: calc(var(--cvx-ps-guide-z, 50) + 30);\n                --cvx-psm-radius: 18px;\n                --cvx-psm-dim: 0.62;\n                --cvx-psm-feather: 18px;\n                --cvx-psm-motion: 200ms;\n\n                \/* Fallbacks (do not override global tokens) *\/\n                --cvx-psm-bg: var(--cvx-glass-bg, rgba(12, 16, 22, 0.72));\n                --cvx-psm-stroke: var(--cvx-stroke, rgba(255, 255, 255, 0.10));\n                --cvx-psm-ink: var(--cvx-ink, rgba(255, 255, 255, 0.92));\n                --cvx-psm-sub: var(--cvx-ink-2, rgba(255, 255, 255, 0.68));\n                --cvx-psm-shadow: var(--cvx-shadow-2, 0 18px 60px rgba(0, 0, 0, 0.55));\n            }\n\n\n\n            \/* Modal base *\/\n            .cvxScope [data-cvx-root=\"ps-controls-modal\"] .cvxPSModal {\n                position: fixed;\n                inset: 0;\n                z-index: var(--cvx-psm-z);\n                display: grid;\n                place-items: center;\n                padding: 18px;\n                opacity: 1;\n                pointer-events: auto;\n                transition: opacity var(--cvx-psm-motion) ease;\n            }\n\n            .cvxScope [data-cvx-root=\"ps-controls-modal\"] .cvxPSModal__backdrop {\n                position: absolute;\n                inset: 0;\n                background: rgba(0, 0, 0, var(--cvx-psm-dim));\n                backdrop-filter: blur(var(--cvx-psm-feather));\n                -webkit-backdrop-filter: blur(var(--cvx-psm-feather));\n            }\n\n            \/* Panel *\/\n            .cvxScope [data-cvx-root=\"ps-controls-modal\"] .cvxPSModal__panel {\n                position: relative;\n                width: min(920px, 100%);\n                max-height: min(78vh, 780px);\n                overflow: hidden;\n                border-radius: var(--cvx-psm-radius);\n                border: 1px solid var(--cvx-psm-stroke);\n                background: var(--cvx-psm-bg);\n                color: var(--cvx-psm-ink);\n                box-shadow: var(--cvx-psm-shadow);\n                backdrop-filter: blur(12px);\n                -webkit-backdrop-filter: blur(12px);\n                transform: translateY(0) scale(1);\n                transition: transform var(--cvx-psm-motion) ease;\n            }\n\n            .cvxScope [data-cvx-root=\"ps-controls-modal\"] .cvxPSModal__backdrop,\n            .cvxScope [data-cvx-root=\"ps-controls-modal\"] .cvxPSModal__close {\n                appearance: none;\n                -webkit-appearance: none;\n                background: none;\n                border: 0;\n                padding: 0;\n            }\n\n\n            \/* Header *\/\n            .cvxScope [data-cvx-root=\"ps-controls-modal\"] .cvxPSModal__head {\n                display: grid;\n                grid-template-columns: 1fr auto;\n                gap: 6px 12px;\n                padding: 14px 16px;\n                border-bottom: 1px solid rgba(255, 255, 255, 0.10);\n                background: linear-gradient(180deg, rgba(255, 255, 255, 0.06), rgba(255, 255, 255, 0.02));\n            }\n\n            .cvxScope [data-cvx-root=\"ps-controls-modal\"] .cvxPSModal__kicker {\n                grid-column: 1 \/ -1;\n                font-size: 11px;\n                letter-spacing: 0.14em;\n                text-transform: uppercase;\n                color: var(--cvx-psm-sub);\n            }\n\n            .cvxScope [data-cvx-root=\"ps-controls-modal\"] .cvxPSModal__title {\n                margin: 0;\n                font-size: 18px;\n                line-height: 1.15;\n                letter-spacing: -0.01em;\n            }\n\n            .cvxScope [data-cvx-root=\"ps-controls-modal\"] .cvxPSModal__headActions {\n                display: flex;\n                align-items: start;\n                justify-content: end;\n            }\n\n            .cvxScope [data-cvx-root=\"ps-controls-modal\"] .cvxPSModal__close {\n                cursor: pointer;\n                user-select: none;\n                width: 34px;\n                height: 34px;\n                border-radius: 999px;\n                display: grid;\n                place-items: center;\n                border: 1px solid rgba(255, 255, 255, 0.12);\n                background: rgba(0, 0, 0, 0.22);\n                color: rgba(255, 255, 255, 0.9);\n                transition: transform 180ms ease, background 180ms ease, border-color 180ms ease;\n            }\n\n            .cvxScope [data-cvx-root=\"ps-controls-modal\"] .cvxPSModal__close:hover {\n                transform: translateY(-1px);\n                background: rgba(0, 0, 0, 0.30);\n                border-color: rgba(255, 255, 255, 0.18);\n            }\n\n            \/* Body *\/\n            .cvxScope [data-cvx-root=\"ps-controls-modal\"] .cvxPSModal__body {\n                padding: 14px 16px 28px;\n                overflow: auto;\n                max-height: calc(min(78vh, 780px) - 64px);\n                scroll-padding-bottom: 28px;\n            }\n\n            .cvxScope [data-cvx-root=\"ps-controls-modal\"] .cvxPSModal__grid {\n                display: grid;\n                grid-template-columns: repeat(2, minmax(0, 1fr));\n                gap: 12px;\n                padding-bottom: 8px;\n            }\n\n            @media (max-width: 720px) {\n                .cvxScope [data-cvx-root=\"ps-controls-modal\"] .cvxPSModal {\n                    padding: 14px 12px 22px;\n                    place-items: center;\n                }\n\n                .cvxScope [data-cvx-root=\"ps-controls-modal\"] .cvxPSModal__panel {\n                    max-height: min(82vh, 780px);\n                }\n\n                .cvxScope [data-cvx-root=\"ps-controls-modal\"] .cvxPSModal__body {\n                    padding: 12px 12px 30px;\n                    scroll-padding-bottom: 30px;\n                }\n\n                .cvxScope [data-cvx-root=\"ps-controls-modal\"] .cvxPSModal__grid {\n                    padding-bottom: 12px;\n                }\n\n                .cvxScope [data-cvx-root=\"ps-controls-modal\"] .cvxPSModal__grid {\n                    grid-template-columns: 1fr;\n                }\n            }\n\n            .cvxScope [data-cvx-root=\"ps-controls-modal\"] .cvxPSModal__card {\n                border-radius: 16px;\n                border: 1px solid rgba(255, 255, 255, 0.10);\n                background: rgba(255, 255, 255, 0.04);\n                padding: 12px 12px 10px;\n            }\n\n            .cvxScope [data-cvx-root=\"ps-controls-modal\"] .cvxPSModal__cardTitle {\n                font-weight: 700;\n                letter-spacing: 0.08em;\n                text-transform: uppercase;\n                font-size: 12px;\n                color: rgba(255, 255, 255, 0.86);\n                margin-bottom: 8px;\n            }\n\n            .cvxScope [data-cvx-root=\"ps-controls-modal\"] .cvxPSModal__list {\n                margin: 0;\n                padding-left: 16px;\n                color: rgba(255, 255, 255, 0.78);\n                font-size: 13px;\n                line-height: 1.45;\n            }\n\n            .cvxScope [data-cvx-root=\"ps-controls-modal\"] .cvxPSModal__list b {\n                color: rgba(255, 255, 255, 0.92);\n            }\n\n\n\n            \/* Reduced motion *\/\n            @media (prefers-reduced-motion: reduce) {\n\n                .cvxScope [data-cvx-root=\"ps-controls-modal\"] .cvxPSModal,\n                .cvxScope [data-cvx-root=\"ps-controls-modal\"] .cvxPSModal__panel,\n                .cvxScope [data-cvx-root=\"ps-controls-modal\"] .cvxPSModal__close {\n                    transition: none !important;\n                }\n            }\n        <\/style>\n    <\/section>\n    <style>\n        \/* =========================================================\n       COMPONENT: Portable Studio\n       Scope: .cvxScope [data-cvx-root=\"portable-studio\"]\n       CSS order:\n       1) Root \/ tokens\n       2) Layout\n       3) Hero\n       4) Components\n       5) States \/ modes\n       6) Responsive\n       7) Accessibility\n    ========================================================= *\/\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] {\n            position: relative;\n            isolation: isolate;\n            width: 100%;\n            max-width: 100%;\n            min-width: 0;\n\n            \/* Resolved defaults (overridden by [data-ps-mode] blocks below) *\/\n            --cvx-ps-core-img: var(--cvx-ps-core-img-capture);\n            --cvx-ps-stage-img: var(--cvx-ps-stage-img-capture);\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] :is(.cvxPSHero, .cvxPSHero__txt, .cvxPSGrid, .cvxCard, .cvxPSSim, .cvxPSAside, .cvxPSStage, .cvxPSGuideBar, .cvxPSGuideCTA, .cvxPSGuideCards, .cvxPSControlsGuideRow, .grp) {\n            min-width: 0;\n            max-width: 100%;\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] [hidden] {\n            display: none !important;\n        }\n\n        \/* -------------------------\n       HERO\n    -------------------------- *\/\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSHero {\n            display: grid;\n            grid-template-columns: 2.05fr .0fr;\n            gap: var(--cvx-ps-hero-gap);\n            align-items: start;\n            margin-bottom: var(--cvx-ps-hero-mb);\n            max-width: 980px;\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSProblem {\n            margin: 0;\n            font-size: 13px;\n            line-height: 1.55;\n            color: rgba(255, 255, 255, .74);\n            max-width: 96ch;\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSProblem b {\n            color: rgba(255, 255, 255, .92);\n        }\n\n\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxTag {\n            font-size: calc(var(--cvx-ps-tag-fs, 11px) * var(--cvxS));\n            white-space: normal;\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxDesc {\n            font-size: calc(var(--cvx-ps-desc-fs, 13px) * var(--cvxS));\n            line-height: var(--cvx-ps-desc-lh);\n        }\n\n        \/* =========================================================\n   HERO TAGS \u2014 unified layout (all breakpoints)\n   - Always below, left aligned\n   - Gap controlled by your desktop variable\n========================================================= *\/\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSHero__txt .cvxTags,\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSHero>.cvxTags {\n            list-style: none;\n            margin: calc(var(--cvx-ps-hero-tags-mt, 10px) * var(--cvxS)) 0 0;\n            padding: 0;\n            justify-content: flex-start;\n            align-items: flex-start;\n\n            gap: var(--cvx-ps-hero-tags-gap, var(--cvx-gap-8));\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSHero__txt .cvxTags>li::marker,\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSHero>.cvxTags>li::marker {\n            content: \"\";\n        }\n\n        \/* -------------------------\n       GRID\n    -------------------------- *\/\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSGrid {\n            display: grid;\n            grid-template-columns: 1.25fr .95fr;\n            gap: var(--cvx-ps-gap);\n            align-items: start;\n        }\n\n        @media (max-width: 1100px) {\n            .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSGrid {\n                grid-template-columns: 1fr;\n            }\n        }\n\n        \/* =========================================================\n       LEFT: SIMULATOR (uses cvxCard base)\n    ========================================================= *\/\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSSim__top {\n            display: flex;\n            align-items: flex-start;\n            justify-content: space-between;\n            gap: 12px;\n            margin-bottom: 10px;\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSSim__head {\n            min-width: 0;\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSSim__hTitle {\n            font-size: 15px;\n            font-weight: 850;\n            color: rgba(255, 255, 255, .92);\n            letter-spacing: .2px;\n            line-height: 1.15;\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSSim__hSub {\n            margin-top: 4px;\n            font-size: 12px;\n            color: rgba(255, 255, 255, .70);\n            line-height: 1.35;\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSSim__switch {\n            flex: 0 0 auto;\n            min-width: min(420px, 100%);\n        }\n\n        @media (max-width: 520px) {\n            .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSSim__top {\n                flex-direction: column;\n                align-items: stretch;\n            }\n\n            .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSSim__switch {\n                min-width: 100%;\n            }\n        }\n\n        \/* Readout *\/\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSSim__readout {\n            display: flex;\n            align-items: flex-start;\n            justify-content: space-between;\n            gap: calc(var(--cvx-ps-readout-gap, 14px) * var(--cvxS));\n\n            padding: calc(var(--cvx-ps-readout-pad-y, 12px) * var(--cvxS)) calc(var(--cvx-ps-readout-pad-x, 12px) * var(--cvxS));\n            border-radius: 14px;\n            border: 1px solid rgba(255, 255, 255, .10);\n            background: rgba(0, 0, 0, .18);\n            box-shadow: inset 0 1px 0 rgba(255, 255, 255, .06);\n            margin: 0 0 calc(var(--cvx-ps-readout-mb, 10px) * var(--cvxS)) 0;\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSSim__modeTitle {\n            font-size: calc(var(--cvx-ps-mode-title-fs, 12px) * var(--cvxS));\n            font-weight: 900;\n            letter-spacing: .12em;\n            color: rgba(255, 255, 255, .88);\n            text-transform: uppercase;\n            line-height: var(--cvx-ps-mode-title-lh, 1.1);\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSSim__modeDesc {\n            margin-top: calc(var(--cvx-ps-mode-desc-mt, 6px) * var(--cvxS));\n            font-size: calc(var(--cvx-ps-mode-desc-fs, 12px) * var(--cvxS));\n            color: rgba(255, 255, 255, .72);\n            line-height: var(--cvx-ps-mode-desc-lh, 1.35);\n            max-width: 60ch;\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSSim__roL {\n            flex: 1 1 auto;\n            min-width: 0;\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSSim__roR {\n            flex: 0 0 auto;\n            display: grid;\n            justify-items: stretch;\n            align-content: start;\n            width: max-content;\n            min-width: calc(78px * var(--cvxS));\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSSim__badge {\n            display: inline-flex;\n            align-items: center;\n            justify-content: center;\n            gap: calc(var(--cvx-ps-badge-gap, 8px) * var(--cvxS));\n            padding: calc(var(--cvx-ps-badge-pad-y, 6px) * var(--cvxS)) calc(var(--cvx-ps-badge-pad-x, 10px) * var(--cvxS));\n            border-radius: 999px;\n            border: 1px solid rgba(255, 255, 255, .12);\n            background: rgba(0, 0, 0, .18);\n            box-shadow: 0 10px 22px rgba(0, 0, 0, .28), inset 0 1px 0 rgba(255, 255, 255, .06);\n            margin-left: auto;\n            width: 100%;\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSSim__badge .dot {\n            width: 8px;\n            height: 8px;\n            border-radius: 999px;\n            background: var(--cvxAccent);\n            box-shadow: 0 0 14px color-mix(in srgb, var(--cvxAccent) 40%, transparent);\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSSim__badge .t {\n            font-size: calc(var(--cvx-ps-badge-font, 11px) * var(--cvxS));\n            font-weight: 900;\n            letter-spacing: .12em;\n            color: rgba(255, 255, 255, .86);\n            white-space: nowrap;\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSSim__meta {\n            margin-top: calc(var(--cvx-ps-meta-mt, 8px) * var(--cvxS));\n            display: grid;\n            grid-template-columns: 1fr auto;\n            gap: calc(var(--cvx-ps-meta-gap-y, 6px) * var(--cvxS)) calc(var(--cvx-ps-meta-gap-x, 10px) * var(--cvxS));\n            justify-content: stretch;\n            font-size: calc(var(--cvx-ps-meta-font, 11px) * var(--cvxS));\n            color: rgba(255, 255, 255, .70);\n            width: 100%;\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSSim__meta .k {\n            opacity: .75;\n            text-align: left;\n            white-space: nowrap;\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSSim__meta .v {\n            font-weight: 850;\n            color: rgba(255, 255, 255, .90);\n            text-align: right;\n            white-space: nowrap;\n        }\n\n        \/* Timeline *\/\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSTimeline {\n            position: relative;\n            border-radius: 14px;\n            border: 1px solid rgba(255, 255, 255, .10);\n            background: linear-gradient(180deg, rgba(255, 255, 255, .05), rgba(0, 0, 0, .18));\n            overflow: hidden;\n            box-shadow: 0 14px 28px rgba(0, 0, 0, .32), inset 0 1px 0 rgba(255, 255, 255, .06);\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSTimeline__grid {\n            position: absolute;\n            inset: 0;\n            display: grid;\n            grid-template-columns: repeat(5, 1fr);\n            opacity: .5;\n            pointer-events: none;\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSTimeline__grid>span {\n            border-right: 1px dashed rgba(255, 255, 255, .10);\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSTimeline__grid>span:last-child {\n            border-right: 0;\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSTimeline__playhead {\n            position: absolute;\n            top: 0;\n            bottom: 0;\n            left: 56%;\n            width: 2px;\n            background: color-mix(in srgb, var(--cvxAccent) 65%, rgba(255, 255, 255, .30));\n            box-shadow: 0 0 18px color-mix(in srgb, var(--cvxAccent) 28%, transparent);\n            opacity: .85;\n            transform: translateX(-1px);\n            pointer-events: none;\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSTimeline__lanes {\n            display: grid;\n            gap: 8px;\n            padding: 12px;\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSTimeline .lane {\n            position: relative;\n            display: grid;\n            grid-template-columns: 46px 1fr;\n            align-items: center;\n            gap: 10px;\n            height: 28px;\n            border-radius: 10px;\n            background: rgba(0, 0, 0, .14);\n            border: 1px solid rgba(255, 255, 255, .07);\n            overflow: hidden;\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSTimeline .lane .lbl {\n            font-size: 11px;\n            font-weight: 900;\n            letter-spacing: .06em;\n            color: rgba(255, 255, 255, .72);\n            text-transform: uppercase;\n            padding-left: 10px;\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSTimeline .lane .clip {\n            position: absolute;\n            left: 25%;\n            height: 12px;\n            border-radius: 999px;\n            background: color-mix(in srgb, var(--cvxAccent) 14%, rgba(255, 255, 255, .10));\n            border: 1px solid color-mix(in srgb, var(--cvxAccent) 20%, rgba(255, 255, 255, .10));\n            box-shadow: inset 0 1px 0 rgba(255, 255, 255, .10);\n            opacity: .9;\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSTimeline .lane .clip.a {\n            width: 30%;\n            top: 8px;\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSTimeline .lane .clip.b {\n            width: 22%;\n            top: 8px;\n            left: 60%;\n            opacity: .65;\n        }\n\n        \/* Track strip *\/\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSTracks {\n            margin-top: 12px;\n            display: grid;\n            gap: 8px;\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSTracks .tr {\n            display: grid;\n            grid-template-columns: 1fr auto 120px;\n            gap: 10px;\n            align-items: center;\n\n            padding: 10px 12px;\n            border-radius: 14px;\n            border: 1px solid rgba(255, 255, 255, .10);\n            background: rgba(0, 0, 0, .16);\n            box-shadow: inset 0 1px 0 rgba(255, 255, 255, .06);\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSTracks .name {\n            font-weight: 850;\n            color: rgba(255, 255, 255, .90);\n            font-size: 12px;\n            letter-spacing: .2px;\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSTracks .btns {\n            display: inline-flex;\n            gap: 6px;\n            justify-content: flex-end;\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSTracks .mini {\n            ...\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSTracks .mini:hover {\n            ...\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSTracks .mini.is-on,\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSTracks .mini[aria-pressed=\"true\"] {\n            ...\n        }\n\n        \/* =========================================================\n   CONTROL BAR (imagen 2)\n========================================================= *\/\n        \/* =========================================================\n   CONTROL BAR (imagen 2) \u2014 PARAMETRIZADO\n   NAV | ZOOM | CONTROL\n========================================================= *\/\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSCtrlBar {\n\n\n            margin: 10px 0 12px;\n            \/* separa del stage igual que otros *\/\n            padding: var(--cvx-ps-bar-pad);\n            border-radius: 16px;\n            border: 1px solid rgba(255, 255, 255, .10);\n            background: rgba(0, 0, 0, .16);\n            box-shadow: inset 0 1px 0 rgba(255, 255, 255, .06);\n\n            display: flex;\n            gap: var(--cvx-ps-bar-gap);\n            align-items: center;\n            justify-content: space-between;\n            flex-wrap: wrap;\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSCtrlBar .grp {\n            display: flex;\n            align-items: center;\n            gap: 8px;\n        }\n\n        \/* Round buttons (nav) *\/\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSCtrlBar .r {\n            width: var(--cvx-ps-bar-round);\n            height: var(--cvx-ps-bar-round);\n            border-radius: var(--cvx-ps-bar-btn-rad);\n            border: 1px solid rgba(255, 255, 255, .12);\n            background: rgba(255, 255, 255, .03);\n            color: rgba(255, 255, 255, .86);\n\n            display: inline-grid;\n            place-items: center;\n            font-size: var(--cvx-ps-bar-font-round);\n            line-height: 1;\n\n            cursor: pointer;\n            box-shadow: inset 0 1px 0 rgba(255, 255, 255, .07);\n\n            transform: translateY(var(--cvx-ps-bar-text-y));\n            transition:\n                transform var(--cvx-ps-dur) var(--cvx-ps-ease),\n                border-color var(--cvx-ps-dur) var(--cvx-ps-ease),\n                background var(--cvx-ps-dur) var(--cvx-ps-ease);\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSCtrlBar .r:hover {\n            transform: translateY(calc(var(--cvx-ps-bar-text-y) + var(--cvx-ps-bar-hover-y)));\n            border-color: color-mix(in srgb, var(--cvxAccent) 22%, rgba(255, 255, 255, .12));\n            background: color-mix(in srgb, var(--cvxAccent) 8%, rgba(255, 255, 255, .03));\n        }\n\n        \/* Pills (zoom + control) *\/\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSCtrlBar .pill {\n            height: var(--cvx-ps-bar-btn-h);\n            padding: 0 var(--cvx-ps-bar-btn-pad-x);\n            border-radius: var(--cvx-ps-bar-btn-rad);\n            border: 1px solid rgba(255, 255, 255, .12);\n            background: rgba(255, 255, 255, .03);\n            color: rgba(255, 255, 255, .86);\n\n            display: inline-grid;\n            place-items: center;\n            font-size: var(--cvx-ps-bar-font);\n            line-height: 1;\n            font-weight: 950;\n            letter-spacing: var(--cvx-ps-bar-letter);\n            text-transform: uppercase;\n\n            cursor: pointer;\n            box-shadow: inset 0 1px 0 rgba(255, 255, 255, .07);\n\n            transform: translateY(var(--cvx-ps-bar-text-y));\n            transition:\n                transform var(--cvx-ps-dur) var(--cvx-ps-ease),\n                border-color var(--cvx-ps-dur) var(--cvx-ps-ease),\n                background var(--cvx-ps-dur) var(--cvx-ps-ease);\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSCtrlBar .pill:hover {\n            transform: translateY(calc(var(--cvx-ps-bar-text-y) + var(--cvx-ps-bar-hover-y)));\n            border-color: color-mix(in srgb, var(--cvxAccent) 22%, rgba(255, 255, 255, .12));\n            background: color-mix(in srgb, var(--cvxAccent) 8%, rgba(255, 255, 255, .03));\n        }\n\n        \/* SHIFT base highlight + toggle ON *\/\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSCtrlBar .pill--strong {\n            border-color: color-mix(in srgb, var(--cvxAccent) 34%, rgba(255, 255, 255, .12));\n            background: linear-gradient(180deg,\n                    color-mix(in srgb, var(--cvxAccent) 16%, rgba(255, 255, 255, .03)),\n                    rgba(0, 0, 0, .18));\n            color: rgba(255, 255, 255, .92);\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSCtrlBar .pill[aria-pressed=\"true\"] {\n            border-color: color-mix(in srgb, var(--cvxAccent) 40%, rgba(255, 255, 255, .12));\n            background: linear-gradient(180deg,\n                    color-mix(in srgb, var(--cvxAccent) 18%, rgba(255, 255, 255, .03)),\n                    rgba(0, 0, 0, .20));\n            box-shadow: 0 0 0 1px color-mix(in srgb, var(--cvxAccent) 10%, transparent) inset;\n            color: rgba(255, 255, 255, .92);\n        }\n\n        \/* Separators *\/\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSCtrlBar .sep {\n            width: 1px;\n            height: var(--cvx-ps-bar-sep-h);\n            border-radius: 999px;\n            background: rgba(255, 255, 255, var(--cvx-ps-bar-sep-alpha));\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSCtrlBar .sep--inner {\n            background: rgba(255, 255, 255, var(--cvx-ps-bar-sep-inner-alpha));\n            margin: 0 2px;\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSCtrlBar .sep--group {\n            align-self: stretch;\n            height: auto;\n            background: rgba(255, 255, 255, var(--cvx-ps-bar-sep-alpha));\n            margin: 0 2px;\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSCtrlBar .r,\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSCtrlBar .pill {\n            display: flex;\n            align-items: var(--cvx-ps-btn-align, center);\n            justify-content: var(--cvx-ps-btn-justify, center);\n            font-size: var(--cvx-ps-btn-fs, inherit);\n            line-height: var(--cvx-ps-btn-lh, 1);\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSCtlCard .r {\n            display: inline-grid;\n            align-content: center;\n            justify-content: center;\n            place-items: center;\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSCtlCard .r .cvxPSBtnTxt {\n            transform: none;\n            \/* <- clave: no offsets en +\/\u2212 dentro de la CtlCard *\/\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSCtrlBar .cvxPSBtnTxt[data-cvx-glyph=\"1\"] {\n            transform: translate(var(--cvx-ps-btn-glyph-tx), var(--cvx-ps-btn-glyph-ty));\n        }\n\n\n        \/* Mobile: si se wrappea, ocultamos separadores de grupo para que no queden \u201csueltos\u201d *\/\n        @media (max-width: 767px) {\n            .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSCtrlBar .sep--group {\n                display: none;\n            }\n        }\n\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSTracks .meter {\n            position: relative;\n            height: 12px;\n            border-radius: 999px;\n            border: 1px solid rgba(255, 255, 255, .10);\n            background: rgba(0, 0, 0, .18);\n            overflow: hidden;\n            box-shadow: inset 0 1px 0 rgba(255, 255, 255, .05);\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSTracks .meter .bar {\n            position: absolute;\n            inset: 0;\n            width: calc(var(--cvx-ps-meter, .12) * 100%);\n            background: linear-gradient(90deg,\n                    rgba(34, 197, 94, .65),\n                    rgba(56, 189, 248, .65),\n                    rgba(139, 92, 246, .60));\n            opacity: .85;\n            transition: width 80ms linear;\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSTracks .meter .peak {\n            position: absolute;\n            top: 0;\n            bottom: 0;\n            left: calc(var(--cvx-ps-peak, .20) * 100%);\n            width: 2px;\n            background: rgba(255, 255, 255, .65);\n            opacity: .55;\n            transform: translateX(-1px);\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSSim__tip {\n            margin-top: 12px;\n            justify-content: flex-start;\n            \/* alinea a la izquierda *\/\n            text-align: left;\n        }\n\n        \/* -------------------------\n   Hint row: Demo + Controls guide link\n-------------------------- *\/\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSControlsGuideRow {\n            display: flex;\n            align-items: center;\n            justify-content: space-between;\n            gap: 12px;\n            margin-top: 12px;\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSControlsGuideRow .cvxTip {\n            flex: 1 1 auto;\n            \/* el \u201cDemo\u201d se estira *\/\n            min-width: 0;\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSControlsGuideLink {\n            appearance: none;\n            -webkit-appearance: none;\n            background: transparent;\n            border: 0;\n            outline: 0;\n            box-shadow: none;\n            padding: 0;\n            margin: 0 0 10px;\n            border-radius: 0;\n\n            flex: 0 0 auto;\n            white-space: nowrap;\n\n            cursor: pointer;\n            user-select: none;\n            -webkit-tap-highlight-color: transparent;\n\n            font: inherit;\n            font-size: 12px;\n            line-height: inherit;\n            letter-spacing: .03em;\n\n            color: color-mix(in srgb, var(--cvxAccent) 70%, rgba(255, 255, 255, .92));\n            text-decoration: underline;\n            text-underline-offset: 3px;\n            text-decoration-thickness: 1px;\n\n            opacity: .9;\n            transition: opacity 180ms ease, transform 180ms ease;\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSControlsGuideLink:hover,\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSControlsGuideLink:focus,\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSControlsGuideLink:focus-visible,\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSControlsGuideLink:active {\n            background: transparent;\n            border: 0;\n            outline: 0;\n            box-shadow: none;\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSControlsGuideLink:hover {\n            opacity: 1;\n            transform: translateY(-1px);\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSControlsGuideLink:focus,\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSControlsGuideLink:focus-visible,\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSControlsGuideLink:active {\n            opacity: 1;\n            transform: none;\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSControlsGuideLink::-moz-focus-inner {\n            border: 0;\n            padding: 0;\n        }\n\n        .cvxScope .cvxTip__meta {\n            display: block;\n            \/* fuerza wrap como \u201cbloque\u201d *\/\n            min-width: 0;\n            \/* habilita wrap en flex *\/\n        }\n\n        .cvxScope .cvxTip__text {\n            display: inline;\n            \/* wrap natural *\/\n            white-space: normal;\n            overflow-wrap: anywhere;\n            \/* evita desbordes *\/\n        }\n\n        \/* =========================================================\n       RIGHT: STAGE + ACC\n    ========================================================= *\/\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSAside {\n            display: grid;\n            gap: var(--cvx-ps-gap);\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSStage {\n            position: relative;\n        }\n\n        \/* Right stage: pick zoom per mode via root vars *\/\n        .cvxScope [data-cvx-root=\"portable-studio\"] {\n            --cvx-ps-stage-bg-size: var(--cvx-ps-stage-bg-size-capture, cover);\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"][data-ps-mode=\"capture\"] {\n            --cvx-ps-stage-bg-size: var(--cvx-ps-stage-bg-size-capture, cover);\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"][data-ps-mode=\"edit\"] {\n            --cvx-ps-stage-bg-size: var(--cvx-ps-stage-bg-size-edit, cover);\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"][data-ps-mode=\"mix\"] {\n            --cvx-ps-stage-bg-size: var(--cvx-ps-stage-bg-size-mix, cover);\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"][data-ps-mode=\"share\"] {\n            --cvx-ps-stage-bg-size: var(--cvx-ps-stage-bg-size-sync, cover);\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSAside .cvxStage {\n            background-size: var(--cvx-ps-stage-bg-size, cover);\n        }\n\n        \/* Right stage: pick background-position per mode via root vars *\/\n        .cvxScope [data-cvx-root=\"portable-studio\"] {\n            --cvx-ps-stage-bg-pos: var(--cvx-ps-stage-bg-pos-capture, 50% 50%);\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"][data-ps-mode=\"capture\"] {\n            --cvx-ps-stage-bg-pos: var(--cvx-ps-stage-bg-pos-capture, 50% 50%);\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"][data-ps-mode=\"edit\"] {\n            --cvx-ps-stage-bg-pos: var(--cvx-ps-stage-bg-pos-edit, 50% 50%);\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"][data-ps-mode=\"mix\"] {\n            --cvx-ps-stage-bg-pos: var(--cvx-ps-stage-bg-pos-mix, 50% 50%);\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"][data-ps-mode=\"share\"] {\n            --cvx-ps-stage-bg-pos: var(--cvx-ps-stage-bg-pos-sync, 50% 50%);\n        }\n\n        \/* Apply to right image stage *\/\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSAside .cvxStage {\n            background-position: var(--cvx-ps-stage-bg-pos, 50% 50%);\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSStage--core {\n            perspective: var(--cvx-ps-core-perspective);\n            transform-style: preserve-3d;\n            overflow: hidden;\n            background-image: none !important;\n            \/* el render base vive en .cvxPSCoreImg *\/\n        }\n\n        \/* Photomontage stack (base render + OLED warpeado) *\/\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSStage--core .cvxPSCoreLayers {\n            position: absolute;\n            inset: 0;\n            z-index: 1;\n            transform-style: preserve-3d;\n            pointer-events: auto;\n            \/* permite interacci\u00f3n con el OLED montado *\/\n        }\n\n        \/* Base render (foto) \u2014 NO debe capturar mouse\/teclas *\/\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSStage--core .cvxPSCoreImg {\n            position: absolute;\n            inset: 0;\n            background-image: var(--stage-img);\n            background-size: var(--cvx-ps-core-bg-size, cover);\n            background-position: var(--stage-bg-pos, 50% 50%);\n            background-repeat: no-repeat;\n            opacity: var(--cvx-ps-core-img-alpha);\n            mix-blend-mode: var(--cvx-ps-core-img-blend);\n            transform: translateZ(calc(var(--cvx-ps-core-img-z) * 1px));\n            will-change: transform;\n            pointer-events: none;\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSStage--core .cvxPSOledZ {\n            position: absolute;\n            inset: 0;\n            transform-style: preserve-3d;\n            transform: translateZ(calc(var(--cvx-ps-oled-z) * 1px));\n            will-change: transform;\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSStage--core .cvxPSOledWarp {\n            position: absolute;\n            left: 0;\n            top: 0;\n            transform-origin: 0 0;\n            transform-style: preserve-3d;\n            will-change: transform;\n\n            \/* Importante: el JS setea width\/height seg\u00fan el payload medido *\/\n            \/* (Si el payload cambia de tama\u00f1o, el warp se recalcula.) *\/\n        }\n\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSStage--core .cvxPSOledMask {\n            position: relative;\n            width: 100%;\n            height: 100%;\n            transform-style: preserve-3d;\n\n            border-radius: var(--cvx-ps-oled-clip-radius, 6px) var(--cvx-ps-oled-clip-radius, 6px) var(--cvx-ps-oled-clip-radius-br, var(--cvx-ps-oled-clip-radius, 6px)) var(--cvx-ps-oled-clip-radius, 6px);\n            overflow: hidden;\n            clip-path: inset(0 round var(--cvx-ps-oled-clip-radius, 6px) var(--cvx-ps-oled-clip-radius, 6px) var(--cvx-ps-oled-clip-radius-br, var(--cvx-ps-oled-clip-radius, 6px)) var(--cvx-ps-oled-clip-radius, 6px));\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSStage--core .cvxPSOledMask::after {\n            content: \"\";\n            position: absolute;\n            inset: 0;\n            pointer-events: none;\n\n            \/* ON\/OFF *\/\n            opacity: var(--cvx-ps-oled-feather-on, 1);\n\n            \/* Feather rectangular (X + Y), controlado por px *\/\n            background:\n                linear-gradient(to right,\n                    rgba(0, 0, 0, .42) 0,\n                    transparent var(--cvx-ps-oled-feather-px, 0px),\n                    transparent calc(100% - var(--cvx-ps-oled-feather-px, 0px)),\n                    rgba(0, 0, 0, .42) 100%),\n                linear-gradient(to bottom,\n                    rgba(0, 0, 0, .42) 0,\n                    transparent var(--cvx-ps-oled-feather-px, 0px),\n                    transparent calc(100% - var(--cvx-ps-oled-feather-px, 0px)),\n                    rgba(0, 0, 0, .42) 100%);\n\n            \/* Mezcla para que act\u00fae como \u201csuavizado\/vignette\u201d sobre el contenido *\/\n            mix-blend-mode: multiply;\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSStage--core .cvxPSOledMount {\n            position: relative;\n            width: 100%;\n            height: 100%;\n            transform-style: preserve-3d;\n        }\n\n        \/* Defensive: if the OLED source was hidden offscreen, neutralize it once mounted *\/\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSStage--core .cvxPSOledPayload {\n            position: relative !important;\n            left: auto !important;\n            top: auto !important;\n            right: auto !important;\n            bottom: auto !important;\n            margin: 0 !important;\n            transform: none !important;\n        }\n\n        \/* OLED emissive (blend + glow)\n       - This is the single block that combines: blend-mode + opacity + brightness\/contrast + bloom.\n       - Targets the actual rendered canvas inside the mounted OLED root. *\/\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSStage--core .cvxPSOledPayload canvas,\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSStage--core .cvxPSOledPayload .cvxOled {\n            mix-blend-mode: var(--cvx-ps-oled-emissive-blend, screen);\n            opacity: var(--cvx-ps-oled-emissive-alpha, .92);\n            filter:\n                brightness(var(--cvx-ps-oled-emissive-gain, 1.10)) contrast(var(--cvx-ps-oled-emissive-contrast, 1.05)) drop-shadow(0 0 var(--cvx-ps-oled-glow-1, 2px) rgba(255, 255, 255, var(--cvx-ps-oled-glow-a1, .22))) drop-shadow(0 0 var(--cvx-ps-oled-glow-2, 6px) rgba(255, 255, 255, var(--cvx-ps-oled-glow-a2, .10)));\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSStage--core .cvxPSOledGlass {\n            position: absolute;\n            inset: 0;\n            background-image: var(--cvx-ps-oled-glass-img);\n            background-size: 100% 100%;\n            background-repeat: no-repeat;\n            opacity: var(--cvx-ps-oled-glass-alpha);\n            mix-blend-mode: var(--cvx-ps-oled-glass-blend, screen);\n            filter: var(--cvx-ps-oled-glass-filter);\n            border-radius: inherit;\n            transform: translateZ(calc(var(--cvx-ps-oled-glass-z) * 1px));\n            will-change: transform;\n            pointer-events: none;\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSStage--core .cvxPSOledShadow {\n            position: absolute;\n            inset: 0;\n            background-image: var(--cvx-ps-oled-shadow-img);\n            background-size: 100% 100%;\n            background-repeat: no-repeat;\n            opacity: var(--cvx-ps-oled-shadow-alpha);\n            mix-blend-mode: var(--cvx-ps-oled-shadow-blend, multiply);\n            filter: var(--cvx-ps-oled-shadow-filter);\n            border-radius: inherit;\n            transform: translateZ(calc(var(--cvx-ps-oled-shadow-z) * 1px));\n            will-change: transform;\n            pointer-events: none;\n        }\n\n        \/* Keep overlay copy above photomontage layers *\/\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSStage--core .cvxPSStage__overlay {\n            z-index: 2;\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSStage__overlay {\n            \/* Overlay card puede ocultarse (no afecta el photomontage)\n         - Adem\u00e1s: si est\u00e1s en modo calibraci\u00f3n (warp debug), la escondemos sola. *\/\n            --_ovon: var(--cvx-ps-overlaycard-on, 1);\n            --_ovvis: var(--_ovon);\n\n            position: absolute;\n            left: 14px;\n            right: 14px;\n            bottom: 14px;\n            display: grid;\n            gap: 10px;\n\n            padding: 12px 12px;\n            border-radius: 16px;\n\n            background: rgba(10, 14, 18, 0.56);\n            border: 1px solid rgba(255, 255, 255, .12);\n            box-shadow: 0 18px 40px rgba(0, 0, 0, .45), inset 0 1px 0 rgba(255, 255, 255, .06);\n\n            backdrop-filter: blur(var(--cvxBlur));\n            -webkit-backdrop-filter: blur(var(--cvxBlur));\n\n            \/* No bloquear interacciones durante calibraci\u00f3n *\/\n            pointer-events: none;\n\n            opacity: var(--_ovvis);\n            transform: translateY(calc((1 - var(--_ovvis)) * var(--cvx-ps-overlaycard-hide-y, 10px)));\n            transition:\n                opacity var(--cvx-ps-dur) var(--cvx-ps-ease),\n                transform var(--cvx-ps-dur) var(--cvx-ps-ease);\n        }\n\n        \/* Per-stage override (optional) *\/\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSStage--core .cvxPSStage__overlay {\n            --_ovon: var(--cvx-ps-overlaycard-core-on, var(--cvx-ps-overlaycard-on, 1));\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSAside .cvxPSStage__overlay {\n            --_ovon: var(--cvx-ps-overlaycard-right-on, var(--cvx-ps-overlaycard-on, 1));\n        }\n\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSStage__txt {\n            font-size: 12px;\n            line-height: 1.35;\n            color: rgba(255, 255, 255, .76);\n            max-width: 100%;\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSStage__overlay .cvxBadge {\n            width: fit-content;\n            max-width: 100%;\n            white-space: nowrap;\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSStage__overlay > .cvxBadge,\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSStage__overlay > .cvxPSStage__txt,\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSStage__overlay > .cvxPSStage__pills {\n            margin: 0;\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSStage__pills {\n            display: flex;\n            flex-wrap: wrap;\n            gap: 8px;\n            list-style: none;\n            margin: 0;\n            padding: 0;\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSGuidePills {\n            list-style: none;\n            margin: 0;\n            padding: 0;\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSStage__pills > li,\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSGuidePills > li {\n            display: inline-flex;\n            min-width: 0;\n            list-style: none;\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSStage__pills > li::marker,\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSGuidePills > li::marker {\n            content: \"\";\n        }\n\n        \/* Accordion spacing tweak *\/\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSAcc {\n            --acc-pad-y: 12px;\n            --acc-pad-x: 12px;\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSAcc .cvxAcc__btn {\n            display: flex;\n            align-items: center;\n            justify-content: space-between;\n            gap: 12px;\n            width: 100%;\n            text-align: left;\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSAcc .cvxAcc__title {\n            flex: 1 1 auto;\n            min-width: 0;\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSAcc .cvxAcc__icon {\n            flex: 0 0 auto;\n            margin-left: auto;\n        }\n\n        \/* =========================================================\n       MODE THEMING + MODE ASSET BINDINGS (data-ps-mode)\n       - Accent must remain mode-driven (do not override)\n    ========================================================= *\/\n        .cvxScope [data-cvx-root=\"portable-studio\"][data-ps-mode=\"capture\"] {\n            --cvxAccent: var(--cvx-ps-accent-capture);\n            --cvx-ps-core-img: var(--cvx-ps-core-img-capture);\n            --cvx-ps-stage-img: var(--cvx-ps-stage-img-capture);\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"][data-ps-mode=\"edit\"] {\n            --cvxAccent: var(--cvx-ps-accent-edit);\n            --cvx-ps-core-img: var(--cvx-ps-core-img-edit);\n            --cvx-ps-stage-img: var(--cvx-ps-stage-img-edit);\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"][data-ps-mode=\"mix\"] {\n            --cvxAccent: var(--cvx-ps-accent-mix);\n            --cvx-ps-core-img: var(--cvx-ps-core-img-mix);\n            --cvx-ps-stage-img: var(--cvx-ps-stage-img-mix);\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"][data-ps-mode=\"share\"] {\n            --cvxAccent: var(--cvx-ps-accent-share);\n            --cvx-ps-core-img: var(--cvx-ps-core-img-share);\n            --cvx-ps-stage-img: var(--cvx-ps-stage-img-share);\n        }\n\n        \/* Timeline clip emphasis per mode *\/\n        .cvxScope [data-cvx-root=\"portable-studio\"][data-ps-mode=\"edit\"] .cvxPSTimeline .clip {\n            border-style: dashed;\n            opacity: .95;\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"][data-ps-mode=\"mix\"] .cvxPSTimeline__playhead {\n            opacity: .45;\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"][data-ps-mode=\"share\"] .cvxPSTimeline {\n            filter: saturate(.9);\n            opacity: .92;\n        }\n\n        @media (prefers-reduced-motion: reduce) {\n            .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSTracks .meter .bar {\n                transition: none;\n            }\n\n            .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSTracks .mini {\n                transition: none;\n            }\n        }\n\n        \/* =========================================================\n           GUIDED TOUR (optional onboarding)\n           - Scope: .cvxScope [data-cvx-root=\"portable-studio\"]\n           - Z: controlled by --cvx-ps-guide-z (JS writes from options.zIndex)\n           ========================================================= *\/\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] {\n            --cvx-ps-guide-z: 50;\n            --cvx-ps-guide-dim: 0.72;\n            --cvx-ps-guide-feather: 18px;\n            --cvx-ps-guide-motion: 200ms;\n            --cvx-ps-guide-pulse: 2200ms;\n            --cvx-ps-guide-pad: 12px;\n            --cvx-ps-guide-card-w: 320px;\n            --cvx-ps-guide-card-maxw: 360px;\n            --cvx-ps-guide-card-gap: 12px;\n            --cvx-ps-guide-bar-pad-y: 8px;\n            --cvx-ps-guide-bar-pad-x: 10px;\n            --cvx-ps-guide-bar-gap: 10px;\n            --cvx-ps-guide-bar-btn-gap: 8px;\n            --cvx-ps-guide-bar-btn-h: 30px;\n            --cvx-ps-guide-bar-btn-px: 10px;\n            --cvx-ps-guide-bar-btn-fs: 11px;\n            \/* GUIDE UI ANCHOR (calculated by JS; token-based fallback) *\/\n            --cvx-ps-guide-ui-inset: var(--cvx-ps-guide-pad);\n            --cvx-ps-guide-ui-x: var(--cvx-ps-guide-pad);\n            --cvx-ps-guide-ui-y: var(--cvx-ps-guide-pad);\n            \/* START CTA RADAR *\/\n            --cvx-ps-guide-start-radar-outset: 6px;\n            \/* cu\u00e1nto \u201csale\u201d desde el per\u00edmetro *\/\n            --cvx-ps-guide-start-radar-alpha: 1;\n            \/* 0..1, permite apagar\/atenuar *\/\n            --cvx-ps-guide-start-radar-glow: .32;\n            \/* intensidad base de glow *\/\n\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSGuide {\n            position: absolute;\n            inset: 0;\n            z-index: var(--cvx-ps-guide-z);\n            pointer-events: none;\n            opacity: 0;\n            transition: opacity var(--cvx-ps-guide-motion) ease;\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"][data-ps-guide-state=\"guided\"] .cvxPSGuide,\n        .cvxScope [data-cvx-root=\"portable-studio\"][data-ps-guide-state=\"idle\"] .cvxPSGuide,\n        .cvxScope [data-cvx-root=\"portable-studio\"][data-ps-guide-state=\"free\"] .cvxPSGuide {\n            opacity: 1;\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSGuideMask {\n            position: absolute;\n            inset: 0;\n            z-index: 10;\n            pointer-events: none;\n            opacity: 0;\n            transition: opacity var(--cvx-ps-guide-motion) ease;\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"][data-ps-guide-mask=\"1\"] .cvxPSGuideMask {\n            opacity: 1;\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSGuideMaskSvg {\n            width: 100%;\n            height: 100%;\n            display: block;\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSGuideMaskSvg [data-ps-guide-mask-path] {\n            fill: rgb(0 0 0 \/ var(--cvx-ps-guide-dim));\n        }\n\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSGuideRadars {\n            position: absolute;\n            inset: 0;\n            z-index: 40;\n            pointer-events: none;\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSGuideRadar {\n            position: absolute;\n            left: calc(var(--x) * 1px);\n            top: calc(var(--y) * 1px);\n            width: calc(var(--r) * 2px);\n            height: calc(var(--r) * 2px);\n            transform: translate(-50%, -50%);\n            border-radius: 999px;\n\n            \/* \u2191 m\u00e1s visible *\/\n            border: 1px solid rgb(255 255 255 \/ 0.62);\n\n            \/* \u2191 m\u00e1s glow + m\u00e1s \u201ccuerpo\u201d *\/\n            box-shadow:\n                0 0 0 1px rgb(0 0 0 \/ 0.55) inset,\n                0 0 0 2px rgb(255 255 255 \/ 0.10),\n                0 0 28px rgb(56 189 248 \/ 0.32),\n                0 0 60px rgb(56 189 248 \/ 0.18);\n\n            will-change: transform, opacity;\n        }\n\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSGuideRadar::after {\n            content: \"\";\n            position: absolute;\n            inset: -4px;\n            border-radius: 999px;\n\n            \/* \u2191 pulso con m\u00e1s presencia *\/\n            border: 1px solid rgb(56 189 248 \/ 0.72);\n            box-shadow:\n                0 0 18px rgb(56 189 248 \/ 0.25),\n                0 0 48px rgb(56 189 248 \/ 0.14);\n\n            opacity: 0;\n            transform: scale(0.96);\n            animation: cvxPSGuidePulse var(--cvx-ps-guide-pulse) ease-out infinite;\n        }\n\n\n        @keyframes cvxPSGuidePulse {\n            0% {\n                opacity: .88;\n                transform: scale(.98);\n            }\n\n            65% {\n                opacity: 0;\n                transform: scale(1.55);\n            }\n\n            100% {\n                opacity: 0;\n                transform: scale(1.55);\n            }\n        }\n\n\n        @media (prefers-reduced-motion: reduce) {\n\n            .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSGuide,\n            .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSGuideMask {\n                transition-duration: 1ms !important;\n            }\n\n            .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSGuideRadar::after {\n                animation: none !important;\n            }\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSGuideCards {\n            position: absolute;\n            inset: 0;\n            z-index: 20;\n            pointer-events: none;\n        }\n\n        \/* If guide uses existing stage overlay cards (left\/right), hide internal guide cards *\/\n        .cvxScope [data-cvx-root=\"portable-studio\"][data-ps-guide-cards=\"stage\"] .cvxPSGuideCards {\n            display: none;\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSGuideCard {\n            position: absolute;\n            display: grid;\n            gap: 4px;\n            width: min(var(--cvx-ps-guide-card-maxw), var(--cvx-ps-guide-card-w));\n            max-width: calc(100% - 24px);\n            padding: 12px 12px 10px;\n            border-radius: 16px;\n            background: linear-gradient(180deg, rgb(255 255 255 \/ 0.08), rgb(255 255 255 \/ 0.05));\n            border: 1px solid rgb(255 255 255 \/ 0.10);\n            box-shadow: 0 14px 50px rgb(0 0 0 \/ 0.55), 0 0 0 1px rgb(0 0 0 \/ 0.25) inset;\n            backdrop-filter: blur(10px);\n            -webkit-backdrop-filter: blur(10px);\n            color: rgb(255 255 255 \/ 0.92);\n            pointer-events: auto;\n            opacity: 0;\n            transform: translateY(6px);\n            transition: opacity var(--cvx-ps-guide-motion) ease, transform var(--cvx-ps-guide-motion) ease;\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"][data-ps-guide-state=\"guided\"] .cvxPSGuideCard {\n            opacity: 1;\n            transform: translateY(0px);\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSGuideCard .k {\n            font-size: 11px;\n            letter-spacing: .12em;\n            text-transform: uppercase;\n            color: rgb(255 255 255 \/ 0.78);\n            margin: 0;\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSGuideCard .d {\n            font-size: 12px;\n            line-height: 1.35;\n            color: rgb(255 255 255 \/ 0.86);\n            margin: 0;\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSGuidePills {\n            display: flex;\n            flex-wrap: wrap;\n            gap: 6px;\n            margin: 2px 0 0;\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSGuidePill {\n            display: inline-flex;\n            align-items: center;\n            padding: 6px 8px;\n            border-radius: 999px;\n            font-size: 11px;\n            letter-spacing: .04em;\n            color: rgb(255 255 255 \/ 0.86);\n            background: rgb(0 0 0 \/ 0.22);\n            border: 1px solid rgb(255 255 255 \/ 0.10);\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSGuideBar {\n            position: absolute;\n            z-index: 30;\n            left: var(--cvx-ps-guide-ui-x);\n            top: var(--cvx-ps-guide-ui-y);\n            right: auto;\n            bottom: auto;\n            transform: none;\n            width: min(calc(100% - 24px), max-content);\n            max-width: min(calc(100% - 24px), var(--cvx-ps-guide-ui-w, calc(100% - 24px)));\n\n            display: grid;\n            grid-template-columns: auto auto;\n            justify-content: flex-start;\n            align-items: center;\n            gap: calc(var(--cvx-ps-guide-bar-gap, 10px) * var(--cvxS));\n            padding:\n                calc(var(--cvx-ps-guide-bar-pad-y, 8px) * var(--cvxS))\n                calc(var(--cvx-ps-guide-bar-pad-x, 10px) * var(--cvxS));\n            border-radius: 999px;\n            pointer-events: none;\n\n            background: rgb(10 16 24 \/ .58);\n            border: 1px solid rgb(255 255 255 \/ .14);\n            box-shadow:\n                0 12px 40px rgb(0 0 0 \/ .55),\n                0 0 0 1px rgb(56 189 248 \/ .12);\n            backdrop-filter: blur(10px);\n\n            opacity: 0;\n            transition: opacity var(--cvx-ps-guide-motion) ease;\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"][data-ps-guide-state=\"guided\"] .cvxPSGuideBar {\n            opacity: 1;\n            transform: translateY(0);\n            pointer-events: auto;\n        }\n\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSGuideBar__meta {\n            font-size: 11px;\n            letter-spacing: .10em;\n            text-transform: uppercase;\n            color: rgb(255 255 255 \/ 0.78);\n            white-space: normal;\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSGuideBar__meta:empty {\n            display: none;\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSGuideBar__btns {\n            display: inline-flex;\n            gap: calc(var(--cvx-ps-guide-bar-btn-gap, 8px) * var(--cvxS));\n            align-items: center;\n            min-width: 0;\n            flex-wrap: nowrap;\n            justify-content: flex-start;\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSGuideBar .sep {\n            width: 1px;\n            height: 18px;\n            background: rgb(255 255 255 \/ 0.10);\n            margin: 0 2px;\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSGuide .b {\n            border-radius: 999px;\n            border: 1px solid rgb(255 255 255 \/ 0.10);\n            background: rgb(0 0 0 \/ 0.18);\n            color: rgb(255 255 255 \/ 0.90);\n            letter-spacing: .06em;\n            text-transform: uppercase;\n            cursor: pointer;\n            transition: transform 180ms ease, background 180ms ease, border-color 180ms ease;\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSGuideBar .b {\n            height: calc(var(--cvx-ps-guide-bar-btn-h, 30px) * var(--cvxS));\n            padding: 0 calc(var(--cvx-ps-guide-bar-btn-px, 10px) * var(--cvxS));\n            font-size: calc(var(--cvx-ps-guide-bar-btn-fs, 11px) * var(--cvxS));\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSGuide .b:hover {\n            transform: translateY(-1px);\n            background: rgb(0 0 0 \/ 0.28);\n            border-color: rgb(255 255 255 \/ 0.18);\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSGuide .b--pri {\n            background: color-mix(in srgb, var(--cvxAccent) 26%, rgb(0 0 0 \/ 0.18));\n            border-color: color-mix(in srgb, var(--cvxAccent) 38%, rgb(255 255 255 \/ 0.12));\n            box-shadow: 0 0 0 1px rgb(0 0 0 \/ 0.25) inset, 0 0 24px color-mix(in srgb, var(--cvxAccent) 28%, transparent);\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSGuideCTA {\n            position: absolute;\n            left: var(--cvx-ps-guide-ui-x);\n            top: var(--cvx-ps-guide-ui-y);\n            right: auto;\n            bottom: auto;\n\n            display: inline-flex;\n            gap: 8px;\n            pointer-events: auto;\n            max-width: calc(100% - 24px);\n\n            opacity: 0;\n            transform: translateY(-4px);\n            transition: opacity var(--cvx-ps-guide-motion) ease, transform var(--cvx-ps-guide-motion) ease;\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"][data-ps-guide-state=\"idle\"] .cvxPSGuideCTA,\n        .cvxScope [data-cvx-root=\"portable-studio\"][data-ps-guide-state=\"free\"] .cvxPSGuideCTA {\n            opacity: 1;\n            transform: translateY(0);\n        }\n\n        \/* =========================================================\n   START CTA RADAR (idle\/free)\n   - Pulse originates at the button perimeter (outset)\n========================================================= *\/\n        .cvxScope [data-cvx-root=\"portable-studio\"][data-ps-guide-state=\"idle\"] .cvxPSGuideCTA [data-ps-guide-start],\n        .cvxScope [data-cvx-root=\"portable-studio\"][data-ps-guide-state=\"free\"] .cvxPSGuideCTA [data-ps-guide-start] {\n            position: relative;\n            z-index: 0;\n            isolation: isolate;\n            overflow: visible;\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"][data-ps-guide-state=\"idle\"] .cvxPSGuideCTA [data-ps-guide-start]::before,\n        .cvxScope [data-cvx-root=\"portable-studio\"][data-ps-guide-state=\"free\"] .cvxPSGuideCTA [data-ps-guide-start]::before {\n            content: \"\";\n            position: absolute;\n            inset: calc(var(--cvx-ps-guide-start-radar-outset, 6px) * -1);\n            border-radius: 999px;\n            pointer-events: none;\n            z-index: -1;\n\n            opacity: calc(var(--cvx-ps-guide-start-radar-alpha, 1) * 1);\n\n            border: 1px solid rgb(255 255 255 \/ 0.62);\n            box-shadow:\n                0 0 0 1px rgb(0 0 0 \/ 0.55) inset,\n                0 0 0 2px rgb(255 255 255 \/ 0.10),\n                0 0 28px rgb(56 189 248 \/ calc(var(--cvx-ps-guide-start-radar-glow, .32) * 1)),\n                0 0 60px rgb(56 189 248 \/ calc(var(--cvx-ps-guide-start-radar-glow, .32) * .56));\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"][data-ps-guide-state=\"idle\"] .cvxPSGuideCTA [data-ps-guide-start]::after,\n        .cvxScope [data-cvx-root=\"portable-studio\"][data-ps-guide-state=\"free\"] .cvxPSGuideCTA [data-ps-guide-start]::after {\n            content: \"\";\n            position: absolute;\n            inset: calc((var(--cvx-ps-guide-start-radar-outset, 6px) + 2px) * -1);\n            border-radius: 999px;\n            pointer-events: none;\n            z-index: -1;\n\n            opacity: 0;\n            transform: scale(0.96);\n\n            border: 1px solid rgb(56 189 248 \/ 0.72);\n            box-shadow:\n                0 0 18px rgb(56 189 248 \/ 0.25),\n                0 0 48px rgb(56 189 248 \/ 0.14);\n\n            animation: cvxPSGuidePulse var(--cvx-ps-guide-pulse) ease-out infinite;\n        }\n\n        \/* Reduced motion *\/\n        @media (prefers-reduced-motion: reduce) {\n\n            .cvxScope [data-cvx-root=\"portable-studio\"][data-ps-guide-state=\"idle\"] .cvxPSGuideCTA [data-ps-guide-start]::after,\n            .cvxScope [data-cvx-root=\"portable-studio\"][data-ps-guide-state=\"free\"] .cvxPSGuideCTA [data-ps-guide-start]::after {\n                animation: none !important;\n                opacity: 0.85;\n                transform: none;\n            }\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"][data-ps-guide-state=\"guided\"] .cvxPSGuideCTA {\n            opacity: 0;\n            pointer-events: none;\n        }\n\n        \/* =========================================================\n   GUIDE TOAST (persistente; se limpia por step o Exit)\n   - Visible s\u00f3lo en guided\n========================================================= *\/\n        \/* =========================================================\n   GUIDE TOAST (hosteado en la imagen derecha)\n   - Centrado horizontal\n   - Entra desde arriba y cae hacia la mitad del stage\n========================================================= *\/\n        .cvxScope [data-cvx-root=\"portable-studio\"] {\n            --cvx-ps-guide-toast-top: 40%;\n            \/* posici\u00f3n final (aprox. \u201cmitad superior\u201d) *\/\n            --cvx-ps-guide-toast-drop: 100px;\n            \/* cu\u00e1nto cae desde arriba (animaci\u00f3n) *\/\n            --cvx-ps-guide-toast-maxw: 420px;\n            --cvx-ps-guide-toast-motion: 2500ms;\n            --cvx-ps-guide-toast-ease: cubic-bezier(.16, 1, .3, 1);\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSToast {\n            position: absolute;\n            left: 50%;\n            top: var(--cvx-ps-guide-toast-top);\n            transform: translate(-50%, calc(-1 * var(--cvx-ps-guide-toast-drop)));\n\n            max-width: min(var(--cvx-ps-guide-toast-maxw), calc(100% - 24px));\n            width: max-content;\n\n            display: grid;\n            gap: 2px;\n            padding: 10px 12px;\n\n            border-radius: 14px;\n            background: linear-gradient(180deg,\n                    rgb(34 38 44 \/ 0.62),\n                    rgb(18 20 24 \/ 0.50));\n            border: 1px solid rgb(255 255 255 \/ 0.10);\n            box-shadow: 0 14px 50px rgb(0 0 0 \/ 0.55), 0 0 0 1px rgb(0 0 0 \/ 0.25) inset;\n            backdrop-filter: blur(10px);\n            -webkit-backdrop-filter: blur(10px);\n\n            color: rgb(255 255 255 \/ 0.92);\n            pointer-events: none;\n\n            opacity: 0;\n\n            \/* Entrada \u201cdrop\u201d *\/\n            transition:\n                opacity var(--cvx-ps-guide-toast-motion) var(--cvx-ps-guide-toast-ease),\n                transform var(--cvx-ps-guide-toast-motion) var(--cvx-ps-guide-toast-ease);\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSToast .m {\n            font-size: 12px;\n            line-height: 1.3;\n            color: rgb(255 255 255 \/ 0.90);\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"][data-ps-guide-state=\"guided\"][data-ps-guide-toast=\"1\"] .cvxPSToast {\n            opacity: 1;\n            transform: translate(-50%, 0);\n        }\n\n        \/* tonos *\/\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSToast[data-tone=\"success\"] {\n            border-color: rgb(34 197 94 \/ 0.35);\n            box-shadow:\n                0 14px 50px rgb(0 0 0 \/ 0.55),\n                0 0 0 1px rgb(34 197 94 \/ 0.18);\n        }\n\n        \/* =========================================================\n   RESPONSIVE PATCH v2.4 (tablet + mobile)\n   - Hero tags right column on tablet\n   - Toolbar stretch on tablet\n   - Mobile: extra vars, cards contract, toolbox 2 rows, demo stack\n========================================================= *\/\n\n        \/* ---------- Connect your tag pad vars (you already defined them) ---------- *\/\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxTag {\n            font-size: calc(var(--cvx-ps-tag-fs-act, var(--cvx-ps-tag-fs, 11px)) * var(--cvxS));\n            padding:\n                calc(var(--cvx-ps-tag-pad-y-act, var(--cvx-ps-tag-pad-y, 7px)) * var(--cvxS))\n                calc(var(--cvx-ps-tag-pad-x-act, var(--cvx-ps-tag-pad-x, 10px)) * var(--cvxS));\n        }\n\n        \/* ---------- Card pad variables for child cards (affects RIGHT card primarily) ---------- *\/\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSGrid>.cvxCard {\n            --cvxCardPadY: var(--cvx-ps-card-pad-y, 10px);\n            --cvxCardPadX: var(--cvx-ps-card-pad-x, 12px);\n        }\n\n        \/* ---------- Stage overlay: move hardcoded inset\/pad\/gap to vars ---------- *\/\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSStage__overlay {\n            left: var(--cvx-ps-ov-inset, 14px);\n            right: var(--cvx-ps-ov-inset, 14px);\n            bottom: var(--cvx-ps-ov-inset, 14px);\n\n            padding: var(--cvx-ps-ov-pad, 12px);\n            gap: var(--cvx-ps-ov-gap, 10px);\n        }\n\n        \/* Stage overlay typography + pills gap (variable-ready) *\/\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSStage__txt {\n            font-size: var(--cvx-ps-ov-txt-fs, 12px);\n            line-height: var(--cvx-ps-ov-txt-lh, 1.35);\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSStage__pills {\n            gap: var(--cvx-ps-ov-pill-gap, 8px);\n        }\n\n        \/* =========================================================\n   TABLET (641\u2013980)\n   1) Hero pills \u201ca la derecha\u201d (stack vertical)\n   2) Toolbar buttons stretch like mode buttons\n========================================================= *\/\n        @media (max-width: 980px) and (min-width: 641px) {\n\n            \/* Toolbar: stretch groups + stretch buttons *\/\n            .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSCtrlBar {\n                flex-wrap: nowrap;\n            }\n\n            .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSCtrlBar .sep--group {\n                display: none;\n            }\n\n            .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSCtrlBar .grp {\n                flex: 1 1 0;\n                min-width: 0;\n                justify-content: stretch;\n            }\n\n            \/* NAV buttons become \u201cpills\u201d and stretch *\/\n            .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSCtrlBar .grp--nav .r {\n                width: auto;\n                height: var(--cvx-ps-bar-btn-h);\n                padding: 0 var(--cvx-ps-bar-btn-pad-x);\n                border-radius: var(--cvx-ps-bar-btn-rad);\n                flex: 1 1 0;\n            }\n\n            \/* Zoom + Sys stretch *\/\n            .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSCtrlBar .grp--zoom .pill,\n            .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSCtrlBar .grp--sys .pill {\n                flex: 1 1 0;\n                min-width: 0;\n            }\n        }\n\n        \/* =========================================================\n   TOOLBAR: 2 filas a <1100px (igual que mobile)\n========================================================= *\/\n        @media (max-width: 1099px) {\n\n            .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSCtrlBar {\n                display: grid;\n                grid-template-columns: 1fr 1fr;\n                grid-auto-rows: auto;\n                gap: var(--cvx-ps-bar-gap);\n                align-items: center;\n            }\n\n            .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSCtrlBar .sep--group {\n                display: none;\n            }\n\n            .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSCtrlBar .grp {\n                min-width: 0;\n            }\n\n            \/* NAV group (col 1) *\/\n            .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSCtrlBar .grp--nav {\n                grid-column: 1;\n                display: grid;\n                grid-auto-flow: column;\n                grid-auto-columns: 1fr;\n                gap: 8px;\n            }\n\n            .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSCtrlBar .grp--nav .r {\n                width: auto;\n                height: var(--cvx-ps-bar-btn-h);\n                padding: 0 var(--cvx-ps-bar-btn-pad-x);\n                border-radius: var(--cvx-ps-bar-btn-rad);\n            }\n\n            \/* ZOOM group (col 2) *\/\n            .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSCtrlBar .grp--zoom {\n                grid-column: 2;\n                display: grid;\n                grid-auto-flow: column;\n                grid-auto-columns: 1fr;\n                gap: 8px;\n            }\n\n            .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSCtrlBar .grp--zoom .pill {\n                width: 100%;\n                min-width: 0;\n            }\n\n            \/* SYS group (fila 2 full width) *\/\n            .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSCtrlBar .grp--sys {\n                grid-column: 1 \/ -1;\n                display: grid;\n                grid-auto-flow: column;\n                grid-auto-columns: 1fr;\n                gap: 8px;\n            }\n\n            .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSCtrlBar .grp--sys .pill {\n                width: 100%;\n                min-width: 0;\n            }\n        }\n\n        \/* =========================================================\n   MOBILE (<=767)\n   - Extra vars for text\/pad\/margins\n   - Stage overlay cards \u201ccontra\u00edbles\u201d + per-side text\/pill vars\n   - Toolbox 2 rows: (NAV|ZOOM) + (SYS stretched)\n   - Demo + guide link stacked\n   - Tour cards left\/right mobile-exclusive typography\/pills\n========================================================= *\/\n        @media (max-width: 600px) {\n\n            \/* Global mobile overrides via your new vars *\/\n            .cvxScope [data-cvx-root=\"portable-studio\"] {\n                --pad-panel: calc(12px * var(--cvxS)) !important;\n                --gap-panel: calc(12px * var(--cvxS)) !important;\n                --cvx-ps-guide-ui-inset: calc(10px * var(--cvxS)) !important;\n                --cvx-ps-guide-bar-pad-y: var(--cvx-ps-guide-bar-pad-y-m, 6px) !important;\n                --cvx-ps-guide-bar-pad-x: var(--cvx-ps-guide-bar-pad-x-m, 8px) !important;\n                --cvx-ps-guide-bar-gap: var(--cvx-ps-guide-bar-gap-m, 6px) !important;\n                --cvx-ps-guide-bar-btn-gap: var(--cvx-ps-guide-bar-btn-gap-m, 6px) !important;\n                --cvx-ps-guide-bar-btn-h: var(--cvx-ps-guide-bar-btn-h-m, 28px) !important;\n                --cvx-ps-guide-bar-btn-px: var(--cvx-ps-guide-bar-btn-px-m, 9px) !important;\n                --cvx-ps-guide-bar-btn-fs: var(--cvx-ps-guide-bar-btn-fs-m, 10px) !important;\n                --cvx-ps-card-pad-y: var(--cvx-ps-card-pad-y-m, 10px) !important;\n                --cvx-ps-card-pad-x: var(--cvx-ps-card-pad-x-m, 8px) !important;\n\n                --cvx-ps-ov-inset: var(--cvx-ps-ov-inset-m, 10px) !important;\n                --cvx-ps-ov-pad: var(--cvx-ps-ov-pad-m, 10px) !important;\n                --cvx-ps-ov-gap: var(--cvx-ps-ov-gap-m, 8px) !important;\n\n                --cvx-ps-bar-pad: calc(var(--cvx-ps-bar-pad-m, 8px) * var(--cvxS)) !important;\n                --cvx-ps-bar-gap: calc(var(--cvx-ps-bar-gap-m, 6px) * var(--cvxS)) !important;\n                --cvx-ps-bar-btn-h: calc(var(--cvx-ps-bar-btn-h-m, 28px) * var(--cvxS)) !important;\n                --cvx-ps-bar-round: calc(var(--cvx-ps-bar-round-m, 28px) * var(--cvxS)) !important;\n                --cvx-ps-bar-btn-pad-x: calc(var(--cvx-ps-bar-btn-pad-x-m, 6px) * var(--cvxS)) !important;\n                --cvx-ps-bar-font: calc(var(--cvx-ps-bar-font-m, 9px) * var(--cvxS)) !important;\n                --cvx-ps-bar-font-round: calc(var(--cvx-ps-bar-font-round-m, 11px) * var(--cvxS)) !important;\n                \n                --cvx-ps-desc-fs: var(--cvx-ps-desc-fs-m, 12px) !important;\n                --cvx-ps-desc-lh: var(--cvx-ps-desc-lh-m, 1.48) !important;\n                --cvx-ps-mode-title-fs: var(--cvx-ps-mode-title-fs-m, 11px) !important;\n                --cvx-ps-mode-title-lh: var(--cvx-ps-mode-title-lh-m, 1.05) !important;\n                --cvx-ps-mode-desc-mt: var(--cvx-ps-mode-desc-mt-m, 4px) !important;\n                --cvx-ps-mode-desc-fs: var(--cvx-ps-mode-desc-fs-m, 10.5px) !important;\n                --cvx-ps-mode-desc-lh: var(--cvx-ps-mode-desc-lh-m, 1.24) !important;\n\n            }\n\n            .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSSim__modeTitle { letter-spacing: .1em; }\n\n            .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSSim__switch {\n                padding: calc(var(--cvx-ps-switch-pad-m, 5px) * var(--cvxS));\n                gap: calc(var(--cvx-ps-switch-gap-m, 4px) * var(--cvxS));\n                border-radius: calc(var(--cvx-ps-switch-radius-m, 18px) * var(--cvxS));\n            }\n\n            .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSSim__switch button {\n                min-height: calc(var(--cvx-ps-switch-btn-h-m, 34px) * var(--cvxS));\n                padding: 0 calc(var(--cvx-ps-switch-btn-px-m, 8px) * var(--cvxS));\n                font-size: calc(var(--cvx-ps-switch-btn-fs-m, 8.5px) * var(--cvxS));\n                letter-spacing: .03em;\n            }\n\n            \/* Stage overlay: contraer + centrar (sin romper hide-y) *\/\n            .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSStage__overlay {\n                width: min(var(--cvx-ps-ov-maxw-m, 520px), calc(100% - (var(--cvx-ps-ov-inset) * 2)));\n                left: 50%;\n                right: auto;\n\n                \/* Mantener el hide-y existente + sumar centrado X *\/\n                transform: translateX(-50%) translateY(calc((1 - var(--_ovvis)) * var(--cvx-ps-overlaycard-hide-y, 10px)));\n            }\n\n            .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSStage__overlay .cvxBadge {\n                max-width: calc(100% - 2px);\n                font-size: calc(10px * var(--cvxS));\n            }\n\n            .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSStage__overlay .cvxPill {\n                white-space: nowrap;\n            }\n\n            .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSStage__overlay[data-ps-guide-card-target] {\n                padding: calc(var(--cvx-ps-ov-pad, 7px) * var(--cvxS)) !important;\n                gap: max(calc(4px * var(--cvxS)), calc(var(--cvx-ps-ov-gap, 6px) * var(--cvxS))) !important;\n            }\n\n            .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSStage__txt {\n                font-size: calc(var(--cvx-ps-ov-txt-fs-m, 10px) * var(--cvxS));\n                line-height: var(--cvx-ps-ov-txt-lh-m, 1.28);\n            }\n\n            .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSStage__overlay[data-ps-guide-card-target] > .cvxBadge {\n                margin-bottom: 1px;\n            }\n\n            .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSStage__overlay[data-ps-guide-card-target] > .cvxPSStage__pills {\n                margin-top: 1px;\n            }\n\n            .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSStage__pills {\n                flex-wrap: nowrap;\n                align-items: center;\n                gap: calc(var(--cvx-ps-ov-pill-row-gap-m, 4px) * var(--cvxS));\n            }\n\n            .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSStage__pills > li {\n                flex: 0 1 auto;\n            }\n\n            \/* Per-side overlay typography\/pills (mobile exclusive) *\/\n            \/* LEFT overlay: vars que s\u00ed conviene dejar en el contenedor (txt + gap) *\/\n            .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSStage__overlay[data-ps-guide-card-target=\"left\"] {\n                --cvx-ps-ov-txt-fs: calc(var(--cvx-ps-ovL-txt-fs-m, 11px) * var(--cvxS)) !important;\n                --cvx-ps-ov-pill-gap: var(--cvx-ps-ovL-pill-gap-m, 6px) !important;\n            }\n\n            \/* LEFT: Badge (ac\u00e1 vive --cvxBadgeFs en el kit, por eso lo seteamos en el elemento) *\/\n            .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSStage__overlay[data-ps-guide-card-target=\"left\"] .cvxBadge {\n                --cvxBadgeFs: calc(var(--cvx-ps-ovL-badge-fs-m, 11px) * var(--cvxS)) !important;\n            }\n\n            \/* LEFT: Pills (ac\u00e1 viven --cvxPillFs\/Pad en el kit) *\/\n            .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSStage__overlay[data-ps-guide-card-target=\"left\"] .cvxPill {\n                --cvxPillFs: calc(var(--cvx-ps-ovL-pill-fs-m, 11px) * var(--cvxS)) !important;\n                --cvxPillPadY: calc(var(--cvx-ps-ovL-pill-py-m, 6px) * var(--cvxS)) !important;\n                --cvxPillPadX: calc(var(--cvx-ps-ovL-pill-px-m, 9px) * var(--cvxS)) !important;\n            }\n\n            \/* RIGHT overlay: contenedor (txt + gap) *\/\n            .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSStage__overlay[data-ps-guide-card-target=\"right\"] {\n                --cvx-ps-ov-txt-fs: calc(var(--cvx-ps-ovR-txt-fs-m, 11px) * var(--cvxS)) !important;\n                --cvx-ps-ov-pill-gap: var(--cvx-ps-ovR-pill-gap-m, 6px) !important;\n            }\n\n            \/* RIGHT: Badge *\/\n            .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSStage__overlay[data-ps-guide-card-target=\"right\"] .cvxBadge {\n                --cvxBadgeFs: calc(var(--cvx-ps-ovR-badge-fs-m, 11px) * var(--cvxS)) !important;\n            }\n\n            \/* RIGHT: Pills *\/\n            .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSStage__overlay[data-ps-guide-card-target=\"right\"] .cvxPill {\n                --cvxPillFs: calc(var(--cvx-ps-ovR-pill-fs-m, 11px) * var(--cvxS)) !important;\n                --cvxPillPadY: calc(var(--cvx-ps-ovR-pill-py-m, 6px) * var(--cvxS)) !important;\n                --cvxPillPadX: calc(var(--cvx-ps-ovR-pill-px-m, 9px) * var(--cvxS)) !important;\n            }\n\n            \/* TOOLBAR: mantener composicion de img1\n               fila 1: NAV + ZOOM\n               fila 2: SYS *\/\n            .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSCtrlBar {\n                display: flex;\n                flex-wrap: wrap;\n                justify-content: flex-start;\n                gap: var(--cvx-ps-bar-gap);\n                align-items: center;\n            }\n\n            .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSCtrlBar .sep--group {\n                display: none;\n            }\n\n            .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSCtrlBar .grp {\n                min-width: 0;\n                gap: calc(var(--cvx-ps-bar-inner-gap-m, 6px) * var(--cvxS));\n            }\n\n            .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSCtrlBar .grp--nav {\n                display: grid;\n                grid-template-columns: repeat(4, minmax(0, 1fr));\n                flex: 1 1 calc(50% - (var(--cvx-ps-bar-gap) * .5));\n                gap: calc(var(--cvx-ps-bar-inner-gap-m, 6px) * var(--cvxS));\n            }\n\n            .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSCtrlBar .grp--nav .r {\n                width: 100%;\n                height: var(--cvx-ps-bar-btn-h);\n                padding: 0;\n                border-radius: var(--cvx-ps-bar-btn-rad);\n            }\n\n            .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSCtrlBar .grp--nav .r .cvxPSBtnTxt {\n                font-size: calc(var(--cvx-ps-bar-nav-fs-m, 12px) * var(--cvxS));\n                transform: scale(1);\n            }\n\n            .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSCtrlBar .grp--nav .r[data-ps-ctl=\"nav-left\"] .cvxPSBtnTxt,\n            .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSCtrlBar .grp--nav .r[data-ps-ctl=\"nav-right\"] .cvxPSBtnTxt {\n                transform: translateY(-.5px) scale(1);\n            }\n\n            .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSCtrlBar .grp--zoom {\n                display: grid;\n                grid-template-columns: repeat(4, minmax(0, 1fr));\n                flex: 1 1 calc(50% - (var(--cvx-ps-bar-gap) * .5));\n                gap: calc(var(--cvx-ps-bar-inner-gap-m, 6px) * var(--cvxS));\n            }\n\n            .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSCtrlBar .grp--zoom .pill {\n                width: 100%;\n                min-width: 0;\n            }\n\n            .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSCtrlBar .grp--sys {\n                display: grid;\n                grid-template-columns: repeat(4, minmax(0, 1fr));\n                flex: 1 1 100%;\n                gap: calc(var(--cvx-ps-bar-inner-gap-m, 6px) * var(--cvxS));\n            }\n\n            .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSCtrlBar .grp--sys .pill {\n                width: 100%;\n                min-width: 0;\n            }\n\n            \/* DEMO + Gu\u00eda de controles: stack vertical *\/\n            .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSControlsGuideRow {\n                flex-direction: column;\n                align-items: stretch;\n                gap: calc(var(--cvx-ps-demo-row-gap-m, 5px) * var(--cvxS));\n                margin-top: calc(8px * var(--cvxS));\n            }\n\n            .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSSim__tip {\n                --tip-font-size: var(--cvx-ps-demo-tip-fs-m, 9.5px) !important;\n                --tip-pad-y: var(--cvx-ps-demo-tip-py-m, 6px) !important;\n                --tip-pad-x: var(--cvx-ps-demo-tip-px-m, 10px) !important;\n                --tip-gap: var(--cvx-ps-demo-tip-gap-m, 3px) !important;\n                white-space: normal;\n                margin-top: 0;\n                justify-content: flex-start;\n                align-items: center;\n                text-align: left;\n            }\n\n            .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSSim__tip .cvxTip__label {\n                display: inline;\n                width: auto;\n                flex: 0 0 auto;\n                margin: 0;\n                text-align: left;\n            }\n\n            .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSSim__tip .cvxTip__text {\n                display: block;\n                flex: 1 1 auto;\n                text-align: left;\n            }\n\n            .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSControlsGuideLink {\n                align-self: flex-end;\n                margin-bottom: 0;\n                font-size: calc(var(--cvx-ps-demo-link-fs-m, 11px) * var(--cvxS));\n            }\n\n            .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSGuideCTA .b {\n                min-height: calc(var(--cvx-ps-guide-cta-h-m, 32px) * var(--cvxS));\n                padding: 0 calc(var(--cvx-ps-guide-cta-px-m, 12px) * var(--cvxS));\n                font-size: calc(var(--cvx-ps-guide-cta-fs-m, 9px) * var(--cvxS));\n                letter-spacing: .04em;\n            }\n\n            \/* TOUR cards: contra\u00edbles + mobile-exclusive typography\/pills per side *\/\n            .cvxScope [data-cvx-root=\"portable-studio\"] {\n                --cvx-ps-guide-card-w: var(--cvx-ps-guide-card-w-m, 290px) !important;\n                --cvx-ps-guide-card-maxw: var(--cvx-ps-guide-card-maxw-m, 320px) !important;\n            }\n\n            .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSGuideCard {\n                padding: calc(var(--cvx-ps-guide-card-py-m, 9px) * var(--cvxS)) calc(var(--cvx-ps-guide-card-px-m, 10px) * var(--cvxS));\n                gap: calc(var(--cvx-ps-guide-card-gap-m, 3px) * var(--cvxS));\n            }\n\n            .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSGuideCard--left {\n                --_kfs: var(--cvx-ps-guide-L-k-fs-m, 10px) !important;\n                --_dfs: var(--cvx-ps-guide-L-d-fs-m, 11px) !important;\n                --_pfs: var(--cvx-ps-guide-L-pill-fs-m, 10px) !important;\n                --_pgap: var(--cvx-ps-guide-L-pill-gap-m, 6px) !important;\n            }\n\n            .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSGuideCard--right {\n                --_kfs: var(--cvx-ps-guide-R-k-fs-m, 10px) !important;\n                --_dfs: var(--cvx-ps-guide-R-d-fs-m, 11px) !important;\n                --_pfs: var(--cvx-ps-guide-R-pill-fs-m, 10px) !important;\n                --_pgap: var(--cvx-ps-guide-R-pill-gap-m, 6px) !important;\n            }\n\n            .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSGuideCard .k {\n                font-size: calc(var(--_kfs, 11px) * var(--cvxS));\n            }\n\n            .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSGuideCard .d {\n                font-size: calc(var(--_dfs, 12px) * var(--cvxS));\n                line-height: 1.24;\n            }\n\n            .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSGuidePills {\n                gap: var(--_pgap, 6px);\n                margin-top: 1px;\n            }\n\n            .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSGuidePill {\n                font-size: calc(var(--_pfs, 11px) * var(--cvxS));\n            }\n\n            .cvxScope [data-cvx-root=\"portable-studio\"] {\n                \/* Mobile AR para el stage izquierdo *\/\n                --cvx-ps-core-ar: var(--cvx-ps-core-ar-m) !important;\n                --cvx-ps-tag-fs: var(--cvx-ps-tag-fs-m, 11px) !important;\n                --cvx-ps-tag-pad-y: var(--cvx-ps-tag-pad-y-m, 7px) !important;\n                --cvx-ps-tag-pad-x: var(--cvx-ps-tag-pad-x-m, 10px) !important;\n                --cvx-ps-hero-tags-mt: var(--cvx-ps-hero-tags-mt-m, 8px) !important;\n\n                \/* OLED warp points (mobile) *\/\n                --cvx-ps-oled-p0-x: var(--cvx-ps-oled-p0-x-m, 21%) !important;\n                --cvx-ps-oled-p0-y: var(--cvx-ps-oled-p0-y-m, 20.5%) !important;\n                --cvx-ps-oled-p1-x: var(--cvx-ps-oled-p1-x-m, 96.6%) !important;\n                --cvx-ps-oled-p1-y: var(--cvx-ps-oled-p1-y-m, 26%) !important;\n                --cvx-ps-oled-p2-x: var(--cvx-ps-oled-p2-x-m, 78%) !important;\n                --cvx-ps-oled-p2-y: var(--cvx-ps-oled-p2-y-m, 67%) !important;\n                --cvx-ps-oled-p3-x: var(--cvx-ps-oled-p3-x-m, 4.7%) !important;\n                --cvx-ps-oled-p3-y: var(--cvx-ps-oled-p3-y-m, 47%) !important;\n\n                --cvx-ps-tag-fs-act: var(--cvx-ps-tag-fs-m, var(--cvx-ps-tag-fs)) !important;\n                --cvx-ps-tag-pad-y-act: var(--cvx-ps-tag-pad-y-m, var(--cvx-ps-tag-pad-y)) !important;\n                --cvx-ps-tag-pad-x-act: var(--cvx-ps-tag-pad-x-m, var(--cvx-ps-tag-pad-x)) !important;\n            }\n\n            .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSHero__txt .cvxTags,\n            .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSHero>.cvxTags {\n                flex-wrap: nowrap;\n                gap: var(--cvx-ps-hero-tags-gap-m, 6px);\n            }\n        }\n\n        @media (max-width: 420px) {\n            .cvxScope [data-cvx-root=\"portable-studio\"] {\n                --pad-panel: calc(11px * var(--cvxS)) !important;\n                --gap-panel: calc(11px * var(--cvxS)) !important;\n                --cvx-ps-guide-ui-inset: calc(10px * var(--cvxS)) !important;\n                --cvx-ps-bar-pad-m: 7px !important;\n                --cvx-ps-bar-gap-m: 5px !important;\n                --cvx-ps-bar-btn-h-m: 26px !important;\n                --cvx-ps-bar-round-m: 26px !important;\n                --cvx-ps-bar-font-m: 8px !important;\n                --cvx-ps-bar-font-round-m: 10px !important;\n                --cvx-ps-switch-btn-h-m: 32px !important;\n                --cvx-ps-switch-btn-px-m: 7px !important;\n                --cvx-ps-switch-btn-fs-m: 8.25px !important;\n                --cvx-ps-mode-desc-fs-m: 10px !important;\n                --cvx-ps-mode-desc-lh-m: 1.22 !important;\n                --cvx-ps-tag-fs: 9px !important;\n                --cvx-ps-tag-pad-y: 5px !important;\n                --cvx-ps-tag-pad-x: 8px !important;\n                --cvx-ps-hero-tags-gap: 5px !important;\n                --cvx-ps-ov-pad: 7px !important;\n                --cvx-ps-ov-gap: 5px !important;\n                --cvx-ps-ov-txt-fs-m: 9.5px !important;\n                --cvx-ps-ov-txt-lh-m: 1.24 !important;\n                --cvx-ps-ovL-badge-fs-m: 9.5px !important;\n                --cvx-ps-ovL-txt-fs-m: 9.5px !important;\n                --cvx-ps-ovR-badge-fs-m: 9.5px !important;\n                --cvx-ps-ovR-txt-fs-m: 9.5px !important;\n                --cvx-ps-ovL-pill-fs-m: 6.75px !important;\n                --cvx-ps-ovR-pill-fs-m: 6.75px !important;\n                --cvx-ps-ovL-pill-px-m: 7px !important;\n                --cvx-ps-ovR-pill-px-m: 7px !important;\n                --cvx-ps-ovL-pill-py-m: 4px !important;\n                --cvx-ps-ovR-pill-py-m: 4px !important;\n                --cvx-ps-ovL-pill-gap-m: 3px !important;\n                --cvx-ps-ovR-pill-gap-m: 3px !important;\n                --cvx-ps-demo-tip-fs-m: 9.25px !important;\n                --cvx-ps-demo-tip-py-m: 6px !important;\n                --cvx-ps-demo-tip-px-m: 9px !important;\n                --cvx-ps-demo-link-fs-m: 10.5px !important;\n                --cvx-ps-guide-cta-h-m: 30px !important;\n                --cvx-ps-guide-cta-px-m: 10px !important;\n                --cvx-ps-guide-cta-fs-m: 8.5px !important;\n                --cvx-ps-guide-card-py-m: 8.5px !important;\n                --cvx-ps-guide-card-px-m: 9.5px !important;\n            }\n\n            .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSControlsGuideLink {\n                align-self: stretch;\n                text-align: right;\n                white-space: normal;\n            }\n\n            .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSGuideBar {\n                left: var(--cvx-ps-guide-ui-x);\n                top: var(--cvx-ps-guide-ui-y);\n                right: auto;\n                width: max-content;\n                max-width: min(calc(100% - (var(--cvx-ps-guide-ui-inset, 10px) * 2)), var(--cvx-ps-guide-ui-w, calc(100% - 20px)));\n                grid-template-columns: auto;\n                border-radius: 18px;\n            }\n\n            .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSGuideBar__btns {\n                display: inline-flex;\n                gap: calc(var(--cvx-ps-guide-bar-btn-gap, 6px) * var(--cvxS));\n            }\n\n            .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSGuideCTA .b {\n                width: auto;\n                max-width: 100%;\n                white-space: nowrap;\n            }\n\n            .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSStage__overlay {\n                bottom: 10px;\n            }\n\n            .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSGuideBar .sep {\n                display: none;\n            }\n        }\n\n        @media (max-width: 360px) {\n            .cvxScope [data-cvx-root=\"portable-studio\"] {\n                --pad-panel: calc(10px * var(--cvxS)) !important;\n                --gap-panel: calc(10px * var(--cvxS)) !important;\n                --cvx-ps-card-pad-y: 8px !important;\n                --cvx-ps-card-pad-x: 7px !important;\n                --cvx-ps-guide-ui-inset: calc(10px * var(--cvxS)) !important;\n                --cvx-ps-ov-inset: 8px !important;\n                --cvx-ps-ov-pad: 6px !important;\n                --cvx-ps-ov-gap: 4px !important;\n                --cvx-ps-bar-pad-m: 6px !important;\n                --cvx-ps-bar-gap-m: 4px !important;\n                --cvx-ps-bar-btn-h-m: 24px !important;\n                --cvx-ps-bar-round-m: 24px !important;\n                --cvx-ps-bar-font-m: 7.5px !important;\n                --cvx-ps-bar-font-round-m: 9px !important;\n                --cvx-ps-switch-pad-m: 4px !important;\n                --cvx-ps-switch-gap-m: 3px !important;\n                --cvx-ps-switch-btn-h-m: 30px !important;\n                --cvx-ps-switch-btn-px-m: 7px !important;\n                --cvx-ps-switch-btn-fs-m: 8px !important;\n                --cvx-ps-tag-fs: 8.5px !important;\n                --cvx-ps-tag-pad-y: 4px !important;\n                --cvx-ps-tag-pad-x: 7px !important;\n                --cvx-ps-hero-tags-gap: 4px !important;\n                --cvx-ps-mode-title-fs-m: 10px !important;\n                --cvx-ps-mode-desc-fs-m: 9.75px !important;\n                --cvx-ps-mode-desc-lh-m: 1.2 !important;\n                --cvx-ps-bar-nav-fs-m: 10.5px !important;\n                --cvx-ps-ov-txt-fs-m: 9.5px !important;\n                --cvx-ps-ov-txt-lh-m: 1.22 !important;\n                --cvx-ps-ovL-badge-fs-m: 9px !important;\n                --cvx-ps-ovL-txt-fs-m: 9px !important;\n                --cvx-ps-ovR-badge-fs-m: 9px !important;\n                --cvx-ps-ovR-txt-fs-m: 9px !important;\n                --cvx-ps-ovL-pill-fs-m: 6.5px !important;\n                --cvx-ps-ovR-pill-fs-m: 6.5px !important;\n                --cvx-ps-ovL-pill-px-m: 6px !important;\n                --cvx-ps-ovR-pill-px-m: 6px !important;\n                --cvx-ps-ovL-pill-gap-m: 3px !important;\n                --cvx-ps-ovR-pill-gap-m: 3px !important;\n                --cvx-ps-demo-tip-fs-m: 9px !important;\n                --cvx-ps-demo-tip-px-m: 8px !important;\n                --cvx-ps-guide-cta-h-m: 28px !important;\n                --cvx-ps-guide-cta-px-m: 9px !important;\n                --cvx-ps-guide-cta-fs-m: 7.75px !important;\n                --cvx-ps-guide-card-py-m: 8px !important;\n                --cvx-ps-guide-card-px-m: 9px !important;\n                --cvx-ps-guide-card-gap-m: 2px !important;\n            }\n\n            .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSCtrlBar {\n                display: flex;\n                gap: var(--cvx-ps-bar-gap);\n            }\n\n            .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSCtrlBar .grp--nav,\n            .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSCtrlBar .grp--sys {\n                grid-template-columns: repeat(4, minmax(0, 1fr));\n            }\n\n            .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSCtrlBar .grp--zoom {\n                grid-template-columns: repeat(4, minmax(0, 1fr));\n            }\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSCtrlBar .grp--nav .r[data-ps-ctl=\"nav-left\"] .cvxPSBtnTxt,\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSCtrlBar .grp--nav .r[data-ps-ctl=\"nav-right\"] .cvxPSBtnTxt {\n            transform: translateY(-1px) scale(1.08);\n        }\n\n        .cvxScope [data-cvx-root=\"portable-studio\"] .cvxPSCtrlBar .grp--nav .r .cvxPSBtnTxt {\n            font-size: 16px;\n            font-weight: 950;\n            line-height: 1;\n            transform: scale(1.08);\n\n        }\n    <\/style>\n\n    <script>\n        \/* =========================================================\n           COMPONENT: Controls Guide Modal\n           Scope: .cvxScope [data-cvx-root=\"ps-controls-modal\"]\n           Responsibility:\n           - Mount \/ unmount modal template\n           - Preserve trigger focus\n           - Close on backdrop or Escape\n        ========================================================= *\/\n        (() => {\n            const scope = document.currentScript.closest('.cvxScope');\n            if (!scope) return;\n\n            const tpl = scope.querySelector('#cvxPSControlsGuideTpl');\n            if (!tpl) return;\n\n            let lastTrigger = null;\n\n            function closeModal() {\n                const modalRoot = scope.querySelector('[data-cvx-root=\"ps-controls-modal-live\"]');\n                if (modalRoot) modalRoot.remove();\n                document.removeEventListener('keydown', onKeydown, true);\n                if (lastTrigger) lastTrigger.focus();\n            }\n\n            function onKeydown(e) {\n                if (e.key === 'Escape') closeModal();\n            }\n\n            scope.addEventListener('click', (e) => {\n                const openBtn = e.target.closest('[data-ps-controls-open]');\n                if (openBtn) {\n                    if (scope.querySelector('[data-cvx-root=\"ps-controls-modal-live\"]')) return;\n                    lastTrigger = openBtn;\n                    const modalNode = tpl.content.firstElementChild.cloneNode(true);\n                    const modalHost = scope.querySelector('[data-cvx-root=\"ps-controls-modal\"]');\n                    if (!modalHost) return;\n                    modalHost.appendChild(modalNode);\n                    document.addEventListener('keydown', onKeydown, true);\n                    modalNode.querySelector('.cvxPSModal__close')?.focus();\n                    return;\n                }\n\n                const closeBtn = e.target.closest('[data-ps-controls-close]');\n                if (closeBtn) closeModal();\n            });\n        })();\n    <\/script>\n\n    <script>\n        \/* =========================================================\n       Portable Studio \u2014 interactive demo (Elementor-safe)\n       - Scope: [data-cvx-root=\"portable-studio\"]\n       - State: root.dataset.psMode\n       - Writes: per-track CSS vars for meters\/peaks\n       - Observers: IntersectionObserver + ResizeObserver\n       - JS order: init guard, helpers, cache, state, render, events, observers, lifecycle, boot\n    ========================================================= *\/\n        (function() {\n            const roots = document.querySelectorAll('.cvxScope [data-cvx-root=\"portable-studio\"]');\n            if (!roots.length) return;\n\n            const clamp = (v, a, b) => Math.max(a, Math.min(b, v));\n\n            function readVarNum(el, name, fallback) {\n                const s = getComputedStyle(el).getPropertyValue(name).trim();\n                if (!s) return fallback;\n                const n = parseFloat(s);\n                return Number.isFinite(n) ? n : fallback;\n            }\n\n            function init(root) {\n                if (root.__cvxPSInit) return;\n                root.__cvxPSInit = true;\n\n                const modeBtns = root.querySelectorAll('[data-ps-mode-btn]');\n                const titleEl = root.querySelector('[data-ps-mode-title]');\n                const descEl = root.querySelector('[data-ps-mode-desc]');\n                const badgeText = root.querySelector('[data-ps-badge-text]');\n                const fxEl = root.querySelector('[data-ps-fx]');\n                const tracksEl = root.querySelector('[data-ps-tracks]');\n\n                const meters = [...root.querySelectorAll('[data-ps-meter]')].map(el => ({\n                    el,\n                    idx: parseInt(el.getAttribute('data-ps-meter'), 10) || 1,\n                    v: 0.12,\n                    peak: 0.20,\n                    peakEl: root.querySelector('[data-ps-peak=\"' + el.getAttribute('data-ps-meter') + '\"]')\n                }));\n\n                \/* =========================================================\n                   OLED PHOTOMONTAGE \u2014 mount + 4-corner warp\n                   - Source element must carry class `.cvxPSComposeTpl`\n                     (or fallback: any `[data-cvx-root=\"oled-compose\"]`)\n                   - The source can be hidden in the layout (tabs\/switch\/offscreen)\n                   - We move it into the core stage mount slot\n                ========================================================= *\/\n                const coreStage = root.querySelector('.cvxPSStage--core');\n                const oledMount = coreStage ? coreStage.querySelector('[data-ps-mount=\"oled\"]') : null;\n                const oledWarp = coreStage ? coreStage.querySelector('[data-ps-oled-warp]') : null;\n\n                function readVarStr(el, name) {\n                    return getComputedStyle(el).getPropertyValue(name).trim();\n                }\n\n                function parseLen(str, ref) {\n                    const v = (str || '').trim();\n                    if (!v) return 0;\n                    if (v.endsWith('%')) return ref * (parseFloat(v) \/ 100);\n                    if (v.endsWith('px')) return parseFloat(v);\n                    const n = parseFloat(v);\n                    return Number.isFinite(n) ? n : 0;\n                }\n\n                function findOledSource() {\n                    \/\/ Prefer closest Elementor section\/column to avoid picking a foreign instance\n                    const scope = root.closest('.elementor-section') || root;\n\n                    \/\/ 1) If user placed a helper class, try to resolve the real OLED root within it\n                    let src = scope.querySelector('.cvxPSComposeTpl');\n                    if (src) {\n                        const inner = src.matches('[data-cvx-root=\"oled-compose\"]') ?\n                            src :\n                            src.querySelector('[data-cvx-root=\"oled-compose\"]');\n                        return inner || src;\n                    }\n\n                    \/\/ 2) Direct OLED root\n                    src = scope.querySelector('[data-cvx-root=\"oled-compose\"]');\n                    if (src) return src;\n\n                    \/\/ 3) Fallback (last resort)\n                    src = document.querySelector('.cvxPSComposeTpl');\n                    if (src) {\n                        const inner = src.matches('[data-cvx-root=\"oled-compose\"]') ?\n                            src :\n                            src.querySelector('[data-cvx-root=\"oled-compose\"]');\n                        return inner || src;\n                    }\n                    return document.querySelector('[data-cvx-root=\"oled-compose\"]');\n                }\n\n                \/* -------------------------------------------------------\n                   OLED \u2192 Portable Studio: Tracks count bridge\n                   - Pull:  oledRoot.__cvxOledGetTrackCount() (si existe)\n                           oledRoot.getAttribute('data-cvx-oled-tracks')\n                   - Push:  evento bubbling \"cvx:oled:tracks\"\n                   - Write: [data-ps-tracks] textContent\n                ------------------------------------------------------- *\/\n                function psParseInt(v, fb) {\n                    const n = parseInt(String(v ?? '').trim(), 10);\n                    return Number.isFinite(n) ? n : fb;\n                }\n\n                function psSetTracks(n) {\n                    if (!tracksEl) return;\n                    const nn = Math.max(0, psParseInt(n, 0));\n                    tracksEl.textContent = String(nn);\n                }\n\n                function psGetTracksFromOled(oled) {\n                    if (!oled) return null;\n\n                    try {\n                        if (typeof oled.__cvxOledGetTrackCount === 'function') {\n                            const n = oled.__cvxOledGetTrackCount();\n                            const nn = psParseInt(n, NaN);\n                            return Number.isFinite(nn) ? nn : null;\n                        }\n                    } catch (_) {}\n\n                    const a = oled.getAttribute ? oled.getAttribute('data-cvx-oled-tracks') : null;\n                    if (a == null) return null;\n\n                    const nn = psParseInt(a, NaN);\n                    return Number.isFinite(nn) ? nn : null;\n                }\n\n                function psResolveOledRoot() {\n                    \/\/ 1) Si ya fue montado, buscar dentro del slot\n                    if (oledMount) {\n                        let o = oledMount.querySelector('[data-cvx-root=\"oled-compose\"]');\n                        if (o) return o;\n\n                        const p = oledMount.firstElementChild;\n                        if (p) {\n                            if (p.matches && p.matches('[data-cvx-root=\"oled-compose\"]')) return p;\n                            o = p.querySelector && p.querySelector('[data-cvx-root=\"oled-compose\"]');\n                            if (o) return o;\n                        }\n                    }\n\n                    \/\/ 2) Si todav\u00eda no est\u00e1 montado, usar la misma resoluci\u00f3n que ya usa Portable Studio\n                    const src = findOledSource();\n                    if (!src) return null;\n\n                    if (src.matches && src.matches('[data-cvx-root=\"oled-compose\"]')) return src;\n                    const inner = src.querySelector && src.querySelector('[data-cvx-root=\"oled-compose\"]');\n                    return inner || src;\n                }\n\n                function psEnsureAttrObserver(oled) {\n                    if (!oled || oled.__cvxPSTracksAttrObs) return;\n                    const mo = new MutationObserver(() => {\n                        const n = psGetTracksFromOled(oled);\n                        if (n != null) psSetTracks(n);\n                    });\n                    mo.observe(oled, {\n                        attributes: true,\n                        attributeFilter: ['data-cvx-oled-tracks']\n                    });\n                    oled.__cvxPSTracksAttrObs = mo;\n                }\n\n                function psSyncTracks(reason) {\n                    const oled = psResolveOledRoot();\n                    if (!oled) return false;\n\n                    psEnsureAttrObserver(oled);\n\n                    const n = psGetTracksFromOled(oled);\n                    if (n == null) return false;\n\n                    psSetTracks(n);\n                    return true;\n                }\n\n                \/\/ Listener 1 vez por root (Elementor-safe). El evento bubblea desde el OLED root.\n                if (tracksEl && !root.__cvxPSTracksBridge) {\n                    root.__cvxPSTracksBridge = true;\n\n                    root.addEventListener('cvx:oled:tracks', (ev) => {\n                        const d = ev && ev.detail;\n                        if (!d || typeof d.tracks === 'undefined') return;\n                        psSetTracks(d.tracks);\n                    });\n                }\n\n                function mountOled() {\n                    if (!oledMount) return false;\n                    if (oledMount.__cvxOledMounted) return true;\n\n                    const src = findOledSource();\n                    if (!src) return false;\n\n                    \/\/ Avoid mounting ourselves\n                    if (coreStage && coreStage.contains(src)) {\n                        oledMount.__cvxOledMounted = true;\n                        psSyncTracks('oled:mount');\n                        return true;\n                    }\n\n                    \/\/ Move source into mount\n                    oledMount.appendChild(src);\n                    src.classList.add('cvxPSOledPayload');\n\n                    \/\/ Ensure visible even if it was hidden by a switch\/tab widget\n\n                    src.style.setProperty('pointer-events', 'auto', 'important');\n                    src.style.setProperty('touch-action', 'none', 'important');\n                    if (!src.getAttribute('tabindex')) src.setAttribute('tabindex', '0');\n                    src.addEventListener('pointerdown', () => {\n                        try {\n                            src.focus({\n                                preventScroll: true\n                            });\n                        } catch (_) {}\n                    }, {\n                        passive: true\n                    });\n\n                    oledMount.__cvxOledMounted = true;\n                    psSyncTracks('oled:mount');\n                    return true;\n                }\n\n                function solve8(A, b) {\n                    \/\/ Gaussian elimination with partial pivoting (8x8)\n                    const n = 8;\n                    for (let i = 0; i < n; i++) {\n                        \/\/ pivot\n                        let maxRow = i;\n                        let maxVal = Math.abs(A[i][i]);\n                        for (let r = i + 1; r < n; r++) {\n                            const v = Math.abs(A[r][i]);\n                            if (v > maxVal) {\n                                maxVal = v;\n                                maxRow = r;\n                            }\n                        }\n                        if (maxVal < 1e-9) return null;\n                        if (maxRow !== i) {\n                            const tmp = A[i];\n                            A[i] = A[maxRow];\n                            A[maxRow] = tmp;\n                            const tb = b[i];\n                            b[i] = b[maxRow];\n                            b[maxRow] = tb;\n                        }\n                        \/\/ normalize row\n                        const pivot = A[i][i];\n                        for (let c = i; c < n; c++) A[i][c] \/= pivot;\n                        b[i] \/= pivot;\n                        \/\/ eliminate\n                        for (let r = 0; r < n; r++) {\n                            if (r === i) continue;\n                            const f = A[r][i];\n                            if (Math.abs(f) < 1e-12) continue;\n                            for (let c = i; c < n; c++) A[r][c] -= f * A[i][c];\n                            b[r] -= f * b[i];\n                        }\n                    }\n                    return b;\n                }\n\n                function computeHomography(w, h, p0, p1, p2, p3) {\n                    \/\/ Unknowns: a b c d e f g h\n                    const pts = [{\n                            u: 0,\n                            v: 0,\n                            x: p0.x,\n                            y: p0.y\n                        },\n                        {\n                            u: w,\n                            v: 0,\n                            x: p1.x,\n                            y: p1.y\n                        },\n                        {\n                            u: w,\n                            v: h,\n                            x: p2.x,\n                            y: p2.y\n                        },\n                        {\n                            u: 0,\n                            v: h,\n                            x: p3.x,\n                            y: p3.y\n                        },\n                    ];\n\n                    const A = [];\n                    const B = [];\n                    for (const p of pts) {\n                        A.push([p.u, p.v, 1, 0, 0, 0, -p.x * p.u, -p.x * p.v]);\n                        B.push(p.x);\n                        A.push([0, 0, 0, p.u, p.v, 1, -p.y * p.u, -p.y * p.v]);\n                        B.push(p.y);\n                    }\n\n                    const sol = solve8(A, B);\n                    if (!sol) return null;\n                    const [a, b, c, d, e, f, g, hp] = sol;\n\n                    \/\/ CSS matrix3d is column-major\n                    return [\n                        a, d, 0, g,\n                        b, e, 0, hp,\n                        0, 0, 1, 0,\n                        c, f, 0, 1\n                    ];\n                }\n\n                let __lastGoodWarp = '';\n                let __warpInv = null; \/\/ inverse homography: stage(x,y) -> plane(u,v)\n                let __planeW = 0;\n                let __planeH = 0;\n\n                function invert3x3(m) {\n                    \/\/ m: row-major 3x3\n                    const a = m[0],\n                        b = m[1],\n                        c = m[2];\n                    const d = m[3],\n                        e = m[4],\n                        f = m[5];\n                    const g = m[6],\n                        h = m[7],\n                        i = m[8];\n                    const A = (e * i - f * h);\n                    const B = -(d * i - f * g);\n                    const C = (d * h - e * g);\n                    const D = -(b * i - c * h);\n                    const E = (a * i - c * g);\n                    const F = -(a * h - b * g);\n                    const G = (b * f - c * e);\n                    const H = -(a * f - c * d);\n                    const I = (a * e - b * d);\n                    const det = a * A + b * B + c * C;\n                    if (!Number.isFinite(det) || Math.abs(det) < 1e-12) return null;\n                    const invDet = 1 \/ det;\n                    return [A * invDet, D * invDet, G * invDet,\n                        B * invDet, E * invDet, H * invDet,\n                        C * invDet, F * invDet, I * invDet\n                    ];\n                }\n\n                function invertHomographyFromMatrix3d(m3d) {\n                    \/\/ Rebuild projective H from matrix3d (column-major)\n                    \/\/ H = [a b c; d e f; g h 1]\n                    const a = m3d[0],\n                        b = m3d[4],\n                        c = m3d[12];\n                    const d = m3d[1],\n                        e = m3d[5],\n                        f = m3d[13];\n                    const g = m3d[3],\n                        h = m3d[7];\n                    return invert3x3([a, b, c, d, e, f, g, h, 1]);\n                }\n\n                function applyInvHomography(invH, x, y) {\n                    \/\/ invH maps stage -> plane (u,v)\n                    const den = invH[6] * x + invH[7] * y + invH[8];\n                    if (!Number.isFinite(den) || Math.abs(den) < 1e-12) return null;\n                    const u = (invH[0] * x + invH[1] * y + invH[2]) \/ den;\n                    const v = (invH[3] * x + invH[4] * y + invH[5]) \/ den;\n                    if (!Number.isFinite(u) || !Number.isFinite(v)) return null;\n                    return {\n                        u,\n                        v\n                    };\n                }\n\n                function applyOledWarp() {\n\n                    if (!coreStage) return;\n\n                    \/\/ Always allow debug UI to be visible even if mounting fails\n                    const safeOn = readVarNum(root, '--cvx-ps-warp-safe-on', 1) > 0.5;\n\n                    const warpUI = coreStage.querySelector('[data-ps-warp-ui]');\n                    if (warpUI) {\n                        warpUI.classList.toggle('is-on', debugOn);\n                        const hudMode = warpUI.querySelector('[data-ps-warp-hud-mode]');\n                        if (hudMode) hudMode.textContent = safeOn ? 'SAFE' : 'RAW';\n                    }\n\n                    if (!oledWarp || !oledMount) return;\n                    if (readVarNum(root, '--cvx-ps-oled-warp-on', 1) < 0.5) {\n                        oledWarp.style.transform = 'none';\n                        return;\n                    }\n\n                    const stageRect = coreStage.getBoundingClientRect();\n                    if (stageRect.width < 12 || stageRect.height < 12) return; \/\/ hidden\n\n                    \/\/ Ensure mounted and measurable\n                    if (!mountOled()) return;\n\n                    \/\/ Measure payload size (source plane)\n                    const payload = oledMount.firstElementChild;\n                    if (!payload) return;\n\n                    \/\/ Temporarily remove transform for accurate measure\n                    const prev = oledWarp.style.transform;\n                    oledWarp.style.transform = 'none';\n                    const r = payload.getBoundingClientRect();\n                    const w = Math.max(1, r.width);\n                    const h = Math.max(1, r.height);\n                    oledWarp.style.width = w + 'px';\n                    oledWarp.style.height = h + 'px';\n\n                    \/\/ Resolve corner points from vars (relative to stage box)\n                    const sx = stageRect.width;\n                    const sy = stageRect.height;\n\n                    const p0 = {\n                        x: parseLen(readVarStr(root, '--cvx-ps-oled-p0-x'), sx),\n                        y: parseLen(readVarStr(root, '--cvx-ps-oled-p0-y'), sy)\n                    };\n                    const p1 = {\n                        x: parseLen(readVarStr(root, '--cvx-ps-oled-p1-x'), sx),\n                        y: parseLen(readVarStr(root, '--cvx-ps-oled-p1-y'), sy)\n                    };\n                    const p2 = {\n                        x: parseLen(readVarStr(root, '--cvx-ps-oled-p2-x'), sx),\n                        y: parseLen(readVarStr(root, '--cvx-ps-oled-p2-y'), sy)\n                    };\n                    const p3 = {\n                        x: parseLen(readVarStr(root, '--cvx-ps-oled-p3-x'), sx),\n                        y: parseLen(readVarStr(root, '--cvx-ps-oled-p3-y'), sy)\n                    };\n\n                    \/\/ SAFE: clamp points inside stage bounds to avoid \"lost\" transforms\n                    if (safeOn) {\n                        const clampPt = (p) => {\n                            p.x = clamp(p.x, 0, sx);\n                            p.y = clamp(p.y, 0, sy);\n                        };\n                        clampPt(p0);\n                        clampPt(p1);\n                        clampPt(p2);\n                        clampPt(p3);\n                    }\n\n                    \/\/ Update debug polygon (in stage coords)\n                    if (warpUI) {\n                        const svg = warpUI.querySelector('[data-ps-warp-svg]');\n                        const poly = warpUI.querySelector('[data-ps-warp-poly]');\n                        if (svg) {\n                            svg.setAttribute('viewBox', `0 0 ${sx} ${sy}`);\n                        }\n                        if (poly) {\n                            poly.setAttribute('points', `${p0.x},${p0.y} ${p1.x},${p1.y} ${p2.x},${p2.y} ${p3.x},${p3.y}`);\n                        }\n                    }\n\n                    const m = computeHomography(w, h, p0, p1, p2, p3);\n                    if (!m) {\n                        \/\/ Keep last good transform (prevents OLED from disappearing)\n                        if (__lastGoodWarp) oledWarp.style.transform = __lastGoodWarp;\n                        else oledWarp.style.transform = prev || 'none';\n                        return;\n                    }\n\n                    \/\/ Sanity check: mapped corners must intersect stage bounds\n                    function mapPt(u, v) {\n                        \/\/ column-major matrix3d\n                        const x = m[0] * u + m[4] * v + m[12];\n                        const y = m[1] * u + m[5] * v + m[13];\n                        const wv = m[3] * u + m[7] * v + m[15];\n                        if (!Number.isFinite(x) || !Number.isFinite(y) || !Number.isFinite(wv) || Math.abs(wv) < 1e-9) return null;\n                        return {\n                            x: x \/ wv,\n                            y: y \/ wv\n                        };\n                    }\n\n                    const q0 = mapPt(0, 0);\n                    const q1 = mapPt(w, 0);\n                    const q2 = mapPt(w, h);\n                    const q3 = mapPt(0, h);\n\n                    if (!q0 || !q1 || !q2 || !q3) {\n                        if (__lastGoodWarp) oledWarp.style.transform = __lastGoodWarp;\n                        else oledWarp.style.transform = prev || 'none';\n                        return;\n                    }\n\n                    const minX = Math.min(q0.x, q1.x, q2.x, q3.x);\n                    const maxX = Math.max(q0.x, q1.x, q2.x, q3.x);\n                    const minY = Math.min(q0.y, q1.y, q2.y, q3.y);\n                    const maxY = Math.max(q0.y, q1.y, q2.y, q3.y);\n\n                    const pad = 8;\n                    const intersects = !(maxX < -pad || minX > sx + pad || maxY < -pad || minY > sy + pad);\n                    if (!intersects) {\n                        if (__lastGoodWarp) oledWarp.style.transform = __lastGoodWarp;\n                        else oledWarp.style.transform = prev || 'none';\n                        return;\n                    }\n\n                    const t = 'matrix3d(' + m.map(v => Number(v.toFixed(9))).join(',') + ')';\n                    oledWarp.style.transform = t;\n                    __lastGoodWarp = t;\n\n                    \/\/ Cache inverse homography for pointer remapping (stage -> plane)\n                    __planeW = w;\n                    __planeH = h;\n                    __warpInv = invertHomographyFromMatrix3d(m);\n\n                }\n\n                let warpRaf = 0;\n                function scheduleOledWarp() {\n                    if (warpRaf) return;\n                    warpRaf = requestAnimationFrame(() => {\n                        warpRaf = 0;\n                        applyOledWarp();\n                    });\n                }\n\n                \/\/ Mount early + keep warping resilient (lazy widgets)\n                if (coreStage) {\n                    const mo = new MutationObserver(() => {\n                        mountOled();\n                        psSyncTracks('oled:corestage-mutation');\n                        scheduleOledWarp();\n                    });\n                    mo.observe(coreStage, {\n                        childList: true,\n                        subtree: true\n                    });\n                    setTimeout(() => {\n                        try {\n                            mo.disconnect();\n                        } catch (_) {}\n                    }, 12000);\n                }\n\n                const modeCopy = {\n                    capture: {\n                        title: 'CAPTURA \u00b7 Take r\u00e1pido',\n                        desc: 'Problema: el setup te come la idea. Soluci\u00f3n: pistas listas, ganancia consistente y monitoreo con FX.',\n                        badge: 'LOCAL',\n                        fx: 'LIVE'\n                    },\n                    edit: {\n                        title: 'EDICI\u00d3N \u00b7 Limpieza y comping',\n                        desc: 'Problema: cortar\/ordenar sin romper nada. Soluci\u00f3n: edici\u00f3n no destructiva para iterar y decidir r\u00e1pido.',\n                        badge: 'LOCAL',\n                        fx: 'POST'\n                    },\n                    mix: {\n                        title: 'MEZCLA \u00b7 Balance y escena',\n                        desc: 'Problema: balance + FX sin rearmar el proyecto. Soluci\u00f3n: mezcla por canal y bus sobre la misma sesi\u00f3n.',\n                        badge: 'LOCAL',\n                        fx: 'BUS'\n                    },\n                    share: {\n                        title: 'SYNC \u00b7 Proyecto vivo',\n                        desc: 'Problema: proyectos aislados y sin versiones. Soluci\u00f3n: sincronizaci\u00f3n a la nube con estados y control de versiones.',\n                        badge: 'CLOUD',\n                        fx: 'SYNC'\n                    }\n                };\n\n                function setMode(mode) {\n                    const m = modeCopy[mode] ? mode : 'capture';\n                    root.setAttribute('data-ps-mode', m);\n\n                    modeBtns.forEach(b => {\n                        const isOn = b.getAttribute('data-ps-mode-btn') === m;\n                        b.classList.toggle('on', isOn);\n                        b.setAttribute('aria-selected', isOn ? 'true' : 'false');\n                    });\n\n                    if (titleEl) titleEl.textContent = modeCopy[m].title;\n                    if (descEl) descEl.textContent = modeCopy[m].desc;\n                    if (badgeText) badgeText.textContent = modeCopy[m].badge;\n                    if (fxEl) fxEl.textContent = modeCopy[m].fx;\n\n                    \/\/ Mode-specific arming suggestion (visual only)\n                    const trs = root.querySelectorAll('.cvxPSTracks .tr');\n                    trs.forEach((tr, i) => {\n                        const armBtn = tr.querySelector('[data-ps-tgl=\"arm\"]');\n                        if (!armBtn) return;\n                        const on = false;\n                        armBtn.classList.toggle('is-on', on);\n                        armBtn.setAttribute('aria-pressed', on ? 'true' : 'false');\n                    });\n                }\n\n                scheduleInitialTPPass();\n\n                function rerenderReadoutForTP() {\n                    const currentMode = root.getAttribute('data-ps-mode') || 'capture';\n                    setMode(currentMode);\n                }\n\n                function scheduleInitialTPPass() {\n                    const run = () => {\n                        requestAnimationFrame(() => {\n                            setTimeout(() => {\n                                rerenderReadoutForTP();\n                            }, 80);\n                        });\n                    };\n\n                    if (document.readyState === 'complete') run();\n                    else window.addEventListener('load', run, {\n                        once: true\n                    });\n                }\n\n                modeBtns.forEach(btn => {\n                    btn.addEventListener('click', () => setMode(btn.getAttribute('data-ps-mode-btn')));\n                });\n\n                \/\/ Mini toggles inside tracks (ARM\/S\/M) \u2014 purely visual demo\n                root.addEventListener('click', (ev) => {\n                    const t = ev.target;\n                    if (!(t instanceof HTMLElement)) return;\n                    if (!t.matches('.cvxPSTracks .mini')) return;\n\n                    const pressed = t.getAttribute('aria-pressed') === 'true';\n                    const next = !pressed;\n                    t.setAttribute('aria-pressed', next ? 'true' : 'false');\n                    t.classList.toggle('is-on', next);\n                });\n\n                \/\/ Meter loop (paused if hidden)\n                let raf = 0;\n                let running = false;\n\n                function tick() {\n                    if (!running) return;\n\n                    const fps = clamp(readVarNum(root, '--cvx-ps-meter-fps', 26), 10, 60);\n                    const slew = clamp(readVarNum(root, '--cvx-ps-meter-slew', 0.16), 0.02, 0.45);\n                    const floor = clamp(readVarNum(root, '--cvx-ps-meter-floor', 0.06), 0, 0.2);\n                    const ceil = clamp(readVarNum(root, '--cvx-ps-meter-ceil', 0.96), 0.6, 1);\n\n                    const stepMs = 1000 \/ fps;\n                    let last = performance.now();\n\n                    function frame(now) {\n                        if (!running) return;\n                        if (now - last >= stepMs) {\n                            last = now;\n\n                            const mode = root.getAttribute('data-ps-mode') || 'capture';\n                            const intensity =\n                                mode === 'capture' ? 1.00 :\n                                mode === 'edit' ? 0.55 :\n                                mode === 'mix' ? 0.80 :\n                                0.25; \/\/ share\n\n                            meters.forEach((m) => {\n                                const rnd = floor + Math.random() * (ceil - floor);\n                                const target = clamp(rnd * intensity, floor, ceil);\n\n                                m.v = m.v + (target - m.v) * slew;\n\n                                \/\/ peak hold\n                                m.peak = Math.max(m.peak * 0.985, m.v);\n                                if (m.el) {\n                                    m.el.style.setProperty('--cvx-ps-meter', m.v.toFixed(4));\n                                }\n                                if (m.peakEl) {\n                                    m.peakEl.style.setProperty('--cvx-ps-peak', m.peak.toFixed(4));\n                                }\n                            });\n                        }\n                        raf = requestAnimationFrame(frame);\n                    }\n\n                    raf = requestAnimationFrame(frame);\n                }\n\n                function start() {\n                    if (running) return;\n                    if (document.hidden) return;\n                    if (root.getBoundingClientRect().width < 8) return; \/\/ hidden in Elementor\n                    running = true;\n                    tick();\n                }\n\n                function stop() {\n                    running = false;\n                    if (raf) cancelAnimationFrame(raf);\n                    raf = 0;\n                }\n\n                const io = new IntersectionObserver((entries) => {\n                    entries.forEach(e => {\n                        if (e.isIntersecting && !document.hidden) start();\n                        else stop();\n                    });\n                }, {\n                    threshold: 0.18\n                });\n\n                const ro = new ResizeObserver(() => {\n                    if (root.getBoundingClientRect().width >= 8 && !document.hidden) start();\n                });\n\n                const onVisibilityChange = () => {\n                    if (document.hidden) {\n                        stop();\n                        return;\n                    }\n                    const rect = root.getBoundingClientRect();\n                    const inViewport = rect.width >= 8 && rect.height >= 8 && rect.bottom > 0 && rect.right > 0 && rect.top < window.innerHeight && rect.left < window.innerWidth;\n                    if (inViewport) start();\n                };\n\n                io.observe(root);\n                ro.observe(root);\n                document.addEventListener('visibilitychange', onVisibilityChange, {\n                    passive: true\n                });\n\n                \/\/ Recompute OLED warp on resize (core stage + payload)\n                if (coreStage) {\n                    const ro2 = new ResizeObserver(() => {\n                        scheduleOledWarp();\n                    });\n                    ro2.observe(coreStage);\n                }\n\n                \/\/ Recompute OLED warp when inline vars change (Elementor editor updates style attrs)\n                const moVars = new MutationObserver(() => {\n                    scheduleOledWarp();\n                });\n                moVars.observe(root, {\n                    attributes: true,\n                    attributeFilter: ['style', 'data-ps-mode']\n                });\n\n                \/\/ Pointer remap (projective) so the OLED stays interactive under perspective warp\n                (function bindOledPointerBridge() {\n                    if (!coreStage || !oledMount) return;\n\n                    const isTextInput = (el) => {\n                        if (!el || !(el instanceof Element)) return false;\n                        const t = (el.tagName || '').toLowerCase();\n                        return t === 'input' || t === 'textarea' || el.isContentEditable;\n                    };\n\n                    function bridge(ev) {\n                        if (!ev.isTrusted) return;\n\n                        \/\/ Don\u2019t interfere with debug handle dragging\n                        const debugOn = readVarNum(root, '--cvx-ps-warp-debug-on', 0) > 0.5;\n                        if (debugOn) return;\n\n                        if (!__warpInv || __planeW <= 1 || __planeH <= 1) return;\n                        if (!oledMount.firstElementChild) return;\n\n                        const stageRect = coreStage.getBoundingClientRect();\n                        if (stageRect.width < 12 || stageRect.height < 12) return;\n\n                        \/\/ Stage-local coords\n                        const sx = ev.clientX - stageRect.left;\n                        const sy = ev.clientY - stageRect.top;\n\n                        const pv = applyInvHomography(__warpInv, sx, sy);\n                        if (!pv) return;\n\n                        \/\/ Only intercept when pointer is within the OLED plane\n                        if (pv.u < 0 || pv.v < 0 || pv.u > __planeW || pv.v > __planeH) return;\n\n                        const payload = oledMount.firstElementChild;\n                        const canvas = payload.querySelector('canvas') || payload;\n\n                        \/\/ Ensure focus for keyboard\n                        if (ev.type === 'pointerdown') {\n                            try {\n                                coreStage.focus({\n                                    preventScroll: true\n                                });\n                            } catch (_) {}\n                            try {\n                                payload.focus({\n                                    preventScroll: true\n                                });\n                            } catch (_) {}\n                            try {\n                                canvas.focus && canvas.focus({\n                                    preventScroll: true\n                                });\n                            } catch (_) {}\n                        }\n\n                        \/\/ Map plane(u,v) -> normalized -> target bbox mapping (expected by most handlers)\n                        const nu = clamp(pv.u \/ __planeW, 0, 1);\n                        const nv = clamp(pv.v \/ __planeH, 0, 1);\n                        const tr = canvas.getBoundingClientRect();\n                        const cx = tr.left + nu * tr.width;\n                        const cy = tr.top + nv * tr.height;\n\n                        \/\/ Re-dispatch a synthetic PointerEvent with corrected clientX\/Y\n                        const pe = new PointerEvent(ev.type, {\n                            bubbles: true,\n                            cancelable: true,\n                            composed: true,\n                            pointerId: ev.pointerId,\n                            pointerType: ev.pointerType,\n                            isPrimary: ev.isPrimary,\n                            buttons: ev.buttons,\n                            button: ev.button,\n                            pressure: ev.pressure,\n                            tangentialPressure: ev.tangentialPressure,\n                            tiltX: ev.tiltX,\n                            tiltY: ev.tiltY,\n                            twist: ev.twist,\n                            width: ev.width,\n                            height: ev.height,\n                            clientX: cx,\n                            clientY: cy,\n                            screenX: ev.screenX,\n                            screenY: ev.screenY,\n                            ctrlKey: ev.ctrlKey,\n                            shiftKey: ev.shiftKey || (root.dataset.psShiftLatch === \"1\"),\n                            altKey: ev.altKey,\n                            metaKey: ev.metaKey\n                        });\n                        canvas.dispatchEvent(pe);\n\n                        ev.preventDefault();\n                        ev.stopPropagation();\n                    }\n\n                    \/\/ Capture phase so we can correct before OLED handlers run\n                    coreStage.addEventListener('pointerdown', bridge, true);\n                    coreStage.addEventListener('pointermove', bridge, true);\n                    coreStage.addEventListener('pointerup', bridge, true);\n                    coreStage.addEventListener('pointercancel', bridge, true);\n\n                    \/\/ Keyboard forwarding (only if last interaction was on OLED)\n                    let lastOledTs = 0;\n\n                    function __psGetOledTarget() {\n                        const payload = oledMount.firstElementChild;\n                        if (!payload) return null;\n\n                        \/\/ Prefer the oled-compose root if present\n                        if (payload.matches && payload.matches('[data-cvx-root=\"oled-compose\"]')) return payload;\n\n                        const r =\n                            (payload.querySelector && payload.querySelector('[data-cvx-root=\"oled-compose\"]')) ||\n                            (payload.querySelector && payload.querySelector('canvas')) ||\n                            payload;\n\n                        return r || payload;\n                    }\n\n                    function __psMarkOledInteraction() {\n                        lastOledTs = performance.now();\n\n                        \/\/ Make sure the OLED target is focusable and focused, so native key routing works\n                        const t = __psGetOledTarget();\n                        if (!t) return;\n\n                        if (!t.hasAttribute('tabindex')) t.setAttribute('tabindex', '0');\n                        try {\n                            t.focus({\n                                preventScroll: true\n                            });\n                        } catch (_) {\n                            try {\n                                t.focus();\n                            } catch (_) {}\n                        }\n                    }\n\n                    coreStage.addEventListener('pointerdown', (ev) => {\n                        if (!ev.isTrusted) return;\n                        __psMarkOledInteraction();\n                    }, true);\n\n                    function __psShouldRouteToOled(ev) {\n                        if (!ev.isTrusted) return false;\n                        if (isTextInput(ev.target)) return false;\n\n                        const t = __psGetOledTarget();\n                        if (!t) return false;\n\n                        \/\/ Route if:\n                        \/\/ - focus is already inside OLED (we may still normalize a couple of keys),\n                        \/\/ - OR the last interaction was on OLED recently.\n                        const focusInOled = t.contains(document.activeElement);\n                        const recent = (performance.now() - lastOledTs) <= 8000;\n\n                        return focusInOled || recent;\n                    }\n\n                    function __psDispatchToOled(ev) {\n                        const t = __psGetOledTarget();\n                        if (!t) return;\n\n                        \/\/ Normalizaci\u00f3n m\u00ednima para layouts donde VOL+ suele venir como Alt+\"=\":\n                        \/\/ (ev.key \"=\" + ev.code \"Equal\" con Alt) -> enviamos key \"+\"\n                        const normKey = (ev.code === 'Equal' && ev.key === '=' && ev.altKey) ? '+' : ev.key;\n\n                        const ke = new KeyboardEvent(ev.type, {\n                            bubbles: true,\n                            cancelable: true,\n                            composed: true,\n                            key: normKey,\n                            code: ev.code,\n                            location: ev.location,\n                            repeat: ev.repeat,\n                            ctrlKey: ev.ctrlKey,\n                            shiftKey: (ev.shiftKey || shiftLatch),\n                            altKey: ev.altKey,\n                            metaKey: ev.metaKey\n                        });\n\n                        t.dispatchEvent(ke);\n                    }\n\n                    document.addEventListener('keydown', (ev) => {\n                        if (!__psShouldRouteToOled(ev)) return;\n\n                        \/\/ Evita scroll\/side-effects del browser (flechas, PgUp\/PgDn, etc.)\n                        ev.preventDefault();\n                        ev.stopPropagation();\n\n                        __psDispatchToOled(ev);\n                    }, true);\n\n                    document.addEventListener('keyup', (ev) => {\n                        if (!__psShouldRouteToOled(ev)) return;\n\n                        ev.preventDefault();\n                        ev.stopPropagation();\n\n                        __psDispatchToOled(ev);\n                    }, true);\n\n                })();\n\n                \/* =========================================================\n                   Control bars -> OLED hotkey forwarder + +TRACK seed rows\n                   ========================================================= *\/\n                (function() {\n                    \"use strict\";\n\n                    const ROOT_SEL = '.cvxScope [data-cvx-root=\"portable-studio\"]';\n\n                    function stripOuterQuotes(s) {\n                        s = (s ?? \"\").trim();\n                        if (!s) return \"\";\n                        const q = s[0];\n                        if ((q === '\"' || q === \"'\") && s[s.length - 1] === q) return s.slice(1, -1);\n                        return s;\n                    }\n\n                    function cssVar(el, name, fallback = \"\") {\n                        const v = getComputedStyle(el).getPropertyValue(name);\n                        const s = stripOuterQuotes(v);\n                        return s || fallback;\n                    }\n\n                    function parseSeedList(seedRaw) {\n                        const s = stripOuterQuotes(seedRaw).trim();\n                        if (!s) return [];\n                        \/\/ JSON array\n                        if (s.startsWith(\"[\") && s.endsWith(\"]\")) {\n                            try {\n                                const arr = JSON.parse(s);\n                                if (Array.isArray(arr)) return arr.map(x => String(x).trim()).filter(Boolean);\n                            } catch (_) {}\n                        }\n                        \/\/ CSV\n                        return s.split(\",\").map(x => stripOuterQuotes(x).trim()).filter(Boolean);\n                    }\n\n                    function parseHotkeySpec(specRaw) {\n                        \/\/ Examples:\n                        \/\/ \"q\"\n                        \/\/ \"PageDown\"\n                        \/\/ \"shift:+\"\n                        \/\/ \"alt:-\"\n                        \/\/ \"ctrl+shift:+\"\n                        const raw = stripOuterQuotes(specRaw).trim();\n                        if (!raw) return null;\n\n                        const out = {\n                            key: raw,\n                            shift: false,\n                            alt: false,\n                            ctrl: false,\n                            meta: false\n                        };\n\n                        const parts = raw.split(\":\");\n                        if (parts.length === 1) return out;\n\n                        const mods = parts[0].split(\"+\").map(s => s.trim().toLowerCase()).filter(Boolean);\n                        const key = parts.slice(1).join(\":\").trim(); \/\/ allow \":\" inside key if ever needed\n\n                        out.key = key || \"\";\n                        out.shift = mods.includes(\"shift\");\n                        out.alt = mods.includes(\"alt\");\n                        out.ctrl = mods.includes(\"ctrl\") || mods.includes(\"control\");\n                        out.meta = mods.includes(\"meta\") || mods.includes(\"cmd\") || mods.includes(\"command\");\n                        return out.key ? out : null;\n                    }\n\n                    function keyMetaFor(key) {\n                        \/\/ Minimal mapping (extend if you add more hotkeys later)\n                        switch (key) {\n                            case \"Escape\":\n                                return {\n                                    code: \"Escape\", keyCode: 27\n                                };\n                            case \"PageUp\":\n                                return {\n                                    code: \"PageUp\", keyCode: 33\n                                };\n                            case \"PageDown\":\n                                return {\n                                    code: \"PageDown\", keyCode: 34\n                                };\n                            case \"Shift\":\n                                return {\n                                    code: \"ShiftLeft\", keyCode: 16\n                                };\n                            case '+':\n                                return {\n                                    code: 'NumpadAdd', keyCode: 107\n                                };\n                            case '-':\n                                return {\n                                    code: 'NumpadSubtract', keyCode: 109\n                                };\n                            case \"Space\":\n                                return {\n                                    code: \"Space\", keyCode: 32\n                                };\n                            default: {\n                                if (key.length === 1) {\n                                    const ch = key.toUpperCase();\n                                    if (\/[A-Z]\/.test(ch)) return {\n                                        code: \"Key\" + ch,\n                                        keyCode: ch.charCodeAt(0)\n                                    };\n                                }\n                                return {\n                                    code: key,\n                                    keyCode: 0\n                                };\n                            }\n                        }\n                    }\n\n                    function getOledTarget(root) {\n                        const coreStage = root.querySelector(\".cvxPSStage--core\");\n                        if (!coreStage) return null;\n\n                        const oledMount =\n                            coreStage.querySelector('[data-cvx-root=\"oled-compose\"]') ||\n                            coreStage.querySelector(\".cvxPSOledPayload\") ||\n                            coreStage.querySelector('[data-ps-mount=\"oled\"]') ||\n                            coreStage;\n\n                        const canvas =\n                            oledMount.querySelector(\"canvas\") ||\n                            oledMount.querySelector(\".cvxOled\") ||\n                            null;\n\n                        const t = canvas || oledMount;\n                        \/\/ aseguro foco\n                        if (!t.hasAttribute(\"tabindex\")) t.setAttribute(\"tabindex\", \"0\");\n                        return t;\n                    }\n\n                    function focusOled(root) {\n                        const t = getOledTarget(root);\n                        if (!t) return null;\n                        try {\n                            t.focus({\n                                preventScroll: true\n                            });\n                        } catch (_) {\n                            try {\n                                t.focus();\n                            } catch (_) {}\n                        }\n                        return t;\n                    }\n\n                    function dispatchKey(target, type, init) {\n                        const ev = new KeyboardEvent(type, Object.assign({\n                            bubbles: true,\n                            cancelable: true,\n                            composed: true\n                        }, init));\n                        target.dispatchEvent(ev);\n                    }\n\n                    function setPressed(btn, on) {\n                        btn.setAttribute(\"aria-pressed\", on ? \"true\" : \"false\");\n                        btn.classList.toggle(\"is-on\", !!on);\n                    }\n\n                    function isPressed(btn) {\n                        \/\/ Fuente de verdad: aria-pressed (tu HTML ya lo trae)\n                        const ap = btn.getAttribute(\"aria-pressed\");\n                        if (ap === \"true\") return true;\n                        if (ap === \"false\") return false;\n\n                        \/\/ Fallback si alg\u00fan bot\u00f3n no tiene aria-pressed por error\n                        return btn.classList.contains(\"is-on\");\n                    }\n\n                    document.querySelectorAll(ROOT_SEL).forEach((root) => {\n                        if (root.__cvxPSCtlOrchV3) return;\n                        root.__cvxPSCtlOrchV3 = true;\n                        root.__cvxPSSendHotkey = sendHotkey; \/\/ expose sender to Guided Tour (scoped per root)\n\n                        \/\/ Hotkeys (CSS vars) \u2014 single source of truth\n                        const VAR = {\n                            xplus: \"--cvx-ps-hk-xplus\",\n                            xminus: \"--cvx-ps-hk-xminus\",\n                            yplus: \"--cvx-ps-hk-yplus\",\n                            yminus: \"--cvx-ps-hk-yminus\",\n\n                            gainPlus: \"--cvx-ps-hk-gain-plus\",\n                            gainMinus: \"--cvx-ps-hk-gain-minus\",\n                            volPlus: \"--cvx-ps-hk-vol-plus\",\n                            volMinus: \"--cvx-ps-hk-vol-minus\",\n\n                            up: \"--cvx-ps-hk-up\",\n                            down: \"--cvx-ps-hk-down\",\n                            left: \"--cvx-ps-hk-left\",\n                            right: \"--cvx-ps-hk-right\",\n                            enter: \"--cvx-ps-hk-enter\",\n                            back: \"--cvx-ps-hk-back\",\n\n                            shift: \"--cvx-ps-hk-shift\",\n                            cancel: \"--cvx-ps-hk-cancel\",\n                            menu: \"--cvx-ps-hk-menu\",\n                            conf: \"--cvx-ps-hk-conf\",\n\n                            solo: \"--cvx-ps-hk-solo\",\n                            mute: \"--cvx-ps-hk-mute\",\n                            arm: \"--cvx-ps-hk-arm\"\n                        };\n\n                        const FALLBACK = {\n                            xplus: \"+\",\n                            xminus: \"-\",\n                            yplus: \"PageDown\",\n                            yminus: \"PageUp\",\n\n                            gainPlus: \"3\",\n                            gainMinus: \"4\",\n                            volPlus: \"1\",\n                            volMinus: \"2\",\n\n                            up: \"ArrowUp\",\n                            down: \"ArrowDown\",\n                            left: \"ArrowLeft\",\n                            right: \"ArrowRight\",\n                            enter: \"Enter\",\n                            back: \"Backspace\",\n\n                            shift: \"Shift\",\n                            cancel: \"Escape\",\n                            menu: \"e\",\n                            conf: \"w\",\n\n                            solo: \"s\",\n                            mute: \"m\",\n                            arm: \"q\"\n                        };\n\n\n                        const shiftKeyName = (cssVar(root, VAR.shift, FALLBACK.shift) || FALLBACK.shift).trim();\n                        let shiftLatch = false;\n\n                        \/\/ Buttons: [data-ps-ctl] and [data-ps-tgl] -> forward as KeyboardEvents into OLED\n                        root.addEventListener(\"click\", (ev) => {\n                            const btn = ev.target.closest(\"[data-ps-ctl],[data-ps-tgl]\");\n                            if (!btn || !root.contains(btn)) return;\n\n                            const id = btn.getAttribute(\"data-ps-ctl\");\n                            const tgl = btn.getAttribute(\"data-ps-tgl\");\n\n                            \/\/ ---------- Controls ----------\n                            if (id) {\n                                ev.preventDefault();\n\n                                if (id === \"shift\") {\n                                    toggleShift(btn);\n                                    return;\n                                }\n\n                                let spec = \"\";\n\n                                if (id === \"x+\") spec = cssVar(root, VAR.xplus, FALLBACK.xplus);\n                                else if (id === \"x-\") spec = cssVar(root, VAR.xminus, FALLBACK.xminus);\n                                else if (id === \"y+\") spec = cssVar(root, VAR.yplus, FALLBACK.yplus);\n                                else if (id === \"y-\") spec = cssVar(root, VAR.yminus, FALLBACK.yminus);\n\n                                else if (id === \"gain+\") spec = cssVar(root, VAR.gainPlus, FALLBACK.gainPlus);\n                                else if (id === \"gain-\") spec = cssVar(root, VAR.gainMinus, FALLBACK.gainMinus);\n                                else if (id === \"vol+\") spec = cssVar(root, VAR.volPlus, FALLBACK.volPlus);\n                                else if (id === \"vol-\") spec = cssVar(root, VAR.volMinus, FALLBACK.volMinus);\n\n                                else if (id === \"cancel\") spec = cssVar(root, VAR.cancel, FALLBACK.cancel);\n                                else if (id === \"menu\") spec = cssVar(root, VAR.menu, FALLBACK.menu);\n                                else if (id === \"conf\") spec = cssVar(root, VAR.conf, FALLBACK.conf);\n\n                                else if (id === \"nav-up\" || id === \"up\") spec = cssVar(root, VAR.up, FALLBACK.up);\n                                else if (id === \"nav-down\" || id === \"down\") spec = cssVar(root, VAR.down, FALLBACK.down);\n                                else if (id === \"nav-left\" || id === \"left\") spec = cssVar(root, VAR.left, FALLBACK.left);\n                                else if (id === \"nav-right\" || id === \"right\") spec = cssVar(root, VAR.right, FALLBACK.right);\n\n                                else if (id === \"enter\") spec = cssVar(root, VAR.enter, FALLBACK.enter);\n                                else if (id === \"back\") spec = cssVar(root, VAR.back, FALLBACK.back);\n\n                                else return;\n\n                                sendHotkey((spec || \"\").trim());\n                                return;\n                            }\n\n                            \/\/ ---------- Toggles ----------\n                            if (tgl) {\n                                ev.preventDefault();\n                                if (tgl === \"shift\") {\n                                    toggleShift(btn);\n                                    return;\n                                }\n\n                                \/\/ UI state\n                                const on = !isPressed(btn);\n                                setPressed(btn, on);\n\n                                let spec = \"\";\n\n                                if (tgl === \"arm\") spec = cssVar(root, VAR.arm, FALLBACK.arm);\n                                else if (tgl === \"solo\") spec = cssVar(root, VAR.solo, FALLBACK.solo);\n                                else if (tgl === \"mute\") spec = cssVar(root, VAR.mute, FALLBACK.mute);\n                                else return;\n\n                                sendHotkey((spec || \"\").trim());\n                                return;\n                            }\n                        });\n\n                        function sendHotkey(specStr) {\n                            if (!specStr) return;\n\n                            const t = focusOled(root);\n                            if (!t) return;\n\n                            const spec = parseHotkeySpec(specStr);\n                            const keyName = spec.key;\n\n                            \/\/ \u201cSpace\u201d debe viajar como espacio real en ev.key\n                            const key = (keyName === \"Space\") ? \" \" : keyName;\n\n                            const km = keyMetaFor(keyName);\n\n                            const init = {\n                                key,\n                                code: km.code,\n                                keyCode: km.keyCode,\n                                which: km.keyCode,\n                                shiftKey: spec.shift || shiftLatch || (keyName === \"Shift\"),\n                                altKey: spec.alt,\n                                ctrlKey: spec.ctrl,\n                                metaKey: spec.meta,\n                                repeat: false\n                            };\n                            requestAnimationFrame(() => {\n                                dispatchKey(t, \"keydown\", init);\n                                dispatchKey(t, \"keyup\", init);\n                            });\n                        }\n\n\n                        \/\/ SHIFT latch \u2014 ligado a --cvx-ps-hk-shift (y adem\u00e1s emite down\/up de esa tecla)\n                        \/\/ SHIFT latch \u2014 ligado a --cvx-ps-hk-shift (y adem\u00e1s emite down\/up de esa tecla)\n                        function setShiftLatch(on, btnMaybe) {\n                            const want = !!on;\n                            if (want === shiftLatch) return;\n\n                            shiftLatch = want;\n\n                            \/\/ Estado observable (para bridge pointer->oled y debug)\n                            root.dataset.psShiftLatch = shiftLatch ? \"1\" : \"0\";\n\n                            \/\/ UI\n                            const btn =\n                                btnMaybe ||\n                                root.querySelector('[data-ps-tgl=\"shift\"],[data-ps-ctl=\"shift\"]');\n                            if (btn) {\n                                setPressed(btn, shiftLatch);\n                                btn.classList.toggle(\"pill--strong\", shiftLatch);\n                            }\n\n                            \/\/ Forward de tecla al OLED (mantiene coherencia interna)\n                            const t = focusOled(root);\n                            if (!t) return;\n\n                            const km = keyMetaFor(shiftKeyName);\n                            const init = {\n                                key: shiftKeyName,\n                                code: km.code,\n                                keyCode: km.keyCode,\n                                which: km.keyCode,\n                                shiftKey: true,\n                                altKey: false,\n                                ctrlKey: false,\n                                metaKey: false,\n                                repeat: false\n                            };\n\n                            requestAnimationFrame(() => {\n                                dispatchKey(t, shiftLatch ? \"keydown\" : \"keyup\", init);\n                            });\n                        }\n\n                        \/\/ Exponer al Guided Tour (scoped per-root)\n                        root.__cvxPSSetShiftLatch = setShiftLatch;\n\n                        function toggleShift(btn) {\n                            setShiftLatch(!shiftLatch, btn);\n                        }\n\n                        \/\/ +TRACK seed logic\n\n                        const seed = parseSeedList(cssVar(root, \"--cvx-ps-track-seed\", \"\"));\n                        const rowsHost = root.querySelector(\".cvxPSCtlCard__rows\");\n                        const nextPill = root.querySelector(\"[data-ps-next-track]\");\n                        const addBtn = root.querySelector(\"[data-ps-add-track]\");\n\n                        function currentRowCount() {\n                            return rowsHost ? rowsHost.querySelectorAll(\".cvxPSCtlRow\").length : 0;\n                        }\n\n                        function nextSeedName() {\n                            const n = currentRowCount(); \/\/ \u201cconsumidos\u201d = rows existentes\n                            if (!seed.length) return \"Track \" + (n + 1);\n                            return seed[n % seed.length];\n                        }\n\n                        function abbr(name) {\n                            const s = String(name || \"\").trim();\n                            if (!s) return \"TRK\";\n                            return s.toUpperCase().replace(\/\\s+\/g, \"\").slice(0, 5);\n                        }\n\n                        function refreshNextPill() {\n                            if (!nextPill) return;\n                            nextPill.textContent = nextSeedName();\n                        }\n\n                        function makeRow(labelFull) {\n                            const nm = abbr(labelFull);\n                            const row = document.createElement(\"div\");\n                            row.className = \"cvxPSCtlRow\";\n                            row.innerHTML = `\n        <div class=\"nm\">${nm}<\/div>\n        <div class=\"r\">\n          <button class=\"b\" data-ps-ctl=\"gain-\"><span class=\"cvxPSBtnTxt\" data-cvx-glyph=\"1\">\u2212<\/span><\/button>\n          <button class=\"b\" data-ps-ctl=\"gain+\"><span class=\"cvxPSBtnTxt\" data-cvx-glyph=\"1\">+<\/span><\/button>\n\n          <button class=\"tg\" data-ps-tgl=\"arm\" aria-pressed=\"false\"><span class=\"cvxPSBtnTxt\">ARM<\/span><\/button>\n          <button class=\"tg\" data-ps-tgl=\"solo\" aria-pressed=\"false\"><span class=\"cvxPSBtnTxt\">S<\/span><\/button>\n          <button class=\"tg\" data-ps-tgl=\"mute\" aria-pressed=\"false\"><span class=\"cvxPSBtnTxt\">M<\/span><\/button>\n\n          <button class=\"b\" data-ps-ctl=\"vol-\"><span class=\"cvxPSBtnTxt\" data-cvx-glyph=\"1\">\u2212<\/span><\/button>\n          <button class=\"b\" data-ps-ctl=\"vol+\"><span class=\"cvxPSBtnTxt\" data-cvx-glyph=\"1\">+<\/span><\/button>\n        <\/div>\n      `;\n                            \/\/ guardo nombre completo por si luego quer\u00e9s usarlo\n                            row.dataset.psTrackName = String(labelFull || \"\");\n                            return row;\n                        }\n\n                        function addTrackRow() {\n                            if (!rowsHost) return;\n                            rowsHost.appendChild(makeRow(nextSeedName()));\n                            refreshNextPill();\n                        }\n\n                        function clearTrackRows() {\n                            if (!rowsHost) return;\n                            rowsHost.querySelectorAll(\".cvxPSCtlRow\").forEach(n => n.remove());\n                            refreshNextPill();\n                        }\n\n                        \/\/ Exponer al Guided Tour \/ macros (scoped per-root)\n                        root.__cvxPSSetTrackRows = (n) => {\n                            const cnt = Math.max(0, Math.min(16, (n | 0)));\n                            clearTrackRows();\n                            for (let i = 0; i < cnt; i++) addTrackRow();\n                        };\n                        if (addBtn && rowsHost) {\n                            addBtn.addEventListener(\"click\", (e) => {\n                                e.preventDefault();\n                                e.stopPropagation();\n                                addTrackRow();\n                            }, true);\n                        }\n                        refreshNextPill();\n\n                    });\n                })();\n\n                \/\/ Initial mount\/warp\n                mountOled();\n                psSyncTracks('oled:init');\n                scheduleOledWarp();\n\n                setMode(root.getAttribute('data-ps-mode') || 'capture');\n                scheduleInitialTPPass();\n\n                \/\/ Accordion behavior (scoped)\n                root.querySelectorAll('.cvxPSAcc .cvxAcc__item').forEach(item => {\n                    const btn = item.querySelector('.cvxAcc__btn');\n                    if (!btn) return;\n                    btn.setAttribute('aria-expanded', item.classList.contains('is-open') ? 'true' : 'false');\n                    btn.addEventListener('click', () => {\n                        const group = item.closest('.cvxPSAcc');\n                        if (!group) return;\n                        const willOpen = !item.classList.contains('is-open');\n                        group.querySelectorAll('.cvxAcc__item').forEach(other => {\n                            const otherBtn = other.querySelector('.cvxAcc__btn');\n                            const shouldOpen = other === item && willOpen;\n                            other.classList.toggle('is-open', shouldOpen);\n                            if (otherBtn) otherBtn.setAttribute('aria-expanded', shouldOpen ? 'true' : 'false');\n                        });\n                    });\n                });\n            }\n\n            roots.forEach(init);\n        })();\n        (function() {\n            \"use strict\";\n\n            const ROOT_SEL = '.cvxScope [data-cvx-root=\"portable-studio\"]';\n            const roots = document.querySelectorAll(ROOT_SEL);\n            if (!roots.length) return;\n\n            \/* =========================================================\n               Helpers (safe \/ no globals)\n            ========================================================= *\/\n            const clamp = (v, a, b) => Math.max(a, Math.min(b, v));\n\n            function prefersReducedMotion() {\n                try {\n                    return !!window.matchMedia && window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches;\n                } catch (_) {\n                    return false;\n                }\n            }\n\n            function stripCssString(s) {\n                const t = String(s || \"\").trim();\n                if (!t) return \"\";\n                \/\/ CSS custom props often come as \"'[...]'\" or \"\\\"[...]\\\"\"\n                const a = t[0],\n                    b = t[t.length - 1];\n                if ((a === \"'\" && b === \"'\") || (a === '\"' && b === '\"')) return t.slice(1, -1);\n                return t;\n            }\n\n            function readCssVar(root, name, fallback) {\n                const v = getComputedStyle(root).getPropertyValue(name);\n                const s = stripCssString(v);\n                return s ? s : fallback;\n            }\n\n            function safeJSONParse(str, fallback) {\n                try {\n                    const s = stripCssString(str);\n                    if (!s) return fallback;\n                    return JSON.parse(s);\n                } catch (_) {\n                    return fallback;\n                }\n            }\n\n            function deepMerge(a, b) {\n                if (!b || typeof b !== \"object\") return a;\n                const out = Array.isArray(a) ? a.slice() : Object.assign({}, a || {});\n                for (const k of Object.keys(b)) {\n                    const bv = b[k];\n                    const av = out[k];\n                    if (bv && typeof bv === \"object\" && !Array.isArray(bv) && av && typeof av === \"object\" && !Array.isArray(av)) {\n                        out[k] = deepMerge(av, bv);\n                    } else {\n                        out[k] = bv;\n                    }\n                }\n                return out;\n            }\n\n            function rafThrottle(fn) {\n                let raf = 0;\n                return function() {\n                    if (raf) return;\n                    raf = requestAnimationFrame(() => {\n                        raf = 0;\n                        fn();\n                    });\n                };\n            }\n\n            \/* =========================================================\n               Mode mapping (v3.12 uses \"share\" in UI; guide wants \"sync\")\n            ========================================================= *\/\n            function readMode(root) {\n                const m = (root.getAttribute(\"data-ps-mode\") || \"\").trim() || \"capture\";\n                return m === \"share\" ? \"sync\" : m; \/\/ normalize to schema key\n            }\n\n            \/* =========================================================\n               Breakpoint key for per-step overrides (m\/t\/d)\n               - Keep it simple; you can override via CSS if desired later\n            ========================================================= *\/\n            function bpKey(rootRectW) {\n                if (rootRectW <= 720) return \"m\";\n                if (rootRectW <= 1060) return \"t\";\n                return \"d\";\n            }\n\n            \/* =========================================================\n               Areas (selector-first; falls back to v3.12 DOM)\n               - OLED area MUST be post-transform: [data-ps-oled-warp] in v3.12\n            ========================================================= *\/\n            function resolveAreas(root) {\n                const areaRoot = root.querySelector('[data-ps-area=\"root\"]') || root;\n                const areaOled = root.querySelector('[data-ps-area=\"oled\"]') || root.querySelector('[data-ps-oled-warp]') || root.querySelector('[data-ps-oled-mask]') || root;\n                const areaLeft = root.querySelector('[data-ps-area=\"left\"]') || root.querySelector(\".cvxPSSim\") || root;\n                const areaRight = root.querySelector('[data-ps-area=\"right\"]') || root.querySelector(\".cvxPSAside\") || root;\n                const areaPanel = root.querySelector('[data-ps-area=\"panel\"]') || root;\n                return {\n                    root: areaRoot,\n                    oled: areaOled,\n                    left: areaLeft,\n                    right: areaRight,\n                    panel: areaPanel\n                };\n            }\n\n            \/* =========================================================\n               Target resolution (Radar\/Hole)\n               - selector-first + anchor + offsets (px\/%)\n               - fallback: normalized coords within area rect\n            ========================================================= *\/\n            function anchorXY(anchor, rect) {\n                switch (anchor) {\n                    case \"tl\":\n                        return {\n                            x: rect.x, y: rect.y\n                        };\n                    case \"tr\":\n                        return {\n                            x: rect.x + rect.w, y: rect.y\n                        };\n                    case \"bl\":\n                        return {\n                            x: rect.x, y: rect.y + rect.h\n                        };\n                    case \"br\":\n                        return {\n                            x: rect.x + rect.w, y: rect.y + rect.h\n                        };\n                    case \"center\":\n                    default:\n                        return {\n                            x: rect.x + rect.w \/ 2, y: rect.y + rect.h \/ 2\n                        };\n                }\n            }\n\n            function localRect(areaRect, targetRect) {\n                return {\n                    x: targetRect.left - areaRect.left,\n                    y: targetRect.top - areaRect.top,\n                    w: targetRect.width,\n                    h: targetRect.height\n                };\n            }\n\n            function resolvePointInRoot(rootRect, areaEl, areaRect, spec, allowRadius) {\n                \/\/ Returns coords in ROOT local space\n                \/\/ spec: { selector, anchor, dxPx, dyPx, dxPct, dyPct, rPx, rPct, xN, yN, rN, ... }\n                let x = null,\n                    y = null,\n                    r = null;\n\n                \/\/ 1) Selector path\n                if (spec && spec.selector) {\n                    const t = areaEl.querySelector(spec.selector);\n                    if (t) {\n                        const tr = t.getBoundingClientRect();\n                        const lr = localRect(areaRect, tr);\n                        const base = anchorXY(spec.anchor || \"center\", lr);\n\n                        const dxPx = Number(spec.dxPx || 0);\n                        const dyPx = Number(spec.dyPx || 0);\n                        const dxPct = Number(spec.dxPct || 0);\n                        const dyPct = Number(spec.dyPct || 0);\n\n                        x = base.x + dxPx + dxPct * lr.w;\n                        y = base.y + dyPx + dyPct * lr.h;\n\n                        if (allowRadius) {\n                            const rPx = Number(spec.rPx || 0);\n                            const rPct = Number(spec.rPct || 0);\n                            r = (rPx > 0) ? rPx : (rPct > 0 ? rPct * Math.min(lr.w, lr.h) : null);\n                        }\n                    }\n                }\n\n                \/\/ 2) Normalized fallback within area\n                if ((x == null || y == null) && spec && spec.xN != null && spec.yN != null) {\n                    x = Number(spec.xN) * areaRect.width;\n                    y = Number(spec.yN) * areaRect.height;\n                    if (allowRadius && spec.rN != null) {\n                        r = Number(spec.rN) * Math.min(areaRect.width, areaRect.height);\n                    }\n                }\n\n                if (x == null || y == null) return null;\n\n                \/\/ Convert (area local) => (root local)\n                const ox = areaRect.left - rootRect.left;\n                const oy = areaRect.top - rootRect.top;\n\n                return {\n                    x: x + ox,\n                    y: y + oy,\n                    r: allowRadius ? (Number.isFinite(r) ? r : 0) : 0\n                };\n            }\n\n            \/* =========================================================\n               Mask path building (SVG, even-odd)\n            ========================================================= *\/\n            function roundedRectPath(x, y, w, h, r) {\n                const rr = clamp(r, 0, Math.min(w, h) \/ 2);\n                const x2 = x + w,\n                    y2 = y + h;\n                if (rr <= 0.001) {\n                    return `M${x},${y}H${x2}V${y2}H${x}Z`;\n                }\n                return [\n                    `M${x+rr},${y}`,\n                    `H${x2-rr}`,\n                    `Q${x2},${y} ${x2},${y+rr}`,\n                    `V${y2-rr}`,\n                    `Q${x2},${y2} ${x2-rr},${y2}`,\n                    `H${x+rr}`,\n                    `Q${x},${y2} ${x},${y2-rr}`,\n                    `V${y+rr}`,\n                    `Q${x},${y} ${x+rr},${y}`,\n                    \"Z\"\n                ].join(\" \");\n            }\n\n            function circlePath(cx, cy, r) {\n                const rr = Math.max(0, r);\n                \/\/ Two arcs circle\n                return `M${cx-rr},${cy}a${rr},${rr} 0 1,0 ${rr*2},0a${rr},${rr} 0 1,0 ${-rr*2},0Z`;\n            }\n\n            \/* =========================================================\n               Hotkey sender (reuse existing if exposed; fallback minimal)\n            ========================================================= *\/\n            function sendHotkey(root, keyOrSpec) {\n                const spec = String(keyOrSpec || \"\").trim();\n                if (!spec) return;\n\n                \/\/ Preferred: use v3.12 sender if you exposed it (Option A)\n                if (typeof root.__cvxPSSendHotkey === \"function\") {\n                    root.__cvxPSSendHotkey(spec);\n                    return;\n                }\n\n                \/\/ Fallback minimal: dispatch key events to mounted OLED payload\n                const t =\n                    root.querySelector('[data-ps-mount=\"oled\"] [data-cvx-root=\"oled-compose\"]') ||\n                    root.querySelector('[data-ps-mount=\"oled\"]') ||\n                    root.querySelector('[data-ps-oled-warp]') ||\n                    root;\n\n                try {\n                    t.focus({\n                        preventScroll: true\n                    });\n                } catch (_) {}\n\n                \/\/ Parse minimal \"mod:Key\" format (shift:\/alt:\/ctrl:\/meta:)\n                const parts = spec.split(\":\").map(s => s.trim()).filter(Boolean);\n                let key = spec,\n                    mods = {\n                        shift: false,\n                        alt: false,\n                        ctrl: false,\n                        meta: false\n                    };\n                if (parts.length >= 2) {\n                    key = parts[parts.length - 1];\n                    for (let i = 0; i < parts.length - 1; i++) {\n                        const m = parts[i].toLowerCase();\n                        if (m === \"shift\") mods.shift = true;\n                        if (m === \"alt\") mods.alt = true;\n                        if (m === \"ctrl\") mods.ctrl = true;\n                        if (m === \"meta\") mods.meta = true;\n                    }\n                }\n\n                const init = {\n                    key,\n                    shiftKey: mods.shift,\n                    altKey: mods.alt,\n                    ctrlKey: mods.ctrl,\n                    metaKey: mods.meta,\n                    bubbles: true,\n                    cancelable: true\n                };\n                requestAnimationFrame(() => {\n                    t.dispatchEvent(new KeyboardEvent(\"keydown\", init));\n                    t.dispatchEvent(new KeyboardEvent(\"keyup\", init));\n                });\n            }\n\n            \/* =========================================================\n               Guide config loading (global defaults + CSS per-mode overrides)\n            ========================================================= *\/\n            function readGlobalDefaults() {\n                const el = document.querySelector('script[type=\"application\/json\"][data-cvx-ps-guide]');\n                if (!el) return null;\n                return safeJSONParse(el.textContent, null);\n            }\n\n            function readModeStepsFromCSS(root, modeKey) {\n                const map = {\n                    capture: \"--cvx-ps-guide-capture\",\n                    edit: \"--cvx-ps-guide-edit\",\n                    mix: \"--cvx-ps-guide-mix\",\n                    sync: \"--cvx-ps-guide-sync\"\n                };\n                const varName = map[modeKey] || map.capture;\n                const raw = getComputedStyle(root).getPropertyValue(varName);\n                const s = stripCssString(raw);\n                if (!s) return null; \/\/ \"not provided\"\n                const arr = safeJSONParse(s, null);\n                return Array.isArray(arr) ? arr : null;\n            }\n\n            function buildGuideModel(root) {\n                const global = readGlobalDefaults() || {};\n                const base = {\n                    version: 1,\n                    options: {\n                        autoStart: \"once\",\n                        startOnceKey: \"cvx_ps_tour_v1_done\",\n                        modePolicy: \"followUser\",\n                        respectReducedMotion: true,\n                        motionMs: 200,\n                        radarPulseMs: 2200,\n                        zIndex: 50,\n                        dim: 0.72,\n                        featherPx: 18\n                    },\n                    modes: {\n                        capture: [],\n                        edit: [],\n                        mix: [],\n                        sync: []\n                    }\n                };\n\n                const merged = deepMerge(base, global);\n\n                \/\/ CSS overrides per mode (priority over global)\n                for (const mk of [\"capture\", \"edit\", \"mix\", \"sync\"]) {\n                    const cssSteps = readModeStepsFromCSS(root, mk);\n                    if (cssSteps !== null) merged.modes[mk] = cssSteps; \/\/ even [] is a valid override\n                }\n\n                return merged;\n            }\n\n            function applyStepOverrides(step, bp) {\n                const o = step && step.overrides && step.overrides[bp];\n                if (!o) return step;\n                \/\/ Shallow-ish deep merge for known subtrees\n                let s = deepMerge(step, o);\n                \/\/ Ensure override blocks don't recursively keep themselves\n                return s;\n            }\n\n            \/* =========================================================\n               UI mount (created if missing) \u2014 scoped inside root\n               - If your HTML\/CSS already include it, we reuse it.\n            ========================================================= *\/\n            function ensureUI(root, opts) {\n                let ui = root.querySelector('.cvxPSGuide[data-ps-guide]');\n                if (!ui) {\n                    ui = document.createElement(\"div\");\n                    ui.className = \"cvxPSGuide\";\n                    ui.setAttribute(\"data-ps-guide\", \"\");\n                    ui.setAttribute(\"aria-hidden\", \"true\");\n\n                    ui.innerHTML = `\n        <div class=\"cvxPSGuide__mask\" data-ps-guide-mask aria-hidden=\"true\">\n          <svg data-ps-guide-mask-svg preserveAspectRatio=\"none\">\n            <path data-ps-guide-mask-path fill-rule=\"evenodd\"><\/path>\n          <\/svg>\n        <\/div>\n\n        <div class=\"cvxPSGuide__radars\" data-ps-guide-radars aria-hidden=\"true\"><\/div>\n\n        <div class=\"cvxPSGuide__cards\" data-ps-guide-cards>\n          <div class=\"cvxPSGuideCard is-left\"  data-ps-guide-card=\"left\">\n            <div class=\"t\" data-ps-guide-title><\/div>\n            <p class=\"d\" data-ps-guide-desc><\/p>\n            <div class=\"p\" data-ps-guide-pills><\/div>\n          <\/div>\n          <div class=\"cvxPSGuideCard is-right\" data-ps-guide-card=\"right\">\n            <div class=\"t\" data-ps-guide-title><\/div>\n            <p class=\"d\" data-ps-guide-desc><\/p>\n            <div class=\"p\" data-ps-guide-pills><\/div>\n          <\/div>\n        <\/div>\n\n        <div class=\"cvxPSGuide__bar\" data-ps-guide-bar>\n          <button type=\"button\" data-ps-guide-back>Back<\/button>\n          <button type=\"button\" data-ps-guide-next>Next<\/button>\n          <button type=\"button\" data-ps-guide-reset>Reset<\/button>\n        <\/div>\n\n        <button type=\"button\" class=\"cvxPSGuide__start\" data-ps-guide-start aria-label=\"Guided tour\">Tour<\/button>\n\n        <div class=\"cvxPSGuide__done\" data-ps-guide-done hidden>\n          <div class=\"msg\">Listo. Exploralo libremente.<\/div>\n          <button type=\"button\" data-ps-guide-close>OK<\/button>\n        <\/div>\n      `;\n                    root.appendChild(ui);\n                }\n\n                \/\/ z-index + basic pointer policy (CSS should refine)\n                ui.style.zIndex = String(Number(opts.zIndex || 50));\n                ui.style.position = ui.style.position || \"absolute\";\n                ui.style.inset = ui.style.inset || \"0\";\n\n                \/\/ Toast (persistente, creado si no existe)\n                let toast = ui.querySelector('[data-ps-guide-toast]');\n                if (!toast) {\n                    toast = document.createElement(\"div\");\n                    toast.className = \"cvxPSToast\";\n                    toast.setAttribute(\"data-ps-guide-toast\", \"\");\n                    toast.setAttribute(\"role\", \"status\");\n                    toast.setAttribute(\"aria-live\", \"polite\");\n                    toast.setAttribute(\"aria-atomic\", \"true\");\n                    toast.innerHTML = `<div class=\"m\" data-ps-guide-toast-msg><\/div>`;\n                    ui.appendChild(toast);\n                }\n                const toastMsg = toast.querySelector(\"[data-ps-guide-toast-msg]\") || toast;\n\n                \/\/ Host del toast: debe vivir \u201cdentro\u201d de la imagen derecha (Compose App)\n                const toastHost =\n                    root.querySelector('.cvxPSAside .cvxStage') ||\n                    root.querySelector('[data-ps-guide-card-target=\"right\"]') ||\n                    ui;\n\n                \/\/ Si el toast viene del markup del tour, lo movemos al stage derecho\n                if (toast && toast.parentNode !== toastHost) {\n                    try {\n                        toastHost.appendChild(toast);\n                    } catch (_) {}\n                }\n\n                \/* INSERTAR ESTO AC\u00c1 (antes del return) *\/\n                const stageLeft = root.querySelector('[data-ps-guide-card-target=\"left\"]');\n                const stageRight = root.querySelector('[data-ps-guide-card-target=\"right\"]');\n\n                const guideLeft = ui.querySelector('[data-ps-guide-card=\"left\"]');\n                const guideRight = ui.querySelector('[data-ps-guide-card=\"right\"]');\n\n                const useStage = !!(stageLeft && stageRight);\n                if (useStage) root.setAttribute(\"data-ps-guide-cards\", \"stage\");\n                else root.removeAttribute(\"data-ps-guide-cards\");\n\n                \/* REEMPLAZAR EL return ENTERO por este *\/\n                return {\n                    ui,\n                    maskSvg: ui.querySelector(\"[data-ps-guide-mask-svg]\"),\n                    maskPath: ui.querySelector(\"[data-ps-guide-mask-path]\"),\n                    radars: ui.querySelector(\"[data-ps-guide-radars]\"),\n                    cardLeft: (useStage ? stageLeft : guideLeft),\n                    cardRight: (useStage ? stageRight : guideRight),\n                    btnBack: ui.querySelector(\"[data-ps-guide-back]\"),\n                    btnNext: ui.querySelector(\"[data-ps-guide-next]\"),\n                    btnReset: ui.querySelector(\"[data-ps-guide-reset]\"),\n                    btnStart: ui.querySelector(\"[data-ps-guide-start]\"),\n                    doneBox: ui.querySelector(\"[data-ps-guide-done]\"),\n                    btnClose: ui.querySelector(\"[data-ps-guide-close]\"),\n                    toast,\n                    toastMsg\n                };\n\n            }\n\n            function renderPills(host, pills) {\n                host.textContent = \"\";\n                if (!Array.isArray(pills) || !pills.length) return;\n                const listMode = \/^(UL|OL)$\/.test(host.tagName);\n                for (const txt of pills) {\n                    const s = document.createElement(\"span\");\n                    s.className = \"pill\";\n                    s.textContent = String(txt);\n                    if (listMode) {\n                        const li = document.createElement(\"li\");\n                        li.appendChild(s);\n                        host.appendChild(li);\n                    } else {\n                        host.appendChild(s);\n                    }\n                }\n            }\n\n            \/* =========================================================\n               Main per-root init\n            ========================================================= *\/\n            roots.forEach((root) => {\n                if (root.__cvxPSGuideInit) return;\n                root.__cvxPSGuideInit = true;\n\n                const guide = buildGuideModel(root);\n                const reduced = prefersReducedMotion() && guide.options && guide.options.respectReducedMotion !== false;\n\n                const opts = deepMerge(guide.options || {}, {\n                    motionMs: reduced ? 0 : Number(guide.options.motionMs || 200),\n                    radarPulseMs: reduced ? 999999 : Number(guide.options.radarPulseMs || 2200),\n                    dim: Number(guide.options.dim ?? 0.72),\n                    featherPx: Number(guide.options.featherPx ?? 18)\n                });\n\n                const ui = ensureUI(root, opts);\n                const areas = resolveAreas(root);\n\n                \/* =========================================================\n                   Guide UI anchor (Bar + CTA)\n                   - Anchors to the LEFT image: .cvxPSStage--core\n                   - Writes: --cvx-ps-guide-ui-x \/ --cvx-ps-guide-ui-y (px, root-local)\n                   - Fallback inset uses token: --cvx-ps-guide-ui-inset -> --cvx-ps-guide-pad\n                ========================================================= *\/\n                const guideAnchorEl =\n                    root.querySelector(\".cvxPSStage--core\") ||\n                    areas.left ||\n                    root;\n\n                function updateGuideUiAnchor() {\n                    const rr = root.getBoundingClientRect();\n                    if (rr.width < 12 || rr.height < 12) return;\n\n                    if (!guideAnchorEl) return;\n                    const ar = guideAnchorEl.getBoundingClientRect();\n                    if (ar.width < 12 || ar.height < 12) return;\n\n                    const inset = readVarNum(\n                        root,\n                        \"--cvx-ps-guide-ui-inset\",\n                        readVarNum(root, \"--cvx-ps-guide-pad\", 12)\n                    );\n\n                    const x = clamp((ar.left - rr.left) + inset, 0, rr.width);\n                    const y = clamp((ar.top - rr.top) + inset, 0, rr.height);\n\n                    root.style.setProperty(\"--cvx-ps-guide-ui-x\", x.toFixed(2) + \"px\");\n                    root.style.setProperty(\"--cvx-ps-guide-ui-y\", y.toFixed(2) + \"px\");\n                }\n\n                \/* Initial + post-layout refresh (Elementor\/editor friendly) *\/\n                updateGuideUiAnchor();\n                requestAnimationFrame(updateGuideUiAnchor);\n\n\n                const state = {\n                    phase: \"idle\", \/\/ idle | guided | free\n                    mode: readMode(root), \/\/ capture|edit|mix|sync\n                    idx: 0,\n                    step: null,\n                    steps: [],\n                    bp: \"d\",\n                    inViewport: false,\n                    visible: false,\n                    advanceDispose: null,\n                    io: null,\n                    ro: null,\n                    scrollHandler: null,\n                    pendingTimer: 0,\n                    toastCarry: 0 \/\/ pasos a conservar toast (carry)\n                };\n\n                function readVarNum(el, name, fallback) {\n                    const v = getComputedStyle(el).getPropertyValue(name).trim();\n                    const n = parseFloat(v);\n                    return Number.isFinite(n) ? n : fallback;\n                }\n\n                function updateGuideUiAnchor() {\n                    const core = root.querySelector(\".cvxPSStage--core\");\n                    if (!core) return;\n\n                    const rr = root.getBoundingClientRect();\n                    const cr = core.getBoundingClientRect();\n\n                    if (rr.width < 12 || rr.height < 12 || cr.width < 12 || cr.height < 12) return;\n\n                    const inset = clamp(readVarNum(root, \"--cvx-ps-guide-ui-inset\", 14), 0, 80);\n\n                    \/\/ Position of core stage top-left relative to root, plus inset\n                    const x = (cr.left - rr.left) + inset;\n                    const y = (cr.top - rr.top) + inset;\n\n                    root.style.setProperty(\"--cvx-ps-guide-ui-x\", x.toFixed(2) + \"px\");\n                    root.style.setProperty(\"--cvx-ps-guide-ui-y\", y.toFixed(2) + \"px\");\n                    root.style.setProperty(\"--cvx-ps-guide-ui-w\", cr.width.toFixed(2) + \"px\");\n                }\n\n                function setPhase(p) {\n                    state.phase = p;\n                    root.setAttribute(\"data-ps-guide-state\", p);\n                    try {\n                        if (p !== \"guided\") {\n                            const ae = document.activeElement;\n                            if (ae && ui && ui.ui && ui.ui.contains(ae) && ae.blur) ae.blur();\n                        }\n                    } catch (_) {}\n                    ui.ui.setAttribute(\"aria-hidden\", p === \"guided\" ? \"false\" : \"true\");\n                    ui.doneBox.hidden = true;\n\n                    \/* NEVER block underlying UI: CSS already handles hit-testing correctly *\/\n                    ui.ui.style.pointerEvents = \"none\";\n                    ui.btnStart.style.pointerEvents = \"auto\";\n                    updateGuideUiAnchor();\n\n                }\n\n\n                function isRootHidden() {\n                    const rr = root.getBoundingClientRect();\n                    return rr.width < 12 || rr.height < 12;\n                }\n\n                function clearAdvance() {\n                    if (state.advanceDispose) {\n                        try {\n                            state.advanceDispose();\n                        } catch (_) {}\n                        state.advanceDispose = null;\n                    }\n                    if (state.pendingTimer) {\n                        clearTimeout(state.pendingTimer);\n                        state.pendingTimer = 0;\n                    }\n                }\n\n                function currentStepsForMode(modeKey) {\n                    const arr = (guide.modes && guide.modes[modeKey]) || [];\n                    return Array.isArray(arr) ? arr.filter(s => !s || s.enabled !== false) : [];\n                }\n\n                function hydrateStep() {\n                    const rr = root.getBoundingClientRect();\n                    state.bp = bpKey(rr.width);\n\n                    state.mode = readMode(root);\n                    state.steps = currentStepsForMode(state.mode);\n\n                    state.idx = clamp(state.idx, 0, Math.max(0, state.steps.length - 1));\n                    const raw = state.steps[state.idx] || null;\n                    state.step = raw ? applyStepOverrides(raw, state.bp) : null;\n                }\n\n                \/* Cards policy (v1.3+):\n                   - If cards.left\/right is missing => keep previous (do not touch).\n                   - title\/desc:\n                       undefined\/missing => keep previous\n                       \"\" (empty string) => keep previous\n                       null => clear explicitly\n                       \"text\" => overwrite\n                   - pills:\n                       undefined\/missing => keep previous\n                       [] => overwrite (clears)\n                       [\"a\",\"b\"] => overwrite\n                       null => clear explicitly\n                *\/\n                function setTextIfMeaningful(el, v) {\n                    if (!el) return;\n\n                    if (v === undefined) return; \/\/ missing => keep previous\n                    if (v === null) { \/\/ explicit clear\n                        el.textContent = \"\";\n                        return;\n                    }\n                    if (typeof v !== \"string\") return;\n\n                    const s = v.trim();\n                    if (!s) return; \/\/ \"\" => keep previous\n                    el.textContent = s;\n                }\n\n                function renderPills(host, pills) {\n                    if (!host) return;\n                    host.innerHTML = \"\";\n\n                    if (!Array.isArray(pills)) return;\n\n                    const palette = [\"var(--cvxAccent)\", \"#8B5CF6\", \"#22C55E\", \"#38BDF8\"];\n                    const listMode = \/^(UL|OL)$\/.test(host.tagName);\n                    pills.forEach((txt, i) => {\n                        const s = (txt == null) ? \"\" : String(txt).trim();\n                        if (!s) return;\n                        const sp = document.createElement(\"span\");\n                        sp.className = \"cvxPill\";\n                        sp.style.setProperty(\"--cvx-pill-accent\", palette[i % palette.length]);\n                        sp.textContent = s;\n                        if (listMode) {\n                            const li = document.createElement(\"li\");\n                            li.appendChild(sp);\n                            host.appendChild(li);\n                        } else {\n                            host.appendChild(sp);\n                        }\n                    });\n                }\n\n                function setPillsIfProvided(host, pills) {\n                    if (!host) return;\n\n                    if (pills === undefined) return; \/\/ missing => keep previous\n                    if (pills === null) { \/\/ explicit clear\n                        host.innerHTML = \"\";\n                        return;\n                    }\n                    if (!Array.isArray(pills)) return;\n\n                    renderPills(host, pills); \/\/ overwrite (empty array clears)\n                }\n\n                function updateCards(step) {\n                    const left = step && step.cards ? step.cards.left : undefined;\n                    const right = step && step.cards ? step.cards.right : undefined;\n\n                    if (ui.cardLeft && left !== undefined) {\n                        const t = ui.cardLeft.querySelector('[data-ps-guide-title]');\n                        const d = ui.cardLeft.querySelector('[data-ps-guide-desc]');\n                        const p = ui.cardLeft.querySelector('[data-ps-guide-pills]');\n\n                        const vTitle = (\"title\" in left) ? left.title : undefined;\n                        const vDesc = (\"desc\" in left) ? left.desc : undefined;\n                        const vPills = (\"pills\" in left) ? left.pills : undefined;\n\n                        setTextIfMeaningful(t, vTitle);\n                        setTextIfMeaningful(d, vDesc);\n                        setPillsIfProvided(p, vPills);\n                    }\n\n                    if (ui.cardRight && right !== undefined) {\n                        const t = ui.cardRight.querySelector('[data-ps-guide-title]');\n                        const d = ui.cardRight.querySelector('[data-ps-guide-desc]');\n                        const p = ui.cardRight.querySelector('[data-ps-guide-pills]');\n\n                        const vTitle = (\"title\" in right) ? right.title : undefined;\n                        const vDesc = (\"desc\" in right) ? right.desc : undefined;\n                        const vPills = (\"pills\" in right) ? right.pills : undefined;\n\n                        setTextIfMeaningful(t, vTitle);\n                        setTextIfMeaningful(d, vDesc);\n                        setPillsIfProvided(p, vPills);\n                    }\n                }\n\n\n                \/* Outside tour: show a stable \u201cmode card\u201d using the first enabled step of that mode. *\/\n                function applyModeDefaultCards(modeKey) {\n                    const rr = root.getBoundingClientRect();\n                    const bp = bpKey(rr.width);\n                    const steps = currentStepsForMode(modeKey);\n                    const first = steps.length ? applyStepOverrides(steps[0], bp) : null;\n                    if (first) updateCards(first);\n                }\n\n\n                function ensureRadarCount(n) {\n                    const host = ui.radars;\n                    if (!host) return [];\n                    const existing = Array.from(host.querySelectorAll(\"[data-ps-guide-radar]\"));\n                    while (existing.length < n) {\n                        const el = document.createElement(\"span\");\n                        el.setAttribute(\"data-ps-guide-radar\", \"\");\n                        el.className = \"cvxPSGuideRadar\";\n                        \/\/ Inline safe geometry defaults (CSS can override visuals)\n                        el.style.position = \"absolute\";\n                        el.style.borderRadius = \"999px\";\n                        el.style.pointerEvents = \"none\";\n                        host.appendChild(el);\n                        existing.push(el);\n                    }\n                    \/\/ Hide extras\n                    existing.forEach((el, i) => {\n                        el.style.display = (i < n) ? \"\" : \"none\";\n                    });\n                    return existing.slice(0, n);\n                }\n\n                function paint(step) {\n                    if (state.phase !== \"guided\") return;\n                    if (!step) return;\n\n                    const rr = root.getBoundingClientRect();\n                    if (rr.width < 12 || rr.height < 12) return;\n                    updateGuideUiAnchor();\n\n                    const areasNow = resolveAreas(root);\n                    const areaRects = {};\n                    for (const k of Object.keys(areasNow)) {\n                        const el = areasNow[k];\n                        const r = el.getBoundingClientRect();\n                        areaRects[k] = r;\n                    }\n\n                    \/\/ 1) Radars\n                    const radars = (step.focus && Array.isArray(step.focus.radars)) ? step.focus.radars.filter(r => !r || r.enabled !== false) : [];\n                    const radarEls = ensureRadarCount(radars.length);\n                    radars.forEach((rt, i) => {\n                        const areaKey = rt.area || \"root\";\n                        const areaEl = areasNow[areaKey] || root;\n                        const areaRect = areaRects[areaKey] || rr;\n\n                        const pt = resolvePointInRoot(rr, areaEl, areaRect, rt, true);\n                        const el = radarEls[i];\n                        if (!pt || !el) return;\n\n                        const r = Math.max(10, Number(pt.r || 0) || (Number(rt.rPx || 0) || 0) || 14);\n                        el.style.width = (r * 2) + \"px\";\n                        el.style.height = (r * 2) + \"px\";\n                        el.style.transform = `translate(${(pt.x - r).toFixed(2)}px, ${(pt.y - r).toFixed(2)}px)`;\n                        el.style.setProperty(\"--cvx-ps-guide-pulse-ms\", String(opts.radarPulseMs));\n                    });\n\n                    \/\/ 2) Mask (optional)\n                    const mask = (step.focus && step.focus.mask) ? step.focus.mask : null;\n                    const maskOn = !!(mask && mask.enabled);\n\n                    if (!ui.maskSvg || !ui.maskPath) return;\n\n                    ui.maskSvg.setAttribute(\"viewBox\", `0 0 ${rr.width} ${rr.height}`);\n                    ui.maskSvg.setAttribute(\"width\", rr.width);\n                    ui.maskSvg.setAttribute(\"height\", rr.height);\n\n                    if (!maskOn) {\n                        \/\/ Clear mask (no dim)\n                        ui.maskPath.setAttribute(\"d\", \"\");\n                        ui.maskSvg.style.opacity = \"0\";\n                    } else {\n                        const dim = Number(mask.dim ?? opts.dim);\n                        const feather = Number(mask.featherPx ?? opts.featherPx);\n                        ui.maskSvg.style.opacity = \"1\";\n                        ui.maskSvg.style.filter = feather > 0 ? `blur(${feather}px)` : \"none\";\n                        ui.maskSvg.style.pointerEvents = \"none\";\n                        ui.maskSvg.style.position = \"absolute\";\n                        ui.maskSvg.style.inset = \"0\";\n                        ui.maskSvg.style.display = \"block\";\n\n                        \/\/ Outer rect\n                        let d = `M0,0H${rr.width}V${rr.height}H0Z`;\n\n                        const holes = Array.isArray(mask.holes) ? mask.holes.filter(h => !h || h.enabled !== false) : [];\n                        holes.forEach((h) => {\n                            const areaKey = h.area || \"root\";\n                            const areaEl = areasNow[areaKey] || root;\n                            const areaRect = areaRects[areaKey] || rr;\n\n                            \/\/ Hole can be selector rect with padding + radius\n                            let holePath = null;\n\n                            if (h.selector) {\n                                const t = areaEl.querySelector(h.selector);\n                                if (t) {\n                                    const tr = t.getBoundingClientRect();\n                                    const lr = localRect(areaRect, tr);\n\n                                    \/\/ Apply offsets like radar (anchor + dx\/dy)\n                                    const base = anchorXY(h.anchor || \"center\", lr);\n                                    const dxPx = Number(h.dxPx || 0);\n                                    const dyPx = Number(h.dyPx || 0);\n                                    const dxPct = Number(h.dxPct || 0);\n                                    const dyPct = Number(h.dyPct || 0);\n\n                                    \/\/ Rebuild as rect around element (not point)\n                                    let x = lr.x,\n                                        y = lr.y,\n                                        w = lr.w,\n                                        hh = lr.h;\n\n                                    \/\/ If anchor offsets are provided, shift rect by same delta (common use: nudges)\n                                    const cx0 = lr.x + lr.w \/ 2;\n                                    const cy0 = lr.y + lr.h \/ 2;\n                                    const cx1 = base.x + dxPx + dxPct * lr.w;\n                                    const cy1 = base.y + dyPx + dyPct * lr.h;\n                                    const ddx = cx1 - cx0;\n                                    const ddy = cy1 - cy0;\n\n                                    x += ddx;\n                                    y += ddy;\n\n                                    const pad = Number(h.paddingPx || 0);\n                                    x -= pad;\n                                    y -= pad;\n                                    w += pad * 2;\n                                    hh += pad * 2;\n\n                                    const rx = areaRect.left - rr.left + x;\n                                    const ry = areaRect.top - rr.top + y;\n\n                                    const rad = Number(h.radiusPx || 0);\n                                    holePath = roundedRectPath(rx, ry, w, hh, rad);\n                                }\n                            }\n\n                            \/\/ Fallback normalized hole\n                            if (!holePath && (h.xN != null && h.yN != null)) {\n                                const xN = Number(h.xN),\n                                    yN = Number(h.yN);\n                                const ox = areaRect.left - rr.left;\n                                const oy = areaRect.top - rr.top;\n\n                                \/\/ If wN\/hN provided => rect, else circle by rN\n                                if (h.wN != null && h.hN != null) {\n                                    const w = Number(h.wN) * areaRect.width;\n                                    const hh = Number(h.hN) * areaRect.height;\n                                    const x = ox + xN * areaRect.width - w \/ 2;\n                                    const y = oy + yN * areaRect.height - hh \/ 2;\n                                    const rad = Number(h.rN || 0) * Math.min(areaRect.width, areaRect.height);\n                                    holePath = roundedRectPath(x, y, w, hh, rad);\n                                } else if (h.rN != null) {\n                                    const cx = ox + xN * areaRect.width;\n                                    const cy = oy + yN * areaRect.height;\n                                    const r = Number(h.rN) * Math.min(areaRect.width, areaRect.height);\n                                    holePath = circlePath(cx, cy, r);\n                                }\n                            }\n\n                            if (holePath) d += holePath;\n                        });\n\n                        ui.maskPath.setAttribute(\"d\", d);\n                        ui.maskPath.setAttribute(\"fill\", `rgba(0,0,0,${clamp(dim,0,0.92)})`);\n                    }\n                }\n\n                const repaint = rafThrottle(() => paint(state.step));\n\n                \/* =========================================================\n                   Step enter: hotkeys + advance rules\n                ========================================================= *\/\n                function runEnter(step) {\n                    const hk = step && step.enter && Array.isArray(step.enter.hotkeys) ? step.enter.hotkeys : [];\n                    if (!hk.length) return;\n\n                    let acc = 0;\n                    hk.forEach((h) => {\n                        const pre = Number(h.preDelayMs || 0);\n                        acc += pre;\n                        const k = (h.spec != null) ? h.spec : h.key; \/\/ allow either \"key\" or \"spec\"\n                        if (!k) return;\n                        setTimeout(() => {\n                            sendHotkey(root, String(k));\n                        }, acc);\n                    });\n                }\n\n                function armAdvance(step) {\n                    clearAdvance();\n                    if (!step || !step.advance) return;\n\n                    const adv = step.advance;\n                    const type = adv.type || \"next\";\n                    const toastCfg = (adv.toast != null) ? adv.toast : step.toast;\n                    \/\/ Timeout advance\n                    if (type === \"timeout\" && Number(adv.timeoutMs || 0) > 0) {\n                        state.pendingTimer = setTimeout(() => next(), Number(adv.timeoutMs));\n                        state.advanceDispose = () => {\n                            clearTimeout(state.pendingTimer);\n                            state.pendingTimer = 0;\n                        };\n                        return;\n                    }\n\n                    \/\/ Click-anchored advance\n                    if (type === \"click\" && adv.click && adv.click.selector) {\n                        const areaKey = adv.click.area || \"root\";\n                        const areaEl = resolveAreas(root)[areaKey] || root;\n                        const sel = adv.click.selector;\n                        const swallow = adv.click.swallow !== false;\n\n                        const onClick = (ev) => {\n                            const t = ev.target && ev.target.closest(sel);\n                            if (!t || !areaEl.contains(t)) return;\n                            if (swallow) {\n                                ev.preventDefault();\n                                ev.stopPropagation();\n                            }\n\n                            \/\/ Side-effect: toast\n                            if (toastCfg) showToast(toastCfg);\n                            \/\/ next policy (default true)\n                            if (adv.next !== false) next();\n                        };\n\n                        areaEl.addEventListener(\"click\", onClick, true);\n                        state.advanceDispose = () => areaEl.removeEventListener(\"click\", onClick, true);\n                        return;\n                    }\n\n                    \/\/ Tap region advance (overlay circle)\n                    \/\/ Tap region advance (swallow works even if OLED handles pointerdown)\n                    \/\/ Tap region advance (overlay circle)\n                    \/\/ - Hit-test SIEMPRE con geometr\u00eda actual (evita pt \u201cstale\u201d)\n                    \/\/ - Swallow REAL: corta pointer* y tambi\u00e9n click (porque click se emite luego del pointerup)\n                    if (type === \"tap\" && adv.tap) {\n                        const swallow = !(adv.tap && adv.tap.swallow === false);\n                        const areaKey = adv.tap.area || \"oled\";\n\n                        \/\/ Accept either: tap.target (selector\/anchor\/offsets) OR normalized circle {xN,yN,rN}\n                        let spec = adv.tap.target || null;\n                        if (!spec && adv.tap.xN != null && adv.tap.yN != null) {\n                            spec = {\n                                xN: adv.tap.xN,\n                                yN: adv.tap.yN,\n                                rN: adv.tap.rN || 0.12\n                            };\n                        }\n                        if (!spec) return;\n\n                        const TAP_SLOP_PX = 12;\n                        let fired = false;\n                        let down = null; \/\/ { id, x0, y0 }\n                        let lastHit = false; \/\/ para bloquear click post-pointer\n\n                        const swallowEv = (ev) => {\n                            if (!swallow) return;\n                            ev.preventDefault();\n                            \/\/ stopImmediatePropagation evita que otros listeners en el mismo target (capturing) sigan corriendo\n                            ev.stopImmediatePropagation();\n                        };\n\n                        \/\/ Recalcula el c\u00edrculo SIEMPRE (rootRect\/areaRect\/pt) para que coincida con radar\/mask.\n                        const resolveCircleNow = () => {\n                            const rr = root.getBoundingClientRect();\n                            const areasNow = resolveAreas(root);\n                            const areaEl = areasNow[areaKey] || root;\n                            const areaRect = areaEl.getBoundingClientRect();\n                            if (rr.width < 12 || rr.height < 12 || areaRect.width < 12 || areaRect.height < 12) return null;\n\n                            const pt = resolvePointInRoot(rr, areaEl, areaRect, spec, true);\n                            if (!pt) return null;\n\n                            const r = Math.max(16, Number(pt.r || 0) || (Number(spec.rPx || 0) || 0) || 28);\n                            return {\n                                rr,\n                                x: pt.x,\n                                y: pt.y,\n                                r\n                            };\n                        };\n\n                        const inCircle = (ev) => {\n                            const c = resolveCircleNow();\n                            if (!c) return false;\n\n                            const x = ev.clientX - c.rr.left;\n                            const y = ev.clientY - c.rr.top;\n                            const dx = x - c.x;\n                            const dy = y - c.y;\n                            return (dx * dx + dy * dy) <= (c.r * c.r);\n                        };\n\n                        const onPD = (ev) => {\n                            if (fired) return;\n                            if (state.phase !== \"guided\") return;\n                            if (!ev.isTrusted) return;\n\n                            lastHit = inCircle(ev);\n                            if (!lastHit) return;\n\n                            down = {\n                                id: ev.pointerId,\n                                x0: ev.clientX,\n                                y0: ev.clientY\n                            };\n                            swallowEv(ev); \/\/ corta el pointerdown que usa el OLED\n                        };\n\n                        const onPU = (ev) => {\n                            if (fired) return;\n                            if (state.phase !== \"guided\") return;\n                            if (!down || down.id !== ev.pointerId) return;\n                            \/* Accept tap if PRESS started inside the circle:\n                               - ignore movement\n                               - allow release outside *\/\n                            down = null;\n\n                            fired = true;\n                            if (toastCfg) showToast(toastCfg);\n                            swallowEv(ev);\n\n                            if (swallow) {\n                                if (adv.next !== false) next();\n                            } else {\n                                requestAnimationFrame(() => {\n                                    if (adv.next !== false) next();\n                                });\n                            }\n                        };\n                        const onPC = () => {\n                            down = null;\n                            lastHit = false;\n                        };\n\n                        \/\/ Bloquea el CLICK que el browser emite luego del pointerup (cuando swallow=true)\n                        const onCK = (ev) => {\n                            if (state.phase !== \"guided\") return;\n                            if (!swallow) return;\n\n                            \/\/ Solo bloqueamos si el \u00faltimo gesto cay\u00f3 dentro del c\u00edrculo o si el click cae dentro del c\u00edrculo\n                            if (!lastHit && !inCircle(ev)) return;\n\n                            swallowEv(ev);\n                        };\n\n                        root.addEventListener(\"pointerdown\", onPD, true);\n                        root.addEventListener(\"pointerup\", onPU, true);\n                        root.addEventListener(\"pointercancel\", onPC, true);\n                        root.addEventListener(\"click\", onCK, true);\n\n                        state.advanceDispose = () => {\n                            root.removeEventListener(\"pointerdown\", onPD, true);\n                            root.removeEventListener(\"pointerup\", onPU, true);\n                            root.removeEventListener(\"pointercancel\", onPC, true);\n                            root.removeEventListener(\"click\", onCK, true);\n                        };\n\n                        return;\n                    }\n                }\n\n                function clearToast() {\n                    root.removeAttribute(\"data-ps-guide-toast\");\n                    if (ui.toastMsg) ui.toastMsg.textContent = \"\";\n                    if (ui.toast) ui.toast.removeAttribute(\"data-tone\");\n                    state.toastCarry = 0;\n                }\n\n                function showToast(toastCfg) {\n                    const cfg = (typeof toastCfg === \"string\") ? {\n                        text: toastCfg\n                    } : (toastCfg || {});\n                    const text = String(cfg.text || \"\").trim();\n                    if (!text) return;\n\n                    if (ui.toastMsg) ui.toastMsg.textContent = text;\n                    if (ui.toast && cfg.tone) ui.toast.setAttribute(\"data-tone\", String(cfg.tone));\n\n                    root.setAttribute(\"data-ps-guide-toast\", \"1\");\n\n                    \/\/ carrySteps: cu\u00e1ntos \"showStep()\" debe sobrevivir (ej. 1 = se ve tambi\u00e9n en el siguiente paso)\n                    const cs = Number(cfg.carrySteps || 0);\n                    state.toastCarry = Number.isFinite(cs) ? Math.max(0, Math.floor(cs)) : 0;\n                }\n\n                function showStep() {\n                    hydrateStep();\n                    \/\/ Toast policy: por defecto se limpia al entrar a un paso,\n                    \/\/ salvo si el paso anterior dej\u00f3 carrySteps > 0.\n                    if (state.toastCarry > 0) state.toastCarry -= 1;\n                    else clearToast();\n\n                    \/\/ No steps => finish immediately\n                    if (!state.step) {\n                        complete();\n                        return;\n                    }\n\n                    updateCards(state.step);\n                    runOledHotkeysFromStep(state.step);\n                    \/\/ Mask delay\/hold behavior (delay is handled by paint scheduling)\n                    const mask = state.step.focus && state.step.focus.mask;\n                    const delayMs = mask && mask.enabled ? Number(mask.delayMs || 0) : 0;\n\n                    \/\/ Paint now (or after delay)\n                    if (delayMs > 0) {\n                        setTimeout(repaint, delayMs);\n                    } else {\n                        repaint();\n                    }\n\n                    runEnter(state.step);\n                    armAdvance(state.step);\n                }\n\n                function startGuided() {\n                    \/* -------------------------------------------------------\n                       Prevent duplicate \u201cdemo macro\u201d while entering guided\n                       - cancels any pending primeDemo tick sequence\n                       - blocks autoprime race for a short window\n                    ------------------------------------------------------- *\/\n                    clearAdvance();\n\n                    \/\/ lock seeding\/autoprime briefly to avoid race with IntersectionObserver onVisible()\n                    const lockMs = clamp(readVarNum(root, \"--cvx-ps-guide-start-lock-ms\", 1600), 0, 20000);\n                    seedLock(lockMs);\n\n                    state.idx = 0;\n                    setPhase(\"guided\");\n                    showStep();\n                }\n\n                function stopGuided(toPhase) {\n                    clearAdvance();\n\n                    \/* Evita \"Blocked aria-hidden...\" al salir con focus dentro del overlay *\/\n                    try {\n                        const ae = document.activeElement;\n                        if (ae && ui && ui.ui && ui.ui.contains(ae) && ae.blur) ae.blur();\n                    } catch (_) {}\n\n                    setPhase(toPhase || \"free\");\n                    state.idx = 0;\n                    state.step = null;\n\n                    \/* Hard-clear guided visuals (paint() no corre fuera de guided) *\/\n                    if (ui && ui.radars) ui.radars.innerHTML = \"\";\n                    if (ui && ui.maskPath) ui.maskPath.setAttribute(\"d\", \"\");\n                    if (ui && ui.maskSvg) ui.maskSvg.style.opacity = \"0\";\n                    root.removeAttribute(\"data-ps-guide-mask\");\n\n                    clearToast();\n\n                    \/* Restore stable per-mode copy outside the tour *\/\n                    applyModeDefaultCards(readMode(root));\n                }\n\n                function next() {\n                    if (state.phase !== \"guided\") return;\n                    clearAdvance();\n\n                    \/\/ Auto-clear SHIFT latch al completar el paso\n                    if (typeof root.__cvxPSSetShiftLatch === \"function\") {\n                        root.__cvxPSSetShiftLatch(false);\n                    } else {\n                        \/\/ Fallback (si por alg\u00fan motivo el setter no existe)\n                        root.dataset.psShiftLatch = \"0\";\n                        const b = root.querySelector('[data-ps-tgl=\"shift\"],[data-ps-ctl=\"shift\"]');\n                        if (b) {\n                            b.setAttribute(\"aria-pressed\", \"false\");\n                            b.classList.remove(\"pill--strong\");\n                        }\n                    }\n\n\n                    state.idx += 1;\n\n                    \/\/ End of current mode steps -> jump to next mode (if it has steps)\n                    if (state.idx >= state.steps.length) {\n                        const order = [\"capture\", \"edit\", \"mix\", \"sync\"];\n                        const i0 = order.indexOf(state.mode);\n                        let nextMode = null;\n\n                        for (let i = i0 + 1; i < order.length; i++) {\n                            const mk = order[i];\n                            if (currentStepsForMode(mk).length) {\n                                nextMode = mk;\n                                break;\n                            }\n                        }\n\n                        if (nextMode) {\n                            \/\/ UI uses \"share\" but guide schema uses \"sync\"\n                            const uiKey = (nextMode === \"sync\") ? \"share\" : nextMode;\n                            const btn = root.querySelector(`[data-ps-mode-btn=\"${uiKey}\"]`);\n\n                            if (btn) btn.click();\n                            else root.setAttribute(\"data-ps-mode\", uiKey);\n\n                            \/\/ In followUser \/ restartOnModeChange, MutationObserver har\u00e1 idx=0 + showStep().\n                            \/\/ If lockToTour, MO no reinicia, as\u00ed que forzamos ac\u00e1:\n                            const pol = String(opts.modePolicy || \"followUser\");\n                            if (pol === \"lockToTour\") {\n                                state.mode = nextMode;\n                                state.idx = 0;\n                                showStep();\n                            }\n                            return;\n                        }\n\n                        \/\/ No more modes with steps => finish tour\n                        complete();\n                        return;\n                    }\n\n                    showStep();\n                }\n\n\n                function back() {\n                    if (state.phase !== \"guided\") return;\n                    clearAdvance();\n                    state.idx = clamp(state.idx - 1, 0, Math.max(0, state.steps.length - 1));\n                    showStep();\n                }\n\n                function seedDemo(cause, force) {\n                    const now = (performance && performance.now) ? performance.now() : Date.now();\n\n                    \/\/ NUEVO: si hay lock activo, no seed (salvo force)\n                    const lockUntil = root.__cvxPSNoSeedUntil || 0;\n                    if (!force && now < lockUntil) return;\n\n                    \/\/ No seed mientras guided (salvo force)\n                    if (!force && state && state.phase === \"guided\") return;\n\n                    const cooldown = clamp(readVarNum(root, \"--cvx-ps-demo-seed-cooldown\", 900), 0, 20000);\n                    const lastTs = root.__cvxPSSeedTs || 0;\n                    if (!force && (now - lastTs) < cooldown) return;\n\n                    root.__cvxPSSeedTs = now;\n                    root.__cvxPSSeedCause = String(cause || \"unknown\");\n\n                    primeDemo({\n                        tracks: 2,\n                        autoplay: true\n                    });\n                }\n\n                function seedLock(ms) {\n                    const now = (performance && performance.now) ? performance.now() : Date.now();\n                    const until = now + clamp((ms | 0) || 0, 0, 20000);\n                    root.__cvxPSNoSeedUntil = Math.max(root.__cvxPSNoSeedUntil || 0, until);\n                }\n\n                function runOledHotkeysFromStep(step) {\n                    const ops = step && step.ops;\n                    if (!ops) return;\n\n                    const hk = ops.oledHotkeys;\n                    if (!Array.isArray(hk) || hk.length === 0) return;\n\n                    \/\/ Bloquea seed\/prime autom\u00e1tico por una ventana corta\n                    seedLock(((ops.noSeedMs | 0) || 1200));\n\n                    \/\/ Ejecuta hotkeys tal cual, sin primeDemo\n                    for (let i = 0; i < hk.length; i++) {\n                        sendHotkey(root, String(hk[i]));\n                    }\n                }\n\n                function primeDemo(opts) {\n                    const tracks = clamp(((opts && opts.tracks) | 0) || 2, 0, 16);\n\n                    \/\/ Ajustables si quer\u00e9s cambiar el \u201cadd track\u201d real del OLED\n                    const addKey = String((opts && opts.addKey) || \"z\");\n                    const playKey = String((opts && opts.playKey) || \"Space\");\n                    const autoplay = !opts || opts.autoplay !== false;\n\n                    \/\/ \u201csubir Y\u201d (PageUp por defecto) + Loop ON\n                    const yUpKey = String(\n                        (opts && opts.yUpKey) ||\n                        (getComputedStyle(root).getPropertyValue(\"--cvx-ps-hk-yminus\").trim() || \"PageUp\")\n                    );\n\n                    const loopKey = String((opts && opts.loopKey) || \"L\");\n\n                    \/\/ NUEVO: ArrowUp + ZoomX (+) parametrizable\n                    const upKey = String(\n                        (opts && opts.upKey) ||\n                        (getComputedStyle(root).getPropertyValue(\"--cvx-ps-hk-up\").trim() || \"ArrowUp\")\n                    );\n\n                    const xPlusKey = String(\n                        (opts && opts.xPlusKey) ||\n                        (getComputedStyle(root).getPropertyValue(\"--cvx-ps-hk-xplus\").trim() || \"+\")\n                    );\n\n                    const xSteps =\n                        clamp(\n                            ((opts && opts.xSteps) | 0) ||\n                            ((readVarNum(root, \"--cvx-ps-demo-xsteps\", 1) | 0) || 0),\n                            0,\n                            8\n                        );\n\n                    \/\/ Flags (por defecto: ambos ON para demo)\n                    const liftView = !opts || opts.liftView !== false; \/\/ yUpKey\n                    const loopOn = !opts || opts.loopOn !== false; \/\/ loopKey\n\n                    const preDelay = clamp(readVarNum(root, \"--cvx-ps-demo-pre-delay\", 180), 0, 2000);\n                    const stepDelay = clamp(readVarNum(root, \"--cvx-ps-demo-step-delay\", 120), 16, 1000);\n\n                    if (isRootHidden()) {\n                        state.pendingTimer = setTimeout(() => primeDemo(opts), 120);\n                        return;\n                    }\n\n                    \/\/ 1) Panel derecho (si el setter existe)\n                    if (typeof root.__cvxPSSetTrackRows === \"function\") {\n                        try {\n                            root.__cvxPSSetTrackRows(tracks);\n                        } catch (_) {}\n                    }\n\n                    \/\/ 2) OLED: reset (estado determin\u00edstico: loop OFF, play OFF, etc.)\n                    sendHotkey(root, \"*\");\n\n                    \/\/ 3) OLED: construir demo + PageUp + ArrowUp + ZoomX(+) + loop + play (secuenciado)\n                    const seq = [];\n                    for (let i = 0; i < tracks; i++) seq.push(addKey);\n\n                    if (liftView && tracks > 0) seq.push(yUpKey); \/\/ tu \u201cx2 en screen\u201d (PageUp)\n                    if (tracks > 0) seq.push(upKey); \/\/ subir selecci\u00f3n (evita quedar en +ADD \/ lower track)\n\n                    for (let k = 0; k < xSteps; k++) seq.push(xPlusKey); \/\/ ZoomX + N\n\n                    if (loopOn) seq.push(loopKey); \/\/ loop ON (toggle desde reset)\n                    if (autoplay) seq.push(playKey);\n\n                    let i = 0;\n                    state.pendingTimer = setTimeout(function tick() {\n                        if (i >= seq.length) return;\n                        sendHotkey(root, seq[i++]);\n                        state.pendingTimer = setTimeout(tick, stepDelay);\n                    }, preDelay);\n                }\n\n                function reset() {\n                    \/\/ Reset \u201ctour done\u201d flag => vuelve a arrancar desde el inicio\n                    const k = String(opts.startOnceKey || \"cvx_ps_tour_v1_done\");\n                    try {\n                        localStorage.removeItem(k);\n                    } catch (_) {}\n\n                    \/\/ Limpieza UI\/state\n                    clearToast();\n                    clearAdvance();\n\n                    \/\/ Volver a modo CAPTURE para coherencia visual (antes de stopGuided => cards estables)\n                    try {\n                        const btn = root.querySelector('[data-ps-mode-btn=\"capture\"]');\n                        if (btn) btn.click();\n                        else root.setAttribute(\"data-ps-mode\", \"capture\");\n                    } catch (_) {}\n\n                    \/\/ IMPORTANTE: stopGuided limpia timers (clearAdvance).\n                    \/\/ Si primeDemo corre antes, se cancela. Por eso: stopGuided -> primeDemo.\n                    stopGuided(\"idle\");\n\n                    \/\/ Seed demo\/OLED: 2 tracks + Y-up + loop + play (defaults de primeDemo)\n                    primeDemo({\n                        tracks: 2,\n                        autoplay: true\n                        \/\/ liftView \/ loopOn default TRUE (no hace falta pasarlos)\n                    });\n                }\n\n                function markDone() {\n                    const k = String(opts.startOnceKey || \"cvx_ps_tour_v1_done\");\n                    try {\n                        localStorage.setItem(k, \"1\");\n                    } catch (_) {}\n                }\n\n                function complete() {\n                    markDone();\n                    clearAdvance();\n\n                    ui.doneBox.hidden = false;\n                    setPhase(\"guided\"); \/\/ still guided while showing done CTA\n                    ui.ui.style.pointerEvents = \"auto\";\n\n                    \/\/ Hide radars\/mask visually (CSS can animate; we do safe clear)\n                    if (ui.maskPath) ui.maskPath.setAttribute(\"d\", \"\");\n                    if (ui.radars) ui.radars.innerHTML = \"\";\n\n                    \/\/ If user clicks OK => free\n                    \/\/ (handler below)\n                }\n\n                \/* =========================================================\n                   Mode policy handling (followUser | lockToTour | restartOnModeChange)\n                   - v3.12 changes data-ps-mode via existing buttons; we observe attribute.\n                ========================================================= *\/\n                const mo = new MutationObserver(() => {\n                    const newMode = readMode(root);\n                    if (newMode === state.mode) return;\n\n                    \/* NOT guided: keep per-mode copy in the existing stage overlays *\/\n                    if (state.phase !== \"guided\") {\n                        state.mode = newMode;\n                        if (typeof applyModeDefaultCards === \"function\") applyModeDefaultCards(newMode);\n                        return;\n                    }\n\n                    \/* guided: honor modePolicy *\/\n                    const pol = String(opts.modePolicy || \"followUser\");\n                    if (pol === \"lockToTour\") {\n                        repaint();\n                        return;\n                    }\n\n                    if (pol === \"restartOnModeChange\") {\n                        state.mode = newMode;\n                        state.idx = 0;\n                        showStep();\n                        return;\n                    }\n\n                    \/\/ followUser\n                    state.mode = newMode;\n                    state.idx = 0; \/\/ predictable; avoids mismatch between step sets\n                    showStep();\n                });\n\n\n                mo.observe(root, {\n                    attributes: true,\n                    attributeFilter: [\"data-ps-mode\"]\n                });\n\n                \/* =========================================================\n                   Observers (Elementor-safe, no measuring while hidden)\n                ========================================================= *\/\n                const onVisible = (isVisible) => {\n                    const nextVisible = !!isVisible && !document.hidden;\n                    const wasVisible = state.visible;\n                    state.visible = nextVisible;\n                    if (!state.visible) {\n                        clearAdvance();\n                        return;\n                    }\n\n                    updateGuideUiAnchor();\n\n                    \/\/ Autoprime demo al entrar al viewport (solo si el tour NO est\u00e1 activo)\n                    if (!wasVisible && readVarNum(root, \"--cvx-ps-demo-autoprime\", 0) > 0.5 && state.phase !== \"guided\") {\n                        seedDemo(\"enter\", false);\n                    }\n\n                    if (state.phase === \"guided\") {\n                        paint(state.step);\n                        armAdvance(state.step);\n                    }\n                };\n\n\n                \/\/ IntersectionObserver\n                try {\n                    state.io = new IntersectionObserver((entries) => {\n                        entries.forEach((e) => {\n                            state.inViewport = !!e.isIntersecting;\n                            onVisible(state.inViewport);\n                        });\n                    }, {\n                        threshold: 0.06\n                    });\n                    state.io.observe(root);\n                } catch (_) {\n                    \/\/ fallback: assume visible\n                    state.inViewport = true;\n                    state.visible = true;\n                }\n\n                document.addEventListener(\"visibilitychange\", () => {\n                    onVisible(state.inViewport);\n                }, {\n                    passive: true\n                });\n                \/* =========================================================\n                   Boot autoprime (refresh-safe)\n                   - Si ya est\u00e1 visible al refrescar, iniciar la DEMO (no tour)\n                   - No depender solo del primer tick del IntersectionObserver\n                ========================================================= *\/\n                (function bootAutoprimeDemo() {\n                    if (root.__cvxPSBootAutoprime) return;\n                    root.__cvxPSBootAutoprime = true;\n\n                    \/\/ Respeta el toggle de autoprime\n                    if (readVarNum(root, \"--cvx-ps-demo-autoprime\", 0) <= 0.5) return;\n\n                    const maxTries = 24; \/\/ ~4\u20135s total\n                    const stepMs = 180; \/\/ retry cadence\n                    let tries = 0;\n\n                    function isInViewport(el, padPx) {\n                        const rr = el.getBoundingClientRect();\n                        const pad = (padPx | 0) || 0;\n                        const vw = window.innerWidth || 0;\n                        const vh = window.innerHeight || 0;\n                        return (\n                            rr.width >= 12 &&\n                            rr.height >= 12 &&\n                            rr.bottom > -pad &&\n                            rr.right > -pad &&\n                            rr.top < (vh + pad) &&\n                            rr.left < (vw + pad)\n                        );\n                    }\n\n                    function tick() {\n                        if (state.phase === \"guided\") return; \/\/ nunca disparar demo si el tour est\u00e1 activo\n                        if (tries++ >= maxTries) return;\n                        if (document.hidden) {\n                            setTimeout(tick, stepMs);\n                            return;\n                        }\n\n                        \/\/ Elementor-safe: no disparar mientras el root no tenga tama\u00f1o real\n                        if (isRootHidden()) {\n                            setTimeout(tick, stepMs);\n                            return;\n                        }\n\n                        \/\/ Solo si realmente est\u00e1 en viewport al refrescar\n                        if (!isInViewport(root, 12)) {\n                            setTimeout(tick, stepMs);\n                            return;\n                        }\n\n                        \/\/ Marcar visible para que el resto de l\u00f3gica no \u201csaltee\u201d anclajes\n                        state.visible = true;\n                        updateGuideUiAnchor();\n\n                        \/\/ Iniciar DEMO (determin\u00edstica: primeDemo resetea y arma)\n                        primeDemo({\n                            tracks: 2,\n                            autoplay: true\n                        });\n                    }\n\n                    \/\/ 1) primer paint\n                    requestAnimationFrame(() => setTimeout(tick, 0));\n                    \/\/ 2) post-load (im\u00e1genes\/fonts\/layout terminan de asentar)\n                    window.addEventListener(\"load\", () => setTimeout(tick, 0), {\n                        once: true\n                    });\n                })();\n                \/\/ ResizeObserver\n                try {\n                    state.ro = new ResizeObserver(() => {\n                        if (isRootHidden()) return;\n                        updateGuideUiAnchor();\n                        if (state.phase === \"guided\") repaint();\n                    });\n\n                    state.ro.observe(root);\n                } catch (_) {}\n\n                \/\/ Scroll (layout shift)\n                state.scrollHandler = rafThrottle(() => {\n                    if (!state.visible || isRootHidden()) return;\n                    updateGuideUiAnchor();\n                    if (state.phase === \"guided\") repaint();\n                });\n\n                window.addEventListener(\"scroll\", state.scrollHandler, {\n                    passive: true\n                });\n                window.addEventListener(\"resize\", state.scrollHandler, {\n                    passive: true\n                });\n\n                \/* =========================================================\n                   UI events\n                ========================================================= *\/\n                ui.btnStart.addEventListener(\"click\", (ev) => {\n                    ev.preventDefault();\n                    ev.stopPropagation();\n                    if (state.phase === \"guided\") return;\n                    startGuided();\n                });\n\n                ui.btnBack.addEventListener(\"click\", (ev) => {\n                    ev.preventDefault();\n                    back();\n                });\n                ui.btnNext.addEventListener(\"click\", (ev) => {\n                    ev.preventDefault();\n                    next();\n                });\n                ui.btnReset.addEventListener(\"click\", (ev) => {\n                    ev.preventDefault();\n                    reset();\n                });\n\n                if (ui.btnClose) {\n                    ui.btnClose.addEventListener(\"click\", (ev) => {\n                        ev.preventDefault();\n\n                        stopGuided(\"free\");\n                        seedDemo(\"exit\", true);\n                    });\n                }\n                \/\/ Escape => exit guided to free (or idle if autoStart never)\n                document.addEventListener(\"keydown\", (ev) => {\n                    if (state.phase !== \"guided\") return;\n                    if (ev.key !== \"Escape\") return;\n                    ev.preventDefault();\n                    ev.stopPropagation();\n\n                    \/\/ If autoStart was \"never\", treat escape as \"idle\"; else \"free\"\n                    const as = String(opts.autoStart || \"once\");\n                    stopGuided(as === \"never\" ? \"idle\" : \"free\");\n\n                    seedDemo(\"exit\", true);\n                }, true);\n\n                \/* =========================================================\n                   AutoStart (once\/never\/always)\n                ========================================================= *\/\n                (function autoStart() {\n                    const as = String(opts.autoStart || \"once\");\n                    if (as === \"never\") {\n                        setPhase(\"idle\");\n                        return;\n                    }\n                    if (as === \"always\") {\n                        startGuided();\n                        return;\n                    }\n\n                    \/\/ once\n                    const k = String(opts.startOnceKey || \"cvx_ps_tour_v1_done\");\n                    let done = false;\n                    try {\n                        done = localStorage.getItem(k) === \"1\";\n                    } catch (_) {}\n                    if (!done) startGuided();\n                    else setPhase(\"free\");\n                })();\n            });\n\n        })();\n    <\/script>\n\n<\/section>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-cbe7874 .cvxPSComposeTpl elementor-widget elementor-widget-ha-content-switcher happy-addon ha-content-switcher\" data-id=\"cbe7874\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"ha-content-switcher.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"ha-content-switcher-wrapper ha-cs-design-button\" data-design-type=\"button\">\n\t\t\t<div class=\"ha-cs-switch-container\">\n\t\t\t\t<div class=\"ha-cs-switch-wrapper  desktop-horizontal horizontal\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<button class=\"ha-cs-button active ha-cs-icon-left\" data-content-id=\"c0cf381\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<span>Primary<\/span>\n\t\t\t\t\t\t\t<\/button>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t<\/div>\n\t\t\t<div class=\"ha-cs-content-container\">\n\t\t\t\t<div class=\"ha-cs-content-wrapper  desktop-horizontal horizontal\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<div id=\"c0cf381\" class=\"ha-cs-content-section active\">\n\t\t\t\t\t\t\t\t\t\t<div data-elementor-type=\"section\" data-elementor-id=\"3951\" class=\"elementor elementor-3951\" data-elementor-settings=\"{&quot;ha_cmc_init_switcher&quot;:&quot;no&quot;}\">\n\t\t\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-c9b2677 elementor-section-boxed elementor-section-height-default elementor-section-height-default\" data-id=\"c9b2677\" data-element_type=\"section\" data-e-type=\"section\" data-settings=\"{&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-f6d81cf\" data-id=\"f6d81cf\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-e10e44c elementor-widget elementor-widget-html\" data-id=\"e10e44c\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<style>\r\n    \/* Minimal, self-contained OLED host (scoped) *\/\r\n    .cvxScope.cvxOledEmbed {\r\n        display: inline-block;\r\n        margin: 0;\r\n        padding: 0;\r\n        line-height: 0;\r\n        font-size: 0;\r\n        \/* evita baseline-gap t\u00edpico de inline-block *\/\r\n    }\r\n\r\n    .cvxScope.cvxOledEmbed [data-cvx-root=\"oled-compose\"] {\r\n        display: inline-block;\r\n        margin: 0;\r\n        padding: 0;\r\n        line-height: 0;\r\n        font-size: 0;\r\n        overflow: visible;\r\n        \/* si el dibujo \u201csale\u201d del viewport por escalado *\/\r\n        isolation: isolate;\r\n        \/* reduce side-effects de blend\/filters externos *\/\r\n    }\r\n\r\n    .cvxScope.cvxOledEmbed .cvxOledWrap {\r\n        display: inline-block;\r\n        margin: 0;\r\n        padding: 0;\r\n        line-height: 0;\r\n        font-size: 0;\r\n        overflow: visible;\r\n        transform-style: preserve-3d;\r\n    }\r\n\r\n    .cvxScope.cvxOledEmbed canvas.cvxOled {\r\n        \/* Reset defensivo contra CSS global (Elementor\/theme) *\/\r\n        border: 0 !important;\r\n        outline: 0 !important;\r\n        max-width: none !important;\r\n        max-height: none !important;\r\n\r\n        display: block;\r\n        width: calc(var(--cvx-oled-w) * var(--cvx-oled-ui-scale)) !important;\r\n        height: calc(var(--cvx-oled-h) * var(--cvx-oled-ui-scale)) !important;\r\n\r\n        image-rendering: pixelated;\r\n        image-rendering: crisp-edges;\r\n        image-rendering: -moz-crisp-edges;\r\n\r\n        background: transparent !important;\r\n        \/* el fondo real lo dibuja tu JS *\/\r\n        border-radius: var(--cvx-oled-css-radius);\r\n        box-shadow: var(--cvx-oled-css-shadow);\r\n\r\n        touch-action: none;\r\n        user-select: none;\r\n    }\r\n<\/style>\r\n\r\n<section class=\"cvxScope cvxOledEmbed\">\r\n    <div data-cvx-root=\"oled-compose\" style=\"\r\n        \/* ---------- CSS (solo presentaci\u00f3n \/ embed) ---------- *\/\r\n      --cvx-oled-w: 256px;\r\n      --cvx-oled-h: 64px;\r\n      --cvx-oled-ui-scale: 1;          \/* escala visual del canvas (CSS) *\/\r\n      --cvx-oled-css-radius: 0px;      \/* dejalo en 0 para \u201csin caja\u201d *\/\r\n      --cvx-oled-css-shadow: none;     \/* idem *\/\r\n\r\n      \/* ---------- Vars le\u00eddas por el JS (opcional override) ---------- *\/\r\n      \/* =====================================================\r\n         PARAMETERS (per-instance)\r\n      ====================================================== *\/\r\n\r\n      \/* Visible scale (web) *\/\r\n      --cvx-oled-ui-scale: 2;\r\n      --cvx-oled-scale-min: 1.0;\r\n      --cvx-oled-scale-max: 1;\r\n\r\n      \/* Render pacing *\/\r\n      --cvx-oled-fr: 30;\r\n      \r\n      \/* Margen extra al final de bloques *\/\r\n        --cvx-oled-timeline-pad-s: 30;\r\n        \r\n        --cvx-oled-region-respect-mute-solo: 0; \/* 1 = vuelve al gating viejo *\/\r\n      \/* =====================================================\r\n         SESSION MODE\r\n         - 1 = DEMO: comportamiento actual (clips fragmentados + wave loop)\r\n         - 0 = NORMAL: al cargar datos\/audio por track, se crea 1 clip desde t=0 usando la duraci\u00f3n completa del archivo\r\n         ====================================================== *\/\r\n      --cvx-oled-session-demo: 0;\r\n\r\n      \/* Cursor nudge (ArrowLeft\/ArrowRight)\r\n         Fraction of the *usable* timeline viewport (excluding track list column).\r\n         Time step = timelineSpan() * this fraction. Shift multiplies by 4.\r\n         Example: 0.0104167 \u2248 1s when span=96s (zoomX=0).\r\n      *\/\r\n      --cvx-oled-cursor-step-frac: 0.0104167;\r\n\r\n      \/* OLED background (raster clear): 0..40 recommended *\/\r\n      --cvx-oled-bg: 0;\r\n\r\n      \/* OLED background (CSS, around the raster) *\/\r\n      --cvx-oled-bg-css: #06080b;\r\n\r\n      \/* Chrome heights in OLED px *\/\r\n      --cvx-oled-header-h: 10;\r\n      --cvx-oled-footer-h: 10;\r\n\r\n      \/* Chrome auto-hide *\/\r\n      --cvx-oled-chrome-hide-ms: 4000;\r\n      --cvx-oled-chrome-min-alpha: .52;\r\n      --cvx-oled-chrome-exp: .70;\r\n\r\n      \/* Chrome animation speeds (0..1) *\/\r\n      --cvx-oled-chrome-anim-in: 0.2;     \/* faster expand *\/\r\n      --cvx-oled-chrome-anim-out: 0.2;   \/* faster collapse *\/\r\n\r\n      \/* Menu animation speeds (0..1) *\/\r\n      --cvx-oled-menu-anim-in: .2;\r\n      --cvx-oled-menu-anim-out: .2;\r\n\r\n      \/* Overlay dim (viewport only) when any panel is open *\/\r\n      --cvx-oled-dim: 0.40;\r\n\r\n      \/* Raster text AA strength (0..0.85) *\/\r\n      --cvx-oled-aa: .15;\r\n\r\n      \/* HUD \/ info alphas *\/\r\n      --cvx-oled-hud-alpha: .92;\r\n      --cvx-oled-region-alpha: .92;\r\n      --cvx-oled-footer-hint-alpha: .78;\r\n      --cvx-oled-label-alpha: .92;\r\n\r\n      \/* HUD toast (center bubble) *\/\r\n      --cvx-oled-hud-toast-alpha: .80;\r\n      --cvx-oled-hud-toast-bg: 90;       \/* 0..255 *\/\r\n      --cvx-oled-hud-toast-ink: 245;     \/* 0..255 *\/\r\n      --cvx-oled-hud-toast-radius: 6;\r\n      --cvx-oled-hud-toast-pad-x: 6;\r\n      --cvx-oled-hud-toast-pad-y: 3;\r\n      --cvx-oled-hud-toast-min-w: 30;\r\n      \/* =====================================================\r\n         AUTOPAN SCROLL\r\n      ====================================================== *\/\r\n      --cvx-oled-autopan-deadpx: 2;\r\n      --cvx-oled-autopan-maxpx: 18;\r\n      --cvx-oled-autopan-gain: 1;\r\n\r\n      \/* =====================================================\r\n         FOOTER TIME FORMATTING (OLED)\r\n         - decimals: 0..3\r\n      ====================================================== *\/\r\n      --cvx-oled-footer-time-decimals: 2;\r\n      --cvx-oled-footer-region-decimals: 2;\r\n      --cvx-oled-footer-meta: 44.1kHz 24bit;\r\n\r\n      \/* =====================================================\r\n         HEADER LEFT (OUTPUT SELECTION LABEL)\r\n      ====================================================== *\/\r\n      --cvx-oled-hdr-left-pad-x: 2;        \/* px *\/\r\n      --cvx-oled-hdr-left-pad-y: 1;        \/* px *\/\r\n      --cvx-oled-hdr-left-ink: 105;        \/* 0..255 (default dim label) *\/\r\n      --cvx-oled-hdr-left-alpha: 1.0;      \/* 0..1 *\/\r\n      --cvx-oled-hdr-left-font-compact: 0; \/* 1=5x6, 0=5x7 *\/\r\n\r\n      \/* =====================================================\r\n         HEADER TRANSPORT (CENTER)\r\n      ====================================================== *\/\r\n      --cvx-oled-hdr-transport-on: 1;\r\n      --cvx-oled-hdr-transport-btn-w: 14;\r\n      --cvx-oled-hdr-transport-btn-h: 10;\r\n      --cvx-oled-hdr-transport-gap: 4;\r\n      --cvx-oled-hdr-transport-radius: 0;\r\n      --cvx-oled-hdr-transport-bg: 45;\r\n      --cvx-oled-hdr-transport-bg-alpha: .55;\r\n      --cvx-oled-hdr-transport-ink: 245;\r\n      --cvx-oled-hdr-transport-ink-dim: 135;\r\n      --cvx-oled-hdr-transport-active-bg: 80;\r\n      --cvx-oled-hdr-transport-active-alpha: .80;\r\n\r\n      \/* =====================================================\r\n         MASTER METERS (top stripes when play\/rec)\r\n      ====================================================== *\/\r\n      --cvx-oled-master-meter-on: 1;\r\n      --cvx-oled-master-meter-alpha: 1.0;\r\n\r\n      \/* 25% width, right-aligned *\/\r\n      --cvx-oled-master-meter-w: 64;       \/* px *\/\r\n      --cvx-oled-master-meter-x: 190;      \/* px (left) = 256 - 64 - 2 *\/\r\n      --cvx-oled-master-meter-y1: 1;       \/* px (top stripe) *\/\r\n      --cvx-oled-master-meter-y2: 5;       \/* px (bottom stripe) *\/\r\n      --cvx-oled-master-meter-h: 2;        \/* px *\/\r\n      --cvx-oled-master-meter-gap: 1;      \/* px (inside stripe) *\/\r\n\r\n      --cvx-oled-master-meter-bg: 40;      \/* 0..255 *\/\r\n      --cvx-oled-master-meter-ink: 235;    \/* 0..255 *\/\r\n      --cvx-oled-master-meter-peak-ink: 255;\r\n      --cvx-oled-master-meter-peak-hold-ms: 700;\r\n      --cvx-oled-master-meter-smooth: .22; \/* 0..1 *\/\r\n\r\n      \/* =====================================================\r\n         SELECTION REGION (body + edges)\r\n         - mode: 0 = lighten (blend to white), 1 = darken (multiply)\r\n      ====================================================== *\/\r\n      --cvx-oled-region-mode: 0;\r\n      --cvx-oled-region-alpha-body: .35;\r\n      --cvx-oled-region-alpha-edge: .95;\r\n\r\n      \/* MARK \/ BADGE (range-applied) *\/\r\n      --cvx-oled-mark-alpha: .70;\r\n      --cvx-oled-mark-ink: .94;\r\n      --cvx-oled-mark-stroke: 0.4;\r\n      --cvx-oled-badge-pointer-on: 1;\r\n\r\n      \/* Global raster strokes ON\/OFF (menu\/clip separators etc) *\/\r\n      --cvx-oled-stroke-on: 1;\r\n\r\n      \/* =====================================================\r\n         TRACK LIST (OLED)\r\n      ====================================================== *\/\r\n      --cvx-oled-list-w: 74;               \/* was fixed 74; now variable *\/\r\n      --cvx-oled-track-divider-on: 1;\r\n      --cvx-oled-track-divider-v: 60;\r\n      \r\n      --cvx-oled-zoomx-fit-on-load: 1;   \/* 1=auto-fit tras cargar audio *\/\r\n      --cvx-oled-zoomx-fit-pad-s: 0.5;   \/* margen en segundos *\/\r\n\r\n      --cvx-oled-track-radius: 1;          \/* 1..6 *\/\r\n      --cvx-oled-track-active-bg: 50;\r\n\r\n      --cvx-oled-track-sel-on: 1;\r\n      --cvx-oled-track-sel-fill-a: 0.0;\r\n      --cvx-oled-track-sel-stroke-on: 1;\r\n      --cvx-oled-track-sel-stroke-a: 0.3;\r\n\r\n      \/* Track text padding (fixes clipped letters in tight rows) *\/\r\n      --cvx-oled-track-pad-l: 2;\r\n      --cvx-oled-track-pad-r: 2;\r\n\r\n      --cvx-oled-track-x2-NamePadT: 2;  \/* px desde ry0 para el t\u00edtulo (X2) *\/\r\n      --cvx-oled-track-x2-SrcPadB: 2;   \/* px desde ry1 para el src (X2) *\/\r\n\r\n\r\n      \/* Track index + ARM *\/\r\n      --cvx-oled-track-index-on: 1;        \/* 1=show number, 0=hide number *\/\r\n      --cvx-oled-track-arm-on: 1;          \/* 1=arm indicator visible *\/\r\n      --cvx-oled-track-arm-SizeMode: 1;   \/* 0=manual (armW\/armH), 1=alto automatico (alto = fila) *\/\r\n      --cvx-oled-track-arm-IdxMode: 1;    \/* 0=indice fuera, 1=indice dentro del ARM *\/\r\n      --cvx-oled-track-arm-w: 10;\r\n      --cvx-oled-track-arm-h: 7;\r\n      --cvx-oled-track-arm-radius: 1;\r\n      --cvx-oled-track-arm-bg-off: 80;\r\n      --cvx-oled-track-arm-bg-on: 130;\r\n      --cvx-oled-track-arm-ink-off: 150;\r\n      --cvx-oled-track-arm-ink-on: 255;\r\n      --cvx-oled-track-arm-alpha: 1.0;\r\n\r\n      \/* MUTE\/SOLO controls (M\/S) *\/\r\n      --cvx-oled-ms-on: 1;\r\n\r\n      --cvx-oled-ms-gap: 2;\r\n      --cvx-oled-ms-radius: 1;\r\n      --cvx-oled-ms-border-on: 0;\r\n      --cvx-oled-ms-border-v: 255;\r\n      --cvx-oled-ms-border-a: .25;\r\n\r\n      \/* Inline (x4) size *\/\r\n      --cvx-oled-ms-box-w-x4: 8;\r\n      --cvx-oled-ms-box-h-x4: 10;\r\n\r\n      \/* Stacked (x2\/x1) size *\/\r\n      --cvx-oled-ms-box-w-x2: 10;\r\n      --cvx-oled-ms-box-h-x2: 10;\r\n\r\n      \/* M\/S palette *\/\r\n      --cvx-oled-ms-off-bg: 18;\r\n      --cvx-oled-ms-off-a: 1.0;\r\n      --cvx-oled-ms-off-ink: 130;\r\n\r\n      --cvx-oled-ms-on-bg: 90;\r\n      --cvx-oled-ms-on-a: 1.0;\r\n      --cvx-oled-ms-on-ink: 255;\r\n\r\n      \/* Track meters (underlabel + vertical) *\/\r\n      --cvx-oled-track-meter-h-on: 1;      \/* underline meter in x4 *\/\r\n      --cvx-oled-track-meter-h-h: 1;\r\n      --cvx-oled-track-meter-h-bg: 55;\r\n      --cvx-oled-track-meter-h-ink: 235;\r\n      --cvx-oled-track-meter-h-alpha: 1.0;\r\n      --cvx-oled-track-meter-h-yoff: 8;    \/* relative to track text top *\/\r\n\r\n      --cvx-oled-track-meter-v-on: 1;      \/* vertical meter in x2\/x1 *\/\r\n      --cvx-oled-track-meter-v-w: 3;\r\n      --cvx-oled-track-meter-v-bg: 45;\r\n      --cvx-oled-track-meter-v-ink: 235;\r\n      --cvx-oled-track-meter-v-alpha: 1.0;\r\n\r\n      --cvx-oled-track-meter-smooth: .26;  \/* 0..1 *\/\r\n\r\n\r\n      --cvx-oled-meter-db-floor: -48;\r\n      --cvx-oled-meter-db-ceil: 0;\r\n\r\n      \/* Source label (x1) *\/\r\n      --cvx-oled-track-src-on: 1;\r\n      --cvx-oled-track-src-ink: 120;\r\n      --cvx-oled-track-src-alpha: .92;\r\n      --cvx-oled-track-src-dy: 10;         \/* px below name baseline *\/\r\n\r\n      --cvx-oled-ctl-gap-full: 3; \/* px extra solo cuando hay labels *\/\r\n      \r\n      \/* =====================================================\r\n         CLIPS (OLED)\r\n      ====================================================== *\/\r\n      --cvx-oled-clip-radius: 6;\r\n      --cvx-oled-clip-stroke-on: 1;\r\n      --cvx-oled-clip-stroke-a: .3;\r\n      --cvx-oled-clip-fill: 30;\r\n      --cvx-oled-clip-ink-active: 200;\r\n      --cvx-oled-clip-ink: 150;\r\n\r\n      \/* Delete behavior *\/\r\n      --cvx-oled-ripple-delete: 1;\r\n\r\n      \/* =====================================================\r\n         MENU (OLED raster) \u2014 3 items + padding + palette\r\n      ====================================================== *\/\r\n      --cvx-oled-menu-visible: 3;\r\n\r\n      \/* Menu geometry *\/\r\n      --cvx-oled-menu-box-w: 136;\r\n      --cvx-oled-menu-box-h: 60;\r\n      --cvx-oled-menu-pad-x: 9;\r\n      --cvx-oled-menu-pad-y: 8;\r\n      --cvx-oled-menu-title-h: 10;\r\n      --cvx-oled-menu-row-h: 25;\r\n      --cvx-oled-menu-row-pad-x: 6;\r\n      --cvx-oled-menu-row-radius: 6;\r\n      --cvx-oled-menu-radius: 6;\r\n\r\n      \/* Text positioning *\/\r\n      --cvx-oled-menu-text-dy: -1;\r\n      --cvx-oled-menu-font-compact: 0;\r\n\r\n      \/* Menu borders (independent of global stroke) *\/\r\n      --cvx-oled-menu-box-border-on: 0;\r\n      --cvx-oled-menu-row-border-on: 0;\r\n\r\n        \/* MENU palette (0..255) *\/\r\n        --cvx-oled-menu-bg: 235;\r\n        --cvx-oled-menu-stroke: 120;\r\n\r\n        --cvx-oled-menu-title-ink: 60;\r\n\r\n        --cvx-oled-menu-item-bg: 235;\r\n        --cvx-oled-menu-item-ink: 150;\r\n\r\n        --cvx-oled-menu-item-bg-on: 85;\r\n        --cvx-oled-menu-item-ink-on: 255;\r\n\r\n        --cvx-oled-menu-pointer-ink: 200;\r\n\r\n      \/* =====================================================\r\n         MASTER BAR + MASTER DRAWER (right side)\r\n      ====================================================== *\/\r\n      --cvx-oled-masterbar-on: 1;\r\n      --cvx-oled-masterbar-w: 8;\r\n      --cvx-oled-masterbar-bg: 35;         \/* 0..255 *\/\r\n      --cvx-oled-masterbar-alpha: 1.0;\r\n\r\n      --cvx-oled-masterbar-tri-ink: 220;\r\n      --cvx-oled-masterbar-tri-alpha: .95;\r\n      --cvx-oled-masterbar-tri-size: 4;    \/* 2..6 *\/\r\n\r\n      \/* Drawer animation *\/\r\n      --cvx-oled-master-anim-in: .2;\r\n      --cvx-oled-master-anim-out: .2;\r\n\r\n      \/* Drawer geometry *\/\r\n      --cvx-oled-master-panel-w: 90;\r\n      --cvx-oled-master-panel-pad-x: 6;\r\n      --cvx-oled-master-panel-pad-y: 4;\r\n      --cvx-oled-master-panel-title-h: 10;\r\n      --cvx-oled-master-panel-row-h: 10;\r\n      --cvx-oled-master-panel-row-gap: 2;\r\n      --cvx-oled-master-panel-row-pad-x: 5;\r\n\r\n      --cvx-oled-master-panel-radius: 6;\r\n      --cvx-oled-master-panel-row-radius: 4;\r\n\r\n        \/* Drawer palette *\/\r\n        --cvx-oled-master-panel-bg: 30;\r\n        --cvx-oled-master-panel-stroke: 90;\r\n        --cvx-oled-master-panel-border-on: 0;\r\n        --cvx-oled-master-panel-row-border-on: 0;\r\n\r\n        --cvx-oled-master-panel-title-ink: 230;\r\n\r\n        \/* Items \u2014 defaults reales del renderer *\/\r\n        --cvx-oled-master-panel-item-bg: 28;\r\n        --cvx-oled-master-panel-item-ink: 185;\r\n        --cvx-oled-master-panel-item-bg-on: 90;\r\n        --cvx-oled-master-panel-item-ink-on: 255;\r\n\r\n      \/* =====================================================\r\n         DATAFILES (per-track waveform sources)\r\n         - Define a comma-separated list of TXT files (Audacity-like: 'time amplitude').\r\n         - These are *available* sources; tracks can be unassigned (empty).\r\n         - Hotkeys (default):\r\n             ALT + 0..9  => assign datafile[index] to active track\r\n             ALT + -     => clear assignment on active track\r\n         ====================================================== *\/\r\n\r\n      \/* Available datafiles list (string array \/ CSV). Example:\r\n         --cvx-oled-datafile:\r\n           '\/wp-content\/uploads\/2026\/02\/sample-data1.txt',\r\n           '\/wp-content\/uploads\/2026\/02\/sample-data2.txt',\r\n           '\/wp-content\/uploads\/2026\/02\/sample-data3.txt';\r\n      *\/\r\n      --cvx-oled-datafile: '\/wp-content\/uploads\/sample-data\/sample-data1.txt',\r\n           '\/wp-content\/uploads\/sample-data\/sample-data2.txt',\r\n           '\/wp-content\/uploads\/sample-data\/sample-data3.txt',\r\n           '\/wp-content\/uploads\/sample-data\/sample-data4.txt',\r\n           '\/wp-content\/uploads\/sample-data\/\/sample-data5.txt',\r\n           '\/wp-content\/uploads\/sample-data\/sample-data6.txt',\r\n           '\/wp-content\/uploads\/sample-data\/sample-data7.txt',\r\n           '\/wp-content\/uploads\/sample-data\/sample-data8.txt',\r\n           '\/wp-content\/uploads\/sample-data\/sample-data9.txt',\r\n           '\/wp-content\/uploads\/sample-data\/sample-data10.txt';\r\n\t\t   \r\n      \/* Datafile sampling rate (samples\/second) used to map samples -> seconds *\/\r\n      --cvx-oled-datafile-sr: 1000;\r\n\r\n      \/* Autoload on init (1=on,0=off). In DEMO you can also mirror to all tracks. *\/\r\n      --cvx-oled-datafile-autoload-on-init: 0;\r\n      --cvx-oled-datafile-autoload-index: 0;      \/* -1 disables *\/\r\n      --cvx-oled-datafile-autoload-track: 0;      \/* -1 = active track *\/\r\n      --cvx-oled-datafile-autoload-all-tracks-demo: 0;\r\n      --cvx-oled-datafile-assign-replaces-clips: 1;\r\n      --cvx-oled-datafile-clear-removes-clips: 1;\r\n\r\n\r\n      \/* No-data fallback (1 = sine \/ 0 = silence). Default follows session-demo. *\/\r\n      --cvx-oled-nodata-sine: var(--cvx-oled-session-demo);\r\n\r\n      \/* Tracks limit *\/\r\n      \/* Tracks limit *\/\r\n      --cvx-oled-tracks-max: 10;\r\n\r\n      \/* Track defaults (array-of-arrays)\r\n         Row order: [name, gainDb, vol(0..100), src, mute, solo, arm]\r\n         Example:\r\n         --cvx-oled-track-defaults: [\r\n           ['VOCAL',-8,23,'MIC_1',0,0,0],\r\n           ['GTR',-6,30,'INST_1-A',0,0,0]\r\n         ];\r\n      *\/\r\n        --cvx-oled-tracks-initial: 0;\r\n        \r\n        --cvx-oled-track-defaults: [\r\n          ['VOCAL',-8,23,'MIC_1',0,0,0],\r\n          ['GTR',-6,30,'INST_1-A',0,0,0],\r\n          ['BASS',-6,30,'INST_1-B',0,0,0],\r\n          ['DRUMS',-8,25,'LINE_1-A',0,0,0],\r\n          ['SYNTH',-8,25,'LINE_1-B',0,0,0]\r\n        ];\r\n\r\n      \/* Generic fallback (used when a row is missing for that index) *\/\r\n      --cvx-oled-track-default-name: 'TRK {n}';\r\n      --cvx-oled-track-default-src: 'LINE_1-A';\r\n      --cvx-oled-track-default-gain-db: -8;\r\n      --cvx-oled-track-default-vol: 23;\r\n      --cvx-oled-track-default-mute: 0;\r\n      --cvx-oled-track-default-solo: 0;\r\n      --cvx-oled-track-default-arm: 0;\r\n\r\n\r\n\r\n      \/* Add-track button behavior: 1=autoload datafile[index], 0=create empty *\/\r\n      --cvx-oled-addtrack-autoload: 1;\r\n\r\n      \/* Hotkey tuning *\/\r\n      --cvx-oled-datafile-hotkeys: 1;\r\n      --cvx-oled-datafile-hotkey-digit0-index: 0; \/* ALT+0 loads this index, ALT+1 => +1, etc. *\/\r\n      --cvx-oled-datafile-hotkey-clear: -;\r\n      \/* Default vertical zoom multiplier (allowed: 1, 2, 4) *\/\r\n      --cvx-oled-zoomy-default: 1;\r\n\r\n      \/* =====================================================\r\n         RESET\r\n      ====================================================== *\/\r\n\r\n      --cvx-oled-hotkey-reset: *; \/* Session reset to boot state (plain key) *\/\r\n\r\n\/* =====================================================\r\n   VERSION POPUP (DEMO)\r\n===================================================== *\/\r\n\r\n\/* Open popup hotkey (plain key). Default: V *\/\r\n--cvx-oled-hotkey-version: V;\r\n\r\n\/* Popup geometry (OLED px) \u2014 default matches mock (not fullscreen) *\/\r\n--cvx-oled-ver-x: 20;\r\n--cvx-oled-ver-y: 4;\r\n--cvx-oled-ver-w: 216;\r\n--cvx-oled-ver-h: 58;\r\n\r\n\/* Bars + spacing *\/\r\n--cvx-oled-ver-top-h: 14;\r\n--cvx-oled-ver-bot-h: 16;\r\n--cvx-oled-ver-pad: 8;   \/* general inner padding *\/\r\n--cvx-oled-ver-gap: 1;\r\n\r\n\/* Background dim (0..1) *\/\r\n--cvx-oled-ver-dim: 0.55;\r\n\r\n\/* Card \/ box styling (SSOT requested) *\/\r\n--cvx-oled-ver-box-bg: 20;     \/* bg=40 *\/\r\n--cvx-oled-ver-box-br: 30;     \/* border=80 (1px) *\/\r\n--cvx-oled-ver-ink: 250;       \/* title + selected btn text *\/\r\n--cvx-oled-ver-ink-sub: 150;   \/* secondary text *\/\r\n\r\n\/* Radii *\/\r\n--cvx-oled-ver-radius: 10;     \/* popup outer *\/\r\n--cvx-oled-ver-box-radius: 6;  \/* mid box *\/\r\n--cvx-oled-ver-pill-radius: 999; \/* default total (clamped to pillH\/2) *\/\r\n\r\n\/* Buttons sizing + alignment *\/\r\n--cvx-oled-ver-btn-pad-x: 8;   \/* (new) makes buttons bigger *\/\r\n--cvx-oled-ver-btn-pad-y: 3;   \/* (new) makes buttons bigger *\/\r\n--cvx-oled-ver-btn-gap-x: 6;   \/* spacing between pills *\/\r\n--cvx-oled-ver-btn-align: 0;   \/* 0=left, 1=center, 2=right *\/\r\n\r\n--cvx-oled-ver-head-pad-x: 4;  \/* padding interno X del header box *\/\r\n--cvx-oled-ver-head-pad-y: 1;  \/* padding interno Y del header box *\/\r\n\r\n--cvx-oled-ver-toast-pad-x: 10; \/* padding horizontal interno *\/\r\n--cvx-oled-ver-toast-pad-y: 20;  \/* padding vertical interno *\/\r\n\r\n\/* Demo strings *\/\r\n--cvx-oled-ver-name: 'VERSE TAKE';\r\n--cvx-oled-ver-note: 'TIGHT TIMING';\r\n--cvx-oled-ver-tag:  'V03';\r\n\r\n\/* History *\/\r\n--cvx-oled-ver-history-tag: 'HISTORY';\r\n\r\n\/* Save toast (wide, like mock) *\/\r\n--cvx-oled-ver-toast-ms: 1500;\r\n--cvx-oled-ver-toast-right: 'HISTORY UPDATED';\r\n--cvx-oled-ver-toast-a: 0.85; \/* black translucent *\/\r\n\r\n      \/* =====================================================\r\n         WEB CHROME (outer card)\r\n      ====================================================== *\/\r\n      --cvx-ui-border-on: 1;\r\n      --cvx-ui-radius: 18px;\r\n      --cvx-ui-pad: 14px;\r\n      --cvx-ui-bg: rgba(14,18,24,.55);\r\n      --cvx-ui-stroke: rgba(255,255,255,.10);\r\n      --cvx-ui-wrap-bg: radial-gradient(140% 120% at 50% 20%, rgba(255,255,255,.6), rgba(0,0,0,.30));\r\n      --cvx-ui-wrap-stroke: rgba(255,255,255,.10);\r\n      --cvx-ui-hint-bg: rgba(0,0,0,.20);\r\n      --cvx-ui-hint-stroke: rgba(255,255,255,.10);\r\n    \">\r\n        <div class=\"cvxOledWrap\">\r\n            <canvas class=\"cvxOled\" width=\"256\" height=\"64\" aria-label=\"OLED\"><\/canvas>\r\n        <\/div>\r\n    <\/div>\r\n<\/section>\r\n\r\n<script>\r\n    (function() {\r\n        \"use strict\";\r\n\r\n        const ROOT_SEL = '.cvxScope [data-cvx-root=\"oled-compose\"]';\r\n\r\n        function clamp(v, a, b) {\r\n            return Math.max(a, Math.min(b, v));\r\n        }\r\n\r\n        function lerp(a, b, t) {\r\n            return a + (b - a) * t;\r\n        }\r\n\r\n        function ampToDbFS(a) {\r\n            a = Math.max(1e-9, Math.abs(a));\r\n            return 20 * Math.log10(a);\r\n        }\r\n\r\n        \/* 0..1 (UI) from linear amplitude (0..1), with optional dB window *\/\r\n        function meterNormFromAmp(a, floorDb, ceilDb) {\r\n            floorDb = (floorDb == null) ? -48 : +floorDb;\r\n            ceilDb = (ceilDb == null) ? 0 : +ceilDb;\r\n            const db = ampToDbFS(a);\r\n            const n = (db - floorDb) \/ Math.max(1e-6, (ceilDb - floorDb));\r\n            return clamp(n, 0, 1);\r\n        }\r\n\r\n\r\n        function easeOutCubic(t) {\r\n            return 1 - Math.pow(1 - t, 3);\r\n        }\r\n\r\n        \/* ---------------------------------------------------------\r\n           5x7 bitmap font (subset)\r\n        --------------------------------------------------------- *\/\r\n        const FONT_5x7 = (function() {\r\n            const M = {};\r\n            const add = (ch, rows) => (M[ch] = rows.map(r => parseInt(r, 2)));\r\n            add(\" \", [\"00000\", \"00000\", \"00000\", \"00000\", \"00000\", \"00000\", \"00000\"]);\r\n            add(\":\", [\"00000\", \"00100\", \"00100\", \"00000\", \"00100\", \"00100\", \"00000\"]);\r\n            add(\"\/\", [\"00001\", \"00010\", \"00100\", \"01000\", \"10000\", \"00000\", \"00000\"]);\r\n            add(\"-\", [\"00000\", \"00000\", \"00000\", \"11111\", \"00000\", \"00000\", \"00000\"]);\r\n            add(\".\", [\"00000\", \"00000\", \"00000\", \"00000\", \"00000\", \"00100\", \"00100\"]);\r\n            add(\"%\", [\"11001\", \"11010\", \"00100\", \"01000\", \"10110\", \"00110\", \"00000\"]);\r\n            add(\"=\", [\"00000\", \"11111\", \"00000\", \"11111\", \"00000\", \"00000\", \"00000\"]);\r\n            add(\">\", [\"10000\", \"01000\", \"00100\", \"00010\", \"00100\", \"01000\", \"10000\"]);\r\n            add(\"<\", [\"00001\", \"00010\", \"00100\", \"01000\", \"00100\", \"00010\", \"00001\"]);\r\n            add(\"\u2026\", [\"00000\", \"00000\", \"00000\", \"10101\", \"00000\", \"00000\", \"00000\"]);\r\n            add(\"+\", [\"00000\", \"00100\", \"00100\", \"11111\", \"00100\", \"00100\", \"00000\"]);\r\n            add(\"[\", [\"00111\", \"00100\", \"00100\", \"00100\", \"00100\", \"00100\", \"00111\"]);\r\n            add(\"]\", [\"11100\", \"00100\", \"00100\", \"00100\", \"00100\", \"00100\", \"11100\"]);\r\n            add(\"|\", [\"00000\", \"00100\", \"00100\", \"00100\", \"00100\", \"00100\", \"00100\"]);\r\n            add(\"\u0394\", [\"00100\", \"00100\", \"01010\", \"01010\", \"10001\", \"10001\", \"11111\"]);\r\n\r\n            add(\"0\", [\"01110\", \"10001\", \"10011\", \"10101\", \"11001\", \"10001\", \"01110\"]);\r\n            add(\"1\", [\"00100\", \"01100\", \"00100\", \"00100\", \"00100\", \"00100\", \"01110\"]);\r\n            add(\"2\", [\"01110\", \"10001\", \"00001\", \"00010\", \"00100\", \"01000\", \"11111\"]);\r\n            add(\"3\", [\"11110\", \"00001\", \"00001\", \"01110\", \"00001\", \"00001\", \"11110\"]);\r\n            add(\"4\", [\"00010\", \"00110\", \"01010\", \"10010\", \"11111\", \"00010\", \"00010\"]);\r\n            add(\"5\", [\"11111\", \"10000\", \"10000\", \"11110\", \"00001\", \"00001\", \"11110\"]);\r\n            add(\"6\", [\"01110\", \"10000\", \"10000\", \"11110\", \"10001\", \"10001\", \"01110\"]);\r\n            add(\"7\", [\"11111\", \"00001\", \"00010\", \"00100\", \"01000\", \"01000\", \"01000\"]);\r\n            add(\"8\", [\"01110\", \"10001\", \"10001\", \"01110\", \"10001\", \"10001\", \"01110\"]);\r\n            add(\"9\", [\"01110\", \"10001\", \"10001\", \"01111\", \"00001\", \"00001\", \"01110\"]);\r\n\r\n            add(\"A\", [\"01110\", \"10001\", \"10001\", \"11111\", \"10001\", \"10001\", \"10001\"]);\r\n            add(\"B\", [\"11110\", \"10001\", \"10001\", \"11110\", \"10001\", \"10001\", \"11110\"]);\r\n            add(\"C\", [\"01110\", \"10001\", \"10000\", \"10000\", \"10000\", \"10001\", \"01110\"]);\r\n            add(\"D\", [\"11110\", \"10001\", \"10001\", \"10001\", \"10001\", \"10001\", \"11110\"]);\r\n            add(\"E\", [\"11111\", \"10000\", \"10000\", \"11110\", \"10000\", \"10000\", \"11111\"]);\r\n            add(\"F\", [\"11111\", \"10000\", \"10000\", \"11110\", \"10000\", \"10000\", \"10000\"]);\r\n            add(\"G\", [\"01110\", \"10001\", \"10000\", \"10111\", \"10001\", \"10001\", \"01110\"]);\r\n            add(\"H\", [\"10001\", \"10001\", \"10001\", \"11111\", \"10001\", \"10001\", \"10001\"]);\r\n            add(\"I\", [\"01110\", \"00100\", \"00100\", \"00100\", \"00100\", \"00100\", \"01110\"]);\r\n            add(\"K\", [\"10001\", \"10010\", \"10100\", \"11000\", \"10100\", \"10010\", \"10001\"]);\r\n            add(\"L\", [\"10000\", \"10000\", \"10000\", \"10000\", \"10000\", \"10000\", \"11111\"]);\r\n            add(\"M\", [\"10001\", \"11011\", \"10101\", \"10101\", \"10001\", \"10001\", \"10001\"]);\r\n            add(\"N\", [\"10001\", \"11001\", \"10101\", \"10011\", \"10001\", \"10001\", \"10001\"]);\r\n            add(\"O\", [\"01110\", \"10001\", \"10001\", \"10001\", \"10001\", \"10001\", \"01110\"]);\r\n            add(\"P\", [\"11110\", \"10001\", \"10001\", \"11110\", \"10000\", \"10000\", \"10000\"]);\r\n            add(\"R\", [\"11110\", \"10001\", \"10001\", \"11110\", \"10100\", \"10010\", \"10001\"]);\r\n            add(\"S\", [\"01111\", \"10000\", \"10000\", \"01110\", \"00001\", \"00001\", \"11110\"]);\r\n            add(\"T\", [\"11111\", \"00100\", \"00100\", \"00100\", \"00100\", \"00100\", \"00100\"]);\r\n            add(\"U\", [\"10001\", \"10001\", \"10001\", \"10001\", \"10001\", \"10001\", \"01110\"]);\r\n            add(\"V\", [\"10001\", \"10001\", \"10001\", \"10001\", \"10001\", \"01010\", \"00100\"]);\r\n            add(\"W\", [\"10001\", \"10001\", \"10001\", \"10101\", \"10101\", \"10101\", \"01010\"]);\r\n            add(\"X\", [\"10001\", \"01010\", \"00100\", \"00100\", \"00100\", \"01010\", \"10001\"]);\r\n            add(\"Y\", [\"10001\", \"01010\", \"00100\", \"00100\", \"00100\", \"00100\", \"00100\"]);\r\n            add(\"Z\", [\"11111\", \"00001\", \"00010\", \"00100\", \"01000\", \"10000\", \"11111\"]);\r\n            return M;\r\n        })();\r\n\r\n        \/* ---------------------------------------------------------\r\n           Raster helpers (grayscale 0..255)\r\n        --------------------------------------------------------- *\/\r\n        function Raster(w, h) {\r\n            this.w = w;\r\n            this.h = h;\r\n            this.fb = new Uint8Array(w * h);\r\n        }\r\n        Raster.prototype.clear = function(v) {\r\n            this.fb.fill(v | 0);\r\n        };\r\n        Raster.prototype.px = function(x, y, v) {\r\n            x |= 0;\r\n            y |= 0;\r\n            if (x < 0 || y < 0 || x >= this.w || y >= this.h) return;\r\n            this.fb[y * this.w + x] = v;\r\n        };\r\n        Raster.prototype.pxMax = function(x, y, v) {\r\n            x |= 0;\r\n            y |= 0;\r\n            if (x < 0 || y < 0 || x >= this.w || y >= this.h) return;\r\n            const i = y * this.w + x;\r\n            if (this.fb[i] < v) this.fb[i] = v;\r\n        };\r\n        Raster.prototype.blendPx = function(x, y, v, a) {\r\n            x |= 0;\r\n            y |= 0;\r\n            if (x < 0 || y < 0 || x >= this.w || y >= this.h) return;\r\n            a = clamp(a, 0, 1);\r\n            const i = y * this.w + x;\r\n            const o = this.fb[i];\r\n            this.fb[i] = (o + (v - o) * a) | 0;\r\n        };\r\n        Raster.prototype.hline = function(x0, x1, y, v) {\r\n            y |= 0;\r\n            x0 |= 0;\r\n            x1 |= 0;\r\n            if (y < 0 || y >= this.h) return;\r\n            if (x0 > x1) {\r\n                const t = x0;\r\n                x0 = x1;\r\n                x1 = t;\r\n            }\r\n            x0 = clamp(x0, 0, this.w - 1);\r\n            x1 = clamp(x1, 0, this.w - 1);\r\n            const off = y * this.w;\r\n            for (let x = x0; x <= x1; x++) this.fb[off + x] = v;\r\n        };\r\n        Raster.prototype.vline = function(x, y0, y1, v) {\r\n            x |= 0;\r\n            y0 |= 0;\r\n            y1 |= 0;\r\n            if (x < 0 || x >= this.w) return;\r\n            if (y0 > y1) {\r\n                const t = y0;\r\n                y0 = y1;\r\n                y1 = t;\r\n            }\r\n            y0 = clamp(y0, 0, this.h - 1);\r\n            y1 = clamp(y1, 0, this.h - 1);\r\n            for (let y = y0; y <= y1; y++) this.fb[y * this.w + x] = v;\r\n        };\r\n        Raster.prototype.fillRect = function(x, y, w, h, v) {\r\n            x |= 0;\r\n            y |= 0;\r\n            w |= 0;\r\n            h |= 0;\r\n            if (w <= 0 || h <= 0) return;\r\n            const x0 = clamp(x, 0, this.w - 1),\r\n                y0 = clamp(y, 0, this.h - 1);\r\n            const x1 = clamp(x + w - 1, 0, this.w - 1),\r\n                y1 = clamp(y + h - 1, 0, this.h - 1);\r\n            for (let yy = y0; yy <= y1; yy++) {\r\n                const off = yy * this.w;\r\n                for (let xx = x0; xx <= x1; xx++) this.fb[off + xx] = v;\r\n            }\r\n        };\r\n        Raster.prototype.blendRect = function(x, y, w, h, v, a) {\r\n            x |= 0;\r\n            y |= 0;\r\n            w |= 0;\r\n            h |= 0;\r\n            if (w <= 0 || h <= 0) return;\r\n            a = clamp(a, 0, 1);\r\n            const x0 = clamp(x, 0, this.w - 1),\r\n                y0 = clamp(y, 0, this.h - 1);\r\n            const x1 = clamp(x + w - 1, 0, this.w - 1),\r\n                y1 = clamp(y + h - 1, 0, this.h - 1);\r\n            for (let yy = y0; yy <= y1; yy++) {\r\n                const off = yy * this.w;\r\n                for (let xx = x0; xx <= x1; xx++) {\r\n                    const i = off + xx;\r\n                    const o = this.fb[i];\r\n                    this.fb[i] = (o + (v - o) * a) | 0;\r\n                }\r\n            }\r\n        };\r\n        Raster.prototype.mulRect = function(x, y, w, h, k) {\r\n            x |= 0;\r\n            y |= 0;\r\n            w |= 0;\r\n            h |= 0;\r\n            k = clamp(k, 0, 1);\r\n            if (w <= 0 || h <= 0) return;\r\n            const x0 = clamp(x, 0, this.w - 1),\r\n                y0 = clamp(y, 0, this.h - 1);\r\n            const x1 = clamp(x + w - 1, 0, this.w - 1),\r\n                y1 = clamp(y + h - 1, 0, this.h - 1);\r\n            for (let yy = y0; yy <= y1; yy++) {\r\n                const off = yy * this.w;\r\n                for (let xx = x0; xx <= x1; xx++) {\r\n                    const i = off + xx;\r\n                    this.fb[i] = (this.fb[i] * k) | 0;\r\n                }\r\n            }\r\n        };\r\n\r\n        \/* round rect AA with blend body + max stroke *\/\r\n        Raster.prototype.blendRoundRectAA = function(x, y, w, h, r, fillV, fillA, strokeV, strokeA) {\r\n            x |= 0;\r\n            y |= 0;\r\n            w |= 0;\r\n            h |= 0;\r\n            r |= 0;\r\n            if (w <= 0 || h <= 0) return;\r\n            r = clamp(r, 1, Math.min(14, (Math.min(w, h) >> 1)));\r\n            fillA = clamp(fillA, 0, 1);\r\n            strokeA = clamp(strokeA, 0, 1);\r\n\r\n            const ss = 5;\r\n            const inv = 1 \/ (ss * ss);\r\n\r\n            const x0 = x,\r\n                y0 = y,\r\n                x1 = x + w - 1,\r\n                y1 = y + h - 1;\r\n\r\n            const cxL = x0 + r - 0.5,\r\n                cxR = x1 - r + 0.5;\r\n            const cyT = y0 + r - 0.5,\r\n                cyB = y1 - r + 0.5;\r\n            const rr = r * r;\r\n\r\n            for (let py = y0; py <= y1; py++) {\r\n                for (let px = x0; px <= x1; px++) {\r\n                    let inside = 0;\r\n\r\n                    for (let sy = 0; sy < ss; sy++) {\r\n                        for (let sx = 0; sx < ss; sx++) {\r\n                            const fx = px + (sx + 0.5) \/ ss;\r\n                            const fy = py + (sy + 0.5) \/ ss;\r\n\r\n                            let ok = false;\r\n\r\n                            if (fx >= (x0 + r) && fx <= (x1 - r) && fy >= y0 && fy <= y1) ok = true;\r\n                            else if (fy >= (y0 + r) && fy <= (y1 - r) && fx >= x0 && fx <= x1) ok = true;\r\n                            else {\r\n                                const ccx = (fx < x0 + r) ? cxL : cxR;\r\n                                const ccy = (fy < y0 + r) ? cyT : cyB;\r\n                                const dx = fx - ccx;\r\n                                const dy = fy - ccy;\r\n                                if (dx * dx + dy * dy <= rr) ok = true;\r\n                            }\r\n                            if (ok) inside++;\r\n                        }\r\n                    }\r\n\r\n                    const cov = inside * inv;\r\n                    if (cov <= 0) continue;\r\n\r\n                    if (fillA > 0) {\r\n                        this.blendPx(px, py, fillV, fillA * cov);\r\n                    }\r\n\r\n                    if (strokeA > 0 && cov > 0) {\r\n                        if (cov < 1) {\r\n                            const sv = Math.round(strokeV * strokeA * Math.min(1, cov + 0.25));\r\n                            this.pxMax(px, py, sv);\r\n                        } else if (r >= 2) {\r\n                            \/\/ Fill-cov==1 corner pixels can sit on the arc edge; force a 1px stroke band there.\r\n                            const inCorner =\r\n                                (px < x0 + r && py < y0 + r) ||\r\n                                (px > x1 - r && py < y0 + r) ||\r\n                                (px < x0 + r && py > y1 - r) ||\r\n                                (px > x1 - r && py > y1 - r);\r\n\r\n                            if (inCorner) {\r\n                                const fx = px + 0.5,\r\n                                    fy = py + 0.5;\r\n                                const ccx = (fx < x0 + r) ? cxL : cxR;\r\n                                const ccy = (fy < y0 + r) ? cyT : cyB;\r\n                                const dx = fx - ccx,\r\n                                    dy = fy - ccy;\r\n\r\n                                const rrIn = (r - 1) * (r - 1); \/\/ 1px inner band\r\n                                const d2 = (dx * dx + dy * dy);\r\n\r\n                                \/* IMPORTANT: only paint the corner stroke band if the pixel center is still within the arc circle.\r\n                                   Otherwise, cov==1 may come from the central rect and this \u201cstretches\u201d the corner into an oval. *\/\r\n                                if (d2 >= rrIn && d2 <= rr) {\r\n                                    const sv = Math.round(strokeV * strokeA);\r\n                                    this.pxMax(px, py, sv);\r\n                                }\r\n                            }\r\n                        }\r\n                    }\r\n                }\r\n            }\r\n\r\n            const sLine = Math.round(strokeV * strokeA);\r\n            if (sLine > 0) {\r\n                this.hline(x0 + r, x1 - r, y0, sLine);\r\n                this.hline(x0 + r, x1 - r, y1, sLine);\r\n                this.vline(x0, y0 + r, y1 - r, sLine);\r\n                this.vline(x1, y0 + r, y1 - r, sLine);\r\n            }\r\n        };\r\n\r\n        \/* AA text \u2014 BLEND mode *\/\r\n        Raster.prototype.textBlendAA = function(x, y, str, fg, aa) {\r\n            aa = (aa == null) ? 0.62 : aa;\r\n            const h1 = clamp(aa * 0.55, 0, 1);\r\n            const h2 = clamp(aa * 0.30, 0, 1);\r\n\r\n            str = String(str || \"\");\r\n            let cx = x | 0;\r\n            const cy = y | 0;\r\n\r\n            for (let i = 0; i < str.length; i++) {\r\n                const ch = str[i].toUpperCase();\r\n                const glyph = FONT_5x7[ch] || FONT_5x7[\" \"];\r\n\r\n                for (let row = 0; row < 7; row++) {\r\n                    const bits = glyph[row];\r\n                    for (let col = 0; col < 5; col++) {\r\n                        if (bits & (1 << (4 - col))) {\r\n                            const px = cx + col;\r\n                            const py = cy + row;\r\n\r\n                            this.blendPx(px, py, fg, 1.0);\r\n\r\n                            this.blendPx(px - 1, py, fg, h1);\r\n                            this.blendPx(px + 1, py, fg, h1);\r\n                            this.blendPx(px, py - 1, fg, h1);\r\n                            this.blendPx(px, py + 1, fg, h1);\r\n\r\n                            this.blendPx(px - 1, py - 1, fg, h2);\r\n                            this.blendPx(px + 1, py - 1, fg, h2);\r\n                            this.blendPx(px - 1, py + 1, fg, h2);\r\n                            this.blendPx(px + 1, py + 1, fg, h2);\r\n                        }\r\n                    }\r\n                }\r\n\r\n                cx += 6;\r\n                if (cx > this.w) break;\r\n            }\r\n        };\r\n        Raster.prototype.textBlendAA6 = function(x, y, str, fg, aa) {\r\n            aa = (aa == null) ? 0.62 : aa;\r\n            const h1 = clamp(aa * 0.55, 0, 1);\r\n            const h2 = clamp(aa * 0.30, 0, 1);\r\n            const map = [0, 1, 2, 3, 4, 6];\r\n\r\n            str = String(str || \"\");\r\n            let cx = x | 0;\r\n            const cy = y | 0;\r\n\r\n            for (let i = 0; i < str.length; i++) {\r\n                const ch = str[i].toUpperCase();\r\n                const glyph = FONT_5x7[ch] || FONT_5x7[\" \"];\r\n\r\n                for (let row = 0; row < 6; row++) {\r\n                    const bits = glyph[map[row]];\r\n                    for (let col = 0; col < 5; col++) {\r\n                        if (bits & (1 << (4 - col))) {\r\n                            const px = cx + col;\r\n                            const py = cy + row;\r\n\r\n                            this.blendPx(px, py, fg, 1.0);\r\n\r\n                            this.blendPx(px - 1, py, fg, h1);\r\n                            this.blendPx(px + 1, py, fg, h1);\r\n                            this.blendPx(px, py - 1, fg, h1);\r\n                            this.blendPx(px, py + 1, fg, h1);\r\n\r\n                            this.blendPx(px - 1, py - 1, fg, h2);\r\n                            this.blendPx(px + 1, py - 1, fg, h2);\r\n                            this.blendPx(px - 1, py + 1, fg, h2);\r\n                            this.blendPx(px + 1, py + 1, fg, h2);\r\n                        }\r\n                    }\r\n                }\r\n\r\n                cx += 6;\r\n                if (cx > this.w) break;\r\n            }\r\n        };\r\n        \/* AA text \u2014 BLEND mode (clipped on X) *\/\r\n        Raster.prototype.textBlendAAClip = function(x, y, str, fg, aa, clipX0, clipX1) {\r\n            aa = (aa == null) ? 0.62 : aa;\r\n            const h1 = clamp(aa * 0.55, 0, 1);\r\n            const h2 = clamp(aa * 0.30, 0, 1);\r\n\r\n            const c0 = (clipX0 == null ? -1e9 : (clipX0 | 0));\r\n            const c1 = (clipX1 == null ? 1e9 : (clipX1 | 0));\r\n\r\n            str = String(str || \"\");\r\n            let cx = x | 0;\r\n            const cy = y | 0;\r\n\r\n            const blend = (px, py, a) => {\r\n                if (px < c0 || px >= c1) return;\r\n                this.blendPx(px, py, fg, a);\r\n            };\r\n\r\n            for (let i = 0; i < str.length; i++) {\r\n                const ch = str[i].toUpperCase();\r\n                const glyph = FONT_5x7[ch] || FONT_5x7[\" \"];\r\n\r\n                for (let row = 0; row < 7; row++) {\r\n                    const bits = glyph[row];\r\n                    for (let col = 0; col < 5; col++) {\r\n                        if (bits & (1 << (4 - col))) {\r\n                            const px = cx + col;\r\n                            const py = cy + row;\r\n\r\n                            blend(px, py, 1.0);\r\n\r\n                            blend(px - 1, py, h1);\r\n                            blend(px + 1, py, h1);\r\n                            blend(px, py - 1, h1);\r\n                            blend(px, py + 1, h1);\r\n\r\n                            blend(px - 1, py - 1, h2);\r\n                            blend(px + 1, py - 1, h2);\r\n                            blend(px - 1, py + 1, h2);\r\n                            blend(px + 1, py + 1, h2);\r\n                        }\r\n                    }\r\n                }\r\n\r\n                cx += 6;\r\n                if (cx > this.w) break;\r\n            }\r\n        };\r\n\r\n        Raster.prototype.textBlendAA6Clip = function(x, y, str, fg, aa, clipX0, clipX1) {\r\n            aa = (aa == null) ? 0.62 : aa;\r\n            const h1 = clamp(aa * 0.55, 0, 1);\r\n            const h2 = clamp(aa * 0.30, 0, 1);\r\n            const map = [0, 1, 2, 3, 4, 6];\r\n\r\n            const c0 = (clipX0 == null ? -1e9 : (clipX0 | 0));\r\n            const c1 = (clipX1 == null ? 1e9 : (clipX1 | 0));\r\n\r\n            str = String(str || \"\");\r\n            let cx = x | 0;\r\n            const cy = y | 0;\r\n\r\n            const blend = (px, py, a) => {\r\n                if (px < c0 || px >= c1) return;\r\n                this.blendPx(px, py, fg, a);\r\n            };\r\n\r\n            for (let i = 0; i < str.length; i++) {\r\n                const ch = str[i].toUpperCase();\r\n                const glyph = FONT_5x7[ch] || FONT_5x7[\" \"];\r\n\r\n                for (let row = 0; row < 6; row++) {\r\n                    const bits = glyph[map[row]];\r\n                    for (let col = 0; col < 5; col++) {\r\n                        if (bits & (1 << (4 - col))) {\r\n                            const px = cx + col;\r\n                            const py = cy + row;\r\n\r\n                            blend(px, py, 1.0);\r\n\r\n                            blend(px - 1, py, h1);\r\n                            blend(px + 1, py, h1);\r\n                            blend(px, py - 1, h1);\r\n                            blend(px, py + 1, h1);\r\n\r\n                            blend(px - 1, py - 1, h2);\r\n                            blend(px + 1, py - 1, h2);\r\n                            blend(px - 1, py + 1, h2);\r\n                            blend(px + 1, py + 1, h2);\r\n                        }\r\n                    }\r\n                }\r\n\r\n                cx += 6;\r\n                if (cx > this.w) break;\r\n            }\r\n        };\r\n        \/* AA text (5x7) \u2014 MAX mode *\/\r\n        Raster.prototype.textAA = function(x, y, str, fg, aa) {\r\n            aa = (aa == null) ? 0.62 : aa;\r\n            const a1 = Math.max(0, Math.min(255, Math.round(fg * aa)));\r\n            const a2 = Math.max(0, Math.min(255, Math.round(fg * aa * 0.55)));\r\n\r\n            str = String(str || \"\");\r\n            let cx = x | 0;\r\n            const cy = y | 0;\r\n\r\n            for (let i = 0; i < str.length; i++) {\r\n                const ch = str[i].toUpperCase();\r\n                const glyph = FONT_5x7[ch] || FONT_5x7[\" \"];\r\n\r\n                for (let row = 0; row < 7; row++) {\r\n                    const bits = glyph[row];\r\n                    for (let col = 0; col < 5; col++) {\r\n                        if (bits & (1 << (4 - col))) {\r\n                            const px = cx + col;\r\n                            const py = cy + row;\r\n                            this.pxMax(px, py, fg);\r\n\r\n                            this.pxMax(px - 1, py, a1);\r\n                            this.pxMax(px + 1, py, a1);\r\n                            this.pxMax(px, py - 1, a1);\r\n                            this.pxMax(px, py + 1, a1);\r\n\r\n                            this.pxMax(px - 1, py - 1, a2);\r\n                            this.pxMax(px + 1, py - 1, a2);\r\n                            this.pxMax(px - 1, py + 1, a2);\r\n                            this.pxMax(px + 1, py + 1, a2);\r\n                        }\r\n                    }\r\n                }\r\n                cx += 6;\r\n                if (cx > this.w) break;\r\n            }\r\n        };\r\n        \/* Compact text (5x6): rows 0,1,2,3,4,6 *\/\r\n        Raster.prototype.textAA6 = function(x, y, str, fg, aa) {\r\n            aa = (aa == null) ? 0.62 : aa;\r\n            const a1 = Math.max(0, Math.min(255, Math.round(fg * aa)));\r\n            const a2 = Math.max(0, Math.min(255, Math.round(fg * aa * 0.55)));\r\n            const map = [0, 1, 2, 3, 4, 6];\r\n\r\n            str = String(str || \"\");\r\n            let cx = x | 0;\r\n            const cy = y | 0;\r\n\r\n            for (let i = 0; i < str.length; i++) {\r\n                const ch = str[i].toUpperCase();\r\n                const glyph = FONT_5x7[ch] || FONT_5x7[\" \"];\r\n\r\n                for (let row = 0; row < 6; row++) {\r\n                    const bits = glyph[map[row]];\r\n                    for (let col = 0; col < 5; col++) {\r\n                        if (bits & (1 << (4 - col))) {\r\n                            const px = cx + col;\r\n                            const py = cy + row;\r\n                            this.pxMax(px, py, fg);\r\n\r\n                            this.pxMax(px - 1, py, a1);\r\n                            this.pxMax(px + 1, py, a1);\r\n                            this.pxMax(px, py - 1, a1);\r\n                            this.pxMax(px, py + 1, a1);\r\n\r\n                            this.pxMax(px - 1, py - 1, a2);\r\n                            this.pxMax(px + 1, py - 1, a2);\r\n                            this.pxMax(px - 1, py + 1, a2);\r\n                            this.pxMax(px + 1, py + 1, a2);\r\n                        }\r\n                    }\r\n                }\r\n                cx += 6;\r\n                if (cx > this.w) break;\r\n            }\r\n        };\r\n\r\n        function makeGrayBlitter(ctx, w, h, tintRGB) {\r\n            const img = ctx.createImageData(w, h);\r\n            const d = img.data;\r\n            const tr = (tintRGB && tintRGB[0] != null) ? tintRGB[0] : 255;\r\n            const tg = (tintRGB && tintRGB[1] != null) ? tintRGB[1] : 255;\r\n            const tb = (tintRGB && tintRGB[2] != null) ? tintRGB[2] : 255;\r\n            const kr = tr \/ 255,\r\n                kg = tg \/ 255,\r\n                kb = tb \/ 255;\r\n\r\n            return function blit(ras) {\r\n                for (let i = 0; i < ras.fb.length; i++) {\r\n                    const v = ras.fb[i];\r\n                    const o = i * 4;\r\n                    d[o + 0] = (v * kr) | 0;\r\n                    d[o + 1] = (v * kg) | 0;\r\n                    d[o + 2] = (v * kb) | 0;\r\n                    d[o + 3] = 255;\r\n                }\r\n                ctx.putImageData(img, 0, 0);\r\n            };\r\n        }\r\n\r\n\r\n        \/* ---------------------------------------------------------\r\n           Demo tracks + clips + per-track controls\r\n        --------------------------------------------------------- *\/\r\n        function buildTracks(isDemo, count, cfg) {\r\n            cfg = cfg || {};\r\n            const defs = Array.isArray(cfg.defs) ? cfg.defs : [];\r\n\r\n            let clipId = 1;\r\n\r\n            function fmtName(tpl, idx) {\r\n                const n = idx + 1;\r\n                tpl = String(tpl || \"TRK {n}\");\r\n                return tpl\r\n                    .replace(\/\\{n\\}\/g, String(n))\r\n                    .replace(\/\\{i\\}\/g, String(idx))\r\n                    .toUpperCase();\r\n            }\r\n\r\n            function demoClips(seed) {\r\n                const clips = [];\r\n\r\n                \/* DEMO: clips fragmentados con offset en la fuente = tiempo del timeline *\/\r\n                let t = 0;\r\n                for (let i = 0; i < 5; i++) {\r\n                    t += 6 + ((seed * (i + 3)) % 7);\r\n                    const len = 10 + ((seed * (i + 5)) % 16);\r\n\r\n                    clips.push({\r\n                        id: clipId++,\r\n                        s: t,\r\n                        e: t + len,\r\n                        o: t,\r\n                        a: 0.5 + (((seed + i * 13) % 50) \/ 100),\r\n                        fx: [],\r\n                        fi: false,\r\n                        fo: false,\r\n                        m: []\r\n                    });\r\n\r\n                    t += len;\r\n                }\r\n                return clips;\r\n            }\r\n\r\n            \/* Si count es null\/undefined, por defecto usa la longitud del arreglo de defaults *\/\r\n            const wantRaw = (count == null) ? defs.length : (count | 0);\r\n            const want = Math.max(0, wantRaw);\r\n\r\n            const out = [];\r\n            for (let i = 0; i < want; i++) {\r\n                const d = defs[i] || null;\r\n\r\n                const name = (d && d.name) ? String(d.name).toUpperCase() : fmtName(cfg.nameTpl, i);\r\n                const src = (d && d.src) ? String(d.src).toUpperCase() : String(cfg.srcDef || \"LINE_1-A\").toUpperCase();\r\n\r\n                const gainDb = (d && d.gainDb != null) ? Number(d.gainDb) : Number(cfg.gainDef != null ? cfg.gainDef : 0);\r\n                const vol = (d && d.vol != null) ? Number(d.vol) : Number(cfg.volDef != null ? cfg.volDef : 50);\r\n\r\n                const mute = (d && d.mute != null) ? !!d.mute : !!cfg.muteDef;\r\n                const solo = (d && d.solo != null) ? !!d.solo : !!cfg.soloDef;\r\n                const arm = (d && d.arm != null) ? !!d.arm : !!cfg.armDef;\r\n\r\n                const seed = 17 + (i * 13);\r\n\r\n                out.push({\r\n                    name,\r\n                    src,\r\n                    clips: isDemo ? demoClips(seed) : [],\r\n\r\n                    seed,\r\n                    mute,\r\n                    solo,\r\n                    arm,\r\n                    gainDb,\r\n                    vol,\r\n\r\n                    aud: null,\r\n                    fileIdx: -1,\r\n                    dataUrl: \"\"\r\n                });\r\n            }\r\n\r\n            return out;\r\n        }\r\n\r\n\r\n        function initRoot(root) {\r\n            if (root.__cvxOledInit) return;\r\n            root.__cvxOledInit = true;\r\n\r\n            const canvas = root.querySelector(\"canvas.cvxOled\");\r\n            if (!canvas) return;\r\n\r\n            const ctx = canvas.getContext(\"2d\", {\r\n                alpha: false,\r\n                desynchronized: true\r\n            });\r\n            if (!ctx) return;\r\n            ctx.imageSmoothingEnabled = false;\r\n\r\n            const W = 256,\r\n                H = 64;\r\n            const ras = new Raster(W, H);\r\n            const blit = makeGrayBlitter(ctx, W, H, [235, 245, 255]);\r\n\r\n            const css = {\r\n                int(name, def) {\r\n                    const v = parseInt(getComputedStyle(root).getPropertyValue(name));\r\n                    return Number.isFinite(v) ? v : def;\r\n                },\r\n                flt(name, def) {\r\n                    const v = parseFloat(getComputedStyle(root).getPropertyValue(name));\r\n                    return Number.isFinite(v) ? v : def;\r\n                },\r\n\r\n                str(name, def) {\r\n                    const v = getComputedStyle(root).getPropertyValue(name);\r\n                    const s = (v == null ? \"\" : String(v)).trim();\r\n                    return s ? s : (def == null ? \"\" : String(def));\r\n                },\r\n                bool(name, def) {\r\n                    const v = parseInt(getComputedStyle(root).getPropertyValue(name));\r\n                    if (!Number.isFinite(v)) return def ? 1 : 0;\r\n                    return v ? 1 : 0;\r\n                }\r\n            };\r\n\r\n            const measureScale = () => {\r\n                const wrap = root.querySelector(\".cvxOledWrap\");\r\n                if (!wrap) return;\r\n                const r = wrap.getBoundingClientRect();\r\n                if (r.width < 10) return;\r\n\r\n                const scaleMin = css.flt(\"--cvx-oled-scale-min\", 3);\r\n                const scaleMax = css.flt(\"--cvx-oled-scale-max\", 10);\r\n\r\n                const usable = r.width - 20;\r\n                const s = clamp(Math.floor(usable \/ W), scaleMin, scaleMax);\r\n                root.style.setProperty(\"--cvx-oled-calc-scale\", String(Math.max(1, s)));\r\n            };\r\n\r\n            let ro = null;\r\n            try {\r\n                ro = new ResizeObserver(() => requestAnimationFrame(measureScale));\r\n                ro.observe(root);\r\n            } catch (_) {}\r\n            measureScale();\r\n\r\n            \/* -------------------------------------------------------\r\n               State\r\n            ------------------------------------------------------- *\/\r\n            const CVX_DEMO_MODE = !!css.bool(\"--cvx-oled-session-demo\", 1);\r\n\r\n\r\n            \/* behavior toggles *\/\r\n            const CVX_NODATA_SINE = !!css.bool(\"--cvx-oled-nodata-sine\", CVX_DEMO_MODE ? 1 : 0);\r\n            \/* recording *\/\r\n            const CVX_REC_LOCK_TRANSPORT = !!css.bool(\"--cvx-oled-rec-lock-transport\", 1); \/* 1 = bloquear mover cursor mientras REC *\/\r\n            const CVX_REC_AUTOLOAD = !!css.bool(\"--cvx-oled-rec-autoload\", 1); \/* 1 = cargar datafile al iniciar REC si falta aud *\/\r\n            const CVX_REC_FILE_BASE = clampi(css.int(\"--cvx-oled-rec-file-base\", 0), 0, 9999); \/* fileIdx = base + trackIndex *\/\r\n            const CVX_REC_DEMO_HZ = clamp(css.flt(\"--cvx-oled-rec-demo-hz\", 1.35), 0.15, 8.0); \/* seno fallback (solo visual) *\/\r\n\r\n            \/* tracks limits *\/\r\n            const CVX_TRACKS_MAX = clampi(css.int(\"--cvx-oled-tracks-max\", 10), 1, 24);\r\n            const CVX_TRACKS_INIT = clampi(css.int(\"--cvx-oled-tracks-initial\", 2), 0, CVX_TRACKS_MAX);\r\n\r\n            \/* track defaults (applied by index when creating tracks) *\/\r\n            const CVX_TRACK_DEFAULTS = parseCssTrackDefaults(css.str(\"--cvx-oled-track-defaults\", \"\"));\r\n            const CVX_TR_DEF_NAME_TPL = css.str(\"--cvx-oled-track-default-name\", \"TRK {n}\");\r\n            const CVX_TR_DEF_SRC = css.str(\"--cvx-oled-track-default-src\", \"LINE_1-A\");\r\n            const CVX_TR_DEF_GAIN_DB = clamp(css.flt(\"--cvx-oled-track-default-gain-db\", -8), -60, 24);\r\n            const CVX_TR_DEF_VOL = clamp(css.flt(\"--cvx-oled-track-default-vol\", 23), 0, 100);\r\n            const CVX_TR_DEF_MUTE = !!css.bool(\"--cvx-oled-track-default-mute\", 0);\r\n            const CVX_TR_DEF_SOLO = !!css.bool(\"--cvx-oled-track-default-solo\", 0);\r\n            const CVX_TR_DEF_ARM = !!css.bool(\"--cvx-oled-track-default-arm\", 0);\r\n\r\n            function defaultTrackName(idx) {\r\n                const n = idx + 1;\r\n                const tpl = String(CVX_TR_DEF_NAME_TPL || \"TRK {n}\");\r\n                return tpl.replace(\/\\{n\\}\/g, String(n)).replace(\/\\{i\\}\/g, String(idx));\r\n            }\r\n\r\n            function trackDefaultsAt(idx) {\r\n                return (CVX_TRACK_DEFAULTS && CVX_TRACK_DEFAULTS[idx]) ? CVX_TRACK_DEFAULTS[idx] : null;\r\n            }\r\n\r\n            const tracks = buildTracks(CVX_DEMO_MODE, CVX_TRACKS_INIT, {\r\n                defs: CVX_TRACK_DEFAULTS,\r\n                \/* array de objetos parseados *\/\r\n                nameTpl: CVX_TR_DEF_NAME_TPL,\r\n                \/* \"TRK {n}\" *\/\r\n                srcDef: CVX_TR_DEF_SRC,\r\n                \/* \"LINE_1-A\" *\/\r\n                gainDef: CVX_TR_DEF_GAIN_DB,\r\n                \/* -8 *\/\r\n                volDef: CVX_TR_DEF_VOL,\r\n                \/* 23 *\/\r\n                muteDef: CVX_TR_DEF_MUTE,\r\n                \/* false *\/\r\n                soloDef: CVX_TR_DEF_SOLO,\r\n                \/* false *\/\r\n                armDef: CVX_TR_DEF_ARM \/* false *\/\r\n            });\r\n\r\n\r\n            \/* clip-id allocator (para clips creados din\u00e1micamente al cargar archivos en modo NORMAL) *\/\r\n            let __clipIdSeq = 1;\r\n            for (const tr of tracks) {\r\n                const list = tr.clips || [];\r\n                for (const c of list) __clipIdSeq = Math.max(__clipIdSeq, ((c.id | 0) + 1) || 1);\r\n            }\r\n\r\n            function allocClipId() {\r\n                return __clipIdSeq++;\r\n            }\r\n\r\n            \/* -------------------------------------------------------\r\n               Tracks count bridge (Portable Studio integration)\r\n               Contract:\r\n               - data-cvx-oled-tracks=\"N\"\r\n               - CustomEvent \"cvx:oled:tracks\" (bubbles) detail:{tracks:N}\r\n               - root.__cvxOledGetTrackCount() => N\r\n            ------------------------------------------------------- *\/\r\n            function reportTracks(reason) {\r\n                const oledRoot = root;\r\n                if (!oledRoot) return;\r\n\r\n                \/* Source of truth: the real tracks array *\/\r\n                const n = Math.max(0, tracks.length | 0);\r\n\r\n                \/* Pull-strong getter (optional but recommended) *\/\r\n                if (typeof oledRoot.__cvxOledGetTrackCount !== \"function\") {\r\n                    oledRoot.__cvxOledGetTrackCount = () => Math.max(0, tracks.length | 0);\r\n                }\r\n\r\n                \/* Avoid redundant dispatches (Elementor can re-render frequently) *\/\r\n                const prev = (oledRoot.__cvxOledTracksN == null) ? null : (oledRoot.__cvxOledTracksN | 0);\r\n                const attr = oledRoot.getAttribute(\"data-cvx-oled-tracks\");\r\n                if (prev === n && attr === String(n)) return;\r\n\r\n                oledRoot.__cvxOledTracksN = n;\r\n\r\n                \/* Pull: attribute *\/\r\n                oledRoot.setAttribute(\"data-cvx-oled-tracks\", String(n));\r\n\r\n                \/* Push: event *\/\r\n                try {\r\n                    oledRoot.dispatchEvent(new CustomEvent(\"cvx:oled:tracks\", {\r\n                        detail: {\r\n                            tracks: n\r\n                        },\r\n                        bubbles: true\r\n                    }));\r\n                } catch (_) {\r\n                    \/* no-op (very old browsers) *\/\r\n                }\r\n            }\r\n\r\n            \/* Init \/ refresh: expose current N immediately (attribute + getter), plus one event *\/\r\n            reportTracks(\"init\");\r\n\r\n            \/* -------------------------------------------------------\r\n               Datafile pool (CSS \"array\" parser)\r\n               - CSS custom properties are strings; we accept a CSV of quoted URLs.\r\n               - Example in style:\r\n                   --cvx-oled-datafile:\r\n                     '\/wp-content\/uploads\/2026\/02\/sample-data1.txt',\r\n                     '\/wp-content\/uploads\/2026\/02\/sample-data2.txt';\r\n            ------------------------------------------------------- *\/\r\n            function parseCssUrlList(raw) {\r\n                raw = (raw == null) ? \"\" : String(raw);\r\n                raw = raw.trim();\r\n                if (!raw) return [];\r\n\r\n                \/\/ remove trailing ';'\r\n                if (raw.endsWith(\";\")) raw = raw.slice(0, -1);\r\n\r\n\r\n\r\n                const out = [];\r\n                \/\/ match: \"...\" | '...' | bareToken\r\n                const re = \/\"([^\"\\\\]*(?:\\\\.[^\"\\\\]*)*)\"|'([^'\\\\]*(?:\\\\.[^'\\\\]*)*)'|([^,]+)\/g;\r\n                let m;\r\n                while ((m = re.exec(raw))) {\r\n                    let s = (m[1] != null) ? m[1] : ((m[2] != null) ? m[2] : m[3]);\r\n                    s = (s == null) ? \"\" : String(s);\r\n\r\n                    \/* Normaliza tokens:\r\n                       - Si cay\u00f3 por la rama \"bareToken\", puede venir con comillas incluidas.\r\n                       - Si el editor parti\u00f3 la URL, puede venir con \\n\/\\t adentro.\r\n                    *\/\r\n                    s = s.replace(\/[\\r\\n\\t]+\/g, \"\").trim();\r\n                    s = s.replace(\/^[\\\"']|[\\\"']$\/g, \"\");\r\n\r\n                    if (!s) continue;\r\n\r\n                    \/\/ strip trailing comma artifacts\r\n                    if (s.endsWith(\",\")) s = s.slice(0, -1).trim();\r\n                    if (!s) continue;\r\n                    out.push(s);\r\n                }\r\n                return out;\r\n            }\r\n\r\n            \/* -----------------------------------------------\r\n               Track defaults (array-of-arrays) parser\r\n               - Preferred syntax:\r\n                 --cvx-oled-track-defaults: [\r\n                   [\"VOCAL\",-8,23,\"MIC_1\",0,0,0],\r\n                   [\"GTR\",-6,30,\"INST_1-A\",0,0,0]\r\n                 ];\r\n                 Row order: [name, gainDb, vol(0..100), src, mute, solo, arm]\r\n               - Fallback syntax (no brackets):\r\n                 VOCAL,-8,23,MIC_1,0,0,0; GTR,-6,30,INST_1-A,0,0,0\r\n               ----------------------------------------------- *\/\r\n            function parseCssTrackDefaults(raw) {\r\n                raw = (raw == null) ? \"\" : String(raw);\r\n                raw = raw.trim();\r\n                if (!raw) return [];\r\n\r\n                \/\/ remove trailing ';'\r\n                raw = raw.replace(\/;\\s*$\/, \"\").trim();\r\n\r\n                \/\/ strip optional wrapping quotes\r\n                if ((raw[0] === '\"' && raw[raw.length - 1] === '\"') || (raw[0] === \"'\" && raw[raw.length - 1] === \"'\")) {\r\n                    raw = raw.slice(1, -1).trim();\r\n                }\r\n\r\n                const rowStrings = [];\r\n\r\n                \/\/ capture inner \"[...]\" rows if present\r\n                const matches = raw.match(\/\\[[^\\[\\]]*\\]\/g);\r\n                if (matches && matches.length) {\r\n                    for (const m of matches) {\r\n                        const inner = m.slice(1, -1).trim();\r\n                        if (inner) rowStrings.push(inner);\r\n                    }\r\n                } else {\r\n                    \/\/ fallback split by ';'\r\n                    raw.split(\";\").forEach(s => {\r\n                        s = String(s || \"\").trim();\r\n                        if (s) rowStrings.push(s);\r\n                    });\r\n                }\r\n\r\n                function toBool(v) {\r\n                    if (v == null) return false;\r\n                    const s = String(v).trim().toLowerCase();\r\n                    if (!s) return false;\r\n                    if (s === \"1\" || s === \"true\" || s === \"on\" || s === \"yes\") return true;\r\n                    if (s === \"0\" || s === \"false\" || s === \"off\" || s === \"no\") return false;\r\n                    const n = parseFloat(s);\r\n                    return isFinite(n) ? (n !== 0) : false;\r\n                }\r\n\r\n                function parseRow(rowStr) {\r\n                    const out = [];\r\n                    const re = \/\"([^\"\\\\]*(?:\\\\.[^\"\\\\]*)*)\"|'([^'\\\\]*(?:\\\\.[^'\\\\]*)*)'|([^,]+)\/g;\r\n                    rowStr.replace(re, (_, dq, sq, bare) => {\r\n                        const v = (dq != null) ? dq : ((sq != null) ? sq : bare);\r\n                        out.push(String(v).trim());\r\n                        return \"\";\r\n                    });\r\n                    return out;\r\n                }\r\n\r\n                const defs = [];\r\n                for (let i = 0; i < rowStrings.length; i++) {\r\n                    const f = parseRow(rowStrings[i]);\r\n                    if (!f.length) continue;\r\n\r\n                    const name = (f[0] || \"\").trim();\r\n                    const gainDb = parseFloat(f[1]);\r\n                    const vol = parseFloat(f[2]);\r\n                    const src = (f[3] || \"\").trim();\r\n\r\n                    defs.push({\r\n                        name: name ? name.toUpperCase() : \"\",\r\n                        gainDb: isFinite(gainDb) ? gainDb : null,\r\n                        vol: isFinite(vol) ? vol : null,\r\n                        src: src ? src.toUpperCase() : \"\",\r\n                        mute: (f.length > 4) ? toBool(f[4]) : null,\r\n                        solo: (f.length > 5) ? toBool(f[5]) : null,\r\n                        arm: (f.length > 6) ? toBool(f[6]) : null\r\n                    });\r\n                }\r\n                return defs;\r\n            }\r\n\r\n\r\n            const CVX_DATAFILES = (function() {\r\n                const raw = css.str(\"--cvx-oled-datafiles\", css.str(\"--cvx-oled-datafile\", \"\"));\r\n                return parseCssUrlList(raw);\r\n            })();\r\n\r\n            const CVX_DATAFILE_HOTKEYS = !!css.bool(\"--cvx-oled-datafile-hotkeys\", 1);\r\n            const CVX_DATAFILE_HK_DIGIT0 = clampi(css.int(\"--cvx-oled-datafile-hotkey-digit0-index\", 0), 0, 9999);\r\n            const CVX_DATAFILE_HK_CLEAR = (css.str(\"--cvx-oled-datafile-hotkey-clear\", \"-\") || \"-\").trim() || \"-\";\r\n            const CVX_HK_RESET = (css.str(\"--cvx-oled-hotkey-reset\", \"*\") || \"*\").trim() || \"*\";\r\n            const CVX_HK_VERSION = (css.str(\"--cvx-oled-hotkey-version\", \"V\") || \"V\").trim() || \"V\";\r\n            const CVX_DATAFILE_AUTO_ON = !!css.bool(\"--cvx-oled-datafile-autoload-on-init\", 1);\r\n            const CVX_DATAFILE_AUTO_IDX = clampi(css.int(\"--cvx-oled-datafile-autoload-index\", 0), -1, 9999);\r\n            const CVX_DATAFILE_AUTO_TR = clampi(css.int(\"--cvx-oled-datafile-autoload-track\", 0), -1, 9999);\r\n            const CVX_DATAFILE_AUTO_ALL_DEMO = !!css.bool(\"--cvx-oled-datafile-autoload-all-tracks-demo\", 1);\r\n\r\n            const CVX_DEMO_FALLBACK_URL = \"\/wp-content\/uploads\/2026\/02\/sample-data1.txt\";\r\n\r\n            function datafilePool() {\r\n                \/\/ In DEMO, keep a sane fallback so the widget stays \u201calive\u201d even without CSS list.\r\n                if (CVX_DATAFILES.length) return CVX_DATAFILES;\r\n                return CVX_DEMO_MODE ? [CVX_DEMO_FALLBACK_URL] : [];\r\n            }\r\n\r\n            function datafileUrlByIndex(idx) {\r\n                const pool = datafilePool();\r\n                if (idx < 0 || idx >= pool.length) return \"\";\r\n                return pool[idx];\r\n            }\r\n\r\n            function clearTrackDatafile(ti) {\r\n                if (!tracks.length) return;\r\n                ti = clampi(ti | 0, 0, tracks.length - 1);\r\n\r\n                const tr = tracks[ti];\r\n                tr.aud = null;\r\n                tr.fileIdx = -1;\r\n                tr.dataUrl = \"\";\r\n\r\n                if (!CVX_DEMO_MODE && css.bool(\"--cvx-oled-datafile-clear-removes-clips\", 1)) {\r\n                    \/\/ NORMAL: optional clip reset on clear\r\n                    tr.clips = [];\r\n                }\r\n                setHud(\"CLR\", 500);\r\n                pokeChrome();\r\n            }\r\n\r\n            async function assignDataFileToTrack(ti, fileIdx, opts) {\r\n                if (!tracks.length) return;\r\n                opts = opts || {};\r\n                const replaceClips = (\"replaceClips\" in opts) ? !!opts.replaceClips : (!CVX_DEMO_MODE && !!css.bool(\"--cvx-oled-datafile-assign-replaces-clips\", 1));\r\n                const keepPlayhead = (\"keepPlayhead\" in opts) ? !!opts.keepPlayhead : false;\r\n                const hudOn = (\"hud\" in opts) ? !!opts.hud : true;\r\n                ti = clampi(ti | 0, 0, tracks.length - 1);\r\n\r\n                fileIdx = fileIdx | 0;\r\n\r\n                const url = datafileUrlByIndex(fileIdx);\r\n                if (!url) {\r\n                    setHud(\"NO FILE\", 750);\r\n                    return;\r\n                }\r\n\r\n                try {\r\n                    const res = await fetch(url, {\r\n                        cache: \"no-store\"\r\n                    });\r\n                    if (!res.ok) throw new Error(\"HTTP \" + res.status);\r\n                    const txt = await res.text();\r\n\r\n                    const samples = parseAudacityTxtToFloat32(txt);\r\n                    if (!samples || !samples.length) throw new Error(\"EMPTY\");\r\n\r\n                    const sr = clampi(css.int(\"--cvx-oled-datafile-sr\", 1000), 1, 192000);\r\n                    const loop = !!CVX_DEMO_MODE; \/\/ DEMO needs looping to keep clips alive\r\n                    const aud = makeAudFromSamples(samples, sr, loop);\r\n\r\n                    const tr = tracks[ti];\r\n\r\n                    \/\/ overwrite previous assignment (requested behavior)\r\n                    tr.aud = aud;\r\n                    tr.fileIdx = fileIdx;\r\n                    tr.dataUrl = url;\r\n\r\n                    if (!CVX_DEMO_MODE && replaceClips) {\r\n                        \/* NORMAL: optionally replace clips with a single full-duration clip *\/\r\n                        const dur = (aud.mono.length \/ Math.max(1, (aud.sr || 44100)));\r\n                        tr.clips = [{\r\n                            id: allocClipId(),\r\n                            s: 0,\r\n                            e: dur,\r\n                            o: 0,\r\n                            a: 1,\r\n                            fx: [],\r\n                            fi: false,\r\n                            fo: false,\r\n                            m: []\r\n                        }];\r\n\r\n                        playhead = 0;\r\n                        viewStart = 0;\r\n                        ensureView();\r\n                    }\r\n\r\n                    setHud(\"LOAD \" + (fileIdx + 1), 750);\r\n                    pokeChrome();\r\n                    if (css.bool(\"--cvx-oled-zoomx-fit-on-load\", 1)) {\r\n                        const dur = trackEndSeconds(ti);\r\n                        if (dur > 0) {\r\n                            fitZoomXToSeconds(dur);\r\n                            viewStart = 0;\r\n                            ensureView();\r\n                        }\r\n                    }\r\n                } catch (err) {\r\n                    console.warn(\"[DATAFILE] load failed\", url, err);\r\n                    setHud(\"LOAD ERR\", 750);\r\n                }\r\n            }\r\n            \/* -------------------------------------------------------\r\n               Datafile: load ONLY audio into track (no clips, no seek)\r\n               - Used by REC autoload to avoid side effects.\r\n            ------------------------------------------------------- *\/\r\n            async function loadDatafileAudioOnly(ti, fileIdx) {\r\n                if (!tracks.length) return false;\r\n                ti = clampi(ti | 0, 0, tracks.length - 1);\r\n                fileIdx = fileIdx | 0;\r\n\r\n                const pool = datafilePool();\r\n                if (!pool.length) return false;\r\n\r\n                fileIdx = clampi(fileIdx, 0, pool.length - 1);\r\n                const url = datafileUrlByIndex(fileIdx);\r\n                if (!url) return false;\r\n\r\n                try {\r\n                    const res = await fetch(url, {\r\n                        cache: \"no-store\"\r\n                    });\r\n                    if (!res.ok) throw new Error(\"HTTP \" + res.status);\r\n                    const txt = await res.text();\r\n\r\n                    const samples = parseAudacityTxtToFloat32(txt);\r\n                    if (!samples || !samples.length) throw new Error(\"EMPTY\");\r\n\r\n                    const sr = clampi(css.int(\"--cvx-oled-datafile-sr\", 1000), 1, 192000);\r\n                    const loop = !!CVX_DEMO_MODE; \/* DEMO: loop to keep it \u201calive\u201d *\/\r\n                    const aud = makeAudFromSamples(samples, sr, loop);\r\n\r\n                    const tr = tracks[ti];\r\n                    tr.aud = aud;\r\n                    tr.fileIdx = fileIdx;\r\n                    tr.dataUrl = url;\r\n\r\n                    return true;\r\n                } catch (err) {\r\n                    console.warn(\"[REC-AUDIO] load failed\", url, err);\r\n                    return false;\r\n                }\r\n            }\r\n\r\n            \/* -------------------------------------------------------\r\n               Autoload datafile on init (DEMO or NORMAL)\r\n            ------------------------------------------------------- *\/\r\n            function autoloadDatafiles() {\r\n                if (!CVX_DATAFILE_AUTO_ON) return;\r\n                if (CVX_DATAFILE_AUTO_IDX < 0) return;\r\n                if (!tracks.length) return;\r\n\r\n                const pool = datafilePool();\r\n                if (!pool.length) return;\r\n\r\n                const idx = clampi(CVX_DATAFILE_AUTO_IDX, 0, pool.length - 1);\r\n\r\n                if (CVX_DEMO_MODE && CVX_DATAFILE_AUTO_ALL_DEMO) {\r\n                    for (let ti = 0; ti < tracks.length; ti++) {\r\n                        assignDataFileToTrack(ti, idx);\r\n                    }\r\n                    return;\r\n                }\r\n\r\n                let ti = CVX_DATAFILE_AUTO_TR;\r\n                if (ti < 0) ti = activeTrack;\r\n                ti = clampi(ti, 0, tracks.length - 1);\r\n\r\n                assignDataFileToTrack(ti, idx);\r\n            }\r\n\r\n            autoloadDatafiles();\r\n\r\n            const master = {\r\n                vol: 78,\r\n                mute: false\r\n            };\r\n\r\n            let zoomX = 2; \/* 0..12 (ver timelineSpan()) *\/\r\n\r\n            \/* zoomY es un \u00cdNDICE (0..2) hacia zoomYMap. La variable CSS se expresa como 1|2|4. *\/\r\n            const zoomYMap = [1, 2, 4];\r\n            let zoomY = css.int(\"--cvx-oled-zoomy-default\", 1); \/* allowed: 1|2|4 *\/\r\n            zoomY = (zoomY === 4) ? 2 : (zoomY === 2 ? 1 : 0);\r\n\r\n\r\n            \/* =========================================================\r\n               WAVE VERTICAL ZOOM (DISPLAY GAIN) \u2014 en dB\r\n               0 dB = 1.0x, +6 dB \u2248 2.0x, +12 dB \u2248 4.0x\r\n               (NO altera el audio, solo la visualizaci\u00f3n)\r\n               ========================================================= *\/\r\n            let waveZoomDb = 0;\r\n            const WAVE_ZOOM_DB_MIN = -24;\r\n            const WAVE_ZOOM_DB_MAX = +24;\r\n\r\n            function waveZoomMul() {\r\n                return Math.pow(10, waveZoomDb \/ 20);\r\n            }\r\n\r\n\r\n            let viewStart = 0;\r\n            let playhead = 12;\r\n\r\n            let isPlaying = false;\r\n            let isRecording = false;\r\n            let isLooping = false;\r\n\r\n            let trackTop = 0;\r\n            let activeTrack = tracks.length ? 0 : -1;\r\n            let multiSel = tracks.length ? new Set([0]) : new Set(); \/* max 2 *\/\r\n\r\n\r\n\r\n            let selection = null; \/* {s,e, tracks:Set} *\/\r\n\r\n            \/* -------------------------------------------------------\r\n               RETAKE REGIONS (persistent)\r\n               - Stored as timeline ranges {a,b}\r\n               - Not cleared by ESC (ESC only clears selection)\r\n               - Deleted only via Edit menu: \"DELETE RETAKE\" when cursor is inside\r\n            ------------------------------------------------------- *\/\r\n            const retakes = []; \/* [{a:number,b:number}] *\/\r\n\r\n            function retakeFindAt(t) {\r\n                t = +t || 0;\r\n                for (let i = retakes.length - 1; i >= 0; i--) { \/\/ last wins (most recent)\r\n                    const r = retakes[i];\r\n                    if (!r) continue;\r\n                    if (t >= r.a && t <= r.b) return {\r\n                        i,\r\n                        a: r.a,\r\n                        b: r.b\r\n                    };\r\n                }\r\n                return null;\r\n            }\r\n\r\n            function retakeAddFromSelection(sel) {\r\n                if (!sel) return false;\r\n                let a = Math.min(sel.s, sel.e);\r\n                let b = Math.max(sel.s, sel.e);\r\n                if (!(b > a + 0.0005)) return false;\r\n\r\n                \/\/ clamp to content timeline (not padded)\r\n                const maxT = timelineMaxSecondsAll();\r\n                a = clamp(a, 0, maxT);\r\n                b = clamp(b, 0, maxT);\r\n\r\n                \/\/ merge overlaps \/ touching (small epsilon)\r\n                const eps = 0.01;\r\n                let na = a,\r\n                    nb = b;\r\n\r\n                for (let i = retakes.length - 1; i >= 0; i--) {\r\n                    const r = retakes[i];\r\n                    if (!r) continue;\r\n                    if (nb < r.a - eps || na > r.b + eps) continue;\r\n                    na = Math.min(na, r.a);\r\n                    nb = Math.max(nb, r.b);\r\n                    retakes.splice(i, 1);\r\n                }\r\n\r\n                retakes.push({\r\n                    a: na,\r\n                    b: nb\r\n                });\r\n                retakes.sort((x, y) => x.a - y.a);\r\n                return true;\r\n            }\r\n\r\n            function retakeDeleteAtPlayhead() {\r\n                const hit = retakeFindAt(playhead);\r\n                if (!hit) return false;\r\n                retakes.splice(hit.i, 1);\r\n                return true;\r\n            }\r\n\r\n            function stripTrackClipsInRange(ti, a, b) {\r\n                if (ti < 0 || ti >= tracks.length) return;\r\n                const tr = tracks[ti];\r\n                if (!tr || !tr.clips || !tr.clips.length) return;\r\n\r\n                let next = [];\r\n                for (const c of tr.clips) next.push(...sliceClipOutsideRegion(c, a, b));\r\n                tr.clips = normalizeClips(next);\r\n            }\r\n\r\n            \/* meters smoothing (resizable; tracks can be created up to --cvx-oled-tracks-max) *\/\r\n            let trMeter = new Float32Array(tracks.length);\r\n            let trPeak = new Float32Array(tracks.length);\r\n            let trPeakT = new Float32Array(tracks.length);\r\n\r\n            function resizeTrackMeterArrays(n) {\r\n                n = Math.max(0, n | 0);\r\n                if (trMeter.length === n) return;\r\n\r\n                const a = new Float32Array(n);\r\n                const b = new Float32Array(n);\r\n                const c = new Float32Array(n);\r\n\r\n                a.set(trMeter.subarray(0, Math.min(n, trMeter.length)));\r\n                b.set(trPeak.subarray(0, Math.min(n, trPeak.length)));\r\n                c.set(trPeakT.subarray(0, Math.min(n, trPeakT.length)));\r\n\r\n                trMeter = a;\r\n                trPeak = b;\r\n                trPeakT = c;\r\n            }\r\n\r\n\r\n            \/* -------------------------------------------------------\r\n               Track factory (for future UI buttons)\r\n               - Respects --cvx-oled-tracks-max\r\n               - Starts empty in NORMAL (no clips) until you assign a datafile\/audio\r\n            ------------------------------------------------------- *\/\r\n            function createTrack(opts) {\r\n                opts = opts || {};\r\n\r\n                if (tracks.length >= CVX_TRACKS_MAX) {\r\n                    setHud(\"MAX TRK\", 750);\r\n                    return false;\r\n                }\r\n\r\n                const idx = tracks.length;\r\n\r\n                \/* defaults por \u00edndice (si existe fila) *\/\r\n                const d = (typeof trackDefaultsAt === \"function\") ? trackDefaultsAt(idx) : null;\r\n\r\n                function fmtName(tpl, i) {\r\n                    const n = i + 1;\r\n                    tpl = String(tpl || \"TRK {n}\");\r\n                    return tpl.replace(\/\\{n\\}\/g, String(n)).replace(\/\\{i\\}\/g, String(i)).toUpperCase();\r\n                }\r\n\r\n                const name = (opts.name != null && String(opts.name).trim()) ?\r\n                    String(opts.name).trim().toUpperCase() :\r\n                    ((d && d.name) ? String(d.name).toUpperCase() :\r\n                        fmtName(CVX_TR_DEF_NAME_TPL, idx));\r\n\r\n                const src = (opts.src != null && String(opts.src).trim()) ?\r\n                    String(opts.src).trim().toUpperCase() :\r\n                    ((d && d.src) ? String(d.src).toUpperCase() :\r\n                        String(CVX_TR_DEF_SRC || \"LINE_1-A\").toUpperCase());\r\n\r\n                const seed = (opts.seed != null) ? (opts.seed | 0) : (17 + idx * 13);\r\n\r\n                const gainDb = clamp(\r\n                    (opts.gainDb != null) ? Number(opts.gainDb) :\r\n                    ((d && d.gainDb != null) ? Number(d.gainDb) : Number(CVX_TR_DEF_GAIN_DB)),\r\n                    -60, 24\r\n                );\r\n\r\n                const vol = clamp(\r\n                    (opts.vol != null) ? Number(opts.vol) :\r\n                    ((d && d.vol != null) ? Number(d.vol) : Number(CVX_TR_DEF_VOL)),\r\n                    0, 100\r\n                );\r\n\r\n                const mute = (opts.mute != null) ? !!opts.mute : ((d && d.mute != null) ? !!d.mute : !!CVX_TR_DEF_MUTE);\r\n                const solo = (opts.solo != null) ? !!opts.solo : ((d && d.solo != null) ? !!d.solo : !!CVX_TR_DEF_SOLO);\r\n                const arm = (opts.arm != null) ? !!opts.arm : ((d && d.arm != null) ? !!d.arm : !!CVX_TR_DEF_ARM);\r\n\r\n                const tr = {\r\n                    name,\r\n                    src,\r\n\r\n                    clips: CVX_DEMO_MODE ? (function() {\r\n                        let clipId = __clipIdSeq;\r\n                        const clips = [];\r\n                        let t = 0;\r\n                        for (let i = 0; i < 5; i++) {\r\n                            t += 6 + ((seed * (i + 3)) % 7);\r\n                            const len = 10 + ((seed * (i + 5)) % 16);\r\n                            clips.push({\r\n                                id: clipId++,\r\n                                s: t,\r\n                                e: t + len,\r\n                                o: t,\r\n                                a: 0.5 + (((seed + i * 13) % 50) \/ 100),\r\n                                fx: [],\r\n                                fi: false,\r\n                                fo: false,\r\n                                m: []\r\n                            });\r\n                            t += len;\r\n                        }\r\n                        __clipIdSeq = clipId;\r\n                        return clips;\r\n                    })() : [],\r\n\r\n                    seed,\r\n                    mute,\r\n                    solo,\r\n                    arm,\r\n                    gainDb,\r\n                    vol,\r\n\r\n                    aud: null,\r\n                    fileIdx: -1,\r\n                    dataUrl: \"\"\r\n                };\r\n\r\n                tracks.push(tr);\r\n                resizeTrackMeterArrays(tracks.length);\r\n                reportTracks(\"track:add\");\r\n\r\n                activeTrack = idx;\r\n                multiSel = new Set([idx]);\r\n\r\n                setHud(\"TRK +\", 650);\r\n                pokeChrome();\r\n                return true;\r\n            }\r\n\r\n            function addTrack(loadData) {\r\n                const ok = createTrack({}); \/* crea solo config si NORMAL *\/\r\n                if (!ok) return;\r\n\r\n                const ti = tracks.length - 1;\r\n                activeTrack = ti;\r\n                multiSel = new Set([ti]);\r\n\r\n                if (loadData) {\r\n                    \/* usa \u00edndice de track como \u00edndice del pool *\/\r\n                    assignDataFileToTrack(ti, ti);\r\n                }\r\n                pokeChrome();\r\n            }\r\n\r\n            let masterL = 0,\r\n                masterR = 0;\r\n            let masterLP = 0,\r\n                masterRP = 0;\r\n            let masterLPt = 0,\r\n                masterRPt = 0;\r\n\r\n            \/* OUTPUT SELECTION (header label) *\/\r\n            const outputSel = {\r\n                type: \"AMPOUT\",\r\n                \/* AMPOUT | UB_EXP | B_EXP *\/\r\n                ports: [1, 2],\r\n                presets: [{\r\n                        type: \"UB_EXP\",\r\n                        ports: [1, 2, 3, 4]\r\n                    },\r\n                    {\r\n                        type: \"UB_EXP\",\r\n                        ports: [1, 2]\r\n                    },\r\n                    {\r\n                        type: \"B_EXP\",\r\n                        ports: [1, 2]\r\n                    },\r\n                    {\r\n                        type: \"B_EXP\",\r\n                        ports: [1]\r\n                    },\r\n                    {\r\n                        type: \"AMPOUT\",\r\n                        ports: [1, 2]\r\n                    },\r\n                    {\r\n                        type: \"AMPOUT\",\r\n                        ports: [1]\r\n                    },\r\n                    {\r\n                        type: \"AMPOUT\",\r\n                        ports: [2]\r\n                    }\r\n                ],\r\n                presetIdx: 4\r\n            };\r\n\r\n            function formatOutputSel(sel) {\r\n                const p = Array.isArray(sel.ports) ? sel.ports.slice().filter(n => Number.isFinite(n)).map(n => (n | 0)) : [];\r\n                const uniq = Array.from(new Set(p)).sort((a, b) => a - b);\r\n                const list = uniq.join(\"|\");\r\n                if (sel.type === \"UB_EXP\") return \"UBExp[\" + list + \"]\";\r\n                if (sel.type === \"B_EXP\") return \"BExp[\" + list + \"]\";\r\n                return \"Amp-Out[\" + list + \"]\";\r\n            }\r\n\r\n            function cycleOutputPreset(dir) {\r\n                const d = (dir == null ? 1 : dir) | 0;\r\n                outputSel.presetIdx = (outputSel.presetIdx + d + outputSel.presets.length) % outputSel.presets.length;\r\n                const p = outputSel.presets[outputSel.presetIdx];\r\n                outputSel.type = p.type;\r\n                outputSel.ports = p.ports.slice();\r\n                setHud(outLabel(), 650);\r\n                pokeChrome();\r\n            }\r\n\r\n            \/* HUD *\/\r\n            let hud = {\r\n                text: \"\",\r\n                until: 0\r\n            };\r\n\r\n            function setHud(text, ms) {\r\n                const hold = (ms != null) ? ms : (css.flt(\"--cvx-oled-hud-ms\", 850));\r\n                hud.text = String(text || \"\");\r\n                hud.until = performance.now() + hold;\r\n            }\r\n\r\n            \/* chrome auto-hide *\/\r\n            const chrome = {\r\n                target: 0,\r\n                v: 0,\r\n                hideAt: 0\r\n            };\r\n\r\n            function pokeChrome() {\r\n                const now = performance.now();\r\n                const hideMs = css.flt(\"--cvx-oled-chrome-hide-ms\", 900);\r\n                chrome.hideAt = now + hideMs;\r\n                chrome.target = 1;\r\n            }\r\n\r\n            \/* Edit menu *\/\r\n            const menu = {\r\n                open: false,\r\n                level: \"main\",\r\n                idx: 0,\r\n                anim: 0\r\n            };\r\n\r\n            function menuItems() {\r\n                if (menu.level === \"fx\") return [\"BACK\", \"CHOR\", \"DLY\", \"RVB\", \"EQ\", \"CMP\", \"CLR FX\"];\r\n                if (menu.level === \"fd\") return [\"BACK\", \"FD IN\", \"FD OUT\", \"XFAD\", \"CLR FD\"];\r\n                const rtLabel = (!selection && retakeFindAt(playhead)) ? \"DELETE RETAKE\" : \"RETAKE\";\r\n                return [\"EXIT\", \"SPLIT\", \"CUT\", \"DELETE\", rtLabel, \"FX>\", \"FD>\"];\r\n            }\r\n\r\n            function activateMenuSelection() {\r\n                const items = menuItems();\r\n                const it = items[clamp(menu.idx, 0, items.length - 1)];\r\n                if (!it) return;\r\n\r\n                if (it === \"EXIT\") {\r\n                    menu.open = false;\r\n                    return;\r\n                }\r\n                if (it === \"BACK\") {\r\n                    menu.level = \"main\";\r\n                    menu.idx = 0;\r\n                    return;\r\n                }\r\n                if (it === \"FX>\") {\r\n                    menu.level = \"fx\";\r\n                    menu.idx = 1;\r\n                    return;\r\n                }\r\n                if (it === \"FD>\") {\r\n                    menu.level = \"fd\";\r\n                    menu.idx = 1;\r\n                    return;\r\n                }\r\n\r\n                execAction(it);\r\n                menu.open = false;\r\n            }\r\n\r\n            \/* -------------------------------------------------------\r\n               CONFIG MENU (DEMO): Sync label only\r\n               0 = Local, 1 = Cloud\r\n            ------------------------------------------------------- *\/\r\n            let syncMode = 0;\r\n\r\n            function masterItems() {\r\n                const tr = (activeTrack >= 0 && activeTrack < tracks.length) ? tracks[activeTrack] : null;\r\n                if (tr) ensureTrackMeta(tr);\r\n\r\n                const syncTxt = syncMode ? \"Cloud\" : \"Local\";\r\n\r\n                return [{\r\n                        id: \"back\",\r\n                        label: \"BACK\"\r\n                    },\r\n\r\n                    \/* NO tocar: Master mute y volumen (se mantienen) *\/\r\n                    {\r\n                        id: \"m_mute\",\r\n                        label: master.mute ? \"MUTE:ON\" : \"MUTE:OFF\"\r\n                    },\r\n                    {\r\n                        id: \"m_volp\",\r\n                        label: \"VOL +\"\r\n                    },\r\n                    {\r\n                        id: \"m_volm\",\r\n                        label: \"VOL -\"\r\n                    },\r\n\r\n                    \/* NUEVO: Out preset label *\/\r\n                    {\r\n                        id: \"out\",\r\n                        label: \"Out: \" + outLabel()\r\n                    },\r\n\r\n                    \/* NUEVOS: Sync \/ Versions (demo) *\/\r\n                    {\r\n                        id: \"sync\",\r\n                        label: \"Sync: \" + syncTxt\r\n                    },\r\n                    {\r\n                        id: \"versions\",\r\n                        label: \"Versions\"\r\n                    },\r\n\r\n                    \/* NUEVOS: Src \/ Mon *\/\r\n                    {\r\n                        id: \"src\",\r\n                        label: \"Track Src\"\r\n                    },\r\n                    {\r\n                        id: \"mon\",\r\n                        label: \"Track Mon\"\r\n                    }\r\n                ];\r\n            }\r\n            \/* Master drawer *\/\r\n            const masterPanel = {\r\n                open: false,\r\n                idx: 0,\r\n                top: 0,\r\n                vis: 3,\r\n                anim: 0\r\n            };\r\n\r\n            \/* -------------------------------------------------------\r\n   VERSION POPUP (DEMO) \u2014 OLED 256\u00d764 overlay\r\n   - Modal: intercepts input while open\r\n   - Two screens: \"save\" and \"history\"\r\n------------------------------------------------------- *\/\r\n            const verPopup = {\r\n                open: false,\r\n                view: \"save\", \/\/ \"save\" | \"history\"\r\n                sel: 1, \/\/ bottom pills selection\r\n                toastUntil: 0,\r\n                toastTxt: \"\",\r\n                toastRight: \"\",\r\n                btns: [],\r\n\r\n                \/* history list *\/\r\n                hist: [{\r\n                        id: \"V03\",\r\n                        name: \"VERSE TAKE\"\r\n                    },\r\n                    {\r\n                        id: \"V02\",\r\n                        name: \"CHORUS DRAFT\"\r\n                    },\r\n                    {\r\n                        id: \"V01\",\r\n                        name: \"IDEA 01\"\r\n                    }\r\n                ],\r\n                hIdx: 0,\r\n                hTop: 0\r\n            };\r\n\r\n            function verOpen() {\r\n                verPopup.open = true;\r\n                verPopup.view = \"save\";\r\n                verPopup.sel = 1; \/\/ default focus: SAVE\r\n                verPopup.toastUntil = 0;\r\n                verPopup.toastTxt = \"\";\r\n\r\n                \/\/ keep modal clean (avoid competing overlays)\r\n                try {\r\n                    menu.open = false;\r\n                } catch (_) {}\r\n                try {\r\n                    masterPanel.open = false;\r\n                } catch (_) {}\r\n\r\n                pokeChrome();\r\n            }\r\n\r\n            function verClose() {\r\n                verPopup.open = false;\r\n                verPopup.view = \"save\";\r\n                verPopup.toastUntil = 0;\r\n                verPopup.toastTxt = \"\";\r\n                verPopup.btns.length = 0;\r\n                pokeChrome();\r\n            }\r\n\r\n            function verGoHistory() {\r\n                verPopup.view = \"history\";\r\n                verPopup.sel = 1; \/\/ default focus: OK\r\n                verPopup.hIdx = 0;\r\n                verPopup.hTop = 0;\r\n\r\n                \/\/ guarantee at least 2 entries\r\n                if (!Array.isArray(verPopup.hist) || verPopup.hist.length < 2) {\r\n                    verPopup.hist = [{\r\n                            id: \"V03\",\r\n                            name: \"VERSE TAKE\"\r\n                        },\r\n                        {\r\n                            id: \"V02\",\r\n                            name: \"CHORUS DRAFT\"\r\n                        }\r\n                    ];\r\n                }\r\n\r\n                pokeChrome();\r\n            }\r\n\r\n            function verBackToSave() {\r\n                verPopup.view = \"save\";\r\n                verPopup.sel = 1; \/\/ default focus: SAVE\r\n                pokeChrome();\r\n            }\r\n\r\n            function verDoSave() {\r\n                const raw = (css.str(\"--cvx-oled-ver-name\", \"V03\") || \"V03\").trim();\r\n                const m = raw.match(\/V\\d+\/i);\r\n                const id = (m ? m[0] : \"V00\").toUpperCase();\r\n                const nm = raw.replace(\/^\\s*V\\d+\\s*\/i, \"\").trim().toUpperCase() || \"TAKE\";\r\n\r\n                const ms = clampi(css.int(\"--cvx-oled-ver-toast-ms\", 820), 300, 2000);\r\n\r\n                \/\/ update history (unique by id, newest first)\r\n                if (!Array.isArray(verPopup.hist)) verPopup.hist = [];\r\n                verPopup.hist = verPopup.hist.filter(it => String(it.id).toUpperCase() !== id);\r\n                verPopup.hist.unshift({\r\n                    id,\r\n                    name: nm\r\n                });\r\n                if (verPopup.hist.length < 2) verPopup.hist.push({\r\n                    id: \"V02\",\r\n                    name: \"CHORUS DRAFT\"\r\n                });\r\n\r\n                verPopup.toastTxt = (\"SAVED: \" + id).toUpperCase();\r\n                verPopup.toastRight = (css.str(\"--cvx-oled-ver-toast-right\", \"HISTORY UPDATED\") || \"HISTORY UPDATED\").toUpperCase();\r\n                verPopup.toastUntil = performance.now() + ms;\r\n\r\n                try {\r\n                    setHud(\"SAVED\", 350);\r\n                } catch (_) {}\r\n\r\n                pokeChrome();\r\n            }\r\n\r\n            function verActivateSelection() {\r\n                if (verPopup.view === \"save\") {\r\n                    \/\/ [BACK] [SAVE] [HISTORY]\r\n                    if (verPopup.sel === 0) return verClose();\r\n                    if (verPopup.sel === 1) return verDoSave();\r\n                    if (verPopup.sel === 2) return verGoHistory();\r\n                    return;\r\n                }\r\n\r\n                \/\/ history: [BACK] [OK]\r\n                if (verPopup.sel === 0) return verBackToSave();\r\n                if (verPopup.sel === 1) return verBackToSave(); \/\/ spec: OK returns to A (save screen) or closes\r\n            }\r\n\r\n            \/* --- drawing helpers (exact px, no HTML layout) --- *\/\r\n            function __tw6(s) {\r\n                return (String(s || \"\").length | 0) * 6;\r\n            }\r\n\r\n            function __tw7(s) {\r\n                return (String(s || \"\").length | 0) * 6;\r\n            } \/\/ 5x7 font still uses 6px advance here\r\n            function __trunc(s, maxChars) {\r\n                s = String(s || \"\");\r\n                if ((s.length | 0) <= (maxChars | 0)) return s;\r\n                if (maxChars <= 3) return s.slice(0, maxChars);\r\n                return s.slice(0, maxChars - 3) + \"...\";\r\n            }\r\n\r\n            \/* ---------------------------------------------------------\r\n               Overflow label marquee (menus)\r\n               - Default: animates ONLY the focused row\r\n               - Uses X-clipped AA text to avoid bleeding into borders\r\n               --------------------------------------------------------- *\/\r\n            function __marqueeOffsetMs(tMs, spanPx, speedPxPerS, holdMs, pingpong) {\r\n                const span = Math.max(0, spanPx || 0);\r\n                if (span <= 0) return 0;\r\n\r\n                const v = Math.max(1e-3, (speedPxPerS || 0) \/ 1000); \/\/ px\/ms\r\n                const dur = span \/ v;\r\n                const hold = Math.max(0, holdMs || 0);\r\n\r\n                if (!pingpong) {\r\n                    const T = hold + dur + 1e-6;\r\n                    const p = (tMs % T);\r\n                    if (p < hold) return 0;\r\n                    return Math.min(span, (p - hold) * v);\r\n                }\r\n\r\n                const T = hold + dur + hold + dur + 1e-6;\r\n                let p = (tMs % T);\r\n                if (p < hold) return 0;\r\n                p -= hold;\r\n                if (p < dur) return Math.min(span, p * v);\r\n                p -= dur;\r\n                if (p < hold) return span;\r\n                p -= hold;\r\n                return Math.max(0, span - p * v);\r\n            }\r\n\r\n            function __drawMenuItemLabel(ras, x, y, label, fg, aa, clipW, idx, isActive) {\r\n                const w = Math.max(1, clipW | 0);\r\n\r\n                \/* Params (optional overrides via CSS vars) *\/\r\n                const mOn = css.bool(\"--cvx-oled-menu-marquee-on\", 1);\r\n                const mAll = css.bool(\"--cvx-oled-menu-marquee-all\", 0);\r\n                const pingpong = css.bool(\"--cvx-oled-menu-marquee-pingpong\", 1);\r\n                const speed = clamp(css.flt(\"--cvx-oled-menu-marquee-speed\", 28), 6, 140); \/\/ px\/s\r\n                const hold = clamp(css.flt(\"--cvx-oled-menu-marquee-hold\", 260), 0, 1200); \/\/ ms\r\n\r\n                const textW = __tw7(label);\r\n                const overflow = textW - w;\r\n\r\n                const canAnim = mOn && overflow > 0 && (mAll || !!isActive);\r\n                if (!canAnim) {\r\n                    const maxChars = Math.max(1, Math.floor(w \/ 6));\r\n                    let s = label;\r\n                    if (s.length > maxChars) s = s.slice(0, Math.max(1, maxChars - 1)) + \"\u2026\";\r\n                    ras.textBlendAA(x, y, s, fg, aa);\r\n                    return;\r\n                }\r\n\r\n                \/* Stable per-row phase offset (avoids \u201cperfect sync\u201d if mAll=1) *\/\r\n                const seed = ((idx | 0) * 1337) | 0;\r\n                const tMs = (uiNowMs + seed) | 0;\r\n                const off = Math.round(__marqueeOffsetMs(tMs, overflow, speed, hold, pingpong));\r\n\r\n                ras.textBlendAAClip(x - off, y, label, fg, aa, x, x + w);\r\n            }\r\n\r\n            function __strokeRect1(x, y, w, h, v) {\r\n                x |= 0;\r\n                y |= 0;\r\n                w |= 0;\r\n                h |= 0;\r\n                if (w <= 1 || h <= 1) return;\r\n                ras.fillRect(x, y, w, 1, v);\r\n                ras.fillRect(x, (y + h - 1) | 0, w, 1, v);\r\n                ras.fillRect(x, y, 1, h, v);\r\n                ras.fillRect((x + w - 1) | 0, y, 1, h, v);\r\n            }\r\n\r\n            function __fillDither2(x, y, w, h, a, b) {\r\n                x |= 0;\r\n                y |= 0;\r\n                w |= 0;\r\n                h |= 0;\r\n                a |= 0;\r\n                b |= 0;\r\n                const x1 = (x + w) | 0,\r\n                    y1 = (y + h) | 0;\r\n                for (let yy = y; yy < y1; yy++) {\r\n                    for (let xx = x; xx < x1; xx++) {\r\n                        ras.px(xx, yy, ((xx ^ yy) & 1) ? b : a);\r\n                    }\r\n                }\r\n            }\r\n\r\n            function drawVersionPopup(dt, aa) {\r\n                if (!verPopup.open) return;\r\n\r\n                const W0 = W | 0,\r\n                    H0 = H | 0;\r\n                aa = clamp((aa == null ? css.flt(\"--cvx-oled-aa\", 0.62) : aa), 0, 0.85);\r\n\r\n                \/* PARAMETERS *\/\r\n                const px = clampi(css.int(\"--cvx-oled-ver-x\", 8), 0, W0 - 2);\r\n                const py = clampi(css.int(\"--cvx-oled-ver-y\", 5), 0, H0 - 2);\r\n                const pw = clampi(css.int(\"--cvx-oled-ver-w\", 240), 40, W0 - px);\r\n                const ph = clampi(css.int(\"--cvx-oled-ver-h\", 54), 30, H0 - py);\r\n\r\n                const topH = clampi(css.int(\"--cvx-oled-ver-top-h\", 12), 8, 18);\r\n                const botH = clampi(css.int(\"--cvx-oled-ver-bot-h\", 12), 8, 18);\r\n                const pad = clampi(css.int(\"--cvx-oled-ver-pad\", 8), 2, 20);\r\n                const gap = clampi(css.int(\"--cvx-oled-ver-gap\", 2), 0, 8);\r\n\r\n                const dimK = clamp(css.flt(\"--cvx-oled-ver-dim\", 0.55), 0, 1);\r\n\r\n                \/* SSOT COLORS *\/\r\n                const boxBg = clampi(css.int(\"--cvx-oled-ver-box-bg\", 40), 0, 255);\r\n                const boxBr = clampi(css.int(\"--cvx-oled-ver-box-br\", 80), 0, 255);\r\n                const ink = clampi(css.int(\"--cvx-oled-ver-ink\", 255), 0, 255);\r\n                const inkSub = clampi(css.int(\"--cvx-oled-ver-ink-sub\", 100), 0, 255);\r\n\r\n                \/* RADII *\/\r\n                const rOut = clampi(css.int(\"--cvx-oled-ver-radius\", 10), 1, 14);\r\n                const rBox = clampi(css.int(\"--cvx-oled-ver-box-radius\", 8), 1, 12);\r\n\r\n                \/* BUTTONS *\/\r\n                const btnPadX = clampi(css.int(\"--cvx-oled-ver-btn-pad-x\", 7), 2, 16);\r\n                const btnPadY = clampi(css.int(\"--cvx-oled-ver-btn-pad-y\", 3), 1, 10);\r\n                const gapX = clampi(css.int(\"--cvx-oled-ver-btn-gap-x\", 6), 0, 14);\r\n                const align = clampi(css.int(\"--cvx-oled-ver-btn-align\", 1), 0, 2);\r\n                const rPill = clampi(css.int(\"--cvx-oled-ver-pill-radius\", 999), 1, 999);\r\n\r\n                \/* TOAST *\/\r\n                const toastA = clamp(css.flt(\"--cvx-oled-ver-toast-a\", 0.72), 0, 1);\r\n\r\n                \/* BACKGROUND DIM (mulRect expects 0..1) *\/\r\n                if (dimK > 0.001) ras.mulRect(0, 0, W0, H0, 1 - dimK);\r\n\r\n                \/* OUTER CARD (titles live here) *\/\r\n                ras.blendRoundRectAA(px, py, pw, ph, rOut, 0, 0.80, boxBr, 1.00);\r\n\r\n                \/* TOP BAR (boxed: title + tag) *\/\r\n                const headPadX = clampi(css.int(\"--cvx-oled-ver-head-pad-x\", 8), 0, 20);\r\n                const headPadY = clampi(css.int(\"--cvx-oled-ver-head-pad-y\", 3), 0, 10);\r\n\r\n                const headX = (px + pad) | 0;\r\n                const headY = (py + 2) | 0;\r\n                const headW = clampi((pw - pad * 2) | 0, 20, pw);\r\n                const headH = clampi((topH - 3) | 0, 8, topH);\r\n\r\n                ras.blendRoundRectAA(headX, headY, headW, headH, rBox, boxBg, 1.00, boxBr, 1.00);\r\n\r\n                const title = (verPopup.view === \"save\") ? \"SAVE VERSION\" : \"VERSIONS\";\r\n                const tag = (verPopup.view === \"save\") ?\r\n                    (css.str(\"--cvx-oled-ver-tag\", \"NEW\") || \"NEW\").toUpperCase() :\r\n                    (css.str(\"--cvx-oled-ver-history-tag\", \"HISTORY\") || \"HISTORY\").toUpperCase();\r\n\r\n                const ty = (headY + ((headH - 7) >> 1)) | 0;\r\n                ras.textAA((headX + headPadX) | 0, ty, title, ink, aa);\r\n\r\n                const tagW = __tw6(tag);\r\n                ras.textAA(((headX + headW - headPadX - tagW) | 0), ty, tag, inkSub, aa);\r\n\r\n                \/* MID BOX (rounded, bg=40, br=80) *\/\r\n                const midX = (px + pad) | 0;\r\n                const midY = (py + topH + gap) | 0;\r\n                const midW = clampi((pw - pad * 2) | 0, 40, pw);\r\n                const midH = clampi((ph - topH - botH - gap * 2) | 0, 10, ph);\r\n\r\n                ras.blendRoundRectAA(midX, midY, midW, midH, rBox, boxBg, 1.00, boxBr, 1.00);\r\n\r\n\r\n\r\n                if (verPopup.view === \"save\") {\r\n                    const name = (css.str(\"--cvx-oled-ver-name\", \"V03  VERSE TAKE\") || \"\").toUpperCase();\r\n                    const note = (css.str(\"--cvx-oled-ver-note\", \"TIGHT TIMING\") || \"\").toUpperCase();\r\n\r\n                    const lx = (midX + 6) | 0;\r\n                    const y1 = (midY + 6) | 0;\r\n                    const y2 = (midY + 16) | 0;\r\n\r\n                    ras.textAA6(lx, y1, \"NAME:\", inkSub, aa);\r\n                    ras.textAA6(lx, y2, \"NOTE:\", inkSub, aa);\r\n\r\n                    const valX = (lx + __tw6(\"NAME:\") + 6) | 0;\r\n\r\n                    \/\/ avoid colliding with the right hint on the first row\r\n                    const maxRight1 = (midX + midW - 6) | 0;\r\n                    const maxChars1 = clampi(((maxRight1 - valX) \/ 6) | 0, 0, 80);\r\n                    const maxChars2 = clampi((((midX + midW - 6) - valX) \/ 6) | 0, 0, 80);\r\n\r\n                    ras.textAA(valX, y1 - 1, __trunc(name, maxChars1), ink, aa);\r\n                    ras.textAA(valX, y2 - 1, __trunc(note, maxChars2), ink, aa);\r\n\r\n                } else {\r\n                    \/\/ HISTORY: vertical list, scrollable\r\n                    const hist = Array.isArray(verPopup.hist) ? verPopup.hist : [];\r\n                    const rowH = 9;\r\n                    const padY = 5;\r\n                    const listX = (midX + 6) | 0;\r\n                    const listY = (midY + padY) | 0;\r\n                    const listW = clampi((midW - 12) | 0, 20, midW);\r\n\r\n                    const vis = Math.max(2, ((midH - (padY * 2)) \/ rowH) | 0);\r\n\r\n                    for (let i = 0; i < vis; i++) {\r\n                        const idx = (verPopup.hTop + i) | 0;\r\n                        if (idx < 0 || idx >= hist.length) break;\r\n\r\n                        const it = hist[idx];\r\n                        const isSel = (idx === (verPopup.hIdx | 0));\r\n\r\n                        const ry = (listY + i * rowH) | 0;\r\n\r\n                        if (isSel) {\r\n                            ras.fillRect(listX - 2, ry - 1, listW + 4, rowH, boxBr);\r\n                        }\r\n\r\n                        const s = (String(it.id || \"\") + \"  \" + String(it.name || \"\")).toUpperCase();\r\n                        const maxChars = clampi((listW \/ 6) | 0, 1, 80);\r\n                        ras.textAA6(listX, ry, __trunc(s, maxChars), isSel ? ink : inkSub, aa);\r\n                    }\r\n                }\r\n\r\n                \/* BOTTOM PILLS *\/\r\n                const botY = (py + ph - botH) | 0;\r\n\r\n                const labels = (verPopup.view === \"save\") ? [\"BACK\", \"SAVE\", \"HISTORY\"] : [\"BACK\", \"OK\"];\r\n                const pillH = clampi((6 + btnPadY * 2) | 0, 8, 14);\r\n                const pillY = (botY + ((botH - pillH) >> 1)) | 0;\r\n\r\n                \/\/ measure widths\r\n                let totalW = 0;\r\n                const widths = [];\r\n                for (let i = 0; i < labels.length; i++) {\r\n                    const bw = clampi(__tw6(labels[i]) + (btnPadX * 2), 24, 140);\r\n                    widths.push(bw);\r\n                    totalW += bw;\r\n                    if (i) totalW += gapX;\r\n                }\r\n\r\n                let bx;\r\n                if (align === 0) bx = (px + pad) | 0;\r\n                else if (align === 2) bx = (px + pw - pad - totalW) | 0;\r\n                else bx = (px + ((pw - totalW) >> 1)) | 0;\r\n\r\n                verPopup.btns.length = 0;\r\n\r\n                for (let i = 0; i < labels.length; i++) {\r\n                    const bw = widths[i] | 0;\r\n                    const isSel = (i === (verPopup.sel | 0));\r\n                    const rr = clampi(rPill, 1, (pillH >> 1) | 0);\r\n\r\n                    \/\/ outline always, fill only if selected\r\n                    ras.blendRoundRectAA(\r\n                        bx, pillY, bw, pillH, rr,\r\n                        isSel ? boxBg : 0,\r\n                        isSel ? 1.00 : 0.00,\r\n                        boxBr,\r\n                        1.00\r\n                    );\r\n\r\n                    const tx = (bx + ((bw - __tw6(labels[i])) >> 1)) | 0;\r\n                    const ty6 = (pillY + ((pillH - 6) >> 1)) | 0;\r\n\r\n                    ras.textAA6(tx, ty6, labels[i], isSel ? ink : inkSub, aa);\r\n\r\n                    verPopup.btns.push({\r\n                        x: bx,\r\n                        y: pillY,\r\n                        w: bw,\r\n                        h: pillH\r\n                    });\r\n                    bx = (bx + bw + gapX) | 0;\r\n                }\r\n\r\n                \/* WIDE TOAST (like mock) *\/\r\n                const now = performance.now();\r\n                if (verPopup.toastUntil && now < verPopup.toastUntil && verPopup.toastTxt) {\r\n                    const tPadX = clampi(css.int(\"--cvx-oled-ver-toast-pad-x\", 10), 0, 24);\r\n                    const tPadY = clampi(css.int(\"--cvx-oled-ver-toast-pad-y\", 4), 0, 12);\r\n\r\n                    const th = clampi((6 + tPadY * 2) | 0, 10, 22); \/\/ 6px textAA6 height + padding\r\n                    const tx = (px + pad) | 0;\r\n                    const tw = clampi((pw - pad * 2) | 0, 40, pw);\r\n                    const ty = (botY - th - 2) | 0;\r\n\r\n                    ras.blendRoundRectAA(tx, ty, tw, th, 6, 0, toastA, boxBr, 1.00);\r\n\r\n                    const left = String(verPopup.toastTxt || \"\").toUpperCase();\r\n                    const right = String(verPopup.toastRight || \"\").toUpperCase();\r\n\r\n                    const tTextY = (ty + ((th - 6) >> 1)) | 0;\r\n\r\n                    ras.textAA6((tx + tPadX) | 0, tTextY, left, ink, aa);\r\n                    const rw = __tw6(right);\r\n                    ras.textAA6(((tx + tw - tPadX - rw) | 0), tTextY, right, inkSub, aa);\r\n                }\r\n            }\r\n            \/* -------------------------------------------------------\r\n            BOOT SNAPSHOT (for hard reset)\r\n            ------------------------------------------------------- *\/\r\n            const __BOOT = {\r\n                master: {\r\n                    vol: master.vol,\r\n                    mute: master.mute\r\n                },\r\n                outputSel: {\r\n                    type: outputSel.type,\r\n                    ports: outputSel.ports.slice(),\r\n                    presetIdx: outputSel.presetIdx\r\n                },\r\n                zoomX: zoomX,\r\n                zoomY: zoomY,\r\n                waveZoomDb: waveZoomDb,\r\n                viewStart: viewStart,\r\n                playhead: playhead\r\n            };\r\n            \/* Track routing (for TRACK drawer items) *\/\r\n            const trackSel = {\r\n                src: [\"MIC_1\", \"MIC_2\", \"INST_1-A\", \"INST_1-B\", \"INST_2-A\", \"INST_2-B\", \"AUX-L\", \"AUX-R\"],\r\n                mon: [\"MAIN\", \"HP\"]\r\n            };\r\n\r\n            function outLabel() {\r\n                \/* placeholder: por ahora usa el formateo actual.\r\n                   cuando me pases el naming de presets lo reemplazamos ac\u00e1. *\/\r\n                return formatOutputSel(outputSel);\r\n            }\r\n\r\n            function ensureTrackMeta(tr) {\r\n                if (tr.__cvxSrcIdx == null) {\r\n                    const cur = String(tr.src || \"\").toUpperCase();\r\n                    const idx = trackSel.src.indexOf(cur);\r\n                    tr.__cvxSrcIdx = (idx >= 0) ? idx : 0;\r\n                    tr.src = trackSel.src[tr.__cvxSrcIdx];\r\n                }\r\n                if (tr.__cvxMonIdx == null) {\r\n                    const cur = String(tr.mon || \"\").toUpperCase();\r\n                    const idx = trackSel.mon.indexOf(cur);\r\n                    tr.__cvxMonIdx = (idx >= 0) ? idx : 0;\r\n                    tr.mon = trackSel.mon[tr.__cvxMonIdx];\r\n                }\r\n            }\r\n\r\n            function cycleTrackSrc(ti, dir) {\r\n                if (ti < 0 || ti >= tracks.length) {\r\n                    setHud(\"NO TRACK\", 450);\r\n                    return;\r\n                }\r\n                const tr = tracks[ti];\r\n                ensureTrackMeta(tr);\r\n                const d = (dir == null ? 1 : dir) | 0;\r\n                tr.__cvxSrcIdx = (tr.__cvxSrcIdx + d + trackSel.src.length) % trackSel.src.length;\r\n                tr.src = trackSel.src[tr.__cvxSrcIdx];\r\n                setHud(\"SRC \" + tr.src, 650);\r\n                pokeChrome();\r\n            }\r\n\r\n            function toggleTrackMon(ti) {\r\n                if (ti < 0 || ti >= tracks.length) {\r\n                    setHud(\"NO TRACK\", 450);\r\n                    return;\r\n                }\r\n                const tr = tracks[ti];\r\n                ensureTrackMeta(tr);\r\n                tr.__cvxMonIdx = (tr.__cvxMonIdx + 1) % trackSel.mon.length;\r\n                tr.mon = trackSel.mon[tr.__cvxMonIdx];\r\n                setHud(\"MON \" + tr.mon, 650);\r\n                pokeChrome();\r\n            }\r\n\r\n            function masterCalcVis(panelH, titleH, padY, rowH, rowGap) {\r\n                const avail = Math.max(0, panelH - (padY * 2) - titleH);\r\n                const step = Math.max(1, rowH + rowGap);\r\n                return clamp(Math.floor((avail + rowGap) \/ step), 1, 10);\r\n            }\r\n\r\n            function masterSyncScroll(itemsLen) {\r\n                const vis = Math.max(1, masterPanel.vis | 0);\r\n                const maxTop = Math.max(0, itemsLen - vis);\r\n\r\n                masterPanel.top = clamp(masterPanel.top | 0, 0, maxTop);\r\n\r\n                if (masterPanel.idx < masterPanel.top) masterPanel.top = masterPanel.idx;\r\n                else if (masterPanel.idx > masterPanel.top + vis - 1) masterPanel.top = masterPanel.idx - vis + 1;\r\n\r\n                masterPanel.top = clamp(masterPanel.top, 0, maxTop);\r\n            }\r\n\r\n            function execMasterAction(item, dir) {\r\n                if (!item || !item.id) return;\r\n\r\n                const d = (dir == null ? 1 : dir) | 0;\r\n\r\n                switch (item.id) {\r\n                    case \"back\":\r\n                        masterPanel.open = false;\r\n                        setHud(\"BACK\", 450);\r\n                        break;\r\n\r\n                        \/* NO tocar: Master mute + vol *\/\r\n                    case \"m_mute\":\r\n                        master.mute = !master.mute;\r\n                        setHud(master.mute ? \"M MUTE\" : \"M UNMUTE\", 700);\r\n                        break;\r\n\r\n                    case \"m_volp\":\r\n                        master.vol = clamp(master.vol + 2, 0, 100);\r\n                        setHud(\"M VOL \" + master.vol, 650);\r\n                        break;\r\n\r\n                    case \"m_volm\":\r\n                        master.vol = clamp(master.vol - 2, 0, 100);\r\n                        setHud(\"M VOL \" + master.vol, 650);\r\n                        break;\r\n\r\n                        \/* NUEVO: Out preset *\/\r\n                    case \"out\":\r\n                        cycleOutputPreset(d);\r\n                        setHud(\"OUT\", 650);\r\n                        break;\r\n                        \/* NUEVOS: Sync \/ Versions (demo) *\/\r\n                    case \"sync\":\r\n                        syncMode = syncMode ? 0 : 1;\r\n                        setHud(syncMode ? \"SYNC CLOUD\" : \"SYNC LOCAL\", 650);\r\n                        break;\r\n\r\n                    case \"versions\":\r\n                        verOpen();\r\n                        break;\r\n                        \/* \u201cEtiqueta\u201d *\/\r\n                    case \"t_hdr\":\r\n                        setHud(\"TRACK\", 450);\r\n                        break;\r\n\r\n                        \/* NUEVOS: Src \/ Mon *\/\r\n                    case \"src\":\r\n                        cycleTrackSrc(activeTrack, d);\r\n                        break;\r\n\r\n                    case \"mon\":\r\n                        toggleTrackMon(activeTrack);\r\n                        break;\r\n\r\n                    default:\r\n                        setHud(\"N\/A\", 550);\r\n                        break;\r\n                }\r\n\r\n                pokeChrome();\r\n            }\r\n\r\n            \/* -------------------------------------------------------\r\n               Layout constants (OLED px)\r\n            ------------------------------------------------------- *\/\r\n            const L = {\r\n                pad: 1,\r\n                headerH: 0,\r\n                footerH: 0,\r\n                listW: 74,\r\n                gap: 2,\r\n                masterBarW: 0\r\n            };\r\n\r\n            function visibleTracksCount() {\r\n                return zoomYMap[clamp(zoomY, 0, zoomYMap.length - 1)];\r\n            }\r\n\r\n            function timelineSpan() {\r\n                const spans = [96, 72, 52, 36, 24, 16, 12, 8, 6, 4, 3, 2, 1];\r\n                return spans[clamp(zoomX, 0, spans.length - 1)];\r\n            }\r\n\r\n            function fitZoomXToSeconds(sec) {\r\n                const spans = [96, 72, 52, 36, 24, 16, 12, 8, 6, 4, 3, 2, 1]; \/\/ misma tabla que timelineSpan()\r\n                const pad = css.flt(\"--cvx-oled-zoomx-fit-pad-s\", 0.5);\r\n                const target = Math.max(0.001, (sec || 0) + pad);\r\n\r\n                \/\/ Buscar el span m\u00e1s chico que a\u00fan cubra \"target\"\r\n                let best = 0; \/\/ fallback al m\u00e1s grande (96s)\r\n                for (let i = spans.length - 1; i >= 0; i--) {\r\n                    if (spans[i] >= target) {\r\n                        best = i;\r\n                        break;\r\n                    }\r\n                }\r\n\r\n                zoomX = clamp(best, 0, spans.length - 1);\r\n            }\r\n\r\n            function trackEndSeconds(ti) {\r\n                if (ti < 0 || ti >= tracks.length) return 0;\r\n                const tr = tracks[ti];\r\n\r\n                \/\/ Preferir clips (si existen)\r\n                let end = 0;\r\n                if (tr.clips && tr.clips.length) {\r\n                    for (const c of tr.clips) end = Math.max(end, c && c.e ? c.e : 0);\r\n                    return end;\r\n                }\r\n\r\n                \/\/ Fallback a duraci\u00f3n de audio\r\n                if (tr.aud && tr.aud.mono && tr.aud.mono.length) {\r\n                    const sr = Math.max(1, tr.aud.sr || 44100);\r\n                    return tr.aud.mono.length \/ sr;\r\n                }\r\n\r\n                return 0;\r\n            }\r\n\r\n            \/* -------------------------------------------------------\r\n               Timeline bounds helpers (seconds)\r\n               - ALL: end of the longest track (clips preferred, else aud length)\r\n               - AUDIBLE: respects SOLO\/MUTE; fallback to ALL if nothing audible\r\n               - Fallback when session empty: --cvx-oled-timeline-max-s (default 160)\r\n            ------------------------------------------------------- *\/\r\n            function timelineMaxSecondsAll() {\r\n                const fallback = clamp(css.flt(\"--cvx-oled-timeline-max-s\", 160), 10, 36000);\r\n                let end = 0;\r\n                for (let ti = 0; ti < tracks.length; ti++) end = Math.max(end, trackEndSeconds(ti));\r\n                return (end > 0.001) ? Math.max(1, end) : fallback;\r\n            }\r\n\r\n            function timelineMaxSecondsAudible() {\r\n                const anySolo = tracks.some(tr => tr && tr.solo);\r\n                let end = 0;\r\n\r\n                for (let ti = 0; ti < tracks.length; ti++) {\r\n                    const tr = tracks[ti];\r\n                    if (!tr) continue;\r\n                    const audible = anySolo ? !!tr.solo : !tr.mute;\r\n                    if (!audible) continue;\r\n                    end = Math.max(end, trackEndSeconds(ti));\r\n                }\r\n\r\n                const all = timelineMaxSecondsAll();\r\n                return (end > 0.001) ? Math.min(end, all) : all;\r\n            }\r\n\r\n            function tickStep(span) {\r\n                if (span >= 80) return 16;\r\n                if (span >= 50) return 10;\r\n                if (span >= 32) return 8;\r\n                return 6;\r\n            }\r\n\r\n            function ensureView() {\r\n                const span = timelineSpan();\r\n\r\n                const maxTPlay = timelineMaxSecondsAll();\r\n\r\n                \/* Durante drag de regi\u00f3n permitimos \u201cpan\u201d m\u00e1s all\u00e1 del contenido para no recortar el gesto *\/\r\n                const padView = draggingRegion ?\r\n                    clamp(css.flt(\"--cvx-oled-timeline-pad-s\", 30), 0, 600) :\r\n                    0;\r\n\r\n                const maxTView = maxTPlay + padView;\r\n\r\n                \/* El cursor (playhead) no se va fuera del contenido real. *\/\r\n                playhead = clamp(playhead, 0, maxTPlay);\r\n\r\n                \/* El viewport s\u00ed puede ir hasta maxTView durante drag. *\/\r\n                viewStart = clamp(viewStart, 0, Math.max(0, maxTView - span));\r\n\r\n                if (!draggingRegion) {\r\n                    if (playhead < viewStart + 2) viewStart = clamp(playhead - 2, 0, maxTView - span);\r\n                    if (playhead > viewStart + span - 2) viewStart = clamp(playhead - (span - 2), 0, maxTView - span);\r\n                }\r\n\r\n                \/* Track list can include a virtual \u201c+ ADD\u201d row *\/\r\n                const canAddRow = (tracks.length < CVX_TRACKS_MAX);\r\n                const listCount = tracks.length + (canAddRow ? 1 : 0);\r\n\r\n                if (!listCount) {\r\n                    activeTrack = -1;\r\n                    trackTop = 0;\r\n                    multiSel.clear();\r\n                    return;\r\n                }\r\n\r\n                \/* Default selection: first row (track 1, or \u201c+ ADD\u201d if empty session) *\/\r\n                if (activeTrack < 0) activeTrack = 0;\r\n\r\n                activeTrack = clamp(activeTrack, 0, listCount - 1);\r\n\r\n                \/* Never keep multi-select on the virtual row *\/\r\n                if (canAddRow && activeTrack === tracks.length) {\r\n                    multiSel.clear();\r\n                }\r\n\r\n                const vt = visibleTracksCount();\r\n                trackTop = clamp(trackTop, 0, Math.max(0, listCount - vt));\r\n\r\n                if (activeTrack < trackTop) trackTop = activeTrack;\r\n                if (activeTrack >= trackTop + vt) trackTop = activeTrack - vt + 1;\r\n            }\r\n\r\n            function timeToX(t) {\r\n                const span = timelineSpan();\r\n                const x0 = L.pad + L.listW + L.gap;\r\n                const x1 = W - L.pad - 1 - L.masterBarW;\r\n                const vw = (x1 - x0 + 1);\r\n                const u = (t - viewStart) \/ span;\r\n                return Math.round(x0 + u * (vw - 1));\r\n            }\r\n\r\n            function xToTime(x) {\r\n                const span = timelineSpan();\r\n                const x0 = L.pad + L.listW + L.gap;\r\n                const x1 = W - L.pad - 1 - L.masterBarW;\r\n                const vw = (x1 - x0 + 1);\r\n                const u = clamp((x - x0) \/ (vw - 1), 0, 1);\r\n                return viewStart + u * span;\r\n            }\r\n\r\n            function dimViewportOnly(k) {\r\n                const y0 = L.headerH;\r\n                const y1 = H - L.footerH - 1;\r\n                if (y0 > y1) return;\r\n                for (let y = y0; y <= y1; y++) {\r\n                    const off = y * W;\r\n                    for (let x = 0; x < W; x++) {\r\n                        ras.fb[off + x] = (ras.fb[off + x] * k) | 0;\r\n                    }\r\n                }\r\n            }\r\n\r\n            function triRight(x, y, v, sz) {\r\n                x |= 0;\r\n                y |= 0;\r\n                sz = clamp(sz | 0, 2, 6);\r\n                ras.pxMax(x, y, v);\r\n                for (let i = 1; i <= sz; i++) {\r\n                    ras.pxMax(x - i, y - i, v);\r\n                    ras.pxMax(x - i, y, v);\r\n                    ras.pxMax(x - i, y + i, v);\r\n                }\r\n                ras.pxMax(x - (sz + 1), y, v);\r\n            }\r\n\r\n            function triLeft(x, y, v, sz) {\r\n                x |= 0;\r\n                y |= 0;\r\n                sz = clamp(sz | 0, 2, 6);\r\n                ras.pxMax(x, y, v);\r\n                for (let i = 1; i <= sz; i++) {\r\n                    ras.pxMax(x + i, y - i, v);\r\n                    ras.pxMax(x + i, y, v);\r\n                    ras.pxMax(x + i, y + i, v);\r\n                }\r\n                ras.pxMax(x + (sz + 1), y, v);\r\n            }\r\n\r\n            function drawSliderUniBar(ras, x, y, w, h, t01, bgV, inkV, a) {\r\n                if (w <= 2 || h <= 0) return;\r\n                const t = clamp(t01, 0, 1);\r\n\r\n                ras.blendRect(x, y, w, h, bgV, a);\r\n\r\n                const fillW = Math.round((w - 1) * t);\r\n                if (fillW > 0) ras.blendRect(x, y, fillW, h, inkV, a);\r\n\r\n                const kx = x + clamp(fillW - 1, 0, w - 2);\r\n                ras.blendRect(kx, y, 2, h, 255, a);\r\n            }\r\n\r\n            function drawSliderGainFulcrum(ras, x, y, w, h, gDb, bgV, inkV, a) {\r\n                if (w <= 4 || h <= 0) return;\r\n\r\n                const v = clamp(gDb, -20, 60);\r\n\r\n                ras.blendRect(x, y, w, h, bgV, a);\r\n\r\n                const cx = x + Math.floor((w - 1) \/ 2);\r\n                ras.blendRect(cx, y, 1, h, 255, a);\r\n\r\n                let kx = cx;\r\n\r\n                if (v < 0) {\r\n                    const t = clamp((-v) \/ 20, 0, 1);\r\n                    kx = cx - Math.round(t * (cx - x));\r\n                    if (kx < cx) ras.blendRect(kx, y, (cx - kx), h, inkV, a);\r\n                } else if (v > 0) {\r\n                    const t = clamp(v \/ 60, 0, 1);\r\n                    const xr = x + w - 1;\r\n                    kx = cx + Math.round(t * (xr - cx));\r\n                    if (kx > cx) ras.blendRect(cx, y, (kx - cx), h, inkV, a);\r\n                }\r\n\r\n                ras.blendRect(clamp(kx - 1, x, x + w - 2), y, 2, h, 255, a);\r\n            }\r\n\r\n            function clampi(v, a, b) {\r\n                return v < a ? a : (v > b ? b : v);\r\n            }\r\n\r\n            function bumpGainDb(ti, d) {\r\n                const tr = tracks[ti];\r\n                tr.gainDb = clampi((tr.gainDb ?? 0) + d, -20, 60);\r\n                recApplyGainToLiveClip(ti);\r\n            }\r\n\r\n            function bumpVol(ti, d) {\r\n                const tr = tracks[ti];\r\n                tr.vol = clampi((tr.vol ?? 0) + d, 0, 100);\r\n            }\r\n\r\n            let _cvxAudioCtx = null;\r\n\r\n            function getAudioCtx() {\r\n                if (_cvxAudioCtx) return _cvxAudioCtx;\r\n                _cvxAudioCtx = new(window.AudioContext || window.webkitAudioContext)();\r\n                return _cvxAudioCtx;\r\n            }\r\n\r\n            function mixToMono(audioBuffer) {\r\n                const n = audioBuffer.length;\r\n                const ch = audioBuffer.numberOfChannels;\r\n                const mono = new Float32Array(n);\r\n\r\n                for (let c = 0; c < ch; c++) {\r\n                    const data = audioBuffer.getChannelData(c);\r\n                    for (let i = 0; i < n; i++) mono[i] += data[i];\r\n                }\r\n\r\n                const inv = 1 \/ Math.max(1, ch);\r\n                for (let i = 0; i < n; i++) mono[i] *= inv;\r\n                return mono;\r\n            }\r\n\r\n            function parseAudacityTxtToFloat32(text) {\r\n                const out = [];\r\n                const lines = String(text || \"\").split(\/\\r?\\n\/);\r\n\r\n                for (let i = 0; i < lines.length; i++) {\r\n                    const ln = lines[i].trim();\r\n                    if (!ln) continue;\r\n\r\n                    \/\/ separadores t\u00edpicos: tab, espacios, coma, punto y coma\r\n                    const parts = ln.split(\/[\\s,;]+\/);\r\n                    if (parts.length < 1) continue;\r\n\r\n                    const v = Number(parts.length === 1 ? parts[0] : parts[1]);\r\n                    if (!Number.isFinite(v)) continue;\r\n                    out.push(v);\r\n                }\r\n\r\n                return new Float32Array(out);\r\n            }\r\n\r\n            function maxAbsFloat32(a) {\r\n                let m = 0;\r\n                for (let i = 0; i < a.length; i++) {\r\n                    const v = a[i];\r\n                    const av = v < 0 ? -v : v;\r\n                    if (av > m) m = av;\r\n                }\r\n                return m;\r\n            }\r\n\r\n            function minMaxFloat32(a) {\r\n                if (!a || !a.length) return {\r\n                    min: 0,\r\n                    max: 0,\r\n                    abs: 0\r\n                };\r\n                let mn = a[0],\r\n                    mx = a[0];\r\n                for (let i = 1; i < a.length; i++) {\r\n                    const v = a[i];\r\n                    if (v < mn) mn = v;\r\n                    else if (v > mx) mx = v;\r\n                }\r\n                return {\r\n                    min: mn,\r\n                    max: mx,\r\n                    abs: Math.max(Math.abs(mn), Math.abs(mx))\r\n                };\r\n            }\r\n\r\n            function makeBinsMinMax(mono, block) {\r\n                const n = Math.ceil(mono.length \/ block);\r\n                const mins = new Float32Array(n);\r\n                const maxs = new Float32Array(n);\r\n\r\n                for (let i = 0; i < n; i++) {\r\n                    const a = i * block;\r\n                    const b = Math.min(mono.length, a + block);\r\n\r\n                    let mn = Infinity;\r\n                    let mx = -Infinity;\r\n\r\n                    for (let j = a; j < b; j++) {\r\n                        const v = mono[j];\r\n                        if (v < mn) mn = v;\r\n                        if (v > mx) mx = v;\r\n                    }\r\n\r\n                    if (!isFinite(mn)) {\r\n                        mn = 0;\r\n                        mx = 0;\r\n                    }\r\n                    mins[i] = mn;\r\n                    maxs[i] = mx;\r\n                }\r\n\r\n                return {\r\n                    mins,\r\n                    maxs\r\n                };\r\n            }\r\n\r\n            \/\/ Mantengo el nombre buildPeakPyramid para no tocar el resto del c\u00f3digo,\r\n            \/\/ pero ahora devuelve mins\/maxs por nivel (no abs peaks).\r\n            function buildPeakPyramid(mono) {\r\n                const levels = [];\r\n\r\n                let block = 256; \/\/ base (samples por bin)\r\n                let {\r\n                    mins,\r\n                    maxs\r\n                } = makeBinsMinMax(mono, block);\r\n\r\n                levels.push({\r\n                    block,\r\n                    mins,\r\n                    maxs\r\n                });\r\n\r\n                while (mins.length > 1024) {\r\n                    const nextN = Math.ceil(mins.length \/ 2);\r\n                    const nextMins = new Float32Array(nextN);\r\n                    const nextMaxs = new Float32Array(nextN);\r\n\r\n                    for (let i = 0; i < nextN; i++) {\r\n                        const a = i * 2;\r\n                        const b = a + 1;\r\n\r\n                        const mnA = mins[a];\r\n                        const mxA = maxs[a];\r\n\r\n                        const mnB = (b < mins.length) ? mins[b] : mnA;\r\n                        const mxB = (b < maxs.length) ? maxs[b] : mxA;\r\n\r\n                        nextMins[i] = (mnA < mnB) ? mnA : mnB;\r\n                        nextMaxs[i] = (mxA > mxB) ? mxA : mxB;\r\n                    }\r\n\r\n                    mins = nextMins;\r\n                    maxs = nextMaxs;\r\n                    block *= 2;\r\n\r\n                    levels.push({\r\n                        block,\r\n                        mins,\r\n                        maxs\r\n                    });\r\n                }\r\n\r\n                return levels;\r\n            }\r\n\r\n\r\n\r\n            function makeAudFromSamples(samples, sr, loop) {\r\n                const mono = samples instanceof Float32Array ? samples : new Float32Array(samples || []);\r\n                const mm = minMaxFloat32(mono);\r\n\r\n\r\n                const out = {\r\n                    sr: sr,\r\n                    mono,\r\n                    levels: buildPeakPyramid(mono),\r\n                    loop: !!loop\r\n\r\n\r\n\r\n                };\r\n\r\n                if (out.loop) {\r\n                    out.loopMin = mm.min;\r\n                    out.loopMax = mm.max;\r\n                    out.loopPeak = mm.abs;\r\n                }\r\n\r\n                return out;\r\n            }\r\n\r\n            function makeDemoAudFromSamples(samples, sr) {\r\n                return makeAudFromSamples(samples, sr, true);\r\n            }\r\n\r\n            const CVX_WAVE_DIRECT_SCAN_MAX = 256; \/\/ samples; <= esto escanea directo el buffer (mejor para zoom cercano)\r\n\r\n            function minMaxRangeDirect(mono, s0, s1) {\r\n                s0 = Math.max(0, Math.min(mono.length, s0));\r\n                s1 = Math.max(0, Math.min(mono.length, s1));\r\n                if (s1 <= s0) return {\r\n                    min: 0,\r\n                    max: 0\r\n                };\r\n\r\n                let mn = Infinity,\r\n                    mx = -Infinity;\r\n                for (let i = s0; i < s1; i++) {\r\n                    const v = mono[i];\r\n                    if (v < mn) mn = v;\r\n                    if (v > mx) mx = v;\r\n                }\r\n                if (!isFinite(mn)) {\r\n                    mn = 0;\r\n                    mx = 0;\r\n                }\r\n                return {\r\n                    min: mn,\r\n                    max: mx\r\n                };\r\n            }\r\n\r\n            function minMaxRangePyramid(aud, s0, s1) {\r\n                if (!aud || !aud.mono || !aud.mono.length) return {\r\n                    min: 0,\r\n                    max: 0\r\n                };\r\n                if (!aud.levels || !aud.levels.length) return minMaxRangeDirect(aud.mono, s0, s1);\r\n\r\n                \/\/ clamp\r\n                s0 = Math.max(0, Math.min(aud.mono.length, s0));\r\n                s1 = Math.max(0, Math.min(aud.mono.length, s1));\r\n                if (s1 <= s0) return {\r\n                    min: 0,\r\n                    max: 0\r\n                };\r\n\r\n                const span = s1 - s0;\r\n\r\n                \/\/ zoom cercano: muestreo real (evita \u201cpiramidado\u201d)\r\n                if (span <= CVX_WAVE_DIRECT_SCAN_MAX) {\r\n                    return minMaxRangeDirect(aud.mono, s0, s1);\r\n                }\r\n\r\n                \/\/ elegir nivel adecuado\r\n                let lvl = aud.levels[0];\r\n                for (let i = 1; i < aud.levels.length; i++) {\r\n                    const cand = aud.levels[i];\r\n                    if (cand.block <= span) lvl = cand;\r\n                    else break;\r\n                }\r\n\r\n                const i0 = Math.floor(s0 \/ lvl.block);\r\n                const i1 = Math.floor((s1 - 1) \/ lvl.block);\r\n\r\n                let mn = Infinity,\r\n                    mx = -Infinity;\r\n                const hi = Math.min(lvl.mins.length - 1, i1);\r\n\r\n                for (let i = Math.max(0, i0); i <= hi; i++) {\r\n                    const a = lvl.mins[i];\r\n                    const b = lvl.maxs[i];\r\n                    if (a < mn) mn = a;\r\n                    if (b > mx) mx = b;\r\n                }\r\n\r\n                if (!isFinite(mn)) {\r\n                    mn = 0;\r\n                    mx = 0;\r\n                }\r\n                return {\r\n                    min: mn,\r\n                    max: mx\r\n                };\r\n            }\r\n\r\n            function minMaxInSampleRange(aud, s0, s1) {\r\n                if (!aud || !aud.mono || !aud.mono.length) return {\r\n                    min: 0,\r\n                    max: 0\r\n                };\r\n                if (s1 <= s0) return {\r\n                    min: 0,\r\n                    max: 0\r\n                };\r\n\r\n                \/\/ modo normal (buffer lineal)\r\n                if (!aud.loop) return minMaxRangePyramid(aud, s0, s1);\r\n\r\n                const N = aud.mono.length;\r\n                const span = s1 - s0;\r\n\r\n                \/\/ si cubre 1+ vueltas, devolv\u00e9 min\/max global del loop\r\n                if (span >= N) {\r\n                    const mn = (aud.loopMin != null) ? aud.loopMin : -(aud.loopPeak || 0);\r\n                    const mx = (aud.loopMax != null) ? aud.loopMax : +(aud.loopPeak || 0);\r\n                    return {\r\n                        min: mn,\r\n                        max: mx\r\n                    };\r\n                }\r\n\r\n                \/\/ wrap robusto\r\n                let a = s0 % N;\r\n                if (a < 0) a += N;\r\n                let b = a + span;\r\n\r\n                if (b <= N) return minMaxRangePyramid(aud, a, b);\r\n\r\n                const r1 = minMaxRangePyramid(aud, a, N);\r\n                const r2 = minMaxRangePyramid(aud, 0, b - N);\r\n                return {\r\n                    min: (r1.min < r2.min) ? r1.min : r2.min,\r\n                    max: (r1.max > r2.max) ? r1.max : r2.max\r\n                };\r\n            }\r\n\r\n\r\n\r\n            async function loadTrackAudioFromFile(ti, file) {\r\n                const ctx = getAudioCtx();\r\n                const ab = await file.arrayBuffer();\r\n                const buf = await ctx.decodeAudioData(ab);\r\n\r\n                const mono = mixToMono(buf);\r\n                const aud = {\r\n                    sr: buf.sampleRate,\r\n                    mono,\r\n                    levels: buildPeakPyramid(mono)\r\n                };\r\n\r\n                tracks[ti].aud = aud; \/\/ <- queda disponible para dibujar\r\n\r\n                if (!CVX_DEMO_MODE) {\r\n                    \/* NORMAL: un \u00fanico clip desde t=0 (alineado), usando la duraci\u00f3n completa del archivo *\/\r\n                    const dur = (aud.mono.length \/ Math.max(1, (aud.sr || 44100)));\r\n                    const tr = tracks[ti];\r\n\r\n                    tr.clips = [{\r\n                        id: allocClipId(),\r\n                        s: 0,\r\n                        e: dur,\r\n                        o: 0,\r\n                        a: 1,\r\n                        fx: [],\r\n                        fi: false,\r\n                        fo: false,\r\n                        m: []\r\n                    }];\r\n\r\n                    \/* alinear vista al inicio tras cargar *\/\r\n                    playhead = 0;\r\n                    viewStart = 0;\r\n                    ensureView();\r\n                }\r\n            }\r\n\r\n            \/\/ binding m\u00ednimo: vos defin\u00eds tus IDs seg\u00fan convenci\u00f3n\r\n            function bindTrackFileInput(inputElOrId, ti) {\r\n                const el = (typeof inputElOrId === \"string\") ?\r\n                    document.getElementById(inputElOrId) :\r\n                    inputElOrId;\r\n\r\n                if (!el) return;\r\n\r\n                el.addEventListener(\"change\", async () => {\r\n                    const f = el.files && el.files[0];\r\n                    if (!f) return;\r\n                    await loadTrackAudioFromFile(ti, f);\r\n                    \/\/ fuerza redraw con tu mecanismo:\r\n                    \/\/ needRedraw = 1;  \u00f3  invalidate();  \u00f3  scheduleFrame();\r\n                });\r\n            }\r\n            \/* =========================================================\r\n               Waveform Summary (min\/max pyramid) + LOD + viewport cache\r\n               - Base block recomendado: 32 (o 16 si quer\u00e9s m\u00e1s detalle)\r\n               - Niveles superiores combinan 2:1\r\n               ========================================================= *\/\r\n\r\n            function buildMinMaxLevelFromSamples(samples, baseBlock) {\r\n                \/\/ samples: Float32Array (mono)\r\n                const n = samples.length;\r\n                const blocks = Math.ceil(n \/ baseBlock);\r\n\r\n                const mins = new Float32Array(blocks);\r\n                const maxs = new Float32Array(blocks);\r\n\r\n                for (let b = 0; b < blocks; b++) {\r\n                    const i0 = b * baseBlock;\r\n                    const i1 = Math.min(n, i0 + baseBlock);\r\n\r\n                    let mn = +Infinity;\r\n                    let mx = -Infinity;\r\n\r\n                    for (let i = i0; i < i1; i++) {\r\n                        const s = samples[i];\r\n                        if (s < mn) mn = s;\r\n                        if (s > mx) mx = s;\r\n                    }\r\n\r\n                    \/\/ En bloques incompletos, mn\/mx quedan bien igual.\r\n                    mins[b] = (mn === +Infinity) ? 0 : mn;\r\n                    maxs[b] = (mx === -Infinity) ? 0 : mx;\r\n                }\r\n\r\n                return {\r\n                    block: baseBlock,\r\n                    mins,\r\n                    maxs,\r\n                    lengthSamples: n\r\n                };\r\n            }\r\n\r\n            function buildNextMinMaxLevel(prevLevel) {\r\n                const {\r\n                    block,\r\n                    mins: pMin,\r\n                    maxs: pMax\r\n                } = prevLevel;\r\n                const nextBlock = block * 2;\r\n                const nextLen = Math.ceil(pMin.length \/ 2);\r\n\r\n                const mins = new Float32Array(nextLen);\r\n                const maxs = new Float32Array(nextLen);\r\n\r\n                for (let i = 0; i < nextLen; i++) {\r\n                    const a = i * 2;\r\n                    const b = a + 1;\r\n\r\n                    const mnA = pMin[a];\r\n                    const mxA = pMax[a];\r\n\r\n                    if (b < pMin.length) {\r\n                        const mnB = pMin[b];\r\n                        const mxB = pMax[b];\r\n                        mins[i] = (mnA < mnB) ? mnA : mnB;\r\n                        maxs[i] = (mxA > mxB) ? mxA : mxB;\r\n                    } else {\r\n                        mins[i] = mnA;\r\n                        maxs[i] = mxA;\r\n                    }\r\n                }\r\n\r\n                return {\r\n                    block: nextBlock,\r\n                    mins,\r\n                    maxs,\r\n                    lengthSamples: prevLevel.lengthSamples\r\n                };\r\n            }\r\n\r\n            function buildWaveSummaryMinMax(samplesMonoOrStereo, opts = {}) {\r\n                \/\/ samplesMonoOrStereo:\r\n                \/\/ - mono: Float32Array\r\n                \/\/ - stereo: { L: Float32Array, R: Float32Array } (mismo largo idealmente)\r\n                const baseBlock = opts.baseBlock ?? 32;\r\n                const maxLevels = opts.maxLevels ?? 16;\r\n\r\n                \/\/ Normalizamos a \"mono envelope\" (min\/max por bloque puede combinar canales)\r\n                \/\/ Para evitar copiar todo a mono, construimos base level por canal y combinamos por bloque.\r\n                const isStereo = samplesMonoOrStereo && samplesMonoOrStereo.L && samplesMonoOrStereo.R;\r\n\r\n                let baseLevel;\r\n                if (!isStereo) {\r\n                    baseLevel = buildMinMaxLevelFromSamples(samplesMonoOrStereo, baseBlock);\r\n                } else {\r\n                    const L = samplesMonoOrStereo.L;\r\n                    const R = samplesMonoOrStereo.R;\r\n                    const n = Math.min(L.length, R.length);\r\n\r\n                    \/\/ Base level por bloque combinando canales, sin buffer intermedio\r\n                    const blocks = Math.ceil(n \/ baseBlock);\r\n                    const mins = new Float32Array(blocks);\r\n                    const maxs = new Float32Array(blocks);\r\n\r\n                    for (let b = 0; b < blocks; b++) {\r\n                        const i0 = b * baseBlock;\r\n                        const i1 = Math.min(n, i0 + baseBlock);\r\n\r\n                        let mn = +Infinity;\r\n                        let mx = -Infinity;\r\n\r\n                        for (let i = i0; i < i1; i++) {\r\n                            const sL = L[i];\r\n                            const sR = R[i];\r\n                            \/\/ Envelope com\u00fan: min = min(L,R), max = max(L,R)\r\n                            \/\/ (alternativa: promedio; pero esto preserva transientes)\r\n                            if (sL < mn) mn = sL;\r\n                            if (sR < mn) mn = sR;\r\n                            if (sL > mx) mx = sL;\r\n                            if (sR > mx) mx = sR;\r\n                        }\r\n\r\n                        mins[b] = (mn === +Infinity) ? 0 : mn;\r\n                        maxs[b] = (mx === -Infinity) ? 0 : mx;\r\n                    }\r\n\r\n                    baseLevel = {\r\n                        block: baseBlock,\r\n                        mins,\r\n                        maxs,\r\n                        lengthSamples: n\r\n                    };\r\n                }\r\n\r\n                const levels = [baseLevel];\r\n                for (let i = 1; i < maxLevels; i++) {\r\n                    const prev = levels[i - 1];\r\n                    if (prev.mins.length <= 1) break;\r\n                    levels.push(buildNextMinMaxLevel(prev));\r\n                }\r\n\r\n                return {\r\n                    levels,\r\n                    lengthSamples: baseLevel.lengthSamples,\r\n                    sampleRate: opts.sampleRate ?? null,\r\n                    version: 1\r\n                };\r\n            }\r\n\r\n            function pickLevelForSPP(summary, samplesPerPixel) {\r\n                \/\/ Elige el nivel cuyo block est\u00e9 \"cerca\" de SPP.\r\n                \/\/ Regla: preferimos block <= SPP, y el m\u00e1s grande posible (reduce trabajo).\r\n                const levels = summary.levels;\r\n\r\n                let best = 0;\r\n                for (let i = 0; i < levels.length; i++) {\r\n                    if (levels[i].block <= samplesPerPixel) best = i;\r\n                    else break;\r\n                }\r\n                return best;\r\n            }\r\n\r\n            \/* ------------------ Viewport cache ------------------ *\/\r\n\r\n            class WaveViewportCache {\r\n                constructor() {\r\n                    this.key = \"\";\r\n                    this.levelIndex = -1;\r\n                    this.colMin = null;\r\n                    this.colMax = null;\r\n                }\r\n\r\n                invalidate() {\r\n                    this.key = \"\";\r\n                    this.levelIndex = -1;\r\n                    this.colMin = null;\r\n                    this.colMax = null;\r\n                }\r\n            }\r\n\r\n            \/**\r\n             * Devuelve columnas min\/max listas para render:\r\n             * - width: cantidad de columnas (pixels) del viewport del track\r\n             * - t0\/t1: ventana temporal visible (segundos)\r\n             * - sr: sample rate (Hz)\r\n             *\/\r\n            function getViewportColumns(summary, cache, t0, t1, sr, width) {\r\n                const n = summary.lengthSamples;\r\n                const s0 = Math.max(0, Math.min(n, Math.floor(t0 * sr)));\r\n                const s1 = Math.max(0, Math.min(n, Math.ceil(t1 * sr)));\r\n                const span = Math.max(1, s1 - s0);\r\n\r\n                const samplesPerPixel = span \/ Math.max(1, width);\r\n                const levelIndex = pickLevelForSPP(summary, samplesPerPixel);\r\n                const L = summary.levels[levelIndex];\r\n\r\n                \/\/ Mapeo a \u00edndices de bloques del nivel elegido\r\n                const b0 = Math.floor(s0 \/ L.block);\r\n                const b1 = Math.ceil(s1 \/ L.block);\r\n\r\n                \/\/ Cache key: si no cambia nada, devolvemos buffers previos\r\n                const key = `${levelIndex}|${b0}|${b1}|${width}`;\r\n                if (cache && cache.key === key && cache.colMin && cache.colMax) {\r\n                    return {\r\n                        levelIndex,\r\n                        colMin: cache.colMin,\r\n                        colMax: cache.colMax\r\n                    };\r\n                }\r\n\r\n                const colMin = new Float32Array(width);\r\n                const colMax = new Float32Array(width);\r\n\r\n                \/\/ Para cada columna (pixel), tomamos el rango de bloques que cubre\r\n                \/\/ y reducimos min\/max usando mins\/maxs del nivel (r\u00e1pido).\r\n                const blocksSpan = Math.max(1, b1 - b0);\r\n\r\n                for (let x = 0; x < width; x++) {\r\n                    const tA = x \/ width;\r\n                    const tB = (x + 1) \/ width;\r\n\r\n                    const bb0 = b0 + Math.floor(tA * blocksSpan);\r\n                    const bb1 = b0 + Math.ceil(tB * blocksSpan);\r\n\r\n                    let mn = +Infinity;\r\n                    let mx = -Infinity;\r\n\r\n                    const i0 = Math.max(0, Math.min(L.mins.length, bb0));\r\n                    const i1 = Math.max(0, Math.min(L.mins.length, bb1));\r\n\r\n                    for (let bi = i0; bi < i1; bi++) {\r\n                        const a = L.mins[bi];\r\n                        const b = L.maxs[bi];\r\n                        if (a < mn) mn = a;\r\n                        if (b > mx) mx = b;\r\n                    }\r\n\r\n                    colMin[x] = (mn === +Infinity) ? 0 : mn;\r\n                    colMax[x] = (mx === -Infinity) ? 0 : mx;\r\n                }\r\n\r\n                if (cache) {\r\n                    cache.key = key;\r\n                    cache.levelIndex = levelIndex;\r\n                    cache.colMin = colMin;\r\n                    cache.colMax = colMax;\r\n                }\r\n\r\n                return {\r\n                    levelIndex,\r\n                    colMin,\r\n                    colMax\r\n                };\r\n            }\r\n\r\n            function drawMarqueeTextAA(ras, x0, y0, maxW, text, inkV, aa, nowMs) {\r\n                const s = String(text ?? \"\");\r\n                if (maxW <= 0) return;\r\n\r\n                \/\/ Par\u00e1metros de fuente (tu OLED usa 6px por char aprox, alto 7px)\r\n                const charW = 6;\r\n\r\n                \/\/ Ventana visible en caracteres (seguridad)\r\n                const winChars = Math.max(1, Math.floor(maxW \/ charW));\r\n                if (winChars <= 0) return;\r\n\r\n                \/\/ Si entra, dibuj\u00e1 normal (igual acotado por seguridad)\r\n                if (s.length <= winChars) {\r\n                    ras.textAA(x0, y0, s, inkV, aa);\r\n                    return;\r\n                }\r\n\r\n                \/\/ Gap entre repeticiones (en chars)\r\n                const gapChars = 3;\r\n                const gap = \" \".repeat(gapChars);\r\n\r\n                \/\/ Texto \u201cinfinito\u201d\r\n                const loop = s + gap;\r\n\r\n                \/\/ Velocidad suave: 1px cada msPerPx.\r\n                \/\/ \u2191 M\u00e1s grande = m\u00e1s lento. (Ej: 18 r\u00e1pido, 28 medio, 45 lento)\r\n                const msPerPx = 40;\r\n\r\n                \/\/ Avance total en p\u00edxeles\r\n                const px = Math.floor(nowMs \/ msPerPx);\r\n\r\n                \/\/ \u00cdndice de caracter y sub-offset en p\u00edxeles dentro del caracter (0..5)\r\n                const L = loop.length;\r\n                const ch = (Math.floor(px \/ charW) % L);\r\n                const dx = (px % charW);\r\n\r\n                \/\/ Duplico para wrap sin if\r\n                const big = loop + loop;\r\n\r\n                \/\/ Cantidad de caracteres a dibujar (considera dx para cubrir todo el ancho)\r\n                const needChars = Math.ceil((maxW + dx) \/ charW);\r\n\r\n                \/\/ Recorto (contenimiento) y desplazo x para el scroll sub-char\r\n                const vis = big.slice(ch, ch + needChars);\r\n\r\n                ras.textAA(x0 - dx, y0, vis, inkV, aa);\r\n            }\r\n\r\n            \/* -------------------------------------------------------\r\n   Transport actions (real state)\r\n------------------------------------------------------- *\/\r\n\r\n            \/* Recording clip state:\r\n               - While REC is ON, we continuously grow (e = playhead) a live clip per ARMED track.\r\n               - If a track is disarmed mid-recording, its live clip is finalized immediately.\r\n               - If a track is armed mid-recording, a new live clip starts at the current playhead.\r\n            *\/\r\n            const recState = {\r\n                clips: new Map()\r\n            }; \/\/ Map<trackIndex, clipRef>\r\n\r\n            function recGainMulDb(db) {\r\n                return Math.pow(10, (Number(db) || 0) \/ 20);\r\n            }\r\n\r\n            \/* =========================================================\r\n               REC: Gain \u201cbaked\u201d por tiempo (evita re-escalar todo el clip)\r\n               - c.a queda como \u201ctrim\u201d est\u00e1tico (compat con clips viejos)\r\n               - c.ge = [{t:secondsFromClipStart, g:linearMul}, ...]\r\n            ========================================================= *\/\r\n\r\n            function clipEnvGainAtRel(ge, tRel) {\r\n                if (!ge || !ge.length) return 1;\r\n                tRel = Math.max(0, Number(tRel) || 0);\r\n                for (let i = ge.length - 1; i >= 0; i--) {\r\n                    if (tRel >= ge[i].t) return ge[i].g;\r\n                }\r\n                return ge[0].g;\r\n            }\r\n\r\n            function clipGainMulAt(c, tAbs) {\r\n                const base = (c && c.a != null) ? c.a : 1;\r\n                const ge = c && c.ge;\r\n                if (!ge || !ge.length) return base;\r\n                const tRel = Math.max(0, (Number(tAbs) || 0) - (Number(c.s) || 0));\r\n                return base * clipEnvGainAtRel(ge, tRel);\r\n            }\r\n\r\n            \/* En REC, \u201cstamp\u201d del gain en el tiempo actual del clip vivo *\/\r\n            function recApplyGainToLiveClip(ti) {\r\n                if (!isRecording) return;\r\n                const c = recState.clips.get(ti);\r\n                if (!c || !c.__rec) return;\r\n\r\n                const tr = tracks[ti];\r\n                const g = recGainMulDb(tr && tr.gainDb != null ? tr.gainDb : 0);\r\n\r\n                const tRel = Math.max(0, playhead - c.s);\r\n\r\n                if (!c.ge || !c.ge.length) c.ge = [{\r\n                    t: 0,\r\n                    g\r\n                }];\r\n\r\n                const ge = c.ge;\r\n                const last = ge[ge.length - 1];\r\n\r\n                \/* Si estamos muy cerca en el tiempo, actualiza el \u00faltimo punto (evita spam) *\/\r\n                if (last && Math.abs(last.t - tRel) < 0.03) {\r\n                    last.g = g;\r\n                } else {\r\n                    \/* Mantener monoton\u00eda *\/\r\n                    if (last && tRel < last.t) {\r\n                        last.g = g;\r\n                    } else {\r\n                        ge.push({\r\n                            t: tRel,\r\n                            g\r\n                        });\r\n                    }\r\n                }\r\n\r\n                \/* L\u00edmite defensivo (mantiene el punto inicial) *\/\r\n                if (ge.length > 96) ge.splice(1, ge.length - 96);\r\n            }\r\n\r\n            \/* Live config (refreshed each frame in draw()) *\/\r\n            let __recSineLive = 1; \/\/ --cvx-oled-rec-sine (default 1)\r\n            let __demoHzLive = 1.35; \/\/ --cvx-oled-demo-hz  (default 1.35 Hz)\r\n\r\n            function recBeginOnTrack(ti, t0, rtB) {\r\n                const tr = tracks[ti];\r\n                if (!tr) return;\r\n\r\n                const c = {\r\n                    id: allocClipId(),\r\n                    s: t0,\r\n                    e: t0 + 0.02, \/\/ tiny visible length; grows each frame\r\n                    o: 0, \/\/ source offset (when a datafile is assigned)\r\n                    a: 1,\r\n                    ge: [{\r\n                        t: 0,\r\n                        g: recGainMulDb(tr.gainDb)\r\n                    }],\r\n                    fx: [],\r\n                    fi: false,\r\n                    fo: false,\r\n                    m: [],\r\n                    __rec: 1,\r\n                    __rtB: (rtB != null ? +rtB : null),\r\n                };\r\n\r\n                tr.clips = tr.clips || [];\r\n                tr.clips.push(c);\r\n                recState.clips.set(ti, c);\r\n            }\r\n\r\n            function recEndOnTrack(ti, t1) {\r\n                const tr = tracks[ti];\r\n                const c = recState.clips.get(ti);\r\n                if (!tr || !c) return;\r\n\r\n                c.e = Math.max(c.s + 0.001, t1);\r\n                recState.clips.delete(ti);\r\n\r\n                \/* Keep clip list tidy (sort + remove micro-clips) *\/\r\n                tr.clips = normalizeClips(tr.clips || []);\r\n            }\r\n\r\n            function recStopAll(tNow) {\r\n                const keys = Array.from(recState.clips.keys());\r\n                for (const ti of keys) recEndOnTrack(ti, tNow);\r\n                recState.clips.clear();\r\n            }\r\n\r\n            function recSync(tNow) {\r\n                const useRetakeGate = (retakes.length > 0);\r\n                const hit = useRetakeGate ? retakeFindAt(tNow) : null;\r\n\r\n                for (let ti = 0; ti < tracks.length; ti++) {\r\n                    const tr = tracks[ti];\r\n                    const has = recState.clips.has(ti);\r\n\r\n                    const canRecNow = !!(tr && tr.arm) && (!useRetakeGate || !!hit);\r\n\r\n                    if (canRecNow) {\r\n                        const rtB = useRetakeGate ? hit.b : null;\r\n\r\n                        if (!has) {\r\n                            \/\/ overwrite content inside retake before starting new take\r\n                            if (useRetakeGate) {\r\n                                stripTrackClipsInRange(ti, hit.a, hit.b);\r\n                            }\r\n                            recBeginOnTrack(ti, tNow, rtB);\r\n\r\n                        } else {\r\n                            const c = recState.clips.get(ti);\r\n                            const limit = (c && c.__rtB != null) ? c.__rtB : null;\r\n\r\n                            \/\/ clamp live end to retake boundary\r\n                            if (limit != null) {\r\n                                c.e = Math.min(tNow, limit);\r\n                                if (tNow >= limit) {\r\n                                    recEndOnTrack(ti, limit);\r\n                                }\r\n                            } else {\r\n                                c.e = tNow;\r\n                            }\r\n                        }\r\n\r\n                    } else {\r\n                        if (has) {\r\n                            const c = recState.clips.get(ti);\r\n                            const limit = (c && c.__rtB != null) ? c.__rtB : null;\r\n                            recEndOnTrack(ti, (limit != null) ? Math.min(tNow, limit) : tNow);\r\n                        }\r\n                    }\r\n                }\r\n            }\r\n            \/* -------------------------------------------------------\r\n               Region playback bounds (demo)\r\n               - Active region = selection.s\/e (only if any selected track is audible under mute\/solo)\r\n               - regionLoopArm: auto-loop is armed only when region is created while NOT playing\r\n               - regionLoop.on: forces looping within the active region bounds\r\n            ------------------------------------------------------- *\/\r\n            const regionLoop = {\r\n                on: false,\r\n                a: 0,\r\n                b: 0\r\n            };\r\n            let regionLoopArm = false;\r\n\r\n            \/* Transport bound:\r\n               - on=true => hay \u201cstop marker\u201d expl\u00edcito (ej: play selection)\r\n               - a\/b => l\u00edmites (segundos)\r\n               - mode=\"region\" reservado por compat\/debug (no dependemos solo de mode)\r\n            *\/\r\n            const playBound = {\r\n                on: false,\r\n                mode: \"none\",\r\n                a: 0,\r\n                b: 0\r\n            };\r\n\r\n            \/* Region drag autopan (continuous, not only on pointermove) *\/\r\n            const regionAutoPan = {\r\n                x: 0,\r\n                overflowPx: 0\r\n            };\r\n\r\n            function getActiveRegionBounds() {\r\n                if (!selection) return null;\r\n\r\n                const maxT = timelineMaxSecondsAll();\r\n                let a = Math.min(selection.s, selection.e);\r\n                let b = Math.max(selection.s, selection.e);\r\n\r\n                a = clamp(a, 0, maxT);\r\n                b = clamp(b, 0, maxT);\r\n                if (!(b > a + 0.0005)) return null;\r\n\r\n                \/* Respect mute\/solo (optional):\r\n                   - When ON: region exists only if at least one explicitly selected track is audible.\r\n                   - When OFF (default): region is a transport\/UI construct and must stay stable (enables reliable looping).\r\n                *\/\r\n                const respectMuteSolo = !!css.bool(\"--cvx-oled-region-respect-mute-solo\", 0);\r\n\r\n                if (respectMuteSolo) {\r\n                    const set = selection.tracks;\r\n                    if (set && set.size) {\r\n                        const anySolo = tracks.some(tr => tr && tr.solo);\r\n                        let anyAudible = false;\r\n\r\n                        for (const ti of set) {\r\n                            const tr = tracks[ti | 0];\r\n                            if (!tr) continue;\r\n                            const audible = anySolo ? !!tr.solo : !tr.mute;\r\n                            if (audible) {\r\n                                anyAudible = true;\r\n                                break;\r\n                            }\r\n                        }\r\n                        if (!anyAudible) return null;\r\n                    }\r\n                }\r\n\r\n                return {\r\n                    a,\r\n                    b\r\n                };\r\n            }\r\n\r\n            function actPlayToggle() {\r\n                const wasPlaying = isPlaying;\r\n                isPlaying = !isPlaying;\r\n\r\n                \/* Leaving PLAY => clear transient bounds *\/\r\n                if (wasPlaying && !isPlaying) {\r\n                    playBound.on = false;\r\n                    playBound.mode = \"none\";\r\n                    setHud(\"PAUSE\", 750);\r\n                    pokeChrome();\r\n                    return;\r\n                }\r\n\r\n                \/* Start playback *\/\r\n                if (!wasPlaying && isPlaying) {\r\n                    playBound.on = false;\r\n                    playBound.mode = \"none\";\r\n\r\n                    const r = (!isRecording) ? getActiveRegionBounds() : null;\r\n\r\n                    if (r) {\r\n                        const wantLoopInRegion = (!!isLooping) || !!regionLoopArm;\r\n\r\n                        if (wantLoopInRegion) {\r\n                            regionLoop.on = true;\r\n                            regionLoop.a = r.a;\r\n                            regionLoop.b = r.b;\r\n\r\n                            \/* keep UI consistent *\/\r\n                            isLooping = true;\r\n                            regionLoopArm = false;\r\n\r\n                            playBound.on = false;\r\n                            playBound.mode = \"none\";\r\n                        } else {\r\n                            \/* Non-loop \u201cplay selection\u201d: stop at selection end *\/\r\n                            playBound.on = true;\r\n                            playBound.mode = \"region\";\r\n                            playBound.a = r.a;\r\n                            playBound.b = r.b;\r\n\r\n                            \/* Si ven\u00eds desde STOP y el cursor est\u00e1 fuera, arranc\u00e1 en el inicio de la selecci\u00f3n *\/\r\n                            if (playhead < r.a || playhead > r.b) playhead = r.a;\r\n                        }\r\n                    } else {\r\n                        regionLoopArm = false;\r\n                        regionLoop.on = false;\r\n                        playBound.on = false;\r\n                        playBound.mode = \"none\";\r\n                    }\r\n\r\n                    setHud(\"PLAY\", 750);\r\n                    pokeChrome();\r\n                    return;\r\n                }\r\n\r\n                \/* fallback *\/\r\n                if (isPlaying) setHud(\"PLAY\", 750);\r\n                else setHud(\"PAUSE\", 750);\r\n                pokeChrome();\r\n            }\r\n\r\n            function actStop() {\r\n                playBound.on = false;\r\n                playBound.mode = \"none\";\r\n                const tNow = playhead;\r\n                if (isRecording) recStopAll(tNow);\r\n\r\n                const r = (!isRecording) ? getActiveRegionBounds() : null;\r\n                playhead = r ? r.a : 0;\r\n                playhead = clamp(playhead, 0, timelineMaxSecondsAll());\r\n                isPlaying = false;\r\n                isRecording = false;\r\n                setHud(\"STOP\", 750);\r\n                pokeChrome();\r\n            }\r\n\r\n            function actRecToggle() {\r\n                if (!isRecording) {\r\n                    \/* REC ON: only if at least one track is armed *\/\r\n                    const anyArmed = tracks.some(tr => tr.arm);\r\n                    if (!anyArmed) {\r\n                        setHud(\"ARM TRK\", 850);\r\n                        pokeChrome();\r\n                        return;\r\n                    }\r\n                    \/* REC autoload: si el track armado no tiene aud pero existe pool, cargalo sin tocar clips ni playhead *\/\r\n                    if (css.bool(\"--cvx-oled-rec-autoload-audio\", 1)) {\r\n                        const pool = datafilePool();\r\n                        if (pool.length) {\r\n                            for (let ti = 0; ti < tracks.length; ti++) {\r\n                                const tr = tracks[ti];\r\n                                if (!tr.arm) continue;\r\n                                if (tr.aud) continue;\r\n\r\n                                const idx = (tr.fileIdx != null && tr.fileIdx >= 0) ? tr.fileIdx : ti;\r\n\r\n                                void loadDatafileAudioOnly(ti, idx).then((ok) => {\r\n                                    if (ok) pokeChrome();\r\n                                });\r\n                            }\r\n                        }\r\n                    }\r\n                    isRecording = true;\r\n                    isPlaying = true;\r\n\r\n                    recSync(playhead); \/\/ create initial live clips for armed tracks\r\n                    setHud(\"REC\", 800);\r\n                } else {\r\n                    \/* REC OFF *\/\r\n                    recStopAll(playhead);\r\n                    isRecording = false;\r\n                    setHud(\"REC OFF\", 800);\r\n                }\r\n                pokeChrome();\r\n            }\r\n\r\n            function actLoopToggle() {\r\n                isLooping = !isLooping;\r\n\r\n                if (!isLooping) {\r\n                    regionLoop.on = false;\r\n                    regionLoopArm = false;\r\n                }\r\n\r\n                setHud(isLooping ? \"LOOP\" : \"LOOP OFF\", 750);\r\n                pokeChrome();\r\n            }\r\n\r\n            \/* -------------------------------------------------------\r\n               Clip ops\r\n            ------------------------------------------------------- *\/\r\n            function cloneClip(c) {\r\n                const out = Object.assign({}, c, {\r\n                    fx: (c.fx || []).slice(),\r\n                    m: (c.m || []).map(mm => ({\r\n                        a: mm.a,\r\n                        b: mm.b,\r\n                        t: String(mm.t || \"\")\r\n                    }))\r\n                });\r\n                if (c.ge && c.ge.length) out.ge = c.ge.map(p => ({\r\n                    t: +p.t,\r\n                    g: +p.g\r\n                }));\r\n                return out;\r\n            }\r\n\r\n            function clipMarksForSegment(marks, segS, segE) {\r\n                if (!marks || !marks.length) return [];\r\n                const out = [];\r\n                for (const mm of marks) {\r\n                    const a = Math.max(segS, mm.a);\r\n                    const b = Math.min(segE, mm.b);\r\n                    if (b > a) out.push({\r\n                        a,\r\n                        b,\r\n                        t: mm.t\r\n                    });\r\n                }\r\n                return out;\r\n            }\r\n\r\n            function splitClipAt(c, t) {\r\n                if (t <= c.s || t >= c.e) return [c];\r\n\r\n                const srcOfs = (c.o != null) ? c.o : c.s; \/\/ fallback si hay clips viejos sin 'o'\r\n\r\n                const a = cloneClip(c);\r\n                a.e = t;\r\n                a.o = srcOfs;\r\n                a.m = clipMarksForSegment(a.m, a.s, a.e);\r\n\r\n                const b = cloneClip(c);\r\n                b.s = t;\r\n                b.o = srcOfs + (t - c.s); \/\/ <- CLAVE: la 2da mitad arranca m\u00e1s adelante en la fuente\r\n                b.m = clipMarksForSegment(b.m, b.s, b.e);\r\n                \/* Rebanar \/ rebasear gain envelope (tiempo relativo al inicio del clip) *\/\r\n                if (c.ge && c.ge.length) {\r\n                    const splitRel = t - c.s;\r\n\r\n                    a.ge = c.ge.filter(p => p.t <= splitRel).map(p => ({\r\n                        t: p.t,\r\n                        g: p.g\r\n                    }));\r\n\r\n                    const gAtSplit = clipEnvGainAtRel(c.ge, splitRel);\r\n                    const tail = c.ge\r\n                        .filter(p => p.t >= splitRel)\r\n                        .map(p => ({\r\n                            t: p.t - splitRel,\r\n                            g: p.g\r\n                        }));\r\n\r\n                    if (!tail.length || tail[0].t > 0) tail.unshift({\r\n                        t: 0,\r\n                        g: gAtSplit\r\n                    });\r\n                    else tail[0].g = gAtSplit;\r\n\r\n                    b.ge = tail;\r\n                }\r\n                return [a, b];\r\n            }\r\n\r\n\r\n            function normalizeClips(list) {\r\n                list.sort((x, y) => x.s - y.s);\r\n                return list.filter(c => (c.e - c.s) > 0.5);\r\n            }\r\n\r\n            function sliceClipOutsideRegion(c, a, b) {\r\n                if (c.e <= a || c.s >= b) return [c];\r\n                let parts = [c];\r\n                parts = parts.flatMap(p => splitClipAt(p, a));\r\n                parts = parts.flatMap(p => splitClipAt(p, b));\r\n                return parts.filter(p => (p.e <= a) || (p.s >= b));\r\n            }\r\n\r\n            function applyCut(sel, ripple) {\r\n                if (!sel) return;\r\n                const a = Math.min(sel.s, sel.e);\r\n                const b = Math.max(sel.s, sel.e);\r\n                const delta = b - a;\r\n\r\n                sel.tracks.forEach(ti => {\r\n                    const tr = tracks[ti];\r\n                    let next = [];\r\n                    for (const c of tr.clips) next.push(...sliceClipOutsideRegion(c, a, b));\r\n\r\n                    if (ripple) {\r\n                        next = next.map(c => {\r\n                            if (c.s >= b) {\r\n                                const n = cloneClip(c);\r\n                                n.s -= delta;\r\n                                n.e -= delta;\r\n                                if (n.m && n.m.length) {\r\n                                    n.m = n.m.map(mm => ({\r\n                                        a: mm.a - delta,\r\n                                        b: mm.b - delta,\r\n                                        t: mm.t\r\n                                    }));\r\n                                }\r\n                                return n;\r\n                            }\r\n                            return c;\r\n                        });\r\n                    }\r\n                    tr.clips = normalizeClips(next);\r\n                });\r\n\r\n                playhead = a;\r\n                sel.s = a;\r\n                sel.e = a + 0.01;\r\n            }\r\n\r\n            function applyDelete(sel, ripple) {\r\n                applyCut(sel, ripple);\r\n            }\r\n\r\n            function findClipAt(ti, t) {\r\n                if (ti < 0 || ti >= tracks.length) return null;\r\n                const tr = tracks[ti];\r\n                for (const c of tr.clips) {\r\n                    if (t >= c.s && t <= c.e) return c;\r\n                }\r\n                return null;\r\n            }\r\n\r\n            function ensureSelectionExists() {\r\n                if (!selection) {\r\n                    selection = {\r\n                        s: playhead - 6,\r\n                        e: playhead + 6,\r\n                        tracks: new Set(multiSel)\r\n                    };\r\n                } else {\r\n                    selection.tracks = new Set(multiSel);\r\n                }\r\n            }\r\n\r\n            \/* -------------------------------------------------------\r\n               EXEC: Menu actions\r\n            ------------------------------------------------------- *\/\r\n            function forEachTargetClip(fn) {\r\n                if (selection && selection.tracks && selection.tracks.size) {\r\n                    const a = Math.min(selection.s, selection.e);\r\n                    const b = Math.max(selection.s, selection.e);\r\n                    selection.tracks.forEach(ti => {\r\n                        const tr = tracks[ti];\r\n                        for (const c of tr.clips) {\r\n                            if (c.e <= a || c.s >= b) continue;\r\n                            fn(tr, c, a, b);\r\n                        }\r\n                    });\r\n                    return true;\r\n                }\r\n\r\n                const c = findClipAt(activeTrack, playhead);\r\n                if (c) {\r\n                    fn(tracks[activeTrack], c, playhead, playhead);\r\n                    return true;\r\n                }\r\n                return false;\r\n            }\r\n\r\n            function execAction(label) {\r\n                const it = String(label || \"\").toUpperCase();\r\n\r\n                const splitAtPlayhead = () => {\r\n                    const targetTracks = (selection && selection.tracks && selection.tracks.size) ?\r\n                        Array.from(selection.tracks) :\r\n                        Array.from(multiSel);\r\n\r\n                    let did = false;\r\n\r\n                    for (const ti of targetTracks) {\r\n                        const tr = tracks[ti];\r\n                        const c = findClipAt(ti, playhead);\r\n                        if (!c) continue;\r\n\r\n                        const parts = splitClipAt(c, playhead);\r\n                        if (parts.length === 1) continue;\r\n\r\n                        const next = [];\r\n                        for (const cc of tr.clips) {\r\n                            if (cc === c) next.push(...parts);\r\n                            else next.push(cc);\r\n                        }\r\n                        tr.clips = normalizeClips(next);\r\n                        did = true;\r\n                    }\r\n\r\n                    if (did) setHud(\"SPLIT\", 700);\r\n                    else setHud(\"NO CLIP\", 650);\r\n                };\r\n\r\n                if (it === \"SPLIT\") {\r\n                    splitAtPlayhead();\r\n                    return;\r\n                }\r\n\r\n                if (it === \"CUT\") {\r\n                    ensureSelectionExists();\r\n                    applyCut(selection, false);\r\n                    setHud(\"CUT\", 700);\r\n                    return;\r\n                }\r\n\r\n                if (it === \"DELETE\") {\r\n                    ensureSelectionExists();\r\n                    const ripple = css.bool(\"--cvx-oled-ripple-delete\", 1) ? true : false;\r\n                    applyDelete(selection, ripple);\r\n                    setHud(\"DELETE\", 700);\r\n                    return;\r\n                }\r\n\r\n                if (it === \"CHOR\" || it === \"DLY\" || it === \"RVB\" || it === \"EQ\" || it === \"CMP\") {\r\n                    const ok = forEachTargetClip((tr, c) => {\r\n                        c.fx = [it];\r\n                    });\r\n                    setHud(ok ? it : \"NO CLIP\", 650);\r\n                    return;\r\n                }\r\n                if (it === \"CLR FX\") {\r\n                    const ok = forEachTargetClip((tr, c) => {\r\n                        c.fx = [];\r\n                    });\r\n                    setHud(ok ? \"FX CLR\" : \"NO CLIP\", 650);\r\n                    return;\r\n                }\r\n\r\n                if (it === \"FD IN\") {\r\n                    const ok = forEachTargetClip((tr, c) => {\r\n                        c.fi = true;\r\n                    });\r\n                    setHud(ok ? \"FD IN\" : \"NO CLIP\", 650);\r\n                    return;\r\n                }\r\n                if (it === \"FD OUT\") {\r\n                    const ok = forEachTargetClip((tr, c) => {\r\n                        c.fo = true;\r\n                    });\r\n                    setHud(ok ? \"FD OUT\" : \"NO CLIP\", 650);\r\n                    return;\r\n                }\r\n                if (it === \"XFAD\") {\r\n                    const ok = forEachTargetClip((tr, c) => {\r\n                        c.fi = true;\r\n                        c.fo = true;\r\n                    });\r\n                    setHud(ok ? \"XFAD\" : \"NO CLIP\", 650);\r\n                    return;\r\n                }\r\n                if (it === \"CLR FD\") {\r\n                    const ok = forEachTargetClip((tr, c) => {\r\n                        c.fi = false;\r\n                        c.fo = false;\r\n                    });\r\n                    setHud(ok ? \"FD CLR\" : \"NO CLIP\", 650);\r\n                    return;\r\n                }\r\n                if (it === \"RETAKE\") {\r\n                    ensureSelectionExists();\r\n                    const ok = retakeAddFromSelection(selection);\r\n                    if (ok) {\r\n                        setHud(\"RETAKE SET\", 650);\r\n                        \/\/ opcional: dejar selecci\u00f3n o limpiarla. Para demo, limpio para que quede solo el retake.\r\n                        selection = null;\r\n                    } else {\r\n                        setHud(\"NO REGION\", 650);\r\n                    }\r\n                    return;\r\n                }\r\n\r\n                if (it === \"DELETE RETAKE\") {\r\n                    const ok = retakeDeleteAtPlayhead();\r\n                    setHud(ok ? \"RETAKE DEL\" : \"NO RETAKE\", 650);\r\n                    return;\r\n                }\r\n                setHud(\"N\/A\", 550);\r\n            }\r\n            \/* -------------------------------------------------------\r\n               HARD RESET (boot state)\r\n               - Triggered by --cvx-oled-hotkey-reset (default \"*\")\r\n               - Rebuilds tracks + UI state to initial load values\r\n            ------------------------------------------------------- *\/\r\n            function __recomputeClipIdSeq() {\r\n                __clipIdSeq = 1;\r\n                for (const tr of tracks) {\r\n                    const list = tr.clips || [];\r\n                    for (const c of list) __clipIdSeq = Math.max(__clipIdSeq, ((c.id | 0) + 1) || 1);\r\n                }\r\n            }\r\n\r\n            function __rebuildTracksBoot() {\r\n                const fresh = buildTracks(CVX_DEMO_MODE, CVX_TRACKS_INIT, {\r\n                    defs: CVX_TRACK_DEFAULTS,\r\n                    nameTpl: CVX_TR_DEF_NAME_TPL,\r\n                    srcDef: CVX_TR_DEF_SRC,\r\n                    gainDef: CVX_TR_DEF_GAIN_DB,\r\n                    volDef: CVX_TR_DEF_VOL,\r\n                    muteDef: CVX_TR_DEF_MUTE,\r\n                    soloDef: CVX_TR_DEF_SOLO,\r\n                    armDef: CVX_TR_DEF_ARM\r\n                });\r\n\r\n                tracks.length = 0;\r\n                for (const t of fresh) tracks.push(t);\r\n\r\n                __recomputeClipIdSeq();\r\n                resizeTrackMeterArrays(tracks.length);\r\n                if (trMeter.length) trMeter.fill(0);\r\n                if (trPeak.length) trPeak.fill(0);\r\n                if (trPeakT.length) trPeakT.fill(0);\r\n                reportTracks(\"tracks:reset\");\r\n            }\r\n\r\n            function resetToBoot() {\r\n                \/* Stop transport and finalize any live REC clips *\/\r\n                if (isPlaying || isRecording) actStop();\r\n                try {\r\n                    recState.clips.clear();\r\n                } catch (_) {}\r\n\r\n                \/* Cancel any active drags (safe: vars exist by runtime) *\/\r\n                try {\r\n                    dragging = false;\r\n                    draggingRegion = false;\r\n                    dragMoved = false;\r\n                    ctlDrag = null;\r\n                } catch (_) {}\r\n\r\n                \/* Panels + HUD *\/\r\n                menu.open = false;\r\n                menu.level = \"main\";\r\n                menu.idx = 0;\r\n                menu.anim = 0;\r\n\r\n                masterPanel.open = false;\r\n                masterPanel.idx = 0;\r\n                masterPanel.top = 0;\r\n                masterPanel.anim = 0;\r\n\r\n                \/* Versions popup (modal) *\/\r\n                try {\r\n                    verPopup.open = false;\r\n                    verPopup.view = \"save\";\r\n                    verPopup.sel = 1; \/* default focus: SAVE *\/\r\n                    verPopup.toastUntil = 0;\r\n                    verPopup.toastTxt = \"\";\r\n                    verPopup.toastRight = \"\";\r\n                    verPopup.btns.length = 0;\r\n                    verPopup.hIdx = 0;\r\n                    verPopup.hTop = 0;\r\n\r\n                    \/* \u201creset borra todo\u201d: volvemos a un history m\u00ednimo (demo) *\/\r\n                    verPopup.hist = [{\r\n                            id: \"V03\",\r\n                            name: \"VERSE TAKE\"\r\n                        },\r\n                        {\r\n                            id: \"V02\",\r\n                            name: \"CHORUS DRAFT\"\r\n                        }\r\n                    ];\r\n                } catch (_) {}\r\n\r\n                \/* Config demo: Sync vuelve a default *\/\r\n                try {\r\n                    syncMode = 0;\r\n                } catch (_) {}\r\n\r\n                hud.text = \"\";\r\n                hud.until = 0;\r\n\r\n                \/* Master + output preset *\/\r\n                master.vol = __BOOT.master.vol;\r\n                master.mute = __BOOT.master.mute;\r\n\r\n                outputSel.type = __BOOT.outputSel.type;\r\n                outputSel.ports = __BOOT.outputSel.ports.slice();\r\n                outputSel.presetIdx = __BOOT.outputSel.presetIdx;\r\n\r\n                masterL = masterR = 0;\r\n                masterLP = masterRP = 0;\r\n                masterLPt = masterRPt = 0;\r\n\r\n                \/* Timeline + zoom *\/\r\n                zoomX = __BOOT.zoomX;\r\n                zoomY = __BOOT.zoomY;\r\n                waveZoomDb = __BOOT.waveZoomDb;\r\n                viewStart = __BOOT.viewStart;\r\n                playhead = __BOOT.playhead;\r\n\r\n                isPlaying = false;\r\n                isRecording = false;\r\n                isLooping = false;\r\n\r\n                \/* Tracks + meters *\/\r\n                __rebuildTracksBoot();\r\n\r\n                \/* List selection *\/\r\n                trackTop = 0;\r\n                activeTrack = -1;\r\n                multiSel = tracks.length ? new Set([0]) : new Set();\r\n                selection = null;\r\n                retakes.length = 0;\r\n\r\n                \/* Re-run init autoload behavior (if enabled) *\/\r\n                autoloadDatafiles();\r\n\r\n                ensureView();\r\n                setHud(\"RESET\", 650);\r\n                pokeChrome();\r\n            }\r\n            \/* -------------------------------------------------------\r\n               Meter model (track + master)\r\n            ------------------------------------------------------- *\/\r\n            function clipLevelAt(tr, t) {\r\n                if (tr.mute) return 0;\r\n\r\n                const ti = tracks.indexOf(tr);\r\n                const c = findClipAt(ti, t);\r\n                if (!c) return 0;\r\n\r\n                \/\/ If real audio is available for this track, drive meters from that audio.\r\n                const aud = tr.aud;\r\n                if (aud && aud.mono && aud.mono.length) {\r\n                    const sr = aud.sr || 44100;\r\n                    const srcOfs = (c.o != null) ? c.o : c.s; \/\/ same mapping used in waveform draw\r\n                    const tSrc = (t - c.s) + srcOfs; \/\/ timeline -> source time\r\n                    if (tSrc < 0) return 0;\r\n\r\n                    \/\/ Small window so the meter follows the visible waveform behavior.\r\n                    const win = Math.max(16, Math.floor(sr * 0.025)); \/\/ ~25 ms\r\n                    const s0 = Math.floor(tSrc * sr);\r\n                    const s1 = s0 + win;\r\n\r\n                    \/\/ IMPORTANT: use the same sampler as waveform draw (supports aud.loop)\r\n                    const mm = minMaxInSampleRange(aud, s0, s1);\r\n                    let peak = Math.max(Math.abs(mm.min), Math.abs(mm.max));\r\n\r\n\r\n                    \/\/ Apply clip + track gain staging (linear)\r\n                    const gClip = clipGainMulAt(c, t); \/\/ <- ahora depende del tiempo si hay c.ge\r\n                    const gVol = (tr.vol != null) ? (tr.vol \/ 100) : 1;\r\n                    const g = gVol * gClip;\r\n\r\n                    peak *= g;\r\n                    return clamp(peak, 0, 1);\r\n                }\r\n\r\n                \/\/ Fallback animation (demo-only if --cvx-oled-nodata-sine=1)\r\n                if (!CVX_NODATA_SINE) return 0;\r\n\r\n                const u = clamp((t - c.s) \/ Math.max(0.001, (c.e - c.s)), 0, 1);\r\n                const tex = Math.sin((u * 6.2831 * 3) + (tr.seed * 0.2)) * 0.5 + 0.5;\r\n                const a = (0.25 + 0.75 * tex) * clipGainMulAt(c, t);\r\n                return clamp(a, 0, 1);\r\n            }\r\n\r\n\r\n            function computeMixLevels(t) {\r\n                let sum = 0;\r\n                const soloAny = tracks.some(tr => tr.solo);\r\n\r\n                \/* si hay al menos 1 track con data real (aud + clips), NO aplicamos wobble senoidal *\/\r\n                let anyReal = false;\r\n\r\n                for (let i = 0; i < tracks.length; i++) {\r\n                    const tr = tracks[i];\r\n                    if (soloAny && !tr.solo) continue;\r\n                    if (tr.mute) continue;\r\n\r\n                    if (tr.aud && tr.clips && tr.clips.length) anyReal = true;\r\n\r\n                    sum += clipLevelAt(tr, t);\r\n                }\r\n\r\n                sum = clamp(sum \/ Math.max(1, tracks.length * 0.55), 0, 1);\r\n\r\n                if (!anyReal) {\r\n                    if (!CVX_NODATA_SINE) return {\r\n                        l: 0,\r\n                        r: 0\r\n                    };\r\n\r\n                    \/* fallback visual: \u201calive\u201d sin data real *\/\r\n                    const l = sum * (0.92 + 0.08 * Math.sin(t * 0.12));\r\n                    const r = sum * (0.92 + 0.08 * Math.cos(t * 0.11));\r\n                    return {\r\n                        l: clamp(l, 0, 1),\r\n                        r: clamp(r, 0, 1)\r\n                    };\r\n                }\r\n\r\n                \/* con data real, el master refleja la amplitud (mono) *\/\r\n                return {\r\n                    l: sum,\r\n                    r: sum\r\n                };\r\n            }\r\n\r\n            \/* -------------------------------------------------------\r\n               Render helpers (format)\r\n            ------------------------------------------------------- *\/\r\n            function formatTPrec(v, dec, pad) {\r\n                dec = clamp((dec == null ? 0 : dec) | 0, 0, 3);\r\n                pad = (pad == null ? 3 : pad) | 0;\r\n                const p = Math.pow(10, dec);\r\n                const n = Math.round(v * p) \/ p;\r\n                let s = n.toFixed(dec);\r\n                if (dec > 0) {\r\n                    const parts = s.split(\".\");\r\n                    parts[0] = String(parts[0]).padStart(pad, \"0\");\r\n                    s = parts[0] + \".\" + parts[1];\r\n                } else {\r\n                    s = String(s).padStart(pad, \"0\");\r\n                }\r\n                return s;\r\n            }\r\n\r\n            \/* -------------------------------------------------------\r\n               Transport icon raster (OLED)\r\n            ------------------------------------------------------- *\/\r\n            function drawPlayIcon(cx, cy, ink, isPaused) {\r\n                if (isPaused) {\r\n                    ras.pxMax(cx - 2, cy - 3, ink);\r\n                    ras.pxMax(cx - 2, cy - 2, ink);\r\n                    ras.pxMax(cx - 2, cy - 1, ink);\r\n                    ras.pxMax(cx - 2, cy + 0, ink);\r\n                    ras.pxMax(cx - 2, cy + 1, ink);\r\n\r\n                    ras.pxMax(cx - 1, cy - 2, ink);\r\n                    ras.pxMax(cx - 1, cy - 1, ink);\r\n                    ras.pxMax(cx - 1, cy + 0, ink);\r\n\r\n                    ras.pxMax(cx - 0, cy - 1, ink);\r\n                } else {\r\n                    ras.vline(cx - 2, cy - 3, cy + 1, ink);\r\n                    ras.vline(cx - 0, cy - 3, cy + 1, ink);\r\n                }\r\n            }\r\n\r\n            function drawStopIcon(cx, cy, ink) {\r\n                ras.fillRect(cx - 3, cy - 3, 5, 5, ink);\r\n            }\r\n\r\n            function drawRecIcon(cx, cy, ink, on) {\r\n                const v = on ? ink : Math.round(ink * 0.55);\r\n                const pts = [\r\n                    [-1, -3],\r\n                    [-2, -3],\r\n                    [0, -3],\r\n                    [-3, -2],\r\n                    [-2, -2],\r\n                    [-1, -2],\r\n                    [0, -2],\r\n                    [1, -2],\r\n                    [-3, -1],\r\n                    [-2, -1],\r\n                    [-1, -1],\r\n                    [0, -1],\r\n                    [1, -1],\r\n                    [-3, 0],\r\n                    [-2, 0],\r\n                    [-1, 0],\r\n                    [0, 0],\r\n                    [1, 0],\r\n                    [-1, 1],\r\n                    [-2, 1],\r\n                    [0, 1]\r\n                ];\r\n                for (const p of pts) ras.pxMax(cx + p[0], cy + p[1], v);\r\n            }\r\n\r\n            function drawLoopIcon(cx, cy, ink, on) {\r\n                const v = on ? ink : Math.round(ink * 0.55);\r\n                ras.pxMax(cx - 3, cy - 2, v);\r\n                ras.pxMax(cx - 4, cy - 2, v);\r\n                ras.pxMax(cx - 4, cy - 1, v);\r\n                ras.pxMax(cx - 4, cy, v);\r\n                ras.pxMax(cx - 4, cy + 1, v);\r\n                ras.pxMax(cx - 4, cy + 2, v);\r\n                ras.pxMax(cx - 3, cy + 2, v);\r\n                ras.pxMax(cx - 2, cy + 2, v);\r\n                ras.pxMax(cx - 1, cy + 2, v);\r\n                ras.pxMax(cx, cy + 2, v);\r\n                ras.pxMax(cx + 1, cy + 2, v);\r\n                ras.pxMax(cx + 2, cy + 2, v);\r\n                ras.pxMax(cx + 3, cy + 2, v);\r\n                ras.pxMax(cx + 3, cy + 1, v);\r\n                ras.pxMax(cx + 3, cy, v);\r\n                ras.pxMax(cx + 3, cy - 1, v);\r\n                ras.pxMax(cx + 3, cy - 2, v);\r\n                ras.pxMax(cx + 2, cy - 2, v);\r\n                ras.pxMax(cx + 1, cy - 2, v);\r\n\r\n                ras.pxMax(cx + 1, cy - 4, v);\r\n                ras.pxMax(cx + 1, cy - 3, v);\r\n                ras.pxMax(cx + 1, cy - 1, v);\r\n                ras.pxMax(cx + 1, cy, v);\r\n                ras.pxMax(cx, cy - 1, v);\r\n                ras.pxMax(cx, cy - 2, v);\r\n                ras.pxMax(cx, cy - 3, v);\r\n                ras.pxMax(cx - 1, cy - 2, v);\r\n            }\r\n\r\n            \/* -------------------------------------------------------\r\n               Render\r\n            ------------------------------------------------------- *\/\r\n            let dragging = false;\r\n            let draggingRegion = false;\r\n            let dragStartT = 0;\r\n            let dragMoved = false;\r\n            let dragStartX = 0;\r\n            let regionPointerId = null; \/\/ mantiene move\/up aunque el puntero salga del canvas\r\n            \/* -------------------------------------------------------\r\n               Control drag (GAIN \/ VOL) \u2014 mouse on sliders (X1)\r\n            ------------------------------------------------------- *\/\r\n            let ctlDrag = null;\r\n            \/* shape:\r\n              { pid:number, kind:\"gain\"|\"vol\", ti:number, barX:number, barW:number }\r\n            *\/\r\n\r\n            function applyCtlFromX(kind, ti, x, barX, barW) {\r\n                if (ti < 0 || ti >= tracks.length) return;\r\n\r\n                const tr = tracks[ti];\r\n                const xClamped = clamp(x, barX, barX + barW - 1);\r\n\r\n                if (kind === \"gain\") {\r\n                    const gMin = -20,\r\n                        gMax = 60;\r\n                    const cx = barX + Math.floor(barW \/ 2);\r\n                    const half = Math.max(1, Math.floor(barW \/ 2));\r\n\r\n                    let g;\r\n                    if (xClamped <= cx) {\r\n                        const t = clamp((xClamped - barX) \/ half, 0, 1);\r\n                        g = gMin + t * (0 - gMin);\r\n                    } else {\r\n                        const t = clamp((xClamped - cx) \/ half, 0, 1);\r\n                        g = 0 + t * (gMax - 0);\r\n                    }\r\n\r\n                    tr.gainDb = clampi(Math.round(g), gMin, gMax);\r\n                    setHud(\"GAIN \" + tr.gainDb + \"DB\", 350);\r\n                    recApplyGainToLiveClip(ti);\r\n                    return;\r\n                }\r\n\r\n                if (kind === \"vol\") {\r\n                    const denom = Math.max(1, (barW - 1));\r\n                    const t = clamp((xClamped - barX) \/ denom, 0, 1);\r\n                    tr.vol = clampi(Math.round(100 * t), 0, 100);\r\n                    setHud(\"VOL \" + tr.vol, 350);\r\n                    return;\r\n                }\r\n            }\r\n\r\n            function draw(dt) {\r\n                ensureView();\r\n\r\n                const now = performance.now();\r\n\r\n                const bg0 = clamp(css.int(\"--cvx-oled-bg\", 0), 0, 80);\r\n                const aa = clamp(css.flt(\"--cvx-oled-aa\", 0.62), 0, 0.85);\r\n\r\n                const hudA = clamp(css.flt(\"--cvx-oled-hud-alpha\", 0.92), 0, 1);\r\n                const footA = clamp(css.flt(\"--cvx-oled-footer-hint-alpha\", 0.78), 0, 1);\r\n                const labelA = clamp(css.flt(\"--cvx-oled-label-alpha\", 0.92), 0, 1);\r\n\r\n                const regMode = css.bool(\"--cvx-oled-region-mode\", 0) ? 1 : 0;\r\n                const regBodyA = clamp(css.flt(\"--cvx-oled-region-alpha-body\", 0.18), 0, 1);\r\n                const regEdgeA = clamp(css.flt(\"--cvx-oled-region-alpha-edge\", 0.95), 0, 1);\r\n\r\n                const markA = clamp(css.flt(\"--cvx-oled-mark-alpha\", 0.34), 0, 1);\r\n                const markInkA = clamp(css.flt(\"--cvx-oled-mark-ink\", 0.94), 0, 1);\r\n                const markStrokeA = clamp(css.flt(\"--cvx-oled-mark-stroke\", 0.62), 0, 1);\r\n\r\n                const strokeOn = css.bool(\"--cvx-oled-stroke-on\", 1) ? 1 : 0;\r\n                \/* Live demo source controls (used by meters + waveform fallback) *\/\r\n                __recSineLive = css.bool(\"--cvx-oled-rec-sine\", 1) ? 1 : 0;\r\n                __demoHzLive = clamp(css.flt(\"--cvx-oled-demo-hz\", 1.35), 0.15, 8.0);\r\n\r\n                const hudActive = (hud.until > now && hud.text);\r\n\r\n                if (menu.open || masterPanel.open || dragging || selection) chrome.target = 1;\r\n                else if (now > chrome.hideAt) chrome.target = 0;\r\n\r\n                const kIn = clamp(css.flt(\"--cvx-oled-chrome-anim-in\", 0.38), 0.02, 0.95);\r\n                const kOut = clamp(css.flt(\"--cvx-oled-chrome-anim-out\", 0.24), 0.02, 0.95);\r\n                chrome.v = lerp(chrome.v, chrome.target, (chrome.target > chrome.v) ? kIn : kOut);\r\n                if (chrome.v < 0.01) chrome.v = 0;\r\n\r\n                const exp = clamp(css.flt(\"--cvx-oled-chrome-exp\", 1.70), 1.0, 2.6);\r\n                const chromep = Math.pow(chrome.v, exp);\r\n\r\n                const baseHeader = clamp(css.int(\"--cvx-oled-header-h\", 5), 0, 12);\r\n                const baseFooter = clamp(css.int(\"--cvx-oled-footer-h\", 5), 0, 12);\r\n                L.headerH = Math.round(baseHeader * chromep);\r\n                L.footerH = Math.round(baseFooter * chromep);\r\n\r\n                const chromeMinA = clamp(css.flt(\"--cvx-oled-chrome-min-alpha\", 0.52), 0, 1);\r\n                const chromeA = chromeMinA + (1 - chromeMinA) * chrome.v;\r\n\r\n                const bright = 235;\r\n                const mid = 175;\r\n                const dim = 105;\r\n\r\n                L.listW = clamp(css.int(\"--cvx-oled-list-w\", 74), 58, 110);\r\n                L.masterBarW = (css.bool(\"--cvx-oled-masterbar-on\", 1) ? clamp(css.int(\"--cvx-oled-masterbar-w\", 10), 6, 18) : 0);\r\n\r\n                \/* ---- region drag autopan (continuous) ---- *\/\r\n                if (draggingRegion && regionAutoPan.overflowPx) {\r\n                    const span = timelineSpan();\r\n                    let maxT = timelineMaxSecondsAll();\r\n                    maxT += clamp(css.flt(\"--cvx-oled-timeline-pad-s\", 30), 0, 600);\r\n\r\n                    \/* must match xToTime() geometry *\/\r\n                    const x0 = L.pad + L.listW + L.gap;\r\n                    const x1 = W - L.pad - 1 - L.masterBarW;\r\n                    const vw = Math.max(1, x1 - x0 + 1);\r\n                    const secPerPx = span \/ Math.max(1, (vw - 1));\r\n\r\n                    const gain = clamp(css.flt(\"--cvx-oled-autopan-gain\", 1.0), 0.25, 6);\r\n                    const panK = (dt \/ 16.6667); \/* preserve legacy \"per move\" feel *\/\r\n\r\n                    const maxVS = Math.max(0, maxT - span);\r\n                    const oldVS = viewStart;\r\n\r\n                    const delta = regionAutoPan.overflowPx * secPerPx * gain * panK;\r\n                    viewStart = clamp(viewStart + delta, 0, maxVS);\r\n\r\n                    \/* Si ya estamos en el borde y seguimos empujando hacia afuera, anul\u00e1 el overflow para que no \u201crebote\u201d *\/\r\n                    if (viewStart === oldVS) {\r\n                        if ((viewStart <= 0 && delta < 0) || (viewStart >= maxVS && delta > 0)) {\r\n                            regionAutoPan.overflowPx = 0;\r\n                        }\r\n                    }\r\n                    \/* Keep selection extending even if pointer is held outside *\/\r\n                    if (selection) selection.e = xToTime(regionAutoPan.x);\r\n                }\r\n\r\n                \/* ---- playback advance (content-aware + region\/loop + REC-safe) ---- *\/\r\n                const maxTAll = timelineMaxSecondsAll();\r\n                const maxTAud = timelineMaxSecondsAudible();\r\n\r\n                \/* Active bounds: selection only when NOT recording *\/\r\n                const reg = (!isRecording) ? getActiveRegionBounds() : null;\r\n\r\n                \/* Keep regionLoop bounds tracking selection (drop if selection is cleared) *\/\r\n                if (regionLoop.on) {\r\n                    if (reg) {\r\n                        regionLoop.a = reg.a;\r\n                        regionLoop.b = reg.b;\r\n                    } else regionLoop.on = false;\r\n                }\r\n\r\n                \/* Loop semantics:\r\n                   - If there is a region and looping is enabled => loop IN region\r\n                   - If no region => loop the audible content (global)\r\n                *\/\r\n                const loopInRegion = !!reg && (regionLoop.on || !!isLooping);\r\n                const loopGlobal = (!!isLooping && !reg);\r\n\r\n                \/* Stop bound:\r\n                   - stop at region end ONLY when playBound.on=true (explicit \u201cplay selection\u201d)\r\n                   - otherwise stop at end of audible content (maxTAud)\r\n                *\/\r\n                let tEnd = maxTAud;\r\n\r\n                \/* Loop en regi\u00f3n: el \u201cfin\u201d que dispara el loop es reg.b (no maxTAud) *\/\r\n                if (loopInRegion && reg) {\r\n                    const b = (regionLoop.on ? regionLoop.b : reg.b);\r\n                    tEnd = Math.min(b, maxTAud);\r\n                } else if (playBound.on && reg) {\r\n                    tEnd = Math.min(playBound.b, maxTAud);\r\n                }\r\n\r\n                if (isPlaying) {\r\n                    const rate = clamp(css.flt(\"--cvx-oled-play-rate\", 1.0), 0.1, 8.0);\r\n                    playhead += (dt \/ 1000) * rate;\r\n\r\n                    \/* REC: nunca auto-stop por tEnd *\/\r\n                    if (isRecording) {\r\n                        recSync(playhead);\r\n                    } else {\r\n                        if (playhead >= tEnd) {\r\n                            if (loopInRegion || loopGlobal) {\r\n                                const loopA = loopInRegion ? (regionLoop.on ? regionLoop.a : reg.a) : 0;\r\n                                const loopB0 = loopInRegion ? (regionLoop.on ? regionLoop.b : reg.b) : maxTAud;\r\n                                const loopB = Math.min(loopB0, maxTAud);\r\n\r\n                                if (loopB > loopA + 0.0005) {\r\n                                    playhead = loopA;\r\n                                } else {\r\n                                    \/* degenerate loop => stop *\/\r\n                                    playhead = tEnd;\r\n                                    isPlaying = false;\r\n                                    playBound.on = false;\r\n                                    playBound.mode = \"none\";\r\n                                    setHud(\"STOP\", 650);\r\n                                }\r\n                            } else {\r\n                                playhead = tEnd;\r\n                                isPlaying = false;\r\n                                playBound.on = false;\r\n                                playBound.mode = \"none\";\r\n                                setHud(\"STOP\", 650);\r\n                            }\r\n                        }\r\n                    }\r\n                } else {\r\n                    if (isRecording) recSync(playhead);\r\n                }\r\n\r\n                \/* meters update *\/\r\n                const smoothTr = clamp(css.flt(\"--cvx-oled-track-meter-smooth\", 0.26), 0.02, 0.95);\r\n                const smoothM = clamp(css.flt(\"--cvx-oled-master-meter-smooth\", 0.22), 0.02, 0.95);\r\n                const peakHold = clamp(css.flt(\"--cvx-oled-master-meter-peak-hold-ms\", 700), 100, 2500);\r\n\r\n                \/* dB window for mapping amp->UI *\/\r\n                const floorDb = css.flt(\"--cvx-oled-meter-db-floor\", -48);\r\n                const ceilDb = css.flt(\"--cvx-oled-meter-db-ceil\", 0);\r\n\r\n                for (let i = 0; i < tracks.length; i++) {\r\n                    const tr = tracks[i];\r\n\r\n                    const lvlAmp = clipLevelAt(tr, playhead); \/* 0..1 (peak) *\/\r\n                    const lvl = meterNormFromAmp(lvlAmp, floorDb, ceilDb); \/* 0..1 (dB-mapped UI) *\/\r\n\r\n                    trMeter[i] = lerp(trMeter[i], lvl, smoothTr);\r\n\r\n                    if (trMeter[i] >= trPeak[i]) {\r\n                        trPeak[i] = trMeter[i];\r\n                        trPeakT[i] = now + peakHold;\r\n                    } else if (now > trPeakT[i]) {\r\n                        trPeak[i] = lerp(trPeak[i], trMeter[i], 0.18);\r\n                    }\r\n                }\r\n\r\n                const mix = computeMixLevels(playhead);\r\n                const mixL = meterNormFromAmp(mix.l, floorDb, ceilDb);\r\n                const mixR = meterNormFromAmp(mix.r, floorDb, ceilDb);\r\n\r\n                masterL = lerp(masterL, master.mute ? 0 : mixL, smoothM);\r\n                masterR = lerp(masterR, master.mute ? 0 : mixR, smoothM);\r\n\r\n                if (masterL >= masterLP) {\r\n                    masterLP = masterL;\r\n                    masterLPt = now + peakHold;\r\n                } else if (now > masterLPt) {\r\n                    masterLP = lerp(masterLP, masterL, 0.18);\r\n                }\r\n\r\n                if (masterR >= masterRP) {\r\n                    masterRP = masterR;\r\n                    masterRPt = now + peakHold;\r\n                } else if (now > masterRPt) {\r\n                    masterRP = lerp(masterRP, masterR, 0.18);\r\n                }\r\n\r\n\r\n\r\n                ras.clear(bg0);\r\n\r\n                \/* panel animations (single source of truth) *\/\r\n                {\r\n                    const kMI = clamp(css.flt(\"--cvx-oled-menu-anim-in\", 0.5), 0.02, 0.95);\r\n                    const kMO = clamp(css.flt(\"--cvx-oled-menu-anim-out\", 0.5), 0.02, 0.95);\r\n                    menu.anim = lerp(menu.anim, menu.open ? 1 : 0, (menu.open ? kMI : kMO));\r\n                    if (menu.anim < 0.001) menu.anim = 0;\r\n\r\n                    const kDI = clamp(css.flt(\"--cvx-oled-master-anim-in\", 0.45), 0.02, 0.95);\r\n                    const kDO = clamp(css.flt(\"--cvx-oled-master-anim-out\", 0.40), 0.02, 0.95);\r\n                    masterPanel.anim = lerp(masterPanel.anim, masterPanel.open ? 1 : 0, (masterPanel.open ? kDI : kDO));\r\n                    if (masterPanel.anim < 0.001) masterPanel.anim = 0;\r\n                }\r\n\r\n                \/* ----------------------------------------------------\r\n                   Header (ONLY: output label + transport icons + meters)\r\n                ----------------------------------------------------- *\/\r\n                if (L.headerH > 0) {\r\n                    const bg = Math.round(10 * chromeA);\r\n                    const stroke = Math.round(40 * chromeA);\r\n\r\n                    ras.fillRect(0, 0, W, L.headerH, bg);\r\n                    if (strokeOn) ras.hline(0, W - 1, L.headerH - 1, stroke);\r\n\r\n                    const padX = clamp(css.int(\"--cvx-oled-hdr-left-pad-x\", 2), 0, 12);\r\n                    const padY = clamp(css.int(\"--cvx-oled-hdr-left-pad-y\", 1), 0, 4);\r\n                    const ink = clamp(css.int(\"--cvx-oled-hdr-left-ink\", dim), 0, 255);\r\n                    const a = clamp(css.flt(\"--cvx-oled-hdr-left-alpha\", 1.0), 0, 1) * chromeA;\r\n                    const compact = css.bool(\"--cvx-oled-hdr-left-font-compact\", 0) ? 1 : 0;\r\n                    const drawText = (compact ? ras.textAA6.bind(ras) : ras.textAA.bind(ras));\r\n\r\n                    const showMasterMeters = css.bool(\"--cvx-oled-master-meter-on\", 1) ? 1 : 0;\r\n                    const meterAlpha = clamp(css.flt(\"--cvx-oled-master-meter-alpha\", 1.0), 0, 1) * chromeA;\r\n\r\n                    const mw = clamp(css.int(\"--cvx-oled-master-meter-w\", 64), 40, 140);\r\n                    const mx = clamp(css.int(\"--cvx-oled-master-meter-x\", (W - mw - 2)), 0, W - mw - 2);\r\n\r\n                    const trOn = css.bool(\"--cvx-oled-hdr-transport-on\", 1) ? 1 : 0;\r\n                    const bw = clamp(css.int(\"--cvx-oled-hdr-transport-btn-w\", 12), 10, 18);\r\n                    const bh = clamp(css.int(\"--cvx-oled-hdr-transport-btn-h\", 8), 7, 10);\r\n                    const gap = clamp(css.int(\"--cvx-oled-hdr-transport-gap\", 4), 2, 10);\r\n                    const rr = clamp(css.int(\"--cvx-oled-hdr-transport-radius\", 3), 1, 6);\r\n                    const tBg = clamp(css.int(\"--cvx-oled-hdr-transport-bg\", 18), 0, 255);\r\n                    const tBgA = clamp(css.flt(\"--cvx-oled-hdr-transport-bg-alpha\", 0.55), 0, 1) * chromeA;\r\n                    const tInk = clamp(css.int(\"--cvx-oled-hdr-transport-ink\", 235), 0, 255);\r\n                    const tInkDim = clamp(css.int(\"--cvx-oled-hdr-transport-ink-dim\", 135), 0, 255);\r\n                    const tActBg = clamp(css.int(\"--cvx-oled-hdr-transport-active-bg\", 70), 0, 255);\r\n                    const tActA = clamp(css.flt(\"--cvx-oled-hdr-transport-active-alpha\", 0.80), 0, 1) * chromeA;\r\n\r\n                    const groupW = (bw * 4) + (gap * 3);\r\n                    const cxGroup = Math.round((W - groupW) \/ 2);\r\n                    const yBtn = clamp(Math.round((L.headerH - bh) \/ 2), 0, Math.max(0, L.headerH - bh));\r\n\r\n                    \/* LEFT: output selection label *\/\r\n                    {\r\n                        const raw = formatOutputSel(outputSel);\r\n                        const leftX = L.pad + padX;\r\n                        const maxX = Math.max(leftX, cxGroup - 4);\r\n                        const maxW = Math.max(0, maxX - leftX);\r\n                        const maxChars = Math.max(1, Math.floor(maxW \/ 6));\r\n                        let s = raw;\r\n                        if (s.length > maxChars) s = s.slice(0, Math.max(1, maxChars - 1)) + \"\u2026\";\r\n                        drawText(leftX, padY, s, Math.round(ink * a), aa);\r\n                    }\r\n\r\n                    \/* CENTER: transport *\/\r\n                    if (trOn && L.headerH >= 8) {\r\n                        const btns = [{\r\n                                id: \"play\",\r\n                                x: cxGroup + 0 * (bw + gap),\r\n                                on: isPlaying\r\n                            },\r\n                            {\r\n                                id: \"stop\",\r\n                                x: cxGroup + 1 * (bw + gap),\r\n                                on: false\r\n                            },\r\n                            {\r\n                                id: \"rec\",\r\n                                x: cxGroup + 2 * (bw + gap),\r\n                                on: isRecording\r\n                            },\r\n                            {\r\n                                id: \"loop\",\r\n                                x: cxGroup + 3 * (bw + gap),\r\n                                on: isLooping\r\n                            }\r\n                        ];\r\n\r\n                        for (const b of btns) {\r\n                            const isOn = !!b.on;\r\n                            const fillV = isOn ? tActBg : tBg;\r\n                            const fillA = isOn ? tActA : tBgA;\r\n                            const inkV = isOn ? tInk : tInkDim;\r\n\r\n                            ras.blendRoundRectAA(b.x, yBtn, bw, bh, rr, fillV, fillA, 255, 0);\r\n\r\n                            const icx = b.x + Math.round(bw \/ 2);\r\n                            const icy = yBtn + Math.round(bh \/ 2);\r\n\r\n                            if (b.id === \"play\") drawPlayIcon(icx, icy, inkV, !isPlaying);\r\n                            else if (b.id === \"stop\") drawStopIcon(icx, icy, tInkDim);\r\n                            else if (b.id === \"rec\") drawRecIcon(icx, icy, tInk, isRecording);\r\n                            else if (b.id === \"loop\") drawLoopIcon(icx, icy, tInk, isLooping);\r\n                        }\r\n                    }\r\n\r\n                    \/* RIGHT: master meters only *\/\r\n                    if (showMasterMeters && (isPlaying || isRecording) && L.headerH >= 8) {\r\n                        const my1 = clamp(css.int(\"--cvx-oled-master-meter-y1\", 1), 0, L.headerH - 2);\r\n                        const my2 = clamp(css.int(\"--cvx-oled-master-meter-y2\", 5), 0, L.headerH - 2);\r\n                        const mh = clamp(css.int(\"--cvx-oled-master-meter-h\", 2), 1, 3);\r\n                        const mg = clamp(css.int(\"--cvx-oled-master-meter-gap\", 1), 0, 2);\r\n\r\n                        const mbg = clamp(css.int(\"--cvx-oled-master-meter-bg\", 40), 0, 255);\r\n                        const mink = clamp(css.int(\"--cvx-oled-master-meter-ink\", 235), 0, 255);\r\n                        const mpk = clamp(css.int(\"--cvx-oled-master-meter-peak-ink\", 255), 0, 255);\r\n\r\n                        ras.blendRect(mx, my1, mw, mh, mbg, meterAlpha);\r\n                        ras.blendRect(mx, my2, mw, mh, mbg, meterAlpha);\r\n\r\n                        const fillW1 = Math.round(mw * clamp(masterL, 0, 1));\r\n                        const fillW2 = Math.round(mw * clamp(masterR, 0, 1));\r\n                        ras.blendRect(mx, my1, fillW1, mh, mink, meterAlpha);\r\n                        ras.blendRect(mx, my2, fillW2, mh, mink, meterAlpha);\r\n\r\n                        const p1 = Math.round(mw * clamp(masterLP, 0, 1));\r\n                        const p2 = Math.round(mw * clamp(masterRP, 0, 1));\r\n                        if (p1 > 0) ras.blendRect(mx + p1 - 1, my1, 2, mh, mpk, meterAlpha);\r\n                        if (p2 > 0) ras.blendRect(mx + p2 - 1, my2, 2, mh, mpk, meterAlpha);\r\n\r\n                        if (mg > 0) {\r\n                            ras.blendRect(mx, my1 + mh, mw, mg, 0, meterAlpha * 0.35);\r\n                        }\r\n                    }\r\n                }\r\n\r\n                \/* ----------------------------------------------------\r\n                   Footer\r\n                   - Left: Zoom\r\n                   - Center: HUD (incl. region tInit\/tEnd\/\u0394)\r\n                   - Right: Play time (playhead)\r\n                ----------------------------------------------------- *\/\r\n                if (L.footerH > 0) {\r\n                    const yF = H - L.footerH;\r\n                    const bg = Math.round(10 * chromeA);\r\n                    const stroke = Math.round(40 * chromeA);\r\n\r\n                    ras.fillRect(0, yF, W, L.footerH, bg);\r\n                    if (strokeOn) ras.hline(0, W - 1, yF, stroke);\r\n\r\n                    const decTime = clamp(css.int(\"--cvx-oled-footer-time-decimals\", 3), 0, 3);\r\n                    const decReg = clamp(css.int(\"--cvx-oled-footer-region-decimals\", 2), 0, 3);\r\n\r\n                    \/* Optional per-instance meta string (e.g. \"44.100kHz \/ 24bit\") *\/\r\n                    const footerMeta = (getComputedStyle(root).getPropertyValue(\"--cvx-oled-footer-meta\") || \"\").trim();\r\n\r\n                    const footerLeft = \"X\" + String(zoomX) + \" Y\" + String(zoomYMap[zoomY]);\r\n                    const footerRight = \"T\" + formatTPrec(playhead, decTime, 3);\r\n\r\n                    let centerText = \"\";\r\n\r\n                    if (masterPanel.open) centerText = \"Master Config\";\r\n                    else if (menu.open) centerText = \"MENU\";\r\n                    else if (selection) {\r\n                        const a0 = Math.min(selection.s, selection.e);\r\n                        const b0 = Math.max(selection.s, selection.e);\r\n                        const d0 = (b0 - a0);\r\n\r\n                        const tA = formatTPrec(a0, decReg, 1);\r\n                        const tB = formatTPrec(b0, decReg, 1);\r\n                        const tD = formatTPrec(d0, decReg, 1);\r\n\r\n                        const candA = \"tinit \" + tA + \" tend \" + tB + \" tdif \" + tD;\r\n                        const candB = \"S:\" + tA + \" \" + \"E:\" + tB + \" \" + \"\u0394:\" + tD;\r\n                        const candC = tA + \"-\" + tB + \" \u0394\" + tD;\r\n\r\n                        const leftSafe = (footerLeft.length * 6) + 10;\r\n                        const rightSafe = (footerRight.length * 6) + 10;\r\n                        const maxChars = Math.max(0, Math.floor((W - leftSafe - rightSafe) \/ 6));\r\n\r\n                        centerText = (candA.length <= maxChars) ? candA : (candB.length <= maxChars) ? candB : candC;\r\n                    } else if (hudActive) {\r\n                        centerText = hud.text;\r\n                    }\r\n\r\n                    ras.textAA(L.pad, yF + 2, footerLeft, Math.round(dim * chromeA), aa);\r\n                    ras.textAA(W - (footerRight.length * 6) - 2, yF + 2, footerRight, Math.round(dim * chromeA), aa);\r\n\r\n                    \/* Default center text when no MENU \/ no selection \/ no HUD *\/\r\n                    let centerAuto = \"\";\r\n                    if (!centerText) {\r\n                        const zi = clamp(zoomY, 0, zoomYMap.length - 1);\r\n                        const yGain = (zoomYMap[zi] || 1);\r\n                        const viewDb = Math.round(20 * Math.log(yGain) \/ Math.LN10);\r\n                        const sDb = (waveZoomDb > 0 ? (\"+\" + waveZoomDb) : String(waveZoomDb));\r\n                        const viewLabel = \"VIEW \" + sDb + \" dB\";\r\n\r\n                        const candA = footerMeta ? (viewLabel + \" - \" + footerMeta) : viewLabel;\r\n                        const candB = footerMeta ? (\"VIEW \" + sDb + \"dB-\" + footerMeta) : (\"VIEW \" + sDb + \"dB\");\r\n                        const candC = viewLabel;\r\n                        const candD = \"VIEW \" + sDb + \"dB\";\r\n\r\n                        const leftSafe = (footerLeft.length * 6) + 10;\r\n                        const rightSafe = (footerRight.length * 6) + 10;\r\n                        const maxChars = Math.max(0, Math.floor((W - leftSafe - rightSafe) \/ 6));\r\n\r\n                        centerAuto =\r\n                            (candA.length <= maxChars) ? candA :\r\n                            (candB.length <= maxChars) ? candB :\r\n                            (candC.length <= maxChars) ? candC :\r\n                            (candD.length <= maxChars) ? candD : \"\";\r\n                    }\r\n\r\n                    const textToDraw = centerText || centerAuto;\r\n\r\n                    if (textToDraw) {\r\n                        const wTxt = textToDraw.length * 6;\r\n                        const leftSafe = (footerLeft.length * 6) + 10;\r\n                        const rightSafe = (footerRight.length * 6) + 10;\r\n                        const cx0 = leftSafe;\r\n                        const cx1 = W - rightSafe;\r\n\r\n                        if (cx1 > cx0 + 12 && wTxt <= (cx1 - cx0)) {\r\n                            const cx = clamp(Math.round((cx0 + cx1 - wTxt) \/ 2), cx0, cx1 - wTxt);\r\n                            ras.textAA(cx, yF + 2, textToDraw, Math.round(mid * chromeA * footA), aa);\r\n                        }\r\n                    }\r\n\r\n                }\r\n\r\n                \/* Body bounds *\/\r\n                const y0 = L.headerH;\r\n                const y1 = H - L.footerH - 1;\r\n                if (y0 > y1) return;\r\n\r\n                const listX0 = L.pad;\r\n                const listX1 = L.pad + L.listW;\r\n\r\n                const viewX0 = listX1 + L.gap;\r\n                const viewX1 = W - L.pad - 1 - L.masterBarW;\r\n\r\n                \/* Track divider *\/\r\n                const dividerOn = css.bool(\"--cvx-oled-track-divider-on\", 1) ? 1 : 0;\r\n                const dividerV = clamp(css.int(\"--cvx-oled-track-divider-v\", 62), 0, 255);\r\n                if (dividerOn && strokeOn) ras.vline(listX1, y0, y1, dividerV);\r\n\r\n                const vt = visibleTracksCount();\r\n                const rowH = Math.floor((y1 - y0 + 1) \/ vt);\r\n\r\n                \/* Track selection params *\/\r\n                const trR = clamp(css.int(\"--cvx-oled-track-radius\", 2), 1, 6);\r\n                const trActiveBg = clamp(css.int(\"--cvx-oled-track-active-bg\", 18), 0, 255);\r\n\r\n                const trSelOn = css.bool(\"--cvx-oled-track-sel-on\", 1) ? 1 : 0;\r\n                const trSelFillA = clamp(css.flt(\"--cvx-oled-track-sel-fill-a\", 0.04), 0, 1);\r\n                const trSelStrokeOn = css.bool(\"--cvx-oled-track-sel-stroke-on\", 0) ? 1 : 0;\r\n                const trSelStrokeA = clamp(css.flt(\"--cvx-oled-track-sel-stroke-a\", 0.35), 0, 1) * strokeOn * trSelStrokeOn;\r\n\r\n                \/* Clip params *\/\r\n                const clipR = clamp(css.int(\"--cvx-oled-clip-radius\", 3), 1, 6);\r\n                const clipFill = clamp(css.int(\"--cvx-oled-clip-fill\", 22), 0, 255);\r\n                const clipStrokeOn = css.bool(\"--cvx-oled-clip-stroke-on\", 0) ? 1 : 0;\r\n                const clipStrokeA = clamp(css.flt(\"--cvx-oled-clip-stroke-a\", 0.55), 0, 1) * strokeOn * clipStrokeOn;\r\n\r\n                const clipInkActive = clamp(css.int(\"--cvx-oled-clip-ink-active\", 220), 0, 255);\r\n                const clipInk = clamp(css.int(\"--cvx-oled-clip-ink\", 175), 0, 255);\r\n\r\n                const pointerOn = css.bool(\"--cvx-oled-badge-pointer-on\", 1) ? 1 : 0;\r\n                const pointerInk = clamp(css.int(\"--cvx-oled-menu-pointer-ink\", 210), 0, 255);\r\n\r\n                \/* Track layout vars *\/\r\n                const tPadL = clamp(css.int(\"--cvx-oled-track-pad-l\", 2), 0, 10);\r\n                const tPadR = clamp(css.int(\"--cvx-oled-track-pad-r\", 2), 0, 10);\r\n                const x2NamePadT = css.int(\"--cvx-oled-track-x2-NamePadT\", 1);\r\n                const x2SrcPadB = css.int(\"--cvx-oled-track-x2-SrcPadB\", 1);\r\n\r\n                const idxOn = css.bool(\"--cvx-oled-track-index-on\", 1) ? 1 : 0;\r\n                const armOn = css.bool(\"--cvx-oled-track-arm-on\", 1) ? 1 : 0;\r\n                const armW = clamp(css.int(\"--cvx-oled-track-arm-w\", 7), 5, 10);\r\n                const armH = clamp(css.int(\"--cvx-oled-track-arm-h\", 10), 10, 64);\r\n                const armR = clamp(css.int(\"--cvx-oled-track-arm-radius\", 2), 1, 6);\r\n                const armBg0 = clamp(css.int(\"--cvx-oled-track-arm-bg-off\", 10), 0, 255);\r\n                const armBg1 = clamp(css.int(\"--cvx-oled-track-arm-bg-on\", 120), 0, 255);\r\n                const armA = clamp(css.flt(\"--cvx-oled-track-arm-alpha\", 1.0), 0, 1);\r\n                const armSizeMode = css.int(\"--cvx-oled-track-arm-SizeMode\", 0); \/\/ 0\/1\r\n                const armIdxMode = css.int(\"--cvx-oled-track-arm-IdxMode\", 0); \/\/ 0\/1\r\n                const armInkOff = clamp(css.int(\"--cvx-oled-track-arm-ink-off\", 80), 0, 255);\r\n                const armInkOn = clamp(css.int(\"--cvx-oled-track-arm-ink-on\", 255), 0, 255);\r\n\r\n\r\n                const msOn = css.bool(\"--cvx-oled-ms-on\", 1) ? 1 : 0;\r\n                const msGap = clamp(css.int(\"--cvx-oled-ms-gap\", 2), 0, 4);\r\n                const msRad = clamp(css.int(\"--cvx-oled-ms-radius\", 2), 1, 6);\r\n                const msBorderOn = css.bool(\"--cvx-oled-ms-border-on\", 0) ? 1 : 0;\r\n                const msBorderV = clamp(css.int(\"--cvx-oled-ms-border-v\", 255), 0, 255);\r\n                const msBorderA = clamp(css.flt(\"--cvx-oled-ms-border-a\", 0.25), 0, 1) * strokeOn * msBorderOn;\r\n\r\n                const msW4 = clamp(css.int(\"--cvx-oled-ms-box-w-x4\", 9), 7, 12);\r\n                const msH4 = clamp(css.int(\"--cvx-oled-ms-box-h-x4\", 8), 7, 10);\r\n                const msW2 = clamp(css.int(\"--cvx-oled-ms-box-w-x2\", 12), 9, 16);\r\n                const msH2 = clamp(css.int(\"--cvx-oled-ms-box-h-x2\", 10), 9, 14);\r\n\r\n                const msOffBg = clamp(css.int(\"--cvx-oled-ms-off-bg\", 18), 0, 255);\r\n                const msOffA = clamp(css.flt(\"--cvx-oled-ms-off-a\", 1.0), 0, 1);\r\n                const msOffInk = clamp(css.int(\"--cvx-oled-ms-off-ink\", 130), 0, 255);\r\n\r\n                const msOnBg = clamp(css.int(\"--cvx-oled-ms-on-bg\", 90), 0, 255);\r\n                const msOnA = clamp(css.flt(\"--cvx-oled-ms-on-a\", 1.0), 0, 1);\r\n                const msOnInk = clamp(css.int(\"--cvx-oled-ms-on-ink\", 255), 0, 255);\r\n\r\n                const meterHOn = css.bool(\"--cvx-oled-track-meter-h-on\", 1) ? 1 : 0;\r\n                const meterHH = clamp(css.int(\"--cvx-oled-track-meter-h-h\", 1), 1, 2);\r\n                const meterHBg = clamp(css.int(\"--cvx-oled-track-meter-h-bg\", 55), 0, 255);\r\n                const meterHInk = clamp(css.int(\"--cvx-oled-track-meter-h-ink\", 235), 0, 255);\r\n                const meterHA = clamp(css.flt(\"--cvx-oled-track-meter-h-alpha\", 1.0), 0, 1);\r\n                const meterHY = clamp(css.int(\"--cvx-oled-track-meter-h-yoff\", 9), 7, 14);\r\n\r\n                const meterVOn = css.bool(\"--cvx-oled-track-meter-v-on\", 1) ? 1 : 0;\r\n                const meterVW = clamp(css.int(\"--cvx-oled-track-meter-v-w\", 3), 2, 5);\r\n                const meterVBg = clamp(css.int(\"--cvx-oled-track-meter-v-bg\", 45), 0, 255);\r\n                const meterVInk = clamp(css.int(\"--cvx-oled-track-meter-v-ink\", 235), 0, 255);\r\n                const meterVA = clamp(css.flt(\"--cvx-oled-track-meter-v-alpha\", 1.0), 0, 1);\r\n\r\n                const srcOn = css.bool(\"--cvx-oled-track-src-on\", 1) ? 1 : 0;\r\n                const srcInk = clamp(css.int(\"--cvx-oled-track-src-ink\", 120), 0, 255);\r\n                const srcA = clamp(css.flt(\"--cvx-oled-track-src-alpha\", 0.92), 0, 1);\r\n                const srcDY = clamp(css.int(\"--cvx-oled-track-src-dy\", 10), 8, 14);\r\n\r\n                function pickVisibleMark(c, vA, vB) {\r\n                    if (c.m && c.m.length) {\r\n                        for (let i = c.m.length - 1; i >= 0; i--) {\r\n                            const mm = c.m[i];\r\n                            if (mm.b <= vA || mm.a >= vB) continue;\r\n                            if (mm.b <= c.s || mm.a >= c.e) continue;\r\n                            return mm;\r\n                        }\r\n                    }\r\n                    const tags = [];\r\n                    if (c.fx && c.fx.length) tags.push(c.fx[0]);\r\n                    if (c.fi) tags.push(\"FI\");\r\n                    if (c.fo) tags.push(\"FO\");\r\n                    if (tags.length) return {\r\n                        a: c.s,\r\n                        b: c.e,\r\n                        t: tags.join(\" \")\r\n                    };\r\n                    return null;\r\n                }\r\n\r\n                \/* ----------------------------------------------------\r\n                   Tracks & clips\r\n                ----------------------------------------------------- *\/\r\n                L.vt = vt;\r\n\r\n                \/* virtual '+ Add Track' row (one extra row after last track, if max not reached) *\/\r\n                const canAddRow = (tracks.length < CVX_TRACKS_MAX);\r\n                const listCount = tracks.length + (canAddRow ? 1 : 0);\r\n\r\n                for (let i = 0; i < vt; i++) {\r\n\r\n                    const ti = trackTop + i;\r\n                    if (ti >= listCount) break;\r\n\r\n                    const ry0 = y0 + i * rowH;\r\n                    const ry1 = (i === vt - 1) ? y1 : (ry0 + rowH - 1);\r\n\r\n                    \/* Guard: allow vt (x2\/x4) > tracks.length (virtual\/empty rows) *\/\r\n                    const isAddRow = (canAddRow && ti === tracks.length);\r\n\r\n                    const isActive = (ti === activeTrack);\r\n                    const isSel = (!isAddRow && multiSel.has(ti));\r\n\r\n                    if (isActive) {\r\n                        ras.fillRect(listX0, ry0, L.listW, (ry1 - ry0 + 1), trActiveBg);\r\n                    }\r\n\r\n                    if (isSel && trSelOn) {\r\n                        ras.blendRoundRectAA(\r\n                            listX0, ry0, L.listW, (ry1 - ry0 + 1), trR,\r\n                            255, trSelFillA,\r\n                            255, trSelStrokeA\r\n                        );\r\n                    }\r\n\r\n                    const ty = clamp(Math.floor((ry0 + ry1 - 7) \/ 2), ry0, ry1 - 7);\r\n\r\n                    if (ti >= tracks.length) {\r\n                        if (isAddRow) {\r\n                            ras.textAA(listX0 + tPadL, ty, \"+ ADD\", Math.round((isActive ? bright : dim) * labelA), aa);\r\n                        }\r\n                        continue;\r\n                    }\r\n\r\n                    let xText = listX0 + tPadL;\r\n\r\n                    const isX4 = (vt >= 4);\r\n                    const isX2 = (vt === 2);\r\n                    const isX1 = (vt === 1);\r\n\r\n                    \/\/ X2: siempre 2 l\u00edneas (si srcOn)\r\n                    \/\/ X1: 2 l\u00edneas solo si hay alto suficiente (tu criterio hist\u00f3rico)\r\n                    const x2TwoLine = !!(isX2 && srcOn);\r\n                    const x1TwoLine = !!(isX1 && srcOn && rowH >= 18);\r\n\r\n                    \/\/ Para futuro: ac\u00e1 ya distingu\u00eds X1 vs X2 sin mezclar l\u00f3gica.\r\n                    const twoLine = (x2TwoLine || x1TwoLine);\r\n\r\n                    const tyName = twoLine ? clamp(ry0 + x2NamePadT, ry0, ry1 - 7) : ty;\r\n                    const tySrc = twoLine ? clamp(ry1 - 7 - x2SrcPadB, ry0, ry1 - 7) : (ty + srcDY);\r\n                    const tyIdx = twoLine ? tyName : ty;\r\n\r\n\r\n                    const msW = isX4 ? msW4 : msW2;\r\n                    const msH = isX4 ? msH4 : msH2;\r\n\r\n                    if (armOn) {\r\n                        const ax = xText + (isX2 ? -1 : 0);\r\n\r\n                        \/\/ 0=manual (armH), 1=auto (alto ~ fila)\r\n                        const aH = (armSizeMode === 1) ?\r\n                            Math.max(7, (ry1 - ry0 + 1) - 2) :\r\n                            armH;\r\n\r\n                        const ay = clamp(Math.floor((ry0 + ry1 - aH) \/ 2), ry0 + 1, ry1 - aH);\r\n\r\n                        const on = tracks[ti].arm ? 1 : 0;\r\n\r\n                        ras.blendRoundRectAA(\r\n                            ax, ay, armW, aH, armR,\r\n                            on ? armBg1 : armBg0, armA,\r\n                            255, 0\r\n                        );\r\n\r\n                        \/\/ \u00cdndice dentro del ARM\r\n                        if (armIdxMode === 1 && idxOn) {\r\n                            const s = String(ti + 1);\r\n                            const tw = s.length * 6; \/\/ ancho aprox fuente 6px\r\n                            const tx = ax + Math.floor(Math.max(0, armW - tw) \/ 2); \/\/ centrado\r\n                            const tyArm = ay + Math.floor(Math.max(0, aH - 7) \/ 2);\r\n\r\n                            ras.textAA(tx, tyArm, s, (on ? armInkOn : armInkOff), aa);\r\n                        }\r\n\r\n                        xText += armW + 2;\r\n                    }\r\n\r\n\r\n                    \/\/ \u00cdndice fuera del ARM (comportamiento actual)\r\n                    if (idxOn && !(armOn && armIdxMode)) {\r\n                        ras.textAA(xText, tyIdx, String(ti + 1), Math.round((isActive ? bright : dim) * labelA), aa);\r\n                        xText += 12;\r\n                    }\r\n\r\n\r\n\r\n\r\n                    let rightZoneW = 0;\r\n                    if (msOn) {\r\n                        rightZoneW = isX4 ? (msW * 2 + msGap) : msW;\r\n                    }\r\n\r\n                    const wantMeterV = (!isX4 && meterVOn) ? 1 : 0;\r\n                    const vMeterGap = wantMeterV ? 2 : 0;\r\n                    const vMeterW = wantMeterV ? meterVW : 0;\r\n\r\n                    const xRightLimit = listX1 - tPadR;\r\n\r\n                    let msX = xRightLimit - rightZoneW;\r\n                    let meterVX = msX - vMeterGap - vMeterW;\r\n\r\n                    const nameX = xText;\r\n                    const nameMaxX = wantMeterV ? (meterVX - 2) : (msOn ? (msX - 2) : xRightLimit);\r\n                    const nameMaxW = Math.max(0, nameMaxX - nameX);\r\n\r\n                    const maxCharsName = Math.max(1, Math.floor(nameMaxW \/ 6));\r\n                    let nm = tracks[ti].name;\r\n                    if (nm.length > maxCharsName) nm = nm.slice(0, Math.max(1, maxCharsName - 1)) + \"\u2026\";\r\n\r\n                    ras.textAA(nameX, tyName, nm, Math.round((isActive ? bright : mid) * labelA), aa);\r\n\r\n                    if (srcOn && ((vt === 1 && rowH >= 18) || isX2)) {\r\n                        const maxCharsSrc = Math.max(1, Math.floor(nameMaxW \/ 6));\r\n                        const srcFull = tracks[ti].src;\r\n\r\n                        const useMarquee = (isX2 || (isX1 && rowH >= 18));\r\n\r\n                        let src = srcFull;\r\n                        if (!useMarquee && src.length > maxCharsSrc) {\r\n                            src = src.slice(0, Math.max(1, maxCharsSrc - 1)) + \"\u2026\";\r\n                        }\r\n\r\n                        const srcInkV = Math.round(srcInk * srcA);\r\n\r\n                        if (useMarquee) {\r\n                            const tMs = (typeof nowMs !== \"undefined\") ? nowMs : performance.now();\r\n                            drawMarqueeTextAA(ras, nameX, tySrc, nameMaxW, srcFull, srcInkV, aa, tMs);\r\n                        } else {\r\n                            ras.textAA(nameX, tySrc, src, srcInkV, aa);\r\n                        }\r\n\r\n                    }\r\n\r\n                    \/\/ ------------------------------------------------------\r\n                    \/\/ Paso 2 (X1): Gain\/Vol horizontales (se ocultan si no entra)\r\n                    \/\/ Pegar ac\u00e1: despu\u00e9s del if(src...) y antes de if(isX4 && meterHOn)\r\n                    \/\/ ------------------------------------------------------\r\n                    if (isX1) {\r\n                        \/\/ espacio entre t\u00edtulo (tyName) y src (tySrc)\r\n                        const ctlTop = tyName + 8; \/\/ 7px texto + 1px gap\r\n                        const ctlBot = tySrc - 1; \/\/ 1px de aire antes del src\r\n                        const ctlH = ctlBot - ctlTop;\r\n\r\n                        const txtH = 7,\r\n                            gapY = 1,\r\n                            barH = 3;\r\n\r\n                        const betweenBars = 3; \/* colapsado: igual que hoy *\/\r\n                        const betweenFull = betweenBars + clamp(css.int(\"--cvx-oled-ctl-gap-full\", 2), 0, 12);\r\n\r\n                        const fullH = (txtH + gapY + barH) * 2 + betweenFull;\r\n                        const barsH = (barH * 2) + betweenBars;\r\n\r\n                        const canFull = (ctlH >= fullH);\r\n                        const canBars = (!canFull && ctlH >= barsH);\r\n                        if (!(canFull || canBars)) {\r\n                            \/* ... ocultar controles ... *\/\r\n                        }\r\n\r\n                        const betweenUse = canFull ? betweenFull : betweenBars;\r\n                        const useH = canFull ? fullH : barsH;\r\n                        const yBase = ctlTop + Math.floor((ctlH - useH) \/ 2);\r\n\r\n                        if ((canFull || canBars) && nameMaxW > 0) {\r\n                            const barX = nameX;\r\n                            const barW = Math.max(14, nameMaxW);\r\n\r\n                            \/\/ centrado vertical del bloque (full o compact)\r\n                            const useH = canFull ? fullH : barsH;\r\n                            const yBase = ctlTop + Math.floor((ctlH - useH) \/ 2);\r\n\r\n                            const inkTxt = Math.round((isActive ? bright : dim) * labelA);\r\n                            const inkBarBg = 36;\r\n                            const inkFill = 180;\r\n                            const inkKnob = 255;\r\n\r\n                            \/\/ ---------- GAIN (-20 .. +60) ----------\r\n                            const gMin = -20,\r\n                                gMax = 60;\r\n                            const gVal = tracks[ti].gainDb;\r\n\r\n                            const gTxtY = canFull ? yBase : 0;\r\n                            const gBarY = canFull ? (gTxtY + txtH + gapY) : yBase;\r\n\r\n                            if (canFull) {\r\n                                const gInt = Math.round(gVal);\r\n                                const gAbs2 = String(Math.min(99, Math.abs(gInt))).padStart(2, \"0\");\r\n                                const gStr = (gInt < 0 ? \"-\" : \"\") + gAbs2 + \"DB\";\r\n                                ras.textAA(barX, gTxtY, \"G:\", inkTxt, aa);\r\n                                ras.textAA(barX + 12, gTxtY, gStr, inkTxt, aa);\r\n                            }\r\n\r\n                            ras.blendRect(barX, gBarY, barW, barH, inkBarBg, 1.0);\r\n                            const cx = barX + Math.floor(barW \/ 2);\r\n                            ras.vline(cx, gBarY, gBarY + barH - 1, 90);\r\n\r\n                            let gPx = cx;\r\n                            if (gVal < 0) {\r\n                                const t = clamp((gVal - gMin) \/ (0 - gMin), 0, 1);\r\n                                gPx = barX + Math.round((barW \/ 2) * t);\r\n                                ras.blendRect(gPx, gBarY, Math.max(1, cx - gPx), barH, inkFill, 1.0);\r\n                            } else {\r\n                                const t = clamp((gVal - 0) \/ (gMax - 0), 0, 1);\r\n                                gPx = cx + Math.round((barW \/ 2) * t);\r\n                                ras.blendRect(cx, gBarY, Math.max(1, gPx - cx), barH, inkFill, 1.0);\r\n                            }\r\n                            ras.blendRect(gPx - 1, gBarY - 1, 2, barH + 2, inkKnob, 1.0);\r\n\r\n                            \/\/ ---------- VOL (0 .. 100) ----------\r\n                            const vVal = clamp(tracks[ti].vol, 0, 100);\r\n\r\n                            const vTxtY = canFull ? (gBarY + barH + betweenUse) : 0;\r\n                            const vBarY = canFull ? (vTxtY + txtH + gapY) : (gBarY + barH + betweenUse);\r\n\r\n                            if (canFull) {\r\n                                ras.textAA(barX, vTxtY, \"V:\", inkTxt, aa);\r\n                                ras.textAA(barX + 12, vTxtY, String(vVal), inkTxt, aa);\r\n                            }\r\n\r\n                            ras.blendRect(barX, vBarY, barW, barH, inkBarBg, 1.0);\r\n                            const vPx = barX + Math.round((barW - 1) * (vVal \/ 100));\r\n                            ras.blendRect(barX, vBarY, Math.max(1, vPx - barX), barH, inkFill, 1.0);\r\n                            ras.blendRect(vPx - 1, vBarY - 1, 2, barH + 2, inkKnob, 1.0);\r\n                        }\r\n\r\n                    }\r\n\r\n\r\n                    if (isX4 && meterHOn) {\r\n                        const lvl = trMeter[ti];\r\n                        const mW = Math.max(8, nameMaxW);\r\n                        const mX = nameX;\r\n                        const mY = clamp(ty + meterHY, ry0, ry1);\r\n                        ras.blendRect(mX, mY, mW, meterHH, meterHBg, meterHA);\r\n                        ras.blendRect(mX, mY, Math.round(mW * lvl), meterHH, meterHInk, meterHA);\r\n\r\n                        const p = Math.round(mW * trPeak[ti]);\r\n                        if (p > 0) ras.blendRect(mX + p - 1, mY, 2, meterHH, 255, meterHA);\r\n                    }\r\n\r\n                    if (wantMeterV) {\r\n                        const lvl = trMeter[ti];\r\n                        const ph = Math.max(10, (ry1 - ry0) - 6);\r\n                        const px = meterVX;\r\n                        const py = ry0 + 3;\r\n                        ras.blendRect(px, py, meterVW, ph, meterVBg, meterVA);\r\n                        const fillH = Math.round(ph * lvl);\r\n                        ras.blendRect(px, py + (ph - fillH), meterVW, fillH, meterVInk, meterVA);\r\n                    }\r\n\r\n                    if (msOn) {\r\n                        const muteOn = tracks[ti].mute ? 1 : 0;\r\n                        const soloOn = tracks[ti].solo ? 1 : 0;\r\n\r\n                        const drawMsBox = (x, y, w, h, label, isOn) => {\r\n                            const fillV = isOn ? msOnBg : msOffBg;\r\n                            const fillA = (isOn ? msOnA : msOffA);\r\n                            const inkV = isOn ? msOnInk : msOffInk;\r\n\r\n                            ras.blendRoundRectAA(\r\n                                x, y, w, h, msRad,\r\n                                fillV, fillA,\r\n                                msBorderV, msBorderA\r\n                            );\r\n                            const tx = x + Math.floor((w - 5) \/ 2);\r\n                            const ty2 = y + Math.floor((h - 7) \/ 2);\r\n                            ras.textAA(tx, ty2, label, inkV, aa);\r\n                        };\r\n\r\n                        if (isX4) {\r\n                            const boxY = clamp(Math.floor((ry0 + ry1 - msH) \/ 2), ry0, ry1 - msH);\r\n                            const xM = msX;\r\n                            const xS = msX + msW + msGap;\r\n\r\n                            drawMsBox(xM + 5, boxY + 1, msW, msH, \"M\", muteOn);\r\n                            drawMsBox(xS + 2, boxY + 1, msW, msH, \"S\", soloOn);\r\n                        } else {\r\n                            const totalH = msH * 2 + msGap;\r\n                            const boxY0 = clamp(Math.floor((ry0 + ry1 - totalH) \/ 2), ry0, ry1 - totalH);\r\n                            const xBox = msX;\r\n\r\n                            drawMsBox(xBox + 2, boxY0 + 1, msW, msH, \"S\", soloOn);\r\n                            drawMsBox(xBox + 2, boxY0 + msH + msGap, msW, msH, \"M\", muteOn);\r\n                        }\r\n                    }\r\n\r\n                    if (strokeOn) ras.hline(viewX0, viewX1, ry1, 36);\r\n\r\n                    const span = timelineSpan();\r\n                    const step = tickStep(span);\r\n                    const tStart = Math.floor(viewStart \/ step) * step;\r\n                    for (let tt = tStart; tt <= viewStart + span; tt += step) {\r\n                        const x = timeToX(tt);\r\n                        if (x < viewX0 || x > viewX1) continue;\r\n                        if (strokeOn) {\r\n                            ras.vline(x, ry0 + 1, ry0 + 2, 58);\r\n                            ras.vline(x, ry1 - 2, ry1 - 1, 36);\r\n                        }\r\n                    }\r\n\r\n                    const tr = tracks[ti];\r\n                    for (const c of tr.clips) {\r\n                        if (c.e < viewStart || c.s > viewStart + span) continue;\r\n\r\n                        const xAraw = timeToX(c.s);\r\n                        const xBraw = timeToX(c.e);\r\n                        const xA = clamp(xAraw, viewX0, viewX1);\r\n                        const xB = clamp(xBraw, viewX0, viewX1);\r\n                        const wpx = Math.max(1, xB - xA);\r\n\r\n                        const clipH = Math.max(6, (ry1 - ry0) - 4);\r\n                        const clipY = ry0 + 2;\r\n\r\n                        ras.blendRoundRectAA(\r\n                            xA, clipY, wpx, clipH, clipR,\r\n                            clipFill, 1.00,\r\n                            180, clipStrokeA\r\n                        );\r\n\r\n                        const cy = Math.floor((ry0 + ry1) \/ 2);\r\n\r\n                        const ampBase = waveZoomMul();\r\n                        const clipBase = (c.a != null) ? c.a : 1;\r\n                        const ge = (c.ge && c.ge.length) ? c.ge : null;\r\n                        let geIdx = ge ? 0 : -1;\r\n                        let geGain = ge ? (clipBase * ge[0].g) : clipBase;\r\n\r\n\r\n                        \/\/ constants para mapear x->t sin xToTime() por pixel\r\n                        const x0t = L.pad + L.listW + L.gap;\r\n                        const x1t = W - L.pad - 1 - L.masterBarW;\r\n                        const vw = (x1t - x0t + 1);\r\n                        const secPerPx = span \/ Math.max(1, (vw - 1));\r\n\r\n                        const halfH = Math.max(1, Math.floor((ry1 - ry0 - 8) \/ 2));\r\n\r\n                        const aud = tracks[ti].aud;\r\n\r\n                        for (let x = xA; x <= xB; x++) {\r\n                            let vMin = 0,\r\n                                vMax = 0;\r\n                            \/* Absolute time range covered by this pixel column *\/\r\n                            const tAbs0 = viewStart + (x - x0t) * secPerPx;\r\n                            const tAbs1 = tAbs0 + secPerPx;\r\n                            const midT = (tAbs0 + tAbs1) * 0.5;\r\n                            if (aud) {\r\n                                const srcOfs = (c.o != null) ? c.o : c.s;\r\n                                const tSrc0 = (tAbs0 - c.s) + srcOfs;\r\n                                const tSrc1 = (tAbs1 - c.s) + srcOfs;\r\n                                const sr = aud.sr || 44100;\r\n                                let s0 = Math.floor(tSrc0 * sr);\r\n                                let s1 = Math.floor(tSrc1 * sr);\r\n                                if (s1 <= s0) s1 = s0 + 1; \/\/ asegura ventana m\u00ednima\r\n                                const mm = minMaxInSampleRange(aud, s0, s1);\r\n                                if (mm) {\r\n                                    vMin = mm.min;\r\n                                    vMax = mm.max;\r\n                                } else {\r\n                                    vMin = 0;\r\n                                    vMax = 0;\r\n                                }\r\n                            } else {\r\n                                \/* Synthetic waveform for DEMO \/ no-file \/ recording *\/\r\n                                const allowSine = (CVX_NODATA_SINE || (isRecording && __recSineLive));\r\n                                if (allowSine) {\r\n                                    \/* IMPORTANT: phase is time-based so the wave doesn't \"stretch\" as the clip grows *\/\r\n                                    const tex = Math.sin((midT * 6.2831 * __demoHzLive) + (tr.seed * 0.2)) * 0.5 + 0.5;\r\n                                    const p = (0.25 + 0.75 * tex);\r\n\r\n                                    vMin = -p;\r\n                                    vMax = +p;\r\n                                } else {\r\n                                    \/* Silence when no data is assigned *\/\r\n                                    vMin = 0;\r\n                                    vMax = 0;\r\n                                }\r\n                            }\r\n\r\n                            if (ge) {\r\n                                const rel = Math.max(0, midT - c.s);\r\n                                while (geIdx + 1 < ge.length && rel >= ge[geIdx + 1].t) {\r\n                                    geIdx++;\r\n                                    geGain = clipBase * ge[geIdx].g;\r\n                                }\r\n                            }\r\n                            const amp = ampBase * geGain;\r\n                            const aMin = vMin * amp;\r\n                            const aMax = vMax * amp;\r\n\r\n                            let y0 = cy - Math.round(aMax * halfH);\r\n                            let y1 = cy - Math.round(aMin * halfH);\r\n                            if (y0 > y1) {\r\n                                const t = y0;\r\n                                y0 = y1;\r\n                                y1 = t;\r\n                            }\r\n\r\n                            const yMinRaw = clipY + 1;\r\n                            const yMaxRaw = clipY + clipH - 2;\r\n                            const yMin = Math.min(yMinRaw, yMaxRaw);\r\n                            const yMax = Math.max(yMinRaw, yMaxRaw);\r\n\r\n                            y0 = clamp(y0, yMin, yMax);\r\n                            y1 = clamp(y1, yMin, yMax);\r\n\r\n                            ras.vline(x, y0, y1, isActive ? clipInkActive : clipInk);\r\n                        }\r\n\r\n\r\n\r\n                        {\r\n                            const vA = viewStart;\r\n                            const vB = viewStart + span;\r\n                            const mm = pickVisibleMark(c, vA, vB);\r\n\r\n                            if (mm) {\r\n                                const bandH = 10;\r\n                                const bandY = clipY + 1;\r\n\r\n                                const ma = Math.max(c.s, mm.a);\r\n                                const mb = Math.min(c.e, mm.b);\r\n\r\n                                const xS = clamp(timeToX(ma), viewX0, viewX1);\r\n                                const xE = clamp(timeToX(mb), viewX0, viewX1);\r\n                                const segW = Math.max(0, xE - xS);\r\n\r\n                                let txt = String(mm.t || \"\").toUpperCase();\r\n\r\n                                const maxBandW = 46;\r\n                                const minBandW = 18;\r\n                                const wantW0 = clamp(txt.length * 6 + 10, minBandW, maxBandW);\r\n                                const maxChars = Math.max(1, Math.floor((wantW0 - 10) \/ 6));\r\n                                if (txt.length > maxChars) txt = txt.slice(0, Math.max(1, maxChars - 1)) + \"\u2026\";\r\n\r\n                                const wantW = clamp(txt.length * 6 + 10, minBandW, maxBandW);\r\n                                const strokeA = markStrokeA * strokeOn;\r\n\r\n                                if (segW >= wantW + 2) {\r\n                                    const bx0 = clamp(Math.round((xS + xE - wantW) \/ 2), xA + 2, xB - wantW - 2);\r\n\r\n                                    ras.blendRoundRectAA(\r\n                                        bx0, bandY, wantW, bandH, 3,\r\n                                        90, markA,\r\n                                        255, strokeA\r\n                                    );\r\n                                    ras.textAA(bx0 + 4, bandY + 2, txt, Math.round(255 * markInkA), aa);\r\n                                } else {\r\n                                    const sideW = wantW;\r\n                                    const sideX = xS - sideW - 5;\r\n\r\n                                    const canLeft = (sideX >= viewX0);\r\n                                    const bx0 = canLeft ? sideX : clamp(xE + 5, viewX0, viewX1 - sideW);\r\n\r\n                                    ras.blendRoundRectAA(\r\n                                        bx0, bandY, sideW, bandH, 3,\r\n                                        90, markA,\r\n                                        255, strokeA\r\n                                    );\r\n                                    ras.textAA(bx0 + 4, bandY + 2, txt, Math.round(255 * markInkA), aa);\r\n\r\n                                    if (pointerOn) {\r\n                                        const tipY = bandY + 5;\r\n                                        if (canLeft) triRight(xS - 1, tipY, pointerInk, 3);\r\n                                        else triLeft(xE + 1, tipY, pointerInk, 3);\r\n                                    }\r\n                                }\r\n                            }\r\n                        }\r\n                    }\r\n\r\n                    \/* RETAKE overlay (persistent) \u2014 per track lane (before selection overlay) *\/\r\n                    if (retakes.length) {\r\n                        const ySelRT = ry0 + 2;\r\n                        const hSelRT = Math.max(1, (ry1 - ry0) - 3);\r\n\r\n                        const kMul = clamp(css.flt(\"--cvx-oled-retake-mul\", 0.65), 0.05, 1);\r\n                        const edgeV = clampi(css.int(\"--cvx-oled-retake-edge-v\", 80), 0, 255);\r\n\r\n                        for (let ri = 0; ri < retakes.length; ri++) {\r\n                            const r = retakes[ri];\r\n                            const xa = clamp(timeToX(r.a), viewX0, viewX1);\r\n                            const xb = clamp(timeToX(r.b), viewX0, viewX1);\r\n                            const x0r = Math.min(xa, xb) | 0;\r\n                            const x1r = Math.max(xa, xb) | 0;\r\n\r\n                            const wRT = Math.max(1, x1r - x0r);\r\n                            ras.mulRect(x0r, ySelRT, wRT, hSelRT, kMul);\r\n\r\n                            ras.vline(x0r, ry0 + 2, ry1 - 2, edgeV);\r\n                            ras.vline(x1r, ry0 + 2, ry1 - 2, edgeV);\r\n                        }\r\n                    }\r\n\r\n                    if (selection && selection.tracks.has(ti)) {\r\n                        const s0 = Math.min(selection.s, selection.e);\r\n                        const s1 = Math.max(selection.s, selection.e);\r\n                        const xs0 = clamp(timeToX(s0), viewX0, viewX1);\r\n                        const xs1 = clamp(timeToX(s1), viewX0, viewX1);\r\n                        const wSel = Math.max(1, xs1 - xs0);\r\n                        const hSel = Math.max(1, (ry1 - ry0) - 3);\r\n                        const ySel = ry0 + 2;\r\n\r\n                        if (regMode) {\r\n                            const k = clamp(1 - regBodyA, 0.15, 1);\r\n                            ras.mulRect(xs0, ySel, wSel, hSel, k);\r\n                        } else {\r\n                            ras.blendRect(xs0, ySel, wSel, hSel, 255, regBodyA);\r\n                        }\r\n\r\n                        const edgeV = Math.round(255 * regEdgeA);\r\n                        ras.vline(xs0, ry0 + 2, ry1 - 2, edgeV);\r\n                        ras.vline(xs1, ry0 + 2, ry1 - 2, edgeV);\r\n                        ras.vline(xs0 + 1, ry0 + 2, ry1 - 2, Math.round(edgeV * 0.55));\r\n                        ras.vline(xs1 - 1, ry0 + 2, ry1 - 2, Math.round(edgeV * 0.55));\r\n                    }\r\n                }\r\n\r\n                const xP = clamp(timeToX(playhead), viewX0, viewX1);\r\n                ras.vline(xP, y0, y1, 235);\r\n\r\n                \/* Master bar (right) *\/\r\n                if (L.masterBarW > 0) {\r\n                    const barA = clamp(css.flt(\"--cvx-oled-masterbar-alpha\", 1.0), 0, 1);\r\n                    const barBg = clamp(css.int(\"--cvx-oled-masterbar-bg\", 14), 0, 255);\r\n                    const triInk = clamp(css.int(\"--cvx-oled-masterbar-tri-ink\", 220), 0, 255);\r\n                    const triA = clamp(css.flt(\"--cvx-oled-masterbar-tri-alpha\", 0.95), 0, 1);\r\n                    const triSz = clamp(css.int(\"--cvx-oled-masterbar-tri-size\", 4), 2, 6);\r\n\r\n                    const bx = W - L.masterBarW;\r\n                    ras.blendRect(bx, y0, L.masterBarW, (y1 - y0 + 1), barBg, barA);\r\n\r\n                    const cy = Math.floor((y0 + y1) \/ 2);\r\n                    const tipX = bx + Math.floor(L.masterBarW \/ 2);\r\n\r\n                    if (masterPanel.open || masterPanel.anim > 0.01) {\r\n                        triRight(tipX + 2, cy, Math.round(triInk * triA), triSz);\r\n                    } else {\r\n                        triLeft(tipX - 2, cy, Math.round(triInk * triA), triSz);\r\n                    }\r\n                }\r\n\r\n                if (menu.anim > 0.001 || masterPanel.anim > 0.001) {\r\n                    const dimVar = css.flt(\"--cvx-oled-dim\", 0.20);\r\n                    dimViewportOnly(clamp(1 - dimVar, 0, 1));\r\n                }\r\n\r\n                \/* HUD TOAST (center) *\/\r\n                if (hudActive) {\r\n                    const aToast = clamp(css.flt(\"--cvx-oled-hud-toast-alpha\", 0.70), 0, 1);\r\n                    const bgToast = clamp(css.int(\"--cvx-oled-hud-toast-bg\", 18), 0, 255);\r\n                    const inkToast = clamp(css.int(\"--cvx-oled-hud-toast-ink\", 245), 0, 255);\r\n                    const rToast = clamp(css.int(\"--cvx-oled-hud-toast-radius\", 6), 1, 6);\r\n                    const px = clamp(css.int(\"--cvx-oled-hud-toast-pad-x\", 6), 3, 12);\r\n                    const py = clamp(css.int(\"--cvx-oled-hud-toast-pad-y\", 3), 2, 8);\r\n                    const minW = clamp(css.int(\"--cvx-oled-hud-toast-min-w\", 36), 24, 96);\r\n\r\n                    const txt = String(hud.text || \"\").toUpperCase();\r\n                    const textW = txt.length * 6;\r\n                    const boxW = clamp(textW + px * 2, minW, W - 10);\r\n                    const boxH = 7 + py * 2;\r\n\r\n                    const cx = Math.round((W - boxW) \/ 2);\r\n                    const cy = clamp(Math.round((y0 + y1 - boxH) \/ 2), y0 + 2, y1 - boxH - 2);\r\n\r\n                    ras.blendRoundRectAA(cx, cy, boxW, boxH, rToast, bgToast, aToast, 255, 0.25);\r\n                    ras.textAA(cx + px, cy + py, txt, Math.round(inkToast * hudA), aa);\r\n                }\r\n\r\n                \/* MENU *\/\r\n                if (menu.anim > 0.01) {\r\n                    const a = easeOutCubic(menu.anim);\r\n\r\n                    const items = menuItems();\r\n                    const vis = clamp(css.int(\"--cvx-oled-menu-visible\", 3), 2, 5);\r\n\r\n                    const menuR = clamp(css.int(\"--cvx-oled-menu-radius\", 5), 1, 6);\r\n                    const rowR = clamp(css.int(\"--cvx-oled-menu-row-radius\", 4), 1, 6);\r\n\r\n                    const menuTextDY = 1 + (css.int(\"--cvx-oled-menu-text-dy\", 0)) | 0;\r\n                    const compactMenuFont = css.bool(\"--cvx-oled-menu-font-compact\", 1) ? 1 : 0;\r\n                    const fontH = compactMenuFont ? 6 : 7;\r\n\r\n                    const menuBg = clamp(css.int(\"--cvx-oled-menu-bg\", 238), 0, 255) | 0;\r\n                    const menuStrokeV = clamp(css.int(\"--cvx-oled-menu-stroke\", 170), 0, 255) | 0;\r\n                    const menuTitleV = clamp(css.int(\"--cvx-oled-menu-title-ink\", 40), 0, 255) | 0;\r\n\r\n                    const itemBg = clamp(css.int(\"--cvx-oled-menu-item-bg\", 205), 0, 255) | 0;\r\n                    const itemInk = clamp(css.int(\"--cvx-oled-menu-item-ink\", 120), 0, 255) | 0;\r\n\r\n                    const itemBgOn = clamp(css.int(\"--cvx-oled-menu-item-bg-on\", 70), 0, 255) | 0;\r\n                    const itemInkOn = clamp(css.int(\"--cvx-oled-menu-item-ink-on\", 255), 0, 255) | 0;\r\n\r\n                    const boxW = clamp(css.int(\"--cvx-oled-menu-box-w\", 132), 96, 200);\r\n                    let boxH = clamp(css.int(\"--cvx-oled-menu-box-h\", 48), 28, 60);\r\n                    boxH = Math.min(boxH, H - 4);\r\n\r\n                    const padX = clamp(css.int(\"--cvx-oled-menu-pad-x\", 9), 4, 20);\r\n                    const padY = clamp(css.int(\"--cvx-oled-menu-pad-y\", 5), 2, 12);\r\n\r\n                    const titleH = clamp(css.int(\"--cvx-oled-menu-title-h\", 10), 7, 16);\r\n                    const rowH2 = clamp(css.int(\"--cvx-oled-menu-row-h\", 9), 7, 12);\r\n                    const rowPadX = clamp(css.int(\"--cvx-oled-menu-row-pad-x\", 6), 4, 14);\r\n\r\n                    const boxBorderOn = css.bool(\"--cvx-oled-menu-box-border-on\", 0) ? 1 : 0;\r\n                    const rowBorderOn = css.bool(\"--cvx-oled-menu-row-border-on\", 0) ? 1 : 0;\r\n\r\n                    const bx = Math.round((W - boxW) \/ 2);\r\n                    const by0 = -boxH - 2;\r\n                    const by1 = Math.round((H - boxH) \/ 2);\r\n                    const by = Math.round(lerp(by0, by1, a));\r\n\r\n                    const boxStrokeA = (0.70 * strokeOn) * boxBorderOn;\r\n                    ras.blendRoundRectAA(bx, by, boxW, boxH, menuR, menuBg, 1.00, menuStrokeV, boxStrokeA);\r\n\r\n                    const title = (menu.level === \"main\") ? \"EDIT\" : (menu.level === \"fx\") ? \"FX\" : \"FD\";\r\n                    const titleX = bx + padX;\r\n                    const titleY = -4 + by + padY + Math.floor((titleH - fontH) \/ 2) + menuTextDY;\r\n\r\n                    if (compactMenuFont) ras.textBlendAA6(titleX, titleY, title, menuTitleV, aa);\r\n                    else ras.textBlendAA(titleX, titleY, title, menuTitleV, aa);\r\n\r\n                    const listY0 = by + padY + titleH;\r\n                    const listY1 = by + boxH - padY;\r\n                    const availH = Math.max(1, (listY1 - listY0));\r\n                    const needH = vis * rowH2;\r\n                    const gap2 = clamp(Math.floor((availH - needH) \/ (vis + 1)), 1, 8);\r\n\r\n                    const rowX = bx + padX;\r\n                    const rowW = boxW - (padX * 2);\r\n\r\n                    const start = clamp(menu.idx - 1, 0, Math.max(0, items.length - vis));\r\n                    const end = Math.min(items.length, start + vis);\r\n\r\n                    for (let i = start; i < end; i++) {\r\n                        const row = i - start;\r\n                        const ry = listY0 + gap2 + row * (rowH2 + gap2);\r\n                        const isOn = (i === menu.idx);\r\n\r\n                        const fillV = isOn ? itemBgOn : itemBg;\r\n                        const inkV = isOn ? itemInkOn : itemInk;\r\n                        const rowStrokeA = (0.28 * strokeOn) * rowBorderOn;\r\n                        ras.blendRoundRectAA(rowX, ry, rowW, rowH2, rowR, fillV, 1.00, 255, rowStrokeA);\r\n                        const textX = rowX + rowPadX;\r\n                        const textY = ry + Math.floor((rowH2 - fontH) \/ 2) + menuTextDY;\r\n\r\n                        const maxChars = Math.max(1, Math.floor((rowW - rowPadX * 2) \/ 6));\r\n                        let label = String(items[i] || \"\");\r\n                        if (label.length > maxChars) label = label.slice(0, Math.max(1, maxChars - 1)) + \"\u2026\";\r\n\r\n                        if (compactMenuFont) ras.textBlendAA6(textX, textY, label, inkV, aa);\r\n                        else ras.textBlendAA(textX, textY, label, inkV, aa);\r\n                    }\r\n                }\r\n\r\n                \/* MASTER DRAWER *\/\r\n                if (masterPanel.anim > 0.001) {\r\n                    const p = easeOutCubic(masterPanel.anim);\r\n\r\n                    const y0b = L.headerH;\r\n                    const y1b = H - L.footerH - 1;\r\n\r\n                    \/* IMPORTANT: sanitize ints with |0 to kill NaN *\/\r\n                    const panelW = (clamp(css.int(\"--cvx-oled-master-panel-w\", 92), 72, 140) | 0);\r\n                    const padX = (clamp(css.int(\"--cvx-oled-master-panel-pad-x\", 6), 4, 12) | 0);\r\n                    const padY = (clamp(css.int(\"--cvx-oled-master-panel-pad-y\", 4), 3, 10) | 0);\r\n                    const titleH = (clamp(css.int(\"--cvx-oled-master-panel-title-h\", 10), 8, 12) | 0);\r\n                    const rowH = (Math.max(1, (clamp(css.int(\"--cvx-oled-master-panel-row-h\", 10), 9, 14) | 0)));\r\n                    const rowGap = (Math.max(0, (clamp(css.int(\"--cvx-oled-master-panel-row-gap\", 2), 0, 4) | 0)));\r\n                    const rowPadX = (clamp(css.int(\"--cvx-oled-master-panel-row-pad-x\", 5), 3, 10) | 0);\r\n\r\n                    const panelR = (clamp(css.int(\"--cvx-oled-master-panel-radius\", 6), 1, 6) | 0);\r\n                    const rowR = (clamp(css.int(\"--cvx-oled-master-panel-row-radius\", 4), 1, 6) | 0);\r\n\r\n                    const bg = (clamp(css.int(\"--cvx-oled-master-panel-bg\", 22), 0, 255) | 0);\r\n                    const stroke = (clamp(css.int(\"--cvx-oled-master-panel-stroke\", 90), 0, 255) | 0);\r\n                    const borderOn = css.bool(\"--cvx-oled-master-panel-border-on\", 0) ? 1 : 0;\r\n                    const rowBorderOn = css.bool(\"--cvx-oled-master-panel-row-border-on\", 0) ? 1 : 0;\r\n\r\n                    const titleInk = (clamp(css.int(\"--cvx-oled-master-panel-title-ink\", 230), 0, 255) | 0);\r\n\r\n                    const itemBg = (clamp(css.int(\"--cvx-oled-master-panel-item-bg\", 28), 0, 255) | 0);\r\n                    const itemInk = (clamp(css.int(\"--cvx-oled-master-panel-item-ink\", 185), 0, 255) | 0);\r\n                    const itemBgOn = (clamp(css.int(\"--cvx-oled-master-panel-item-bg-on\", 90), 0, 255) | 0);\r\n                    const itemInkOn = (clamp(css.int(\"--cvx-oled-master-panel-item-ink-on\", 255), 0, 255) | 0);\r\n\r\n                    \/* Items: harden against non-array *\/\r\n                    const itemsRaw = masterItems();\r\n                    const items = Array.isArray(itemsRaw) ? itemsRaw : [];\r\n                    const len = items.length | 0;\r\n\r\n                    \/* Clamp selection (and write back SSOT) *\/\r\n                    let selIdx = clamp((masterPanel.idx | 0), 0, Math.max(0, len - 1));\r\n                    masterPanel.idx = selIdx;\r\n\r\n                    \/* Compute panelH from content (safe) *\/\r\n                    const contentH = (titleH + padY * 2 + (len * rowH) + Math.max(0, (len - 1) * rowGap)) | 0;\r\n                    const maxPanelH = ((y1b - y0b + 1) - 2) | 0;\r\n                    const panelH = (clamp(contentH, 24, Math.max(24, maxPanelH)) | 0);\r\n\r\n                    const px0 = (Math.round((W - panelW) + (1 - p) * (panelW + 4)) | 0);\r\n                    const py0 = (clamp(Math.round((y0b + y1b - panelH) \/ 2), y0b + 1, y1b - panelH - 1) | 0);\r\n\r\n                    ras.blendRoundRectAA(\r\n                        px0, py0, panelW, panelH,\r\n                        panelR,\r\n                        bg, 1.0,\r\n                        stroke, (borderOn ? 0.6 : 0)\r\n                    );\r\n\r\n                    ras.textBlendAA(px0 + padX, py0 + padY, \"Master\", titleInk, aa);\r\n\r\n                    \/* Visible window: compute by geometry (no NaN breaks) *\/\r\n                    const innerH = Math.max(0, (panelH - (padY * 2) - titleH) | 0);\r\n                    const stepH = (rowH + rowGap) | 0;\r\n                    const vis = (stepH > 0) ?\r\n                        Math.max(0, Math.min(len, Math.floor((innerH + rowGap) \/ stepH))) :\r\n                        0;\r\n\r\n                    if (!Number.isFinite(masterPanel.top)) masterPanel.top = 0;\r\n                    let top = clamp((masterPanel.top | 0), 0, Math.max(0, len - vis));\r\n\r\n                    \/* Keep selection inside window *\/\r\n                    if (selIdx < top) top = selIdx;\r\n                    else if (vis > 0 && selIdx >= top + vis) top = selIdx - vis + 1;\r\n\r\n                    masterPanel.top = top;\r\n\r\n                    \/* Render *\/\r\n                    const rw = Math.max(1, (panelW - padX * 2) | 0);\r\n                    const rh = rowH | 0;\r\n\r\n                    let ry = (py0 + padY + titleH) | 0;\r\n\r\n                    for (let row = 0; row < vis; row++) {\r\n                        const i = top + row;\r\n                        if (i >= len) break;\r\n\r\n                        const it = items[i];\r\n                        const isOn = (i === selIdx);\r\n\r\n                        ras.blendRoundRectAA(\r\n                            px0 + padX, ry, rw, rh, rowR,\r\n                            isOn ? itemBgOn : itemBg, 1.0,\r\n                            stroke, (rowBorderOn ? 0.30 : 0)\r\n                        );\r\n\r\n\r\n                        \/* Label: accept string or object *\/\r\n                        let label = \"\";\r\n                        if (typeof it === \"string\") label = it;\r\n                        else if (it && typeof it === \"object\") {\r\n                            label = (it.label ?? it.name ?? it.title ?? \"\");\r\n                        }\r\n                        label = String(label);\r\n\r\n                        const maxChars = Math.max(1, Math.floor((rw - rowPadX * 2) \/ 6));\r\n                        const tx = px0 + padX + rowPadX;\r\n                        const ty = ry + Math.floor((rowH - 7) \/ 2);\r\n                        const clipW = Math.max(1, rw - rowPadX * 2);\r\n\r\n                        __drawMenuItemLabel(\r\n                            ras,\r\n                            tx,\r\n                            ty,\r\n                            label,\r\n                            isOn ? itemInkOn : itemInk,\r\n                            aa,\r\n                            clipW,\r\n                            i,\r\n                            isOn\r\n                        );\r\n\r\n                        ry = (ry + stepH) | 0;\r\n                    }\r\n                }\r\n\r\n                \/* -------------------------------------------------------\r\n                   Version popup overlay (DEMO) \u2014 always last\r\n                ------------------------------------------------------- *\/\r\n                drawVersionPopup(dt, aa);\r\n            }\r\n\r\n            \/* -------------------------------------------------------\r\n               Interaction (keyboard + pointer)\r\n            ------------------------------------------------------- *\/\r\n            function clientToOled(ev) {\r\n                const r = canvas.getBoundingClientRect();\r\n                const x = (ev.clientX - r.left) \/ r.width;\r\n                const y = (ev.clientY - r.top) \/ r.height;\r\n                return {\r\n                    x: clamp(Math.round(x * W), 0, W - 1),\r\n                    y: clamp(Math.round(y * H), 0, H - 1)\r\n                };\r\n            }\r\n\r\n            function hitTransport(x, y) {\r\n                if (L.headerH < 8) return null;\r\n                if (y > L.headerH) return null;\r\n\r\n                const bw = clamp(css.int(\"--cvx-oled-hdr-transport-btn-w\", 12), 10, 18);\r\n                const bh = clamp(css.int(\"--cvx-oled-hdr-transport-btn-h\", 8), 7, 10);\r\n                const gap = clamp(css.int(\"--cvx-oled-hdr-transport-gap\", 4), 2, 10);\r\n                const groupW = (bw * 4) + (gap * 3);\r\n                const cxGroup = Math.round((W - groupW) \/ 2);\r\n                const yBtn = clamp(Math.round((L.headerH - bh) \/ 2), 0, Math.max(0, L.headerH - bh));\r\n\r\n                if (y < yBtn || y > yBtn + bh) return null;\r\n                for (let i = 0; i < 4; i++) {\r\n                    const bx = cxGroup + i * (bw + gap);\r\n                    if (x >= bx && x <= bx + bw) {\r\n                        return [\"play\", \"stop\", \"rec\", \"loop\"][i];\r\n                    }\r\n                }\r\n                return null;\r\n            }\r\n\r\n            function menuHitTest(x, y) {\r\n                if (menu.anim <= 0.01) return null;\r\n\r\n                const items = menuItems();\r\n                const vis = clamp(css.int(\"--cvx-oled-menu-visible\", 3), 2, 5);\r\n\r\n                const boxW = clamp(css.int(\"--cvx-oled-menu-box-w\", 132), 96, 200);\r\n                let boxH = clamp(css.int(\"--cvx-oled-menu-box-h\", 48), 28, 60);\r\n                boxH = Math.min(boxH, H - 4);\r\n\r\n                const padX = clamp(css.int(\"--cvx-oled-menu-pad-x\", 9), 4, 20);\r\n                const padY = clamp(css.int(\"--cvx-oled-menu-pad-y\", 5), 2, 12);\r\n                const titleH = clamp(css.int(\"--cvx-oled-menu-title-h\", 10), 7, 16);\r\n                const rowH = clamp(css.int(\"--cvx-oled-menu-row-h\", 9), 7, 12);\r\n\r\n                const bx = Math.round((W - boxW) \/ 2);\r\n                const by0 = -boxH - 2;\r\n                const by1 = Math.round((H - boxH) \/ 2);\r\n                const a = easeOutCubic(menu.anim);\r\n                const by = Math.round(lerp(by0, by1, a));\r\n\r\n                if (x < bx || x > bx + boxW || y < by || y > by + boxH) return null;\r\n\r\n                const listY0 = by + padY + titleH;\r\n                const listY1 = by + boxH - padY;\r\n                const availH = Math.max(1, (listY1 - listY0));\r\n                const needH = vis * rowH;\r\n                const gap = clamp(Math.floor((availH - needH) \/ (vis + 1)), 1, 8);\r\n\r\n                const rowX = bx + padX;\r\n                const rowW = boxW - (padX * 2);\r\n\r\n                const start = clamp(menu.idx - 1, 0, Math.max(0, items.length - vis));\r\n                const end = Math.min(items.length, start + vis);\r\n\r\n                for (let i = start; i < end; i++) {\r\n                    const row = i - start;\r\n                    const ry = listY0 + gap + row * (rowH + gap);\r\n                    if (x >= rowX && x <= rowX + rowW && y >= ry && y <= ry + rowH) return i;\r\n                }\r\n                return -1;\r\n            }\r\n\r\n            function masterHitTest(x, y) {\r\n                if (masterPanel.anim <= 0.01) return null;\r\n\r\n                const y0b = L.headerH;\r\n                const y1b = H - L.footerH - 1;\r\n\r\n                const panelW = (clamp(css.int(\"--cvx-oled-master-panel-w\", 92), 72, 140) | 0);\r\n                const padX = (clamp(css.int(\"--cvx-oled-master-panel-pad-x\", 6), 4, 12) | 0);\r\n                const padY = (clamp(css.int(\"--cvx-oled-master-panel-pad-y\", 4), 3, 10) | 0);\r\n                const titleH = (clamp(css.int(\"--cvx-oled-master-panel-title-h\", 10), 8, 12) | 0);\r\n                const rowH = (Math.max(1, (clamp(css.int(\"--cvx-oled-master-panel-row-h\", 10), 9, 14) | 0)));\r\n                const rowGap = (Math.max(0, (clamp(css.int(\"--cvx-oled-master-panel-row-gap\", 2), 0, 4) | 0)));\r\n\r\n                const itemsRaw = masterItems();\r\n                const items = Array.isArray(itemsRaw) ? itemsRaw : [];\r\n                const len = items.length | 0;\r\n\r\n                const contentH = (titleH + padY * 2 + (len * rowH) + Math.max(0, (len - 1) * rowGap)) | 0;\r\n                const maxPanelH = ((y1b - y0b + 1) - 2) | 0;\r\n                const panelH = (clamp(contentH, 24, Math.max(24, maxPanelH)) | 0);\r\n\r\n                const p = easeOutCubic(masterPanel.anim);\r\n                const px0 = (Math.round((W - panelW) + (1 - p) * (panelW + 4)) | 0);\r\n                const py0 = (clamp(Math.round((y0b + y1b - panelH) \/ 2), y0b + 1, y1b - panelH - 1) | 0);\r\n\r\n                if (x < px0 || x > px0 + panelW || y < py0 || y > py0 + panelH) return null;\r\n\r\n                const listY = (py0 + padY + titleH) | 0;\r\n                const innerH = Math.max(0, (panelH - (padY * 2) - titleH) | 0);\r\n                const stepH = (rowH + rowGap) | 0;\r\n\r\n                const vis = (stepH > 0) ? Math.max(0, Math.min(len, Math.floor((innerH + rowGap) \/ stepH))) : 0;\r\n                const maxTop = Math.max(0, len - vis);\r\n\r\n                const top = clamp((masterPanel.top | 0), 0, maxTop);\r\n\r\n                if (y < listY || y > listY + innerH) return -1;\r\n\r\n                const localY = (y - listY) | 0;\r\n                const row = (stepH > 0) ? Math.floor(localY \/ stepH) : 0;\r\n                if (row < 0 || row >= vis) return -1;\r\n\r\n                const inRowY = (localY - row * stepH) < rowH;\r\n                if (!inRowY) return -1;\r\n\r\n                const idx = top + row;\r\n                if (idx < 0 || idx >= len) return -1;\r\n\r\n                return idx;\r\n            }\r\n\r\n            canvas.tabIndex = 0;\r\n            canvas.setAttribute(\"tabindex\", \"0\");\r\n\r\n            canvas.addEventListener(\"pointerdown\", (ev) => {\r\n                ev.preventDefault();\r\n                try {\r\n                    canvas.setPointerCapture(ev.pointerId);\r\n                } catch (_) {}\r\n                canvas.focus({\r\n                    preventScroll: true\r\n                });\r\n                pokeChrome();\r\n\r\n                const p = clientToOled(ev);\r\n\r\n                \/* -------------------------------------------------------\r\n                   Version popup (DEMO) \u2014 pointer routing\r\n                   - Click pill: selects\r\n                   - Click selected pill: activates\r\n                ------------------------------------------------------- *\/\r\n                if (verPopup.open) {\r\n                    const x = p.x | 0,\r\n                        y = p.y | 0;\r\n                    let hit = -1;\r\n                    for (let i = 0; i < verPopup.btns.length; i++) {\r\n                        const b = verPopup.btns[i];\r\n                        if (x >= b.x && x < (b.x + b.w) && y >= b.y && y < (b.y + b.h)) {\r\n                            hit = i;\r\n                            break;\r\n                        }\r\n                    }\r\n                    if (hit >= 0) {\r\n                        verPopup.sel = hit; \/\/ mantiene highlight consistente\r\n                        verActivateSelection(); \/\/ 1 click = OK\r\n                    }\r\n                    return;\r\n                }\r\n\r\n                \/* master bar toggle *\/\r\n                if (css.bool(\"--cvx-oled-masterbar-on\", 1) && L.masterBarW > 0) {\r\n                    const bx = W - L.masterBarW;\r\n                    const y0 = L.headerH;\r\n                    const y1 = H - L.footerH - 1;\r\n                    if (p.x >= bx && p.y >= y0 && p.y <= y1) {\r\n                        if (menu.open) menu.open = false;\r\n                        masterPanel.open = !masterPanel.open;\r\n                        masterPanel.idx = 0;\r\n                        pokeChrome();\r\n                        return;\r\n                    }\r\n                }\r\n\r\n                \/* click inside master panel => activate; click outside => close (consume) *\/\r\n                if (masterPanel.open) {\r\n                    const idx = masterHitTest(p.x, p.y);\r\n                    if (idx != null && idx >= 0) {\r\n                        const items = masterItems();\r\n                        masterPanel.idx = clamp(idx, 0, Math.max(0, items.length - 1));\r\n                        execMasterAction(items[masterPanel.idx], ev.shiftKey ? -1 : 1);\r\n                        return;\r\n                    }\r\n                    if (idx === -1) {\r\n                        return; \/* inside panel but not on a row *\/\r\n                    }\r\n                    masterPanel.open = false;\r\n                    pokeChrome();\r\n                    return;\r\n                }\r\n\r\n                \/* click inside menu => activate; click outside => close (consume) *\/\r\n                if (menu.open) {\r\n                    const hitIdx = menuHitTest(p.x, p.y);\r\n                    if (hitIdx != null && hitIdx >= 0) {\r\n                        menu.idx = hitIdx;\r\n                        activateMenuSelection();\r\n                        pokeChrome();\r\n                        return;\r\n                    }\r\n                    menu.open = false;\r\n                    pokeChrome();\r\n                    return;\r\n                }\r\n\r\n                \/* transport *\/\r\n                const hit = hitTransport(p.x, p.y);\r\n                if (hit) {\r\n                    if (hit === \"play\") actPlayToggle();\r\n                    else if (hit === \"stop\") actStop();\r\n                    else if (hit === \"rec\") actRecToggle();\r\n                    else if (hit === \"loop\") actLoopToggle();\r\n                    return;\r\n                }\r\n\r\n                \/* output preset cycle (left header zone) *\/\r\n                if (p.y <= L.headerH && p.x < 90) {\r\n                    cycleOutputPreset(ev.shiftKey ? -1 : 1);\r\n                    return;\r\n                }\r\n\r\n                const y0 = L.headerH;\r\n                const y1 = H - L.footerH - 1;\r\n                const listX1 = L.pad + L.listW;\r\n\r\n                \/* click on track list *\/\r\n                if (p.y >= y0 && p.y <= y1 && p.x <= listX1) {\r\n                    const vt = visibleTracksCount();\r\n                    const rowH = Math.floor((y1 - y0 + 1) \/ vt);\r\n                    const idx = clamp(Math.floor((p.y - y0) \/ Math.max(1, rowH)), 0, vt - 1);\r\n                    const canAddRow = (tracks.length < CVX_TRACKS_MAX);\r\n                    const listCount = tracks.length + (canAddRow ? 1 : 0);\r\n                    if (!listCount) return;\r\n\r\n                    const ti = clamp(trackTop + idx, 0, listCount - 1);\r\n                    activeTrack = ti;\r\n                    \/* Virtual \u201c+ ADD\u201d row: selectable, but has no per-track toggles *\/\r\n                    if (canAddRow && ti === tracks.length) {\r\n                        \/* \u201c+ ADD\u201d acts like a button: click creates a track *\/\r\n                        const loadData = !!css.bool(\"--cvx-oled-addtrack-autoload\", 1);\r\n\r\n                        actStop(); \/* safe: stops PLAY\/REC if needed *\/\r\n                        addTrack(loadData); \/* same behavior as ENTER in +ADD *\/\r\n\r\n                        return;\r\n                    }\r\n                    if (ev.shiftKey) {\r\n                        const next = new Set(multiSel);\r\n                        if (next.has(ti)) next.delete(ti);\r\n                        else next.add(ti);\r\n\r\n                        \/* enforce max 2 *\/\r\n                        while (next.size > 2) {\r\n                            const first = next.values().next().value;\r\n                            next.delete(first);\r\n                        }\r\n                        if (next.size === 0) next.add(ti);\r\n                        multiSel = next;\r\n                    } else {\r\n                        multiSel = new Set([ti]);\r\n                    }\r\n                    \/* ---------------- ARM hit-test (toggle) ---------------- *\/\r\n                    {\r\n                        const listX0 = L.pad;\r\n\r\n                        const idxOn = css.bool(\"--cvx-oled-track-index-on\", 1) ? 1 : 0;\r\n                        const armOn = css.bool(\"--cvx-oled-track-arm-on\", 1) ? 1 : 0;\r\n\r\n                        if (armOn && ti >= 0 && ti < tracks.length) {\r\n                            const tPadL = clamp(css.int(\"--cvx-oled-track-pad-l\", 2), 0, 10);\r\n\r\n                            const armW = clamp(css.int(\"--cvx-oled-track-arm-w\", 7), 5, 12);\r\n                            const armH = clamp(css.int(\"--cvx-oled-track-arm-h\", 10), 7, 64);\r\n                            const armSizeMode = css.int(\"--cvx-oled-track-arm-SizeMode\", 0); \/\/ 0\/1\r\n                            const armIdxMode = css.int(\"--cvx-oled-track-arm-IdxMode\", 0); \/\/ 0\/1\r\n\r\n                            const rowY0 = y0 + idx * rowH;\r\n                            const rowY1 = (idx === vt - 1) ? y1 : (rowY0 + rowH - 1);\r\n\r\n                            const isX2 = (vt === 2);\r\n                            const ax = (listX0 + tPadL + (isX2 ? -1 : 0)) | 0;\r\n\r\n                            const aH = (armSizeMode === 1) ?\r\n                                Math.max(7, (rowY1 - rowY0 + 1) - 2) :\r\n                                armH;\r\n\r\n                            const ay = clamp(Math.floor((rowY0 + rowY1 - aH) \/ 2), rowY0 + 1, rowY1 - aH);\r\n\r\n                            if (p.x >= ax && p.x <= ax + armW && p.y >= ay && p.y <= ay + aH) {\r\n                                tracks[ti].arm = !tracks[ti].arm;\r\n                                setHud(tracks[ti].arm ? \"ARM\" : \"ARM OFF\", 550);\r\n                                pokeChrome();\r\n                                return;\r\n                            }\r\n                        }\r\n                    }\r\n                    \/* ------------- GAIN\/VOL slider hit-test (X1) ------------- *\/\r\n                    if (vt === 1 && ti >= 0 && ti < tracks.length) {\r\n                        const srcOn = css.bool(\"--cvx-oled-track-src-on\", 1) ? 1 : 0;\r\n                        if (srcOn && rowH >= 18) {\r\n\r\n                            const listX0 = L.pad;\r\n                            const tPadL = clamp(css.int(\"--cvx-oled-track-pad-l\", 2), 0, 10);\r\n                            const tPadR = clamp(css.int(\"--cvx-oled-track-pad-r\", 2), 0, 10);\r\n\r\n                            const idxOn = css.bool(\"--cvx-oled-track-index-on\", 1) ? 1 : 0;\r\n                            const armOn = css.bool(\"--cvx-oled-track-arm-on\", 1) ? 1 : 0;\r\n                            const armW = clamp(css.int(\"--cvx-oled-track-arm-w\", 7), 5, 12);\r\n                            const armIdxMode = css.int(\"--cvx-oled-track-arm-IdxMode\", 0); \/\/ 0\/1\r\n\r\n                            const x2NamePadT = css.int(\"--cvx-oled-track-x2-NamePadT\", 1);\r\n                            const x2SrcPadB = css.int(\"--cvx-oled-track-x2-SrcPadB\", 1);\r\n\r\n                            \/\/ y-geometry igual al draw (X1 two-line)\r\n                            const rowY0 = y0;\r\n                            const rowY1 = y1;\r\n\r\n                            const tyName = clamp(rowY0 + x2NamePadT, rowY0, rowY1 - 7);\r\n                            const tySrc = clamp(rowY1 - 7 - x2SrcPadB, rowY0, rowY1 - 7);\r\n\r\n                            \/\/ nameX \/ nameMaxW (aprox igual a draw, reservando zona derecha)\r\n                            let xText = listX0 + tPadL;\r\n                            if (armOn) xText += armW + 2;\r\n                            if (idxOn && !(armOn && armIdxMode)) xText += 12;\r\n\r\n                            const msOn = css.bool(\"--cvx-oled-ms-on\", 1) ? 1 : 0;\r\n                            const msGap = clamp(css.int(\"--cvx-oled-ms-gap\", 2), 0, 4);\r\n                            const msW = clamp(css.int(\"--cvx-oled-ms-box-w-x2\", 12), 9, 16);\r\n\r\n                            const meterVOn = css.bool(\"--cvx-oled-track-meter-v-on\", 1) ? 1 : 0;\r\n                            const meterVW = clamp(css.int(\"--cvx-oled-track-meter-v-w\", 3), 2, 6);\r\n\r\n                            const rightZoneW = msOn ? msW : 0;\r\n                            const wantMeterV = meterVOn ? 1 : 0;\r\n                            const vMeterGap = wantMeterV ? 2 : 0;\r\n                            const vMeterW = wantMeterV ? meterVW : 0;\r\n\r\n                            const listX1 = L.pad + L.listW;\r\n                            const xRightLimit = listX1 - tPadR;\r\n\r\n                            const msX = xRightLimit - rightZoneW;\r\n                            const meterVX = msX - vMeterGap - vMeterW;\r\n\r\n                            const nameX = xText;\r\n                            const nameMaxX = wantMeterV ? (meterVX - 2) : (msOn ? (msX - 2) : xRightLimit);\r\n                            const nameMaxW = Math.max(0, nameMaxX - nameX);\r\n\r\n                            if (nameMaxW > 0) {\r\n                                \/\/ barras igual a draw\r\n                                const ctlTop = tyName + 8;\r\n                                const ctlBot = tySrc - 1;\r\n                                const ctlH = ctlBot - ctlTop;\r\n\r\n                                const txtH = 7,\r\n                                    gapY = 1,\r\n                                    barH = 3;\r\n\r\n                                const betweenBars = 3; \/* colapsado: igual que hoy *\/\r\n                                const betweenFull = betweenBars + clamp(css.int(\"--cvx-oled-ctl-gap-full\", 2), 0, 12);\r\n\r\n                                const fullH = (txtH + gapY + barH) * 2 + betweenFull;\r\n                                const barsH = (barH * 2) + betweenBars;\r\n\r\n                                const canFull = (ctlH >= fullH);\r\n                                const canBars = (!canFull && ctlH >= barsH);\r\n                                if (!(canFull || canBars)) {\r\n                                    \/* ... ocultar controles ... *\/\r\n                                }\r\n\r\n                                const betweenUse = canFull ? betweenFull : betweenBars;\r\n                                const useH = canFull ? fullH : barsH;\r\n                                const yBase = ctlTop + Math.floor((ctlH - useH) \/ 2);\r\n\r\n                                if (canFull || canBars) {\r\n                                    const barX = nameX;\r\n                                    const barW = Math.max(14, nameMaxW);\r\n\r\n                                    const useH = canFull ? fullH : barsH;\r\n                                    const yBase = ctlTop + Math.floor((ctlH - useH) \/ 2);\r\n\r\n                                    const gBarY = canFull ? (yBase + txtH + gapY) : yBase;\r\n                                    const vBarY = canFull ?\r\n                                        (gBarY + barH + betweenUse + txtH + gapY) :\r\n                                        (gBarY + barH + betweenUse);\r\n                                    \/\/ hit tolerances\r\n                                    const yPad = 2;\r\n\r\n                                    const inX = (p.x >= barX && p.x <= barX + barW);\r\n                                    if (inX) {\r\n                                        const g0 = (gBarY - yPad),\r\n                                            g1 = (gBarY + barH + yPad);\r\n                                        const v0 = (vBarY - yPad),\r\n                                            v1 = (vBarY + barH + yPad);\r\n\r\n                                        const inG = (p.y >= g0 && p.y <= g1);\r\n                                        const inV = (p.y >= v0 && p.y <= v1);\r\n\r\n                                        if (inG || inV) {\r\n                                            const gMid = gBarY + (barH - 1) * 0.5;\r\n                                            const vMid = vBarY + (barH - 1) * 0.5;\r\n\r\n                                            const dg = inG ? Math.abs(p.y - gMid) : 1e9;\r\n                                            const dv = inV ? Math.abs(p.y - vMid) : 1e9;\r\n\r\n                                            const kind = (dv < dg) ? \"vol\" : \"gain\";\r\n\r\n                                            ctlDrag = {\r\n                                                pid: ev.pointerId,\r\n                                                kind,\r\n                                                ti,\r\n                                                barX,\r\n                                                barW\r\n                                            };\r\n                                            applyCtlFromX(kind, ti, p.x, barX, barW);\r\n                                            pokeChrome();\r\n                                            return;\r\n                                        }\r\n                                    }\r\n                                }\r\n                            }\r\n                        }\r\n                    }\r\n                    \/* M\/S click zones (approx; matches draw geometry) *\/\r\n                    const isX4 = (vt >= 4);\r\n                    const msW = isX4 ? clamp(css.int(\"--cvx-oled-ms-box-w-x4\", 9), 7, 12) : clamp(css.int(\"--cvx-oled-ms-box-w-x2\", 12), 9, 16);\r\n                    const msH = isX4 ? clamp(css.int(\"--cvx-oled-ms-box-h-x4\", 8), 7, 10) : clamp(css.int(\"--cvx-oled-ms-box-h-x2\", 10), 9, 14);\r\n                    const msGap = clamp(css.int(\"--cvx-oled-ms-gap\", 2), 0, 4);\r\n                    const tPadR = clamp(css.int(\"--cvx-oled-track-pad-r\", 2), 0, 10);\r\n\r\n                    const xRightLimit = listX1 - tPadR;\r\n\r\n                    if (isX4) {\r\n                        const xM = xRightLimit - (msW * 2 + msGap);\r\n                        const xS = xM + msW + msGap;\r\n                        const rowY0 = y0 + idx * rowH;\r\n                        const rowY1 = (idx === vt - 1) ? y1 : (rowY0 + rowH - 1);\r\n                        const boxY = clamp(Math.floor((rowY0 + rowY1 - msH) \/ 2), rowY0, rowY1 - msH);\r\n\r\n                        if (p.x >= xM && p.x <= xM + msW && p.y >= boxY && p.y <= boxY + msH) {\r\n                            tracks[activeTrack].mute = !tracks[activeTrack].mute;\r\n                            setHud(tracks[activeTrack].mute ? \"MUTE\" : \"MUTE OFF\", 750);\r\n                            return;\r\n                        }\r\n                        if (p.x >= xS && p.x <= xS + msW && p.y >= boxY && p.y <= boxY + msH) {\r\n                            tracks[activeTrack].solo = !tracks[activeTrack].solo;\r\n                            setHud(tracks[activeTrack].solo ? \"SOLO\" : \"SOLO OFF\", 750);\r\n                            return;\r\n                        }\r\n                    } else {\r\n                        const xBox = xRightLimit - msW;\r\n                        const totalH = msH * 2 + msGap;\r\n                        const rowY0 = y0 + idx * rowH;\r\n                        const rowY1 = (idx === vt - 1) ? y1 : (rowY0 + rowH - 1);\r\n                        const boxY0 = clamp(Math.floor((rowY0 + rowY1 - totalH) \/ 2), rowY0, rowY1 - totalH);\r\n                        const yS0 = boxY0;\r\n                        const yM0 = boxY0 + msH + msGap;\r\n\r\n                        if (p.x >= xBox && p.x <= xBox + msW && p.y >= yS0 && p.y <= yS0 + msH) {\r\n                            tracks[activeTrack].solo = !tracks[activeTrack].solo;\r\n                            setHud(tracks[activeTrack].solo ? \"SOLO\" : \"SOLO OFF\", 750);\r\n                            return;\r\n                        }\r\n                        if (p.x >= xBox && p.x <= xBox + msW && p.y >= yM0 && p.y <= yM0 + msH) {\r\n                            tracks[activeTrack].mute = !tracks[activeTrack].mute;\r\n                            setHud(tracks[activeTrack].mute ? \"MUTE\" : \"MUTE OFF\", 750);\r\n                            return;\r\n                        }\r\n                    }\r\n\r\n                    return;\r\n                }\r\n\r\n                \/* click in timeline area (only inside track viewport, right of list) *\/\r\n                if (p.y >= y0 && p.y <= y1) {\r\n                    if (p.x > (listX1 + L.gap)) {\r\n                        dragStartT = xToTime(p.x);\r\n                        dragStartX = p.x;\r\n                        dragMoved = false;\r\n                        dragging = true;\r\n                        draggingRegion = true;\r\n\r\n                        \/* you already captured pointer at the top of pointerdown *\/\r\n                        selection = null;\r\n\r\n                        \/* auto-loop only if PLAY is pressed from stopped state (spec: if already playing, do not arm) *\/\r\n                        regionLoop.on = false;\r\n                        regionLoopArm = !isPlaying;\r\n\r\n                        setHud(\"REGION\", 450);\r\n                        pokeChrome();\r\n                        return;\r\n                    }\r\n                }\r\n\r\n\r\n            });\r\n\r\n            canvas.addEventListener(\"pointermove\", (ev) => {\r\n                \/* Control drag has priority over region drag *\/\r\n                if (ctlDrag && ctlDrag.pid === ev.pointerId) {\r\n                    const p = clientToOled(ev);\r\n                    applyCtlFromX(ctlDrag.kind, ctlDrag.ti, p.x, ctlDrag.barX, ctlDrag.barW);\r\n                    pokeChrome();\r\n                    return;\r\n                }\r\n\r\n                if (!draggingRegion) return;\r\n                const p = clientToOled(ev);\r\n\r\n                \/* =========================================================\r\n                   Auto-pan timeline when dragging outside viewport\r\n                   ========================================================= *\/\r\n                const span = timelineSpan();\r\n                const maxT = timelineMaxSecondsAll();\r\n\r\n                \/* must match xToTime() geometry *\/\r\n                const x0 = L.pad + L.listW + L.gap;\r\n                const x1 = W - L.pad - 1 - L.masterBarW;\r\n                const vw = Math.max(1, x1 - x0 + 1);\r\n\r\n                const dead = clamp(css.int(\"--cvx-oled-autopan-deadpx\", 2), 0, 12);\r\n                const maxPx = clamp(css.int(\"--cvx-oled-autopan-maxpx\", 18), 2, 96);\r\n\r\n                let overflow = 0;\r\n                if (p.x < x0 - dead) overflow = p.x - (x0 - dead);\r\n                else if (p.x > x1 + dead) overflow = p.x - (x1 + dead);\r\n\r\n                \/* store for continuous pan inside draw() *\/\r\n                regionAutoPan.x = p.x;\r\n                regionAutoPan.overflowPx = overflow ? clamp(overflow, -maxPx, maxPx) : 0;\r\n\r\n                const t = xToTime(p.x);\r\n\r\n\r\n                if (!selection) {\r\n                    selection = {\r\n                        s: dragStartT,\r\n                        e: dragStartT,\r\n                        tracks: new Set(multiSel)\r\n                    };\r\n                }\r\n\r\n                selection.e = t;\r\n\r\n                \/* movement detection must be pixel-based, not time-based *\/\r\n                const pxThr = clamp(css.int(\"--cvx-oled-region-drag-px\", 2), 1, 12);\r\n                if (Math.abs(p.x - dragStartX) >= pxThr) dragMoved = true;\r\n            });\r\n\r\n            canvas.addEventListener(\"pointerup\", (ev) => {\r\n                if (ctlDrag && ctlDrag.pid === ev.pointerId) {\r\n                    ctlDrag = null;\r\n                    try {\r\n                        canvas.releasePointerCapture(ev.pointerId);\r\n                    } catch (_) {}\r\n                    pokeChrome();\r\n                    return;\r\n                }\r\n\r\n                if (!draggingRegion) return;\r\n\r\n                dragging = false;\r\n                draggingRegion = false;\r\n                regionAutoPan.overflowPx = 0;\r\n\r\n                try {\r\n                    canvas.releasePointerCapture(ev.pointerId);\r\n                } catch (_) {}\r\n\r\n                pokeChrome();\r\n\r\n                \/* click-only => move playhead and clear selection *\/\r\n                if (!dragMoved) {\r\n                    if (isRecording) {\r\n                        setHud(\"REC LOCK\", 550);\r\n                    } else {\r\n                        playhead = clamp(dragStartT, 0, timelineMaxSecondsAll());\r\n                        selection = null;\r\n                        regionLoop.on = false;\r\n                        regionLoopArm = false;\r\n                    }\r\n                }\r\n\r\n            });\r\n\r\n\r\n            canvas.addEventListener(\"keydown\", (ev) => {\r\n                const k = ev.key;\r\n                const key = (k && k.length === 1) ? k.toUpperCase() : k;\r\n\r\n                \/* -------------------------------------------------------\r\n                   Datafile hotkeys (ALT + digit \/ ALT + clear)\r\n                   - Uses the CSS datafile pool (see --cvx-oled-datafile)\r\n                ------------------------------------------------------- *\/\r\n                if (CVX_DATAFILE_HOTKEYS && ev.altKey && !ev.ctrlKey && !ev.metaKey) {\r\n                    const clearKey = (CVX_DATAFILE_HK_CLEAR || \"-\");\r\n                    if (key === clearKey) {\r\n                        ev.preventDefault();\r\n                        ev.stopPropagation();\r\n                        if (activeTrack < 0 || activeTrack >= tracks.length) {\r\n                            setHud(\"NO TRACK\", 450);\r\n                            return;\r\n                        }\r\n\r\n                        clearTrackDatafile(activeTrack);\r\n                        return;\r\n                    }\r\n                    if (key >= \"0\" && key <= \"9\") {\r\n                        ev.preventDefault();\r\n                        ev.stopPropagation();\r\n                        if (activeTrack < 0 || activeTrack >= tracks.length) {\r\n                            setHud(\"NO TRACK\", 450);\r\n                            return;\r\n                        }\r\n\r\n                        const digit = (key.charCodeAt(0) - 48) | 0;\r\n                        const fileIdx = (CVX_DATAFILE_HK_DIGIT0 + digit) | 0;\r\n                        assignDataFileToTrack(activeTrack, fileIdx);\r\n                        return;\r\n                    }\r\n                }\r\n                \/* -------------------------------------------------------\r\n                   Hard reset hotkey (boot state)\r\n                ------------------------------------------------------- *\/\r\n                if (!ev.altKey && !ev.ctrlKey && !ev.metaKey) {\r\n                    const rk = (CVX_HK_RESET || \"\").trim();\r\n                    if (rk && key === rk.toUpperCase()) {\r\n                        ev.preventDefault();\r\n                        ev.stopPropagation();\r\n                        resetToBoot();\r\n                        return;\r\n                    }\r\n                }\r\n\r\n                const stop = () => {\r\n                    ev.preventDefault();\r\n                    ev.stopPropagation();\r\n                };\r\n\r\n                \/* -------------------------------------------------------\r\n                   Version popup (DEMO)\r\n                   - Open by --cvx-oled-hotkey-version (default \"V\")\r\n                   - Modal navigation: Left\/Right cycles bottom pills\r\n                   - Enter executes, '.' acts as BACK\r\n                ------------------------------------------------------- *\/\r\n                if (!verPopup.open && !ev.altKey && !ev.ctrlKey && !ev.metaKey) {\r\n                    const vk = (CVX_HK_VERSION || \"\").trim();\r\n                    if (vk && key === vk.toUpperCase()) {\r\n                        stop();\r\n                        verOpen();\r\n                        return;\r\n                    }\r\n                }\r\n\r\n                if (verPopup.open) {\r\n                    const btnCount = (verPopup.view === \"save\") ? 3 : 2;\r\n                    if (verPopup.view === \"history\") {\r\n                        const n = (Array.isArray(verPopup.hist) ? verPopup.hist.length : 0) | 0;\r\n                        if (n > 0 && key === \"ArrowUp\") {\r\n                            stop();\r\n                            verPopup.hIdx = clamp(verPopup.hIdx - 1, 0, n - 1);\r\n                            if (verPopup.hIdx < verPopup.hTop) verPopup.hTop = verPopup.hIdx;\r\n                            pokeChrome();\r\n                            return;\r\n                        }\r\n                        if (n > 0 && key === \"ArrowDown\") {\r\n                            stop();\r\n                            verPopup.hIdx = clamp(verPopup.hIdx + 1, 0, n - 1);\r\n                            const vis = 2; \/\/ draw shows at least 2 rows\r\n                            if (verPopup.hIdx >= verPopup.hTop + vis) verPopup.hTop = verPopup.hIdx - (vis - 1);\r\n                            pokeChrome();\r\n                            return;\r\n                        }\r\n                    }\r\n                    if (key === \"ArrowLeft\") {\r\n                        stop();\r\n                        verPopup.sel = (verPopup.sel - 1 + btnCount) % btnCount;\r\n                        pokeChrome();\r\n                        return;\r\n                    }\r\n                    if (key === \"ArrowRight\") {\r\n                        stop();\r\n                        verPopup.sel = (verPopup.sel + 1) % btnCount;\r\n                        pokeChrome();\r\n                        return;\r\n                    }\r\n                    if (key === \".\" || key === \"Escape\") {\r\n                        stop();\r\n                        \/\/ BACK behavior: history -> save, save -> close\r\n                        if (verPopup.view === \"history\") verBackToSave();\r\n                        else verClose();\r\n                        return;\r\n                    }\r\n                    if (key === \"Enter\") {\r\n                        stop();\r\n                        verActivateSelection();\r\n                        return;\r\n                    }\r\n\r\n                    \/\/ swallow other shortcuts while modal is open\r\n                    return;\r\n                }\r\n\r\n                \/* master panel navigation *\/\r\n                if (masterPanel.open) {\r\n                    const items = masterItems();\r\n                    const maxIdx = Math.max(0, items.length - 1);\r\n\r\n                    if (key === \"ArrowUp\") {\r\n                        stop();\r\n                        masterPanel.idx = clamp(masterPanel.idx - 1, 0, maxIdx);\r\n                        masterSyncScroll(items.length);\r\n                        pokeChrome();\r\n                        return;\r\n                    }\r\n\r\n                    if (key === \"ArrowDown\") {\r\n                        stop();\r\n                        masterPanel.idx = clamp(masterPanel.idx + 1, 0, maxIdx);\r\n                        masterSyncScroll(items.length);\r\n                        pokeChrome();\r\n                        return;\r\n                    }\r\n\r\n                    if (key === \".\") {\r\n                        stop();\r\n                        masterPanel.open = false;\r\n                        pokeChrome();\r\n                        return;\r\n                    }\r\n                    if (key === \"Enter\") {\r\n                        stop();\r\n                        execMasterAction(items[masterPanel.idx], ev.shiftKey ? -1 : 1);\r\n                        pokeChrome();\r\n                        return;\r\n                    }\r\n                    return;\r\n                }\r\n\r\n                \/* edit menu navigation *\/\r\n                if (menu.open) {\r\n                    const items = menuItems();\r\n                    const maxIdx = Math.max(0, items.length - 1);\r\n\r\n                    if (key === \"ArrowUp\") {\r\n                        stop();\r\n                        menu.idx = clamp(menu.idx - 1, 0, maxIdx);\r\n                        pokeChrome();\r\n                        return;\r\n                    }\r\n                    if (key === \"ArrowDown\") {\r\n                        stop();\r\n                        menu.idx = clamp(menu.idx + 1, 0, maxIdx);\r\n                        pokeChrome();\r\n                        return;\r\n                    }\r\n                    if (key === \".\") {\r\n                        stop();\r\n                        menu.open = false;\r\n                        pokeChrome();\r\n                        return;\r\n                    }\r\n                    if (key === \"Enter\") {\r\n                        stop();\r\n                        activateMenuSelection();\r\n                        pokeChrome();\r\n                        return;\r\n                    }\r\n                    return;\r\n                }\r\n\r\n                \/* global shortcuts *\/\r\n                if (key === \" \" || key === \"Spacebar\") {\r\n                    stop();\r\n                    actPlayToggle();\r\n                    return;\r\n                }\r\n                if (key === \"R\") {\r\n                    stop();\r\n                    actRecToggle();\r\n                    return;\r\n                }\r\n                if (key === \"L\") {\r\n                    stop();\r\n                    actLoopToggle();\r\n                    return;\r\n                }\r\n\r\n                if (key === \"W\") {\r\n                    stop();\r\n                    masterPanel.open = true;\r\n                    masterPanel.idx = 0;\r\n                    masterPanel.top = 0;\r\n                    pokeChrome();\r\n                    return;\r\n                }\r\n\r\n                if (key === \"E\") {\r\n                    stop();\r\n                    menu.open = true;\r\n                    menu.level = \"main\";\r\n                    menu.idx = 0;\r\n                    pokeChrome();\r\n                    return;\r\n                }\r\n                if (key === \"O\") {\r\n                    stop();\r\n                    cycleOutputPreset(ev.shiftKey ? -1 : 1);\r\n                    return;\r\n                }\r\n\r\n                if (key === \"A\") {\r\n                    stop();\r\n                    addTrack(false); \/* vac\u00edo *\/\r\n                    return;\r\n                }\r\n\r\n                if (key === \"Z\") {\r\n                    stop();\r\n                    addTrack(true); \/* crea + carga datafile[idx] *\/\r\n                    return;\r\n                }\r\n                if (key === \"Enter\") {\r\n                    const canAddRow = (tracks.length < CVX_TRACKS_MAX);\r\n                    if (canAddRow && activeTrack === tracks.length) {\r\n                        stop();\r\n                        addTrack(!!css.bool(\"--cvx-oled-addtrack-autoload\", 1));\r\n                        return;\r\n                    }\r\n                }\r\n                if (key === \"q\" || key === \"Q\") {\r\n                    stop();\r\n                    if (activeTrack < 0 || activeTrack >= tracks.length) {\r\n                        setHud(\"NO TRACK\", 450);\r\n                        return;\r\n                    }\r\n                    tracks[activeTrack].arm = !tracks[activeTrack].arm;\r\n                    pokeChrome();\r\n                    setHud(tracks[activeTrack].arm ? \"ARM\" : \"ARM OFF\", 550);\r\n                    return;\r\n                }\r\n\r\n                if (key === \".\") {\r\n                    stop();\r\n                    if (selection) {\r\n                        selection = null;\r\n                        setHud(\"CLR\", 450);\r\n                        return;\r\n                    }\r\n                    if (isPlaying || isRecording) {\r\n                        actStop();\r\n                        return;\r\n                    }\r\n                    return;\r\n                }\r\n\r\n                if (key === \"Delete\" || key === \"Backspace\") {\r\n                    stop();\r\n                    ensureSelectionExists();\r\n                    const ripple = css.bool(\"--cvx-oled-ripple-delete\", 1) ? true : false;\r\n                    applyDelete(selection, ripple);\r\n                    setHud(\"DELETE\", 650);\r\n                    pokeChrome();\r\n                    return;\r\n                }\r\n\r\n                if (key === \"X\") {\r\n                    stop();\r\n                    ensureSelectionExists();\r\n                    applyCut(selection, false);\r\n                    setHud(\"CUT\", 650);\r\n                    pokeChrome();\r\n                    return;\r\n                }\r\n                if (key === \"C\") {\r\n                    stop();\r\n                    execAction(\"SPLIT\");\r\n                    pokeChrome();\r\n                    return;\r\n                }\r\n\r\n                if (key === \"ArrowLeft\") {\r\n                    if (isRecording) {\r\n                        setHud(\"REC LOCK\", 550);\r\n                        return;\r\n                    }\r\n\r\n                    stop();\r\n\r\n                    \/* Cursor step as a fraction of the *usable* viewport width (not full 256px) *\/\r\n                    const span = timelineSpan();\r\n                    const x0 = L.pad + L.listW + L.gap;\r\n                    const x1 = W - L.pad - 1 - L.masterBarW;\r\n                    const vw = Math.max(2, (x1 - x0 + 1)); \/* usable viewport px *\/\r\n                    const frac = clamp(css.flt(\"--cvx-oled-cursor-step-frac\", 0.0104167), 0.00025, 0.5);\r\n                    const pxStep = Math.max(1, Math.round(vw * frac)); \/* px per keypress (relative) *\/\r\n                    const secPerPx = span \/ Math.max(1, (vw - 1));\r\n                    const mult = ev.shiftKey ? 4 : 1;\r\n\r\n                    const step = Math.max(1e-3, pxStep * secPerPx) * mult;\r\n                    playhead = clamp(playhead - step, 0, timelineMaxSecondsAll());\r\n                    pokeChrome();\r\n                    return;\r\n                }\r\n                if (key === \"ArrowRight\") {\r\n                    if (isRecording) {\r\n                        setHud(\"REC LOCK\", 550);\r\n                        return;\r\n                    }\r\n\r\n                    stop();\r\n\r\n                    \/* Cursor step as a fraction of the *usable* viewport width (not full 256px) *\/\r\n                    const span = timelineSpan();\r\n                    const x0 = L.pad + L.listW + L.gap;\r\n                    const x1 = W - L.pad - 1 - L.masterBarW;\r\n                    const vw = Math.max(2, (x1 - x0 + 1)); \/* usable viewport px *\/\r\n                    const frac = clamp(css.flt(\"--cvx-oled-cursor-step-frac\", 0.0104167), 0.00025, 0.5);\r\n                    const pxStep = Math.max(1, Math.round(vw * frac)); \/* px per keypress (relative) *\/\r\n                    const secPerPx = span \/ Math.max(1, (vw - 1));\r\n                    const mult = ev.shiftKey ? 4 : 1;\r\n\r\n                    const step = Math.max(1e-3, pxStep * secPerPx) * mult;\r\n                    playhead = clamp(playhead + step, 0, timelineMaxSecondsAll());\r\n                    pokeChrome();\r\n                    return;\r\n                }\r\n                if (key === \"ArrowUp\") {\r\n                    stop();\r\n\r\n                    const canAddRow = (tracks.length < CVX_TRACKS_MAX);\r\n                    const listCount = tracks.length + (canAddRow ? 1 : 0);\r\n                    if (!listCount) {\r\n                        activeTrack = -1;\r\n                        multiSel.clear();\r\n                        pokeChrome();\r\n                        return;\r\n                    }\r\n\r\n                    activeTrack = clamp(activeTrack - 1, 0, listCount - 1);\r\n\r\n                    if (canAddRow && activeTrack === tracks.length) {\r\n                        multiSel.clear();\r\n                        setHud(\"+ ADD\", 450);\r\n                        pokeChrome();\r\n                        return;\r\n                    }\r\n\r\n                    if (ev.shiftKey) {\r\n                        if (multiSel.has(activeTrack)) {\r\n                            if (multiSel.size > 1) multiSel.delete(activeTrack);\r\n                        } else {\r\n                            multiSel.add(activeTrack);\r\n                        }\r\n                    } else {\r\n                        multiSel = new Set([activeTrack]);\r\n                    }\r\n\r\n                    setHud(\"TRACK \" + (activeTrack + 1) + \" \" + tracks[activeTrack].name, 650);\r\n                    pokeChrome();\r\n                    return;\r\n                }\r\n\r\n                if (key === \"ArrowDown\") {\r\n                    stop();\r\n\r\n                    const canAddRow = (tracks.length < CVX_TRACKS_MAX);\r\n                    const listCount = tracks.length + (canAddRow ? 1 : 0);\r\n                    if (!listCount) {\r\n                        activeTrack = -1;\r\n                        multiSel.clear();\r\n                        pokeChrome();\r\n                        return;\r\n                    }\r\n\r\n                    activeTrack = clamp(activeTrack + 1, 0, listCount - 1);\r\n\r\n                    if (canAddRow && activeTrack === tracks.length) {\r\n                        multiSel.clear();\r\n                        setHud(\"+ ADD\", 450);\r\n                        pokeChrome();\r\n                        return;\r\n                    }\r\n\r\n                    if (ev.shiftKey) {\r\n                        if (multiSel.has(activeTrack)) {\r\n                            if (multiSel.size > 1) multiSel.delete(activeTrack);\r\n                        } else {\r\n                            multiSel.add(activeTrack);\r\n                        }\r\n                    } else {\r\n                        multiSel = new Set([activeTrack]);\r\n                    }\r\n\r\n                    setHud(\"TRACK \" + (activeTrack + 1) + \" \" + tracks[activeTrack].name, 650);\r\n                    pokeChrome();\r\n                    return;\r\n                }\r\n\r\n                \/\/ Solo en X1\r\n                \/\/ Solo en X1\r\n                if ((L.vt | 0) === 1) {\r\n\r\n                    const ti = activeTrack;\r\n                    const code = ev.code || \"\";\r\n\r\n                    const volPlus = (key === \"1\" || code === \"Digit1\" || code === \"Numpad1\");\r\n                    const volMinus = (key === \"2\" || code === \"Digit2\" || code === \"Numpad2\");\r\n\r\n                    const gainPlus = (key === \"3\" || code === \"Digit3\" || code === \"Numpad3\");\r\n                    const gainMinus = (key === \"4\" || code === \"Digit4\" || code === \"Numpad4\");\r\n\r\n                    if (ti >= 0 && ti < tracks.length) {\r\n\r\n                        \/\/ VOL + \/ - => 1 \/ 2\r\n                        if (volPlus || volMinus) {\r\n                            ev.preventDefault();\r\n                            bumpVol(ti, volPlus ? +1 : -1);\r\n                            pokeChrome();\r\n                            return; \/\/ evita que caiga a otros handlers\r\n                        }\r\n\r\n                        \/\/ GAIN + \/ - => 3 \/ 4\r\n                        if (gainPlus || gainMinus) {\r\n                            ev.preventDefault();\r\n                            bumpGainDb(ti, gainPlus ? +1 : -1);\r\n                            pokeChrome();\r\n                            return;\r\n                        }\r\n                    }\r\n                }\r\n\r\n\r\n                if (key === \"+\" || key === \"=\") {\r\n                    stop();\r\n                    zoomX = clamp(zoomX + 1, 0, 12);\r\n                    setHud(\"ZOOM X \" + zoomX, 450);\r\n                    pokeChrome();\r\n                    return;\r\n                }\r\n                if (key === \"-\" || key === \"_\") {\r\n                    stop();\r\n                    zoomX = clamp(zoomX - 1, 0, 12);\r\n                    setHud(\"ZOOM X \" + zoomX, 450);\r\n                    pokeChrome();\r\n                    return;\r\n                }\r\n\r\n\r\n                if (key === \"PageUp\") {\r\n                    stop();\r\n                    if (ev.shiftKey) {\r\n                        waveZoomDb = clamp(waveZoomDb - 1, WAVE_ZOOM_DB_MIN, WAVE_ZOOM_DB_MAX);\r\n                        setHud(\"VIEW \" + (waveZoomDb >= 0 ? \"+\" : \"\") + waveZoomDb + \" dB\", 450);\r\n                    } else {\r\n                        zoomY = clamp(zoomY + 1, 0, 2);\r\n                        setHud(\"ZOOM Y \" + zoomYMap[zoomY], 450);\r\n                    }\r\n                    pokeChrome();\r\n                    return;\r\n                }\r\n\r\n                if (key === \"PageDown\") {\r\n                    stop();\r\n                    if (ev.shiftKey) {\r\n                        waveZoomDb = clamp(waveZoomDb + 1, WAVE_ZOOM_DB_MIN, WAVE_ZOOM_DB_MAX);\r\n                        setHud(\"VIEW \" + (waveZoomDb >= 0 ? \"+\" : \"\") + waveZoomDb + \" dB\", 450);\r\n                    } else {\r\n                        zoomY = clamp(zoomY - 1, 0, 2);\r\n                        setHud(\"ZOOM Y \" + zoomYMap[zoomY], 450);\r\n                    }\r\n                    pokeChrome();\r\n                    return;\r\n                }\r\n\r\n\r\n                \/\/ quick toggles for track mute\/solo on active track\r\n                if (key === \"m\" || key === \"M\") {\r\n                    stop();\r\n                    if (activeTrack < 0 || activeTrack >= tracks.length) {\r\n                        setHud(\"NO TRACK\", 450);\r\n                        return;\r\n                    }\r\n                    tracks[activeTrack].mute = !tracks[activeTrack].mute;\r\n                    pokeChrome();\r\n                    setHud(tracks[activeTrack].mute ? \"MUTE\" : \"UNMUTE\", 450);\r\n                    return;\r\n                }\r\n                if (key === \"s\" || key === \"S\") {\r\n                    stop();\r\n                    if (activeTrack < 0 || activeTrack >= tracks.length) {\r\n                        setHud(\"NO TRACK\", 450);\r\n                        return;\r\n                    }\r\n                    tracks[activeTrack].solo = !tracks[activeTrack].solo;\r\n                    pokeChrome();\r\n                    setHud(tracks[activeTrack].solo ? \"SOLO\" : \"SOLO OFF\", 450);\r\n                    return;\r\n                }\r\n            });\r\n\r\n            \/* -------------------------------------------------------\r\n               Animation loop\r\n            ------------------------------------------------------- *\/\r\n            let lastT = performance.now();\r\n            let uiNowMs = lastT;\r\n\r\n            function frame(t) {\r\n                const dt = Math.max(0, t - lastT);\r\n                lastT = t;\r\n                uiNowMs = t;\r\n\r\n                draw(dt);\r\n                blit(ras);\r\n                requestAnimationFrame(frame);\r\n            }\r\n            requestAnimationFrame(frame);\r\n\r\n            pokeChrome();\r\n        }\r\n\r\n        function initAll() {\r\n            const nodes = document.querySelectorAll(ROOT_SEL);\r\n            for (const n of nodes) initRoot(n);\r\n        }\r\n\r\n        if (document.readyState === \"loading\") {\r\n            document.addEventListener(\"DOMContentLoaded\", initAll, {\r\n                passive: true\r\n            });\r\n        } else {\r\n            initAll();\r\n        }\r\n\r\n        try {\r\n            const mo = new MutationObserver((muts) => {\r\n                for (const m of muts) {\r\n                    for (const n of m.addedNodes) {\r\n                        if (!n || n.nodeType !== 1) continue;\r\n                        if (n.matches && n.matches(ROOT_SEL)) initRoot(n);\r\n                        const q = (n.querySelectorAll ? n.querySelectorAll(ROOT_SEL) : null);\r\n                        if (q && q.length) {\r\n                            for (const el of q) initRoot(el);\r\n                        }\r\n                    }\r\n                }\r\n            });\r\n            mo.observe(document.documentElement, {\r\n                childList: true,\r\n                subtree: true\r\n            });\r\n        } catch (_) {}\r\n\r\n    })();\r\n<\/script>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<\/div>\n\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-13f29bf elementor-section-height-min-height elementor-section-items-stretch fx_section elementor-section-boxed elementor-section-height-default\" data-id=\"13f29bf\" data-element_type=\"section\" data-e-type=\"section\" id=\"soundMixer\" data-settings=\"{&quot;background_background&quot;:&quot;gradient&quot;,&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t\t<div class=\"elementor-background-overlay\"><\/div>\n\t\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-b978fb6\" data-id=\"b978fb6\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<section class=\"elementor-section elementor-inner-section elementor-element elementor-element-03fb87e elementor-section-full_width elementor-section-height-default elementor-section-height-default\" data-id=\"03fb87e\" data-element_type=\"section\" data-e-type=\"section\" data-settings=\"{&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-no\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-inner-column elementor-element elementor-element-2bdbd39\" data-id=\"2bdbd39\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-5e65a0e animated-slow elementor-invisible elementor-widget elementor-widget-heading\" data-id=\"5e65a0e\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;slideInDown&quot;}\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Mezcladora<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-d08d3d4 elementor-invisible elementor-widget elementor-widget-ha-svg-draw happy-addon ha-svg-draw\" data-id=\"d08d3d4\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;slideInLeft&quot;}\" data-widget_type=\"ha-svg-draw.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\n\t\t\t\t<div class=\"ha-svg-draw-container\">\n\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t\n  \n    \n      \n      \n    \n  \n  \n\n\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t<\/div>\n\n\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-inner-section elementor-element elementor-element-c589da3 elementor-section-full_width elementor-section-height-default elementor-section-height-default\" data-id=\"c589da3\" data-element_type=\"section\" data-e-type=\"section\" data-settings=\"{&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-no\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-inner-column elementor-element elementor-element-586b021\" data-id=\"586b021\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-e3b38b2 animated-slow elementor-invisible elementor-widget elementor-widget-heading\" data-id=\"e3b38b2\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;fadeIn&quot;,&quot;_animation_delay&quot;:300}\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Nivela, mezcla, amplifica<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-e009fa4 elementor-invisible elementor-widget elementor-widget-heading\" data-id=\"e009fa4\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;fadeInDown&quot;,&quot;_animation_delay&quot;:200}\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Control local o desde Compose App<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-inner-section elementor-element elementor-element-5aae27e elementor-section-full_width elementor-section-height-default elementor-section-height-default\" data-id=\"5aae27e\" data-element_type=\"section\" data-e-type=\"section\" data-settings=\"{&quot;animation&quot;:&quot;none&quot;,&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-no\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-inner-column elementor-element elementor-element-f4096e5\" data-id=\"f4096e5\" data-element_type=\"column\" data-e-type=\"column\" data-settings=\"{&quot;animation&quot;:&quot;none&quot;}\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-1e7f2c0 e-transform animated-fast elementor-invisible elementor-widget elementor-widget-ha-content-switcher happy-addon ha-content-switcher\" data-id=\"1e7f2c0\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;fadeInUp&quot;,&quot;_animation_delay&quot;:100,&quot;_transform_translateX_effect&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;_transform_translateX_effect_tablet&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;_transform_translateX_effect_mobile&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;_transform_translateY_effect&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;_transform_translateY_effect_tablet&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;_transform_translateY_effect_mobile&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]}}\" data-widget_type=\"ha-content-switcher.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"ha-content-switcher-wrapper ha-cs-design-button\" data-design-type=\"button\">\n\t\t\t<div class=\"ha-cs-switch-container\">\n\t\t\t\t<div class=\"ha-cs-switch-wrapper  desktop-horizontal horizontal\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<button class=\"ha-cs-button active ha-cs-icon-left\" data-content-id=\"77b8221\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<div class=\"ha-cs-icon-wrapper\"><i class=\"huge huge-workflow-circle-04\"><\/i><\/div>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<span>Ruteo<\/span>\n\t\t\t\t\t\t\t<\/button>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<button class=\"ha-cs-button  ha-cs-icon-left\" data-content-id=\"605a9af\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<div class=\"ha-cs-icon-wrapper\"><i class=\"huge huge-sliders-vertical\"><\/i><\/div>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<span>Equalizador<\/span>\n\t\t\t\t\t\t\t<\/button>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<button class=\"ha-cs-button  ha-cs-icon-left\" data-content-id=\"9d4e93f\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<div class=\"ha-cs-icon-wrapper\"><i class=\"huge huge-connect\"><\/i><\/div>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<span>M\u00f3dulos I\/O<\/span>\n\t\t\t\t\t\t\t<\/button>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t<\/div>\n\t\t\t<div class=\"ha-cs-content-container\">\n\t\t\t\t<div class=\"ha-cs-content-wrapper  desktop-horizontal horizontal\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<div id=\"77b8221\" class=\"ha-cs-content-section active\">\n\t\t\t\t\t\t\t\t\t\t<div data-elementor-type=\"section\" data-elementor-id=\"2654\" class=\"elementor elementor-2654\" data-elementor-settings=\"{&quot;ha_cmc_init_switcher&quot;:&quot;no&quot;}\">\n\t\t\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-1ac27c1 animated-fast elementor-section-height-min-height elementor-section-items-stretch elementor-hidden-mobile elementor-section-boxed elementor-section-height-default elementor-invisible\" data-id=\"1ac27c1\" data-element_type=\"section\" data-e-type=\"section\" data-settings=\"{&quot;animation&quot;:&quot;fadeInUp&quot;,&quot;animation_delay&quot;:200,&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-08ef47e\" data-id=\"08ef47e\" data-element_type=\"column\" data-e-type=\"column\" data-settings=\"{&quot;animation&quot;:&quot;none&quot;,&quot;animation_delay&quot;:0}\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-c1f2fbf elementor-widget elementor-widget-html\" data-id=\"c1f2fbf\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;none&quot;,&quot;_animation_delay&quot;:0}\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<!-- =========================================================\r\nCubeVox Routing Overlay (V8) + OpenPort Padding Parametrizable (V8.1)\r\nOBJETIVO:\r\n- Escalar TODO (textos, cards, pills, port-shapes, espaciados, offsets) con el ancho\r\n- EXCEPTO: grosor de l\u00edneas y tama\u00f1o\/velocidad de part\u00edculas (quedan constantes)\r\n- Robusto ante \"switch de secciones\" en Elementor:\r\n  * NO recalcula geometr\u00eda cuando el contenedor est\u00e1 oculto (width\/height ~ 0)\r\n  * Cuando vuelve a ser visible, fuerza rebuild y recupera contornos OpenPort\r\n\r\nCAMBIO V8.1 (este fix):\r\n- Padding interno de cada OpenPort (izq\/der) parametrizable por variables CSS por nodo (HP\/AUX\/IN1\/IN2)\r\n- Reordenada la medici\u00f3n en JS para que el contorno (SVG OpenPort) siga el padding real (sin guiones\/espacios fake)\r\n\r\nNOTA:\r\n- Eliminado cualquier \"bg image\" interno y cualquier dependencia a tama\u00f1o de imagen en px.\r\n- Si quer\u00e9s mantener la misma proporci\u00f3n visual del layout, us\u00e1 --stage-ar (ratio num\u00e9rico).\r\n========================================================= -->\r\n<div class=\"cvxScope\">\r\n  <section data-cvx-root=\"routing-kpis\"\r\n    style=\"\r\n      --kpi-cols: 4;\r\n      --kpi-cols-xs: 1;\r\n      --kpi-gap: 10px;\r\n      --kpi-pad: 10px;\r\n\r\n      --kpi-num-fs: 30px;\r\n      --kpi-unit-fs: 10px;\r\n      --kpi-text-fs: 11px;\r\n    \"\r\n  >\r\n    <div data-kpi-grid>\r\n      <article class=\"cvxCard\" data-kpi>\r\n        <div data-kpi-top>\r\n          <div data-kpi-num>10<\/div>\r\n          <div data-kpi-unit>IN<\/div>\r\n        <\/div>\r\n        <div data-kpi-title>Entradas simult\u00e1neas*<\/div>\r\n        <p data-kpi-text>\r\n          IN1 A\/B + IN2 A\/B + AUX o DIG (est\u00e9reo\/dual-mono), m\u00e1s entradas v\u00eda <strong>m\u00f3dulos de expansi\u00f3n<\/strong>.\r\n        <\/p>\r\n      <\/article>\r\n\r\n      <article class=\"cvxCard\" data-kpi>\r\n        <div data-kpi-top>\r\n          <div data-kpi-num>6<\/div>\r\n          <div data-kpi-unit>OUT<\/div>\r\n        <\/div>\r\n        <div data-kpi-title>Salidas por canal*<\/div>\r\n        <p data-kpi-text>\r\n          Main + Monitor + Auriculares, con salidas adicionales disponibles mediante <strong>m\u00f3dulos de expansi\u00f3n<\/strong>.\r\n        <\/p>\r\n      <\/article>\r\n\r\n      <article class=\"cvxCard\" data-kpi>\r\n        <div data-kpi-top>\r\n          <div data-kpi-num>A\/B<\/div>\r\n          <div data-kpi-unit>FAST<\/div>\r\n        <\/div>\r\n        <div data-kpi-title>Subcanales por encoder<\/div>\r\n        <p data-kpi-text>\r\n          Alternancia r\u00e1pida de subcanal (A\/B) sin perder el control del mix. El color confirma qu\u00e9 est\u00e1s ajustando.\r\n        <\/p>\r\n      <\/article>\r\n\r\n      <article class=\"cvxCard\" data-kpi>\r\n        <div data-kpi-top>\r\n          <div data-kpi-num>\u2387<\/div>\r\n          <div data-kpi-unit>MIXBUS<\/div>\r\n        <\/div>\r\n        <div data-kpi-title>Ruteo claro<\/div>\r\n        <p data-kpi-text>\r\n          Entradas \u2192 canales \u2192 salidas, con mapping digital (BT\/SD\/USB) y auxiliares sin men\u00fas eternos.\r\n        <\/p>\r\n      <\/article>\r\n    <\/div>\r\n  <\/section>\r\n    <section data-cvx-root=\"routing\" style=\"\r\n    --debug: 1;\r\n    \r\n      \/* =========================\r\n         PANEL (Starter Kit cvxPanel)\r\n      ========================== *\/\r\n      --pad-panel: 18px;   \/* padding interno del panel *\/\r\n      --gap-panel: 18px;\r\n\r\n      \/* =========================\r\n         IMAGEN (contain) \u2013 par\u00e1metros por instancia\r\n      ========================== *\/\r\n      --cvx-routing-img: url('\/wp-content\/uploads\/cubevox-front-open-render.webp');             \/* ejemplo: url('...') *\/\r\n      --cvx-routing-img-fit: contain;      \/* contain | cover *\/\r\n      --cvx-routing-img-pos: 50% 10%;      \/* posicion *\/\r\n      --cvx-routing-img-op: .5;           \/* opacidad *\/\r\n      --cvx-routing-img-ar: 3.2528; \/* width\/height REAL de la imagen (NUM\u00c9RICO) *\/\r\n      \/* =========================\r\n         ALTURA \/ PROPORCI\u00d3N del stage\r\n      ========================== *\/\r\n--cvx-routing-stage-ar: auto;                         \/* desactiva aspect-ratio *\/\r\n+ --cvx-routing-stage-ar: var(--cvx-routing-img-ar, 3.26); \/* stage = AR real de la imagen *\/\r\n--cvx-routing-stage-min-h: 450px;                     \/* m\u00ednimo real *\/\r\n    \">\r\n        <div class=\"cvxPanel\">\r\n            <div class=\"cvx-routing-stage\">\r\n                <div id=\"cvxRoutingOverlayV8\" style=\"\r\n      \/* =====================================================\r\n         0) ESCALADO RESPONSIVO (UI ONLY)\r\n         - s=1 a partir de --ui-base (px)\r\n         - por debajo, baja hasta --ui-min\r\n         - afecta: tipograf\u00edas, cards, pills, offsets, tama\u00f1os de port-shapes\r\n         - NO afecta: line stroke-width, particle radius\/speed (son constantes)\r\n      ====================================================== *\/\r\n      --ui-base: 1100;    \/* px (ancho a partir del cual s=1) *\/\r\n      --ui-min:  0.58;    \/* l\u00edmite inferior de escala UI *\/\r\n      --s: 1;             \/* escala UI actual (la setea el JS) *\/\r\n      --ui-max: 1.25;   \/* permite crecer en pantallas grandes (1.10\u20131.40 t\u00edpico) *\/\r\n\/* =====================================================\r\n   1) PROPORCI\u00d3N \/ ALTURA DEL STAGE (parametrizable)\r\n   - AR (aspect-ratio) por defecto\r\n   - O height fijo si sete\u00e1s --cvx-routing-stage-h y pon\u00e9s AR en auto\r\n====================================================== *\/\r\n--stage-ar: var(--cvx-routing-stage-ar, 3.26);         \/* width\/height o 'auto' *\/\r\n--stage-h:  var(--cvx-routing-stage-h, auto);          \/* px \/ vh \/ etc o 'auto' *\/\r\n--min-h:    var(--cvx-routing-stage-min-h, 260px);     \/* m\u00ednimo absoluto *\/\r\n\r\n      \/* =====================================================\r\n         2) COLORIMETR\u00cdA \/ TIPOGRAF\u00cdA (global)\r\n      ====================================================== *\/\r\n      --accent: #5AAAFF;\r\n      --glow:   rgba(90,170,255,.45);\r\n      --text:   rgba(255,255,255,.92);\r\n      --muted:  rgba(255,255,255,.72);\r\n\r\n      \/* Pills m\u00e1s opacas => evita que \u201cse vean\u201d l\u00edneas detr\u00e1s *\/\r\n      --node-bg: rgba(27, 51, 77, 0.52);\r\n\r\n      \/* =====================================================\r\n         3) L\u00cdNEAS Y PART\u00cdCULAS (NO ESCALAN CON --s)\r\n         Ajust\u00e1s ac\u00e1 y se mantienen constantes aunque baje el ancho.\r\n      ====================================================== *\/\r\n      --line-w: 2;                 \/* px *\/\r\n      --pair-gap: 12;              \/* separaci\u00f3n paralela (px) NO escala *\/\r\n      --quad-gap: 9;               \/* separaci\u00f3n paralela (px) NO escala *\/\r\n      --particles-per-path: 2;\r\n      --particle-speed: 0.2;\r\n      --particle-r: 3;             \/* px NO escala *\/\r\n\r\n      \/* =====================================================\r\n         4) TIP BANNER (parametrizable)\r\n      ====================================================== *\/\r\n      --tip-x: 50%;\r\n      --tip-y: 20%;\r\n      --tip-dx: -320px;\r\n      --tip-dy: -60px;\r\n\r\n      --tip-bg: rgba(10, 14, 18, 0.52);   \/* SIN degrad\u00e9 *\/\r\n      --tip-br: rgba(255,255,255,0.10);\r\n      --tip-shadow: 0 14px 26px rgba(0,0,0,.38), inset 0 1px 0 rgba(255,255,255,.06);\r\n\r\n      --tip-dot: var(--accent);\r\n      --tip-dot-glow: var(--glow);\r\n\r\n      --tip-label-color: rgba(255,255,255,.88);\r\n      --tip-text-color:  rgba(255,255,255,.70);\r\n      --tip-font-size: 13px;\r\n      --tip-label-w: 700;\r\n      --tip-text-w:  450;\r\n      --tip-letter: .10px;\r\n      --tip-pad-y:  10px;\r\n      --tip-pad-x:  14px;\r\n      --tip-gap:    10px;\r\n      --tip-dot-size: 10px;\r\n\r\n      \/* =====================================================\r\n         5) CARDS (base; todo escala por --s)\r\n      ====================================================== *\/\r\n      --card-w:   300px;\r\n      --card-gap: 50px;\r\n      --mask-pad: 1;        \/* px base (NUM\u00c9RICO); s\u00ed escala con --s *\/\r\n\r\n      \/* =====================================================\r\n         6) OPENPORT SHAPES (base; s\u00ed escala con --s)\r\n      ====================================================== *\/\r\n      --port-outer-r: 40px;\r\n      --port-hole-r:  10px;\r\n      --port-pin:     6px;\r\n      --port-pin-dx:  0px;\r\n      --port-pin-dy:  0px;\r\n\r\n      \/* =====================================================\r\n         6B) OPENPORT PADDING (s\u00ed escala con --s)  [V8.1]\r\n         - padding interno del pill (NO afecta l\u00edneas\/part\u00edculas)\r\n         - por nodo: hp\/aux\/in1\/in2\r\n         TIP:\r\n         - AUX m\u00e1s aire a la izquierda => sub\u00ed --aux-pad-l\r\n         - Espacio al final a la derecha => sub\u00ed --hp-pad-r \/ --in1-pad-r, etc.\r\n      ====================================================== *\/\r\n      --port-pad-y: 7px;     \/* default vertical *\/\r\n      --port-pad-l: 7px;    \/* default left  *\/\r\n      --port-pad-r: 7px;    \/* default right *\/\r\n\r\n      \/* Overrides por nodo (toc\u00e1s estos para ajustar cada pill) *\/\r\n      --hp-pad-l:  var(--port-pad-l);\r\n      --hp-pad-r: calc(var(--port-pad-r) + 12px);\r\n\r\n      --aux-pad-l: calc(var(--port-pad-l) + 12px);\r\n      --aux-pad-r: var(--port-pad-r);\r\n\r\n      --in1-pad-l: var(--port-pad-l);\r\n      --in1-pad-r: calc(var(--port-pad-r) + 12px);\r\n\r\n\r\n      --in2-pad-l: calc(var(--port-pad-l) + 12px);\r\n      --in2-pad-r: var(--port-pad-r);\r\n\r\n      \/* =====================================================\r\n         7) POSICIONES (en %)\r\n         - No te preocupes por el \u201ccalce inicial\u201d; dej\u00e9 algo similar.\r\n         - Ajust\u00e1s manualmente estas variables.\r\n      ====================================================== *\/\r\n      --bus-x: 50%;   --bus-y: 75%;\r\n      --merge-x: 50%; --merge-y: 60%;\r\n      --dig-x: 50%;   --dig-y: 10%;\r\n\r\n      --hp-x:  33.1%; --hp-y:  26.8%;\r\n      --aux-x: 66.3%; --aux-y: 26.8%;\r\n\r\n      --in1-x: 30.9%; --in1-y: 51%;\r\n      --in2-x: 68.4%; --in2-y: 51%;\r\n\r\n      --spkR-x: 81.5%; --spkR-y: 55%;\r\n      --spkL-x: 18.0%; --spkL-y: 55%;\r\n\r\n      \/* Micro-ajustes (px) => s\u00ed escalan por --s *\/\r\n      --dig-dx: 0px;     --dig-dy: -25px;\r\n      --sw-dx:  0px;     --sw-dy:  -50px;\r\n      --bus-dx: 0px;     --bus-dy: 90px;\r\n\r\n      --in1-dx: -44px;   --in1-dy: -10px;\r\n      --in2-dx:  44px;   --in2-dy: -10px;\r\n\r\n      --hp-dx:  -54px;   --hp-dy:  12px;\r\n      --aux-dx:  54px;   --aux-dy: 12px;\r\n\r\n      --spkL-dx: 0px;    --spkL-dy: 30px;\r\n      --spkR-dx: 0px;    --spkR-dy: 30px;\r\n\r\n      \/* Lanes (X de control para bezier, en %) *\/\r\n      --lane-in1:   42%;\r\n      --lane-in2:   55%;\r\n      --lane-aux:   50%;\r\n      --lane-dig:   50%;\r\n      --lane-merge: 50%;\r\n      --lane-hp:    45%;\r\n      --lane-spkR:  60%;\r\n      --lane-spkL:  40%;\r\n      --lane-exp:   70%;\r\n\r\n      \/* Debug *\/\r\n      --anim: 1;\r\n      --debug: 0;\r\n\r\n      position: relative;\r\n      width: 100%;\r\n\r\n\/* Mantener proporciones por AR o forzar height *\/\r\nheight: var(--stage-h);\r\naspect-ratio: var(--stage-ar);\r\nmin-height: var(--min-h);\r\n\r\n      overflow: visible;\r\n      pointer-events: none;\r\n    \">\r\n                    <style>\r\n                    \/* =========================================================\r\n   ROUTING KPIs \u2014 m\u00ednimo CSS (depende de .cvxCard del kit)\r\n========================================================= *\/\r\n.cvxScope [data-cvx-root=\"routing-kpis\"]{\r\n  margin-bottom: calc(18px * var(--cvxS, 1));\r\n}\r\n.cvxScope [data-cvx-root=\"routing-kpis\"] [data-kpi-grid]{\r\n  display: grid;\r\n  grid-template-columns: repeat(var(--kpi-cols, 2), minmax(0, 1fr));\r\n  gap: calc(var(--kpi-gap, 12px) * var(--cvxS, 1));\r\n}\r\n\r\n@media (max-width: 360px){\r\n  .cvxScope [data-cvx-root=\"routing-kpis\"] [data-kpi-grid]{\r\n    grid-template-columns: repeat(var(--kpi-cols-xs, 1), minmax(0, 1fr));\r\n  }\r\n}\r\n\r\n.cvxScope [data-cvx-root=\"routing-kpis\"] [data-kpi]{\r\n  padding: calc(var(--kpi-pad, 14px) * var(--cvxS, 1));\r\n}\r\n\r\n.cvxScope [data-cvx-root=\"routing-kpis\"] [data-kpi-top]{\r\n  display: flex;\r\n  align-items: baseline;\r\n  gap: calc(8px * var(--cvxS, 1));\r\n  margin-bottom: calc(6px * var(--cvxS, 1));\r\n}\r\n\r\n.cvxScope [data-cvx-root=\"routing-kpis\"] [data-kpi-num]{\r\n  font-size: calc(var(--kpi-num-fs, 34px) * var(--cvxS, 1));\r\n  font-weight: var(--cvxWBold, 850);\r\n  line-height: 1;\r\n  letter-spacing: -0.02em;\r\n}\r\n\r\n.cvxScope [data-cvx-root=\"routing-kpis\"] [data-kpi-unit]{\r\n  font-size: calc(var(--kpi-unit-fs, 12px) * var(--cvxS, 1));\r\n  letter-spacing: .12em;\r\n  text-transform: uppercase;\r\n  opacity: .75;\r\n  white-space: nowrap;\r\n}\r\n\r\n.cvxScope [data-cvx-root=\"routing-kpis\"] [data-kpi-title]{\r\n  font-weight: var(--cvxWBold, 850);\r\n  margin-bottom: calc(6px * var(--cvxS, 1));\r\n}\r\n\r\n.cvxScope [data-cvx-root=\"routing-kpis\"] [data-kpi-text]{\r\n  margin: 0;\r\n  opacity: .82;\r\n  font-size: calc(var(--kpi-text-fs, 13px) * var(--cvxS, 1));\r\n  line-height: 1.42;\r\n  overflow-wrap: anywhere;\r\n}\r\n                        \/* =========================================================\r\n         A) BASE \/ LAYERS\r\n      ========================================================== *\/\r\n                        #cvxRoutingOverlayV8 * {\r\n                            box-sizing: border-box;\r\n                            font-family: inherit;\r\n                        }\r\n\r\n                        #cvxRoutingOverlayV8 .cvx-svg {\r\n                            position: absolute;\r\n                            inset: 0;\r\n                            width: 100%;\r\n                            height: 100%;\r\n                            overflow: visible;\r\n                            z-index: 1;\r\n                        }\r\n\r\n                        \/* =========================================================\r\n   A0) MEDIA BG (contain)\r\n   - Renderiza la imagen definida por variables del section\r\n========================================================== *\/\r\n                        #cvxRoutingOverlayV8 .cvx-routing-media {\r\n                            position: absolute;\r\n                            inset: 0;\r\n                            z-index: 0;\r\n                            \/* debajo del SVG (z=1) y nodos\/cards (z=3) *\/\r\n                            pointer-events: none;\r\n\r\n                            background-image: var(--cvx-routing-img, none);\r\n                            background-repeat: no-repeat;\r\n                            background-size: var(--cvx-routing-img-fit, contain);\r\n                            background-position: var(--cvx-routing-img-pos, 50% 50%);\r\n                            opacity: var(--cvx-routing-img-op, .22);\r\n                        }\r\n\r\n                        \/* =========================================================\r\n   A0B) STAGE SPACE (contain-aligned)\r\n   - Coordenadas reales del \"content box\" de la imagen (contain)\r\n   - JS setea: --cvx-routing-calc-img-x\/y\/w\/h\r\n========================================================= *\/\r\n                        #cvxRoutingOverlayV8 .cvx-stageSpace {\r\n                            position: absolute;\r\n                            left: var(--cvx-routing-calc-img-x, 0px);\r\n                            top: var(--cvx-routing-calc-img-y, 0px);\r\n                            width: var(--cvx-routing-calc-img-w, 100%);\r\n                            height: var(--cvx-routing-calc-img-h, 100%);\r\n                            z-index: 1;\r\n                            \/* arriba del media (z=0) *\/\r\n                            pointer-events: none;\r\n                            \r\n                            outline: calc(1px * var(--debug)) dashed rgba(90,170,255,.55);\r\noutline-offset: -1px;\r\n                        }\r\n\r\n                        \/* Mantener interactividad interna *\/\r\n                        #cvxRoutingOverlayV8 .cvx-stageSpace .cvx-ui {\r\n                            pointer-events: auto;\r\n                        }\r\n\r\n                        \/* =========================================================\r\n         B) TIP BANNER (sin degrad\u00e9, texto fino)\r\n      ========================================================== *\/\r\n                        #cvxRoutingOverlayV8 .cvx-tip {\r\n                            position: absolute;\r\n                            left: calc(var(--tip-x) + (var(--tip-dx) * var(--s)));\r\n                            top: calc(var(--tip-y) + (var(--tip-dy) * var(--s)));\r\n                            transform: translate(-50%, -50%);\r\n                            display: flex;\r\n                            align-items: center;\r\n                            gap: calc(var(--tip-gap) * var(--s));\r\n                            padding: calc(var(--tip-pad-y) * var(--s)) calc(var(--tip-pad-x) * var(--s));\r\n                            border-radius: 999px;\r\n\r\n                            background: var(--tip-bg);\r\n                            border: 1px solid var(--tip-br);\r\n                            box-shadow: var(--tip-shadow);\r\n\r\n                            -webkit-backdrop-filter: blur(10px);\r\n                            backdrop-filter: blur(10px);\r\n\r\n                            pointer-events: none;\r\n                            z-index: 3;\r\n                            white-space: nowrap;\r\n                        }\r\n\r\n                        #cvxRoutingOverlayV8 .cvx-tipDot {\r\n                            width: calc(var(--tip-dot-size) * var(--s));\r\n                            height: calc(var(--tip-dot-size) * var(--s));\r\n                            border-radius: 999px;\r\n                            background: var(--tip-dot);\r\n                            box-shadow: 0 0 calc(16px * var(--s)) var(--tip-dot-glow);\r\n                            flex: 0 0 auto;\r\n                        }\r\n\r\n                        #cvxRoutingOverlayV8 .cvx-tipLabel {\r\n                            color: var(--tip-label-color);\r\n                            font-size: calc(var(--tip-font-size) * var(--s));\r\n                            font-weight: var(--tip-label-w);\r\n                            letter-spacing: var(--tip-letter);\r\n                            line-height: 1;\r\n                        }\r\n\r\n                        #cvxRoutingOverlayV8 .cvx-tipText {\r\n                            color: var(--tip-text-color);\r\n                            font-size: calc(var(--tip-font-size) * var(--s));\r\n                            font-weight: var(--tip-text-w);\r\n                            letter-spacing: 0;\r\n                            line-height: 1;\r\n                        }\r\n\r\n                        \/* =========================================================\r\n         C) NODE PILLS\r\n      ========================================================== *\/\r\n                        #cvxRoutingOverlayV8 .cvx-node {\r\n                            position: absolute;\r\n                            transform: translate(-50%, -50%);\r\n                            display: flex;\r\n                            align-items: center;\r\n                            gap: calc(8px * var(--s));\r\n                            padding: calc(7px * var(--s)) calc(10px * var(--s));\r\n                            border-radius: 999px;\r\n                            background: var(--node-bg);\r\n                            border: 1px solid rgba(255, 255, 255, .14);\r\n                            color: rgba(255, 255, 255, .92);\r\n                            font-size: calc(12px * var(--s));\r\n                            font-weight: 850;\r\n                            letter-spacing: .25px;\r\n                            text-shadow: 0 calc(10px * var(--s)) calc(26px * var(--s)) rgba(0, 0, 0, .45);\r\n                            white-space: nowrap;\r\n                            pointer-events: none;\r\n                            -webkit-backdrop-filter: blur(10px);\r\n                            backdrop-filter: blur(10px);\r\n                            z-index: 3;\r\n                        }\r\n\r\n                        #cvxRoutingOverlayV8 .cvx-badge {\r\n                            font-size: calc(10px * var(--s));\r\n                            padding: calc(2px * var(--s)) calc(7px * var(--s));\r\n                            border-radius: 999px;\r\n                            background: rgba(90, 170, 255, .10);\r\n                            border: 1px solid rgba(90, 170, 255, .22);\r\n                            color: rgba(255, 255, 255, .94);\r\n                            font-weight: 950;\r\n                            letter-spacing: .35px;\r\n                        }\r\n\r\n                        #cvxRoutingOverlayV8 .cvx-hint {\r\n                            opacity: .80;\r\n                            font-weight: 800;\r\n                        }\r\n\r\n                        \/* =========================================================\r\n         D) OPENPORT (port node: pill + burbuja + agujero transparente)\r\n         IMPORTANTE:\r\n         - El contorno se dibuja en el SVG interno (renderPortSVG)\r\n         - Este bloque NO debe recalcularse con width=0 cuando el contenedor est\u00e1 oculto.\r\n      ========================================================== *\/\r\n                        #cvxRoutingOverlayV8 .cvx-node--port {\r\n                            padding: 0;\r\n                            border: 0;\r\n                            background: transparent;\r\n                            box-shadow: none;\r\n                            -webkit-backdrop-filter: none;\r\n                            backdrop-filter: none;\r\n                            display: block;\r\n                            width: var(--box-w, 240px);\r\n                            height: var(--pill-h, 30px);\r\n                            z-index: 3;\r\n\r\n                            \/* [V8.1] defaults de padding (por nodo se override) *\/\r\n                            --pad-y: var(--port-pad-y);\r\n                            --pad-l: var(--port-pad-l);\r\n                            --pad-r: var(--port-pad-r);\r\n                        }\r\n\r\n                        \/* [V8.1] overrides por nodo (HP\/AUX\/IN1\/IN2) *\/\r\n                        #cvxRoutingOverlayV8 .cvx-node--port[data-node=\"hp\"] {\r\n                            --pad-l: var(--hp-pad-l);\r\n                            --pad-r: var(--hp-pad-r);\r\n                        }\r\n\r\n                        #cvxRoutingOverlayV8 .cvx-node--port[data-node=\"aux\"] {\r\n                            --pad-l: var(--aux-pad-l);\r\n                            --pad-r: var(--aux-pad-r);\r\n                        }\r\n\r\n                        #cvxRoutingOverlayV8 .cvx-node--port[data-node=\"in1\"] {\r\n                            --pad-l: var(--in1-pad-l);\r\n                            --pad-r: var(--in1-pad-r);\r\n                        }\r\n\r\n                        #cvxRoutingOverlayV8 .cvx-node--port[data-node=\"in2\"] {\r\n                            --pad-l: var(--in2-pad-l);\r\n                            --pad-r: var(--in2-pad-r);\r\n                        }\r\n\r\n                        #cvxRoutingOverlayV8 .cvx-portSvg {\r\n                            position: absolute;\r\n                            inset: 0;\r\n                            width: 100%;\r\n                            height: 100%;\r\n                            pointer-events: none;\r\n                        }\r\n\r\n                        #cvxRoutingOverlayV8 .cvx-portContent {\r\n                            position: absolute;\r\n                            top: 0;\r\n                            height: 100%;\r\n                            display: flex;\r\n                            align-items: center;\r\n                            gap: calc(8px * var(--s));\r\n\r\n                            \/* [V8.1] padding parametrizable por nodo *\/\r\n                            padding: calc(var(--pad-y) * var(--s)) calc(var(--pad-r) * var(--s)) calc(var(--pad-y) * var(--s)) calc(var(--pad-l) * var(--s));\r\n\r\n                            border-radius: 999px;\r\n                            color: rgba(255, 255, 255, .92);\r\n                            font-size: calc(12px * var(--s));\r\n                            font-weight: 850;\r\n                            letter-spacing: .25px;\r\n                            white-space: nowrap;\r\n                            text-shadow: 0 calc(10px * var(--s)) calc(26px * var(--s)) rgba(0, 0, 0, .45);\r\n                            pointer-events: none;\r\n                        }\r\n\r\n                        #cvxRoutingOverlayV8 .cvx-node--port[data-port=\"right\"] .cvx-portContent {\r\n                            left: 0;\r\n                            width: var(--pill-w, 210px);\r\n                        }\r\n\r\n                        #cvxRoutingOverlayV8 .cvx-node--port[data-port=\"left\"] .cvx-portContent {\r\n                            left: var(--port-outer-r-local, var(--port-outer-r));\r\n                            width: var(--pill-w, 210px);\r\n                        }\r\n\r\n                        #cvxRoutingOverlayV8 .cvx-node--port .cvx-portPin {\r\n                            position: absolute;\r\n                            left: calc(var(--pin-x, 0px) + var(--port-pin-dx));\r\n                            top: calc(var(--pin-y, 0px) + var(--port-pin-dy));\r\n                            width: calc(var(--port-pin) * var(--s));\r\n                            height: calc(var(--port-pin) * var(--s));\r\n                            transform: translate(-50%, -50%);\r\n                            border-radius: 999px;\r\n                            background: var(--accent);\r\n                            pointer-events: none;\r\n                            z-index: 2;\r\n                        }\r\n\r\n                        \/* =========================================================\r\n         E) MERGE DOT\r\n      ========================================================== *\/\r\n                        #cvxRoutingOverlayV8 .cvx-mergeDot {\r\n                            position: absolute;\r\n                            left: var(--merge-x);\r\n                            top: var(--merge-y);\r\n                            transform: translate(-50%, -50%);\r\n                            width: calc(14px * var(--s));\r\n                            height: calc(14px * var(--s));\r\n                            border-radius: 999px;\r\n                            background: rgba(90, 170, 255, .18);\r\n                            border: 1px solid rgba(90, 170, 255, .40);\r\n                            box-shadow: 0 0 calc(22px * var(--s)) rgba(90, 170, 255, .20);\r\n                            pointer-events: none;\r\n                            z-index: 3;\r\n                        }\r\n\r\n                        \/* =========================================================\r\n         F) CARDS\r\n      ========================================================== *\/\r\n                        #cvxRoutingOverlayV8 .cvx-card {\r\n                            position: absolute;\r\n                            transform: translate(-50%, -50%);\r\n                            width: calc(var(--card-w) * var(--s));\r\n                            padding: calc(10px * var(--s)) calc(12px * var(--s));\r\n                            border-radius: calc(16px * var(--s));\r\n                            background: linear-gradient(180deg, rgba(255, 255, 255, .08), rgba(255, 255, 255, .02));\r\n                            border: 1px solid rgba(255, 255, 255, .14);\r\n                            box-shadow: 0 calc(16px * var(--s)) calc(34px * var(--s)) rgba(0, 0, 0, .45), inset 0 1px 0 rgba(255, 255, 255, .08);\r\n                            -webkit-backdrop-filter: blur(10px);\r\n                            backdrop-filter: blur(10px);\r\n                            z-index: 3;\r\n                        }\r\n\r\n                        #cvxRoutingOverlayV8 .cvx-infoTitle {\r\n                            font-size: calc(12px * var(--s));\r\n                            font-weight: 950;\r\n                            letter-spacing: .28px;\r\n                            color: rgba(255, 255, 255, .92);\r\n                            margin-bottom: calc(8px * var(--s));\r\n                            display: flex;\r\n                            align-items: center;\r\n                            gap: calc(10px * var(--s));\r\n                        }\r\n\r\n                        #cvxRoutingOverlayV8 .cvx-infoDot {\r\n                            width: calc(9px * var(--s));\r\n                            height: calc(9px * var(--s));\r\n                            border-radius: 999px;\r\n                            background: var(--accent);\r\n                            box-shadow: 0 0 calc(16px * var(--s)) var(--glow);\r\n                        }\r\n\r\n                        #cvxRoutingOverlayV8 .cvx-infoList {\r\n                            display: flex;\r\n                            flex-direction: column;\r\n                            gap: calc(7px * var(--s));\r\n                            font-size: calc(12px * var(--s));\r\n                            line-height: 1.25;\r\n                            color: var(--muted);\r\n                        }\r\n\r\n                        #cvxRoutingOverlayV8 .cvx-infoLine {\r\n                            display: flex;\r\n                            gap: calc(10px * var(--s));\r\n                            align-items: flex-start;\r\n                        }\r\n\r\n                        #cvxRoutingOverlayV8 .cvx-mini {\r\n                            width: calc(8px * var(--s));\r\n                            height: calc(8px * var(--s));\r\n                            border-radius: 999px;\r\n                            margin-top: calc(4px * var(--s));\r\n                            background: rgba(255, 255, 255, .35);\r\n                            box-shadow: 0 0 0 2px rgba(255, 255, 255, .10) inset;\r\n                            flex: 0 0 auto;\r\n                        }\r\n\r\n                        #cvxRoutingOverlayV8 .cvx-busPill {\r\n                            display: flex;\r\n                            align-items: center;\r\n                            justify-content: center;\r\n                            gap: calc(10px * var(--s));\r\n                            font-weight: 950;\r\n                            letter-spacing: .35px;\r\n                            color: var(--text);\r\n                            padding: calc(8px * var(--s)) calc(10px * var(--s));\r\n                            border-radius: 999px;\r\n                            background: rgba(90, 170, 255, .14);\r\n                            border: 1px solid rgba(90, 170, 255, .30);\r\n                            box-shadow: 0 0 calc(24px * var(--s)) rgba(90, 170, 255, .18);\r\n                            font-size: calc(13px * var(--s));\r\n                        }\r\n\r\n                        #cvxRoutingOverlayV8 .cvx-dot {\r\n                            width: calc(10px * var(--s));\r\n                            height: calc(10px * var(--s));\r\n                            border-radius: 999px;\r\n                            background: var(--accent);\r\n                            box-shadow: 0 0 calc(18px * var(--s)) var(--glow);\r\n                        }\r\n\r\n                        #cvxRoutingOverlayV8 .cvx-busFoot {\r\n                            margin-top: calc(8px * var(--s));\r\n                            display: flex;\r\n                            flex-direction: column;\r\n                            gap: calc(6px * var(--s));\r\n                            font-size: calc(12px * var(--s));\r\n                            line-height: 1.25;\r\n                            color: var(--muted);\r\n                        }\r\n\r\n                        \/* =========================================================\r\n         G) UI (AUX\/DIG & EXP)\r\n      ========================================================== *\/\r\n                        #cvxRoutingOverlayV8 .cvx-ui {\r\n                            display: flex;\r\n                            gap: calc(6px * var(--s));\r\n                            padding: calc(6px * var(--s));\r\n                            border-radius: calc(14px * var(--s));\r\n                            background: rgba(255, 255, 255, .04);\r\n                            border: 1px solid rgba(255, 255, 255, .10);\r\n                            box-shadow: 0 calc(14px * var(--s)) calc(28px * var(--s)) rgba(0, 0, 0, .35), inset 0 1px 0 rgba(255, 255, 255, .06);\r\n                            -webkit-backdrop-filter: blur(10px);\r\n                            backdrop-filter: blur(10px);\r\n                            pointer-events: auto;\r\n                            user-select: none;\r\n                            z-index: 3;\r\n                        }\r\n\r\n                        #cvxRoutingOverlayV8 .cvx-ui--abs {\r\n                            position: absolute;\r\n                            transform: translate(-50%, -50%);\r\n                        }\r\n\r\n                        #cvxRoutingOverlayV8 .cvx-ui button {\r\n                            all: unset;\r\n                            cursor: pointer;\r\n                            user-select: none;\r\n                            flex: 1;\r\n                            text-align: center;\r\n                            font-size: calc(11px * var(--s));\r\n                            font-weight: 950;\r\n                            padding: calc(7px * var(--s)) calc(10px * var(--s));\r\n                            border-radius: calc(11px * var(--s));\r\n                            color: rgba(255, 255, 255, .78);\r\n                            border: 1px solid rgba(255, 255, 255, .10);\r\n                            background: rgba(255, 255, 255, .02);\r\n                            letter-spacing: .25px;\r\n                        }\r\n\r\n                        #cvxRoutingOverlayV8 .cvx-ui button.on {\r\n                            color: rgba(255, 255, 255, .94);\r\n                            border-color: rgba(90, 170, 255, .30);\r\n                            background: linear-gradient(180deg, rgba(90, 170, 255, .18), rgba(90, 170, 255, .06));\r\n                            box-shadow: 0 0 0 1px rgba(90, 170, 255, .10) inset;\r\n                        }\r\n\r\n                        #cvxRoutingOverlayV8 .cvx-ui--grid {\r\n                            display: grid;\r\n                            grid-template-columns: repeat(2, 1fr);\r\n                            gap: calc(6px * var(--s));\r\n                            padding: 0;\r\n                            border: none;\r\n                            background: transparent;\r\n                            box-shadow: none;\r\n                            -webkit-backdrop-filter: none;\r\n                            backdrop-filter: none;\r\n                        }\r\n\r\n                        #cvxRoutingOverlayV8 .cvx-chip {\r\n                            all: unset;\r\n                            cursor: pointer;\r\n                            user-select: none;\r\n                            display: flex;\r\n                            align-items: center;\r\n                            justify-content: space-between;\r\n                            gap: calc(8px * var(--s));\r\n                            padding: calc(8px * var(--s)) calc(10px * var(--s));\r\n                            border-radius: calc(12px * var(--s));\r\n                            font-size: calc(11px * var(--s));\r\n                            font-weight: 950;\r\n                            color: rgba(255, 255, 255, .84);\r\n                            border: 1px solid rgba(255, 255, 255, .10);\r\n                            background: rgba(255, 255, 255, .02);\r\n                            letter-spacing: .25px;\r\n                        }\r\n\r\n                        #cvxRoutingOverlayV8 .cvx-chip.on {\r\n                            color: rgba(255, 255, 255, .94);\r\n                            border-color: rgba(90, 170, 255, .30);\r\n                            background: linear-gradient(180deg, rgba(90, 170, 255, .16), rgba(90, 170, 255, .05));\r\n                            box-shadow: 0 0 0 1px rgba(90, 170, 255, .10) inset;\r\n                        }\r\n\r\n                        #cvxRoutingOverlayV8 .cvx-chip .k {\r\n                            opacity: .85;\r\n                        }\r\n\r\n                        #cvxRoutingOverlayV8 .cvx-chip .v {\r\n                            opacity: .95;\r\n                            padding: calc(2px * var(--s)) calc(8px * var(--s));\r\n                            border-radius: 999px;\r\n                            border: 1px solid rgba(255, 255, 255, .10);\r\n                            background: rgba(0, 0, 0, .18);\r\n                        }\r\n\r\n                        #cvxRoutingOverlayV8 .cvx-chip.on .v {\r\n                            border-color: rgba(90, 170, 255, .28);\r\n                            background: rgba(90, 170, 255, .10);\r\n                        }\r\n\r\n                        #cvxRoutingOverlayV8 .cvx-panelNote {\r\n                            margin-top: calc(8px * var(--s));\r\n                            font-size: calc(11px * var(--s));\r\n                            color: rgba(255, 255, 255, .70);\r\n                            line-height: 1.25;\r\n                        }\r\n\r\n                        \/* Debug cross *\/\r\n                        #cvxRoutingOverlayV8 .cvx-cross {\r\n                            position: absolute;\r\n                            left: 50%;\r\n                            top: 50%;\r\n                            width: calc(14px * var(--s));\r\n                            height: calc(14px * var(--s));\r\n                            transform: translate(-50%, -50%);\r\n                            opacity: var(--debug);\r\n                            pointer-events: none;\r\n                        }\r\n\r\n                        #cvxRoutingOverlayV8 .cvx-cross:before,\r\n                        #cvxRoutingOverlayV8 .cvx-cross:after {\r\n                            content: \"\";\r\n                            position: absolute;\r\n                            inset: 0;\r\n                            margin: auto;\r\n                            background: rgba(90, 170, 255, .45);\r\n                            box-shadow: 0 0 calc(14px * var(--s)) rgba(90, 170, 255, .18);\r\n                        }\r\n\r\n                        #cvxRoutingOverlayV8 .cvx-cross:before {\r\n                            width: 100%;\r\n                            height: 1px;\r\n                            top: 50%;\r\n                            transform: translateY(-50%);\r\n                        }\r\n\r\n                        #cvxRoutingOverlayV8 .cvx-cross:after {\r\n                            width: 1px;\r\n                            height: 100%;\r\n                            left: 50%;\r\n                            transform: translateX(-50%);\r\n                        }\r\n                    <\/style>\r\n\r\n                    <!-- MEDIA BG (contain) -->\r\n                    <div class=\"cvx-routing-media\" aria-hidden=\"true\"><\/div>\r\n                    <div class=\"cvx-stageSpace\">\r\n\r\n                        <!-- TIP -->\r\n                        <div class=\"cvx-tip\" aria-hidden=\"true\">\r\n                            <span class=\"cvx-tipDot\"><\/span>\r\n                            <span class=\"cvx-tipLabel\">Tip:<\/span>\r\n                            <span class=\"cvx-tipText\">cambi\u00e1 AUX\/DIG y configur\u00e1 EXP para ver el ruteo<\/span>\r\n                        <\/div>\r\n\r\n                        <!-- SVG -->\r\n                        <svg class=\"cvx-svg\" aria-hidden=\"true\">\r\n                            <defs>\r\n                                <filter id=\"cvxGlowV8\">\r\n                                    <feGaussianBlur stdDeviation=\"2.2\" result=\"b\" \/>\r\n                                    <feMerge>\r\n                                        <feMergeNode in=\"b\" \/>\r\n                                        <feMergeNode in=\"SourceGraphic\" \/>\r\n                                    <\/feMerge>\r\n                                <\/filter>\r\n\r\n                                <mask id=\"cvxMaskV8\" maskUnits=\"userSpaceOnUse\">\r\n                                    <rect id=\"cvxMaskBaseV8\" x=\"0\" y=\"0\" width=\"1\" height=\"1\" fill=\"white\" \/>\r\n                                    <g id=\"cvxMaskCutsV8\"><\/g>\r\n                                <\/mask>\r\n\r\n                                <g id=\"cvxGradDefsV8\"><\/g>\r\n                            <\/defs>\r\n\r\n                            <g data-layer=\"paths\" mask=\"url(#cvxMaskV8)\"><\/g>\r\n                            <g data-layer=\"markers\" mask=\"url(#cvxMaskV8)\"><\/g>\r\n                            <g data-layer=\"particles\" mask=\"url(#cvxMaskV8)\"><\/g>\r\n                        <\/svg>\r\n\r\n                        <!-- NODES -->\r\n                        <div class=\"cvx-node\" data-node=\"dig\" style=\"left:calc(var(--dig-x) + (var(--dig-dx) * var(--s))); top:calc(var(--dig-y) + (var(--dig-dy) * var(--s)));\">\r\n                            <span class=\"cvx-badge\">DIG<\/span><span class=\"cvx-hint\">BT\/USB\/SD\/WiFi<\/span>\r\n                            <span class=\"cvx-cross\"><\/span>\r\n                        <\/div>\r\n\r\n                        <div class=\"cvx-node cvx-node--port\" data-node=\"hp\" data-port=\"right\" style=\"left:calc(var(--hp-x) + (var(--hp-dx) * var(--s))); top:calc(var(--hp-y) + (var(--hp-dy) * var(--s)));\">\r\n                            <svg class=\"cvx-portSvg\" aria-hidden=\"true\"><\/svg>\r\n                            <div class=\"cvx-portContent\">\r\n                                <span class=\"cvx-badge\">HP<\/span><span class=\"cvx-hint\">OUT<\/span>\r\n                            <\/div>\r\n                            <span class=\"cvx-portPin\" aria-hidden=\"true\"><\/span>\r\n                            <span class=\"cvx-cross\"><\/span>\r\n                        <\/div>\r\n\r\n                        <div class=\"cvx-node cvx-node--port\" data-node=\"aux\" data-port=\"left\" style=\"left:calc(var(--aux-x) + (var(--aux-dx) * var(--s))); top:calc(var(--aux-y) + (var(--aux-dy) * var(--s)));\">\r\n                            <svg class=\"cvx-portSvg\" aria-hidden=\"true\"><\/svg>\r\n                            <div class=\"cvx-portContent\">\r\n                                <span class=\"cvx-badge\">AUX<\/span><span class=\"cvx-hint\">IN<\/span>\r\n                            <\/div>\r\n                            <span class=\"cvx-portPin\" aria-hidden=\"true\"><\/span>\r\n                            <span class=\"cvx-cross\"><\/span>\r\n                        <\/div>\r\n\r\n                        <div class=\"cvx-node cvx-node--port\" data-node=\"in1\" data-port=\"right\" style=\"left:calc(var(--in1-x) + (var(--in1-dx) * var(--s))); top:calc(var(--in1-y) + (var(--in1-dy) * var(--s)));\">\r\n                            <svg class=\"cvx-portSvg\" aria-hidden=\"true\"><\/svg>\r\n                            <div class=\"cvx-portContent\">\r\n                                <span class=\"cvx-badge\">XLR | TRS<\/span><span class=\"cvx-hint\">IN<\/span>\r\n                            <\/div>\r\n                            <span class=\"cvx-portPin\" aria-hidden=\"true\"><\/span>\r\n                            <span class=\"cvx-cross\"><\/span>\r\n                        <\/div>\r\n\r\n                        <div class=\"cvx-node cvx-node--port\" data-node=\"in2\" data-port=\"left\" style=\"left:calc(var(--in2-x) + (var(--in2-dx) * var(--s))); top:calc(var(--in2-y) + (var(--in2-dy) * var(--s)));\">\r\n                            <svg class=\"cvx-portSvg\" aria-hidden=\"true\"><\/svg>\r\n                            <div class=\"cvx-portContent\">\r\n                                <span class=\"cvx-badge\">XLR | TRS<\/span><span class=\"cvx-hint\">IN<\/span>\r\n                            <\/div>\r\n                            <span class=\"cvx-portPin\" aria-hidden=\"true\"><\/span>\r\n                            <span class=\"cvx-cross\"><\/span>\r\n                        <\/div>\r\n\r\n                        <div class=\"cvx-node\" data-node=\"spkR\" style=\"left:calc(var(--spkR-x) + (var(--spkR-dx) * var(--s))); top:calc(var(--spkR-y) + (var(--spkR-dy) * var(--s)));\">\r\n                            <span class=\"cvx-badge\">SPK R<\/span><span class=\"cvx-hint\">Front\/Back<\/span>\r\n                            <span class=\"cvx-cross\"><\/span>\r\n                        <\/div>\r\n\r\n                        <div class=\"cvx-node\" data-node=\"spkL\" style=\"left:calc(var(--spkL-x) + (var(--spkL-dx) * var(--s))); top:calc(var(--spkL-y) + (var(--spkL-dy) * var(--s)));\">\r\n                            <span class=\"cvx-badge\">SPK L<\/span><span class=\"cvx-hint\">Front\/Back<\/span>\r\n                            <span class=\"cvx-cross\"><\/span>\r\n                        <\/div>\r\n\r\n                        <!-- MERGE -->\r\n                        <div class=\"cvx-mergeDot\"><\/div>\r\n                        <div data-node=\"merge\" style=\"position:absolute; left:var(--merge-x); top:var(--merge-y); width:1px; height:1px;\">\r\n                            <span class=\"cvx-cross\"><\/span>\r\n                        <\/div>\r\n\r\n                        <!-- AUX\/DIG UI -->\r\n                        <div class=\"cvx-ui cvx-ui--abs\" data-ui=\"auxdig\" style=\"left:calc(var(--merge-x) + (var(--sw-dx) * var(--s))); top:calc(var(--merge-y) + 11% + (var(--sw-dy) * var(--s)));\">\r\n                            <button type=\"button\" data-set=\"AUX\" class=\"on\">AUX<\/button>\r\n                            <button type=\"button\" data-set=\"DIG\">DIG<\/button>\r\n                        <\/div>\r\n\r\n                        <!-- BUS CARD -->\r\n                        <div class=\"cvx-card cvx-mix\" data-node=\"bus\" style=\"left:calc(var(--bus-x) + (var(--bus-dx) * var(--s))); top:calc(var(--bus-y) + (var(--bus-dy) * var(--s)));\">\r\n                            <div class=\"cvx-busPill\"><span class=\"cvx-dot\"><\/span> MIX BUS<\/div>\r\n                            <div class=\"cvx-busFoot\">\r\n                                <div class=\"cvx-infoLine\"><span class=\"cvx-mini\"><\/span><span><b>SPK L<\/b> y <b>SPK R<\/b>: mezcla principal por bafle (<b>Front\/Back<\/b>).<\/span><\/div>\r\n                                <div class=\"cvx-infoLine\"><span class=\"cvx-mini\"><\/span><span><b>HP<\/b>: mezcla de monitoreo dedicada, independiente de speakers.<\/span><\/div>\r\n                            <\/div>\r\n                            <span class=\"cvx-cross\"><\/span>\r\n                        <\/div>\r\n\r\n                        <!-- INFO CARD -->\r\n                        <div class=\"cvx-card cvx-info\" data-card=\"info\" style=\"\r\n        left:calc(var(--bus-x) + (var(--bus-dx) * var(--s)) - (var(--card-w) * var(--s)) - (var(--card-gap) * var(--s)));\r\n        top:calc(var(--bus-y) + (var(--bus-dy) * var(--s)));\r\n      \">\r\n                            <div class=\"cvx-infoTitle\"><span class=\"cvx-infoDot\"><\/span> Flujo de audio<\/div>\r\n                            <div class=\"cvx-infoList\">\r\n                                <div class=\"cvx-infoLine\"><span class=\"cvx-mini\"><\/span><span>Entr\u00e1s por <b>XLR | TRS<\/b> (A\/B) + <b>AUX<\/b> o <b>DIG<\/b><\/span><\/div>\r\n                                <div class=\"cvx-infoLine\"><span class=\"cvx-mini\"><\/span><span><b>AUX<\/b> y <b>DIG<\/b> comparten un par est\u00e9reo (eleg\u00eds uno)<\/span><\/div>\r\n                                <div class=\"cvx-infoLine\"><span class=\"cvx-mini\"><\/span><span><b>EXP<\/b> suma canales configurables <b>IN<\/b> u <b>OUT<\/b><\/span><\/div>\r\n                                <div class=\"cvx-infoLine\"><span class=\"cvx-mini\"><\/span><span>El <b>MIX BUS<\/b> genera dos salidas: <b>SPK<\/b> (por bafle) y <b>HP<\/b> (monitor independiente).<\/span><\/div>\r\n                            <\/div>\r\n                        <\/div>\r\n\r\n                        <!-- EXP CARD -->\r\n                        <div class=\"cvx-card cvx-panel\" data-card=\"exp\" style=\"\r\n        left:calc(var(--bus-x) + (var(--bus-dx) * var(--s)) + (var(--card-w) * var(--s)) + (var(--card-gap) * var(--s)));\r\n        top:calc(var(--bus-y) + (var(--bus-dy) * var(--s)));\r\n      \">\r\n                            <div class=\"cvx-panelHead\" style=\"display:flex;align-items:center;justify-content:space-between;gap:calc(10px*var(--s));margin-bottom:calc(8px*var(--s));\">\r\n                                <div style=\"font-size:calc(11px*var(--s));letter-spacing:.38px;font-weight:950;color:rgba(255,255,255,.86);text-transform:uppercase;opacity:.92;\">M\u00f3dulos I\/O<\/div>\r\n                                <div class=\"cvx-node\" data-node=\"exp\" style=\"position:relative;left:auto;top:auto;transform:none;padding:calc(6px*var(--s)) calc(9px*var(--s));font-size:calc(11px*var(--s));background:rgba(0,0,0,.35);pointer-events:none;\">\r\n                                    <span class=\"cvx-badge\">EXP<\/span><span class=\"cvx-hint\">I\/O<\/span>\r\n                                    <span class=\"cvx-cross\"><\/span>\r\n                                <\/div>\r\n                            <\/div>\r\n\r\n                            <div class=\"cvx-ui\" data-ui=\"expMode\" style=\"margin-bottom:calc(8px * var(--s));\">\r\n                                <button type=\"button\" data-set=\"BAL\" class=\"on\">BAL x2<\/button>\r\n                                <button type=\"button\" data-set=\"UNBAL\">UNBAL x4<\/button>\r\n                            <\/div>\r\n\r\n                            <div class=\"cvx-ui cvx-ui--grid\" data-ui=\"expMap\"><\/div>\r\n\r\n                            <div class=\"cvx-panelNote\">Canales configurables como <b>IN<\/b> u <b>OUT<\/b> individualmente.<\/div>\r\n                        <\/div>\r\n                    <\/div>\r\n                    <script>\r\n                        (() => {\r\n                            'use strict';\r\n\r\n                            \/* =========================================================\r\n                               0) Guard anti doble init (Elementor puede re-ejecutar scripts)\r\n                            ========================================================== *\/\r\n                            const KEY = '__CVX_ROUTING_OVERLAY_V8__';\r\n                            if (window[KEY]?.destroy) window[KEY].destroy();\r\n\r\n                            const root = document.getElementById('cvxRoutingOverlayV8');\r\n                            if (!root) return;\r\n                            \/* ---------------------------------------------------------\r\n                               StageSpace = content box real de background-size: contain\r\n                               Inputs (CSS vars):\r\n                                 --cvx-routing-img-ar   (num\u00e9rico width\/height)\r\n                                 --cvx-routing-img-fit  (contain|cover)  (solo contain se alinea)\r\n                                 --cvx-routing-img-pos  (ej \"50% 10%\")\r\n                               Outputs (CSS vars calculadas):\r\n                                 --cvx-routing-calc-img-x\/y\/w\/h\r\n                            --------------------------------------------------------- *\/\r\n                            const stage = root.querySelector('.cvx-stageSpace') || root;\r\n\r\n                            function posToken01(tok, axis) {\r\n                                const t = (tok || '').trim().toLowerCase();\r\n                                if (!t) return 0.5;\r\n                                if (t.endsWith('%')) return clamp(parseFloat(t) \/ 100, 0, 1);\r\n                                if (axis === 'x') {\r\n                                    if (t === 'left') return 0;\r\n                                    if (t === 'center') return 0.5;\r\n                                    if (t === 'right') return 1;\r\n                                } else {\r\n                                    if (t === 'top') return 0;\r\n                                    if (t === 'center') return 0.5;\r\n                                    if (t === 'bottom') return 1;\r\n                                }\r\n                                const n = parseFloat(t);\r\n                                return Number.isFinite(n) ? clamp(n, 0, 1) : 0.5;\r\n                            }\r\n\r\n                            function readObjPos01() {\r\n                                const p = cssStr('--cvx-routing-img-pos') || '50% 50%';\r\n                                const parts = p.trim().split(\/\\s+\/);\r\n                                return {\r\n                                    x: posToken01(parts[0] || '50%', 'x'),\r\n                                    y: posToken01(parts[1] || '50%', 'y')\r\n                                };\r\n                            }\r\n\r\n                            function updateContainBox() {\r\n                                const fit = (cssStr('--cvx-routing-img-fit') || 'contain').trim();\r\n                                const rr = root.getBoundingClientRect();\r\n                                const W = Math.max(1, rr.width);\r\n                                const H = Math.max(1, rr.height);\r\n\r\n                                \/\/ Si no es contain, evitamos \"pretender\" coordenadas: stage = root\r\n                                if (fit !== 'contain') {\r\n                                    root.style.setProperty('--cvx-routing-calc-img-x', '0px');\r\n                                    root.style.setProperty('--cvx-routing-calc-img-y', '0px');\r\n                                    root.style.setProperty('--cvx-routing-calc-img-w', `${W}px`);\r\n                                    root.style.setProperty('--cvx-routing-calc-img-h', `${H}px`);\r\n                                    return;\r\n                                }\r\n\r\n                                const ar = cssNum('--cvx-routing-img-ar', W \/ H); \/\/ width\/height\r\n                                const pos = readObjPos01();\r\n\r\n                                \/\/ contain: escala por el factor m\u00ednimo\r\n                                const s = Math.min(W \/ (ar * 1000), H \/ 1000); \/\/ truco: evitamos conocer pixeles reales\r\n                                const imgW = (ar * 1000) * s;\r\n                                const imgH = 1000 * s;\r\n\r\n                                const freeX = W - imgW;\r\n                                const freeY = H - imgH;\r\n\r\n                                const x = freeX * pos.x;\r\n                                const y = freeY * pos.y;\r\n\r\n                                root.style.setProperty('--cvx-routing-calc-img-x', `${x}px`);\r\n                                root.style.setProperty('--cvx-routing-calc-img-y', `${y}px`);\r\n                                root.style.setProperty('--cvx-routing-calc-img-w', `${imgW}px`);\r\n                                root.style.setProperty('--cvx-routing-calc-img-h', `${imgH}px`);\r\n                            }\r\n                            \/* =========================================================\r\n                               1) Refs SVG layers\r\n                            ========================================================== *\/\r\n                            const svg = root.querySelector('.cvx-svg');\r\n                            const gPaths = svg.querySelector('[data-layer=\"paths\"]');\r\n                            const gMarkers = svg.querySelector('[data-layer=\"markers\"]');\r\n                            const gParticles = svg.querySelector('[data-layer=\"particles\"]');\r\n\r\n                            const maskBase = svg.querySelector('#cvxMaskBaseV8');\r\n                            const maskCuts = svg.querySelector('#cvxMaskCutsV8');\r\n                            const gradDefs = svg.querySelector('#cvxGradDefsV8');\r\n\r\n                            const q = (sel) => root.querySelector(sel);\r\n\r\n                            \/* =========================================================\r\n                               2) Nodes & UI\r\n                            ========================================================== *\/\r\n                            const nodes = {\r\n                                dig: q('[data-node=\"dig\"]'),\r\n                                hp: q('[data-node=\"hp\"]'),\r\n                                aux: q('[data-node=\"aux\"]'),\r\n                                in1: q('[data-node=\"in1\"]'),\r\n                                in2: q('[data-node=\"in2\"]'),\r\n                                spkR: q('[data-node=\"spkR\"]'),\r\n                                spkL: q('[data-node=\"spkL\"]'),\r\n                                exp: q('[data-node=\"exp\"]'),\r\n                                merge: q('[data-node=\"merge\"]'),\r\n                                bus: q('[data-node=\"bus\"]')\r\n                            };\r\n\r\n                            const cardInfo = q('[data-card=\"info\"]');\r\n                            const cardExp = q('[data-card=\"exp\"]');\r\n                            const cardBus = nodes.bus;\r\n\r\n                            const uiAuxDig = q('[data-ui=\"auxdig\"]');\r\n                            const uiExpMode = q('[data-ui=\"expMode\"]');\r\n                            const uiExpMap = q('[data-ui=\"expMap\"]');\r\n\r\n                            \/* =========================================================\r\n                               3) State\r\n                            ========================================================== *\/\r\n                            const state = {\r\n                                auxdig: 'AUX', \/\/ AUX | DIG\r\n                                expMode: 'BAL', \/\/ BAL | UNBAL\r\n                                expCh: ['IN', 'IN', 'IN', 'IN'] \/\/ CH1..CH4\r\n                            };\r\n\r\n                            \/* =========================================================\r\n                               4) Helpers CSS vars\r\n                            ========================================================== *\/\r\n                            const NS = 'http:\/\/www.w3.org\/2000\/svg';\r\n                            const getCS = () => getComputedStyle(root);\r\n                            const cssStr = (name) => getCS().getPropertyValue(name).trim();\r\n                            const cssNum = (name, fallback) => {\r\n                                const v = cssStr(name);\r\n                                const n = parseFloat(v);\r\n                                return Number.isFinite(n) ? n : fallback;\r\n                            };\r\n                            const cssPct01 = (name, fallback01) => {\r\n                                const v = cssStr(name);\r\n                                if (!v) return fallback01;\r\n                                if (v.endsWith('%')) return Math.max(0, Math.min(1, parseFloat(v) \/ 100));\r\n                                const n = parseFloat(v);\r\n                                return Number.isFinite(n) ? Math.max(0, Math.min(1, n)) : fallback01;\r\n                            };\r\n                            const clamp = (n, a, b) => Math.max(a, Math.min(b, n));\r\n\r\n                            \/* =========================================================\r\n                               5) UI scale (solo UI)\r\n                               - s = clamp(ui-min, width\/ui-base, 1)\r\n                               - NO tocamos line-w ni particle-r\r\n                            ========================================================== *\/\r\n                            let uiScale = 1;\r\n\r\n                            function updateScale() {\r\n                                const base = cssNum('--ui-base', 1100);\r\n                                const minS = cssNum('--ui-min', 0.58);\r\n                                const w = stage.getBoundingClientRect().width;\r\n                                if (w < 2) return false; \/\/ contenedor oculto\r\nconst maxS = cssNum('--ui-max', 1);\r\nconst s = clamp(w \/ base, minS, maxS);\r\nif (Math.abs(s - uiScale) < 0.002) return false;\r\n                                uiScale = s;\r\n                                root.style.setProperty('--s', String(s));\r\n                                return true;\r\n                            }\r\n\r\n                            function isVisibleEnough() {\r\n                                const r = root.getBoundingClientRect();\r\n                                const cs = getCS();\r\n                                if (cs.display === 'none' || cs.visibility === 'hidden') return false;\r\n                                return (r.width > 20 && r.height > 20);\r\n                            }\r\n\r\n                            function isAnimOn() {\r\n                                const anim = cssNum('--anim', 1);\r\n                                const reduced = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;\r\n                                return anim === 1 && !reduced;\r\n                            }\r\n\r\n                            function setUIButtonState(container, value) {\r\n                                container.querySelectorAll('button').forEach(b => b.classList.toggle('on', b.dataset.set === value));\r\n                            }\r\n\r\n                            function getCenter(el) {\r\n                                const r = el.getBoundingClientRect();\r\n                                const rr = stage.getBoundingClientRect();\r\n                                return {\r\n                                    x: (r.left - rr.left) + r.width \/ 2,\r\n                                    y: (r.top - rr.top) + r.height \/ 2\r\n                                };\r\n                            }\r\n\r\n                            function isPortNode(el) {\r\n                                return !!(el && el.classList && el.classList.contains('cvx-node--port'));\r\n                            }\r\n\r\n                            function getPinCenter(el) {\r\n                                const pin = el.querySelector('.cvx-portPin');\r\n                                if (!pin) return getCenter(el);\r\n                                const r = pin.getBoundingClientRect();\r\n                                const rr = stage.getBoundingClientRect();\r\n                                return {\r\n                                    x: (r.left - rr.left) + r.width \/ 2,\r\n                                    y: (r.top - rr.top) + r.height \/ 2\r\n                                };\r\n                            }\r\n\r\n                            function getAnchor(el) {\r\n                                return isPortNode(el) ? getPinCenter(el) : getCenter(el);\r\n                            }\r\n\r\n                            \/* =========================================================\r\n                               6) Pools (DOM reuse)\r\n                            ========================================================== *\/\r\n                            const pathPool = new Map(); \/\/ key -> path\r\n                            const particlePool = []; \/\/ {el, pathKey, phase, speedMul, baseSpeed}\r\n                            const markerPool = new Map(); \/\/ key -> circle\r\n                            const gradPool = new Map(); \/\/ id -> linearGradient\r\n\r\n                            \/* =========================================================\r\n                               7) Paths: l\u00ednea NO escala (stroke-width constante)\r\n                            ========================================================== *\/\r\n                            function ensurePath(key) {\r\n                                if (pathPool.has(key)) return pathPool.get(key);\r\n                                const p = document.createElementNS(NS, 'path');\r\n                                p.setAttribute('data-key', key);\r\n                                p.setAttribute('fill', 'none');\r\n                                p.setAttribute('stroke-linecap', 'round');\r\n                                p.setAttribute('filter', 'url(#cvxGlowV8)');\r\n                                p.style.opacity = '0.95';\r\n                                gPaths.appendChild(p);\r\n                                pathPool.set(key, p);\r\n                                return p;\r\n                            }\r\n\r\n                            function applyLineStyle(p) {\r\n                                const w = cssNum('--line-w', 2);\r\n                                p.setAttribute('stroke-width', String(w)); \/\/ constante\r\n                            }\r\n\r\n                            function ensureMarker(key) {\r\n                                if (markerPool.has(key)) return markerPool.get(key);\r\n                                const c = document.createElementNS(NS, 'circle');\r\n                                c.setAttribute('r', String(4.2)); \/\/ constante\r\n                                c.setAttribute('fill', 'rgba(90,170,255,.30)');\r\n                                c.setAttribute('stroke', 'rgba(90,170,255,.55)');\r\n                                c.setAttribute('stroke-width', '1');\r\n                                c.setAttribute('filter', 'url(#cvxGlowV8)');\r\n                                c.style.opacity = '0.80';\r\n                                gMarkers.appendChild(c);\r\n                                markerPool.set(key, c);\r\n                                return c;\r\n                            }\r\n\r\n                            function removeUnused(map, used) {\r\n                                for (const [k, el] of map.entries()) {\r\n                                    if (!used.has(k)) {\r\n                                        el.remove();\r\n                                        map.delete(k);\r\n                                    }\r\n                                }\r\n                            }\r\n\r\n                            function offsetsFor(count) {\r\n                                const pairGap = cssNum('--pair-gap', 12); \/\/ NO escala\r\n                                const quadGap = cssNum('--quad-gap', 9); \/\/ NO escala\r\n                                if (count === 2) return [-pairGap \/ 2, +pairGap \/ 2];\r\n                                if (count === 4) return [-1.5 * quadGap, -0.5 * quadGap, +0.5 * quadGap, +1.5 * quadGap];\r\n                                return [0];\r\n                            }\r\n\r\n                            function resolvePerpOffset(a, b, mag) {\r\n                                const dx = b.x - a.x;\r\n                                const dy = b.y - a.y;\r\n                                const verticalish = Math.abs(dy) > Math.abs(dx) * 1.15;\r\n                                return verticalish ? {\r\n                                    ox: mag,\r\n                                    oy: 0\r\n                                } : {\r\n                                    ox: 0,\r\n                                    oy: mag\r\n                                };\r\n                            }\r\n\r\n                            function buildBezierLane(a, b, off, lanePct01, w, pinStart, pinEnd) {\r\n                                const laneX = (typeof lanePct01 === 'number') ? (lanePct01 * w) : ((a.x + b.x) * 0.5);\r\n\r\n                                const x1 = pinStart ? a.x : (a.x + off.ox);\r\n                                const y1 = pinStart ? a.y : (a.y + off.oy);\r\n                                const x2 = pinEnd ? b.x : (b.x + off.ox);\r\n                                const y2 = pinEnd ? b.y : (b.y + off.oy);\r\n\r\n                                const c1y = pinStart ? (a.y + off.oy) : y1;\r\n                                const c2y = pinEnd ? (b.y + off.oy) : y2;\r\n\r\n                                return `M ${x1} ${y1} C ${laneX} ${c1y} ${laneX} ${c2y} ${x2} ${y2}`;\r\n                            }\r\n\r\n                            \/* =========================================================\r\n                               8) EXP map UI\r\n                            ========================================================== *\/\r\n                            function expCount() {\r\n                                return (state.expMode === 'UNBAL') ? 4 : 2;\r\n                            }\r\n\r\n                            function renderExpMap() {\r\n                                const n = expCount();\r\n                                uiExpMap.innerHTML = '';\r\n                                for (let i = 0; i < n; i++) {\r\n                                    const btn = document.createElement('button');\r\n                                    btn.type = 'button';\r\n                                    btn.className = 'cvx-chip' + (state.expCh[i] === 'IN' ? ' on' : '');\r\n                                    btn.dataset.ch = String(i);\r\n                                    const label = (state.expCh[i] === 'IN') ? 'IN \\u2190' : 'OUT \\u2192';\r\n                                    btn.innerHTML = `<span class=\"k\">CH${i+1} <\/span><span class=\"v\">${label}<\/span>`;\r\n                                    uiExpMap.appendChild(btn);\r\n                                }\r\n                            }\r\n\r\n                            \/* =========================================================\r\n                               9) Gradientes (orientan el \u201cflow\u201d hacia el destino)\r\n                            ========================================================== *\/\r\n                            function ensureGradient(id, ax, ay, bx, by) {\r\n                                if (gradPool.has(id)) return gradPool.get(id);\r\n\r\n                                const lg = document.createElementNS(NS, 'linearGradient');\r\n                                lg.setAttribute('id', id);\r\n                                lg.setAttribute('gradientUnits', 'userSpaceOnUse');\r\n                                lg.setAttribute('x1', ax);\r\n                                lg.setAttribute('y1', ay);\r\n                                lg.setAttribute('x2', bx);\r\n                                lg.setAttribute('y2', by);\r\n\r\n                                const mk = (off, col) => {\r\n                                    const s = document.createElementNS(NS, 'stop');\r\n                                    s.setAttribute('offset', off);\r\n                                    s.setAttribute('stop-color', col);\r\n                                    return s;\r\n                                };\r\n\r\n                                lg.appendChild(mk('0%', 'rgba(90,170,255,.55)'));\r\n                                lg.appendChild(mk('90%', 'rgba(90,170,255,.78)'));\r\n                                lg.appendChild(mk('95%', 'rgba(90,170,255,.28)'));\r\n                                lg.appendChild(mk('100%', 'rgba(90,170,255,0)'));\r\n\r\n                                gradDefs.appendChild(lg);\r\n                                gradPool.set(id, lg);\r\n                                return lg;\r\n                            }\r\n\r\n                            \/* =========================================================\r\n                               10) Particles (NO escalan con --s)\r\n                            ========================================================== *\/\r\n                            function rebuildParticles() {\r\n                                while (gParticles.firstChild) gParticles.removeChild(gParticles.firstChild);\r\n                                particlePool.length = 0;\r\n                                if (!isAnimOn()) return;\r\n\r\n                                const perPath = Math.max(1, Math.min(5, cssNum('--particles-per-path', 5)));\r\n                                const baseSpeed = Math.max(0.05, Math.min(0.8, cssNum('--particle-speed', 0.22)));\r\n                                const accent = cssStr('--accent') || '#5AAAFF';\r\n                                const pr = Math.max(2, cssNum('--particle-r', 3)); \/\/ constante\r\n\r\n                                for (const [key, p] of pathPool.entries()) {\r\n                                    if (p.dataset.active !== '1') continue;\r\n                                    for (let i = 0; i < perPath; i++) {\r\n                                        const c = document.createElementNS(NS, 'circle');\r\n                                        c.setAttribute('r', String(pr));\r\n                                        c.setAttribute('fill', accent);\r\n                                        c.setAttribute('filter', 'url(#cvxGlowV8)');\r\n                                        c.style.opacity = '0.0';\r\n                                        gParticles.appendChild(c);\r\n\r\n                                        particlePool.push({\r\n                                            el: c,\r\n                                            pathKey: key,\r\n                                            phase: i \/ perPath,\r\n                                            speedMul: 1 + i * 0.12,\r\n                                            baseSpeed\r\n                                        });\r\n                                    }\r\n                                }\r\n                            }\r\n\r\n                            function rebuildMarkers() {\r\n                                const used = new Set();\r\n                                const key = 'bus_hp_0';\r\n                                const p = pathPool.get(key);\r\n                                if (p && p.dataset.active === '1') {\r\n                                    const m = ensureMarker('hpTap');\r\n                                    const len = p.__len || p.getTotalLength();\r\n                                    const pt = p.getPointAtLength(len * 0.22);\r\n                                    m.setAttribute('cx', pt.x.toFixed(2));\r\n                                    m.setAttribute('cy', pt.y.toFixed(2));\r\n                                    used.add('hpTap');\r\n                                }\r\n                                removeUnused(markerPool, used);\r\n                            }\r\n\r\n                            \/* =========================================================\r\n                               11) Mask cuts (cards + switch)\r\n                               - El pad S\u00cd escala con UI (porque cards\/pills cambian de tama\u00f1o)\r\n                            ========================================================== *\/\r\n                            function ensureMaskRect(id) {\r\n                                let r = maskCuts.querySelector(`[data-cut=\"${id}\"]`);\r\n                                if (!r) {\r\n                                    r = document.createElementNS(NS, 'rect');\r\n                                    r.setAttribute('data-cut', id);\r\n                                    r.setAttribute('fill', 'black');\r\n                                    maskCuts.appendChild(r);\r\n                                }\r\n                                r.setAttribute('rx', String(18 * uiScale));\r\n                                return r;\r\n                            }\r\n\r\n                            function setMaskFromEl(id, el, pad) {\r\n                                const rr = stage.getBoundingClientRect();\r\n                                const r = el.getBoundingClientRect();\r\n                                const x = (r.left - rr.left) - pad;\r\n                                const y = (r.top - rr.top) - pad;\r\n                                const w = r.width + pad * 2;\r\n                                const h = r.height + pad * 2;\r\n\r\n                                const cut = ensureMaskRect(id);\r\n                                cut.setAttribute('x', x.toFixed(2));\r\n                                cut.setAttribute('y', y.toFixed(2));\r\n                                cut.setAttribute('width', w.toFixed(2));\r\n                                cut.setAttribute('height', h.toFixed(2));\r\n                            }\r\n\r\n                            function rebuildMask(w, h) {\r\n                                const pad = cssNum('--mask-pad', 10) * uiScale;\r\n                                maskBase.setAttribute('x', '0');\r\n                                maskBase.setAttribute('y', '0');\r\n                                maskBase.setAttribute('width', String(w));\r\n                                maskBase.setAttribute('height', String(h));\r\n\r\n                                setMaskFromEl('cardBus', cardBus, pad);\r\n                                setMaskFromEl('cardInfo', cardInfo, pad);\r\n                                setMaskFromEl('cardExp', cardExp, pad);\r\n                                setMaskFromEl('swAuxDig', uiAuxDig, pad);\r\n\r\n                                const keep = new Set(['cardBus', 'cardInfo', 'cardExp', 'swAuxDig']);\r\n                                [...maskCuts.querySelectorAll('rect[data-cut]')].forEach(r => {\r\n                                    if (!keep.has(r.getAttribute('data-cut'))) r.remove();\r\n                                });\r\n                            }\r\n\r\n                            \/* =========================================================\r\n                               12) OPENPORT SVG renderer\r\n                               - CR\u00cdTICO: no renderizar con widths 0 (cuando el contenedor est\u00e1 oculto)\r\n                               - Guardamos \u00faltima geometr\u00eda v\u00e1lida por key para evitar \u201cperder contorno\u201d.\r\n                            ========================================================== *\/\r\n                            const lastPortMetrics = new Map(); \/\/ key -> {pillW,pillH,outerR,holeR,port}\r\n\r\n                            function roundedRectPath(x, y, w, h, r) {\r\n                                const rr = Math.max(0, Math.min(r, Math.min(w, h) * 0.5));\r\n                                const x2 = x + w,\r\n                                    y2 = y + h;\r\n                                return [\r\n                                    `M ${x+rr} ${y}`,\r\n                                    `H ${x2-rr}`,\r\n                                    `A ${rr} ${rr} 0 0 1 ${x2} ${y+rr}`,\r\n                                    `V ${y2-rr}`,\r\n                                    `A ${rr} ${rr} 0 0 1 ${x2-rr} ${y2}`,\r\n                                    `H ${x+rr}`,\r\n                                    `A ${rr} ${rr} 0 0 1 ${x} ${y2-rr}`,\r\n                                    `V ${y+rr}`,\r\n                                    `A ${rr} ${rr} 0 0 1 ${x+rr} ${y}`,\r\n                                    `Z`\r\n                                ].join(' ');\r\n                            }\r\n\r\n                            function circlePath(cx, cy, r) {\r\n                                const x0 = cx + r,\r\n                                    y0 = cy;\r\n                                const x1 = cx - r,\r\n                                    y1 = cy;\r\n                                return [\r\n                                    `M ${x0} ${y0}`,\r\n                                    `A ${r} ${r} 0 1 0 ${x1} ${y1}`,\r\n                                    `A ${r} ${r} 0 1 0 ${x0} ${y0}`,\r\n                                    `Z`\r\n                                ].join(' ');\r\n                            }\r\n\r\n                            function renderPortSVG(svgEl, key, port, pillW, pillH, outerR, holeR) {\r\n                                while (svgEl.firstChild) svgEl.removeChild(svgEl.firstChild);\r\n\r\n                                const boxW = pillW + outerR;\r\n                                svgEl.setAttribute('viewBox', `0 0 ${boxW} ${pillH}`);\r\n                                svgEl.setAttribute('preserveAspectRatio', 'none');\r\n\r\n                                const defs = document.createElementNS(NS, 'defs');\r\n                                const filterId = `cvxPortFxV8_${key}`;\r\n                                const maskId = `cvxPortMaskV8_${key}`;\r\n\r\n                                const f = document.createElementNS(NS, 'filter');\r\n                                f.setAttribute('id', filterId);\r\n                                f.setAttribute('x', '-20%');\r\n                                f.setAttribute('y', '-20%');\r\n                                f.setAttribute('width', '140%');\r\n                                f.setAttribute('height', '140%');\r\n                                f.setAttribute('color-interpolation-filters', 'sRGB');\r\n\r\n                                \/* Stroke \u201coutline\u201d alrededor de la forma (s\u00ed escala con UI) *\/\r\n                                const m1 = document.createElementNS(NS, 'feMorphology');\r\n                                m1.setAttribute('in', 'SourceAlpha');\r\n                                m1.setAttribute('operator', 'dilate');\r\n                                m1.setAttribute('radius', String(0.9 * uiScale));\r\n                                m1.setAttribute('result', 'dil');\r\n\r\n                                const c1 = document.createElementNS(NS, 'feComposite');\r\n                                c1.setAttribute('in', 'dil');\r\n                                c1.setAttribute('in2', 'SourceAlpha');\r\n                                c1.setAttribute('operator', 'out');\r\n                                c1.setAttribute('result', 'outline');\r\n\r\n                                const flood = document.createElementNS(NS, 'feFlood');\r\n                                flood.setAttribute('flood-color', 'rgba(27,51,77,1)');\r\n                                flood.setAttribute('result', 'col');\r\n\r\n                                const c2 = document.createElementNS(NS, 'feComposite');\r\n                                c2.setAttribute('in', 'col');\r\n                                c2.setAttribute('in2', 'outline');\r\n                                c2.setAttribute('operator', 'in');\r\n                                c2.setAttribute('result', 'stroke');\r\n\r\n                                const merge = document.createElementNS(NS, 'feMerge');\r\n                                const mn1 = document.createElementNS(NS, 'feMergeNode');\r\n                                mn1.setAttribute('in', 'stroke');\r\n                                const mn2 = document.createElementNS(NS, 'feMergeNode');\r\n                                mn2.setAttribute('in', 'SourceGraphic');\r\n                                merge.appendChild(mn1);\r\n                                merge.appendChild(mn2);\r\n\r\n                                f.appendChild(m1);\r\n                                f.appendChild(c1);\r\n                                f.appendChild(flood);\r\n                                f.appendChild(c2);\r\n                                f.appendChild(merge);\r\n                                defs.appendChild(f);\r\n\r\n                                const mask = document.createElementNS(NS, 'mask');\r\n                                mask.setAttribute('id', maskId);\r\n                                mask.setAttribute('maskUnits', 'userSpaceOnUse');\r\n\r\n                                const mr = document.createElementNS(NS, 'rect');\r\n                                mr.setAttribute('x', '0');\r\n                                mr.setAttribute('y', '0');\r\n                                mr.setAttribute('width', String(boxW));\r\n                                mr.setAttribute('height', String(pillH));\r\n                                mr.setAttribute('fill', 'white');\r\n\r\n                                const cx = (port === 'left') ? outerR : pillW;\r\n                                const cy = pillH \/ 2;\r\n\r\n                                const hole = document.createElementNS(NS, 'circle');\r\n                                hole.setAttribute('cx', String(cx));\r\n                                hole.setAttribute('cy', String(cy));\r\n                                hole.setAttribute('r', String(holeR));\r\n                                hole.setAttribute('fill', 'black');\r\n\r\n                                mask.appendChild(mr);\r\n                                mask.appendChild(hole);\r\n                                defs.appendChild(mask);\r\n\r\n                                svgEl.appendChild(defs);\r\n\r\n                                const rectX = (port === 'left') ? outerR : 0;\r\n                                const r = Math.max(1, pillH \/ 2);\r\n\r\n                                const d = [\r\n                                    roundedRectPath(rectX, 0, pillW, pillH, r),\r\n                                    circlePath(cx, cy, outerR)\r\n                                ].join(' ');\r\n\r\n                                const path = document.createElementNS(NS, 'path');\r\n                                path.setAttribute('d', d);\r\n                                path.setAttribute('fill', cssStr('--node-bg') || 'rgba(0,0,0,.52)');\r\n                                path.setAttribute('mask', `url(#${maskId})`);\r\n                                path.setAttribute('filter', `url(#${filterId})`);\r\n\r\n                                svgEl.appendChild(path);\r\n                            }\r\n\r\n                            function layoutPortNodes() {\r\n                                const list = [{\r\n                                        key: 'hp',\r\n                                        el: nodes.hp\r\n                                    },\r\n                                    {\r\n                                        key: 'aux',\r\n                                        el: nodes.aux\r\n                                    },\r\n                                    {\r\n                                        key: 'in1',\r\n                                        el: nodes.in1\r\n                                    },\r\n                                    {\r\n                                        key: 'in2',\r\n                                        el: nodes.in2\r\n                                    }\r\n                                ];\r\n\r\n                                const outerUser = cssNum('--port-outer-r', 18) * uiScale;\r\n                                const holeUser = cssNum('--port-hole-r', 11) * uiScale;\r\n\r\n                                for (const {\r\n                                        key,\r\n                                        el\r\n                                    }\r\n                                    of list) {\r\n                                    if (!el) continue;\r\n                                    const content = el.querySelector('.cvx-portContent');\r\n                                    const svgEl = el.querySelector('.cvx-portSvg');\r\n                                    const pin = el.querySelector('.cvx-portPin');\r\n                                    if (!content || !svgEl || !pin) continue;\r\n\r\n                                    \/* [V8.1] IMPORTANTE: setear max-content ANTES de medir\r\n                                       as\u00ed el getBoundingClientRect incluye el padding real y el SVG acompa\u00f1a *\/\r\n                                    content.style.width = 'max-content';\r\n\r\n                                    \/* Medici\u00f3n: si est\u00e1 oculto, getBoundingClientRect da 0.\r\n                                       => NO tocamos nada y preservamos el \u00faltimo contorno v\u00e1lido. *\/\r\n                                    const cr = content.getBoundingClientRect();\r\n                                    const valid = (cr.width > 20 && cr.height > 16);\r\n\r\n                                    if (!valid) {\r\n                                        const prev = lastPortMetrics.get(key);\r\n                                        if (prev) {\r\n                                            \/\/ Re-aplica tama\u00f1os previos (por si Elementor reconstruy\u00f3 el DOM)\r\n                                            el.style.setProperty('--pill-w', `${prev.pillW}px`);\r\n                                            el.style.setProperty('--pill-h', `${prev.pillH}px`);\r\n                                            el.style.setProperty('--port-outer-r-local', `${prev.outerR}px`);\r\n                                            el.style.setProperty('--port-hole-r-local', `${prev.holeR}px`);\r\n                                            el.style.setProperty('--box-w', `${(prev.pillW + prev.outerR)}px`);\r\n                                            el.style.width = `${(prev.pillW + prev.outerR)}px`;\r\n                                            el.style.height = `${prev.pillH}px`;\r\n                                            el.style.setProperty('--pin-x', `${(prev.port === 'left') ? prev.outerR : prev.pillW}px`);\r\n                                            el.style.setProperty('--pin-y', `${(prev.pillH\/2)}px`);\r\n                                            \/\/ Si el SVG qued\u00f3 vac\u00edo por alg\u00fan motivo, lo re-renderiza con prev.\r\n                                            if (!svgEl.firstChild) renderPortSVG(svgEl, key, prev.port, prev.pillW, prev.pillH, prev.outerR, prev.holeR);\r\n                                        }\r\n                                        continue;\r\n                                    }\r\n\r\n                                    const pillW = Math.max(1, cr.width);\r\n                                    const pillH = Math.max(1, cr.height);\r\n\r\n                                    const maxOuter = Math.max(10 * uiScale, (pillH \/ 2) - 1);\r\n                                    const outerR = Math.max(10 * uiScale, Math.min(outerUser, maxOuter));\r\n                                    const holeR = Math.max(6 * uiScale, Math.min(holeUser, outerR - 3 * uiScale));\r\n\r\n                                    const port = el.dataset.port; \/\/ left|right\r\n                                    const boxW = pillW + outerR;\r\n\r\n                                    el.style.setProperty('--pill-w', `${pillW}px`);\r\n                                    el.style.setProperty('--pill-h', `${pillH}px`);\r\n                                    el.style.setProperty('--port-outer-r-local', `${outerR}px`);\r\n                                    el.style.setProperty('--port-hole-r-local', `${holeR}px`);\r\n                                    el.style.setProperty('--box-w', `${boxW}px`);\r\n                                    el.style.width = `${boxW}px`;\r\n                                    el.style.height = `${pillH}px`;\r\n\r\n                                    const pinX = (port === 'left') ? outerR : pillW;\r\n                                    const pinY = pillH \/ 2;\r\n\r\n                                    el.style.setProperty('--pin-x', `${pinX}px`);\r\n                                    el.style.setProperty('--pin-y', `${pinY}px`);\r\n\r\n                                    renderPortSVG(svgEl, key, port, pillW, pillH, outerR, holeR);\r\n\r\n                                    lastPortMetrics.set(key, {\r\n                                        pillW,\r\n                                        pillH,\r\n                                        outerR,\r\n                                        holeR,\r\n                                        port\r\n                                    });\r\n                                }\r\n                            }\r\n\r\n                            \/* =========================================================\r\n                               13) Rebuild geometry (paths\/gradients\/mask\/particles)\r\n                               - NO correr cuando el contenedor est\u00e1 oculto\r\n                            ========================================================== *\/\r\n                            function rebuildGeometry() {\r\n                                if (!isVisibleEnough()) return false;\r\n                                \r\n                                \/* 1) Recalcular SIEMPRE el content-box del contain (stageSpace) *\/\r\n                                updateContainBox();\r\n                                \r\n                                \/* 2) Ahora s\u00ed: escalar UI usando el ancho REAL del stageSpace *\/\r\n                                updateScale();\r\n                                \r\n                                \/* 3) Medir puertos y luego geometr\u00eda *\/\r\n                                layoutPortNodes();\r\n                                \r\n                                const rr = stage.getBoundingClientRect();\r\n                                const w = Math.max(1, rr.width);\r\n                                const h = Math.max(1, rr.height);\r\n\r\n                                svg.setAttribute('viewBox', `0 0 ${w} ${h}`);\r\n                                svg.setAttribute('preserveAspectRatio', 'none');\r\n\r\n                                rebuildMask(w, h);\r\n\r\n                                const A = {\r\n                                    dig: getAnchor(nodes.dig),\r\n                                    hp: getAnchor(nodes.hp),\r\n                                    aux: getAnchor(nodes.aux),\r\n                                    in1: getAnchor(nodes.in1),\r\n                                    in2: getAnchor(nodes.in2),\r\n                                    spkR: getAnchor(nodes.spkR),\r\n                                    spkL: getAnchor(nodes.spkL),\r\n                                    exp: getAnchor(nodes.exp),\r\n                                    merge: getAnchor(nodes.merge),\r\n                                    bus: getAnchor(nodes.bus)\r\n                                };\r\n\r\n                                const lanes = {\r\n                                    in1: cssPct01('--lane-in1', 0.42),\r\n                                    in2: cssPct01('--lane-in2', 0.55),\r\n                                    aux: cssPct01('--lane-aux', 0.50),\r\n                                    dig: cssPct01('--lane-dig', 0.50),\r\n                                    merge: cssPct01('--lane-merge', 0.50),\r\n                                    hp: cssPct01('--lane-hp', 0.45),\r\n                                    spkR: cssPct01('--lane-spkR', 0.60),\r\n                                    spkL: cssPct01('--lane-spkL', 0.40),\r\n                                    exp: cssPct01('--lane-exp', 0.70)\r\n                                };\r\n\r\n                                const conns = [{\r\n                                        id: 'in1_bus',\r\n                                        from: 'in1',\r\n                                        to: 'bus',\r\n                                        count: 2,\r\n                                        active: () => true,\r\n                                        lane: lanes.in1,\r\n                                        dirAt: () => +1\r\n                                    },\r\n                                    {\r\n                                        id: 'in2_bus',\r\n                                        from: 'in2',\r\n                                        to: 'bus',\r\n                                        count: 2,\r\n                                        active: () => true,\r\n                                        lane: lanes.in2,\r\n                                        dirAt: () => +1\r\n                                    },\r\n\r\n                                    {\r\n                                        id: 'aux_merge',\r\n                                        from: 'aux',\r\n                                        to: 'merge',\r\n                                        count: 2,\r\n                                        active: () => state.auxdig === 'AUX',\r\n                                        lane: lanes.aux,\r\n                                        dirAt: () => +1\r\n                                    },\r\n                                    {\r\n                                        id: 'dig_merge',\r\n                                        from: 'dig',\r\n                                        to: 'merge',\r\n                                        count: 2,\r\n                                        active: () => state.auxdig === 'DIG',\r\n                                        lane: lanes.dig,\r\n                                        dirAt: () => +1\r\n                                    },\r\n\r\n                                    {\r\n                                        id: 'merge_bus',\r\n                                        from: 'merge',\r\n                                        to: 'bus',\r\n                                        count: 2,\r\n                                        active: () => true,\r\n                                        lane: lanes.merge,\r\n                                        dirAt: () => +1\r\n                                    },\r\n\r\n                                    {\r\n                                        id: 'exp_bus',\r\n                                        from: 'exp',\r\n                                        to: 'bus',\r\n                                        count: (state.expMode === 'UNBAL') ? 4 : 2,\r\n                                        active: () => true,\r\n                                        lane: lanes.exp,\r\n                                        dirAt: (i) => (state.expCh[i] === 'IN') ? +1 : -1\r\n                                    },\r\n\r\n                                    {\r\n                                        id: 'bus_spkR',\r\n                                        from: 'bus',\r\n                                        to: 'spkR',\r\n                                        count: 2,\r\n                                        active: () => true,\r\n                                        lane: lanes.spkR,\r\n                                        dirAt: () => +1\r\n                                    },\r\n                                    {\r\n                                        id: 'bus_spkL',\r\n                                        from: 'bus',\r\n                                        to: 'spkL',\r\n                                        count: 2,\r\n                                        active: () => true,\r\n                                        lane: lanes.spkL,\r\n                                        dirAt: () => +1\r\n                                    },\r\n\r\n                                    {\r\n                                        id: 'bus_hp',\r\n                                        from: 'bus',\r\n                                        to: 'hp',\r\n                                        count: 2,\r\n                                        active: () => true,\r\n                                        lane: lanes.hp,\r\n                                        dirAt: () => +1\r\n                                    }\r\n                                ];\r\n\r\n                                const usedPaths = new Set();\r\n                                const usedGrads = new Set();\r\n\r\n                                for (const c of conns) {\r\n                                    const on = c.active();\r\n                                    const offs = offsetsFor(c.count);\r\n                                    const shareGrad = (c.count === 2 && c.id !== 'exp_bus');\r\n                                    let gradShared = null;\r\n\r\n                                    if (shareGrad) {\r\n                                        gradShared = `cvxG8_${c.id}_${c.from}_${c.to}`;\r\n                                        ensureGradient(gradShared, A[c.from].x.toFixed(2), A[c.from].y.toFixed(2), A[c.to].x.toFixed(2), A[c.to].y.toFixed(2));\r\n                                        usedGrads.add(gradShared);\r\n                                    }\r\n\r\n                                    offs.forEach((mag, i) => {\r\n                                        const key = `${c.id}_${i}`;\r\n                                        usedPaths.add(key);\r\n\r\n                                        const p = ensurePath(key);\r\n                                        applyLineStyle(p); \/\/ constante\r\n\r\n                                        const fromEl = nodes[c.from];\r\n                                        const toEl = nodes[c.to];\r\n                                        const pinStart = isPortNode(fromEl);\r\n                                        const pinEnd = isPortNode(toEl);\r\n\r\n                                        const off = (pinStart || pinEnd) ?\r\n                                            {\r\n                                                ox: 0,\r\n                                                oy: mag\r\n                                            } \/\/ si pin, separamos sobre control-points\r\n                                            :\r\n                                            resolvePerpOffset(A[c.from], A[c.to], mag);\r\n\r\n                                        const d = buildBezierLane(A[c.from], A[c.to], off, c.lane, w, pinStart, pinEnd);\r\n                                        p.setAttribute('d', d);\r\n\r\n                                        p.dataset.active = on ? '1' : '0';\r\n                                        p.style.opacity = on ? '0.95' : '0.12';\r\n\r\n                                        const dir = c.dirAt ? c.dirAt(i) : +1;\r\n                                        p.dataset.dir = String(dir);\r\n\r\n                                        let gid = gradShared;\r\n                                        if (!gid) {\r\n                                            const from = (dir >= 0) ? c.from : c.to;\r\n                                            const to = (dir >= 0) ? c.to : c.from;\r\n                                            gid = `cvxG8_${c.id}_${i}_${from}_${to}`;\r\n                                            ensureGradient(gid, A[from].x.toFixed(2), A[from].y.toFixed(2), A[to].x.toFixed(2), A[to].y.toFixed(2));\r\n                                            usedGrads.add(gid);\r\n                                        }\r\n                                        p.setAttribute('stroke', `url(#${gid})`);\r\n                                        p.__len = p.getTotalLength();\r\n                                    });\r\n                                }\r\n\r\n                                removeUnused(pathPool, usedPaths);\r\n\r\n                                for (const [id, el] of gradPool.entries()) {\r\n                                    if (!usedGrads.has(id)) {\r\n                                        el.remove();\r\n                                        gradPool.delete(id);\r\n                                    }\r\n                                }\r\n\r\n                                rebuildParticles();\r\n                                rebuildMarkers();\r\n                                return true;\r\n                            }\r\n\r\n                            \/* =========================================================\r\n                               14) Animation tick (particles)\r\n                            ========================================================== *\/\r\n                            let raf = 0;\r\n                            let running = true;\r\n\r\n                            function tick() {\r\n                                raf = requestAnimationFrame(tick);\r\n                                if (!running) return;\r\n                                if (!isAnimOn() || particlePool.length === 0) return;\r\n\r\n                                const t = performance.now() * 0.001;\r\n\r\n                                for (const part of particlePool) {\r\n                                    const path = pathPool.get(part.pathKey);\r\n                                    if (!path || path.dataset.active !== '1') continue;\r\n\r\n                                    const dir = (path.dataset.dir === '-1') ? -1 : +1;\r\n                                    const len = path.__len || path.getTotalLength();\r\n\r\n                                    let u = (t * part.baseSpeed * part.speedMul + part.phase) % 1;\r\n                                    if (dir < 0) u = 1 - u;\r\n\r\n                                    const pt = path.getPointAtLength(u * len);\r\n                                    part.el.setAttribute('cx', pt.x.toFixed(2));\r\n                                    part.el.setAttribute('cy', pt.y.toFixed(2));\r\n\r\n                                    const fade = Math.sin(Math.PI * u);\r\n                                    part.el.style.opacity = String(0.72 * fade);\r\n                                }\r\n                            }\r\n\r\n                            \/* =========================================================\r\n                               15) Scheduling robusto (para \u201cswitch de secciones\u201d Elementor)\r\n                               - Si est\u00e1 oculto, reintenta hasta que tenga layout v\u00e1lido.\r\n                            ========================================================== *\/\r\n                            let pending = 0;\r\n\r\n                            function scheduleRebuild() {\r\n                                if (pending) cancelAnimationFrame(pending);\r\n                                pending = requestAnimationFrame(() => {\r\n                                    pending = 0;\r\n                                    if (rebuildGeometry()) return;\r\n\r\n                                    \/\/ Si sigue oculto, reintenta (poco costo) hasta que vuelva\r\n                                    let tries = 0;\r\n                                    const retry = () => {\r\n                                        tries++;\r\n                                        if (tries > 25) return; \/\/ ~25*60ms = 1.5s m\u00e1ximo\r\n                                        if (rebuildGeometry()) return;\r\n                                        setTimeout(retry, 60);\r\n                                    };\r\n                                    retry();\r\n                                });\r\n                            }\r\n                            \/* =========================================================\r\n                               16) UI bindings\r\n                            ========================================================== *\/\r\n                            function bindUI() {\r\n                                uiAuxDig.addEventListener('click', (e) => {\r\n                                    const b = e.target.closest('button[data-set]');\r\n                                    if (!b) return;\r\n                                    state.auxdig = b.dataset.set;\r\n                                    setUIButtonState(uiAuxDig, state.auxdig);\r\n                                    scheduleRebuild();\r\n                                });\r\n\r\n                                uiExpMode.addEventListener('click', (e) => {\r\n                                    const b = e.target.closest('button[data-set]');\r\n                                    if (!b) return;\r\n                                    state.expMode = b.dataset.set;\r\n                                    setUIButtonState(uiExpMode, state.expMode);\r\n                                    renderExpMap();\r\n                                    scheduleRebuild();\r\n                                });\r\n\r\n                                uiExpMap.addEventListener('click', (e) => {\r\n                                    const b = e.target.closest('button.cvx-chip');\r\n                                    if (!b) return;\r\n                                    const i = parseInt(b.dataset.ch, 10);\r\n                                    state.expCh[i] = (state.expCh[i] === 'IN') ? 'OUT' : 'IN';\r\n                                    renderExpMap();\r\n                                    scheduleRebuild();\r\n                                });\r\n\r\n                                setUIButtonState(uiAuxDig, state.auxdig);\r\n                                setUIButtonState(uiExpMode, state.expMode);\r\n                                renderExpMap();\r\n                            }\r\n\r\n                            \/* =========================================================\r\n                               17) Observers\r\n                               - ResizeObserver: responde a cambios de width (vw)\r\n                               - IntersectionObserver: cuando vuelve visible, rebuild inmediato\r\n                               - MutationObserver: detecta cambios de style\/class (Elementor toggle)\r\n                            ========================================================== *\/\r\n                            let ro = null,\r\n                                io = null,\r\n                                mo = null;\r\n\r\n                            function initObservers() {\r\n                                ro = new ResizeObserver(() => scheduleRebuild());\r\n                                ro.observe(root);\r\n\r\n                                io = new IntersectionObserver((entries) => {\r\n                                    const e = entries[0];\r\n                                    running = !!(e && e.isIntersecting);\r\n                                    if (running) scheduleRebuild(); \/\/ al volver a mostrarse, repara OpenPort\/paths\r\n                                }, {\r\n                                    threshold: 0.05\r\n                                });\r\n                                io.observe(root);\r\n\r\n                                mo = new MutationObserver(() => scheduleRebuild());\r\n                                mo.observe(root, {\r\n                                    attributes: true,\r\n                                    attributeFilter: ['style', 'class']\r\n                                });\r\n                                \/\/ Tambi\u00e9n sirve observar al padre si Elementor lo oculta a nivel contenedor\r\n                                if (root.parentElement) mo.observe(root.parentElement, {\r\n                                    attributes: true,\r\n                                    attributeFilter: ['style', 'class']\r\n                                });\r\n\r\n                                window.addEventListener('visibilitychange', () => {\r\n                                    if (!document.hidden) scheduleRebuild();\r\n                                }, {\r\n                                    passive: true\r\n                                });\r\n                            }\r\n\r\n                            \/* =========================================================\r\n                               18) Init\r\n                            ========================================================== *\/\r\n                            function init() {\r\n                                bindUI();\r\n                                initObservers();\r\n\r\n                                \/\/ Doble RAF para asegurar layout antes de medir\r\n                                requestAnimationFrame(() => requestAnimationFrame(scheduleRebuild));\r\n                                raf = requestAnimationFrame(tick);\r\n                            }\r\n\r\n                            window[KEY] = {\r\n                                destroy() {\r\n                                    try {\r\n                                        if (ro) ro.disconnect();\r\n                                    } catch (_) {}\r\n                                    try {\r\n                                        if (io) io.disconnect();\r\n                                    } catch (_) {}\r\n                                    try {\r\n                                        if (mo) mo.disconnect();\r\n                                    } catch (_) {}\r\n                                    try {\r\n                                        if (pending) cancelAnimationFrame(pending);\r\n                                    } catch (_) {}\r\n                                    try {\r\n                                        if (raf) cancelAnimationFrame(raf);\r\n                                    } catch (_) {}\r\n                                }\r\n                            };\r\n\r\n                            init();\r\n                        })();\r\n                    <\/script>\r\n                <\/div>\r\n            <\/div>\r\n        <\/div>\r\n\r\n    <\/section>\r\n<\/div>\r\n<style>\r\n    .cvxScope [data-cvx-root=\"routing\"] .cvxPanel {\r\n        overflow: visible;\r\n        \/* evita corte de elementos absolutos del overlay *\/\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"routing\"] .cvx-routing-stage {\r\n        position: relative;\r\n        width: 100%;\r\n    }\r\n<\/style>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-4b982c5 animated-fast elementor-section-height-min-height elementor-section-items-stretch elementor-hidden-desktop elementor-hidden-tablet elementor-section-boxed elementor-section-height-default elementor-invisible\" data-id=\"4b982c5\" data-element_type=\"section\" data-e-type=\"section\" data-settings=\"{&quot;animation&quot;:&quot;fadeInUp&quot;,&quot;animation_delay&quot;:200,&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-ae075a5\" data-id=\"ae075a5\" data-element_type=\"column\" data-e-type=\"column\" data-settings=\"{&quot;animation&quot;:&quot;none&quot;,&quot;animation_delay&quot;:0}\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-ede32be elementor-widget elementor-widget-html\" data-id=\"ede32be\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;none&quot;,&quot;_animation_delay&quot;:0}\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<section class=\"cvxScope\">\r\n\r\n  <!-- =========================================================\r\n       STARTER KIT (ACTUAL) \u2014 Scope: .cvxScope\r\n       ========================================================= -->\r\n  <style id=\"cvx-starter-kit\">\r\n\/* =========================================================\r\n   CubeVox Starter Kit\r\n   Scope: .cvxScope\r\n   Objetivo:\r\n   - Tokens unificados (glass, stroke, blur, sombras, tipograf\u00eda).\r\n   - Componentes reusables: Panel, Card, Pill\/Badge, Tip, Switch, Chip (segmented),\r\n     Accordion, Stage (imagen con overlay).\r\n   - Alta parametrizaci\u00f3n por CSS vars. Compatibilidad con widgets que ya usan\r\n     --accent\/--text\/--muted\/--glass\/--stroke (alias).\r\n========================================================= *\/\r\n\r\n.cvxScope{\r\n  \/* -------------------------\r\n     0) Aliases \/ Compat\r\n     - Si un widget define --accent, --text, etc, se \u201cmapea\u201d a tokens cvx.\r\n  -------------------------- *\/\r\n  --cvxAccent: var(--accent, #5AAAFF);\r\n  --cvxGlow:   var(--glow, rgba(90,170,255,.45));\r\n\r\n  --cvxText:   var(--text, rgba(255,255,255,.92));\r\n  --cvxMuted:  var(--muted, rgba(255,255,255,.70));\r\n\r\n  --cvxGlassBg:     var(--glass, rgba(14,18,24,.58));\r\n  --cvxGlassStroke: var(--stroke, rgba(255,255,255,.10));\r\n\r\n  \/* -------------------------\r\n     1) Material \/ Profundidad\r\n  -------------------------- *\/\r\n  --cvxBlur: 10px;\r\n\r\n  --cvxShadowLG: 0 22px 60px rgba(0,0,0,.55);\r\n  --cvxShadowMD: 0 18px 50px rgba(0,0,0,.45);\r\n  --cvxShadowSM: 0 14px 30px rgba(0,0,0,.60);\r\n\r\n  --cvxRadiusLG: 18px;\r\n  --cvxRadiusMD: 16px;\r\n  --cvxRadiusSM: 14px;\r\n\r\n  --cvxStrokeSoft: rgba(255,255,255,.09);\r\n  --cvxStrokeHard: rgba(255,255,255,.14);\r\n\r\n  \/* \u201cAccent wash\u201d (EQ look): iluminaci\u00f3n suave, no invasiva *\/\r\n  --cvxWashA: 22%;   \/* intensidad wash 1 *\/\r\n  --cvxWashB: 14%;   \/* intensidad wash 2 *\/\r\n  --cvxWashPos1X: 0%;\r\n  --cvxWashPos1Y: 0%;\r\n  --cvxWashPos2X: 100%;\r\n  --cvxWashPos2Y: 100%;\r\n\r\n  \/* -------------------------\r\n     2) Tipograf\u00eda (base)\r\n  -------------------------- *\/\r\n  --cvxFont: system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif;\r\n\r\n  \/* Weight \u201cEQ-like\u201d *\/\r\n  --cvxWHeavy: 950;\r\n  --cvxWBold:  850;\r\n  --cvxWMed:   650;\r\n\r\n  \/* -------------------------\r\n     3) Escala UI (routing usa --s; ac\u00e1 damos un alias)\r\n  -------------------------- *\/\r\n  --cvxS: var(--s, 1);\r\n}\r\n\r\n.cvxScope, .cvxScope *{ box-sizing:border-box; }\r\n.cvxScope{ font-family: var(--cvxFont); }\r\n\r\n\/* =========================================================\r\n   A) Base reset para botones dentro del scope\r\n========================================================= *\/\r\n.cvxScope button{\r\n  font: inherit;\r\n  color: inherit;\r\n  -webkit-appearance:none;\r\n  appearance:none;\r\n  -webkit-tap-highlight-color: transparent;\r\n}\r\n.cvxScope button:focus{ outline:none; }\r\n.cvxScope button:focus-visible{\r\n  outline: 2px solid color-mix(in srgb, var(--cvxAccent) 65%, transparent);\r\n  outline-offset: 2px;\r\n  border-radius: 14px;\r\n}\r\n\r\n\/* =========================================================\r\n   B) Panel (glass container)\r\n   Uso: class=\"cvxPanel\" (opcional: cvxPanel--off para apagar caja)\r\n========================================================= *\/\r\n.cvxScope .cvxPanel{\r\n  --cvxPanelPad: var(--pad-panel, 18px);\r\n  --cvxPanelGap: var(--gap-panel, 18px);\r\n\r\n  padding: var(--cvxPanelPad);\r\n  border-radius: var(--cvxRadiusLG);\r\n  background: var(--cvxGlassBg);\r\n  border: 1px solid var(--cvxGlassStroke);\r\n  box-shadow: var(--cvxShadowLG);\r\n\r\n  backdrop-filter: blur(var(--cvxBlur));\r\n  -webkit-backdrop-filter: blur(var(--cvxBlur));\r\n\r\n  overflow: hidden;\r\n}\r\n.cvxScope .cvxPanel.cvxPanel--off{\r\n  padding:0 !important;\r\n  background: transparent !important;\r\n  border:0 !important;\r\n  box-shadow:none !important;\r\n  backdrop-filter:none !important;\r\n  -webkit-backdrop-filter:none !important;\r\n}\r\n\r\n\/* =========================================================\r\n   C) Card (glass card \/ info)\r\n   Uso: class=\"cvxCard\"\r\n   Incluye wash EQ-style por defecto (parametrizable).\r\n========================================================= *\/\r\n.cvxScope .cvxCard{\r\n  --cvxCardPadY: 10px;\r\n  --cvxCardPadX: 12px;\r\n\r\n  position: relative;\r\n  border-radius: var(--cvxRadiusMD);\r\n  border: 1px solid var(--cvxStrokeHard);\r\n  background:\r\n    linear-gradient(180deg, rgba(255,255,255,.08), rgba(255,255,255,.02));\r\n  box-shadow:\r\n    0 calc(16px * var(--cvxS)) calc(34px * var(--cvxS)) rgba(0,0,0,.45),\r\n    inset 0 1px 0 rgba(255,255,255,.08);\r\n\r\n  backdrop-filter: blur(var(--cvxBlur));\r\n  -webkit-backdrop-filter: blur(var(--cvxBlur));\r\n\r\n  padding: calc(var(--cvxCardPadY) * var(--cvxS)) calc(var(--cvxCardPadX) * var(--cvxS));\r\n}\r\n.cvxScope .cvxCard::before{\r\n  content:\"\";\r\n  position:absolute; inset:0;\r\n  pointer-events:none;\r\n  border-radius: inherit;\r\n  background:\r\n    radial-gradient(120% 140% at var(--cvxWashPos1X) var(--cvxWashPos1Y),\r\n      color-mix(in srgb, var(--cvxAccent) var(--cvxWashA), transparent),\r\n      transparent 55%),\r\n    radial-gradient(120% 140% at var(--cvxWashPos2X) var(--cvxWashPos2Y),\r\n      color-mix(in srgb, var(--cvxAccent) var(--cvxWashB), transparent),\r\n      transparent 60%);\r\n  opacity: .85;\r\n}\r\n\r\n\/* =========================================================\r\n   D) Stage (imagen) con overlay\r\n   Uso: class=\"cvxStage\"\r\n   Variables: --cvxStageImg, --cvxStageAR, --cvxStageBgPos, --cvxStageOverlayAlpha\r\n========================================================= *\/\r\n.cvxScope .cvxStage{\r\n  --cvxStageAR: var(--stage-ar, 17 \/ 8);\r\n  --cvxStageImg: var(--stage-img, none);\r\n  --cvxStageBgPos: var(--stage-bg-pos, 50% 25%);\r\n  --cvxStageRadius: var(--stage-radius, 16px);\r\n  --cvxStageOverlayAlpha: var(--stage-overlay-alpha, .12);\r\n\r\n  position: relative;\r\n  aspect-ratio: var(--cvxStageAR);\r\n  width: 100%;\r\n\r\n  border-radius: var(--cvxStageRadius);\r\n  border: 1px solid rgba(255,255,255,.10);\r\n  overflow: hidden;\r\n\r\n  background-image: var(--cvxStageImg);\r\n  background-size: cover;\r\n  background-position: var(--cvxStageBgPos);\r\n\r\n  box-shadow: var(--cvxShadowMD);\r\n}\r\n.cvxScope .cvxStage::after{\r\n  content:\"\";\r\n  position:absolute; inset:0;\r\n  pointer-events:none;\r\n  opacity: var(--cvxStageOverlayAlpha);\r\n  background:\r\n    radial-gradient(120% 120% at 50% 30%,\r\n      rgba(0,0,0,.10),\r\n      rgba(0,0,0,.55) 70%,\r\n      rgba(0,0,0,.75));\r\n}\r\n\r\n\/* =========================================================\r\n   E) Badge + Pill (Routing nodes \/ tags)\r\n========================================================= *\/\r\n.cvxScope .cvxBadge{\r\n  --cvxBadgeFs: calc(10px * var(--cvxS));\r\n  display:inline-flex;\r\n  align-items:center;\r\n  gap: 6px;\r\n  font-size: var(--cvxBadgeFs);\r\n  padding: calc(2px * var(--cvxS)) calc(7px * var(--cvxS));\r\n  border-radius: 999px;\r\n  background: color-mix(in srgb, var(--cvxAccent) 10%, transparent);\r\n  border: 1px solid color-mix(in srgb, var(--cvxAccent) 22%, transparent);\r\n  color: rgba(255,255,255,.94);\r\n  font-weight: var(--cvxWHeavy);\r\n  letter-spacing:.35px;\r\n}\r\n\r\n.cvxScope .cvxPill{\r\n  --cvxPillBg: rgba(27, 51, 77, 0.52);\r\n  --cvxPillFs: calc(12px * var(--cvxS));\r\n  --cvxPillPadY: calc(7px * var(--cvxS));\r\n  --cvxPillPadX: calc(10px * var(--cvxS));\r\n\r\n  display:inline-flex;\r\n  align-items:center;\r\n  gap: calc(8px * var(--cvxS));\r\n  padding: var(--cvxPillPadY) var(--cvxPillPadX);\r\n  border-radius: 999px;\r\n  background: var(--cvxPillBg);\r\n  border: 1px solid rgba(255,255,255,.14);\r\n\r\n  color: var(--cvxText);\r\n  font-size: var(--cvxPillFs);\r\n  font-weight: var(--cvxWBold);\r\n  letter-spacing:.25px;\r\n  white-space: nowrap;\r\n\r\n  text-shadow: 0 calc(10px * var(--cvxS)) calc(26px * var(--cvxS)) rgba(0,0,0,.45);\r\n\r\n  backdrop-filter: blur(var(--cvxBlur));\r\n  -webkit-backdrop-filter: blur(var(--cvxBlur));\r\n}\r\n\r\n\/* =========================================================\r\n   F) Tip banner (Routing tip)\r\n========================================================= *\/\r\n.cvxScope .cvxTip{\r\n  --cvxTipBg: rgba(10, 14, 18, 0.52);\r\n  --cvxTipBr: rgba(255,255,255,0.10);\r\n  --cvxTipShadow: 0 14px 26px rgba(0,0,0,.38), inset 0 1px 0 rgba(255,255,255,.06);\r\n\r\n  --cvxTipFs: calc(var(--tip-font-size, 13px) * var(--cvxS));\r\n  --cvxTipPadY: calc(var(--tip-pad-y, 10px) * var(--cvxS));\r\n  --cvxTipPadX: calc(var(--tip-pad-x, 14px) * var(--cvxS));\r\n  --cvxTipGap:  calc(var(--tip-gap, 10px) * var(--cvxS));\r\n  --cvxTipDot:  calc(var(--tip-dot-size, 10px) * var(--cvxS));\r\n\r\n  display:flex;\r\n  align-items:center;\r\n  gap: var(--cvxTipGap);\r\n  padding: var(--cvxTipPadY) var(--cvxTipPadX);\r\n  border-radius: 999px;\r\n\r\n  background: var(--cvxTipBg);\r\n  border: 1px solid var(--cvxTipBr);\r\n  box-shadow: var(--cvxTipShadow);\r\n\r\n  backdrop-filter: blur(var(--cvxBlur));\r\n  -webkit-backdrop-filter: blur(var(--cvxBlur));\r\n\r\n  white-space: nowrap;\r\n}\r\n.cvxScope .cvxTip__dot{\r\n  width: var(--cvxTipDot);\r\n  height: var(--cvxTipDot);\r\n  border-radius: 999px;\r\n  background: var(--cvxAccent);\r\n  box-shadow: 0 0 calc(16px * var(--cvxS)) var(--cvxGlow);\r\n  flex: 0 0 auto;\r\n}\r\n.cvxScope .cvxTip__label{\r\n  font-size: var(--cvxTipFs);\r\n  font-weight: var(--tip-label-w, 700);\r\n  color: rgba(255,255,255,.88);\r\n  letter-spacing: var(--tip-letter, .10px);\r\n  line-height: 1;\r\n}\r\n.cvxScope .cvxTip__text{\r\n  font-size: var(--cvxTipFs);\r\n  font-weight: var(--tip-text-w, 450);\r\n  color: rgba(255,255,255,.70);\r\n  line-height: 1;\r\n}\r\n\r\n\/* =========================================================\r\n   G) Switch \/ UI group (AUX\/DIG y EXP)\r\n========================================================= *\/\r\n.cvxScope .cvxSwitch{\r\n  --cvxSwitchPad:  calc(6px * var(--cvxS));\r\n  --cvxSwitchGap:  calc(6px * var(--cvxS));\r\n  --cvxSwitchRad:  calc(14px * var(--cvxS));\r\n  --cvxSwitchBtnRad: calc(11px * var(--cvxS));\r\n  --cvxSwitchFs:   calc(11px * var(--cvxS));\r\n\r\n  display:flex;\r\n  gap: var(--cvxSwitchGap);\r\n  padding: var(--cvxSwitchPad);\r\n  border-radius: var(--cvxSwitchRad);\r\n\r\n  background: rgba(255,255,255,.04);\r\n  border: 1px solid rgba(255,255,255,.10);\r\n  box-shadow:\r\n    0 calc(14px * var(--cvxS)) calc(28px * var(--cvxS)) rgba(0,0,0,.35),\r\n    inset 0 1px 0 rgba(255,255,255,.06);\r\n\r\n  backdrop-filter: blur(var(--cvxBlur));\r\n  -webkit-backdrop-filter: blur(var(--cvxBlur));\r\n\r\n  user-select:none;\r\n}\r\n.cvxScope .cvxSwitch > button{\r\n  all: unset;\r\n  cursor:pointer;\r\n  user-select:none;\r\n  flex: 1;\r\n  text-align:center;\r\n\r\n  font-size: var(--cvxSwitchFs);\r\n  font-weight: var(--cvxWHeavy);\r\n  padding: calc(7px * var(--cvxS)) calc(10px * var(--cvxS));\r\n  border-radius: var(--cvxSwitchBtnRad);\r\n\r\n  color: rgba(255,255,255,.78);\r\n  border: 1px solid rgba(255,255,255,.10);\r\n  background: rgba(255,255,255,.02);\r\n  letter-spacing:.25px;\r\n}\r\n.cvxScope .cvxSwitch > button.on{\r\n  color: rgba(255,255,255,.94);\r\n  border-color: color-mix(in srgb, var(--cvxAccent) 30%, transparent);\r\n  background: linear-gradient(180deg,\r\n    color-mix(in srgb, var(--cvxAccent) 18%, transparent),\r\n    color-mix(in srgb, var(--cvxAccent)  6%, transparent));\r\n  box-shadow: 0 0 0 1px color-mix(in srgb, var(--cvxAccent) 10%, transparent) inset;\r\n}\r\n\r\n\/* grid variant (expMap) *\/\r\n.cvxScope .cvxSwitch.cvxSwitch--grid{\r\n  display:grid;\r\n  grid-template-columns: repeat(2, 1fr);\r\n  gap: calc(6px * var(--cvxS));\r\n  padding: 0;\r\n  border: none;\r\n  background: transparent;\r\n  box-shadow: none;\r\n  backdrop-filter:none;\r\n  -webkit-backdrop-filter:none;\r\n}\r\n\r\n\/* chip inside expMap (si quer\u00e9s mantener markup actual) *\/\r\n.cvxScope .cvxMiniChip{\r\n  all: unset;\r\n  cursor:pointer;\r\n  user-select:none;\r\n  display:flex;\r\n  align-items:center;\r\n  justify-content:space-between;\r\n  gap: calc(8px * var(--cvxS));\r\n\r\n  padding: calc(8px * var(--cvxS)) calc(10px * var(--cvxS));\r\n  border-radius: calc(12px * var(--cvxS));\r\n\r\n  font-size: calc(11px * var(--cvxS));\r\n  font-weight: var(--cvxWHeavy);\r\n  color: rgba(255,255,255,.84);\r\n\r\n  border: 1px solid rgba(255,255,255,.10);\r\n  background: rgba(255,255,255,.02);\r\n  letter-spacing:.25px;\r\n}\r\n.cvxScope .cvxMiniChip.on{\r\n  color: rgba(255,255,255,.94);\r\n  border-color: color-mix(in srgb, var(--cvxAccent) 30%, transparent);\r\n  background: linear-gradient(180deg,\r\n    color-mix(in srgb, var(--cvxAccent) 16%, transparent),\r\n    color-mix(in srgb, var(--cvxAccent)  5%, transparent));\r\n  box-shadow: 0 0 0 1px color-mix(in srgb, var(--cvxAccent) 10%, transparent) inset;\r\n}\r\n.cvxScope .cvxMiniChip .k{ opacity:.85; }\r\n.cvxScope .cvxMiniChip .v{\r\n  opacity:.95;\r\n  padding: calc(2px * var(--cvxS)) calc(8px * var(--cvxS));\r\n  border-radius: 999px;\r\n  border: 1px solid rgba(255,255,255,.10);\r\n  background: rgba(0,0,0,.18);\r\n}\r\n.cvxScope .cvxMiniChip.on .v{\r\n  border-color: color-mix(in srgb, var(--cvxAccent) 28%, transparent);\r\n  background: color-mix(in srgb, var(--cvxAccent) 10%, rgba(0,0,0,.18));\r\n}\r\n\r\n\/* =========================================================\r\n   H) Chip (EQ segmented) \u2014 reusado tal cual tu markup\r\n========================================================= *\/\r\n.cvxScope .cvxChip{\r\n  --cvxChipAccent: var(--accent, var(--cvxAccent));\r\n\r\n  --cvxChipTop: rgba(255,255,255,.065);\r\n  --cvxChipMid: rgba(0,0,0,.33);\r\n  --cvxChipBot: rgba(0,0,0,.18);\r\n\r\n  --cvxChipBdBase: color-mix(in srgb, var(--cvxChipAccent) 16%, rgba(255,255,255,.14));\r\n  --cvxChipBdInner: rgba(255,255,255,.06);\r\n  --cvxChipShadowOut: rgba(0,0,0,.60);\r\n\r\n  --cvxChipRadius: var(--chip-radius, 12px);\r\n  --cvxChipGapIn:  var(--chip-gap-in, 5px);\r\n  --cvxChipPadT:   var(--chip-pad-t, 6px);\r\n  --cvxChipPadX:   var(--chip-pad-x, 10px);\r\n  --cvxChipPadB:   var(--chip-pad-b, 10px);\r\n\r\n  --cvxChipLineInset: var(--chip-line-inset-x, 10px);\r\n  --cvxChipLineBottom:var(--chip-line-bottom, 5px);\r\n  --cvxChipLineH:     var(--chip-lineHeight, 2px);\r\n  --cvxChipLineBlur:  var(--chip-lineBlur, 10px);\r\n  --cvxChipLineOp:    var(--chip-lineOpacity, .30);\r\n\r\n  display:inline-flex;\r\n  align-items:center;\r\n  justify-content: space-between;\r\n  gap: var(--cvxChipGapIn);\r\n  padding: var(--cvxChipPadT) var(--cvxChipPadX) var(--cvxChipPadB);\r\n\r\n  border-radius: var(--cvxChipRadius);\r\n  border: 1px solid var(--cvxChipBdBase);\r\n\r\n  background:\r\n    linear-gradient(180deg, var(--cvxChipTop), rgba(255,255,255,0) 38%),\r\n    linear-gradient(180deg, var(--cvxChipMid), var(--cvxChipBot));\r\n\r\n  box-shadow:\r\n    0 14px 30px var(--cvxChipShadowOut),\r\n    inset 0 1px 0 rgba(255,255,255,.08),\r\n    inset 0 -1px 0 rgba(0,0,0,.55),\r\n    inset 0 0 0 1px var(--cvxChipBdInner);\r\n\r\n  position: relative;\r\n  line-height:1;\r\n  cursor:pointer;\r\n  user-select:none;\r\n\r\n  transition: transform .15s ease, border-color .15s ease, box-shadow .15s ease, background .15s ease;\r\n}\r\n.cvxScope .cvxChip::after{\r\n  content:\"\";\r\n  position:absolute;\r\n  left: var(--cvxChipLineInset);\r\n  right: var(--cvxChipLineInset);\r\n  bottom: var(--cvxChipLineBottom);\r\n  height: var(--cvxChipLineH);\r\n  border-radius: 999px;\r\n  background: color-mix(in srgb, var(--cvxChipAccent) 88%, transparent);\r\n  box-shadow: 0 0 var(--cvxChipLineBlur) color-mix(in srgb, var(--cvxChipAccent) 28%, transparent);\r\n  opacity: var(--cvxChipLineOp);\r\n  transition: opacity .15s ease, box-shadow .15s ease, transform .15s ease;\r\n}\r\n.cvxScope .cvxChip:hover{\r\n  transform: translateY(-1px);\r\n  border-color: color-mix(in srgb, var(--cvxChipAccent) 58%, rgba(255,255,255,.16));\r\n  background:\r\n    linear-gradient(180deg, color-mix(in srgb, var(--cvxChipAccent) 6%, transparent), rgba(255,255,255,0) 42%),\r\n    linear-gradient(180deg, var(--cvxChipMid), var(--cvxChipBot));\r\n  box-shadow:\r\n    0 16px 34px rgba(0,0,0,.65),\r\n    0 0 0 2px color-mix(in srgb, var(--cvxChipAccent) 12%, transparent),\r\n    inset 0 1px 0 rgba(255,255,255,.08),\r\n    inset 0 -1px 0 rgba(0,0,0,.55),\r\n    inset 0 0 0 1px rgba(255,255,255,.07);\r\n  --cvxChipLineOp: .40;\r\n}\r\n.cvxScope .cvxChip.is-active{\r\n  border-color: color-mix(in srgb, var(--cvxChipAccent) 78%, rgba(255,255,255,.16));\r\n  background:\r\n    linear-gradient(180deg, color-mix(in srgb, var(--cvxChipAccent) 12%, transparent), rgba(255,255,255,0) 44%),\r\n    linear-gradient(180deg, rgba(0,0,0,.32), rgba(0,0,0,.16));\r\n  box-shadow:\r\n    0 18px 40px rgba(0,0,0,.68),\r\n    0 0 0 2px color-mix(in srgb, var(--cvxChipAccent) 22%, transparent),\r\n    inset 0 1px 0 rgba(255,255,255,.09),\r\n    inset 0 -1px 0 rgba(0,0,0,.55),\r\n    inset 0 0 0 1px color-mix(in srgb, var(--cvxChipAccent) 16%, rgba(255,255,255,.06));\r\n  --cvxChipLineOp: .98;\r\n  --cvxChipLineBlur: 14px;\r\n}\r\n\r\n.cvxScope .cvxChip__label{\r\n  font-weight: 900;\r\n  font-size: var(--fs-chip-label, 10px);\r\n  letter-spacing: var(--chip-label-ls, .1em);\r\n  color: rgba(255,255,255,.72);\r\n  white-space: nowrap;\r\n}\r\n.cvxScope .cvxChip.is-active .cvxChip__label{ color: rgba(255,255,255,.92); }\r\n\r\n.cvxScope .cvxChip__seg{\r\n  display:inline-flex;\r\n  overflow:hidden;\r\n  border-radius: var(--chip-seg-radius, 999px);\r\n  border: 1px solid rgba(255,255,255,.14);\r\n  background: rgba(0,0,0,.18);\r\n  box-shadow: inset 0 1px 0 rgba(255,255,255,.06), inset 0 -1px 0 rgba(0,0,0,.45);\r\n}\r\n.cvxScope .cvxChip__segBtn{\r\n  padding: var(--chip-seg-pad-y, 4px) var(--chip-seg-pad-x, 6px);\r\n  font-weight: 900;\r\n  font-size: var(--fs-chip-seg, 8px);\r\n  letter-spacing: var(--chip-seg-ls, .10em);\r\n  color: rgba(255,255,255,.86);\r\n  border: 0;\r\n  background: transparent;\r\n  user-select:none;\r\n}\r\n.cvxScope .cvxChip__segBtn.is-on{\r\n  background: color-mix(in srgb, var(--cvxChipAccent) 18%, rgba(0,0,0,.22));\r\n  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--cvxChipAccent) 12%, transparent);\r\n}\r\n.cvxScope .cvxChip.is-active .cvxChip__segBtn.is-on{\r\n  background: color-mix(in srgb, var(--cvxChipAccent) 28%, rgba(0,0,0,.22));\r\n  box-shadow:\r\n    inset 0 0 0 1px color-mix(in srgb, var(--cvxChipAccent) 20%, transparent),\r\n    0 0 14px color-mix(in srgb, var(--cvxChipAccent) 14%, transparent);\r\n}\r\n\r\n\/* =========================================================\r\n   I) Accordion (EQ-like)\r\n========================================================= *\/\r\n.cvxScope .cvxAcc{\r\n  border-radius: var(--cvxRadiusMD);\r\n  border: 1px solid rgba(255,255,255,.09);\r\n  background: rgba(0,0,0,.20);\r\n  overflow:hidden;\r\n}\r\n.cvxScope .cvxAcc__item{ border-top: 1px solid rgba(255,255,255,.07); }\r\n.cvxScope .cvxAcc__item:first-child{ border-top:0; }\r\n\r\n.cvxScope .cvxAcc__btn{\r\n  width:100%;\r\n  background: transparent;\r\n  border:0;\r\n  padding: var(--acc-pad-y, 12px) var(--acc-pad-x, 12px);\r\n  display:flex;\r\n  align-items:center;\r\n  justify-content: space-between;\r\n  gap: 10px;\r\n  cursor:pointer;\r\n  transition: background .15s ease;\r\n}\r\n.cvxScope .cvxAcc__btn:hover{ background: rgba(255,255,255,.03); }\r\n\r\n.cvxScope .cvxAcc__title{\r\n  color: rgba(255,255,255,.90);\r\n  font-weight: var(--cvxWMed);\r\n  font-size: var(--fs-acc-title, 13px);\r\n}\r\n.cvxScope .cvxAcc__icon{\r\n  width: 22px; height: 22px;\r\n  border-radius: 999px;\r\n  border: 1px solid rgba(255,255,255,.10);\r\n  background: rgba(0,0,0,.20);\r\n  display:flex;\r\n  align-items:center;\r\n  justify-content:center;\r\n  flex: 0 0 22px;\r\n}\r\n.cvxScope .cvxAcc__icon::before{\r\n  content:\"+\";\r\n  font-weight: 900;\r\n  color: rgba(255,255,255,.60);\r\n  line-height: 1;\r\n  transform: translateY(var(--acc-icon-shift-y, -.5px));\r\n}\r\n.cvxScope .cvxAcc__item.is-open .cvxAcc__icon::before{\r\n  content:\"\u2013\";\r\n  color: rgba(255,255,255,.80);\r\n}\r\n.cvxScope .cvxAcc__body{\r\n  display:none;\r\n  padding: 0 var(--acc-pad-x, 12px) var(--acc-pad-y, 12px);\r\n  color: rgba(255,255,255,.68);\r\n  font-size: var(--fs-acc-body, 12px);\r\n  line-height: 1.45;\r\n}\r\n.cvxScope .cvxAcc__item.is-open .cvxAcc__body{ display:block; }\r\n\r\n\/* =========================================================\r\n   J) Icon Card (icon + title + subtitle)\r\n========================================================= *\/\r\n.cvxScope .cvxIconCards{\r\n  display: grid;\r\n  gap: calc(10px * var(--cvxS));\r\n}\r\n\r\n.cvxScope .cvxIconCard{\r\n  --icPadY: calc(12px * var(--cvxS));\r\n  --icPadX: calc(14px * var(--cvxS));\r\n  --icGap:  calc(12px * var(--cvxS));\r\n\r\n  display: flex;\r\n  align-items: flex-start;\r\n  gap: var(--icGap);\r\n\r\n  padding: var(--icPadY) var(--icPadX);\r\n  border-radius: var(--cvxRadiusMD);\r\n\r\n  background: linear-gradient(180deg, rgba(255,255,255,.08), rgba(255,255,255,.02));\r\n  border: 1px solid rgba(255,255,255,.12);\r\n  box-shadow: 0 10px 22px rgba(0,0,0,.35), inset 0 1px 0 rgba(255,255,255,.08);\r\n\r\n  backdrop-filter: blur(var(--cvxBlur));\r\n  -webkit-backdrop-filter: blur(var(--cvxBlur));\r\n\r\n  transition: transform .18s ease, border-color .18s ease, box-shadow .18s ease, background .18s ease;\r\n}\r\n\r\n.cvxScope .cvxIconCard:hover{\r\n  transform: translateY(-1px);\r\n  border-color: color-mix(in srgb, var(--cvxAccent) 22%, rgba(255,255,255,.12));\r\n  box-shadow: 0 14px 28px rgba(0,0,0,.40), inset 0 1px 0 rgba(255,255,255,.10);\r\n}\r\n\r\n\/* Icon container *\/\r\n.cvxScope .cvxIconCard__icon{\r\n  --icSize: calc(36px * var(--cvxS));\r\n\r\n  width: var(--icSize);\r\n  height: var(--icSize);\r\n  flex: 0 0 var(--icSize);\r\n\r\n  border-radius: calc(12px * var(--cvxS));\r\n  display: flex;\r\n  align-items: center;\r\n  justify-content: center;\r\n\r\n  background: radial-gradient(circle at 30% 30%,\r\n    color-mix(in srgb, var(--cvxAccent) 34%, transparent),\r\n    color-mix(in srgb, var(--cvxAccent) 12%, transparent) 55%,\r\n    rgba(255,255,255,.03));\r\n\r\n  border: 1px solid color-mix(in srgb, var(--cvxAccent) 18%, rgba(255,255,255,.12));\r\n  box-shadow: 0 8px 18px rgba(30,90,200,.18);\r\n  overflow: hidden;\r\n}\r\n\r\n\/* IMG control *\/\r\n.cvxScope .cvxIconCard__icon img{\r\n  width: calc(22px * var(--cvxS));\r\n  height: calc(22px * var(--cvxS));\r\n  display: block;\r\n  object-fit: contain;\r\n  opacity: .95;\r\n  filter: drop-shadow(0 2px 6px color-mix(in srgb, var(--cvxAccent) 35%, transparent));\r\n}\r\n\r\n.cvxScope .cvxIconCard__txt{ min-width: 0; }\r\n\r\n.cvxScope .cvxIconCard__title{\r\n  color: rgba(255,255,255,.94);\r\n  font-weight: var(--cvxWBold);\r\n  font-size: calc(15px * var(--cvxS));\r\n  letter-spacing: .15px;\r\n  line-height: 1.15;\r\n}\r\n\r\n.cvxScope .cvxIconCard__sub{\r\n  margin-top: calc(4px * var(--cvxS));\r\n  color: rgba(255,255,255,.74);\r\n  font-weight: 450;\r\n  font-size: calc(12px * var(--cvxS));\r\n  line-height: 1.35;\r\n}\r\n\r\n\/* =========================================================\r\n   K) Icon Cards \u2014 Mobile strip (solo iconos en 1 fila)\r\n========================================================= *\/\r\n@media (max-width: 767px){\r\n\r\n  .cvxScope .cvxIconCards.cvxIconCards--mobStrip{\r\n    display:flex;\r\n    align-items:center;\r\n    justify-content:space-evenly;\r\n    gap: calc(10px * var(--cvxS));\r\n\r\n    padding: calc(14px * var(--cvxS));\r\n    border-radius: var(--cvxRadiusLG);\r\n\r\n    background: linear-gradient(180deg, rgba(255,255,255,.07), rgba(255,255,255,.025));\r\n    border: 1px solid rgba(255,255,255,.12);\r\n    box-shadow: 0 10px 22px rgba(0,0,0,.35), inset 0 1px 0 rgba(255,255,255,.08);\r\n\r\n    backdrop-filter: blur(var(--cvxBlur));\r\n    -webkit-backdrop-filter: blur(var(--cvxBlur));\r\n  }\r\n\r\n  .cvxScope .cvxIconCards.cvxIconCards--mobStrip .cvxIconCard{\r\n    padding: 0;\r\n    background: transparent;\r\n    border: 0;\r\n    box-shadow: none;\r\n    backdrop-filter: none;\r\n    -webkit-backdrop-filter: none;\r\n\r\n    transform: none;\r\n    align-items:center;\r\n  }\r\n  .cvxScope .cvxIconCards.cvxIconCards--mobStrip .cvxIconCard:hover{\r\n    transform:none;\r\n    border-color: transparent;\r\n    box-shadow:none;\r\n  }\r\n\r\n  .cvxScope .cvxIconCards.cvxIconCards--mobStrip .cvxIconCard__txt{ display:none; }\r\n\r\n  .cvxScope .cvxIconCards.cvxIconCards--mobStrip .cvxIconCard__icon{\r\n    --icSize: calc(44px * var(--cvxS));\r\n  }\r\n  .cvxScope .cvxIconCards.cvxIconCards--mobStrip .cvxIconCard__icon img{\r\n    width: calc(28px * var(--cvxS));\r\n    height: calc(28px * var(--cvxS));\r\n  }\r\n}\r\n  <\/style>\r\n\r\n  <!-- =========================================================\r\n       ROUTING \u2014 Mobile Only (layout + par\u00e1metros reales)\r\n       ========================================================= -->\r\n  <style>\r\n    \/* (Opcional) ocultar en desktop *\/\r\n     @media (min-width: 767px){ .cvxScope .cvxRM{ display:none !important; } } \r\n\r\n    .cvxScope .cvxRM{\r\n      \/* --- Escala (JS setea --s en ESTE root) --- *\/\r\n      --ui-base: 420;\r\n      --ui-min: .72;\r\n      --ui-max: 1.00;\r\n\r\n      \/* --- Spacing (conecta con el kit) --- *\/\r\n      --rm-pad: 22px;\r\n      --rm-gap: 14px;\r\n      --pad-panel: calc(var(--rm-pad) * var(--cvxS));\r\n      --gap-panel: calc(var(--rm-gap) * var(--cvxS));\r\n\r\n      \/* --- Tokens del kit (overrides locales, visibles) --- *\/\r\n      --rm-blur: 10px;\r\n      --rm-wash-a: 22%;\r\n      --rm-wash-b: 14%;\r\n\r\n      --rm-radius-panel: 18px;\r\n      --rm-radius-card: 16px;\r\n      --rm-radius-stage: 16px;\r\n\r\n      --rm-card-pad-x: 12px;\r\n      --rm-card-pad-y: 10px;\r\n\r\n      \/* --- Tipograf\u00eda local (solo para kicker\/title\/desc) --- *\/\r\n      --rm-kicker-fs: 12px;\r\n      --rm-kicker-ls: .18em;\r\n\r\n      --rm-title-fs: 28px;\r\n      --rm-title-lh: 1.10;\r\n\r\n      --rm-desc-fs: 14px;\r\n      --rm-desc-lh: 1.45;\r\n\r\n      \/* --- Stage --- *\/\r\n      --rm-stage-ar: 16 \/ 9;\r\n      --rm-stage-bg-pos: 50% 25%;\r\n      --rm-stage-overlay: .12;\r\n      --rm-stage-mb: 14px;\r\n\r\n      \/* --- KPI grid \/ cards --- *\/\r\n      --rm-kpi-cols-lg: 2;\r\n      --rm-kpi-cols-xs: 1;\r\n      --rm-kpi-gap: 12px;\r\n      --rm-kpi-pad: 14px;\r\n\r\n      --rm-kpi-num-fs: 34px;\r\n      --rm-kpi-unit-fs: 12px;\r\n      --rm-kpi-text-fs: 13px;\r\n\r\n      \/* --- Nota --- *\/\r\n      --rm-note-fs: 12px;\r\n\r\n      \/* --- Imagen stage --- *\/\r\n      --rm-hero: url('\/wp-content\/uploads\/2026\/01\/ROUTING_MOBILE_PLACEHOLDER.jpg');\r\n\r\n      \/* --- CR\u00cdTICO: hacer que el kit escale en este sub\u00e1rbol --- *\/\r\n      --cvxS: var(--s, 1);\r\n\r\n      \/* --- Aplicar overrides del kit --- *\/\r\n      --cvxBlur: var(--rm-blur);\r\n      --cvxWashA: var(--rm-wash-a);\r\n      --cvxWashB: var(--rm-wash-b);\r\n\r\n      --cvxRadiusLG: var(--rm-radius-panel);\r\n      --cvxRadiusMD: var(--rm-radius-card);\r\n    }\r\n\r\n    \/* Evitar que min-content rompa el grid *\/\r\n    .cvxScope .cvxRM,\r\n    .cvxScope .cvxRM *{ min-width: 0; }\r\n\r\n    .cvxScope .cvxRM{\r\n      display: grid;\r\n      gap: var(--gap-panel);\r\n    }\r\n\r\n    \/* Reparametrizar padding del Card del kit *\/\r\n    .cvxScope .cvxRM .cvxCard{\r\n      --cvxCardPadX: var(--rm-card-pad-x);\r\n      --cvxCardPadY: var(--rm-card-pad-y);\r\n    }\r\n\r\n    \/* Kicker \/ Title \/ Desc (mismo dise\u00f1o, sin inventar \u201cotro kit\u201d) *\/\r\n    .cvxScope .cvxRM b,\r\n    .cvxScope .cvxRM strong{ font-weight: var(--cvxWBold); }\r\n\r\n    .cvxScope .cvxRM__kicker{\r\n      font-size: calc(var(--rm-kicker-fs) * var(--cvxS));\r\n      letter-spacing: var(--rm-kicker-ls);\r\n      text-transform: uppercase;\r\n      opacity: .72;\r\n      margin: 0 0 calc(8px * var(--cvxS));\r\n    }\r\n    .cvxScope .cvxRM__title{\r\n      font-size: calc(var(--rm-title-fs) * var(--cvxS));\r\n      line-height: var(--rm-title-lh);\r\n      font-weight: var(--cvxWBold);\r\n      margin: 0 0 calc(10px * var(--cvxS));\r\n    }\r\n    .cvxScope .cvxRM__desc{\r\n      font-size: calc(var(--rm-desc-fs) * var(--cvxS));\r\n      line-height: var(--rm-desc-lh);\r\n      opacity: .86;\r\n      margin: 0;\r\n    }\r\n\r\n    .cvxScope .cvxRM__pills{\r\n      display:flex;\r\n      flex-wrap: wrap;\r\n      gap: calc(10px * var(--cvxS));\r\n      margin-top: calc(14px * var(--cvxS));\r\n    }\r\n\r\n    \/* Stage (componente real del kit) *\/\r\n    .cvxScope .cvxRM__stage{\r\n      --stage-ar: var(--rm-stage-ar);\r\n      --stage-img: var(--rm-hero);\r\n      --stage-bg-pos: var(--rm-stage-bg-pos);\r\n      --stage-overlay-alpha: var(--rm-stage-overlay);\r\n      --stage-radius: var(--rm-radius-stage);\r\n\r\n      margin-bottom: calc(var(--rm-stage-mb) * var(--cvxS));\r\n    }\r\n\r\n    \/* Asegurar que el hint est\u00e9 arriba del overlay *\/\r\n    .cvxScope .cvxRM__stage::after{ z-index: 0; }\r\n    .cvxScope .cvxRM__stageHint{\r\n      position:absolute;\r\n      left: calc(14px * var(--cvxS));\r\n      bottom: calc(14px * var(--cvxS));\r\n      display:flex;\r\n      flex-wrap: wrap;\r\n      gap: calc(8px * var(--cvxS));\r\n      max-width: calc(100% - (28px * var(--cvxS)));\r\n      z-index: 1;\r\n    }\r\n\r\n    \/* KPI grid \u2014 FIX overflow: minmax(0,1fr) *\/\r\n    .cvxScope .cvxRM{ --rm-kpi-cols: var(--rm-kpi-cols-lg); }\r\n    @media (max-width: 360px){\r\n      .cvxScope .cvxRM{ --rm-kpi-cols: var(--rm-kpi-cols-xs); }\r\n    }\r\n    .cvxScope .cvxRM__kpiGrid{\r\n      display:grid;\r\n      grid-template-columns: repeat(var(--rm-kpi-cols), minmax(0, 1fr));\r\n      gap: calc(var(--rm-kpi-gap) * var(--cvxS));\r\n    }\r\n    .cvxScope .cvxRM__kpi{\r\n      padding: calc(var(--rm-kpi-pad) * var(--cvxS));\r\n    }\r\n    .cvxScope .cvxRM__kpiTop{\r\n      display:flex;\r\n      align-items: baseline;\r\n      gap: calc(8px * var(--cvxS));\r\n      margin-bottom: calc(6px * var(--cvxS));\r\n    }\r\n    .cvxScope .cvxRM__kpiNum{\r\n      font-size: calc(var(--rm-kpi-num-fs) * var(--cvxS));\r\n      font-weight: var(--cvxWBold);\r\n      line-height: 1;\r\n      letter-spacing: -.02em;\r\n    }\r\n    .cvxScope .cvxRM__kpiUnit{\r\n      font-size: calc(var(--rm-kpi-unit-fs) * var(--cvxS));\r\n      letter-spacing: .12em;\r\n      text-transform: uppercase;\r\n      opacity: .75;\r\n      white-space: nowrap;\r\n    }\r\n    .cvxScope .cvxRM__kpiTitle{\r\n      font-weight: var(--cvxWBold);\r\n      margin-bottom: calc(6px * var(--cvxS));\r\n    }\r\n    .cvxScope .cvxRM__kpiText{\r\n      margin: 0;\r\n      opacity: .82;\r\n      font-size: calc(var(--rm-kpi-text-fs) * var(--cvxS));\r\n      line-height: 1.42;\r\n      overflow-wrap: anywhere; \/* evita desborde por palabras largas *\/\r\n    }\r\n\r\n    .cvxScope .cvxRM__iconStrip{\r\n      margin-top: calc(2px * var(--cvxS));\r\n    }\r\n\r\n    .cvxScope .cvxRM__acc .cvxAcc__body{\r\n      font-size: calc(13px * var(--cvxS));\r\n      line-height: 1.45;\r\n      opacity: .88;\r\n    }\r\n    .cvxScope .cvxRM__list{\r\n      margin: 0;\r\n      padding-left: 1.1em;\r\n    }\r\n\r\n    .cvxScope .cvxRM__note{\r\n      font-size: calc(var(--rm-note-fs) * var(--cvxS));\r\n    }\r\n  <\/style>\r\n\r\n  <!-- =========================================================\r\n       MARKUP\r\n       ========================================================= -->\r\n  <div\r\n    class=\"cvxPanel cvxRM\"\r\n    data-cvx-root=\"routingMobile\"\r\n    style=\"\r\n      --ui-base: 420;\r\n      --ui-min: .72;\r\n      --ui-max: 1;\r\n\r\n      --rm-pad: 22px;\r\n      --rm-gap: 14px;\r\n\r\n      --rm-title-fs: 28px;\r\n      --rm-desc-fs: 14px;\r\n\r\n      --rm-stage-ar: 16 \/ 9;\r\n      --rm-stage-bg-pos: 50% 25%;\r\n      --rm-stage-overlay: .12;\r\n\r\n      --rm-kpi-cols-lg: 2;\r\n      --rm-kpi-cols-xs: 1;\r\n\r\n      --rm-hero: url('https:\/\/cube-vox.com\/wp-content\/uploads\/cubevox-hifi-open-closeup-trs.webp');\r\n    \"\r\n  >\r\n    <header>\r\n      <div class=\"cvxRM__kicker\">ROUTING<\/div>\r\n\r\n      <h2 class=\"cvxRM__title\">Hasta 10 canales de entrada simult\u00e1neos*<\/h2>\r\n\r\n      <p class=\"cvxRM__desc\">\r\n        Convert\u00ed fuentes f\u00edsicas y digitales en canales de mezcla y arm\u00e1s salidas separadas a\r\n        <strong>Main<\/strong>, <strong>Monitor<\/strong> y <strong>Auriculares<\/strong>.\r\n      <\/p>\r\n\r\n      <div class=\"cvxRM__pills\">\r\n        <span class=\"cvxPill\">Entradas dual-mono \/ est\u00e9reo<\/span>\r\n        <span class=\"cvxPill\">Subcanales A\/B por encoder<\/span>\r\n        <span class=\"cvxPill\">M\u00f3dulos de expansi\u00f3n<\/span>\r\n      <\/div>\r\n    <\/header>\r\n\r\n    <div class=\"cvxStage cvxRM__stage\" aria-label=\"Vista general de routing\">\r\n      <div class=\"cvxRM__stageHint\" aria-hidden=\"true\">\r\n        <span class=\"cvxBadge\">AUX<\/span>\r\n        <span class=\"cvxBadge\">DIG<\/span>\r\n        <span class=\"cvxBadge\">MAIN \/ MON \/ HP<\/span>\r\n      <\/div>\r\n    <\/div>\r\n\r\n    <div class=\"cvxRM__kpiGrid\">\r\n      <div class=\"cvxCard cvxRM__kpi\">\r\n        <div class=\"cvxRM__kpiTop\">\r\n          <div class=\"cvxRM__kpiNum\">10<\/div>\r\n          <div class=\"cvxRM__kpiUnit\">IN<\/div>\r\n        <\/div>\r\n        <div class=\"cvxRM__kpiTitle\">Entradas simult\u00e1neas*<\/div>\r\n        <p class=\"cvxRM__kpiText\">\r\n          IN1 A\/B + IN2 A\/B + AUX o DIG (est\u00e9reo\/dual-mono), m\u00e1s entradas v\u00eda <strong>m\u00f3dulos de expansi\u00f3n<\/strong>.\r\n        <\/p>\r\n      <\/div>\r\n\r\n      <div class=\"cvxCard cvxRM__kpi\">\r\n        <div class=\"cvxRM__kpiTop\">\r\n          <div class=\"cvxRM__kpiNum\">6<\/div>\r\n          <div class=\"cvxRM__kpiUnit\">OUT<\/div>\r\n        <\/div>\r\n        <div class=\"cvxRM__kpiTitle\">Salidas por canal*<\/div>\r\n        <p class=\"cvxRM__kpiText\">\r\n          Main + Monitor + Auriculares, con salidas adicionales disponibles mediante <strong>m\u00f3dulos de expansi\u00f3n<\/strong>.\r\n        <\/p>\r\n      <\/div>\r\n\r\n      <div class=\"cvxCard cvxRM__kpi\">\r\n        <div class=\"cvxRM__kpiTop\">\r\n          <div class=\"cvxRM__kpiNum\">A\/B<\/div>\r\n          <div class=\"cvxRM__kpiUnit\">FAST<\/div>\r\n        <\/div>\r\n        <div class=\"cvxRM__kpiTitle\">Subcanales por encoder<\/div>\r\n        <p class=\"cvxRM__kpiText\">\r\n          Alternancia r\u00e1pida de subcanal (A\/B) sin perder el control del mix. El color confirma qu\u00e9 est\u00e1s ajustando.\r\n        <\/p>\r\n      <\/div>\r\n\r\n      <div class=\"cvxCard cvxRM__kpi\">\r\n        <div class=\"cvxRM__kpiTop\">\r\n          <div class=\"cvxRM__kpiNum\">\u2387<\/div>\r\n          <div class=\"cvxRM__kpiUnit\">MIXBUS<\/div>\r\n        <\/div>\r\n        <div class=\"cvxRM__kpiTitle\">Ruteo claro<\/div>\r\n        <p class=\"cvxRM__kpiText\">\r\n          Entradas \u2192 canales \u2192 salidas, con mapping digital (BT\/SD\/USB) y auxiliares sin men\u00fas eternos.\r\n        <\/p>\r\n      <\/div>\r\n    <\/div>\r\n\r\n    <div class=\"cvxAcc cvxRM__acc\" data-cvx-acc>\r\n      <div class=\"cvxAcc__item is-open\">\r\n        <button class=\"cvxAcc__btn\" type=\"button\" aria-expanded=\"true\">\r\n          <span class=\"cvxAcc__title\">C\u00f3mo se arma el ruteo<\/span>\r\n          <span class=\"cvxAcc__icon\" aria-hidden=\"true\"><\/span>\r\n        <\/button>\r\n        <div class=\"cvxAcc__body\">\r\n          <ol class=\"cvxRM__list\">\r\n            <li>Eleg\u00ed la fuente del canal (IN1\/IN2\/AUX\/DIG).<\/li>\r\n            <li>Defin\u00ed el subcanal: <strong>A<\/strong> o <strong>B<\/strong> (dual-mono) o <strong>stereo<\/strong>.<\/li>\r\n            <li>Asign\u00e1 la salida: <strong>Main<\/strong>, <strong>Monitor<\/strong> o <strong>Auriculares<\/strong>.<\/li>\r\n          <\/ol>\r\n        <\/div>\r\n      <\/div>\r\n\r\n      <div class=\"cvxAcc__item\">\r\n        <button class=\"cvxAcc__btn\" type=\"button\" aria-expanded=\"false\">\r\n          <span class=\"cvxAcc__title\">Qu\u00e9 significa \u201cm\u00f3dulos de expansi\u00f3n\u201d<\/span>\r\n          <span class=\"cvxAcc__icon\" aria-hidden=\"true\"><\/span>\r\n        <\/button>\r\n        <div class=\"cvxAcc__body\">\r\n          Sum\u00e1s entradas\/salidas f\u00edsicas seg\u00fan el m\u00f3dulo instalado, sin cambiar tu flujo de mezcla.\r\n        <\/div>\r\n      <\/div>\r\n\r\n      <div class=\"cvxAcc__item\">\r\n        <button class=\"cvxAcc__btn\" type=\"button\" aria-expanded=\"false\">\r\n          <span class=\"cvxAcc__title\">Que es Mix Bus<\/span>\r\n          <span class=\"cvxAcc__icon\" aria-hidden=\"true\"><\/span>\r\n        <\/button>\r\n        <div class=\"cvxAcc__body\">\r\n          Es el procesamiento que realiza el DSP para mezclar cualquier se\u00f1al disponible en cualquier combinacion elegida, otorgando alta flexibilidad y control sobre el sonido.\r\n        <\/div>\r\n      <\/div>\r\n    <\/div>\r\n\r\n    <div class=\"cvxMiniChip \" role=\"note\" aria-label=\"Nota sobre m\u00e1ximos\">\r\n      <span class=\"cvxTip__dot\"><\/span>\r\n      <span class=\"cvxTip__label\">*<\/span>\r\n      <span class=\"cvxTip__text \">\r\n        Cantidad m\u00e1xima de entradas y salidas puede variar segun configuraciones y modulos de expanci\u00f3n conectados.\r\n      <\/span>\r\n    <\/div>\r\n  <\/div>\r\n\r\n  <!-- =========================================================\r\n       SCRIPT (scale + accordion)\r\n       ========================================================= -->\r\n  <script>\r\n    (() => {\r\n      \"use strict\";\r\n\r\n      const root = document.querySelector('.cvxScope [data-cvx-root=\"routingMobile\"]');\r\n      if (!root) return;\r\n\r\n      const KEY = \"__CVX_ROUTING_MOB__\";\r\n      if (window[KEY]?.destroy) window[KEY].destroy();\r\n\r\n      const clamp = (v, a, b) => Math.max(a, Math.min(b, v));\r\n\r\n      const updateScale = () => {\r\n        const w = root.clientWidth || 420;\r\n        const cs = getComputedStyle(root);\r\n\r\n        const base = parseFloat(cs.getPropertyValue(\"--ui-base\")) || 420;\r\n        const minS = parseFloat(cs.getPropertyValue(\"--ui-min\")) || 0.72;\r\n        const maxS = parseFloat(cs.getPropertyValue(\"--ui-max\")) || 1.0;\r\n\r\n        const s = clamp(w \/ base, minS, maxS);\r\n        root.style.setProperty(\"--s\", String(s));\r\n      };\r\n\r\n      const ro = new ResizeObserver(updateScale);\r\n      ro.observe(root);\r\n      updateScale();\r\n\r\n      const acc = root.querySelector(\"[data-cvx-acc]\");\r\n      if (acc) {\r\n        acc.addEventListener(\"click\", (e) => {\r\n          const btn = e.target.closest(\".cvxAcc__btn\");\r\n          if (!btn) return;\r\n\r\n          const item = btn.closest(\".cvxAcc__item\");\r\n          if (!item) return;\r\n\r\n          const isOpen = item.classList.contains(\"is-open\");\r\n          item.classList.toggle(\"is-open\", !isOpen);\r\n          btn.setAttribute(\"aria-expanded\", String(!isOpen));\r\n        });\r\n      }\r\n\r\n      window[KEY] = {\r\n        destroy() {\r\n          ro.disconnect();\r\n        }\r\n      };\r\n    })();\r\n  <\/script>\r\n\r\n<\/section>\r\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<\/div>\n\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<div id=\"605a9af\" class=\"ha-cs-content-section \">\n\t\t\t\t\t\t\t\t\t\t<div data-elementor-type=\"section\" data-elementor-id=\"2744\" class=\"elementor elementor-2744\" data-elementor-settings=\"{&quot;ha_cmc_init_switcher&quot;:&quot;no&quot;}\">\n\t\t\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-1ac27c1 elementor-section-full_width elementor-section-height-min-height elementor-section-items-stretch animated-fast elementor-section-height-default elementor-invisible\" data-id=\"1ac27c1\" data-element_type=\"section\" data-e-type=\"section\" data-settings=\"{&quot;animation&quot;:&quot;fadeInUp&quot;,&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-no\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-08ef47e animated-slow\" data-id=\"08ef47e\" data-element_type=\"column\" data-e-type=\"column\" data-settings=\"{&quot;animation&quot;:&quot;none&quot;,&quot;animation_delay&quot;:1500}\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-c1f2fbf elementor-widget elementor-widget-html\" data-id=\"c1f2fbf\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<!-- =========================================================\r\nCubeVox \u2014 Touch EQ Widget (V8)\r\nNotas por secci\u00f3n:\r\nA) Variables (inline style): assets, breakpoints, layout toggles, tipograf\u00edas, chips\/hint, pin coords.\r\nB) Layout: panel 2 columnas \/ apilado. El STAGE mantiene aspect-ratio fijo (controlado por --stage-ar).\r\nC) Controles: chips + hint. Regla de estabilidad:\r\n   - Hint \u201ca la derecha\u201d => chips como m\u00e1ximo 2 columnas (2x2).\r\n   - Hint \u201cabajo\u201d => chips pueden pasar a 4 columnas si entra.\r\nD) Meter dB: altura sincronizada con la altura renderizada del SVG (evita que el meter estire el contenedor).\r\n========================================================= -->\r\n\r\n<div class=\"cvxEqV8\" data-cvx-eq-v8\r\n  style=\"\r\n    \/* =========================\r\n       ASSETS\r\n       ========================= *\/\r\n    --stage-img:url('\/wp-content\/uploads\/cubevox-hifi-open-wood-violet-render.webp');\r\n\r\n    \/* =========================\r\n       BREAKPOINTS (JS lee estos valores)\r\n       ========================= *\/\r\n    --bp-panel-stack: 860;   \/* px: por debajo, panel apilado (intro\/right\/eq en 1 columna) *\/\r\n    --bp-hint-stack:  767;   \/* px: por debajo, hint forzado abajo (aunque entre a la derecha) *\/\r\n\r\n    \/* =========================\r\n       TOGGLES \/ LAYOUT\r\n       ========================= *\/\r\n    --eq-enabled: 1;            \/* 0 = oculta el widget completo *\/\r\n    --panel-shell: 1;           \/* 0 = sin caja padre (sin padding\/borde\/sombra) *\/\r\n    --stageTop-br: 0;           \/* 1 = label\/hint del stage abajo-derecha *\/\r\n    --stageTop-inset: 10px;     \/* separaci\u00f3n desde bordes del stage *\/\r\n    --stage-bg-pos: 50% 25%;    \/* background-position del stage *\/\r\n\r\n    \/* =========================\r\n       STAGE (aspect-ratio fijo)\r\n       ========================= *\/\r\n    --stage-ar: 17 \/ 8;\r\n\r\n    \/* =========================\r\n       TIPOGRAF\u00cdA \/ ESPACIADOS\r\n       ========================= *\/\r\n    --fs-kicker:12px;\r\n    --fs-title:22px;\r\n    --fs-desc:12px;\r\n\r\n    --pad-panel:18px;\r\n    --gap-panel:18px;\r\n\r\n    --fs-stageLabel:10px;\r\n    --fs-stageHint:11px;\r\n    --fs-tags:12px;\r\n\r\n    --fs-hud-lbl:11px;\r\n    --fs-hud-val:11px;\r\n    --fs-grid:12px;\r\n    --fs-meter:11px;\r\n\r\n    \/* Mobile overrides *\/\r\n    --fs-kicker-m:11px;\r\n    --fs-title-m:20px;\r\n    --fs-desc-m:12px;\r\n\r\n    --fs-stageLabel-m:8px;\r\n    --fs-stageHint-m:9px;\r\n    --fs-tags-m:10px;\r\n\r\n    --fs-hud-lbl-m:9px;\r\n    --fs-hud-val-m:9px;\r\n    --fs-grid-m:11px;\r\n    --fs-meter-m:10px;\r\n\r\n    --fs-chip-label-m:10px;\r\n    --fs-chip-seg-m:10px;\r\n    --chip-seg-pad-x-m:9px;\r\n\r\n    --fs-hint-m:11px;\r\n\r\n    --fs-acc-title-m:12px;\r\n    --fs-acc-body-m:11px;\r\n\r\n    \/* Stage *\/\r\n    --stage-radius:16px;\r\n    --stage-w-max-stacked: 560px;\r\n\r\n    \/* Overlay stage *\/\r\n    --stage-overlay-alpha: 0.12;\r\n    --stage-overlay-strength: 1;\r\n\r\n    \/* =========================\r\n       Chips (cvxChip)\r\n       ========================= *\/\r\n    --chip-gap:10px;\r\n    --chips-pad-x: 0px;\r\n\r\n    --chip-w-min:135px;\r\n    --chip-w-max:280px;\r\n    --chip-fit-extra: 0px;\r\n\r\n    \/* Hint column sizing *\/\r\n    --hint-col-min: 270px;\r\n    --hint-col-max: 420px;\r\n\r\n    \/* Gap real entre columna chips y hint (debe matchear el CSS) *\/\r\n    --ctrl-gap: 12px;\r\n\r\n    \/* Cap din\u00e1mico del hint (CSS)\r\n       Nota: se reserva espacio como si se pudiera ir a 4 chips m\u00ednimos,\r\n       pero JS evita 4 columnas cuando el hint est\u00e1 a la derecha. *\/\r\n    --chips-need4: calc(\r\n      var(--chip-w-min) + var(--chip-w-min) + var(--chip-w-min) + var(--chip-w-min) +\r\n      var(--chip-gap) + var(--chip-gap) + var(--chip-gap) +\r\n      var(--chip-fit-extra)\r\n    );\r\n    --hint-col-cap: clamp(\r\n      var(--hint-col-min),\r\n      calc(100% - var(--chips-need4) - var(--ctrl-gap)),\r\n      var(--hint-col-max)\r\n    );\r\n\r\n    \/* Geometr\u00eda \/ padding interno *\/\r\n    --chip-radius:12px;\r\n    --chip-gap-in:5px;\r\n    --chip-pad-t:6px;\r\n    --chip-pad-x:10px;\r\n    --chip-pad-b:10px;\r\n\r\n    \/* Label *\/\r\n    --fs-chip-label:10px;\r\n    --chip-label-ls:.1em;\r\n\r\n    \/* Segment *\/\r\n    --chip-seg-radius:999px;\r\n    --chip-seg-pad-y:4px;\r\n    --chip-seg-pad-x:6px;\r\n    --fs-chip-seg:8px;\r\n    --chip-seg-ls:.10em;\r\n\r\n    \/* L\u00ednea inferior (acento) *\/\r\n    --chip-line-inset-x:10px;\r\n    --chip-line-bottom:5px;\r\n    --chip-lineHeight:2px;\r\n    --chip-lineBlur:10px;\r\n    --chip-lineOpacity:.3;\r\n\r\n    \/* Hint *\/\r\n    --fs-hint:12px;\r\n    --hint-pad-y:10px;\r\n    --hint-pad-x:12px;\r\n\r\n    \/* Acorde\u00f3n *\/\r\n    --fs-acc-title:13px;\r\n    --fs-acc-body:12px;\r\n    --acc-pad-y:12px;\r\n    --acc-pad-x:12px;\r\n    --acc-icon-shift-y:-.5px;\r\n\r\n    \/* EQ drag *\/\r\n    --node-hit-r: 16;\r\n    --node-hit-r-m: 22;\r\n\r\n    \/* =========================\r\n       PIN COORDS\r\n       ========================= *\/\r\n    --pin-touch-x: 60;\r\n    --pin-touch-y: 50;\r\n    --pin-touch-rk: 0.012;\r\n    --pin-touch-wk: 0.18;\r\n\r\n    --pin-menu-x: 55;\r\n    --pin-menu-y: 28;\r\n    --pin-menu-rk: 0.012;\r\n    --pin-menu-wk: 0.18;\r\n\r\n    --pin-subch-x: 60;\r\n    --pin-subch-y: 51;\r\n    --pin-subch-rk: 0.012;\r\n    --pin-subch-wk: 0.18;\r\n\r\n    \/* =========================\r\n       OFFSETS (item 3 = subch)\r\n       ========================= *\/\r\n    --subch-enc-master-dx: -17;\r\n    --subch-enc-master-dy: -16.5;\r\n\r\n    --subch-enc-media-dx:  6.5;\r\n    --subch-enc-media-dy:  -29;\r\n\r\n    --subch-enc-in1-dx:   -10.5;\r\n    --subch-enc-in1-dy:    8;\r\n\r\n    --subch-enc-in2-dx:    12;\r\n    --subch-enc-in2-dy:   -6;\r\n\r\n    \/* Offsets FINOS por subcanal *\/\r\n    --subch-id-master-main-dx: 0;  --subch-id-master-main-dy: 0;\r\n    --subch-id-master-hp-dx:   0;  --subch-id-master-hp-dy:   0;\r\n\r\n    --subch-id-media-aux-dx:   0;  --subch-id-media-aux-dy:   0;\r\n    --subch-id-media-dig-dx:   0;  --subch-id-media-dig-dy:   0;\r\n\r\n    --subch-id-in1-a-dx:       0;  --subch-id-in1-a-dy:       0;\r\n    --subch-id-in1-b-dx:       0;  --subch-id-in1-b-dy:       0;\r\n\r\n    --subch-id-in2-a-dx:       0;  --subch-id-in2-a-dy:       0;\r\n    --subch-id-in2-b-dx:       0;  --subch-id-in2-b-dy:       0;\r\n\r\n    \/* =========================\r\n       COLORES POR SUBCANAL\r\n       ========================= *\/\r\n    --c-main:#FFFFFF;\r\n    --c-hp:#FFFF2B;\r\n    --c-aux:#FF7A00;\r\n    --c-dig:#20FF20;\r\n\r\n    --c-in1a:#FF0D0D;\r\n    --c-in1b:#DB24FF;\r\n\r\n    --c-in2a:#0B0BFF;\r\n    --c-in2b:#0CFFFF;\r\n  \">\r\n\r\n  <div class=\"cvxEqV8__panel\">\r\n\r\n    <!-- INTRO -->\r\n    <div class=\"cvxEqV8__intro\">\r\n      <div class=\"cvxEqV8__kicker\">EQ T\u00c1CTIL<\/div>\r\n      <h3 class=\"cvxEqV8__title\">Ecualizador Param\u00e9trico por Canal<\/h3>\r\n      <p class=\"cvxEqV8__desc\">\r\n        <b>Panel r\u00e1pido: <\/b>ajust\u00e1 dB al instante y defin\u00ed frecuencia + Q desde el men\u00fa.\r\n      <\/p>\r\n      <div class=\"cvxEqV8__tags\">\r\n        <span>13 bandas ajustables<\/span>\r\n        <span>Canal activo por color<\/span>\r\n        <span>Ajuste r\u00e1pido de dB<\/span>\r\n      <\/div>\r\n    <\/div>\r\n\r\n    <!-- DERECHA: STAGE + ACORDE\u00d3N -->\r\n    <div class=\"cvxEqV8__right\">\r\n\r\n      <div class=\"cvxEqV8__stage\" data-stage aria-hidden=\"true\">\r\n        <div class=\"cvxEqV8__stageTop\">\r\n          <span class=\"cvxEqV8__stageLabel\">FOCO<\/span>\r\n          <span class=\"cvxEqV8__stageHint\" data-stage-label>Panel EQ<\/span>\r\n        <\/div>\r\n\r\n        <div class=\"cvxEqV8__pin\" aria-hidden=\"true\"><\/div>\r\n      <\/div>\r\n\r\n      <div class=\"cvxEqV8__acc\" data-acc>\r\n        <div class=\"cvxEqV8__accItem is-open\" data-acc-item data-spot=\"touch\">\r\n          <button class=\"cvxEqV8__accBtn\" type=\"button\">\r\n            <span class=\"cvxEqV8__accTitle\">Panel t\u00e1ctil: ganancia (dB) inmediata<\/span>\r\n            <span class=\"cvxEqV8__accIcon\" aria-hidden=\"true\"><\/span>\r\n          <\/button>\r\n          <div class=\"cvxEqV8__accBody\">\r\n            Ajust\u00e1 la <b>ganancia por banda<\/b> en tiempo real sobre el <b>subcanal activo<\/b>.\r\n            El <b>color<\/b> confirma qu\u00e9 est\u00e1s modificando.\r\n          <\/div>\r\n        <\/div>\r\n\r\n        <div class=\"cvxEqV8__accItem\" data-acc-item data-spot=\"menu\">\r\n          <button class=\"cvxEqV8__accBtn\" type=\"button\">\r\n            <span class=\"cvxEqV8__accTitle\">Men\u00fa del dispositivo: frecuencia + Q por banda<\/span>\r\n            <span class=\"cvxEqV8__accIcon\" aria-hidden=\"true\"><\/span>\r\n          <\/button>\r\n          <div class=\"cvxEqV8__accBody\">\r\n            Para cada una de las 13 bandas defin\u00eds <b>frecuencia central<\/b> y <b>factor Q<\/b>\r\n            desde el men\u00fa del dispositivo (pantalla OLED). El panel se usa para el ajuste r\u00e1pido de dB.\r\n          <\/div>\r\n        <\/div>\r\n\r\n        <div class=\"cvxEqV8__accItem\" data-acc-item data-spot=\"subch\">\r\n          <button class=\"cvxEqV8__accBtn\" type=\"button\">\r\n            <span class=\"cvxEqV8__accTitle\">Subcanales por encoder (alternancia r\u00e1pida)<\/span>\r\n            <span class=\"cvxEqV8__accIcon\" aria-hidden=\"true\"><\/span>\r\n          <\/button>\r\n          <div class=\"cvxEqV8__accBody\">\r\n            Cada encoder controla 2 subcanales. En el equipo la alternancia se hace con <b>doble toque<\/b>.\r\n            En esta demo se emula con un segundo toque sobre el chip.\r\n          <\/div>\r\n        <\/div>\r\n      <\/div>\r\n\r\n    <\/div>\r\n\r\n    <!-- IZQUIERDA: EQ + CONTROLES -->\r\n    <div class=\"cvxEqV8__eqBlock\">\r\n\r\n      <div class=\"cvxEqV8__hero\">\r\n        <div class=\"cvxEqV8__eq\" id=\"cvxEq13V8\">\r\n          <div class=\"cvxEqV8__hud\">\r\n            <div class=\"cvxEqV8__hudItem\">\r\n              <span class=\"cvxEqV8__hudLbl\">Subcanal<\/span>\r\n              <span class=\"cvxEqV8__hudVal\" data-eq-sub>\u2014<\/span>\r\n            <\/div>\r\n            <div class=\"cvxEqV8__hudItem\">\r\n              <span class=\"cvxEqV8__hudLbl\">Banda<\/span>\r\n              <span class=\"cvxEqV8__hudVal\" data-eq-band>\u2014<\/span>\r\n            <\/div>\r\n            <div class=\"cvxEqV8__hudItem\">\r\n              <span class=\"cvxEqV8__hudLbl\">Ganancia<\/span>\r\n              <span class=\"cvxEqV8__hudVal\" data-eq-db>0.0 dB<\/span>\r\n            <\/div>\r\n          <\/div>\r\n\r\n          <svg class=\"cvxEqV8__svg\" viewBox=\"0 0 720 180\" role=\"img\" aria-label=\"EQ interactivo 13 bandas\">\r\n            <g class=\"cvxEqV8__grid\">\r\n              <path d=\"M70 25H690 M70 90H690 M70 155H690\"><\/path>\r\n              <path d=\"M70 25V155\"><\/path>\r\n              <text x=\"22\" y=\"30\">+12<\/text>\r\n              <text x=\"40\" y=\"95\">0<\/text>\r\n              <text x=\"24\" y=\"160\">-12<\/text>\r\n            <\/g>\r\n            <path class=\"cvxEqV8__curve\" d=\"\"><\/path>\r\n            <g class=\"cvxEqV8__nodes\"><\/g>\r\n          <\/svg>\r\n\r\n          <div class=\"cvxEqV8__eqSpot\"><\/div>\r\n        <\/div>\r\n\r\n        <div class=\"cvxEqV8__meter\" aria-hidden=\"true\">\r\n          <div class=\"cvxEqV8__meterTrack\">\r\n            <div class=\"cvxEqV8__meterZero\"><\/div>\r\n            <div class=\"cvxEqV8__meterFill\" data-eq-fill><\/div>\r\n            <div class=\"cvxEqV8__meterThumb\" data-eq-thumb><\/div>\r\n          <\/div>\r\n          <div class=\"cvxEqV8__meterTicks\">\r\n            <span>+12<\/span><span>+6<\/span><span>0<\/span><span>-6<\/span><span>-12<\/span>\r\n          <\/div>\r\n        <\/div>\r\n      <\/div>\r\n\r\n      <div class=\"cvxEqV8__ctrlWrap\">\r\n        <div class=\"cvxEqV8__ctrl\">\r\n\r\n          <button class=\"cvxEqV8__chip cvxChip cvxChip--v2\" type=\"button\" data-enc=\"master\" aria-label=\"MASTER selector MAIN\/HP\">\r\n            <span class=\"cvxChip__label\">MASTER<\/span>\r\n            <span class=\"cvxChip__seg\" aria-hidden=\"true\">\r\n              <span class=\"cvxChip__segBtn is-on\">MAIN<\/span>\r\n              <span class=\"cvxChip__segBtn\">HP<\/span>\r\n            <\/span>\r\n          <\/button>\r\n\r\n          <button class=\"cvxEqV8__chip cvxChip cvxChip--v2\" type=\"button\" data-enc=\"media\" aria-label=\"MEDIA selector AUX\/DIG\">\r\n            <span class=\"cvxChip__label\">MEDIA<\/span>\r\n            <span class=\"cvxChip__seg\" aria-hidden=\"true\">\r\n              <span class=\"cvxChip__segBtn is-on\">AUX<\/span>\r\n              <span class=\"cvxChip__segBtn\">DIG<\/span>\r\n            <\/span>\r\n          <\/button>\r\n\r\n          <button class=\"cvxEqV8__chip cvxChip cvxChip--v2\" type=\"button\" data-enc=\"in1\" aria-label=\"IN1 selector A\/B\">\r\n            <span class=\"cvxChip__label\">IN1<\/span>\r\n            <span class=\"cvxChip__seg\" aria-hidden=\"true\">\r\n              <span class=\"cvxChip__segBtn is-on\">A<\/span>\r\n              <span class=\"cvxChip__segBtn\">B<\/span>\r\n            <\/span>\r\n          <\/button>\r\n\r\n          <button class=\"cvxEqV8__chip cvxChip cvxChip--v2\" type=\"button\" data-enc=\"in2\" aria-label=\"IN2 selector A\/B\">\r\n            <span class=\"cvxChip__label\">IN2<\/span>\r\n            <span class=\"cvxChip__seg\" aria-hidden=\"true\">\r\n              <span class=\"cvxChip__segBtn is-on\">A<\/span>\r\n              <span class=\"cvxChip__segBtn\">B<\/span>\r\n            <\/span>\r\n          <\/button>\r\n\r\n        <\/div>\r\n\r\n        <div class=\"cvxEqV8__hint\">\r\n          <b>C\u00f3mo probarlo:<\/b><br>\r\n          1) Toc\u00e1 un <b>encoder<\/b> para seleccionarlo.<br>\r\n          2) Toc\u00e1 de nuevo para <b>alternar<\/b> su subcanal.<br>\r\n          3) En el gr\u00e1fico, <b>desliz\u00e1 vertical<\/b> los puntos para ajustar dB.\r\n        <\/div>\r\n      <\/div>\r\n    <\/div>\r\n\r\n  <\/div>\r\n<\/div>\r\n\r\n<style>\r\n\/* =========================================================\r\n   Base \/ Tokens\r\n========================================================= *\/\r\n.cvxEqV8{\r\n  --text: rgba(255,255,255,.92);\r\n  --muted: rgba(255,255,255,.70);\r\n  --glass: rgba(14,18,24,.58);\r\n  --stroke: rgba(255,255,255,.10);\r\n  --shadow: 0 22px 60px rgba(0,0,0,.55);\r\n\r\n  --pin-x: 56%;\r\n  --pin-y: 52%;\r\n  --pin-r: 10px;\r\n  --pin-wave: 120px;\r\n\r\n  \/* Altura del meter (sincronizada por JS con la altura renderizada del SVG) *\/\r\n  --meter-h: 180px;\r\n\r\n  width: min(1080px, 100%);\r\n  max-width: 100%;\r\n  margin: 22px 0 0;\r\n  font-family: system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif;\r\n\r\n  overflow-x: hidden;\r\n}\r\n.cvxEqV8, .cvxEqV8 *{ box-sizing: border-box; }\r\n\r\n\/* Reset contra theme *\/\r\n.cvxEqV8 button{\r\n  font: inherit;\r\n  color: inherit;\r\n  appearance: none;\r\n  -webkit-appearance: none;\r\n  -webkit-tap-highlight-color: transparent;\r\n}\r\n.cvxEqV8 button:focus{ outline: none; }\r\n.cvxEqV8 button:focus-visible{\r\n  outline: 2px solid color-mix(in srgb, var(--accent, var(--chip-accent, var(--c-main))) 65%, transparent);\r\n  outline-offset: 2px;\r\n  border-radius: 14px;\r\n}\r\n\r\n\/* =========================================================\r\n   Panel layout\r\n========================================================= *\/\r\n.cvxEqV8__panel{\r\n  display:grid;\r\n  grid-template-columns: 1.12fr .88fr;\r\n  grid-template-areas:\r\n    \"intro right\"\r\n    \"eq    right\";\r\n  gap: var(--gap-panel);\r\n  padding: var(--pad-panel);\r\n  border-radius: 18px;\r\n  background: var(--glass);\r\n  border: 1px solid var(--stroke);\r\n  box-shadow: var(--shadow);\r\n  backdrop-filter: blur(10px);\r\n  -webkit-backdrop-filter: blur(10px);\r\n  overflow: hidden;\r\n}\r\n\r\n\/* Caja padre OFF *\/\r\n.cvxEqV8.is-shell-off .cvxEqV8__panel{\r\n  padding: 0 !important;\r\n  background: transparent !important;\r\n  border: 0 !important;\r\n  box-shadow: none !important;\r\n  backdrop-filter: none !important;\r\n  -webkit-backdrop-filter: none !important;\r\n}\r\n\r\n.cvxEqV8__intro{ grid-area: intro; min-width:0; }\r\n.cvxEqV8__right{ grid-area: right; min-width:0; position:relative; z-index: 2; }\r\n.cvxEqV8__eqBlock{ grid-area: eq; min-width:0; position:relative; z-index: 1; }\r\n\r\n.cvxEqV8__kicker{\r\n  display:inline-block;\r\n  font-size: var(--fs-kicker);\r\n  letter-spacing: .16em;\r\n  text-transform: uppercase;\r\n  color: var(--muted);\r\n  margin-bottom: 8px;\r\n}\r\n.cvxEqV8__title{\r\n  margin: 0 0 10px;\r\n  font-size: var(--fs-title);\r\n  line-height: 1.15;\r\n  color: var(--text);\r\n}\r\n.cvxEqV8__desc{\r\n  margin: 0;\r\n  font-size: var(--fs-desc);\r\n  line-height: 1.55;\r\n  color: var(--muted);\r\n}\r\n.cvxEqV8__desc b{ color: var(--text); font-weight: 650; }\r\n\r\n\/* =========================================================\r\n   Stage (imagen) \u2014 aspect-ratio fijo\r\n========================================================= *\/\r\n.cvxEqV8__stage{\r\n  position: relative;\r\n  aspect-ratio: var(--stage-ar, 17 \/ 8);\r\n  height: auto;\r\n  width: 100%;\r\n\r\n  border-radius: var(--stage-radius);\r\n  border: 1px solid rgba(255,255,255,.10);\r\n  overflow: hidden;\r\n  background-image: var(--stage-img);\r\n  background-size: cover;\r\n  background-position: var(--stage-bg-pos);\r\n  box-shadow: 0 18px 50px rgba(0,0,0,.45);\r\n  margin-top: 35px;\r\n}\r\n.cvxEqV8__stage::after{\r\n  content:\"\";\r\n  position:absolute; inset:0;\r\n  pointer-events:none;\r\n  opacity: var(--stage-overlay-alpha);\r\n  background:\r\n    radial-gradient(120% 120% at 50% 30%,\r\n      rgba(0,0,0, calc(.10 * var(--stage-overlay-strength))),\r\n      rgba(0,0,0, calc(.55 * var(--stage-overlay-strength))) 70%,\r\n      rgba(0,0,0, calc(.75 * var(--stage-overlay-strength)))\r\n    );\r\n}\r\n\r\n.cvxEqV8__stageTop{\r\n  position:absolute;\r\n  top: var(--stageTop-inset);\r\n  left: var(--stageTop-inset);\r\n  display:flex;\r\n  gap: 10px;\r\n  align-items: center;\r\n  z-index: 4;\r\n  min-width: 0;\r\n}\r\n.cvxEqV8.is-stageTopBR .cvxEqV8__stageTop{\r\n  top: auto;\r\n  left: auto;\r\n  bottom: var(--stageTop-inset);\r\n  right: var(--stageTop-inset);\r\n}\r\n\r\n.cvxEqV8__stageLabel{\r\n  font-size: var(--fs-stageLabel);\r\n  letter-spacing: .14em;\r\n  text-transform: uppercase;\r\n  color: rgba(255,255,255,.65);\r\n  border: 1px solid rgba(255,255,255,.12);\r\n  background: rgba(0,0,0,.25);\r\n  padding: 6px 10px;\r\n  border-radius: 999px;\r\n  white-space: nowrap;\r\n}\r\n.cvxEqV8__stageHint{\r\n  font-size: var(--fs-stageHint);\r\n  color: rgba(255,255,255,.86);\r\n  font-weight: 650;\r\n  border: 1px solid rgba(255,255,255,.10);\r\n  background: rgba(0,0,0,.22);\r\n  padding: 6px 10px;\r\n  border-radius: 999px;\r\n  white-space: nowrap;\r\n  overflow: hidden;\r\n  text-overflow: ellipsis;\r\n  max-width: 60%;\r\n}\r\n\r\n\/* Pin + ondas *\/\r\n.cvxEqV8__pin{\r\n  position:absolute;\r\n  left: var(--pin-x);\r\n  top:  var(--pin-y);\r\n  width: calc(var(--pin-r) * 2);\r\n  height: calc(var(--pin-r) * 2);\r\n  transform: translate(-50%, -50%);\r\n  border-radius: 999px;\r\n  z-index: 3;\r\n  pointer-events:none;\r\n\r\n  background: color-mix(in srgb, var(--eq-accent, var(--c-main)) 70%, rgba(255,255,255,.20));\r\n  box-shadow:\r\n    0 0 0 2px rgba(255,255,255,.12),\r\n    0 0 18px color-mix(in srgb, var(--eq-accent, var(--c-main)) 35%, transparent);\r\n}\r\n.cvxEqV8__pin::before,\r\n.cvxEqV8__pin::after{\r\n  content:\"\";\r\n  position:absolute;\r\n  inset: 50% auto auto 50%;\r\n  width: calc(var(--pin-r) * 2);\r\n  height: calc(var(--pin-r) * 2);\r\n  transform: translate(-50%, -50%);\r\n  border-radius: 999px;\r\n  border: 2px solid color-mix(in srgb, var(--eq-accent, var(--c-main)) 55%, transparent);\r\n  opacity: .55;\r\n  filter: drop-shadow(0 0 18px color-mix(in srgb, var(--eq-accent, var(--c-main)) 26%, transparent));\r\n  animation: cvxPinWave 1.8s ease-out infinite;\r\n}\r\n.cvxEqV8__pin::after{\r\n  animation-delay: .9s;\r\n  opacity: .45;\r\n}\r\n@keyframes cvxPinWave{\r\n  0%   { transform: translate(-50%,-50%) scale(1);   opacity: .55; }\r\n  70%  { transform: translate(-50%,-50%) scale(calc(var(--pin-wave) \/ (var(--pin-r) * 2))); opacity: 0; }\r\n  100% { opacity: 0; }\r\n}\r\n\r\n\/* =========================================================\r\n   Accordion\r\n========================================================= *\/\r\n.cvxEqV8__acc{\r\n  margin-top: 12px;\r\n  border-radius: 16px;\r\n  border: 1px solid rgba(255,255,255,.09);\r\n  background: rgba(0,0,0,.20);\r\n  overflow:hidden;\r\n}\r\n.cvxEqV8__accItem{ border-top: 1px solid rgba(255,255,255,.07); }\r\n.cvxEqV8__accItem:first-child{ border-top:0; }\r\n\r\n.cvxEqV8__accBtn{\r\n  width:100%;\r\n  background: transparent !important;\r\n  border:0 !important;\r\n  padding: var(--acc-pad-y) var(--acc-pad-x);\r\n  display:flex;\r\n  align-items:center;\r\n  justify-content: space-between;\r\n  gap: 10px;\r\n  cursor:pointer;\r\n  transition: background .15s ease;\r\n}\r\n.cvxEqV8__accBtn:hover{ background: rgba(255,255,255,.03) !important; }\r\n\r\n.cvxEqV8__accTitle{\r\n  color: rgba(255,255,255,.90);\r\n  font-weight: 650;\r\n  font-size: var(--fs-acc-title);\r\n}\r\n.cvxEqV8__accIcon{\r\n  width: 22px; height: 22px;\r\n  border-radius: 999px;\r\n  border: 1px solid rgba(255,255,255,.10);\r\n  background: rgba(0,0,0,.20);\r\n  display:flex;\r\n  align-items:center;\r\n  justify-content:center;\r\n  flex: 0 0 22px;\r\n}\r\n.cvxEqV8__accItem .cvxEqV8__accIcon::before{\r\n  content:\"+\";\r\n  font-weight: 900;\r\n  color: rgba(255,255,255,.60);\r\n  line-height: 1;\r\n  transform: translateY(var(--acc-icon-shift-y));\r\n}\r\n.cvxEqV8__accItem.is-open .cvxEqV8__accIcon::before{\r\n  content:\"\u2013\";\r\n  color: rgba(255,255,255,.80);\r\n  transform: translateY(var(--acc-icon-shift-y));\r\n}\r\n.cvxEqV8__accBody{\r\n  display:none;\r\n  padding: 0 var(--acc-pad-x) var(--acc-pad-y);\r\n  color: rgba(255,255,255,.68);\r\n  font-size: var(--fs-acc-body);\r\n  line-height: 1.45;\r\n}\r\n.cvxEqV8__accItem.is-open .cvxEqV8__accBody{ display:block; }\r\n\r\n\/* Tags *\/\r\n.cvxEqV8__tags{\r\n  display:flex;\r\n  flex-wrap: wrap;\r\n  gap: 8px;\r\n  margin-top: 12px;\r\n}\r\n.cvxEqV8__tags span{\r\n  font-size: var(--fs-tags);\r\n  color: rgba(255,255,255,.78);\r\n  border: 1px solid rgba(255,255,255,.10);\r\n  background: rgba(0,0,0,.22);\r\n  padding: 7px 10px;\r\n  border-radius: 999px;\r\n}\r\n\r\n\/* =========================================================\r\n   EQ + Meter\r\n   Cambio clave: el meter NO fuerza la altura.\r\n   - Se alinea arriba.\r\n   - La altura del track se sincroniza con el SVG (JS -> --meter-h).\r\n========================================================= *\/\r\n.cvxEqV8__hero{\r\n  margin-top: 14px;\r\n  display:grid;\r\n  grid-template-columns: minmax(0, 1fr) 88px;\r\n  gap: 12px;\r\n  align-items: stretch; \/* evita que el meter estire el bloque del EQ *\/\r\n}\r\n.cvxEqV8__eq{\r\n  position: relative;\r\n  border-radius: 14px;\r\n  border: 1px solid rgba(255,255,255,.10);\r\n  background:\r\n    radial-gradient(120% 140% at 0% 0%, color-mix(in srgb, var(--eq-accent, var(--c-main)) 22%, transparent), transparent 55%),\r\n    radial-gradient(120% 140% at 100% 100%, color-mix(in srgb, var(--eq-accent, var(--c-main)) 14%, transparent), transparent 60%),\r\n    rgba(0,0,0,.25);\r\n  padding: 10px 10px 12px;\r\n  overflow:hidden;\r\n\r\n  min-width: 0;\r\n  touch-action: none;\r\n  overscroll-behavior: contain;\r\n}\r\n.cvxEqV8__hud{\r\n  display:flex;\r\n  gap: 10px;\r\n  justify-content: space-between;\r\n  align-items: baseline;\r\n  margin-bottom: 6px;\r\n}\r\n.cvxEqV8__hudItem{ display:flex; gap:8px; align-items: baseline; min-width:0; }\r\n.cvxEqV8__hudLbl{ font-size: var(--fs-hud-lbl); color: rgba(255,255,255,.58); }\r\n.cvxEqV8__hudVal{ font-size: var(--fs-hud-val); color: rgba(255,255,255,.92); font-weight: 650; }\r\n\r\n.cvxEqV8__svg{\r\n  width:100%;\r\n  height:auto;\r\n  display:block;\r\n  touch-action: none;\r\n}\r\n.cvxEqV8__grid path{ stroke: rgba(255,255,255,.08); stroke-width:1; fill:none; }\r\n.cvxEqV8__grid text{ fill: rgba(255,255,255,.32); font-size: var(--fs-grid); }\r\n\r\n.cvxEqV8__curve{\r\n  stroke: color-mix(in srgb, var(--eq-accent, var(--c-main)) 90%, white 10%);\r\n  stroke-width: 2.6;\r\n  fill:none;\r\n  filter: drop-shadow(0 0 12px color-mix(in srgb, var(--eq-accent, var(--c-main)) 26%, transparent));\r\n  transition: stroke .18s ease, filter .18s ease;\r\n}\r\n.cvxEqV8__node{ cursor: ns-resize; }\r\n.cvxEqV8__nodeHit{ fill: transparent; touch-action: none; }\r\n.cvxEqV8__node circle{\r\n  fill: rgba(255,255,255,.14);\r\n  stroke: rgba(255,255,255,.22);\r\n  stroke-width: 1;\r\n}\r\n.cvxEqV8__node .cvxEqV8__nodeGlow{\r\n  fill: color-mix(in srgb, var(--eq-accent, var(--c-main)) 20%, transparent);\r\n  stroke: color-mix(in srgb, var(--eq-accent, var(--c-main)) 92%, transparent);\r\n  stroke-width: 2;\r\n  filter: drop-shadow(0 0 14px color-mix(in srgb, var(--eq-accent, var(--c-main)) 35%, transparent));\r\n  opacity: 0;\r\n  transition: opacity .15s ease;\r\n}\r\n.cvxEqV8__node.is-active .cvxEqV8__nodeGlow{ opacity: 1; }\r\n\r\n.cvxEqV8__eqSpot{\r\n  position:absolute;\r\n  inset:0;\r\n  pointer-events:none;\r\n  background: radial-gradient(240px 160px at 54% 76%,\r\n    color-mix(in srgb, var(--eq-accent, var(--c-main)) 18%, transparent),\r\n    transparent 62%);\r\n  opacity: 0;\r\n  transition: opacity .20s ease;\r\n}\r\n.cvxEqV8__eq.is-highlight .cvxEqV8__eqSpot{ opacity: 1; }\r\n\r\n\/* Meter *\/\r\n.cvxEqV8__meter{\r\n  border-radius: 14px;\r\n  border: 1px solid rgba(255,255,255,.09);\r\n  background: rgba(0,0,0,.22);\r\n  padding: 10px 10px;\r\n  display:flex;\r\n  gap: 10px;\r\n  align-items: stretch; \/* no fuerza altura del row *\/\r\n}\r\n.cvxEqV8__meterTrack{\r\n  position: relative;\r\n  width: 18px;\r\n  height: 100%; \r\n  flex: 0 0 18px;\r\n  border-radius: 999px;\r\n  background: rgba(255,255,255,.06);\r\n  border: 1px solid rgba(255,255,255,.07);\r\n}\r\n.cvxEqV8__meterZero{\r\n  position:absolute;\r\n  left:-6px; right:-6px;\r\n  top: 50%;\r\n  height: 1px;\r\n  background: rgba(255,255,255,.22);\r\n}\r\n.cvxEqV8__meterFill{\r\n  position:absolute;\r\n  left:3px; right:3px;\r\n  top: 50%;\r\n  height: 0px;\r\n  border-radius: 999px;\r\n  background: color-mix(in srgb, var(--eq-accent, var(--c-main)) 60%, transparent);\r\n  filter: drop-shadow(0 0 12px color-mix(in srgb, var(--eq-accent, var(--c-main)) 22%, transparent));\r\n}\r\n.cvxEqV8__meterThumb{\r\n  position:absolute;\r\n  left: 50%;\r\n  width: 26px;\r\n  height: 2px;\r\n  transform: translateX(-50%);\r\n  background: color-mix(in srgb, var(--eq-accent, var(--c-main)) 92%, transparent);\r\n  filter: drop-shadow(0 0 10px color-mix(in srgb, var(--eq-accent, var(--c-main)) 26%, transparent));\r\n  opacity: .9;\r\n}\r\n.cvxEqV8__meterTicks{\r\n  display:flex;\r\n  flex-direction: column;\r\n  justify-content: space-between;\r\n  font-size: var(--fs-meter);\r\n  color: rgba(255,255,255,.40);\r\n  height: 100%; \r\n}\r\n\r\n\/* =========================================================\r\n   Controles + Hint\r\n========================================================= *\/\r\n.cvxEqV8__ctrlWrap{\r\n  display:grid !important;\r\n  grid-template-columns: minmax(0, 1fr) minmax(var(--hint-col-min), var(--hint-col-cap, var(--hint-col-max))) !important;\r\n  gap: var(--ctrl-gap);\r\n  align-items: start;\r\n  margin-top: 12px;\r\n  min-width: 0;\r\n}\r\n.cvxEqV8.is-hint-below .cvxEqV8__ctrlWrap{\r\n  grid-template-columns: 1fr !important;\r\n}\r\n\r\n.cvxEqV8__ctrl{\r\n  display:grid;\r\n  gap: var(--chip-gap);\r\n  padding: 0 var(--chips-pad-x);\r\n  min-width: 0;\r\n  grid-template-columns: repeat(2, minmax(0, 1fr));\r\n}\r\n\r\n.cvxEqV8[data-chip-cols=\"4\"] .cvxEqV8__ctrl{\r\n  grid-template-columns: repeat(4, minmax(var(--chip-w-min), var(--chip-w-max)));\r\n}\r\n.cvxEqV8[data-chip-cols=\"2\"] .cvxEqV8__ctrl{\r\n  grid-template-columns: repeat(2, minmax(var(--chip-w-min), var(--chip-w-max)));\r\n}\r\n.cvxEqV8[data-chip-cols=\"1\"] .cvxEqV8__ctrl{\r\n  grid-template-columns: 1fr;\r\n}\r\n\r\n.cvxEqV8__chip{\r\n  min-width: 0;\r\n  width: 100%;\r\n}\r\n\r\n\/* ===== cvxChip (scoped) ===== *\/\r\n.cvxEqV8__chip.cvxChip{\r\n  --accent: var(--c-main);\r\n\r\n  --chipTop: rgba(255,255,255,.065);\r\n  --chipMid: rgba(0,0,0,.33);\r\n  --chipBot: rgba(0,0,0,.18);\r\n\r\n  --bdBase: color-mix(in srgb, var(--accent) 16%, rgba(255,255,255,.14));\r\n  --bdInner: rgba(255,255,255,.06);\r\n  --shadowOut: rgba(0,0,0,.60);\r\n\r\n  --txt: rgba(255,255,255,.90);\r\n  --muted: rgba(255,255,255,.72);\r\n\r\n  --lineOpacity: var(--chip-lineOpacity);\r\n  --lineBlur: var(--chip-lineBlur);\r\n  --lineHeight: var(--chip-lineHeight);\r\n\r\n  display:inline-flex;\r\n  align-items:center;\r\n  justify-content: space-between;\r\n  gap: var(--chip-gap-in);\r\n  padding: var(--chip-pad-t) var(--chip-pad-x) var(--chip-pad-b);\r\n  border-radius: var(--chip-radius);\r\n  border:1px solid var(--bdBase);\r\n\r\n  background:\r\n    linear-gradient(180deg, var(--chipTop), rgba(255,255,255,0) 38%),\r\n    linear-gradient(180deg, var(--chipMid), var(--chipBot));\r\n\r\n  box-shadow:\r\n    0 14px 30px var(--shadowOut),\r\n    inset 0 1px 0 rgba(255,255,255,.08),\r\n    inset 0 -1px 0 rgba(0,0,0,.55),\r\n    inset 0 0 0 1px var(--bdInner);\r\n\r\n  position:relative;\r\n  line-height:1;\r\n  cursor:pointer;\r\n  user-select:none;\r\n\r\n  transition:\r\n    transform .15s ease,\r\n    border-color .15s ease,\r\n    box-shadow .15s ease,\r\n    background .15s ease;\r\n}\r\n.cvxEqV8__chip.cvxChip::after{\r\n  content:\"\";\r\n  position:absolute;\r\n  left: var(--chip-line-inset-x);\r\n  right: var(--chip-line-inset-x);\r\n  bottom: var(--chip-line-bottom);\r\n  height: var(--lineHeight);\r\n  border-radius:999px;\r\n  background: color-mix(in srgb, var(--accent) 88%, transparent);\r\n  box-shadow: 0 0 var(--lineBlur) color-mix(in srgb, var(--accent) 28%, transparent);\r\n  opacity: var(--lineOpacity);\r\n  transition: opacity .15s ease, box-shadow .15s ease, transform .15s ease;\r\n}\r\n.cvxEqV8__chip.cvxChip:hover{\r\n  transform: translateY(-1px);\r\n  border-color: color-mix(in srgb, var(--accent) 58%, rgba(255,255,255,.16));\r\n  background:\r\n    linear-gradient(180deg,\r\n      color-mix(in srgb, var(--accent) 6%, transparent),\r\n      rgba(255,255,255,0) 42%),\r\n    linear-gradient(180deg, var(--chipMid), var(--chipBot));\r\n  box-shadow:\r\n    0 16px 34px rgba(0,0,0,.65),\r\n    0 0 0 2px color-mix(in srgb, var(--accent) 12%, transparent),\r\n    inset 0 1px 0 rgba(255,255,255,.08),\r\n    inset 0 -1px 0 rgba(0,0,0,.55),\r\n    inset 0 0 0 1px rgba(255,255,255,.07);\r\n  --lineOpacity: .40;\r\n}\r\n.cvxEqV8__chip.cvxChip:focus-visible{\r\n  border-color: color-mix(in srgb, var(--accent) 60%, rgba(255,255,255,.16));\r\n  box-shadow:\r\n    0 16px 34px rgba(0,0,0,.65),\r\n    0 0 0 2px color-mix(in srgb, var(--accent) 14%, transparent),\r\n    inset 0 1px 0 rgba(255,255,255,.08),\r\n    inset 0 -1px 0 rgba(0,0,0,.55),\r\n    inset 0 0 0 1px rgba(255,255,255,.07);\r\n  --lineOpacity: .44;\r\n}\r\n.cvxEqV8__chip.cvxChip.is-active{\r\n  border-color: color-mix(in srgb, var(--accent) 78%, rgba(255,255,255,.16));\r\n  background:\r\n    linear-gradient(180deg,\r\n      color-mix(in srgb, var(--accent) 12%, transparent),\r\n      rgba(255,255,255,0) 44%),\r\n    linear-gradient(180deg, rgba(0,0,0,.32), rgba(0,0,0,.16));\r\n  box-shadow:\r\n    0 18px 40px rgba(0,0,0,.68),\r\n    0 0 0 2px color-mix(in srgb, var(--accent) 22%, transparent),\r\n    inset 0 1px 0 rgba(255,255,255,.09),\r\n    inset 0 -1px 0 rgba(0,0,0,.55),\r\n    inset 0 0 0 1px color-mix(in srgb, var(--accent) 16%, rgba(255,255,255,.06));\r\n  --lineOpacity: .98;\r\n  --lineBlur: 14px;\r\n}\r\n\r\n.cvxEqV8__chip .cvxChip__label{\r\n  font-weight:900;\r\n  font-size: var(--fs-chip-label);\r\n  letter-spacing: var(--chip-label-ls);\r\n  color: var(--muted);\r\n  white-space:nowrap;\r\n}\r\n.cvxEqV8__chip.cvxChip.is-active .cvxChip__label{ color: rgba(255,255,255,.92); }\r\n\r\n.cvxEqV8__chip .cvxChip__seg{\r\n  display:inline-flex;\r\n  overflow:hidden;\r\n  border-radius: var(--chip-seg-radius);\r\n  border:1px solid rgba(255,255,255,.14);\r\n  background: rgba(0,0,0,.18);\r\n  box-shadow:\r\n    inset 0 1px 0 rgba(255,255,255,.06),\r\n    inset 0 -1px 0 rgba(0,0,0,.45);\r\n}\r\n.cvxEqV8__chip .cvxChip__segBtn{\r\n  padding: var(--chip-seg-pad-y) var(--chip-seg-pad-x);\r\n  font-weight:900;\r\n  font-size: var(--fs-chip-seg);\r\n  letter-spacing: var(--chip-seg-ls);\r\n  color: rgba(255,255,255,.86);\r\n  border:0;\r\n  background: transparent;\r\n  user-select:none;\r\n}\r\n.cvxEqV8__chip .cvxChip__segBtn.is-on{\r\n  background: color-mix(in srgb, var(--accent) 18%, rgba(0,0,0,.22));\r\n  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent) 12%, transparent);\r\n}\r\n.cvxEqV8__chip.cvxChip.is-active .cvxChip__segBtn.is-on{\r\n  background: color-mix(in srgb, var(--accent) 28%, rgba(0,0,0,.22));\r\n  box-shadow:\r\n    inset 0 0 0 1px color-mix(in srgb, var(--accent) 20%, transparent),\r\n    0 0 14px color-mix(in srgb, var(--accent) 14%, transparent);\r\n}\r\n\r\n.cvxEqV8__hint{\r\n  border-radius: 14px;\r\n  border: 1px solid rgba(255,255,255,.09);\r\n  background: rgba(0,0,0,.20);\r\n  padding: var(--hint-pad-y) var(--hint-pad-x);\r\n  font-size: var(--fs-hint);\r\n  color: rgba(255,255,255,.60);\r\n  line-height: 1.35;\r\n  min-width: 0;\r\n}\r\n.cvxEqV8__hint b{ color: rgba(255,255,255,.88); font-weight: 800; }\r\n\r\n\/* =========================================================\r\n   Layout classes (JS)\r\n========================================================= *\/\r\n.cvxEqV8.is-panel-stacked .cvxEqV8__panel{\r\n  grid-template-columns: 1fr;\r\n  grid-template-areas:\r\n    \"intro\"\r\n    \"right\"\r\n    \"eq\";\r\n}\r\n.cvxEqV8.is-panel-stacked .cvxEqV8__hero{ grid-template-columns: 1fr; }\r\n.cvxEqV8.is-panel-stacked .cvxEqV8__meter{ display:none; }\r\n\r\n.cvxEqV8.is-panel-stacked .cvxEqV8__stage{\r\n  width: 100%;\r\n  max-width: var(--stage-w-max-stacked);\r\n  margin-inline: auto;\r\n}\r\n.cvxEqV8.is-panel-stacked .cvxEqV8__stageHint{ max-width: 72%; }\r\n\r\n\/* =========================================================\r\n   Responsive tipograf\u00eda\r\n========================================================= *\/\r\n@media (max-width: 860px){\r\n  .cvxEqV8{\r\n    --fs-kicker: var(--fs-kicker-m);\r\n    --fs-title: var(--fs-title-m);\r\n    --fs-desc: var(--fs-desc-m);\r\n\r\n    --fs-stageLabel: var(--fs-stageLabel-m);\r\n    --fs-stageHint:  var(--fs-stageHint-m);\r\n    --fs-tags:       var(--fs-tags-m);\r\n\r\n    --fs-hud-lbl: var(--fs-hud-lbl-m);\r\n    --fs-hud-val: var(--fs-hud-val-m);\r\n    --fs-grid:    var(--fs-grid-m);\r\n    --fs-meter:   var(--fs-meter-m);\r\n\r\n    --fs-chip-label: var(--fs-chip-label-m);\r\n    --fs-chip-seg:   var(--fs-chip-seg-m);\r\n    --chip-seg-pad-x: var(--chip-seg-pad-x-m);\r\n\r\n    --fs-hint: var(--fs-hint-m);\r\n\r\n    --fs-acc-title: var(--fs-acc-title-m);\r\n    --fs-acc-body:  var(--fs-acc-body-m);\r\n\r\n    --node-hit-r: var(--node-hit-r-m);\r\n  }\r\n}\r\n<\/style>\r\n\r\n<script>\r\n(() => {\r\n  'use strict';\r\n\r\n  const KEY = '__CVX_EQ_V8__';\r\n  if (window[KEY]?.destroy) window[KEY].destroy();\r\n\r\n  const host = document.querySelector('[data-cvx-eq-v8]');\r\n  if (!host) return;\r\n\r\n  const PASSIVE_FALSE = { passive:false };\r\n\r\n  const getNum = (name, fallback) => {\r\n    const v = parseFloat(getComputedStyle(host).getPropertyValue(name));\r\n    return Number.isFinite(v) ? v : fallback;\r\n  };\r\n\r\n  if (getNum('--eq-enabled', 1) <= 0) {\r\n    host.style.display = 'none';\r\n    return;\r\n  }\r\n\r\n  if (getNum('--panel-shell', 1) <= 0) host.classList.add('is-shell-off');\r\n  if (getNum('--stageTop-br', 0) > 0) host.classList.add('is-stageTopBR');\r\n\r\n  const stage = host.querySelector('[data-stage]');\r\n  const stageLabel = host.querySelector('[data-stage-label]');\r\n\r\n  const eqRoot = host.querySelector('#cvxEq13V8');\r\n  const svg = eqRoot?.querySelector('svg');\r\n  const nodesG = eqRoot?.querySelector('.cvxEqV8__nodes');\r\n  const curve = eqRoot?.querySelector('.cvxEqV8__curve');\r\n\r\n  const elSub  = eqRoot?.querySelector('[data-eq-sub]');\r\n  const elBand = eqRoot?.querySelector('[data-eq-band]');\r\n  const elDb   = eqRoot?.querySelector('[data-eq-db]');\r\n  const elFill = host.querySelector('[data-eq-fill]');\r\n  const elThumb= host.querySelector('[data-eq-thumb]');\r\n\r\n  const ctrlWrap = host.querySelector('.cvxEqV8__ctrlWrap');\r\n  const ctrlGrid = host.querySelector('.cvxEqV8__ctrl');\r\n\r\n  if (!stage || !eqRoot || !svg || !nodesG || !curve || !elSub || !elBand || !elDb) return;\r\n\r\n  const clamp = (v,a,b)=> Math.max(a, Math.min(b, v));\r\n\r\n  \/* =========================================================\r\n     Layout sync (panel + hint + chip cols + meter height)\r\n  ========================================================= *\/\r\n  let layoutRaf = 0;\r\n\r\n  function getPxVar(name, fallback){\r\n    const v = parseFloat(getComputedStyle(host).getPropertyValue(name));\r\n    return Number.isFinite(v) ? v : fallback;\r\n  }\r\n\r\n  function syncMeterHeight(){\r\n    if (!svg) return;\r\n    const r = svg.getBoundingClientRect();\r\n    if (!r.height || r.height < 1) return;\r\n    host.style.setProperty('--meter-h', `${Math.round(r.height)}px`);\r\n  }\r\n\r\n  function syncLayout(){\r\n    const vw = window.innerWidth || document.documentElement.clientWidth || 9999;\r\n    const bpPanel = getNum('--bp-panel-stack', 860);\r\n    const bpHint  = getNum('--bp-hint-stack', 767);\r\n\r\n    const panelStacked = vw <= bpPanel;\r\n    host.classList.toggle('is-panel-stacked', panelStacked);\r\n\r\n    const wrapW = ctrlWrap?.getBoundingClientRect().width || 0;\r\n\r\n    const chipMin = getPxVar('--chip-w-min', 150);\r\n    const gap     = getPxVar('--chip-gap', 10);\r\n    const extra   = getPxVar('--chip-fit-extra', 0);\r\n\r\n    const need4 = (4 * chipMin) + (3 * gap) + extra;\r\n    const need2 = (2 * chipMin) + (1 * gap) + extra;\r\n\r\n    const hintMin = getPxVar('--hint-col-min', 270);\r\n    const ctrlGap = getPxVar('--ctrl-gap', 12);\r\n\r\n    \/* Regla:\r\n       - En pantallas chicas (bpHint) o panel apilado => hint abajo.\r\n       - Aun sin bpHint: si no entra [2 chips-col + hintMin + gap], hint abajo.\r\n    *\/\r\n    const mustHintBelow =\r\n      panelStacked ||\r\n      (vw <= bpHint) ||\r\n      (wrapW > 0 && wrapW < (need2 + ctrlGap + hintMin));\r\n\r\n    host.classList.toggle('is-hint-below', mustHintBelow);\r\n\r\n    \/* Chip cols:\r\n       - Hint a la derecha => m\u00e1ximo 2 columnas (2x2).\r\n       - Hint abajo => se permite 4 columnas si entra.\r\n    *\/\r\n    const gridW = ctrlGrid?.getBoundingClientRect().width || wrapW;\r\n\r\n    let cols = 2;\r\n    if (mustHintBelow){\r\n      if (gridW >= need4) cols = 4;\r\n      else if (gridW >= need2) cols = 2;\r\n      else cols = 1;\r\n    } else {\r\n      cols = (gridW >= need2) ? 2 : 1;\r\n    }\r\n\r\n    cols = clamp(cols, 1, 4);\r\n    host.dataset.chipCols = String(cols);\r\n\r\n    \/* Meter height sync (evita que el meter fuerce el alto del bloque) *\/\r\n    syncMeterHeight();\r\n  }\r\n\r\n  function scheduleLayout(){\r\n    if (layoutRaf) cancelAnimationFrame(layoutRaf);\r\n    layoutRaf = requestAnimationFrame(() => {\r\n      layoutRaf = 0;\r\n      syncLayout();\r\n      applyPin(currentSpotKey);\r\n      updateNodeHitRadius();\r\n    });\r\n  }\r\n\r\n  \/* Observers *\/\r\n  let roLayout;\r\n  if (window.ResizeObserver && ctrlWrap){\r\n    roLayout = new ResizeObserver(() => scheduleLayout());\r\n    roLayout.observe(ctrlWrap);\r\n  }\r\n\r\n  \/* =========================================================\r\n     Pin presets + sizing\r\n  ========================================================= *\/\r\n  const PIN_DEFAULTS = {\r\n    touch: { x:60, y:45, rk:0.012, wk:0.18, label:'Panel EQ' },\r\n    menu:  { x:55, y:21, rk:0.012, wk:0.18, label:'Display \/ Men\u00fa' },\r\n    subch: { x:60, y:45, rk:0.012, wk:0.18, label:'Encoder \/ Subcanal' },\r\n  };\r\n\r\n  const PIN_LIMITS = { minR: 7, maxR: 14, minW: 90, maxW: 180 };\r\n\r\n  let currentSpotKey = 'touch';\r\n  let activeEnc = 'master';\r\n  let activeId = 'master.main';\r\n\r\n  function getPreset(key){\r\n    const d = PIN_DEFAULTS[key] || PIN_DEFAULTS.touch;\r\n    return {\r\n      x:  getNum(`--pin-${key}-x`,  d.x),\r\n      y:  getNum(`--pin-${key}-y`,  d.y),\r\n      rk: getNum(`--pin-${key}-rk`, d.rk),\r\n      wk: getNum(`--pin-${key}-wk`, d.wk),\r\n      label: d.label\r\n    };\r\n  }\r\n\r\n  function getSubchEncOffset(enc){\r\n    return {\r\n      dx: getNum(`--subch-enc-${enc}-dx`, 0),\r\n      dy: getNum(`--subch-enc-${enc}-dy`, 0),\r\n    };\r\n  }\r\n  function getSubchIdOffset(id){\r\n    const k = id.replace('.', '-');\r\n    return {\r\n      dx: getNum(`--subch-id-${k}-dx`, 0),\r\n      dy: getNum(`--subch-id-${k}-dy`, 0),\r\n    };\r\n  }\r\n\r\n  function applyPin(presetKey){\r\n    currentSpotKey = presetKey || currentSpotKey;\r\n    const p = getPreset(currentSpotKey);\r\n\r\n    let x = p.x, y = p.y;\r\n\r\n    if (currentSpotKey === 'subch'){\r\n      const oEnc = getSubchEncOffset(activeEnc);\r\n      const oId  = getSubchIdOffset(activeId);\r\n      x += (oEnc.dx || 0) + (oId.dx || 0);\r\n      y += (oEnc.dy || 0) + (oId.dy || 0);\r\n    }\r\n\r\n    host.style.setProperty('--pin-x', `${x}%`);\r\n    host.style.setProperty('--pin-y', `${y}%`);\r\n    if (stageLabel) stageLabel.textContent = p.label || 'Foco';\r\n\r\n    const rect = stage.getBoundingClientRect();\r\n    const r = clamp(rect.width * (p.rk || 0.012), PIN_LIMITS.minR, PIN_LIMITS.maxR);\r\n    const wave = clamp(rect.width * (p.wk || 0.18), PIN_LIMITS.minW, PIN_LIMITS.maxW);\r\n\r\n    host.style.setProperty('--pin-r', `${Math.round(r)}px`);\r\n    host.style.setProperty('--pin-wave', `${Math.round(wave)}px`);\r\n  }\r\n\r\n  \/* =========================================================\r\n     EQ model + rendering\r\n  ========================================================= *\/\r\n  const dbMin = -12, dbMax = 12;\r\n  const vb = { x0: 70, x1: 690, yTop: 25, yBot: 155 };\r\n  const N = 13;\r\n\r\n  const subch = [\r\n    { id:'master.main', label:'MASTER \u2022 MAIN', cssColor:'--c-main' },\r\n    { id:'master.hp',   label:'MASTER \u2022 HP',   cssColor:'--c-hp' },\r\n    { id:'media.aux',   label:'MEDIA \u2022 AUX',   cssColor:'--c-aux' },\r\n    { id:'media.dig',   label:'MEDIA \u2022 DIG',   cssColor:'--c-dig' },\r\n    { id:'in1.a',       label:'IN1 \u2022 A',       cssColor:'--c-in1a' },\r\n    { id:'in1.b',       label:'IN1 \u2022 B',       cssColor:'--c-in1b' },\r\n    { id:'in2.a',       label:'IN2 \u2022 A',       cssColor:'--c-in2a' },\r\n    { id:'in2.b',       label:'IN2 \u2022 B',       cssColor:'--c-in2b' },\r\n  ];\r\n  const byId = new Map(subch.map(t => [t.id, t]));\r\n\r\n  const encPairs = {\r\n    master: ['master.main','master.hp'],\r\n    media:  ['media.aux','media.dig'],\r\n    in1:    ['in1.a','in1.b'],\r\n    in2:    ['in2.a','in2.b'],\r\n  };\r\n\r\n  const encState = {\r\n    master: 'master.main',\r\n    media:  'media.aux',\r\n    in1:    'in1.a',\r\n    in2:    'in2.a',\r\n  };\r\n\r\n  const x = Array.from({length:N}, (_,i)=> vb.x0 + (i*(vb.x1 - vb.x0)\/(N-1)));\r\n\r\n  const eqStore = {};\r\n  const mkFlat = () => Array.from({length:N}, ()=>0);\r\n\r\n  eqStore['master.main'] = [0, 1, 2, 1, 0,-1,-1, 0, 1, 2, 1, 0, 0];\r\n  eqStore['master.hp']   = [0, 0, 2, 1, 0,-1,-2,-1, 0, 1, 1, 0, 0];\r\n  eqStore['media.aux']   = [0, 1, 1, 0,-1,-2,-1, 0, 1, 1, 0, 0, 0];\r\n  eqStore['media.dig']   = [0, 0,-1,-2,-2,-1, 0, 1, 2, 2, 1, 0, 0];\r\n  eqStore['in1.a']       = [0, 0, 1, 2, 1, 0,-1,-1, 0, 1, 2, 1, 0];\r\n  eqStore['in1.b']       = [0,-1,-2,-1, 0, 1, 2, 1, 0,-1,-1, 0, 0];\r\n  eqStore['in2.a']       = [0, 1, 2, 2, 1, 0,-1, 0, 1, 2, 2, 1, 0];\r\n  eqStore['in2.b']       = [0, 0,-1,-1, 0, 1, 2, 2, 1, 0, 0, 0, 0];\r\n\r\n  let db = eqStore['master.main'] || mkFlat();\r\n  let activeBand = 6;\r\n  let dragging = false;\r\n  let raf = 0;\r\n  let dirty = true;\r\n\r\n  function yFromDb(d){\r\n    const t = (dbMax - d) \/ (dbMax - dbMin);\r\n    return vb.yTop + t * (vb.yBot - vb.yTop);\r\n  }\r\n  function dbFromY(y){\r\n    const t = (y - vb.yTop) \/ (vb.yBot - vb.yTop);\r\n    return dbMax - t * (dbMax - dbMin);\r\n  }\r\n\r\n  function catmullRom2bezier(points){\r\n    if (points.length < 2) return '';\r\n    let d = `M ${points[0].x.toFixed(2)} ${points[0].y.toFixed(2)}`;\r\n    for (let i=0; i<points.length-1; i++){\r\n      const p0 = points[i-1] || points[i];\r\n      const p1 = points[i];\r\n      const p2 = points[i+1];\r\n      const p3 = points[i+2] || p2;\r\n\r\n      const c1x = p1.x + (p2.x - p0.x) \/ 6;\r\n      const c1y = p1.y + (p2.y - p0.y) \/ 6;\r\n      const c2x = p2.x - (p3.x - p1.x) \/ 6;\r\n      const c2y = p2.y - (p3.y - p1.y) \/ 6;\r\n\r\n      d += ` C ${c1x.toFixed(2)} ${c1y.toFixed(2)}, ${c2x.toFixed(2)} ${c2y.toFixed(2)}, ${p2.x.toFixed(2)} ${p2.y.toFixed(2)}`;\r\n    }\r\n    return d;\r\n  }\r\n\r\n  function svgPointFromClient(clientX, clientY){\r\n    const rect = svg.getBoundingClientRect();\r\n    const vx = (clientX - rect.left) \/ rect.width  * 720;\r\n    const vy = (clientY - rect.top)  \/ rect.height * 180;\r\n    return { x: vx, y: vy };\r\n  }\r\n\r\n  function setAccentFromSub(id){\r\n    const t = byId.get(id);\r\n    if (!t) return;\r\n    const color = getComputedStyle(host).getPropertyValue(t.cssColor).trim();\r\n    host.style.setProperty('--eq-accent', color || getComputedStyle(host).getPropertyValue('--c-main').trim());\r\n  }\r\n\r\n  function updateReadouts(){\r\n    const t = byId.get(activeId);\r\n    elSub.textContent = t ? t.label : activeId;\r\n\r\n    const v = db[activeBand] ?? 0;\r\n    elDb.textContent = `${v >= 0 ? '+' : ''}${v.toFixed(1)} dB`;\r\n\r\n    if (elFill && elThumb){\r\n      const norm = (v - dbMin) \/ (dbMax - dbMin);\r\n      const yPerc = (1 - norm) * 100;\r\n      elThumb.style.top = `${yPerc}%`;\r\n\r\n      const zero = 50, from = zero, to = yPerc;\r\n      if (to < from){\r\n        elFill.style.top = `${to}%`;\r\n        elFill.style.height = `${from - to}%`;\r\n      }else{\r\n        elFill.style.top = `${from}%`;\r\n        elFill.style.height = `${to - from}%`;\r\n      }\r\n    }\r\n  }\r\n\r\n  function setActiveBand(i){\r\n    activeBand = clamp(i, 0, N-1);\r\n    elBand.textContent = String(activeBand + 1);\r\n    updateReadouts();\r\n\r\n    nodesG.querySelectorAll('.cvxEqV8__node').forEach((g, idx) => {\r\n      g.classList.toggle('is-active', idx === activeBand);\r\n    });\r\n\r\n    dirty = true;\r\n    scheduleDraw();\r\n  }\r\n\r\n  function getNodeHitR(){\r\n    return clamp(getNum('--node-hit-r', 16), 10, 30);\r\n  }\r\n\r\n  function updateNodeHitRadius(){\r\n    const r = getNodeHitR();\r\n    nodesG.querySelectorAll('.cvxEqV8__nodeHit').forEach(c => c.setAttribute('r', String(r)));\r\n  }\r\n\r\n  function buildNodes(){\r\n    nodesG.innerHTML = '';\r\n    const hitR = getNodeHitR();\r\n\r\n    for (let i=0; i<N; i++){\r\n      const g = document.createElementNS('http:\/\/www.w3.org\/2000\/svg','g');\r\n      g.classList.add('cvxEqV8__node');\r\n      g.dataset.idx = String(i);\r\n\r\n      const hit = document.createElementNS('http:\/\/www.w3.org\/2000\/svg','circle');\r\n      hit.setAttribute('class','cvxEqV8__nodeHit');\r\n      hit.setAttribute('r', String(hitR));\r\n\r\n      const glow = document.createElementNS('http:\/\/www.w3.org\/2000\/svg','circle');\r\n      glow.setAttribute('class','cvxEqV8__nodeGlow');\r\n      glow.setAttribute('r','8');\r\n\r\n      const c = document.createElementNS('http:\/\/www.w3.org\/2000\/svg','circle');\r\n      c.setAttribute('r','4.5');\r\n\r\n      g.appendChild(hit);\r\n      g.appendChild(glow);\r\n      g.appendChild(c);\r\n      nodesG.appendChild(g);\r\n\r\n      g.addEventListener('pointerdown', (e) => {\r\n        e.preventDefault();\r\n        e.stopPropagation();\r\n        g.setPointerCapture(e.pointerId);\r\n        dragging = true;\r\n        eqRoot.classList.add('is-highlight');\r\n        setActiveBand(i);\r\n      });\r\n\r\n      g.addEventListener('pointermove', (e) => {\r\n        if (!dragging || activeBand !== i) return;\r\n        e.preventDefault();\r\n        const pt = svgPointFromClient(e.clientX, e.clientY);\r\n        const y = clamp(pt.y, vb.yTop, vb.yBot);\r\n        db[i] = clamp(dbFromY(y), dbMin, dbMax);\r\n        updateReadouts();\r\n        dirty = true;\r\n        scheduleDraw();\r\n      });\r\n\r\n      const stopDrag = () => {\r\n        dragging = false;\r\n        eqRoot.classList.remove('is-highlight');\r\n      };\r\n      g.addEventListener('pointerup', stopDrag);\r\n      g.addEventListener('pointercancel', stopDrag);\r\n\r\n      g.addEventListener('click', () => setActiveBand(i));\r\n    }\r\n    setActiveBand(activeBand);\r\n  }\r\n\r\n  function draw(){\r\n    raf = 0;\r\n    if (!dirty) return;\r\n\r\n    const pts = Array.from({length:N}, (_,i)=>({ x: x[i], y: yFromDb(db[i]) }));\r\n    curve.setAttribute('d', catmullRom2bezier(pts));\r\n\r\n    nodesG.querySelectorAll('.cvxEqV8__node').forEach((g, i) => {\r\n      const y = yFromDb(db[i]);\r\n      g.setAttribute('transform', `translate(${x[i].toFixed(2)},${y.toFixed(2)})`);\r\n    });\r\n\r\n    dirty = false;\r\n  }\r\n  function scheduleDraw(){\r\n    if (raf) return;\r\n    raf = requestAnimationFrame(draw);\r\n  }\r\n\r\n  function animateTo(targetArr, ms=170){\r\n    const start = db.slice();\r\n    const target = targetArr.slice();\r\n    const t0 = performance.now();\r\n\r\n    function step(now){\r\n      const t = clamp((now - t0)\/ms, 0, 1);\r\n      const k = 1 - Math.pow(1 - t, 3);\r\n      for (let i=0;i<N;i++){\r\n        db[i] = start[i] + (target[i] - start[i]) * k;\r\n      }\r\n      updateReadouts();\r\n      dirty = true;\r\n      scheduleDraw();\r\n      if (t < 1) requestAnimationFrame(step);\r\n    }\r\n    requestAnimationFrame(step);\r\n  }\r\n\r\n  const preventTouchScroll = (e) => { if (dragging) e.preventDefault(); };\r\n  window.addEventListener('touchmove', preventTouchScroll, PASSIVE_FALSE);\r\n\r\n  \/* =========================================================\r\n     Chips (encoder + subcanal)\r\n  ========================================================= *\/\r\n  const chipBtns = host.querySelectorAll('.cvxEqV8__chip');\r\n\r\n  function setChipAccent(btn, subId){\r\n    const t = byId.get(subId);\r\n    const color = t ? getComputedStyle(host).getPropertyValue(t.cssColor).trim() : '';\r\n    const final = color || getComputedStyle(host).getPropertyValue('--c-main').trim();\r\n    btn.style.setProperty('--accent', final);\r\n  }\r\n\r\n  function isSecondSeg(enc, id){\r\n    if (enc === 'master') return id.endsWith('.hp');\r\n    if (enc === 'media')  return id.endsWith('.dig');\r\n    if (enc === 'in1')    return id.endsWith('.b');\r\n    if (enc === 'in2')    return id.endsWith('.b');\r\n    return false;\r\n  }\r\n\r\n  function syncChipsUI(){\r\n    chipBtns.forEach(btn => {\r\n      const enc = btn.getAttribute('data-enc');\r\n      btn.classList.toggle('is-active', enc === activeEnc);\r\n\r\n      const currentId = encState[enc];\r\n      setChipAccent(btn, currentId);\r\n\r\n      const segBtns = btn.querySelectorAll('.cvxChip__segBtn');\r\n      if (segBtns.length >= 2){\r\n        const second = isSecondSeg(enc, currentId);\r\n        segBtns[0].classList.toggle('is-on', !second);\r\n        segBtns[1].classList.toggle('is-on',  second);\r\n      }\r\n    });\r\n  }\r\n\r\n  function setActiveSub(id, animated=true){\r\n    if (!byId.has(id)) return;\r\n    const prevId = activeId;\r\n    activeId = id;\r\n\r\n    if (!eqStore[activeId]) eqStore[activeId] = mkFlat();\r\n    const targetArr = eqStore[activeId].slice();\r\n\r\n    db = eqStore[activeId];\r\n    setAccentFromSub(activeId);\r\n    updateReadouts();\r\n    dirty = true;\r\n    scheduleDraw();\r\n\r\n    if (animated && prevId !== activeId){\r\n      for (let i=0;i<N;i++) db[i] = 0;\r\n      animateTo(targetArr, 170);\r\n    }\r\n\r\n    if (currentSpotKey === 'subch') applyPin('subch');\r\n  }\r\n\r\n  function toggleEnc(enc){\r\n    const [a,b] = encPairs[enc] || [];\r\n    if (!a || !b) return;\r\n    encState[enc] = (encState[enc] === a) ? b : a;\r\n  }\r\n\r\n  chipBtns.forEach(btn => {\r\n    const enc = btn.getAttribute('data-enc');\r\n    btn.addEventListener('click', () => {\r\n      if (enc !== activeEnc){\r\n        activeEnc = enc;\r\n        setActiveSub(encState[enc], true);\r\n      } else {\r\n        toggleEnc(enc);\r\n        setActiveSub(encState[enc], true);\r\n      }\r\n      syncChipsUI();\r\n      scheduleLayout();\r\n    });\r\n  });\r\n\r\n  \/* =========================================================\r\n     Accordion -> pin focus\r\n  ========================================================= *\/\r\n  const acc = host.querySelector('[data-acc]');\r\n  const items = acc?.querySelectorAll('[data-acc-item]') || [];\r\n\r\n  items.forEach(item => {\r\n    const btn = item.querySelector('.cvxEqV8__accBtn');\r\n    btn?.addEventListener('click', () => {\r\n      items.forEach(it => it.classList.remove('is-open'));\r\n      item.classList.add('is-open');\r\n\r\n      const key = item.getAttribute('data-spot') || 'touch';\r\n      applyPin(key);\r\n    });\r\n  });\r\n\r\n  \/* =========================================================\r\n     Resize handling\r\n  ========================================================= *\/\r\n  const onResize = () => scheduleLayout();\r\n  window.addEventListener('resize', onResize);\r\n\r\n  \/* =========================================================\r\n     Init\r\n  ========================================================= *\/\r\n  buildNodes();\r\n  setAccentFromSub(activeId);\r\n  syncChipsUI();\r\n  updateReadouts();\r\n\r\n  const openItem = acc?.querySelector('.cvxEqV8__accItem.is-open') || items[0];\r\n  applyPin(openItem?.getAttribute('data-spot') || 'touch');\r\n\r\n  dirty = true;\r\n  scheduleDraw();\r\n\r\n  scheduleLayout();\r\n\r\n  window[KEY] = {\r\n    destroy(){\r\n      cancelAnimationFrame(raf);\r\n      if (layoutRaf) cancelAnimationFrame(layoutRaf);\r\n\r\n      window.removeEventListener('touchmove', preventTouchScroll, PASSIVE_FALSE);\r\n      window.removeEventListener('resize', onResize);\r\n\r\n      if (roLayout) roLayout.disconnect();\r\n\r\n      const clone = host.cloneNode(true);\r\n      host.parentNode && host.parentNode.replaceChild(clone, host);\r\n    }\r\n  };\r\n})();\r\n<\/script>\r\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<\/div>\n\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<div id=\"9d4e93f\" class=\"ha-cs-content-section \">\n\t\t\t\t\t\t\t\t\t\t<div data-elementor-type=\"section\" data-elementor-id=\"2746\" class=\"elementor elementor-2746\" data-elementor-settings=\"{&quot;ha_cmc_init_switcher&quot;:&quot;no&quot;}\">\n\t\t\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-1ac27c1 elementor-section-full_width elementor-section-height-min-height elementor-section-items-stretch animated-fast elementor-section-height-default elementor-invisible\" data-id=\"1ac27c1\" data-element_type=\"section\" data-e-type=\"section\" data-settings=\"{&quot;animation&quot;:&quot;fadeInUp&quot;,&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-08ef47e animated-fast\" data-id=\"08ef47e\" data-element_type=\"column\" data-e-type=\"column\" data-settings=\"{&quot;animation&quot;:&quot;none&quot;,&quot;animation_delay&quot;:1500}\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-c1f2fbf elementor-widget elementor-widget-html\" data-id=\"c1f2fbf\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<section class=\"cvxScope\">\r\n\r\n    <!-- =========================================================\r\n       STARTER KIT (scoped)\r\n  ========================================================== -->\r\n    <style>\r\n        .cvxScope {\r\n            --cvx-accent: #7CE7FF;\r\n\r\n            --cvx-text: rgba(255, 255, 255, .92);\r\n            --cvx-muted: rgba(255, 255, 255, .70);\r\n            --cvx-dim: rgba(255, 255, 255, .55);\r\n\r\n            --cvx-glass: rgba(14, 18, 24, .58);\r\n            --cvx-card: rgba(0, 0, 0, .20);\r\n\r\n            --cvx-stroke: rgba(255, 255, 255, .10);\r\n            --cvx-shadow-panel: 0 22px 60px rgba(0, 0, 0, .55);\r\n            --cvx-shadow-card: 0 18px 50px rgba(0, 0, 0, .45);\r\n            --cvx-shadow-float: 0 16px 34px rgba(0, 0, 0, .65);\r\n\r\n            --cvx-blur: 10px;\r\n\r\n            --cvx-r-panel: 18px;\r\n            --cvx-r-media: 16px;\r\n            --cvx-r-card: 16px;\r\n            --cvx-r-box: 14px;\r\n            --cvx-r-round: 999px;\r\n\r\n            --cvx-font: system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif;\r\n\r\n            --cvx-fs-kicker: 12px;\r\n            --cvx-fs-title: 22px;\r\n            --cvx-fs-body: 12px;\r\n            --cvx-fs-tag: 12px;\r\n            --cvx-fs-ui: 12px;\r\n\r\n            --cvx-lh-title: 1.15;\r\n            --cvx-lh-body: 1.55;\r\n\r\n            --cvx-t: 200ms;\r\n            --cvx-ease: ease-out;\r\n\r\n            font-family: var(--cvx-font);\r\n            color: var(--cvx-text);\r\n            max-width: 100%;\r\n        }\r\n\r\n        .cvxScope,\r\n        .cvxScope * {\r\n            box-sizing: border-box;\r\n        }\r\n\r\n        .cvxScope button {\r\n            font: inherit;\r\n            color: inherit;\r\n            appearance: none;\r\n            -webkit-appearance: none;\r\n            -webkit-tap-highlight-color: transparent;\r\n            touch-action: manipulation;\r\n        }\r\n\r\n        .cvxScope button:focus {\r\n            outline: none;\r\n        }\r\n\r\n        .cvxScope button:focus-visible {\r\n            outline: 2px solid color-mix(in srgb, var(--cvx-accent) 65%, transparent);\r\n            outline-offset: 2px;\r\n            border-radius: 14px;\r\n        }\r\n\r\n        .cvxScope b,\r\n        .cvxScope strong {\r\n            font-weight: 820;\r\n        }\r\n\r\n        @media (prefers-reduced-motion: reduce) {\r\n            .cvxScope * {\r\n                transition-duration: 0ms !important;\r\n                animation-duration: 0ms !important;\r\n            }\r\n        }\r\n\r\n        .cvxKicker {\r\n            display: inline-block;\r\n            font-size: var(--cvx-fs-kicker);\r\n            letter-spacing: .16em;\r\n            text-transform: uppercase;\r\n            color: var(--cvx-muted);\r\n            margin-bottom: 8px;\r\n        }\r\n\r\n        .cvxTitle {\r\n            margin: 0 0 10px;\r\n            font-size: var(--cvx-fs-title);\r\n            line-height: var(--cvx-lh-title);\r\n            color: var(--cvx-text);\r\n        }\r\n\r\n        .cvxDesc {\r\n            margin: 0;\r\n            font-size: var(--cvx-fs-body);\r\n            line-height: var(--cvx-lh-body);\r\n            color: var(--cvx-muted);\r\n        }\r\n\r\n        .cvxDesc b {\r\n            color: var(--cvx-text);\r\n            font-weight: 820;\r\n        }\r\n\r\n        .cvxTags {\r\n            display: flex;\r\n            flex-wrap: wrap;\r\n            gap: 8px;\r\n            margin-top: 12px;\r\n        }\r\n\r\n        .cvxTag {\r\n            font-size: var(--cvx-fs-tag);\r\n            color: rgba(255, 255, 255, .78);\r\n            border: 1px solid rgba(255, 255, 255, .10);\r\n            background: rgba(0, 0, 0, .22);\r\n            padding: 7px 10px;\r\n            border-radius: var(--cvx-r-round);\r\n        }\r\n\r\n        .cvxMedia {\r\n            position: relative;\r\n            aspect-ratio: var(--cvx-media-ar);\r\n            width: 100%;\r\n            border-radius: var(--cvx-r-media);\r\n            border: 1px solid rgba(255, 255, 255, .10);\r\n            overflow: hidden;\r\n            background: rgba(0, 0, 0, .18);\r\n            box-shadow: var(--cvx-shadow-card);\r\n            transform: translateZ(0);\r\n        }\r\n\r\n        .cvxMedia>img {\r\n            width: 100%;\r\n            height: 100%;\r\n            display: block;\r\n            object-fit: var(--cvx-media-fit);\r\n            object-position: var(--cvx-media-pos);\r\n        }\r\n\r\n        .cvxMedia::after {\r\n            content: \"\";\r\n            position: absolute;\r\n            inset: 0;\r\n            pointer-events: none;\r\n            opacity: var(--cvx-media-overlay);\r\n            background:\r\n                radial-gradient(120% 120% at 50% 30%,\r\n                    rgba(0, 0, 0, .10),\r\n                    rgba(0, 0, 0, .55) 70%,\r\n                    rgba(0, 0, 0, .75));\r\n        }\r\n    <\/style>\r\n\r\n    <!-- =========================================================\r\n       M\u00d3DULOS I\/O \u2014 SECCI\u00d3N\r\n  ========================================================== -->\r\n    <div id=\"cvxModulesIO\" class=\"cvxMods\" data-mobile-viewer-first=\"1\" data-mobile-autoscroll=\"0\" aria-label=\"CubeVox M\u00f3dulos I\/O\" style=\"\r\n          --cvx-mods-gap: 12px;\r\n          --cvx-pad-panel: 16px;\r\n          --cvx-mods-padTop: 14px;\r\n\r\n          --cvx-mods-media-ar: 16 \/ 9;\r\n          --cvx-mods-media-h: auto;\r\n          --cvx-mods-media-h-m: auto;\r\n\r\n          --cvx-toast-hold-1: 1400;\r\n          --cvx-toast-hold-2: 1200;\r\n          --cvx-toast-gap:    220;\r\n          --cvx-toast-t:      220;\r\n\r\n          --cvx-cfg-left:   8px;\r\n          --cvx-cfg-right:  8px;\r\n          --cvx-cfg-top:    auto;\r\n          --cvx-cfg-bottom: 0px;\r\n          --cvx-cfg-w:      auto;\r\n          --cvx-cfg-r:      14px;\r\n          --cvx-cfg-maxh:   35%;\r\n          --cvx-cfg-pad:    10px;\r\n\r\n          --cvx-cfg-left-m:   4px;\r\n          --cvx-cfg-right-m:  4px;\r\n          --cvx-cfg-top-m:    auto;\r\n          --cvx-cfg-bottom-m: 0px;\r\n          --cvx-cfg-r-m:      14px;\r\n          --cvx-cfg-maxh-m:   40%;\r\n          --cvx-cfg-pad-m:    8px;\r\n\r\n          --cvx-cfg-head-gap: 10px;\r\n          --cvx-cfg-head-rgap: 10px;\r\n          --cvx-cfg-head-mb:  6px;\r\n\r\n          --cvx-cfg-dot-size: 8px;\r\n          --cvx-cfg-dot-y:    0px;\r\n\r\n          --cvx-cfg-fs-ttl:    11px;\r\n          --cvx-cfg-fs-count:  10px;\r\n          --cvx-cfg-fs-item:   11px;\r\n\r\n          --cvx-cfg-fs-ttl-m:   10px;\r\n          --cvx-cfg-fs-count-m: 9px;\r\n          --cvx-cfg-fs-item-m:  9px;\r\n\r\n          --cvx-cfg-cols:    2;\r\n          --cvx-cfg-gap-x:  20px;\r\n          --cvx-cfg-gap-y:   2px;\r\n\r\n          --cvx-cfg-cols-m:  2;\r\n          --cvx-cfg-gap-x-m: 12px;\r\n          --cvx-cfg-gap-y-m:  2px;\r\n\r\n          --cvx-cfg-pill-padY: 4px;\r\n          --cvx-cfg-pill-padX: 8px;\r\n          --cvx-cfg-pill-r:    6px;\r\n\r\n          --cvx-cfg-count-ml:   auto;\r\n          --cvx-cfg-count-minw: 96px;\r\n          --cvx-cfg-count-ta:   right;\r\n          --cvx-cfg-count-x:    0px;\r\n          --cvx-cfg-count-y:    0px;\r\n\r\n          --cvx-cfg-hide-disabled: 0;\r\n\r\n          --cvx-cfg-audio-on: 1;\r\n          --cvx-cfg-audio-mt: -6px;\r\n          --cvx-cfg-audio-mr: -5px;\r\n          --cvx-cfg-audio-padX: 10px;\r\n          --cvx-cfg-audio-padY: 2px;\r\n          --cvx-cfg-audio-r: 999px;\r\n          --cvx-cfg-audio-scale: 0.8;\r\n          --cvx-cfg-audio-speed: 900ms;\r\n          --cvx-cfg-audio-gap: 5px;\r\n          --cvx-cfg-audio-barW: 4px;\r\n\r\n          --cvx-status-mt: 16px;\r\n\r\n          --cvx-dlg-pad: 14px;\r\n          --cvx-dlg-maxw: 560px;\r\n          --cvx-dlg-maxh: calc(100svh - 28px);\r\n       \">\r\n\r\n        <div class=\"cvxMods__grid\">\r\n\r\n            <!-- LEFT -->\r\n            <article class=\"cvxModsCard cvxModsCard--list\">\r\n                <div class=\"cvxModsCard__top\">\r\n                    <div class=\"cvxKicker\">M\u00d3DULOS I\/O<\/div>\r\n                    <h3 class=\"cvxTitle\">Expand\u00ed entradas y salidas sin fricci\u00f3n<\/h3>\r\n                    <p class=\"cvxDesc\">\r\n                        <b>CubeVox<\/b> detecta el m\u00f3dulo y habilita configuraci\u00f3n en <b>men\u00fas dedicados<\/b>.\r\n                    <\/p>\r\n\r\n                    <div class=\"cvxTags\" aria-hidden=\"true\">\r\n                        <span class=\"cvxTag\">Auto-ID<\/span>\r\n                        <span class=\"cvxTag\">Auto-config<\/span>\r\n                        <span class=\"cvxTag\">Men\u00fa dedicado<\/span>\r\n                    <\/div>\r\n                <\/div>\r\n\r\n                <div class=\"cvxModsCard__body\">\r\n                    <div class=\"cvxModsList\" role=\"listbox\" aria-label=\"Selector de m\u00f3dulo\">\r\n\r\n                        <button class=\"cvxModsItem is-active\" type=\"button\" role=\"option\" aria-selected=\"true\" data-mod=\"unbal\">\r\n                            <div class=\"cvxModsItem__main\">\r\n                                <div class=\"cvxModsItem__name\">Unbalanced I|O Expanded<\/div>\r\n                                <div class=\"cvxModsItem__desc\">Para instrumentos, pedales y l\u00edneas cortas.<\/div>\r\n                            <\/div>\r\n                            <div class=\"cvxModsItem__chips\" aria-hidden=\"true\">\r\n                                <span class=\"cvxTag\">4 canales<\/span>\r\n                            <\/div>\r\n                        <\/button>\r\n\r\n                        <button class=\"cvxModsItem\" type=\"button\" role=\"option\" aria-selected=\"false\" data-mod=\"bal\">\r\n                            <div class=\"cvxModsItem__main\">\r\n                                <div class=\"cvxModsItem__name\">Balanced I|O Expanded<\/div>\r\n                                <div class=\"cvxModsItem__desc\">Menos ruido en estudio y tendidos largos.<\/div>\r\n                            <\/div>\r\n                            <div class=\"cvxModsItem__chips\" aria-hidden=\"true\">\r\n                                <span class=\"cvxTag\">2 canales<\/span>\r\n                            <\/div>\r\n                        <\/button>\r\n\r\n                        <button class=\"cvxModsItem\" type=\"button\" role=\"option\" aria-selected=\"false\" data-mod=\"amp\">\r\n                            <div class=\"cvxModsItem__main\">\r\n                                <div class=\"cvxModsItem__name\">Amplified Stereo Output<\/div>\r\n                                <div class=\"cvxModsItem__desc\">Salida amplificada a Speakon para pasivos.<\/div>\r\n                            <\/div>\r\n                            <div class=\"cvxModsItem__chips\" aria-hidden=\"true\">\r\n                                <span class=\"cvxTag\">2\u00d775 W RMS<\/span>\r\n                            <\/div>\r\n                        <\/button>\r\n\r\n                    <\/div>\r\n\r\n                    <div class=\"cvxModsList__foot\">\r\n                        <span class=\"cvxDesc\"><b>Ecosistema en expansi\u00f3n:<\/b> nuevos m\u00f3dulos en desarrollo.<\/span>\r\n                    <\/div>\r\n                <\/div>\r\n            <\/article>\r\n\r\n            <!-- RIGHT -->\r\n            <article class=\"cvxModsCard cvxModsCard--viewer\" id=\"cvxViewer\">\r\n                <div class=\"cvxModsCard__top cvxModsTopRow\">\r\n                    <div class=\"cvxModsTopRow__left\">\r\n                        <span class=\"cvxTag cvxMods__tagDim\">M\u00f3dulo<\/span>\r\n                        <div class=\"cvxModsTopRow__title\" id=\"cvxModTitle\">Unbalanced I|O Expanded<\/div>\r\n                    <\/div>\r\n\r\n                    <div class=\"cvxModsTopRow__right\">\r\n                        <button class=\"cvxSpecBtn\" type=\"button\" id=\"cvxSpecBtn\" aria-haspopup=\"dialog\" aria-controls=\"cvxSpecDlg\" aria-expanded=\"false\">\r\n                            Ficha t\u00e9cnica\r\n                        <\/button>\r\n\r\n                        <label class=\"cvxToggle\" title=\"Simular conexi\u00f3n (auto-ID + auto-config)\">\r\n                            <input id=\"cvxConnect\" type=\"checkbox\">\r\n                            <span class=\"cvxToggle__ui\" aria-hidden=\"true\"><\/span>\r\n                            <span class=\"cvxToggle__lbl\">Conectar<\/span>\r\n                        <\/label>\r\n                    <\/div>\r\n                <\/div>\r\n\r\n                <div class=\"cvxModsCard__body\">\r\n                    <p class=\"cvxModsSubline\" id=\"cvxModSub\"><\/p>\r\n\r\n                    <div class=\"cvxMedia cvxModsMedia\" id=\"cvxModsMedia\" style=\"\r\n            --cvx-media-ar: var(--cvx-mods-media-ar);\r\n            --cvx-media-fit: cover;\r\n            --cvx-media-pos: 50% 50%;\r\n            --cvx-media-overlay: 0.10;\r\n          \">\r\n                        <img id=\"cvxModImg\" alt=\"M\u00f3dulo seleccionado\" loading=\"lazy\">\r\n\r\n                        <div class=\"cvxCfg\" id=\"cvxCfg\" aria-hidden=\"true\">\r\n                            <div class=\"cvxCfg__head\">\r\n                                <span class=\"cvxCfg__dot\" aria-hidden=\"true\"><\/span>\r\n\r\n                                <div class=\"cvxCfg__headTxt\">\r\n                                    <div class=\"cvxCfg__ttl\" id=\"cvxCfgTitle\">Perfil aplicado<\/div>\r\n                                <\/div>\r\n\r\n                                <div class=\"cvxCfg__headR\" aria-hidden=\"true\">\r\n                                    <div class=\"cvxCfg__count\" id=\"cvxCfgCount\">0\/0 canales<\/div>\r\n\r\n                                    <div class=\"cvxCfgAudio\" id=\"cvxCfgAudio\" aria-hidden=\"true\">\r\n                                        <span><\/span><span><\/span><span><\/span><span><\/span><span><\/span>\r\n                                    <\/div>\r\n                                <\/div>\r\n                            <\/div>\r\n\r\n                            <div class=\"cvxCfg__grid\" id=\"cvxCfgRows\"><\/div>\r\n                        <\/div>\r\n\r\n                        <div class=\"cvxToast\" id=\"cvxToast\" role=\"status\" aria-live=\"polite\"><\/div>\r\n                    <\/div>\r\n\r\n                    <div class=\"cvxModsMeta\">\r\n                        <div class=\"cvxBadge\" id=\"cvxStatusBadge\">\r\n                            <span class=\"cvxBadge__dot\" aria-hidden=\"true\"><\/span>\r\n                            <span class=\"cvxBadge__txt\">Desconectado<\/span>\r\n                        <\/div>\r\n\r\n                        <div class=\"cvxModsFoot\">\r\n                            <span class=\"cvxModsNote\" id=\"cvxModsNote\">*Valores sujetos a validaci\u00f3n final.<\/span>\r\n                        <\/div>\r\n                    <\/div>\r\n                <\/div>\r\n            <\/article>\r\n\r\n        <\/div>\r\n\r\n        <!-- =========================================================\r\n         DIALOG \u2014 Ficha t\u00e9cnica\r\n    ========================================================== -->\r\n        <div class=\"cvxSpecDlg\" id=\"cvxSpecDlg\" role=\"dialog\" aria-modal=\"true\" aria-labelledby=\"cvxSpecTitle\" aria-hidden=\"true\">\r\n            <div class=\"cvxSpecDlg__backdrop\" data-cvx-close><\/div>\r\n\r\n            <div class=\"cvxSpecDlg__panel\" role=\"document\">\r\n                <div class=\"cvxSpecDlg__head\">\r\n                    <div class=\"cvxSpecDlg__headL\">\r\n                        <div class=\"cvxSpecDlg__kicker\">FICHA T\u00c9CNICA<\/div>\r\n                        <div class=\"cvxSpecDlg__title\" id=\"cvxSpecTitle\">Unbalanced I|O Expanded<\/div>\r\n                    <\/div>\r\n\r\n                    <button class=\"cvxSpecDlg__close\" type=\"button\" aria-label=\"Cerrar\" data-cvx-close>\u00d7<\/button>\r\n                <\/div>\r\n\r\n                <div class=\"cvxSpecDlg__body\">\r\n                    <ul class=\"cvxSpecList\" id=\"cvxSpecList\"><\/ul>\r\n                    <div class=\"cvxSpecNote\" id=\"cvxSpecNote\" hidden>\r\n                        * Valores sujetos a validaci\u00f3n final.\r\n                    <\/div>\r\n                <\/div>\r\n            <\/div>\r\n        <\/div>\r\n\r\n    <\/div>\r\n\r\n    <!-- =========================================================\r\n       CSS LOCAL\r\n  ========================================================== -->\r\n    <style>\r\n        \/* ===== Layout ===== *\/\r\n        .cvxScope #cvxModulesIO .cvxMods__grid {\r\n            display: grid;\r\n            grid-template-columns: 0.95fr 1.05fr;\r\n            gap: var(--cvx-mods-gap);\r\n        }\r\n\r\n        @media (max-width: 860px) {\r\n            .cvxScope #cvxModulesIO .cvxMods__grid {\r\n                display: flex;\r\n                flex-direction: column;\r\n                gap: var(--cvx-mods-gap);\r\n            }\r\n\r\n            .cvxScope #cvxModulesIO[data-mobile-viewer-first=\"1\"] .cvxModsCard--viewer {\r\n                order: 1;\r\n            }\r\n\r\n            .cvxScope #cvxModulesIO[data-mobile-viewer-first=\"1\"] .cvxModsCard--list {\r\n                order: 2;\r\n            }\r\n\r\n            .cvxScope #cvxModulesIO[data-mobile-viewer-first=\"0\"] .cvxModsCard--list {\r\n                order: 1;\r\n            }\r\n\r\n            .cvxScope #cvxModulesIO[data-mobile-viewer-first=\"0\"] .cvxModsCard--viewer {\r\n                order: 2;\r\n            }\r\n        }\r\n\r\n        \/* ===== Card surface ===== *\/\r\n        .cvxScope #cvxModulesIO .cvxModsCard {\r\n            position: relative;\r\n            border-radius: var(--cvx-r-panel);\r\n            border: 1px solid rgba(255, 255, 255, .10);\r\n            background:\r\n                radial-gradient(140% 120% at 12% 0%, color-mix(in srgb, var(--cvx-accent) 18%, transparent), transparent 58%),\r\n                linear-gradient(180deg, rgba(255, 255, 255, .06), rgba(255, 255, 255, .02)),\r\n                rgba(14, 18, 24, .58);\r\n            box-shadow: var(--cvx-shadow-panel);\r\n            backdrop-filter: blur(var(--cvx-blur));\r\n            -webkit-backdrop-filter: blur(var(--cvx-blur));\r\n            overflow: hidden;\r\n        }\r\n\r\n        .cvxScope #cvxModulesIO .cvxModsCard__top {\r\n            padding: var(--cvx-mods-padTop) var(--cvx-pad-panel);\r\n            border-bottom: 1px solid rgba(255, 255, 255, .07);\r\n        }\r\n\r\n        .cvxScope #cvxModulesIO .cvxModsCard__body {\r\n            padding: var(--cvx-pad-panel);\r\n        }\r\n\r\n        \/* Dim tag *\/\r\n        .cvxScope #cvxModulesIO .cvxMods__tagDim {\r\n            opacity: .82;\r\n            border-color: rgba(255, 255, 255, .10);\r\n            background: rgba(0, 0, 0, .18);\r\n            color: rgba(255, 255, 255, .76);\r\n        }\r\n\r\n        \/* ===== List items (restaura animaciones como antes) ===== *\/\r\n        .cvxScope #cvxModulesIO .cvxModsList {\r\n            display: grid;\r\n            gap: 10px;\r\n        }\r\n\r\n        .cvxScope #cvxModulesIO .cvxModsItem {\r\n            text-align: left;\r\n            width: 100%;\r\n            border-radius: var(--cvx-r-card);\r\n            border: 1px solid rgba(255, 255, 255, .10);\r\n            background:\r\n                linear-gradient(180deg, rgba(255, 255, 255, .03), rgba(255, 255, 255, .012)),\r\n                rgba(0, 0, 0, .16);\r\n            padding: 12px;\r\n            cursor: pointer;\r\n\r\n            display: grid;\r\n            grid-template-columns: 1fr auto;\r\n            gap: 10px 12px;\r\n            align-items: start;\r\n\r\n            transition: transform var(--cvx-t) var(--cvx-ease),\r\n                border-color var(--cvx-t) var(--cvx-ease),\r\n                box-shadow var(--cvx-t) var(--cvx-ease);\r\n        }\r\n\r\n        .cvxScope #cvxModulesIO .cvxModsItem:hover {\r\n            transform: translateY(-1px);\r\n            border-color: rgba(255, 255, 255, .16);\r\n            box-shadow: 0 14px 30px rgba(0, 0, 0, .35);\r\n        }\r\n\r\n        .cvxScope #cvxModulesIO .cvxModsItem.is-active {\r\n            border-color: color-mix(in srgb, var(--cvx-accent) 30%, rgba(255, 255, 255, .16));\r\n            box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--cvx-accent) 16%, transparent);\r\n        }\r\n\r\n        .cvxScope #cvxModulesIO .cvxModsItem__main {\r\n            min-width: 0;\r\n        }\r\n\r\n        .cvxScope #cvxModulesIO .cvxModsItem__name {\r\n            font-size: 14px;\r\n            font-weight: 820;\r\n            color: rgba(255, 255, 255, .92);\r\n        }\r\n\r\n        .cvxScope #cvxModulesIO .cvxModsItem__desc {\r\n            margin-top: 4px;\r\n            font-size: 12px;\r\n            color: rgba(255, 255, 255, .62);\r\n        }\r\n\r\n        .cvxScope #cvxModulesIO .cvxModsItem__chips {\r\n            display: flex;\r\n            gap: 8px;\r\n            align-items: center;\r\n            justify-content: flex-end;\r\n            align-self: center;\r\n        }\r\n\r\n        @media (max-width: 560px) {\r\n            .cvxScope #cvxModulesIO .cvxModsItem {\r\n                grid-template-columns: 1fr;\r\n            }\r\n\r\n            .cvxScope #cvxModulesIO .cvxModsItem__chips {\r\n                justify-content: flex-start;\r\n            }\r\n        }\r\n\r\n        .cvxScope #cvxModulesIO .cvxModsList__foot {\r\n            margin-top: 12px;\r\n            padding-top: 12px;\r\n            border-top: 1px solid rgba(255, 255, 255, .08);\r\n        }\r\n\r\n        \/* ===== Viewer top ===== *\/\r\n        .cvxScope #cvxModulesIO .cvxModsTopRow {\r\n            display: flex;\r\n            align-items: center;\r\n            justify-content: space-between;\r\n            gap: 12px;\r\n            flex-wrap: wrap;\r\n        }\r\n\r\n        .cvxScope #cvxModulesIO .cvxModsTopRow__left {\r\n            display: flex;\r\n            flex-direction: column;\r\n            gap: 8px;\r\n            min-width: 0;\r\n        }\r\n\r\n        .cvxScope #cvxModulesIO .cvxModsTopRow__title {\r\n            font-size: 16px;\r\n            font-weight: 800;\r\n            color: rgba(255, 255, 255, .92);\r\n        }\r\n\r\n        .cvxScope #cvxModulesIO .cvxModsTopRow__right {\r\n            display: flex;\r\n            align-items: center;\r\n            gap: 12px;\r\n            flex-wrap: wrap;\r\n        }\r\n\r\n        .cvxScope #cvxModulesIO .cvxModsSubline {\r\n            margin: 0 0 10px;\r\n            font-size: 12px;\r\n            line-height: 1.35;\r\n            color: rgba(255, 255, 255, .70);\r\n        }\r\n\r\n        .cvxScope #cvxModulesIO .cvxModsSubline b {\r\n            color: rgba(255, 255, 255, .92);\r\n            font-weight: 840;\r\n        }\r\n\r\n        \/* Animaci\u00f3n cambio m\u00f3dulo (mantiene reveal) *\/\r\n        .cvxScope #cvxModulesIO #cvxViewer.is-switching .cvxModsTopRow__title {\r\n            animation: cvxReveal 420ms var(--cvx-ease) both;\r\n        }\r\n\r\n        .cvxScope #cvxModulesIO #cvxViewer.is-switching .cvxModsSubline {\r\n            animation: cvxReveal 520ms var(--cvx-ease) both;\r\n        }\r\n\r\n        @keyframes cvxReveal {\r\n            0% {\r\n                opacity: 0;\r\n                transform: translateY(6px);\r\n                filter: blur(2px);\r\n            }\r\n\r\n            100% {\r\n                opacity: 1;\r\n                transform: translateY(0);\r\n                filter: blur(0);\r\n            }\r\n        }\r\n\r\n        \/* Spec btn *\/\r\n        .cvxScope #cvxModulesIO .cvxSpecBtn {\r\n            border-radius: 999px;\r\n            border: 1px solid rgba(255, 255, 255, .14);\r\n            background: rgba(255, 255, 255, .06);\r\n            padding: 8px 12px;\r\n            font-size: 12px;\r\n            font-weight: 780;\r\n            color: rgba(255, 255, 255, .86);\r\n            cursor: pointer;\r\n            transition: transform var(--cvx-t) var(--cvx-ease),\r\n                border-color var(--cvx-t) var(--cvx-ease),\r\n                background var(--cvx-t) var(--cvx-ease),\r\n                box-shadow var(--cvx-t) var(--cvx-ease);\r\n        }\r\n\r\n        .cvxScope #cvxModulesIO .cvxSpecBtn:hover {\r\n            transform: translateY(-1px);\r\n            border-color: color-mix(in srgb, var(--cvx-accent) 22%, rgba(255, 255, 255, .14));\r\n            box-shadow: 0 10px 22px rgba(0, 0, 0, .30);\r\n        }\r\n\r\n        \/* Toggle *\/\r\n        .cvxScope #cvxModulesIO .cvxToggle {\r\n            display: flex;\r\n            align-items: center;\r\n            gap: 10px;\r\n            cursor: pointer;\r\n            user-select: none;\r\n            color: rgba(255, 255, 255, .78);\r\n            font-size: 12px;\r\n        }\r\n\r\n        .cvxScope #cvxModulesIO .cvxToggle input {\r\n            position: absolute;\r\n            opacity: 0;\r\n            pointer-events: none;\r\n        }\r\n\r\n        .cvxScope #cvxModulesIO .cvxToggle__ui {\r\n            width: 44px;\r\n            height: 26px;\r\n            border-radius: 999px;\r\n            border: 1px solid rgba(255, 255, 255, .14);\r\n            background: rgba(255, 255, 255, .06);\r\n            position: relative;\r\n            transition: background var(--cvx-t) var(--cvx-ease),\r\n                border-color var(--cvx-t) var(--cvx-ease),\r\n                box-shadow var(--cvx-t) var(--cvx-ease);\r\n            box-shadow: inset 0 1px 0 rgba(255, 255, 255, .06);\r\n        }\r\n\r\n        .cvxScope #cvxModulesIO .cvxToggle__ui::before {\r\n            content: \"\";\r\n            width: 20px;\r\n            height: 20px;\r\n            border-radius: 999px;\r\n            position: absolute;\r\n            left: 3px;\r\n            top: 2px;\r\n            background: rgba(255, 255, 255, .78);\r\n            transition: transform var(--cvx-t) var(--cvx-ease),\r\n                background var(--cvx-t) var(--cvx-ease);\r\n            box-shadow: 0 10px 18px rgba(0, 0, 0, .35);\r\n        }\r\n\r\n        .cvxScope #cvxModulesIO .cvxToggle input:checked+.cvxToggle__ui {\r\n            background: color-mix(in srgb, var(--cvx-accent) 18%, rgba(255, 255, 255, .06));\r\n            border-color: color-mix(in srgb, var(--cvx-accent) 32%, rgba(255, 255, 255, .14));\r\n            box-shadow:\r\n                inset 0 1px 0 rgba(255, 255, 255, .06),\r\n                0 0 0 7px color-mix(in srgb, var(--cvx-accent) 12%, transparent);\r\n        }\r\n\r\n        .cvxScope #cvxModulesIO .cvxToggle input:checked+.cvxToggle__ui::before {\r\n            transform: translateX(18px);\r\n            background: rgba(255, 255, 255, .92);\r\n        }\r\n\r\n        \/* Media crossfade *\/\r\n        .cvxScope #cvxModulesIO .cvxModsMedia {\r\n            isolation: isolate;\r\n            height: var(--cvx-mods-media-h);\r\n            transition: box-shadow var(--cvx-t) var(--cvx-ease),\r\n                border-color var(--cvx-t) var(--cvx-ease);\r\n        }\r\n\r\n        @media (max-width: 767px) {\r\n            .cvxScope #cvxModulesIO .cvxModsMedia {\r\n                height: var(--cvx-mods-media-h-m);\r\n            }\r\n        }\r\n\r\n        .cvxScope #cvxModulesIO .cvxModsMedia>img {\r\n            position: relative;\r\n            z-index: 0;\r\n            opacity: 1;\r\n            transform: scale(1);\r\n            transition: opacity 260ms var(--cvx-ease), transform 420ms var(--cvx-ease);\r\n            will-change: opacity, transform;\r\n        }\r\n\r\n        .cvxScope #cvxModulesIO .cvxModsMedia.is-fading>img {\r\n            opacity: 0;\r\n            transform: scale(1.02);\r\n        }\r\n\r\n        \/* Halo alrededor de la imagen cuando est\u00e1 conectado (sin part\u00edculas) *\/\r\n        .cvxScope #cvxModulesIO .cvxModsMedia::before {\r\n            content: \"\";\r\n            position: absolute;\r\n            inset: -2px;\r\n            border-radius: inherit;\r\n            pointer-events: none;\r\n            opacity: 0;\r\n            transition: opacity var(--cvx-t) var(--cvx-ease);\r\n            background:\r\n                radial-gradient(120% 120% at 50% 15%,\r\n                    color-mix(in srgb, var(--cvx-accent) 18%, transparent),\r\n                    transparent 60%),\r\n                radial-gradient(120% 120% at 50% 95%,\r\n                    color-mix(in srgb, var(--cvx-accent) 12%, transparent),\r\n                    transparent 55%);\r\n        }\r\n\r\n        .cvxScope #cvxModulesIO .cvxModsMedia.is-connected {\r\n            border-color: color-mix(in srgb, var(--cvx-accent) 28%, rgba(255, 255, 255, .12));\r\n            box-shadow:\r\n                0 0 0 1px color-mix(in srgb, var(--cvx-accent) 14%, transparent),\r\n                0 0 0 10px color-mix(in srgb, var(--cvx-accent) 10%, transparent),\r\n                var(--cvx-shadow-card);\r\n        }\r\n\r\n        .cvxScope #cvxModulesIO .cvxModsMedia.is-connected::before {\r\n            opacity: 1;\r\n        }\r\n\r\n        \/* ===== Active pulse (glow + blur) para tarjeta seleccionada ===== *\/\r\n        .cvxScope #cvxModulesIO .cvxModsItem {\r\n            position: relative;\r\n            overflow: hidden;\r\n        }\r\n\r\n        .cvxScope #cvxModulesIO .cvxModsItem::before {\r\n            content: \"\";\r\n            position: absolute;\r\n            inset: -14px;\r\n            border-radius: inherit;\r\n            pointer-events: none;\r\n            z-index: 0;\r\n\r\n            \/* \u201cblur glow\u201d *\/\r\n            background:\r\n                radial-gradient(120% 140% at 18% 0%,\r\n                    color-mix(in srgb, var(--cvx-accent) 26%, transparent),\r\n                    transparent 60%),\r\n                radial-gradient(120% 140% at 85% 100%,\r\n                    color-mix(in srgb, var(--cvx-accent) 14%, transparent),\r\n                    transparent 62%);\r\n            filter: blur(14px);\r\n            opacity: 0;\r\n            transform: scale(.98);\r\n            transition: opacity var(--cvx-t) var(--cvx-ease);\r\n            will-change: transform, opacity;\r\n        }\r\n\r\n        .cvxScope #cvxModulesIO .cvxModsItem>* {\r\n            position: relative;\r\n            z-index: 1;\r\n        }\r\n\r\n        .cvxScope #cvxModulesIO .cvxModsItem.is-active::before {\r\n            opacity: .55;\r\n            animation: cvxActivePulse 1.55s ease-in-out infinite;\r\n        }\r\n\r\n        @keyframes cvxActivePulse {\r\n\r\n            0%,\r\n            100% {\r\n                opacity: .32;\r\n                transform: scale(.985);\r\n            }\r\n\r\n            50% {\r\n                opacity: .70;\r\n                transform: scale(1.02);\r\n            }\r\n        }\r\n\r\n        @media (prefers-reduced-motion: reduce) {\r\n            .cvxScope #cvxModulesIO .cvxModsItem.is-active::before {\r\n                animation: none !important;\r\n            }\r\n        }\r\n\r\n        \/* PERFIL *\/\r\n        .cvxScope #cvxModulesIO .cvxCfg {\r\n            position: absolute;\r\n            left: var(--cvx-cfg-left);\r\n            right: var(--cvx-cfg-right);\r\n            top: var(--cvx-cfg-top);\r\n            bottom: var(--cvx-cfg-bottom);\r\n            width: var(--cvx-cfg-w);\r\n            z-index: 4;\r\n\r\n            max-height: var(--cvx-cfg-maxh);\r\n            overflow: hidden;\r\n\r\n            border-radius: var(--cvx-cfg-r);\r\n            border: 1px solid rgba(255, 255, 255, .12);\r\n\r\n            background:\r\n                linear-gradient(180deg, rgba(255, 255, 255, .07), rgba(255, 255, 255, .02)),\r\n                rgba(12, 14, 20, .26);\r\n            backdrop-filter: blur(var(--cvx-blur));\r\n            -webkit-backdrop-filter: blur(var(--cvx-blur));\r\n            box-shadow: 0 18px 46px rgba(0, 0, 0, .42);\r\n\r\n            padding: var(--cvx-cfg-pad);\r\n\r\n            opacity: 0;\r\n            transform: translateY(10px);\r\n            transition: opacity 260ms var(--cvx-ease), transform 260ms var(--cvx-ease);\r\n            pointer-events: none;\r\n        }\r\n\r\n        .cvxScope #cvxModulesIO .cvxModsMedia.cfg-ready .cvxCfg {\r\n            opacity: 1;\r\n            transform: translateY(0);\r\n        }\r\n\r\n        @media (max-width: 767px) {\r\n            .cvxScope #cvxModulesIO .cvxCfg {\r\n                left: var(--cvx-cfg-left-m, var(--cvx-cfg-left));\r\n                right: var(--cvx-cfg-right-m, var(--cvx-cfg-right));\r\n                top: var(--cvx-cfg-top-m, var(--cvx-cfg-top));\r\n                bottom: var(--cvx-cfg-bottom-m, var(--cvx-cfg-bottom));\r\n                border-radius: var(--cvx-cfg-r-m, var(--cvx-cfg-r));\r\n                max-height: var(--cvx-cfg-maxh-m, var(--cvx-cfg-maxh));\r\n                padding: var(--cvx-cfg-pad-m, var(--cvx-cfg-pad));\r\n            }\r\n        }\r\n\r\n        .cvxScope #cvxModulesIO .cvxCfg__head {\r\n            display: flex;\r\n            align-items: center;\r\n            gap: var(--cvx-cfg-head-gap);\r\n            margin-bottom: var(--cvx-cfg-head-mb);\r\n        }\r\n\r\n        .cvxScope #cvxModulesIO .cvxCfg__dot {\r\n            width: var(--cvx-cfg-dot-size);\r\n            height: var(--cvx-cfg-dot-size);\r\n            border-radius: 999px;\r\n            background: color-mix(in srgb, var(--cvx-accent) 92%, white 8%);\r\n            box-shadow: 0 0 14px color-mix(in srgb, var(--cvx-accent) 28%, transparent);\r\n            flex: 0 0 var(--cvx-cfg-dot-size);\r\n            transform: translateY(var(--cvx-cfg-dot-y));\r\n        }\r\n\r\n        .cvxScope #cvxModulesIO .cvxCfg__headTxt {\r\n            min-width: 0;\r\n            flex: 1 1 auto;\r\n        }\r\n\r\n        .cvxScope #cvxModulesIO .cvxCfg__ttl {\r\n            font-size: var(--cvx-cfg-fs-ttl);\r\n            font-weight: 860;\r\n            color: rgba(255, 255, 255, .92);\r\n            line-height: 1.15;\r\n            white-space: nowrap;\r\n            overflow: hidden;\r\n            text-overflow: ellipsis;\r\n        }\r\n\r\n        .cvxScope #cvxModulesIO .cvxCfg__headR {\r\n            display: flex;\r\n            align-items: center;\r\n            gap: var(--cvx-cfg-head-rgap);\r\n            flex: 0 0 auto;\r\n        }\r\n\r\n        .cvxScope #cvxModulesIO .cvxCfg__count {\r\n            font-size: var(--cvx-cfg-fs-count);\r\n            color: rgba(255, 255, 255, .78);\r\n            letter-spacing: .08em;\r\n            text-transform: uppercase;\r\n            white-space: nowrap;\r\n\r\n            margin-left: var(--cvx-cfg-count-ml);\r\n            min-width: var(--cvx-cfg-count-minw);\r\n            text-align: var(--cvx-cfg-count-ta);\r\n            transform: translate(var(--cvx-cfg-count-x), var(--cvx-cfg-count-y));\r\n        }\r\n\r\n        .cvxScope #cvxModulesIO .cvxCfgAudio {\r\n            display: flex;\r\n            gap: var(--cvx-cfg-audio-gap);\r\n            align-items: flex-end;\r\n            padding: var(--cvx-cfg-audio-padY) var(--cvx-cfg-audio-padX);\r\n            border-radius: var(--cvx-cfg-audio-r);\r\n            border: 1px solid rgba(255, 255, 255, .12);\r\n            background: rgba(10, 12, 16, .34);\r\n            backdrop-filter: blur(var(--cvx-blur));\r\n            -webkit-backdrop-filter: blur(var(--cvx-blur));\r\n            transform: scale(var(--cvx-cfg-audio-scale));\r\n            margin-top: var(--cvx-cfg-audio-mt);\r\n            margin-right: var(--cvx-cfg-audio-mr);\r\n            opacity: 0;\r\n            transition: opacity 240ms var(--cvx-ease);\r\n            pointer-events: none;\r\n        }\r\n\r\n        .cvxScope #cvxModulesIO .cvxModsMedia.cfg-ready .cvxCfgAudio {\r\n            opacity: calc(var(--cvx-cfg-audio-on) * 1);\r\n        }\r\n\r\n        .cvxScope #cvxModulesIO .cvxCfgAudio span {\r\n            width: var(--cvx-cfg-audio-barW);\r\n            height: 10px;\r\n            border-radius: 999px;\r\n            background: color-mix(in srgb, var(--cvx-accent) 78%, white 22%);\r\n            box-shadow: 0 0 14px color-mix(in srgb, var(--cvx-accent) 22%, transparent);\r\n            animation: cvxCfgBars var(--cvx-cfg-audio-speed) ease-in-out infinite;\r\n            transform-origin: bottom;\r\n            opacity: .92;\r\n        }\r\n\r\n        .cvxScope #cvxModulesIO .cvxCfgAudio span:nth-child(2) {\r\n            animation-delay: -120ms;\r\n            height: 14px;\r\n        }\r\n\r\n        .cvxScope #cvxModulesIO .cvxCfgAudio span:nth-child(3) {\r\n            animation-delay: -240ms;\r\n            height: 18px;\r\n        }\r\n\r\n        .cvxScope #cvxModulesIO .cvxCfgAudio span:nth-child(4) {\r\n            animation-delay: -160ms;\r\n            height: 12px;\r\n        }\r\n\r\n        .cvxScope #cvxModulesIO .cvxCfgAudio span:nth-child(5) {\r\n            animation-delay: -80ms;\r\n            height: 16px;\r\n        }\r\n\r\n        @keyframes cvxCfgBars {\r\n\r\n            0%,\r\n            100% {\r\n                transform: scaleY(.55);\r\n                opacity: .70;\r\n            }\r\n\r\n            50% {\r\n                transform: scaleY(1.05);\r\n                opacity: 1;\r\n            }\r\n        }\r\n\r\n        .cvxScope #cvxModulesIO .cvxCfg__grid {\r\n            display: grid;\r\n            grid-template-columns: repeat(var(--cvx-cfg-cols), minmax(0, 1fr));\r\n            column-gap: var(--cvx-cfg-gap-x);\r\n            row-gap: var(--cvx-cfg-gap-y);\r\n        }\r\n\r\n        .cvxScope #cvxModulesIO .cvxCfgPill {\r\n            display: grid;\r\n            grid-template-columns: auto 1fr auto;\r\n            gap: 10px;\r\n            align-items: center;\r\n\r\n            border-radius: var(--cvx-cfg-pill-r);\r\n            border: 1px solid rgba(255, 255, 255, .10);\r\n            background: rgba(0, 0, 0, .14);\r\n\r\n            padding: var(--cvx-cfg-pill-padY) var(--cvx-cfg-pill-padX);\r\n\r\n            font-size: var(--cvx-cfg-fs-item);\r\n            color: rgba(255, 255, 255, .80);\r\n            line-height: 1.2;\r\n            min-width: 0;\r\n        }\r\n\r\n        .cvxScope #cvxModulesIO .cvxCfgPill.is-off {\r\n            opacity: .55;\r\n            filter: saturate(.9);\r\n        }\r\n\r\n        .cvxScope #cvxModulesIO .cvxCfgPill b {\r\n            color: rgba(255, 255, 255, .94);\r\n            font-weight: 860;\r\n            white-space: nowrap;\r\n        }\r\n\r\n        .cvxScope #cvxModulesIO .cvxCfgRole {\r\n            color: rgba(255, 255, 255, .70);\r\n            text-transform: uppercase;\r\n            letter-spacing: .10em;\r\n            font-size: var(--cvx-cfg-fs-count);\r\n            justify-self: start;\r\n            white-space: nowrap;\r\n        }\r\n\r\n        .cvxScope #cvxModulesIO .cvxCfgVal {\r\n            color: rgba(255, 255, 255, .92);\r\n            font-weight: 860;\r\n            white-space: nowrap;\r\n        }\r\n\r\n        @media (max-width: 767px) {\r\n            .cvxScope #cvxModulesIO .cvxCfg__grid {\r\n                grid-template-columns: repeat(var(--cvx-cfg-cols-m), minmax(0, 1fr));\r\n                column-gap: var(--cvx-cfg-gap-x-m);\r\n                row-gap: var(--cvx-cfg-gap-y-m);\r\n            }\r\n\r\n            .cvxScope #cvxModulesIO .cvxCfg__ttl {\r\n                font-size: var(--cvx-cfg-fs-ttl-m);\r\n            }\r\n\r\n            .cvxScope #cvxModulesIO .cvxCfg__count {\r\n                font-size: var(--cvx-cfg-fs-count-m);\r\n            }\r\n\r\n            .cvxScope #cvxModulesIO .cvxCfgPill {\r\n                font-size: var(--cvx-cfg-fs-item-m);\r\n            }\r\n\r\n            .cvxScope #cvxModulesIO .cvxCfgRole {\r\n                font-size: var(--cvx-cfg-fs-count-m);\r\n            }\r\n        }\r\n\r\n        \/* Toast *\/\r\n        .cvxScope #cvxModulesIO .cvxToast {\r\n            position: absolute;\r\n            left: 12px;\r\n            top: 12px;\r\n            z-index: 6;\r\n            padding: 10px 12px;\r\n            border-radius: var(--cvx-r-round);\r\n            border: 1px solid color-mix(in srgb, var(--cvx-accent) 28%, rgba(255, 255, 255, .12));\r\n            background: rgba(10, 12, 16, .60);\r\n            backdrop-filter: blur(var(--cvx-blur));\r\n            -webkit-backdrop-filter: blur(var(--cvx-blur));\r\n            color: rgba(255, 255, 255, .92);\r\n            font-size: 12px;\r\n            font-weight: 780;\r\n            opacity: 0;\r\n            transform: translateY(-8px);\r\n            transition: opacity calc(var(--cvx-toast-t) * 1ms) var(--cvx-ease),\r\n                transform calc(var(--cvx-toast-t) * 1ms) var(--cvx-ease);\r\n            box-shadow: 0 18px 46px rgba(0, 0, 0, .42);\r\n        }\r\n\r\n        .cvxScope #cvxModulesIO .cvxToast.is-on {\r\n            opacity: 1;\r\n            transform: translateY(0);\r\n        }\r\n\r\n        \/* Estado *\/\r\n        .cvxScope #cvxModulesIO .cvxModsMeta {\r\n            margin-top: var(--cvx-status-mt);\r\n            display: flex;\r\n            gap: 12px;\r\n            align-items: center;\r\n            flex-wrap: wrap;\r\n        }\r\n\r\n        .cvxScope #cvxModulesIO .cvxBadge {\r\n            display: flex;\r\n            align-items: center;\r\n            gap: 10px;\r\n            padding: 10px 12px;\r\n            border-radius: var(--cvx-r-box);\r\n            border: 1px solid rgba(255, 255, 255, .10);\r\n            background: rgba(0, 0, 0, .16);\r\n            min-width: min(220px, 100%);\r\n        }\r\n\r\n        .cvxScope #cvxModulesIO .cvxBadge__dot {\r\n            width: 10px;\r\n            height: 10px;\r\n            border-radius: 999px;\r\n            background: rgba(255, 255, 255, .24);\r\n        }\r\n\r\n        .cvxScope #cvxModulesIO .cvxBadge.is-on .cvxBadge__dot {\r\n            background: color-mix(in srgb, var(--cvx-accent) 92%, white 8%);\r\n            box-shadow: 0 0 18px color-mix(in srgb, var(--cvx-accent) 30%, transparent);\r\n        }\r\n\r\n        .cvxScope #cvxModulesIO .cvxBadge__txt {\r\n            font-size: 12px;\r\n            font-weight: 780;\r\n            color: rgba(255, 255, 255, .88);\r\n        }\r\n\r\n        .cvxScope #cvxModulesIO .cvxModsFoot {\r\n            flex: 1;\r\n            min-width: 180px;\r\n            display: flex;\r\n            justify-content: flex-end;\r\n        }\r\n\r\n        .cvxScope #cvxModulesIO .cvxModsNote {\r\n            font-size: 12px;\r\n            color: rgba(255, 255, 255, .55);\r\n        }\r\n\r\n        \/* Dialog (centrado SIEMPRE en viewport: soporta \u201cportal\u201d a body) *\/\r\n        .cvxScope #cvxModulesIO .cvxSpecDlg,\r\n        .cvxSpecDlg[data-cvx-portal=\"1\"] {\r\n            position: fixed;\r\n            inset: 0;\r\n            z-index: 999999;\r\n            display: none;\r\n\r\n            font-family: var(--cvx-font);\r\n            color: var(--cvx-text);\r\n        }\r\n\r\n        .cvxScope #cvxModulesIO .cvxSpecDlg.is-on,\r\n        .cvxSpecDlg[data-cvx-portal=\"1\"].is-on {\r\n            display: flex;\r\n            align-items: center;\r\n            justify-content: center;\r\n            padding: var(--cvx-dlg-pad);\r\n        }\r\n\r\n        .cvxScope #cvxModulesIO .cvxSpecDlg__backdrop,\r\n        .cvxSpecDlg[data-cvx-portal=\"1\"] .cvxSpecDlg__backdrop {\r\n            position: absolute;\r\n            inset: 0;\r\n            background: rgba(0, 0, 0, .58);\r\n            backdrop-filter: blur(6px);\r\n            -webkit-backdrop-filter: blur(6px);\r\n            touch-action: none;\r\n        }\r\n\r\n        .cvxScope #cvxModulesIO .cvxSpecDlg__panel,\r\n        .cvxSpecDlg[data-cvx-portal=\"1\"] .cvxSpecDlg__panel {\r\n            position: relative;\r\n            width: min(var(--cvx-dlg-maxw), calc(100vw - 28px));\r\n            max-height: var(--cvx-dlg-maxh);\r\n            border-radius: 18px;\r\n            border: 1px solid rgba(255, 255, 255, .12);\r\n            background:\r\n                radial-gradient(140% 120% at 12% 0%, color-mix(in srgb, var(--cvx-accent) 16%, transparent), transparent 62%),\r\n                linear-gradient(180deg, rgba(255, 255, 255, .06), rgba(255, 255, 255, .02)),\r\n                rgba(10, 12, 16, .72);\r\n            box-shadow: var(--cvx-shadow-float);\r\n            overflow: hidden;\r\n\r\n            display: flex;\r\n            flex-direction: column;\r\n        }\r\n\r\n        .cvxScope #cvxModulesIO .cvxSpecDlg__head,\r\n        .cvxSpecDlg[data-cvx-portal=\"1\"] .cvxSpecDlg__head {\r\n            padding: 16px 16px 12px;\r\n            border-bottom: 1px solid rgba(255, 255, 255, .08);\r\n            display: flex;\r\n            align-items: flex-start;\r\n            justify-content: space-between;\r\n            gap: 12px;\r\n        }\r\n\r\n        .cvxScope #cvxModulesIO .cvxSpecDlg__kicker,\r\n        .cvxSpecDlg[data-cvx-portal=\"1\"] .cvxSpecDlg__kicker {\r\n            font-size: 12px;\r\n            letter-spacing: .16em;\r\n            text-transform: uppercase;\r\n            color: rgba(255, 255, 255, .70);\r\n            margin: 0 0 6px;\r\n        }\r\n\r\n        .cvxScope #cvxModulesIO .cvxSpecDlg__title,\r\n        .cvxSpecDlg[data-cvx-portal=\"1\"] .cvxSpecDlg__title {\r\n            font-size: 16px;\r\n            font-weight: 820;\r\n            color: rgba(255, 255, 255, .92);\r\n            line-height: 1.2;\r\n        }\r\n\r\n        .cvxScope #cvxModulesIO .cvxSpecDlg__close,\r\n        .cvxSpecDlg[data-cvx-portal=\"1\"] .cvxSpecDlg__close {\r\n            width: 40px;\r\n            height: 40px;\r\n            border-radius: 999px;\r\n            border: 1px solid rgba(255, 255, 255, .14);\r\n            background: rgba(255, 255, 255, .06);\r\n\r\n            display: flex;\r\n            align-items: center;\r\n            justify-content: center;\r\n\r\n            cursor: pointer;\r\n            font-size: 24px;\r\n            line-height: 1;\r\n            \/* FIX: centra la \u00d7 *\/\r\n            padding: 0;\r\n            color: rgba(255, 255, 255, .86);\r\n        }\r\n\r\n        .cvxScope #cvxModulesIO .cvxSpecDlg__close:hover,\r\n        .cvxSpecDlg[data-cvx-portal=\"1\"] .cvxSpecDlg__close:hover {\r\n            border-color: rgba(255, 255, 255, .18);\r\n        }\r\n\r\n        .cvxScope #cvxModulesIO .cvxSpecDlg__body,\r\n        .cvxSpecDlg[data-cvx-portal=\"1\"] .cvxSpecDlg__body {\r\n            padding: 12px 16px 16px;\r\n            overflow: auto;\r\n            -webkit-overflow-scrolling: touch;\r\n            overscroll-behavior: contain;\r\n        }\r\n\r\n        .cvxScope #cvxModulesIO .cvxSpecList,\r\n        .cvxSpecDlg[data-cvx-portal=\"1\"] .cvxSpecList {\r\n            margin: 0;\r\n            padding: 0 0 0 16px;\r\n            display: grid;\r\n            gap: 8px;\r\n            color: rgba(255, 255, 255, .78);\r\n            font-size: 12px;\r\n            line-height: 1.45;\r\n        }\r\n\r\n        .cvxScope #cvxModulesIO .cvxSpecList b,\r\n        .cvxSpecDlg[data-cvx-portal=\"1\"] .cvxSpecList b {\r\n            color: rgba(255, 255, 255, .92);\r\n            font-weight: 820;\r\n        }\r\n\r\n        .cvxScope #cvxModulesIO .cvxSpecNote,\r\n        .cvxSpecDlg[data-cvx-portal=\"1\"] .cvxSpecNote {\r\n            margin-top: 12px;\r\n            padding-top: 12px;\r\n            border-top: 1px solid rgba(255, 255, 255, .08);\r\n            color: rgba(255, 255, 255, .62);\r\n            font-size: 12px;\r\n        }\r\n\r\n        @media (prefers-reduced-motion: reduce) {\r\n            .cvxScope #cvxModulesIO .cvxCfgAudio span {\r\n                animation: none !important;\r\n            }\r\n        }\r\n\r\n        \/* Ocultar chip\/label \"M\u00f3dulo\" y recuperar espacio *\/\r\n        .cvxScope #cvxModulesIO .cvxModsTopRow__left>.cvxMods__tagDim {\r\n            display: none !important;\r\n        }\r\n    <\/style>\r\n\r\n    <!-- =========================================================\r\n       JS \u2014 l\u00f3gica (popup centrado viewport + halo restore)\r\n  ========================================================== -->\r\n    <script>\r\n        (() => {\r\n            'use strict';\r\n\r\n            const KEY = '__CVX_MODULES_IO_KIT_V9_FIXPORTAL__';\r\n            if (window[KEY]?.destroy) window[KEY].destroy();\r\n\r\n            const root = document.getElementById('cvxModulesIO');\r\n            if (!root) return;\r\n\r\n            const IMG = {\r\n                unbal: '\/wp-content\/uploads\/cubevox-closed-unbalanced-io-expanded-rear.webp',\r\n                bal: '\/wp-content\/uploads\/cubevox-closed-balanced-io-expanded-rear.webp',\r\n                amp: '\/wp-content\/uploads\/cubevox-closed-amplified-stereo-output-rear.webp'\r\n            };\r\n\r\n            const LANG = (() => {\r\n                const htmlLang = (document.documentElement.getAttribute('lang') || '').toLowerCase();\r\n                if (htmlLang.startsWith('en')) return 'en';\r\n                if (\/^\\\/en(?:\\\/|$)\/i.test(window.location.pathname)) return 'en';\r\n                return 'es';\r\n            })();\r\n\r\n            const I18N = {\r\n                es: {\r\n                    ariaRoot: 'CubeVox M\u00f3dulos I\/O',\r\n                    selectorLabel: 'Selector de m\u00f3dulo',\r\n                    specBtn: 'Ficha t\u00e9cnica',\r\n                    connect: 'Conectar',\r\n                    techSheet: 'FICHA T\u00c9CNICA',\r\n                    close: 'Cerrar',\r\n                    disconnected: 'Desconectado',\r\n                    connected: 'Conectado \u2022 Auto-ID + Auto-config \u2713',\r\n                    detected: 'M\u00f3dulo detectado: %s',\r\n                    profileApplied: 'Perfil aplicado: %s',\r\n                    channels: '%1$s\/%2$s canales',\r\n                    note: '*Valores sujetos a validaci\u00f3n final.'\r\n                },\r\n                en: {\r\n                    ariaRoot: 'CubeVox I\/O Modules',\r\n                    selectorLabel: 'Module selector',\r\n                    specBtn: 'Product Specs',\r\n                    connect: 'Connect',\r\n                    techSheet: 'PRODUCT SPECS',\r\n                    close: 'Close',\r\n                    disconnected: 'Disconnected',\r\n                    connected: 'Connected \u2022 Auto-ID + Auto-config \u2713',\r\n                    detected: 'Module detected: %s',\r\n                    profileApplied: 'Profile applied: %s',\r\n                    channels: '%1$s\/%2$s channels',\r\n                    note: '*Values subject to final validation.'\r\n                }\r\n            };\r\n\r\n            const T = I18N[LANG];\r\n\r\n            function fmt(str, ...args) {\r\n                let i = 0;\r\n                return String(str).replace(\/%(\\d+\\$)?s\/g, (_, n) => {\r\n                    if (n) return String(args[Number(n.slice(0, -1)) - 1] ?? '');\r\n                    return String(args[i++] ?? '');\r\n                });\r\n            }\r\n\r\n            const META = LANG === 'en' ?\r\n                {\r\n                    unbal: {\r\n                        title: 'Unbalanced I|O Expanded',\r\n                        listDesc: 'For instruments, pedals, and short lines.',\r\n                        chip: '4 channels',\r\n                        sub: 'Fine trim per channel to <b>squeeze headroom<\/b> in instrument chains*',\r\n                        profile: 'UNBAL-4TS v1',\r\n                        ports: [{\r\n                                p: 'Port 1',\r\n                                role: 'output',\r\n                                val: '+4 dBu',\r\n                                active: 0\r\n                            },\r\n                            {\r\n                                p: 'Port 2',\r\n                                role: 'input',\r\n                                val: '+14 dBu',\r\n                                active: 1\r\n                            },\r\n                            {\r\n                                p: 'Port 3',\r\n                                role: 'input',\r\n                                val: '+14 dBu',\r\n                                active: 1\r\n                            },\r\n                            {\r\n                                p: 'Port 4',\r\n                                role: 'output',\r\n                                val: '+4 dBu',\r\n                                active: 1\r\n                            }\r\n                        ],\r\n                        specs: [\r\n                            '<b>Format<\/b>: 4 TS channels (unbalanced I\/O)',\r\n                            '<b>Per-port routing<\/b>: each channel configurable as IN or OUT',\r\n                            '<b>Trim<\/b> per channel (input\/output)*'\r\n                        ],\r\n                        note: false\r\n                    },\r\n                    bal: {\r\n                        title: 'Balanced I|O Expanded',\r\n                        listDesc: 'Lower noise in studio and long cable runs.',\r\n                        chip: '2 channels',\r\n                        sub: '<b>Better noise rejection<\/b> and higher stability on <b>long runs<\/b>*',\r\n                        profile: 'BAL-2TRS v1',\r\n                        ports: [{\r\n                                p: 'Channel 1',\r\n                                role: 'output',\r\n                                val: '+4 dBu',\r\n                                active: 1\r\n                            },\r\n                            {\r\n                                p: 'Channel 2',\r\n                                role: 'input',\r\n                                val: '+14 dBu',\r\n                                active: 1\r\n                            }\r\n                        ],\r\n                        specs: [\r\n                            '<b>Format<\/b>: 2 TRS channels (balanced I\/O)',\r\n                            '<b>Per-channel routing<\/b>: configurable as IN or OUT',\r\n                            'Improved immunity to interference'\r\n                        ],\r\n                        note: false\r\n                    },\r\n                    amp: {\r\n                        title: 'Amplified Stereo Output',\r\n                        listDesc: 'Amplified Speakon output for passive speakers.',\r\n                        chip: '2\u00d775 W RMS',\r\n                        sub: '<b>150 W RMS<\/b> total (2\u00d775 W) @ 4 \u03a9 \u2022 routed through <b>Mix Bus<\/b>*',\r\n                        profile: 'AMP-SPEAKON v1',\r\n                        ports: [{\r\n                                p: 'Output L',\r\n                                role: 'output',\r\n                                val: '75 W RMS',\r\n                                active: 1\r\n                            },\r\n                            {\r\n                                p: 'Output R',\r\n                                role: 'output',\r\n                                val: '75 W RMS',\r\n                                active: 1\r\n                            }\r\n                        ],\r\n                        specs: [\r\n                            '<b>Output<\/b>: Speakon (4 poles)',\r\n                            '<b>Power<\/b>: 2\u00d775 W RMS @ 4 \u03a9 (<b>150 W RMS total<\/b>)*',\r\n                            'Routing through <b>Mix Bus<\/b>*'\r\n                        ],\r\n                        note: true\r\n                    }\r\n                } :\r\n                {\r\n                    unbal: {\r\n                        title: 'I\/O Desbalanceado Expandido',\r\n                        listDesc: 'Para instrumentos, pedales y l\u00edneas cortas.',\r\n                        chip: '4 canales',\r\n                        sub: 'Canales con ajuste fino de nivel para <b>exprimir headroom<\/b> en cadenas de instrumento*',\r\n                        profile: 'UNBAL-4TS v1',\r\n                        ports: [{\r\n                                p: 'Puerto 1',\r\n                                role: 'output',\r\n                                val: '+4 dBu',\r\n                                active: 0\r\n                            },\r\n                            {\r\n                                p: 'Puerto 2',\r\n                                role: 'input',\r\n                                val: '+14 dBu',\r\n                                active: 1\r\n                            },\r\n                            {\r\n                                p: 'Puerto 3',\r\n                                role: 'input',\r\n                                val: '+14 dBu',\r\n                                active: 1\r\n                            },\r\n                            {\r\n                                p: 'Puerto 4',\r\n                                role: 'output',\r\n                                val: '+4 dBu',\r\n                                active: 1\r\n                            }\r\n                        ],\r\n                        specs: [\r\n                            '<b>Formato<\/b>: 4 canales TS (I\/O desbalanceado)',\r\n                            '<b>Ruteo por puerto<\/b>: cada canal configurable como IN u OUT',\r\n                            '<b>Trim<\/b> individual por canal (entrada\/salida)*'\r\n                        ],\r\n                        note: false\r\n                    },\r\n                    bal: {\r\n                        title: 'I\/O Balanceado Expandido',\r\n                        listDesc: 'Menos ruido en estudio y tendidos largos.',\r\n                        chip: '2 canales',\r\n                        sub: '<b>Rechazo de ruido<\/b> y estabilidad superior en <b>tendidos largos<\/b>*',\r\n                        profile: 'BAL-2TRS v1',\r\n                        ports: [{\r\n                                p: 'Canal 1',\r\n                                role: 'output',\r\n                                val: '+4 dBu',\r\n                                active: 1\r\n                            },\r\n                            {\r\n                                p: 'Canal 2',\r\n                                role: 'input',\r\n                                val: '+14 dBu',\r\n                                active: 1\r\n                            }\r\n                        ],\r\n                        specs: [\r\n                            '<b>Formato<\/b>: 2 canales TRS (I\/O balanceado)',\r\n                            '<b>Ruteo por canal<\/b>: configurable como IN u OUT',\r\n                            'Mejor inmunidad a interferencias'\r\n                        ],\r\n                        note: false\r\n                    },\r\n                    amp: {\r\n                        title: 'Salida Est\u00e9reo Amplificada',\r\n                        listDesc: 'Salida amplificada a Speakon para pasivos.',\r\n                        chip: '2\u00d775 W RMS',\r\n                        sub: '<b>150 W RMS<\/b> total (2\u00d775 W) @ 4 \u03a9 \u2022 ruteo por <b>Mix Bus<\/b>*',\r\n                        profile: 'AMP-SPEAKON v1',\r\n                        ports: [{\r\n                                p: 'Salida L',\r\n                                role: 'output',\r\n                                val: '75 W RMS',\r\n                                active: 1\r\n                            },\r\n                            {\r\n                                p: 'Salida R',\r\n                                role: 'output',\r\n                                val: '75 W RMS',\r\n                                active: 1\r\n                            }\r\n                        ],\r\n                        specs: [\r\n                            '<b>Salida<\/b>: Speakon (4 polos)',\r\n                            '<b>Potencia<\/b>: 2\u00d775 W RMS @ 4 \u03a9 (<b>150 W RMS total<\/b>)*',\r\n                            'Ruteo por <b>Mix Bus<\/b>*'\r\n                        ],\r\n                        note: true\r\n                    }\r\n                };\r\n            const modBtns = Array.from(root.querySelectorAll('.cvxModsItem'));\r\n            const imgEl = root.querySelector('#cvxModImg');\r\n            const titleEl = root.querySelector('#cvxModTitle');\r\n            const subEl = root.querySelector('#cvxModSub');\r\n            const viewerEl = root.querySelector('#cvxViewer');\r\n            const mediaEl = root.querySelector('#cvxModsMedia');\r\n\r\n            const connectEl = root.querySelector('#cvxConnect');\r\n            const badgeEl = root.querySelector('#cvxStatusBadge');\r\n            const badgeTxt = badgeEl?.querySelector('.cvxBadge__txt');\r\n            const toastEl = root.querySelector('#cvxToast');\r\n\r\n            const cfgTitle = root.querySelector('#cvxCfgTitle');\r\n            const cfgCount = root.querySelector('#cvxCfgCount');\r\n            const cfgRows = root.querySelector('#cvxCfgRows');\r\n            const toggleLbl = root.querySelector('.cvxToggle__lbl');\r\n            const noteEl = root.querySelector('#cvxModsNote');\r\n            const listboxEl = root.querySelector('.cvxModsList');\r\n            const dlgKicker = root.querySelector('.cvxSpecDlg__kicker');\r\n            const closeBtn = root.querySelector('.cvxSpecDlg__close');\r\n            \/\/ Dialog\r\n            let dlg = root.querySelector('#cvxSpecDlg');\r\n            const specBtn = root.querySelector('#cvxSpecBtn');\r\n            let dlgTitle = root.querySelector('#cvxSpecTitle');\r\n            let specList = root.querySelector('#cvxSpecList');\r\n            let specNote = root.querySelector('#cvxSpecNote');\r\n\r\n            let current = 'unbal';\r\n            let toastTimer = null;\r\n            let stepTimers = [];\r\n\r\n            \/\/ Scroll lock\r\n            let prevHtmlOverflow = '';\r\n            let prevBodyOverflow = '';\r\n            let prevBodyPadR = '';\r\n\r\n            function lockScroll() {\r\n                prevHtmlOverflow = document.documentElement.style.overflow || '';\r\n                prevBodyOverflow = document.body.style.overflow || '';\r\n                prevBodyPadR = document.body.style.paddingRight || '';\r\n\r\n                const sbGap = window.innerWidth - document.documentElement.clientWidth;\r\n                if (sbGap > 0) document.body.style.paddingRight = sbGap + 'px';\r\n\r\n                document.documentElement.style.overflow = 'hidden';\r\n                document.body.style.overflow = 'hidden';\r\n            }\r\n\r\n            function unlockScroll() {\r\n                document.documentElement.style.overflow = prevHtmlOverflow;\r\n                document.body.style.overflow = prevBodyOverflow;\r\n                document.body.style.paddingRight = prevBodyPadR;\r\n            }\r\n\r\n            function clearStepTimers() {\r\n                stepTimers.forEach(t => clearTimeout(t));\r\n                stepTimers = [];\r\n            }\r\n\r\n            function readVarNum(name, fallback) {\r\n                const v = getComputedStyle(root).getPropertyValue(name).trim();\r\n                if (!v) return fallback;\r\n                const n = Number(v);\r\n                return Number.isFinite(n) ? n : fallback;\r\n            }\r\n\r\n            function setSafeHTML(el, html) {\r\n                if (!el) return;\r\n                const tmp = document.createElement('div');\r\n                tmp.innerHTML = html || '';\r\n                tmp.querySelectorAll('*').forEach(node => {\r\n                    const tag = node.tagName.toLowerCase();\r\n                    if (tag === 'b' || tag === 'strong' || tag === 'br') {\r\n                        [...node.attributes].forEach(a => node.removeAttribute(a.name));\r\n                        return;\r\n                    }\r\n                    node.replaceWith(...node.childNodes);\r\n                });\r\n                el.innerHTML = tmp.innerHTML;\r\n            }\r\n\r\n            function showToast(msg, holdMs) {\r\n                if (!toastEl) return;\r\n                toastEl.textContent = msg;\r\n                toastEl.classList.add('is-on');\r\n                clearTimeout(toastTimer);\r\n                toastTimer = setTimeout(() => toastEl.classList.remove('is-on'), holdMs);\r\n            }\r\n\r\n            function setImage(url, alt) {\r\n                if (!imgEl || !mediaEl) return;\r\n                mediaEl.classList.add('is-fading');\r\n                const pre = new Image();\r\n                pre.onload = () => {\r\n                    imgEl.src = url;\r\n                    imgEl.alt = alt || 'M\u00f3dulo seleccionado';\r\n                    requestAnimationFrame(() => mediaEl.classList.remove('is-fading'));\r\n                };\r\n                pre.src = url;\r\n            }\r\n\r\n            function revealViewer() {\r\n                if (!viewerEl) return;\r\n                viewerEl.classList.remove('is-switching');\r\n                requestAnimationFrame(() => {\r\n                    viewerEl.classList.add('is-switching');\r\n                    setTimeout(() => viewerEl.classList.remove('is-switching'), 650);\r\n                });\r\n            }\r\n\r\n            function roleToLabel(role) {\r\n                if (role === 'input') return 'IN';\r\n                if (role === 'output') return 'OUT';\r\n                return role ? String(role).toUpperCase() : '';\r\n            }\r\n\r\n            function applyStaticI18n() {\r\n                root.setAttribute('aria-label', T.ariaRoot);\r\n                listboxEl?.setAttribute('aria-label', T.selectorLabel);\r\n\r\n                if (specBtn) specBtn.textContent = T.specBtn;\r\n                if (toggleLbl) toggleLbl.textContent = T.connect;\r\n                if (noteEl) noteEl.textContent = T.note;\r\n                if (dlgKicker) dlgKicker.textContent = T.techSheet;\r\n                if (closeBtn) closeBtn.setAttribute('aria-label', T.close);\r\n\r\n                modBtns.forEach(btn => {\r\n                    const m = META[btn.dataset.mod];\r\n                    if (!m) return;\r\n\r\n                    const nameEl = btn.querySelector('.cvxModsItem__name');\r\n                    const descEl = btn.querySelector('.cvxModsItem__desc');\r\n                    const chipEl = btn.querySelector('.cvxTag');\r\n\r\n                    if (nameEl) nameEl.textContent = m.title;\r\n                    if (descEl) descEl.textContent = m.listDesc;\r\n                    if (chipEl) chipEl.textContent = m.chip;\r\n                });\r\n            }\r\n\r\n            function renderCfg() {\r\n                const m = META[current];\r\n                if (!m) return;\r\n\r\n                const hideDisabled = readVarNum('--cvx-cfg-hide-disabled', 0) === 1;\r\n                const ports = (m.ports || []).map(p => ({\r\n                    ...p,\r\n                    _enabled: !!p.active\r\n                }));\r\n                const total = ports.length;\r\n                const enabledCount = ports.filter(x => x._enabled).length;\r\n\r\n                if (cfgTitle) cfgTitle.textContent = fmt(T.profileApplied, m.profile);\r\n                if (cfgCount) cfgCount.textContent = fmt(T.channels, enabledCount, total);\r\n\r\n                if (cfgRows) {\r\n                    cfgRows.innerHTML = ports\r\n                        .filter(x => hideDisabled ? x._enabled : true)\r\n                        .map(x => {\r\n                            const off = x._enabled ? '' : ' is-off';\r\n                            return `\r\n            <div class=\"cvxCfgPill${off}\">\r\n              <b>${x.p}<\/b>\r\n              <div class=\"cvxCfgRole\">${roleToLabel(x.role)}<\/div>\r\n              <div class=\"cvxCfgVal\">${x.val}<\/div>\r\n            <\/div>\r\n          `;\r\n                        }).join('');\r\n                }\r\n            }\r\n\r\n            function handshake() {\r\n                clearStepTimers();\r\n                const m = META[current];\r\n                if (!m) return;\r\n\r\n                const HOLD1 = readVarNum('--cvx-toast-hold-1', 1400);\r\n                const HOLD2 = readVarNum('--cvx-toast-hold-2', 1200);\r\n                const GAP = readVarNum('--cvx-toast-gap', 220);\r\n\r\n                mediaEl?.classList.remove('cfg-ready');\r\n\r\n                showToast(fmt(T.detected, m.title), HOLD1);\r\n                stepTimers.push(setTimeout(() => {\r\n                    showToast(fmt(T.profileApplied, m.profile), HOLD2);\r\n                }, HOLD1 + GAP));\r\n\r\n                stepTimers.push(setTimeout(() => {\r\n                    mediaEl?.classList.add('cfg-ready');\r\n                }, (HOLD1 + GAP) + HOLD2 + 180));\r\n            }\r\n\r\n            function applyConnectionState({\r\n                handshakeOn = true\r\n            } = {}) {\r\n                const on = !!connectEl?.checked;\r\n\r\n                \/\/ Halo restore\r\n                mediaEl?.classList.toggle('is-connected', on);\r\n\r\n                if (mediaEl && !on) {\r\n                    mediaEl.classList.remove('cfg-ready');\r\n                }\r\n\r\n                if (badgeEl) {\r\n                    badgeEl.classList.toggle('is-on', on);\r\n                    if (badgeTxt) badgeTxt.textContent = on ? T.connected : T.disconnected;\r\n                }\r\n\r\n                if (on) {\r\n                    renderCfg();\r\n                    if (handshakeOn) handshake();\r\n                    else mediaEl?.classList.add('cfg-ready');\r\n                } else {\r\n                    clearStepTimers();\r\n                    showToast(T.disconnected, 1200);\r\n                }\r\n            }\r\n\r\n            function setModule(key, {\r\n                fromClick = false\r\n            } = {}) {\r\n                current = key;\r\n\r\n                modBtns.forEach(b => {\r\n                    const on = b.dataset.mod === key;\r\n                    b.classList.toggle('is-active', on);\r\n                    b.setAttribute('aria-selected', on ? 'true' : 'false');\r\n                });\r\n\r\n                const m = META[key] || {\r\n                    title: key,\r\n                    sub: '',\r\n                    specs: []\r\n                };\r\n\r\n                if (titleEl) titleEl.textContent = m.title || key;\r\n                setSafeHTML(subEl, m.sub || '');\r\n\r\n                setImage(IMG[key], m.title || 'M\u00f3dulo seleccionado');\r\n                revealViewer();\r\n\r\n                if (connectEl?.checked) {\r\n                    applyConnectionState({\r\n                        handshakeOn: true\r\n                    });\r\n                } else {\r\n                    renderCfg();\r\n                    mediaEl?.classList.remove('cfg-ready');\r\n                }\r\n\r\n                if (fromClick && root.dataset.mobileAutoscroll === '1') {\r\n                    const isMobile = window.matchMedia('(max-width: 860px)').matches;\r\n                    if (isMobile) viewerEl?.scrollIntoView({\r\n                        behavior: 'smooth',\r\n                        block: 'start'\r\n                    });\r\n                }\r\n\r\n                if (dlg?.classList.contains('is-on')) renderSpecs();\r\n            }\r\n\r\n            function renderSpecs() {\r\n                const m = META[current] || {\r\n                    title: current,\r\n                    specs: [],\r\n                    note: false\r\n                };\r\n                if (dlgTitle) dlgTitle.textContent = m.title || current;\r\n                if (specList) specList.innerHTML = (m.specs || []).map(s => `<li>${s}<\/li>`).join('');\r\n                if (specNote) specNote.hidden = !m.note;\r\n            }\r\n\r\n            function syncVarsToDlg() {\r\n                if (!dlg) return;\r\n                const cs = getComputedStyle(root);\r\n                const vars = [\r\n                    '--cvx-accent', '--cvx-text', '--cvx-font', '--cvx-blur', '--cvx-shadow-float', '--cvx-t', '--cvx-ease',\r\n                    '--cvx-dlg-pad', '--cvx-dlg-maxw', '--cvx-dlg-maxh'\r\n                ];\r\n                vars.forEach(v => {\r\n                    const val = cs.getPropertyValue(v).trim();\r\n                    if (val) dlg.style.setProperty(v, val);\r\n                });\r\n            }\r\n\r\n            function bindDlgCloseHandlers() {\r\n                if (!dlg) return;\r\n                const closeEls = Array.from(dlg.querySelectorAll('[data-cvx-close]'));\r\n                closeEls.forEach(el => el.addEventListener('click', (e) => {\r\n                    e.preventDefault();\r\n                    closeDlg();\r\n                }));\r\n                dlg.querySelector('.cvxSpecDlg__panel')?.addEventListener('click', (e) => e.stopPropagation());\r\n            }\r\n\r\n            \/\/ Portal a body (evita bugs de \u201cfixed\u201d en contenedores con transform\/backdrop-filter)\r\n            function portalDlgToBody() {\r\n                if (!dlg) return;\r\n                if (dlg.dataset.cvxPortal === '1') return;\r\n\r\n                dlg.dataset.cvxPortal = '1';\r\n                document.body.appendChild(dlg);\r\n\r\n                \/\/ refresca referencias porque el dialog sali\u00f3 del root\r\n                dlgTitle = dlg.querySelector('#cvxSpecTitle');\r\n                specList = dlg.querySelector('#cvxSpecList');\r\n                specNote = dlg.querySelector('#cvxSpecNote');\r\n\r\n                bindDlgCloseHandlers();\r\n            }\r\n\r\n            function openDlg() {\r\n                if (!dlg) return;\r\n\r\n                portalDlgToBody();\r\n                syncVarsToDlg();\r\n                renderSpecs();\r\n\r\n                dlg.classList.add('is-on');\r\n                dlg.setAttribute('aria-hidden', 'false');\r\n                specBtn?.setAttribute('aria-expanded', 'true');\r\n\r\n                lockScroll();\r\n            }\r\n\r\n            function closeDlg() {\r\n                if (!dlg) return;\r\n\r\n                dlg.classList.remove('is-on');\r\n                dlg.setAttribute('aria-hidden', 'true');\r\n                specBtn?.setAttribute('aria-expanded', 'false');\r\n\r\n                unlockScroll();\r\n\r\n                if (window.matchMedia('(pointer:fine)').matches) {\r\n                    try {\r\n                        specBtn?.focus?.({\r\n                            preventScroll: true\r\n                        });\r\n                    } catch (_) {\r\n                        specBtn?.focus?.();\r\n                    }\r\n                }\r\n            }\r\n\r\n            function onKey(e) {\r\n                if (e.key === 'Escape' && dlg?.classList.contains('is-on')) closeDlg();\r\n            }\r\n\r\n            \/\/ Events\r\n            modBtns.forEach(b => b.addEventListener('click', () => setModule(b.dataset.mod, {\r\n                fromClick: true\r\n            })));\r\n            connectEl?.addEventListener('change', () => applyConnectionState({\r\n                handshakeOn: true\r\n            }));\r\n\r\n            specBtn?.addEventListener('click', (e) => {\r\n                e.preventDefault();\r\n                openDlg();\r\n            });\r\n            document.addEventListener('keydown', onKey);\r\n\r\n            applyStaticI18n();\r\n            \/\/ Init\r\n            setModule(current, {\r\n                fromClick: false\r\n            });\r\n            applyConnectionState({\r\n                handshakeOn: false\r\n            });\r\n\r\n            window[KEY] = {\r\n                destroy() {\r\n                    clearTimeout(toastTimer);\r\n                    clearStepTimers();\r\n                    document.removeEventListener('keydown', onKey);\r\n                    try {\r\n                        closeDlg();\r\n                    } catch (_) {}\r\n                }\r\n            };\r\n        })();\r\n    <\/script>\r\n\r\n<\/section>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<\/div>\n\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-9a3b4de elementor-section-height-min-height elementor-section-items-stretch fx_section elementor-section-boxed elementor-section-height-default\" data-id=\"9a3b4de\" data-element_type=\"section\" data-e-type=\"section\" id=\"audioInterface\" data-settings=\"{&quot;background_background&quot;:&quot;gradient&quot;,&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t\t<div class=\"elementor-background-overlay\"><\/div>\n\t\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-375fb3d\" data-id=\"375fb3d\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<section class=\"elementor-section elementor-inner-section elementor-element elementor-element-88147e0 elementor-section-full_width elementor-section-height-default elementor-section-height-default\" data-id=\"88147e0\" data-element_type=\"section\" data-e-type=\"section\" data-settings=\"{&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-no\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-inner-column elementor-element elementor-element-3d5667c\" data-id=\"3d5667c\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-b6580bf animated-slow elementor-invisible elementor-widget elementor-widget-heading\" data-id=\"b6580bf\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;slideInDown&quot;}\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">INTERFAZ DE AUDIO<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-c2a746a elementor-invisible elementor-widget elementor-widget-ha-svg-draw happy-addon ha-svg-draw\" data-id=\"c2a746a\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;slideInLeft&quot;}\" data-widget_type=\"ha-svg-draw.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\n\t\t\t\t<div class=\"ha-svg-draw-container\">\n\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t\n  \n    \n      \n      \n    \n  \n  \n\n\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t<\/div>\n\n\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-inner-section elementor-element elementor-element-93cc2af elementor-section-full_width elementor-section-height-default elementor-section-height-default\" data-id=\"93cc2af\" data-element_type=\"section\" data-e-type=\"section\" data-settings=\"{&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-no\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-inner-column elementor-element elementor-element-b83abfa\" data-id=\"b83abfa\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-b9beb7b animated-slow elementor-invisible elementor-widget elementor-widget-heading\" data-id=\"b9beb7b\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;fadeIn&quot;,&quot;_animation_delay&quot;:300}\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Interfaz de alta fidelidad<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-e86a0a4 elementor-invisible elementor-widget elementor-widget-heading\" data-id=\"e86a0a4\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;fadeInDown&quot;,&quot;_animation_delay&quot;:200}\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Hi-Res 24-bit \/ 192 kHz<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-inner-section elementor-element elementor-element-49a1024 elementor-section-full_width elementor-section-height-default elementor-section-height-default\" data-id=\"49a1024\" data-element_type=\"section\" data-e-type=\"section\" data-settings=\"{&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-no\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-inner-column elementor-element elementor-element-876ddec\" data-id=\"876ddec\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-773d436 elementor-widget elementor-widget-html\" data-id=\"773d436\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<section class=\"cvxScope\">\r\n    <section class=\"cvxPanel\" data-cvx-root=\"audio-interface-hifi\" data-ai-input=\"mic\" data-ai-send=\"fx\" data-ai-monitor=\"dsp\" data-ai-util=\"loopback\" style=\"\r\n      \/* =========================================================\r\n         BREAKPOINTS (JS + CSS)\r\n      ========================================================== *\/\r\n      --cvx-ai-bp-tablet: 980px;\r\n      --cvx-ai-bp-mobile: 620px;\r\n\r\n      \/* =========================================================\r\n         RESPONSIVE VARS (Desktop \/ Tablet \/ Mobile)\r\n      ========================================================== *\/\r\n\r\n      \/* Layout gaps *\/\r\n      --cvx-ai-gap-d: 18px;\r\n      --cvx-ai-gap-t: 16px;\r\n      --cvx-ai-gap-m: 14px;\r\n\r\n      \/* HERO *\/\r\n      --cvx-ai-hero-mb-d: 16px;\r\n      --cvx-ai-hero-mb-t: 14px;\r\n      --cvx-ai-hero-mb-m: 12px;\r\n\r\n      --cvx-ai-kicker-fs-d: 11px;\r\n      --cvx-ai-kicker-fs-t: 11px;\r\n      --cvx-ai-kicker-fs-m: 10px;\r\n\r\n      --cvx-ai-kicker-track-d: .18em;\r\n      --cvx-ai-kicker-track-t: .18em;\r\n      --cvx-ai-kicker-track-m: .18em;\r\n\r\n      --cvx-ai-sub-fs-d: clamp(18px, 2.2vw, 28px);\r\n      --cvx-ai-sub-fs-t: clamp(18px, 3.2vw, 26px);\r\n      --cvx-ai-sub-fs-m: clamp(18px, 6.0vw, 22px);\r\n\r\n      --cvx-ai-sub-lh-d: 1.12;\r\n      --cvx-ai-sub-lh-t: 1.12;\r\n      --cvx-ai-sub-lh-m: 1.12;\r\n\r\n      --cvx-ai-desc-fs-d: 13px;\r\n      --cvx-ai-desc-fs-t: 13px;\r\n      --cvx-ai-desc-fs-m: 11px;\r\n\r\n      --cvx-ai-desc-lh-d: 1.55;\r\n      --cvx-ai-desc-lh-t: 1.55;\r\n      --cvx-ai-desc-lh-m: 1.55;\r\n\r\n      \/* HERO TAGS (los tags del texto superior) *\/\r\n      --cvx-ai-tag-fs-d: 11px;\r\n      --cvx-ai-tag-fs-t: 11px;\r\n      --cvx-ai-tag-fs-m: 9px;\r\n\r\n      --cvx-ai-tag-pad-y-d: 7px;\r\n      --cvx-ai-tag-pad-y-t: 7px;\r\n      --cvx-ai-tag-pad-y-m: 4px;\r\n\r\n      --cvx-ai-tag-pad-x-d: 10px;\r\n      --cvx-ai-tag-pad-x-t: 10px;\r\n      --cvx-ai-tag-pad-x-m: 9px;\r\n\r\n      \/* =========================================================\r\n         STAGE (Diagrama)\r\n      ========================================================== *\/\r\n      --cvx-ai-stage-ar: 17 \/ 10;\r\n      --cvx-ai-stage-img: none;\r\n      --cvx-ai-stage-pos: 50% 35%;\r\n\r\n      \/* Overlay inset fijo (NO deforma el SVG) *\/\r\n      --cvx-ai-stage-inset-d: 10px;\r\n      --cvx-ai-stage-inset-t: 10px;\r\n      --cvx-ai-stage-inset-m: 10px;\r\n\r\n      \/* Escala\/shift uniforme (aire sin deformaci\u00f3n) *\/\r\n      --cvx-ai-stage-scale-d: 1;\r\n      --cvx-ai-stage-scale-t: 1;\r\n      --cvx-ai-stage-scale-m: .94;\r\n\r\n      --cvx-ai-stage-shiftY-d: 0px;\r\n      --cvx-ai-stage-shiftY-t: 0px;\r\n      --cvx-ai-stage-shiftY-m: 6px;\r\n\r\n      \/* SVG TEXT (nodos) *\/\r\n      --cvx-ai-svg-t1-fs-d: 16px; \/* labels (INPUT \/ DSP...) *\/\r\n      --cvx-ai-svg-t1-fs-t: 20px;\r\n      --cvx-ai-svg-t1-fs-m: 20px;\r\n\r\n      --cvx-ai-svg-t1-track-d: .22em;\r\n      --cvx-ai-svg-t1-track-t: .22em;\r\n      --cvx-ai-svg-t1-track-m: .20em;\r\n\r\n      --cvx-ai-svg-t2-fs-d: 16px; \/* values *\/\r\n      --cvx-ai-svg-t2-fs-t: 16px;\r\n      --cvx-ai-svg-t2-fs-m: 16px;\r\n\r\n      \/* SVG NODE STYLE *\/\r\n      --cvx-ai-node-stroke: rgba(255,255,255,.12);\r\n      --cvx-ai-node-stroke-w: 1.25px;\r\n      --cvx-ai-node-fill: rgba(0,0,0,.26);\r\n      --cvx-ai-node-active-stroke: color-mix(in srgb, var(--cvxAccent) 58%, rgba(255,255,255,.22));\r\n      --cvx-ai-node-active-fill: rgba(0,0,0,.32);\r\n\r\n      \/* SVG LINES *\/\r\n      --cvx-ai-edge-w-d: 3px;\r\n      --cvx-ai-edge-w-t: 3px;\r\n      --cvx-ai-edge-w-m: 2.75px;\r\n\r\n      --cvx-ai-edge-flow-w-d: 3.25px;\r\n      --cvx-ai-edge-flow-w-t: 3.25px;\r\n      --cvx-ai-edge-flow-w-m: 3.0px;\r\n\r\n      \/* Legend \u201cpills\u201d dentro del gr\u00e1fico *\/\r\n      --cvx-ai-legend-fs-d: 10px;\r\n      --cvx-ai-legend-fs-t: 10px;\r\n      --cvx-ai-legend-fs-m: 8px;\r\n\r\n      --cvx-ai-legend-pad-y-d: 8px;\r\n      --cvx-ai-legend-pad-y-t: 8px;\r\n      --cvx-ai-legend-pad-y-m: 4px;\r\n\r\n      --cvx-ai-legend-pad-x-d: 16px;\r\n      --cvx-ai-legend-pad-x-t: 10px;\r\n      --cvx-ai-legend-pad-x-m: 8px;\r\n\r\n      --cvx-ai-legend-gap-d: 10px;\r\n      --cvx-ai-legend-gap-t: 10px;\r\n      --cvx-ai-legend-gap-m: 8px;\r\n\r\n      --cvx-ai-legend-bottom-d: 10px;\r\n      --cvx-ai-legend-bottom-t: 10px;\r\n      --cvx-ai-legend-bottom-m: 8px;\r\n\r\n      --cvx-ai-legend-side-d: 12px;\r\n      --cvx-ai-legend-side-t: 12px;\r\n      --cvx-ai-legend-side-m: 8px;\r\n\r\n      --cvx-ai-legend-top-hint-d: 10px; \/* \u201cL\u00ednea animada...\u201d *\/\r\n      --cvx-ai-legend-top-hint-t: 10px;\r\n      --cvx-ai-legend-top-hint-m: 10px;\r\n\r\n      --cvx-ai-legend-max-how-d: calc(100% - 20px);\r\n      --cvx-ai-legend-max-how-t: calc(100% - 20px);\r\n      --cvx-ai-legend-max-how-m: calc(100% - 20px);\r\n\r\n      \/* Badge \u201cFlujo\u201d *\/\r\n      --cvx-ai-badge-fs-d: 10px;\r\n      --cvx-ai-badge-fs-t: 10px;\r\n      --cvx-ai-badge-fs-m: 8px;\r\n\r\n      --cvx-ai-badge-pad-y-d: 8px;\r\n      --cvx-ai-badge-pad-y-t: 8px;\r\n      --cvx-ai-badge-pad-y-m: 4px;\r\n\r\n      --cvx-ai-badge-pad-x-d: 16px;\r\n      --cvx-ai-badge-pad-x-t: 16px;\r\n      --cvx-ai-badge-pad-x-m: 8px;\r\n\r\n      \/* =========================================================\r\n         DIAGRAM POPOVER (tap: send \/ monitor \/ util)\r\n      ========================================================== *\/\r\n      --cvx-ai-pop-fs-d: 11px;\r\n      --cvx-ai-pop-fs-t: 11px;\r\n      --cvx-ai-pop-fs-m: 10px;\r\n\r\n      --cvx-ai-pop-pad-d: 10px;\r\n      --cvx-ai-pop-pad-t: 10px;\r\n      --cvx-ai-pop-pad-m: 9px;\r\n\r\n      --cvx-ai-pop-gap-d: 8px;\r\n      --cvx-ai-pop-gap-t: 8px;\r\n      --cvx-ai-pop-gap-m: 7px;\r\n\r\n      --cvx-ai-pop-radius: 16px;\r\n      --cvx-ai-pop-maxw-d: 280px;\r\n      --cvx-ai-pop-maxw-t: 280px;\r\n      --cvx-ai-pop-maxw-m: 260px;\r\n\r\n      --cvx-ai-pop-btn-pad-y-d: 8px;\r\n      --cvx-ai-pop-btn-pad-y-t: 8px;\r\n      --cvx-ai-pop-btn-pad-y-m: 7px;\r\n\r\n      --cvx-ai-pop-btn-pad-x-d: 10px;\r\n      --cvx-ai-pop-btn-pad-x-t: 10px;\r\n      --cvx-ai-pop-btn-pad-x-m: 9px;\r\n\r\n      \/* =========================================================\r\n         MEDIA CARD (imagen + estado)\r\n      ========================================================== *\/\r\n      --cvx-ai-media-ar: 16 \/ 10;\r\n      --cvx-ai-media-img: url('\/wp-content\/uploads\/cubevox-hifi-trs-connection-render.webp');\r\n      --cvx-ai-media-pos: 50% 50%;\r\n\r\n      --cvx-ai-media-meta-pad-y-d: 12px;\r\n      --cvx-ai-media-meta-pad-y-t: 12px;\r\n      --cvx-ai-media-meta-pad-y-m: 11px;\r\n\r\n      --cvx-ai-media-meta-pad-x-d: 12px;\r\n      --cvx-ai-media-meta-pad-x-t: 12px;\r\n      --cvx-ai-media-meta-pad-x-m: 11px;\r\n\r\n      --cvx-ai-media-k-fs-d: 11px;\r\n      --cvx-ai-media-k-fs-t: 11px;\r\n      --cvx-ai-media-k-fs-m: 10px;\r\n\r\n      --cvx-ai-media-k-track-d: .18em;\r\n      --cvx-ai-media-k-track-t: .18em;\r\n      --cvx-ai-media-k-track-m: .18em;\r\n\r\n      --cvx-ai-media-v-fs-d: 12px;\r\n      --cvx-ai-media-v-fs-t: 12px;\r\n      --cvx-ai-media-v-fs-m: 12px;\r\n\r\n      --cvx-ai-media-v-lh-d: 1.45;\r\n      --cvx-ai-media-v-lh-t: 1.45;\r\n      --cvx-ai-media-v-lh-m: 1.45;\r\n\r\n      \/* =========================================================\r\n         FLOW ANIMATION\r\n      ========================================================== *\/\r\n      --cvx-ai-flow-speed: 1.15s;\r\n      --cvx-ai-line-opacity: .22;\r\n      --cvx-ai-flow-opacity: .92;\r\n\r\n      \/* Accent *\/\r\n      --cvx-ai-accent: var(--cvxAccent);\r\n\r\n      \/* =========================================================\r\n         CONTROLS STYLE (Kit overrides)\r\n      ========================================================== *\/\r\n      --cvx-ai-controls-pad-y-d: 10px;\r\n      --cvx-ai-controls-pad-y-t: 10px;\r\n      --cvx-ai-controls-pad-y-m: 10px;\r\n\r\n      --cvx-ai-controls-pad-x-d: 12px;\r\n      --cvx-ai-controls-pad-x-t: 12px;\r\n      --cvx-ai-controls-pad-x-m: 12px;\r\n\r\n      --cvx-ai-controls-gap-d: 8px;\r\n      --cvx-ai-controls-gap-t: 8px;\r\n      --cvx-ai-controls-gap-m: 8px;\r\n\r\n      --cvx-ai-group-gap: 0px;\r\n      --cvx-ai-btn-gap-d: 8px;\r\n      --cvx-ai-btn-gap-t: 8px;\r\n      --cvx-ai-btn-gap-m: 8px;\r\n\r\n      --cvx-ai-title-fs-d: 10px;\r\n      --cvx-ai-title-fs-t: 10px;\r\n      --cvx-ai-title-fs-m: 10px;\r\n\r\n      --cvx-ai-title-track-d: .14em;\r\n      --cvx-ai-title-track-t: .14em;\r\n      --cvx-ai-title-track-m: .14em;\r\n\r\n      --cvx-ai-row-title-w: 110px;\r\n\r\n      --cvx-ai-chip-pad-y-d: 8px;\r\n      --cvx-ai-chip-pad-y-t: 8px;\r\n      --cvx-ai-chip-pad-y-m: 8px;\r\n\r\n      --cvx-ai-chip-pad-x-d: 10px;\r\n      --cvx-ai-chip-pad-x-t: 10px;\r\n      --cvx-ai-chip-pad-x-m: 10px;\r\n\r\n      --cvx-ai-chip-label-fs-d: 10px;\r\n      --cvx-ai-chip-label-fs-t: 10px;\r\n      --cvx-ai-chip-label-fs-m: 10px;\r\n\r\n      --cvx-ai-chip-seg-fs-d: 9px;\r\n      --cvx-ai-chip-seg-fs-t: 9px;\r\n      --cvx-ai-chip-seg-fs-m: 9px;\r\n\r\n      \/* =========================================================\r\n         CONTROLS LAYOUT (JS)\r\n      ========================================================== *\/\r\n      --cvx-ai-controls-layout-d: row;\r\n      --cvx-ai-controls-layout-t: row;\r\n      --cvx-ai-controls-layout-m: stack;\r\n\r\n      \/* AUX TEXT (JS) *\/\r\n      --cvx-ai-aux-d: active;\r\n      --cvx-ai-aux-t: active;\r\n      --cvx-ai-aux-m: off;\r\n    \">\r\n        <!-- =========================================================\r\n         HERO\r\n    ========================================================== -->\r\n        <header class=\"cvxAiHifiHero\">\r\n            <div class=\"cvxAiHifiHero__txt\">\r\n                <div class=\"cvxKicker\">USB-C \/ ROUTING<\/div>\r\n\r\n\r\n                <p class=\"cvxDesc\">\r\n                    Conect\u00e1 por <b>USB-C<\/b> como interfaz hacia PC\/Mac y control\u00e1 el flujo desde el dispositivo:\r\n                    defin\u00ed si el DAW recibe <b>se\u00f1al limpia<\/b> o <b>procesada<\/b>, y ajust\u00e1 el <b>monitoreo<\/b> sin romper la sesi\u00f3n.\r\n                <\/p>\r\n\r\n                <div class=\"cvxTags\" aria-label=\"Caracter\u00edsticas clave\">\r\n                    <span class=\"cvxTag\">USB-C \u2194 DAW<\/span>\r\n                    <span class=\"cvxTag\">Monitoreo Direct \/ DSP \/ RT<\/span>\r\n                    <span class=\"cvxTag\">Loopback \/ Reamp<\/span>\r\n                    <span class=\"cvxTag\">Safety (Dry+FX)<\/span>\r\n                <\/div>\r\n            <\/div>\r\n        <\/header>\r\n\r\n        <!-- =========================================================\r\n         MAIN GRID\r\n    ========================================================== -->\r\n        <div class=\"cvxAiHifiGrid\">\r\n            <!-- LEFT -->\r\n            <div class=\"cvxAiHifiLeft\">\r\n                <div class=\"cvxStage cvxAiHifiStage\" style=\"\r\n            --stage-ar: var(--cvx-ai-stage-ar);\r\n            --stage-img: var(--cvx-ai-stage-img);\r\n            --stage-bg-pos: var(--cvx-ai-stage-pos);\r\n            --stage-overlay-alpha: .14;\r\n          \" aria-label=\"Diagrama de ruteo de interfaz\">\r\n                    <div class=\"cvxAiHifiOverlay\" aria-hidden=\"true\">\r\n                        <!-- =====================================================\r\n                 DIAGRAMA (SVG)\r\n                 - El dibujo est\u00e1 EN ESTE SVG.\r\n                 - La interacci\u00f3n se hace con rects transparentes data-ai-hit.\r\n            ====================================================== -->\r\n                        <svg class=\"cvxAiHifiSvg\" viewBox=\"0 0 1000 470\" preserveAspectRatio=\"xMidYMid meet\">\r\n                            <!-- NODES (visual) -->\r\n                            <g class=\"n\">\r\n                                <!-- INPUTS (3 bloques) -->\r\n                                <rect class=\"node node--in node--inMic\" x=\"40\" y=\"60\" width=\"190\" height=\"70\" rx=\"18\"><\/rect>\r\n                                <text class=\"t1\" x=\"135\" y=\"96\" text-anchor=\"middle\">INPUT<\/text>\r\n                                <text class=\"t2\" x=\"135\" y=\"120\" text-anchor=\"middle\">MIC \/ XLR<\/text>\r\n\r\n                                <rect class=\"node node--in node--inTrs\" x=\"40\" y=\"170\" width=\"190\" height=\"70\" rx=\"18\"><\/rect>\r\n                                <text class=\"t1\" x=\"135\" y=\"206\" text-anchor=\"middle\">INPUT<\/text>\r\n                                <text class=\"t2\" x=\"135\" y=\"230\" text-anchor=\"middle\">INST\/LINE \/ TRS<\/text>\r\n\r\n                                <rect class=\"node node--in node--inExp\" x=\"40\" y=\"280\" width=\"190\" height=\"70\" rx=\"18\"><\/rect>\r\n                                <text class=\"t1\" x=\"135\" y=\"316\" text-anchor=\"middle\">INPUT<\/text>\r\n                                <text class=\"t2\" x=\"135\" y=\"340\" text-anchor=\"middle\">EXPANDER \/ I\/O<\/text>\r\n\r\n                                <!-- ANALOG FRONT END (antes PRE\/AGC) -->\r\n                                <rect class=\"node\" x=\"300\" y=\"170\" width=\"190\" height=\"70\" rx=\"18\"><\/rect>\r\n\r\n                                <text class=\"t1\" x=\"395\" y=\"196\" text-anchor=\"middle\">\r\n                                    <tspan x=\"395\">ANALOG<\/tspan>\r\n                                    <tspan x=\"395\" dy=\"20\">FRONT END<\/tspan>\r\n                                <\/text>\r\n                                <text class=\"t2\" x=\"395\" y=\"236\" text-anchor=\"middle\">PRE \/ AGC<\/text>\r\n\r\n                                <!-- MIX BUS (nuevo) -->\r\n                                <rect class=\"node\" x=\"510\" y=\"170\" width=\"150\" height=\"70\" rx=\"18\"><\/rect>\r\n                                <text class=\"t1\" x=\"585\" y=\"206\" text-anchor=\"middle\">MIX BUS<\/text>\r\n                                <text class=\"t2\" x=\"585\" y=\"230\" text-anchor=\"middle\">ROUTING<\/text>\r\n\r\n                                <!-- DSP (reubicado) -->\r\n                                <rect class=\"node\" x=\"680\" y=\"170\" width=\"120\" height=\"70\" rx=\"18\"><\/rect>\r\n                                <text class=\"t1\" x=\"740\" y=\"206\" text-anchor=\"middle\">DSP<\/text>\r\n                                <text class=\"t2\" x=\"740\" y=\"230\" text-anchor=\"middle\" data-ai-out=\"nodeDsp\">ON<\/text>\r\n\r\n                                <!-- USB-C (reubicado) -->\r\n                                <rect class=\"node\" x=\"820\" y=\"170\" width=\"150\" height=\"70\" rx=\"18\"><\/rect>\r\n                                <text class=\"t1\" x=\"895\" y=\"206\" text-anchor=\"middle\">USB-C<\/text>\r\n                                <text class=\"t2\" x=\"895\" y=\"230\" text-anchor=\"middle\" data-ai-out=\"nodeUsb\">FX<\/text>\r\n\r\n                                <!-- MONITOR (sin cambio de bloque, se mantiene posici\u00f3n original) -->\r\n                                <rect class=\"node\" x=\"530\" y=\"320\" width=\"210\" height=\"70\" rx=\"18\"><\/rect>\r\n                                <text class=\"t1\" x=\"635\" y=\"356\" text-anchor=\"middle\">MONITOR<\/text>\r\n                                <text class=\"t2\" x=\"635\" y=\"380\" text-anchor=\"middle\" data-ai-out=\"nodeMon\">DSP<\/text>\r\n\r\n                                <!-- OUT (reubicado para alinear con USB) -->\r\n                                <rect class=\"node\" x=\"820\" y=\"320\" width=\"150\" height=\"70\" rx=\"18\"><\/rect>\r\n                                <text class=\"t1\" x=\"895\" y=\"356\" text-anchor=\"middle\">OUT<\/text>\r\n                                <text class=\"t2\" x=\"895\" y=\"380\" text-anchor=\"middle\">HP \/ MAIN<\/text>\r\n\r\n                            <\/g>\r\n\r\n                            <!-- EDGES (base + flow overlay) -->\r\n                            <g class=\"e\">\r\n                                <!-- Inputs -> Analog FE (solo uno se activa) -->\r\n                                <path class=\"edge\" data-ai-edge=\"in-mic-afe\" d=\"M230,95 C265,95 265,205 300,205\"><\/path>\r\n                                <path class=\"edge edge--flow\" data-ai-edge=\"in-mic-afe\" d=\"M230,95 C265,95 265,205 300,205\"><\/path>\r\n\r\n                                <path class=\"edge\" data-ai-edge=\"in-trs-afe\" d=\"M230,205 C260,205 270,205 300,205\"><\/path>\r\n                                <path class=\"edge edge--flow\" data-ai-edge=\"in-trs-afe\" d=\"M230,205 C260,205 270,205 300,205\"><\/path>\r\n\r\n                                <path class=\"edge\" data-ai-edge=\"in-exp-afe\" d=\"M230,315 C265,315 265,205 300,205\"><\/path>\r\n                                <path class=\"edge edge--flow\" data-ai-edge=\"in-exp-afe\" d=\"M230,315 C265,315 265,205 300,205\"><\/path>\r\n\r\n                                <!-- Analog FE -> Mix Bus -->\r\n                                <path class=\"edge\" data-ai-edge=\"afe-mix\" d=\"M490,205 C500,205 500,205 510,205\"><\/path>\r\n                                <path class=\"edge edge--flow\" data-ai-edge=\"afe-mix\" d=\"M490,205 C500,205 500,205 510,205\"><\/path>\r\n\r\n                                <!-- Mix Bus -> DSP -->\r\n                                <path class=\"edge\" data-ai-edge=\"mix-dsp\" d=\"M660,205 C670,205 670,205 680,205\"><\/path>\r\n                                <path class=\"edge edge--flow\" data-ai-edge=\"mix-dsp\" d=\"M660,205 C670,205 670,205 680,205\"><\/path>\r\n\r\n                                <!-- DSP -> USB -->\r\n                                <path class=\"edge\" data-ai-edge=\"dsp-usb\" d=\"M800,205 C810,205 810,205 820,205\"><\/path>\r\n                                <path class=\"edge edge--flow\" data-ai-edge=\"dsp-usb\" d=\"M800,205 C810,205 810,205 820,205\"><\/path>\r\n\r\n                                <!-- Mix Bus -> USB (DRY \/ bypass, ruta superior para evitar cruces) -->\r\n                                <path class=\"edge\" data-ai-edge=\"mix-usb\" d=\"M660,205 C680,110 800,110 820,205\"><\/path>\r\n                                <path class=\"edge edge--flow\" data-ai-edge=\"mix-usb\" d=\"M660,205 C680,110 800,110 820,205\"><\/path>\r\n\r\n                                <!-- DSP -> MON (DSP monitoring) -->\r\n                                <path class=\"edge\" data-ai-edge=\"dsp-mon\" d=\"M740,240 C740,275 690,300 635,320\"><\/path>\r\n                                <path class=\"edge edge--flow\" data-ai-edge=\"dsp-mon\" d=\"M740,240 C740,275 690,300 635,320\"><\/path>\r\n\r\n                                <!-- Mix Bus -> MON (DIRECT monitoring) -->\r\n                                <path class=\"edge\" data-ai-edge=\"mix-mon\" d=\"M585,240 C605,300 440,285 530,355\"><\/path>\r\n                                <path class=\"edge edge--flow\" data-ai-edge=\"mix-mon\" d=\"M585,240 C605,300 440,285 530,355\"><\/path>\r\n\r\n                                <!-- USB -> MON (ROUNDTRIP) -->\r\n                                <path class=\"edge\" data-ai-edge=\"dest-mon\" d=\"M895,240 C895,300 810,305 740,355\"><\/path>\r\n                                <path class=\"edge edge--flow\" data-ai-edge=\"dest-mon\" d=\"M895,240 C895,300 810,305 740,355\"><\/path>\r\n\r\n                                <!-- MON -> OUT -->\r\n                                <path class=\"edge\" data-ai-edge=\"mon-out\" d=\"M740,355 C780,355 780,355 820,355\"><\/path>\r\n                                <path class=\"edge edge--flow\" data-ai-edge=\"mon-out\" d=\"M740,355 C780,355 780,355 820,355\"><\/path>\r\n\r\n                                <!-- UTIL (sin bloque): rutas internas visuales en \u00e1rea superior -->\r\n                                <!-- LOOPBACK: USB -> MIX BUS -->\r\n                                <path class=\"edge\" data-ai-edge=\"usb-mix\" d=\"M895,170 C895,60 585,60 585,170\"><\/path>\r\n                                <path class=\"edge edge--flow\" data-ai-edge=\"usb-mix\" d=\"M895,170 C895,60 585,60 585,170\"><\/path>\r\n\r\n                                <!-- REAMP: USB -> ANALOG FE -->\r\n                                <path class=\"edge\" data-ai-edge=\"usb-afe\" d=\"M895,170 C895,40 395,40 395,170\"><\/path>\r\n                                <path class=\"edge edge--flow\" data-ai-edge=\"usb-afe\" d=\"M895,170 C895,40 395,40 395,170\"><\/path>\r\n                            <\/g>\r\n\r\n\r\n                            <!-- HIT ZONES (interaction) -->\r\n                            <g class=\"h\">\r\n                                <rect class=\"hit\" x=\"40\" y=\"60\" width=\"190\" height=\"70\" rx=\"18\" data-ai-hit=\"input-mic\"><\/rect>\r\n                                <rect class=\"hit\" x=\"40\" y=\"170\" width=\"190\" height=\"70\" rx=\"18\" data-ai-hit=\"input-trs\"><\/rect>\r\n                                <rect class=\"hit\" x=\"40\" y=\"280\" width=\"190\" height=\"70\" rx=\"18\" data-ai-hit=\"input-exp\"><\/rect>\r\n\r\n                                <!-- SEND: ahora sobre USB-C -->\r\n                                <rect class=\"hit\" x=\"820\" y=\"170\" width=\"150\" height=\"70\" rx=\"18\" data-ai-hit=\"send\"><\/rect>\r\n\r\n                                <!-- MONITOR -->\r\n                                <rect class=\"hit\" x=\"530\" y=\"320\" width=\"210\" height=\"70\" rx=\"18\" data-ai-hit=\"monitor\"><\/rect>\r\n\r\n                                <!-- UTIL: ahora sobre Analog Front End (antes era el bloque UTIL) -->\r\n                                <rect class=\"hit\" x=\"300\" y=\"170\" width=\"190\" height=\"70\" rx=\"18\" data-ai-hit=\"util\"><\/rect>\r\n                            <\/g>\r\n\r\n                        <\/svg>\r\n                    <\/div>\r\n\r\n                    <div class=\"cvxAiHifiLegend\" aria-hidden=\"true\">\r\n                        <span class=\"cvxBadge\">Flujo<\/span>\r\n                        <span class=\"cvxAiHifiLegend__txt\" data-ai-out=\"flow\">INPUT \u2192 PRE\/AGC \u2192 (DSP) \u2192 USB-C \/ MON<\/span>\r\n                    <\/div>\r\n\r\n                    <span class=\"cvxAiHifiLegend__how cvxAiHifiLegend__how--tr\" aria-hidden=\"true\">\r\n                        L\u00ednea animada = ruta activa \u00b7 Toc\u00e1 INPUT \/ USB-C \/ MONITOR \/ ANALOG FE\r\n\r\n                    <\/span>\r\n\r\n                    <!-- Popover (tap USB-C \/ MONITOR \/ UTIL) -->\r\n                    <div class=\"cvxAiHifiPop\" hidden aria-hidden=\"true\">\r\n                        <div class=\"cvxAiHifiPop__k\" data-ai-pop=\"title\">Selecci\u00f3n<\/div>\r\n                        <div class=\"cvxAiHifiPop__grid\" data-ai-pop=\"grid\"><\/div>\r\n                    <\/div>\r\n                <\/div>\r\n\r\n                <!-- CONTROLS -->\r\n                <div class=\"cvxAiHifiControls cvxPanel\" role=\"group\" aria-label=\"Controles de demostraci\u00f3n\">\r\n                    <div class=\"cvxAiHifiGroup\">\r\n                        <div class=\"cvxAiHifiGroup__title\">Entrada<\/div>\r\n                        <div class=\"cvxAiHifiBtnGrid\" role=\"tablist\" aria-label=\"Tipo de entrada\">\r\n                            <button class=\"cvxChip is-active cvxAiHifiChip\" type=\"button\" data-ai-group=\"input\" data-ai-value=\"mic\" aria-pressed=\"true\" style=\"--accent: var(--cvx-ai-accent);\">\r\n                                <span class=\"cvxChip__label\">MIC<\/span>\r\n                                <span class=\"cvxChip__seg\" aria-hidden=\"true\"><span class=\"cvxChip__segBtn is-on\">XLR<\/span><\/span>\r\n                            <\/button>\r\n\r\n                            <button class=\"cvxChip cvxAiHifiChip\" type=\"button\" data-ai-group=\"input\" data-ai-value=\"trs\" aria-pressed=\"false\" style=\"--accent: var(--cvx-ai-accent);\">\r\n                                <span class=\"cvxChip__label\">INST\/LINE<\/span>\r\n                                <span class=\"cvxChip__seg\" aria-hidden=\"true\"><span class=\"cvxChip__segBtn is-on\">TRS<\/span><\/span>\r\n                            <\/button>\r\n\r\n                            <button class=\"cvxChip cvxAiHifiChip\" type=\"button\" data-ai-group=\"input\" data-ai-value=\"exp\" aria-pressed=\"false\" style=\"--accent: var(--cvx-ai-accent);\">\r\n                                <span class=\"cvxChip__label\">EXPANDER<\/span>\r\n                                <span class=\"cvxChip__seg\" aria-hidden=\"true\"><span class=\"cvxChip__segBtn is-on\">I\/O<\/span><\/span>\r\n                            <\/button>\r\n                        <\/div>\r\n                    <\/div>\r\n\r\n                    <div class=\"cvxAiHifiGroup cvxHairlineNote\">\r\n                        <div class=\"cvxAiHifiGroup__title\">Env\u00edo a DAW<\/div>\r\n                        <div class=\"cvxAiHifiBtnGrid\" role=\"tablist\" aria-label=\"Qu\u00e9 env\u00eda CubeVox al DAW\">\r\n                            <button class=\"cvxChip is-active cvxAiHifiChip\" type=\"button\" data-ai-group=\"send\" data-ai-value=\"fx\" aria-pressed=\"true\" style=\"--accent: var(--cvx-ai-accent);\">\r\n                                <span class=\"cvxChip__label\">FX<\/span>\r\n                                <span class=\"cvxChip__seg\" aria-hidden=\"true\"><span class=\"cvxChip__segBtn is-on\">PROC<\/span><\/span>\r\n                            <\/button>\r\n\r\n                            <button class=\"cvxChip cvxAiHifiChip\" type=\"button\" data-ai-group=\"send\" data-ai-value=\"dry\" aria-pressed=\"false\" style=\"--accent: var(--cvx-ai-accent);\">\r\n                                <span class=\"cvxChip__label\">DRY<\/span>\r\n                                <span class=\"cvxChip__seg\" aria-hidden=\"true\"><span class=\"cvxChip__segBtn is-on\">CLEAN<\/span><\/span>\r\n                            <\/button>\r\n\r\n                            <button class=\"cvxChip cvxAiHifiChip\" type=\"button\" data-ai-group=\"send\" data-ai-value=\"blend\" aria-pressed=\"false\" style=\"--accent: var(--cvx-ai-accent);\">\r\n                                <span class=\"cvxChip__label\">BLEND<\/span>\r\n                                <span class=\"cvxChip__seg\" aria-hidden=\"true\"><span class=\"cvxChip__segBtn is-on\">MIX<\/span><\/span>\r\n                            <\/button>\r\n                        <\/div>\r\n                    <\/div>\r\n                <\/div>\r\n\r\n                <div class=\"cvxAiHifiControls cvxPanel\" role=\"group\" aria-label=\"Controles de demostraci\u00f3n\">\r\n                    <div class=\"cvxAiHifiGroup\">\r\n                        <div class=\"cvxAiHifiGroup__title\">Monitoreo<\/div>\r\n                        <div class=\"cvxAiHifiBtnGrid\" role=\"tablist\" aria-label=\"Modo de monitoreo\">\r\n                            <button class=\"cvxChip cvxAiHifiChip\" type=\"button\" data-ai-group=\"monitor\" data-ai-value=\"direct\" aria-pressed=\"false\" style=\"--accent: var(--cvx-ai-accent);\">\r\n                                <span class=\"cvxChip__label\">DIRECT<\/span>\r\n                                <span class=\"cvxChip__seg\" aria-hidden=\"true\"><span class=\"cvxChip__segBtn is-on\">SIN DSP<\/span><\/span>\r\n                            <\/button>\r\n\r\n                            <button class=\"cvxChip is-active cvxAiHifiChip\" type=\"button\" data-ai-group=\"monitor\" data-ai-value=\"dsp\" aria-pressed=\"true\" style=\"--accent: var(--cvx-ai-accent);\">\r\n                                <span class=\"cvxChip__label\">DSP<\/span>\r\n                                <span class=\"cvxChip__seg\" aria-hidden=\"true\"><span class=\"cvxChip__segBtn is-on\">FX ON<\/span><\/span>\r\n                            <\/button>\r\n\r\n                            <button class=\"cvxChip cvxAiHifiChip\" type=\"button\" data-ai-group=\"monitor\" data-ai-value=\"roundtrip\" aria-pressed=\"false\" style=\"--accent: var(--cvx-ai-accent);\">\r\n                                <span class=\"cvxChip__label\">RT<\/span>\r\n                                <span class=\"cvxChip__seg\" aria-hidden=\"true\"><span class=\"cvxChip__segBtn is-on\">DAW<\/span><\/span>\r\n                            <\/button>\r\n                        <\/div>\r\n                    <\/div>\r\n\r\n                    <div class=\"cvxAiHifiGroup cvxHairlineNote\">\r\n                        <div class=\"cvxAiHifiGroup__title\">Utilidad<\/div>\r\n                        <div class=\"cvxAiHifiBtnGrid\" role=\"tablist\" aria-label=\"Utilidades de ruteo\">\r\n                            <button class=\"cvxChip is-active cvxAiHifiChip\" type=\"button\" data-ai-group=\"util\" data-ai-value=\"loopback\" aria-pressed=\"true\" style=\"--accent: var(--cvx-ai-accent);\">\r\n                                <span class=\"cvxChip__label\">LOOPBACK<\/span>\r\n                                <span class=\"cvxChip__seg\" aria-hidden=\"true\"><span class=\"cvxChip__segBtn is-on\">INT<\/span><\/span>\r\n                            <\/button>\r\n\r\n                            <button class=\"cvxChip cvxAiHifiChip\" type=\"button\" data-ai-group=\"util\" data-ai-value=\"reamp\" aria-pressed=\"false\" style=\"--accent: var(--cvx-ai-accent);\">\r\n                                <span class=\"cvxChip__label\">REAMP<\/span>\r\n                                <span class=\"cvxChip__seg\" aria-hidden=\"true\"><span class=\"cvxChip__segBtn is-on\">S\/R<\/span><\/span>\r\n                            <\/button>\r\n\r\n                            <button class=\"cvxChip cvxAiHifiChip\" type=\"button\" data-ai-group=\"util\" data-ai-value=\"safety\" aria-pressed=\"false\" style=\"--accent: var(--cvx-ai-accent);\">\r\n                                <span class=\"cvxChip__label\">SAFETY<\/span>\r\n                                <span class=\"cvxChip__seg\" aria-hidden=\"true\"><span class=\"cvxChip__segBtn is-on\">DRY+FX<\/span><\/span>\r\n                            <\/button>\r\n                        <\/div>\r\n                    <\/div>\r\n                <\/div>\r\n            <\/div>\r\n\r\n            <!-- RIGHT -->\r\n            <div class=\"cvxAiHifiRight\">\r\n                <div class=\"cvxCard cvxAiHifiMedia\" aria-label=\"Imagen del dispositivo y estado de ruteo\" aria-live=\"polite\">\r\n                    <div class=\"cvxAiHifiMedia__img\" role=\"img\" aria-label=\"CubeVox\"><\/div>\r\n                    <div class=\"cvxAiHifiMedia__meta\">\r\n                        <div class=\"k\">Estado<\/div>\r\n                        <div class=\"v notranslate\" data-ai-out=\"readout\"><\/div>\r\n                    <\/div>\r\n                <\/div>\r\n\r\n                <div class=\"cvxAcc cvxAiHifiAcc\" aria-label=\"Detalles\">\r\n                    <div class=\"cvxAcc__item is-open\">\r\n                        <button class=\"cvxAcc__btn\" type=\"button\">\r\n                            <span class=\"cvxAcc__title\">Ruteo hacia el host (FX \/ DRY \/ BLEND)<\/span>\r\n                            <span class=\"cvxAcc__icon\" aria-hidden=\"true\"><\/span>\r\n                        <\/button>\r\n                        <div class=\"cvxAcc__body\">\r\n                            Eleg\u00ed qu\u00e9 se\u00f1al llega a tu DAW: <b>procesada<\/b> (FX), <b>limpia<\/b> (DRY) o <b>mezclada<\/b> (BLEND).\r\n                            Esto permite grabaci\u00f3n flexible sin forzar una \u00fanica cadena.\r\n                        <\/div>\r\n                    <\/div>\r\n\r\n                    <div class=\"cvxAcc__item\">\r\n                        <button class=\"cvxAcc__btn\" type=\"button\">\r\n                            <span class=\"cvxAcc__title\">Monitoreo (DIRECT \/ DSP \/ RT)<\/span>\r\n                            <span class=\"cvxAcc__icon\" aria-hidden=\"true\"><\/span>\r\n                        <\/button>\r\n                        <div class=\"cvxAcc__body\">\r\n                            <b>DIRECT<\/b> prioriza respuesta inmediata, <b>DSP<\/b> agrega procesamiento interno sin depender del DAW,\r\n                            y <b>RT<\/b> permite escuchar el retorno del proyecto (\u00fatil para decisiones dentro de la sesi\u00f3n).\r\n                        <\/div>\r\n                    <\/div>\r\n\r\n                    <div class=\"cvxAcc__item\">\r\n                        <button class=\"cvxAcc__btn\" type=\"button\">\r\n                            <span class=\"cvxAcc__title\">Utilidades (Loopback \/ Reamp \/ Safety)<\/span>\r\n                            <span class=\"cvxAcc__icon\" aria-hidden=\"true\"><\/span>\r\n                        <\/button>\r\n                        <div class=\"cvxAcc__body\">\r\n                            <b>Loopback<\/b> habilita ruteos internos, <b>Reamp<\/b> facilita enviar\/retornar se\u00f1al del DAW para reprocesar,\r\n                            y <b>Safety<\/b> mantiene una ruta paralela limpia adem\u00e1s de la procesada.\r\n                        <\/div>\r\n                    <\/div>\r\n                <\/div>\r\n            <\/div>\r\n        <\/div>\r\n\r\n        <!-- =========================================================\r\n         LOCAL CSS (widget-specific) \u2014 NO incluye el Starter Kit\r\n    ========================================================== -->\r\n        <style>\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"] {\r\n                --cvx-hifi-accent: var(--cvx-ai-accent, var(--cvxAccent));\r\n\r\n                \/* ===== ACTIVE (defaults = Desktop) ===== *\/\r\n                --cvx-hifi-gap: var(--cvx-ai-gap-d);\r\n\r\n                --cvx-ai-hero-mb: var(--cvx-ai-hero-mb-d);\r\n\r\n                --cvx-ai-kicker-fs: var(--cvx-ai-kicker-fs-d);\r\n                --cvx-ai-kicker-track: var(--cvx-ai-kicker-track-d);\r\n\r\n                --cvx-ai-sub-fs: var(--cvx-ai-sub-fs-d);\r\n                --cvx-ai-sub-lh: var(--cvx-ai-sub-lh-d);\r\n\r\n                --cvx-ai-desc-fs: var(--cvx-ai-desc-fs-d);\r\n                --cvx-ai-desc-lh: var(--cvx-ai-desc-lh-d);\r\n\r\n                --cvx-ai-tag-fs: var(--cvx-ai-tag-fs-d);\r\n                --cvx-ai-tag-pad-y: var(--cvx-ai-tag-pad-y-d);\r\n                --cvx-ai-tag-pad-x: var(--cvx-ai-tag-pad-x-d);\r\n\r\n                --cvx-ai-stage-inset: var(--cvx-ai-stage-inset-d);\r\n                --cvx-ai-stage-scale: var(--cvx-ai-stage-scale-d);\r\n                --cvx-ai-stage-shiftY: var(--cvx-ai-stage-shiftY-d);\r\n\r\n                --cvx-ai-svg-t1-fs: var(--cvx-ai-svg-t1-fs-d);\r\n                --cvx-ai-svg-t1-track: var(--cvx-ai-svg-t1-track-d);\r\n                --cvx-ai-svg-t2-fs: var(--cvx-ai-svg-t2-fs-d);\r\n\r\n                --cvx-ai-edge-w: var(--cvx-ai-edge-w-d);\r\n                --cvx-ai-edge-flow-w: var(--cvx-ai-edge-flow-w-d);\r\n\r\n                --cvx-ai-legend-fs: var(--cvx-ai-legend-fs-d);\r\n                --cvx-ai-legend-pad-y: var(--cvx-ai-legend-pad-y-d);\r\n                --cvx-ai-legend-pad-x: var(--cvx-ai-legend-pad-x-d);\r\n                --cvx-ai-legend-gap: var(--cvx-ai-legend-gap-d);\r\n                --cvx-ai-legend-bottom: var(--cvx-ai-legend-bottom-d);\r\n                --cvx-ai-legend-side: var(--cvx-ai-legend-side-d);\r\n                --cvx-ai-legend-top-hint: var(--cvx-ai-legend-top-hint-d);\r\n                --cvx-ai-legend-max-how: var(--cvx-ai-legend-max-how-d);\r\n\r\n                --cvx-ai-badge-fs: var(--cvx-ai-badge-fs-d);\r\n                --cvx-ai-badge-pad-y: var(--cvx-ai-badge-pad-y-d);\r\n                --cvx-ai-badge-pad-x: var(--cvx-ai-badge-pad-x-d);\r\n\r\n                --cvx-ai-media-meta-pad-y: var(--cvx-ai-media-meta-pad-y-d);\r\n                --cvx-ai-media-meta-pad-x: var(--cvx-ai-media-meta-pad-x-d);\r\n                --cvx-ai-media-k-fs: var(--cvx-ai-media-k-fs-d);\r\n                --cvx-ai-media-k-track: var(--cvx-ai-media-k-track-d);\r\n                --cvx-ai-media-v-fs: var(--cvx-ai-media-v-fs-d);\r\n                --cvx-ai-media-v-lh: var(--cvx-ai-media-v-lh-d);\r\n\r\n                --cvx-ai-controls-pad-y: var(--cvx-ai-controls-pad-y-d);\r\n                --cvx-ai-controls-pad-x: var(--cvx-ai-controls-pad-x-d);\r\n                --cvx-ai-controls-gap: var(--cvx-ai-controls-gap-d);\r\n                --cvx-ai-btn-gap: var(--cvx-ai-btn-gap-d);\r\n                --cvx-ai-title-fs: var(--cvx-ai-title-fs-d);\r\n                --cvx-ai-title-track: var(--cvx-ai-title-track-d);\r\n                --cvx-ai-chip-pad-y: var(--cvx-ai-chip-pad-y-d);\r\n                --cvx-ai-chip-pad-x: var(--cvx-ai-chip-pad-x-d);\r\n                --cvx-ai-chip-label-fs: var(--cvx-ai-chip-label-fs-d);\r\n                --cvx-ai-chip-seg-fs: var(--cvx-ai-chip-seg-fs-d);\r\n\r\n                --cvx-ai-pop-fs: var(--cvx-ai-pop-fs-d);\r\n                --cvx-ai-pop-pad: var(--cvx-ai-pop-pad-d);\r\n                --cvx-ai-pop-gap: var(--cvx-ai-pop-gap-d);\r\n                --cvx-ai-pop-maxw: var(--cvx-ai-pop-maxw-d);\r\n                --cvx-ai-pop-btn-pad-y: var(--cvx-ai-pop-btn-pad-y-d);\r\n                --cvx-ai-pop-btn-pad-x: var(--cvx-ai-pop-btn-pad-x-d);\r\n            }\r\n\r\n            @media (max-width: 980px) {\r\n                .cvxScope [data-cvx-root=\"audio-interface-hifi\"] {\r\n                    --cvx-hifi-gap: var(--cvx-ai-gap-t);\r\n\r\n                    --cvx-ai-hero-mb: var(--cvx-ai-hero-mb-t);\r\n\r\n                    --cvx-ai-kicker-fs: var(--cvx-ai-kicker-fs-t);\r\n                    --cvx-ai-kicker-track: var(--cvx-ai-kicker-track-t);\r\n\r\n                    --cvx-ai-sub-fs: var(--cvx-ai-sub-fs-t);\r\n                    --cvx-ai-sub-lh: var(--cvx-ai-sub-lh-t);\r\n\r\n                    --cvx-ai-desc-fs: var(--cvx-ai-desc-fs-t);\r\n                    --cvx-ai-desc-lh: var(--cvx-ai-desc-lh-t);\r\n\r\n                    --cvx-ai-tag-fs: var(--cvx-ai-tag-fs-t);\r\n                    --cvx-ai-tag-pad-y: var(--cvx-ai-tag-pad-y-t);\r\n                    --cvx-ai-tag-pad-x: var(--cvx-ai-tag-pad-x-t);\r\n\r\n                    --cvx-ai-stage-inset: var(--cvx-ai-stage-inset-t);\r\n                    --cvx-ai-stage-scale: var(--cvx-ai-stage-scale-t);\r\n                    --cvx-ai-stage-shiftY: var(--cvx-ai-stage-shiftY-t);\r\n\r\n                    --cvx-ai-svg-t1-fs: var(--cvx-ai-svg-t1-fs-t);\r\n                    --cvx-ai-svg-t1-track: var(--cvx-ai-svg-t1-track-t);\r\n                    --cvx-ai-svg-t2-fs: var(--cvx-ai-svg-t2-fs-t);\r\n\r\n                    --cvx-ai-edge-w: var(--cvx-ai-edge-w-t);\r\n                    --cvx-ai-edge-flow-w: var(--cvx-ai-edge-flow-w-t);\r\n\r\n                    --cvx-ai-legend-fs: var(--cvx-ai-legend-fs-t);\r\n                    --cvx-ai-legend-pad-y: var(--cvx-ai-legend-pad-y-t);\r\n                    --cvx-ai-legend-pad-x: var(--cvx-ai-legend-pad-x-t);\r\n                    --cvx-ai-legend-gap: var(--cvx-ai-legend-gap-t);\r\n                    --cvx-ai-legend-bottom: var(--cvx-ai-legend-bottom-t);\r\n                    --cvx-ai-legend-side: var(--cvx-ai-legend-side-t);\r\n                    --cvx-ai-legend-top-hint: var(--cvx-ai-legend-top-hint-t);\r\n                    --cvx-ai-legend-max-how: var(--cvx-ai-legend-max-how-t);\r\n\r\n                    --cvx-ai-badge-fs: var(--cvx-ai-badge-fs-t);\r\n                    --cvx-ai-badge-pad-y: var(--cvx-ai-badge-pad-y-t);\r\n                    --cvx-ai-badge-pad-x: var(--cvx-ai-badge-pad-x-t);\r\n\r\n                    --cvx-ai-media-meta-pad-y: var(--cvx-ai-media-meta-pad-y-t);\r\n                    --cvx-ai-media-meta-pad-x: var(--cvx-ai-media-meta-pad-x-t);\r\n                    --cvx-ai-media-k-fs: var(--cvx-ai-media-k-fs-t);\r\n                    --cvx-ai-media-k-track: var(--cvx-ai-media-k-track-t);\r\n                    --cvx-ai-media-v-fs: var(--cvx-ai-media-v-fs-t);\r\n                    --cvx-ai-media-v-lh: var(--cvx-ai-media-v-lh-t);\r\n\r\n                    --cvx-ai-controls-pad-y: var(--cvx-ai-controls-pad-y-t);\r\n                    --cvx-ai-controls-pad-x: var(--cvx-ai-controls-pad-x-t);\r\n                    --cvx-ai-controls-gap: var(--cvx-ai-controls-gap-t);\r\n                    --cvx-ai-btn-gap: var(--cvx-ai-btn-gap-t);\r\n                    --cvx-ai-title-fs: var(--cvx-ai-title-fs-t);\r\n                    --cvx-ai-title-track: var(--cvx-ai-title-track-t);\r\n                    --cvx-ai-chip-pad-y: var(--cvx-ai-chip-pad-y-t);\r\n                    --cvx-ai-chip-pad-x: var(--cvx-ai-chip-pad-x-t);\r\n                    --cvx-ai-chip-label-fs: var(--cvx-ai-chip-label-fs-t);\r\n                    --cvx-ai-chip-seg-fs: var(--cvx-ai-chip-seg-fs-t);\r\n\r\n                    --cvx-ai-pop-fs: var(--cvx-ai-pop-fs-t);\r\n                    --cvx-ai-pop-pad: var(--cvx-ai-pop-pad-t);\r\n                    --cvx-ai-pop-gap: var(--cvx-ai-pop-gap-t);\r\n                    --cvx-ai-pop-maxw: var(--cvx-ai-pop-maxw-t);\r\n                    --cvx-ai-pop-btn-pad-y: var(--cvx-ai-pop-btn-pad-y-t);\r\n                    --cvx-ai-pop-btn-pad-x: var(--cvx-ai-pop-btn-pad-x-t);\r\n                }\r\n            }\r\n\r\n            @media (max-width: 620px) {\r\n                .cvxScope [data-cvx-root=\"audio-interface-hifi\"] {\r\n                    --cvx-hifi-gap: var(--cvx-ai-gap-m);\r\n\r\n                    --cvx-ai-hero-mb: var(--cvx-ai-hero-mb-m);\r\n\r\n                    --cvx-ai-kicker-fs: var(--cvx-ai-kicker-fs-m);\r\n                    --cvx-ai-kicker-track: var(--cvx-ai-kicker-track-m);\r\n\r\n                    --cvx-ai-sub-fs: var(--cvx-ai-sub-fs-m);\r\n                    --cvx-ai-sub-lh: var(--cvx-ai-sub-lh-m);\r\n\r\n                    --cvx-ai-desc-fs: var(--cvx-ai-desc-fs-m);\r\n                    --cvx-ai-desc-lh: var(--cvx-ai-desc-lh-m);\r\n\r\n                    --cvx-ai-tag-fs: var(--cvx-ai-tag-fs-m);\r\n                    --cvx-ai-tag-pad-y: var(--cvx-ai-tag-pad-y-m);\r\n                    --cvx-ai-tag-pad-x: var(--cvx-ai-tag-pad-x-m);\r\n\r\n                    --cvx-ai-stage-inset: var(--cvx-ai-stage-inset-m);\r\n                    --cvx-ai-stage-scale: var(--cvx-ai-stage-scale-m);\r\n                    --cvx-ai-stage-shiftY: var(--cvx-ai-stage-shiftY-m);\r\n\r\n                    --cvx-ai-svg-t1-fs: var(--cvx-ai-svg-t1-fs-m);\r\n                    --cvx-ai-svg-t1-track: var(--cvx-ai-svg-t1-track-m);\r\n                    --cvx-ai-svg-t2-fs: var(--cvx-ai-svg-t2-fs-m);\r\n\r\n                    --cvx-ai-edge-w: var(--cvx-ai-edge-w-m);\r\n                    --cvx-ai-edge-flow-w: var(--cvx-ai-edge-flow-w-m);\r\n\r\n                    --cvx-ai-legend-fs: var(--cvx-ai-legend-fs-m);\r\n                    --cvx-ai-legend-pad-y: var(--cvx-ai-legend-pad-y-m);\r\n                    --cvx-ai-legend-pad-x: var(--cvx-ai-legend-pad-x-m);\r\n                    --cvx-ai-legend-gap: var(--cvx-ai-legend-gap-m);\r\n                    --cvx-ai-legend-bottom: var(--cvx-ai-legend-bottom-m);\r\n                    --cvx-ai-legend-side: var(--cvx-ai-legend-side-m);\r\n                    --cvx-ai-legend-top-hint: var(--cvx-ai-legend-top-hint-m);\r\n                    --cvx-ai-legend-max-how: var(--cvx-ai-legend-max-how-m);\r\n\r\n                    --cvx-ai-badge-fs: var(--cvx-ai-badge-fs-m);\r\n                    --cvx-ai-badge-pad-y: var(--cvx-ai-badge-pad-y-m);\r\n                    --cvx-ai-badge-pad-x: var(--cvx-ai-badge-pad-x-m);\r\n\r\n                    --cvx-ai-media-meta-pad-y: var(--cvx-ai-media-meta-pad-y-m);\r\n                    --cvx-ai-media-meta-pad-x: var(--cvx-ai-media-meta-pad-x-m);\r\n                    --cvx-ai-media-k-fs: var(--cvx-ai-media-k-fs-m);\r\n                    --cvx-ai-media-k-track: var(--cvx-ai-media-k-track-m);\r\n                    --cvx-ai-media-v-fs: var(--cvx-ai-media-v-fs-m);\r\n                    --cvx-ai-media-v-lh: var(--cvx-ai-media-v-lh-m);\r\n\r\n                    --cvx-ai-controls-pad-y: var(--cvx-ai-controls-pad-y-m);\r\n                    --cvx-ai-controls-pad-x: var(--cvx-ai-controls-pad-x-m);\r\n                    --cvx-ai-controls-gap: var(--cvx-ai-controls-gap-m);\r\n                    --cvx-ai-btn-gap: var(--cvx-ai-btn-gap-m);\r\n                    --cvx-ai-title-fs: var(--cvx-ai-title-fs-m);\r\n                    --cvx-ai-title-track: var(--cvx-ai-title-track-m);\r\n                    --cvx-ai-chip-pad-y: var(--cvx-ai-chip-pad-y-m);\r\n                    --cvx-ai-chip-pad-x: var(--cvx-ai-chip-pad-x-m);\r\n                    --cvx-ai-chip-label-fs: var(--cvx-ai-chip-label-fs-m);\r\n                    --cvx-ai-chip-seg-fs: var(--cvx-ai-chip-seg-fs-m);\r\n\r\n                    --cvx-ai-pop-fs: var(--cvx-ai-pop-fs-m);\r\n                    --cvx-ai-pop-pad: var(--cvx-ai-pop-pad-m);\r\n                    --cvx-ai-pop-gap: var(--cvx-ai-pop-gap-m);\r\n                    --cvx-ai-pop-maxw: var(--cvx-ai-pop-maxw-m);\r\n                    --cvx-ai-pop-btn-pad-y: var(--cvx-ai-pop-btn-pad-y-m);\r\n                    --cvx-ai-pop-btn-pad-x: var(--cvx-ai-pop-btn-pad-x-m);\r\n                }\r\n            }\r\n\r\n            \/* ===== HERO ===== *\/\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"] .cvxAiHifiHero {\r\n                display: grid;\r\n                grid-template-columns: 1.15fr .85fr;\r\n                gap: var(--cvx-hifi-gap);\r\n                align-items: start;\r\n                margin-bottom: var(--cvx-ai-hero-mb);\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"] .cvxKicker {\r\n                font-size: var(--cvx-ai-kicker-fs);\r\n                letter-spacing: var(--cvx-ai-kicker-track);\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"] .cvxAiHifiSub {\r\n                margin: 0 0 10px;\r\n                font-size: var(--cvx-ai-sub-fs);\r\n                line-height: var(--cvx-ai-sub-lh);\r\n                color: color-mix(in srgb, var(--cvx-hifi-accent) 78%, white);\r\n                font-weight: 420;\r\n                letter-spacing: .2px;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"] .cvxDesc {\r\n                font-size: var(--cvx-ai-desc-fs);\r\n                line-height: var(--cvx-ai-desc-lh);\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"] b,\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"] strong {\r\n                font-weight: 850;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"] .cvxTag {\r\n                font-size: var(--cvx-ai-tag-fs);\r\n                padding: var(--cvx-ai-tag-pad-y) var(--cvx-ai-tag-pad-x);\r\n            }\r\n\r\n            \/* ===== MAIN GRID ===== *\/\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"] .cvxAiHifiGrid {\r\n                display: grid;\r\n                grid-template-columns: 1.15fr .85fr;\r\n                gap: var(--cvx-hifi-gap);\r\n                align-items: start;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"] .cvxAiHifiLeft,\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"] .cvxAiHifiRight {\r\n                min-width: 0;\r\n            }\r\n\r\n            \/* ===== MEDIA ===== *\/\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"] .cvxAiHifiMedia {\r\n                width: 100%;\r\n                border-radius: 18px;\r\n                overflow: hidden;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"] .cvxAiHifiMedia__img {\r\n                aspect-ratio: var(--cvx-ai-media-ar);\r\n                border-radius: 14px;\r\n                background-image:\r\n                    radial-gradient(120% 110% at 30% 15%,\r\n                        color-mix(in srgb, var(--cvx-hifi-accent) 16%, transparent),\r\n                        rgba(0, 0, 0, .20) 52%,\r\n                        rgba(0, 0, 0, .55)),\r\n                    var(--cvx-ai-media-img);\r\n                background-position: var(--cvx-ai-media-pos);\r\n                background-size: cover;\r\n                border: 1px solid rgba(255, 255, 255, .10);\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"] .cvxAiHifiMedia__meta {\r\n                margin-top: 10px;\r\n                padding: var(--cvx-ai-media-meta-pad-y) var(--cvx-ai-media-meta-pad-x);\r\n                border-radius: 16px;\r\n                border: 1px solid rgba(255, 255, 255, .10);\r\n                background: rgba(0, 0, 0, .18);\r\n                backdrop-filter: blur(var(--cvxBlur));\r\n                -webkit-backdrop-filter: blur(var(--cvxBlur));\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"] .cvxAiHifiMedia__meta .k {\r\n                font-size: var(--cvx-ai-media-k-fs);\r\n                letter-spacing: var(--cvx-ai-media-k-track);\r\n                text-transform: uppercase;\r\n                color: rgba(255, 255, 255, .62);\r\n                margin-bottom: 6px;\r\n                font-weight: 850;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"] .cvxAiHifiMedia__meta .v {\r\n                color: rgba(255, 255, 255, .78);\r\n                font-size: var(--cvx-ai-media-v-fs);\r\n                line-height: var(--cvx-ai-media-v-lh);\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"] .cvxAiHifiMedia__meta .v b {\r\n                color: rgba(255, 255, 255, .92);\r\n                font-weight: 850;\r\n            }\r\n\r\n            \/* ===== STAGE ===== *\/\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"] .cvxAiHifiStage {\r\n                position: relative;\r\n                background-image:\r\n                    radial-gradient(120% 120% at 45% 50%,\r\n                        color-mix(in srgb, var(--cvx-hifi-accent) 24%, transparent),\r\n                        rgba(20, 20, 20, .25) 60%,\r\n                        rgba(0, 0, 0, .45)),\r\n                    var(--cvx-ai-stage-img);\r\n                background-position: var(--cvx-ai-stage-pos);\r\n                background-size: cover;\r\n                overflow: hidden;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"] .cvxAiHifiOverlay {\r\n                position: absolute;\r\n                top: var(--cvx-ai-stage-inset);\r\n                right: var(--cvx-ai-stage-inset);\r\n                bottom: var(--cvx-ai-stage-inset);\r\n                left: var(--cvx-ai-stage-inset);\r\n                border-radius: 14px;\r\n                pointer-events: auto;\r\n                overflow: hidden;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"] .cvxAiHifiSvg {\r\n                width: 100%;\r\n                height: 100%;\r\n                display: block;\r\n                transform-origin: 50% 50%;\r\n                transform: translateY(var(--cvx-ai-stage-shiftY)) scale(var(--cvx-ai-stage-scale));\r\n            }\r\n\r\n            \/* Legend block *\/\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"] .cvxAiHifiLegend {\r\n                position: absolute;\r\n                left: var(--cvx-ai-legend-side);\r\n                right: var(--cvx-ai-legend-side);\r\n                bottom: var(--cvx-ai-legend-bottom);\r\n                display: flex;\r\n                align-items: center;\r\n                justify-content: space-between;\r\n                gap: var(--cvx-ai-legend-gap);\r\n                pointer-events: none;\r\n                flex-wrap: wrap;\r\n                z-index: 2;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"] .cvxBadge {\r\n                font-size: var(--cvx-ai-badge-fs);\r\n                padding: var(--cvx-ai-badge-pad-y) var(--cvx-ai-badge-pad-x);\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"] .cvxAiHifiLegend__txt,\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"] .cvxAiHifiLegend__how {\r\n                font-size: var(--cvx-ai-legend-fs);\r\n                color: rgba(255, 255, 255, .72);\r\n                padding: var(--cvx-ai-legend-pad-y) var(--cvx-ai-legend-pad-x);\r\n                border-radius: 999px;\r\n                border: 1px solid rgba(255, 255, 255, .10);\r\n                background: rgba(0, 0, 0, .16);\r\n                backdrop-filter: blur(var(--cvxBlur));\r\n                -webkit-backdrop-filter: blur(var(--cvxBlur));\r\n                overflow: hidden;\r\n                text-overflow: ellipsis;\r\n                white-space: nowrap;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"] .cvxAiHifiLegend__how {\r\n                color: rgba(255, 255, 255, .68);\r\n                opacity: .92;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"] .cvxAiHifiLegend__how--tr {\r\n                position: absolute;\r\n                top: var(--cvx-ai-legend-top-hint);\r\n                left: var(--cvx-ai-legend-top-hint);\r\n                z-index: 3;\r\n                pointer-events: none;\r\n                max-width: var(--cvx-ai-legend-max-how);\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"] .cvxAiHifiLegend__txt {\r\n                max-width: calc(100% - 90px);\r\n            }\r\n\r\n            \/* SVG styling *\/\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"] .cvxAiHifiSvg .node {\r\n                fill: var(--cvx-ai-node-fill);\r\n                stroke: var(--cvx-ai-node-stroke);\r\n                stroke-width: var(--cvx-ai-node-stroke-w);\r\n            }\r\n\r\n            \/* Active input node highlight *\/\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"][data-ai-input=\"mic\"] .cvxAiHifiSvg .node--inMic,\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"][data-ai-input=\"trs\"] .cvxAiHifiSvg .node--inTrs,\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"][data-ai-input=\"exp\"] .cvxAiHifiSvg .node--inExp {\r\n                stroke: var(--cvx-ai-node-active-stroke);\r\n                fill: var(--cvx-ai-node-active-fill);\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"] .cvxAiHifiSvg .t1 {\r\n                font: 900 var(--cvx-ai-svg-t1-fs)\/1 var(--cvxFont);\r\n                letter-spacing: var(--cvx-ai-svg-t1-track);\r\n                fill: rgba(255, 255, 255, .78);\r\n                pointer-events: none;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"] .cvxAiHifiSvg .t2 {\r\n                font: 700 var(--cvx-ai-svg-t2-fs)\/1 var(--cvxFont);\r\n                fill: rgba(255, 255, 255, .92);\r\n                opacity: .92;\r\n                pointer-events: none;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"] .cvxAiHifiSvg .edge {\r\n                fill: none;\r\n                stroke: rgba(255, 255, 255, 1);\r\n                opacity: var(--cvx-ai-line-opacity);\r\n                stroke-width: var(--cvx-ai-edge-w);\r\n                stroke-linecap: round;\r\n                pointer-events: none;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"] .cvxAiHifiSvg .edge--flow {\r\n                stroke: color-mix(in srgb, var(--cvx-hifi-accent) 88%, transparent);\r\n                stroke-width: var(--cvx-ai-edge-flow-w);\r\n                opacity: 0;\r\n                stroke-dasharray: 6 14;\r\n                animation: cvxAiHifiFlow var(--cvx-ai-flow-speed) linear infinite;\r\n                filter: drop-shadow(0 0 8px color-mix(in srgb, var(--cvx-hifi-accent) 30%, transparent));\r\n                pointer-events: none;\r\n            }\r\n\r\n            @keyframes cvxAiHifiFlow {\r\n                to {\r\n                    stroke-dashoffset: -40;\r\n                }\r\n            }\r\n\r\n            @media (prefers-reduced-motion: reduce) {\r\n                .cvxScope [data-cvx-root=\"audio-interface-hifi\"] .cvxAiHifiSvg .edge--flow {\r\n                    animation: none;\r\n                }\r\n            }\r\n\r\n            \/* HIT ZONES *\/\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"] .cvxAiHifiSvg .hit {\r\n                fill: transparent;\r\n                stroke: transparent;\r\n                pointer-events: all;\r\n                cursor: pointer;\r\n            }\r\n\r\n            \/* Active edges (always) *\/\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"] .cvxAiHifiSvg [data-ai-edge=\"mon-out\"].edge--flow {\r\n                opacity: .88;\r\n            }\r\n\r\n            \/* Active input edge *\/\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"][data-ai-input=\"mic\"] .cvxAiHifiSvg [data-ai-edge=\"in-mic-afe\"].edge--flow {\r\n                opacity: var(--cvx-ai-flow-opacity);\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"][data-ai-input=\"trs\"] .cvxAiHifiSvg [data-ai-edge=\"in-trs-afe\"].edge--flow {\r\n                opacity: var(--cvx-ai-flow-opacity);\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"][data-ai-input=\"exp\"] .cvxAiHifiSvg [data-ai-edge=\"in-exp-afe\"].edge--flow {\r\n                opacity: var(--cvx-ai-flow-opacity);\r\n            }\r\n\r\n\r\n            \/* USB SEND *\/\r\n            \/* AFE -> MIX siempre visible como ruta base de la interfaz *\/\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"] .cvxAiHifiSvg [data-ai-edge=\"afe-mix\"].edge--flow {\r\n                opacity: calc(var(--cvx-ai-flow-opacity) * .78);\r\n            }\r\n\r\n            \/* SEND: FX *\/\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"][data-ai-send=\"fx\"] .cvxAiHifiSvg [data-ai-edge=\"mix-dsp\"].edge--flow,\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"][data-ai-send=\"fx\"] .cvxAiHifiSvg [data-ai-edge=\"dsp-usb\"].edge--flow {\r\n                opacity: var(--cvx-ai-flow-opacity);\r\n            }\r\n\r\n            \/* SEND: DRY *\/\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"][data-ai-send=\"dry\"] .cvxAiHifiSvg [data-ai-edge=\"mix-usb\"].edge--flow {\r\n                opacity: var(--cvx-ai-flow-opacity);\r\n            }\r\n\r\n            \/* SEND: BLEND *\/\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"][data-ai-send=\"blend\"] .cvxAiHifiSvg [data-ai-edge=\"mix-dsp\"].edge--flow,\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"][data-ai-send=\"blend\"] .cvxAiHifiSvg [data-ai-edge=\"dsp-usb\"].edge--flow,\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"][data-ai-send=\"blend\"] .cvxAiHifiSvg [data-ai-edge=\"mix-usb\"].edge--flow {\r\n                opacity: calc(var(--cvx-ai-flow-opacity) * .78);\r\n            }\r\n\r\n\r\n            \/* SAFETY: muestra paralelos (equivalente visual a DRY+FX) *\/\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"][data-ai-util=\"safety\"] .cvxAiHifiSvg [data-ai-edge=\"mix-dsp\"].edge--flow,\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"][data-ai-util=\"safety\"] .cvxAiHifiSvg [data-ai-edge=\"dsp-usb\"].edge--flow,\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"][data-ai-util=\"safety\"] .cvxAiHifiSvg [data-ai-edge=\"mix-usb\"].edge--flow {\r\n                opacity: calc(var(--cvx-ai-flow-opacity) * .72);\r\n            }\r\n\r\n            \/* LOOPBACK \/ REAMP: rutas internas sin nodo UTIL *\/\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"][data-ai-util=\"loopback\"] .cvxAiHifiSvg [data-ai-edge=\"usb-mix\"].edge--flow {\r\n                opacity: .82;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"][data-ai-util=\"reamp\"] .cvxAiHifiSvg [data-ai-edge=\"usb-afe\"].edge--flow {\r\n                opacity: .82;\r\n            }\r\n\r\n\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"][data-ai-monitor=\"dsp\"] .cvxAiHifiSvg [data-ai-edge=\"dsp-mon\"].edge--flow {\r\n                opacity: var(--cvx-ai-flow-opacity);\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"][data-ai-monitor=\"direct\"] .cvxAiHifiSvg [data-ai-edge=\"mix-mon\"].edge--flow {\r\n                opacity: var(--cvx-ai-flow-opacity);\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"][data-ai-monitor=\"roundtrip\"] .cvxAiHifiSvg [data-ai-edge=\"dest-mon\"].edge--flow {\r\n                opacity: var(--cvx-ai-flow-opacity);\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"][data-ai-send=\"dry\"][data-ai-monitor=\"dsp\"] .cvxAiHifiSvg [data-ai-edge=\"mix-dsp\"].edge--flow {\r\n                opacity: calc(var(--cvx-ai-flow-opacity) * .86);\r\n            }\r\n\r\n\r\n            \/* SAFETY: muestra paralelos (equivalente visual a DRY+FX) *\/\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"][data-ai-util=\"safety\"] .cvxAiHifiSvg [data-ai-edge=\"mix-dsp\"].edge--flow,\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"][data-ai-util=\"safety\"] .cvxAiHifiSvg [data-ai-edge=\"dsp-usb\"].edge--flow,\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"][data-ai-util=\"safety\"] .cvxAiHifiSvg [data-ai-edge=\"mix-usb\"].edge--flow {\r\n                opacity: calc(var(--cvx-ai-flow-opacity) * .72);\r\n            }\r\n\r\n            \/* LOOPBACK \/ REAMP: rutas internas sin nodo UTIL *\/\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"][data-ai-util=\"loopback\"] .cvxAiHifiSvg [data-ai-edge=\"usb-mix\"].edge--flow {\r\n                opacity: .82;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"][data-ai-util=\"reamp\"] .cvxAiHifiSvg [data-ai-edge=\"usb-afe\"].edge--flow {\r\n                opacity: .82;\r\n            }\r\n\r\n\r\n            \/* ===== POPOVER ===== *\/\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"] .cvxAiHifiPop {\r\n                position: absolute;\r\n                z-index: 5;\r\n                max-width: var(--cvx-ai-pop-maxw);\r\n                border-radius: var(--cvx-ai-pop-radius);\r\n                padding: var(--cvx-ai-pop-pad);\r\n                border: 1px solid rgba(255, 255, 255, .12);\r\n                background: rgba(0, 0, 0, .28);\r\n                backdrop-filter: blur(var(--cvxBlur));\r\n                -webkit-backdrop-filter: blur(var(--cvxBlur));\r\n                box-shadow: 0 10px 40px rgba(0, 0, 0, .45);\r\n                transform: translate3d(0, 0, 0);\r\n                will-change: transform;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"] .cvxAiHifiPop__k {\r\n                font-size: var(--cvx-ai-pop-fs);\r\n                letter-spacing: .14em;\r\n                text-transform: uppercase;\r\n                color: rgba(255, 255, 255, .72);\r\n                font-weight: 850;\r\n                margin: 0 0 8px;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"] .cvxAiHifiPop__grid {\r\n                display: grid;\r\n                gap: var(--cvx-ai-pop-gap);\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"] .cvxAiHifiPop__btn {\r\n                width: 100%;\r\n                display: flex;\r\n                align-items: center;\r\n                justify-content: space-between;\r\n                gap: 10px;\r\n                font: 750 var(--cvx-ai-pop-fs)\/1.2 var(--cvxFont);\r\n                padding: var(--cvx-ai-pop-btn-pad-y) var(--cvx-ai-pop-btn-pad-x);\r\n                border-radius: 12px;\r\n                border: 1px solid rgba(255, 255, 255, .10);\r\n                background: rgba(0, 0, 0, .18);\r\n                color: rgba(255, 255, 255, .86);\r\n                cursor: pointer;\r\n                text-align: left;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"] .cvxAiHifiPop__btn:hover {\r\n                border-color: rgba(255, 255, 255, .16);\r\n                background: rgba(0, 0, 0, .26);\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"] .cvxAiHifiPop__btn.is-active {\r\n                border-color: color-mix(in srgb, var(--cvx-hifi-accent) 45%, rgba(255, 255, 255, .16));\r\n                background: color-mix(in srgb, var(--cvx-hifi-accent) 12%, rgba(0, 0, 0, .22));\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"] .cvxAiHifiPop__pill {\r\n                font-size: 10px;\r\n                padding: 6px 10px;\r\n                border-radius: 999px;\r\n                border: 1px solid rgba(255, 255, 255, .10);\r\n                background: rgba(0, 0, 0, .14);\r\n                color: rgba(255, 255, 255, .70);\r\n                white-space: nowrap;\r\n            }\r\n\r\n            .cvxHairlineNote {\r\n                position: relative;\r\n                margin-top: 0px;\r\n                padding-top: 8px;\r\n                font-size: 12px;\r\n                line-height: 1.45;\r\n                letter-spacing: .02em;\r\n                color: rgba(255, 255, 255, .60);\r\n            }\r\n\r\n            .cvxHairlineNote::before {\r\n                content: \"\";\r\n                position: absolute;\r\n                top: 0;\r\n                left: 0;\r\n                right: 0;\r\n                height: 1px;\r\n                background: linear-gradient(90deg, rgba(255, 255, 255, .2), rgba(255, 255, 255, .2), transparent);\r\n            }\r\n\r\n            .cvxHairlineNote b,\r\n            .cvxHairlineNote strong {\r\n                color: rgba(255, 255, 255, .86);\r\n                font-weight: 650;\r\n            }\r\n\r\n            \/* ===== CONTROLS ===== *\/\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"] .cvxAiHifiControls {\r\n                margin-top: 14px;\r\n\r\n                --cvxCardPadY: var(--cvx-ai-controls-pad-y);\r\n                --cvxCardPadX: var(--cvx-ai-controls-pad-x);\r\n\r\n                --chip-pad-t: var(--cvx-ai-chip-pad-y);\r\n                --chip-pad-b: var(--cvx-ai-chip-pad-y);\r\n                --chip-pad-x: var(--cvx-ai-chip-pad-x);\r\n                --fs-chip-label: var(--cvx-ai-chip-label-fs);\r\n                --fs-chip-seg: var(--cvx-ai-chip-seg-fs);\r\n\r\n                display: grid;\r\n                gap: var(--cvx-ai-controls-gap);\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"] .cvxAiHifiGroup {\r\n                min-width: 0;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"] .cvxAiHifiGroup__title {\r\n                font-size: var(--cvx-ai-title-fs);\r\n                letter-spacing: var(--cvx-ai-title-track);\r\n                text-transform: uppercase;\r\n                color: rgba(255, 255, 255, .70);\r\n                font-weight: 800;\r\n                margin: 0 0 10px;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"] .cvxAiHifiBtnGrid {\r\n                display: grid;\r\n                grid-template-columns: repeat(3, minmax(0, 1fr));\r\n                gap: var(--cvx-ai-btn-gap);\r\n                align-items: stretch;\r\n                min-width: 0;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"] .cvxAiHifiBtnGrid .cvxChip {\r\n                width: 100%;\r\n                min-width: 0;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"] .cvxAiHifiBtnGrid .cvxChip__label {\r\n                overflow: hidden;\r\n                text-overflow: ellipsis;\r\n                white-space: nowrap;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"] .cvxAiHifiControls[data-aux=\"off\"] .cvxChip__seg {\r\n                display: none;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"] .cvxAiHifiControls[data-aux=\"active\"] .cvxChip__seg {\r\n                display: none;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"] .cvxAiHifiControls[data-aux=\"active\"] .cvxChip.is-active .cvxChip__seg {\r\n                display: inline-flex;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"] .cvxAiHifiControls[data-layout=\"row\"] {\r\n                grid-template-columns: 1fr;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"] .cvxAiHifiControls[data-layout=\"row\"] .cvxAiHifiGroup {\r\n                display: grid;\r\n                grid-template-columns: minmax(100px, var(--cvx-ai-row-title-w)) 1fr;\r\n                gap: var(--cvx-ai-group-gap);\r\n                align-items: center;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"] .cvxAiHifiControls[data-layout=\"row\"] .cvxAiHifiGroup__title {\r\n                margin: 0;\r\n                padding-right: 6px;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"] .cvxAiHifiControls[data-layout=\"grid2\"] {\r\n                grid-template-columns: repeat(2, minmax(0, 1fr));\r\n                gap: var(--cvx-ai-controls-gap);\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"] .cvxAiHifiControls[data-layout=\"stack\"] {\r\n                grid-template-columns: 1fr;\r\n            }\r\n\r\n            \/* Responsive: el grid general *\/\r\n            @media (max-width: 980px) {\r\n                .cvxScope [data-cvx-root=\"audio-interface-hifi\"] .cvxAiHifiHero {\r\n                    grid-template-columns: 1fr;\r\n                }\r\n\r\n                .cvxScope [data-cvx-root=\"audio-interface-hifi\"] .cvxAiHifiGrid {\r\n                    grid-template-columns: 1fr;\r\n                }\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"audio-interface-hifi\"] .cvxAiHifiAcc {\r\n                margin-top: 12px;\r\n            }\r\n        <\/style>\r\n\r\n        <!-- =========================================================\r\n         LOCAL JS (Elementor-safe)\r\n    ========================================================== -->\r\n        <script>\r\n            (function() {\r\n                var roots = document.querySelectorAll('.cvxScope [data-cvx-root=\"audio-interface-hifi\"]');\r\n                if (!roots || !roots.length) return;\r\n\r\n                var LABELS = {\r\n                    input: {\r\n                        mic: 'MIC \/ XLR',\r\n                        trs: 'INST\/LINE \/ TRS',\r\n                        exp: 'EXPANDER \/ I\/O'\r\n                    },\r\n                    send: {\r\n                        fx: 'FX',\r\n                        dry: 'DRY',\r\n                        blend: 'BLEND'\r\n                    },\r\n                    monitor: {\r\n                        direct: 'DIRECT',\r\n                        dsp: 'DSP',\r\n                        roundtrip: 'RT'\r\n                    },\r\n                    util: {\r\n                        loopback: 'LOOPBACK',\r\n                        reamp: 'REAMP',\r\n                        safety: 'SAFETY'\r\n                    }\r\n                };\r\n\r\n                var POP = {\r\n                    send: [{\r\n                            v: 'fx',\r\n                            l: 'FX',\r\n                            r: 'PROC'\r\n                        },\r\n                        {\r\n                            v: 'dry',\r\n                            l: 'DRY',\r\n                            r: 'CLEAN'\r\n                        },\r\n                        {\r\n                            v: 'blend',\r\n                            l: 'BLEND',\r\n                            r: 'MIX'\r\n                        }\r\n                    ],\r\n                    monitor: [{\r\n                            v: 'direct',\r\n                            l: 'DIRECT',\r\n                            r: 'SIN DSP'\r\n                        },\r\n                        {\r\n                            v: 'dsp',\r\n                            l: 'DSP',\r\n                            r: 'FX ON'\r\n                        },\r\n                        {\r\n                            v: 'roundtrip',\r\n                            l: 'RT',\r\n                            r: 'DAW'\r\n                        }\r\n                    ],\r\n                    util: [{\r\n                            v: 'loopback',\r\n                            l: 'LOOPBACK',\r\n                            r: 'INT'\r\n                        },\r\n                        {\r\n                            v: 'reamp',\r\n                            l: 'REAMP',\r\n                            r: 'S\/R'\r\n                        },\r\n                        {\r\n                            v: 'safety',\r\n                            l: 'SAFETY',\r\n                            r: 'DRY+FX'\r\n                        }\r\n                    ]\r\n                };\r\n\r\n                var LANG = (function() {\r\n                    var htmlLang = (document.documentElement.getAttribute('lang') || '').toLowerCase();\r\n                    if (htmlLang.indexOf('en') === 0) return 'en';\r\n                    if (\/^\\\/en(?:\\\/|$)\/i.test(window.location.pathname)) return 'en';\r\n                    return 'es';\r\n                })();\r\n\r\n                var TXT = {\r\n                    es: {\r\n                        readoutLeadInput: 'Entrada',\r\n                        readoutLeadSend: 'DAW recibe',\r\n                        readoutLeadMon: 'Monitoreo',\r\n                        readoutLeadUtil: 'Utilidad',\r\n\r\n                        input: {\r\n                            mic: 'MIC (XLR)',\r\n                            trs: 'INST\/LINE (TRS)',\r\n                            exp: 'EXPANDER (I\/O)'\r\n                        },\r\n                        send: {\r\n                            fx: 'procesado (FX)',\r\n                            dry: 'limpio (DRY)',\r\n                            blend: 'mezcla (BLEND)'\r\n                        },\r\n                        monitor: {\r\n                            direct: 'DIRECT',\r\n                            dsp: 'DSP',\r\n                            roundtrip: 'RT'\r\n                        },\r\n                        util: {\r\n                            loopback: 'Loopback',\r\n                            reamp: 'Reamp',\r\n                            safety: 'Safety'\r\n                        }\r\n                    },\r\n                    en: {\r\n                        readoutLeadInput: 'Input',\r\n                        readoutLeadSend: 'DAW receives',\r\n                        readoutLeadMon: 'Monitoring',\r\n                        readoutLeadUtil: 'Utility',\r\n\r\n                        input: {\r\n                            mic: 'MIC (XLR)',\r\n                            trs: 'INST\/LINE (TRS)',\r\n                            exp: 'EXPANDER (I\/O)'\r\n                        },\r\n                        send: {\r\n                            fx: 'processed (FX)',\r\n                            dry: 'clean (DRY)',\r\n                            blend: 'blend (BLEND)'\r\n                        },\r\n                        monitor: {\r\n                            direct: 'DIRECT',\r\n                            dsp: 'DSP',\r\n                            roundtrip: 'RT'\r\n                        },\r\n                        util: {\r\n                            loopback: 'Loopback',\r\n                            reamp: 'Reamp',\r\n                            safety: 'Safety'\r\n                        }\r\n                    }\r\n                };\r\n\r\n                function q(root, sel) {\r\n                    return root.querySelector(sel);\r\n                }\r\n\r\n                function setText(el, txt) {\r\n                    if (el) el.textContent = txt;\r\n                }\r\n\r\n                function readVar(root, name, fallback) {\r\n                    var v = getComputedStyle(root).getPropertyValue(name);\r\n                    v = (v || '').trim();\r\n                    return v || fallback;\r\n                }\r\n\r\n                function parsePx(v, fallback) {\r\n                    var n = parseFloat(String(v || '').replace('px', '').trim());\r\n                    return isFinite(n) ? n : fallback;\r\n                }\r\n\r\n                function normMode(v) {\r\n                    v = String(v || '').trim().toLowerCase();\r\n                    if (v === 'row' || v === 'fila' || v === 'r' || v === '1') return 'row';\r\n                    if (v === 'grid2' || v === '2col' || v === 'grid-2' || v === '2') return 'grid2';\r\n                    if (v === 'stack' || v === '1col' || v === 'col' || v === '3') return 'stack';\r\n                    return 'row';\r\n                }\r\n\r\n                function normAux(v) {\r\n                    v = String(v || '').trim().toLowerCase();\r\n                    if (v === 'off' || v === '0' || v === 'hide') return 'off';\r\n                    if (v === 'active' || v === '1') return 'active';\r\n                    return 'all';\r\n                }\r\n\r\n                function syncVisuals(root) {\r\n                    ['input', 'send', 'monitor', 'util'].forEach(function(group) {\r\n                        var btns = root.querySelectorAll('.cvxAiHifiChip[data-ai-group=\"' + group + '\"][data-ai-value]');\r\n                        btns.forEach(function(b) {\r\n                            var key =\r\n                                (group === 'input') ? root.dataset.aiInput :\r\n                                (group === 'send') ? root.dataset.aiSend :\r\n                                (group === 'monitor') ? root.dataset.aiMonitor :\r\n                                root.dataset.aiUtil;\r\n\r\n                            var on = key === b.getAttribute('data-ai-value');\r\n                            b.classList.toggle('is-active', on);\r\n                            b.setAttribute('aria-pressed', on ? 'true' : 'false');\r\n                        });\r\n                    });\r\n                }\r\n\r\n                function applyControlsLayout(root) {\r\n                    var controlsList = root.querySelectorAll('.cvxAiHifiControls');\r\n                    if (!controlsList || !controlsList.length) return;\r\n\r\n                    var w = root.getBoundingClientRect().width;\r\n\r\n                    var bpT = parsePx(readVar(root, '--cvx-ai-bp-tablet', '980px'), 980);\r\n                    var bpM = parsePx(readVar(root, '--cvx-ai-bp-mobile', '620px'), 620);\r\n\r\n                    var layoutD = normMode(readVar(root, '--cvx-ai-controls-layout-d', 'row'));\r\n                    var layoutT = normMode(readVar(root, '--cvx-ai-controls-layout-t', 'grid2'));\r\n                    var layoutM = normMode(readVar(root, '--cvx-ai-controls-layout-m', 'stack'));\r\n\r\n                    var auxD = normAux(readVar(root, '--cvx-ai-aux-d', 'all'));\r\n                    var auxT = normAux(readVar(root, '--cvx-ai-aux-t', 'active'));\r\n                    var auxM = normAux(readVar(root, '--cvx-ai-aux-m', 'off'));\r\n\r\n                    var layout = (w <= bpM) ? layoutM : (w <= bpT) ? layoutT : layoutD;\r\n                    var aux = (w <= bpM) ? auxM : (w <= bpT) ? auxT : auxD;\r\n\r\n                    controlsList.forEach(function(controls) {\r\n                        controls.setAttribute('data-layout', layout);\r\n                        controls.setAttribute('data-aux', aux);\r\n                    });\r\n                }\r\n\r\n                function clamp(n, a, b) {\r\n                    return Math.max(a, Math.min(b, n));\r\n                }\r\n\r\n                function popClose(root) {\r\n                    var pop = q(root, '.cvxAiHifiPop');\r\n                    if (!pop) return;\r\n                    pop.hidden = true;\r\n                    pop.setAttribute('aria-hidden', 'true');\r\n                    root.__cvxPopOpen = false;\r\n                    root.__cvxPopKind = null;\r\n                }\r\n\r\n                function popOpen(root, kind, clientX, clientY) {\r\n                    var pop = q(root, '.cvxAiHifiPop');\r\n                    var stage = q(root, '.cvxAiHifiStage');\r\n                    if (!pop || !stage) return;\r\n\r\n                    if (root.__cvxPopOpen && root.__cvxPopKind === kind) {\r\n                        popClose(root);\r\n                        return;\r\n                    }\r\n\r\n                    var title = q(root, '[data-ai-pop=\"title\"]');\r\n                    var grid = q(root, '[data-ai-pop=\"grid\"]');\r\n                    if (!grid) return;\r\n\r\n                    var t = (kind === 'send') ? 'Env\u00edo a DAW' : (kind === 'monitor') ? 'Monitoreo' : 'Utilidad';\r\n                    if (title) title.textContent = t;\r\n\r\n                    var current =\r\n                        (kind === 'send') ? (root.dataset.aiSend || 'fx') :\r\n                        (kind === 'monitor') ? (root.dataset.aiMonitor || 'dsp') :\r\n                        (root.dataset.aiUtil || 'loopback');\r\n\r\n                    grid.innerHTML = '';\r\n                    (POP[kind] || []).forEach(function(opt) {\r\n                        var b = document.createElement('button');\r\n                        b.type = 'button';\r\n                        b.className = 'cvxAiHifiPop__btn' + (opt.v === current ? ' is-active' : '');\r\n                        b.setAttribute('data-ai-pop-opt', opt.v);\r\n                        b.setAttribute('data-ai-pop-kind', kind);\r\n\r\n                        var left = document.createElement('span');\r\n                        left.textContent = opt.l;\r\n\r\n                        var pill = document.createElement('span');\r\n                        pill.className = 'cvxAiHifiPop__pill';\r\n                        pill.textContent = opt.r;\r\n\r\n                        b.appendChild(left);\r\n                        b.appendChild(pill);\r\n                        grid.appendChild(b);\r\n                    });\r\n\r\n                    pop.hidden = false;\r\n                    pop.setAttribute('aria-hidden', 'false');\r\n                    root.__cvxPopOpen = true;\r\n                    root.__cvxPopKind = kind;\r\n\r\n                    \/\/ Position (clamped to stage)\r\n                    var r = stage.getBoundingClientRect();\r\n                    var px = clientX - r.left;\r\n                    var py = clientY - r.top;\r\n\r\n                    \/\/ Force layout for width\/height\r\n                    pop.style.left = '0px';\r\n                    pop.style.top = '0px';\r\n                    pop.style.transform = 'translate3d(-9999px,-9999px,0)';\r\n                    var pr = pop.getBoundingClientRect();\r\n\r\n                    var m = 10;\r\n                    var x = clamp(px, m, r.width - pr.width - m);\r\n                    var y = clamp(py, m, r.height - pr.height - m);\r\n\r\n                    pop.style.transform = 'translate3d(' + x + 'px,' + y + 'px,0)';\r\n                }\r\n\r\n                function render(root) {\r\n                    var input = root.dataset.aiInput || 'mic';\r\n                    var send = root.dataset.aiSend || 'fx';\r\n                    var mon = root.dataset.aiMonitor || 'dsp';\r\n                    var util = root.dataset.aiUtil || 'loopback';\r\n\r\n                    var dspOn = !(send === 'dry' && mon === 'direct');\r\n                    setText(q(root, '[data-ai-out=\"nodeDsp\"]'), dspOn ? 'ON' : 'OFF');\r\n\r\n                    setText(q(root, '[data-ai-out=\"nodeUsb\"]'), (send === 'dry') ? 'DRY' : (send === 'blend') ? 'BLEND' : 'FX');\r\n\r\n                    var monLabel = (mon === 'roundtrip') ? 'RT' : (mon === 'direct') ? 'DIRECT' : 'DSP';\r\n                    setText(q(root, '[data-ai-out=\"nodeMon\"]'), monLabel);\r\n\r\n                    var t = TXT[LANG] || TXT.es;\r\n\r\n                    var inLabel = t.input[input] || t.input.mic;\r\n                    var sendLabel = t.send[send] || t.send.fx;\r\n                    var monLabelReadout = t.monitor[mon] || t.monitor.dsp;\r\n                    var utilLabel = t.util[util] || t.util.loopback;\r\n\r\n                    var ro = q(root, '[data-ai-out=\"readout\"]');\r\n                    if (ro) {\r\n                        ro.textContent = '';\r\n\r\n                        function addReadoutPart(label, value) {\r\n                            ro.appendChild(document.createTextNode(label + ' '));\r\n\r\n                            var b = document.createElement('b');\r\n                            b.textContent = value;\r\n                            ro.appendChild(b);\r\n\r\n                            ro.appendChild(document.createTextNode('. '));\r\n                        }\r\n\r\n                        addReadoutPart(t.readoutLeadInput, inLabel);\r\n                        addReadoutPart(t.readoutLeadSend, sendLabel);\r\n                        addReadoutPart(t.readoutLeadMon, monLabelReadout);\r\n                        addReadoutPart(t.readoutLeadUtil, utilLabel);\r\n                    }\r\n                    var flow = 'INPUT (' + (input === 'mic' ? 'MIC' : input === 'trs' ? 'TRS' : 'EXP') + ') \u2192 ANALOG FE \u2192 MIX BUS';\r\n                    if (send === 'fx' || send === 'blend' || (send === 'dry' && mon === 'dsp') || util === 'safety') flow += ' \u2192 (DSP)';\r\n                    flow += (send === 'dry') ? ' \u2192 USB-C (DRY)' : (send === 'blend') ? ' \u2192 USB-C (BLEND)' : ' \u2192 USB-C (FX)';\r\n                    flow += (mon === 'direct') ? ' \u2022 MON: DIRECT' : (mon === 'roundtrip') ? ' \u2022 MON: RT' : ' \u2022 MON: DSP';\r\n                    flow += (util === 'loopback') ? ' \u2022 UTIL: LOOPBACK' : (util === 'reamp') ? ' \u2022 UTIL: REAMP' : ' \u2022 UTIL: SAFETY';\r\n                    setText(q(root, '[data-ai-out=\"flow\"]'), flow);\r\n\r\n\r\n                    applyControlsLayout(root);\r\n                    syncVisuals(root);\r\n                }\r\n\r\n                function init(root) {\r\n                    if (root.__cvxAiHifiInit) return;\r\n                    root.__cvxAiHifiInit = true;\r\n\r\n                    var raf = 0;\r\n\r\n                    function schedule() {\r\n                        cancelAnimationFrame(raf);\r\n                        raf = requestAnimationFrame(function() {\r\n                            render(root);\r\n                        });\r\n                    }\r\n\r\n                    \/\/ Close popover on outside click (within this root)\r\n                    root.addEventListener('click', function(e) {\r\n                        \/\/ Accordion\r\n                        var accBtn = e.target.closest && e.target.closest('.cvxAcc__btn');\r\n                        if (accBtn && root.contains(accBtn)) {\r\n                            var item = accBtn.closest('.cvxAcc__item');\r\n                            if (item) item.classList.toggle('is-open');\r\n                            return;\r\n                        }\r\n\r\n                        \/\/ Popover option click\r\n                        var popOpt = e.target.closest && e.target.closest('[data-ai-pop-opt][data-ai-pop-kind]');\r\n                        if (popOpt && root.contains(popOpt)) {\r\n                            var kind = popOpt.getAttribute('data-ai-pop-kind');\r\n                            var val = popOpt.getAttribute('data-ai-pop-opt');\r\n                            if (kind === 'send') root.dataset.aiSend = val;\r\n                            else if (kind === 'monitor') root.dataset.aiMonitor = val;\r\n                            else if (kind === 'util') root.dataset.aiUtil = val;\r\n\r\n                            popClose(root);\r\n                            render(root);\r\n                            return;\r\n                        }\r\n\r\n                        \/\/ Diagram hit zones\r\n                        var hit = e.target.closest && e.target.closest('[data-ai-hit]');\r\n                        if (hit && root.contains(hit)) {\r\n                            var k = hit.getAttribute('data-ai-hit');\r\n\r\n                            if (k === 'input-mic') {\r\n                                root.dataset.aiInput = 'mic';\r\n                                popClose(root);\r\n                                render(root);\r\n                                return;\r\n                            }\r\n                            if (k === 'input-trs') {\r\n                                root.dataset.aiInput = 'trs';\r\n                                popClose(root);\r\n                                render(root);\r\n                                return;\r\n                            }\r\n                            if (k === 'input-exp') {\r\n                                root.dataset.aiInput = 'exp';\r\n                                popClose(root);\r\n                                render(root);\r\n                                return;\r\n                            }\r\n\r\n                            if (k === 'send') {\r\n                                popOpen(root, 'send', e.clientX, e.clientY);\r\n                                return;\r\n                            }\r\n                            if (k === 'monitor') {\r\n                                popOpen(root, 'monitor', e.clientX, e.clientY);\r\n                                return;\r\n                            }\r\n                            if (k === 'util') {\r\n                                popOpen(root, 'util', e.clientX, e.clientY);\r\n                                return;\r\n                            }\r\n                        }\r\n\r\n                        \/\/ Chip click\r\n                        var btn = e.target.closest && e.target.closest('button[data-ai-group][data-ai-value]');\r\n                        if (btn && root.contains(btn)) {\r\n                            var group = btn.getAttribute('data-ai-group');\r\n                            var value = btn.getAttribute('data-ai-value');\r\n\r\n                            if (group === 'input') root.dataset.aiInput = value;\r\n                            else if (group === 'send') root.dataset.aiSend = value;\r\n                            else if (group === 'monitor') root.dataset.aiMonitor = value;\r\n                            else if (group === 'util') root.dataset.aiUtil = value;\r\n\r\n                            popClose(root);\r\n                            render(root);\r\n                            return;\r\n                        }\r\n\r\n                        \/\/ Click outside popover closes it\r\n                        if (root.__cvxPopOpen) {\r\n                            var pop = q(root, '.cvxAiHifiPop');\r\n                            if (pop && !pop.contains(e.target)) {\r\n                                popClose(root);\r\n                            }\r\n                        }\r\n                    });\r\n\r\n                    \/\/ ESC closes popover (when focus is inside root)\r\n                    root.addEventListener('keydown', function(e) {\r\n                        if (e.key === 'Escape' && root.__cvxPopOpen) {\r\n                            popClose(root);\r\n                        }\r\n                    });\r\n\r\n                    window.addEventListener('resize', schedule, {\r\n                        passive: true\r\n                    });\r\n\r\n                    render(root);\r\n                }\r\n\r\n                roots.forEach(init);\r\n            })();\r\n        <\/script>\r\n    <\/section>\r\n<\/section>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-26a5d96 elementor-section-height-min-height elementor-section-items-stretch fx_section elementor-section-boxed elementor-section-height-default\" data-id=\"26a5d96\" data-element_type=\"section\" data-e-type=\"section\" id=\"multiEffect\" data-settings=\"{&quot;background_background&quot;:&quot;gradient&quot;,&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t\t<div class=\"elementor-background-overlay\"><\/div>\n\t\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-afdee67\" data-id=\"afdee67\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<section class=\"elementor-section elementor-inner-section elementor-element elementor-element-a47f960 elementor-section-full_width elementor-section-height-default elementor-section-height-default\" data-id=\"a47f960\" data-element_type=\"section\" data-e-type=\"section\" data-settings=\"{&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-no\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-inner-column elementor-element elementor-element-4153224\" data-id=\"4153224\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-9fdaa3e animated-slow elementor-invisible elementor-widget elementor-widget-heading\" data-id=\"9fdaa3e\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;slideInDown&quot;}\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Multi-efectos<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-adfde8e elementor-invisible elementor-widget elementor-widget-ha-svg-draw happy-addon ha-svg-draw\" data-id=\"adfde8e\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;slideInLeft&quot;}\" data-widget_type=\"ha-svg-draw.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\n\t\t\t\t<div class=\"ha-svg-draw-container\">\n\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t\n  \n    \n      \n      \n    \n  \n  \n\n\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t<\/div>\n\n\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-inner-section elementor-element elementor-element-fc3a8f5 elementor-section-full_width elementor-section-height-default elementor-section-height-default\" data-id=\"fc3a8f5\" data-element_type=\"section\" data-e-type=\"section\" data-settings=\"{&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-no\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-inner-column elementor-element elementor-element-8b39ad7\" data-id=\"8b39ad7\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-95ec03a animated-slow elementor-invisible elementor-widget elementor-widget-heading\" data-id=\"95ec03a\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;fadeIn&quot;,&quot;_animation_delay&quot;:300}\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Tus efectos, siempre listos<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-e6ebabb elementor-invisible elementor-widget elementor-widget-heading\" data-id=\"e6ebabb\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;fadeInDown&quot;,&quot;_animation_delay&quot;:200}\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Presets y escenas; local o en la nube<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-inner-section elementor-element elementor-element-844b2b6 elementor-section-full_width elementor-section-height-default elementor-section-height-default\" data-id=\"844b2b6\" data-element_type=\"section\" data-e-type=\"section\" data-settings=\"{&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-no\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-inner-column elementor-element elementor-element-1168b2e\" data-id=\"1168b2e\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-6b1f794 elementor-widget elementor-widget-html\" data-id=\"6b1f794\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<section class=\"cvxScope\">\r\n    <section data-cvx-root=\"fx\" style=\"\r\n      \/* =========================================================\r\n         FX \u2014 PARAMETROS (EDITABLES)\r\n         Nota: Para valores \u201cdesktop vs mobile\u201d, editar los sufijos -d \/ -m.\r\n      ========================================================= *\/\r\n\r\n      \/* Layout *\/\r\n      --cvx-fx-bp-mobile: 767px;\r\n      --cvx-fx-gap-d: 18px;\r\n      --cvx-fx-gap-m: 14px;\r\n\r\n      \/* Assets *\/\r\n      --cvx-fx-img-device: url('\/wp-content\/uploads\/cubevox-fx-editing-closeup.webp');\r\n      --cvx-fx-img-remote: url('\/wp-content\/uploads\/compose-app-effects-smartphone-over-shoulder.webp');\r\n      --cvx-fx-stage-ar: 16\/8;\r\n      --cvx-fx-stage-pos: 50% 45%;\r\n      --cvx-fx-remote-ar: 17\/7;\r\n\r\n      \/* Tipograf\u00eda *\/\r\n      --cvx-fx-fs-eye-d: 12px;\r\n      --cvx-fx-fs-eye-m: 11px;\r\n      --cvx-fx-fs-lead-d: 14px;\r\n      --cvx-fx-fs-lead-m: 13px;\r\n      --cvx-fx-fs-ui-d: 12px;\r\n      --cvx-fx-fs-ui-m: 12px;\r\n      --cvx-fx-fs-node-d: 15px;\r\n      --cvx-fx-fs-node-m: 15px;\r\n\r\n      \/* Latencia (slider) *\/\r\n      --cvx-fx-lat-min: 1.5;\r\n      --cvx-fx-lat-max: 8.0;\r\n      --cvx-fx-lat-default: 6.5;\r\n\r\n      \/* Capacidad (bloques) *\/\r\n      --cvx-fx-cap-min: 64;   \/* a lat-min *\/\r\n      --cvx-fx-cap-max: 128;  \/* a lat-max *\/\r\n      --cvx-fx-used-inst: 61; \/* \u201cescena cargada\u201d (ejemplo) *\/\r\n      --cvx-fx-used-voz: 57;\r\n      --cvx-fx-used-dj: 55;\r\n\r\n      \/* Cadena (SVG) \u2014 geometr\u00eda *\/\r\n      --cvx-fx-svg-w: 760;\r\n      --cvx-fx-svg-h: 210;\r\n\r\n      --cvx-fx-io-w-d: 124;\r\n      --cvx-fx-io-w-m: 118;\r\n      --cvx-fx-io-h-d: 56;\r\n      --cvx-fx-io-h-m: 54;\r\n      --cvx-fx-io-pad-d: 18;\r\n      --cvx-fx-io-pad-m: 14;\r\n\r\n      --cvx-fx-line-y-d: 140;\r\n      --cvx-fx-line-y-m: 140;\r\n      --cvx-fx-branch-y-d: 90; \/* solo Instrumento *\/\r\n      --cvx-fx-branch-y-m: 90;\r\n\r\n      \/* Pills de efectos *\/\r\n      --cvx-fx-node-w-d: 162;\r\n      --cvx-fx-node-w-m: 158;\r\n      --cvx-fx-node-h-d: 30;\r\n      --cvx-fx-node-h-m: 30;\r\n      --cvx-fx-node-r-d: 10;\r\n      --cvx-fx-node-r-m: 10;\r\n\r\n      --cvx-fx-node-pad-x: 4px;   \/* margen\/padding horizontal *\/\r\n      --cvx-fx-node-gap-d: 10;     \/* separaci\u00f3n entre pills *\/\r\n      --cvx-fx-node-gap-m: 10;\r\n\r\n      \/* Flujo (dash) *\/\r\n      --cvx-fx-flow-dash: 10;\r\n      --cvx-fx-flow-gap: 14;\r\n      --cvx-fx-flow-base: 2400ms;\r\n\r\n      \/* Orden de efectos (editable) *\/\r\n      --cvx-fx-order-inst: PRE,COMP,DRIVE,AMP,CAB,SUM,REV;\r\n      --cvx-fx-order-inst-par: MOD,DELAY;  \/* paralelo (despu\u00e9s de COMP) *\/\r\n      --cvx-fx-branch-after: COMP;\r\n\r\n      --cvx-fx-order-voz: PRE,GATE,COMP,DEESS,EQ,REV;\r\n      --cvx-fx-order-dj: PRE,EQ,FILTER,SAT,WIDTH,DELAY;\r\n    \">\r\n        <div class=\"cvxFxGrid\">\r\n            <!-- ================= LEFT ================= -->\r\n            <div class=\"cvxFxCol cvxFxCol--left\">\r\n                <div class=\"cvxCard cvxFxCard\">\r\n                    <div class=\"cvxFxEyebrow\">CADENAS + PRESETS POR CANAL<\/div>\r\n\r\n                    <p class=\"cvxFxLead\">\r\n                        Arm\u00e1 cadenas por canal y guard\u00e1 presets\/bancos. Pod\u00e9s operar desde el dispositivo o desde <b>Compose<\/b>.\r\n                    <\/p>\r\n\r\n                    <!-- Latencia (global) -->\r\n                    <div class=\"cvxFxLatency\" aria-label=\"Objetivo de latencia (global)\">\r\n                        <div class=\"cvxFxLatencyHead\">\r\n                            <div class=\"cvxFxLatencyTitle\">Objetivo de latencia<\/div>\r\n                            <div class=\"cvxFxLatencyMeta\">\r\n                                <span data-cvx-fx-lat-label>6.5 ms<\/span>\r\n                                <span class=\"cvxFxSep\">\u2022<\/span>\r\n                                <span>Disp <b data-cvx-fx-cap-label>\u2014<\/b><\/span>\r\n                                <span class=\"cvxFxSep\">\u2022<\/span>\r\n                                <span>Libres <b data-cvx-fx-free-label>\u2014<\/b><\/span>\r\n                            <\/div>\r\n                        <\/div>\r\n\r\n                        <input class=\"cvxFxRange\" type=\"range\" data-cvx-fx-lat-range min=\"1.5\" max=\"8.0\" step=\"0.1\" value=\"6.5\" aria-label=\"Ajustar objetivo de latencia en milisegundos\" \/>\r\n\r\n                        <div class=\"cvxFxLatencyHint\">\r\n                            Defin\u00eds un objetivo y el motor orquesta CPU\/RAM\/latencia, adaptando la complejidad para sostener una respuesta consistente cuando cambian condiciones (carga, canales activos, routing).\r\n                        <\/div>\r\n                    <\/div>\r\n\r\n                    <!-- Switch + control disponible (Compose \/ Footswitch \/ ms \/ DSP) -->\r\n                    <div class=\"cvxFxRow cvxFxRow--top\">\r\n                        <div class=\"cvxFxSwitch\" data-cvx-fx-mode aria-label=\"Contexto de cadena\">\r\n                            <button type=\"button\" class=\"on\" data-mode=\"instrumento\">Instrumento<\/button>\r\n                            <button type=\"button\" data-mode=\"voz\">Voz<\/button>\r\n                            <button type=\"button\" data-mode=\"linea\">DJ\/Line<\/button>\r\n                        <\/div>\r\n\r\n                        <div class=\"cvxFxPills cvxFxPills--metrics\" aria-label=\"Control disponible\">\r\n                            <span class=\"cvxFxPill cvxFxPill--ok\"><i class=\"cvxDot\" aria-hidden=\"true\"><\/i>Compose<\/span>\r\n                            <span class=\"cvxFxPill cvxFxPill--off cvxFxPill--dev\"><i class=\"cvxDot\" aria-hidden=\"true\"><\/i>Footswitch<\/span>\r\n\r\n                            <span class=\"cvxFxPill cvxFxPill--ms\" data-cvx-fx-ms-pill>\r\n                                <i class=\"cvxDot\" aria-hidden=\"true\"><\/i>\r\n                                <span data-cvx-fx-ms-read translate=\"no\" class=\"notranslate\">6.5 ms<\/span>\r\n                            <\/span>\r\n\r\n                            <span class=\"cvxFxPill cvxFxPill--dsp cvxFxPill\" data-cvx-fx-dsp-pill>\r\n                                <span>DSP Load<\/span>\r\n                                <b data-cvx-fx-dsp-label translate=\"no\" class=\"notranslate\">\u2014%<\/b>\r\n                            <\/span>\r\n                        <\/div>\r\n                    <\/div>\r\n\r\n                    <!-- Cadena -->\r\n                    <div class=\"cvxFxChain\" aria-label=\"Cadena (demo)\">\r\n                        <div class=\"cvxFxChainHead\">\r\n                            <div class=\"cvxFxChainTitle\">\r\n                                <b>Perfil:<\/b> <span data-cvx-fx-profile>Instrumento \u2022 Humbucker<\/span>\r\n                            <\/div>\r\n                            <div class=\"cvxFxChainMeta\"><span data-cvx-fx-scene>Preset: Warm Clean<\/span><\/div>\r\n                        <\/div>\r\n\r\n                        <svg class=\"cvxFxSvg\" data-cvx-fx-svg viewBox=\"0 0 760 210\" role=\"img\" aria-label=\"Ruta de efectos\"><\/svg>\r\n\r\n                        <div class=\"cvxFxChainHint\">\r\n                            <span class=\"cvxFxDot\" aria-hidden=\"true\"><\/span>\r\n                            <span>\r\n                                En vivo, pod\u00e9s alternar presets\/bancos desde <b>Compose<\/b> o con un <b>footswitch Bluetooth + NFC<\/b> (en desarrollo) para control hands-free.\r\n                            <\/span>\r\n                        <\/div>\r\n                    <\/div>\r\n\r\n                    <div class=\"cvxFxNote\" role=\"note\" aria-label=\"NFC Link\">\r\n                        <span class=\"cvxFxNoteDot\" aria-hidden=\"true\"><\/span>\r\n                        <span class=\"cvxFxNoteText\">\r\n                            <b>NFC Link:<\/b> accesorios y dispositivos del ecosistema se enlazan por proximidad para sincronizar y configurar de forma guiada.\r\n                        <\/span>\r\n                    <\/div>\r\n                <\/div>\r\n            <\/div>\r\n\r\n            <!-- ================= RIGHT ================= -->\r\n            <div class=\"cvxFxCol cvxFxCol--right\">\r\n                <!-- Imagen 1 + card-info (igual patr\u00f3n que Control remoto) -->\r\n                <div class=\"cvxCard cvxFxStage\" aria-label=\"Procesamiento de Nueva Generaci\u00f3n\">\r\n                    <div class=\"cvxFxStageMedia\" aria-hidden=\"true\"><\/div>\r\n\r\n\r\n\r\n                    <div class=\"cvxFxStageBar\" aria-label=\"Procesamiento de Nueva Generaci\u00f3n\">\r\n                        <div class=\"cvxFxRemoteTitle\">Procesamiento de Nueva Generaci\u00f3n<\/div>\r\n                        <div class=\"cvxFxRemoteText\">\r\n                            Impulsado por el chip <b>SHARC+<\/b> m\u00e1s potente del mundo. Desde latencia ultra-baja para vivo hasta configuraciones de estudio con m\u00e1s de <b>100 efectos simult\u00e1neos<\/b>.\r\n                        <\/div>\r\n                    <\/div>\r\n                <\/div>\r\n\r\n                <!-- Imagen 2 + card-info -->\r\n                <div class=\"cvxCard cvxFxRemote\" aria-label=\"Control remoto (imagen)\">\r\n                    <div class=\"cvxFxRemoteImg\" role=\"img\" aria-label=\"Compose controlando presets\"><\/div>\r\n                    <div class=\"cvxFxRemoteBar\">\r\n                        <div class=\"cvxFxRemoteTitle\">Control remoto<\/div>\r\n                        <div class=\"cvxFxRemoteText\">\r\n                            Selecci\u00f3n de <b>presets<\/b> y <b>bancos<\/b> desde Compose. Preparado para control hands-free con footswitch (dev).\r\n                        <\/div>\r\n                    <\/div>\r\n                <\/div>\r\n            <\/div>\r\n        <\/div>\r\n\r\n        <style>\r\n            \/* =========================\r\n         FX \u2014 minimal + overflow-safe\r\n      ========================== *\/\r\n            .cvxScope [data-cvx-root=\"fx\"] {\r\n                overflow-x: clip;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"fx\"] b,\r\n            .cvxScope [data-cvx-root=\"fx\"] strong {\r\n                font-weight: var(--cvxWBold, 850);\r\n            }\r\n\r\n            \/* Desktop\/Mobile var switch (edit via -d \/ -m) *\/\r\n            .cvxScope [data-cvx-root=\"fx\"] {\r\n                --cvx-fx-gap: var(--cvx-fx-gap-d);\r\n                --cvx-fx-fs-eye: var(--cvx-fx-fs-eye-d);\r\n                --cvx-fx-fs-lead: var(--cvx-fx-fs-lead-d);\r\n                --cvx-fx-fs-ui: var(--cvx-fx-fs-ui-d);\r\n                --cvx-fx-fs-node: var(--cvx-fx-fs-node-d);\r\n\r\n                --cvx-fx-io-w: var(--cvx-fx-io-w-d);\r\n                --cvx-fx-io-h: var(--cvx-fx-io-h-d);\r\n                --cvx-fx-io-pad: var(--cvx-fx-io-pad-d);\r\n\r\n                --cvx-fx-line-y: var(--cvx-fx-line-y-d);\r\n                --cvx-fx-branch-y: var(--cvx-fx-branch-y-d);\r\n\r\n                --cvx-fx-node-w: var(--cvx-fx-node-w-d);\r\n                --cvx-fx-node-h: var(--cvx-fx-node-h-d);\r\n                --cvx-fx-node-r: var(--cvx-fx-node-r-d);\r\n                --cvx-fx-node-gap: var(--cvx-fx-node-gap-d);\r\n            }\r\n\r\n            @media (max-width: 767px) {\r\n                .cvxScope [data-cvx-root=\"fx\"] {\r\n                    --cvx-fx-gap: var(--cvx-fx-gap-m);\r\n                    --cvx-fx-fs-eye: var(--cvx-fx-fs-eye-m);\r\n                    --cvx-fx-fs-lead: var(--cvx-fx-fs-lead-m);\r\n                    --cvx-fx-fs-ui: var(--cvx-fx-fs-ui-m);\r\n                    --cvx-fx-fs-node: var(--cvx-fx-fs-node-m);\r\n\r\n                    --cvx-fx-io-w: var(--cvx-fx-io-w-m);\r\n                    --cvx-fx-io-h: var(--cvx-fx-io-h-m);\r\n                    --cvx-fx-io-pad: var(--cvx-fx-io-pad-m);\r\n\r\n                    --cvx-fx-line-y: var(--cvx-fx-line-y-m);\r\n                    --cvx-fx-branch-y: var(--cvx-fx-branch-y-m);\r\n\r\n                    --cvx-fx-node-w: var(--cvx-fx-node-w-m);\r\n                    --cvx-fx-node-h: var(--cvx-fx-node-h-m);\r\n                    --cvx-fx-node-r: var(--cvx-fx-node-r-m);\r\n                    --cvx-fx-node-gap: var(--cvx-fx-node-gap-m);\r\n                }\r\n            }\r\n\r\n            \/* Grid anti-overflow *\/\r\n            .cvxScope [data-cvx-root=\"fx\"] .cvxFxGrid {\r\n                display: grid;\r\n                grid-template-columns: minmax(0, 1.05fr) minmax(0, .95fr);\r\n                gap: var(--cvx-fx-gap);\r\n                align-items: start;\r\n                min-width: 0;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"fx\"] .cvxFxCol {\r\n                min-width: 0;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"fx\"] :where(.cvxFxGrid, .cvxCard) {\r\n                min-width: 0;\r\n                max-width: 100%;\r\n            }\r\n\r\n            @media (max-width: 767px) {\r\n                .cvxScope [data-cvx-root=\"fx\"] .cvxFxGrid {\r\n                    grid-template-columns: minmax(0, 1fr);\r\n                }\r\n            }\r\n\r\n            \/* Left card *\/\r\n            .cvxScope [data-cvx-root=\"fx\"] .cvxFxCard {\r\n                padding: 14px;\r\n                display: grid;\r\n                gap: 12px;\r\n                min-width: 0;\r\n            }\r\n\r\n            \/* Wrap-safety *\/\r\n            .cvxScope [data-cvx-root=\"fx\"] :where(.cvxFxLead, .cvxFxLatencyHint, .cvxFxChainHint, .cvxFxRemoteText, .cvxFxNoteText) {\r\n                overflow-wrap: anywhere;\r\n                word-break: break-word;\r\n                hyphens: auto;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"fx\"] .cvxFxEyebrow {\r\n                color: rgba(255, 255, 255, .72);\r\n                font-weight: 850;\r\n                letter-spacing: .16em;\r\n                text-transform: uppercase;\r\n                font-size: var(--cvx-fx-fs-eye);\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"fx\"] .cvxFxLead {\r\n                margin: 0;\r\n                color: rgba(255, 255, 255, .82);\r\n                font-size: var(--cvx-fx-fs-lead);\r\n                line-height: 1.45;\r\n            }\r\n\r\n            \/* Row *\/\r\n            .cvxScope [data-cvx-root=\"fx\"] .cvxFxRow {\r\n                display: flex;\r\n                flex-wrap: wrap;\r\n                gap: 10px;\r\n                align-items: center;\r\n                min-width: 0;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"fx\"] .cvxFxRow--top {\r\n                display: grid;\r\n                grid-template-columns: minmax(0, 1fr);\r\n                gap: 10px;\r\n                align-items: start;\r\n            }\r\n\r\n            \/* Switch *\/\r\n            .cvxScope [data-cvx-root=\"fx\"] .cvxFxSwitch {\r\n                display: flex;\r\n                width: 100%;\r\n                min-width: 0;\r\n                border-radius: 14px;\r\n                border: 1px solid rgba(255, 255, 255, .10);\r\n                background: rgba(0, 0, 0, .18);\r\n                overflow: hidden;\r\n                box-shadow: inset 0 1px 0 rgba(255, 255, 255, .06);\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"fx\"] .cvxFxSwitch button {\r\n                flex: 1 1 0;\r\n                min-width: 0;\r\n                padding: 10px 10px;\r\n                border: 0;\r\n                background: transparent;\r\n                color: rgba(255, 255, 255, .74);\r\n                font: inherit;\r\n                font-size: var(--cvx-fx-fs-ui);\r\n                font-weight: 850;\r\n                letter-spacing: .02em;\r\n                white-space: nowrap;\r\n                overflow: hidden;\r\n                text-overflow: ellipsis;\r\n                cursor: pointer;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"fx\"] .cvxFxSwitch button.on {\r\n                background: color-mix(in srgb, var(--cvxAccent) 22%, rgba(255, 255, 255, .06));\r\n                color: rgba(255, 255, 255, .92);\r\n            }\r\n\r\n            \/* Pills (control disponible) *\/\r\n            .cvxScope [data-cvx-root=\"fx\"] .cvxFxPills {\r\n                display: flex;\r\n                flex-wrap: wrap;\r\n                gap: 8px;\r\n                min-width: 0;\r\n                max-width: 100%;\r\n                justify-content: flex-end;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"fx\"] .cvxFxPills--metrics {\r\n                width: 100%;\r\n                display: grid;\r\n                grid-template-columns: repeat(4, minmax(0, 1fr));\r\n                gap: 8px;\r\n                justify-content: stretch;\r\n                align-items: stretch;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"fx\"] .cvxFxPill {\r\n                display: inline-flex;\r\n                align-items: center;\r\n                gap: 8px;\r\n                border: 1px solid rgba(255, 255, 255, .10);\r\n                background: rgba(0, 0, 0, .18);\r\n                color: rgba(255, 255, 255, .78);\r\n                border-radius: 999px;\r\n                padding: 8px 10px;\r\n                font-size: var(--cvx-fx-fs-ui);\r\n                box-shadow: inset 0 1px 0 rgba(255, 255, 255, .06);\r\n                white-space: nowrap;\r\n                max-width: 100%;\r\n                min-width: 0;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"fx\"] .cvxFxPills--metrics .cvxFxPill {\r\n                width: 100%;\r\n                justify-content: center;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"fx\"] .cvxFxPills--metrics .cvxFxPill--dsp {\r\n                justify-content: space-between;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"fx\"] .cvxFxPill--dev {\r\n                border-color: color-mix(in srgb, var(--cvxAccent) 22%, rgba(255, 255, 255, .10));\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"fx\"] .cvxFxPill--off {\r\n                opacity: .58;\r\n                filter: grayscale(.2);\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"fx\"] .cvxFxPill--ok {\r\n                color: rgba(255, 255, 255, .86);\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"fx\"] .cvxFxPill--ms {\r\n                color: rgba(255, 255, 255, .84);\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"fx\"] .cvxFxPill--dsp {\r\n                justify-content: space-between;\r\n                min-width: 0;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"fx\"] .cvxFxPill--grow {\r\n                flex: 1 0 100%;\r\n                \/* Ocupa el 100% del ancho y fuerza nueva l\u00ednea *\/\r\n                min-width: 0;\r\n                margin-top: 0px;\r\n                \/* Separaci\u00f3n opcional *\/\r\n                justify-content: space-between;\r\n                \/* Mantiene el estilo original *\/\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"fx\"] .cvxDot {\r\n                width: 8px;\r\n                height: 8px;\r\n                border-radius: 999px;\r\n                background: rgba(255, 255, 255, .22);\r\n                box-shadow: 0 0 0 1px rgba(255, 255, 255, .10) inset;\r\n                flex: 0 0 auto;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"fx\"] .cvxFxPill--ok .cvxDot {\r\n                background: var(--cvxAccent);\r\n                box-shadow: 0 0 14px color-mix(in srgb, var(--cvxAccent) 40%, transparent);\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"fx\"] .cvxFxPill--ms .cvxDot {\r\n                background: color-mix(in srgb, var(--cvxAccent) 75%, rgba(255, 255, 255, .15));\r\n                box-shadow: 0 0 14px color-mix(in srgb, var(--cvxAccent) 35%, transparent);\r\n            }\r\n\r\n            \/* Latency card *\/\r\n            .cvxScope [data-cvx-root=\"fx\"] .cvxFxLatency {\r\n                border-radius: var(--cvxRadiusMD);\r\n                border: 1px solid rgba(255, 255, 255, .10);\r\n                background: rgba(0, 0, 0, .18);\r\n                padding: 12px;\r\n                box-shadow: inset 0 1px 0 rgba(255, 255, 255, .06);\r\n                min-width: 0;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"fx\"] .cvxFxLatencyHead {\r\n                display: flex;\r\n                align-items: baseline;\r\n                justify-content: space-between;\r\n                gap: 10px;\r\n                min-width: 0;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"fx\"] .cvxFxLatencyTitle {\r\n                color: rgba(255, 255, 255, .90);\r\n                font-weight: 850;\r\n                font-size: 13px;\r\n                min-width: 0;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"fx\"] .cvxFxLatencyMeta {\r\n                color: rgba(255, 255, 255, .68);\r\n                font-size: 12px;\r\n                white-space: nowrap;\r\n                flex: 0 0 auto;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"fx\"] .cvxFxSep {\r\n                opacity: .55;\r\n                padding: 0 6px;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"fx\"] .cvxFxRange {\r\n                width: 100%;\r\n                margin-top: 10px;\r\n                accent-color: var(--cvxAccent);\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"fx\"] .cvxFxLatencyHint {\r\n                margin-top: 10px;\r\n                color: rgba(255, 255, 255, .66);\r\n                font-size: 12px;\r\n                line-height: 1.35;\r\n            }\r\n\r\n            \/* Chain card *\/\r\n            .cvxScope [data-cvx-root=\"fx\"] .cvxFxChain {\r\n                border-radius: var(--cvxRadiusMD);\r\n                border: 1px solid rgba(255, 255, 255, .10);\r\n                background: radial-gradient(90% 120% at 35% 55%, color-mix(in srgb, var(--cvxAccent) 18%, transparent), transparent 60%),\r\n                    linear-gradient(180deg, rgba(255, 255, 255, .06), rgba(0, 0, 0, .22));\r\n                padding: 12px;\r\n                overflow: hidden;\r\n                box-shadow: inset 0 1px 0 rgba(255, 255, 255, .06);\r\n                min-width: 0;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"fx\"] .cvxFxChainHead {\r\n                display: flex;\r\n                align-items: baseline;\r\n                justify-content: space-between;\r\n                gap: 12px;\r\n                margin-bottom: 10px;\r\n                min-width: 0;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"fx\"] .cvxFxChainTitle {\r\n                color: rgba(255, 255, 255, .90);\r\n                font-weight: 800;\r\n                font-size: 13px;\r\n                min-width: 0;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"fx\"] .cvxFxChainMeta {\r\n                color: rgba(255, 255, 255, .62);\r\n                font-size: 12px;\r\n                min-width: 0;\r\n                white-space: nowrap;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"fx\"] .cvxFxSvg {\r\n                width: 100%;\r\n                max-width: 100%;\r\n                height: auto;\r\n                display: block;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"fx\"] .fxPath {\r\n                fill: none;\r\n                stroke-linecap: round;\r\n                stroke-linejoin: round;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"fx\"] .fxPath--base {\r\n                stroke: rgba(255, 255, 255, .14);\r\n                stroke-width: 6;\r\n                filter: drop-shadow(0 10px 24px rgba(0, 0, 0, .55));\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"fx\"] .fxPath--flow {\r\n                stroke: color-mix(in srgb, var(--cvxAccent) 65%, rgba(255, 255, 255, .10));\r\n                stroke-width: 3.6;\r\n                stroke-dasharray: var(--cvx-fx-flow-dash) var(--cvx-fx-flow-gap);\r\n                opacity: .78;\r\n                animation: cvxFxDash var(--cvx-fx-calc-flow, var(--cvx-fx-flow-base)) linear infinite;\r\n                filter: drop-shadow(0 0 18px color-mix(in srgb, var(--cvxAccent) 42%, transparent));\r\n            }\r\n\r\n            @keyframes cvxFxDash {\r\n                to {\r\n                    stroke-dashoffset: -150;\r\n                }\r\n            }\r\n\r\n            \/* Effect pills (cuadrados + texto m\u00e1s grande) *\/\r\n            .cvxScope [data-cvx-root=\"fx\"] .fxPill rect {\r\n                fill: rgba(0, 0, 0, .5);\r\n                stroke: rgba(255, 255, 255, .16);\r\n                stroke-width: 1;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"fx\"] .fxPill text {\r\n                fill: rgba(255, 255, 255, .82);\r\n                font-size: var(--cvx-fx-fs-node);\r\n                font-weight: 900;\r\n                letter-spacing: .04em;\r\n            }\r\n\r\n            \/* IO micro-cards *\/\r\n            .cvxScope [data-cvx-root=\"fx\"] .fxIO rect {\r\n                fill: rgba(0, 0, 0, .34);\r\n                stroke: rgba(255, 255, 255, .14);\r\n                stroke-width: 1;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"fx\"] .fxIO .t1 {\r\n                fill: rgba(255, 255, 255, .72);\r\n                font-size: 13px;\r\n                font-weight: 900;\r\n                letter-spacing: .14em;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"fx\"] .fxIO .t2 {\r\n                fill: rgba(255, 255, 255, .92);\r\n                font-size: 12px;\r\n                font-weight: 900;\r\n                letter-spacing: .02em;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"fx\"] .cvxFxChainHint {\r\n                display: flex;\r\n                align-items: flex-start;\r\n                gap: 10px;\r\n                margin-top: 10px;\r\n                padding-top: 10px;\r\n                border-top: 1px solid rgba(255, 255, 255, .07);\r\n                color: rgba(255, 255, 255, .68);\r\n                font-size: 12px;\r\n                line-height: 1.35;\r\n                min-width: 0;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"fx\"] .cvxFxDot {\r\n                width: 10px;\r\n                height: 10px;\r\n                border-radius: 999px;\r\n                background: var(--cvxAccent);\r\n                box-shadow: 0 0 18px color-mix(in srgb, var(--cvxAccent) 45%, transparent);\r\n                flex: 0 0 auto;\r\n                margin-top: 2px;\r\n            }\r\n\r\n            \/* NFC note *\/\r\n            .cvxScope [data-cvx-root=\"fx\"] .cvxFxNote {\r\n                display: flex;\r\n                align-items: flex-start;\r\n                gap: 10px;\r\n                padding: 12px;\r\n                border-radius: var(--cvxRadiusMD);\r\n                border: 1px solid color-mix(in srgb, var(--cvxAccent) 22%, rgba(255, 255, 255, .10));\r\n                background: color-mix(in srgb, rgba(0, 0, 0, .22) 70%, transparent);\r\n                min-width: 0;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"fx\"] .cvxFxNoteDot {\r\n                width: 10px;\r\n                height: 10px;\r\n                border-radius: 999px;\r\n                background: color-mix(in srgb, var(--cvxAccent) 78%, white 0%);\r\n                box-shadow: 0 0 18px color-mix(in srgb, var(--cvxAccent) 40%, transparent);\r\n                flex: 0 0 auto;\r\n                margin-top: 3px;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"fx\"] .cvxFxNoteText {\r\n                color: rgba(255, 255, 255, .72);\r\n                font-size: 12px;\r\n                line-height: 1.35;\r\n                min-width: 0;\r\n            }\r\n\r\n            \/* Stage *\/\r\n            .cvxScope [data-cvx-root=\"fx\"] .cvxFxStage {\r\n                padding: 10px;\r\n                display: grid;\r\n                gap: 10px;\r\n                min-width: 0;\r\n                margin-bottom: 10px;\r\n\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"fx\"] .cvxFxStageMedia {\r\n                position: relative;\r\n                border-radius: calc(var(--cvxRadiusMD) - 2px);\r\n                border: 1px solid rgba(255, 255, 255, .10);\r\n                aspect-ratio: var(--cvx-fx-stage-ar);\r\n                overflow: hidden;\r\n                background-image:\r\n                    var(--cvx-fx-img-device),\r\n                    radial-gradient(90% 120% at 25% 25%, color-mix(in srgb, var(--cvxAccent) 18%, transparent), transparent 60%),\r\n                    linear-gradient(180deg, rgba(255, 255, 255, .06), rgba(0, 0, 0, .24));\r\n                background-size: cover;\r\n                background-position: var(--cvx-fx-stage-pos);\r\n                box-shadow: inset 0 1px 0 rgba(255, 255, 255, .06);\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"fx\"] .cvxFxStageOverlay {\r\n                position: absolute;\r\n                left: 12px;\r\n                right: 12px;\r\n                bottom: 12px;\r\n                display: flex;\r\n                gap: 8px;\r\n                flex-wrap: wrap;\r\n                pointer-events: none;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"fx\"] .cvxFxBadge {\r\n                border: 1px solid rgba(255, 255, 255, .10);\r\n                background: rgba(0, 0, 0, .18);\r\n                color: rgba(255, 255, 255, .82);\r\n                border-radius: 999px;\r\n                padding: 8px 10px;\r\n                font-size: 12px;\r\n                white-space: nowrap;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"fx\"] .cvxFxStageBar {\r\n                border-radius: calc(var(--cvxRadiusMD) - 2px);\r\n                border: 1px solid rgba(255, 255, 255, .10);\r\n                background: rgba(0, 0, 0, .18);\r\n                padding: 10px;\r\n                box-shadow: inset 0 1px 0 rgba(255, 255, 255, .06);\r\n                min-width: 0;\r\n            }\r\n\r\n            \/* Remote *\/\r\n            .cvxScope [data-cvx-root=\"fx\"] .cvxFxRemote {\r\n                padding: 10px;\r\n                display: grid;\r\n                gap: 10px;\r\n                min-width: 0;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"fx\"] .cvxFxRemoteImg {\r\n\r\n                border-radius: calc(var(--cvxRadiusMD) - 2px);\r\n                border: 1px solid rgba(255, 255, 255, .10);\r\n                background-image:\r\n                    var(--cvx-fx-img-remote),\r\n                    radial-gradient(90% 120% at 25% 25%, color-mix(in srgb, var(--cvxAccent) 18%, transparent), transparent 60%),\r\n                    linear-gradient(180deg, rgba(255, 255, 255, .06), rgba(0, 0, 0, .22));\r\n                background-size: cover;\r\n                background-position: 50% 45%;\r\n                aspect-ratio: var(--cvx-fx-remote-ar);\r\n                overflow: hidden;\r\n                min-width: 0;\r\n                box-shadow: inset 0 1px 0 rgba(255, 255, 255, .06);\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"fx\"] .cvxFxRemoteBar {\r\n                border-radius: calc(var(--cvxRadiusMD) - 2px);\r\n                border: 1px solid rgba(255, 255, 255, .10);\r\n                background: rgba(0, 0, 0, .18);\r\n                padding: 10px;\r\n                min-width: 0;\r\n                box-shadow: inset 0 1px 0 rgba(255, 255, 255, .06);\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"fx\"] .cvxFxRemoteTitle {\r\n                color: rgba(255, 255, 255, .90);\r\n                font-weight: 850;\r\n                font-size: 13px;\r\n                margin-bottom: 6px;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"fx\"] .cvxFxRemoteText {\r\n                color: rgba(255, 255, 255, .72);\r\n                font-size: 12px;\r\n                line-height: 1.35;\r\n                min-width: 0;\r\n            }\r\n\r\n            \/* Quitar negrita al texto din\u00e1mico del perfil *\/\r\n            .cvxScope [data-cvx-root=\"fx\"] .cvxFxChainTitle span[data-cvx-fx-profile] {\r\n                font-weight: 400;\r\n                \/* O el peso normal que uses *\/\r\n                color: rgba(255, 255, 255, .78);\r\n                \/* Ajusta el color si es necesario *\/\r\n            }\r\n\r\n            @media (prefers-reduced-motion: reduce) {\r\n                .cvxScope [data-cvx-root=\"fx\"] .fxPath--flow {\r\n                    animation: none !important;\r\n                }\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"fx\"] .cvxFxPill--ms {\r\n                min-width: 0;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"fx\"] .cvxFxPill--dsp {\r\n                min-width: 0;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"fx\"] [data-cvx-fx-ms-read] {\r\n                display: inline-block;\r\n                min-width: 5.5ch;\r\n                font-variant-numeric: tabular-nums;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"fx\"] [data-cvx-fx-dsp-label] {\r\n                display: inline-block;\r\n                min-width: 3ch;\r\n                text-align: right;\r\n                font-variant-numeric: tabular-nums;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"fx\"] [data-cvx-fx-ms-read]:empty::after {\r\n                content: \"0.0 ms\";\r\n                visibility: hidden;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"fx\"] [data-cvx-fx-dsp-label]:empty::after {\r\n                content: \"00%\";\r\n                visibility: hidden;\r\n            }\r\n\r\n            \/* =========================================================\r\n   FX pills \u2014 override final v2\r\n   - Una sola l\u00f3gica:\r\n   - Se estiran cuando entran en una fila\r\n   - Si no entran por ancho m\u00ednimo de contenido, envuelven a 2 filas\r\n========================================================= *\/\r\n\r\n            .cvxScope [data-cvx-root=\"fx\"] .cvxFxRow--top {\r\n                display: grid;\r\n                grid-template-columns: minmax(0, 1fr);\r\n                gap: 10px;\r\n                align-items: start;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"fx\"] .cvxFxSwitch {\r\n                width: 100%;\r\n                min-width: 0;\r\n                flex: unset;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"fx\"] .cvxFxPills--metrics {\r\n                width: 100%;\r\n                display: flex;\r\n                flex-wrap: wrap;\r\n                align-items: stretch;\r\n                justify-content: flex-start;\r\n                gap: 8px;\r\n                min-width: 0;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"fx\"] .cvxFxPills--metrics .cvxFxPill {\r\n                flex: 1 1 0;\r\n                width: auto;\r\n                min-width: max-content;\r\n                max-width: 100%;\r\n                justify-content: center;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"fx\"] .cvxFxPills--metrics .cvxFxPill--dsp {\r\n                justify-content: space-between;\r\n            }\r\n\r\n            @media (max-width: 767px) {\r\n                .cvxScope [data-cvx-root=\"fx\"] .cvxFxPills--metrics {\r\n                    gap: 6px;\r\n                }\r\n\r\n                .cvxScope [data-cvx-root=\"fx\"] .cvxFxPills--metrics .cvxFxPill {\r\n                    padding: 8px 8px;\r\n                }\r\n\r\n                .cvxScope [data-cvx-root=\"fx\"] .cvxFxPills--metrics .cvxFxPill--dsp {\r\n                    gap: 6px;\r\n                }\r\n            }\r\n        <\/style>\r\n\r\n        <script>\r\n            (() => {\r\n                'use strict';\r\n\r\n                const roots = document.querySelectorAll('.cvxScope [data-cvx-root=\"fx\"]');\r\n                roots.forEach((root) => {\r\n                    if (root.__cvxFxInit) return;\r\n                    root.__cvxFxInit = true;\r\n\r\n                    const modeWrap = root.querySelector('[data-cvx-fx-mode]');\r\n                    const svg = root.querySelector('[data-cvx-fx-svg]');\r\n\r\n                    const range = root.querySelector('[data-cvx-fx-lat-range]');\r\n                    const latLabel = root.querySelector('[data-cvx-fx-lat-label]');\r\n                    const capLabel = root.querySelector('[data-cvx-fx-cap-label]');\r\n                    const freeLabel = root.querySelector('[data-cvx-fx-free-label]');\r\n\r\n                    const profileEl = root.querySelector('[data-cvx-fx-profile]');\r\n                    const sceneEl = root.querySelector('[data-cvx-fx-scene]');\r\n\r\n                    const msReadEl = root.querySelector('[data-cvx-fx-ms-read]');\r\n                    const dspLblEl = root.querySelector('[data-cvx-fx-dsp-label]');\r\n\r\n                    const csNum = (name, fallback) => {\r\n                        const v = getComputedStyle(root).getPropertyValue(name).trim();\r\n                        const n = Number(v);\r\n                        return Number.isFinite(n) ? n : fallback;\r\n                    };\r\n                    const csStr = (name, fallback) => {\r\n                        const v = getComputedStyle(root).getPropertyValue(name).trim();\r\n                        return v ? v : fallback;\r\n                    };\r\n                    const clamp = (v, a, b) => Math.max(a, Math.min(b, v));\r\n                    const round1 = (v) => Math.round(v * 10) \/ 10;\r\n\r\n                    const parseList = (s) => String(s || '')\r\n                        .split(',')\r\n                        .map(x => x.trim())\r\n                        .filter(Boolean);\r\n\r\n                    const CFG = {\r\n                        profiles: {\r\n                            instrumento: 'INST \u2022 Humbucker',\r\n                            voz: 'MIC \u2022 Condenser',\r\n                            linea: 'LINE \u2022 Stereo'\r\n                        },\r\n                        scenes: {\r\n                            instrumento: 'Preset: Warm Clean',\r\n                            voz: 'Preset: Vocal Tight',\r\n                            linea: 'Preset: DJ Wide'\r\n                        },\r\n                        io: {\r\n                            instrumento: {\r\n                                in: ['SOURCE', 'IN1 \u2022 TRS\/TS'],\r\n                                out: ['OUTPUT', 'MAIN']\r\n                            },\r\n                            voz: {\r\n                                in: ['SOURCE', 'IN2 \u2022 XLR'],\r\n                                out: ['OUTPUT', 'MAIN']\r\n                            },\r\n                            linea: {\r\n                                in: ['SOURCE', 'MEDIA \u2022 AUX'],\r\n                                out: ['OUTPUT', 'MAIN']\r\n                            }\r\n                        }\r\n                    };\r\n\r\n                    let mode = 'instrumento';\r\n\r\n                    function capacityFromLatency(ms) {\r\n                        const minMs = csNum('--cvx-fx-lat-min', 1.5);\r\n                        const maxMs = csNum('--cvx-fx-lat-max', 8.0);\r\n                        const capMin = csNum('--cvx-fx-cap-min', 64);\r\n                        const capMax = csNum('--cvx-fx-cap-max', 128);\r\n                        const t = (ms - minMs) \/ (maxMs - minMs);\r\n                        return Math.round(capMin + clamp(t, 0, 1) * (capMax - capMin));\r\n                    }\r\n\r\n                    function usedBlocksForMode(m) {\r\n                        const key = m === 'instrumento' ? '--cvx-fx-used-inst' :\r\n                            m === 'voz' ? '--cvx-fx-used-voz' :\r\n                            '--cvx-fx-used-dj';\r\n                        return csNum(key, 58);\r\n                    }\r\n\r\n                    function flowFromLatency(ms) {\r\n                        const base = 2400;\r\n                        const delta = clamp((6.5 - ms) * 120, -700, 500);\r\n                        return Math.max(1300, base + delta);\r\n                    }\r\n\r\n                    function setLatency(ms) {\r\n                        const min = csNum('--cvx-fx-lat-min', 1.5);\r\n                        const max = csNum('--cvx-fx-lat-max', 8.0);\r\n                        const v = clamp(ms, min, max);\r\n\r\n                        \/\/ Labels (sin ruido: UI estable)\r\n                        if (latLabel) latLabel.textContent = `${round1(v).toFixed(1)} ms`;\r\n\r\n                        const cap = capacityFromLatency(v);\r\n                        const used = usedBlocksForMode(mode);\r\n                        const free = Math.max(0, cap - used);\r\n\r\n                        if (capLabel) capLabel.textContent = String(cap);\r\n                        if (freeLabel) freeLabel.textContent = String(free);\r\n\r\n                        \/\/ Dash speed\r\n                        root.style.setProperty('--cvx-fx-calc-flow', `${flowFromLatency(v)}ms`);\r\n\r\n                        \/\/ DSP load (base, luego se \u201coscila\u201d levemente)\r\n                        const load = clamp((used \/ Math.max(1, cap)) * 100, 0, 99);\r\n                        root.__cvxFxBase = {\r\n                            ms: v,\r\n                            cap,\r\n                            used,\r\n                            load\r\n                        };\r\n\r\n                        \/* Sync inmediato (evita dependencia exclusiva de rAF en iOS\/mobile) *\/\r\n                        if (msReadEl) msReadEl.textContent = `${round1(v).toFixed(1)} ms`;\r\n                        if (dspLblEl) dspLblEl.textContent = `${Math.round(load)}%`;\r\n\r\n                    }\r\n\r\n                    function mkEl(tag, attrs = {}) {\r\n                        const el = document.createElementNS('http:\/\/www.w3.org\/2000\/svg', tag);\r\n                        Object.entries(attrs).forEach(([k, v]) => el.setAttribute(k, String(v)));\r\n                        return el;\r\n                    }\r\n\r\n                    function addIO(svgRoot, x, y, w, h, title, value) {\r\n                        const g = mkEl('g', {\r\n                            class: 'fxIO',\r\n                            transform: `translate(${x},${y})`\r\n                        });\r\n                        const rect = mkEl('rect', {\r\n                            x: 0,\r\n                            y: 0,\r\n                            width: w,\r\n                            height: h,\r\n                            rx: 12,\r\n                            ry: 12\r\n                        });\r\n                        const t1 = mkEl('text', {\r\n                            class: 't1',\r\n                            x: 12,\r\n                            y: 18\r\n                        });\r\n                        t1.textContent = title;\r\n                        const t2 = mkEl('text', {\r\n                            class: 't2',\r\n                            x: 12,\r\n                            y: 40\r\n                        });\r\n                        t2.textContent = value;\r\n                        g.appendChild(rect);\r\n                        g.appendChild(t1);\r\n                        g.appendChild(t2);\r\n                        svgRoot.appendChild(g);\r\n                        return {\r\n                            x,\r\n                            y,\r\n                            w,\r\n                            h,\r\n                            cx: x + w \/ 2,\r\n                            bottom: y + h\r\n                        };\r\n                    }\r\n\r\n                    function addPill(svgRoot, x, y, w, h, r, label) {\r\n                        const g = mkEl('g', {\r\n                            class: 'fxPill',\r\n                            transform: `translate(${x},${y})`\r\n                        });\r\n                        const rect = mkEl('rect', {\r\n                            x: -w \/ 2,\r\n                            y: -h \/ 2,\r\n                            width: w,\r\n                            height: h,\r\n                            rx: r,\r\n                            ry: r\r\n                        });\r\n                        const text = mkEl('text', {\r\n                            x: 0,\r\n                            y: 4,\r\n                            'text-anchor': 'middle'\r\n                        });\r\n                        text.textContent = label;\r\n                        g.appendChild(rect);\r\n                        g.appendChild(text);\r\n                        svgRoot.appendChild(g);\r\n                        return {\r\n                            x,\r\n                            y\r\n                        };\r\n                    }\r\n\r\n                    function renderChain() {\r\n                        if (!svg) return;\r\n                        svg.innerHTML = '';\r\n\r\n                        const W = csNum('--cvx-fx-svg-w', 760);\r\n                        const H = csNum('--cvx-fx-svg-h', 210);\r\n                        svg.setAttribute('viewBox', `0 0 ${W} ${H}`);\r\n\r\n                        const ioW = csNum('--cvx-fx-io-w', 124);\r\n                        const ioH = csNum('--cvx-fx-io-h', 56);\r\n                        const ioPad = csNum('--cvx-fx-io-pad', 18);\r\n\r\n                        const yLine = csNum('--cvx-fx-line-y', 132);\r\n                        const yBranch = csNum('--cvx-fx-branch-y', 168);\r\n\r\n                        const nodeW = csNum('--cvx-fx-node-w', 62);\r\n                        const nodeH = csNum('--cvx-fx-node-h', 28);\r\n                        const nodeR = csNum('--cvx-fx-node-r', 10);\r\n                        const gap = csNum('--cvx-fx-node-gap', 7);\r\n\r\n                        const ioY = 14;\r\n\r\n                        const g = mkEl('g', {});\r\n\r\n                        \/\/ IO microcards\r\n                        const ioCfg = CFG.io[mode] || CFG.io.instrumento;\r\n                        const inBox = addIO(g, ioPad, ioY, ioW, ioH, ioCfg.in[0], ioCfg.in[1]);\r\n                        const outBox = addIO(g, W - ioPad - ioW, ioY, ioW, ioH, ioCfg.out[0], ioCfg.out[1]);\r\n\r\n                        \/\/ Orders\r\n                        const orderInst = parseList(csStr('--cvx-fx-order-inst', 'PRE,COMP,DRIVE,AMP,CAB,SUM,REV'));\r\n                        const orderInstPar = parseList(csStr('--cvx-fx-order-inst-par', 'MOD,DELAY'));\r\n                        const branchAfter = (csStr('--cvx-fx-branch-after', 'COMP') || 'COMP').trim();\r\n\r\n                        const orderVoz = parseList(csStr('--cvx-fx-order-voz', 'PRE,GATE,COMP,DEESS,EQ,REV'));\r\n                        const orderDj = parseList(csStr('--cvx-fx-order-dj', 'PRE,EQ,FILTER,SAT,WIDTH,DELAY'));\r\n\r\n                        const listMain =\r\n                            mode === 'instrumento' ? orderInst :\r\n                            mode === 'voz' ? orderVoz :\r\n                            orderDj;\r\n\r\n                        const hasParallel = (mode === 'instrumento' && orderInstPar.length > 0);\r\n\r\n                        \/\/ x positions for main line pills (centered between IO elbows)\r\n                        const xStart = inBox.cx + 18;\r\n                        const xEnd = outBox.cx - 18;\r\n                        const n = listMain.length;\r\n\r\n                        const totalMain = (n * nodeW) + ((n - 1) * gap);\r\n                        const usable = (xEnd - xStart);\r\n                        const scale = Math.min(1, usable \/ Math.max(1, totalMain));\r\n                        const wScaled = Math.max(54, Math.round(nodeW * scale));\r\n                        const gapScaled = Math.max(4, Math.round(gap * scale));\r\n\r\n                        const xs = [];\r\n                        let x = xStart + (wScaled \/ 2);\r\n                        for (let i = 0; i < n; i++) {\r\n                            xs.push(x);\r\n                            x += wScaled + gapScaled;\r\n                        }\r\n\r\n                        \/\/ Base path (recta + 90\u00b0 hacia IO)\r\n                        const pBase = mkEl('path', {\r\n                            class: 'fxPath fxPath--base',\r\n                            d: `M ${inBox.cx} ${inBox.bottom} L ${inBox.cx} ${yLine} L ${outBox.cx} ${yLine} L ${outBox.cx} ${outBox.bottom}`\r\n                        });\r\n                        const pFlow = mkEl('path', {\r\n                            class: 'fxPath fxPath--flow',\r\n                            d: pBase.getAttribute('d')\r\n                        });\r\n                        g.appendChild(pBase);\r\n                        g.appendChild(pFlow);\r\n\r\n                        \/\/ Parallel branch (solo Instrumento, despu\u00e9s de COMP)\r\n                        let xBranchFrom = null;\r\n                        let xJoinTo = null;\r\n\r\n                        if (hasParallel) {\r\n                            const idx = listMain.findIndex(s => s === branchAfter);\r\n                            const idxAfter = Math.max(0, idx); \/\/ si no encuentra, toma 0\r\n                            xBranchFrom = xs[idxAfter] || xs[1] || xStart + 30;\r\n\r\n                            \/\/ Join = nodo \"SUM\" si existe, sino el \u00faltimo\r\n                            const idxSum = listMain.findIndex(s => s === 'SUM');\r\n                            xJoinTo = xs[idxSum >= 0 ? idxSum : (xs.length - 2)] || (xEnd - 40);\r\n\r\n                            const pBBase = mkEl('path', {\r\n                                class: 'fxPath fxPath--base',\r\n                                d: `M ${xBranchFrom} ${yLine} L ${xBranchFrom} ${yBranch} L ${xJoinTo} ${yBranch} L ${xJoinTo} ${yLine}`\r\n                            });\r\n                            const pBFlow = mkEl('path', {\r\n                                class: 'fxPath fxPath--flow',\r\n                                d: pBBase.getAttribute('d')\r\n                            });\r\n                            g.appendChild(pBBase);\r\n                            g.appendChild(pBFlow);\r\n\r\n                            \/\/ Parallel pills (centrados entre branchFrom y joinTo)\r\n                            const m = orderInstPar.length;\r\n                            const span = Math.max(1, (xJoinTo - xBranchFrom));\r\n                            const step = span \/ (m + 1);\r\n                            for (let i = 0; i < m; i++) {\r\n                                addPill(g, xBranchFrom + step * (i + 1), yBranch, wScaled, nodeH, nodeR, orderInstPar[i]);\r\n                            }\r\n                        }\r\n\r\n                        \/\/ Main pills\r\n                        for (let i = 0; i < listMain.length; i++) {\r\n                            addPill(g, xs[i], yLine, wScaled, nodeH, nodeR, listMain[i]);\r\n                        }\r\n\r\n                        svg.appendChild(g);\r\n                    }\r\n\r\n                    function setMode(next) {\r\n                        mode = next || 'instrumento';\r\n                        if (profileEl) profileEl.textContent = CFG.profiles[mode] || CFG.profiles.instrumento;\r\n                        if (sceneEl) sceneEl.textContent = CFG.scenes[mode] || CFG.scenes.instrumento;\r\n\r\n                        if (modeWrap) {\r\n                            modeWrap.querySelectorAll('button[data-mode]').forEach((b) => {\r\n                                b.classList.toggle('on', b.getAttribute('data-mode') === mode);\r\n                            });\r\n                        }\r\n\r\n                        renderChain();\r\n\r\n                        \/\/ Recalcular m\u00e9tricas con el mismo slider value actual\r\n                        if (range) setLatency(Number(range.value));\r\n                    }\r\n\r\n                    \/\/ UI: switch\r\n                    if (modeWrap) {\r\n                        modeWrap.addEventListener('click', (e) => {\r\n                            const btn = e.target.closest('button[data-mode]');\r\n                            if (!btn) return;\r\n                            setMode(btn.getAttribute('data-mode'));\r\n                        });\r\n                    }\r\n\r\n                    \/\/ UI: slider\r\n                    if (range) {\r\n                        const min = csNum('--cvx-fx-lat-min', 1.5);\r\n                        const max = csNum('--cvx-fx-lat-max', 8.0);\r\n                        const def = csNum('--cvx-fx-lat-default', 6.5);\r\n\r\n                        range.min = String(min);\r\n                        range.max = String(max);\r\n                        range.step = '0.1';\r\n                        range.value = String(def);\r\n\r\n                        const onInput = () => setLatency(Number(range.value));\r\n                        range.addEventListener('input', onInput, {\r\n                            passive: true\r\n                        });\r\n                        range.addEventListener('change', onInput, {\r\n                            passive: true\r\n                        });\r\n\r\n                        setLatency(def);\r\n                    }\r\n\r\n                    \/\/ Oscilaci\u00f3n leve (ms + dsp load) para legibilidad del cambio\r\n                    let t = 0;\r\n                    let frameId = null;\r\n                    let lastTime = 0;\r\n\r\n                    const tick = (timestamp) => {\r\n                        \/* Mantener vivo el loop aunque base todav\u00eda no exista (Elementor\/iOS timing) *\/\r\n                        frameId = requestAnimationFrame(tick);\r\n\r\n                        \/\/ Controlar FPS usando las variables CSS\r\n                        const flowBase = csNum('--cvx-fx-flow-base', 2400);\r\n                        const interval = Math.max(100, flowBase \/ 5); \/\/ ~5 actualizaciones por ciclo base\r\n\r\n                        if (!lastTime || timestamp - lastTime >= interval) {\r\n                            lastTime = timestamp;\r\n                            t += 1;\r\n\r\n                            const base = root.__cvxFxBase;\r\n                            if (!base) return;\r\n\r\n                            \/\/ ms: +\/- 0.15 (no \"salta\" de unidad)\r\n                            const msJit = clamp((Math.sin(t \/ 6) * 0.12) + (Math.sin(t \/ 17) * 0.05), -0.15, 0.15);\r\n                            const msShow = round1(base.ms + msJit);\r\n                            if (msReadEl) msReadEl.textContent = `${msShow.toFixed(1)} ms`;\r\n\r\n                            \/\/ dsp: +\/- 2%\r\n                            const dspJit = clamp((Math.sin(t \/ 7) * 1.2) + (Math.sin(t \/ 19) * 0.8), -2.0, 2.0);\r\n                            const dspShow = Math.round(clamp(base.load + dspJit, 1, 99));\r\n                            if (dspLblEl) dspLblEl.textContent = `${dspShow}%`;\r\n                        }\r\n                    };\r\n                    \/\/ Iniciar animaci\u00f3n\r\n                    frameId = requestAnimationFrame(tick);\r\n\r\n                    \/\/ Cleanup (si el DOM se recicla)\r\n                    root.addEventListener('DOMNodeRemoved', () => {\r\n                        if (frameId) cancelAnimationFrame(frameId);\r\n                    }, {\r\n                        once: true\r\n                    });\r\n\r\n                    \/\/ Init\r\n                    setMode('instrumento');\r\n                });\r\n            })();\r\n        <\/script>\r\n    <\/section>\r\n<\/section>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-b4a819a elementor-section-height-min-height elementor-section-items-stretch fx_section elementor-section-boxed elementor-section-height-default\" data-id=\"b4a819a\" data-element_type=\"section\" data-e-type=\"section\" id=\"amplifier\" data-settings=\"{&quot;background_background&quot;:&quot;gradient&quot;,&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t\t<div class=\"elementor-background-overlay\"><\/div>\n\t\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-0a94570\" data-id=\"0a94570\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<section class=\"elementor-section elementor-inner-section elementor-element elementor-element-f6fb44b elementor-section-full_width elementor-section-height-default elementor-section-height-default\" data-id=\"f6fb44b\" data-element_type=\"section\" data-e-type=\"section\" data-settings=\"{&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-no\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-inner-column elementor-element elementor-element-2d65b17\" data-id=\"2d65b17\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-1acc6bc animated-slow elementor-invisible elementor-widget elementor-widget-heading\" data-id=\"1acc6bc\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;slideInDown&quot;}\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Amplificador<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-89d9a73 elementor-invisible elementor-widget elementor-widget-ha-svg-draw happy-addon ha-svg-draw\" data-id=\"89d9a73\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;slideInLeft&quot;}\" data-widget_type=\"ha-svg-draw.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\n\t\t\t\t<div class=\"ha-svg-draw-container\">\n\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t\n  \n    \n      \n      \n    \n  \n  \n\n\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t<\/div>\n\n\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-inner-section elementor-element elementor-element-014414e elementor-section-full_width elementor-section-height-default elementor-section-height-default\" data-id=\"014414e\" data-element_type=\"section\" data-e-type=\"section\" data-settings=\"{&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-no\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-inner-column elementor-element elementor-element-92d245c\" data-id=\"92d245c\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-b0f6c83 animated-slow elementor-invisible elementor-widget elementor-widget-heading\" data-id=\"b0f6c83\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;fadeIn&quot;,&quot;_animation_delay&quot;:300}\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Suena como profesional<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-cf50716 elementor-invisible elementor-widget elementor-widget-heading\" data-id=\"cf50716\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;fadeInDown&quot;,&quot;_animation_delay&quot;:200}\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">donde quiera que vayas<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-inner-section elementor-element elementor-element-0b93b5a elementor-section-full_width elementor-section-height-default elementor-section-height-default\" data-id=\"0b93b5a\" data-element_type=\"section\" data-e-type=\"section\" data-settings=\"{&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-no\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-inner-column elementor-element elementor-element-ea3e9aa\" data-id=\"ea3e9aa\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-2a7f0b9 elementor-widget elementor-widget-html\" data-id=\"2a7f0b9\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<style>\r\n    \/* =========================================================\r\n   AFE \/ Amplifier section (Front-End Anal\u00f3gico)\r\n   Scope: .cvxScope [data-cvx-root=\"amp-afe\"]\r\n   Dependencias: CubeVox Starter Kit global (Panel\/Card\/Chip\/Stage\/Accordion)\r\n========================================================= *\/\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] {\r\n        \/* =========================\r\n     PARAMETERS\r\n  ========================== *\/\r\n        --cvx-afe-maxw: 1180px;\r\n        --cvx-afe-panel-pad: 18px;\r\n        --cvx-afe-gap: 18px;\r\n        --cvx-afe-gap-sm: 12px;\r\n\r\n        \/* Grid (overflow-safe like FX) *\/\r\n        --cvx-afe-cols: minmax(0, 1.18fr) minmax(0, 0.82fr);\r\n        --cvx-afe-stack-bp: 980px;\r\n\r\n        \/* Card *\/\r\n        --cvx-afe-card-pad: 18px;\r\n        --cvx-afe-card-radius: var(--cvxRadiusLG);\r\n        --cvx-afe-card-gap: 14px;\r\n\r\n        \/* Section header (inputs card) *\/\r\n        --cvx-afe-sec-title-fs: 13.5px;\r\n        --cvx-afe-sec-title-w: 860;\r\n        --cvx-afe-sec-desc-fs: 12.75px;\r\n\r\n        \/* Sub-cards \/ tiles *\/\r\n        --cvx-afe-tile-pad: 14px;\r\n        --cvx-afe-tile-radius: 14px;\r\n        --cvx-afe-tile-minh: 88px;\r\n\r\n        \/* Trim block *\/\r\n        --cvx-afe-trim-pad: 12px;\r\n        --cvx-afe-trim-radius: 14px;\r\n\r\n        \/* Typography (local) *\/\r\n        --cvx-afe-fs-title: 15.0px;\r\n        \/* ligeramente m\u00e1s FX *\/\r\n        --cvx-afe-fs-desc: 13.0px;\r\n        --cvx-afe-fs-label: 12.25px;\r\n        --cvx-afe-fs-value: 15px;\r\n        --cvx-afe-fs-tileK: 11px;\r\n        --cvx-afe-fs-tileV: 16px;\r\n        --cvx-afe-fs-tileS: 12px;\r\n        --cvx-afe-fs-scale: 12.25px;\r\n\r\n        \/* Inputs (chips) *\/\r\n        --cvx-afe-chip-gap: 12px;\r\n        --cvx-afe-chip-minh: 54px;\r\n        --cvx-afe-chip-pad: 12px;\r\n        --cvx-afe-chip-label-w: 44px;\r\n\r\n        \/* Switch buttons *\/\r\n        --cvx-afe-sw-h: 30px;\r\n        --cvx-afe-sw-pad-x: 12px;\r\n        --cvx-afe-sw-radius: 8px;\r\n        \/* FX-ish *\/\r\n        --cvx-afe-sw-gap: 8px;\r\n\r\n        \/* Mini segmented *\/\r\n        --cvx-afe-mini-h: 30px;\r\n        --cvx-afe-mini-pad: 5px;\r\n        --cvx-afe-mini-radius: 999px;\r\n        --cvx-afe-mini-btn-radius: 999px;\r\n        --cvx-afe-mini-fs: 11px;\r\n        --cvx-afe-mini-ls: .10em;\r\n\r\n        \/* Mini note next to mini segments *\/\r\n        --cvx-afe-mini-note-fs: 12px;\r\n\r\n        \/* Range *\/\r\n        --cvx-afe-range-h: 28px;\r\n\r\n        \/* Meter *\/\r\n        --cvx-afe-meter-h: 10px;\r\n        --cvx-afe-meter-radius: 999px;\r\n        --cvx-afe-meter-glow: 0 0 24px color-mix(in srgb, var(--cvxAccent) 45%, transparent);\r\n\r\n        \/* Stage *\/\r\n        --cvx-afe-stage-img-url: url('\/wp-content\/uploads\/cubevox-front-control-panel-closeup.webp');\r\n        --cvx-afe-stage-fit: contain;\r\n        --cvx-afe-stage-ar: 16\/13;\r\n        --cvx-afe-stage-scale: 1.15;\r\n        --cvx-afe-stage-shift-x: 0px;\r\n        --cvx-afe-stage-shift-y: 0px;\r\n        --cvx-afe-stage-inset: 0%;\r\n        --cvx-afe-stage-radius: var(--cvxRadiusLG);\r\n        --cvx-afe-stage-brd: rgba(255, 255, 255, .14);\r\n        --cvx-afe-stage-surface: rgba(255, 255, 255, .035);\r\n\r\n        \/* Info banner under image *\/\r\n        --cvx-afe-info-pad: 14px;\r\n        --cvx-afe-info-title-fs: 14px;\r\n        --cvx-afe-info-desc-fs: 12.75px;\r\n        --cvx-afe-info-chip-gap: 8px;\r\n\r\n        \/* Sim card *\/\r\n        --cvx-afe-sim-pad: 12px;\r\n        --cvx-afe-sim-radius: 14px;\r\n        --cvx-afe-sim-title-fs: 12.5px;\r\n        --cvx-afe-sim-sub-fs: 11px;\r\n        --cvx-afe-sim-val-fs: 12.5px;\r\n        --cvx-afe-sim-range-h: 26px;\r\n\r\n        \/* AGC desc card *\/\r\n        --cvx-afe-agcdesc-pad: 12px;\r\n        --cvx-afe-agcdesc-radius: 14px;\r\n        --cvx-afe-agcdesc-title-fs: 12.5px;\r\n        --cvx-afe-agcdesc-body-fs: 12.5px;\r\n\r\n        \/* FX-like surfaces *\/\r\n        --cvx-afe-surface: rgba(0, 0, 0, .18);\r\n        --cvx-afe-surface2: rgba(0, 0, 0, .22);\r\n        --cvx-afe-brd: rgba(255, 255, 255, .10);\r\n        --cvx-afe-brd-soft: rgba(255, 255, 255, .08);\r\n        --cvx-afe-inset: inset 0 1px 0 rgba(255, 255, 255, .06);\r\n\r\n        \/* Motion *\/\r\n        --cvx-afe-t: 200ms;\r\n        --cvx-afe-ease: cubic-bezier(.2, .8, .2, 1);\r\n\r\n        \/* overflow guard (like FX) *\/\r\n        overflow-x: clip;\r\n    }\r\n\r\n    \/* Peso bold consistente *\/\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] b,\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] strong {\r\n        font-weight: var(--cvxWBold, 850);\r\n    }\r\n\r\n    \/* =========================\r\n   Layout\r\n========================== *\/\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfePanel {\r\n        max-width: var(--cvx-afe-maxw);\r\n        margin-inline: auto;\r\n        padding: var(--cvx-afe-panel-pad);\r\n        min-width: 0;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeGrid {\r\n        display: grid;\r\n        grid-template-columns: var(--cvx-afe-cols);\r\n        gap: var(--cvx-afe-gap);\r\n        align-items: start;\r\n        min-width: 0;\r\n    }\r\n\r\n    @media (max-width: 980px) {\r\n        .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeGrid {\r\n            grid-template-columns: 1fr;\r\n        }\r\n    }\r\n\r\n    \/* Cols anti-overflow *\/\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeCol {\r\n        display: grid;\r\n        gap: var(--cvx-afe-gap);\r\n        min-width: 0;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeCol>* {\r\n        min-width: 0;\r\n        max-width: 100%;\r\n    }\r\n\r\n    \/* Wrap-safety (columna derecha + accordion + descripciones) *\/\r\n    .cvxScope [data-cvx-root=\"amp-afe\"]:where(.cvxAfeCardDesc, .cvxAfeSecDesc, .cvxAfeInfoDesc, .cvxAfeAgcDescBody, .cvxAfeTileS, .cvxAfeScale, .cvxAcc__body, .cvxAcc__title) {\r\n        overflow-wrap: anywhere;\r\n        word-break: break-word;\r\n        hyphens: auto;\r\n        min-width: 0;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] :where(.cvxCard, .cvxAfeCard) {\r\n        min-width: 0;\r\n        max-width: 100%;\r\n    }\r\n\r\n    \/* Pills overflow-safe (por si .cvxPill usa nowrap global) *\/\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeInfoPills {\r\n        min-width: 0;\r\n        max-width: 100%;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeInfoPills .cvxPill {\r\n        max-width: 100%;\r\n        overflow: hidden;\r\n        text-overflow: ellipsis;\r\n    }\r\n\r\n    \/* =========================\r\n   Cards\r\n========================== *\/\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeCard {\r\n        padding: var(--cvx-afe-card-pad);\r\n        border-radius: var(--cvx-afe-card-radius);\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeCardHd {\r\n        display: grid;\r\n        gap: 8px;\r\n        margin-bottom: var(--cvx-afe-card-gap);\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeCardTitle {\r\n        font-size: var(--cvx-afe-fs-title);\r\n        letter-spacing: .02em;\r\n        font-weight: 850;\r\n        \/* FX-ish *\/\r\n        color: rgba(255, 255, 255, .90);\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeCardDesc {\r\n        font-size: var(--cvx-afe-fs-desc);\r\n        color: rgba(255, 255, 255, .72);\r\n        line-height: 1.45;\r\n    }\r\n\r\n    \/* Inputs section header (inside the inputs card) *\/\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeSecHd {\r\n        display: grid;\r\n        gap: 6px;\r\n        margin-bottom: 12px;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeSecTitle {\r\n        font-size: var(--cvx-afe-sec-title-fs);\r\n        font-weight: 850;\r\n        color: rgba(255, 255, 255, .90);\r\n        letter-spacing: .02em;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeSecDesc {\r\n        font-size: var(--cvx-afe-sec-desc-fs);\r\n        color: rgba(255, 255, 255, .70);\r\n        line-height: 1.45;\r\n    }\r\n\r\n    \/* =========================\r\n   Input chips\r\n========================== *\/\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeInputs {\r\n        display: grid;\r\n        grid-template-columns: repeat(3, minmax(0, 1fr));\r\n        gap: var(--cvx-afe-chip-gap);\r\n        min-width: 0;\r\n    }\r\n\r\n    @media (max-width: 700px) {\r\n        .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeInputs {\r\n            grid-template-columns: 1fr;\r\n        }\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeIn {\r\n        cursor: pointer;\r\n        min-height: var(--cvx-afe-chip-minh);\r\n        padding: var(--cvx-afe-chip-pad);\r\n        user-select: none;\r\n        transition: transform var(--cvx-afe-t) var(--cvx-afe-ease), box-shadow var(--cvx-afe-t) var(--cvx-afe-ease);\r\n        outline: none;\r\n        min-width: 0;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeIn:focus-visible {\r\n        box-shadow: 0 0 0 2px color-mix(in srgb, var(--cvxAccent) 55%, transparent), var(--cvxShadowSM);\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeIn.is-active {\r\n        box-shadow: 0 0 0 1px color-mix(in srgb, var(--cvxAccent) 55%, transparent), var(--cvxShadowSM);\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeIn .cvxChip__label {\r\n        width: var(--cvx-afe-chip-label-w);\r\n        font-weight: 900;\r\n        letter-spacing: .08em;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeIn .cvxChip__seg {\r\n        margin-left: auto;\r\n        min-width: 0;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeIn .cvxChip__segBtn {\r\n        min-width: 46px;\r\n        height: 25px;\r\n        line-height: 25px;\r\n        padding: 0 12px;\r\n        border-radius: 0px;\r\n        transition: background var(--cvx-afe-t) var(--cvx-afe-ease), color var(--cvx-afe-t) var(--cvx-afe-ease), opacity var(--cvx-afe-t) var(--cvx-afe-ease);\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeIn .cvxChip__segBtn.is-disabled {\r\n        opacity: .35;\r\n        pointer-events: none;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeIn .cvxChip__segBtn.is-on {\r\n        background: color-mix(in srgb, var(--cvxAccent) 22%, rgba(255, 255, 255, .06));\r\n        color: rgba(255, 255, 255, .92);\r\n    }\r\n\r\n    \/* =========================\r\n   Controls\r\n========================== *\/\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeCtrlGrid {\r\n        display: grid;\r\n        grid-template-columns: 1fr 1fr;\r\n        gap: var(--cvx-afe-gap-sm);\r\n        margin-bottom: var(--cvx-afe-gap-sm);\r\n        min-width: 0;\r\n    }\r\n\r\n    @media (max-width: 620px) {\r\n        .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeCtrlGrid {\r\n            grid-template-columns: 1fr;\r\n        }\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeCtrl {\r\n        display: grid;\r\n        gap: 8px;\r\n        min-width: 0;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeLbl {\r\n        font-size: var(--cvx-afe-fs-label);\r\n        color: rgba(255, 255, 255, .72);\r\n        letter-spacing: .02em;\r\n        font-weight: 750;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeSwitch {\r\n        display: flex;\r\n        flex-wrap: wrap;\r\n        gap: var(--cvx-afe-sw-gap);\r\n        min-width: 0;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeSwBtn {\r\n        height: var(--cvx-afe-sw-h);\r\n        padding: 0 var(--cvx-afe-sw-pad-x);\r\n        border-radius: var(--cvx-afe-sw-radius);\r\n        background: var(--cvx-afe-surface);\r\n        border: 1px solid var(--cvx-afe-brd);\r\n        box-shadow: var(--cvx-afe-inset);\r\n        color: rgba(255, 255, 255, .74);\r\n        font-weight: 850;\r\n        letter-spacing: .02em;\r\n        transition:\r\n            background var(--cvx-afe-t) var(--cvx-afe-ease),\r\n            border-color var(--cvx-afe-t) var(--cvx-afe-ease),\r\n            transform var(--cvx-afe-t) var(--cvx-afe-ease),\r\n            color var(--cvx-afe-t) var(--cvx-afe-ease),\r\n            opacity var(--cvx-afe-t) var(--cvx-afe-ease);\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeSwBtn:hover {\r\n        transform: translateY(-1px);\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeSwBtn.is-on {\r\n        background: color-mix(in srgb, var(--cvxAccent) 22%, rgba(255, 255, 255, .06));\r\n        border-color: color-mix(in srgb, var(--cvxAccent) 22%, rgba(255, 255, 255, .10));\r\n        color: rgba(255, 255, 255, .92);\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeSwBtn.is-disabled {\r\n        opacity: .35;\r\n        pointer-events: none;\r\n    }\r\n\r\n    \/* Select *\/\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeSelectWrap {\r\n        position: relative;\r\n        width: 100%;\r\n        min-width: 0;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeSelect {\r\n        width: 100%;\r\n        height: var(--cvx-afe-sw-h);\r\n        padding: 0 42px 0 12px;\r\n        border-radius: var(--cvx-afe-sw-radius);\r\n        background: var(--cvx-afe-surface);\r\n        border: 1px solid var(--cvx-afe-brd);\r\n        box-shadow: var(--cvx-afe-inset);\r\n        color: rgba(255, 255, 255, .90);\r\n        font: inherit;\r\n        font-weight: 720;\r\n        outline: none;\r\n        appearance: none;\r\n        min-width: 0;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeSelect:focus-visible {\r\n        box-shadow: 0 0 0 2px color-mix(in srgb, var(--cvxAccent) 55%, transparent), var(--cvx-afe-inset);\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeSelectChevron {\r\n        position: absolute;\r\n        right: 12px;\r\n        top: 50%;\r\n        transform: translateY(-50%);\r\n        opacity: .7;\r\n        pointer-events: none;\r\n        font-size: 12px;\r\n    }\r\n\r\n    \/* =========================\r\n   Mini segmented\r\n========================== *\/\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeMiniRow {\r\n        display: grid;\r\n        grid-template-columns: 1fr 1fr;\r\n        gap: var(--cvx-afe-gap-sm);\r\n        align-items: center;\r\n        margin-top: 8px;\r\n        min-width: 0;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeMiniGroup {\r\n        display: inline-flex;\r\n        align-items: center;\r\n        gap: 10px;\r\n        min-width: 0;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeMiniGroup--right {\r\n        justify-self: end;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeMiniGroup--left {\r\n        justify-self: start;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeMiniSeg {\r\n        display: inline-flex;\r\n        align-items: center;\r\n        padding: var(--cvx-afe-mini-pad);\r\n        border-radius: var(--cvx-afe-mini-radius);\r\n        background: var(--cvx-afe-surface);\r\n        border: 1px solid var(--cvx-afe-brd);\r\n        box-shadow: var(--cvx-afe-inset);\r\n        user-select: none;\r\n        min-width: 0;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeMiniSeg.is-disabled {\r\n        opacity: .35;\r\n        pointer-events: none;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeMiniBtn {\r\n        height: var(--cvx-afe-mini-h);\r\n        padding: 0 14px;\r\n        border-radius: var(--cvx-afe-mini-btn-radius);\r\n        border: 0;\r\n        \/* m\u00e1s FX: sin borde interno *\/\r\n        background: transparent;\r\n        color: rgba(255, 255, 255, .74);\r\n        font-weight: 900;\r\n        font-size: var(--cvx-afe-mini-fs);\r\n        letter-spacing: var(--cvx-afe-mini-ls);\r\n        transition: background var(--cvx-afe-t) var(--cvx-afe-ease), color var(--cvx-afe-t) var(--cvx-afe-ease), transform var(--cvx-afe-t) var(--cvx-afe-ease);\r\n        min-width: 0;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeMiniBtn:hover {\r\n        transform: translateY(-1px);\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeMiniBtn.is-on {\r\n        background: color-mix(in srgb, var(--cvxAccent) 22%, rgba(255, 255, 255, .06));\r\n        color: rgba(255, 255, 255, .92);\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeMiniNote {\r\n        font-size: var(--cvx-afe-mini-note-fs);\r\n        color: rgba(255, 255, 255, .70);\r\n        white-space: nowrap;\r\n        overflow: hidden;\r\n        text-overflow: ellipsis;\r\n        max-width: 160px;\r\n        min-width: 0;\r\n    }\r\n\r\n    \/* Subchannel row under signal buttons *\/\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeSubchRow {\r\n        margin-top: 10px;\r\n        display: flex;\r\n        align-items: center;\r\n        gap: 10px;\r\n        min-width: 0;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeSubchLbl {\r\n        font-size: var(--cvx-afe-fs-label);\r\n        color: rgba(255, 255, 255, .72);\r\n        letter-spacing: .02em;\r\n        white-space: nowrap;\r\n    }\r\n\r\n    \/* =========================\r\n   Trim + Meter\r\n========================== *\/\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeTrim {\r\n        display: grid;\r\n        gap: 10px;\r\n        padding: var(--cvx-afe-trim-pad);\r\n        border-radius: var(--cvx-afe-trim-radius);\r\n        border: 1px solid var(--cvx-afe-brd);\r\n        background: var(--cvx-afe-surface);\r\n        box-shadow: var(--cvx-afe-inset);\r\n        margin-bottom: var(--cvx-afe-gap-sm);\r\n        min-width: 0;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeTrimVal {\r\n        font-size: var(--cvx-afe-fs-value);\r\n        font-weight: 880;\r\n        letter-spacing: .02em;\r\n        color: rgba(255, 255, 255, .92);\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeTrimHint {\r\n        font-size: 12px;\r\n        color: rgba(255, 255, 255, .68);\r\n        justify-self: end;\r\n        text-align: right;\r\n        min-width: 0;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeRange {\r\n        width: 100%;\r\n        height: var(--cvx-afe-range-h);\r\n        accent-color: var(--cvxAccent);\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeRange.is-disabled {\r\n        opacity: .55;\r\n        pointer-events: none;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeMeter {\r\n        position: relative;\r\n        height: var(--cvx-afe-meter-h);\r\n        border-radius: var(--cvx-afe-meter-radius);\r\n        overflow: hidden;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeMeterTrack {\r\n        position: absolute;\r\n        inset: 0;\r\n        background:\r\n            linear-gradient(90deg,\r\n                rgba(90, 170, 255, .55) 0%,\r\n                rgba(90, 255, 214, .45) 35%,\r\n                rgba(255, 210, 90, .42) 70%,\r\n                rgba(255, 90, 126, .48) 100%);\r\n        opacity: .35;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeMeterFill {\r\n        position: absolute;\r\n        inset: 0;\r\n        width: 0%;\r\n        background:\r\n            linear-gradient(90deg,\r\n                rgba(90, 170, 255, .85) 0%,\r\n                rgba(90, 255, 214, .70) 40%,\r\n                rgba(255, 210, 90, .62) 75%,\r\n                rgba(255, 90, 126, .76) 100%);\r\n        filter: drop-shadow(var(--cvx-afe-meter-glow));\r\n        transform-origin: left center;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeMeterPeak {\r\n        position: absolute;\r\n        top: -3px;\r\n        width: 2px;\r\n        height: calc(var(--cvx-afe-meter-h) + 6px);\r\n        left: 0%;\r\n        background: rgba(255, 255, 255, .75);\r\n        box-shadow: 0 0 10px rgba(255, 255, 255, .55);\r\n        opacity: .9;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeTrimTop {\r\n        display: grid;\r\n        grid-template-columns: auto max-content minmax(0, 1fr);\r\n        gap: 10px;\r\n        align-items: center;\r\n        min-width: 0;\r\n        min-height: 24px;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeHeadroomLine {\r\n        display: grid;\r\n        grid-template-columns: auto max-content minmax(0, 1fr);\r\n        gap: 10px;\r\n        align-items: center;\r\n        min-width: 0;\r\n        min-height: 20px;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeTrimVal,\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeHeadroomVal {\r\n        white-space: nowrap;\r\n        line-height: 1;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeTrimHint,\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeHeadroomHint {\r\n        white-space: nowrap;\r\n        overflow: hidden;\r\n        text-overflow: ellipsis;\r\n        line-height: 1.2;\r\n    }\r\n\r\n    @media (max-width: 560px) {\r\n\r\n        .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeTrimTop,\r\n        .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeHeadroomLine {\r\n            grid-template-columns: auto max-content;\r\n            row-gap: 6px;\r\n        }\r\n\r\n        .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeTrimHint,\r\n        .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeHeadroomHint {\r\n            grid-column: 1 \/ -1;\r\n            justify-self: start;\r\n            text-align: left;\r\n            white-space: normal;\r\n            overflow: visible;\r\n            text-overflow: clip;\r\n        }\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeHeadroomLbl {\r\n        font-size: 12px;\r\n        letter-spacing: .04em;\r\n        color: rgba(255, 255, 255, .62);\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeHeadroomVal {\r\n        font-size: 12.5px;\r\n        font-weight: 860;\r\n        color: rgba(255, 255, 255, .90);\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeHeadroomHint {\r\n        font-size: 12px;\r\n        color: rgba(255, 255, 255, .62);\r\n        justify-self: end;\r\n        text-align: right;\r\n        min-width: 0;\r\n    }\r\n\r\n    \/* =========================\r\n   AGC\r\n========================== *\/\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeAgc {\r\n        display: grid;\r\n        gap: 10px;\r\n        min-width: 0;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeAgcTop {\r\n        display: grid;\r\n        grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);\r\n        gap: 12px;\r\n        align-items: stretch;\r\n        min-width: 0;\r\n    }\r\n\r\n    @media (max-width: 520px) {\r\n        .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeAgcTop {\r\n            grid-template-columns: 1fr;\r\n        }\r\n    }\r\n\r\n    \/* Sim card *\/\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeSimCard {\r\n        padding: var(--cvx-afe-sim-pad);\r\n        border-radius: var(--cvx-afe-sim-radius);\r\n        border: 1px solid var(--cvx-afe-brd);\r\n        background: var(--cvx-afe-surface);\r\n        box-shadow: var(--cvx-afe-inset);\r\n        display: grid;\r\n        gap: 8px;\r\n        min-width: 0;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeSimTop {\r\n        display: grid;\r\n        grid-template-columns: 1fr auto;\r\n        gap: 10px;\r\n        align-items: baseline;\r\n        min-width: 0;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeSimTitle {\r\n        font-size: var(--cvx-afe-sim-title-fs);\r\n        color: rgba(255, 255, 255, .86);\r\n        font-weight: 850;\r\n        letter-spacing: .02em;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeSimVal {\r\n        font-size: var(--cvx-afe-sim-val-fs);\r\n        color: rgba(255, 255, 255, .90);\r\n        font-weight: 880;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeSimSub {\r\n        font-size: var(--cvx-afe-sim-sub-fs);\r\n        color: rgba(255, 255, 255, .60);\r\n        font-weight: 800;\r\n        letter-spacing: .12em;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeSimRange {\r\n        width: 100%;\r\n        height: var(--cvx-afe-sim-range-h);\r\n        accent-color: var(--cvxAccent);\r\n    }\r\n\r\n    \/* AGC description card *\/\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeAgcDescCard {\r\n        padding: var(--cvx-afe-agcdesc-pad);\r\n        border-radius: var(--cvx-afe-agcdesc-radius);\r\n        border: 1px solid var(--cvx-afe-brd);\r\n        background: var(--cvx-afe-surface);\r\n        box-shadow: var(--cvx-afe-inset);\r\n        display: grid;\r\n        gap: 6px;\r\n        min-width: 0;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeAgcDescTitle {\r\n        font-size: var(--cvx-afe-agcdesc-title-fs);\r\n        color: rgba(255, 255, 255, .86);\r\n        font-weight: 850;\r\n        letter-spacing: .02em;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeAgcDescBody {\r\n        font-size: var(--cvx-afe-agcdesc-body-fs);\r\n        color: rgba(255, 255, 255, .70);\r\n        line-height: 1.45;\r\n        min-width: 0;\r\n    }\r\n\r\n    \/* =========================\r\n   Results tiles\r\n========================== *\/\r\n    \/* =========================\r\n   Results tiles: 4x1 \u2192 2x2 \u2192 1x4 (sin scroll horizontal)\r\n========================== *\/\r\n\r\n    \/* Importante: permitir que el card se achique dentro del layout (grid\/flex padre) *\/\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeCard--results {\r\n        min-width: 0;\r\n        \/* clave anti-overflow en grid\/flex *\/\r\n        max-width: 100%;\r\n        overflow-x: clip;\r\n        \/* fallback: evita barra por 1\u20132px de desborde *\/\r\n    }\r\n\r\n    \/* Grid de tiles *\/\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeTiles {\r\n        display: grid;\r\n        grid-template-columns: repeat(4, minmax(0, 1fr));\r\n        \/* clave: 0 permite shrink real *\/\r\n        gap: 12px;\r\n        \/* ajust\u00e1 si quer\u00e9s *\/\r\n        width: 100%;\r\n    }\r\n\r\n    \/* Cada tile tambi\u00e9n debe poder encogerse *\/\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeTile {\r\n        min-width: 0;\r\n        \/* clave: evita que contenido fuerce overflow *\/\r\n    }\r\n\r\n    \/* Evitar que valores largos \u201cempujen\u201d el grid *\/\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeTileV,\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeTileS {\r\n        min-width: 0;\r\n        max-width: 100%;\r\n        white-space: normal;\r\n        \/* NO nowrap *\/\r\n        overflow-wrap: anywhere;\r\n        \/* corta strings raros *\/\r\n        word-break: break-word;\r\n    }\r\n\r\n    \/* Breakpoints: 2x2 y luego 1x4 *\/\r\n    @media (max-width: 860px) {\r\n        .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeTiles {\r\n            grid-template-columns: repeat(2, minmax(0, 1fr));\r\n        }\r\n    }\r\n\r\n    @media (max-width: 520px) {\r\n        .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeTiles {\r\n            grid-template-columns: 1fr;\r\n        }\r\n    }\r\n\r\n\r\n    @media (max-width: 620px) {\r\n        .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeTiles {\r\n            grid-template-columns: 1fr;\r\n        }\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeTile {\r\n        padding: var(--cvx-afe-tile-pad);\r\n        border-radius: var(--cvx-afe-tile-radius);\r\n        border: 1px solid var(--cvx-afe-brd);\r\n        background: var(--cvx-afe-surface);\r\n        box-shadow: var(--cvx-afe-inset);\r\n        display: grid;\r\n        gap: 6px;\r\n        min-height: var(--cvx-afe-tile-minh);\r\n        min-width: 0;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeTileK {\r\n        font-size: var(--cvx-afe-fs-tileK);\r\n        letter-spacing: .18em;\r\n        color: rgba(255, 255, 255, .55);\r\n        font-weight: 820;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeTileV {\r\n        font-size: var(--cvx-afe-fs-tileV);\r\n        font-weight: 900;\r\n        letter-spacing: .02em;\r\n        color: rgba(255, 255, 255, .92);\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeTileS {\r\n        font-size: var(--cvx-afe-fs-tileS);\r\n        color: rgba(255, 255, 255, .68);\r\n        line-height: 1.25;\r\n    }\r\n\r\n    \/* Scale text *\/\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeScale {\r\n        margin-top: 12px;\r\n        padding-top: 12px;\r\n        border-top: 1px solid rgba(255, 255, 255, .07);\r\n        font-size: var(--cvx-afe-fs-scale);\r\n        color: rgba(255, 255, 255, .68);\r\n        line-height: 1.45;\r\n        min-width: 0;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeScale b {\r\n        color: rgba(255, 255, 255, .92);\r\n        font-weight: 880;\r\n    }\r\n\r\n    \/* =========================\r\n   Stage (image)\r\n========================== *\/\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeStage {\r\n        border-radius: var(--cvx-afe-stage-radius);\r\n        overflow: hidden;\r\n        position: relative;\r\n\r\n        min-height: var(--cvx-afe-stage-minh);\r\n        aspect-ratio: var(--cvx-afe-stage-ar);\r\n        max-width: 100%;\r\n\r\n        \/* \u2705 borde + frame visibles (parametrizables) *\/\r\n        border: 1px solid var(--cvx-afe-stage-brd, rgba(255, 255, 255, .10));\r\n        background: var(--cvx-afe-stage-surface, rgba(255, 255, 255, .03));\r\n        box-shadow: var(--cvx-afe-stage-shadow, inset 0 1px 0 rgba(255, 255, 255, .06), 0 18px 40px rgba(0, 0, 0, .35));\r\n    }\r\n\r\n    \/* \u2705 imagen + FX dentro del clip del radio *\/\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeStage::before {\r\n        content: \"\";\r\n        position: absolute;\r\n        inset: var(--cvx-afe-stage-inset, 0%);\r\n        z-index: 0;\r\n\r\n        transform:\r\n            translate3d(var(--cvx-afe-stage-shift-x, 0px), var(--cvx-afe-stage-shift-y, 0px), 0) scale(var(--cvx-afe-stage-scale, 1));\r\n\r\n        background-image:\r\n            var(--cvx-afe-stage-img-url, none),\r\n            var(--cvx-afe-stage-fx, radial-gradient(140% 90% at 20% 20%, rgba(90, 170, 255, .22), transparent 55%),\r\n                radial-gradient(120% 80% at 80% 30%, rgba(159, 90, 255, .20), transparent 60%),\r\n                linear-gradient(180deg, rgba(255, 255, 255, .06), rgba(255, 255, 255, .00)));\r\n        background-repeat: no-repeat, no-repeat;\r\n        background-position: center, center;\r\n        background-size: var(--cvx-afe-stage-fit, contain), cover;\r\n\r\n        filter: saturate(1.03) contrast(1.03);\r\n    }\r\n\r\n    \/* \u2705 overlay arriba, pero sin tapar el borde *\/\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeStage::after {\r\n        content: \"\";\r\n        position: absolute;\r\n        inset: 0;\r\n        z-index: 1;\r\n\r\n        background:\r\n            radial-gradient(120% 80% at 50% 0%, rgba(0, 0, 0, .15), transparent 60%),\r\n            radial-gradient(120% 80% at 50% 100%, rgba(0, 0, 0, .30), transparent 60%),\r\n            linear-gradient(180deg, rgba(0, 0, 0, .10), rgba(0, 0, 0, .16));\r\n        pointer-events: none;\r\n    }\r\n\r\n    \/* Info banner under the image stage *\/\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeInfoBanner {\r\n        margin-top: var(--cvx-afe-gap-sm);\r\n        padding: var(--cvx-afe-info-pad);\r\n        border-radius: var(--cvxRadiusMD);\r\n\r\n        border: 1px solid var(--cvx-afe-brd);\r\n        background: var(--cvx-afe-surface);\r\n        box-shadow: var(--cvx-afe-inset);\r\n\r\n        min-width: 0;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeInfoTitle {\r\n        font-size: var(--cvx-afe-info-title-fs);\r\n        font-weight: 850;\r\n        color: rgba(255, 255, 255, .90);\r\n        letter-spacing: .02em;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeInfoDesc {\r\n        margin-top: 6px;\r\n        font-size: var(--cvx-afe-info-desc-fs);\r\n        color: rgba(255, 255, 255, .72);\r\n        line-height: 1.45;\r\n        min-width: 0;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeInfoPills {\r\n        margin-top: 10px;\r\n        display: flex;\r\n        flex-wrap: wrap;\r\n        gap: var(--cvx-afe-info-chip-gap);\r\n        min-width: 0;\r\n        max-width: 100%;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeMiniNote:empty {\r\n        display: none;\r\n    }\r\n\r\n    \/* ===== AGC: segmented group (dentro de mini-card) ===== *\/\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeMiniSeg--agc {\r\n        width: 100%;\r\n        display: flex;\r\n        flex-wrap: nowrap;\r\n        \/* 1 sola fila *\/\r\n        align-items: center;\r\n\r\n        \/* FX switch look *\/\r\n        gap: 0;\r\n        \/* segmentado real *\/\r\n        padding: 4px;\r\n        border-radius: 14px;\r\n        background: var(--cvx-afe-surface);\r\n        border: 1px solid var(--cvx-afe-brd);\r\n        box-shadow: var(--cvx-afe-inset);\r\n        overflow: hidden;\r\n\r\n        min-width: 0;\r\n    }\r\n\r\n    \/* 3 botones iguales ocupando el ancho del grupo *\/\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeMiniSeg--agc .cvxAfeSwBtn {\r\n        flex: 1 1 0;\r\n        \/* 33\/33\/33 *\/\r\n        min-width: 0;\r\n\r\n        \/* neutralizar \u201cbot\u00f3n suelto\u201d y hacerlo \u201csegment\u201d *\/\r\n        height: var(--cvx-afe-mini-h);\r\n        padding: 0 10px;\r\n\r\n        border: 0;\r\n        box-shadow: none;\r\n        background: transparent;\r\n        border-radius: 10px;\r\n\r\n        font-weight: 850;\r\n        font-size: 12px;\r\n        letter-spacing: .02em;\r\n        color: rgba(255, 255, 255, .74);\r\n\r\n        text-align: center;\r\n        white-space: nowrap;\r\n        overflow: hidden;\r\n        text-overflow: ellipsis;\r\n    }\r\n\r\n    \/* =========================================================\r\n   HEADER: kicker\/t\u00edtulo\/desc\/tags\r\n========================================================= *\/\r\n    .cvxKicker {\r\n        display: inline-block;\r\n        font-size: var(--cvx-fs-kicker);\r\n        letter-spacing: .16em;\r\n        text-transform: uppercase;\r\n        color: var(--cvx-muted);\r\n        margin-bottom: 8px;\r\n    }\r\n\r\n    .cvxTitle {\r\n        margin: 0 0 1px;\r\n        font-size: var(--cvx-fs-title);\r\n        line-height: var(--cvx-lh-title);\r\n        color: var(--cvx-text);\r\n    }\r\n\r\n    .cvxDesc {\r\n        margin: 0;\r\n        font-size: var(--cvx-fs-body);\r\n        line-height: var(--cvx-lh-body);\r\n        color: var(--cvx-muted);\r\n    }\r\n\r\n    .cvxDesc b {\r\n        color: var(--cvx-text);\r\n        font-weight: 650;\r\n    }\r\n\r\n    .cvxTags {\r\n        display: flex;\r\n        flex-wrap: wrap;\r\n        gap: var(--cvx-gap-8);\r\n        margin-top: 12px;\r\n    }\r\n\r\n    .cvxTag {\r\n        font-size: var(--cvx-fs-tag);\r\n        color: rgba(255, 255, 255, .78);\r\n        border: 1px solid var(--cvx-stroke);\r\n        background: rgba(0, 0, 0, .22);\r\n        padding: 7px 10px;\r\n        border-radius: var(--cvx-r-round);\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeMiniSeg--agc .cvxAfeSwBtn.is-on {\r\n        background: color-mix(in srgb, var(--cvxAccent) 22%, rgba(255, 255, 255, .06));\r\n        color: rgba(255, 255, 255, .92);\r\n    }\r\n\r\n    \/* sin \u201csalto\u201d hover dentro del segmented *\/\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeMiniSeg--agc .cvxAfeSwBtn:hover {\r\n        transform: none;\r\n    }\r\n\r\n\r\n\r\n    \/* Reduced motion *\/\r\n    @media (prefers-reduced-motion: reduce) {\r\n\r\n        .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeIn,\r\n        .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeSwBtn,\r\n        .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeMiniBtn {\r\n            transition: none !important;\r\n        }\r\n    }\r\n\r\n    \/* =========================================================\r\n   AFE \u2014 estabilidad de altura en bloques din\u00e1micos\r\n========================================================= *\/\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeSimCard,\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeAgcDescCard {\r\n        align-content: start;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeSimTop {\r\n        display: grid;\r\n        grid-template-columns: minmax(0, 1fr) max-content;\r\n        gap: 10px;\r\n        align-items: center;\r\n        min-height: 24px;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeSimTitle,\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeSimVal {\r\n        line-height: 1.1;\r\n        white-space: nowrap;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeSimSub {\r\n        display: block;\r\n        min-height: 1.3em;\r\n        line-height: 1.3;\r\n        white-space: nowrap;\r\n        overflow: hidden;\r\n        text-overflow: ellipsis;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeAgcDescTitle {\r\n        min-height: 1.3em;\r\n        line-height: 1.3;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeAgcDescBody {\r\n        min-height: 2.9em;\r\n        \/* reserva aprox. 2 l\u00edneas *\/\r\n        line-height: 1.45;\r\n    }\r\n\r\n    \/* =========================================================\r\n   AFE \u2014 select styling\r\n========================================================= *\/\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeSelectWrap {\r\n        position: relative;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeSelect {\r\n        width: 100%;\r\n        height: 42px;\r\n        padding: 0 40px 0 14px;\r\n        border-radius: 14px;\r\n        border: 1px solid color-mix(in srgb, var(--cvxAccent) 35%, rgba(255, 255, 255, .10));\r\n        background:\r\n            linear-gradient(180deg, rgba(255, 255, 255, .05), rgba(255, 255, 255, .015)),\r\n            rgba(0, 0, 0, .22);\r\n        box-shadow:\r\n            inset 0 1px 0 rgba(255, 255, 255, .06),\r\n            0 0 0 1px rgba(56, 189, 248, .18);\r\n        color: rgba(255, 255, 255, .92);\r\n        font-weight: 800;\r\n        font-size: 13px;\r\n        line-height: 42px;\r\n        appearance: none;\r\n        -webkit-appearance: none;\r\n        -moz-appearance: none;\r\n        outline: none;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeSelect:hover {\r\n        border-color: color-mix(in srgb, var(--cvxAccent) 55%, rgba(255, 255, 255, .10));\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeSelect:focus,\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeSelect:focus-visible {\r\n        border-color: color-mix(in srgb, var(--cvxAccent) 70%, rgba(255, 255, 255, .10));\r\n        box-shadow:\r\n            inset 0 1px 0 rgba(255, 255, 255, .06),\r\n            0 0 0 1px rgba(56, 189, 248, .28),\r\n            0 0 0 3px rgba(56, 189, 248, .14);\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeSelectChevron {\r\n        right: 14px;\r\n        font-size: 11px;\r\n        color: rgba(255, 255, 255, .72);\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeSelect option {\r\n        background: #071627;\r\n        color: rgba(255, 255, 255, .94);\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"amp-afe\"] .cvxAfeSelect option:checked {\r\n        background: #355a86;\r\n        color: #fff;\r\n    }\r\n<\/style>\r\n\r\n\r\n<section class=\"cvxScope\">\r\n    <section data-cvx-root=\"amp-afe\" class=\"cvxAfeRoot\" data-phantom-policy=\"cond_only\" style=\"\r\n      \/* ============================================\r\n         INSTANCE PARAMETERS (Elementor: Advanced > Custom CSS)\r\n         --------------------------------------------\r\n         Image:\r\n         --cvx-afe-stage-img: url('http:\/\/cube-vox.com\/wp-content\/uploads\/2026\/02\/IMG_5496.jpeg');  (optional)\r\n         --cvx-afe-stage-scale \/ shift-x \/ shift-y\r\n      ============================================ *\/\r\n         --cvx-afe-stage-img: url('http:\/\/cube-vox.com\/wp-content\/uploads\/2026\/02\/IMG_5496.jpeg');\r\n    \">\r\n        <div class=\"cvxPanel cvxAfePanel\">\r\n\r\n            <!-- Parent shell wrapping ALL big cards (both columns) -->\r\n            <!--<div class=\"cvxCard cvxAfeShell\"> -->\r\n            <div class=\"cvxAfeGrid\">\r\n\r\n                <!-- LEFT: Controls + Results -->\r\n\r\n\r\n\r\n\r\n\r\n                <div class=\"cvxAfeCol cvxAfeCol--left\">\r\n\r\n\r\n                    <div class=\"cvxKicker\">Amp + Cab + FX<\/div>\r\n                    <h3 class=\"cvxTitle\">Preserv\u00e1 la se\u00f1al, dise\u00f1\u00e1 el ampli<\/h3>\r\n                    <p class=\"cvxDesc\">\r\n                        Optimizaci\u00f3n de <b>impedancia<\/b> y <b>din\u00e1mica<\/b>; luego <b>amplis<\/b> y <b>cabinas (IR)<\/b> para definir el <b>tono final<\/b> <\/p>\r\n\r\n\r\n\r\n\r\n                    <!-- Inputs card (wrap the input chips + heading like image 7) -->\r\n                    <div class=\"cvxCard cvxAfeCard cvxAfeCard--inputs\">\r\n                        <div class=\"cvxAfeSecHd\">\r\n                            <div class=\"cvxAfeCardTitle\">Selecci\u00f3n de entrada<\/div>\r\n                            <div class=\"cvxAfeSecDesc\">IN1\/IN2 alternan <b>XLR<\/b> o <b>TRS<\/b>. IN3 habilita <b>AUX 3.5<\/b> (DIG deshabilitado).<\/div>\r\n                        <\/div>\r\n\r\n                        <div class=\"cvxAfeInputs\" role=\"tablist\" aria-label=\"Entradas f\u00edsicas\">\r\n                            <div class=\"cvxChip cvxAfeIn is-active\" role=\"tab\" tabindex=\"0\" aria-selected=\"true\" data-in=\"in1\">\r\n                                <span class=\"cvxChip__label\">IN1<\/span>\r\n                                <span class=\"cvxChip__seg\" role=\"group\" aria-label=\"Conector IN1\">\r\n                                    <button class=\"cvxChip__segBtn is-on\" type=\"button\" data-port=\"xlr\">XLR<\/button>\r\n                                    <button class=\"cvxChip__segBtn\" type=\"button\" data-port=\"trs\">TRS<\/button>\r\n                                <\/span>\r\n                            <\/div>\r\n\r\n                            <div class=\"cvxChip cvxAfeIn\" role=\"tab\" tabindex=\"0\" aria-selected=\"false\" data-in=\"in2\">\r\n                                <span class=\"cvxChip__label\">IN2<\/span>\r\n                                <span class=\"cvxChip__seg\" role=\"group\" aria-label=\"Conector IN2\">\r\n                                    <button class=\"cvxChip__segBtn is-on\" type=\"button\" data-port=\"xlr\">XLR<\/button>\r\n                                    <button class=\"cvxChip__segBtn\" type=\"button\" data-port=\"trs\">TRS<\/button>\r\n                                <\/span>\r\n                            <\/div>\r\n\r\n                            <div class=\"cvxChip cvxAfeIn\" role=\"tab\" tabindex=\"0\" aria-selected=\"false\" data-in=\"in3\">\r\n                                <span class=\"cvxChip__label\">IN3<\/span>\r\n                                <span class=\"cvxChip__seg\" role=\"group\" aria-label=\"Conector IN3\">\r\n                                    <button class=\"cvxChip__segBtn is-disabled\" type=\"button\" data-port=\"dig\" aria-disabled=\"true\">DIG<\/button>\r\n                                    <button class=\"cvxChip__segBtn is-on\" type=\"button\" data-port=\"aux\">AUX<\/button>\r\n                                <\/span>\r\n                            <\/div>\r\n                        <\/div>\r\n                    <\/div>\r\n\r\n                    <!-- Main control card -->\r\n                    <div class=\"cvxCard cvxAfeCard\">\r\n                        <div class=\"cvxAfeCardHd\">\r\n                            <div class=\"cvxAfeCardTitle\">Front-End Anal\u00f3gico<\/div>\r\n                            <div class=\"cvxAfeCardDesc\">\r\n                                Ajuste por canal: acople de impedancia, trim fino y AGC anti-clipping. Perfiles por se\u00f1al + modo manual.\r\n                            <\/div>\r\n                        <\/div>\r\n\r\n                        <div class=\"cvxAfeCtrlGrid\">\r\n                            <div class=\"cvxAfeCtrl\">\r\n                                <div class=\"cvxAfeLbl\">Tipo de se\u00f1al<\/div>\r\n                                <div class=\"cvxAfeSwitch\" role=\"group\" aria-label=\"Tipo de se\u00f1al\">\r\n                                    <button type=\"button\" class=\"cvxAfeSwBtn is-on\" data-role=\"sig\" data-sig=\"mic\">Mic<\/button>\r\n                                    <button type=\"button\" class=\"cvxAfeSwBtn\" data-role=\"sig\" data-sig=\"inst\">Inst<\/button>\r\n                                    <button type=\"button\" class=\"cvxAfeSwBtn\" data-role=\"sig\" data-sig=\"line\">Line<\/button>\r\n                                <\/div>\r\n\r\n                                <!-- Subchannel selector (A \/ B \/ ST) -->\r\n                                <div class=\"cvxAfeSubchRow\" aria-label=\"Subcanal\">\r\n                                    <div class=\"cvxAfeSubchLbl\">Subcanal<\/div>\r\n                                    <div class=\"cvxAfeMiniSeg\" role=\"group\" aria-label=\"Selector de subcanal\">\r\n                                        <button type=\"button\" class=\"cvxAfeMiniBtn is-on\" data-role=\"subch\" data-subch=\"a\">A<\/button>\r\n                                        <button type=\"button\" class=\"cvxAfeMiniBtn\" data-role=\"subch\" data-subch=\"b\">B<\/button>\r\n                                        <button type=\"button\" class=\"cvxAfeMiniBtn\" data-role=\"subch\" data-subch=\"st\">ST<\/button>\r\n                                    <\/div>\r\n                                <\/div>\r\n                            <\/div>\r\n\r\n                            <div class=\"cvxAfeCtrl\">\r\n                                <div class=\"cvxAfeLbl\">Perfil<\/div>\r\n                                <div class=\"cvxAfeSelectWrap\">\r\n                                    <select class=\"cvxAfeSelect\" data-role=\"profile\" aria-label=\"Perfil\"><\/select>\r\n                                    <span class=\"cvxAfeSelectChevron\" aria-hidden=\"true\">\u25be<\/span>\r\n                                <\/div>\r\n\r\n                                <!-- PHNT bottom-left \/ ST-MONO bottom-right (no external labels) -->\r\n                                <div class=\"cvxAfeMiniRow\" aria-label=\"Controles r\u00e1pidos\">\r\n                                    <div class=\"cvxAfeMiniGroup cvxAfeMiniGroup--left\">\r\n                                        <div class=\"cvxAfeMiniSeg\" data-role=\"phantomSeg\" aria-label=\"Phantom\">\r\n                                            <button type=\"button\" class=\"cvxAfeMiniBtn\" data-role=\"phantomBtn\" aria-pressed=\"false\">PHNT<\/button>\r\n                                        <\/div>\r\n                                        <div class=\"cvxAfeMiniNote\" data-role=\"phantomNote\">48V<\/div>\r\n                                    <\/div>\r\n\r\n                                    <div class=\"cvxAfeMiniGroup cvxAfeMiniGroup--right\">\r\n                                        <div class=\"cvxAfeMiniSeg\" data-role=\"stSeg\" role=\"group\" aria-label=\"ST \/ MONO\">\r\n                                            <button type=\"button\" class=\"cvxAfeMiniBtn is-on\" data-role=\"stBtn\" data-stm=\"st\">ST<\/button>\r\n                                            <button type=\"button\" class=\"cvxAfeMiniBtn\" data-role=\"stBtn\" data-stm=\"mono\">MONO<\/button>\r\n                                        <\/div>\r\n                                        <div class=\"cvxAfeMiniNote\" data-role=\"stereoNote\">Stereo<\/div>\r\n                                    <\/div>\r\n                                <\/div>\r\n                            <\/div>\r\n                        <\/div>\r\n\r\n                        <!-- Trim + headroom meter -->\r\n                        <div class=\"cvxAfeTrim\">\r\n                            <div class=\"cvxAfeTrimTop\">\r\n                                <div class=\"cvxAfeLbl\">Trim<\/div>\r\n                                <div class=\"cvxAfeTrimVal notranslate\" data-role=\"trimVal\">0.0 dB<\/div>\r\n                                <div class=\"cvxAfeTrimHint\" data-role=\"trimHint\">Perfil: \u2014<\/div>\r\n                            <\/div>\r\n\r\n                            <input class=\"cvxAfeRange\" data-role=\"trim\" type=\"range\" min=\"-12\" max=\"24\" step=\"0.5\" value=\"0\" aria-label=\"Trim\" \/>\r\n\r\n                            <div class=\"cvxAfeMeter\" aria-label=\"Headroom\">\r\n                                <div class=\"cvxAfeMeterTrack\"><\/div>\r\n                                <div class=\"cvxAfeMeterFill\" data-role=\"meterFill\"><\/div>\r\n                                <div class=\"cvxAfeMeterPeak\" data-role=\"meterPeak\"><\/div>\r\n                            <\/div>\r\n\r\n                            <div class=\"cvxAfeHeadroomLine\">\r\n                                <div class=\"cvxAfeHeadroomLbl\">Headroom<\/div>\r\n                                <div class=\"cvxAfeHeadroomVal notranslate\" data-role=\"headroomVal\">\u2014 dB<\/div>\r\n                                <div class=\"cvxAfeHeadroomHint\" data-role=\"clipHint\">No Clipping<\/div>\r\n                            <\/div>\r\n                        <\/div>\r\n\r\n                        <!-- AGC -->\r\n                        <div class=\"cvxAfeAgc\">\r\n                            <div class=\"cvxAfeAgcTop\">\r\n\r\n                                <!-- Sim card (left of AGC buttons) -->\r\n                                <div class=\"cvxAfeSimCard\" aria-label=\"Simulaci\u00f3n de intensidad\">\r\n                                    <div class=\"cvxAfeSimTop\">\r\n                                        <div class=\"cvxAfeSimTitle\">Simulaci\u00f3n de intensidad<\/div>\r\n                                        <div class=\"cvxAfeSimVal\" data-role=\"simPct\">55%<\/div>\r\n                                    <\/div>\r\n                                    <div class=\"cvxAfeSimSub\" data-role=\"simKey\">\u2014<\/div>\r\n                                    <input class=\"cvxAfeSimRange\" data-role=\"sim\" type=\"range\" min=\"0\" max=\"100\" step=\"1\" value=\"55\" aria-label=\"Nivel de se\u00f1al simulada\" \/>\r\n                                <\/div>\r\n\r\n                                <!-- AGC description card (like image 5) -->\r\n                                <div class=\"cvxAfeAgcDescCard\" aria-label=\"Descripci\u00f3n AGC\">\r\n                                    <div class=\"cvxAfeAgcDescTitle\">AGC \/ Clip Guard<\/div>\r\n                                    <div class=\"cvxAfeMiniSeg cvxAfeMiniSeg--agc\" role=\"group\" aria-label=\"AGC\">\r\n                                        <button type=\"button\" class=\"cvxAfeSwBtn is-on\" data-role=\"agc\" data-agc=\"off\">OFF<\/button>\r\n                                        <button type=\"button\" class=\"cvxAfeSwBtn\" data-role=\"agc\" data-agc=\"soft\">Soft<\/button>\r\n                                        <button type=\"button\" class=\"cvxAfeSwBtn\" data-role=\"agc\" data-agc=\"safe\">Safe<\/button>\r\n                                    <\/div>\r\n                                    <div class=\"cvxAfeAgcDescBody\" data-role=\"agcNote\"><\/div>\r\n                                <\/div>\r\n                            <\/div>\r\n\r\n\r\n                        <\/div>\r\n\r\n                    <\/div>\r\n\r\n\r\n\r\n                <\/div>\r\n\r\n                <!-- RIGHT: Image + info banner + accordion cards -->\r\n                <div class=\"cvxAfeCol cvxAfeCol--right\">\r\n\r\n                    <!-- Image stage card -->\r\n                    <div class=\"cvxCard cvxAfeCard\" style=\"margin-top:0px;\">\r\n                        <div class=\"cvxStage cvxAfeStage\" aria-label=\"Imagen de referencia\"><\/div>\r\n\r\n                        <!-- Info banner outside the image (like image 9 distribution) -->\r\n                        <div class=\"cvxCard cvxAfeInfoBanner\" aria-label=\"Bloque informativo\">\r\n                            <div class=\"cvxAfeInfoTitle\">El \u201cfeel\u201d arranca en la entrada<\/div>\r\n                            <div class=\"cvxAfeInfoDesc\">\r\n                                La captura correcta define din\u00e1mica, ataque y headroom. Perfiles por conector y un AGC anti-clip configurable.\r\n                            <\/div>\r\n                            <div class=\"cvxAfeInfoPills\" aria-label=\"Etiquetas\">\r\n                                <span class=\"cvxPill\">Hi-Z \/ Line \/ Mic<\/span>\r\n                                <span class=\"cvxPill\">Trim manual<\/span>\r\n                                <span class=\"cvxPill\">AGC Safe<\/span>\r\n                            <\/div>\r\n                        <\/div>\r\n                    <\/div>\r\n\r\n                    <!-- Accordion card (single-open) -->\r\n                    <div class=\"cvxCard cvxAfeCard\" aria-label=\"Detalles\">\r\n                        <div class=\"cvxAcc\" data-role=\"acc\">\r\n                            <div class=\"cvxAcc__item is-open\">\r\n                                <button class=\"cvxAcc__btn\" type=\"button\">\r\n                                    <span class=\"cvxAcc__title\">Qu\u00e9 resuelve<\/span>\r\n                                    <span class=\"cvxAcc__icon\" aria-hidden=\"true\"><\/span>\r\n                                <\/button>\r\n                                <div class=\"cvxAcc__body\">\r\n                                    <div>\u2022 Compatibilidad real: perfiles por XLR\/TRS\/AUX con rangos calibrados.<\/div>\r\n                                    <div>\u2022 Anti-clip: SOFT (clips espor\u00e1dicos) vs SAFE (sin clipping).<\/div>\r\n                                    <div>\u2022 Control: Trim manual por entrada, o autom\u00e1tico cuando el AGC est\u00e1 activo.<\/div>\r\n                                <\/div>\r\n                            <\/div>\r\n\r\n                            <div class=\"cvxAcc__item\">\r\n                                <button class=\"cvxAcc__btn\" type=\"button\">\r\n                                    <span class=\"cvxAcc__title\">Perfiles por conector<\/span>\r\n                                    <span class=\"cvxAcc__icon\" aria-hidden=\"true\"><\/span>\r\n                                <\/button>\r\n                                <div class=\"cvxAcc__body\">\r\n                                    Los perfiles definen una base consistente (impedancia + sensibilidad). Si mov\u00e9s el trim, el perfil pasa a <b>Manual<\/b>.\r\n                                <\/div>\r\n                            <\/div>\r\n\r\n                            <div class=\"cvxAcc__item\">\r\n                                <button class=\"cvxAcc__btn\" type=\"button\">\r\n                                    <span class=\"cvxAcc__title\">AGC SOFT vs SAFE<\/span>\r\n                                    <span class=\"cvxAcc__icon\" aria-hidden=\"true\"><\/span>\r\n                                <\/button>\r\n                                <div class=\"cvxAcc__body\">\r\n                                    SOFT ejemplifica una protecci\u00f3n \u201cmusical\u201d con picos ocasionales. SAFE ajusta para evitar saturaci\u00f3n del ADC.\r\n                                <\/div>\r\n                            <\/div>\r\n                        <\/div>\r\n                    <\/div>\r\n\r\n                <\/div>\r\n\r\n            <\/div>\r\n            <!-- Result card -->\r\n            <div class=\"cvxCard cvxAfeCard cvxAfeCard--results\" style=\"margin-top: 18px;\">\r\n                <div class=\"cvxAfeCardHd\">\r\n                    <div class=\"cvxAfeCardTitle\">Resultado (captura)<\/div>\r\n                    <div class=\"cvxAfeCardDesc\">El perfil configura impedancia + sensibilidad base. El trim ajusta fino (o lo gobierna el AGC).<\/div>\r\n                <\/div>\r\n\r\n                <div class=\"cvxAfeTiles\">\r\n                    <div class=\"cvxAfeTile\">\r\n                        <div class=\"cvxAfeTileK\">MODO<\/div>\r\n                        <div class=\"cvxAfeTileV\" data-role=\"resMode\">\u2014<\/div>\r\n                        <div class=\"cvxAfeTileS\" data-role=\"resModeSub\">\u2014<\/div>\r\n                    <\/div>\r\n\r\n                    <div class=\"cvxAfeTile\">\r\n                        <div class=\"cvxAfeTileK\">IMPEDANCIA<\/div>\r\n                        <div class=\"cvxAfeTileV\" data-role=\"resZ\">\u2014<\/div>\r\n                        <div class=\"cvxAfeTileS\" data-role=\"resZSub\">\u2014<\/div>\r\n                    <\/div>\r\n\r\n                    <div class=\"cvxAfeTile\">\r\n                        <div class=\"cvxAfeTileK\">TRIM<\/div>\r\n                        <div class=\"cvxAfeTileV\" data-role=\"resTrim\">\u2014<\/div>\r\n                        <div class=\"cvxAfeTileS\" data-role=\"resTrimSub\">\u2014<\/div>\r\n                    <\/div>\r\n\r\n                    <div class=\"cvxAfeTile\">\r\n                        <div class=\"cvxAfeTileK\">CONVERSI\u00d3N<\/div>\r\n                        <div class=\"cvxAfeTileV\">Hi-Fi ADC<\/div>\r\n                        <div class=\"cvxAfeTileS\">Burr-Brown (TI)<\/div>\r\n                    <\/div>\r\n                <\/div>\r\n\r\n                <div class=\"cvxAfeScale\">\r\n                    <span class=\"cvxAfeScaleLbl\">Escala (bajo \u2192 alto):<\/span>\r\n                    <span data-role=\"scaleText\"><\/span>\r\n                <\/div>\r\n            <\/div>\r\n\r\n        <\/div>\r\n\r\n        <!--<\/div>-->\r\n    <\/section>\r\n<\/section>\r\n\r\n<script>\r\n    (() => {\r\n        const ROOT_SEL = '.cvxScope [data-cvx-root=\"amp-afe\"]';\r\n        const roots = document.querySelectorAll(ROOT_SEL);\r\n\r\n        const clamp = (v, a, b) => Math.max(a, Math.min(b, v));\r\n        const IS_EN = (() => {\r\n            const htmlLang = (document.documentElement.getAttribute('lang') || '').toLowerCase();\r\n            return htmlLang.startsWith('en') || \/^\\\/en(?:\\\/|$)\/i.test(window.location.pathname);\r\n        })();\r\n        \/* =========================================================\r\n           TRIM RANGE POLICY (por puerto)\r\n           - XLR (MIC): 10..50 dB\r\n           - TRS:      -20..15 dB\r\n           - AUX\/DIG:  -20..15 dB\r\n        ========================================================= *\/\r\n        const LEGACY_TRIM_MIN = -12;\r\n        const LEGACY_TRIM_MAX = 24;\r\n\r\n        function getTrimRangeForPort(port) {\r\n            if (port === 'xlr') return {\r\n                min: 10,\r\n                max: 50,\r\n                step: 0.1\r\n            };\r\n            if (port === 'trs') return {\r\n                min: -20,\r\n                max: 15,\r\n                step: 0.1\r\n            };\r\n            return {\r\n                min: -20,\r\n                max: 15,\r\n                step: 0.1\r\n            }; \/\/ aux \/ dig\r\n        }\r\n\r\n        function normalizeTrimForPort(port, rawVal) {\r\n            const r = getTrimRangeForPort(port);\r\n            let v = rawVal;\r\n\r\n            \/\/ s\u00f3lo MIC\/XLR: remapeo legacy (-12..24) -> (10..50) si cae por debajo del m\u00ednimo\r\n            if (port === 'xlr') {\r\n                const isLegacy = (v >= LEGACY_TRIM_MIN && v <= LEGACY_TRIM_MAX);\r\n                const needsMap = isLegacy && (v < r.min);\r\n                if (needsMap) {\r\n                    const t = (v - LEGACY_TRIM_MIN) \/ (LEGACY_TRIM_MAX - LEGACY_TRIM_MIN); \/\/ 0..1\r\n                    v = r.min + t * (r.max - r.min);\r\n                }\r\n            }\r\n\r\n            return clamp(v, r.min, r.max);\r\n        }\r\n\r\n        function clampTrimToPort(port, v) {\r\n            const r = getTrimRangeForPort(port);\r\n            return clamp(v, r.min, r.max);\r\n        }\r\n\r\n        \/** Profile database (demo values) *\/\r\n        const PROFILE_DB = {\r\n            mic: [{\r\n                    id: 'mic_condenser',\r\n                    label: 'Condenser',\r\n                    modeSub: 'Sensibilidad: Alta',\r\n                    z: '2.2 k\u03a9',\r\n                    zSub: 'Entrada mic optimizada',\r\n                    trim: -2.0,\r\n                    scaleKey: 'Mic \u2013 Condenser',\r\n                    phantomAllowed: true\r\n                },\r\n                {\r\n                    id: 'mic_dynamic',\r\n                    label: 'Dynamic',\r\n                    modeSub: 'Sensibilidad: Media',\r\n                    z: '2.2 k\u03a9',\r\n                    zSub: 'Entrada mic optimizada',\r\n                    trim: +2.0,\r\n                    scaleKey: 'Mic \u2013 Dynamic',\r\n                    phantomAllowed: false\r\n                },\r\n                {\r\n                    id: 'mic_ribbon',\r\n                    label: 'Ribbon',\r\n                    modeSub: 'Sensibilidad: Baja',\r\n                    z: '2.2 k\u03a9',\r\n                    zSub: 'Entrada mic optimizada',\r\n                    trim: +6.0,\r\n                    scaleKey: 'Mic \u2013 Ribbon',\r\n                    phantomAllowed: false\r\n                },\r\n            ],\r\n            inst: [{\r\n                    id: 'inst_single',\r\n                    label: 'Single Coil',\r\n                    modeSub: 'Sensibilidad: Alta',\r\n                    z: '1 M\u03a9',\r\n                    zSub: 'Acople para pickups pasivos',\r\n                    trim: +4.0,\r\n                    scaleKey: 'Inst \u2013 Single-coil'\r\n                },\r\n                {\r\n                    id: 'inst_humb',\r\n                    label: 'Humbucker',\r\n                    modeSub: 'Sensibilidad: Media',\r\n                    z: '1 M\u03a9',\r\n                    zSub: 'Headroom extra para salida alta',\r\n                    trim: 0.0,\r\n                    scaleKey: 'Inst \u2013 Humbucker'\r\n                },\r\n                {\r\n                    id: 'inst_ceramic',\r\n                    label: 'Ceramic \/ Active',\r\n                    modeSub: 'Sensibilidad: Baja',\r\n                    z: '1 M\u03a9',\r\n                    zSub: 'Optimizado para se\u00f1al fuerte',\r\n                    trim: -4.0,\r\n                    scaleKey: 'Inst \u2013 Active'\r\n                },\r\n            ],\r\n            line: [{\r\n                    id: 'line_m10',\r\n                    label: '\u221210 dBV (Dom\u00e9stico)',\r\n                    modeSub: 'Nivel: \u221210 dBV',\r\n                    z: '20 k\u03a9',\r\n                    zSub: 'L\u00edneas cortas \/ consumo',\r\n                    trim: 0.0,\r\n                    scaleKey: 'Line \u2013 \u221210 dBV'\r\n                },\r\n                {\r\n                    id: 'line_p4',\r\n                    label: '+4 dBu (Pro)',\r\n                    modeSub: 'Nivel: +4 dBu',\r\n                    z: '20 k\u03a9',\r\n                    zSub: 'Equipo profesional',\r\n                    trim: -6.0,\r\n                    scaleKey: 'Line \u2013 +4 dBu'\r\n                },\r\n            ],\r\n            aux: [{\r\n                id: 'aux_consumer',\r\n                label: 'Consumer (Stereo)',\r\n                modeSub: 'Nivel: \u221210 dBV',\r\n                z: '10 k\u03a9',\r\n                zSub: 'Aux 3.5 mm',\r\n                trim: 0.0,\r\n                scaleKey: 'AUX \u2013 \u221210 dBV'\r\n            }, ],\r\n        };\r\n\r\n        const SCALE_ORDER = [\r\n            'Mic \u2013 Condenser',\r\n            'Mic \u2013 Dynamic',\r\n            'Mic \u2013 Ribbon',\r\n            'Inst \u2013 Single-coil',\r\n            'Inst \u2013 Humbucker',\r\n            'Inst \u2013 Active',\r\n            'Line \u2013 \u221210 dBV',\r\n            'Line \u2013 +4 dBu',\r\n            'AUX \u2013 \u221210 dBV',\r\n        ];\r\n\r\n        const deepClone = (obj) => JSON.parse(JSON.stringify(obj));\r\n\r\n        function getProfileById(id) {\r\n            for (const group of Object.values(PROFILE_DB)) {\r\n                const p = group.find(x => x.id === id);\r\n                if (p) return p;\r\n            }\r\n            return null;\r\n        }\r\n\r\n        function defaultProfileFor(sig, port) {\r\n            if (sig === 'mic') return 'mic_condenser';\r\n            if (sig === 'inst') return 'inst_single';\r\n            if (sig === 'line') return (port === 'aux' ? 'aux_consumer' : 'line_m10');\r\n            return 'line_m10';\r\n        }\r\n\r\n        function allowedSubchannels(sig) {\r\n            if (sig === 'mic') return {\r\n                a: true,\r\n                b: false,\r\n                st: false\r\n            };\r\n            if (sig === 'inst') return {\r\n                a: true,\r\n                b: true,\r\n                st: false\r\n            };\r\n            if (sig === 'line') return {\r\n                a: true,\r\n                b: true,\r\n                st: true\r\n            };\r\n            return {\r\n                a: true,\r\n                b: true,\r\n                st: true\r\n            };\r\n        }\r\n\r\n        function makeCfgDefaults(port) {\r\n            if (port === 'xlr') {\r\n                const baseId = 'mic_condenser';\r\n                const p = getProfileById(baseId);\r\n                const t = normalizeTrimForPort(port, p ? p.trim : 0);\r\n                return {\r\n                    sig: 'mic',\r\n                    profile: baseId,\r\n                    profileBase: baseId,\r\n                    phantom: false,\r\n                    stereo: true,\r\n                    manualTrim: t,\r\n                    agc: 'off',\r\n                    agcTrim: t,\r\n                    sim: 55,\r\n                    memSig: {}\r\n                };\r\n            }\r\n            if (port === 'trs') {\r\n                const baseId = 'inst_single';\r\n                const p = getProfileById(baseId);\r\n                const t = normalizeTrimForPort(port, p ? p.trim : 0);\r\n                return {\r\n                    sig: 'inst',\r\n                    profile: baseId,\r\n                    profileBase: baseId,\r\n                    phantom: false,\r\n                    stereo: true,\r\n                    manualTrim: t,\r\n                    agc: 'off',\r\n                    agcTrim: t,\r\n                    sim: 55,\r\n                    memSig: {}\r\n                };\r\n            }\r\n            if (port === 'aux') {\r\n                const baseId = 'aux_consumer';\r\n                const p = getProfileById(baseId);\r\n                const t = normalizeTrimForPort(port, p ? p.trim : 0);\r\n                return {\r\n                    sig: 'line',\r\n                    profile: baseId,\r\n                    profileBase: baseId,\r\n                    phantom: false,\r\n                    stereo: true,\r\n                    manualTrim: t,\r\n                    agc: 'off',\r\n                    agcTrim: t,\r\n                    sim: 55,\r\n                    memSig: {}\r\n                };\r\n            }\r\n            \/\/ dig (disabled): treat like line\r\n            const baseId = 'line_m10';\r\n            const p = getProfileById(baseId);\r\n            const t = normalizeTrimForPort(port, p ? p.trim : 0);\r\n            return {\r\n                sig: 'line',\r\n                profile: baseId,\r\n                profileBase: baseId,\r\n                phantom: false,\r\n                stereo: true,\r\n                manualTrim: t,\r\n                agc: 'off',\r\n                agcTrim: t,\r\n                sim: 55,\r\n                memSig: {}\r\n            };\r\n        }\r\n\r\n        function defaultsForPort(inKey, port) {\r\n            return {\r\n                port,\r\n                subch: (port === 'aux') ? 'st' : 'a',\r\n                cfg: makeCfgDefaults(port),\r\n                mem: {}\r\n            };\r\n        }\r\n\r\n        function init(root) {\r\n            const phantomPolicy = (root.getAttribute('data-phantom-policy') || 'cond_only').toLowerCase();\r\n\r\n            if (root.dataset.cvxInited === '1') return;\r\n            root.dataset.cvxInited = '1';\r\n\r\n            const els = {\r\n                chips: Array.from(root.querySelectorAll('.cvxAfeIn')),\r\n                segBtns: (chip) => Array.from(chip.querySelectorAll('.cvxChip__segBtn')),\r\n\r\n                sigBtns: Array.from(root.querySelectorAll('[data-role=\"sig\"][data-sig]'))\r\n                    .filter(b => ['mic', 'inst', 'line'].includes((b.dataset.sig || '').toLowerCase())),\r\n\r\n                subchBtns: Array.from(root.querySelectorAll('[data-role=\"subch\"][data-subch]'))\r\n                    .filter(b => ['a', 'b', 'st'].includes((b.dataset.subch || '').toLowerCase())),\r\n\r\n                agcBtns: Array.from(root.querySelectorAll('[data-role=\"agc\"][data-agc]'))\r\n                    .filter(b => ['off', 'soft', 'safe'].includes((b.dataset.agc || '').toLowerCase())),\r\n\r\n                profile: root.querySelector('[data-role=\"profile\"]'),\r\n\r\n                phantomSeg: root.querySelector('[data-role=\"phantomSeg\"]'),\r\n                phantomBtn: root.querySelector('[data-role=\"phantomBtn\"]'),\r\n                phantomNote: root.querySelector('[data-role=\"phantomNote\"]'),\r\n\r\n                stSeg: root.querySelector('[data-role=\"stSeg\"]'),\r\n                stBtns: Array.from(root.querySelectorAll('[data-role=\"stBtn\"][data-stm]'))\r\n                    .filter(b => ['st', 'mono'].includes((b.dataset.stm || '').toLowerCase())),\r\n                stereoNote: root.querySelector('[data-role=\"stereoNote\"]'),\r\n\r\n                trim: root.querySelector('[data-role=\"trim\"]'),\r\n                trimVal: root.querySelector('[data-role=\"trimVal\"]'),\r\n                trimHint: root.querySelector('[data-role=\"trimHint\"]'),\r\n\r\n                headroomVal: root.querySelector('[data-role=\"headroomVal\"]'),\r\n                clipHint: root.querySelector('[data-role=\"clipHint\"]'),\r\n                meterFill: root.querySelector('[data-role=\"meterFill\"]'),\r\n                meterPeak: root.querySelector('[data-role=\"meterPeak\"]'),\r\n\r\n                sim: root.querySelector('[data-role=\"sim\"]'),\r\n                simPct: root.querySelector('[data-role=\"simPct\"]'),\r\n                simKey: root.querySelector('[data-role=\"simKey\"]'),\r\n\r\n                agcNote: root.querySelector('[data-role=\"agcNote\"]'),\r\n\r\n                resMode: root.querySelector('[data-role=\"resMode\"]'),\r\n                resModeSub: root.querySelector('[data-role=\"resModeSub\"]'),\r\n                resZ: root.querySelector('[data-role=\"resZ\"]'),\r\n                resZSub: root.querySelector('[data-role=\"resZSub\"]'),\r\n                resTrim: root.querySelector('[data-role=\"resTrim\"]'),\r\n                resTrimSub: root.querySelector('[data-role=\"resTrimSub\"]'),\r\n                scaleText: root.querySelector('[data-role=\"scaleText\"]'),\r\n\r\n                acc: root.querySelector('[data-role=\"acc\"]'),\r\n                accItems: Array.from(root.querySelectorAll('[data-role=\"acc\"] .cvxAcc__item')),\r\n                accBtns: Array.from(root.querySelectorAll('[data-role=\"acc\"] .cvxAcc__btn')),\r\n            };\r\n            \/\/ ---------------------------------------------------------\r\n            \/\/ Marker fijo: \u201czona de pico\u201d sobre la barra (misma barra del needle)\r\n            \/\/ ---------------------------------------------------------\r\n            (() => {\r\n                const track =\r\n                    (els.meterPeak && els.meterPeak.parentElement) ||\r\n                    (els.meterFill && els.meterFill.parentElement);\r\n\r\n                if (!track) {\r\n                    els.meterMark = null;\r\n                    return;\r\n                }\r\n\r\n                \/\/ asegurar contexto de posicionamiento sin invadir CSS global\r\n                const cs = window.getComputedStyle(track);\r\n                if (cs.position === 'static') track.style.position = 'relative';\r\n\r\n                let mk = track.querySelector('[data-role=\"meterMark\"]');\r\n                if (!mk) {\r\n                    mk = document.createElement('div');\r\n                    mk.setAttribute('data-role', 'meterMark');\r\n                    mk.style.position = 'absolute';\r\n                    mk.style.top = '-2px';\r\n                    mk.style.bottom = '-2px';\r\n                    mk.style.width = '2px';\r\n                    mk.style.borderRadius = '2px';\r\n                    mk.style.background = 'rgba(255,255,255,0.65)';\r\n                    mk.style.boxShadow = '0 0 0 1px rgba(0,0,0,0.35), 0 0 10px rgba(0,0,0,0.35)';\r\n                    mk.style.pointerEvents = 'none';\r\n                    mk.style.zIndex = '3';\r\n                    track.appendChild(mk);\r\n                }\r\n                els.meterMark = mk;\r\n            })();\r\n\r\n            const states = {\r\n                in1: defaultsForPort('in1', 'trs'),\r\n                in2: defaultsForPort('in2', 'xlr'),\r\n                in3: defaultsForPort('in3', 'aux'),\r\n            };\r\n            \/\/ =========================\r\n            \/\/ INIT OVERRIDES (in1)\r\n            \/\/ in1: TRS \/ B \/ Single Coil \/ Sim 89% \/ AGC=soft\r\n            \/\/ =========================\r\n            states.in1.subch = 'b';\r\n\r\n            \/\/ TRS defaults ya arrancan en Inst + Single Coil, pero lo fijamos expl\u00edcito:\r\n            states.in1.cfg.sig = 'inst';\r\n            states.in1.cfg.profile = 'inst_single';\r\n            states.in1.cfg.profileBase = 'inst_single';\r\n\r\n            \/\/ Simulaci\u00f3n\r\n            states.in1.cfg.sim = 89;\r\n\r\n            \/\/ AGC\r\n            states.in1.cfg.agc = 'soft';\r\n            states.in1.cfg.agcTrim = states.in1.cfg.manualTrim; \/\/ arranque estable\r\n\r\n            let activeKey = 'in1';\r\n\r\n            const getWrap = (k = activeKey) => states[k];\r\n            const getCfg = (k = activeKey) => states[k].cfg;\r\n\r\n            function sanitizeState(w) {\r\n                const c = w.cfg;\r\n\r\n                \/\/ (1) Restricciones por puerto\r\n                if (w.port === 'xlr') c.sig = 'mic';\r\n                if (w.port === 'aux') c.sig = 'line';\r\n                if (w.port === 'trs' && c.sig === 'mic') c.sig = 'inst';\r\n\r\n                \/\/ (2) Subcanales v\u00e1lidos por se\u00f1al\r\n                const allowSub = allowedSubchannels(c.sig);\r\n                if (!allowSub[w.subch]) {\r\n                    w.subch = allowSub.a ? 'a' : (allowSub.b ? 'b' : 'a');\r\n                }\r\n\r\n                \/\/ (3) Profile group\r\n                const group = (w.port === 'aux') ? 'aux' : c.sig;\r\n                const list = PROFILE_DB[group] || [];\r\n                const validIds = new Set(list.map(p => p.id));\r\n                if (c.profile !== 'manual' && !validIds.has(c.profile)) {\r\n                    c.profile = defaultProfileFor(c.sig, w.port);\r\n                }\r\n                if (!c.profileBase || !getProfileById(c.profileBase)) {\r\n                    c.profileBase = (c.profile === 'manual') ? defaultProfileFor(c.sig, w.port) : c.profile;\r\n                }\r\n\r\n                \/\/ (4) Phantom allowed\r\n                const base = getProfileById(c.profileBase);\r\n                const phantomAllowed = (c.sig === 'mic' && base && (phantomPolicy === 'always' || base.phantomAllowed === true));\r\n                if (!phantomAllowed) c.phantom = false;\r\n\r\n                \/\/ (5) TRIM clamp\/normalize por puerto (incluye AGC)\r\n                if (w.port === 'xlr') {\r\n                    c.manualTrim = normalizeTrimForPort('xlr', c.manualTrim);\r\n                    c.agcTrim = normalizeTrimForPort('xlr', c.agcTrim);\r\n                } else {\r\n                    c.manualTrim = clampTrimToPort(w.port, c.manualTrim);\r\n                    c.agcTrim = clampTrimToPort(w.port, c.agcTrim);\r\n                }\r\n\r\n                \/\/ (6) AGC hygiene\r\n                if (c.agc === 'off') {\r\n                    c.agcTrim = c.manualTrim;\r\n                }\r\n            }\r\n\r\n            function buildProfileOptions(w) {\r\n                const c = w.cfg;\r\n                const group = (w.port === 'aux') ? 'aux' : c.sig;\r\n                const baseList = PROFILE_DB[group] || [];\r\n                return [{\r\n                    id: 'manual',\r\n                    label: 'Manual (trim libre)'\r\n                }, ...baseList.map(p => ({\r\n                    id: p.id,\r\n                    label: p.label\r\n                }))];\r\n            }\r\n\r\n            function saveCurrentToMem(inKey) {\r\n                const w = states[inKey];\r\n                w.mem = w.mem || {};\r\n                w.mem[w.port] = deepClone({\r\n                    port: w.port,\r\n                    subch: w.subch,\r\n                    cfg: w.cfg\r\n                });\r\n            }\r\n\r\n            function loadPortState(inKey, port) {\r\n                const w = states[inKey];\r\n                w.mem = w.mem || {};\r\n                const snap = w.mem[port];\r\n                if (snap) {\r\n                    w.port = port;\r\n                    w.subch = snap.subch || w.subch;\r\n                    w.cfg = snap.cfg || w.cfg;\r\n                    return;\r\n                }\r\n                const fresh = defaultsForPort(inKey, port);\r\n                w.port = fresh.port;\r\n                w.subch = fresh.subch;\r\n                w.cfg = fresh.cfg;\r\n                w.mem[port] = deepClone({\r\n                    port: w.port,\r\n                    subch: w.subch,\r\n                    cfg: w.cfg\r\n                });\r\n            }\r\n\r\n            function setActiveInput(inKey) {\r\n                activeKey = inKey;\r\n                els.chips.forEach(ch => {\r\n                    const on = ch.dataset.in === inKey;\r\n                    ch.classList.toggle('is-active', on);\r\n                    ch.setAttribute('aria-selected', on ? 'true' : 'false');\r\n                });\r\n                render();\r\n            }\r\n\r\n            function setPortForActive(port) {\r\n                const inKey = activeKey;\r\n                if (inKey === 'in3' && port === 'dig') return;\r\n\r\n                const w = getWrap();\r\n                if (w.port === port) return;\r\n\r\n                saveCurrentToMem(inKey);\r\n                loadPortState(inKey, port);\r\n                render();\r\n            }\r\n\r\n            function setSubchForActive(subch) {\r\n                const w = getWrap();\r\n                sanitizeState(w);\r\n\r\n                const allowSub = allowedSubchannels(w.cfg.sig);\r\n                if (!allowSub[subch]) return;\r\n\r\n                w.subch = subch;\r\n                render();\r\n            }\r\n\r\n            function setSigForActive(sig) {\r\n                const w = getWrap();\r\n                const c = w.cfg;\r\n\r\n                if (!['mic', 'inst', 'line'].includes(sig)) return;\r\n\r\n                if (w.port === 'xlr') sig = 'mic';\r\n                if (w.port === 'aux') sig = 'line';\r\n                if (w.port === 'trs' && sig === 'mic') return;\r\n\r\n                if (c.sig === sig) return;\r\n\r\n                c.memSig = c.memSig || {};\r\n                c.memSig[c.sig] = {\r\n                    profile: c.profile,\r\n                    profileBase: c.profileBase,\r\n                    manualTrim: c.manualTrim,\r\n                    stereo: c.stereo,\r\n                    phantom: c.phantom,\r\n                    agc: c.agc,\r\n                    agcTrim: c.agcTrim,\r\n                    sim: c.sim\r\n                };\r\n\r\n                c.sig = sig;\r\n\r\n                const cached = c.memSig[sig];\r\n                if (cached) {\r\n                    c.profile = cached.profile;\r\n                    c.profileBase = cached.profileBase;\r\n                    c.manualTrim = cached.manualTrim;\r\n                    c.stereo = cached.stereo;\r\n                    c.phantom = cached.phantom;\r\n                    c.agc = cached.agc;\r\n                    c.agcTrim = cached.agcTrim ?? cached.manualTrim;\r\n                    c.sim = cached.sim ?? c.sim;\r\n                } else {\r\n                    const defId = defaultProfileFor(sig, w.port);\r\n                    c.profile = defId;\r\n                    c.profileBase = defId;\r\n                    const p = getProfileById(defId);\r\n                    const rawT = p ? p.trim : 0;\r\n                    const t = normalizeTrimForPort(w.port, rawT);\r\n\r\n                    c.manualTrim = t;\r\n                    c.phantom = false;\r\n                    c.agc = 'off';\r\n                    c.agcTrim = t;\r\n                    c.sim = c.sim ?? 55;\r\n                }\r\n\r\n                sanitizeState(w);\r\n                render();\r\n            }\r\n\r\n            function setProfileForActive(profileId) {\r\n                const w = getWrap();\r\n                const c = w.cfg;\r\n\r\n                c.profile = profileId;\r\n\r\n                if (profileId !== 'manual') {\r\n                    c.profileBase = profileId;\r\n                    const p = getProfileById(profileId);\r\n                    if (p) {\r\n                        c.manualTrim = normalizeTrimForPort(w.port, p.trim);\r\n                        if (c.agc === 'off' && els.trim) {\r\n                            els.trim.value = String(c.manualTrim);\r\n                        }\r\n                    }\r\n                }\r\n\r\n                sanitizeState(w);\r\n                render();\r\n            }\r\n\r\n            function setTrimForActive(trimVal) {\r\n                const w = getWrap();\r\n                const c = w.cfg;\r\n\r\n                const r = getTrimRangeForPort(w.port);\r\n                c.manualTrim = clamp(trimVal, r.min, r.max);\r\n                c.profile = 'manual';\r\n\r\n                if (!c.profileBase || !getProfileById(c.profileBase)) {\r\n                    c.profileBase = defaultProfileFor(c.sig, w.port);\r\n                }\r\n\r\n                sanitizeState(w);\r\n                render();\r\n            }\r\n\r\n            function setAgcForActive(mode) {\r\n                const w = getWrap();\r\n                const c = w.cfg;\r\n\r\n                if (!['off', 'soft', 'safe'].includes(mode)) return;\r\n                if (c.agc === mode) return;\r\n\r\n                c.agc = mode;\r\n\r\n                \/\/ Arranque: AGC parte del trim manual actual (en rango)\r\n                c.agcTrim = c.manualTrim;\r\n\r\n                sanitizeState(w);\r\n                render();\r\n            }\r\n\r\n            function togglePhantom() {\r\n                const w = getWrap();\r\n                const c = w.cfg;\r\n\r\n                sanitizeState(w);\r\n\r\n                const base = getProfileById(c.profileBase);\r\n                const allowed = (c.sig === 'mic' && base && (phantomPolicy === 'always' || base.phantomAllowed));\r\n                if (!allowed) return;\r\n\r\n                c.phantom = !c.phantom;\r\n                render();\r\n            }\r\n\r\n            function setStereoMode(stm) {\r\n                const w = getWrap();\r\n                const c = w.cfg;\r\n\r\n                sanitizeState(w);\r\n\r\n                const stSegAllowed = (c.sig === 'line' && (w.port === 'trs' || w.port === 'aux') && w.subch === 'st');\r\n                if (!stSegAllowed) return;\r\n\r\n                c.stereo = (stm === 'st');\r\n                render();\r\n            }\r\n\r\n            function setSimLevel(v) {\r\n                const w = getWrap();\r\n                const c = w.cfg;\r\n                c.sim = clamp(v, 0, 100);\r\n                render();\r\n            }\r\n\r\n            function setDisabled(el, disabled) {\r\n                if (!el) return;\r\n                el.classList.toggle('is-disabled', !!disabled);\r\n                if (disabled) el.setAttribute('aria-disabled', 'true');\r\n                else el.removeAttribute('aria-disabled');\r\n            }\r\n\r\n            \/\/ =========================================================\r\n            \/\/ dBFS MODEL + METER (animado) + HEADROOM (a 0 dBFS)\r\n            \/\/ =========================================================\r\n            \/\/ Umbral de \u201cpico\u201d (cercan\u00eda a 0 dBFS sin clip)\r\n            const PEAK_WARN_DBFS = -6; \/\/ zona de pico a partir de -6 dBFS\r\n\r\n            let raf = 0;\r\n            let t0 = performance.now();\r\n\r\n            function getBaseProfile(w) {\r\n                const c = w.cfg;\r\n                return getProfileById(c.profileBase) || getProfileById(defaultProfileFor(c.sig, w.port));\r\n            }\r\n\r\n            \/\/ Base peak (dBFS) antes de aplicar TRIM.\r\n            \/\/ Calibrado para que:\r\n            \/\/ - MIC\/XLR: con 50 dB pod\u00e9s llegar a 0 dBFS (y clip) en perfiles \"hot\".\r\n            \/\/ - TRS Inst\/Line: con 15 dB pod\u00e9s llegar a 0 dBFS en se\u00f1ales fuertes.\r\n            function inputPeakDbfs(w, now) {\r\n                const c = w.cfg;\r\n                const p = getBaseProfile(w);\r\n\r\n                let base = -30;\r\n\r\n                if (w.port === 'xlr') { \/\/ mic\r\n                    \/\/ -46 (cond) \/ -50 (dyn) \/ -54 (rib)  => con 50 dB: +4 \/ 0 \/ -4\r\n                    base =\r\n                        (p && p.id === 'mic_condenser') ? -46 :\r\n                        (p && p.id === 'mic_dynamic') ? -50 :\r\n                        (p && p.id === 'mic_ribbon') ? -54 : -50;\r\n                } else if (w.port === 'trs' && c.sig === 'inst') {\r\n                    \/\/ single -22 \/ humb -19 \/ active -15  => con 15 dB: -7 \/ -4 \/ 0\r\n                    base =\r\n                        (p && p.id === 'inst_single') ? -22 :\r\n                        (p && p.id === 'inst_humb') ? -19 :\r\n                        (p && p.id === 'inst_ceramic') ? -15 : -20;\r\n                } else if (c.sig === 'line') {\r\n                    \/\/ line nominal: con 15 dB puede tocar 0 en se\u00f1ales pro\r\n                    base =\r\n                        (p && p.id === 'line_p4') ? -15 :\r\n                        (p && p.id === 'line_m10') ? -18 : -15;\r\n                } else if (w.port === 'aux') {\r\n                    base = -18;\r\n                }\r\n\r\n                \/\/ Sim: +\/- ~6 dB alrededor del punto medio\r\n                const sim = clamp(parseInt(c.sim ?? 55, 10), 0, 100);\r\n                const simDb = (sim - 55) * (12 \/ 100);\r\n                base += simDb;\r\n\r\n                \/\/ Din\u00e1mica\/ataque: oscilaci\u00f3n + ruido\r\n                const t = (now - t0) \/ 1000;\r\n                const wob = 1.6 * Math.sin(t * 2.1) + 0.9 * Math.sin(t * 5.2);\r\n                const noise = (Math.random() - 0.5) * 0.8;\r\n\r\n                \/\/ Transientes (p\u00faa\/ataque): spikes ocasionales\r\n                const spike = (Math.random() < 0.05) ? (2.5 + Math.random() * 2.5) : 0;\r\n\r\n                return base + wob + noise + spike;\r\n            }\r\n\r\n            function outputPeakDbfs(w, now) {\r\n                const c = w.cfg;\r\n                const trimDb = (c.agc !== 'off') ? c.agcTrim : c.manualTrim;\r\n                return inputPeakDbfs(w, now) + trimDb;\r\n            }\r\n\r\n            function ampFromDbfs(dbfs) {\r\n                \/\/ dbfs <= 0: amp 0..1\r\n                const x = Math.min(dbfs, 0);\r\n                return Math.pow(10, x \/ 20);\r\n            }\r\n\r\n            function renderMeterAndHeadroom(w, peakDbfs) {\r\n                const c = w.cfg;\r\n\r\n                \/\/ Meter en amplitud lineal (visual con gamma leve para no \u201cmorir\u201d a -40 dBFS)\r\n                const a = clamp(ampFromDbfs(peakDbfs), 0, 1);\r\n                const vis = Math.pow(a, 0.65);\r\n                const pct = clamp(vis * 100, 0, 100);\r\n                \/\/ Marker fijo en la \u201czona de pico\u201d (PEAK_WARN_DBFS)\r\n                if (els.meterMark) {\r\n                    const aMk = clamp(ampFromDbfs(PEAK_WARN_DBFS), 0, 1);\r\n                    const visMk = Math.pow(aMk, 0.65);\r\n                    const pctMk = clamp(visMk * 100, 0, 100);\r\n                    els.meterMark.style.left = pctMk.toFixed(2) + '%';\r\n                }\r\n\r\n                if (els.meterFill) els.meterFill.style.width = pct.toFixed(2) + '%';\r\n                if (els.meterPeak) els.meterPeak.style.left = pct.toFixed(2) + '%';\r\n\r\n                \/\/ Headroom real a 0 dBFS: headroom = max(0, -peakDbfs)\r\n                const headroom = clamp(-peakDbfs, 0, 96);\r\n                if (els.headroomVal) els.headroomVal.textContent = headroom.toFixed(1) + ' dB';\r\n\r\n                const clipping = peakDbfs >= 0;\r\n                const peaking = (!clipping && peakDbfs >= PEAK_WARN_DBFS);\r\n\r\n                if (els.clipHint) {\r\n                    if (clipping) {\r\n                        els.clipHint.textContent = (c.agc === 'soft') ? 'Clipping (Soft)' : 'Clipping';\r\n                    } else if (peaking) {\r\n                        els.clipHint.textContent = (c.agc === 'soft') ? 'Soft Peak' : (IS_EN ? 'Peak' : 'Pico');\r\n                    } else {\r\n                        els.clipHint.textContent = 'No Clipping';\r\n                    }\r\n                }\r\n\r\n            }\r\n\r\n            function agcUpdate(w, peakDbfs) {\r\n                const c = w.cfg;\r\n                if (c.agc === 'off') return;\r\n\r\n                const r = getTrimRangeForPort(w.port);\r\n\r\n                \/\/ Objetivo de meter (peak) en dBFS\r\n                \/\/ SAFE: m\u00e1s conservador, evita clip con margen\r\n                \/\/ SOFT: cerca de 0 con tolerancia ocasional a picos\r\n                const target =\r\n                    (c.agc === 'safe') ? -12 :\r\n                    (c.agc === 'soft') ? -6 : -9;\r\n\r\n                \/\/ En SOFT permitimos picos raros: target moment\u00e1neo m\u00e1s alto\r\n                const softBurst = (c.agc === 'soft' && Math.random() < 0.04) ? (+4) : 0;\r\n                const tgt = target + softBurst;\r\n\r\n                const err = peakDbfs - tgt; \/\/ >0: muy caliente (cerca\/arriba de 0), hay que bajar trim\r\n                const atk = (c.agc === 'safe') ? 0.35 : 0.22; \/\/ bajar r\u00e1pido\r\n                const rel = (c.agc === 'safe') ? 0.10 : 0.14; \/\/ subir lento\r\n\r\n                const k = (err > 0) ? atk : rel;\r\n                const delta = err * k;\r\n\r\n                c.agcTrim = clamp(c.agcTrim - delta, r.min, r.max);\r\n            }\r\n\r\n            \/\/ =========================\r\n            \/\/ Events\r\n            \/\/ =========================\r\n            els.chips.forEach(chip => {\r\n                chip.addEventListener('click', (e) => {\r\n                    const target = e.target;\r\n                    if (target && target.classList && target.classList.contains('cvxChip__segBtn')) return;\r\n                    setActiveInput(chip.dataset.in);\r\n                });\r\n\r\n                chip.addEventListener('keydown', (e) => {\r\n                    if (e.key === 'Enter' || e.key === ' ') {\r\n                        e.preventDefault();\r\n                        setActiveInput(chip.dataset.in);\r\n                    }\r\n                });\r\n\r\n                els.segBtns(chip).forEach(btn => {\r\n                    btn.addEventListener('click', (e) => {\r\n                        e.preventDefault();\r\n                        e.stopPropagation();\r\n                        if (btn.classList.contains('is-disabled')) return;\r\n                        setActiveInput(chip.dataset.in);\r\n                        setPortForActive(btn.dataset.port);\r\n                    });\r\n                });\r\n            });\r\n\r\n            els.sigBtns.forEach(btn => {\r\n                btn.addEventListener('click', (e) => {\r\n                    e.stopPropagation();\r\n                    if (btn.classList.contains('is-disabled')) return;\r\n                    setSigForActive((btn.dataset.sig || '').toLowerCase());\r\n                });\r\n            });\r\n\r\n            els.subchBtns.forEach(btn => {\r\n                btn.addEventListener('click', (e) => {\r\n                    e.stopPropagation();\r\n                    if (btn.classList.contains('is-disabled')) return;\r\n                    setSubchForActive((btn.dataset.subch || '').toLowerCase());\r\n                });\r\n            });\r\n\r\n            if (els.profile) {\r\n                els.profile.addEventListener('change', () => {\r\n                    setProfileForActive(els.profile.value);\r\n                });\r\n            }\r\n\r\n            if (els.phantomBtn) {\r\n                els.phantomBtn.addEventListener('click', (e) => {\r\n                    e.stopPropagation();\r\n                    if (els.phantomSeg && els.phantomSeg.classList.contains('is-disabled')) return;\r\n                    togglePhantom();\r\n                });\r\n            }\r\n\r\n            els.stBtns.forEach(btn => {\r\n                btn.addEventListener('click', (e) => {\r\n                    e.stopPropagation();\r\n                    if (els.stSeg && els.stSeg.classList.contains('is-disabled')) return;\r\n                    setStereoMode((btn.dataset.stm || '').toLowerCase());\r\n                });\r\n            });\r\n\r\n            if (els.trim) {\r\n                els.trim.addEventListener('input', () => {\r\n                    const c = getCfg();\r\n                    if (c.agc !== 'off') return;\r\n                    setTrimForActive(parseFloat(els.trim.value));\r\n                });\r\n            }\r\n\r\n            if (els.sim) {\r\n                els.sim.addEventListener('input', () => {\r\n                    setSimLevel(parseInt(els.sim.value, 10));\r\n                });\r\n            }\r\n\r\n            els.agcBtns.forEach(btn => {\r\n                btn.addEventListener('click', (e) => {\r\n                    e.stopPropagation();\r\n                    if (btn.classList.contains('is-disabled')) return;\r\n                    setAgcForActive((btn.dataset.agc || '').toLowerCase());\r\n                });\r\n            });\r\n\r\n            if (els.acc && els.accBtns.length) {\r\n                els.accBtns.forEach((btn) => {\r\n                    btn.addEventListener('click', () => {\r\n                        const item = btn.closest('.cvxAcc__item');\r\n                        const isOpen = item.classList.contains('is-open');\r\n                        els.accItems.forEach(it => it.classList.remove('is-open'));\r\n                        if (!isOpen) item.classList.add('is-open');\r\n                    });\r\n                });\r\n            }\r\n\r\n            function render() {\r\n                const w = getWrap();\r\n                const c = getCfg();\r\n                sanitizeState(w);\r\n\r\n                \/\/ Slider range seg\u00fan puerto activo\r\n                if (els.trim) {\r\n                    const r = getTrimRangeForPort(w.port);\r\n                    els.trim.min = String(r.min);\r\n                    els.trim.max = String(r.max);\r\n                    els.trim.step = String(r.step);\r\n                }\r\n\r\n                \/\/ (A) chips: port on\r\n                els.chips.forEach(chip => {\r\n                    const k = chip.dataset.in;\r\n                    const wk = getWrap(k);\r\n                    els.segBtns(chip).forEach(b => {\r\n                        b.classList.toggle('is-on', b.dataset.port === wk.port);\r\n                    });\r\n                });\r\n\r\n                \/\/ (B) signal buttons allowed by port\r\n                const allowMic = (w.port === 'xlr');\r\n                const allowInst = (w.port === 'trs');\r\n                const allowLine = (w.port === 'trs' || w.port === 'aux');\r\n\r\n                els.sigBtns.forEach(b => {\r\n                    const sig = (b.dataset.sig || '').toLowerCase();\r\n                    const allowed = (sig === 'mic') ? allowMic : (sig === 'inst') ? allowInst : allowLine;\r\n                    b.classList.toggle('is-disabled', !allowed);\r\n                    b.classList.toggle('is-on', c.sig === sig);\r\n                });\r\n\r\n                \/\/ (C) subchannels allowed\r\n                const allowSub = allowedSubchannels(c.sig);\r\n                els.subchBtns.forEach(b => {\r\n                    const key = (b.dataset.subch || '').toLowerCase();\r\n                    b.classList.toggle('is-disabled', !allowSub[key]);\r\n                    b.classList.toggle('is-on', w.subch === key);\r\n                });\r\n\r\n                \/\/ (D) profile options\r\n                const base = getProfileById(c.profileBase);\r\n                if (els.profile) {\r\n                    const opts = buildProfileOptions(w);\r\n                    const cur = c.profile;\r\n                    els.profile.innerHTML = opts.map(o => `<option value=\"${o.id}\">${o.label}<\/option>`).join('');\r\n                    els.profile.value = opts.some(o => o.id === cur) ? cur : 'manual';\r\n                }\r\n\r\n                \/\/ (E) phantom enable\r\n                const phantomAllowed = (c.sig === 'mic' && base && (phantomPolicy === 'always' || base.phantomAllowed === true));\r\n                setDisabled(els.phantomSeg, !phantomAllowed);\r\n                if (els.phantomNote) els.phantomNote.textContent = '';\r\n                if (els.phantomBtn) {\r\n                    els.phantomBtn.classList.toggle('is-on', !!c.phantom);\r\n                    els.phantomBtn.setAttribute('aria-pressed', c.phantom ? 'true' : 'false');\r\n                }\r\n\r\n                \/\/ (F) ST\/MONO enable\r\n                const stSegAllowed = (c.sig === 'line' && (w.port === 'trs' || w.port === 'aux') && w.subch === 'st');\r\n                setDisabled(els.stSeg, !stSegAllowed);\r\n                if (els.stereoNote) els.stereoNote.textContent = '';\r\n                els.stBtns.forEach(btn => {\r\n                    const want = (btn.dataset.stm || '').toLowerCase();\r\n                    const isOn = (want === (c.stereo ? 'st' : 'mono'));\r\n                    btn.classList.toggle('is-on', isOn);\r\n                });\r\n\r\n                \/\/ (G) AGC state + trim disable\r\n                const agcOn = (c.agc !== 'off');\r\n                if (els.trim) {\r\n                    els.trim.classList.toggle('is-disabled', agcOn);\r\n                    els.trim.disabled = agcOn;\r\n                }\r\n                els.agcBtns.forEach(b => b.classList.toggle('is-on', (b.dataset.agc || '').toLowerCase() === c.agc));\r\n\r\n                const shownTrim = agcOn ? c.agcTrim : c.manualTrim;\r\n                if (els.trimVal) els.trimVal.textContent = `${shownTrim.toFixed(1)} dB`;\r\n                if (els.trim) els.trim.value = String(shownTrim);\r\n\r\n                if (els.trimHint) {\r\n                    if (c.profile === 'manual') {\r\n                        els.trimHint.textContent = IS_EN ?\r\n                            (agcOn ? `Profile: Manual \u2022 AGC ${c.agc.toUpperCase()}` : `Profile: Manual`) :\r\n                            (agcOn ? `Perfil: Manual \u2022 AGC ${c.agc.toUpperCase()}` : `Perfil: Manual`);\r\n                    } else {\r\n                        const pLbl = base ? base.label : '\u2014';\r\n                        els.trimHint.textContent = IS_EN ?\r\n                            (agcOn ? `Profile: ${pLbl} \u2022 AGC ${c.agc.toUpperCase()}` : `Profile: ${pLbl}`) :\r\n                            (agcOn ? `Perfil: ${pLbl} \u2022 AGC ${c.agc.toUpperCase()}` : `Perfil: ${pLbl}`);\r\n                    }\r\n                }\r\n                const sim = clamp(parseInt(c.sim ?? 55, 10), 0, 100);\r\n                if (els.sim) els.sim.value = String(sim);\r\n                if (els.simPct) els.simPct.textContent = `${sim}%`;\r\n                if (els.simKey) els.simKey.textContent = (base && base.scaleKey) ? base.scaleKey.toUpperCase() : '\u2014';\r\n\r\n                const prettySig = (c.sig || '').toUpperCase();\r\n                const prettyPort = (w.port || '').toUpperCase();\r\n\r\n                const modeSub = !base ? '\u2014' : (\r\n                    !IS_EN ? base.modeSub :\r\n                    String(base.modeSub)\r\n                    .replace('Sensibilidad: Alta', 'Sensitivity: High')\r\n                    .replace('Sensibilidad: Media', 'Sensitivity: Medium')\r\n                    .replace('Sensibilidad: Baja', 'Sensitivity: Low')\r\n                );\r\n                const z = base ? base.z : '\u2014';\r\n                const zSub = !base ? '\u2014' : (\r\n                    !IS_EN ? base.zSub :\r\n                    String(base.zSub)\r\n                    .replace('Entrada mic optimizada', 'Optimized mic input')\r\n                    .replace('Acople para pickups pasivos', 'Coupling for passive pickups')\r\n                    .replace('Headroom extra para salida alta', 'Extra headroom for high-output signals')\r\n                    .replace('Optimizado para se\u00f1al fuerte', 'Optimized for strong signal')\r\n                    .replace('L\u00edneas cortas \/ consumo', 'Short runs \/ consumer gear')\r\n                    .replace('Equipo profesional', 'Professional gear')\r\n                    .replace('Aux 3.5 mm', '3.5 mm aux')\r\n                );\r\n\r\n                if (els.resMode) els.resMode.textContent = prettySig || '\u2014';\r\n                if (els.resModeSub) {\r\n                    els.resModeSub.textContent =\r\n                        (w.port === 'aux') ?\r\n                        (IS_EN ? '3.5 mm aux (stereo)' : 'Aux 3.5 mm (est\u00e9reo)') :\r\n                        `${prettyPort} \u2022 ${modeSub}`;\r\n                }\r\n                if (els.resZ) els.resZ.textContent = z;\r\n                if (els.resZSub) els.resZSub.textContent = zSub;\r\n\r\n                if (agcOn) {\r\n                    if (els.resTrim) els.resTrim.textContent = `Auto (${c.agc.toUpperCase()})`;\r\n                    if (els.resTrimSub) els.resTrimSub.textContent = IS_EN ? 'Trim controlled by AGC' : 'Trim gobernado por AGC';\r\n                } else {\r\n                    if (els.resTrim) els.resTrim.textContent = `${c.manualTrim.toFixed(1)} dB`;\r\n                    if (els.resTrimSub) els.resTrimSub.textContent = IS_EN ?\r\n                        ((c.profile === 'manual') ? 'Manual adjustment' : 'Profile base') :\r\n                        ((c.profile === 'manual') ? 'Ajuste manual' : 'Base por perfil');\r\n                }\r\n\r\n                const curKey = base ? base.scaleKey : '';\r\n                if (els.scaleText) {\r\n                    els.scaleText.innerHTML =\r\n                        ` ` +\r\n                        SCALE_ORDER.map(k => k === curKey ? `<b>${k}<\/b>` : k).join(' \\u2192 ');\r\n                }\r\n\r\n                if (els.agcNote) {\r\n                    els.agcNote.textContent = IS_EN ?\r\n                        (\r\n                            (c.agc === 'off') ?\r\n                            'OFF: you use manual trim and preserve headroom according to your calibration.' :\r\n                            (c.agc === 'soft') ?\r\n                            'SOFT: regulates to reduce saturation, allowing occasional peaks.' :\r\n                            'SAFE: regulates to avoid clipping with a safety margin.'\r\n                        ) :\r\n                        (\r\n                            (c.agc === 'off') ?\r\n                            'OFF: us\u00e1s el trim manual y aprovech\u00e1s headroom seg\u00fan tu calibraci\u00f3n.' :\r\n                            (c.agc === 'soft') ?\r\n                            'SOFT: regula para evitar saturaci\u00f3n, permitiendo picos ocasionales.' :\r\n                            'SAFE: regula para evitar clipping con margen de seguridad.'\r\n                        );\r\n                }\r\n                \/\/ Primer frame coherente (sin esperar al tick)\r\n                const pk = outputPeakDbfs(w, performance.now());\r\n                renderMeterAndHeadroom(w, pk);\r\n            }\r\n\r\n            function tick(now) {\r\n                const w = getWrap();\r\n                sanitizeState(w);\r\n\r\n                \/\/ Medimos con trim actual (AGC o manual)\r\n                let pk = outputPeakDbfs(w, now);\r\n\r\n                \/\/ AGC ajusta para sostener objetivo (en dBFS)\r\n                if (w.cfg.agc !== 'off') {\r\n                    agcUpdate(w, pk);\r\n                    sanitizeState(w);\r\n\r\n                    \/\/ Re-medir post-ajuste (mejora estabilidad visual)\r\n                    pk = outputPeakDbfs(w, now);\r\n\r\n                    \/\/ Reflejar trim AGC en UI (sin llamar render completo)\r\n                    if (els.trimVal) els.trimVal.textContent = `${w.cfg.agcTrim.toFixed(1)} dB`;\r\n                    if (els.trim) els.trim.value = String(w.cfg.agcTrim);\r\n                }\r\n\r\n                renderMeterAndHeadroom(w, pk);\r\n                raf = requestAnimationFrame(tick);\r\n            }\r\n\r\n            render();\r\n            raf = requestAnimationFrame(tick);\r\n\r\n            const mo = new MutationObserver(() => {\r\n                if (!document.body.contains(root)) {\r\n                    if (raf) cancelAnimationFrame(raf);\r\n                    mo.disconnect();\r\n                }\r\n            });\r\n            mo.observe(document.body, {\r\n                childList: true,\r\n                subtree: true\r\n            });\r\n        }\r\n\r\n        roots.forEach(init);\r\n    })();\r\n<\/script>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"ha-bg-parallax-wrap-hide elementor-section elementor-top-section elementor-element elementor-element-3cd7e28 elementor-section-height-min-height elementor-section-items-stretch fx_section ha-bg-parallax-yes elementor-section-boxed elementor-section-height-default\" data-ha-bg-parallax=\"{&quot;type&quot;:&quot;opacity&quot;,&quot;speed&quot;:2,&quot;android&quot;:0,&quot;ios&quot;:0,&quot;size&quot;:&quot;cover&quot;,&quot;repeat&quot;:&quot;no-repeat&quot;}\" data-id=\"3cd7e28\" data-element_type=\"section\" data-e-type=\"section\" id=\"bluetoothWifiSpeaker\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;,&quot;ha_bg_parallax_switcher&quot;:&quot;yes&quot;,&quot;ha_bg_parallax_type&quot;:&quot;opacity&quot;,&quot;ha_bg_parallax_speed&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:2,&quot;sizes&quot;:[]},&quot;ha_bg_parallax_enable_on_android&quot;:&quot;yes&quot;,&quot;ha_bg_parallax_enable_on_ios&quot;:&quot;yes&quot;,&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t\t<div class=\"elementor-background-overlay\"><\/div>\n\t\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-cdeb55f\" data-id=\"cdeb55f\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<section class=\"elementor-section elementor-inner-section elementor-element elementor-element-dcf22c6 elementor-section-full_width elementor-section-height-default elementor-section-height-default\" data-id=\"dcf22c6\" data-element_type=\"section\" data-e-type=\"section\" data-settings=\"{&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-inner-column elementor-element elementor-element-21041a1\" data-id=\"21041a1\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-54bc315 animated-slow elementor-invisible elementor-widget elementor-widget-heading\" data-id=\"54bc315\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;slideInDown&quot;}\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">SPEAKER INAL\u00c1MBRICO<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-f505670 elementor-invisible elementor-widget elementor-widget-ha-svg-draw happy-addon ha-svg-draw\" data-id=\"f505670\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;slideInLeft&quot;}\" data-widget_type=\"ha-svg-draw.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\n\t\t\t\t<div class=\"ha-svg-draw-container\">\n\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t\n  \n    \n      \n      \n    \n  \n  \n\n\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t<\/div>\n\n\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-inner-section elementor-element elementor-element-e0f69ca elementor-section-full_width elementor-section-height-default elementor-section-height-default\" data-id=\"e0f69ca\" data-element_type=\"section\" data-e-type=\"section\" data-settings=\"{&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-no\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-inner-column elementor-element elementor-element-685bcbb\" data-id=\"685bcbb\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-73baffa animated-slow elementor-invisible elementor-widget elementor-widget-heading\" data-id=\"73baffa\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;fadeIn&quot;,&quot;_animation_delay&quot;:300}\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Conectate y listo<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-d7af2b9 elementor-invisible elementor-widget elementor-widget-heading\" data-id=\"d7af2b9\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;fadeInDown&quot;,&quot;_animation_delay&quot;:200}\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">M\u00fasica sin interrupciones<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-inner-section elementor-element elementor-element-559eedb elementor-section-full_width elementor-section-height-default elementor-section-height-default\" data-id=\"559eedb\" data-element_type=\"section\" data-e-type=\"section\" data-settings=\"{&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-33 elementor-inner-column elementor-element elementor-element-9f5f329 elementor-hidden-mobile\" data-id=\"9f5f329\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-a09decb elementor-invisible elementor-widget elementor-widget-text-editor\" data-id=\"a09decb\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;fadeInLeft&quot;}\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<div style=\"display: flex; align-items: flex-start; gap: 10px; margin: 0 0 10px 0;\"><div style=\"flex: 0 0 auto; line-height: 1; margin-top: 2px;\"><span style=\"color: rgba(160,210,255,0.95); font-size: 16px; font-weight: bold;\">\u2713<\/span><\/div><div style=\"font-size: 14px; line-height: 1.45;\"><strong>Reproduc\u00ed sin depender del celular:<\/strong> CubeVox se conecta a los servicios y el m\u00f3vil solo controla<\/div><\/div><p><!-- Item 2 --><\/p><div style=\"display: flex; align-items: flex-start; gap: 10px; margin: 0 0 10px 0;\"><div style=\"flex: 0 0 auto; line-height: 1; margin-top: 2px;\"><span style=\"color: rgba(160,210,255,0.95); font-size: 16px; font-weight: bold;\">\u2713<\/span><\/div><div style=\"font-size: 14px; line-height: 1.45;\"><strong>Sonido 360\u00b0 en modo cerrado:<\/strong> cobertura uniforme en toda la habitaci\u00f3n<\/div><\/div><p><!-- Item 3 --><\/p><div style=\"display: flex; align-items: flex-start; gap: 10px; margin: 0 0 10px 0;\"><div style=\"flex: 0 0 auto; line-height: 1; margin-top: 2px;\"><span style=\"color: rgba(160,210,255,0.95); font-size: 16px; font-weight: bold;\">\u2713<\/span><\/div><div style=\"font-size: 14px; line-height: 1.45;\"><strong>Movete libre:<\/strong> al sonar por Wi-Fi, la m\u00fasica no se corta cuando te alej\u00e1s<\/div><\/div><p><!-- Item 4 (actualizado con Bluetooth 5.1 + aptX) --><\/p><div style=\"display: flex; align-items: flex-start; gap: 10px; margin: 0 0 10px 0;\"><div style=\"flex: 0 0 auto; line-height: 1; margin-top: 2px;\"><span style=\"color: rgba(160,210,255,0.95); font-size: 16px; font-weight: bold;\">\u2713<\/span><\/div><div style=\"font-size: 14px; line-height: 1.45;\"><strong>Conect\u00e1 todo r\u00e1pido:<\/strong> NFC y emparejamiento m\u00faltiple para sumar dispositivos, con Bluetooth 5.1 (aptX) cuando prioriz\u00e1s baja latencia<\/div><\/div><p><!-- Item 5 --><\/p><div style=\"display: flex; align-items: flex-start; gap: 10px; margin: 0 0 10px 0;\"><div style=\"flex: 0 0 auto; line-height: 1; margin-top: 2px;\"><span style=\"color: rgba(160,210,255,0.95); font-size: 16px; font-weight: bold;\">\u2713<\/span><\/div><div style=\"font-size: 14px; line-height: 1.45;\"><strong>Tu biblioteca siempre lista:<\/strong> USB-A y microSD para reproducci\u00f3n offline y en modo cerrado<\/div><\/div><p><!-- Item 6 --><\/p><div style=\"display: flex; align-items: flex-start; gap: 10px; margin: 0;\"><div style=\"flex: 0 0 auto; line-height: 1; margin-top: 2px;\"><span style=\"color: rgba(160,210,255,0.95); font-size: 16px; font-weight: bold;\">\u2713<\/span><\/div><div style=\"font-size: 14px; line-height: 1.45;\"><strong>Control inmediato:<\/strong> panel t\u00e1ctil retroiluminado para reproducci\u00f3n y volumen<\/div><\/div>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t<div class=\"elementor-column elementor-col-33 elementor-inner-column elementor-element elementor-element-06112ef elementor-hidden-mobile\" data-id=\"06112ef\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap\">\n\t\t\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t<div class=\"elementor-column elementor-col-33 elementor-inner-column elementor-element elementor-element-f73184c\" data-id=\"f73184c\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-6a77e6b elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile elementor-widget elementor-widget-html\" data-id=\"6a77e6b\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<!-- Dynamic VH Spacer (solo c\u00f3digo) -->\r\n<style>\r\n  [data-vh-spacer]{\r\n    display:block;\r\n    height: var(--vh-spacer-h, 0px);\r\n    min-height: 0px;\r\n    pointer-events: none;\r\n  }\r\n<\/style>\r\n\r\n<script>\r\n(() => {\r\n  \/**\r\n   * Dynamic VH Spacers\r\n   * Requisitos:\r\n   * - Secci\u00f3n objetivo:       [data-vh-section]\r\n   * - Contenido medible:      [data-vh-content] (recomendado; si no existe usa la secci\u00f3n)\r\n   * - Espaciadores internos:  [data-vh-spacer] (pueden estar anidados en sub-secciones)\r\n   *\r\n   * Opcional:\r\n   * - data-weight=\"N\" en cada spacer para repartir excedente proporcional\r\n   * - data-vh-offset=\"px\" en la secci\u00f3n para restar (ej: header sticky)\r\n   *\/\r\n\r\n  const sections = new Map();\r\n  let ro;\r\n\r\n  function getViewportH(){\r\n    const vv = window.visualViewport;\r\n    return (vv && vv.height) ? vv.height : window.innerHeight;\r\n  }\r\n\r\n  function getOffsetPx(section){\r\n    const a = section.getAttribute('data-vh-offset');\r\n    const n = a ? Number(a) : 0;\r\n    return Number.isFinite(n) ? n : 0;\r\n function parseWeight(spacer){\r\n    const w = Number(spacer.getAttribute('data-weight') || '1');\r\n    return (Number.isFinite(w) && w > 0) ? w : 1;\r\n  }\r\n\r\n  function collect(){\r\n    sections.clear();\r\n    document.querySelectorAll('[data-vh-section]').forEach(section => {\r\n      const content = section.querySelector('[data-vh-content]') || section;\r\n      const spacers = Array.from(section.querySelectorAll('[data-vh-spacer]'));\r\n      if (!spacers.length) return;\r\n      sections.set(section, { content, spacers });\r\n    });\r\n  }\r\n\r\n  function updateSection(section){\r\n    const entry = sections.get(section);\r\n    if (!entry) return;\r\n\r\n    const { content, spacers } = entry;\r\n\r\n    \/\/ 1) Reset para medir altura natural\r\n    spacers.forEach(s => s.style.setProperty('--vh-spacer-h', '0px'));\r\n\r\n    \/\/ 2) Medir altura natural del contenido\r\n    const naturalH = Math.round(content.getBoundingClientRect().height);\r\n\r\n    \/\/ 3) Objetivo: viewport - offset\r\n    const targetH = Math.max(0, Math.round(getViewportH() - getOffsetPx(section)));\r\n\r\n    \/\/ 4) Excedente\r\n    const extra = Math.max(0, targetH - naturalH);\r\n\r\n    if (extra <= 0){\r\n      spacers.forEach(s => s.style.setProperty('--vh-spacer-h', '0px'));\r\n      return;\r\n    }\r\n\r\n    \/\/ 5) Reparto por pesos (con redondeo estable)\r\n    const weights = spacers.map(parseWeight);\r\n    const sumW = weights.reduce((a,b)=>a+b, 0);\r\n\r\n    let remaining = extra;\r\n    spacers.forEach((s, i) => {\r\n      const portion = (i === spacers.length - 1)\r\n        ? remaining\r\n        : Math.round(extra * (weights[i] \/ sumW));\r\n      remaining -= portion;\r\n      s.style.setProperty('--vh-spacer-h', portion + 'px');\r\n    });\r\n  }\r\n\r\n  let raf = 0;\r\n  function updateAll(){\r\n    cancelAnimationFrame(raf);\r\n    raf = requestAnimationFrame(() => {\r\n      sections.forEach((_v, section) => updateSection(section));\r\n    });\r\n  }\r\n\r\n  function bind(){\r\n    ro?.disconnect?.();\r\n    ro = new ResizeObserver(() => updateAll());\r\n\r\n    sections.forEach(({ content }, section) => {\r\n      ro.observe(content);\r\n      ro.observe(section);\r\n    });\r\n\r\n    window.addEventListener('resize', updateAll, { passive: true });\r\n    window.visualViewport?.addEventListener('resize', updateAll, { passive: true });\r\n    window.addEventListener('load', updateAll, { passive: true });\r\n\r\n    \/\/ Por cargas tard\u00edas (imgs\/fonts\/layout)\r\n    document.addEventListener('load', (e) => {\r\n      const t = e.target;\r\n      if (t && t.tagName === 'IMG') updateAll();\r\n    }, true);\r\n  }\r\n\r\n  \/\/ Init\r\n  collect();\r\n  bind();\r\n  updateAll();\r\n\r\n  \/\/ Si tu DOM cambia luego (Elementor\/WP), llam\u00e1 a:\r\n  \/\/ window.__cvxVhSpacerRefresh?.();\r\n  window.__cvxVhSpacerRefresh = () => { collect(); bind(); updateAll(); };\r\n})();\r\n<\/script>\r\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-7e973a1 elementor-widget elementor-widget-html\" data-id=\"7e973a1\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<div class=\"cvxScope\" style=\"max-width:320px; width:100%; margin:0 auto;\">\r\n<div class=\"cvxIconCards cvxIconCards--mobStrip\" aria-label=\"Conectividad\">\r\n\r\n    <div class=\"cvxIconCard\">\r\n      <div class=\"cvxIconCard__icon\">\r\n        <img decoding=\"async\" src=\"\/wp-content\/uploads\/wifi-connectivity-icon.webp\" alt=\"Wi-Fi\">\r\n      <\/div>\r\n      <div class=\"cvxIconCard__txt\">\r\n        <div class=\"cvxIconCard__title\">Wi-Fi AP &amp; Host<\/div>\r\n        <div class=\"cvxIconCard__sub\">Cliente y punto de acceso integrados<\/div>\r\n      <\/div>\r\n    <\/div>\r\n\r\n    <div class=\"cvxIconCard\">\r\n      <div class=\"cvxIconCard__icon\">\r\n        <img decoding=\"async\" src=\"\/wp-content\/uploads\/bluetooth-connectivity-icon.webp\" alt=\"Bluetooth\">\r\n      <\/div>\r\n      <div class=\"cvxIconCard__txt\">\r\n        <div class=\"cvxIconCard__title\">Bluetooth 5.1 + aptX<\/div>\r\n        <div class=\"cvxIconCard__sub\">Baja latencia y mayor estabilidad<\/div>\r\n      <\/div>\r\n    <\/div>\r\n\r\n    <div class=\"cvxIconCard\">\r\n      <div class=\"cvxIconCard__icon\">\r\n        <img decoding=\"async\" src=\"\/wp-content\/uploads\/nfc-connectivity-icon.webp\" alt=\"NFC\">\r\n      <\/div>\r\n      <div class=\"cvxIconCard__txt\">\r\n        <div class=\"cvxIconCard__title\">NFC + emparejamiento m\u00faltiple<\/div>\r\n        <div class=\"cvxIconCard__sub\">Conexi\u00f3n inmediata y simult\u00e1nea<\/div>\r\n      <\/div>\r\n    <\/div>\r\n\r\n    <div class=\"cvxIconCard\">\r\n      <div class=\"cvxIconCard__icon\">\r\n        <img decoding=\"async\" src=\"\/wp-content\/uploads\/usb-connectivity-icon.webp\" alt=\"USB\">\r\n      <\/div>\r\n      <div class=\"cvxIconCard__txt\">\r\n        <div class=\"cvxIconCard__title\">USB-C + USB-A<\/div>\r\n        <div class=\"cvxIconCard__sub\">Datos, carga y perif\u00e9ricos<\/div>\r\n      <\/div>\r\n    <\/div>\r\n\r\n  <\/div>\r\n<\/div>\r\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-4061a62 elementor-section-height-min-height elementor-section-items-stretch fx_section elementor-section-boxed elementor-section-height-default\" data-id=\"4061a62\" data-element_type=\"section\" data-e-type=\"section\" id=\"composeCloud\" data-settings=\"{&quot;background_background&quot;:&quot;gradient&quot;,&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t\t<div class=\"elementor-background-overlay\"><\/div>\n\t\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-053c2f9\" data-id=\"053c2f9\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<section class=\"elementor-section elementor-inner-section elementor-element elementor-element-a131283 elementor-section-full_width elementor-section-height-default elementor-section-height-default\" data-id=\"a131283\" data-element_type=\"section\" data-e-type=\"section\" data-settings=\"{&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-no\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-inner-column elementor-element elementor-element-8f0b3b9\" data-id=\"8f0b3b9\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-1c4813a animated-slow elementor-invisible elementor-widget elementor-widget-heading\" data-id=\"1c4813a\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;slideInDown&quot;}\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Compose &amp; Cloud<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-5d79ba9 elementor-invisible elementor-widget elementor-widget-ha-svg-draw happy-addon ha-svg-draw\" data-id=\"5d79ba9\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;slideInLeft&quot;}\" data-widget_type=\"ha-svg-draw.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\n\t\t\t\t<div class=\"ha-svg-draw-container\">\n\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t\n  \n    \n      \n      \n    \n  \n  \n\n\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t<\/div>\n\n\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-inner-section elementor-element elementor-element-0a9f499 elementor-section-full_width elementor-section-height-default elementor-section-height-default\" data-id=\"0a9f499\" data-element_type=\"section\" data-e-type=\"section\" data-settings=\"{&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-no\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-inner-column elementor-element elementor-element-0c5c8d3\" data-id=\"0c5c8d3\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-d14afaa animated-slow elementor-invisible elementor-widget elementor-widget-heading\" data-id=\"d14afaa\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;fadeIn&quot;,&quot;_animation_delay&quot;:300}\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Control total de tu m\u00fasica<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-2f7b78d elementor-invisible elementor-widget elementor-widget-heading\" data-id=\"2f7b78d\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;fadeInDown&quot;,&quot;_animation_delay&quot;:200}\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">est\u00e9s donde est\u00e9s<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-inner-section elementor-element elementor-element-aa0c83a elementor-section-full_width elementor-section-height-default elementor-section-height-default\" data-id=\"aa0c83a\" data-element_type=\"section\" data-e-type=\"section\" data-settings=\"{&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-no\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-inner-column elementor-element elementor-element-cd1a4fb\" data-id=\"cd1a4fb\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-f2ff7d6 elementor-widget elementor-widget-html\" data-id=\"f2ff7d6\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<section class=\"cvxScope\">\r\n    <section data-cvx-root=\"compose-cloud\" data-cvx-cc-layout=\"wide\" data-cvx-cc-orient=\"portrait\" data-cvx-cc-phone-shell=\"off\" style=\"\r\n    \/* =========================================================\r\n   PAR\u00c1METROS (por instancia)\r\n   - Sufijos:\r\n     -d = escritorio (desktop)\r\n     -m = m\u00f3vil (mobile)\r\n   ========================================================= *\/\r\n\r\n\/* =========================\r\n   1) MAQUETACI\u00d3N RESPONSIVA\r\n   ========================= *\/\r\n\r\n\/* Punto de corte (en p\u00edxeles) para pasar de layout \u201cancho\u201d a \u201capilado\u201d.\r\n   Nota: el JavaScript lee este valor como n\u00famero. *\/\r\n--cvx-cc-bp-stack: 700;\r\n\r\n\/* Escala general de la secci\u00f3n (multiplica tama\u00f1os internos).\r\n   Se integra con el Starter Kit a trav\u00e9s de la variable de escala global. *\/\r\n--cvx-cc-s-d: 1;\r\n--cvx-cc-s-m: .96;\r\n\r\n\/* =========================\r\n   2) ESPACIADO DE PANELES\r\n   ========================= *\/\r\n\r\n\/* Padding interno del panel principal (el contenedor grande). *\/\r\n--cvx-cc-panel-pad-d: 18px;\r\n--cvx-cc-panel-pad-m: 14px;\r\n\r\n\/* Separaci\u00f3n vertical entre paneles \/ bloques dentro de la secci\u00f3n. *\/\r\n--cvx-cc-panel-gap-d: 18px;\r\n--cvx-cc-panel-gap-m: 14px;\r\n\r\n\/* =========================\r\n   3) LAYOUT DE COMPOSE\r\n   ========================= *\/\r\n\r\n\/* Separaci\u00f3n entre columna de historia y columna del tel\u00e9fono (o entre bloques en mobile). *\/\r\n--cvx-cc-compose-gap-d: 22px;\r\n--cvx-cc-compose-gap-m: 16px;\r\n\r\n\/* Mostrar u ocultar el encabezado est\u00e1tico de la secci\u00f3n (kicker + t\u00edtulo + texto + tags).\r\n   \u00datil si Elementor ya renderiza ese encabezado.\r\n   1 = mostrar, 0 = ocultar *\/\r\n--cvx-cc-sec-head-on-d: 1;\r\n--cvx-cc-sec-head-on-m: 1;\r\n\r\n\/* Separaci\u00f3n interna del encabezado est\u00e1tico (distancia entre sus elementos). *\/\r\n--cvx-cc-sec-gap-d: 14px;\r\n--cvx-cc-sec-gap-m: 12px;\r\n\r\n\/* Mostrar u ocultar el encabezado din\u00e1mico por pantalla (kicker\/t\u00edtulo\/desc + controles).\r\n   1 = visible, 0 = colapsado (queda en el DOM). *\/\r\n--cvx-cc-head-on-d: 1;\r\n--cvx-cc-head-on-m: 1;\r\n\r\n\/* =========================\r\n   4) MINI-CARDS (HISTORIA)\r\n   ========================= *\/\r\n\r\n\/* Fondo del card superior que contiene: encabezado din\u00e1mico + mini-cards (m\u00e1s oscuro). *\/\r\n--cvx-cc-compose-head-bg-d: rgba(0,0,0,.22);\r\n--cvx-cc-compose-head-bg-m: rgba(0,0,0,.20);\r\n\r\n\/* Fondo de cada mini-card (sub-cards). *\/\r\n--cvx-cc-mini-bg-d: rgba(0,0,0,.12);\r\n--cvx-cc-mini-bg-m: rgba(0,0,0,.10);\r\n\r\n\/* Borde de cada mini-card. *\/\r\n--cvx-cc-mini-stroke-d: rgba(255,255,255,.10);\r\n--cvx-cc-mini-stroke-m: rgba(255,255,255,.10);\r\n\r\n\/* Intensidad del \u201cbrillo\u201d (glow) interno decorativo en mini-cards. *\/\r\n--cvx-cc-mini-glow-a-d: .55;\r\n--cvx-cc-mini-glow-a-m: .50;\r\n\r\n\/* Separaci\u00f3n vertical entre el encabezado din\u00e1mico y la grilla de mini-cards. *\/\r\n--cvx-cc-minis-top-gap-d: 16px;\r\n--cvx-cc-minis-top-gap-m: 10px;\r\n\r\n\/* Gaps de mini-cards. *\/\r\n--cvx-cc-minis-gap-d: 20px;\r\n--cvx-cc-minis-gap-m: 10px;\r\n\r\n\/* Cantidad de columnas de mini-cards seg\u00fan estado.\r\n   - \u201cwide-por\u201d: escritorio en vertical (pantalla portrait)\r\n   - \u201cwide-lan\u201d: escritorio en horizontal (pantalla landscape)\r\n   - \u201cstack\u201d: m\u00f3vil (layout apilado) *\/\r\n--cvx-cc-min-cols-wide-por: 1;\r\n--cvx-cc-min-cols-wide-lan: 2;\r\n--cvx-cc-min-cols-stack: 1;\r\n\r\n\/* =========================\r\n   5) TEL\u00c9FONO (MOCKUP + VENTANA)\r\n   ========================= *\/\r\n\r\n\/* Ruta del PNG del marco del tel\u00e9fono (\u00fanico marco vertical). *\/\r\n--cvx-cc-phone-frame-src: \/wp-content\/uploads\/iphone-11-pro-max-portrait-frame.webp;\r\n\r\n\/* \u201cVentana\u201d (recorte) por donde se ve el contenido (imagen\/video) detr\u00e1s del marco.\r\n   Formato: top right bottom left.\r\n   Ajust\u00e1 estos valores para que el contenido calce perfecto dentro de la pantalla del mockup.  (top right bottom left) *\/\r\n   \r\n   \/* Ventana vertical (portrait) *\/\r\n--cvx-cc-inset-por-y: 4.5%;   \/* top y bottom base *\/\r\n--cvx-cc-inset-por-x: 6%;   \/* left y right base *\/\r\n--cvx-cc-inset-por-dy: 0%;    \/* ajuste fino vertical *\/\r\n--cvx-cc-inset-por-dx: 0%;    \/* ajuste fino horizontal *\/\r\n\r\n\/* Ventana horizontal (landscape) *\/\r\n--cvx-cc-inset-lan-y: 29%;   \/* top y bottom base *\/\r\n--cvx-cc-inset-lan-x: -36.4%;   \/* left y right base *\/\r\n--cvx-cc-inset-lan-dy: 0%;    \/* ajuste fino vertical *\/\r\n--cvx-cc-inset-lan-dx: 0%;    \/* ajuste fino horizontal *\/\r\n\r\n\r\n--cvx-cc-por-screen-scale-d: 1;\r\n--cvx-cc-por-screen-scale-m: 1;\r\n\r\n\/* Ancho del rig del tel\u00e9fono (escala visual del mockup). *\/\r\n--cvx-cc-phone-w-d: 340px;\r\n--cvx-cc-phone-w-m: 300px;\r\n\r\n\/* Alto del escenario donde vive el tel\u00e9fono (evita truncado vertical).\r\n   Nota: en tu implementaci\u00f3n, V y H est\u00e1n igualados para mantener tama\u00f1o consistente. *\/\r\n--cvx-cc-phone-stage-h-por-d: 640px;\r\n--cvx-cc-phone-stage-h-por-m: 640px;\r\n--cvx-cc-phone-stage-h-lan-d: 400px;\r\n--cvx-cc-phone-stage-h-lan-m: 300px;\r\n\r\n\r\n--cvx-cc-media-fit-por: contain;   \/* contain = sin recorte \/ cover = llena recortando *\/\r\n--cvx-cc-media-fit-lan: contain;\r\n\r\n--cvx-cc-media-pos-por: 50% 50%;   \/* centrado *\/\r\n--cvx-cc-media-pos-lan: 50% 50%;\r\n\r\n\/* =========================\r\n   6) MODO HORIZONTAL (ROTACI\u00d3N)\r\n   ========================= *\/\r\n\r\n\/* Rotaci\u00f3n antihoraria para simular landscape usando el mismo marco vertical. *\/\r\n--cvx-cc-lan-rot: 90deg;\r\n\r\n\/* Escala del tel\u00e9fono en landscape (idealmente 1 para mantener proporci\u00f3n). *\/\r\n--cvx-cc-lan-scale-d: 1;\r\n--cvx-cc-lan-scale-m: 1;\r\n\r\n\/* Traslaci\u00f3n fina del tel\u00e9fono (en p\u00edxeles) para centrar tras rotar. *\/\r\n--cvx-cc-lan-tx-d: 0px;\r\n--cvx-cc-lan-ty-d: 0px;\r\n--cvx-cc-lan-tx-m: 0px;\r\n--cvx-cc-lan-ty-m: 0px;\r\n\r\n\/* Escala extra del contenido dentro de la ventana en modo horizontal\r\n   (sirve para \u201cllenar\u201d mejor cuando se rota, especialmente en m\u00f3vil). *\/\r\n--cvx-cc-lan-screen-scale-d: 1.04;\r\n--cvx-cc-lan-screen-scale-m: 1.04;\r\n\r\n\/* =========================\r\n   7) NAVEGACI\u00d3N POR PUNTOS (DOTS)\r\n   ========================= *\/\r\n\r\n\/* Tama\u00f1o de cada punto. *\/\r\n--cvx-cc-dot-size-d: 12px;\r\n--cvx-cc-dot-size-m: 12px;\r\n\r\n\/* Separaci\u00f3n entre puntos. *\/\r\n--cvx-cc-dot-gap-d: 14px;\r\n--cvx-cc-dot-gap-m: 14px;\r\n\r\n\/* =========================\r\n   8) VELOCIDAD DE REPRODUCCI\u00d3N (VIDEOS)\r\n   ========================= *\/\r\n\r\n\/* Velocidad de reproducci\u00f3n (playbackRate).\r\n   1 = normal, 0.8 = m\u00e1s lento, 1.2 = m\u00e1s r\u00e1pido.\r\n   Se aplica al video cuando entra al screen o al tocar el radar \u201cplay\u201d. *\/\r\n--cvx-cc-vrate-home: 1;\r\n--cvx-cc-vrate-mydevice: 1;\r\n--cvx-cc-vrate-settings: 1;\r\n\r\n\/* =========================\r\n   9) AJUSTE FINO DE RADARES (HOTSPOTS)\r\n   ========================= *\/\r\n\r\n\/* Desplazamientos finos del radar respecto a la posici\u00f3n base.\r\n   Unidad: fracci\u00f3n del ancho\/alto del viewport (0.01 = 1%).\r\n   Ajust\u00e1s X\/Y sin tocar el JSON. *\/\r\n\r\n\/* Radar del desplegable (dropdown) en Settings (para disparar \u201cplay\u201d). *\/\r\n--cvx-cc-hs-settings-dx: 0;\r\n--cvx-cc-hs-settings-dy: 0;\r\n\r\n\/* Radar para abrir DAW desde Projects. *\/\r\n--cvx-cc-hs-daw-dx: 0;\r\n--cvx-cc-hs-daw-dy: 0;\r\n\r\n\/* Radar del engranaje (configuraci\u00f3n) en My Devices. *\/\r\n--cvx-cc-hs-gear-dx: 0;\r\n--cvx-cc-hs-gear-dy: 0;\r\n\r\n\/* Radar sobre la tarjeta de CubeVox (para ir a FX). *\/\r\n--cvx-cc-hs-fx-dx: 0;\r\n--cvx-cc-hs-fx-dy: 0;\r\n\r\n\/* Radar sobre CH1 en FX (para ir a Remote). *\/\r\n--cvx-cc-hs-ch1-dx: 0;\r\n--cvx-cc-hs-ch1-dy: 0;\r\n\r\n\/* =========================\r\n   10) AQA CLOUD (ESPACIADO)\r\n   ========================= *\/\r\n\r\n\/* Separaci\u00f3n interna del layout de Cloud (columna flujo vs columna m\u00f3dulos). *\/\r\n--cvx-cc-cloud-gap-d: 22px;\r\n--cvx-cc-cloud-gap-m: 16px;\r\n    \">\r\n\r\n        <!-- =========================================================\r\n         CONFIG (screens + cloud modules)\r\n         - img: screenshot\/image to show behind the phone frame\r\n         - orientation: \"portrait\" | \"landscape\"\r\n         - minis: up to 4 mini-cards (title\/desc\/optional thumb)\r\n         ========================================================= -->\r\n        <script type=\"application\/json\" data-cvx-cc-config>\r\n            {\r\n                \"version\": 1,\r\n                \"options\": {\r\n                    \"autoplayMs\": 3400,\r\n                    \"respectReducedMotion\": true\r\n                },\r\n                \"compose\": {\r\n                    \"screens\": [{\r\n                            \"id\": \"home\",\r\n                            \"orientation\": \"portrait\",\r\n                            \"kicker\": \"HOME\",\r\n                            \"title\": \"Tus proyectos, listos para retomar.\",\r\n                            \"desc\": \"Widgets para proyectos con filtros, accesos a controles espec\u00edficos, estado de conexi\u00f3n, acciones r\u00e1pidas y mucho mas.\",\r\n                            \"minis\": [{\r\n                                    \"t\": \"Continuar sesi\u00f3n\",\r\n                                    \"d\": \"Tu proyecto activo, con el punto exacto para retomar (toma, edici\u00f3n o mezcla).\",\r\n                                    \"thumb\": \"\"\r\n                                },\r\n                                {\r\n                                    \"t\": \"Accesos de producci\u00f3n\",\r\n                                    \"d\": \"Aatajos a DAW, FX y export seg\u00fan el estado del proyecto.\",\r\n                                    \"thumb\": \"\"\r\n                                },\r\n                                {\r\n                                    \"t\": \"Atajos de dispositivos\",\r\n                                    \"d\": \"Tus equipos principales (CubeVox y otros) con estado y acciones disponibles.\",\r\n                                    \"thumb\": \"\"\r\n                                },\r\n                                {\r\n                                    \"t\": \"Pendientes cr\u00edticos\",\r\n                                    \"d\": \"Proyectos compartidos con cambios, recursos por probar, o dispositivos que requieren actualizaci\u00f3n\/atenci\u00f3n.\",\r\n                                    \"thumb\": \"\"\r\n                                }\r\n                            ],\r\n                            \"video\": {\r\n                                \"src\": \"\/wp-content\/uploads\/compose-studio-home-screen.mp4\",\r\n                                \"autoplay\": true,\r\n                                \"loop\": true,\r\n                                \"rateVar\": \"--cvx-cc-vrate-home\"\r\n                            }\r\n                        },\r\n\r\n                        {\r\n                            \"id\": \"projects\",\r\n                            \"orientation\": \"portrait\",\r\n                            \"kicker\": \"PROJECTS\",\r\n                            \"title\": \"Privados, compartidos o colaborativos.\",\r\n                            \"desc\": \"Todos tus proyectos en un solo lugar para mantener orden a medida que el proyecto crece.\",\r\n                            \"minis\": [{\r\n                                    \"t\": \"Colaboraci\u00f3n & Delegaci\u00f3n\",\r\n                                    \"d\": \"Pod\u00e9s mantener un proyecto privado o sumar colaboradores con permisos puntuales (por ejemplo, delegar la mezcla del master o la edici\u00f3n de pistas espec\u00edficas).\",\r\n                                    \"thumb\": \"\"\r\n                                },\r\n                                {\r\n                                    \"t\": \"Entrada inmediata\",\r\n                                    \"d\": \"Crear o importar y empezar a producir, sin pasos innecesarios.\",\r\n                                    \"thumb\": \"\"\r\n                                },\r\n                                {\r\n                                    \"t\": \"Filtros + b\u00fasqueda\",\r\n                                    \"d\": \"Encontr\u00e1s por tipo, actividad, o criterio de trabajo (lo que evita \u201cscroll infinito\u201d).\",\r\n                                    \"thumb\": \"\"\r\n                                },\r\n                                {\r\n                                    \"t\": \"Contribuci\u00f3n\",\r\n                                    \"d\": \"Puedes encontrar los proyectos de terceros en los que estas trabajando y solicitar m\u00e1s permisos si los requieres.\",\r\n                                    \"thumb\": \"\"\r\n                                }\r\n                            ],\r\n                            \"seq\": {\r\n                                \"frames\": [\r\n                                    \"\/wp-content\/uploads\/compose-studio-projects-private-screen.webp\",\r\n                                    \"\/wp-content\/uploads\/compose-studio-projects-shared-screen.webp\",\r\n                                    \"\/wp-content\/uploads\/compose-studio-projects-collaborations-screen.webp\",\r\n                                    \"\/wp-content\/uploads\/compose-studio-projects-all-scren.webp\"\r\n                                ],\r\n                                \"frameMs\": 1200\r\n                            },\r\n                            \"hotspots\": [{\r\n                                \"id\": \"hs_daw\",\r\n                                \"action\": \"goto\",\r\n                                \"to\": \"daw\",\r\n                                \"x\": 0.52,\r\n                                \"y\": 0.847,\r\n                                \"w\": 0.4,\r\n                                \"h\": 0.06,\r\n                                \"dxVar\": \"--cvx-cc-hs-daw-dx\",\r\n                                \"dyVar\": \"--cvx-cc-hs-daw-dy\"\r\n                            }]\r\n                        },\r\n\r\n                        {\r\n                            \"id\": \"daw\",\r\n                            \"orientation\": \"landscape\",\r\n                            \"kicker\": \"Compose, el DAW de AQA\",\r\n                            \"title\": \"Produc\u00ed multipista, de la idea al master final\",\r\n                            \"desc\": \"Nuestro Digital Audio Workstation (Compose), es el espacio para construir proyectos multipista con edici\u00f3n no destructiva: grab\u00e1s, organiz\u00e1s y refin\u00e1s tomas, aplic\u00e1s efectos en contexto, mezcl\u00e1s con control y termin\u00e1s con un master listo para exportar o compartir.\",\r\n                            \"minis\": [{\r\n                                    \"t\": \"Multipista real\",\r\n                                    \"d\": \"Cre\u00e1 y gestion\u00e1 sesiones con varias pistas, capas y secciones, manteniendo orden y control a medida que el proyecto crece.\",\r\n                                    \"thumb\": \"\"\r\n                                },\r\n                                {\r\n                                    \"t\": \"Edici\u00f3n no destructiva\",\r\n                                    \"d\": \"Ajust\u00e1s sin comprometer el original: cortes, movimientos y decisiones reversibles para iterar r\u00e1pido sin perder material.\",\r\n                                    \"thumb\": \"\"\r\n                                },\r\n                                {\r\n                                    \"t\": \"Mixing y mastering\",\r\n                                    \"d\": \"Balance, paneos y procesamiento por pista\/bus, m\u00e1s un cierre de master para dejar el tema consistente y listo para entrega.\",\r\n                                    \"thumb\": \"\"\r\n                                },\r\n                                {\r\n                                    \"t\": \"Export y stems\",\r\n                                    \"d\": \"Renderiz\u00e1 el proyecto final o export\u00e1 stems para seguir en otro entorno, colaborar o entregar a mezcla externa.\",\r\n                                    \"thumb\": \"\"\r\n                                }\r\n                            ],\r\n                            \"img\": \"\/wp-content\/uploads\/compose-studio-daw-screen.webp\"\r\n                        },\r\n\r\n                        {\r\n                            \"id\": \"mydevice\",\r\n                            \"orientation\": \"portrait\",\r\n                            \"kicker\": \"MY DEVICES\",\r\n                            \"title\": \"Equipos registrados, bajo tu cuenta.\",\r\n                            \"desc\": \"Estado, firmware update y panel de control: para configurar y operar remotamente todos tus dispositivos.\",\r\n                            \"minis\": [{\r\n                                    \"t\": \"Registro por QR\",\r\n                                    \"d\": \"Asoci\u00e1s el equipo a tu cuenta en segundos; queda habilitado para gesti\u00f3n en el ecosistema.\",\r\n                                    \"thumb\": \"\"\r\n                                },\r\n                                {\r\n                                    \"t\": \"Estado verificable\",\r\n                                    \"d\": \"Conectado\/desconectado, y lectura resumida de salud (red, conexiones activas, bater\u00eda, etc.).\",\r\n                                    \"thumb\": \"\"\r\n                                },\r\n                                {\r\n                                    \"t\": \"Actualizaciones remotas\",\r\n                                    \"d\": \"Detect\u00e1s equipos con update pendiente (pesta\u00f1a \u201cNeeds Update\u201d) y dispar\u00e1s FW Update sin cables.\",\r\n                                    \"thumb\": \"\"\r\n                                },\r\n                                {\r\n                                    \"t\": \"V\u00ednculo con garant\u00eda\/soporte\",\r\n                                    \"d\": \"El registro sirve como validaci\u00f3n de dispositivo dentro de AQA (lo que hace posible garant\u00eda y control de ciclo de vida).\",\r\n                                    \"thumb\": \"\"\r\n                                }\r\n                            ],\r\n                            \"video\": {\r\n                                \"src\": \"\/wp-content\/uploads\/compose-studio-my-devices-screen.mp4\",\r\n                                \"autoplay\": false,\r\n                                \"loop\": false,\r\n                                \"rateVar\": \"--cvx-cc-vrate-mydevice\"\r\n                            },\r\n                            \"hotspots\": [{\r\n                                    \"id\": \"hs_gear_play\",\r\n                                    \"action\": \"play\",\r\n                                    \"x\": 0.367,\r\n                                    \"y\": 0.414,\r\n                                    \"w\": 0.1,\r\n                                    \"h\": 0.05,\r\n                                    \"dxVar\": \"--cvx-cc-hs-gear-dx\",\r\n                                    \"dyVar\": \"--cvx-cc-hs-gear-dy\"\r\n                                },\r\n                                {\r\n                                    \"id\": \"hs_cubevox_fx\",\r\n                                    \"action\": \"goto\",\r\n                                    \"to\": \"cubeVox_workspace\",\r\n                                    \"x\": 0.06,\r\n                                    \"y\": 0.295,\r\n                                    \"w\": 0.40,\r\n                                    \"h\": 0.12,\r\n                                    \"dxVar\": \"--cvx-cc-hs-fx-dx\",\r\n                                    \"dyVar\": \"--cvx-cc-hs-fx-dy\"\r\n                                }\r\n                            ]\r\n                        },\r\n\r\n                        {\r\n                            \"id\": \"cubeVox_workspace\",\r\n                            \"orientation\": \"landscape\",\r\n                            \"kicker\": \"CUBEVOX WORKSPACE\",\r\n                            \"title\": \"Configur\u00e1 CubeVox como un sistema completo\",\r\n                            \"desc\": \"Este entorno es la consola integral del dispositivo: defin\u00eds entradas (CH1\/CH2, AUX, BT), salidas y m\u00f3dulos de expansi\u00f3n, y dej\u00e1s preparado el flujo con ruteos, cadenas y presets listos para tocar o producir.\",\r\n                            \"minis\": [{\r\n                                    \"t\": \"Entradas y fuentes\",\r\n                                    \"d\": \"Defin\u00eds qu\u00e9 entra y c\u00f3mo entra: canales de instrumento, auxiliar y fuentes digitales como Bluetooth, con el tipo de ruteo listo para el uso que necesit\u00e1s.\",\r\n                                    \"thumb\": \"\"\r\n                                },\r\n                                {\r\n                                    \"t\": \"Cadena y presets\",\r\n                                    \"d\": \"Arm\u00e1s la cadena por canal y guard\u00e1s configuraciones reutilizables, ideal para preparar bancos y volver a un sonido en segundos.\",\r\n                                    \"thumb\": \"\"\r\n                                },\r\n                                {\r\n                                    \"t\": \"Salidas y monitoreo\",\r\n                                    \"d\": \"Ajust\u00e1s c\u00f3mo sale el audio y c\u00f3mo te escuch\u00e1s: destinos, niveles y monitoreo para adaptar CubeVox al entorno sin reconfigurar toda la sesi\u00f3n.\",\r\n                                    \"thumb\": \"\"\r\n                                },\r\n                                {\r\n                                    \"t\": \"M\u00f3dulos y expansi\u00f3n\",\r\n                                    \"d\": \"Acced\u00e9s a configuraciones de m\u00f3dulos conectados y capacidades adicionales, integr\u00e1ndolos al flujo como parte del sistema y no como accesorios aislados.\",\r\n                                    \"thumb\": \"\"\r\n                                }\r\n                            ],\r\n                            \"img\": \"\/wp-content\/uploads\/compose-studio-fx-screen.webp\",\r\n                            \"hotspots\": [{\r\n                                \"id\": \"hs_ch1_remote\",\r\n                                \"action\": \"goto\",\r\n                                \"to\": \"input_settings\",\r\n                                \"x\": 0.278,\r\n                                \"y\": 0.75,\r\n                                \"w\": 0.06,\r\n                                \"h\": 0.2,\r\n                                \"dxVar\": \"--cvx-cc-hs-ch1-dx\",\r\n                                \"dyVar\": \"--cvx-cc-hs-ch1-dy\"\r\n                            }]\r\n                        },\r\n\r\n                        {\r\n                            \"id\": \"input_settings\",\r\n                            \"orientation\": \"landscape\",\r\n                            \"kicker\": \"INPUT SETTINGS\",\r\n                            \"title\": \"Calibr\u00e1 cada entrada para que el sonido responda\",\r\n                            \"desc\": \"Ajustes finos del front-end por canal: nivel, din\u00e1mica y protecci\u00f3n antes del DSP, para que la cadena y los presets se comporten de forma consistente y predecible.\",\r\n                            \"minis\": [{\r\n                                    \"t\": \"Selecci\u00f3n de canal\",\r\n                                    \"d\": \"Eleg\u00eds exactamente qu\u00e9 entrada est\u00e1s ajustando (por ejemplo CH1\/CH2) y trabaj\u00e1s sobre ese perfil sin afectar el resto del sistema.\",\r\n                                    \"thumb\": \"\"\r\n                                },\r\n                                {\r\n                                    \"t\": \"Auto Gain Control\",\r\n                                    \"d\": \"AGC para estabilizar la entrada cuando cambia la din\u00e1mica: mantiene un rango \u00fatil de nivel sin estar corrigiendo a mano en cada toma.\",\r\n                                    \"thumb\": \"\"\r\n                                },\r\n                                {\r\n                                    \"t\": \"Clip y protecci\u00f3n\",\r\n                                    \"d\": \"Defin\u00eds umbrales y comportamiento ante picos: detecci\u00f3n de clip y atenuaci\u00f3n autom\u00e1tica para evitar distorsi\u00f3n no deseada en el punto m\u00e1s cr\u00edtico del flujo.\",\r\n                                    \"thumb\": \"\"\r\n                                },\r\n                                {\r\n                                    \"t\": \"Ganancia y volumen\",\r\n                                    \"d\": \"Ajust\u00e1s gain y volumen del canal para llegar al DSP con headroom correcto y monitoreo controlado, dejando el input \u201cen su punto\u201d para tocar o grabar.\",\r\n                                    \"thumb\": \"\"\r\n                                }\r\n                            ],\r\n                            \"img\": \"\/wp-content\/uploads\/compose-studio-fx-remote-screen.webp\",\r\n                            \"hotspots\": [{\r\n                                \"id\": \"hs_remote_back_mydevice\",\r\n                                \"action\": \"goto\",\r\n                                \"to\": \"mydevice\",\r\n                                \"x\": 0.859,\r\n                                \"y\": 0.012,\r\n                                \"w\": 0.07,\r\n                                \"h\": 0.1\r\n                            }]\r\n                        },\r\n\r\n                        {\r\n                            \"id\": \"store\",\r\n                            \"orientation\": \"portrait\",\r\n                            \"kicker\": \"AQA STORE\",\r\n                            \"title\": \"Recursos listos para producir.\",\r\n                            \"desc\": \"Simplifica tus proyectos con nuestro cat\u00e1logo. Pod\u00e9s probar presets\/FX con una toma limpia de hasta 10 s de tu instrumento, elegir entre contenido gratuito o pago (AQA + Comunidad) y publicar tus propios recursos para monetizar..\",\r\n                            \"minis\": [{\r\n                                    \"t\": \"SAMPLES\",\r\n                                    \"d\": \"Biblioteca de sonidos listos para producir: preescuch\u00e1s, eleg\u00eds y guard\u00e1s packs en tu cuenta para usarlos en cualquier proyecto.\",\r\n                                    \"thumb\": \"\"\r\n                                },\r\n                                {\r\n                                    \"t\": \"EFFECTS\",\r\n                                    \"d\": \"Efectos y m\u00f3dulos para moldear el audio en tiempo real o en edici\u00f3n; pod\u00e9s compararlos antes de integrarlos a tu cadena.\",\r\n                                    \"thumb\": \"\"\r\n                                },\r\n                                {\r\n                                    \"t\": \"PRESETS\",\r\n                                    \"d\": \"Presets completos, listos para tu contexto: pod\u00e9s evaluarlos sobre tu toma limpia (hasta 10 s) para escuchar el resultado con tu instrumento y tu din\u00e1mica.\",\r\n                                    \"thumb\": \"\"\r\n                                },\r\n                                {\r\n                                    \"t\": \"TOOLS\",\r\n                                    \"d\": \"Herramientas que expanden funcionalidades: agregan capacidades nuevas a CubeVox y al flujo de Compose (no es solo \u201ccontenido\u201d, es ampliaci\u00f3n de sistema).\",\r\n                                    \"thumb\": \"\"\r\n                                }\r\n                            ],\r\n                            \"seq\": {\r\n                                \"frames\": [\r\n                                    \"\/wp-content\/uploads\/compose-studio-aqa-samples-screen.webp\",\r\n                                    \"\/wp-content\/uploads\/compose-studio-aqa-effects-screen.webp\",\r\n                                    \"\/wp-content\/uploads\/compose-studio-aqa-presets-screen.webp\",\r\n                                    \"\/wp-content\/uploads\/compose-studio-aqa-tools-screen.webp\"\r\n                                ],\r\n                                \"frameMs\": 1100\r\n                            }\r\n                        },\r\n\r\n                        {\r\n                            \"id\": \"settings\",\r\n                            \"orientation\": \"portrait\",\r\n                            \"kicker\": \"SETTINGS\",\r\n                            \"title\": \"Toda la configuraci\u00f3n en un solo lugar.\",\r\n                            \"desc\": \"Settings re\u00fane cada parametro configurable de manera clara: cuenta, preferencias de la app y la configuraci\u00f3n del dispositivo seleccionado.\",\r\n                            \"minis\": [{\r\n                                    \"t\": \"Cuenta y seguridad\",\r\n                                    \"d\": \"Administr\u00e1 perfil, acceso y plan, con controles de seguridad para que tu biblioteca, proyectos y dispositivos queden protegidos y bajo la misma cuenta.\",\r\n                                    \"thumb\": \"\"\r\n                                },\r\n                                {\r\n                                    \"t\": \"Preferencias de la app\",\r\n                                    \"d\": \"Ajust\u00e1 idioma, tema y notificaciones para adaptar Compose a tu forma de trabajo.\",\r\n                                    \"thumb\": \"\"\r\n                                },\r\n                                {\r\n                                    \"t\": \"Configuraci\u00f3n del dispositivo\",\r\n                                    \"d\": \"Ajust\u00e1 el equipo activo desde un panel ordenado: conectividad y estado, entradas y salidas, niveles y modos de operaci\u00f3n para dejarlo listo seg\u00fan tu setup.\"\r\n                                },\r\n                                {\r\n                                    \"t\": \"Privacidad y soporte\",\r\n                                    \"d\": \"Gestion\u00e1 privacidad y datos, consult\u00e1 informaci\u00f3n legal y acced\u00e9 a ayuda y soporte cuando lo necesites, sin salir del entorno de Compose.\"\r\n                                }\r\n                            ],\r\n                            \"video\": {\r\n                                \"src\": \"\/wp-content\/uploads\/compose-studio-product-settings-screen.mp4\",\r\n                                \"autoplay\": false,\r\n                                \"loop\": false,\r\n                                \"rateVar\": \"--cvx-cc-vrate-settings\"\r\n                            },\r\n                            \"hotspots\": [{\r\n                                \"id\": \"hs_settings_play\",\r\n                                \"action\": \"play\",\r\n                                \"x\": 0.834,\r\n                                \"y\": 0.10,\r\n                                \"w\": 0.12,\r\n                                \"h\": 0.06,\r\n                                \"dxVar\": \"--cvx-cc-hs-settings-dx\",\r\n                                \"dyVar\": \"--cvx-cc-hs-settings-dy\"\r\n                            }]\r\n                        }\r\n                    ]\r\n                },\r\n                \"cloud\": {\r\n                    \"modules\": {\r\n                        \"library\": {\r\n                            \"label\": \"Library\",\r\n                            \"title\": \"Tu library, siempre lista\",\r\n                            \"desc\": \"Tu colecci\u00f3n de presets, samples y tools, m\u00e1s versiones y backups para retomar un proyecto sin perder nada.\",\r\n                            \"hint\": \"Objetivo: recursos, versiones y backups en un solo lugar.\",\r\n                            \"items\": [{\r\n                                    \"t\": \"Colecci\u00f3n\",\r\n                                    \"s\": \"Presets \u00b7 samples \u00b7 tools guardados (tu inventario).\",\r\n                                    \"m1\": \"Organiz\u00e1\"\r\n                                },\r\n                                {\r\n                                    \"t\": \"Versiones\",\r\n                                    \"s\": \"Snapshots del proyecto \u00b7 comparar cambios \u00b7 restaurar.\",\r\n                                    \"m1\": \"Retom\u00e1\"\r\n                                },\r\n                                {\r\n                                    \"t\": \"Backups\",\r\n                                    \"s\": \"Resguardo autom\u00e1tico \u00b7 continuidad cuando la sesi\u00f3n importa.\",\r\n                                    \"m1\": \"Resguard\u00e1\"\r\n                                }\r\n                            ]\r\n                        },\r\n                        \"market\": {\r\n                            \"label\": \"AQA Store\",\r\n                            \"title\": \"Marketplace creativo, integrado al ecosistema.\",\r\n                            \"desc\": \"Descubr\u00ed recursos listos para producir (presets, samples y tools) y, cuando est\u00e9s listo, public\u00e1 tus propias creaciones gratis o a la venta para monetizar tu cuenta.\",\r\n                            \"hint\": \"Encuentra lo que necesitas o cr\u00e9alo y  publ\u00edcalo. AQA Store tambi\u00e9n es tu vidriera\",\r\n                            \"items\": [{\r\n                                    \"t\": \"Descubrir\",\r\n                                    \"s\": \"Cat\u00e1logo curado: AQA + comunidad, gratis y pago.\",\r\n                                    \"m1\": \"Explor\u00e1\"\r\n                                },\r\n                                {\r\n                                    \"t\": \"Probar\",\r\n                                    \"s\": \"Previews con referencia real, antes de adoptarlo.\",\r\n                                    \"m1\": \"Eleg\u00ed\"\r\n                                },\r\n                                {\r\n                                    \"t\": \"Publicar\",\r\n                                    \"s\": \"Sub\u00ed tus recursos y eleg\u00ed: contribuir o generar ganancias.\",\r\n                                    \"m1\": \"Cre\u00e1\"\r\n                                }\r\n                            ]\r\n                        },\r\n                        \"ops\": {\r\n                            \"label\": \"Oportunidades\",\r\n                            \"title\": \"Oportunidades para crecer\",\r\n                            \"desc\": \"Cuando un proyecto est\u00e1 listo para salir al mundo, AQA Cloud habilita visibilidad, colaboraci\u00f3n y mejora continua alrededor de tu trabajo\",\r\n                            \"hint\": \"Publicaci\u00f3n, colaboraci\u00f3n y mejora continua, en el mismo ecosistema.\",\r\n                            \"items\": [{\r\n                                    \"t\": \"Visibilidad\",\r\n                                    \"s\": \"Podr\u00e1s presentar y compartir tu trabajo con control y claridad.\",\r\n                                    \"m1\": \"Mostr\u00e1\"\r\n                                },\r\n                                {\r\n                                    \"t\": \"Colaboraci\u00f3n\",\r\n                                    \"s\": \"Permite sumar personas con permisos y coordinaci\u00f3n ordenada.\",\r\n                                    \"m1\": \"Conect\u00e1\"\r\n                                },\r\n                                {\r\n                                    \"t\": \"Crecimiento\",\r\n                                    \"s\": \"Con cada entrega mediante feedback y evoluci\u00f3n iterativa.\",\r\n                                    \"m1\": \"Mejor\u00e1\"\r\n                                }\r\n                            ]\r\n                        },\r\n                        \"sub\": {\r\n                            \"label\": \"Suscripci\u00f3n\",\r\n                            \"title\": \"Premium incluido por lanzamiento\",\r\n                            \"desc\": \"6 meses de acceso premium para explorar el ecosistema completo y validar el flujo en proyectos reales.\",\r\n                            \"hint\": \"Acceso gratis siempre disponible; tu eliges el plan que mejor se adapte.\",\r\n                            \"items\": [{\r\n                                    \"t\": \"Almacenamiento\",\r\n                                    \"s\": \"M\u00e1s espacio para proyectos y recursos, pensado para sesiones largas.\",\r\n                                    \"m1\": \"Ampli\u00e1\"\r\n                                },\r\n                                {\r\n                                    \"t\": \"Herramientas premium\",\r\n                                    \"s\": \"Versiones y accesos avanzados, m\u00e1s tools\/FX exclusivos.\",\r\n                                    \"m1\": \"Desbloque\u00e1\"\r\n                                },\r\n                                {\r\n                                    \"t\": \"Beneficios\",\r\n                                    \"s\": \"Acceso a mejoras y beneficios del ecosistema, seg\u00fan tu plan.\",\r\n                                    \"m1\": \"Acced\u00e9\"\r\n                                }\r\n                            ]\r\n                        }\r\n                    }\r\n                }\r\n            }\r\n        <\/script>\r\n\r\n        <style>\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"][data-cvx-cc-phone-shell=\"off\"] .cvxCCPhoneStage {\r\n                border: 0 !important;\r\n                background: transparent !important;\r\n                box-shadow: none !important;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"][data-cvx-cc-phone-shell=\"off\"] .cvxCCPhoneStage::before {\r\n                opacity: 0 !important;\r\n            }\r\n\r\n            \/* =========================================================\r\n         COMPONENT: Compose & Cloud\r\n         Scope: .cvxScope [data-cvx-root=\"compose-cloud\"]\r\n         Requires: Starter Kit loaded globally.\r\n      ========================================================= *\/\r\n\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"] {\r\n                \/* Derived vars (switch by layout state) *\/\r\n                --cvxS: var(--cvx-cc-s-d);\r\n                --cvx-cc-panel-pad: var(--cvx-cc-panel-pad-d);\r\n                --cvx-cc-panel-gap: var(--cvx-cc-panel-gap-d);\r\n                --cvx-cc-compose-gap: var(--cvx-cc-compose-gap-d);\r\n                --cvx-cc-cloud-gap: var(--cvx-cc-cloud-gap-d);\r\n                --cvx-cc-sec-head-on: var(--cvx-cc-sec-head-on-d);\r\n                --cvx-cc-sec-gap: var(--cvx-cc-sec-gap-d);\r\n                --cvx-cc-lan-screen-scale: var(--cvx-cc-lan-screen-scale-d);\r\n                --cvx-cc-por-screen-scale: var(--cvx-cc-por-screen-scale-d);\r\n                --cvx-cc-head-on: var(--cvx-cc-head-on-d);\r\n                --cvx-cc-dot-size: var(--cvx-cc-dot-size-d);\r\n                --cvx-cc-dot-gap: var(--cvx-cc-dot-gap-d);\r\n\r\n                --cvx-cc-phone-w: var(--cvx-cc-phone-w-d);\r\n                --cvx-cc-stage-h-por: var(--cvx-cc-phone-stage-h-por-d);\r\n                --cvx-cc-stage-h-lan: var(--cvx-cc-phone-stage-h-lan-d);\r\n                --cvx-cc-lan-scale: var(--cvx-cc-lan-scale-d);\r\n                --cvx-cc-lan-tx: var(--cvx-cc-lan-tx-d);\r\n                --cvx-cc-lan-ty: var(--cvx-cc-lan-ty-d);\r\n                --cvx-cc-head-bg: var(--cvx-cc-compose-head-bg-d);\r\n                --cvx-cc-mini-bg: var(--cvx-cc-mini-bg-d);\r\n                --cvx-cc-mini-stroke: var(--cvx-cc-mini-stroke-d);\r\n                --cvx-cc-mini-glow-a: var(--cvx-cc-mini-glow-a-d);\r\n                --cvx-cc-minis-top-gap: var(--cvx-cc-minis-top-gap-d);\r\n                --cvx-cc-minis-gap: var(--cvx-cc-minis-gap-d);\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"][data-cvx-cc-layout=\"stack\"] {\r\n                --cvxS: var(--cvx-cc-s-m);\r\n                --cvx-cc-panel-pad: var(--cvx-cc-panel-pad-m);\r\n                --cvx-cc-panel-gap: var(--cvx-cc-panel-gap-m);\r\n                --cvx-cc-compose-gap: var(--cvx-cc-compose-gap-m);\r\n                --cvx-cc-cloud-gap: var(--cvx-cc-cloud-gap-m);\r\n                --cvx-cc-sec-head-on: var(--cvx-cc-sec-head-on-m);\r\n                --cvx-cc-sec-gap: var(--cvx-cc-sec-gap-m);\r\n                --cvx-cc-lan-screen-scale: var(--cvx-cc-lan-screen-scale-m);\r\n                --cvx-cc-por-screen-scale: var(--cvx-cc-por-screen-scale-m);\r\n                --cvx-cc-head-on: var(--cvx-cc-head-on-m);\r\n                --cvx-cc-dot-size: var(--cvx-cc-dot-size-m);\r\n                --cvx-cc-dot-gap: var(--cvx-cc-dot-gap-m);\r\n\r\n                --cvx-cc-phone-w: var(--cvx-cc-phone-w-m);\r\n                --cvx-cc-stage-h-por: var(--cvx-cc-phone-stage-h-por-m);\r\n                --cvx-cc-stage-h-lan: var(--cvx-cc-phone-stage-h-lan-m);\r\n                --cvx-cc-lan-scale: var(--cvx-cc-lan-scale-m);\r\n                --cvx-cc-lan-tx: var(--cvx-cc-lan-tx-m);\r\n                --cvx-cc-lan-ty: var(--cvx-cc-lan-ty-m);\r\n                --cvx-cc-head-bg: var(--cvx-cc-compose-head-bg-m);\r\n                --cvx-cc-mini-bg: var(--cvx-cc-mini-bg-m);\r\n                --cvx-cc-mini-stroke: var(--cvx-cc-mini-stroke-m);\r\n                --cvx-cc-mini-glow-a: var(--cvx-cc-mini-glow-a-m);\r\n                --cvx-cc-minis-top-gap: var(--cvx-cc-minis-top-gap-m);\r\n                --cvx-cc-minis-gap: var(--cvx-cc-minis-gap-m);\r\n            }\r\n\r\n            \/* =========================================================\r\n         Panel wrapper\r\n      ========================================================= *\/\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"] .cvxCCStack {\r\n                display: grid;\r\n                gap: calc(var(--cvx-cc-panel-gap) * var(--cvxS));\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"] .cvxPanel {\r\n                padding: calc(var(--cvx-cc-panel-pad) * var(--cvxS));\r\n            }\r\n\r\n            \/* =========================================================\r\n         SECTION HEADS (static)\r\n         - Toggle with --cvx-cc-sec-head-on-*\r\n      ========================================================= *\/\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"] .cvxCCSectionHead {\r\n                display: grid;\r\n                gap: calc(var(--cvx-cc-sec-gap) * var(--cvxS));\r\n                margin-bottom: calc(var(--cvx-cc-panel-gap) * var(--cvxS));\r\n                opacity: calc(.10 + (var(--cvx-cc-sec-head-on) * .90));\r\n                max-height: calc(var(--cvx-cc-sec-head-on) * 420px);\r\n                overflow: hidden;\r\n                transition: max-height .22s ease, opacity .22s ease;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"] .cvxCCSectionHead .cvxTags {\r\n                margin-top: calc(2px * var(--cvxS));\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"] .cvxCCSectionHead .cvxTitle {\r\n                margin: 0;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"] .cvxCCSectionHead .cvxDesc {\r\n                margin: 0;\r\n            }\r\n\r\n            \/* =========================================================\r\n         COMPOSE layout (single panel)\r\n      ========================================================= *\/\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"] .cvxCCCompose {\r\n                display: grid;\r\n                gap: calc(var(--cvx-cc-compose-gap) * var(--cvxS));\r\n                grid-template-columns: 1.05fr .95fr;\r\n                align-items: start;\r\n                grid-template-areas: \"story phone\";\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"] .cvxCCStory {\r\n                grid-area: story;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"] .cvxCCPhoneCol {\r\n                grid-area: phone;\r\n            }\r\n\r\n            \/* Stack (mobile) *\/\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"][data-cvx-cc-layout=\"stack\"] .cvxCCCompose {\r\n                grid-template-columns: 1fr;\r\n                grid-template-areas: \"story\" \"phone\";\r\n            }\r\n\r\n            \/* Landscape screen: move story above phone to avoid cramped rotated layout *\/\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"][data-cvx-cc-orient=\"landscape\"] .cvxCCCompose {\r\n                grid-template-columns: 1fr;\r\n                grid-template-areas: \"story\" \"phone\";\r\n            }\r\n\r\n            \/* =========================================================\r\n         Story header (dynamic) + controls\r\n      ========================================================= *\/\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"] .cvxCCHead {\r\n                display: grid;\r\n                gap: calc(10px * var(--cvxS));\r\n                margin-bottom: calc(12px * var(--cvxS));\r\n\r\n                \/* Collapsible via --cvx-cc-head-on *\/\r\n                max-height: calc(var(--cvx-cc-head-on) * 520px);\r\n                opacity: calc(.15 + (var(--cvx-cc-head-on) * .85));\r\n                transform: translateY(calc((1 - var(--cvx-cc-head-on)) * -6px));\r\n                overflow: hidden;\r\n                transition: max-height .22s ease, opacity .22s ease, transform .22s ease;\r\n            }\r\n\r\n            \/* Minis dentro del head card (unidad narrativa) *\/\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"] .cvxCCHead {\r\n                background: var(--cvx-cc-head-bg);\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"] .cvxCCStory {\r\n                height: auto !important;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"] .cvxCCHead {\r\n                height: auto !important;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"] .cvxCCHead .cvxCCMinis {\r\n                margin-top: calc(var(--cvx-cc-minis-top-gap) * var(--cvxS));\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"] .cvxCCHead .cvxCCMini {\r\n                background: var(--cvx-cc-mini-bg);\r\n                border-color: var(--cvx-cc-mini-stroke);\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"] .cvxCCHead .cvxCCMini::before {\r\n                opacity: var(--cvx-cc-mini-glow-a);\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"] .cvxCCHeadTop {\r\n                display: flex;\r\n                align-items: center;\r\n                justify-content: space-between;\r\n                gap: calc(18px * var(--cvxS));\r\n                flex-wrap: wrap;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"] .cvxCCControls {\r\n                display: flex;\r\n                gap: calc(8px * var(--cvxS));\r\n                align-items: center;\r\n                flex-wrap: wrap;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"] .cvxCCControls .cvxPill {\r\n                cursor: pointer;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"] .cvxCCControls .cvxPill.is-off {\r\n                opacity: .78;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"] .cvxCCScreenTitle {\r\n                margin: 0;\r\n                font-size: calc(18px * var(--cvxS));\r\n                line-height: 1.12;\r\n                color: var(--cvxText);\r\n                letter-spacing: -.01em;\r\n                margin: calc(10px * var(--cvxS)) 0 calc(8px * var(--cvxS)) 0 !important;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"] .cvxCCScreenDesc {\r\n                margin: 0;\r\n                font-size: calc(12px * var(--cvxS));\r\n                line-height: 1.55;\r\n                color: var(--cvxMuted);\r\n            }\r\n\r\n            \/* =========================================================\r\n         Mini cards (dynamic)\r\n      ========================================================= *\/\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"] .cvxCCMinis {\r\n                --cvx-cc-min-cols: var(--cvx-cc-min-cols-wide-por);\r\n                display: grid;\r\n                gap: calc(var(--cvx-cc-minis-gap) * var(--cvxS));\r\n                grid-template-columns: repeat(var(--cvx-cc-min-cols), minmax(0, 1fr));\r\n            }\r\n\r\n            \/* Landscape: 2x2 suggestion *\/\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"][data-cvx-cc-orient=\"landscape\"] .cvxCCMinis {\r\n                --cvx-cc-min-cols: var(--cvx-cc-min-cols-wide-lan);\r\n            }\r\n\r\n            \/* Stack: single column *\/\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"][data-cvx-cc-layout=\"stack\"] .cvxCCMinis {\r\n                --cvx-cc-min-cols: var(--cvx-cc-min-cols-stack);\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"] .cvxCCMini {\r\n                display: flex;\r\n                align-items: center;\r\n                justify-content: space-between;\r\n                gap: calc(12px * var(--cvxS));\r\n                padding: calc(10px * var(--cvxS)) calc(12px * var(--cvxS));\r\n                border-radius: var(--cvxRadiusMD);\r\n                border: 1px solid rgba(255, 255, 255, .12);\r\n                background: rgba(0, 0, 0, .18);\r\n                position: relative;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"] .cvxCCMini::before {\r\n                content: \"\";\r\n                position: absolute;\r\n                inset: 0;\r\n                border-radius: inherit;\r\n                pointer-events: none;\r\n                background: radial-gradient(120% 160% at 20% 0%, color-mix(in srgb, var(--cvxAccent) 14%, transparent), transparent 55%);\r\n                opacity: .75;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"] .cvxCCMini .t {\r\n                position: relative;\r\n                z-index: 1;\r\n                min-width: 0;\r\n                display: grid;\r\n                gap: calc(4px * var(--cvxS));\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"] .cvxCCMini .t b {\r\n                font-size: calc(13px * var(--cvxS));\r\n                letter-spacing: .1px;\r\n                color: rgba(255, 255, 255, .92);\r\n                white-space: nowrap;\r\n                overflow: hidden;\r\n                text-overflow: ellipsis;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"] .cvxCCMini .t span {\r\n                font-size: calc(12px * var(--cvxS));\r\n                color: rgba(255, 255, 255, .65);\r\n                line-height: 1.35;\r\n                display: -webkit-box;\r\n                -webkit-line-clamp: 2;\r\n                -webkit-box-orient: vertical;\r\n                overflow: hidden;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"] .cvxCCMini .thumb {\r\n                position: relative;\r\n                z-index: 1;\r\n                width: calc(48px * var(--cvxS));\r\n                height: calc(36px * var(--cvxS));\r\n                border-radius: calc(10px * var(--cvxS));\r\n                border: 1px solid rgba(255, 255, 255, .12);\r\n                background: rgba(0, 0, 0, .22);\r\n                overflow: hidden;\r\n                flex: 0 0 auto;\r\n                display: none;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"] .cvxCCMini .thumb img {\r\n                width: 100%;\r\n                height: 100%;\r\n                object-fit: cover;\r\n                object-position: 50% 50%;\r\n                display: block;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"] .cvxCCMini[data-has-thumb=\"1\"] .thumb {\r\n                display: block;\r\n            }\r\n\r\n            \/* =========================================================\r\n         Phone stage (single mockup + rotating rig)\r\n      ========================================================= *\/\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"] .cvxCCPhoneCol {\r\n                display: grid;\r\n                gap: calc(2px * var(--cvxS));\r\n                justify-items: center;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"] .cvxCCPhoneStage {\r\n                width: 100%;\r\n                height: var(--cvx-cc-stage-h-por);\r\n                border-radius: var(--cvxRadiusLG);\r\n                border: 1px solid rgba(255, 255, 255, .10);\r\n                background: rgba(0, 0, 0, .14);\r\n                box-shadow: var(--cvxShadowMD);\r\n                position: relative;\r\n                overflow: visible;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"][data-cvx-cc-orient=\"landscape\"] .cvxCCPhoneStage {\r\n                height: var(--cvx-cc-stage-h-lan);\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"] .cvxCCPhoneStage::before {\r\n                content: \"\";\r\n                position: absolute;\r\n                inset: -140px;\r\n                pointer-events: none;\r\n                background:\r\n                    radial-gradient(700px 280px at 20% 10%, color-mix(in srgb, var(--cvxAccent) 16%, transparent), transparent 62%),\r\n                    radial-gradient(700px 280px at 85% 60%, color-mix(in srgb, var(--cvxAccent) 10%, transparent), transparent 62%);\r\n                opacity: .85;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"] .cvxCCPhoneRig {\r\n                position: absolute;\r\n                left: 50%;\r\n                top: 47%;\r\n                width: var(--cvx-cc-phone-w);\r\n                transform: translate(-50%, -50%) scale(var(--cvx-cc-rig-fit-scale, 1));\r\n                transform-origin: 50% 50%;\r\n                will-change: transform;\r\n                transition: transform .22s cubic-bezier(.2, .8, .2, 1);\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"][data-cvx-cc-orient=\"landscape\"] .cvxCCPhoneRig {\r\n                transform:\r\n                    translate(-50%, -50%) translate(var(--cvx-cc-lan-tx), var(--cvx-cc-lan-ty)) rotate(var(--cvx-cc-lan-rot)) scale(calc(var(--cvx-cc-lan-scale) * var(--cvx-cc-rig-fit-scale, 1)));\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"] .cvxCCViewport {\r\n                position: absolute;\r\n                inset: calc(var(--cvx-cc-inset-por-y) + var(--cvx-cc-inset-por-dy)) calc(var(--cvx-cc-inset-por-x) + var(--cvx-cc-inset-por-dx)) calc(var(--cvx-cc-inset-por-y) + var(--cvx-cc-inset-por-dy)) calc(var(--cvx-cc-inset-por-x) + var(--cvx-cc-inset-por-dx));\r\n                \/* sin \u201ccaja\u201d visible *\/\r\n                background: transparent;\r\n                border: 0;\r\n                border-radius: 0;\r\n\r\n                \/* sigue recortando dentro del hueco del frame *\/\r\n                overflow: hidden;\r\n            }\r\n\r\n\r\n            \/* =========================================================\r\n   HOTSPOTS (radar + tap)\r\n========================================================= *\/\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"] .cvxCCHotspots {\r\n                position: absolute;\r\n\r\n                \/* Misma geometr\u00eda que el viewport (portrait) *\/\r\n                inset:\r\n                    calc(var(--cvx-cc-inset-por-y) + var(--cvx-cc-inset-por-dy)) calc(var(--cvx-cc-inset-por-x) + var(--cvx-cc-inset-por-dx)) calc(var(--cvx-cc-inset-por-y) + var(--cvx-cc-inset-por-dy)) calc(var(--cvx-cc-inset-por-x) + var(--cvx-cc-inset-por-dx));\r\n\r\n                z-index: 6;\r\n                \/* arriba del frame (.cvxCCFrame tiene 5) *\/\r\n                pointer-events: none;\r\n                overflow: visible;\r\n                \/* permite que los radares desborden del host *\/\r\n            }\r\n\r\n            \/* Hide hotspots while a clip is playing (radar off) *\/\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"] .cvxCCHotspots[data-hide=\"1\"] {\r\n                display: none !important;\r\n            }\r\n\r\n            \/* Alineaci\u00f3n con el contenido en landscape (igual que .cvxCCScreen) *\/\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"][data-cvx-cc-orient=\"landscape\"] .cvxCCHotspots {\r\n                inset:\r\n                    calc(var(--cvx-cc-inset-lan-y) + var(--cvx-cc-inset-lan-dy)) calc(var(--cvx-cc-inset-lan-x) + var(--cvx-cc-inset-lan-dx)) calc(var(--cvx-cc-inset-lan-y) + var(--cvx-cc-inset-lan-dy)) calc(var(--cvx-cc-inset-lan-x) + var(--cvx-cc-inset-lan-dx));\r\n\r\n                transform: rotate(-90deg) scale(var(--cvx-cc-lan-screen-scale));\r\n                transform-origin: 50% 50%;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"] .cvxCCHs {\r\n                position: absolute;\r\n                pointer-events: auto;\r\n                border: 0;\r\n                background: transparent;\r\n                padding: 0;\r\n                cursor: pointer;\r\n                border-radius: 999px;\r\n                -webkit-tap-highlight-color: transparent;\r\n                overflow: visible;\r\n\r\n                \/* look del anillo base (similar a portable-studio) *\/\r\n                box-shadow:\r\n                    0 0 0 1px rgb(0 0 0 \/ 0.55) inset,\r\n                    0 0 0 2px rgb(255 255 255 \/ 0.10),\r\n                    0 0 28px color-mix(in srgb, var(--cvxAccent) 32%, transparent),\r\n                    0 0 60px color-mix(in srgb, var(--cvxAccent) 18%, transparent);\r\n\r\n                will-change: transform, opacity;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"] .cvxCCHs::before,\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"] .cvxCCHs::after {\r\n                content: \"\";\r\n                position: absolute;\r\n                inset: 0;\r\n                border-radius: 999px;\r\n                pointer-events: none;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"] .cvxCCHs::before {\r\n                \/* anillo visible\/blanco + leve tinte *\/\r\n                border: 1px solid rgb(255 255 255 \/ 0.62);\r\n                background:\r\n                    radial-gradient(circle at 50% 50%,\r\n                        color-mix(in srgb, var(--cvxAccent) 14%, transparent) 0%,\r\n                        color-mix(in srgb, var(--cvxAccent) 8%, transparent) 58%,\r\n                        transparent 78%);\r\n            }\r\n\r\n            @keyframes cvxHsPulse {\r\n                0% {\r\n                    opacity: .88;\r\n                    transform: scale(.98);\r\n                }\r\n\r\n                65% {\r\n                    opacity: 0;\r\n                    transform: scale(1.55);\r\n                }\r\n\r\n                100% {\r\n                    opacity: 0;\r\n                    transform: scale(1.55);\r\n                }\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"] .cvxCCHs::after {\r\n                inset: -4px;\r\n                \/* pulso nace desde el per\u00edmetro *\/\r\n                border: 1px solid color-mix(in srgb, var(--cvxAccent) 72%, transparent);\r\n\r\n                box-shadow:\r\n                    0 0 18px color-mix(in srgb, var(--cvxAccent) 25%, transparent),\r\n                    0 0 48px color-mix(in srgb, var(--cvxAccent) 14%, transparent);\r\n\r\n                opacity: 0;\r\n                transform: scale(.96);\r\n                animation: cvxHsPulse 2.2s ease-out infinite;\r\n            }\r\n\r\n            @media (prefers-reduced-motion: reduce) {\r\n                .cvxScope [data-cvx-root=\"compose-cloud\"] .cvxCCHs::after {\r\n                    animation: none !important;\r\n                }\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"][data-cvx-cc-orient=\"landscape\"] .cvxCCViewport {\r\n                inset: calc(var(--cvx-cc-inset-lan-y) + var(--cvx-cc-inset-lan-dy)) calc(var(--cvx-cc-inset-lan-x) + var(--cvx-cc-inset-lan-dx)) calc(var(--cvx-cc-inset-lan-y) + var(--cvx-cc-inset-lan-dy)) calc(var(--cvx-cc-inset-lan-x) + var(--cvx-cc-inset-lan-dx));\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"][data-cvx-cc-orient=\"landscape\"] .cvxCCViewport {\r\n                transform: rotate(-90deg) scale(var(--cvx-cc-lan-screen-scale));\r\n                transform-origin: 50% 50%;\r\n            }\r\n\r\n\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"] .cvxCCScreen {\r\n                position: absolute;\r\n                inset: 0;\r\n                width: 100%;\r\n                height: 100%;\r\n                object-fit: var(--cvx-cc-media-fit-por);\r\n                object-position: var(--cvx-cc-media-pos-por);\r\n                opacity: 0;\r\n                transition: opacity .22s cubic-bezier(.2, .8, .2, 1);\r\n                will-change: opacity;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"][data-cvx-cc-orient=\"portrait\"] .cvxCCScreen {\r\n                transform: scale(var(--cvx-cc-por-screen-scale));\r\n                transform-origin: 50% 50%;\r\n            }\r\n\r\n            \/* Portrait clips: show full UI (no crop top\/bottom) *\/\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"][data-cvx-cc-orient=\"portrait\"] video.cvxCCScreen {\r\n                object-fit: contain;\r\n                background: #000;\r\n                \/* dentro de la pantalla, no \u201ccaja\u201d *\/\r\n            }\r\n\r\n            \/* Landscape images: avoid center-slice caused by cover *\/\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"][data-cvx-cc-orient=\"landscape\"] img.cvxCCScreen {\r\n                object-fit: contain;\r\n                background: #000;\r\n            }\r\n\r\n\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"] .cvxCCScreen[data-on=\"1\"] {\r\n                opacity: 1;\r\n            }\r\n\r\n            \/* When the phone rig rotates to landscape, keep the screen content upright *\/\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"][data-cvx-cc-orient=\"landscape\"] .cvxCCScreen {\r\n                transform: none;\r\n                object-fit: var(--cvx-cc-media-fit-lan);\r\n                object-position: var(--cvx-cc-media-pos-lan);\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"] .cvxCCFrame {\r\n                width: 100%;\r\n                height: auto;\r\n                display: block;\r\n                position: relative;\r\n                z-index: 5;\r\n                pointer-events: none;\r\n                filter: drop-shadow(0 18px 40px rgba(0, 0, 0, .55));\r\n            }\r\n\r\n            \/* =========================================================\r\n         Dots (kept below the phone)\r\n      ========================================================= *\/\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"] .cvxCCDots {\r\n                display: flex;\r\n                gap: var(--cvx-cc-dot-gap);\r\n                align-items: center;\r\n                justify-content: center;\r\n                user-select: none;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"] .cvxCCDots>button {\r\n                width: var(--cvx-cc-dot-size);\r\n                height: var(--cvx-cc-dot-size);\r\n                padding: 0;\r\n                border-radius: 999px;\r\n                border: 1px solid rgba(255, 255, 255, .16);\r\n                background: rgba(255, 255, 255, .10);\r\n                cursor: pointer;\r\n                transition: transform .18s ease, background .18s ease, border-color .18s ease;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"] .cvxCCDots>button[aria-current=\"true\"] {\r\n                background: color-mix(in srgb, var(--cvxAccent) 55%, rgba(255, 255, 255, .10));\r\n                border-color: color-mix(in srgb, var(--cvxAccent) 42%, rgba(255, 255, 255, .16));\r\n                transform: scale(1.22);\r\n            }\r\n\r\n            .cvxCCDots {\r\n                margin-bottom: calc(50px * var(--cvxS));\r\n            }\r\n\r\n            \/* =========================================================\r\n         CLOUD: flow card (match first version proportions)\r\n      ========================================================= *\/\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"] .cvxCCFlowTop {\r\n                display: flex;\r\n                align-items: flex-start;\r\n                justify-content: space-between;\r\n                gap: calc(12px * var(--cvxS));\r\n                flex-wrap: wrap;\r\n                margin-bottom: calc(6px * var(--cvxS));\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"] .cvxCCFlowH {\r\n                margin: 0;\r\n                font-size: calc(16px * var(--cvxS));\r\n                letter-spacing: -.01em;\r\n                color: rgba(255, 255, 255, .92);\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"] .cvxCCFlowP {\r\n                margin: 0;\r\n                font-size: calc(12px * var(--cvxS));\r\n                color: rgba(255, 255, 255, .62);\r\n                line-height: 1.45;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"] .cvxCCFlowChip {\r\n                cursor: default;\r\n                user-select: none;\r\n                pointer-events: none;\r\n            }\r\n\r\n            \/* Node rows like the original version *\/\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"] .cvxCCNodeRow {\r\n                padding: calc(12px * var(--cvxS)) calc(12px * var(--cvxS));\r\n                border-radius: var(--cvxRadiusLG);\r\n                border: 1px solid rgba(255, 255, 255, .12);\r\n                background: rgba(0, 0, 0, .16);\r\n                position: relative;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"] .cvxCCNodeRow+.cvxCCNodeRow::after {\r\n                content: \"\";\r\n                position: absolute;\r\n                left: calc(27px * var(--cvxS));\r\n                top: calc(-10px * var(--cvxS));\r\n                width: 2px;\r\n                height: calc(10px * var(--cvxS));\r\n                background: color-mix(in srgb, var(--cvxAccent) 28%, rgba(255, 255, 255, .10));\r\n                box-shadow: 0 0 18px color-mix(in srgb, var(--cvxAccent) 22%, transparent);\r\n                opacity: .9;\r\n            }\r\n\r\n            \/* =========================================================\r\n         CLOUD layout (single panel)\r\n      ========================================================= *\/\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"] .cvxCCCloud {\r\n                display: grid;\r\n                gap: calc(var(--cvx-cc-cloud-gap) * var(--cvxS));\r\n                grid-template-columns: .95fr 1.05fr;\r\n                align-items: start;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"][data-cvx-cc-layout=\"stack\"] .cvxCCCloud {\r\n                grid-template-columns: 1fr;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"] .cvxCCFlow {\r\n                display: grid;\r\n                gap: calc(10px * var(--cvxS));\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"] .cvxCCNode {\r\n                display: grid;\r\n                grid-template-columns: auto 1fr auto;\r\n                align-items: center;\r\n                gap: calc(12px * var(--cvxS));\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"] .cvxCCNode .ic {\r\n                width: calc(34px * var(--cvxS));\r\n                height: calc(34px * var(--cvxS));\r\n                border-radius: calc(12px * var(--cvxS));\r\n                border: 1px solid rgba(255, 255, 255, .14);\r\n                background: linear-gradient(180deg, rgba(255, 255, 255, .08), rgba(0, 0, 0, .28));\r\n                display: grid;\r\n                place-items: center;\r\n                box-shadow: 0 10px 24px rgba(0, 0, 0, .35);\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"] .cvxCCNode .tt {\r\n                min-width: 0;\r\n                display: grid;\r\n                gap: calc(4px * var(--cvxS));\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"] .cvxCCNode .tt b {\r\n                font-size: calc(13px * var(--cvxS));\r\n                white-space: nowrap;\r\n                overflow: hidden;\r\n                text-overflow: ellipsis;\r\n                color: rgba(255, 255, 255, .92);\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"] .cvxCCNode .tt span {\r\n                font-size: calc(12px * var(--cvxS));\r\n                color: rgba(255, 255, 255, .62);\r\n                white-space: nowrap;\r\n                overflow: hidden;\r\n                text-overflow: ellipsis;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"] .cvxCCList {\r\n                display: grid;\r\n                gap: calc(10px * var(--cvxS));\r\n                margin-top: calc(6px * var(--cvxS));\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"] .cvxCCItem {\r\n                display: flex;\r\n                align-items: center;\r\n                justify-content: space-between;\r\n                gap: calc(10px * var(--cvxS));\r\n                padding: calc(10px * var(--cvxS)) calc(12px * var(--cvxS));\r\n                border-radius: var(--cvxRadiusMD);\r\n                border: 1px solid rgba(255, 255, 255, .12);\r\n                background: rgba(0, 0, 0, .18);\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"] .cvxCCMeta {\r\n                display: flex;\r\n                gap: calc(8px * var(--cvxS));\r\n                white-space: nowrap;\r\n            }\r\n\r\n            .cvxScope [data-cvx-root=\"compose-cloud\"] .cvxCCStory>.cvxCard.cvxCCHead {\r\n                display: flex !important;\r\n                flex-direction: column !important;\r\n\r\n                \/* el alto lo define el contenido *\/\r\n                height: fit-content !important;\r\n                max-height: none !important;\r\n\r\n                \/* no recortes internos del contenido *\/\r\n                overflow: visible !important;\r\n            }\r\n\r\n            #compose,\r\n            #cloud {\r\n                scroll-margin-top: 60px;\r\n                \/* 50px de men\u00fa + 10px de aire *\/\r\n            }\r\n\r\n            .cvxScope .cvxCCFlowTitle {\r\n                display: flex;\r\n                flex-wrap: wrap;\r\n                align-items: center;\r\n                gap: var(--cvx-cc-flow-title-gap, 12px);\r\n            }\r\n\r\n            .cvxScope .cvxCCFlowTitle .cvxCCFlowH {\r\n                margin: 0;\r\n            }\r\n\r\n            .cvxScope .cvxCCFlowTitle .cvxCCFlowChip {\r\n                margin-left: auto;\r\n            }\r\n\r\n            .cvxScope .cvxCCFlowTitle .cvxCCFlowP {\r\n                flex-basis: 100%;\r\n                margin-top: var(--cvx-cc-flow-title-p-mt, 8px);\r\n            }\r\n\r\n            \/* Reduced motion *\/\r\n            @media (prefers-reduced-motion: reduce) {\r\n\r\n                .cvxScope [data-cvx-root=\"compose-cloud\"] .cvxCCPhoneRig,\r\n                .cvxScope [data-cvx-root=\"compose-cloud\"] .cvxCCScreen,\r\n                .cvxScope [data-cvx-root=\"compose-cloud\"] .cvxCCHead,\r\n                .cvxScope [data-cvx-root=\"compose-cloud\"] .cvxCCDots>button {\r\n                    transition: none !important;\r\n                }\r\n\r\n                .cvxScope [data-cvx-root=\"compose-cloud\"][data-cvx-cc-orient=\"landscape\"] .cvxCCScreen {\r\n                    transform: none !important;\r\n                }\r\n            }\r\n        <\/style>\r\n\r\n        <div class=\"cvxCCStack\">\r\n\r\n            <!-- =====================================================\r\n           COMPOSE (panel only; external Elementor handles main kicker\/title\/subtitle)\r\n           ===================================================== -->\r\n            <div id=\"compose\" class=\"cvxPanel\" data-cvx-cc-panel=\"compose\">\r\n                <header class=\"cvxCCSectionHead\" data-cvx-cc-sec=\"compose\">\r\n                    <div class=\"cvxKicker\">COMPOSE STUDIO APP<\/div>\r\n                    <h3 class=\"cvxTitle\">Edit\u00e1 y control\u00e1 tus proyectos, desde cualquier dispositivo.<\/h3>\r\n                    <p class=\"cvxDesc\">Compose App expande la experiencia y te da el control: <b>edici\u00f3n multipista<\/b>, <b>gesti\u00f3n de tomas y presets<\/b> y conexi\u00f3n con <b>AQA Cloud<\/b> para tener tus sesiones <b>sincronizadas<\/b>, <b>con historial de cambios<\/b> y listas para <b>compartir o colaborar<\/b>\r\n                    <\/p>\r\n                    <div class=\"cvxTags\">\r\n                        <span class=\"cvxTag\">Multipista<\/span>\r\n                        <span class=\"cvxTag\">Presets<\/span>\r\n                        <span class=\"cvxTag\">Control remoto<\/span>\r\n                        <span class=\"cvxTag\">Sync r\u00e1pido<\/span>\r\n                    <\/div>\r\n                <\/header>\r\n\r\n                <div class=\"cvxCCCompose\">\r\n\r\n                    <!-- Story column (dynamic kicker\/title\/desc + controls + mini cards) -->\r\n                    <div class=\"cvxCCStory\">\r\n\r\n                        <div class=\"cvxCard cvxCCHead\" data-cvx-cc-head>\r\n                            <div class=\"cvxCCHeadTop\">\r\n                                <div class=\"cvxTip\" style=\"--tip-font-size:12px; --tip-pad-y:10px; --tip-pad-x:14px;\">\r\n                                    <span class=\"cvxTip__dot\" aria-hidden=\"true\"><\/span>\r\n                                    <span class=\"cvxTip__label\" data-cvx-cc-kicker>CAPTURA \u2192 ORDEN<\/span>\r\n                                    <span class=\"cvxTip__text\" data-cvx-cc-step>1\/3<\/span>\r\n                                <\/div>\r\n\r\n                                <div class=\"cvxCCControls\" aria-label=\"Controles de Compose\">\r\n                                    <button class=\"cvxPill\" type=\"button\" data-cvx-cc-action=\"prev\">Anterior<\/button>\r\n                                    <button class=\"cvxPill\" type=\"button\" data-cvx-cc-action=\"next\">Siguiente<\/button>\r\n                                    <button class=\"cvxPill is-off\" type=\"button\" data-cvx-cc-action=\"autoplay\">Autoplay<\/button>\r\n                                <\/div>\r\n                            <\/div>\r\n\r\n                            <h4 class=\"cvxCCScreenTitle\" data-cvx-cc-title><\/h4>\r\n                            <p class=\"cvxCCScreenDesc\" data-cvx-cc-desc>\r\n\r\n                            <\/p>\r\n\r\n                            <div class=\"cvxCCMinis\" data-cvx-cc-minis aria-label=\"Mini cards de historia\">\r\n                                <!-- JS renders minis -->\r\n                            <\/div>\r\n                        <\/div>\r\n\r\n                    <\/div>\r\n\r\n                    <!-- Phone column (single mockup + rotating rig) -->\r\n                    <div class=\"cvxCCPhoneCol\" aria-label=\"Mockup Compose\">\r\n                        <div class=\"cvxCCPhoneStage\">\r\n                            <div class=\"cvxCCPhoneRig\" data-cvx-cc-rig>\r\n                                <div class=\"cvxCCViewport\">\r\n                                    <!-- Images (2 slots for crossfade) -->\r\n                                    <img class=\"cvxCCScreen\" data-cvx-cc-img data-slot=\"a\" data-on=\"1\" alt=\"Screen\" loading=\"lazy\" \/>\r\n                                    <img class=\"cvxCCScreen\" data-cvx-cc-img data-slot=\"b\" data-on=\"0\" alt=\"Screen\" loading=\"lazy\" \/>\r\n\r\n                                    <!-- Videos (2 slots for crossfade between different videos) -->\r\n                                    <video class=\"cvxCCScreen\" data-cvx-cc-vid data-slot=\"a\" data-on=\"0\" muted playsinline preload=\"metadata\"><\/video>\r\n                                    <video class=\"cvxCCScreen\" data-cvx-cc-vid data-slot=\"b\" data-on=\"0\" muted playsinline preload=\"metadata\"><\/video>\r\n\r\n\r\n                                <\/div>\r\n                                <img class=\"cvxCCFrame\" data-cvx-cc-frame alt=\"Phone frame\" loading=\"lazy\" \/>\r\n                                <!-- Hotspots overlay -->\r\n                                <div class=\"cvxCCHotspots\" data-cvx-cc-hotspots aria-label=\"Hotspots\"><\/div>\r\n                            <\/div>\r\n                        <\/div>\r\n\r\n                        <div class=\"cvxCCDots\" role=\"tablist\" aria-label=\"P\u00e1ginas\">\r\n                            <!-- JS renders dots -->\r\n                        <\/div>\r\n                    <\/div>\r\n\r\n                <\/div>\r\n            <\/div>\r\n\r\n            <!-- =====================================================\r\n           AQA CLOUD (panel only; keep proportions; no staffing claims)\r\n           ===================================================== -->\r\n            <div id=\"cloud\" class=\"cvxPanel\" data-cvx-cc-panel=\"cloud\">\r\n                <header class=\"cvxCCSectionHead\" data-cvx-cc-sec=\"cloud\">\r\n                    <div class=\"cvxKicker\">AQA CLOUD<\/div>\r\n                    <h3 class=\"cvxTitle\">La plataforma detr\u00e1s de tu ecosistema.<\/h3>\r\n                    <p class=\"cvxDesc\">AQA Cloud es la base que sostiene CubeVox y Compose cuando el proyecto crece: almacenamiento y continuidad, versionado, control de acceso en proyectos compartidos y herramientas de gesti\u00f3n para mantener orden, trazabilidad y coordinaci\u00f3n. Adem\u00e1s suma una capa de comunidad y visibilidad para impulsar tu trabajo al mundo.<\/p>\r\n                    <div class=\"cvxTags\">\r\n                        <span class=\"cvxTag\">Library & versiones<\/span>\r\n                        <span class=\"cvxTag\">Tools<\/span>\r\n                        <span class=\"cvxTag\">Oportunidades<\/span>\r\n                        <span class=\"cvxTag\">Suscripci\u00f3n<\/span>\r\n                    <\/div>\r\n                <\/header>\r\n\r\n                <div class=\"cvxCCCloud\">\r\n\r\n                    <!-- Flow (left) -->\r\n                    <div class=\"cvxCard\" data-cvx-cc-cloud-flow>\r\n                        <div class=\"cvxCCFlow\">\r\n\r\n                            <div class=\"cvxCCFlowTop\">\r\n                                <div class=\"cvxCCFlowTitle\">\r\n                                    <h4 class=\"cvxCCFlowH\">Continuidad de proyecto<\/h4>\r\n                                    <span class=\"cvxPill cvxCCFlowChip\" aria-hidden=\"true\">1 proyecto \u00b7 N versiones<\/span>\r\n                                    <p class=\"cvxCCFlowP\"><b>AQA Cloud para escalar: <\/b>accesos por rol, versiones claras y continuidad entre quienes trabajan.<\/p>\r\n                                <\/div>\r\n\r\n                            <\/div>\r\n\r\n                            <div class=\"cvxCCNode cvxCCNodeRow\">\r\n                                <div class=\"ic\" aria-hidden=\"true\">\u29c9<\/div>\r\n                                <div class=\"tt\"><b>CubeVox<\/b><span>captura \u00b7 monitoreo \u00b7 FX<\/span><\/div>\r\n                                <span class=\"cvxTag\">Take<\/span>\r\n                            <\/div>\r\n                            <div class=\"cvxCCNode cvxCCNodeRow\">\r\n                                <div class=\"ic\" aria-hidden=\"true\">\u25ce<\/div>\r\n                                <div class=\"tt\"><b>Compose Studio (core \/ app \/ cloud)<\/b><span>edici\u00f3n \u00b7 presets \u00b7 control<\/span><\/div>\r\n                                <span class=\"cvxTag\">Edit<\/span>\r\n                            <\/div>\r\n                            <div class=\"cvxCCNode cvxCCNodeRow\">\r\n                                <div class=\"ic\" aria-hidden=\"true\">\u2601<\/div>\r\n                                <div class=\"tt\"><b>AQA Cloud<\/b><span>sync \u00b7 recursos \u00b7 comunidad<\/span><\/div>\r\n                                <span class=\"cvxTag\">Scale<\/span>\r\n                            <\/div>\r\n\r\n                            <p class=\"cvxDesc\" style=\"margin:0; opacity:.88;\"><b>Tip: <\/b>El flujo local no depende de la nube; cloud aporta versiones, control de acceso y expansi\u00f3n.<\/p>\r\n                        <\/div>\r\n                    <\/div>\r\n\r\n                    <!-- Modules (right) -->\r\n                    <div style=\"display:grid; gap: calc(12px * var(--cvxS));\">\r\n                        <div class=\"cvxSwitch\" role=\"tablist\" aria-label=\"M\u00f3dulos\" data-cvx-cc-cloud-switch>\r\n                            <!-- JS renders tabs -->\r\n                        <\/div>\r\n\r\n                        <div class=\"cvxCard\" aria-live=\"polite\">\r\n                            <div style=\"display:grid; gap: calc(10px * var(--cvxS));\">\r\n                                <div>\r\n                                    <h4 class=\"cvxCCScreenTitle\" style=\"font-size: calc(16px * var(--cvxS));\" data-cvx-cc-cloud-title>Continuidad del proyecto<\/h4>\r\n                                    <p class=\"cvxCCScreenDesc\" data-cvx-cc-cloud-desc>\r\n                                        Muy pronto: funciones conectadas para que tus proyectos no se pierdan y siempre puedas retomar donde lo dejaste.\r\n                                    <\/p>\r\n                                <\/div>\r\n\r\n                                <div class=\"cvxCCList\" data-cvx-cc-cloud-list><\/div>\r\n\r\n                                <div style=\"display:flex; align-items:center; justify-content:space-between; gap:10px; flex-wrap:wrap;\">\r\n                                    <span class=\"cvxDesc\" style=\"margin:0; opacity:.85;\" data-cvx-cc-cloud-hint>El objetivo: continuidad sin dependencia de setup.<\/span>\r\n                                <\/div>\r\n                            <\/div>\r\n                        <\/div>\r\n                    <\/div>\r\n\r\n                <\/div>\r\n            <\/div>\r\n\r\n        <\/div>\r\n\r\n        <script>\r\n            (function() {\r\n                const roots = document.querySelectorAll('.cvxScope [data-cvx-root=\"compose-cloud\"]');\r\n                roots.forEach((root) => {\r\n                    if (root.__cvxCCInit) return;\r\n                    root.__cvxCCInit = true;\r\n\r\n                    \/* -----------------------------------------------------\r\n                       Helpers\r\n                    ----------------------------------------------------- *\/\r\n                    const prefersReduced = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;\r\n\r\n                    function readVarNum(el, name, fallback) {\r\n                        const v = (getComputedStyle(el).getPropertyValue(name) || '').trim();\r\n                        const n = Number(String(v).replace(\/[^0-9.\\-]\/g, ''));\r\n                        return Number.isFinite(n) ? n : fallback;\r\n                    }\r\n\r\n                    function q(sel) {\r\n                        return root.querySelector(sel);\r\n                    }\r\n\r\n                    function qa(sel) {\r\n                        return Array.from(root.querySelectorAll(sel));\r\n                    }\r\n\r\n                    function safeJSON(scriptEl) {\r\n                        if (!scriptEl) return null;\r\n                        try {\r\n                            return JSON.parse(scriptEl.textContent);\r\n                        } catch (_) {\r\n                            return null;\r\n                        }\r\n                    }\r\n\r\n                    function escapeHtml(s) {\r\n                        return String(s)\r\n                            .replaceAll('&', '&amp;')\r\n                            .replaceAll('<', '&lt;')\r\n                            .replaceAll('>', '&gt;')\r\n                            .replaceAll('\"', '&quot;')\r\n                            .replaceAll(\"'\", '&#039;');\r\n                    }\r\n\r\n                    \/* -----------------------------------------------------\r\n                       Layout state (Elementor-safe)\r\n                       - Reads: --cvx-cc-bp-stack\r\n                       - Writes: data-cvx-cc-layout=\"wide|stack\"\r\n                    ----------------------------------------------------- *\/\r\n                    const bp = readVarNum(root, '--cvx-cc-bp-stack', 980);\r\n                    const applyLayout = () => {\r\n                        const r = root.getBoundingClientRect();\r\n                        if (r.width < 12 || r.height < 12) return;\r\n                        root.setAttribute('data-cvx-cc-layout', r.width <= bp ? 'stack' : 'wide');\r\n                        requestAnimationFrame(fitPhoneRigToStage);\r\n                    };\r\n\r\n                    if ('ResizeObserver' in window) {\r\n                        const ro = new ResizeObserver(() => requestAnimationFrame(applyLayout));\r\n                        ro.observe(root);\r\n                    }\r\n                    applyLayout();\r\n\r\n                    \/* -----------------------------------------------------\r\n                       CONFIG\r\n                    ----------------------------------------------------- *\/\r\n                    const cfg = safeJSON(q('[data-cvx-cc-config]')) || {};\r\n                    const opts = cfg.options || {};\r\n                    const autoplayMs = Math.max(1400, Number(opts.autoplayMs) || 3400);\r\n                    const screens = (cfg.compose && Array.isArray(cfg.compose.screens)) ? cfg.compose.screens : [];\r\n                    const menuIndices = screens\r\n                        .map((s, i) => ({\r\n                            s,\r\n                            i\r\n                        }))\r\n                        .filter(o => (o.s && o.s.orientation !== 'landscape')); \/\/ 5 men\u00fas verticales\r\n                    let menuPos = 0; \/\/ \u00edndice dentro de menuIndices (0..4)\r\n                    const cloud = (cfg.cloud && cfg.cloud.modules) ? cfg.cloud.modules : {};\r\n\r\n                    \/* -----------------------------------------------------\r\n                       COMPOSE\r\n                    ----------------------------------------------------- *\/\r\n                    const elK = q('[data-cvx-cc-kicker]');\r\n                    const elStep = q('[data-cvx-cc-step]');\r\n                    const elT = q('[data-cvx-cc-title]');\r\n                    const elD = q('[data-cvx-cc-desc]');\r\n                    const minisEl = q('[data-cvx-cc-minis]');\r\n\r\n                    const btnPrev = q('[data-cvx-cc-action=\"prev\"]');\r\n                    const btnNext = q('[data-cvx-cc-action=\"next\"]');\r\n                    const btnAuto = q('[data-cvx-cc-action=\"autoplay\"]');\r\n\r\n                    const frameEl = q('[data-cvx-cc-frame]');\r\n                    const rigEl = q('[data-cvx-cc-rig]');\r\n                    const stageEl = q('.cvxCCPhoneStage');\r\n\r\n                    const imgEls = qa('[data-cvx-cc-img]');\r\n                    const vidEls = qa('[data-cvx-cc-vid]');\r\n                    const hsEl = q('[data-cvx-cc-hotspots]');\r\n                    let seqTimer = null;\r\n                    let mediaTok = 0;\r\n                    const dotsEl = q('.cvxCCDots');\r\n\r\n                    \/* Hotspot temporal de fin de clip (ej. cerrar panel lateral en mydevice) *\/\r\n                    let runtimeHotspots = null;\r\n\r\n                    let idx = 0;\r\n                    let autoplay = false;\r\n                    let timer = null;\r\n\r\n                    \/\/ Frame image from CSS var\r\n                    (function setFrame() {\r\n                        if (!frameEl) return;\r\n                        const src = (getComputedStyle(root).getPropertyValue('--cvx-cc-phone-frame-src') || '').trim();\r\n                        if (src) frameEl.src = src;\r\n                    })();\r\n\r\n                    if (frameEl) {\r\n                        if (frameEl.complete) {\r\n                            requestAnimationFrame(fitPhoneRigToStage);\r\n                        } else {\r\n                            frameEl.addEventListener('load', () => {\r\n                                requestAnimationFrame(() => requestAnimationFrame(fitPhoneRigToStage));\r\n                            }, {\r\n                                once: true\r\n                            });\r\n                        }\r\n                    }\r\n\r\n                    \/\/ Crossfade slots\r\n                    const slotOn = {\r\n                        a: 1,\r\n                        b: 0\r\n                    };\r\n                    let tok = 0;\r\n\r\n                    function hideAll(els) {\r\n                        els.forEach(el => el.setAttribute('data-on', '0'));\r\n                    }\r\n\r\n                    function activeEl(els) {\r\n                        return els.find(el => el.getAttribute('data-on') === '1') || els[0];\r\n                    }\r\n\r\n                    function idleEl(els) {\r\n                        const a = activeEl(els);\r\n                        return els.find(el => el !== a) || els[1] || a;\r\n                    }\r\n\r\n                    function setImage(src, keepSeqTimer) {\r\n                        if (!keepSeqTimer && seqTimer) {\r\n                            clearInterval(seqTimer);\r\n                            clearTimeout(seqTimer);\r\n                            seqTimer = null;\r\n                        }\r\n                        hideAll(vidEls);\r\n                        if (!imgEls.length) return;\r\n\r\n                        const a = activeEl(imgEls);\r\n                        const b = idleEl(imgEls);\r\n                        const my = ++mediaTok;\r\n\r\n                        b.setAttribute('data-on', '0');\r\n                        b.onload = () => {\r\n                            if (my !== mediaTok) return;\r\n                            b.setAttribute('data-on', '1');\r\n                            a.setAttribute('data-on', '0');\r\n                        };\r\n                        b.src = src || '';\r\n                    }\r\n\r\n                    function setSeq(seq) {\r\n                        if (!seq || !Array.isArray(seq.frames) || !seq.frames.length) {\r\n                            setImage('');\r\n                            return;\r\n                        }\r\n                        const frames = seq.frames;\r\n                        const frameMs = Math.max(650, Number(seq.frameMs) || 1100);\r\n\r\n                        \/\/ Limpia timer anterior (interval o timeout)\r\n                        if (seqTimer) {\r\n                            clearInterval(seqTimer);\r\n                            clearTimeout(seqTimer);\r\n                            seqTimer = null;\r\n                        }\r\n\r\n                        let i = 0;\r\n                        setImage(frames[0], true);\r\n\r\n                        if (frames.length > 1) {\r\n                            seqTimer = setInterval(() => {\r\n                                i = (i + 1) % frames.length;\r\n                                setImage(frames[i], true);\r\n                            }, frameMs);\r\n                        }\r\n                    }\r\n\r\n                    function setVideo(v) {\r\n                        if (seqTimer) {\r\n                            clearInterval(seqTimer);\r\n                            seqTimer = null;\r\n                        }\r\n                        hideAll(imgEls);\r\n                        if (!vidEls.length) return;\r\n\r\n                        const src = (v && v.src) ? v.src : '';\r\n                        const autoplay = !!(v && v.autoplay);\r\n                        const loop = !!(v && v.loop);\r\n\r\n                        const a = activeEl(vidEls);\r\n                        const b = idleEl(vidEls);\r\n                        const my = ++mediaTok;\r\n\r\n                        \/\/ detener el anterior\r\n                        try {\r\n                            a.pause();\r\n                        } catch (_) {}\r\n                        a.onended = null; \/\/ evita handlers viejos al reutilizar slots\r\n\r\n                        b.setAttribute('data-on', '0');\r\n                        b.loop = loop;\r\n                        b.muted = true;\r\n                        b.playsInline = true;\r\n\r\n                        const rateVar = (v && v.rateVar) ? v.rateVar : '';\r\n                        const rate = rateVar ? readVarNum(root, rateVar, 1) : 1;\r\n                        b.playbackRate = Math.max(0.5, Math.min(2, rate));\r\n\r\n                        b.onloadedmetadata = async () => {\r\n                            if (my !== mediaTok) return;\r\n                            try {\r\n                                b.currentTime = 0;\r\n                                if (autoplay && !((opts.respectReducedMotion !== false) && prefersReduced)) {\r\n                                    await b.play();\r\n                                } else {\r\n                                    b.pause(); \/\/ muestra frame 0\r\n                                }\r\n                            } catch (_) {\r\n                                try {\r\n                                    b.pause();\r\n                                } catch (__) {}\r\n                            }\r\n                            b.setAttribute('data-on', '1');\r\n                            a.setAttribute('data-on', '0');\r\n                        };\r\n\r\n                        \/* Fin de clip: mydevice muestra solo radar de reset\/cierre del panel lateral *\/\r\n                        b.onended = () => {\r\n                            if (my !== mediaTok) return;\r\n\r\n                            const sNow = screens[idx] || {};\r\n                            if (hsEl) hsEl.setAttribute('data-hide', '0');\r\n\r\n                            if (sNow.id === 'mydevice') {\r\n                                runtimeHotspots = [{\r\n                                    id: 'hs_mydevice_reset_panel',\r\n                                    action: 'reset_clip',\r\n                                    \/* Flecha izquierda-centro (ajustable si hiciera falta) *\/\r\n                                    x: -0.005,\r\n                                    y: 0.385,\r\n                                    w: 0.1,\r\n                                    h: 0.14\r\n                                }];\r\n                                renderHotspots(runtimeHotspots);\r\n                            } else {\r\n                                runtimeHotspots = null;\r\n                                renderHotspots(sNow.hotspots);\r\n                            }\r\n                        };\r\n\r\n                        b.src = src;\r\n                        b.load();\r\n                    }\r\n\r\n                    function renderMinis(list) {\r\n                        if (!minisEl) return;\r\n                        const minis = Array.isArray(list) ? list.slice(0, 4) : [];\r\n                        minisEl.innerHTML = minis.map((m) => {\r\n                            const hasThumb = m && m.thumb ? '1' : '0';\r\n                            const thumb = (m && m.thumb) ? `<span class=\"thumb\"><img decoding=\"async\" src=\"${escapeHtml(m.thumb)}\" alt=\"\" loading=\"lazy\"><\/span>` : `<span class=\"thumb\" aria-hidden=\"true\"><\/span>`;\r\n                            return `\r\n                <div class=\"cvxCCMini\" data-has-thumb=\"${hasThumb}\">\r\n                  <div class=\"t\"><b>${escapeHtml(m.t || '')}<\/b><span>${escapeHtml(m.d || '')}<\/span><\/div>\r\n                  ${thumb}\r\n                <\/div>\r\n              `.trim();\r\n                        }).join('');\r\n                    }\r\n\r\n                    function renderHotspots(list) {\r\n                        if (!hsEl) return;\r\n                        const hs = Array.isArray(list) ? list : [];\r\n                        if (!hs.length) {\r\n                            hsEl.innerHTML = '';\r\n                            return;\r\n                        }\r\n\r\n                        hsEl.innerHTML = hs.map(h => {\r\n                            return `<button type=\"button\" class=\"cvxCCHs\"\r\n      data-action=\"${escapeHtml(h.action||'')}\"\r\n      data-to=\"${escapeHtml(h.to||'')}\"\r\n      style=\"left:${(h.x*100).toFixed(2)}%; top:${(h.y*100).toFixed(2)}%;\r\n             width:${(h.w*100).toFixed(2)}%; height:${(h.h*100).toFixed(2)}%;\"><\/button>`;\r\n                        }).join('');\r\n\r\n                        hs.forEach((h, i) => {\r\n                            const btn = hsEl.children[i];\r\n                            if (!btn) return;\r\n                            const dx = h.dxVar ? readVarNum(root, h.dxVar, 0) : 0;\r\n                            const dy = h.dyVar ? readVarNum(root, h.dyVar, 0) : 0;\r\n                            btn.style.left = ((h.x + dx) * 100).toFixed(2) + '%';\r\n                            btn.style.top = ((h.y + dy) * 100).toFixed(2) + '%';\r\n                        });\r\n                    }\r\n\r\n                    function buildDots() {\r\n                        if (!dotsEl) return;\r\n                        dotsEl.innerHTML = menuIndices.map((_, i) => {\r\n                            return `<button type=\"button\" aria-label=\"Men\u00fa ${i+1}\" aria-current=\"${i===0?'true':'false'}\" data-i=\"${i}\"><\/button>`;\r\n                        }).join('');\r\n                    }\r\n                    if (hsEl) {\r\n                        hsEl.addEventListener('click', async (ev) => {\r\n                            const b = ev.target && ev.target.closest && ev.target.closest('button.cvxCCHs');\r\n                            if (!b) return;\r\n\r\n                            const action = b.getAttribute('data-action') || '';\r\n                            const to = b.getAttribute('data-to') || '';\r\n\r\n                            stopAuto();\r\n\r\n                            if (action === 'goto' && to) {\r\n                                const j = screens.findIndex(s => s && s.id === to);\r\n                                if (j >= 0) render(j);\r\n                                return;\r\n                            }\r\n\r\n                            if (action === 'reset_clip') {\r\n                                const v = activeEl(vidEls);\r\n                                try {\r\n                                    if (v) {\r\n                                        v.pause();\r\n                                        v.currentTime = 0; \/\/ vuelve al frame 0 del clip\r\n                                    }\r\n                                } catch (_) {}\r\n\r\n                                runtimeHotspots = null;\r\n\r\n                                const sNow = screens[idx] || {};\r\n                                renderHotspots(sNow.hotspots); \/\/ restaura gear + cubevox\r\n                                if (hsEl) hsEl.setAttribute('data-hide', '0');\r\n                                return;\r\n                            }\r\n\r\n                            if (action === 'goto' && to) {\r\n                                const j = screens.findIndex(s => s && s.id === to);\r\n                                if (j >= 0) render(j);\r\n                                return;\r\n                            }\r\n\r\n                            if (action === 'play') {\r\n                                const v = activeEl(vidEls);\r\n                                if (!v) return;\r\n                                try {\r\n                                    if (hsEl) hsEl.setAttribute('data-hide', '1'); \/\/ radar off durante el clip\r\n\r\n                                    v.currentTime = 0;\r\n\r\n                                    const s = screens[idx] || {};\r\n                                    const rv = (s.video && s.video.rateVar) ? s.video.rateVar : '';\r\n                                    if (rv) v.playbackRate = Math.max(0.5, Math.min(2, readVarNum(root, rv, 1)));\r\n\r\n                                    await v.play(); \/\/ al terminar queda en \u00faltimo frame (freeze)\r\n                                } catch (_) {}\r\n                            }\r\n                        });\r\n                    }\r\n\r\n                    function setDotByMenuPos() {\r\n                        if (!dotsEl) return;\r\n                        Array.from(dotsEl.querySelectorAll('button[data-i]')).forEach((b) => {\r\n                            const bi = Number(b.getAttribute('data-i'));\r\n                            b.setAttribute('aria-current', bi === menuPos ? 'true' : 'false');\r\n                        });\r\n                    }\r\n\r\n                    function setOrient(o) {\r\n                        root.setAttribute('data-cvx-cc-orient', o === 'landscape' ? 'landscape' : 'portrait');\r\n                    }\r\n\r\n                    function fitPhoneRigToStage() {\r\n                        if (!rigEl || !stageEl) return;\r\n\r\n                        const sr = stageEl.getBoundingClientRect();\r\n                        if (sr.width < 12 || sr.height < 12) return;\r\n\r\n                        \/\/ Medida BASE del rig (sin transform), estable y predecible\r\n                        const rawW = rigEl.offsetWidth;\r\n                        const rawH = rigEl.offsetHeight;\r\n                        if (rawW < 12 || rawH < 12) return;\r\n\r\n                        const orient = root.getAttribute('data-cvx-cc-orient') === 'landscape' ? 'landscape' : 'portrait';\r\n\r\n                        \/\/ Footprint final esperado del rig dentro del stage (sin depender de la transici\u00f3n)\r\n                        let boxW = rawW;\r\n                        let boxH = rawH;\r\n\r\n                        if (orient === 'landscape') {\r\n                            const lanScale = Math.max(0.01, readVarNum(root, '--cvx-cc-lan-scale', 1));\r\n                            \/\/ rotate(-90deg): intercambia ancho\/alto visuales\r\n                            boxW = rawH * lanScale;\r\n                            boxH = rawW * lanScale;\r\n                        }\r\n\r\n                        \/\/ margen interno opcional para que no toque bordes\r\n                        const fitPad = 8; \/\/ px\r\n\r\n                        const availW = Math.max(1, sr.width - fitPad * 2);\r\n                        const availH = Math.max(1, sr.height - fitPad * 2);\r\n\r\n                        const fit = Math.min(availW \/ boxW, availH \/ boxH);\r\n\r\n                        \/\/ Solo reduce, no agranda por encima de 1\r\n                        const safeFit = Math.max(0.1, Math.min(1, fit));\r\n\r\n                        root.style.setProperty('--cvx-cc-rig-fit-scale', String(safeFit));\r\n                    }\r\n\r\n                    function render(i) {\r\n                        if (!screens.length) return;\r\n                        idx = ((i % screens.length) + screens.length) % screens.length;\r\n                        const s = screens[idx] || {};\r\n                        const mp = menuIndices.findIndex(o => o.i === idx);\r\n                        if (mp >= 0) menuPos = mp; \/\/ solo si es uno de los 5 men\u00fas\r\n                        const o = (s.orientation === 'landscape') ? 'landscape' : 'portrait';\r\n                        const prevO = root.getAttribute('data-cvx-cc-orient') || 'portrait';\r\n\r\n                        setOrient(o);\r\n\r\n                        if (o !== prevO) {\r\n                            \/\/ Esperar a que termine la transici\u00f3n de rotaci\u00f3n antes de medir\r\n                            clearTimeout(root.__cvxCCFitAfterRotateT);\r\n                            root.__cvxCCFitAfterRotateT = setTimeout(() => {\r\n                                requestAnimationFrame(fitPhoneRigToStage);\r\n                            }, prefersReduced ? 0 : 240); \/\/ un poco > 220ms del CSS\r\n                        } else {\r\n                            requestAnimationFrame(() => requestAnimationFrame(fitPhoneRigToStage));\r\n                        }\r\n\r\n                        if (elK) elK.textContent = s.kicker || (o === 'landscape' ? 'REMOTE' : 'COMPOSE');\r\n                        if (elStep) elStep.textContent = `${menuPos+1}\/${menuIndices.length}`;\r\n                        if (elT) elT.textContent = s.title || '';\r\n                        if (elD) elD.textContent = s.desc || '';\r\n\r\n                        \/\/ media priority: video > seq > img\r\n                        if (s.video && s.video.src) setVideo(s.video);\r\n                        else if (s.seq && s.seq.frames) setSeq(s.seq);\r\n                        else setImage(s.img || '');\r\n\r\n                        renderMinis(s.minis);\r\n\r\n                        \/* Al entrar a una screen, limpiar cualquier hotspot temporal (ej. reset de clip) *\/\r\n                        runtimeHotspots = null;\r\n                        renderHotspots(s.hotspots);\r\n\r\n                        \/\/ Reset radar visibility on screen entry\r\n                        if (hsEl) hsEl.setAttribute('data-hide', '0');\r\n\r\n                        \/\/ If this screen is a \"tap-to-play\" clip, force idle frame 0 on entry\r\n                        if (s.video && s.video.src && !s.video.autoplay) {\r\n                            const v = activeEl(vidEls);\r\n                            if (v) {\r\n                                try {\r\n                                    v.pause();\r\n                                    v.currentTime = 0;\r\n                                } catch (_) {}\r\n                            }\r\n                        }\r\n                        setDotByMenuPos();\r\n                        if (autoplay) armAutoplayTimer();\r\n                    }\r\n\r\n                    function getAutoplayDelayForScreen(s) {\r\n                        let ms = autoplayMs;\r\n\r\n                        if (s && s.seq && Array.isArray(s.seq.frames) && s.seq.frames.length > 1) {\r\n                            const frameMs = Math.max(650, Number(s.seq.frameMs) || 1100);\r\n\r\n                            \/\/ Tiempo para mostrar todos los frames del seq (4 en projects\/store)\r\n                            \/\/ + peque\u00f1o colch\u00f3n para que el \u00faltimo frame se llegue a percibir.\r\n                            const seqFullMs = (frameMs * s.seq.frames.length) + 180;\r\n\r\n                            ms = Math.max(ms, seqFullMs);\r\n                        }\r\n\r\n                        return ms;\r\n                    }\r\n\r\n                    function armAutoplayTimer() {\r\n                        if (!autoplay) return;\r\n\r\n                        if (timer) {\r\n                            clearInterval(timer);\r\n                            clearTimeout(timer);\r\n                            timer = null;\r\n                        }\r\n                        const sNow = screens[idx] || {};\r\n                        const delay = getAutoplayDelayForScreen(sNow);\r\n\r\n                        timer = setTimeout(() => {\r\n                            timer = null;\r\n                            const next = (menuPos + 1) % menuIndices.length;\r\n                            render(menuIndices[next].i);\r\n                        }, delay);\r\n                    }\r\n\r\n                    function stopAuto() {\r\n                        autoplay = false;\r\n                        if (timer) {\r\n                            clearInterval(timer);\r\n                            clearTimeout(timer);\r\n                            timer = null;\r\n                        }\r\n                        if (btnAuto) {\r\n                            btnAuto.classList.add('is-off');\r\n                            btnAuto.textContent = 'Autoplay';\r\n                        }\r\n                    }\r\n\r\n                    function startAuto() {\r\n                        if ((opts.respectReducedMotion !== false) && prefersReduced) return;\r\n                        autoplay = true;\r\n                        if (btnAuto) {\r\n                            btnAuto.classList.remove('is-off');\r\n                            btnAuto.textContent = 'Autoplay: ON';\r\n                        }\r\n\r\n                        if (timer) {\r\n                            clearInterval(timer);\r\n                            clearTimeout(timer);\r\n                            timer = null;\r\n                        }\r\n\r\n                        armAutoplayTimer();\r\n                    }\r\n                    if (btnPrev) btnPrev.addEventListener('click', () => {\r\n                        stopAuto();\r\n                        const prev = (menuPos - 1 + menuIndices.length) % menuIndices.length;\r\n                        render(menuIndices[prev].i);\r\n                    });\r\n                    if (btnNext) btnNext.addEventListener('click', () => {\r\n                        stopAuto();\r\n                        const next = (menuPos + 1) % menuIndices.length;\r\n                        render(menuIndices[next].i);\r\n                    });\r\n                    if (btnAuto) btnAuto.addEventListener('click', () => {\r\n                        autoplay ? stopAuto() : startAuto();\r\n                    });\r\n\r\n                    if (dotsEl) {\r\n                        dotsEl.addEventListener('click', (ev) => {\r\n                            const b = ev.target && ev.target.closest && ev.target.closest('button[data-i]');\r\n                            if (!b) return;\r\n                            stopAuto();\r\n                            const mi = Number(b.getAttribute('data-i'));\r\n                            const target = menuIndices[mi];\r\n                            if (target) render(target.i);\r\n                        });\r\n                    }\r\n\r\n                    \/\/ Pause autoplay when not visible\r\n                    if ('IntersectionObserver' in window) {\r\n                        const io = new IntersectionObserver((entries) => {\r\n                            const e = entries && entries[0];\r\n                            if (!e) return;\r\n                            if (!e.isIntersecting) {\r\n                                if (timer) {\r\n                                    clearInterval(timer);\r\n                                    timer = null;\r\n                                }\r\n                            } else {\r\n                                if (autoplay && !timer) startAuto();\r\n                            }\r\n                        }, {\r\n                            threshold: 0.14\r\n                        });\r\n                        io.observe(root);\r\n                    }\r\n\r\n                    buildDots();\r\n\r\n                    \/* \r\n                    reemplazar con:  \r\n                    const firstLand = screens.findIndex(s => s && s.orientation === 'landscape');\r\n                    render(firstLand >= 0 ? firstLand : 0);\r\n                    *\/\r\n                    render(0);\r\n\r\n                    \/* -----------------------------------------------------\r\n                       CLOUD\r\n                    ----------------------------------------------------- *\/\r\n                    const sw = q('[data-cvx-cc-cloud-switch]');\r\n                    const cT = q('[data-cvx-cc-cloud-title]');\r\n                    const cD = q('[data-cvx-cc-cloud-desc]');\r\n                    const cH = q('[data-cvx-cc-cloud-hint]');\r\n                    const cL = q('[data-cvx-cc-cloud-list]');\r\n\r\n                    const keys = Object.keys(cloud || {});\r\n                    let cKey = keys[0] || 'library';\r\n\r\n                    function renderCloud(key) {\r\n                        const m = (cloud && cloud[key]) ? cloud[key] : cloud[cKey];\r\n                        if (!m) return;\r\n                        cKey = key;\r\n\r\n                        if (cT) cT.textContent = m.title || '';\r\n                        if (cD) cD.textContent = m.desc || '';\r\n                        if (cH) cH.textContent = m.hint || '';\r\n\r\n                        if (cL) {\r\n                            const items = Array.isArray(m.items) ? m.items : [];\r\n                            cL.innerHTML = items.map((it) => {\r\n                                return `\r\n                  <div class=\"cvxCCItem\">\r\n                    <div style=\"min-width:0; display:grid; gap:4px;\">\r\n                      <b style=\"font-size: calc(13px * var(--cvxS)); color: rgba(255,255,255,.92); white-space:nowrap; overflow:hidden; text-overflow:ellipsis;\">${escapeHtml(it.t || '')}<\/b>\r\n                      <span style=\"font-size: calc(12px * var(--cvxS)); color: rgba(255,255,255,.62); white-space:nowrap; overflow:hidden; text-overflow:ellipsis;\">${escapeHtml(it.s || '')}<\/span>\r\n                    <\/div>\r\n                        <div class=\"cvxCCMeta\">\r\n                          ${(it.m1 != null && String(it.m1).trim() !== '') ? `<span class=\"cvxTag\">${escapeHtml(String(it.m1))}<\/span>` : ''}\r\n                          ${(it.m2 != null && String(it.m2).trim() !== '') ? `<span class=\"cvxTag\">${escapeHtml(String(it.m2))}<\/span>` : ''}\r\n                        <\/div>\r\n                  <\/div>\r\n                `.trim();\r\n                            }).join('');\r\n                        }\r\n\r\n                        if (sw) {\r\n                            Array.from(sw.querySelectorAll('button[data-k]')).forEach((b) => {\r\n                                b.classList.toggle('on', b.getAttribute('data-k') === cKey);\r\n                            });\r\n                        }\r\n                    }\r\n\r\n                    function rerenderDynamicTextForTP() {\r\n                        \/\/ Re-emite el contenido din\u00e1mico para que TP lo detecte ya inicializado.\r\n                        render(idx);\r\n                        renderCloud(cKey);\r\n\r\n                        \/\/ Re-emite tambi\u00e9n las labels del switch cloud, porque salen del JSON.\r\n                        if (sw) {\r\n                            Array.from(sw.querySelectorAll('button[data-k]')).forEach((b) => {\r\n                                const k = b.getAttribute('data-k');\r\n                                const m = cloud[k] || {};\r\n                                b.textContent = m.label || k;\r\n                            });\r\n                        }\r\n                    }\r\n\r\n                    function scheduleInitialTPPass() {\r\n                        const run = () => {\r\n                            requestAnimationFrame(() => {\r\n                                setTimeout(() => {\r\n                                    rerenderDynamicTextForTP();\r\n                                }, 80);\r\n                            });\r\n                        };\r\n\r\n                        if (document.readyState === 'complete') run();\r\n                        else window.addEventListener('load', run, {\r\n                            once: true\r\n                        });\r\n                    }\r\n\r\n                    if (sw) {\r\n                        sw.innerHTML = keys.map((k, i) => {\r\n                            const m = cloud[k] || {};\r\n                            const on = i === 0 ? 'on' : '';\r\n                            return `<button type=\"button\" class=\"${on}\" data-k=\"${escapeHtml(k)}\" role=\"tab\" aria-selected=\"${i===0?'true':'false'}\">${escapeHtml(m.label || k)}<\/button>`;\r\n                        }).join('');\r\n\r\n                        sw.addEventListener('click', (ev) => {\r\n                            const b = ev.target && ev.target.closest && ev.target.closest('button[data-k]');\r\n                            if (!b) return;\r\n                            const k = b.getAttribute('data-k');\r\n                            if (!k) return;\r\n                            Array.from(sw.querySelectorAll('button[data-k]')).forEach((x) => x.setAttribute('aria-selected', x === b ? 'true' : 'false'));\r\n                            renderCloud(k);\r\n                        });\r\n                    }\r\n\r\n\r\n                    renderCloud(cKey);\r\n                    scheduleInitialTPPass();\r\n                });\r\n            })();\r\n        <\/script>\r\n\r\n    <\/section>\r\n<\/section>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-fc5b396 fx_section elementor-section-height-min-height elementor-section-items-stretch elementor-section-boxed elementor-section-height-default\" data-id=\"fc5b396\" data-element_type=\"section\" data-e-type=\"section\" id=\"design\" data-settings=\"{&quot;background_background&quot;:&quot;gradient&quot;,&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t\t<div class=\"elementor-background-overlay\"><\/div>\n\t\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-e81f160\" data-id=\"e81f160\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<section class=\"elementor-section elementor-inner-section elementor-element elementor-element-a442e57 elementor-section-boxed elementor-section-height-default elementor-section-height-default\" data-id=\"a442e57\" data-element_type=\"section\" data-e-type=\"section\" data-settings=\"{&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-no\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-inner-column elementor-element elementor-element-08f0fc3\" data-id=\"08f0fc3\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-6279262 animated-slow elementor-invisible elementor-widget elementor-widget-heading\" data-id=\"6279262\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;slideInDown&quot;}\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Dise\u00f1o<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-8d03f45 elementor-invisible elementor-widget elementor-widget-ha-svg-draw happy-addon ha-svg-draw\" data-id=\"8d03f45\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;slideInLeft&quot;}\" data-widget_type=\"ha-svg-draw.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\n\t\t\t\t<div class=\"ha-svg-draw-container\">\n\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t\n  \n    \n      \n      \n    \n  \n  \n\n\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t<\/div>\n\n\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-inner-section elementor-element elementor-element-56fd7b6 elementor-section-boxed elementor-section-height-default elementor-section-height-default\" data-id=\"56fd7b6\" data-element_type=\"section\" data-e-type=\"section\" data-settings=\"{&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-no\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-inner-column elementor-element elementor-element-3589f82\" data-id=\"3589f82\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-fb80679 animated-slow elementor-invisible elementor-widget elementor-widget-heading\" data-id=\"fb80679\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;fadeIn&quot;}\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Doble Modo<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-inner-section elementor-element elementor-element-77b1ecd elementor-section-boxed elementor-section-height-default elementor-section-height-default\" data-id=\"77b1ecd\" data-element_type=\"section\" data-e-type=\"section\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;,&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-no\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-50 elementor-inner-column elementor-element elementor-element-6e6b1bc\" data-id=\"6e6b1bc\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-abb8f3a animated-slow elementor-invisible elementor-widget elementor-widget-heading\" data-id=\"abb8f3a\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;fadeInDown&quot;}\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Cerrado suena. Abierto crea<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-fb40730 animated-slow elementor-invisible elementor-widget elementor-widget-text-editor\" data-id=\"fb40730\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;fadeInUp&quot;}\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p data-start=\"1254\" data-end=\"1624\"><strong data-start=\"361\" data-end=\"373\">Cerrado:<\/strong> lo llev\u00e1s f\u00e1cil y lo us\u00e1s al instante como speaker inal\u00e1mbrico, con el sistema protegido y compacto.<\/p><p data-start=\"209\" data-end=\"611\"><strong data-start=\"477\" data-end=\"489\">Abierto:<\/strong> se transforma en una estaci\u00f3n de trabajo con acceso directo a controles y conexiones para operar con rapidez y sin perder tiempo armando setup.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t<div class=\"elementor-column elementor-col-50 elementor-inner-column elementor-element elementor-element-a91102c\" data-id=\"a91102c\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-ebd47ed animated-slow e-transform e-transform ha-has-bg-overlay elementor-invisible elementor-widget elementor-widget-ha-image-compare happy-addon ha-image-compare\" data-id=\"ebd47ed\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;fadeInRight&quot;,&quot;_transform_translateX_effect_hover&quot;:{&quot;unit&quot;:&quot;%&quot;,&quot;size&quot;:-50,&quot;sizes&quot;:[]},&quot;_transform_translateX_effect_hover_tablet&quot;:{&quot;unit&quot;:&quot;%&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;_transform_translateX_effect_hover_mobile&quot;:{&quot;unit&quot;:&quot;%&quot;,&quot;size&quot;:0,&quot;sizes&quot;:[]},&quot;_transform_scale_effect_hover&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:1.2,&quot;sizes&quot;:[]},&quot;_transform_scale_effect_hover_mobile&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:1,&quot;sizes&quot;:[]},&quot;_transform_translateY_effect_hover&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;_transform_translateY_effect_hover_tablet&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;_transform_translateY_effect_hover_mobile&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;_transform_scale_effect_hover_tablet&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]}}\" data-widget_type=\"ha-image-compare.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t        <div class=\"twentytwenty-container hajs-image-comparison\" data-happy-settings=\"{&quot;default_offset_pct&quot;:0.5,&quot;orientation&quot;:&quot;horizontal&quot;,&quot;no_overlay&quot;:false,&quot;move_handle&quot;:&quot;on_swipe&quot;,&quot;before_label&quot;:&quot;&quot;,&quot;after_label&quot;:&quot;&quot;}\">\n            <img decoding=\"async\" width=\"1024\" height=\"683\" src=\"https:\/\/cube-vox.com\/wp-content\/uploads\/cubevox-hifi-open-wood-floor-render.webp\" class=\"elementor-animation-disable-animation attachment-full size-full wp-image-5756\" alt=\"\" srcset=\"https:\/\/cube-vox.com\/wp-content\/uploads\/cubevox-hifi-open-wood-floor-render.webp 1024w, https:\/\/cube-vox.com\/wp-content\/uploads\/cubevox-hifi-open-wood-floor-render-600x400.webp 600w, https:\/\/cube-vox.com\/wp-content\/uploads\/cubevox-hifi-open-wood-floor-render-300x200.webp 300w, https:\/\/cube-vox.com\/wp-content\/uploads\/cubevox-hifi-open-wood-floor-render-768x512.webp 768w, https:\/\/cube-vox.com\/wp-content\/uploads\/cubevox-hifi-open-wood-floor-render-18x12.webp 18w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><img decoding=\"async\" width=\"1024\" height=\"683\" src=\"https:\/\/cube-vox.com\/wp-content\/uploads\/cubevox-hifi-closed-wood-floor-render.webp\" class=\"elementor-animation-disable-animation attachment-full size-full wp-image-5752\" alt=\"\" srcset=\"https:\/\/cube-vox.com\/wp-content\/uploads\/cubevox-hifi-closed-wood-floor-render.webp 1024w, https:\/\/cube-vox.com\/wp-content\/uploads\/cubevox-hifi-closed-wood-floor-render-600x400.webp 600w, https:\/\/cube-vox.com\/wp-content\/uploads\/cubevox-hifi-closed-wood-floor-render-300x200.webp 300w, https:\/\/cube-vox.com\/wp-content\/uploads\/cubevox-hifi-closed-wood-floor-render-768x512.webp 768w, https:\/\/cube-vox.com\/wp-content\/uploads\/cubevox-hifi-closed-wood-floor-render-18x12.webp 18w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/>        <\/div>\n        \t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-inner-section elementor-element elementor-element-ac4a7d5 elementor-reverse-mobile elementor-section-boxed elementor-section-height-default elementor-section-height-default\" data-id=\"ac4a7d5\" data-element_type=\"section\" data-e-type=\"section\" data-settings=\"{&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-no\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-50 elementor-inner-column elementor-element elementor-element-0be12c5\" data-id=\"0be12c5\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-2448019 elementor-widget__width-inherit animated-slow e-transform e-transform ha-has-bg-overlay elementor-invisible elementor-widget elementor-widget-html\" data-id=\"2448019\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;fadeInLeft&quot;,&quot;_transform_translateX_effect_hover&quot;:{&quot;unit&quot;:&quot;%&quot;,&quot;size&quot;:50,&quot;sizes&quot;:[]},&quot;_transform_translateX_effect_hover_tablet&quot;:{&quot;unit&quot;:&quot;%&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;_transform_translateX_effect_hover_mobile&quot;:{&quot;unit&quot;:&quot;%&quot;,&quot;size&quot;:0,&quot;sizes&quot;:[]},&quot;_transform_scale_effect_hover&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:1.2,&quot;sizes&quot;:[]},&quot;_transform_scale_effect_hover_mobile&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:1,&quot;sizes&quot;:[]},&quot;_transform_translateY_effect_hover&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;_transform_translateY_effect_hover_tablet&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;_transform_translateY_effect_hover_mobile&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;_transform_scale_effect_hover_tablet&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]}}\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t  <div style=\"left: 0px; width: 100%; height: 0px; position: relative; padding-bottom: 60%; overflow: hidden;\">\r\n    <iframe src=\"\/wp-content\/CubeVox%20HiFi%203D\/CubeVox%20HiFi%203D.html\"\r\n                 allowfullscreen\r\n                 style=\"position: absolute; top: 0px; center: 0px; height: 100%; width: 1px; min-width: 100%; *width: 100%;border-radius: 20px;\"\r\n                 frameborder=\"0\"\r\n                 scrolling=\"no\">\r\n    <\/iframe>\r\n  <\/div>\r\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t<div class=\"elementor-column elementor-col-50 elementor-inner-column elementor-element elementor-element-f98dcda\" data-id=\"f98dcda\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-664ae17 animated-slow elementor-invisible elementor-widget elementor-widget-heading\" data-id=\"664ae17\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;fadeInDown&quot;}\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Miralo de cerca<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-211fded animated-slow elementor-invisible elementor-widget elementor-widget-text-editor\" data-id=\"211fded\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;fadeInUp&quot;}\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Expl\u00f3ralo y entender\u00e1s por qu\u00e9 es \u00fanico: control real, feedback claro y operaci\u00f3n directa.<\/p><p>Todo pensado para que puedas pasar de \u201creproducir\u201d a \u201ccrear\u201d sin cambiar de equipo.<\/p><p><strong><span style=\"color: #95c0d6;\">\u00a0 \u00a0 \u2022\u00a0 \u00a0<\/span><\/strong>Controles dedicados + indicadores para lectura inmediata.<br \/><strong><span style=\"color: #95c0d6;\">\u00a0 \u00a0 \u2022\u00a0 \u00a0<\/span><\/strong>Perfiles de uso para cambiar de escenario en segundos.<br \/><strong><span style=\"color: #95c0d6;\">\u00a0 \u00a0 \u2022\u00a0 \u00a0<\/span><\/strong>Estructura pensada para portabilidad y operaci\u00f3n.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-e559c34 fx_section elementor-section-items-stretch elementor-section-height-min-height elementor-section-boxed elementor-section-height-default\" data-id=\"e559c34\" data-element_type=\"section\" data-e-type=\"section\" id=\"innovative\" data-settings=\"{&quot;background_background&quot;:&quot;gradient&quot;,&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t\t<div class=\"elementor-background-overlay\"><\/div>\n\t\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-3a5672c\" data-id=\"3a5672c\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<section class=\"elementor-section elementor-inner-section elementor-element elementor-element-1193990 elementor-section-full_width elementor-section-height-default elementor-section-height-default\" data-id=\"1193990\" data-element_type=\"section\" data-e-type=\"section\" data-settings=\"{&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-no\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-inner-column elementor-element elementor-element-7908d04\" data-id=\"7908d04\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-f079e58 animated-slow elementor-invisible elementor-widget elementor-widget-heading\" data-id=\"f079e58\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;slideInDown&quot;}\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Innovador<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-264d72e elementor-invisible elementor-widget elementor-widget-ha-svg-draw happy-addon ha-svg-draw\" data-id=\"264d72e\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;slideInLeft&quot;}\" data-widget_type=\"ha-svg-draw.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\n\t\t\t\t<div class=\"ha-svg-draw-container\">\n\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t\n  \n    \n      \n      \n    \n  \n  \n\n\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t<\/div>\n\n\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-inner-section elementor-element elementor-element-e7a1df1 elementor-section-full_width elementor-section-height-default elementor-section-height-default\" data-id=\"e7a1df1\" data-element_type=\"section\" data-e-type=\"section\" data-settings=\"{&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-no\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-50 elementor-inner-column elementor-element elementor-element-55ee96f\" data-id=\"55ee96f\" data-element_type=\"column\" data-e-type=\"column\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-10545f4 animated-slow elementor-invisible elementor-widget elementor-widget-heading\" data-id=\"10545f4\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;fadeIn&quot;}\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Lo esencial<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-b9cf2a3 elementor-invisible elementor-widget elementor-widget-heading\" data-id=\"b9cf2a3\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;fadeInDown&quot;}\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">en un Todo en Uno<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-6e61f2b animated-slow elementor-invisible elementor-widget elementor-widget-text-editor\" data-id=\"6e61f2b\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;fadeInUp&quot;,&quot;_animation_delay&quot;:400}\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Cambi\u00e1 de escenario en segundos: reproduc\u00ed, toc\u00e1, grab\u00e1 o proces\u00e1 sin rearmar tu set.<\/p><p><strong><span style=\"color: #95c0d6;\">\u00a0 \u00a0 \u2022<\/span>\u00a0 \u00a0<\/strong>Bater\u00eda extra\u00edble + carga r\u00e1pida USB-C 60W<br \/><strong><span style=\"color: #95c0d6;\">\u00a0 \u00a0 \u2022\u00a0\u00a0<\/span> <\/strong>Teclado multimedia con botones retroiluminados<br \/><strong><span style=\"color: #95c0d6;\">\u00a0 \u00a0 \u2022\u00a0\u00a0<\/span><\/strong> DSP + EQ param\u00e9trico en tiempo real<br \/><strong><span style=\"color: #95c0d6;\">\u00a0 \u00a0 \u2022\u00a0\u00a0<\/span><\/strong>\u00a0Conectividad f\u00edsica e inalambrica y puerto de expansi\u00f3n<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t<div class=\"elementor-column elementor-col-50 elementor-inner-column elementor-element elementor-element-2994dc0\" data-id=\"2994dc0\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-ee8d5b7 elementor-invisible elementor-widget elementor-widget-html\" data-id=\"ee8d5b7\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;fadeInRight&quot;}\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<div id=\"cvx-feature-grid\" class=\"cvx-feature-grid\">\r\n  <!-- Card 1 -->\r\n  <article class=\"cvx-card\" tabindex=\"0\" role=\"button\"\r\n           data-full=\"\/wp-content\/uploads\/cubevox-removable-battery-closeup.webp\"\r\n           data-caption=\"Bater\u00eda extra\u00edble \u2014 Autonom\u00eda extendida y reemplazo en segundos. Pensada para sesiones en movimiento.\">\r\n    <img decoding=\"async\" class=\"cvx-img\" src=\"\/wp-content\/uploads\/cubevox-removable-battery-closeup.webp\" alt=\"Bater\u00eda extra\u00edble\" loading=\"lazy\">\r\n    <div class=\"cvx-overlay\">\r\n      <span class=\"cvx-accent\"><\/span>\r\n      <div class=\"cvx-text\">\r\n        <h3>Bater\u00eda extra\u00edble<\/h3>\r\n        <p>Autonom\u00eda extendida y reemplazo en segundos. Pensada para sesiones en movimiento.<\/p>\r\n      <\/div>\r\n    <\/div>\r\n  <\/article>\r\n\r\n  <!-- Card 2 -->\r\n  <article class=\"cvx-card\" tabindex=\"0\" role=\"button\"\r\n           data-full=\"\/wp-content\/uploads\/cubevox-multimedia-keypad-closeup.webp\"\r\n           data-caption=\"M\u00f3dulo multimedia \u2014 Controles retroiluminados y acceso directo a reproducci\u00f3n, carga y almacenamiento.\">\r\n    <img decoding=\"async\" class=\"cvx-img\" src=\"\/wp-content\/uploads\/cubevox-multimedia-keypad-closeup.webp\" alt=\"M\u00f3dulo multimedia\" loading=\"lazy\">\r\n    <div class=\"cvx-overlay\">\r\n      <span class=\"cvx-accent\"><\/span>\r\n      <div class=\"cvx-text\">\r\n        <h3>M\u00f3dulo multimedia<\/h3>\r\n        <p>Controles retroiluminados y acceso directo a reproducci\u00f3n, carga y almacenamiento.<\/p>\r\n      <\/div>\r\n    <\/div>\r\n  <\/article>\r\n\r\n  <!-- Card 3 -->\r\n  <article class=\"cvx-card\" tabindex=\"0\" role=\"button\"\r\n           data-full=\"\/wp-content\/uploads\/cubevox-hifi-back-isometric-render.webp\"\r\n           data-caption=\"Conectividad \u2014 USB-C, USB-A, MIDI, Bluetooth 5.1, Wi-Fi 2.4 GHz y NFC para un flujo sin fricci\u00f3n.\">\r\n    <img decoding=\"async\" class=\"cvx-img\" src=\"\/wp-content\/uploads\/cubevox-hifi-back-isometric-render.webp\" alt=\"Conectividad\" loading=\"lazy\">\r\n    <div class=\"cvx-overlay\">\r\n      <span class=\"cvx-accent\"><\/span>\r\n      <div class=\"cvx-text\">\r\n        <h3>Conectividad<\/h3>\r\n        <p>USB-C, USB-A, MIDI, Bluetooth 5.1, Wi-Fi 2.4 GHz y NFC para un flujo sin fricci\u00f3n.<\/p>\r\n      <\/div>\r\n    <\/div>\r\n  <\/article>\r\n\r\n  <!-- Card 4 -->\r\n  <article class=\"cvx-card\" tabindex=\"0\" role=\"button\"\r\n           data-full=\"\/wp-content\/uploads\/cubevox-equalizer-closeup.webp\"\r\n           data-caption=\"DSP + EQ param\u00e9trico \u2014 Procesamiento en tiempo real con ruteo configurable y control f\u00edsico inmediato.\">\r\n    <img decoding=\"async\" class=\"cvx-img\" src=\"\/wp-content\/uploads\/cubevox-equalizer-closeup.webp\" alt=\"DSP + EQ param\u00e9trico\" loading=\"lazy\">\r\n    <div class=\"cvx-overlay\">\r\n      <span class=\"cvx-accent\"><\/span>\r\n      <div class=\"cvx-text\">\r\n        <h3>DSP + EQ param\u00e9trico<\/h3>\r\n        <p>Procesamiento en tiempo real con ruteo configurable y control f\u00edsico inmediato.<\/p>\r\n      <\/div>\r\n    <\/div>\r\n  <\/article>\r\n<\/div>\r\n\r\n<!-- Lightbox (sin bot\u00f3n de cerrar; cierra tocando el fondo o con ESC) -->\r\n<div id=\"cvx-lightbox\" class=\"cvx-lightbox\" aria-hidden=\"true\">\r\n  <figure class=\"cvx-lb-figure\" role=\"document\">\r\n    <img class=\"cvx-lb-img\" alt=\"\">\r\n    <figcaption class=\"cvx-lb-caption\"><\/figcaption>\r\n  <\/figure>\r\n<\/div>\r\n\r\n<style>\r\n  \/* ====== GRID (2x2 SIEMPRE, tambi\u00e9n en m\u00f3vil) ====== *\/\r\n  #cvx-feature-grid.cvx-feature-grid{\r\n    --radius: 18px;\r\n    --gap: 22px;\r\n\r\n    \/* overlay cards *\/\r\n    --overlayH: 40%;\r\n    --accent: #38BDF8;\r\n    --glassTop: rgba(10,18,28,0.10);\r\n    --glassBot: rgba(10,18,28,0.34);\r\n    --text: rgba(255,255,255,0.92);\r\n    --muted: rgba(255,255,255,0.78);\r\n\r\n    display: grid !important;\r\n    grid-template-columns: repeat(2, minmax(0, 1fr)) !important;\r\n    gap: var(--gap) !important;\r\n    align-items: stretch !important;\r\n\r\n    width: 100%;\r\n    box-sizing: border-box;\r\n  }\r\n\r\n  @media (max-width: 1024px){\r\n    #cvx-feature-grid.cvx-feature-grid{\r\n      grid-template-columns: repeat(2, minmax(0, 1fr)) !important;\r\n    }\r\n  }\r\n  @media (max-width: 767px){\r\n    #cvx-feature-grid.cvx-feature-grid{\r\n      grid-template-columns: repeat(2, minmax(0, 1fr)) !important;\r\n      gap: 12px !important;\r\n    }\r\n  }\r\n\r\n  \/* ====== CARD ====== *\/\r\n  #cvx-feature-grid .cvx-card{\r\n    position: relative;\r\n    border-radius: var(--radius);\r\n    overflow: hidden;\r\n    background: #0b111a;\r\n    box-shadow: 0 18px 45px rgba(0,0,0,0.45);\r\n    transform: translateZ(0);\r\n\r\n    aspect-ratio: 16 \/ 14;\r\n    min-height: 0;\r\n    min-width: 0;\r\n\r\n    cursor: zoom-in;\r\n    outline: none;\r\n  }\r\n\r\n  #cvx-feature-grid .cvx-card:focus-visible{\r\n    box-shadow: 0 18px 45px rgba(0,0,0,0.45), 0 0 0 2px rgba(56,189,248,0.55);\r\n  }\r\n\r\n  #cvx-feature-grid .cvx-img{\r\n    position: absolute;\r\n    inset: 0;\r\n    width: 100%;\r\n    height: 100%;\r\n    display: block;\r\n    object-fit: cover;\r\n    object-position: center;\r\n    transform: scale(1.03);\r\n    filter: saturate(1.05) contrast(1.03);\r\n    transition: transform 450ms ease;\r\n  }\r\n\r\n  \/* ====== OVERLAY ====== *\/\r\n  #cvx-feature-grid .cvx-overlay{\r\n    position: absolute;\r\n    left: 0; right: 0; bottom: 0;\r\n    height: var(--overlayH);\r\n    display: grid;\r\n    grid-template-columns: 8px 1fr;\r\n    gap: 14px;\r\n    padding: 14px 16px 16px 14px;\r\n\r\n    background: linear-gradient(180deg, var(--glassTop), var(--glassBot));\r\n    backdrop-filter: blur(14px) saturate(1.15);\r\n    -webkit-backdrop-filter: blur(14px) saturate(1.15);\r\n  }\r\n\r\n  #cvx-feature-grid .cvx-accent{\r\n    width: 4px;\r\n    border-radius: 999px;\r\n    background: linear-gradient(180deg, rgba(56,189,248,0.95), rgba(96,165,250,0.75));\r\n    align-self: stretch;\r\n    margin-top: 2px;\r\n    box-shadow: 0 0 18px rgba(56,189,248,0.22);\r\n  }\r\n\r\n  #cvx-feature-grid .cvx-text h3{\r\n    margin: 0;\r\n    color: var(--text);\r\n    font-size: 15px;\r\n    line-height: 1.15;\r\n    font-weight: 600;\r\n\r\n    display: -webkit-box;\r\n    -webkit-box-orient: vertical;\r\n    -webkit-line-clamp: 1;\r\n    overflow: hidden;\r\n    min-height: 1.5em;\r\n  }\r\n\r\n  #cvx-feature-grid .cvx-text p{\r\n    margin: 0;\r\n    color: var(--muted);\r\n    font-size: 11px;\r\n    line-height: 1;\r\n    font-weight: 400;\r\n\r\n    display: -webkit-box;\r\n    -webkit-box-orient: vertical;\r\n    -webkit-line-clamp: 3;\r\n    overflow: hidden;\r\n  }\r\n\r\n  #cvx-feature-grid .cvx-card:hover .cvx-img{\r\n    transform: scale(1.08);\r\n  }\r\n\r\n  #cvx-feature-grid .cvx-card::after{\r\n    content:\"\";\r\n    position:absolute;\r\n    inset:0;\r\n    border-radius: var(--radius);\r\n    pointer-events:none;\r\n    box-shadow: inset 0 0 0 1px rgba(255,255,255,0.07);\r\n  }\r\n\r\n  \/* ====== AJUSTES SOLO CELULAR: overlay m\u00e1s compacto + m\u00e1s texto ====== *\/\r\n  @media (max-width: 767px){\r\n    #cvx-feature-grid .cvx-overlay{\r\n      padding: 10px !important;\r\n      gap: 8px !important;\r\n      grid-template-columns: 6px 1fr !important;\r\n      height: 48% !important;\r\n    }\r\n\r\n    #cvx-feature-grid .cvx-accent{\r\n      width: 3px !important;\r\n      margin-top: 0 !important;\r\n    }\r\n\r\n    #cvx-feature-grid .cvx-text p{\r\n      -webkit-line-clamp: 4 !important;\r\n      line-height: 1.1 !important;\r\n    }\r\n\r\n    #cvx-feature-grid .cvx-text h3{\r\n      font-size: 13px !important;\r\n    }\r\n    #cvx-feature-grid .cvx-text p{\r\n      font-size: 10px !important;\r\n      line-height: 1.05 !important;\r\n    }\r\n  }\r\n\r\n  \/* ====== LIGHTBOX (sin bot\u00f3n, con blur elegante + animaci\u00f3n) ====== *\/\r\n  .cvx-lightbox{\r\n    position: fixed;\r\n    inset: 0;\r\n    z-index: 999999;\r\n    padding: 18px;\r\n    box-sizing: border-box;\r\n\r\n    \/* Estado cerrado (pero presente para permitir transici\u00f3n) *\/\r\n    display: grid;\r\n    place-items: center;\r\n    opacity: 0;\r\n    visibility: hidden;\r\n    pointer-events: none;\r\n\r\n    background: rgba(0,0,0,0.76);\r\n    backdrop-filter: blur(10px) saturate(1.05);\r\n    -webkit-backdrop-filter: blur(10px) saturate(1.05);\r\n\r\n    transition: opacity 220ms ease, visibility 220ms ease;\r\n  }\r\n\r\n  .cvx-lightbox.is-open{\r\n    opacity: 1;\r\n    visibility: visible;\r\n    pointer-events: auto;\r\n  }\r\n\r\n  \/* Animaci\u00f3n del contenido *\/\r\n  .cvx-lb-figure{\r\n    margin: 0;\r\n    width: min(980px, 92vw);\r\n    max-height: 88vh;\r\n    display: grid;\r\n    gap: 12px;\r\n    align-items: center;\r\n    justify-items: center;\r\n\r\n    opacity: 0;\r\n    transform: translateY(10px) scale(0.985);\r\n    transition: transform 260ms ease, opacity 220ms ease;\r\n  }\r\n\r\n  .cvx-lightbox.is-open .cvx-lb-figure{\r\n    opacity: 1;\r\n    transform: translateY(0) scale(1);\r\n  }\r\n\r\n  \/* Estado \u201ccerrando\u201d para animar salida *\/\r\n  .cvx-lightbox.is-closing{\r\n    opacity: 0;\r\n    visibility: visible; \/* mantiene visible durante la salida *\/\r\n    pointer-events: none;\r\n  }\r\n  .cvx-lightbox.is-closing .cvx-lb-figure{\r\n    opacity: 0;\r\n    transform: translateY(8px) scale(0.99);\r\n  }\r\n\r\n  \/* Imagen con bordes redondeados *\/\r\n  .cvx-lb-img{\r\n    width: auto;\r\n    max-width: 92vw;\r\n    height: auto;\r\n    max-height: 78vh;\r\n\r\n    border-radius: 18px; \/* m\u00e1s redondeado *\/\r\n    box-shadow: 0 30px 80px rgba(0,0,0,0.62);\r\n    transform: translateZ(0);\r\n  }\r\n\r\n  \/* Texto como \u201cbanner\u201d con blur gris elegante *\/\r\n  .cvx-lb-caption{\r\n    max-width: min(980px, 92vw);\r\n    color: rgba(255,255,255,0.90);\r\n    font-size: 13px;\r\n    line-height: 1.25;\r\n    text-align: center;\r\n\r\n    padding: 10px 14px;\r\n    border-radius: 14px;\r\n\r\n    background: linear-gradient(180deg, rgba(160,160,160,0.12), rgba(60,60,60,0.26));\r\n    backdrop-filter: blur(14px) saturate(1.05);\r\n    -webkit-backdrop-filter: blur(14px) saturate(1.05);\r\n\r\n    box-shadow: inset 0 0 0 1px rgba(255,255,255,0.08);\r\n  }\r\n\r\n  \/* Bloqueo de scroll cuando el lightbox est\u00e1 abierto *\/\r\n  body.cvx-lb-open{\r\n    overflow: hidden !important;\r\n  }\r\n<\/style>\r\n\r\n<script>\r\n(function(){\r\n  function ready(fn){\r\n    if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', fn);\r\n    else fn();\r\n  }\r\n\r\n  ready(function(){\r\n    var grid = document.getElementById('cvx-feature-grid');\r\n    if (!grid) return;\r\n\r\n    var lb = document.getElementById('cvx-lightbox');\r\n    if (!lb) return;\r\n\r\n    var imgEl = lb.querySelector('.cvx-lb-img');\r\n    var capEl = lb.querySelector('.cvx-lb-caption');\r\n\r\n    var CLOSE_MS = 260; \/\/ debe ser >= a las transiciones del figure\/lightbox\r\n\r\n    function openLightbox(src, caption, alt){\r\n      \/\/ Reset de estados\r\n      lb.classList.remove('is-closing');\r\n      lb.classList.add('is-open');\r\n      lb.setAttribute('aria-hidden','false');\r\n      document.body.classList.add('cvx-lb-open');\r\n\r\n      imgEl.src = src;\r\n      imgEl.alt = alt || '';\r\n      capEl.textContent = caption || '';\r\n    }\r\n\r\n    function closeLightbox(){\r\n      if (!lb.classList.contains('is-open')) return;\r\n\r\n      lb.classList.add('is-closing');\r\n      lb.classList.remove('is-open');\r\n      lb.setAttribute('aria-hidden','true');\r\n      document.body.classList.remove('cvx-lb-open');\r\n\r\n      \/\/ limpiar al final para evitar \u201cflash\u201d al reabrir\r\n      window.setTimeout(function(){\r\n        lb.classList.remove('is-closing');\r\n        imgEl.removeAttribute('src');\r\n        imgEl.alt = '';\r\n        capEl.textContent = '';\r\n      }, CLOSE_MS);\r\n    }\r\n\r\n    \/\/ Abrir al click\/tap en tarjeta\r\n    grid.addEventListener('click', function(e){\r\n      var card = e.target.closest('.cvx-card');\r\n      if (!card || !grid.contains(card)) return;\r\n\r\n      var full = card.getAttribute('data-full');\r\n      var caption = card.getAttribute('data-caption') || '';\r\n      var img = card.querySelector('.cvx-img');\r\n      var alt = img ? img.getAttribute('alt') : '';\r\n\r\n      if (full) openLightbox(full, caption, alt);\r\n    });\r\n\r\n    \/\/ Abrir con teclado (Enter \/ Space) cuando la tarjeta tiene foco\r\n    grid.addEventListener('keydown', function(e){\r\n      var card = e.target.closest('.cvx-card');\r\n      if (!card || !grid.contains(card)) return;\r\n\r\n      if (e.key === 'Enter' || e.key === ' '){\r\n        e.preventDefault();\r\n        var full = card.getAttribute('data-full');\r\n        var caption = card.getAttribute('data-caption') || '';\r\n        var img = card.querySelector('.cvx-img');\r\n        var alt = img ? img.getAttribute('alt') : '';\r\n        if (full) openLightbox(full, caption, alt);\r\n      }\r\n    });\r\n\r\n    \/\/ Cerrar tocando el fondo (cualquier click fuera del figure)\r\n    lb.addEventListener('click', function(e){\r\n      var insideFigure = e.target.closest('.cvx-lb-figure');\r\n      if (!insideFigure) closeLightbox();\r\n    });\r\n\r\n    \/\/ Cerrar con ESC\r\n    document.addEventListener('keydown', function(e){\r\n      if (e.key === 'Escape' && (lb.classList.contains('is-open') || lb.classList.contains('is-closing'))){\r\n        closeLightbox();\r\n      }\r\n    });\r\n  });\r\n})();\r\n<\/script>\r\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-fae6b93 elementor-widget elementor-widget-text-editor\" data-id=\"fae6b93\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Toc\u00e1 la imagen para verla en grande. Toc\u00e1 fuera para volver.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-3fb7406 fx_section elementor-section-items-stretch elementor-section-height-min-height elementor-section-boxed elementor-section-height-default\" data-id=\"3fb7406\" data-element_type=\"section\" data-e-type=\"section\" id=\"compact\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;,&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t\t<div class=\"elementor-background-overlay\"><\/div>\n\t\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-50 elementor-top-column elementor-element elementor-element-6badfbc\" data-id=\"6badfbc\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<section class=\"elementor-section elementor-inner-section elementor-element elementor-element-e3d098c elementor-section-full_width elementor-section-height-default elementor-section-height-default\" data-id=\"e3d098c\" data-element_type=\"section\" data-e-type=\"section\" data-settings=\"{&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-no\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-inner-column elementor-element elementor-element-a22a09c\" data-id=\"a22a09c\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-94efa8b animated-slow elementor-invisible elementor-widget elementor-widget-heading\" data-id=\"94efa8b\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;slideInDown&quot;}\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Compacto<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-0c39003 elementor-invisible elementor-widget elementor-widget-ha-svg-draw happy-addon ha-svg-draw\" data-id=\"0c39003\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;slideInLeft&quot;}\" data-widget_type=\"ha-svg-draw.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\n\t\t\t\t<div class=\"ha-svg-draw-container\">\n\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t\n  \n    \n      \n      \n    \n  \n  \n\n\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t<\/div>\n\n\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-inner-section elementor-element elementor-element-43da594 elementor-section-full_width elementor-section-height-default elementor-section-height-default\" data-id=\"43da594\" data-element_type=\"section\" data-e-type=\"section\" data-settings=\"{&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-no\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-inner-column elementor-element elementor-element-67de346\" data-id=\"67de346\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-69713d4 animated-slow elementor-invisible elementor-widget elementor-widget-heading\" data-id=\"69713d4\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;fadeIn&quot;}\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Compacto<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-5506859 elementor-invisible elementor-widget elementor-widget-heading\" data-id=\"5506859\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;fadeInDown&quot;}\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">y resistente<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-85bef7b elementor-invisible elementor-widget elementor-widget-text-editor\" data-id=\"85bef7b\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;fadeInLeft&quot;}\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p><span style=\"color: #80afd9;\">Dise\u00f1ado para <\/span><b>moverse<\/b><\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-inner-section elementor-element elementor-element-4e2b370 elementor-section-full_width elementor-section-height-default elementor-section-height-default\" data-id=\"4e2b370\" data-element_type=\"section\" data-e-type=\"section\" data-settings=\"{&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-inner-column elementor-element elementor-element-857f266\" data-id=\"857f266\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-365f325 elementor-widget__width-initial animated-slow elementor-view-default elementor-invisible elementor-widget elementor-widget-icon\" data-id=\"365f325\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;fadeIn&quot;}\" data-widget_type=\"icon.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-icon-wrapper\">\n\t\t\t<div class=\"elementor-icon\">\n\t\t\t<i aria-hidden=\"true\" class=\"fas fa-weight-hanging\"><\/i>\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-6aa7458 elementor-widget__width-initial animated-slow elementor-invisible elementor-widget elementor-widget-text-editor\" data-id=\"6aa7458\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;fadeIn&quot;}\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>2,5 kg<\/p><h3 style=\"font-size: 13px;\"><span style=\"color: #c8c8c8;\">Con baterias incluidas<\/span><\/h3>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-6aff120 elementor-widget__width-initial elementor-widget elementor-widget-html\" data-id=\"6aff120\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<div class=\"cvx-sep-css\"><\/div>\r\n\r\n<style>\r\n  .cvx-sep-css{\r\n    width:100%;\r\n    height:2px;\r\n    border-radius:999px;\r\n    background: linear-gradient(\r\n      90deg,\r\n      rgba(199,207,218,0) 0%,\r\n      rgba(199,207,218,0.40) 18%,\r\n      rgba(199,207,218,0.65) 50%,\r\n      rgba(199,207,218,0.40) 82%,\r\n      rgba(199,207,218,0) 100%\r\n    );\r\n  }\r\n<\/style>\r\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-4a4dc28 elementor-widget__width-initial animated-slow elementor-view-default elementor-invisible elementor-widget elementor-widget-icon\" data-id=\"4a4dc28\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;fadeIn&quot;,&quot;_animation_delay&quot;:400}\" data-widget_type=\"icon.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-icon-wrapper\">\n\t\t\t<div class=\"elementor-icon\">\n\t\t\t<i aria-hidden=\"true\" class=\"fas fa-ruler-combined\"><\/i>\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-8f21c3f elementor-widget__width-initial animated-slow elementor-widget-mobile__width-initial elementor-invisible elementor-widget elementor-widget-text-editor\" data-id=\"8f21c3f\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;fadeIn&quot;,&quot;_animation_delay&quot;:400}\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>10&#215;10 cm<\/p><h3 style=\"font-size: 13px;\"><span style=\"color: #c8c8c8;\">Cabe en tu mano<\/span><\/h3>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-cd86d76 elementor-widget elementor-widget-html\" data-id=\"cd86d76\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<div class=\"cvx-sep-css\"><\/div>\r\n\r\n<style>\r\n  .cvx-sep-css{\r\n    width:100%;\r\n    height:2px;\r\n    border-radius:999px;\r\n    background: linear-gradient(\r\n      90deg,\r\n      rgba(199,207,218,0) 0%,\r\n      rgba(199,207,218,0.40) 18%,\r\n      rgba(199,207,218,0.85) 50%,\r\n      rgba(199,207,218,0.40) 82%,\r\n      rgba(199,207,218,0) 100%\r\n    );\r\n  }\r\n<\/style>\r\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-624459f elementor-widget__width-initial animated-slow elementor-view-default elementor-invisible elementor-widget elementor-widget-icon\" data-id=\"624459f\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;fadeIn&quot;,&quot;_animation_delay&quot;:800}\" data-widget_type=\"icon.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-icon-wrapper\">\n\t\t\t<div class=\"elementor-icon\">\n\t\t\t<i aria-hidden=\"true\" class=\"huge huge-arrow-horizontal\"><\/i>\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-297c504 elementor-widget__width-initial animated-slow elementor-invisible elementor-widget elementor-widget-text-editor\" data-id=\"297c504\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;fadeIn&quot;,&quot;_animation_delay&quot;:800}\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>25 cm<\/p><h3 style=\"font-size: 13px;\"><span style=\"color: #c8c8c8;\">Cerrado<\/span><\/h3>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-49e06fd elementor-widget elementor-widget-html\" data-id=\"49e06fd\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<div class=\"cvx-sep-css\"><\/div>\r\n\r\n<style>\r\n  .cvx-sep-css{\r\n    width:100%;\r\n    height:2px;\r\n    border-radius:999px;\r\n    background: linear-gradient(\r\n      90deg,\r\n      rgba(199,207,218,0) 0%,\r\n      rgba(199,207,218,0.40) 18%,\r\n      rgba(199,207,218,0.85) 50%,\r\n      rgba(199,207,218,0.40) 82%,\r\n      rgba(199,207,218,0) 100%\r\n    );\r\n  }\r\n<\/style>\r\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-b5ffd77 elementor-widget__width-initial animated-slow elementor-view-default elementor-invisible elementor-widget elementor-widget-icon\" data-id=\"b5ffd77\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;fadeIn&quot;,&quot;_animation_delay&quot;:1200}\" data-widget_type=\"icon.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-icon-wrapper\">\n\t\t\t<div class=\"elementor-icon\">\n\t\t\t<i aria-hidden=\"true\" class=\"fas fa-shield-alt\"><\/i>\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-dc6aa4a elementor-widget__width-initial animated-slow elementor-invisible elementor-widget elementor-widget-text-editor\" data-id=\"dc6aa4a\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;fadeIn&quot;,&quot;_animation_delay&quot;:1200}\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Aluminio anodizado<\/p><h3 style=\"font-size: 13px;\"><span style=\"color: #c8c8c8;\">Cuerpo resistente, listo para uso diario<\/span><\/h3>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t<div class=\"elementor-column elementor-col-50 elementor-top-column elementor-element elementor-element-ea0d815 elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile\" data-id=\"ea0d815\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap\">\n\t\t\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-656af80 elementor-section-height-min-height elementor-section-items-stretch fx_section elementor-section-boxed elementor-section-height-default\" data-id=\"656af80\" data-element_type=\"section\" data-e-type=\"section\" id=\"sonidoAcustica\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;,&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t\t<div class=\"elementor-background-overlay\"><\/div>\n\t\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-58efc21\" data-id=\"58efc21\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<section class=\"elementor-section elementor-inner-section elementor-element elementor-element-a02dfc5 elementor-section-full_width elementor-section-height-default elementor-section-height-default\" data-id=\"a02dfc5\" data-element_type=\"section\" data-e-type=\"section\" data-settings=\"{&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-no\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-inner-column elementor-element elementor-element-629dfed\" data-id=\"629dfed\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-91e124a animated-slow elementor-invisible elementor-widget elementor-widget-heading\" data-id=\"91e124a\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;slideInDown&quot;}\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Sonido \/ Ac\u00fastica<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-1911c9d elementor-invisible elementor-widget elementor-widget-ha-svg-draw happy-addon ha-svg-draw\" data-id=\"1911c9d\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;slideInLeft&quot;}\" data-widget_type=\"ha-svg-draw.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\n\t\t\t\t<div class=\"ha-svg-draw-container\">\n\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t\n  \n    \n      \n      \n    \n  \n  \n\n\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t<\/div>\n\n\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-inner-section elementor-element elementor-element-c025adb elementor-section-full_width elementor-section-height-default elementor-section-height-default\" data-id=\"c025adb\" data-element_type=\"section\" data-e-type=\"section\" data-settings=\"{&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-no\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-inner-column elementor-element elementor-element-70be460\" data-id=\"70be460\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-8038cdf elementor-invisible elementor-widget elementor-widget-heading\" data-id=\"8038cdf\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;fadeIn&quot;}\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">La potencia que buscas<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-2dcaab6 elementor-invisible elementor-widget elementor-widget-heading\" data-id=\"2dcaab6\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;fadeInDown&quot;}\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">con proyecci\u00f3n envolvente<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-8124791 animated-slow elementor-invisible elementor-widget elementor-widget-counter\" data-id=\"8124791\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;fadeInUp&quot;,&quot;_animation_delay&quot;:500}\" data-widget_type=\"counter.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-counter\">\n\t\t\t\t\t\t<div class=\"elementor-counter-number-wrapper\">\n\t\t\t\t<span class=\"elementor-counter-number-prefix\">Hasta <\/span>\n\t\t\t\t<span class=\"elementor-counter-number\" data-duration=\"3000\" data-to-value=\"98\" data-from-value=\"0\">0<\/span>\n\t\t\t\t<span class=\"elementor-counter-number-suffix\"> dB SPL<\/span>\n\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-2f1384c animated-slow elementor-invisible elementor-widget elementor-widget-accordion\" data-id=\"2f1384c\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;fadeIn&quot;,&quot;_animation_delay&quot;:1000}\" data-widget_type=\"accordion.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-accordion\">\n\t\t\t\t\t\t\t<div class=\"elementor-accordion-item\">\n\t\t\t\t\t<div id=\"elementor-tab-title-4931\" class=\"elementor-tab-title\" data-tab=\"1\" role=\"button\" aria-controls=\"elementor-tab-content-4931\" aria-expanded=\"false\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<span class=\"elementor-accordion-icon elementor-accordion-icon-left\" aria-hidden=\"true\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<span class=\"elementor-accordion-icon-closed\"><i class=\"fas fa-chevron-down\"><\/i><\/span>\n\t\t\t\t\t\t\t\t<span class=\"elementor-accordion-icon-opened\"><i class=\"fas fa-chevron-up\"><\/i><\/span>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/span>\n\t\t\t\t\t\t\t\t\t\t\t\t<a class=\"elementor-accordion-title\" tabindex=\"0\">4 x Transductores BMR<\/a>\n\t\t\t\t\t<\/div>\n\t\t\t\t\t<div id=\"elementor-tab-content-4931\" class=\"elementor-tab-content elementor-clearfix\" data-tab=\"1\" role=\"region\" aria-labelledby=\"elementor-tab-title-4931\"><p>Los BMR generan una <strong data-start=\"2272\" data-end=\"2293\">dispersi\u00f3n amplia<\/strong> para que el sonido se mantenga consistente a lo largo de la habitaci\u00f3n. Escuch\u00e1s definici\u00f3n y balance sin depender de estar \u201cfrente al parlante\u201d. M\u00e1s escena, menos puntos ciegos.<\/p><\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t\t\t<div class=\"elementor-accordion-item\">\n\t\t\t\t\t<div id=\"elementor-tab-title-4932\" class=\"elementor-tab-title\" data-tab=\"2\" role=\"button\" aria-controls=\"elementor-tab-content-4932\" aria-expanded=\"false\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<span class=\"elementor-accordion-icon elementor-accordion-icon-left\" aria-hidden=\"true\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<span class=\"elementor-accordion-icon-closed\"><i class=\"fas fa-chevron-down\"><\/i><\/span>\n\t\t\t\t\t\t\t\t<span class=\"elementor-accordion-icon-opened\"><i class=\"fas fa-chevron-up\"><\/i><\/span>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/span>\n\t\t\t\t\t\t\t\t\t\t\t\t<a class=\"elementor-accordion-title\" tabindex=\"0\">4 x Radiadores Pasivos<\/a>\n\t\t\t\t\t<\/div>\n\t\t\t\t\t<div id=\"elementor-tab-content-4932\" class=\"elementor-tab-content elementor-clearfix\" data-tab=\"2\" role=\"region\" aria-labelledby=\"elementor-tab-title-4932\"><p>Optimizamos los recintos mediante An\u00e1lisis de Elementos Finitos (FEA), para que los radiadores pasivos aporten <strong data-start=\"2552\" data-end=\"2576\">graves con autoridad<\/strong> manteniendo control y eficiencia. El resultado es un low-end m\u00e1s s\u00f3lido, con menos compresi\u00f3n perceptible cuando sub\u00eds el volumen.<\/p><\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-307ea7c elementor-section-height-min-height elementor-section-items-stretch fx_section elementor-section-boxed elementor-section-height-default\" data-id=\"307ea7c\" data-element_type=\"section\" data-e-type=\"section\" id=\"specs\" data-settings=\"{&quot;background_background&quot;:&quot;gradient&quot;,&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t\t<div class=\"elementor-background-overlay\"><\/div>\n\t\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-dcc90a4\" data-id=\"dcc90a4\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<section class=\"elementor-section elementor-inner-section elementor-element elementor-element-07a6f15 elementor-section-full_width elementor-section-height-default elementor-section-height-default\" data-id=\"07a6f15\" data-element_type=\"section\" data-e-type=\"section\" data-settings=\"{&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-no\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-inner-column elementor-element elementor-element-402e8fb\" data-id=\"402e8fb\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-9949cb3 animated-slow elementor-invisible elementor-widget elementor-widget-heading\" data-id=\"9949cb3\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;slideInDown&quot;}\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">DATOS T\u00c9CNICOS<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-327a5b7 elementor-invisible elementor-widget elementor-widget-ha-svg-draw happy-addon ha-svg-draw\" data-id=\"327a5b7\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;slideInLeft&quot;}\" data-widget_type=\"ha-svg-draw.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\n\t\t\t\t<div class=\"ha-svg-draw-container\">\n\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t\n  \n    \n      \n      \n    \n  \n  \n\n\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t<\/div>\n\n\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-inner-section elementor-element elementor-element-bc01484 elementor-section-full_width elementor-section-height-default elementor-section-height-default\" data-id=\"bc01484\" data-element_type=\"section\" data-e-type=\"section\" data-settings=\"{&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-no\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-inner-column elementor-element elementor-element-e833a2c\" data-id=\"e833a2c\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-e4731c3 animated-slow elementor-invisible elementor-widget elementor-widget-heading\" data-id=\"e4731c3\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;fadeIn&quot;,&quot;_animation_delay&quot;:300}\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Definici\u00f3n del producto<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-e68dd1d elementor-invisible elementor-widget elementor-widget-heading\" data-id=\"e68dd1d\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;fadeInDown&quot;,&quot;_animation_delay&quot;:200}\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Comparativa por rol y ficha t\u00e9cnica<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-inner-section elementor-element elementor-element-5e00ccc elementor-section-full_width elementor-section-height-default elementor-section-height-default\" data-id=\"5e00ccc\" data-element_type=\"section\" data-e-type=\"section\" data-settings=\"{&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-no\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-inner-column elementor-element elementor-element-3f96726\" data-id=\"3f96726\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-8d0efba elementor-widget elementor-widget-html\" data-id=\"8d0efba\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<!-- =====================================================\r\n     COMPONENT: Technical Data (Comparativa + Especificaciones)\r\n        Root: .cvxScope [data-cvx-root=\"tech-data\"]\r\n        Notes:\r\n       - Replace the image URLs with your WP Media URLs.\r\n       - Starter Kit is assumed globally loaded (tokens + base components).\r\n===================================================== -->\r\n\r\n<div class=\"cvxScope\">\r\n\r\n    <section data-cvx-root=\"tech-data\" data-cvx-tech-compare=\"speaker\" style=\"\r\n      \/* PARAMETERS (per-instance) *\/\r\n      --cvx-tech-maxw: 1120px;\r\n      --cvx-tech-pad: 0px;\r\n      --cvx-tech-gap: 14px;\r\n      --cvx-tech-radius: 18px;\r\n      --cvx-tech-stroke-a: 0.14;\r\n      --cvx-tech-surface-a: 0.02;\r\n      --cvx-tech-blur: 14px;\r\n      --cvx-tech-tab-h: 42px;\r\n      --cvx-tech-img-ar: 16\/9;\r\n      --cvx-tech-modal-z: 80;\r\n\r\n      \/* IMAGE SOURCES (set WP Media URLs here) *\/\r\n      --cvx-tech-img-infographic: \/wp-content\/uploads\/cubevox-hifi-technical-infographic-es.webp;\r\n    \">\r\n        <div class=\"cvxPanel\">\r\n\r\n            <!-- HEADER \r\n            <header class=\"cvxTechHead\">\r\n                <div class=\"cvxTechKicker\">DATOS T\u00c9CNICOS<\/div>\r\n                <h2 class=\"cvxTechTitle\">Definici\u00f3n del producto<\/h2>\r\n                <p class=\"cvxTechDesc\">Comparativa por rol y ficha t\u00e9cnica para validar con detalle.<\/p>\r\n            <\/header>\r\n-->\r\n            <!-- TABS -->\r\n            <nav class=\"cvxTechTabs\" role=\"tablist\" aria-label=\"Datos t\u00e9cnicos\">\r\n                <button type=\"button\" class=\"cvxTechTab\" role=\"tab\" aria-selected=\"true\" aria-controls=\"cvxTechPanelCompare\" data-cvx-tech-tab=\"compare\">\r\n                    Comparativa\r\n                <\/button>\r\n                <button type=\"button\" class=\"cvxTechTab\" role=\"tab\" aria-selected=\"false\" aria-controls=\"cvxTechPanelSpecs\" data-cvx-tech-tab=\"specs\" tabindex=\"-1\">\r\n                    Especificaciones\r\n                <\/button>\r\n            <\/nav>\r\n\r\n            <!-- PANELS -->\r\n            <div class=\"cvxTechPanels\">\r\n                <!-- Panel: Comparativa -->\r\n                <section id=\"cvxTechPanelCompare\" class=\"cvxTechPanel\" role=\"tabpanel\" tabindex=\"0\" data-cvx-tech-panel=\"compare\">\r\n                    <div class=\"cvxTechGrid cvxTechGrid--compare\">\r\n                        <article class=\"cvxTechCard cvxTechCard--wide\" data-cvx-tech-card>\r\n                            <div class=\"cvxTechCardHead\">\r\n                                <h3 class=\"cvxTechCardTitle\">Comparativa por rol<\/h3>\r\n                                <p class=\"cvxTechCardDesc\">CubeVox integra roles que normalmente requieren varios equipos. Compar\u00e1 por categor\u00eda.<\/p>\r\n                            <\/div>\r\n\r\n                            <div class=\"cvxTechComparePick\" role=\"toolbar\" aria-label=\"Comparar CubeVox con\"> <button type=\"button\" class=\"cvxTechCompareChip\" data-cvx-tech-pick=\"speaker\" aria-pressed=\"true\">Speaker<\/button>\r\n                                <button type=\"button\" class=\"cvxTechCompareChip\" data-cvx-tech-pick=\"amp\" aria-pressed=\"false\">Amplificador<\/button>\r\n                                <button type=\"button\" class=\"cvxTechCompareChip\" data-cvx-tech-pick=\"iface\" aria-pressed=\"false\">Interfaz<\/button>\r\n                                <button type=\"button\" class=\"cvxTechCompareChip\" data-cvx-tech-pick=\"mixer\" aria-pressed=\"false\">Mezcladora<\/button>\r\n                                <button type=\"button\" class=\"cvxTechCompareChip\" data-cvx-tech-pick=\"mfx\" aria-pressed=\"false\">Multi\u2011Efectos<\/button>\r\n                            <\/div>\r\n\r\n                            <div class=\"cvxTechTableWrap\" role=\"region\" aria-label=\"Tabla comparativa\" tabindex=\"0\">\r\n                                <table class=\"cvxTechTable\">\r\n                                    <thead>\r\n                                        <tr>\r\n                                            <th scope=\"col\" class=\"cvxTechTh cvxTechTh--feat\">Features<\/th>\r\n                                            <th scope=\"col\" class=\"cvxTechTh\">CubeVox<\/th>\r\n                                            <th scope=\"col\" class=\"cvxTechTh\">Speaker<\/th>\r\n                                            <th scope=\"col\" class=\"cvxTechTh\">Amplificador<\/th>\r\n                                            <th scope=\"col\" class=\"cvxTechTh\">Interfaz<\/th>\r\n                                            <th scope=\"col\" class=\"cvxTechTh\">Mezcladora<\/th>\r\n                                            <th scope=\"col\" class=\"cvxTechTh\">Multi\u2011Efectos<\/th>\r\n                                        <\/tr>\r\n                                    <\/thead>\r\n                                    <tbody>\r\n                                        <tr class=\"cvxTechTr\">\r\n                                            <th scope=\"row\" class=\"cvxTechTd cvxTechTd--feat\">\r\n                                                <div class=\"cvxTechFeat\">Salida a parlantes<\/div>\r\n                                                <div class=\"cvxTechFeatSub\">proyecci\u00f3n \u00b7 volumen \u00b7 escucha en sala<\/div>\r\n                                            <\/th>\r\n                                            <td class=\"cvxTechTd\"><span class=\"cvxTechMark cvxTechMark--yes\" aria-label=\"Completo\">\u2713<\/span><\/td>\r\n                                            <td class=\"cvxTechTd\"><span class=\"cvxTechMark cvxTechMark--yes\" aria-label=\"Completo\">\u2713<\/span><\/td>\r\n                                            <td class=\"cvxTechTd\"><span class=\"cvxTechMark cvxTechMark--yes\" aria-label=\"Completo\">\u2713<\/span><\/td>\r\n                                            <td class=\"cvxTechTd\"><span class=\"cvxTechMark cvxTechMark--no\" aria-label=\"No\">\u00d7<\/span><\/td>\r\n                                            <td class=\"cvxTechTd\"><span class=\"cvxTechMark cvxTechMark--partial\" aria-label=\"Parcial\">\u25d0<\/span><\/td>\r\n                                            <td class=\"cvxTechTd\"><span class=\"cvxTechMark cvxTechMark--no\" aria-label=\"No\">\u00d7<\/span><\/td>\r\n                                        <\/tr>\r\n\r\n                                        <tr class=\"cvxTechTr\">\r\n                                            <th scope=\"row\" class=\"cvxTechTd cvxTechTd--feat\">\r\n                                                <div class=\"cvxTechFeat\">Interfaz \/ grabaci\u00f3n<\/div>\r\n                                                <div class=\"cvxTechFeatSub\">USB \u00b7 MIDI \u00b7 monitoreo<\/div>\r\n                                            <\/th>\r\n                                            <td class=\"cvxTechTd\"><span class=\"cvxTechMark cvxTechMark--yes\" aria-label=\"Completo\">\u2713<\/span><\/td>\r\n                                            <td class=\"cvxTechTd\"><span class=\"cvxTechMark cvxTechMark--no\" aria-label=\"No\">\u00d7<\/span><\/td>\r\n                                            <td class=\"cvxTechTd\"><span class=\"cvxTechMark cvxTechMark--no\" aria-label=\"No\">\u00d7<\/span><\/td>\r\n                                            <td class=\"cvxTechTd\"><span class=\"cvxTechMark cvxTechMark--yes\" aria-label=\"Completo\">\u2713<\/span><\/td>\r\n                                            <td class=\"cvxTechTd\"><span class=\"cvxTechMark cvxTechMark--partial\" aria-label=\"Parcial\">\u25d0<\/span><\/td>\r\n                                            <td class=\"cvxTechTd\"><span class=\"cvxTechMark cvxTechMark--partial\" aria-label=\"Parcial\">\u25d0<\/span><\/td>\r\n                                        <\/tr>\r\n\r\n                                        <tr class=\"cvxTechTr\">\r\n                                            <th scope=\"row\" class=\"cvxTechTd cvxTechTd--feat\">\r\n                                                <div class=\"cvxTechFeat\">I\/O + ruteo<\/div>\r\n                                                <div class=\"cvxTechFeatSub\">m\u00faltiples entradas\/salidas \u00b7 buses \u00b7 multiplexaci\u00f3n<\/div>\r\n                                            <\/th>\r\n                                            <td class=\"cvxTechTd\"><span class=\"cvxTechMark cvxTechMark--yes\" aria-label=\"Completo\">\u2713<\/span><\/td>\r\n                                            <td class=\"cvxTechTd\"><span class=\"cvxTechMark cvxTechMark--no\" aria-label=\"No\">\u00d7<\/span><\/td>\r\n                                            <td class=\"cvxTechTd\"><span class=\"cvxTechMark cvxTechMark--no\" aria-label=\"No\">\u00d7<\/span><\/td>\r\n                                            <td class=\"cvxTechTd\"><span class=\"cvxTechMark cvxTechMark--partial\" aria-label=\"Parcial\">\u25d0<\/span><\/td>\r\n                                            <td class=\"cvxTechTd\"><span class=\"cvxTechMark cvxTechMark--yes\" aria-label=\"Completo\">\u2713<\/span><\/td>\r\n                                            <td class=\"cvxTechTd\"><span class=\"cvxTechMark cvxTechMark--no\" aria-label=\"No\">\u00d7<\/span><\/td>\r\n                                        <\/tr>\r\n\r\n                                        <tr class=\"cvxTechTr\">\r\n                                            <th scope=\"row\" class=\"cvxTechTd cvxTechTd--feat\">\r\n                                                <div class=\"cvxTechFeat\">FX en tiempo real<\/div>\r\n                                                <div class=\"cvxTechFeatSub\">DSP \u00b7 cadena \u00b7 control<\/div>\r\n                                            <\/th>\r\n                                            <td class=\"cvxTechTd\"><span class=\"cvxTechMark cvxTechMark--yes\" aria-label=\"Completo\">\u2713<\/span><\/td>\r\n                                            <td class=\"cvxTechTd\"><span class=\"cvxTechMark cvxTechMark--no\" aria-label=\"No\">\u00d7<\/span><\/td>\r\n                                            <td class=\"cvxTechTd\"><span class=\"cvxTechMark cvxTechMark--partial\" aria-label=\"Parcial\">\u25d0<\/span><\/td>\r\n                                            <td class=\"cvxTechTd\"><span class=\"cvxTechMark cvxTechMark--no\" aria-label=\"No\">\u00d7<\/span><\/td>\r\n                                            <td class=\"cvxTechTd\"><span class=\"cvxTechMark cvxTechMark--partial\" aria-label=\"Parcial\">\u25d0<\/span><\/td>\r\n                                            <td class=\"cvxTechTd\"><span class=\"cvxTechMark cvxTechMark--yes\" aria-label=\"Completo\">\u2713<\/span><\/td>\r\n                                        <\/tr>\r\n\r\n                                        <tr class=\"cvxTechTr\">\r\n                                            <th scope=\"row\" class=\"cvxTechTd cvxTechTd--feat\">\r\n                                                <div class=\"cvxTechFeat\">Presets \/ recall<\/div>\r\n                                                <div class=\"cvxTechFeatSub\">guardar \u00b7 recuperar \u00b7 bancos<\/div>\r\n                                            <\/th>\r\n                                            <td class=\"cvxTechTd\"><span class=\"cvxTechMark cvxTechMark--yes\" aria-label=\"Completo\">\u2713<\/span><\/td>\r\n                                            <td class=\"cvxTechTd\"><span class=\"cvxTechMark cvxTechMark--no\" aria-label=\"No\">\u00d7<\/span><\/td>\r\n                                            <td class=\"cvxTechTd\"><span class=\"cvxTechMark cvxTechMark--no\" aria-label=\"No\">\u00d7<\/span><\/td>\r\n                                            <td class=\"cvxTechTd\"><span class=\"cvxTechMark cvxTechMark--no\" aria-label=\"No\">\u00d7<\/span><\/td>\r\n                                            <td class=\"cvxTechTd\"><span class=\"cvxTechMark cvxTechMark--no\" aria-label=\"No\">\u00d7<\/span><\/td>\r\n                                            <td class=\"cvxTechTd\"><span class=\"cvxTechMark cvxTechMark--yes\" aria-label=\"Completo\">\u2713<\/span><\/td>\r\n                                        <\/tr>\r\n\r\n                                        <tr class=\"cvxTechTr\">\r\n                                            <th scope=\"row\" class=\"cvxTechTd cvxTechTd--feat\">\r\n                                                <div class=\"cvxTechFeat\">DAW no destructivo<\/div>\r\n                                                <div class=\"cvxTechFeatSub\">timeline \u00b7 edici\u00f3n \u00b7 export<\/div>\r\n                                            <\/th>\r\n                                            <td class=\"cvxTechTd\"><span class=\"cvxTechMark cvxTechMark--yes\" aria-label=\"Completo\">\u2713<\/span><\/td>\r\n                                            <td class=\"cvxTechTd\"><span class=\"cvxTechMark cvxTechMark--no\" aria-label=\"No\">\u00d7<\/span><\/td>\r\n                                            <td class=\"cvxTechTd\"><span class=\"cvxTechMark cvxTechMark--no\" aria-label=\"No\">\u00d7<\/span><\/td>\r\n                                            <td class=\"cvxTechTd\"><span class=\"cvxTechMark cvxTechMark--no\" aria-label=\"No\">\u00d7<\/span><\/td>\r\n                                            <td class=\"cvxTechTd\"><span class=\"cvxTechMark cvxTechMark--no\" aria-label=\"No\">\u00d7<\/span><\/td>\r\n                                            <td class=\"cvxTechTd\"><span class=\"cvxTechMark cvxTechMark--no\" aria-label=\"No\">\u00d7<\/span><\/td>\r\n                                        <\/tr>\r\n                                    <\/tbody>\r\n                                <\/table>\r\n                            <\/div>\r\n\r\n                            <div class=\"cvxTechLegend\" aria-label=\"Leyenda\">\r\n                                <div class=\"cvxTechLegendLeft\" aria-label=\"Estados\">\r\n                                    <span class=\"cvxTechLegendItem\"><span class=\"cvxTechMark cvxTechMark--yes\" aria-hidden=\"true\">\u2713<\/span>Completo<\/span>\r\n                                    <span class=\"cvxTechLegendItem\"><span class=\"cvxTechMark cvxTechMark--no\" aria-hidden=\"true\">\u00d7<\/span>No<\/span>\r\n                                <\/div>\r\n                                <div class=\"cvxTechLegendNote\">\r\n                                    <span class=\"cvxTechMark cvxTechMark--partial\" aria-hidden=\"true\">\u25d0<\/span>\r\n                                    <span>Parcial = disponible con limitaciones t\u00edpicas.<\/span>\r\n                                <\/div>\r\n                            <\/div>\r\n                        <\/article>\r\n\r\n                        <aside class=\"cvxTechCard\" data-cvx-tech-card>\r\n                            <div class=\"cvxTechCardHead\">\r\n                                <h3 class=\"cvxTechCardTitle\">Checklist t\u00e9cnico<\/h3>\r\n                                <p class=\"cvxTechCardDesc\">Qu\u00e9 incluye CubeVox en un solo sistema.<\/p>\r\n                            <\/div>\r\n\r\n                            <ul class=\"cvxTechList\" role=\"list\">\r\n                                <li class=\"cvxTechListItem\"><span class=\"cvxTechDot\" aria-hidden=\"true\"><\/span>Parlantes integrados + proyecci\u00f3n<\/li>\r\n                                <li class=\"cvxTechListItem\"><span class=\"cvxTechDot\" aria-hidden=\"true\"><\/span>I\/O configurable + ruteo<\/li>\r\n                                <li class=\"cvxTechListItem\"><span class=\"cvxTechDot\" aria-hidden=\"true\"><\/span>DSP + EQ param\u00e9trico<\/li>\r\n                                <li class=\"cvxTechListItem\"><span class=\"cvxTechDot\" aria-hidden=\"true\"><\/span>AGC y control de din\u00e1mica<\/li>\r\n                                <li class=\"cvxTechListItem\"><span class=\"cvxTechDot\" aria-hidden=\"true\"><\/span>Conectividad (USB\/MIDI\/BT\/Wi\u2011Fi\/NFC)<\/li>\r\n                                <li class=\"cvxTechListItem\"><span class=\"cvxTechDot\" aria-hidden=\"true\"><\/span>Bater\u00eda extra\u00edble + carga r\u00e1pida<\/li>\r\n                                <li class=\"cvxTechListItem\"><span class=\"cvxTechDot\" aria-hidden=\"true\"><\/span>Puerto de expansi\u00f3n (m\u00f3dulos)<\/li>\r\n                            <\/ul>\r\n\r\n                            <p class=\"cvxTechFine\">La tabla compara roles t\u00edpicos por categor\u00eda; la ficha t\u00e9cnica ampl\u00eda el detalle.<\/p>\r\n                        <\/aside>\r\n                    <\/div>\r\n\r\n                <\/section>\r\n\r\n                <!-- Panel: Especificaciones -->\r\n                <section id=\"cvxTechPanelSpecs\" class=\"cvxTechPanel\" role=\"tabpanel\" tabindex=\"0\" data-cvx-tech-panel=\"specs\" hidden>\r\n                    <div class=\"cvxTechGrid cvxTechGrid--specs\">\r\n                        <article class=\"cvxTechCard cvxTechCard--wide\" data-cvx-tech-card>\r\n                            <div class=\"cvxTechCardHead\">\r\n                                <h3 class=\"cvxTechCardTitle\">Infograf\u00eda t\u00e9cnica<\/h3>\r\n                                <p class=\"cvxTechCardDesc\">I\/O, expansi\u00f3n y controles: una vista \u00fanica para entender la arquitectura del sistema.<\/p>\r\n                            <\/div>\r\n\r\n                            <figure class=\"cvxTechFigure\">\r\n                                <div class=\"cvxTechImgWrap cvxTechImgWrap--tall\" data-cvx-tech-zoomable>\r\n                                    <img class=\"cvxTechImg\" data-cvx-tech-img=\"infographic\" alt=\"Infograf\u00eda t\u00e9cnica de CubeVox\" loading=\"lazy\" src='\/wp-content\/uploads\/cubevox-hifi-technical-infographic-es.webp' \/>\r\n                                <\/div>\r\n                                <figcaption class=\"cvxTechCap\">Infograf\u00eda \u00b7 CubeVox HiFi<\/figcaption>\r\n                            <\/figure>\r\n\r\n                            <div class=\"cvxTechCardActions\">\r\n                                <button type=\"button\" class=\"cvxTechPill\" data-cvx-tech-open data-cvx-src='\/wp-content\/uploads\/cubevox-hifi-technical-infographic-es.webp' data-cvx-img-key=\"infographic\" data-cvx-title=\"Infograf\u00eda t\u00e9cnica\">\r\n                                    Ver en grande\r\n                                <\/button>\r\n                            <\/div>\r\n                        <\/article>\r\n\r\n                        <aside class=\"cvxTechCard\" data-cvx-tech-card>\r\n                            <div class=\"cvxTechCardHead\">\r\n                                <h3 class=\"cvxTechCardTitle\">Lectura r\u00e1pida<\/h3>\r\n                                <p class=\"cvxTechCardDesc\">Un resumen de alto nivel, alineado a lo que vas a ver en la infograf\u00eda.<\/p>\r\n                            <\/div>\r\n\r\n                            <dl class=\"cvxTechDL\">\r\n                                <div class=\"cvxTechDLRow\">\r\n                                    <dt>Entradas<\/dt>\r\n                                    <dd>CH1\/CH2 instrumentos (XLR\/TRS), auxiliar TRS 3.5 y fuentes digitales (BT\/USB\/SD).<\/dd>\r\n                                <\/div>\r\n                                <div class=\"cvxTechDLRow\">\r\n                                    <dt>Salidas<\/dt>\r\n                                    <dd>Auriculares, salidas de estudio con niveles conmutables y rutas de monitor\/maestro.<\/dd>\r\n                                <\/div>\r\n                                <div class=\"cvxTechDLRow\">\r\n                                    <dt>Procesamiento<\/dt>\r\n                                    <dd>DSP + EQ param\u00e9trico por canal, control de ganancia y herramientas de ruteo.<\/dd>\r\n                                <\/div>\r\n                                <div class=\"cvxTechDLRow\">\r\n                                    <dt>Expansi\u00f3n<\/dt>\r\n                                    <dd>Puerto Studio para m\u00f3dulos (balanceado, desbalanceado, salida amplificada, etc.).<\/dd>\r\n                                <\/div>\r\n                            <\/dl>\r\n\r\n                            <p class=\"cvxTechFine\">Los valores finales y variantes de m\u00f3dulos pueden depender de la configuraci\u00f3n elegida.<\/p>\r\n                        <\/aside>\r\n                    <\/div>\r\n                <\/section>\r\n            <\/div>\r\n        <\/div>\r\n\r\n        <!-- MODAL (image zoom) -->\r\n        <div class=\"cvxTechModal\" data-cvx-tech-modal hidden>\r\n            <div class=\"cvxTechModalBackdrop\" data-cvx-tech-close><\/div>\r\n            <div class=\"cvxTechModalDialog\" role=\"dialog\" aria-modal=\"true\" aria-label=\"Vista ampliada\">\r\n                <div class=\"cvxTechModalTop\">\r\n                    <div class=\"cvxTechModalTitle\" data-cvx-tech-modal-title>Vista<\/div>\r\n                    <button type=\"button\" class=\"cvxTechModalClose\" data-cvx-tech-close aria-label=\"Cerrar\">\u2715<\/button>\r\n                <\/div>\r\n                <div class=\"cvxTechModalBody\">\r\n                    <div class=\"cvxTechZoomStage\" data-cvx-tech-zoomstage>\r\n                        <img class=\"cvxTechModalImg\" data-cvx-tech-modal-img alt=\"\" \/>\r\n                        <div class=\"cvxTechLens\" data-cvx-tech-lens hidden aria-hidden=\"true\"><\/div>\r\n                    <\/div>\r\n                <\/div>\r\n            <\/div>\r\n        <\/div>\r\n    <\/section>\r\n<\/div>\r\n<style>\r\n    \/* =====================================================\r\n     COMPONENT: Technical Data (local CSS)\r\n  ===================================================== *\/\r\n\r\n    \/* MODAL BOUNDS (usable por JS y fallback CSS) *\/\r\n    .cvxScope [data-cvx-root=\"tech-data\"] {\r\n        --cvx-tech-modal-gutter: 26px;\r\n        \/* margen total (\u224813px arriba\/abajo) *\/\r\n        --cvx-tech-modal-maxw: min(1100px, calc(100vw - var(--cvx-tech-modal-gutter)));\r\n        --cvx-tech-modal-maxh: min(calc(100vh - var(--cvx-tech-modal-gutter)), 860px);\r\n    }\r\n\r\n    \/* iOS\/Android modernos: viewport real (sin saltos por barras) *\/\r\n    @supports (height: 1dvh) {\r\n        .cvxScope [data-cvx-root=\"tech-data\"] {\r\n            --cvx-tech-modal-maxh: min(calc(100dvh - var(--cvx-tech-modal-gutter)), 860px);\r\n        }\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"tech-data\"] {\r\n        max-width: var(--cvx-tech-maxw);\r\n        margin-inline: auto;\r\n        padding: var(--cvx-tech-pad);\r\n    }\r\n.cvxScope [data-cvx-root=\"tech-data\"] [hidden] {\r\n    display: none !important;\r\n}\r\n\r\n    .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechHead {\r\n        display: grid;\r\n        gap: 8px;\r\n        margin-bottom: 14px;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechKicker {\r\n        letter-spacing: 0.18em;\r\n        text-transform: uppercase;\r\n        font-size: 12px;\r\n        color: rgba(255, 255, 255, 0.72);\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechTitle {\r\n        margin: 0;\r\n        font-size: clamp(22px, 2.2vw, 30px);\r\n        line-height: 1.08;\r\n        color: rgba(255, 255, 255, 0.96);\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechDesc {\r\n        margin: 0;\r\n        color: rgba(255, 255, 255, 0.66);\r\n        font-size: 14px;\r\n        line-height: 1.35;\r\n        max-width: 66ch;\r\n    }\r\n\r\n    \/* Tabs *\/\r\n    .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechTabs {\r\n        display: grid;\r\n        grid-auto-flow: column;\r\n        grid-auto-columns: 1fr;\r\n        gap: 10px;\r\n        align-items: stretch;\r\n        margin: 12px 0 14px;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechTab {\r\n        height: var(--cvx-tech-tab-h);\r\n        border-radius: 999px;\r\n        border: 1px solid rgba(255, 255, 255, var(--cvx-tech-stroke-a));\r\n        background: rgba(255, 255, 255, 0.04);\r\n        color: rgba(255, 255, 255, 0.86);\r\n        font-weight: 600;\r\n        font-size: 13px;\r\n        cursor: pointer;\r\n        transition: transform 180ms ease-out, background 180ms ease-out, border-color 180ms ease-out;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechTab[aria-selected=\"true\"] {\r\n        background: rgba(56, 189, 248, 0.12);\r\n        border-color: rgba(56, 189, 248, 0.45);\r\n    }\r\n\r\n    @media (hover:hover) {\r\n        .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechTab:hover {\r\n            transform: translateY(-1px);\r\n            background: rgba(255, 255, 255, 0.06);\r\n        }\r\n    }\r\n\r\n    \/* Cards + layout *\/\r\n    .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechPanels {\r\n        display: grid;\r\n        gap: var(--cvx-tech-gap);\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechGrid {\r\n        display: grid;\r\n        grid-template-columns: repeat(2, minmax(0, 1fr));\r\n        gap: var(--cvx-tech-gap);\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechGrid--specs {\r\n        grid-template-columns: 1.35fr 0.65fr;\r\n        align-items: start;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechGrid--specs .cvxTechCard--wide {\r\n        align-self: start !important;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechGrid--compare {\r\n        grid-template-columns: 1.35fr 0.65fr;\r\n        align-items: start;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechGrid--compare .cvxTechCard--wide {\r\n        grid-column: 1 \/ 2;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechCard {\r\n        border-radius: var(--cvx-tech-radius);\r\n        border: 1px solid rgba(255, 255, 255, var(--cvx-tech-stroke-a));\r\n        background: rgba(255, 255, 255, var(--cvx-tech-surface-a));\r\n        backdrop-filter: blur(var(--cvx-tech-blur));\r\n        -webkit-backdrop-filter: blur(var(--cvx-tech-blur));\r\n        box-shadow: 0 16px 48px rgba(0, 0, 0, 0.35);\r\n        padding: 14px;\r\n        display: grid;\r\n        gap: 12px;\r\n        min-width: 0;\r\n\r\n        \/* Ensure cards grow with content (Elementor layouts can impose equal-height\/clip styles) *\/\r\n        height: auto !important;\r\n        max-height: none !important;\r\n        overflow: visible !important;\r\n        align-content: start;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechCard--wide {\r\n        grid-column: 1 \/ -1;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechGrid--specs .cvxTechCard--wide {\r\n        grid-column: 1 \/ 2;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechCardHead {\r\n        display: grid;\r\n        gap: 6px;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechCardTitle {\r\n        margin: 0;\r\n        font-size: 15px;\r\n        color: rgba(255, 255, 255, 0.92);\r\n        letter-spacing: 0.01em;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechCardDesc {\r\n        margin: 0;\r\n        font-size: 13px;\r\n        line-height: 1.35;\r\n        color: rgba(255, 255, 255, 0.64);\r\n    }\r\n\r\n    \/* Comparativa table *\/\r\n    .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechTableWrap {\r\n        border-radius: 14px;\r\n        border: 1px solid rgba(255, 255, 255, 0.10);\r\n        background: rgba(0, 0, 0, 0.18);\r\n        overflow: hidden;\r\n\r\n        \/* Avoid accidental clipping when parent imposes heights *\/\r\n        height: auto;\r\n        max-height: none;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechTable {\r\n        width: 100%;\r\n        border-collapse: collapse;\r\n        min-width: 0;\r\n        \/* columns are switched via selector; no horizontal scroll *\/\r\n    }\r\n\r\n    \/* Compare picker *\/\r\n    .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechComparePick {\r\n        display: flex;\r\n        flex-wrap: wrap;\r\n        gap: 8px;\r\n        align-items: center;\r\n        justify-content: flex-start;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechCompareChip {\r\n        height: 32px;\r\n        padding: 0 12px;\r\n        border-radius: 999px;\r\n        border: 1px solid rgba(255, 255, 255, 0.14);\r\n        background: rgba(0, 0, 0, 0.18);\r\n        color: rgba(255, 255, 255, 0.80);\r\n        font-size: 12px;\r\n        font-weight: 700;\r\n        cursor: pointer;\r\n        transition: transform 180ms ease-out, border-color 180ms ease-out, background 180ms ease-out;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechCompareChip[aria-pressed=\"true\"] {\r\n        background: rgba(56, 189, 248, 0.12);\r\n        border-color: rgba(56, 189, 248, 0.45);\r\n        color: rgba(255, 255, 255, 0.92);\r\n    }\r\n\r\n    @media (hover:hover) {\r\n        .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechCompareChip:hover {\r\n            transform: translateY(-1px);\r\n            border-color: rgba(56, 189, 248, 0.35);\r\n        }\r\n    }\r\n\r\n    \/* Table column switching: show CubeVox + 1 category *\/\r\n    .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechTable tr> :nth-child(n+3) {\r\n        display: none;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"tech-data\"][data-cvx-tech-compare=\"speaker\"] .cvxTechTable tr> :nth-child(3) {\r\n        display: table-cell !important;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"tech-data\"][data-cvx-tech-compare=\"amp\"] .cvxTechTable tr> :nth-child(4) {\r\n        display: table-cell !important;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"tech-data\"][data-cvx-tech-compare=\"iface\"] .cvxTechTable tr> :nth-child(5) {\r\n        display: table-cell !important;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"tech-data\"][data-cvx-tech-compare=\"mixer\"] .cvxTechTable tr> :nth-child(6) {\r\n        display: table-cell !important;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"tech-data\"][data-cvx-tech-compare=\"mfx\"] .cvxTechTable tr> :nth-child(7) {\r\n        display: table-cell !important;\r\n    }\r\n\r\n    \/* Highlight selected competitor header *\/\r\n    .cvxScope [data-cvx-root=\"tech-data\"][data-cvx-tech-compare=\"speaker\"] .cvxTechTable thead tr> :nth-child(3),\r\n    .cvxScope [data-cvx-root=\"tech-data\"][data-cvx-tech-compare=\"amp\"] .cvxTechTable thead tr> :nth-child(4),\r\n    .cvxScope [data-cvx-root=\"tech-data\"][data-cvx-tech-compare=\"iface\"] .cvxTechTable thead tr> :nth-child(5),\r\n    .cvxScope [data-cvx-root=\"tech-data\"][data-cvx-tech-compare=\"mixer\"] .cvxTechTable thead tr> :nth-child(6),\r\n    .cvxScope [data-cvx-root=\"tech-data\"][data-cvx-tech-compare=\"mfx\"] .cvxTechTable thead tr> :nth-child(7) {\r\n        background: rgba(56, 189, 248, 0.10);\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechTh,\r\n    .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechTd {\r\n        padding: 10px 10px;\r\n        border-bottom: 1px solid rgba(255, 255, 255, 0.10);\r\n        border-right: 1px solid rgba(255, 255, 255, 0.08);\r\n        text-align: center;\r\n        vertical-align: middle;\r\n        color: rgba(255, 255, 255, 0.78);\r\n        font-size: 12px;\r\n        white-space: nowrap;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechTh {\r\n        position: sticky;\r\n        top: 0;\r\n        background: rgba(10, 14, 20, 0.86);\r\n        z-index: 1;\r\n        font-weight: 700;\r\n        letter-spacing: 0.08em;\r\n        text-transform: uppercase;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechTh--feat,\r\n    .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechTd--feat {\r\n        text-align: left;\r\n        white-space: normal;\r\n        min-width: 240px;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechFeat {\r\n        font-size: 13px;\r\n        font-weight: 700;\r\n        color: rgba(255, 255, 255, 0.90);\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechFeatSub {\r\n        margin-top: 4px;\r\n        font-size: 12px;\r\n        color: rgba(255, 255, 255, 0.58);\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechMark {\r\n        display: inline-grid;\r\n        place-items: center;\r\n        width: 22px;\r\n        height: 22px;\r\n        border-radius: 999px;\r\n        border: 1px solid rgba(255, 255, 255, 0.14);\r\n\r\n        \/* Use pseudo-glyphs to keep vertical alignment consistent across fonts *\/\r\n        font-size: 0;\r\n        line-height: 0;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechMark::before {\r\n        display: block;\r\n        font-size: 14px;\r\n        line-height: 1;\r\n        font-weight: 900;\r\n        transform: translateY(-0.5px);\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechMark--yes::before {\r\n        content: \"\u2713\";\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechMark--no::before {\r\n        content: \"\u00d7\";\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechMark--yes {\r\n        background: rgba(56, 189, 248, 0.14);\r\n        border-color: rgba(56, 189, 248, 0.42);\r\n        color: rgba(255, 255, 255, 0.92);\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechMark--no {\r\n        background: rgba(255, 255, 255, 0.04);\r\n        color: rgba(255, 255, 255, 0.55);\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechMark--partial {\r\n        background: rgba(255, 255, 255, 0.06);\r\n        border-color: rgba(255, 255, 255, 0.18);\r\n        color: rgba(255, 255, 255, 0.78);\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechMark--partial::before {\r\n        content: \"\u25d0\";\r\n    }\r\n\r\n    \/* Legend *\/\r\n    .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechLegend {\r\n        display: flex;\r\n        flex-wrap: wrap;\r\n        gap: 10px 14px;\r\n        align-items: center;\r\n        justify-content: space-between;\r\n        padding: 10px 2px 0;\r\n        color: rgba(255, 255, 255, 0.62);\r\n        font-size: 12px;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechLegendLeft {\r\n        display: inline-flex;\r\n        flex-wrap: wrap;\r\n        gap: 10px 14px;\r\n        align-items: center;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechLegendItem {\r\n        display: inline-flex;\r\n        gap: 8px;\r\n        align-items: center;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechLegend .cvxTechMark {\r\n        width: 18px;\r\n        height: 18px;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechLegend .cvxTechMark::before {\r\n        font-size: 12px;\r\n        transform: translateY(-0.4px);\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechLegendNote {\r\n        display: inline-flex;\r\n        gap: 8px;\r\n        align-items: center;\r\n        color: rgba(255, 255, 255, 0.52);\r\n        text-align: right;\r\n    }\r\n\r\n    \/* Checklist *\/\r\n    .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechList {\r\n        margin: 0;\r\n        padding: 0;\r\n        list-style: none;\r\n        display: grid;\r\n        gap: 10px;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechListItem {\r\n        display: grid;\r\n        grid-template-columns: 10px 1fr;\r\n        gap: 10px;\r\n        align-items: start;\r\n        color: rgba(255, 255, 255, 0.70);\r\n        font-size: 13px;\r\n        line-height: 1.35;\r\n        padding: 10px;\r\n        border-radius: 14px;\r\n        border: 1px solid rgba(255, 255, 255, 0.12);\r\n        background: rgba(0, 0, 0, 0.16);\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechDot {\r\n        width: 10px;\r\n        height: 10px;\r\n        border-radius: 999px;\r\n        margin-top: 4px;\r\n        background: rgba(56, 189, 248, 0.75);\r\n        box-shadow: 0 0 0 4px rgba(56, 189, 248, 0.12);\r\n    }\r\n\r\n    \/* Figures *\/\r\n    .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechFigure {\r\n        margin: 0;\r\n        display: grid;\r\n        gap: 8px;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechImgWrap {\r\n        border-radius: 14px;\r\n        overflow: hidden;\r\n        border: 1px solid rgba(255, 255, 255, 0.10);\r\n        background: rgba(0, 0, 0, 0.20);\r\n        aspect-ratio: var(--cvx-tech-img-ar);\r\n        display: grid;\r\n        place-items: center;\r\n        cursor: zoom-in;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechImgWrap--tall {\r\n        \/* La infograf\u00eda real es ~16:9 (2047x1152). Usar el AR \u201creal\u201d evita espacio sobrante. *\/\r\n        aspect-ratio: var(--cvx-tech-img-ar);\r\n        \/* default ya est\u00e1 en 16\/9 *\/\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechImg {\r\n        width: 100%;\r\n        height: 100%;\r\n        object-fit: contain;\r\n        transform: translateZ(0);\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechCap {\r\n        font-size: 12px;\r\n        color: rgba(255, 255, 255, 0.56);\r\n    }\r\n\r\n    \/* Actions *\/\r\n    .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechCardActions {\r\n        display: flex;\r\n        justify-content: flex-end;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechPill {\r\n        border-radius: 999px;\r\n        border: 1px solid rgba(255, 255, 255, 0.14);\r\n        background: rgba(0, 0, 0, 0.20);\r\n        color: rgba(255, 255, 255, 0.86);\r\n        padding: 9px 12px;\r\n        font-size: 12px;\r\n        font-weight: 600;\r\n        cursor: pointer;\r\n        transition: transform 180ms ease-out, border-color 180ms ease-out;\r\n    }\r\n\r\n    @media (hover:hover) {\r\n        .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechPill:hover {\r\n            transform: translateY(-1px);\r\n            border-color: rgba(56, 189, 248, 0.45);\r\n        }\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechFoot {\r\n        margin: 10px 2px 0;\r\n        color: rgba(255, 255, 255, 0.52);\r\n        font-size: 12px;\r\n    }\r\n\r\n    \/* DL summary *\/\r\n    .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechDL {\r\n        margin: 0;\r\n        display: grid;\r\n        gap: 10px;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechDLRow {\r\n        display: grid;\r\n        gap: 6px;\r\n        padding: 10px;\r\n        border-radius: 14px;\r\n        border: 1px solid rgba(255, 255, 255, 0.12);\r\n        background: rgba(0, 0, 0, 0.18);\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechDLRow dt {\r\n        font-size: 12px;\r\n        font-weight: 700;\r\n        letter-spacing: 0.08em;\r\n        text-transform: uppercase;\r\n        color: rgba(255, 255, 255, 0.72);\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechDLRow dd {\r\n        margin: 0;\r\n        font-size: 13px;\r\n        line-height: 1.35;\r\n        color: rgba(255, 255, 255, 0.62);\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechFine {\r\n        margin: 0;\r\n        font-size: 12px;\r\n        color: rgba(255, 255, 255, 0.50);\r\n    }\r\n\r\n    \/* Modal *\/\r\n    .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechModal {\r\n        position: fixed;\r\n        inset: 0;\r\n        z-index: var(--cvx-tech-modal-z);\r\n        display: grid;\r\n        place-items: center;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechModalBackdrop {\r\n        position: absolute;\r\n        inset: 0;\r\n        background: rgba(0, 0, 0, 0.66);\r\n        backdrop-filter: blur(10px);\r\n        -webkit-backdrop-filter: blur(10px);\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechModalDialog {\r\n        position: relative;\r\n        width: var(--cvx-tech-modal-maxw);\r\n        height: var(--cvx-tech-modal-h, var(--cvx-tech-modal-maxh));\r\n        \/* JS setea --cvx-tech-modal-h *\/\r\n        max-height: var(--cvx-tech-modal-maxh);\r\n\r\n        border-radius: 18px;\r\n        border: 1px solid rgba(255, 255, 255, 0.16);\r\n        background: rgba(10, 14, 20, 0.88);\r\n        box-shadow: 0 30px 90px rgba(0, 0, 0, 0.55);\r\n        overflow: hidden;\r\n\r\n        display: grid;\r\n        grid-template-rows: auto 1fr;\r\n        \/* top + body *\/\r\n        min-height: 0;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechModalTop {\r\n        display: flex;\r\n        align-items: center;\r\n        justify-content: space-between;\r\n        padding: 12px 12px;\r\n        border-bottom: 1px solid rgba(255, 255, 255, 0.10);\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechModalTitle {\r\n        font-size: 13px;\r\n        font-weight: 700;\r\n        color: rgba(255, 255, 255, 0.86);\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechModalClose {\r\n        width: 34px;\r\n        height: 34px;\r\n        border-radius: 999px;\r\n        border: 1px solid rgba(255, 255, 255, 0.14);\r\n        background: rgba(255, 255, 255, 0.06);\r\n        color: rgba(255, 255, 255, 0.88);\r\n        cursor: pointer;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechModalBody {\r\n        padding: 12px;\r\n        display: grid;\r\n        place-items: center;\r\n        min-height: 0;\r\n        overflow: hidden;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechZoomStage {\r\n        position: relative;\r\n        width: 100%;\r\n        height: 100%;\r\n        display: grid;\r\n        place-items: center;\r\n        overflow: hidden;\r\n        border-radius: 14px;\r\n    }\r\n\r\n    \/* MODAL IMAGE FIT (evita recortes top\/bottom y respeta alto disponible) *\/\r\n    .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechModalImg {\r\n        width: 100%;\r\n        height: 100%;\r\n        display: block;\r\n        object-fit: contain;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechLens {\r\n        position: absolute;\r\n        z-index: 2;\r\n        width: 220px;\r\n        height: 220px;\r\n        border-radius: 16px;\r\n        border: 1px solid rgba(255, 255, 255, 0.18);\r\n        background: rgba(10, 14, 20, 0.55);\r\n        box-shadow: 0 24px 70px rgba(0, 0, 0, 0.55);\r\n        outline: 1px solid rgba(56, 189, 248, 0.18);\r\n        pointer-events: none;\r\n        transform: translate(-50%, -50%);\r\n        backdrop-filter: blur(2px);\r\n        -webkit-backdrop-filter: blur(2px);\r\n        background-repeat: no-repeat;\r\n    }\r\n\r\n    @media (pointer: coarse) {\r\n        .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechLens {\r\n            display: none !important;\r\n        }\r\n    }\r\n\r\n    \/* Responsive *\/\r\n    @media (max-width: 900px) {\r\n\r\n        .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechGrid,\r\n        .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechGrid--specs,\r\n        .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechGrid--compare {\r\n            grid-template-columns: 1fr;\r\n        }\r\n\r\n        .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechGrid--specs .cvxTechCard--wide {\r\n            grid-column: auto;\r\n        }\r\n\r\n        .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechImgWrap--tall {\r\n            aspect-ratio: 16\/10;\r\n        }\r\n    }\r\n\r\n    @media (prefers-reduced-motion: reduce) {\r\n\r\n        .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechTab,\r\n        .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechPill {\r\n            transition: none;\r\n        }\r\n    }\r\n\r\n    \/* MODAL CLOSE (X) \u2014 tuning *\/\r\n    .cvxScope [data-cvx-root=\"tech-data\"] {\r\n        --cvx-tech-close-sz: 34px;\r\n        \/* tama\u00f1o del bot\u00f3n *\/\r\n        --cvx-tech-close-fs: 14px;\r\n        \/* tama\u00f1o de la X *\/\r\n        --cvx-tech-close-x: 0px;\r\n        \/* mover en X (derecha +) *\/\r\n        --cvx-tech-close-y: 0px;\r\n        \/* mover en Y (abajo +) *\/\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechModalClose {\r\n        width: var(--cvx-tech-close-sz);\r\n        height: var(--cvx-tech-close-sz);\r\n        padding: 0;\r\n        display: grid;\r\n        place-items: center;\r\n        \/* centra la X dentro del c\u00edrculo *\/\r\n        font-size: var(--cvx-tech-close-fs);\r\n        line-height: 1;\r\n        \/* evita que la X \u201ccaiga\u201d *\/\r\n        transform: translate(var(--cvx-tech-close-x), var(--cvx-tech-close-y));\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"tech-data\"] {\r\n        --cvx-tech-mark-nudge-x: 0px;\r\n        \/* izquierda *\/\r\n        --cvx-tech-mark-nudge-y: 1px;\r\n        \/* abajo *\/\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechMark::before {\r\n        transform: translate(var(--cvx-tech-mark-nudge-x), var(--cvx-tech-mark-nudge-y));\r\n    }\r\n\r\n    \/* =====================================================\r\n   TABLE MOBILE FIT \u2014 keep (Features + CubeVox) stable, 3rd dynamic\r\n===================================================== *\/\r\n\r\n    .cvxScope [data-cvx-root=\"tech-data\"] {\r\n        \/* PARAMETERS *\/\r\n        --cvx-tech-tbl-fs: 12px;\r\n        --cvx-tech-tbl-pad-y: 10px;\r\n        --cvx-tech-tbl-pad-x: 10px;\r\n        --cvx-tech-tbl-feat-w: auto;\r\n        --cvx-tech-tbl-feat-minw: 240px;\r\n        --cvx-tech-tbl-col-fixed: 92px;\r\n        \/* CubeVox + competitor *\/\r\n        --cvx-tech-feat-fs: 13px;\r\n        --cvx-tech-feat-sub-fs: 12px;\r\n    }\r\n\r\n    @media (max-width: 560px) {\r\n\r\n        .cvxScope [data-cvx-root=\"tech-data\"] {\r\n            --cvx-tech-tbl-fs: 11px;\r\n            --cvx-tech-tbl-pad-y: 9px;\r\n            --cvx-tech-tbl-pad-x: 8px;\r\n\r\n            \/* 1ra columna el\u00e1stica (se achica) *\/\r\n            --cvx-tech-tbl-feat-w: clamp(100px, 56vw, 120px);\r\n            --cvx-tech-tbl-feat-minw: 0px;\r\n\r\n            \/* 2da + 3ra fijas (CubeVox + din\u00e1mica) *\/\r\n            --cvx-tech-tbl-col-fixed: 72px;\r\n\r\n            --cvx-tech-feat-fs: 12px;\r\n            --cvx-tech-feat-sub-fs: 11px;\r\n        }\r\n\r\n        \/* Layout: controla anchos por celda *\/\r\n        .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechTable {\r\n            table-layout: fixed;\r\n        }\r\n\r\n        \/* Celdas *\/\r\n        .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechTh,\r\n        .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechTd {\r\n            padding: var(--cvx-tech-tbl-pad-y) var(--cvx-tech-tbl-pad-x);\r\n            font-size: calc(var(--cvx-tech-tbl-fs) * var(--cvxS, 1));\r\n        }\r\n\r\n        \/* Header: permitir wrap si el JS no corre (fallback) *\/\r\n        .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechTh {\r\n            white-space: normal;\r\n            word-break: break-word;\r\n            line-height: 1.15;\r\n            letter-spacing: 0.06em;\r\n        }\r\n\r\n        \/* Anchos: 1ra el\u00e1stica, 2da fija, 3ra (cualquiera >=3) fija *\/\r\n        .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechTable tr> :nth-child(1) {\r\n            width: var(--cvx-tech-tbl-feat-w);\r\n        }\r\n\r\n        .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechTable tr> :nth-child(2),\r\n        .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechTable tr> :nth-child(n+3) {\r\n            width: var(--cvx-tech-tbl-col-fixed);\r\n        }\r\n\r\n        \/* Features column: sin m\u00ednimo duro *\/\r\n        .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechTh--feat,\r\n        .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechTd--feat {\r\n            min-width: var(--cvx-tech-tbl-feat-minw);\r\n            white-space: normal;\r\n            \/* ya lo ten\u00edas, lo reforzamos *\/\r\n        }\r\n\r\n        \/* Tipograf\u00eda interna de Features *\/\r\n        .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechFeat {\r\n            font-size: calc(var(--cvx-tech-feat-fs) * var(--cvxS, 1));\r\n        }\r\n\r\n        .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechFeatSub {\r\n            font-size: calc(var(--cvx-tech-feat-sub-fs) * var(--cvxS, 1));\r\n        }\r\n\r\n        \/* Marca *\/\r\n        .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechMark {\r\n            width: 20px;\r\n            height: 20px;\r\n        }\r\n\r\n        .cvxScope [data-cvx-root=\"tech-data\"] .cvxTechMark::before {\r\n            font-size: 13px;\r\n        }\r\n    }\r\n<\/style>\r\n\r\n<script>\r\n    \/* =====================================================\r\n     COMPONENT: Technical Data\r\n     - Tabs: [data-cvx-tech-tab] -> toggles panels\r\n     - Modal zoom: [data-cvx-tech-open] \/ [data-cvx-tech-zoomable]\r\n     Elementor-safe: per-root guard + no globals\r\n  ===================================================== *\/\r\n    (function() {\r\n        const roots = document.querySelectorAll('.cvxScope [data-cvx-root=\"tech-data\"]');\r\n\r\n        roots.forEach((root) => {\r\n            if (root.__cvxTechInited) return;\r\n            root.__cvxTechInited = true;\r\n\r\n            const tabBtns = Array.from(root.querySelectorAll('[data-cvx-tech-tab]'));\r\n            const panels = {\r\n                compare: root.querySelector('[data-cvx-tech-panel=\"compare\"]'),\r\n                specs: root.querySelector('[data-cvx-tech-panel=\"specs\"]')\r\n            };\r\n\r\n            const modal = root.querySelector('[data-cvx-tech-modal]');\r\n            const modalImg = root.querySelector('[data-cvx-tech-modal-img]');\r\n            const modalTitle = root.querySelector('[data-cvx-tech-modal-title]');\r\n            const zoomStage = root.querySelector('[data-cvx-tech-zoomstage]');\r\n            const lens = root.querySelector('[data-cvx-tech-lens]');\r\n            const LENS_ZOOM = 2;\r\n\r\n            \/* -----------------------------------------------------\r\n               Image sources from CSS vars (per-instance)\r\n            ----------------------------------------------------- *\/\r\n            function readCssUrlVar(varName) {\r\n                const css = getComputedStyle(root);\r\n                let v = (css.getPropertyValue(varName) || '').trim();\r\n                if (!v) return '';\r\n                if (v.startsWith('url(')) v = v.replace(\/^url\\((.*)\\)$\/i, '$1').trim();\r\n                if ((v.startsWith('\"') && v.endsWith('\"')) || (v.startsWith(\"'\") && v.endsWith(\"'\"))) v = v.slice(1, -1).trim();\r\n                return v;\r\n            }\r\n\r\n            const imgMap = {\r\n                infographic: readCssUrlVar('--cvx-tech-img-infographic')\r\n            };\r\n\r\n            \/* Sync thumb + button source from CSS var *\/\r\n            if (imgMap.infographic) {\r\n                const imgEl = root.querySelector('[data-cvx-tech-img=\"infographic\"]');\r\n                if (imgEl) imgEl.setAttribute('src', imgMap.infographic);\r\n\r\n                root.querySelectorAll('[data-cvx-tech-open][data-cvx-img-key=\"infographic\"]').forEach((btn) => {\r\n                    btn.setAttribute('data-cvx-src', imgMap.infographic);\r\n                });\r\n            }\r\n\r\n            \/* -----------------------------------------------------\r\n               Modal fit (reduce \u201caire\u201d en mobile + evita recortes)\r\n            ----------------------------------------------------- *\/\r\n            const dialog = root.querySelector('.cvxTechModalDialog');\r\n            const modalTop = root.querySelector('.cvxTechModalTop');\r\n            const modalBody = root.querySelector('.cvxTechModalBody');\r\n\r\n            function parseAspectRatio(raw) {\r\n                const s = String(raw || '').trim();\r\n                const m = s.match(\/^(\\d+(?:\\.\\d+)?)\\s*\\\/\\s*(\\d+(?:\\.\\d+)?)$\/);\r\n                if (!m) return 16 \/ 9;\r\n                const a = parseFloat(m[1]),\r\n                    b = parseFloat(m[2]);\r\n                return (a > 0 && b > 0) ? (a \/ b) : (16 \/ 9);\r\n            }\r\n\r\n            let fitRaf = 0;\r\n\r\n            function scheduleModalFit() {\r\n                if (fitRaf) return;\r\n                fitRaf = requestAnimationFrame(() => {\r\n                    fitRaf = 0;\r\n                    fitModalToImage();\r\n                });\r\n            }\r\n\r\n            function fitModalToImage() {\r\n                if (!modal || modal.hasAttribute('hidden')) return;\r\n                if (!dialog || !modalBody || !modalImg) return;\r\n\r\n                const vv = window.visualViewport;\r\n                const vh = vv ? vv.height : window.innerHeight;\r\n\r\n                const gutter = parseFloat(getComputedStyle(root).getPropertyValue('--cvx-tech-modal-gutter')) || 26;\r\n                const maxH = Math.min(Math.max(0, vh - gutter), 860);\r\n                if (maxH <= 0) return;\r\n\r\n                const bodyCS = getComputedStyle(modalBody);\r\n                const padY = (parseFloat(bodyCS.paddingTop) || 0) + (parseFloat(bodyCS.paddingBottom) || 0);\r\n                const padX = (parseFloat(bodyCS.paddingLeft) || 0) + (parseFloat(bodyCS.paddingRight) || 0);\r\n\r\n                const topH = modalTop ? modalTop.getBoundingClientRect().height : 0;\r\n\r\n                const stageW = Math.max(1, modalBody.clientWidth - padX);\r\n\r\n                const ar =\r\n                    (modalImg.naturalWidth && modalImg.naturalHeight) ?\r\n                    (modalImg.naturalWidth \/ modalImg.naturalHeight) :\r\n                    parseAspectRatio(getComputedStyle(root).getPropertyValue('--cvx-tech-img-ar'));\r\n\r\n                const desiredImgH = stageW \/ ar;\r\n                const targetH = Math.min(maxH, topH + padY + desiredImgH);\r\n\r\n                root.style.setProperty('--cvx-tech-modal-h', Math.round(targetH) + 'px');\r\n            }\r\n\r\n            \/* Re-fit en cambios de viewport (mobile toolbars incluidas) *\/\r\n            const vv = window.visualViewport;\r\n            const onVpChange = () => {\r\n                if (modal && !modal.hasAttribute('hidden')) scheduleModalFit();\r\n            };\r\n            (window.addEventListener && window.addEventListener('resize', onVpChange, {\r\n                passive: true\r\n            }));\r\n            if (vv && vv.addEventListener) {\r\n                vv.addEventListener('resize', onVpChange, {\r\n                    passive: true\r\n                });\r\n                vv.addEventListener('scroll', onVpChange, {\r\n                    passive: true\r\n                });\r\n            }\r\n\r\n            \/* -----------------------------------------------------\r\n               Compare picker (CubeVox + 1 category)\r\n            ----------------------------------------------------- *\/\r\n            const pickBtns = Array.from(root.querySelectorAll('[data-cvx-tech-pick]'));\r\n\r\n            function setCompare(key) {\r\n                if (!key) return;\r\n                root.setAttribute('data-cvx-tech-compare', key);\r\n                pickBtns.forEach((b) => {\r\n                    b.setAttribute('aria-pressed', b.getAttribute('data-cvx-tech-pick') === key ? 'true' : 'false');\r\n                });\r\n            }\r\n\r\n            \/\/ Init\r\n            const pressed = pickBtns.find((b) => b.getAttribute('aria-pressed') === 'true');\r\n            const initialCompare = (root.getAttribute('data-cvx-tech-compare') || (pressed && pressed.getAttribute('data-cvx-tech-pick')) || 'speaker').trim();\r\n            setCompare(initialCompare);\r\n\r\n            \/\/ Click\r\n            pickBtns.forEach((btn) => {\r\n                btn.addEventListener('click', () => setCompare(btn.getAttribute('data-cvx-tech-pick')));\r\n            });\r\n\r\n            function setActiveTab(key) {\r\n                tabBtns.forEach((b) => {\r\n                    const isOn = b.getAttribute('data-cvx-tech-tab') === key;\r\n                    b.setAttribute('aria-selected', isOn ? 'true' : 'false');\r\n                    b.tabIndex = isOn ? 0 : -1;\r\n                });\r\n\r\n                Object.keys(panels).forEach((k) => {\r\n                    const p = panels[k];\r\n                    if (!p) return;\r\n                    if (k === key) p.removeAttribute('hidden');\r\n                    else p.setAttribute('hidden', '');\r\n                });\r\n            }\r\n\r\n            tabBtns.forEach((btn) => {\r\n                btn.addEventListener('click', () => setActiveTab(btn.getAttribute('data-cvx-tech-tab')));\r\n                btn.addEventListener('keydown', (ev) => {\r\n                    if (ev.key !== 'ArrowLeft' && ev.key !== 'ArrowRight') return;\r\n                    ev.preventDefault();\r\n                    const idx = tabBtns.indexOf(btn);\r\n                    const next = ev.key === 'ArrowRight' ? (idx + 1) % tabBtns.length : (idx - 1 + tabBtns.length) % tabBtns.length;\r\n                    tabBtns[next].focus();\r\n                });\r\n            });\r\n\r\n            function openModal(src, title, key) {\r\n                if (!modal || !modalImg) return;\r\n\r\n                modalImg.src = src;\r\n                modalImg.alt = title || '';\r\n                if (modalTitle) modalTitle.textContent = title || 'Vista';\r\n\r\n                \/\/ Lupa: solo habilitada para la infograf\u00eda\r\n                const lensEnabled = (key === 'infographic');\r\n                if (lens) {\r\n                    lens.hidden = !lensEnabled;\r\n                    lens.dataset.cvxLensEnabled = lensEnabled ? '1' : '0';\r\n                    if (lensEnabled) {\r\n                        lens.style.backgroundImage = `url(\"${src}\")`;\r\n                    } else {\r\n                        lens.style.backgroundImage = '';\r\n                    }\r\n                }\r\n\r\n                modal.removeAttribute('hidden');\r\n                document.documentElement.style.overflow = 'hidden';\r\n                \/\/ Fit a la imagen (evita aire en mobile y recortes en desktop)\r\n                if (modalImg) {\r\n                    modalImg.onload = () => scheduleModalFit();\r\n                    if (modalImg.complete) scheduleModalFit();\r\n                }\r\n                scheduleModalFit();\r\n            }\r\n\r\n            function closeModal() {\r\n                if (!modal || modal.hasAttribute('hidden')) return;\r\n                modal.setAttribute('hidden', '');\r\n                if (modalImg) modalImg.removeAttribute('src');\r\n\r\n                if (lens) {\r\n                    lens.hidden = true;\r\n                    lens.dataset.cvxLensEnabled = '0';\r\n                    lens.style.backgroundImage = '';\r\n                }\r\n\r\n                document.documentElement.style.overflow = '';\r\n                root.style.removeProperty('--cvx-tech-modal-h');\r\n            }\r\n\r\n            root.addEventListener('click', (ev) => {\r\n                const openBtn = ev.target.closest('[data-cvx-tech-open]');\r\n                if (openBtn) {\r\n                    const key = openBtn.getAttribute('data-cvx-img-key') || '';\r\n                    let src = openBtn.getAttribute('data-cvx-src') || '';\r\n                    if (!src && key && imgMap[key]) src = imgMap[key];\r\n\r\n                    const title = openBtn.getAttribute('data-cvx-title') || '';\r\n                    if (src) openModal(src, title, key);\r\n                    return;\r\n                }\r\n\r\n                const zoomable = ev.target.closest('[data-cvx-tech-zoomable]');\r\n                if (zoomable) {\r\n                    const img = zoomable.querySelector('img');\r\n                    const src = img && img.getAttribute('src');\r\n                    const title = (img && img.getAttribute('alt')) || 'Vista';\r\n                    const key = (img && img.getAttribute('data-cvx-tech-img')) || '';\r\n                    const url = (key && imgMap[key]) ? imgMap[key] : src;\r\n                    if (url && !url.startsWith('data:')) openModal(url, title, key);\r\n                    return;\r\n                }\r\n\r\n                if (ev.target.closest('[data-cvx-tech-close]')) {\r\n                    closeModal();\r\n                }\r\n            });\r\n\r\n            window.addEventListener('keydown', (ev) => {\r\n                if (ev.key === 'Escape') closeModal();\r\n            }, {\r\n                passive: true\r\n            });\r\n\r\n            \/* -----------------------------------------------------\r\n   Lens behavior (infographic only)\r\n----------------------------------------------------- *\/\r\n            if (zoomStage && lens && modalImg && window.matchMedia) {\r\n                const canLens = window.matchMedia('(pointer:fine)').matches;\r\n                let raf = 0;\r\n                let lastEv = null;\r\n\r\n                function clamp(v, a, b) {\r\n                    return Math.max(a, Math.min(b, v));\r\n                }\r\n\r\n                function render() {\r\n                    raf = 0;\r\n                    if (!lastEv) return;\r\n                    if (lens.dataset.cvxLensEnabled !== '1') {\r\n                        lens.hidden = true;\r\n                        return;\r\n                    }\r\n                    if (!canLens) {\r\n                        lens.hidden = true;\r\n                        return;\r\n                    }\r\n                    if (!modal || modal.hasAttribute('hidden')) {\r\n                        lens.hidden = true;\r\n                        return;\r\n                    }\r\n\r\n                    const ev = lastEv;\r\n                    const stageR = zoomStage.getBoundingClientRect();\r\n                    const imgR = modalImg.getBoundingClientRect();\r\n\r\n                    \/\/ Mostrar la lupa solo si el mouse est\u00e1 sobre el \u00e1rea real renderizada del <img> (object-fit: contain)\r\n                    const insideImg =\r\n                        ev.clientX >= imgR.left && ev.clientX <= imgR.right &&\r\n                        ev.clientY >= imgR.top && ev.clientY <= imgR.bottom;\r\n\r\n                    if (!insideImg) {\r\n                        lens.hidden = true;\r\n                        return;\r\n                    }\r\n                    lens.hidden = false;\r\n\r\n                    const lw = lens.offsetWidth || 220;\r\n                    const lh = lens.offsetHeight || 220;\r\n                    const halfW = lw \/ 2;\r\n                    const halfH = lh \/ 2;\r\n\r\n                    \/\/ Cursor en coords del stage (clamp para que la lente no se salga)\r\n                    let x = ev.clientX - stageR.left;\r\n                    let y = ev.clientY - stageR.top;\r\n                    x = clamp(x, halfW, stageR.width - halfW);\r\n                    y = clamp(y, halfH, stageR.height - halfH);\r\n\r\n                    lens.style.left = x + 'px';\r\n                    lens.style.top = y + 'px';\r\n\r\n                    \/\/ Cursor relativo al \u00e1rea del image (0..1)\r\n                    const xr = clamp((ev.clientX - imgR.left) \/ Math.max(1, imgR.width), 0, 1);\r\n                    const yr = clamp((ev.clientY - imgR.top) \/ Math.max(1, imgR.height), 0, 1);\r\n\r\n                    const bgW = imgR.width * LENS_ZOOM;\r\n                    const bgH = imgR.height * LENS_ZOOM;\r\n                    lens.style.backgroundSize = bgW + 'px ' + bgH + 'px';\r\n\r\n                    \/\/ Offset para centrar el punto bajo el cursor dentro de la lente\r\n                    const bx = -(xr * bgW - halfW);\r\n                    const by = -(yr * bgH - halfH);\r\n                    lens.style.backgroundPosition = bx + 'px ' + by + 'px';\r\n                }\r\n\r\n                function schedule(ev) {\r\n                    lastEv = ev;\r\n                    if (!raf) raf = requestAnimationFrame(render);\r\n                }\r\n\r\n                zoomStage.addEventListener('mousemove', schedule, {\r\n                    passive: true\r\n                });\r\n                zoomStage.addEventListener('mouseleave', () => {\r\n                    lens.hidden = true;\r\n                }, {\r\n                    passive: true\r\n                });\r\n            }\r\n\r\n\r\n            \/\/ Default state\r\n            setActiveTab('compare');\r\n\r\n        });\r\n    })();\r\n<\/script>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-cf43e9f reservation_section elementor-section-boxed elementor-section-height-default elementor-section-height-default\" data-id=\"cf43e9f\" data-element_type=\"section\" data-e-type=\"section\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;,&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-ae1d24a\" data-id=\"ae1d24a\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-8af8303 elementor-widget elementor-widget-html\" data-id=\"8af8303\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<section class=\"cvx-reserve-band\" aria-labelledby=\"cvx-reserve-band-title\">\r\n  <div class=\"cvx-reserve-band__bg\"><\/div>\r\n\r\n  <div class=\"cvx-reserve-band__inner\">\r\n    <p class=\"cvx-reserve-band__eyebrow\">RESERVA<\/p>\r\n\r\n    <h2 id=\"cvx-reserve-band-title\" class=\"cvx-reserve-band__title\">\r\n      Reserv\u00e1 hoy tu CubeVox\r\n    <\/h2>\r\n\r\n    <p class=\"cvx-reserve-band__text\">\r\n     Acced\u00e9 al mejor precio disponible en la campa\u00f1a. Tu reserva es acreditable al precio final.\r\n    <\/p>\r\n\r\n    <div class=\"cvx-reserve-band__footer\">\r\n      <div class=\"cvx-reserve-band__meta\">\r\n        <div class=\"cvx-reserve-band__chips\" aria-hidden=\"true\">\r\n          <span>Mejor precio<\/span>\r\n          <span>Reserva acreditable<\/span>\r\n          <span>Cupos limitados<\/span>\r\n        <\/div>\r\n\r\n        <p class=\"cvx-reserve-band__micro\">\r\n         Sumate hoy a la campa\u00f1a.\r\n        <\/p>\r\n      <\/div>\r\n\r\n      <div class=\"cvx-reserve-band__ctaWrap\">\r\n        <a class=\"cvx-reserve-band__btn\" href=\"#reservations-main\" data-cvx-scroll-target=\"#reservations-main\">\r\n          Reservar mi CubeVox\r\n        <\/a>\r\n      <\/div>\r\n    <\/div>\r\n  <\/div>\r\n<\/section>\r\n\r\n<style>\r\n  .cvx-reserve-band{\r\n    --cvx-bg: #0f1116;\r\n    --cvx-border: rgba(255,255,255,.09);\r\n    --cvx-text: rgba(255,255,255,.96);\r\n    --cvx-text-soft: rgba(255,255,255,.76);\r\n    --cvx-text-dim: rgba(255,255,255,.56);\r\n\r\n    position: relative;\r\n    isolation: isolate;\r\n    overflow: hidden;\r\n    margin: clamp(28px, 5vw, 64px) auto;\r\n    padding: clamp(30px, 4.5vw, 56px);\r\n    border: 1px solid var(--cvx-border);\r\n    border-radius: 28px;\r\n    background:\r\n      radial-gradient(circle at 82% 78%, rgba(89,184,255,.09), transparent 24%),\r\n      linear-gradient(180deg, rgba(255,255,255,.028) 0%, rgba(255,255,255,.012) 100%),\r\n      var(--cvx-bg);\r\n    box-shadow:\r\n      inset 0 1px 0 rgba(255,255,255,.025),\r\n      0 18px 48px rgba(0,0,0,.24);\r\n  }\r\n\r\n  .cvx-reserve-band__bg{\r\n    position: absolute;\r\n    right: -120px;\r\n    bottom: -120px;\r\n    width: 340px;\r\n    height: 340px;\r\n    border-radius: 50%;\r\n    background: radial-gradient(circle, rgba(89,184,255,.12) 0%, rgba(89,184,255,0) 68%);\r\n    filter: blur(18px);\r\n    pointer-events: none;\r\n    z-index: 0;\r\n  }\r\n\r\n  .cvx-reserve-band__inner{\r\n    position: relative;\r\n    z-index: 1;\r\n    max-width: 1120px;\r\n  }\r\n\r\n  .cvx-reserve-band__eyebrow{\r\n    margin: 0 0 10px;\r\n    color: var(--cvx-text-dim);\r\n    font-size: 12px;\r\n    line-height: 1;\r\n    letter-spacing: .18em;\r\n    font-weight: 700;\r\n  }\r\n\r\n  .cvx-reserve-band__title{\r\n    margin: 0;\r\n    max-width: 10ch;\r\n    color: var(--cvx-text);\r\n    font-size: clamp(40px, 6vw, 74px);\r\n    line-height: .95;\r\n    font-weight: 500;\r\n    letter-spacing: -.04em;\r\n  }\r\n\r\n  .cvx-reserve-band__text{\r\n    margin: 22px 0 0;\r\n    max-width: 760px;\r\n    color: var(--cvx-text-soft);\r\n    font-size: clamp(17px, 1.7vw, 20px);\r\n    line-height: 1.55;\r\n  }\r\n\r\n  .cvx-reserve-band__footer{\r\n    display: flex;\r\n    align-items: flex-end;\r\n    justify-content: space-between;\r\n    gap: 28px;\r\n    margin-top: 28px;\r\n  }\r\n\r\n  .cvx-reserve-band__meta{\r\n    flex: 1 1 auto;\r\n    min-width: 0;\r\n  }\r\n\r\n  .cvx-reserve-band__chips{\r\n    display: flex;\r\n    flex-wrap: wrap;\r\n    gap: 10px;\r\n  }\r\n\r\n  .cvx-reserve-band__chips span{\r\n    display: inline-flex;\r\n    align-items: center;\r\n    min-height: 34px;\r\n    padding: 0 14px;\r\n    border-radius: 999px;\r\n    border: 1px solid rgba(255,255,255,.08);\r\n    background: rgba(255,255,255,.022);\r\n    color: rgba(255,255,255,.76);\r\n    font-size: 12px;\r\n    font-weight: 600;\r\n    white-space: nowrap;\r\n  }\r\n\r\n  .cvx-reserve-band__micro{\r\n    margin: 14px 0 0;\r\n    color: var(--cvx-text-dim);\r\n    font-size: 13px;\r\n    line-height: 1.45;\r\n  }\r\n\r\n  .cvx-reserve-band__ctaWrap{\r\n    flex: 0 0 auto;\r\n    display: flex;\r\n    justify-content: flex-end;\r\n  }\r\n\r\n  .cvx-reserve-band__btn{\r\n    display: inline-flex;\r\n    align-items: center;\r\n    justify-content: center;\r\n    min-width: 300px;\r\n    min-height: 58px;\r\n    padding: 0 24px;\r\n    border-radius: 18px;\r\n    border: 1px solid rgba(89,184,255,.58);\r\n    background: linear-gradient(180deg, rgba(89,184,255,.13) 0%, rgba(89,184,255,.07) 100%);\r\n    color: #fff;\r\n    text-decoration: none;\r\n    font-size: 16px;\r\n    font-weight: 700;\r\n    letter-spacing: -.01em;\r\n    box-shadow:\r\n      inset 0 1px 0 rgba(255,255,255,.06),\r\n      0 10px 24px rgba(23,93,148,.18);\r\n    transition: transform .18s ease, border-color .18s ease, box-shadow .18s ease, background .18s ease;\r\n  }\r\n\r\n  .cvx-reserve-band__btn:hover{\r\n    transform: translateY(-1px);\r\n    border-color: rgba(89,184,255,.78);\r\n    background: linear-gradient(180deg, rgba(89,184,255,.17) 0%, rgba(89,184,255,.09) 100%);\r\n    box-shadow:\r\n      inset 0 1px 0 rgba(255,255,255,.08),\r\n      0 14px 28px rgba(23,93,148,.22);\r\n  }\r\n\r\n  .cvx-reserve-band__btn:focus-visible{\r\n    outline: none;\r\n    box-shadow:\r\n      0 0 0 3px rgba(89,184,255,.16),\r\n      inset 0 1px 0 rgba(255,255,255,.08),\r\n      0 14px 28px rgba(23,93,148,.22);\r\n  }\r\n\r\n  @media (max-width: 800px){\r\n    .cvx-reserve-band{\r\n      padding: 24px 18px;\r\n      border-radius: 22px;\r\n    }\r\n\r\n    .cvx-reserve-band__bg{\r\n      right: -120px;\r\n      bottom: -140px;\r\n      width: 240px;\r\n      height: 240px;\r\n    }\r\n\r\n    .cvx-reserve-band__title{\r\n      max-width: 8ch;\r\nfont-size: clamp(28px, 30vw, 45px) !important;\r\n    }\r\n\r\n    .cvx-reserve-band__text{\r\n      max-width: none;\r\n      font-size: 15px;\r\n    }\r\n\r\n    .cvx-reserve-band__footer{\r\n      flex-direction: column;\r\n      align-items: center;\r\n      text-align: center;\r\n    }\r\n\r\n    .cvx-reserve-band__meta{\r\n      width: 100%;\r\n    }\r\n\r\n    .cvx-reserve-band__chips{\r\n      justify-content: center;\r\n    }\r\n\r\n    .cvx-reserve-band__micro{\r\n      text-align: center;\r\n    }\r\n\r\n    .cvx-reserve-band__ctaWrap{\r\n      width: 100%;\r\n      justify-content: center;\r\n    }\r\n\r\n    .cvx-reserve-band__btn{\r\n      width: 100%;\r\n      min-width: 0;\r\n      min-height: 54px;\r\n    }\r\n  }\r\n<\/style>\r\n\r\n<script>\r\n  (function () {\r\n    var triggers = document.querySelectorAll('[data-cvx-scroll-target]');\r\n    triggers.forEach(function (trigger) {\r\n      trigger.addEventListener('click', function (e) {\r\n        var selector = trigger.getAttribute('data-cvx-scroll-target');\r\n        var target = selector ? document.querySelector(selector) : null;\r\n        if (!target) return;\r\n        e.preventDefault();\r\n        target.scrollIntoView({ behavior: 'smooth', block: 'start' });\r\n      });\r\n    });\r\n  })();\r\n<\/script>\r\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-97bdc43 fx_section elementor-section-height-min-height elementor-section-items-stretch elementor-section-boxed elementor-section-height-default\" data-id=\"97bdc43\" data-element_type=\"section\" data-e-type=\"section\" id=\"faq\" data-settings=\"{&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-b53cd3a\" data-id=\"b53cd3a\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<section class=\"elementor-section elementor-inner-section elementor-element elementor-element-900ca58 elementor-section-full_width elementor-section-height-default elementor-section-height-default\" data-id=\"900ca58\" data-element_type=\"section\" data-e-type=\"section\" data-settings=\"{&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-no\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-inner-column elementor-element elementor-element-9e8dbb3\" data-id=\"9e8dbb3\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-8feafb0 elementor-invisible elementor-widget elementor-widget-heading\" data-id=\"8feafb0\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;fadeInUp&quot;}\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">FAQ<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-15f1b40 elementor-widget elementor-widget-ha-svg-draw happy-addon ha-svg-draw\" data-id=\"15f1b40\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"ha-svg-draw.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\n\t\t\t\t<div class=\"ha-svg-draw-container\">\n\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t\n  \n    \n      \n      \n    \n  \n  \n\n\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t<\/div>\n\n\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-b07ca09 elementor-widget elementor-widget-heading\" data-id=\"b07ca09\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Preguntas frecuentes<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<div class=\"elementor-element elementor-element-95ce574 elementor-widget elementor-widget-eael-adv-accordion\" data-id=\"95ce574\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"eael-adv-accordion.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t            <div class=\"eael-adv-accordion\" id=\"eael-adv-accordion-95ce574\" data-scroll-on-click=\"\" data-scroll-speed=\"300\" data-accordion-id=\"95ce574\" data-accordion-type=\"accordion\" data-toogle-speed=\"300\">\n            <div class=\"eael-accordion-list\">\n\t\t\t\t\t<div id=\"cmo-puedo-adquirir-cubevox\" class=\"elementor-tab-title eael-accordion-header\" tabindex=\"0\" data-tab=\"1\" aria-controls=\"elementor-tab-content-1571\"><span class=\"eael-accordion-tab-title\">\u00bfC\u00f3mo puedo adquirir CubeVox?<\/span><i aria-hidden=\"true\" class=\"fa-toggle fas fa-angle-right\"><\/i><\/div><div id=\"elementor-tab-content-1571\" class=\"eael-accordion-content clearfix\" data-tab=\"1\" aria-labelledby=\"cmo-puedo-adquirir-cubevox\"><p>Puedes adquirir CubeVox a trav\u00e9s de nuestro sitio de manera anticipada o cuando lancemos la campa\u00f1a de crowdfunding en Indiegogo. Luego de la preventa, lo podr\u00e1s seguir encontrando aqu\u00ed pero al precio de lista mientras se lanza la segunda campa\u00f1a en Kickstarter.<\/p><\/div>\n\t\t\t\t\t<\/div><div class=\"eael-accordion-list\">\n\t\t\t\t\t<div id=\"quin-paga-los-costos-de-envo-y-tarifas-de-importacin\" class=\"elementor-tab-title eael-accordion-header\" tabindex=\"0\" data-tab=\"2\" aria-controls=\"elementor-tab-content-1572\"><span class=\"eael-accordion-tab-title\">\u00bfQui\u00e9n paga los costos de env\u00edo y tarifas de importaci\u00f3n?<\/span><i aria-hidden=\"true\" class=\"fa-toggle fas fa-angle-right\"><\/i><\/div><div id=\"elementor-tab-content-1572\" class=\"eael-accordion-content clearfix\" data-tab=\"2\" aria-labelledby=\"quin-paga-los-costos-de-envo-y-tarifas-de-importacin\"><p style=\"text-align: left\">El comprador es responsable de pagar los costos de env\u00edo, as\u00ed como cualquier tarifa de importaci\u00f3n y aranceles aduaneros.<\/p><\/div>\n\t\t\t\t\t<\/div><div class=\"eael-accordion-list\">\n\t\t\t\t\t<div id=\"cundo-recibir-mi-cubevox\" class=\"elementor-tab-title eael-accordion-header\" tabindex=\"0\" data-tab=\"3\" aria-controls=\"elementor-tab-content-1573\"><span class=\"eael-accordion-tab-title\">\u00bfCu\u00e1ndo recibir\u00e9 mi CubeVox?<\/span><i aria-hidden=\"true\" class=\"fa-toggle fas fa-angle-right\"><\/i><\/div><div id=\"elementor-tab-content-1573\" class=\"eael-accordion-content clearfix\" data-tab=\"3\" aria-labelledby=\"cundo-recibir-mi-cubevox\"><p>La fecha de env\u00edo puede variar en funci\u00f3n del funding que logremos. Te recomendamos estar atento a las actualizaciones en nuestras redes.<\/p><\/div>\n\t\t\t\t\t<\/div><div class=\"eael-accordion-list\">\n\t\t\t\t\t<div id=\"puedo-comprar-bateras-adicionales-para-cubevox\" class=\"elementor-tab-title eael-accordion-header\" tabindex=\"0\" data-tab=\"4\" aria-controls=\"elementor-tab-content-1574\"><span class=\"eael-accordion-tab-title\">\u00bfPuedo comprar bater\u00edas adicionales para CubeVox?<\/span><i aria-hidden=\"true\" class=\"fa-toggle fas fa-angle-right\"><\/i><\/div><div id=\"elementor-tab-content-1574\" class=\"eael-accordion-content clearfix\" data-tab=\"4\" aria-labelledby=\"puedo-comprar-bateras-adicionales-para-cubevox\"><p>S\u00ed, CubeVox cuenta con una bater\u00eda extra\u00edble de 54wh, y podr\u00e1s comprar bater\u00edas adicionales en nuestra tienda.<\/p><\/div>\n\t\t\t\t\t<\/div><div class=\"eael-accordion-list\">\n\t\t\t\t\t<div id=\"cual-ser-el-primer-compose-studio\" class=\"elementor-tab-title eael-accordion-header\" tabindex=\"0\" data-tab=\"5\" aria-controls=\"elementor-tab-content-1575\"><span class=\"eael-accordion-tab-title\">\u00bfCual ser\u00e1 el primer Compose Studio?<\/span><i aria-hidden=\"true\" class=\"fa-toggle fas fa-angle-right\"><\/i><\/div><div id=\"elementor-tab-content-1575\" class=\"eael-accordion-content clearfix\" data-tab=\"5\" aria-labelledby=\"cual-ser-el-primer-compose-studio\"><p>Compose Studio es una caracter\u00edstica especial que se desarrollar\u00e1 inicialmente en nuestra plataforma WEB, y luego se lanzar\u00e1n las aplicaciones m\u00f3viles. Los plazos variar\u00e1n seg\u00fan el nivel de funding.<\/p><\/div>\n\t\t\t\t\t<\/div><div class=\"eael-accordion-list\">\n\t\t\t\t\t<div id=\"estar-incluido-el-dsp-en-cubevox\" class=\"elementor-tab-title eael-accordion-header\" tabindex=\"0\" data-tab=\"6\" aria-controls=\"elementor-tab-content-1576\"><span class=\"eael-accordion-tab-title\">\u00bfEstar\u00e1 incluido el DSP en CubeVox?<\/span><i aria-hidden=\"true\" class=\"fa-toggle fas fa-angle-right\"><\/i><\/div><div id=\"elementor-tab-content-1576\" class=\"eael-accordion-content clearfix\" data-tab=\"6\" aria-labelledby=\"estar-incluido-el-dsp-en-cubevox\"><p>S\u00ed, pero la caracter\u00edstica DSP de CubeVox se desarrollar\u00e1 una vez que se alcancen los niveles de funding descritos en la campa\u00f1a.<\/p><\/div>\n\t\t\t\t\t<\/div><div class=\"eael-accordion-list\">\n\t\t\t\t\t<div id=\"puedo-utilizar-cubevox-cerrado\" class=\"elementor-tab-title eael-accordion-header\" tabindex=\"0\" data-tab=\"7\" aria-controls=\"elementor-tab-content-1577\"><span class=\"eael-accordion-tab-title\">\u00bfPuedo utilizar CubeVox cerrado?<\/span><i aria-hidden=\"true\" class=\"fa-toggle fas fa-angle-right\"><\/i><\/div><div id=\"elementor-tab-content-1577\" class=\"eael-accordion-content clearfix\" data-tab=\"7\" aria-labelledby=\"puedo-utilizar-cubevox-cerrado\"><p>Si, puedes utilizarlo como un parlante inal\u00e1mbrico o para reproducir m\u00fasica mediante Bluetooth, USB o MicroSD, en este modo dispones de controles multimedia retroiliminados. Recuerda que cuando CubeVox est\u00e1 cerrado, los parlantes que quedan ocultos ser\u00e1n desactivados. Esto reduce la potencia, pero incrementa la duraci\u00f3n de la bater\u00eda.<\/p><\/div>\n\t\t\t\t\t<\/div><div class=\"eael-accordion-list\">\n\t\t\t\t\t<div id=\"desarrollarn-una-pedaleracontrolador-para-cambios-de-efectos-del-cubevox\" class=\"elementor-tab-title eael-accordion-header\" tabindex=\"0\" data-tab=\"8\" aria-controls=\"elementor-tab-content-1578\"><span class=\"eael-accordion-tab-title\">\u00bfDesarrollar\u00e1n una pedalera\/controlador para cambios de efectos del CubeVox?<\/span><i aria-hidden=\"true\" class=\"fa-toggle fas fa-angle-right\"><\/i><\/div><div id=\"elementor-tab-content-1578\" class=\"eael-accordion-content clearfix\" data-tab=\"8\" aria-labelledby=\"desarrollarn-una-pedaleracontrolador-para-cambios-de-efectos-del-cubevox\"><p>S\u00ed, tenemos avanzado el desarrollo de una pedalera inal\u00e1mbrica que se enlazar\u00e1 mediante NFC\/Bluetooth con varios switch y pedal de expresi\u00f3n. Este accesorio se desarrollar\u00e1 m\u00e1s adelante en una campa\u00f1a nueva que se anunciar\u00e1 en nuestro sitio.<\/p><\/div>\n\t\t\t\t\t<\/div><div class=\"eael-accordion-list\">\n\t\t\t\t\t<div id=\"cul-es-la-duracin-de-la-batera-de-cubevox\" class=\"elementor-tab-title eael-accordion-header\" tabindex=\"0\" data-tab=\"9\" aria-controls=\"elementor-tab-content-1579\"><span class=\"eael-accordion-tab-title\">\u00bfCu\u00e1l es la duraci\u00f3n de la bater\u00eda de CubeVox?<\/span><i aria-hidden=\"true\" class=\"fa-toggle fas fa-angle-right\"><\/i><\/div><div id=\"elementor-tab-content-1579\" class=\"eael-accordion-content clearfix\" data-tab=\"9\" aria-labelledby=\"cul-es-la-duracin-de-la-batera-de-cubevox\"><p>CubeVox cuenta con una bater\u00eda extra\u00edble de 54wh, que ofrece una duraci\u00f3n en reproducci\u00f3n continua de hasta 14 horas en modo cerrado y 9 horas en modo abierto al 50% del volumen.<\/p><\/div>\n\t\t\t\t\t<\/div><div class=\"eael-accordion-list\">\n\t\t\t\t\t<div id=\"puedo-usar-cubevox-mientras-se-est-cargando\" class=\"elementor-tab-title eael-accordion-header\" tabindex=\"0\" data-tab=\"10\" aria-controls=\"elementor-tab-content-15710\"><span class=\"eael-accordion-tab-title\">\u00bfPuedo usar CubeVox mientras se est\u00e1 cargando?<\/span><i aria-hidden=\"true\" class=\"fa-toggle fas fa-angle-right\"><\/i><\/div><div id=\"elementor-tab-content-15710\" class=\"eael-accordion-content clearfix\" data-tab=\"10\" aria-labelledby=\"puedo-usar-cubevox-mientras-se-est-cargando\"><p>S\u00ed, Dise\u00f1amos CubeVox para que puedas usarlo en todo momento, incluso cuando lo cargas, ya que acepta carga r\u00e1pida de hasta 60 vatios. Solo considera que si el consumo del equipo es mayor que el de tu dispositivo de carga, este se descargar\u00e1 en vez de recargarse.<\/p><\/div>\n\t\t\t\t\t<\/div><div class=\"eael-accordion-list\">\n\t\t\t\t\t<div id=\"se-podrn-comprar-accesorios-para-cubevox-en-la-campaa-de-crowdfunding\" class=\"elementor-tab-title eael-accordion-header\" tabindex=\"0\" data-tab=\"11\" aria-controls=\"elementor-tab-content-15711\"><span class=\"eael-accordion-tab-title\">\u00bfSe podr\u00e1n comprar accesorios para CubeVox en la campa\u00f1a de crowdfunding?<\/span><i aria-hidden=\"true\" class=\"fa-toggle fas fa-angle-right\"><\/i><\/div><div id=\"elementor-tab-content-15711\" class=\"eael-accordion-content clearfix\" data-tab=\"11\" aria-labelledby=\"se-podrn-comprar-accesorios-para-cubevox-en-la-campaa-de-crowdfunding\"><p>Por el momento, la campa\u00f1a se enfoca en el CubeVox en s\u00ed mismo y sus caracter\u00edsticas principales. Sin embargo, una vez que se lance el producto al mercado, habr\u00e1 accesorios adicionales disponibles para su compra en nuestro sitio web.<\/p><\/div>\n\t\t\t\t\t<\/div><div class=\"eael-accordion-list\">\n\t\t\t\t\t<div id=\"qu-tipo-de-conectividad-tiene-cubevox\" class=\"elementor-tab-title eael-accordion-header\" tabindex=\"0\" data-tab=\"12\" aria-controls=\"elementor-tab-content-15712\"><span class=\"eael-accordion-tab-title\">\u00bfQu\u00e9 tipo de conectividad tiene CubeVox?<\/span><i aria-hidden=\"true\" class=\"fa-toggle fas fa-angle-right\"><\/i><\/div><div id=\"elementor-tab-content-15712\" class=\"eael-accordion-content clearfix\" data-tab=\"12\" aria-labelledby=\"qu-tipo-de-conectividad-tiene-cubevox\"><p>CubeVox cuenta con conectividad NFC, Bluetooth 5.1 BLE Aptx y WiFi 2.4GHz Wifi &#8211; 802.11b\/g\/n para una f\u00e1cil conexi\u00f3n con dispositivos m\u00f3viles y computadoras.<\/p><\/div>\n\t\t\t\t\t<\/div><div class=\"eael-accordion-list\">\n\t\t\t\t\t<div id=\"cules-son-las-dimensiones-y-peso-de-cubevox\" class=\"elementor-tab-title eael-accordion-header\" tabindex=\"0\" data-tab=\"13\" aria-controls=\"elementor-tab-content-15713\"><span class=\"eael-accordion-tab-title\">\u00bfCu\u00e1les son las dimensiones y peso de CubeVox?<\/span><i aria-hidden=\"true\" class=\"fa-toggle fas fa-angle-right\"><\/i><\/div><div id=\"elementor-tab-content-15713\" class=\"eael-accordion-content clearfix\" data-tab=\"13\" aria-labelledby=\"cules-son-las-dimensiones-y-peso-de-cubevox\"><p>CubeVox tiene unas dimensiones de 25 cm x 10 cm x 10 cm en modo cerrado y 50 cm en modo abierto, su peso es de 2,6 kg.<\/p><\/div>\n\t\t\t\t\t<\/div><div class=\"eael-accordion-list\">\n\t\t\t\t\t<div id=\"ofrecen-una-garanta-para-cubevox\" class=\"elementor-tab-title eael-accordion-header\" tabindex=\"0\" data-tab=\"14\" aria-controls=\"elementor-tab-content-15714\"><span class=\"eael-accordion-tab-title\">\u00bfOfrecen una garant\u00eda para CubeVox?<\/span><i aria-hidden=\"true\" class=\"fa-toggle fas fa-angle-right\"><\/i><\/div><div id=\"elementor-tab-content-15714\" class=\"eael-accordion-content clearfix\" data-tab=\"14\" aria-labelledby=\"ofrecen-una-garanta-para-cubevox\"><p>S\u00ed, ofrecemos una garant\u00eda limitada de 1 a\u00f1o para el CubeVox a partir de la fecha de compra. En caso de cualquier problema con el producto, por favor cont\u00e1ctanos para m\u00e1s informaci\u00f3n sobre c\u00f3mo proceder.<\/p><\/div>\n\t\t\t\t\t<\/div><\/div>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-03f8696 elementor-section-boxed elementor-section-height-default elementor-section-height-default\" data-id=\"03f8696\" data-element_type=\"section\" data-e-type=\"section\" data-settings=\"{&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-3eb6f5e\" data-id=\"3eb6f5e\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-fd37fcb elementor-widget-divider--view-line elementor-widget elementor-widget-divider\" data-id=\"fd37fcb\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"divider.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-divider\">\n\t\t\t<span class=\"elementor-divider-separator\">\n\t\t\t\t\t\t<\/span>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<section class=\"elementor-section elementor-inner-section elementor-element elementor-element-2e32177 elementor-section-boxed elementor-section-height-default elementor-section-height-default\" data-id=\"2e32177\" data-element_type=\"section\" data-e-type=\"section\" data-settings=\"{&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-inner-column elementor-element elementor-element-9fffba5\" data-id=\"9fffba5\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-fc26882 elementor-widget elementor-widget-text-editor\" data-id=\"fc26882\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>* Todas las especificaciones y las descripciones proporcionadas aqu\u00ed pueden ser diferentes de las especificaciones y las descripciones reales para el producto. AQA se reserva el derecho a realizar cambios a esta documentaci\u00f3n y al producto aqu\u00ed descrito, en cualquier momento, sin obligaci\u00f3n por parte de AQA de proporcionar una notificaci\u00f3n acerca de dicho cambio. Todas las funciones, las caracter\u00edsticas, las especificaciones, el software y otra informaci\u00f3n del producto proporcionada en esta documentaci\u00f3n que incluye, entre otros, los beneficios, el dise\u00f1o, el precio, los componentes, el rendimiento, la disponibilidad y las capacidades del producto est\u00e1n sujetos a cambio sin notificaci\u00f3n ni obligaci\u00f3n. Los contenidos dentro de la pantalla son im\u00e1genes simuladas y son solo con fines de demostraci\u00f3n.<br \/>* CubeVox HiFi no incluye cargador.<\/p><ol class=\"common-bottom-disclaimer__list\" role=\"list\" data-title=\"Ver descargo de responsabilidad\"><li class=\"common-bottom-disclaimer__list-item\" role=\"listitem\" data-sup=\"1\">La terminacion superficial puede variar en el trascurso de la produccion.<\/li><li class=\"common-bottom-disclaimer__list-item\" role=\"listitem\" data-sup=\"2\">La carcasa del dispositivo podr\u00e1 ser de aluminio, plastico o madera.<\/li><li class=\"common-bottom-disclaimer__list-item\" role=\"listitem\" data-sup=\"3\">Los efectos iniciales, la capacidad de crear efectos propios, la integracion con DAW y el propio Compose Studio en todas sus implementaciones se desarrollaran si se alcanzan los niveles de funding descriptos en la campa\u00f1a.<\/li><li class=\"common-bottom-disclaimer__list-item\" role=\"listitem\" data-sup=\"4\">Valores nominales especificos tales como db SPL, THD, SNR, Rango Dinamico, entre otros, pueden ser ligeramente distintos a los informados en esta pagina, dado que en la produccion y con mayor financiamiento, podrian existir cambios que afecten cada uno de ellos.<\/li><\/ol>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<div class=\"elementor-element elementor-element-89ee3b6 elementor-widget elementor-widget-html\" data-id=\"89ee3b6\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<!-- =====================================================\r\n     COMPONENT: OUR APPROACH Panel \/ Overlay\r\n     Root: .cvxScope [data-cvx-root=\"our-approach\"]\r\n     Notes:\r\n     - Starter Kit global is assumed already loaded.\r\n     - This component is scoped and can live inside an HTML widget.\r\n     - Open from a menu item or link with href=\"#our-approach\"\r\n===================================================== -->\r\n\r\n<div class=\"cvxScope\">\r\n  <section data-cvx-root=\"our-approach\"\r\n           aria-labelledby=\"cvx-oa-title\"\r\n           style=\"\r\n            --cvx-oa-z: 1400;\r\n            --cvx-oa-overlay: rgba(3, 8, 18, 0.74);\r\n            --cvx-oa-panel-bg: linear-gradient(180deg, rgba(10,16,30,.90) 0%, rgba(8,13,24,.94) 100%);\r\n            --cvx-oa-border: rgba(255,255,255,.10);\r\n            --cvx-oa-shadow: 0 28px 80px rgba(0,0,0,.42);\r\n            --cvx-oa-maxw: 1020px;\r\n            --cvx-oa-radius: 24px;\r\n            --cvx-oa-pad: clamp(18px, 2vw, 28px);\r\n            --cvx-oa-gap: clamp(14px, 1.6vw, 22px);\r\n            --cvx-oa-close-size: 42px;\r\n            --cvx-oa-blur: 14px;\r\n            --cvx-oa-title: clamp(24px, 3.3vw, 46px);\r\n            --cvx-oa-sub: clamp(14px, 1.15vw, 17px);\r\n            --cvx-oa-kicker: 12px;\r\n            --cvx-oa-copy: clamp(14px, 1.02vw, 16px);\r\n            --cvx-oa-card-title: clamp(15px, 1.2vw, 18px);\r\n            --cvx-oa-card-pad: clamp(16px, 1.5vw, 22px);\r\n            --cvx-oa-card-radius: 20px;\r\n            --cvx-oa-card-minh: 208px;\r\n            --cvx-oa-grid-gap: clamp(12px, 1.3vw, 18px);\r\n            --cvx-oa-hero-gap: 12px;\r\n            --cvx-oa-metric-gap: 10px;\r\n            --cvx-oa-chip-gap: 8px;\r\n            --cvx-oa-chip-pad-y: 8px;\r\n            --cvx-oa-chip-pad-x: 12px;\r\n            --cvx-oa-chip-radius: 999px;\r\n            --cvx-oa-chip-bg: rgba(255,255,255,.055);\r\n            --cvx-oa-chip-bd: rgba(255,255,255,.09);\r\n            --cvx-oa-card-bg: linear-gradient(180deg, rgba(255,255,255,.055) 0%, rgba(255,255,255,.035) 100%);\r\n            --cvx-oa-card-bd: rgba(255,255,255,.10);\r\n            --cvx-oa-accent-soft: rgba(56,189,248,.16);\r\n            --cvx-oa-accent-line: rgba(56,189,248,.34);\r\n            --cvx-oa-muted: rgba(226,232,240,.74);\r\n            --cvx-oa-strong: #F8FAFC;\r\n            --cvx-oa-bottom-gap: 14px;\r\n            --cvx-oa-cta-gap: 10px;\r\n            --cvx-oa-mobile-panel-h: min(100dvh - 20px, 920px);\r\n           \">\r\n\r\n    <div class=\"cvx-oa-overlay\" data-cvx-close=\"our-approach\" hidden><\/div>\r\n\r\n    <div class=\"cvx-oa-shell\" hidden>\r\n      <div class=\"cvx-oa-panel\" role=\"dialog\" aria-modal=\"true\" aria-describedby=\"cvx-oa-subtitle\" tabindex=\"-1\">\r\n        <button class=\"cvx-oa-close\" type=\"button\" aria-label=\"Cerrar panel\" data-cvx-close=\"our-approach\">\r\n          <span aria-hidden=\"true\">\u00d7<\/span>\r\n        <\/button>\r\n\r\n        <div class=\"cvx-oa-head\">\r\n          <span class=\"cvx-oa-kicker\">NUESTRO ENFOQUE<\/span>\r\n          <h2 id=\"cvx-oa-title\" class=\"cvx-oa-title\">Menos equipos, menos vueltas. M\u00e1s tiempo para crear.<\/h2>\r\n          <p id=\"cvx-oa-subtitle\" class=\"cvx-oa-subtitle\">\r\n            CubeVox fue pensado para algo muy simple: que puedas crear, practicar, grabar y moverte con una sola herramienta, en lugar de depender de varios equipos para cada etapa.\r\n          <\/p>\r\n\r\n          <div class=\"cvx-oa-chips\" aria-label=\"Claves del enfoque\">\r\n            <span class=\"cvx-oa-chip\">Una herramienta para m\u00e1s momentos<\/span>\r\n            <span class=\"cvx-oa-chip\">Port\u00e1til sin sentirse limitada<\/span>\r\n            <span class=\"cvx-oa-chip\">Menos fricci\u00f3n, m\u00e1s continuidad<\/span>\r\n            <span class=\"cvx-oa-chip\">Audio serio, uso real<\/span>\r\n          <\/div>\r\n        <\/div>\r\n\r\n        <div class=\"cvx-oa-grid\">\r\n          <article class=\"cvx-oa-card cvx-oa-card--problem\">\r\n            <span class=\"cvx-oa-card-kicker\">EL PROBLEMA<\/span>\r\n            <h3 class=\"cvx-oa-card-title\">Hoy muchas personas necesitan un equipo para practicar, otro para grabar y otro para llevar la m\u00fasica a otro lugar.<\/h3>\r\n            <p class=\"cvx-oa-copy\">\r\n              Eso hace que algo que deber\u00eda ser directo se vuelva lento. Hay que conectar, adaptar, volver a configurar y, muchas veces, aceptar menos control o menos calidad con tal de ganar portabilidad.\r\n            <\/p>\r\n            <ul class=\"cvx-oa-points\" aria-label=\"Puntos de fricci\u00f3n\">\r\n              <li>M\u00e1s equipos de los necesarios para hacer tareas que est\u00e1n conectadas entre s\u00ed<\/li>\r\n              <li>Tiempo perdido armando el setup en vez de avanzar con la m\u00fasica<\/li>\r\n              <li>Opciones port\u00e1tiles que obligan a resignar funciones o experiencia de uso<\/li>\r\n            <\/ul>\r\n          <\/article>\r\n\r\n          <article class=\"cvx-oa-card cvx-oa-card--approach\">\r\n            <span class=\"cvx-oa-card-kicker\">EL ENFOQUE<\/span>\r\n            <h3 class=\"cvx-oa-card-title\">El enfoque de CubeVox es juntar en un solo equipo tareas que normalmente est\u00e1n repartidas.<\/h3>\r\n            <p class=\"cvx-oa-copy\">\r\n              En vez de saltar entre distintos dispositivos seg\u00fan el momento, CubeVox busca darte una base m\u00e1s continua para trabajar con audio: crear, procesar, reproducir y adaptarte al contexto sin rehacer todo cada vez.\r\n            <\/p>\r\n            <ul class=\"cvx-oa-points\" aria-label=\"Principios de dise\u00f1o\">\r\n              <li>Un sistema m\u00e1s simple de llevar y de usar<\/li>\r\n              <li>M\u00e1s continuidad entre pr\u00e1ctica, creaci\u00f3n y producci\u00f3n<\/li>\r\n              <li>Menos dependencia de armar un setup distinto para cada situaci\u00f3n<\/li>\r\n            <\/ul>\r\n          <\/article>\r\n\r\n          <article class=\"cvx-oa-card cvx-oa-card--value\">\r\n            <span class=\"cvx-oa-card-kicker\">POR QU\u00c9 IMPORTA<\/span>\r\n            <h3 class=\"cvx-oa-card-title\">El valor est\u00e1 en poder avanzar m\u00e1s r\u00e1pido y con menos fricci\u00f3n, sin sentir que est\u00e1s usando una soluci\u00f3n recortada.<\/h3>\r\n            <p class=\"cvx-oa-copy\">\r\n              CubeVox no busca reemplazar solo un aparato. Busca simplificar todo el recorrido. Por eso su valor no est\u00e1 solo en lo que incluye, sino en lo que te evita: cargar menos, configurar menos e interrumpirte menos.\r\n            <\/p>\r\n            <div class=\"cvx-oa-metrics\" aria-label=\"Dimensiones de valor\">\r\n              <span class=\"cvx-oa-metric\">Menos equipos<\/span>\r\n              <span class=\"cvx-oa-metric\">Menos tiempo de armado<\/span>\r\n              <span class=\"cvx-oa-metric\">M\u00e1s continuidad<\/span>\r\n              <span class=\"cvx-oa-metric\">M\u00e1s libertad para crear<\/span>\r\n            <\/div>\r\n          <\/article>\r\n        <\/div>\r\n\r\n        <div class=\"cvx-oa-bottom\">\r\n          <p class=\"cvx-oa-bottom-copy\">\r\n            En pocas palabras: CubeVox busca que trabajar con audio sea m\u00e1s simple, m\u00e1s port\u00e1til y m\u00e1s continuo, sin obligarte a pasar de un equipo a otro para poder avanzar.\r\n          <\/p>\r\n\r\n          <div class=\"cvx-oa-actions\">\r\n            <a class=\"cvx-oa-btn cvx-oa-btn--primary\" href=\"#uses\">Explorar CubeVox<\/a>\r\n          <\/div>\r\n        <\/div>\r\n      <\/div>\r\n    <\/div>\r\n  <\/section>\r\n<\/div>\r\n\r\n<style>\r\n  .cvxScope [data-cvx-root=\"our-approach\"]{\r\n    position: relative;\r\n    z-index: var(--cvx-oa-z);\r\n  }\r\n\r\n  .cvxScope [data-cvx-root=\"our-approach\"] *{ box-sizing: border-box; }\r\n\r\n  .cvxScope [data-cvx-root=\"our-approach\"] .cvx-oa-overlay,\r\n  .cvxScope [data-cvx-root=\"our-approach\"] .cvx-oa-shell{\r\n    position: fixed;\r\n    inset: 0;\r\n    opacity: 0;\r\n    pointer-events: none;\r\n    transition: opacity .28s ease;\r\n  }\r\n\r\n  .cvxScope [data-cvx-root=\"our-approach\"] .cvx-oa-overlay{\r\n    background: var(--cvx-oa-overlay);\r\n    backdrop-filter: blur(calc(var(--cvx-oa-blur) * .7));\r\n    -webkit-backdrop-filter: blur(calc(var(--cvx-oa-blur) * .7));\r\n  }\r\n\r\n  .cvxScope [data-cvx-root=\"our-approach\"] .cvx-oa-shell{\r\n    display: grid;\r\n    place-items: center;\r\n    padding: 22px;\r\n  }\r\n\r\n  .cvxScope [data-cvx-root=\"our-approach\"] .cvx-oa-panel{\r\n    position: relative;\r\n    width: min(100%, var(--cvx-oa-maxw));\r\n    max-height: min(100dvh - 34px, 900px);\r\n    overflow: auto;\r\n    border-radius: var(--cvx-oa-radius);\r\n    padding: var(--cvx-oa-pad);\r\n    background: var(--cvx-oa-panel-bg);\r\n    border: 1px solid var(--cvx-oa-border);\r\n    box-shadow: var(--cvx-oa-shadow);\r\n    color: var(--cvx-oa-strong);\r\n    scrollbar-width: thin;\r\n    scrollbar-color: rgba(255,255,255,.18) transparent;\r\n  }\r\n\r\n  .cvxScope [data-cvx-root=\"our-approach\"] .cvx-oa-panel::-webkit-scrollbar{ width: 10px; }\r\n  .cvxScope [data-cvx-root=\"our-approach\"] .cvx-oa-panel::-webkit-scrollbar-thumb{\r\n    background: rgba(255,255,255,.18);\r\n    border-radius: 999px;\r\n    border: 2px solid transparent;\r\n    background-clip: padding-box;\r\n  }\r\n\r\n  .cvxScope [data-cvx-root=\"our-approach\"] .cvx-oa-close{\r\n    position: absolute;\r\n    top: 18px;\r\n    right: 18px;\r\n    display: inline-flex;\r\n    align-items: center;\r\n    justify-content: center;\r\n    width: var(--cvx-oa-close-size);\r\n    height: var(--cvx-oa-close-size);\r\n    padding: 0;\r\n    border-radius: 999px;\r\n    border: 1px solid rgba(255,255,255,.12);\r\n    background: rgba(255,255,255,.045);\r\n    color: #fff;\r\n    cursor: pointer;\r\n    backdrop-filter: blur(8px);\r\n    -webkit-backdrop-filter: blur(8px);\r\n    transition: transform .18s ease, background .18s ease, border-color .18s ease, box-shadow .18s ease;\r\n    z-index: 3;\r\n    box-shadow: inset 0 1px 0 rgba(255,255,255,.03);\r\n  }\r\n\r\n  .cvxScope [data-cvx-root=\"our-approach\"] .cvx-oa-close span{\r\n    display: block;\r\n    line-height: 1;\r\n    font-size: 22px;\r\n    transform: translateY(-1px);\r\n  }\r\n\r\n  .cvxScope [data-cvx-root=\"our-approach\"] .cvx-oa-close:hover{\r\n    transform: translateY(-1px);\r\n    background: rgba(255,255,255,.08);\r\n    border-color: rgba(255,255,255,.18);\r\n    box-shadow: 0 8px 24px rgba(0,0,0,.22);\r\n  }\r\n\r\n  .cvxScope [data-cvx-root=\"our-approach\"] .cvx-oa-head{\r\n    display: grid;\r\n    gap: var(--cvx-oa-hero-gap);\r\n    margin-top: 4px;\r\n    padding-right: calc(var(--cvx-oa-close-size) + 18px);\r\n  }\r\n\r\n  .cvxScope [data-cvx-root=\"our-approach\"] .cvx-oa-kicker,\r\n  .cvxScope [data-cvx-root=\"our-approach\"] .cvx-oa-card-kicker{\r\n    display: inline-flex;\r\n    align-items: center;\r\n    width: fit-content;\r\n    min-height: 26px;\r\n    padding: 0 10px;\r\n    border-radius: 999px;\r\n    border: 1px solid var(--cvx-oa-accent-line);\r\n    background: var(--cvx-oa-accent-soft);\r\n    color: #E0F2FE;\r\n    font-size: var(--cvx-oa-kicker);\r\n    font-weight: 700;\r\n    letter-spacing: .14em;\r\n    text-transform: uppercase;\r\n  }\r\n\r\n  .cvxScope [data-cvx-root=\"our-approach\"] .cvx-oa-title{\r\n    margin: 0;\r\n    font-size: var(--cvx-oa-title);\r\n    line-height: 1.04;\r\n    letter-spacing: -.03em;\r\n    text-wrap: balance;\r\n    max-width: 18ch;\r\n  }\r\n\r\n  .cvxScope [data-cvx-root=\"our-approach\"] .cvx-oa-subtitle{\r\n    margin: 0;\r\n    max-width: 820px;\r\n    color: var(--cvx-oa-muted);\r\n    font-size: var(--cvx-oa-sub);\r\n    line-height: 1.55;\r\n    text-wrap: pretty;\r\n  }\r\n\r\n  .cvxScope [data-cvx-root=\"our-approach\"] .cvx-oa-chips,\r\n  .cvxScope [data-cvx-root=\"our-approach\"] .cvx-oa-metrics{\r\n    display: flex;\r\n    flex-wrap: wrap;\r\n    gap: var(--cvx-oa-chip-gap);\r\n  }\r\n\r\n  .cvxScope [data-cvx-root=\"our-approach\"] .cvx-oa-chip,\r\n  .cvxScope [data-cvx-root=\"our-approach\"] .cvx-oa-metric{\r\n    display: inline-flex;\r\n    align-items: center;\r\n    min-height: 36px;\r\n    padding: var(--cvx-oa-chip-pad-y) var(--cvx-oa-chip-pad-x);\r\n    border-radius: var(--cvx-oa-chip-radius);\r\n    border: 1px solid var(--cvx-oa-chip-bd);\r\n    background: var(--cvx-oa-chip-bg);\r\n    color: rgba(248,250,252,.94);\r\n    font-size: 13px;\r\n    line-height: 1.2;\r\n  }\r\n\r\n  .cvxScope [data-cvx-root=\"our-approach\"] .cvx-oa-grid{\r\n    display: grid;\r\n    grid-template-columns: repeat(3, minmax(0, 1fr));\r\n    gap: var(--cvx-oa-grid-gap);\r\n    margin-top: clamp(18px, 2vw, 24px);\r\n  }\r\n\r\n  .cvxScope [data-cvx-root=\"our-approach\"] .cvx-oa-card{\r\n    display: grid;\r\n    align-content: start;\r\n    gap: 12px;\r\n    min-height: var(--cvx-oa-card-minh);\r\n    padding: var(--cvx-oa-card-pad);\r\n    border-radius: var(--cvx-oa-card-radius);\r\n    border: 1px solid var(--cvx-oa-card-bd);\r\n    background: var(--cvx-oa-card-bg);\r\n    box-shadow: inset 0 1px 0 rgba(255,255,255,.03);\r\n  }\r\n\r\n  .cvxScope [data-cvx-root=\"our-approach\"] .cvx-oa-card-title{\r\n    margin: 0;\r\n    font-size: var(--cvx-oa-card-title);\r\n    line-height: 1.18;\r\n    letter-spacing: -.02em;\r\n    text-wrap: balance;\r\n  }\r\n\r\n  .cvxScope [data-cvx-root=\"our-approach\"] .cvx-oa-copy{\r\n    margin: 0;\r\n    color: var(--cvx-oa-muted);\r\n    font-size: var(--cvx-oa-copy);\r\n    line-height: 1.65;\r\n    text-wrap: pretty;\r\n  }\r\n\r\n  .cvxScope [data-cvx-root=\"our-approach\"] .cvx-oa-points{\r\n    display: grid;\r\n    gap: 10px;\r\n    margin: 0;\r\n    padding: 0;\r\n    list-style: none;\r\n  }\r\n\r\n  .cvxScope [data-cvx-root=\"our-approach\"] .cvx-oa-points li{\r\n    position: relative;\r\n    padding-left: 16px;\r\n    color: rgba(248,250,252,.88);\r\n    font-size: 13px;\r\n    line-height: 1.45;\r\n  }\r\n\r\n  .cvxScope [data-cvx-root=\"our-approach\"] .cvx-oa-points li::before{\r\n    content: \"\";\r\n    position: absolute;\r\n    left: 0;\r\n    top: .58em;\r\n    width: 6px;\r\n    height: 6px;\r\n    border-radius: 999px;\r\n    background: #38BDF8;\r\n    box-shadow: 0 0 0 4px rgba(56,189,248,.14);\r\n  }\r\n\r\n  .cvxScope [data-cvx-root=\"our-approach\"] .cvx-oa-bottom{\r\n    display: grid;\r\n    gap: var(--cvx-oa-bottom-gap);\r\n    margin-top: clamp(18px, 2vw, 24px);\r\n    padding-top: clamp(12px, 1.5vw, 18px);\r\n    border-top: 1px solid rgba(255,255,255,.09);\r\n  }\r\n\r\n  .cvxScope [data-cvx-root=\"our-approach\"] .cvx-oa-bottom-copy{\r\n    margin: 0;\r\n    max-width: 840px;\r\n    color: rgba(248,250,252,.84);\r\n    font-size: 14px;\r\n    line-height: 1.6;\r\n  }\r\n\r\n  .cvxScope [data-cvx-root=\"our-approach\"] .cvx-oa-actions{\r\n    display: flex;\r\n    flex-wrap: wrap;\r\n    gap: var(--cvx-oa-cta-gap);\r\n  }\r\n\r\n  .cvxScope [data-cvx-root=\"our-approach\"] .cvx-oa-btn{\r\n    display: inline-flex;\r\n    align-items: center;\r\n    justify-content: center;\r\n    min-width: 188px;\r\n    min-height: 50px;\r\n    padding: 0 18px;\r\n    border-radius: 12px;\r\n    font-size: 15px;\r\n    font-weight: 600;\r\n    line-height: 1;\r\n    text-decoration: none;\r\n    cursor: pointer;\r\n    transition: transform .18s ease, border-color .18s ease, background .18s ease, color .18s ease, box-shadow .18s ease;\r\n  }\r\n\r\n  .cvxScope [data-cvx-root=\"our-approach\"] .cvx-oa-btn:hover{\r\n    transform: translateY(-1px);\r\n  }\r\n\r\n  .cvxScope [data-cvx-root=\"our-approach\"] .cvx-oa-btn--primary{\r\n    border: 1px solid rgba(56,189,248,.34);\r\n    background: linear-gradient(180deg, rgba(56,189,248,.18) 0%, rgba(56,189,248,.12) 100%);\r\n    color: #F8FAFC;\r\n    box-shadow: inset 0 1px 0 rgba(255,255,255,.04);\r\n  }\r\n\r\n  .cvxScope [data-cvx-root=\"our-approach\"] .cvx-oa-btn--primary:hover{\r\n    border-color: rgba(56,189,248,.48);\r\n    background: linear-gradient(180deg, rgba(56,189,248,.24) 0%, rgba(56,189,248,.16) 100%);\r\n  }\r\n\r\n  .cvxScope [data-cvx-root=\"our-approach\"] .cvx-oa-btn--secondary{\r\n    border: 1px solid rgba(255,255,255,.14);\r\n    background: rgba(255,255,255,.035);\r\n    color: rgba(248,250,252,.96);\r\n    box-shadow: inset 0 1px 0 rgba(255,255,255,.03);\r\n  }\r\n\r\n  .cvxScope [data-cvx-root=\"our-approach\"] .cvx-oa-btn--secondary:hover{\r\n    border-color: rgba(255,255,255,.22);\r\n    background: rgba(255,255,255,.06);\r\n  }\r\n\r\n  .cvxScope [data-cvx-root=\"our-approach\"].is-open .cvx-oa-overlay,\r\n  .cvxScope [data-cvx-root=\"our-approach\"].is-open .cvx-oa-shell{\r\n    opacity: 1;\r\n    pointer-events: auto;\r\n  }\r\n\r\n  @media (max-width: 980px){\r\n    .cvxScope [data-cvx-root=\"our-approach\"] .cvx-oa-grid{\r\n      grid-template-columns: 1fr;\r\n    }\r\n  }\r\n\r\n  @media (max-width: 767px){\r\n    .cvxScope [data-cvx-root=\"our-approach\"] .cvx-oa-shell{\r\n      align-items: end;\r\n      padding: 10px;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"our-approach\"] .cvx-oa-panel{\r\n      width: 100%;\r\n      max-height: var(--cvx-oa-mobile-panel-h);\r\n      border-radius: 22px 22px 18px 18px;\r\n      padding: 16px;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"our-approach\"] .cvx-oa-head{\r\n      padding-right: calc(var(--cvx-oa-close-size) + 10px);\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"our-approach\"] .cvx-oa-title{\r\n      max-width: 13ch;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"our-approach\"] .cvx-oa-actions{\r\n      display: grid;\r\n      grid-template-columns: 1fr;\r\n    }\r\n\r\n    .cvxScope [data-cvx-root=\"our-approach\"] .cvx-oa-btn{\r\n      width: 100%;\r\n      min-width: 0;\r\n    }\r\n  }\r\n\r\n  @media (prefers-reduced-motion: reduce){\r\n    .cvxScope [data-cvx-root=\"our-approach\"] .cvx-oa-overlay,\r\n    .cvxScope [data-cvx-root=\"our-approach\"] .cvx-oa-shell,\r\n    .cvxScope [data-cvx-root=\"our-approach\"] .cvx-oa-close,\r\n    .cvxScope [data-cvx-root=\"our-approach\"] .cvx-oa-btn{\r\n      transition: none !important;\r\n    }\r\n  }\r\n<\/style>\r\n\r\n<script>\r\n  (function(){\r\n    const root = document.querySelector('.cvxScope [data-cvx-root=\"our-approach\"]');\r\n    if(!root || root.__cvxOurApproachBound) return;\r\n    root.__cvxOurApproachBound = true;\r\n\r\n    const overlay = root.querySelector('.cvx-oa-overlay');\r\n    const shell = root.querySelector('.cvx-oa-shell');\r\n    const panel = root.querySelector('.cvx-oa-panel');\r\n    const hashOpeners = Array.from(document.querySelectorAll('a[href=\"#our-approach\"]'));\r\n    const internalClosers = Array.from(root.querySelectorAll('[data-cvx-close=\"our-approach\"]'));\r\n\r\n    let lastActive = null;\r\n    let bodyOverflow = '';\r\n    let scrollY = 0;\r\n\r\n    function getFocusable(){\r\n      return Array.from(panel.querySelectorAll(\r\n        'a[href], button:not([disabled]), textarea:not([disabled]), input:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex=\"-1\"])'\r\n      )).filter(el => el.offsetParent !== null || el === document.activeElement);\r\n    }\r\n\r\n    function lockScroll(){\r\n      scrollY = window.scrollY || window.pageYOffset || 0;\r\n      bodyOverflow = document.body.style.overflow;\r\n      document.body.style.overflow = 'hidden';\r\n    }\r\n\r\n    function unlockScroll(){\r\n      document.body.style.overflow = bodyOverflow || '';\r\n      window.scrollTo(0, scrollY);\r\n    }\r\n\r\n    function openPanel(ev){\r\n      if(ev) ev.preventDefault();\r\n      if(root.classList.contains('is-open')) return;\r\n      lastActive = document.activeElement;\r\n      overlay.hidden = false;\r\n      shell.hidden = false;\r\n      root.classList.add('is-open');\r\n      lockScroll();\r\n      requestAnimationFrame(() => {\r\n        (getFocusable()[0] || panel).focus();\r\n      });\r\n    }\r\n\r\n    function closePanel(ev){\r\n      if(ev) ev.preventDefault();\r\n      root.classList.remove('is-open');\r\n      unlockScroll();\r\n      if(window.location.hash === '#our-approach'){\r\n        if(window.history && typeof window.history.replaceState === 'function'){\r\n          window.history.replaceState(null, '', window.location.pathname + window.location.search);\r\n        } else {\r\n          window.location.hash = '';\r\n        }\r\n      }\r\n      const cleanup = () => {\r\n        overlay.hidden = true;\r\n        shell.hidden = true;\r\n        overlay.removeEventListener('transitionend', cleanup);\r\n      };\r\n      overlay.addEventListener('transitionend', cleanup);\r\n      setTimeout(cleanup, 320);\r\n      if(lastActive && typeof lastActive.focus === 'function'){\r\n        requestAnimationFrame(() => lastActive.focus());\r\n      }\r\n    }\r\n\r\n    function onKeydown(ev){\r\n      if(!root.classList.contains('is-open')) return;\r\n\r\n      if(ev.key === 'Escape'){\r\n        closePanel(ev);\r\n        return;\r\n      }\r\n\r\n      if(ev.key !== 'Tab') return;\r\n      const items = getFocusable();\r\n      if(!items.length){\r\n        ev.preventDefault();\r\n        panel.focus();\r\n        return;\r\n      }\r\n      const first = items[0];\r\n      const last = items[items.length - 1];\r\n      if(ev.shiftKey && document.activeElement === first){\r\n        ev.preventDefault();\r\n        last.focus();\r\n      } else if(!ev.shiftKey && document.activeElement === last){\r\n        ev.preventDefault();\r\n        first.focus();\r\n      }\r\n    }\r\n\r\n    hashOpeners.forEach(link => {\r\n      link.addEventListener('click', () => {\r\n        if(window.location.hash === '#our-approach' && !root.classList.contains('is-open')){\r\n          openPanel();\r\n        }\r\n      });\r\n    });\r\n\r\n    internalClosers.forEach(btn => btn.addEventListener('click', closePanel));\r\n    const actionLinks = root.querySelectorAll('.cvx-oa-actions a[href]');\r\nactionLinks.forEach(link => {\r\n  link.addEventListener('click', () => {\r\n    closePanel();\r\n  });\r\n});\r\n    document.addEventListener('keydown', onKeydown);\r\n\r\n    if(window.location.hash === '#our-approach'){\r\n      openPanel();\r\n    }\r\n\r\n    window.addEventListener('hashchange', () => {\r\n      if(window.location.hash === '#our-approach') {\r\n        openPanel();\r\n      }\r\n    });\r\n  })();\r\n<\/script>\r\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>CubeVox HiFi is a premium all-in-one portable audio system for playing, performing, monitoring and creating. \/ CubeVox HiFi es un sistema de audio port\u00e1til premium todo en uno para reproducir, tocar, monitorear y crear.<\/p>","protected":false},"author":1,"featured_media":7052,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-7064","page","type-page","status-publish","has-post-thumbnail","hentry"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.4 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>CubeVox | Portable All-in-One Audio Studio<\/title>\n<meta name=\"description\" content=\"A portable all-in-one device and creative ecosystem that empowers independent musicians to record, produce, and share their music anywhere\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/cube-vox.com\/en\/home\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"CubeVox | Portable All-in-One Audio Studio\" \/>\n<meta property=\"og:description\" content=\"A portable all-in-one device and creative ecosystem that empowers independent musicians to record, produce, and share their music anywhere\" \/>\n<meta property=\"og:url\" content=\"https:\/\/cube-vox.com\/en\/home\/\" \/>\n<meta property=\"og:site_name\" content=\"Cubevox\" \/>\n<meta property=\"article:modified_time\" content=\"2026-04-13T18:42:17+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/cube-vox.com\/wp-content\/uploads\/CubeVox.webp\" \/>\n\t<meta property=\"og:image:width\" content=\"1536\" \/>\n\t<meta property=\"og:image:height\" content=\"1024\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/webp\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data1\" content=\"31 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/cube-vox.com\\\/home\\\/\",\"url\":\"https:\\\/\\\/cube-vox.com\\\/home\\\/\",\"name\":\"CubeVox | Portable All-in-One Audio Studio\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/cube-vox.com\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/cube-vox.com\\\/home\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/cube-vox.com\\\/home\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/cube-vox.com\\\/wp-content\\\/uploads\\\/CubeVox.webp\",\"datePublished\":\"2026-04-11T06:48:16+00:00\",\"dateModified\":\"2026-04-13T18:42:17+00:00\",\"description\":\"A portable all-in-one device and creative ecosystem that empowers independent musicians to record, produce, and share their music anywhere\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/cube-vox.com\\\/home\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/cube-vox.com\\\/home\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/cube-vox.com\\\/home\\\/#primaryimage\",\"url\":\"https:\\\/\\\/cube-vox.com\\\/wp-content\\\/uploads\\\/CubeVox.webp\",\"contentUrl\":\"https:\\\/\\\/cube-vox.com\\\/wp-content\\\/uploads\\\/CubeVox.webp\",\"width\":1536,\"height\":1024},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/cube-vox.com\\\/home\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/cube-vox.com\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"CubeVox\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/cube-vox.com\\\/#website\",\"url\":\"https:\\\/\\\/cube-vox.com\\\/\",\"name\":\"Cubevox\",\"description\":\"Accuracy-Quality-Audio\",\"publisher\":{\"@id\":\"https:\\\/\\\/cube-vox.com\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/cube-vox.com\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/cube-vox.com\\\/#organization\",\"name\":\"Cubevox\",\"url\":\"https:\\\/\\\/cube-vox.com\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/cube-vox.com\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/cube-vox.com\\\/wp-content\\\/uploads\\\/cubevox-logo-mark.webp\",\"contentUrl\":\"https:\\\/\\\/cube-vox.com\\\/wp-content\\\/uploads\\\/cubevox-logo-mark.webp\",\"width\":1445,\"height\":368,\"caption\":\"Cubevox\"},\"image\":{\"@id\":\"https:\\\/\\\/cube-vox.com\\\/#\\\/schema\\\/logo\\\/image\\\/\"}}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"CubeVox | Portable All-in-One Audio Studio","description":"A portable all-in-one device and creative ecosystem that empowers independent musicians to record, produce, and share their music anywhere","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:\/\/cube-vox.com\/en\/home\/","og_locale":"en_US","og_type":"article","og_title":"CubeVox | Portable All-in-One Audio Studio","og_description":"A portable all-in-one device and creative ecosystem that empowers independent musicians to record, produce, and share their music anywhere","og_url":"https:\/\/cube-vox.com\/en\/home\/","og_site_name":"Cubevox","article_modified_time":"2026-04-13T18:42:17+00:00","og_image":[{"width":1536,"height":1024,"url":"https:\/\/cube-vox.com\/wp-content\/uploads\/CubeVox.webp","type":"image\/webp"}],"twitter_card":"summary_large_image","twitter_misc":{"Est. reading time":"31 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/cube-vox.com\/home\/","url":"https:\/\/cube-vox.com\/home\/","name":"CubeVox | Portable All-in-One Audio Studio","isPartOf":{"@id":"https:\/\/cube-vox.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/cube-vox.com\/home\/#primaryimage"},"image":{"@id":"https:\/\/cube-vox.com\/home\/#primaryimage"},"thumbnailUrl":"https:\/\/cube-vox.com\/wp-content\/uploads\/CubeVox.webp","datePublished":"2026-04-11T06:48:16+00:00","dateModified":"2026-04-13T18:42:17+00:00","description":"A portable all-in-one device and creative ecosystem that empowers independent musicians to record, produce, and share their music anywhere","breadcrumb":{"@id":"https:\/\/cube-vox.com\/home\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/cube-vox.com\/home\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cube-vox.com\/home\/#primaryimage","url":"https:\/\/cube-vox.com\/wp-content\/uploads\/CubeVox.webp","contentUrl":"https:\/\/cube-vox.com\/wp-content\/uploads\/CubeVox.webp","width":1536,"height":1024},{"@type":"BreadcrumbList","@id":"https:\/\/cube-vox.com\/home\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/cube-vox.com\/"},{"@type":"ListItem","position":2,"name":"CubeVox"}]},{"@type":"WebSite","@id":"https:\/\/cube-vox.com\/#website","url":"https:\/\/cube-vox.com\/","name":"Cubevox","description":"Accuracy-Quality-Audio","publisher":{"@id":"https:\/\/cube-vox.com\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/cube-vox.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/cube-vox.com\/#organization","name":"Cubevox","url":"https:\/\/cube-vox.com\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cube-vox.com\/#\/schema\/logo\/image\/","url":"https:\/\/cube-vox.com\/wp-content\/uploads\/cubevox-logo-mark.webp","contentUrl":"https:\/\/cube-vox.com\/wp-content\/uploads\/cubevox-logo-mark.webp","width":1445,"height":368,"caption":"Cubevox"},"image":{"@id":"https:\/\/cube-vox.com\/#\/schema\/logo\/image\/"}}]}},"_links":{"self":[{"href":"https:\/\/cube-vox.com\/en\/wp-json\/wp\/v2\/pages\/7064","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/cube-vox.com\/en\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/cube-vox.com\/en\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/cube-vox.com\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/cube-vox.com\/en\/wp-json\/wp\/v2\/comments?post=7064"}],"version-history":[{"count":3,"href":"https:\/\/cube-vox.com\/en\/wp-json\/wp\/v2\/pages\/7064\/revisions"}],"predecessor-version":[{"id":7078,"href":"https:\/\/cube-vox.com\/en\/wp-json\/wp\/v2\/pages\/7064\/revisions\/7078"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/cube-vox.com\/en\/wp-json\/wp\/v2\/media\/7052"}],"wp:attachment":[{"href":"https:\/\/cube-vox.com\/en\/wp-json\/wp\/v2\/media?parent=7064"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}