{"title":"Productos Físicos","description":"\u003cp\u003eColección de todos nuestros productos físicos disponibles en la tienda.\u003c\/p\u003e","products":[{"product_id":"sgp-card-mini","title":"SGP card mini","description":"\u003cbody\u003e\n\n\n    \u003cmeta charset=\"UTF-8\"\u003e\n    \u003cmeta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"\u003e\n    \u003ctitle\u003eSGP CARD MINI - Premium Hub\u003c\/title\u003e\n    \n    \u003c!-- Google Fonts: Space Grotesk (Headers) and Inter (Body) --\u003e\n    \u003clink rel=\"preconnect\" href=\"https:\/\/fonts.googleapis.com\"\u003e\n    \u003clink rel=\"preconnect\" href=\"https:\/\/fonts.gstatic.com\" crossorigin\u003e\n    \u003clink href=\"https:\/\/fonts.googleapis.com\/css2?family=Inter:wght@400;500;600\u0026amp;family=Space+Grotesk:wght@700;800\u0026amp;display=swap\" rel=\"stylesheet\"\u003e\n\n    \u003cstyle\u003e\n        \/* =========================================\n           NEUMORPHIC SYSTEM VARIABLES\n           ========================================= *\/\n        :root {\n            \/* Color Palette *\/\n            --bg-color: #e0e5ec;\n            --text-main: #2d3748;\n            --text-muted: #718096;\n            --accent: #eab308; \/* Premium Amber\/Gold *\/\n            --success: #38a169;\n            --danger: #e53e3e;\n            \n            \/* Shadows (Extrusion\/Sunken Effects) *\/\n            --shadow-light: rgba(255, 255, 255, 0.8);\n            --shadow-dark: rgba(163, 177, 198, 0.6);\n            --neu-out: 9px 9px 16px var(--shadow-dark), -9px -9px 16px var(--shadow-light);\n            --neu-out-sm: 5px 5px 10px var(--shadow-dark), -5px -5px 10px var(--shadow-light);\n            --neu-in: inset 6px 6px 10px var(--shadow-dark), inset -6px -6px 10px var(--shadow-light);\n            \n            \/* Border Radii *\/\n            --radius-xl: 40px;\n            --radius-lg: 30px;\n            --radius-pill: 100px;\n            \n            \/* Transitions *\/\n            --transition: all 0.25s ease-in-out;\n        }\n\n        \/* =========================================\n           RESET \u0026 BASE STYLES\n           ========================================= *\/\n        * {\n            box-sizing: border-box;\n            margin: 0;\n            padding: 0;\n        }\n\n        body {\n            background-color: var(--bg-color);\n            color: var(--text-main);\n            font-family: 'Inter', sans-serif;\n            line-height: 1.6;\n            -webkit-font-smoothing: antialiased;\n            padding: 20px;\n            overflow-x: hidden;\n        }\n\n        h1, h2, h3, h4 {\n            font-family: 'Space Grotesk', sans-serif;\n            font-weight: 800;\n            color: var(--text-main);\n            margin-bottom: 15px;\n            letter-spacing: -0.5px;\n        }\n\n        \/* =========================================\n           NEUMORPHIC CONTAINERS\n           ========================================= *\/\n        .product-container { max-width: 1000px; margin: 0 auto; padding-bottom: 60px; }\n        .neu-card { background: var(--bg-color); border-radius: var(--radius-xl); box-shadow: var(--neu-out); padding: 40px; margin-bottom: 40px; }\n        .neu-card-sm { background: var(--bg-color); border-radius: var(--radius-lg); box-shadow: var(--neu-out); padding: 25px; display: flex; flex-direction: column; gap: 15px; }\n        .neu-sunken { background: var(--bg-color); border-radius: var(--radius-lg); box-shadow: var(--neu-in); padding: 25px; }\n        \n        .neu-icon { width: 60px; height: 60px; border-radius: 50%; background: var(--bg-color); box-shadow: var(--neu-out); display: flex; align-items: center; justify-content: center; color: var(--accent); font-size: 24px; margin-bottom: 10px; }\n        .svg-icon { width: 28px; height: 28px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }\n\n        \/* =========================================\n           HEADER \u0026 HERO\n           ========================================= *\/\n        .header-section { text-align: center; margin-bottom: 50px; padding-top: 20px; }\n        .badge { display: inline-block; background: var(--bg-color); box-shadow: var(--neu-in); padding: 8px 20px; border-radius: var(--radius-pill); font-size: 13px; font-weight: 600; color: var(--accent); text-transform: uppercase; letter-spacing: 2px; margin-bottom: 20px; }\n        .main-title { font-size: clamp(36px, 6vw, 64px); background: linear-gradient(135deg, #2d3748 0%, #718096 100%); -webkit-background-clip: text; -webkit-text-fill-color: transparent; margin-bottom: 10px; }\n        \n        .hero-image-wrapper { margin: 30px auto; max-width: 350px; border-radius: var(--radius-xl); padding: 15px; background: var(--bg-color); box-shadow: var(--neu-out); }\n        .hero-image-wrapper img { width: 100%; height: auto; border-radius: var(--radius-lg); display: block; }\n\n        \/* =========================================\n           INTERACTIVE 3D VIEWER\n           ========================================= *\/\n        .viewer-3d-container { \n            width: 100%; \n            height: 400px; \n            border-radius: var(--radius-xl); \n            box-shadow: var(--neu-in); \n            overflow: hidden; \n            position: relative; \n            cursor: grab; \n            display: flex; \n            flex-direction: column; \n            margin-bottom: 50px;\n        }\n        .viewer-3d-container:active { cursor: grabbing; }\n        .viewer-instructions { \n            position: absolute; \n            bottom: 20px; \n            left: 0; \n            right: 0; \n            text-align: center; \n            color: var(--text-muted); \n            font-size: 13px; \n            font-weight: 500; \n            pointer-events: none; \n            z-index: 10; \n        }\n        #three-canvas-container { flex: 1; width: 100%; height: 100%; outline: none; }\n\n        \/* =========================================\n           VIDEOS \u0026 MEDIA GRIDS\n           ========================================= *\/\n        .video-container { border-radius: var(--radius-lg); overflow: hidden; box-shadow: var(--neu-out); position: relative; background: var(--bg-color); padding: 10px; margin-bottom: 20px; }\n        .video-container video { width: 100%; aspect-ratio: 16\/9; object-fit: cover; border-radius: 20px; display: block; }\n        .video-square video { aspect-ratio: 1\/1; }\n        .video-label { text-align: center; font-size: 13px; font-weight: 600; color: var(--text-muted); margin-top: 15px; margin-bottom: 10px; text-transform: uppercase; letter-spacing: 1px; }\n\n        .demo-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 30px; margin-bottom: 30px; }\n\n        \/* =========================================\n           FEATURES GRIDS\n           ========================================= *\/\n        .section-title { text-align: center; font-size: 28px; margin-bottom: 40px; margin-top: 60px; }\n        .features-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 30px; margin-bottom: 50px; }\n        .feature-title { font-size: 18px; margin-bottom: 5px; }\n        .feature-desc { color: var(--text-muted); font-size: 15px; }\n\n        \/* List Styling *\/\n        .neu-list { list-style: none; padding: 0; }\n        .neu-list li { display: flex; align-items: center; gap: 15px; padding: 12px 0; border-bottom: 1px solid rgba(163, 177, 198, 0.3); color: var(--text-muted); font-size: 15px; }\n        .neu-list li:last-child { border-bottom: none; }\n        .neu-list li strong { color: var(--text-main); }\n        .neu-list .check { color: var(--success); font-weight: bold; font-size: 18px; }\n\n        \/* AI Section Special *\/\n        .ai-box { text-align: center; }\n        .ai-prompt { display: inline-block; background: var(--bg-color); box-shadow: var(--neu-in); padding: 15px 30px; border-radius: var(--radius-pill); font-family: monospace; color: var(--text-muted); margin: 20px 0; }\n\n        \/* Disclaimer *\/\n        .disclaimer { margin-top: 60px; text-align: center; }\n        .disclaimer p { font-size: 12px; color: var(--text-muted); margin-top: 10px; }\n\n        \/* Animations *\/\n    @keyframes fadeUp { from { opacity: 0; transform: translateY(30px); } to { opacity: 1; transform: translateY(0); } }\n    .reveal { animation: fadeUp 0.8s cubic-bezier(0.16, 1, 0.3, 1) forwards; }\n\u003c\/style\u003e\n\n\n\n\u003cdiv class=\"product-container reveal\"\u003e\n\n    \u003c!-- Header Section --\u003e\n    \u003cheader class=\"header-section\"\u003e\n        \u003ch1 class=\"main-title\"\u003eSGP CARD MINI\u003c\/h1\u003e\n        \n        \u003c!-- Call to Action \/ Urgency Badge --\u003e\n        \u003cdiv style=\"margin-bottom: 20px;\"\u003e\n            \u003cspan style=\"display: inline-block; background: var(--bg-color); box-shadow: var(--neu-out-sm); color: var(--danger); padding: 8px 20px; border-radius: var(--radius-pill); font-size: 14px; font-weight: 700; letter-spacing: 0.5px;\"\u003e\n                🔥 SECURE YOURS NOW, LIMITED UNITS AVAILABLE\n            \u003c\/span\u003e\n        \u003c\/div\u003e\n\n        \u003cp class=\"subtitle\" style=\"font-size: 18px; color: var(--text-muted); font-weight: 500; max-width: 600px; margin: 0 auto; margin-bottom: 40px;\"\u003eFull-spectrum engineering in a pocket format. Discover the ultimate portable diagnostic and research tool.\u003c\/p\u003e\n\n        \u003c!-- Trailer Section --\u003e\n        \u003cdiv class=\"neu-card\" style=\"padding: 10px; max-width: 800px; margin: 0 auto 30px auto;\"\u003e\n            \u003cdiv class=\"video-container\" style=\"margin-bottom: 0; box-shadow: none;\"\u003e\n                \u003cvideo poster=\"https:\/\/cdn.shopify.com\/s\/files\/1\/1057\/9807\/4700\/files\/rn-image_picker_lib_temp_d122d386-d879-44d4-ba3e-0d906128942d.png?v=1778713734\" controls autoplay aria-label=\"SGP Card Mini Trailer\" style=\"border-radius: var(--radius-lg);\"\u003e\n                    \u003csource src=\"https:\/\/cdn.shopify.com\/videos\/c\/o\/v\/6792e53f67ec4b1592e61448da0beb18.mp4\" type=\"video\/mp4\"\u003e\n                    Your browser does not support HTML5 video.\n                \u003c\/source\u003e\u003c\/video\u003e\n            \u003c\/div\u003e\n        \u003c\/div\u003e\n        \n        \u003cdiv class=\"hero-image-wrapper\"\u003e\n            \u003cimg src=\"https:\/\/sgpcard.com\/wp-content\/uploads\/2025\/12\/47711.jpg\" alt=\"SGP Card Mini\" loading=\"lazy\"\u003e\n        \u003c\/div\u003e\n    \u003c\/header\u003e\n\n    \u003c!-- Interactive 3D Model --\u003e\n    \u003ch2 class=\"section-title\"\u003e🔍 Interactive 3D Preview\u003c\/h2\u003e\n    \u003cdiv class=\"viewer-3d-container\"\u003e\n        \u003cdiv id=\"three-canvas-container\"\u003e\u003c\/div\u003e\n        \u003cdiv class=\"viewer-instructions\"\u003eClick \u0026amp; drag to explore • Triple-click to reveal internals\u003c\/div\u003e\n    \u003c\/div\u003e\n\n    \u003c!-- Overview Video --\u003e\n    \u003ch2 class=\"section-title\"\u003e🎬 Overview \u0026amp; Presentation\u003c\/h2\u003e\n    \u003cdiv class=\"neu-card\" style=\"padding: 20px;\"\u003e\n        \u003cdiv class=\"video-container\" style=\"margin-bottom: 0;\"\u003e\n            \u003cvideo preload=\"metadata\" controls aria-label=\"SGP Card Mini Technical Overview\"\u003e\n                \u003csource src=\"https:\/\/sgpcard.com\/wp-content\/uploads\/2026\/03\/SGPCARDMINI__Multi-Tool.mp4\" type=\"video\/mp4\"\u003e\n                Your browser does not support HTML5 video.\n            \u003c\/source\u003e\u003c\/video\u003e\n        \u003c\/div\u003e\n    \u003c\/div\u003e\n\n    \u003c!-- Hardware \u0026 Sensors --\u003e\n    \u003ch2 class=\"section-title\"\u003e🔧 Hardware \u0026amp; Senses\u003c\/h2\u003e\n    \n    \u003cdiv class=\"features-grid\"\u003e\n        \u003cdiv class=\"neu-card-sm\"\u003e\n            \u003cdiv class=\"neu-icon\"\u003e\u003csvg class=\"svg-icon\" viewbox=\"0 0 24 24\"\u003e\u003cpath d=\"M5 12.55a11 11 0 0 1 14.08 0\"\u003e\u003c\/path\u003e\u003cpath d=\"M1.42 9a16 16 0 0 1 21.16 0\"\u003e\u003c\/path\u003e\u003ccircle cx=\"12\" cy=\"20\" r=\"1\"\u003e\u003c\/circle\u003e\u003c\/svg\u003e\u003c\/div\u003e\n            \u003ch3 class=\"feature-title\"\u003eMulti-Protocol Core\u003c\/h3\u003e\n            \u003cul class=\"neu-list\" style=\"margin-top: 10px;\"\u003e\n                \u003cli style=\"padding: 6px 0; border: none; font-size: 14px;\"\u003e\n\u003cspan style=\"font-size: 18px;\"\u003e📶\u003c\/span\u003e Wi-Fi Capability\u003c\/li\u003e\n                \u003cli style=\"padding: 6px 0; border: none; font-size: 14px;\"\u003e\n\u003cspan style=\"font-size: 18px;\"\u003e🛜\u003c\/span\u003e Bluetooth Integrated\u003c\/li\u003e\n                \u003cli style=\"padding: 6px 0; border: none; font-size: 14px;\"\u003e\n\u003cspan style=\"font-size: 18px;\"\u003e📡\u003c\/span\u003e LoRa \u0026amp; RF (Sub-GHz)\u003c\/li\u003e\n                \u003cli style=\"padding: 6px 0; border: none; font-size: 14px;\"\u003e\n\u003cspan style=\"font-size: 18px;\"\u003e🗼\u003c\/span\u003e High-Gain Antenna\u003c\/li\u003e\n            \u003c\/ul\u003e\n        \u003c\/div\u003e\n\n        \u003cdiv class=\"neu-card-sm\"\u003e\n            \u003cdiv class=\"neu-icon\"\u003e\u003csvg class=\"svg-icon\" viewbox=\"0 0 24 24\"\u003e\u003crect x=\"4\" y=\"4\" width=\"16\" height=\"16\" rx=\"2\" ry=\"2\"\u003e\u003c\/rect\u003e\u003crect x=\"9\" y=\"9\" width=\"6\" height=\"6\"\u003e\u003c\/rect\u003e\u003cline x1=\"9\" y1=\"1\" x2=\"9\" y2=\"4\"\u003e\u003c\/line\u003e\u003cline x1=\"15\" y1=\"1\" x2=\"15\" y2=\"4\"\u003e\u003c\/line\u003e\u003cline x1=\"9\" y1=\"20\" x2=\"9\" y2=\"23\"\u003e\u003c\/line\u003e\u003cline x1=\"15\" y1=\"20\" x2=\"15\" y2=\"23\"\u003e\u003c\/line\u003e\u003c\/svg\u003e\u003c\/div\u003e\n            \u003ch3 class=\"feature-title\"\u003ePhysical I\/O\u003c\/h3\u003e\n            \u003cul class=\"neu-list\" style=\"margin-top: 10px;\"\u003e\n                \u003cli style=\"padding: 6px 0; border: none; font-size: 14px;\"\u003e\n\u003cspan style=\"font-size: 18px;\"\u003e🔌\u003c\/span\u003e USB-C Expansion\u003c\/li\u003e\n                \u003cli style=\"padding: 6px 0; border: none; font-size: 14px;\"\u003e\n\u003cspan style=\"font-size: 18px;\"\u003e🔗\u003c\/span\u003e USB OTG Support\u003c\/li\u003e\n                \u003cli style=\"padding: 6px 0; border: none; font-size: 14px;\"\u003e\n\u003cspan style=\"font-size: 18px;\"\u003e💾\u003c\/span\u003e Integrated SD Slot\u003c\/li\u003e\n            \u003c\/ul\u003e\n        \u003c\/div\u003e\n\n        \u003cdiv class=\"neu-card-sm\"\u003e\n            \u003cdiv class=\"neu-icon\"\u003e\u003csvg class=\"svg-icon\" viewbox=\"0 0 24 24\"\u003e\u003cpath d=\"M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z\"\u003e\u003c\/path\u003e\u003cline x1=\"22\" y1=\"6\" x2=\"2\" y2=\"6\"\u003e\u003c\/line\u003e\u003cpath d=\"M12 14a2 2 0 1 0 0-4 2 2 0 0 0 0 4z\"\u003e\u003c\/path\u003e\u003c\/svg\u003e\u003c\/div\u003e\n            \u003ch3 class=\"feature-title\"\u003eRadio \u0026amp; Access\u003c\/h3\u003e\n            \u003cul class=\"neu-list\" style=\"margin-top: 10px;\"\u003e\n                \u003cli style=\"padding: 6px 0; border: none; font-size: 14px;\"\u003e\n\u003cspan style=\"font-size: 18px;\"\u003e📱\u003c\/span\u003e Built-in NFC\u003c\/li\u003e\n                \u003cli style=\"padding: 6px 0; border: none; font-size: 14px;\"\u003e\n\u003cspan style=\"font-size: 18px;\"\u003e🏷️\u003c\/span\u003e RFID Testing\u003c\/li\u003e\n                \u003cli style=\"padding: 6px 0; border: none; font-size: 14px;\"\u003e\n\u003cspan style=\"font-size: 18px;\"\u003e🕹️\u003c\/span\u003e Universal IR\u003c\/li\u003e\n                \u003cli style=\"padding: 6px 0; border: none; font-size: 14px;\"\u003e\n\u003cspan style=\"font-size: 18px;\"\u003e🚪\u003c\/span\u003e Access Control Eval\u003c\/li\u003e\n            \u003c\/ul\u003e\n        \u003c\/div\u003e\n\n        \u003cdiv class=\"neu-card-sm\"\u003e\n            \u003cdiv class=\"neu-icon\"\u003e\u003csvg class=\"svg-icon\" viewbox=\"0 0 24 24\"\u003e\u003cpath d=\"M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z\"\u003e\u003c\/path\u003e\u003cpath d=\"M19 10v2a7 7 0 0 1-14 0v-2\"\u003e\u003c\/path\u003e\u003cline x1=\"12\" y1=\"19\" x2=\"12\" y2=\"23\"\u003e\u003c\/line\u003e\u003cline x1=\"8\" y1=\"23\" x2=\"16\" y2=\"23\"\u003e\u003c\/line\u003e\u003c\/svg\u003e\u003c\/div\u003e\n            \u003ch3 class=\"feature-title\"\u003eEnvironmental\u003c\/h3\u003e\n            \u003cul class=\"neu-list\" style=\"margin-top: 10px;\"\u003e\n                \u003cli style=\"padding: 6px 0; border: none; font-size: 14px;\"\u003e\n\u003cspan style=\"font-size: 18px;\"\u003e🎙️\u003c\/span\u003e Onboard Microphone\u003c\/li\u003e\n                \u003cli style=\"padding: 6px 0; border: none; font-size: 14px;\"\u003e\n\u003cspan style=\"font-size: 18px;\"\u003e👁️\u003c\/span\u003e Wi-Fi CSI Tech\u003c\/li\u003e\n                \u003cli style=\"padding: 6px 0; border: none; font-size: 14px;\"\u003e\n\u003cspan style=\"font-size: 18px;\"\u003e🌍\u003c\/span\u003e Advanced Sensing\u003c\/li\u003e\n            \u003c\/ul\u003e\n        \u003c\/div\u003e\n        \n        \u003cdiv class=\"neu-card-sm\"\u003e\n            \u003cdiv class=\"neu-icon\"\u003e\u003csvg class=\"svg-icon\" viewbox=\"0 0 24 24\"\u003e\u003cpath d=\"M22 11.08V12a10 10 0 1 1-5.93-9.14\"\u003e\u003c\/path\u003e\u003cpolyline points=\"22 4 12 14.01 9 11.01\"\u003e\u003c\/polyline\u003e\u003c\/svg\u003e\u003c\/div\u003e\n            \u003ch3 class=\"feature-title\"\u003eDirect Feedback\u003c\/h3\u003e\n            \u003cul class=\"neu-list\" style=\"margin-top: 10px;\"\u003e\n                \u003cli style=\"padding: 6px 0; border: none; font-size: 14px;\"\u003e\n\u003cspan style=\"font-size: 18px;\"\u003e💡\u003c\/span\u003e Status LED\u003c\/li\u003e\n                \u003cli style=\"padding: 6px 0; border: none; font-size: 14px;\"\u003e\n\u003cspan style=\"font-size: 18px;\"\u003e🔊\u003c\/span\u003e Integrated Buzzer\u003c\/li\u003e\n                \u003cli style=\"padding: 6px 0; border: none; font-size: 14px;\"\u003e\n\u003cspan style=\"font-size: 18px;\"\u003e⚡\u003c\/span\u003e Immediate Status\u003c\/li\u003e\n            \u003c\/ul\u003e\n        \u003c\/div\u003e\n\n        \u003cdiv class=\"neu-card-sm\"\u003e\n            \u003cdiv class=\"neu-icon\"\u003e\u003csvg class=\"svg-icon\" viewbox=\"0 0 24 24\"\u003e\u003ccircle cx=\"12\" cy=\"12\" r=\"10\"\u003e\u003c\/circle\u003e\u003ccircle cx=\"12\" cy=\"12\" r=\"6\"\u003e\u003c\/circle\u003e\u003ccircle cx=\"12\" cy=\"12\" r=\"2\"\u003e\u003c\/circle\u003e\u003c\/svg\u003e\u003c\/div\u003e\n            \u003ch3 class=\"feature-title\"\u003eRadar \u0026amp; Logic\u003c\/h3\u003e\n            \u003cul class=\"neu-list\" style=\"margin-top: 10px;\"\u003e\n                \u003cli style=\"padding: 6px 0; border: none; font-size: 14px;\"\u003e\n\u003cspan style=\"font-size: 18px;\"\u003e📡\u003c\/span\u003e Radar Functions\u003c\/li\u003e\n                \u003cli style=\"padding: 6px 0; border: none; font-size: 14px;\"\u003e\n\u003cspan style=\"font-size: 18px;\"\u003e👤\u003c\/span\u003e Presence Sensing\u003c\/li\u003e\n                \u003cli style=\"padding: 6px 0; border: none; font-size: 14px;\"\u003e\n\u003cspan style=\"font-size: 18px;\"\u003e💻\u003c\/span\u003e Custom Codes\u003c\/li\u003e\n                \u003cli style=\"padding: 6px 0; border: none; font-size: 14px;\"\u003e\n\u003cspan style=\"font-size: 18px;\"\u003e🧩\u003c\/span\u003e Easy to Program\u003c\/li\u003e\n            \u003c\/ul\u003e\n        \u003c\/div\u003e\n    \u003c\/div\u003e\n\n    \u003c!-- What can you do with it? --\u003e\n    \u003ch2 class=\"section-title\"\u003e⚡ What can you do with it?\u003c\/h2\u003e\n    \n    \u003cdiv class=\"features-grid\"\u003e\n        \u003cdiv class=\"neu-card-sm\"\u003e\n            \u003ch3 class=\"feature-title\" style=\"color: var(--accent);\"\u003e01. Wi-Fi Diagnostics\u003c\/h3\u003e\n            \u003cp class=\"feature-desc\"\u003ePerform advanced network scanning, rigorous connectivity testing, and access point simulation.\u003c\/p\u003e\n        \u003c\/div\u003e\n        \u003cdiv class=\"neu-card-sm\"\u003e\n            \u003ch3 class=\"feature-title\" style=\"color: var(--accent);\"\u003e02. RF Analysis\u003c\/h3\u003e\n            \u003cp class=\"feature-desc\"\u003eConduct precise signal testing and perform deep remote control synchronization studies.\u003c\/p\u003e\n        \u003c\/div\u003e\n        \u003cdiv class=\"neu-card-sm\"\u003e\n            \u003ch3 class=\"feature-title\" style=\"color: var(--accent);\"\u003e03. Off-Grid Comms\u003c\/h3\u003e\n            \u003cp class=\"feature-desc\"\u003eTest and deploy secure, decentralized local networks with an impressive +15km range.\u003c\/p\u003e\n        \u003c\/div\u003e\n        \u003cdiv class=\"neu-card-sm\"\u003e\n            \u003ch3 class=\"feature-title\" style=\"color: var(--accent);\"\u003e04. BT\/USB Testing\u003c\/h3\u003e\n            \u003cp class=\"feature-desc\"\u003eExecute Bluetooth peripheral emulation and perform comprehensive protocol analysis.\u003c\/p\u003e\n        \u003c\/div\u003e\n        \u003cdiv class=\"neu-card-sm\"\u003e\n            \u003ch3 class=\"feature-title\" style=\"color: var(--accent);\"\u003e05. Open Source\u003c\/h3\u003e\n            \u003cp class=\"feature-desc\"\u003eWith the vast amount of built-in functions, you have the absolute freedom to build and execute whatever project comes to your mind.\u003c\/p\u003e\n        \u003c\/div\u003e\n        \u003cdiv class=\"neu-card-sm\"\u003e\n            \u003ch3 class=\"feature-title\" style=\"color: var(--accent);\"\u003e06. Learning \u0026amp; Coding\u003c\/h3\u003e\n            \u003cp class=\"feature-desc\"\u003eMaster new technologies and programming skills, all packed into a powerful device that fits right in your pocket.\u003c\/p\u003e\n        \u003c\/div\u003e\n    \u003c\/div\u003e\n\n    \u003c!-- In Action \/ Demos --\u003e\n    \u003ch2 class=\"section-title\"\u003e🎥 In Action \/ Demos\u003c\/h2\u003e\n\n    \u003c!-- Square Videos Grid --\u003e\n    \u003cdiv class=\"demo-grid\"\u003e\n        \u003cdiv\u003e\n            \u003cdiv class=\"video-container video-square\"\u003e\n                \u003cvideo preload=\"metadata\" controls aria-label=\"Network Diagnostic Demo 1\"\u003e\n                    \u003csource src=\"https:\/\/sgpcard.com\/wp-content\/uploads\/2026\/02\/AQMMB7J2fq_uO1V8y_cVOjS4_IT6RC_b38aKaYE5xdDBZ8q7E7MCUZH04gr_Feo0.mp4\" type=\"video\/mp4\"\u003e\u003c\/video\u003e\n            \u003c\/div\u003e\n            \u003cdiv class=\"video-label\"\u003eNetwork Diagnostics\u003c\/div\u003e\n        \u003c\/div\u003e\n        \u003cdiv\u003e\n            \u003cdiv class=\"video-container video-square\"\u003e\n                \u003cvideo preload=\"metadata\" controls aria-label=\"Signal Analysis Demo 2\"\u003e\n                    \u003csource src=\"https:\/\/sgpcard.com\/wp-content\/uploads\/2026\/02\/AQMBWaAYxmFglUfESVN1u5YVdL0KImOkz_uWeSP5K2jF84HUcmaTciYdPGfjedv00.mp4\" type=\"video\/mp4\"\u003e\u003c\/video\u003e\n            \u003c\/div\u003e\n            \u003cdiv class=\"video-label\"\u003eSignal Analysis\u003c\/div\u003e\n        \u003c\/div\u003e\n        \u003cdiv\u003e\n            \u003cdiv class=\"video-container video-square\"\u003e\n                \u003cvideo preload=\"metadata\" controls aria-label=\"System Diagnostics Demo 4\"\u003e\n                    \u003csource src=\"https:\/\/sgpcard.com\/wp-content\/uploads\/2026\/02\/AQMKoswfA7w_A4zcAO9EoCyFSip0DmG2pYm8F1cEqRLRAdl5iflUiIrad0ze0Ll.mp4\" type=\"video\/mp4\"\u003e\u003c\/video\u003e\n            \u003c\/div\u003e\n            \u003cdiv class=\"video-label\"\u003eSystem Diagnostics\u003c\/div\u003e\n        \u003c\/div\u003e\n    \u003c\/div\u003e\n\n    \u003c!-- Wide Demo Video --\u003e\n    \u003cdiv class=\"neu-card\" style=\"padding: 20px;\"\u003e\n        \u003cdiv class=\"video-container\" style=\"margin-bottom: 0;\"\u003e\n            \u003cvideo preload=\"metadata\" controls aria-label=\"Wi-Fi Spatial Analysis Demo\"\u003e\n                \u003csource src=\"https:\/\/sgpcard.com\/wp-content\/uploads\/2026\/03\/Seeing_Through_Walls_w__WiFi.mp4\" type=\"video\/mp4\"\u003e\u003c\/video\u003e\n        \u003c\/div\u003e\n        \u003cdiv class=\"video-label\" style=\"margin-bottom: 0;\"\u003eWi-Fi Spatial Analysis\u003c\/div\u003e\n    \u003c\/div\u003e\n\n    \u003c!-- Setup \u0026 Package Grid --\u003e\n    \u003cdiv style=\"display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 40px; margin-bottom: 50px;\"\u003e\n        \n        \u003c!-- Easy to Use --\u003e\n        \u003cdiv class=\"neu-sunken\"\u003e\n            \u003ch3 style=\"display: flex; align-items: center; gap: 10px;\"\u003e\n\u003cspan style=\"font-size: 24px;\"\u003e📲\u003c\/span\u003e Easy to Use\u003c\/h3\u003e\n            \u003cp style=\"color: var(--text-muted); margin-bottom: 20px;\"\u003eTotal control from your Smartphone or PC.\u003c\/p\u003e\n            \u003cul class=\"neu-list\"\u003e\n                \u003cli\u003e\n\u003cspan class=\"check\"\u003e✓\u003c\/span\u003e \u003cspan\u003e\u003cstrong\u003eNo installation:\u003c\/strong\u003e Everything works directly from the browser.\u003c\/span\u003e\n\u003c\/li\u003e\n                \u003cli\u003e\n\u003cspan class=\"check\"\u003e✓\u003c\/span\u003e \u003cspan\u003e\u003cstrong\u003eVisual Interface:\u003c\/strong\u003e Professional dashboard control panel.\u003c\/span\u003e\n\u003c\/li\u003e\n                \u003cli\u003e\n\u003cspan class=\"check\"\u003e✓\u003c\/span\u003e \u003cspan\u003e\u003cstrong\u003eReady to use:\u003c\/strong\u003e Take it out of the box and start analyzing.\u003c\/span\u003e\n\u003c\/li\u003e\n            \u003c\/ul\u003e\n        \u003c\/div\u003e\n\n        \u003c!-- The Package Includes --\u003e\n        \u003cdiv class=\"neu-sunken\"\u003e\n            \u003ch3 style=\"display: flex; align-items: center; gap: 10px;\"\u003e\n\u003cspan style=\"font-size: 24px;\"\u003e📦\u003c\/span\u003e The Package Includes\u003c\/h3\u003e\n            \u003cul class=\"neu-list\"\u003e\n                \u003cli\u003e\n\u003cspan class=\"check\"\u003e✔\u003c\/span\u003e \u003cspan\u003e1× \u003cstrong\u003eSGP Card Mini\u003c\/strong\u003e (Development edition)\u003c\/span\u003e\n\u003c\/li\u003e\n                \u003cli\u003e\n\u003cspan class=\"check\"\u003e✔\u003c\/span\u003e \u003cspan\u003e1× \u003cstrong\u003eShielded Case\u003c\/strong\u003e (Transport protection)\u003c\/span\u003e\n\u003c\/li\u003e\n                \u003cli\u003e\n\u003cspan class=\"check\"\u003e✔\u003c\/span\u003e \u003cspan\u003e1× \u003cstrong\u003eUSB-C Cable\u003c\/strong\u003e (High speed)\u003c\/span\u003e\n\u003c\/li\u003e\n                \u003cli\u003e\n\u003cspan class=\"check\"\u003e🎁\u003c\/span\u003e \u003cspan\u003e\u003cstrong\u003eBonus Gifts:\u003c\/strong\u003e Exclusive surprises included in your package.\u003c\/span\u003e\n\u003c\/li\u003e\n                \u003cli\u003e\n\u003cspan class=\"check\"\u003e💻\u003c\/span\u003e \u003cspan\u003e\u003cstrong\u003eFull Software Suite:\u003c\/strong\u003e Access to diagnostic programs and tools.\u003c\/span\u003e\n\u003c\/li\u003e\n                \u003cli\u003e\n\u003cspan class=\"check\"\u003e🔓\u003c\/span\u003e \u003cspan\u003e\u003cstrong\u003eLifetime Access:\u003c\/strong\u003e To source code and continuous updates.\u003c\/span\u003e\n\u003c\/li\u003e\n            \u003c\/ul\u003e\n        \u003c\/div\u003e\n\n    \u003c\/div\u003e\n\n    \u003c!-- Legal Disclaimer --\u003e\n    \u003cdiv class=\"disclaimer neu-sunken\"\u003e\n        \u003ch4 style=\"color: var(--danger); font-size: 14px; margin-bottom: 5px; text-transform: uppercase;\"\u003e🔒 Responsibility Protocol\u003c\/h4\u003e\n        \u003cp\u003eProfessional tool designed strictly for education, IT research, and authorized network diagnostics. The user is solely responsible for compliance with all local laws and regulations regarding electronic transmissions.\u003c\/p\u003e\n    \u003c\/div\u003e\n\n\u003c\/div\u003e\n\n\u003c!-- Three.js Library --\u003e\n\u003cscript src=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/three.js\/r128\/three.min.js\"\u003e\u003c\/script\u003e\n\u003cscript\u003e\n    window.addEventListener('load', function() {\n        const container = document.getElementById('three-canvas-container');\n        if (!container) return;\n        \n        \/\/ Setup scene\n        const scene = new THREE.Scene();\n        const camera = new THREE.PerspectiveCamera(45, container.clientWidth \/ container.clientHeight, 0.1, 100);\n        camera.position.z = 4.5; \n\n        const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });\n        renderer.setSize(container.clientWidth, container.clientHeight);\n        renderer.setPixelRatio(window.devicePixelRatio);\n        container.appendChild(renderer.domElement);\n\n        const deviceGroup = new THREE.Group();\n        scene.add(deviceGroup);\n\n        \/\/ Lighting\n        const ambientLight = new THREE.AmbientLight(0xffffff, 0.6);\n        scene.add(ambientLight);\n        const dirLight = new THREE.DirectionalLight(0xffffff, 0.8);\n        dirLight.position.set(5, 5, 5);\n        scene.add(dirLight);\n        const fillLight = new THREE.DirectionalLight(0xffffff, 0.3);\n        fillLight.position.set(-5, 0, -5);\n        scene.add(fillLight);\n\n        \/\/ --- MODEL CONSTRUCTION ---\n        \n        \/\/ Dimensions based on photos (credit card proportions, but thicker)\n        const width = 1.3;\n        const height = 2.0;\n        const depth = 0.25;\n\n        \/\/ GRUPOS PARA LA VISTA EXPLOSIONADA (Transformer)\n        const frontPart = new THREE.Group();\n        const backPart = new THREE.Group();\n        const internalsPart = new THREE.Group();\n        \n        deviceGroup.add(frontPart);\n        deviceGroup.add(backPart);\n        deviceGroup.add(internalsPart);\n\n        \/\/ Material for main body (dark grey, slightly rough)\n        const bodyMat = new THREE.MeshStandardMaterial({ \n            color: 0x1a1a1a,\n            roughness: 0.8,\n            metalness: 0.1\n        });\n\n        \/\/ 1. Main Body (Divided in two halves)\n        const frontGeo = new THREE.BoxGeometry(width, height, depth\/2);\n        const frontCase = new THREE.Mesh(frontGeo, bodyMat);\n        frontCase.position.z = depth\/4; \/\/ Desplazado hacia adelante\n        frontPart.add(frontCase);\n\n        const backGeo = new THREE.BoxGeometry(width, height, depth\/2);\n        const backCase = new THREE.Mesh(backGeo, bodyMat);\n        backCase.position.z = -depth\/4; \/\/ Desplazado hacia atrás\n        backPart.add(backCase);\n\n        \/\/ 2. Solar Panel (Front Face)\n        const solarCanvas = document.createElement('canvas');\n        solarCanvas.width = 256;\n        solarCanvas.height = 512;\n        const sCtx = solarCanvas.getContext('2d');\n        \n        sCtx.fillStyle = '#2c3e50';\n        sCtx.fillRect(0, 0, 256, 512);\n        sCtx.strokeStyle = '#1a252f';\n        sCtx.lineWidth = 4;\n        for(let i=1; i\u003c12; i++) {\n            sCtx.beginPath();\n            sCtx.moveTo(0, i*(512\/12));\n            sCtx.lineTo(256, i*(512\/12));\n            sCtx.stroke();\n        }\n        sCtx.strokeStyle = '#bdc3c7';\n        sCtx.lineWidth = 2;\n        sCtx.beginPath();\n        sCtx.moveTo(128, 0);\n        sCtx.lineTo(128, 512);\n        sCtx.stroke();\n        sCtx.strokeStyle = '#000000';\n        sCtx.lineWidth = 8;\n        sCtx.strokeRect(0,0,256,512);\n\n        const solarTex = new THREE.CanvasTexture(solarCanvas);\n        const solarMat = new THREE.MeshStandardMaterial({ \n            map: solarTex, roughness: 0.2, metalness: 0.3\n        });\n        \n        const solarWidth = width - 0.1;\n        const solarHeight = height - 0.1;\n        const solarGeo = new THREE.PlaneGeometry(solarWidth, solarHeight);\n        const solarPanel = new THREE.Mesh(solarGeo, solarMat);\n        solarPanel.position.set(0, 0, (depth\/2) + 0.005);\n        frontPart.add(solarPanel); \/\/ Attach to FRONT\n\n        \/\/ 3. Back Face Details (LED hole and square button)\n        const ledGeo = new THREE.CircleGeometry(0.04, 32);\n        let isButtonPressed = false;\n        let blueOverrideTimer = null;\n\n        const ledMat = new THREE.MeshStandardMaterial({ \n            color: 0xffffff, emissive: 0xffffff, emissiveIntensity: 2\n        });\n        const ledHole = new THREE.Mesh(ledGeo, ledMat);\n        ledHole.position.set(0.3, 0.7, -(depth\/2) - 0.001);\n        ledHole.rotation.y = Math.PI;\n        backPart.add(ledHole); \/\/ Attach to BACK\n\n        \/\/ Square Button\n        const buttonWidth = 0.18;\n        const buttonHeight = 0.22;\n        const buttonDepth = 0.02;\n        const btnGeo = new THREE.BoxGeometry(buttonWidth, buttonHeight, buttonDepth);\n        const btnMat = new THREE.MeshStandardMaterial({ color: 0x111111, roughness: 0.9 });\n        const backButton = new THREE.Mesh(btnGeo, btnMat);\n        \n        const initialButtonZ = -(depth\/2) - (buttonDepth\/2) + 0.005;\n        backButton.position.set(0, 0.65, initialButtonZ);\n        backButton.userData = { originalZ: initialButtonZ };\n        backPart.add(backButton); \/\/ Attach to BACK\n\n        \/\/ Button Frame\n        const frameGeo = new THREE.RingGeometry(0.12, 0.14, 4);\n        const frameMat = new THREE.MeshBasicMaterial({ color: 0x000000 });\n        const buttonFrame = new THREE.Mesh(frameGeo, frameMat);\n        buttonFrame.position.set(0, 0.65, -(depth\/2) - 0.001);\n        buttonFrame.rotation.y = Math.PI;\n        buttonFrame.rotation.z = Math.PI \/ 4;\n        backPart.add(buttonFrame); \/\/ Attach to BACK\n\n        const holeMat = new THREE.MeshBasicMaterial({ color: 0x000000 });\n\n        \/\/ 4. Top Ports\n        const portsGroup = new THREE.Group();\n        portsGroup.position.set(0, height\/2 + 0.001, 0);\n        \n        const sdGeo = new THREE.BoxGeometry(0.3, 0.01, 0.05);\n        const sdSlot = new THREE.Mesh(sdGeo, holeMat);\n        sdSlot.position.set(-0.4, 0, 0);\n        portsGroup.add(sdSlot);\n\n        const roundPortGeo = new THREE.CylinderGeometry(0.03, 0.03, 0.02, 16);\n        const roundPort = new THREE.Mesh(roundPortGeo, holeMat);\n        roundPort.rotation.x = Math.PI \/ 2;\n        roundPort.position.set(0, 0, 0);\n        portsGroup.add(roundPort);\n\n        const usbcGeo = new THREE.BoxGeometry(0.25, 0.01, 0.08);\n        const usbcPort = new THREE.Mesh(usbcGeo, holeMat);\n        usbcPort.position.set(0.35, 0, 0);\n        portsGroup.add(usbcPort);\n\n        backPart.add(portsGroup); \/\/ Attach to BACK\n\n        \/\/ 5. Ranura MicroSD lateral\n        const sdY = -height\/2 + 0.4; \n        const sdZ = 0;\n        \n        const sideSdSlotGeo = new THREE.BoxGeometry(0.05, 0.22, 0.04);\n        const sideSdSlot = new THREE.Mesh(sideSdSlotGeo, holeMat);\n        sideSdSlot.position.set(-width\/2, sdY, sdZ);\n        backPart.add(sideSdSlot); \/\/ Attach to BACK\n\n        const sdCardGeo = new THREE.BoxGeometry(0.14, 0.18, 0.02);\n        const sdCardMat = new THREE.MeshStandardMaterial({ color: 0x111111, roughness: 0.5 });\n        const sdCard = new THREE.Mesh(sdCardGeo, sdCardMat);\n        \n        const sdStickerGeo = new THREE.PlaneGeometry(0.08, 0.12);\n        const sdStickerMat = new THREE.MeshBasicMaterial({ color: 0xcc0000 });\n        const sdSticker = new THREE.Mesh(sdStickerGeo, sdStickerMat);\n        sdSticker.position.set(0, 0, 0.011);\n        sdCard.add(sdSticker);\n\n        const sdInsertedX = -width\/2 + 0.05;\n        const sdEjectedX = -width\/2 - 0.08;\n        \n        let targetSdX = sdInsertedX;\n        let currentSdX = sdInsertedX;\n        sdCard.position.set(currentSdX, sdY, sdZ);\n        sdCard.userData = { isInserted: true };\n        backPart.add(sdCard); \/\/ Attach to BACK\n\n        \/\/ --- 6. INTERNALS (PCB, Batería, Antenas) ---\n        \n        \/\/ Placa Base (PCB Verde)\n        const pcbGeo = new THREE.BoxGeometry(width - 0.2, height - 0.2, 0.02);\n        const pcbMat = new THREE.MeshStandardMaterial({ \n            color: 0x225533, \/\/ Verde PCB\n            roughness: 0.7, \n            metalness: 0.2 \n        });\n        const pcb = new THREE.Mesh(pcbGeo, pcbMat);\n        \n        \/\/ Texto \"SGPCard Mini\" simulado en la PCB (Borde derecho)\n        const textCanvas = document.createElement('canvas');\n        textCanvas.width = 64; textCanvas.height = 256;\n        const ctxText = textCanvas.getContext('2d');\n        ctxText.fillStyle = '#225533'; ctxText.fillRect(0,0,64,256);\n        ctxText.fillStyle = '#ffffff'; ctxText.font = 'bold 30px Arial';\n        ctxText.translate(32, 128); ctxText.rotate(Math.PI \/ 2);\n        ctxText.fillText('SGPCard Mini', -90, 10);\n        const textTex = new THREE.CanvasTexture(textCanvas);\n        const textMat = new THREE.MeshBasicMaterial({ map: textTex, transparent: true });\n        const textMesh = new THREE.Mesh(new THREE.PlaneGeometry(0.2, 0.8), textMat);\n        textMesh.position.set(0.4, -0.4, 0.011);\n        pcb.add(textMesh);\n\n        \/\/ Componentes en la PCB\n        const metalMat = new THREE.MeshStandardMaterial({ color: 0xcccccc, roughness: 0.3, metalness: 0.8 }); \/\/ Plateado para escudos\n        const darkChipMat = new THREE.MeshStandardMaterial({ color: 0x111111, roughness: 0.6 }); \/\/ Negro mate para chips\n\n        \/\/ 1. ESP32 Module (Arriba Izquierda)\n        const espGroup = new THREE.Group();\n        espGroup.position.set(-0.25, 0.6, 0.02);\n        \n        const espShield = new THREE.Mesh(new THREE.BoxGeometry(0.35, 0.45, 0.04), metalMat);\n        espGroup.add(espShield);\n        \n        const espAntenna = new THREE.Mesh(new THREE.BoxGeometry(0.15, 0.45, 0.04), darkChipMat);\n        espAntenna.position.set(-0.25, 0, 0); \/\/ Antena PCB negra a la izquierda\n        espGroup.add(espAntenna);\n        pcb.add(espGroup);\n\n        \/\/ 2. LoRa Module (Ra-02) (Arriba Derecha)\n        const loraShield = new THREE.Mesh(new THREE.BoxGeometry(0.45, 0.4, 0.05), metalMat);\n        loraShield.position.set(0.25, 0.55, 0.025);\n        pcb.add(loraShield);\n\n        \/\/ 3. Buzzer (Debajo del ESP32)\n        const buzzer = new THREE.Mesh(new THREE.BoxGeometry(0.25, 0.25, 0.1), darkChipMat);\n        buzzer.position.set(-0.25, 0.2, 0.05);\n        pcb.add(buzzer);\n\n        \/\/ 4. Lector MicroSD (Abajo Izquierda)\n        const sdReaderMat = new THREE.MeshStandardMaterial({ color: 0xaaaaaa, roughness: 0.5, metalness: 0.6 });\n        const sdReader = new THREE.Mesh(new THREE.BoxGeometry(0.35, 0.4, 0.06), sdReaderMat);\n        sdReader.position.set(-0.25, -0.5, 0.03);\n        pcb.add(sdReader);\n\n        \/\/ 5. Pequeños componentes SMD y botones (Centro y Arriba)\n        const smdMat = new THREE.MeshStandardMaterial({ color: 0x888888, roughness: 0.4 });\n        const internalBtnGeo = new THREE.BoxGeometry(0.06, 0.06, 0.03);\n        \n        const btn1 = new THREE.Mesh(internalBtnGeo, metalMat); \/\/ Boot\/Reset\n        btn1.position.set(0, 0.6, 0.015);\n        pcb.add(btn1);\n        \n        const btn2 = new THREE.Mesh(internalBtnGeo, metalMat);\n        btn2.position.set(0, 0.45, 0.015);\n        pcb.add(btn2);\n\n        \/\/ Chip pequeño abajo en el centro\n        const centerChip = new THREE.Mesh(new THREE.BoxGeometry(0.15, 0.15, 0.02), darkChipMat);\n        centerChip.position.set(0.1, -0.5, 0.01);\n        pcb.add(centerChip);\n\n        internalsPart.add(pcb);\n\n        \/\/ Batería Lipo (Cubriendo la parte inferior)\n        const batteryGroup = new THREE.Group();\n        batteryGroup.position.set(0, -0.2, 0.08); \/\/ Elevada sobre la PCB\n        \n        \/\/ Cuerpo plateado\n        const batteryGeo = new THREE.BoxGeometry(0.9, 0.8, 0.08);\n        const batteryMat = new THREE.MeshStandardMaterial({ color: 0xdddddd, roughness: 0.4, metalness: 0.3 });\n        const batteryBody = new THREE.Mesh(batteryGeo, batteryMat);\n        batteryGroup.add(batteryBody);\n        \n        \/\/ Cinta Kapton Amarilla en el borde derecho\n        const kaptonGeo = new THREE.BoxGeometry(0.15, 0.81, 0.082);\n        const kaptonMat = new THREE.MeshStandardMaterial({ color: 0xcca800, roughness: 0.6, transparent: true, opacity: 0.9 });\n        const kaptonTape = new THREE.Mesh(kaptonGeo, kaptonMat);\n        kaptonTape.position.set(0.38, 0, 0);\n        batteryGroup.add(kaptonTape);\n\n        \/\/ Cables de la batería (Rojo y Negro simulados)\n        const wireMatRed = new THREE.LineBasicMaterial({ color: 0xff0000, linewidth: 2 });\n        const wireMatBlack = new THREE.LineBasicMaterial({ color: 0x000000, linewidth: 2 });\n        \n        const pointsRed = [];\n        pointsRed.push(new THREE.Vector3(0.4, -0.4, 0));\n        pointsRed.push(new THREE.Vector3(0.4, -0.6, 0.05));\n        pointsRed.push(new THREE.Vector3(0, -0.8, 0.1));\n        const geoRed = new THREE.BufferGeometry().setFromPoints(pointsRed);\n        const lineRed = new THREE.Line(geoRed, wireMatRed);\n        batteryGroup.add(lineRed);\n\n        const pointsBlack = [];\n        pointsBlack.push(new THREE.Vector3(0.3, -0.4, 0));\n        pointsBlack.push(new THREE.Vector3(0.2, -0.6, -0.02));\n        pointsBlack.push(new THREE.Vector3(-0.2, -0.7, -0.05));\n        const geoBlack = new THREE.BufferGeometry().setFromPoints(pointsBlack);\n        const lineBlack = new THREE.Line(geoBlack, wireMatBlack);\n        batteryGroup.add(lineBlack);\n\n        internalsPart.add(batteryGroup);\n\n        \/\/ Antena de cable (Negra, saliendo a la izquierda)\n        const antennaCurve = new THREE.QuadraticBezierCurve3(\n            new THREE.Vector3(0.2, 0.5, 0.03), \/\/ Empieza en el módulo LoRa\n            new THREE.Vector3(-0.5, 0.5, 0.1), \/\/ Punto de control\n            new THREE.Vector3(-0.8, -0.2, 0.2)  \/\/ Extremo\n        );\n        const antennaTubeGeo = new THREE.TubeGeometry(antennaCurve, 20, 0.015, 8, false);\n        const antennaTubeMat = new THREE.MeshStandardMaterial({ color: 0x111111, roughness: 0.8 });\n        const wireAntenna = new THREE.Mesh(antennaTubeGeo, antennaTubeMat);\n        internalsPart.add(wireAntenna);\n\n        \/\/ Initial rotation to show it's 3D\n        deviceGroup.rotation.y = Math.PI \/ 4;\n        deviceGroup.rotation.x = 0.1;\n\n        \/\/ --- INTERACTION LOGIC ---\n        let isDragging = false;\n        let previousMousePosition = { x: 0, y: 0 };\n        let time = 0;\n        let isExploded = false;\n        let clickCount = 0;\n        let clickTimer = null;\n\n        const getCoords = (e) =\u003e {\n            const rect = container.getBoundingClientRect();\n            let clientX, clientY;\n            if (e.touches \u0026\u0026 e.touches.length \u003e 0) {\n                clientX = e.touches[0].clientX;\n                clientY = e.touches[0].clientY;\n            } else {\n                clientX = e.clientX;\n                clientY = e.clientY;\n            }\n            return { x: clientX - rect.left, y: clientY - rect.top };\n        };\n\n        const startInteraction = (e) =\u003e {\n            isDragging = true;\n            previousMousePosition = getCoords(e);\n        };\n        \n        const doInteraction = (e) =\u003e {\n            if (isDragging) {\n                const coords = getCoords(e);\n                const deltaMove = { \n                    x: coords.x - previousMousePosition.x, \n                    y: coords.y - previousMousePosition.y \n                };\n                deviceGroup.rotation.y += deltaMove.x * 0.01;\n                deviceGroup.rotation.x += deltaMove.y * 0.01;\n                previousMousePosition = coords;\n            }\n        };\n        \n        const endInteraction = () =\u003e { isDragging = false; };\n\n        \/\/ Mouse events\n        container.addEventListener('mousedown', startInteraction);\n        document.addEventListener('mousemove', doInteraction);\n        document.addEventListener('mouseup', endInteraction);\n        \n        \/\/ Touch events\n        container.addEventListener('touchstart', startInteraction, {passive: true});\n        document.addEventListener('touchmove', doInteraction, {passive: true});\n        document.addEventListener('touchend', endInteraction);\n\n        \/\/ RAYCASTER FOR CLICKS\n        const raycaster = new THREE.Raycaster();\n        const mouse = new THREE.Vector2();\n\n        container.addEventListener('click', (e) =\u003e {\n            if (isDragging) return;\n\n            \/\/ Lógica de Triple Clic (Transformer)\n            clickCount++;\n            if (clickCount === 1) {\n                clickTimer = setTimeout(() =\u003e {\n                    clickCount = 0;\n                }, 400); \/\/ 400ms para hacer los 3 clics\n            } else if (clickCount === 3) {\n                isExploded = !isExploded; \/\/ Alternar estado\n                clickCount = 0;\n                clearTimeout(clickTimer);\n                return; \/\/ Evita activar el botón o la SD en el tercer clic\n            }\n\n            const rect = container.getBoundingClientRect();\n            mouse.x = ((e.clientX - rect.left) \/ container.clientWidth) * 2 - 1;\n            mouse.y = -((e.clientY - rect.top) \/ container.clientHeight) * 2 + 1;\n\n            raycaster.setFromCamera(mouse, camera);\n\n            \/\/ Interacción con Botón Trasero\n            const intersectsBtn = raycaster.intersectObject(backButton);\n            if (intersectsBtn.length \u003e 0) {\n                backButton.position.z = backButton.userData.originalZ + 0.015;\n                isButtonPressed = true;\n                if (blueOverrideTimer) clearTimeout(blueOverrideTimer);\n\n                setTimeout(() =\u003e {\n                    backButton.position.z = backButton.userData.originalZ;\n                }, 150);\n                \n                blueOverrideTimer = setTimeout(() =\u003e {\n                    isButtonPressed = false;\n                }, 800);\n            }\n\n            \/\/ Interacción con Tarjeta SD\n            const intersectsSd = raycaster.intersectObject(sdCard);\n            const intersectsSlot = raycaster.intersectObject(sideSdSlot);\n            if (intersectsSd.length \u003e 0 || intersectsSlot.length \u003e 0) {\n                sdCard.userData.isInserted = !sdCard.userData.isInserted;\n                targetSdX = sdCard.userData.isInserted ? sdInsertedX : sdEjectedX;\n            }\n        });\n\n        window.addEventListener('resize', () =\u003e {\n            camera.aspect = container.clientWidth \/ container.clientHeight;\n            camera.updateProjectionMatrix();\n            renderer.setSize(container.clientWidth, container.clientHeight);\n        });\n\n        \/\/ --- ANIMATION LOOP ---\n        function animate() {\n            requestAnimationFrame(animate);\n            time += 0.02;\n\n            \/\/ Animación Tarjeta SD\n            currentSdX += (targetSdX - currentSdX) * 0.15;\n            sdCard.position.x = currentSdX;\n\n            \/\/ Animación \"Transformer\"\n            const targetFrontZ = isExploded ? 0.6 : 0;\n            const targetBackZ = isExploded ? -0.6 : 0;\n            \n            frontPart.position.z += (targetFrontZ - frontPart.position.z) * 0.1;\n            backPart.position.z += (targetBackZ - backPart.position.z) * 0.1;\n\n            \/\/ Ocultar cables rojo\/negro y la antena cuando está cerrado para que no atraviesen la carcasa\n            const isOpening = isExploded || Math.abs(frontPart.position.z) \u003e 0.05;\n            lineRed.visible = isOpening;\n            lineBlack.visible = isOpening;\n            wireAntenna.visible = isOpening;\n\n            \/\/ Lógica LED\n            if (isButtonPressed) {\n                \/\/ Si el botón está pulsado, forzar color azul intenso\n                ledMat.color.setHex(0x0044ff);\n                ledMat.emissive.setHex(0x0044ff);\n            } else {\n                \/\/ Si no, hacer un ciclo de colores HSL continuo basado en el tiempo\n                const hue = (time * 0.15) % 1; \n                ledMat.color.setHSL(hue, 1, 0.5);\n                ledMat.emissive.setHSL(hue, 1, 0.5);\n            }\n\n            if (!isDragging) {\n                deviceGroup.rotation.y += 0.005;\n                deviceGroup.position.y = Math.sin(time) * 0.05;\n            }\n\n            renderer.render(scene, camera);\n        }\n        \n        animate();\n    });\n\u003c\/script\u003e\n\n\n\u003c\/body\u003e","brand":"sgpstore","offers":[{"title":"Default Title","offer_id":57533474963788,"sku":null,"price":270.0,"currency_code":"EUR","in_stock":true}],"thumbnail_url":"\/\/cdn.shopify.com\/s\/files\/1\/1057\/9807\/4700\/files\/FullSizeRender_48c5d163-f95d-4ee5-a82f-4245298636f4.jpg?v=1782838344"},{"product_id":"sgp-phantom","title":"SGP phantom","description":"\u003cbody\u003e\n\n\n\n    \u003cmeta charset=\"UTF-8\"\u003e\n    \u003cmeta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"\u003e\n    \u003ctitle\u003eSGP PHANTOM - Advanced Hub\u003c\/title\u003e\n    \n    \u003c!-- Google Fonts: Space Grotesk (Headers) and Inter (Body) --\u003e\n    \u003clink rel=\"preconnect\" href=\"https:\/\/fonts.googleapis.com\"\u003e\n    \u003clink rel=\"preconnect\" href=\"https:\/\/fonts.gstatic.com\" crossorigin\u003e\n    \u003clink href=\"https:\/\/fonts.googleapis.com\/css2?family=Inter:wght@400;500;600\u0026amp;family=Space+Grotesk:wght@700;800\u0026amp;display=swap\" rel=\"stylesheet\"\u003e\n\n    \u003cstyle\u003e\n        :root {\n            \/* Neumorphic Color Palette *\/\n            --bg-color: #e0e5ec;\n            --text-main: #2d3748;\n            --text-muted: #718096;\n            --accent: #eab308; \/* Premium Amber\/Gold *\/\n            --success: #38a169;\n            --danger: #e53e3e;\n            \n            \/* Shadows (Extrusion\/Sunken Effects) *\/\n            --shadow-light: rgba(255, 255, 255, 0.8);\n            --shadow-dark: rgba(163, 177, 198, 0.6);\n            --neu-out: 9px 9px 16px var(--shadow-dark), -9px -9px 16px var(--shadow-light);\n            --neu-out-sm: 5px 5px 10px var(--shadow-dark), -5px -5px 10px var(--shadow-light);\n            --neu-in: inset 6px 6px 10px var(--shadow-dark), inset -6px -6px 10px var(--shadow-light);\n            \n            \/* Border Radii *\/\n            --radius-xl: 40px;\n            --radius-lg: 30px;\n            --radius-pill: 100px;\n            --transition: all 0.25s ease-in-out;\n        }\n\n        * { box-sizing: border-box; margin: 0; padding: 0; }\n\n        body {\n            background-color: var(--bg-color);\n            color: var(--text-main);\n            font-family: 'Inter', sans-serif;\n            line-height: 1.6;\n            -webkit-font-smoothing: antialiased;\n            padding: 20px;\n            overflow-x: hidden;\n        }\n\n        h1, h2, h3, h4 {\n            font-family: 'Space Grotesk', sans-serif;\n            font-weight: 800;\n            color: var(--text-main);\n            margin-bottom: 15px;\n            letter-spacing: -0.5px;\n        }\n\n        .product-container { max-width: 1000px; margin: 0 auto; padding-bottom: 60px; }\n        \n        .neu-card { background: var(--bg-color); border-radius: var(--radius-xl); box-shadow: var(--neu-out); padding: 40px; margin-bottom: 40px; }\n        .neu-card-sm { background: var(--bg-color); border-radius: var(--radius-lg); box-shadow: var(--neu-out); padding: 25px; display: flex; flex-direction: column; gap: 15px; }\n        .neu-sunken { background: var(--bg-color); border-radius: var(--radius-lg); box-shadow: var(--neu-in); padding: 20px; }\n\n        .neu-icon { width: 60px; height: 60px; border-radius: 50%; background: var(--bg-color); box-shadow: var(--neu-out); display: flex; align-items: center; justify-content: center; color: var(--accent); font-size: 24px; margin-bottom: 10px; }\n        .svg-icon { width: 28px; height: 28px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }\n\n        \/* Header *\/\n        .header-section { text-align: center; margin-bottom: 50px; padding-top: 20px; }\n        .badge { display: inline-block; background: var(--bg-color); box-shadow: var(--neu-in); padding: 8px 20px; border-radius: var(--radius-pill); font-size: 13px; font-weight: 600; color: var(--accent); text-transform: uppercase; letter-spacing: 2px; margin-bottom: 20px; }\n        .main-title { font-size: clamp(32px, 5vw, 56px); background: linear-gradient(135deg, #2d3748 0%, #718096 100%); -webkit-background-clip: text; -webkit-text-fill-color: transparent; margin-bottom: 10px; }\n        .subtitle { font-size: clamp(16px, 2vw, 20px); color: var(--text-muted); font-weight: 500; max-width: 700px; margin: 0 auto 30px auto; }\n\n        \/* Media Grid (Videos) *\/\n        .media-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 30px; margin-bottom: 50px; }\n        .video-container { border-radius: var(--radius-lg); overflow: hidden; box-shadow: var(--neu-out); position: relative; background: var(--bg-color); padding: 10px; }\n        .video-container video { width: 100%; aspect-ratio: 16\/9; object-fit: cover; border-radius: 20px; display: block; }\n        .video-label { text-align: center; font-size: 12px; font-weight: 600; color: var(--text-muted); margin-top: 15px; margin-bottom: 5px; text-transform: uppercase; letter-spacing: 1px; }\n\n        \/* Features Grid *\/\n        .features-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 30px; margin-bottom: 50px; }\n        .feature-title { font-size: 18px; margin-bottom: 5px; }\n        .feature-desc { color: var(--text-muted); font-size: 15px; }\n\n        \/* Gallery (Grid Mosaico) *\/\n        .gallery-wrapper { margin-top: 50px; margin-bottom: 50px; }\n        .gallery-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 20px; padding: 20px; }\n        .gallery-item { border-radius: var(--radius-lg); padding: 8px; box-shadow: var(--neu-out); background: var(--bg-color); transition: var(--transition); }\n        .gallery-item:hover { transform: translateY(-5px); box-shadow: 12px 12px 20px var(--shadow-dark), -12px -12px 20px var(--shadow-light); }\n        \n        \/* Contenedor CRT para el efecto de TV Antigua *\/\n        .crt-wrapper { position: relative; border-radius: 22px; overflow: hidden; }\n        .gallery-item img { width: 100%; aspect-ratio: 4\/3; object-fit: cover; display: block; filter: contrast(125%) saturate(70%) sepia(30%) hue-rotate(10deg); }\n        \n        \/* Scanlines y Viñeta *\/\n        .crt-wrapper::after {\n            content: \"\";\n            position: absolute;\n            top: 0; left: 0; right: 0; bottom: 0;\n            background: linear-gradient(rgba(0, 0, 0, 0) 50%, rgba(0, 0, 0, 0.15) 50%);\n            background-size: 100% 4px;\n            box-shadow: inset 0 0 30px rgba(0,0,0,0.6);\n            pointer-events: none;\n            z-index: 2;\n        }\n\n        \/* Interactive 3D Viewer *\/\n        .viewer-3d-container { width: 100%; height: 500px; border-radius: var(--radius-xl); box-shadow: var(--neu-in); overflow: hidden; position: relative; cursor: grab; display: flex; flex-direction: column; }\n        .viewer-3d-container:active { cursor: grabbing; }\n        .viewer-instructions { position: absolute; bottom: 20px; left: 0; right: 0; text-align: center; color: var(--text-muted); font-size: 13px; font-weight: 500; pointer-events: none; z-index: 10; }\n        \n        #three-canvas-container { flex: 1; width: 100%; height: 100%; outline: none; }\n\n        \/* Disclaimer *\/\n        .disclaimer { margin-top: 60px; text-align: center; }\n        .disclaimer p { font-size: 12px; color: var(--text-muted); margin-top: 10px; }\n\n        \/* Animación Fade *\/\n        @keyframes fadeUp { from { opacity: 0; transform: translateY(30px); } to { opacity: 1; transform: translateY(0); } }\n        .reveal { animation: fadeUp 0.8s cubic-bezier(0.16, 1, 0.3, 1) forwards; }\n\n        @media (max-width: 768px) { .neu-card { padding: 25px; } .main-title { font-size: 32px; } .viewer-3d-container { height: 450px; } }\n    \u003c\/style\u003e\n\n\n\n\u003cdiv class=\"product-container reveal\"\u003e\n\n    \u003cheader class=\"header-section\"\u003e\n        \u003cdiv class=\"badge\"\u003eProfessional Hardware\u003c\/div\u003e\n        \u003ch1 class=\"main-title\"\u003eSGP PHANTOM\u003c\/h1\u003e\n        \u003cp class=\"subtitle\"\u003eThe ultimate IT diagnostic and environmental monitoring hub. Designed for network administrators and security researchers.\u003c\/p\u003e\n        \n        \u003cdiv class=\"neu-sunken\" style=\"display: inline-block; max-width: 800px; margin: 0 auto;\"\u003e\n            \u003cp style=\"color: var(--text-main); font-size: 16px; font-weight: 500;\"\u003e\n                Driven by the high-performance \u003cstrong\u003eESP32-S3\u003c\/strong\u003e architecture, the Phantom is more than a learning platform—it’s a field-ready asset for digital and physical diagnostics.\n            \u003c\/p\u003e\n        \u003c\/div\u003e\n    \u003c\/header\u003e\n\n    \u003c!-- Video Showcase --\u003e\n    \u003cdiv class=\"media-grid\"\u003e\n        \u003cdiv\u003e\n            \u003cdiv class=\"video-container\"\u003e\n                \u003cvideo id=\"promo-video\" autoplay loop playsinline controls aria-label=\"SGP Phantom Preview\"\u003e\n                    \u003csource src=\"https:\/\/cdn.shopify.com\/videos\/c\/o\/v\/463c1561c81043c8b70c2d00cd7cbcf8.mp4\" type=\"video\/mp4\"\u003e\n                    Your browser does not support HTML5 video.\n                \u003c\/source\u003e\u003c\/video\u003e\n            \u003c\/div\u003e\n            \u003cdiv class=\"video-label\"\u003ePhantom Showcase\u003c\/div\u003e\n        \u003c\/div\u003e\n        \u003cdiv\u003e\n            \u003cdiv class=\"video-container\"\u003e\n                \u003cvideo preload=\"metadata\" controls aria-label=\"SGP Phantom Hardware Overview\" poster=\"https:\/\/sgpcard.com\/wp-content\/uploads\/2026\/03\/photo_2026-03-05_19-06-26.jpg\"\u003e\n                    \u003csource src=\"https:\/\/sgpcard.com\/wp-content\/uploads\/2026\/03\/The_SGP_Phantom-1.mp4\" type=\"video\/mp4\"\u003e\n                    Your browser does not support HTML5 video.\n                \u003c\/source\u003e\u003c\/video\u003e\n            \u003c\/div\u003e\n            \u003cdiv class=\"video-label\"\u003eHardware Overview\u003c\/div\u003e\n        \u003c\/div\u003e\n        \u003cdiv\u003e\n            \u003cdiv class=\"video-container\"\u003e\n                \u003cvideo preload=\"metadata\" controls aria-label=\"SGP Phantom Diagnostic Interface\" poster=\"https:\/\/sgpcard.com\/wp-content\/uploads\/2026\/03\/photo_2026-03-05_19-06-10.jpg\"\u003e\n                    \u003csource src=\"https:\/\/sgpcard.com\/wp-content\/uploads\/2026\/02\/VID_20260220_162621_335_bsl.mp4\" type=\"video\/mp4\"\u003e\n                    Your browser does not support HTML5 video.\n                \u003c\/source\u003e\u003c\/video\u003e\n            \u003c\/div\u003e\n            \u003cdiv class=\"video-label\"\u003eDiagnostic Interface\u003c\/div\u003e\n        \u003c\/div\u003e\n    \u003c\/div\u003e\n\n    \u003ch2 style=\"text-align: center; margin-bottom: 40px; font-size: 28px;\"\u003eCore Operational Capabilities\u003c\/h2\u003e\n    \n    \u003cdiv class=\"features-grid\"\u003e\n        \u003cdiv class=\"neu-card-sm\"\u003e\n            \u003cdiv class=\"neu-icon\"\u003e\u003csvg class=\"svg-icon\" viewbox=\"0 0 24 24\"\u003e\u003crect x=\"4\" y=\"4\" width=\"16\" height=\"16\" rx=\"2\" ry=\"2\"\u003e\u003c\/rect\u003e\u003crect x=\"9\" y=\"9\" width=\"6\" height=\"6\"\u003e\u003c\/rect\u003e\u003c\/svg\u003e\u003c\/div\u003e\n            \u003ch3 class=\"feature-title\"\u003eESP32-S3 Command Center\u003c\/h3\u003e\n            \u003cp class=\"feature-desc\"\u003eFully programmable silicon. Deploy diagnostic scripts, automate IT routines, and analyze system infrastructure with raw S3 power.\u003c\/p\u003e\n        \u003c\/div\u003e\n        \u003cdiv class=\"neu-card-sm\"\u003e\n            \u003cdiv class=\"neu-icon\"\u003e\u003csvg class=\"svg-icon\" viewbox=\"0 0 24 24\"\u003e\u003crect x=\"2\" y=\"3\" width=\"20\" height=\"14\" rx=\"2\" ry=\"2\"\u003e\u003c\/rect\u003e\u003cline x1=\"8\" y1=\"21\" x2=\"16\" y2=\"21\"\u003e\u003c\/line\u003e\u003c\/svg\u003e\u003c\/div\u003e\n            \u003ch3 class=\"feature-title\"\u003eProfessional LCD Interface\u003c\/h3\u003e\n            \u003cp class=\"feature-desc\"\u003eHigh-definition screen paired with 3 programmable physical buttons for rapid tool deployment in field testing scenarios.\u003c\/p\u003e\n        \u003c\/div\u003e\n        \u003cdiv class=\"neu-card-sm\"\u003e\n            \u003cdiv class=\"neu-icon\"\u003e\u003csvg class=\"svg-icon\" viewbox=\"0 0 24 24\"\u003e\u003cpath d=\"M12 2.69l5.66 5.66a8 8 0 1 1-11.31 0z\"\u003e\u003c\/path\u003e\u003c\/svg\u003e\u003c\/div\u003e\n            \u003ch3 class=\"feature-title\"\u003eEnvironmental Sensing\u003c\/h3\u003e\n            \u003cp class=\"feature-desc\"\u003eIntegrated BME680 multi-sensor. Monitor Air Quality (VOCs), Temperature, Humidity, Barometric Pressure, and Altitude in real-time.\u003c\/p\u003e\n        \u003c\/div\u003e\n        \u003cdiv class=\"neu-card-sm\"\u003e\n            \u003cdiv class=\"neu-icon\"\u003e\u003csvg class=\"svg-icon\" viewbox=\"0 0 24 24\"\u003e\u003cpath d=\"M5 12.55a11 11 0 0 1 14.08 0\"\u003e\u003c\/path\u003e\u003cpath d=\"M1.42 9a16 16 0 0 1 21.16 0\"\u003e\u003c\/path\u003e\u003c\/svg\u003e\u003c\/div\u003e\n            \u003ch3 class=\"feature-title\"\u003eSignal Analysis\u003c\/h3\u003e\n            \u003cp class=\"feature-desc\"\u003eNative Wi-Fi \u0026amp; Bluetooth stacks for comprehensive wireless analysis and protocol analysis.\u003c\/p\u003e\n        \u003c\/div\u003e\n        \u003cdiv class=\"neu-card-sm\"\u003e\n            \u003cdiv class=\"neu-icon\"\u003e\u003csvg class=\"svg-icon\" viewbox=\"0 0 24 24\"\u003e\u003cpolygon points=\"12 2 2 7 12 12 22 7 12 2\"\u003e\u003c\/polygon\u003e\u003cpolyline points=\"2 17 12 22 22 17\"\u003e\u003c\/polyline\u003e\u003cpolyline points=\"2 12 12 17 22 12\"\u003e\u003c\/polyline\u003e\u003c\/svg\u003e\u003c\/div\u003e\n            \u003ch3 class=\"feature-title\"\u003eLimitless Expansion\u003c\/h3\u003e\n            \u003cp class=\"feature-desc\"\u003eOpen architecture allows you to bridge external hardware and sensors, scaling your capabilities as the mission evolves.\u003c\/p\u003e\n        \u003c\/div\u003e\n        \u003cdiv class=\"neu-card-sm\"\u003e\n            \u003cdiv class=\"neu-icon\"\u003e\u003csvg class=\"svg-icon\" viewbox=\"0 0 24 24\"\u003e\u003cpath d=\"M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z\"\u003e\u003c\/path\u003e\u003c\/svg\u003e\u003c\/div\u003e\n            \u003ch3 class=\"feature-title\"\u003eHigh-Fidelity Visuals\u003c\/h3\u003e\n            \u003cp class=\"feature-desc\"\u003eOptimized UI rendering with over 263,000 colors for clear data visualization under any lighting condition.\u003c\/p\u003e\n        \u003c\/div\u003e\n        \u003cdiv class=\"neu-card-sm\"\u003e\n            \u003cdiv class=\"neu-icon\"\u003e\u003csvg class=\"svg-icon\" viewbox=\"0 0 24 24\"\u003e\u003crect x=\"3\" y=\"11\" width=\"18\" height=\"11\" rx=\"2\" ry=\"2\"\u003e\u003c\/rect\u003e\u003cpath d=\"M7 11V7a5 5 0 0 1 10 0v4\"\u003e\u003c\/path\u003e\u003c\/svg\u003e\u003c\/div\u003e\n            \u003ch3 class=\"feature-title\"\u003eRFID\/NFC RC522 Reader\u003c\/h3\u003e\n            \u003cp class=\"feature-desc\"\u003eIntegrated 13.56MHz module. Read and analyze smart cards and tags natively from the device.\u003c\/p\u003e\n        \u003c\/div\u003e\n        \u003cdiv class=\"neu-card-sm\"\u003e\n            \u003cdiv class=\"neu-icon\"\u003e\u003csvg class=\"svg-icon\" viewbox=\"0 0 24 24\"\u003e\u003cpath d=\"M12 20a8 8 0 1 0 0-16 8 8 0 0 0 0 16z\"\u003e\u003c\/path\u003e\u003cpath d=\"M12 14a2 2 0 1 0 0-4 2 2 0 0 0 0 4z\"\u003e\u003c\/path\u003e\u003cpath d=\"M12 2v2\"\u003e\u003c\/path\u003e\u003cpath d=\"M12 20v2\"\u003e\u003c\/path\u003e\u003cpath d=\"M2 12h2\"\u003e\u003c\/path\u003e\u003cpath d=\"M20 12h2\"\u003e\u003c\/path\u003e\u003c\/svg\u003e\u003c\/div\u003e\n            \u003ch3 class=\"feature-title\"\u003eRadar \u0026amp; IoT Connectivity\u003c\/h3\u003e\n            \u003cp class=\"feature-desc\"\u003eDeploy spatial radar mapping applications and connect to the global internet network for remote data transfer and updates.\u003c\/p\u003e\n        \u003c\/div\u003e\n        \u003cdiv class=\"neu-card-sm\"\u003e\n            \u003cdiv class=\"neu-icon\"\u003e\u003csvg class=\"svg-icon\" viewbox=\"0 0 24 24\"\u003e\u003crect x=\"8\" y=\"2\" width=\"8\" height=\"4\" rx=\"1\" ry=\"1\"\u003e\u003c\/rect\u003e\u003crect x=\"4\" y=\"6\" width=\"16\" height=\"16\" rx=\"2\" ry=\"2\"\u003e\u003c\/rect\u003e\u003cline x1=\"12\" y1=\"11\" x2=\"12\" y2=\"17\"\u003e\u003c\/line\u003e\u003cline x1=\"9\" y1=\"14\" x2=\"15\" y2=\"14\"\u003e\u003c\/line\u003e\u003c\/svg\u003e\u003c\/div\u003e\n            \u003ch3 class=\"feature-title\"\u003eExtended Power \u0026amp; USB OTG\u003c\/h3\u003e\n            \u003cp class=\"feature-desc\"\u003eHigh-capacity \u003cstrong\u003e\u0026gt;500 mAh battery\u003c\/strong\u003e for extended field ops, plus USB OTG port to interface with external peripheral devices directly.\u003c\/p\u003e\n        \u003c\/div\u003e\n    \u003c\/div\u003e\n\n    \u003c!-- Hardware Gallery --\u003e\n    \u003cdiv class=\"gallery-wrapper\"\u003e\n        \u003ch2 style=\"text-align: center; margin-bottom: 10px; font-size: 28px;\"\u003eHardware Gallery\u003c\/h2\u003e\n        \u003cp style=\"text-align: center; color: var(--text-muted); font-size: 14px; margin-bottom: 20px;\"\u003eExplore the premium build quality\u003c\/p\u003e\n        \n        \u003cdiv class=\"gallery-grid neu-sunken\"\u003e\n            \u003cdiv class=\"gallery-item\"\u003e\n                \u003cdiv class=\"crt-wrapper\"\u003e\n                    \u003cimg src=\"https:\/\/sgpcard.com\/wp-content\/uploads\/2026\/03\/photo_2026-03-05_19-06-26.jpg\" alt=\"Sensor BME680\" loading=\"lazy\"\u003e\n                \u003c\/div\u003e\n            \u003c\/div\u003e\n            \u003cdiv class=\"gallery-item\"\u003e\n                \u003cdiv class=\"crt-wrapper\"\u003e\n                    \u003cimg src=\"https:\/\/sgpcard.com\/wp-content\/uploads\/2026\/03\/photo_2026-03-05_19-06-38.jpg\" alt=\"Motherboard\" loading=\"lazy\"\u003e\n                \u003c\/div\u003e\n            \u003c\/div\u003e\n            \u003cdiv class=\"gallery-item\"\u003e\n                \u003cdiv class=\"crt-wrapper\"\u003e\n                    \u003cimg src=\"https:\/\/sgpcard.com\/wp-content\/uploads\/2026\/03\/photo_2026-03-05_19-06-10.jpg\" alt=\"LCD Interface Detail\" loading=\"lazy\"\u003e\n                \u003c\/div\u003e\n            \u003c\/div\u003e\n            \u003cdiv class=\"gallery-item\"\u003e\n                \u003cdiv class=\"crt-wrapper\"\u003e\n                    \u003cimg src=\"https:\/\/sgpcard.com\/wp-content\/uploads\/2026\/03\/photo_2026-03-05_19-05-49.jpg\" alt=\"Connectivity Ports\" loading=\"lazy\"\u003e\n                \u003c\/div\u003e\n            \u003c\/div\u003e\n        \u003c\/div\u003e\n    \u003c\/div\u003e\n\n    \u003c!-- Interactive 3D Model --\u003e\n    \u003ch2 style=\"text-align: center; margin-bottom: 10px; font-size: 28px;\"\u003eInteractive 3D Preview\u003c\/h2\u003e\n    \u003cdiv class=\"viewer-3d-container\"\u003e\n        \u003cdiv id=\"three-canvas-container\"\u003e\u003c\/div\u003e\n        \u003cdiv class=\"viewer-instructions\"\u003eClick and drag to rotate. Tap side buttons to interact.\u003c\/div\u003e\n    \u003c\/div\u003e\n\n    \u003c!-- Legal Disclaimer --\u003e\n    \u003cdiv class=\"disclaimer neu-sunken\"\u003e\n        \u003ch4 style=\"color: var(--danger); font-size: 14px; margin-bottom: 5px; text-transform: uppercase;\"\u003eResponsibility Protocol\u003c\/h4\u003e\n        \u003cp\u003eProfessional engineering tool designed strictly for STEM education, IT research, and authorized network diagnostics. The user is solely responsible for compliance with all local laws and regulations. This is not a surveillance device.\u003c\/p\u003e\n    \u003c\/div\u003e\n\n\u003c\/div\u003e\n\n\u003cscript src=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/three.js\/r128\/three.min.js\"\u003e\u003c\/script\u003e\n\u003cscript\u003e\n    window.addEventListener('load', function() {\n        const container = document.getElementById('three-canvas-container');\n        if (!container) return;\n        \n        const scene = new THREE.Scene();\n        const camera = new THREE.PerspectiveCamera(45, container.clientWidth \/ container.clientHeight, 0.1, 100);\n        camera.position.z = 5; \n\n        const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });\n        renderer.setSize(container.clientWidth, container.clientHeight);\n        renderer.setPixelRatio(window.devicePixelRatio);\n        container.appendChild(renderer.domElement);\n\n        const deviceGroup = new THREE.Group();\n        scene.add(deviceGroup);\n\n        const ambientLight = new THREE.AmbientLight(0xffffff, 0.7);\n        scene.add(ambientLight);\n        const dirLight = new THREE.DirectionalLight(0xffffff, 0.9);\n        dirLight.position.set(5, 5, 5);\n        scene.add(dirLight);\n\n        \/\/ 1. Cuerpo del SGP Phantom (Bloque vertical)\n        const bodyWidth = 1.2;\n        const bodyHeight = 2.4;\n        const bodyDepth = 0.22; \/\/ Grosor reducido (antes 0.4) para un perfil delgado\n        \n        const shape = new THREE.Shape();\n        shape.moveTo(-bodyWidth\/2, bodyHeight\/2);\n        shape.lineTo(bodyWidth\/2, bodyHeight\/2);\n        shape.lineTo(bodyWidth\/2, -bodyHeight\/2);\n        shape.lineTo(-bodyWidth\/2, -bodyHeight\/2);\n        shape.lineTo(-bodyWidth\/2, bodyHeight\/2);\n\n        \/\/ Agujero cuadrado abajo a la derecha\n        const hole = new THREE.Path();\n        hole.moveTo(0.38, -0.92);\n        hole.lineTo(0.52, -0.92);\n        hole.lineTo(0.52, -1.06);\n        hole.lineTo(0.38, -1.06);\n        hole.lineTo(0.38, -0.92);\n        shape.holes.push(hole);\n\n        const extrudeSettings = {\n            depth: bodyDepth,\n            bevelEnabled: true,\n            bevelThickness: 0.02,\n            bevelSize: 0.02,\n            bevelSegments: 3\n        };\n        const bodyGeo = new THREE.ExtrudeGeometry(shape, extrudeSettings);\n        bodyGeo.translate(0, 0, -bodyDepth\/2); \/\/ Centrar extrusión\n\n        const bodyMat = new THREE.MeshStandardMaterial({ \n            color: 0x111111,\n            roughness: 0.85, \n            metalness: 0.2 \n        });\n        const body = new THREE.Mesh(bodyGeo, bodyMat);\n        deviceGroup.add(body);\n\n        \/\/ 2. Pantalla LCD (Moved to TOP half)\n        const screenCanvas = document.createElement('canvas');\n        screenCanvas.width = 256;\n        screenCanvas.height = 256;\n        const ctx = screenCanvas.getContext('2d');\n        const screenTex = new THREE.CanvasTexture(screenCanvas);\n        \n        const screenWidth = 1.05;\n        const screenHeight = 1.05;\n        const screenGeo = new THREE.PlaneGeometry(screenWidth, screenHeight);\n        const screenMat = new THREE.MeshBasicMaterial({ map: screenTex });\n        const screen = new THREE.Mesh(screenGeo, screenMat);\n        \n        \/\/ Postion screen on TOP half of the device face (Ajustado por el bisel de la extrusión)\n        screen.position.set(0, 0.5, (bodyDepth \/ 2) + 0.025); \n        deviceGroup.add(screen);\n\n        const glassGeo = new THREE.PlaneGeometry(screenWidth, screenHeight);\n        const glassMat = new THREE.MeshStandardMaterial({ \n            color: 0x000000, \n            transparent: true, \n            opacity: 0.2, \n            roughness: 0.1, \n            metalness: 0.9 \n        });\n        const glass = new THREE.Mesh(glassGeo, glassMat);\n        glass.position.set(0, 0.5, (bodyDepth \/ 2) + 0.035);\n        deviceGroup.add(glass);\n\n        \/\/ 3. Botones Laterales (Borde Derecho, alineados con la pantalla arriba)\n        const btnGeo = new THREE.BoxGeometry(0.15, 0.3, 0.08); \/\/ Botones adaptados al nuevo grosor\n        const btnMat = new THREE.MeshStandardMaterial({ color: 0x050505, roughness: 0.9 });\n        const interactiveButtons = [];\n\n        for(let i=0; i\u003c3; i++) {\n            const btn = new THREE.Mesh(btnGeo, btnMat);\n            \/\/ Posicionar a la derecha (eje X positivo), mitad superior (eje Y positivo)\n            const startX = (bodyWidth \/ 2) + 0.05;\n            btn.position.set(startX, 0.8 - (i * 0.35), 0);\n            \n            btn.userData = { \n                id: i, \n                originalX: startX,\n                programName: i === 0 ? 'MENU' : (i === 1 ? 'RADAR' : 'SENSORS')\n            };\n            \n            deviceGroup.add(btn);\n            interactiveButtons.push(btn);\n        }\n\n        \/\/ 4. Interacciones de Ratón y Táctil\n        let isDragging = false;\n        let previousMousePosition = { x: 0, y: 0 };\n        let clickStartPos = { x: 0, y: 0 };\n        const raycaster = new THREE.Raycaster();\n        const mouse = new THREE.Vector2();\n\n        let currentProgram = 'MENU'; \n        let time = 0;\n\n        const getCoords = (e) =\u003e {\n            const rect = container.getBoundingClientRect();\n            let clientX, clientY;\n\n            if (e.changedTouches \u0026\u0026 e.changedTouches.length \u003e 0) {\n                clientX = e.changedTouches[0].clientX;\n                clientY = e.changedTouches[0].clientY;\n            } else {\n                clientX = e.clientX;\n                clientY = e.clientY;\n            }\n\n            return {\n                x: clientX - rect.left,\n                y: clientY - rect.top,\n                normX: ((clientX - rect.left) \/ container.clientWidth) * 2 - 1,\n                normY: -((clientY - rect.top) \/ container.clientHeight) * 2 + 1\n            };\n        };\n\n        const startInteraction = (e) =\u003e {\n            isDragging = true;\n            const coords = getCoords(e);\n            previousMousePosition = { x: coords.x, y: coords.y };\n            clickStartPos = { x: coords.x, y: coords.y };\n        };\n        \n        const doInteraction = (e) =\u003e {\n            if (isDragging) {\n                const coords = getCoords(e);\n                const deltaMove = { \n                    x: coords.x - previousMousePosition.x, \n                    y: coords.y - previousMousePosition.y \n                };\n                deviceGroup.rotation.y += deltaMove.x * 0.01;\n                deviceGroup.rotation.x += deltaMove.y * 0.01;\n                previousMousePosition = { x: coords.x, y: coords.y };\n            }\n        };\n        \n        const endInteraction = (e) =\u003e {\n            isDragging = false;\n            const coords = getCoords(e);\n            const dist = Math.sqrt(Math.pow(coords.x - clickStartPos.x, 2) + Math.pow(coords.y - clickStartPos.y, 2));\n            \n            \/\/ Si no hubo apenas arrastre, es un clic (pulsación de botón)\n            if (dist \u003c 5) { \n                mouse.x = coords.normX;\n                mouse.y = coords.normY;\n                raycaster.setFromCamera(mouse, camera);\n\n                const intersects = raycaster.intersectObjects(interactiveButtons);\n                if (intersects.length \u003e 0) {\n                    const btn = intersects[0].object;\n                    currentProgram = btn.userData.programName; \n                    \n                    \/\/ Animar botón hundiéndose\n                    btn.position.x = btn.userData.originalX - 0.08;\n                    setTimeout(() =\u003e {\n                        btn.position.x = btn.userData.originalX;\n                    }, 150);\n                }\n            }\n        };\n\n        container.addEventListener('mousedown', startInteraction);\n        document.addEventListener('mousemove', doInteraction);\n        document.addEventListener('mouseup', endInteraction);\n        \n        container.addEventListener('touchstart', startInteraction, {passive: true});\n        document.addEventListener('touchmove', doInteraction, {passive: true});\n        document.addEventListener('touchend', endInteraction);\n\n        window.addEventListener('resize', () =\u003e {\n            camera.aspect = container.clientWidth \/ container.clientHeight;\n            camera.updateProjectionMatrix();\n            renderer.setSize(container.clientWidth, container.clientHeight);\n        });\n\n        \/\/ 5. Funciones de Dibujo (Programas)\n        const drawMenu = () =\u003e {\n            ctx.fillStyle = '#39ff14';\n            ctx.font = 'bold 20px monospace';\n            ctx.fillText('SGP OS', 75, 40);\n            ctx.fillRect(15, 55, 226, 2);\n            \n            ctx.font = '16px monospace';\n            const items = ['\u003e MOTION SENSE', '\u003e WIFI MOTION', '\u003e GPIO CONTROL', '\u003e ENV SENSOR', '\u003e GAS MONITOR'];\n            items.forEach((item, i) =\u003e {\n                if (Math.floor(time * 1.5) % items.length === i) {\n                    ctx.fillStyle = '#1a401a';\n                    ctx.fillRect(15, 75 + i * 30 - 16, 226, 22);\n                    ctx.fillStyle = '#39ff14';\n                }\n                ctx.fillText(item, 20, 75 + i * 30);\n            });\n        };\n\n        const drawSensors = () =\u003e {\n            ctx.fillStyle = '#39ff14';\n            ctx.font = 'bold 20px monospace';\n            ctx.fillText('BME680 SENSOR', 50, 40);\n            ctx.fillRect(15, 55, 226, 2);\n            \n            ctx.font = '18px monospace';\n            const t = (24.1 + Math.sin(time)*0.5).toFixed(1);\n            const h = (42.5 + Math.cos(time)*1.2).toFixed(1);\n            \n            ctx.fillText(`TEMP : ${t} C`, 20, 100);\n            ctx.fillText(`HUM  : ${h} %`, 20, 140);\n            ctx.fillText(`PRES : 1013 hPa`, 20, 180);\n            \n            ctx.fillStyle = Math.sin(time*5) \u003e 0 ? '#39ff14' : '#1a401a';\n            ctx.fillText(`VOC  : DETECTING...`, 20, 220);\n        };\n\n        const drawRadar = () =\u003e {\n            const centerX = 128, centerY = 128, maxRadius = 115;\n            ctx.strokeStyle = '#1a401a'; \n            ctx.lineWidth = 1;\n            ctx.beginPath();\n            for(let r = 30; r \u003c maxRadius; r += 30) ctx.arc(centerX, centerY, r, 0, Math.PI * 2);\n            ctx.moveTo(centerX - maxRadius, centerY); ctx.lineTo(centerX + maxRadius, centerY);\n            ctx.moveTo(centerX, centerY - maxRadius); ctx.lineTo(centerX, centerY + maxRadius);\n            ctx.stroke();\n\n            const sweepAngle = (time * 3) % (Math.PI * 2);\n            const gradient = ctx.createConicGradient(sweepAngle + Math.PI\/2, centerX, centerY);\n            gradient.addColorStop(0, 'rgba(57, 255, 20, 0)');\n            gradient.addColorStop(0.7, 'rgba(57, 255, 20, 0.05)');\n            gradient.addColorStop(1, 'rgba(57, 255, 20, 0.5)');\n            ctx.fillStyle = gradient;\n            ctx.beginPath(); ctx.moveTo(centerX, centerY);\n            ctx.arc(centerX, centerY, maxRadius, sweepAngle - 0.7, sweepAngle);\n            ctx.lineTo(centerX, centerY); ctx.fill();\n\n            ctx.strokeStyle = '#39ff14'; ctx.lineWidth = 2;\n            ctx.beginPath(); ctx.moveTo(centerX, centerY);\n            ctx.lineTo(centerX + Math.cos(sweepAngle)*maxRadius, centerY + Math.sin(sweepAngle)*maxRadius);\n            ctx.stroke();\n\n            ctx.fillStyle = '#39ff14';\n            ctx.beginPath(); ctx.arc(centerX, centerY, 3 + Math.sin(time*8)*1.5, 0, Math.PI*2); ctx.fill();\n            ctx.beginPath(); ctx.arc(centerX + 60, centerY - 40, 4, 0, Math.PI*2); ctx.fill();\n            ctx.beginPath(); ctx.arc(centerX - 50, centerY + 70, 4, 0, Math.PI*2); ctx.fill();\n            \n            ctx.font = 'bold 14px monospace';\n            ctx.fillText('RF SCAN: ACTIVE', 10, 25);\n            ctx.font = '12px monospace';\n            ctx.fillText('SIGNALS: 2', 10, 245);\n        };\n\n        \/\/ 6. Bucle Principal\n        function animate() {\n            requestAnimationFrame(animate);\n            time += 0.02;\n\n            ctx.fillStyle = '#020502';\n            ctx.fillRect(0, 0, 256, 256);\n\n            if (currentProgram === 'MENU') drawMenu();\n            else if (currentProgram === 'RADAR') drawRadar();\n            else if (currentProgram === 'SENSORS') drawSensors();\n\n            screenTex.needsUpdate = true;\n\n            if (!isDragging) {\n                deviceGroup.rotation.y += 0.005;\n                deviceGroup.position.y = Math.sin(time) * 0.05; \/\/ Hovering muy sutil\n            }\n\n            renderer.render(scene, camera);\n        }\n        \n        animate();\n    });\n\n    \/\/ Control de volumen al máximo y manejo del bloqueo de Autoplay del navegador\n    window.addEventListener('DOMContentLoaded', () =\u003e {\n        const promoVideo = document.getElementById('promo-video');\n        if (promoVideo) {\n            promoVideo.volume = 1.0; \/\/ Volumen al 100%\n            \n            \/\/ Intentar reproducir (los navegadores suelen bloquearlo si no está en silencio)\n            let playPromise = promoVideo.play();\n            \n            if (playPromise !== undefined) {\n                playPromise.catch(error =\u003e {\n                    console.log(\"El navegador bloqueó el autoplay con sonido. Esperando interacción del usuario.\");\n                    \/\/ Si se bloquea, reproducir inmediatamente cuando el usuario haga clic en cualquier parte de la página\n                    document.body.addEventListener('click', function playOnFirstClick() {\n                        promoVideo.volume = 1.0;\n                        promoVideo.play();\n                        document.body.removeEventListener('click', playOnFirstClick);\n                    }, { once: true });\n                });\n            }\n        }\n    });\n\u003c\/script\u003e\n\n\n\u003c\/body\u003e","brand":"sgpstore","offers":[{"title":"Default Title","offer_id":57533564780876,"sku":null,"price":249.0,"currency_code":"EUR","in_stock":true}],"thumbnail_url":"\/\/cdn.shopify.com\/s\/files\/1\/1057\/9807\/4700\/files\/D8025B21-0260-4080-99E6-6335FFA3C388.jpg?v=1782756000"},{"product_id":"sgp-spectre","title":"SGP Spectre","description":"\u003cbody\u003e\n\n\n    \u003cmeta charset=\"UTF-8\"\u003e\n    \u003cmeta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"\u003e\n    \u003ctitle\u003eSGP Spectre - Product Description\u003c\/title\u003e\n    \u003clink rel=\"preconnect\" href=\"https:\/\/fonts.googleapis.com\"\u003e\n    \u003clink rel=\"preconnect\" href=\"https:\/\/fonts.gstatic.com\" crossorigin\u003e\n    \u003clink href=\"https:\/\/fonts.googleapis.com\/css2?family=Orbitron:wght@500;600;700;800\u0026amp;family=Inter:wght@400;500;600\u0026amp;display=swap\" rel=\"stylesheet\"\u003e\n    \u003cscript src=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/three.js\/r128\/three.min.js\"\u003e\u003c\/script\u003e\n    \u003cscript src=\"https:\/\/d3js.org\/d3.v7.min.js\"\u003e\u003c\/script\u003e\n    \u003cscript src=\"https:\/\/unpkg.com\/topojson-client@3\"\u003e\u003c\/script\u003e\n\n\n\n\u003cstyle\u003e\n  .spectre-desc {\n    font-family: 'Inter', sans-serif;\n    background: transparent;\n    padding: clamp(30px, 5vw, 60px) 16px;\n    color: #4a5568;\n    max-width: 1100px;\n    margin: 0 auto;\n  }\n\n  \/* Cabecera \/ Intro *\/\n  .spectre-hero {\n    text-align: center;\n    margin-bottom: 40px;\n    opacity: 0;\n    transform: translateY(20px);\n    animation: fadeUp 0.8s ease forwards;\n  }\n\n  .spectre-title {\n    font-family: 'Orbitron', sans-serif;\n    font-weight: 800;\n    font-size: clamp(32px, 5vw, 56px);\n    color: #2d3748;\n    margin: 0 0 10px 0;\n    letter-spacing: 2px;\n    text-transform: uppercase;\n    text-shadow: 2px 2px 4px rgba(255,255,255,0.8);\n  }\n\n  .spectre-subtitle {\n    font-size: clamp(16px, 2vw, 20px);\n    font-weight: 600;\n    color: #eab308;\n    text-transform: uppercase;\n    letter-spacing: 3px;\n    margin: 0 0 20px 0;\n  }\n\n  .spectre-intro {\n    max-width: 700px;\n    margin: 0 auto;\n    font-size: 16px;\n    line-height: 1.6;\n  }\n\n  \/* PANTALLA TÁCTIL SIMULADA *\/\n  .spectre-device-wrapper {\n    display: flex;\n    justify-content: center;\n    margin: 0 auto 60px auto;\n    opacity: 0;\n    transform: translateY(20px);\n  }\n\n  .spectre-device-wrapper.is-visible {\n    animation: fadeUp 0.8s ease forwards;\n    animation-delay: 0.3s;\n  }\n\n  .spectre-device-casing {\n    background: #e0e5ec;\n    padding: 16px;\n    border-radius: 40px;\n    box-shadow: \n      12px 12px 24px rgba(163, 177, 198, 0.6), \n      -12px -12px 24px rgba(255, 255, 255, 0.8);\n    border: 1px solid rgba(255,255,255,0.4);\n    display: flex;\n    align-items: center;\n    justify-content: center;\n  }\n\n  .spectre-device-bezel {\n    background: #1e293b;\n    padding: 10px;\n    border-radius: 28px;\n    box-shadow: inset 2px 2px 6px rgba(0,0,0,0.8), inset -2px -2px 6px rgba(255,255,255,0.1);\n  }\n\n  .spectre-screen {\n    background: #0f172a;\n    width: 280px;\n    height: 450px;\n    border-radius: 20px;\n    position: relative;\n    overflow: hidden;\n    display: flex;\n    flex-direction: column;\n    border: 2px solid #000;\n    box-shadow: inset 0 0 20px rgba(0,0,0,0.9);\n    color: #e2e8f0;\n    font-family: 'Orbitron', sans-serif;\n  }\n\n  .spectre-screen::before {\n    content: \" \";\n    display: block;\n    position: absolute;\n    top: 0; left: 0; bottom: 0; right: 0;\n    background: linear-gradient(rgba(18, 16, 16, 0) 50%, rgba(0, 0, 0, 0.25) 50%), linear-gradient(90deg, rgba(255, 0, 0, 0.06), rgba(0, 255, 0, 0.02), rgba(0, 0, 255, 0.06));\n    z-index: 50;\n    background-size: 100% 3px, 3px 100%;\n    pointer-events: none;\n  }\n\n  .spectre-screen-glare {\n    position: absolute;\n    top: 0; left: -50%; width: 200%; height: 100%;\n    background: linear-gradient(to bottom right, rgba(255,255,255,0.08) 0%, rgba(255,255,255,0) 40%);\n    pointer-events: none;\n    transform: rotate(-15deg);\n    z-index: 55;\n  }\n\n  .spectre-status-bar {\n    display: flex;\n    justify-content: space-between;\n    align-items: center;\n    padding: 8px 16px;\n    font-size: 11px;\n    color: #94a3b8;\n    background: #0f172a;\n    border-bottom: 1px solid rgba(255,255,255,0.05);\n    z-index: 40;\n    position: relative;\n  }\n\n  .spectre-status-icons { display: flex; gap: 8px; color: #eab308; }\n\n  .spectre-view-container {\n    flex: 1;\n    position: relative;\n    overflow: hidden;\n    z-index: 30;\n  }\n\n  .spectre-view {\n    position: absolute;\n    top: 0; left: 0; width: 100%; height: 100%;\n    background: #0f172a;\n    display: none;\n    flex-direction: column;\n    padding: 16px;\n    box-sizing: border-box;\n    overflow-y: auto;\n    scrollbar-width: none;\n  }\n  .spectre-view::-webkit-scrollbar { display: none; }\n  \n  .spectre-view.active {\n    display: flex;\n    animation: fadeInApp 0.3s ease;\n  }\n\n  @keyframes fadeInApp {\n    from { opacity: 0; transform: scale(0.95); }\n    to { opacity: 1; transform: scale(1); }\n  }\n\n  \/* HOME GRID *\/\n  #view-home {\n    grid-template-columns: repeat(3, 1fr);\n    grid-auto-rows: 80px;\n    gap: 16px 10px;\n    padding: 24px 16px;\n    align-content: start;\n  }\n  #view-home.active { display: grid; }\n\n  .spectre-app {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: start;\n    gap: 8px;\n    cursor: pointer;\n    transition: transform 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275);\n    position: relative;\n    z-index: 40;\n  }\n\n  .spectre-app:active { transform: scale(0.9); }\n\n  .app-icon {\n    width: 54px;\n    height: 54px;\n    background: linear-gradient(135deg, #1e293b, #0f172a);\n    border-radius: 14px;\n    display: flex;\n    justify-content: center;\n    align-items: center;\n    font-size: 26px;\n    box-shadow: 4px 4px 10px rgba(0,0,0,0.8), -1px -1px 6px rgba(255,255,255,0.05);\n    border: 1px solid rgba(255,255,255,0.08);\n    position: relative;\n  }\n\n  .app-icon.has-badge::after {\n    content: ''; position: absolute; top: -2px; right: -2px; width: 12px; height: 12px;\n    background: #ef4444; border-radius: 50%; border: 2px solid #0f172a;\n    animation: pulseBadge 2s infinite;\n  }\n\n  @keyframes pulseBadge {\n    0% { box-shadow: 0 0 0 0 rgba(239, 68, 68, 0.7); }\n    70% { box-shadow: 0 0 0 6px rgba(239, 68, 68, 0); }\n    100% { box-shadow: 0 0 0 0 rgba(239, 68, 68, 0); }\n  }\n\n  .app-name {\n    color: #cbd5e1; font-size: 10px; font-family: 'Inter', sans-serif;\n    font-weight: 600; text-align: center; text-transform: uppercase; letter-spacing: 0.5px;\n  }\n\n  .spectre-home-bar {\n    height: 30px; background: #0f172a; display: flex; justify-content: center;\n    align-items: center; z-index: 40; position: relative; cursor: pointer;\n    border-top: 1px solid rgba(255,255,255,0.05);\n  }\n\n  .spectre-home-indicator {\n    width: 80px; height: 4px; background: #cbd5e1; border-radius: 4px;\n    transition: background 0.2s, transform 0.2s;\n  }\n  .spectre-home-bar:hover .spectre-home-indicator { background: #eab308; transform: scaleY(1.5); }\n\n  .app-header {\n    text-align: center; color: #eab308; font-size: 14px; letter-spacing: 2px;\n    margin-bottom: 20px; border-bottom: 1px solid rgba(234, 179, 8, 0.3); padding-bottom: 8px;\n  }\n\n  \/* APPS STYLES *\/\n  .radar-container {\n    position: relative; width: 200px; height: 200px; margin: 0 auto 20px auto;\n    border-radius: 50%; border: 2px solid #22c55e;\n    background: radial-gradient(circle, rgba(34,197,94,0.1) 0%, rgba(15,23,42,1) 70%); overflow: hidden;\n  }\n  .radar-grid {\n    position: absolute; top:0; left:0; width:100%; height:100%;\n    background-image: linear-gradient(#22c55e 1px, transparent 1px), linear-gradient(90deg, #22c55e 1px, transparent 1px);\n    background-size: 40px 40px; opacity: 0.2; border-radius: 50%;\n  }\n  .radar-sweep {\n    position: absolute; top: 50%; left: 50%; width: 100px; height: 100px;\n    background: conic-gradient(from 0deg, transparent 70%, rgba(34,197,94,0.8) 100%);\n    transform-origin: 0% 0%; animation: radarSpin 2s linear infinite;\n  }\n  .sat-dot { position: absolute; width: 6px; height: 6px; background: #fff; border-radius: 50%; box-shadow: 0 0 8px #fff; }\n  @keyframes radarSpin { 100% { transform: rotate(360deg); } }\n  .gnss-data { font-family: 'Inter', monospace; font-size: 12px; color: #22c55e; line-height: 1.8; }\n\n  .lora-console {\n    flex: 1; background: #000; border: 1px solid #334155; border-radius: 8px;\n    padding: 10px; font-family: monospace; font-size: 11px; color: #38bdf8;\n    overflow-y: hidden; display: flex; flex-direction: column; justify-content: flex-end;\n  }\n  .lora-line { margin: 2px 0; opacity: 0.8; }\n  .lora-line.tx { color: #eab308; }\n\n  #wifi-canvas { width: 100%; height: 150px; background: #000; border: 1px solid #334155; border-radius: 8px; margin-bottom: 16px; }\n  .wifi-networks { font-family: 'Inter', sans-serif; font-size: 11px; }\n  .wifi-net { display: flex; justify-content: space-between; padding: 6px 0; border-bottom: 1px solid #1e293b; }\n  .wifi-net strong { color: #e2e8f0; } .wifi-net span { color: #22c55e; }\n\n  #cellular-globe-container { width: 100%; height: 180px; margin: 0 auto 16px auto; position: relative; border-radius: 50%; overflow: hidden; background: #000; box-shadow: 0 0 30px rgba(234, 179, 8, 0.2); }\n  .cell-info { text-align: center; font-family: 'Inter', monospace; font-size: 12px; color: #eab308; background: rgba(0,0,0,0.5); padding: 10px; border-radius: 8px; border: 1px solid #334155; }\n\n  .terminal-view { font-family: monospace; font-size: 12px; color: #4ade80; flex: 1; overflow-y: hidden; display: flex; flex-direction: column; justify-content: flex-end; }\n  .term-line { margin: 2px 0; text-shadow: 0 0 5px rgba(74, 222, 128, 0.5); }\n  .term-cursor { display: inline-block; width: 8px; height: 12px; background: #4ade80; animation: blink 1s step-end infinite; }\n  @keyframes blink { 50% { opacity: 0; } }\n\n  .settings-list { display: flex; flex-direction: column; gap: 16px; }\n  .setting-item { display: flex; justify-content: space-between; align-items: center; font-family: 'Inter', sans-serif; font-size: 14px; color: #cbd5e1; }\n  .toggle { width: 40px; height: 20px; background: #334155; border-radius: 20px; position: relative; cursor: pointer; }\n  .toggle.on { background: #22c55e; }\n  .toggle::after { content: ''; position: absolute; top: 2px; left: 2px; width: 16px; height: 16px; background: #fff; border-radius: 50%; transition: 0.2s; }\n  .toggle.on::after { left: 22px; }\n\n  .chat-msg { margin-bottom: 8px; font-family: 'Inter', sans-serif; font-size: 11px; max-width: 85%; padding: 6px 10px; border-radius: 12px; clear: both; word-wrap: break-word;}\n  .chat-msg.rx { background: #1e293b; color: #cbd5e1; float: left; border-bottom-left-radius: 2px; }\n  .chat-msg.tx { background: #22c55e; color: #000; float: right; border-bottom-right-radius: 2px; }\n  \n  .signal-console { flex: 1; background: #000; border: 1px solid #7f1d1d; border-radius: 8px; padding: 10px; font-family: monospace; font-size: 10px; color: #ef4444; overflow-y: hidden; display: flex; flex-direction: column; justify-content: flex-end; }\n  \n  .d-pad { display: grid; grid-template-columns: 35px 35px 35px; gap: 6px; justify-content: center; margin-top: 12px; }\n  .d-pad button { background: #1e293b; border: 1px solid #334155; color: #a855f7; border-radius: 6px; padding: 8px; font-weight: bold; cursor: pointer; transition: 0.1s; display: flex; justify-content: center; align-items: center;}\n  .d-pad button:active { background: #a855f7; color: #000; transform: scale(0.9); }\n\n  .rf-radar-container {\n    position: relative; width: 200px; height: 200px; margin: 0 auto 20px auto;\n    border-radius: 50%; border: 2px solid #f97316;\n    background: radial-gradient(circle, rgba(249,115,22,0.1) 0%, rgba(15,23,42,1) 70%); overflow: hidden;\n  }\n  .rf-sweep {\n    position: absolute; top: 50%; left: 50%; width: 100px; height: 100px;\n    background: conic-gradient(from 0deg, transparent 70%, rgba(249,115,22,0.8) 100%);\n    transform-origin: 0% 0%; animation: rfSpin 1.5s linear infinite;\n  }\n  .rf-dot { position: absolute; width: 8px; height: 8px; background: #ef4444; border-radius: 50%; box-shadow: 0 0 10px #ef4444; }\n  @keyframes rfSpin { 100% { transform: rotate(-360deg); } }\n\n  .music-player { text-align: center; }\n  .music-cover { width: 120px; height: 120px; background: #1e293b; border-radius: 12px; margin: 0 auto 16px auto; display:flex; justify-content:center; align-items:center; font-size:40px; box-shadow: 0 4px 15px rgba(0,0,0,0.5); }\n  .music-title { font-size: 14px; color: #f8fafc; font-weight:bold; margin-bottom: 4px; }\n  .music-artist { font-family: 'Inter', sans-serif; font-size: 11px; color: #94a3b8; margin-bottom: 16px; }\n  .music-controls { display: flex; justify-content: center; gap: 16px; align-items: center; }\n  .music-btn { background: #334155; color: #fff; border:none; border-radius:50%; width:40px; height:40px; cursor:pointer; font-size:16px; display:flex; justify-content:center; align-items:center;}\n  #eq-canvas { width: 100%; height: 50px; margin-top: 20px; border-radius:8px; background: #000; }\n\n  .sd-explorer { font-family: 'Inter', sans-serif; font-size: 12px; }\n  .sd-item { display: flex; align-items: center; gap: 10px; padding: 10px 8px; border-bottom: 1px solid #1e293b; color: #cbd5e1; }\n  .sd-icon { font-size: 16px; }\n\n  .usb-console {\n    flex: 1; background: #000; border: 1px solid #0ea5e9; border-radius: 8px;\n    padding: 10px; font-family: monospace; font-size: 11px; color: #bae6fd;\n    overflow-y: auto; display: flex; flex-direction: column;\n  }\n  .usb-line { margin: 3px 0; }\n  .usb-success { color: #38bdf8; font-weight: bold; }\n\n  \/* Banners y Grid *\/\n  .spectre-features { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 30px; margin-bottom: 50px; }\n  .spectre-card { background: #e0e5ec; border-radius: 30px; padding: 32px 24px; border: 1px solid rgba(255,255,255,0.2); box-shadow: 10px 10px 20px rgba(163, 177, 198, 0.5), -10px -10px 20px rgba(255, 255, 255, 0.8); transition: all 0.3s ease; opacity: 0; transform: translateY(20px); }\n  .spectre-card.is-visible { animation: fadeUp 0.6s ease forwards; }\n  .spectre-card:hover { box-shadow: inset 8px 8px 16px rgba(163, 177, 198, 0.6), inset -8px -8px 16px rgba(255, 255, 255, 0.9); transform: translateY(-5px); }\n  .spectre-icon { font-size: 32px; margin-bottom: 20px; display: inline-flex; width: 64px; height: 64px; align-items: center; justify-content: center; border-radius: 50%; background: #e0e5ec; box-shadow: 4px 4px 8px rgba(163, 177, 198, 0.5), -4px -4px 8px rgba(255, 255, 255, 0.8); }\n  .spectre-card-title { font-family: 'Orbitron', sans-serif; font-size: 18px; font-weight: 700; color: #2d3748; margin: 0 0 12px 0; }\n  .spectre-card-text { font-size: 14px; line-height: 1.5; margin: 0; }\n\n  .spectre-banner { background: #e0e5ec; border-radius: 40px; padding: 40px; text-align: center; box-shadow: inset 10px 10px 20px rgba(163, 177, 198, 0.5), inset -10px -10px 20px rgba(255, 255, 255, 0.8); border: 1px solid rgba(255,255,255,0.4); opacity: 0; transform: translateY(20px); }\n  .spectre-banner.is-visible { animation: fadeUp 0.8s ease forwards; }\n  .spectre-banner-title { font-family: 'Orbitron', sans-serif; font-size: 24px; font-weight: 800; color: #2d3748; margin: 0 0 16px 0; }\n\n  .spectre-prep { background: #e0e5ec; border-radius: 40px; padding: 50px 30px; margin-bottom: 50px; text-align: center; border: 1px solid rgba(255,255,255,0.4); box-shadow: 10px 10px 20px rgba(163, 177, 198, 0.5), -10px -10px 20px rgba(255, 255, 255, 0.8); opacity: 0; transform: translateY(20px); }\n  .spectre-prep.is-visible { animation: fadeUp 0.8s ease forwards; }\n  .spectre-prep-title { font-family: 'Orbitron', sans-serif; font-size: clamp(22px, 4vw, 32px); font-weight: 800; color: #eab308; margin: 0 0 20px 0; text-transform: uppercase; letter-spacing: 2px; }\n  .spectre-prep-text { font-size: 16px; line-height: 1.7; max-width: 800px; margin: 0 auto; color: #4a5568; }\n\n  .spectre-grid-list { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 16px; margin-top: 30px; }\n  .spectre-tag { background: #e0e5ec; padding: 12px 16px; border-radius: 12px; font-family: 'Orbitron', sans-serif; font-size: 13px; font-weight: 600; color: #2d3748; box-shadow: 4px 4px 8px rgba(163, 177, 198, 0.5), -4px -4px 8px rgba(255, 255, 255, 0.8); }\n\n  @keyframes fadeUp { to { opacity: 1; transform: translateY(0); } }\n\n  @media (max-width: 768px) {\n    .spectre-banner { padding: 30px 20px; border-radius: 24px; }\n    .spectre-prep { padding: 40px 20px; border-radius: 24px; }\n  }\n\u003c\/style\u003e\n\n\u003cdiv class=\"spectre-desc\"\u003e\n  \n  \u003c!-- HERO INTRO --\u003e\n  \u003cdiv class=\"spectre-hero\"\u003e\n    \u003cp class=\"spectre-subtitle\"\u003eThe Ultimate Tactical Device\u003c\/p\u003e\n    \u003ch1 class=\"spectre-title\"\u003eSGP Spectre\u003c\/h1\u003e\n    \u003cp class=\"spectre-intro\"\u003e\n      Engineered for extreme environments and advanced operations, the SGP Spectre is a true 007-style multi-tool designed to go with you to the end of the world. Whether you are deeply off-grid or in the heart of the city, this device provides unparalleled connectivity, tracking, and signal analysis in the palm of your hand.\n    \u003c\/p\u003e\n  \u003c\/div\u003e\n\n  \u003c!-- PANTALLA TÁCTIL SIMULADA --\u003e\n  \u003cdiv class=\"spectre-device-wrapper\" id=\"spectre-screen\"\u003e\n    \u003cdiv class=\"spectre-device-casing\"\u003e\n      \u003cdiv class=\"spectre-device-bezel\"\u003e\n        \u003cdiv class=\"spectre-screen\"\u003e\n          \n          \u003c!-- Barra de estado --\u003e\n          \u003cdiv class=\"spectre-status-bar\"\u003e\n            \u003cspan class=\"time\"\u003e14:00\u003c\/span\u003e\n            \u003cdiv class=\"spectre-status-icons\"\u003e\n              \u003cspan style=\"color: #cbd5e1;\"\u003e⚲\u003c\/span\u003e\n              \u003cspan\u003e📶\u003c\/span\u003e\n              \u003cspan\u003e🔋98%\u003c\/span\u003e\n            \u003c\/div\u003e\n          \u003c\/div\u003e\n\n          \u003c!-- Contenedor Principal de Vistas --\u003e\n          \u003cdiv class=\"spectre-view-container\"\u003e\n            \n            \u003c!-- VISTA: HOME (Apps Grid) --\u003e\n            \u003cdiv id=\"view-home\" class=\"spectre-view active\"\u003e\n              \u003cdiv class=\"spectre-app\" onclick=\"openApp('gnss')\"\u003e\n                \u003cdiv class=\"app-icon has-badge\"\u003e🛰️\u003c\/div\u003e\n                \u003cspan class=\"app-name\"\u003eGNSS\u003c\/span\u003e\n              \u003c\/div\u003e\n              \u003cdiv class=\"spectre-app\" onclick=\"openApp('lora')\"\u003e\n                \u003cdiv class=\"app-icon\"\u003e📡\u003c\/div\u003e\n                \u003cspan class=\"app-name\"\u003eLoRa\u003c\/span\u003e\n              \u003c\/div\u003e\n              \u003cdiv class=\"spectre-app\" onclick=\"openApp('wifi')\"\u003e\n                \u003cdiv class=\"app-icon\"\u003e🛜\u003c\/div\u003e\n                \u003cspan class=\"app-name\"\u003eWi-Fi CSI\u003c\/span\u003e\n              \u003c\/div\u003e\n              \u003cdiv class=\"spectre-app\" onclick=\"openApp('cellular')\"\u003e\n                \u003cdiv class=\"app-icon\"\u003e🌍\u003c\/div\u003e\n                \u003cspan class=\"app-name\"\u003eCellular\u003c\/span\u003e\n              \u003c\/div\u003e\n              \u003cdiv class=\"spectre-app\" onclick=\"openApp('terminal')\"\u003e\n                \u003cdiv class=\"app-icon\" style=\"color: #4ade80;\"\u003e\u0026gt;_\u003c\/div\u003e\n                \u003cspan class=\"app-name\"\u003eTerminal\u003c\/span\u003e\n              \u003c\/div\u003e\n              \u003cdiv class=\"spectre-app\" onclick=\"openApp('chat')\"\u003e\n                \u003cdiv class=\"app-icon\" style=\"color: #38bdf8;\"\u003e💬\u003c\/div\u003e\n                \u003cspan class=\"app-name\"\u003eP2P Chat\u003c\/span\u003e\n              \u003c\/div\u003e\n              \u003cdiv class=\"spectre-app\" onclick=\"openApp('signal')\"\u003e\n                \u003cdiv class=\"app-icon\" style=\"color: #ef4444;\"\u003e📡\u003c\/div\u003e\n                \u003cspan class=\"app-name\"\u003eSignal Suite\u003c\/span\u003e\n              \u003c\/div\u003e\n              \u003cdiv class=\"spectre-app\" onclick=\"openApp('game')\"\u003e\n                \u003cdiv class=\"app-icon\" style=\"color: #a855f7;\"\u003e👾\u003c\/div\u003e\n                \u003cspan class=\"app-name\"\u003eSnake\u003c\/span\u003e\n              \u003c\/div\u003e\n              \u003cdiv class=\"spectre-app\" onclick=\"openApp('settings')\"\u003e\n                \u003cdiv class=\"app-icon\" style=\"color: #cbd5e1;\"\u003e⚙️\u003c\/div\u003e\n                \u003cspan class=\"app-name\"\u003eSettings\u003c\/span\u003e\n              \u003c\/div\u003e\n              \n              \u003c!-- NUEVAS APPS --\u003e\n              \u003cdiv class=\"spectre-app\" onclick=\"openApp('rfradar')\"\u003e\n                \u003cdiv class=\"app-icon\" style=\"color: #f97316;\"\u003e🎯\u003c\/div\u003e\n                \u003cspan class=\"app-name\"\u003eRF Radar\u003c\/span\u003e\n              \u003c\/div\u003e\n              \u003cdiv class=\"spectre-app\" onclick=\"openApp('music')\"\u003e\n                \u003cdiv class=\"app-icon\" style=\"color: #fb7185;\"\u003e🎵\u003c\/div\u003e\n                \u003cspan class=\"app-name\"\u003eMedia\u003c\/span\u003e\n              \u003c\/div\u003e\n              \u003cdiv class=\"spectre-app\" onclick=\"openApp('sdcard')\"\u003e\n                \u003cdiv class=\"app-icon\" style=\"color: #fbbf24;\"\u003e💾\u003c\/div\u003e\n                \u003cspan class=\"app-name\"\u003eSD Card\u003c\/span\u003e\n              \u003c\/div\u003e\n              \u003cdiv class=\"spectre-app\" onclick=\"openApp('usbotg')\"\u003e\n                \u003cdiv class=\"app-icon\" style=\"color: #0ea5e9;\"\u003e🔌\u003c\/div\u003e\n                \u003cspan class=\"app-name\"\u003eUSB OTG\u003c\/span\u003e\n              \u003c\/div\u003e\n            \u003c\/div\u003e\n\n            \u003c!-- VISTA: GNSS --\u003e\n            \u003cdiv id=\"view-gnss\" class=\"spectre-view\"\u003e\n              \u003cdiv class=\"app-header\"\u003eGNSS TRACKER\u003c\/div\u003e\n              \u003cdiv class=\"radar-container\" id=\"radar-box\"\u003e\n                \u003cdiv class=\"radar-grid\"\u003e\u003c\/div\u003e\n                \u003cdiv class=\"radar-sweep\"\u003e\u003c\/div\u003e\n              \u003c\/div\u003e\n              \u003cdiv class=\"gnss-data\" id=\"gnss-coords\"\u003e\n                STATUS: SEARCHING...\u003cbr\u003e\n                LAT: --.----\u003cbr\u003e\n                LON: --.----\u003cbr\u003e\n                SATS: 0\n              \u003c\/div\u003e\n            \u003c\/div\u003e\n\n            \u003c!-- VISTA: LoRa --\u003e\n            \u003cdiv id=\"view-lora\" class=\"spectre-view\"\u003e\n              \u003cdiv class=\"app-header\"\u003eLORA COMMS\u003c\/div\u003e\n              \u003cdiv class=\"lora-console\" id=\"lora-log\"\u003e\n                \u003cdiv class=\"lora-line\"\u003eInit LoRa Module... OK\u003c\/div\u003e\n                \u003cdiv class=\"lora-line\"\u003eBand: 868 MHz \/ 915 MHz\u003c\/div\u003e\n                \u003cdiv class=\"lora-line\"\u003eListening for beacons...\u003c\/div\u003e\n              \u003c\/div\u003e\n            \u003c\/div\u003e\n\n            \u003c!-- VISTA: Wi-Fi CSI --\u003e\n            \u003cdiv id=\"view-wifi\" class=\"spectre-view\"\u003e\n              \u003cdiv class=\"app-header\"\u003eWI-FI CSI ANALYSIS\u003c\/div\u003e\n              \u003ccanvas id=\"wifi-canvas\"\u003e\u003c\/canvas\u003e\n              \u003cdiv class=\"wifi-networks\"\u003e\n                \u003cdiv class=\"wifi-net\"\u003e\n\u003cstrong\u003eSGP_SECURE_5G\u003c\/strong\u003e \u003cspan\u003e-42 dBm\u003c\/span\u003e\n\u003c\/div\u003e\n                \u003cdiv class=\"wifi-net\"\u003e\n\u003cstrong\u003eHidden_Network\u003c\/strong\u003e \u003cspan\u003e-68 dBm\u003c\/span\u003e\n\u003c\/div\u003e\n                \u003cdiv class=\"wifi-net\"\u003e\n\u003cstrong\u003eGUEST_WIFI\u003c\/strong\u003e \u003cspan\u003e-85 dBm\u003c\/span\u003e\n\u003c\/div\u003e\n              \u003c\/div\u003e\n            \u003c\/div\u003e\n\n            \u003c!-- VISTA: Cellular --\u003e\n            \u003cdiv id=\"view-cellular\" class=\"spectre-view\"\u003e\n              \u003cdiv class=\"app-header\"\u003eGLOBAL CELLULAR\u003c\/div\u003e\n              \u003cdiv id=\"cellular-globe-container\"\u003e\u003c\/div\u003e\n              \u003cdiv class=\"cell-info\"\u003e\n                \u003cdiv\u003eNETWORK: \u003cspan style=\"color:#fff;\"\u003eSGP TACTICAL\u003c\/span\u003e\n\u003c\/div\u003e\n                \u003cdiv\u003eBAND: \u003cspan style=\"color:#fff;\"\u003eLTE-B7 (2600MHz)\u003c\/span\u003e\n\u003c\/div\u003e\n                \u003cdiv\u003eSECURE TUNNEL: \u003cspan style=\"color:#22c55e;\"\u003eESTABLISHED\u003c\/span\u003e\n\u003c\/div\u003e\n              \u003c\/div\u003e\n            \u003c\/div\u003e\n\n            \u003c!-- VISTA: Terminal --\u003e\n            \u003cdiv id=\"view-terminal\" class=\"spectre-view\"\u003e\n              \u003cdiv class=\"app-header\"\u003eROOT TERMINAL\u003c\/div\u003e\n              \u003cdiv class=\"terminal-view\" id=\"terminal-log\"\u003e\n                \u003cdiv class=\"term-line\"\u003e\u003cspan class=\"term-cursor\"\u003e\u003c\/span\u003e\u003c\/div\u003e\n              \u003c\/div\u003e\n            \u003c\/div\u003e\n\n            \u003c!-- VISTA: Settings --\u003e\n            \u003cdiv id=\"view-settings\" class=\"spectre-view\"\u003e\n              \u003cdiv class=\"app-header\"\u003eSYSTEM CONFIG\u003c\/div\u003e\n              \u003cdiv class=\"settings-list\"\u003e\n                \u003cdiv class=\"setting-item\"\u003e\n                  \u003cspan\u003eBluetooth LE\u003c\/span\u003e\n                  \u003cdiv class=\"toggle on\" onclick=\"this.classList.toggle('on')\"\u003e\u003c\/div\u003e\n                \u003c\/div\u003e\n                \u003cdiv class=\"setting-item\"\u003e\n                  \u003cspan\u003eEco Mode\u003c\/span\u003e\n                  \u003cdiv class=\"toggle\" onclick=\"this.classList.toggle('on')\"\u003e\u003c\/div\u003e\n                \u003c\/div\u003e\n                \u003cdiv class=\"setting-item\"\u003e\n                  \u003cspan\u003eBuzzer Audio\u003c\/span\u003e\n                  \u003cdiv class=\"toggle on\" onclick=\"this.classList.toggle('on')\"\u003e\u003c\/div\u003e\n                \u003c\/div\u003e\n                \u003cdiv class=\"setting-item\" style=\"margin-top: 20px; justify-content:center;\"\u003e\n                  \u003cbutton style=\"background:#eab308; border:none; padding:8px 16px; border-radius:8px; font-family:'Orbitron'; font-weight:bold; cursor:pointer;\"\u003eUPDATE FIRMWARE\u003c\/button\u003e\n                \u003c\/div\u003e\n              \u003c\/div\u003e\n            \u003c\/div\u003e\n\n            \u003c!-- VISTA: LoRa Chat --\u003e\n            \u003cdiv id=\"view-chat\" class=\"spectre-view\"\u003e\n              \u003cdiv class=\"app-header\" style=\"color: #38bdf8; border-color: rgba(56, 189, 248, 0.3);\"\u003eENCRYPTED P2P CHAT\u003c\/div\u003e\n              \u003cdiv id=\"chat-messages\" style=\"flex:1; overflow-y:auto; margin-bottom:10px; scrollbar-width: none;\"\u003e\n                \u003cdiv class=\"chat-msg rx\"\u003eConnection established. AES-256 enabled.\u003c\/div\u003e\n              \u003c\/div\u003e\n              \u003cdiv style=\"display:flex; gap:6px;\"\u003e\n                \u003cinput type=\"text\" id=\"chat-input\" style=\"flex:1; background:#1e293b; border:1px solid #334155; color:#fff; border-radius:6px; padding:6px 10px; font-size:12px; outline:none;\" placeholder=\"Type \/msg...\" onkeypress=\"if(event.key === 'Enter') sendChat()\"\u003e\n                \u003cbutton onclick=\"sendChat()\" style=\"background:#38bdf8; color:#000; border:none; border-radius:6px; padding:0 12px; font-weight:bold; cursor:pointer;\"\u003eTX\u003c\/button\u003e\n              \u003c\/div\u003e\n            \u003c\/div\u003e\n\n            \u003c!-- VISTA: Signal Suite --\u003e\n            \u003cdiv id=\"view-signal\" class=\"spectre-view\"\u003e\n              \u003cdiv class=\"app-header\" style=\"color: #ef4444; border-color: rgba(239, 68, 68, 0.3);\"\u003eSIGNAL SCANNER\u003c\/div\u003e\n              \u003cdiv class=\"signal-console\" id=\"signal-log\"\u003e\n                 \u003cdiv\u003eAwaiting command...\u003c\/div\u003e\n              \u003c\/div\u003e\n              \u003cdiv style=\"margin-top: 12px; display:flex; gap:8px;\"\u003e\n                \u003cbutton onclick=\"runSignalAction('scan')\" style=\"flex:1; background:#1e293b; color:#ef4444; border:1px solid #ef4444; padding:8px; border-radius:6px; font-family:'Orbitron'; font-size:10px; cursor:pointer;\"\u003eNET SCAN\u003c\/button\u003e\n                \u003cbutton onclick=\"runSignalAction('analyze')\" style=\"flex:1; background:#ef4444; color:#fff; border:none; padding:8px; border-radius:6px; font-family:'Orbitron'; font-weight:bold; font-size:10px; cursor:pointer;\"\u003eSEND\u003c\/button\u003e\n              \u003c\/div\u003e\n            \u003c\/div\u003e\n\n            \u003c!-- VISTA: Game (Snake) --\u003e\n            \u003cdiv id=\"view-game\" class=\"spectre-view\"\u003e\n              \u003cdiv class=\"app-header\" style=\"color: #a855f7; border-color: rgba(168, 85, 247, 0.3);\"\u003eSNAKE.EXE\u003c\/div\u003e\n              \u003ccanvas id=\"snake-canvas\" width=\"220\" height=\"180\" style=\"background:#0f172a; border:2px solid #334155; border-radius:8px; margin:0 auto; display:block; box-shadow: inset 0 0 10px #000;\"\u003e\u003c\/canvas\u003e\n              \n              \u003cdiv class=\"d-pad\"\u003e\n                \u003cdiv\u003e\u003c\/div\u003e\n                \u003cbutton onclick=\"changeSnakeDir(0,-1)\"\u003e\u003csvg width=\"16\" height=\"16\" viewbox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\u003e\u003cpath d=\"m18 15-6-6-6 6\"\u003e\u003c\/path\u003e\u003c\/svg\u003e\u003c\/button\u003e\n                \u003cdiv\u003e\u003c\/div\u003e\n                \u003cbutton onclick=\"changeSnakeDir(-1,0)\"\u003e\u003csvg width=\"16\" height=\"16\" viewbox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\u003e\u003cpath d=\"m15 18-6-6 6-6\"\u003e\u003c\/path\u003e\u003c\/svg\u003e\u003c\/button\u003e\n                \u003cbutton onclick=\"initSnakeGame()\" style=\"background:#334155; color:#cbd5e1; font-size:10px;\"\u003eRST\u003c\/button\u003e\n                \u003cbutton onclick=\"changeSnakeDir(1,0)\"\u003e\u003csvg width=\"16\" height=\"16\" viewbox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\u003e\u003cpath d=\"m9 18 6-6-6-6\"\u003e\u003c\/path\u003e\u003c\/svg\u003e\u003c\/button\u003e\n                \u003cdiv\u003e\u003c\/div\u003e\n                \u003cbutton onclick=\"changeSnakeDir(0,1)\"\u003e\u003csvg width=\"16\" height=\"16\" viewbox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\u003e\u003cpath d=\"m6 9 6 6 6-6\"\u003e\u003c\/path\u003e\u003c\/svg\u003e\u003c\/button\u003e\n                \u003cdiv\u003e\u003c\/div\u003e\n              \u003c\/div\u003e\n            \u003c\/div\u003e\n\n            \u003c!-- VISTA: RF Radar --\u003e\n            \u003cdiv id=\"view-rfradar\" class=\"spectre-view\"\u003e\n              \u003cdiv class=\"app-header\" style=\"color:#f97316; border-color:rgba(249,115,22,0.3);\"\u003eRF SPECTRUM RADAR\u003c\/div\u003e\n              \u003cdiv class=\"rf-radar-container\" id=\"rf-radar-box\"\u003e\n                \u003cdiv class=\"radar-grid\" style=\"background-image: linear-gradient(#f97316 1px, transparent 1px), linear-gradient(90deg, #f97316 1px, transparent 1px);\"\u003e\u003c\/div\u003e\n                \u003cdiv class=\"rf-sweep\"\u003e\u003c\/div\u003e\n              \u003c\/div\u003e\n              \u003cdiv class=\"gnss-data\" style=\"color:#f97316; text-align:center;\"\u003e\n                FREQ: 2.4GHz \/ 5.8GHz\u003cbr\u003e\n                SCANNING FOR ANOMALIES...\n              \u003c\/div\u003e\n            \u003c\/div\u003e\n\n            \u003c!-- VISTA: Music Player --\u003e\n            \u003cdiv id=\"view-music\" class=\"spectre-view\"\u003e\n              \u003cdiv class=\"app-header\" style=\"color:#fb7185; border-color:rgba(251,113,133,0.3);\"\u003eMEDIA PLAYER\u003c\/div\u003e\n              \u003cdiv class=\"music-player\"\u003e\n                \u003cdiv class=\"music-cover\"\u003e🎧\u003c\/div\u003e\n                \u003cdiv class=\"music-title\"\u003eTactical_Vibes.mp3\u003c\/div\u003e\n                \u003cdiv class=\"music-artist\"\u003eSGP Internal Storage\u003c\/div\u003e\n                \n                \u003cdiv class=\"music-controls\"\u003e\n                  \u003cbutton class=\"music-btn\" onclick=\"toggleMusic(false)\"\u003e⏮\u003c\/button\u003e\n                  \u003cbutton class=\"music-btn\" id=\"music-play-btn\" onclick=\"toggleMusic(true)\" style=\"width:50px; height:50px; font-size:20px;\"\u003e▶\u003c\/button\u003e\n                  \u003cbutton class=\"music-btn\" onclick=\"toggleMusic(false)\"\u003e⏭\u003c\/button\u003e\n                \u003c\/div\u003e\n                \n                \u003ccanvas id=\"eq-canvas\"\u003e\u003c\/canvas\u003e\n              \u003c\/div\u003e\n            \u003c\/div\u003e\n\n            \u003c!-- VISTA: SD Card --\u003e\n            \u003cdiv id=\"view-sdcard\" class=\"spectre-view\"\u003e\n              \u003cdiv class=\"app-header\" style=\"color:#fbbf24; border-color:rgba(251,191,36,0.3);\"\u003eSD CARD BROWSER\u003c\/div\u003e\n              \u003cdiv class=\"sd-explorer\" id=\"sd-file-list\"\u003e\n                \u003c!-- Se inyecta por JS --\u003e\n              \u003c\/div\u003e\n              \u003cdiv style=\"margin-top:auto; font-size:10px; color:#94a3b8; text-align:center;\"\u003eCAPACITY: 58GB \/ 64GB\u003c\/div\u003e\n            \u003c\/div\u003e\n\n            \u003c!-- VISTA: USB OTG --\u003e\n            \u003cdiv id=\"view-usbotg\" class=\"spectre-view\"\u003e\n              \u003cdiv class=\"app-header\" style=\"color:#0ea5e9; border-color:rgba(14,165,233,0.3);\"\u003eUSB HOST (OTG)\u003c\/div\u003e\n              \u003cdiv class=\"usb-console\" id=\"usb-log\"\u003e\n                \u003c!-- Se inyecta por JS --\u003e\n              \u003c\/div\u003e\n            \u003c\/div\u003e\n\n          \u003c\/div\u003e \u003c!-- End View Container --\u003e\n\n          \u003c!-- Home Button Bar (siempre visible) --\u003e\n          \u003cdiv class=\"spectre-home-bar\" onclick=\"goHome()\"\u003e\n            \u003cdiv class=\"spectre-home-indicator\"\u003e\u003c\/div\u003e\n          \u003c\/div\u003e\n\n          \u003c!-- Efecto cristal --\u003e\n          \u003cdiv class=\"spectre-screen-glare\"\u003e\u003c\/div\u003e\n\n        \u003c\/div\u003e\n      \u003c\/div\u003e\n    \u003c\/div\u003e\n  \u003c\/div\u003e\n\n  \u003c!-- FEATURES GRID --\u003e\n  \u003cdiv class=\"spectre-features\" id=\"spectre-features\"\u003e\n    \u003cdiv class=\"spectre-card\"\u003e\n      \u003cdiv class=\"spectre-icon\"\u003e🛰️\u003c\/div\u003e\n      \u003ch3 class=\"spectre-card-title\"\u003eHelical GNSS Tracking\u003c\/h3\u003e\n      \u003cp class=\"spectre-card-text\"\u003eEquipped with a high-precision helical antenna. Track your real-time location, detect overhead satellites, and identify their unique registration IDs instantly.\u003c\/p\u003e\n    \u003c\/div\u003e\n    \u003cdiv class=\"spectre-card\"\u003e\n      \u003cdiv class=\"spectre-icon\"\u003e📡\u003c\/div\u003e\n      \u003ch3 class=\"spectre-card-title\"\u003eLong-Range Dual-Band LoRa\u003c\/h3\u003e\n      \u003cp class=\"spectre-card-text\"\u003eStay connected off the grid. Communicate with other devices miles away without needing cellular service or internet access.\u003c\/p\u003e\n    \u003c\/div\u003e\n    \u003cdiv class=\"spectre-card\"\u003e\n      \u003cdiv class=\"spectre-icon\"\u003e📶\u003c\/div\u003e\n      \u003ch3 class=\"spectre-card-title\"\u003eWi-Fi CSI \u0026amp; Dedicated Antenna\u003c\/h3\u003e\n      \u003cp class=\"spectre-card-text\"\u003eAdvanced Channel State Information capabilities. Analyze Wi-Fi signals, map environments, and detect movement using dedicated hardware.\u003c\/p\u003e\n    \u003c\/div\u003e\n    \u003cdiv class=\"spectre-card\"\u003e\n      \u003cdiv class=\"spectre-icon\"\u003e👆\u003c\/div\u003e\n      \u003ch3 class=\"spectre-card-title\"\u003eProgrammable Touch Screen\u003c\/h3\u003e\n      \u003cp class=\"spectre-card-text\"\u003eTotal control at your fingertips. An intuitive, highly responsive, and fully programmable display tailored for rapid field operation.\u003c\/p\u003e\n    \u003c\/div\u003e\n    \u003cdiv class=\"spectre-card\"\u003e\n      \u003cdiv class=\"spectre-icon\"\u003e🌍\u003c\/div\u003e\n      \u003ch3 class=\"spectre-card-title\"\u003eSIM Card Slot \u0026amp; Connectivity\u003c\/h3\u003e\n      \u003cp class=\"spectre-card-text\"\u003eInsert a SIM card for independent internet access. Features integrated Bluetooth, Wi-Fi, and a versatile USB OTG port for endless expansions.\u003c\/p\u003e\n    \u003c\/div\u003e\n    \u003cdiv class=\"spectre-card\"\u003e\n      \u003cdiv class=\"spectre-icon\"\u003e🔋\u003c\/div\u003e\n      \u003ch3 class=\"spectre-card-title\"\u003eEndurance \u0026amp; Power\u003c\/h3\u003e\n      \u003cp class=\"spectre-card-text\"\u003eFitted with a high-capacity battery built to outlast your missions, plus powerful built-in speakers for clear audio alerts and communications.\u003c\/p\u003e\n    \u003c\/div\u003e\n  \u003c\/div\u003e\n\n  \u003c!-- PREPAREDNESS \/ ADVENTURER SECTION --\u003e\n  \u003cdiv class=\"spectre-prep\" id=\"spectre-prep\"\u003e\n    \u003cdiv class=\"spectre-icon\" style=\"margin-bottom: 20px;\"\u003e🏕️\u003c\/div\u003e\n    \u003ch2 class=\"spectre-prep-title\"\u003eBuilt for Adventurers \u0026amp; Enthusiasts\u003c\/h2\u003e\n    \u003cp class=\"spectre-prep-text\"\u003e\n      \u003cstrong\u003ePrepare for the real end of the world.\u003c\/strong\u003e Achieve true autonomy and off-grid readiness with our fully \u003cstrong\u003eprogrammable, open-source\u003c\/strong\u003e device. Whether you are prepping for worst-case scenarios or venturing into the unknown, the Spectre gives you the tools to survive and thrive without relying on conventional infrastructure.\n    \u003c\/p\u003e\n  \u003c\/div\u003e\n\n  \u003c!-- BOTTOM BANNER --\u003e\n  \u003cdiv class=\"spectre-banner\" id=\"spectre-banner\"\u003e\n    \u003ch3 class=\"spectre-banner-title\"\u003eA 007 Gadget In Your Pocket\u003c\/h3\u003e\n    \u003cp style=\"margin:0; font-size: 15px; max-width: 600px; margin: 0 auto;\"\u003e\n      \u003cstrong\u003eThe ultimate tool for professionals.\u003c\/strong\u003e The SGP Spectre isn't just a gadget; it's a completely self-sufficient ecosystem. Scan, track, communicate, and analyze with an arsenal of built-in hardware tailored for advanced operations.\n    \u003c\/p\u003e\n    \u003cdiv class=\"spectre-grid-list\"\u003e\n      \u003cdiv class=\"spectre-tag\"\u003eHelical Antenna\u003c\/div\u003e\n      \u003cdiv class=\"spectre-tag\"\u003eGPS \/ GNSS\u003c\/div\u003e\n      \u003cdiv class=\"spectre-tag\"\u003eDual-Band LoRa\u003c\/div\u003e\n      \u003cdiv class=\"spectre-tag\"\u003eWi-Fi CSI\u003c\/div\u003e\n      \u003cdiv class=\"spectre-tag\"\u003eIMU Sensor\u003c\/div\u003e\n      \u003cdiv class=\"spectre-tag\"\u003eTouch Screen\u003c\/div\u003e\n      \u003cdiv class=\"spectre-tag\"\u003eBuilt-in Speakers\u003c\/div\u003e\n      \u003cdiv class=\"spectre-tag\"\u003eUSB OTG\u003c\/div\u003e\n      \u003cdiv class=\"spectre-tag\"\u003eBluetooth\u003c\/div\u003e\n    \u003c\/div\u003e\n  \u003c\/div\u003e\n\n\u003c\/div\u003e\n\n\u003cscript\u003e\n  \/\/ --- VARIABLES GLOBALES DEL SIMULADOR TÁCTICO ---\n  let termInterval, gnssInterval, chatInterval, signalInterval, snakeInterval, rfInterval, usbInterval, sdInterval;\n  let wifiAnimFrame, musicAnimFrame, musicTimeout;\n  let isMusicPlaying = false;\n  let phoneGlobeInitialized = false;\n\n  \/\/ IMPORTANTE: Función maestra para matar todos los procesos en 2º plano y evitar bloqueos.\n  function clearAllApps() {\n    if(termInterval) clearInterval(termInterval);\n    if(gnssInterval) clearInterval(gnssInterval);\n    if(chatInterval) clearInterval(chatInterval);\n    if(signalInterval) clearInterval(signalInterval);\n    if(snakeInterval) clearInterval(snakeInterval);\n    if(rfInterval) clearInterval(rfInterval);\n    if(usbInterval) clearInterval(usbInterval);\n    if(sdInterval) clearInterval(sdInterval);\n    \n    if(wifiAnimFrame) cancelAnimationFrame(wifiAnimFrame);\n    if(musicAnimFrame) cancelAnimationFrame(musicAnimFrame);\n    if(musicTimeout) clearTimeout(musicTimeout);\n  }\n\n  \/\/ --- NAVEGACIÓN DEL SISTEMA OPERATIVO SIMULADO ---\n  function openApp(appId) {\n    \/\/ 1. Matar procesos anteriores para no saturar CPU\n    clearAllApps();\n    \n    \/\/ 2. Ocultar todas las vistas\n    document.querySelectorAll('.spectre-view').forEach(view =\u003e {\n      view.classList.remove('active');\n    });\n    \n    \/\/ 3. Mostrar la solicitada y ejecutar lógica\n    const target = document.getElementById('view-' + appId);\n    if(target) {\n      target.classList.add('active');\n      \n      if(appId === 'terminal') startTerminal();\n      if(appId === 'wifi') initWifiCanvas();\n      if(appId === 'cellular') initCellularGlobe();\n      if(appId === 'gnss') updateGNSS();\n      if(appId === 'chat') initChat();\n      if(appId === 'game') initSnakeGame();\n      if(appId === 'signal') document.getElementById('signal-log').innerHTML = '\u003cdiv\u003eAwaiting command...\u003c\/div\u003e';\n      \n      if(appId === 'rfradar') initRFRadar();\n      if(appId === 'music') initMusicUI();\n      if(appId === 'sdcard') initSDCard();\n      if(appId === 'usbotg') initUSBOTG();\n    }\n  }\n\n  function goHome() {\n    \/\/ Limpiar TODO para evitar que el navegador se bloquee\n    clearAllApps();\n    \n    document.querySelectorAll('.spectre-view').forEach(view =\u003e {\n      view.classList.remove('active');\n    });\n    document.getElementById('view-home').classList.add('active');\n  }\n\n  \/\/ --- LÓGICA DE APLICACIONES INDIVIDUALES ---\n\n  \/\/ 1. GNSS Radar\n  function updateGNSS() {\n    const coordsBox = document.getElementById('gnss-coords');\n    const radarBox = document.getElementById('radar-box');\n    \n    radarBox.querySelectorAll('.sat-dot').forEach(e =\u003e e.remove());\n\n    let lat = 40.0000;\n    let lon = -3.0000;\n    let sats = 0;\n\n    gnssInterval = setInterval(() =\u003e {\n      if(sats \u003c 12 \u0026\u0026 Math.random() \u003e 0.5) {\n        sats++;\n        lat += (Math.random() - 0.5) * 0.001;\n        lon += (Math.random() - 0.5) * 0.001;\n        \n        const dot = document.createElement('div');\n        dot.className = 'sat-dot';\n        dot.style.left = (20 + Math.random() * 150) + 'px';\n        dot.style.top = (20 + Math.random() * 150) + 'px';\n        dot.style.opacity = '1';\n        radarBox.appendChild(dot);\n      }\n      \n      coordsBox.innerHTML = `\n        STATUS: ${sats \u003e 3 ? '\u003cspan style=\"color:#fff;\"\u003e3D FIX OK\u003c\/span\u003e' : 'ACQUIRING...'} \u003cbr\u003e\n        LAT: ${lat.toFixed(5)} N \u003cbr\u003e\n        LON: ${Math.abs(lon).toFixed(5)} W \u003cbr\u003e\n        SATS: ${sats}\n      `;\n    }, 1000);\n  }\n\n  \/\/ 2. LoRa Logs (Global Interval solo si está activo)\n  setInterval(() =\u003e {\n    const log = document.getElementById('lora-log');\n    if(!log || !document.getElementById('view-lora').classList.contains('active')) return;\n    if(log.children.length \u003e 8) log.removeChild(log.firstChild);\n    \n    const line = document.createElement('div');\n    line.className = 'lora-line ' + (Math.random() \u003e 0.5 ? 'tx' : 'rx');\n    if(line.classList.contains('tx')) {\n      line.innerText = `[${new Date().getSeconds()}] TX -\u003e PING NODE_${Math.floor(Math.random()*100)}`;\n    } else {\n      line.innerText = `[${new Date().getSeconds()}] RX \u003c- ACK (-${90 + Math.floor(Math.random()*30)} dBm)`;\n    }\n    log.appendChild(line);\n  }, 2500);\n\n  \/\/ 3. Wi-Fi CSI Canvas\n  function initWifiCanvas() {\n    const canvas = document.getElementById('wifi-canvas');\n    if(!canvas) return;\n    const ctx = canvas.getContext('2d');\n    canvas.width = canvas.parentElement.clientWidth - 32;\n    canvas.height = 150;\n    \n    let time = 0;\n    function drawWave() {\n      if(!document.getElementById('view-wifi').classList.contains('active')) return;\n      \n      ctx.fillStyle = '#000';\n      ctx.fillRect(0, 0, canvas.width, canvas.height);\n      \n      ctx.beginPath();\n      ctx.lineWidth = 2;\n      ctx.strokeStyle = '#22c55e';\n      \n      for(let x = 0; x \u003c canvas.width; x++) {\n        const y = Math.sin(x * 0.05 + time) * 30 + \n                  Math.sin(x * 0.1 + time*1.5) * 15 + \n                  (Math.random() * 10 - 5) + \n                  canvas.height \/ 2;\n        \n        if(x === 0) ctx.moveTo(x, y);\n        else ctx.lineTo(x, y);\n      }\n      ctx.stroke();\n      \n      time += 0.1;\n      wifiAnimFrame = requestAnimationFrame(drawWave);\n    }\n    drawWave();\n  }\n\n  \/\/ 4. Cellular Globe\n  function initCellularGlobe() {\n    if(phoneGlobeInitialized) return;\n    const container = document.getElementById('cellular-globe-container');\n    if(!container || typeof THREE === 'undefined') return;\n    phoneGlobeInitialized = true;\n\n    const scene = new THREE.Scene();\n    const camera = new THREE.PerspectiveCamera(45, container.clientWidth \/ container.clientHeight, 0.1, 100);\n    camera.position.z = 2.2;\n\n    const renderer = new THREE.WebGLRenderer({ alpha: true, antialias: true });\n    renderer.setSize(container.clientWidth, container.clientHeight);\n    container.appendChild(renderer.domElement);\n\n    const globeGroup = new THREE.Group();\n    scene.add(globeGroup);\n\n    fetch('https:\/\/unpkg.com\/world-atlas@2.0.2\/countries-110m.json')\n      .then(res =\u003e res.json())\n      .then(world =\u003e {\n          const w = 1024, h = 512;\n          const canvas = document.createElement('canvas');\n          canvas.width = w; canvas.height = h;\n          const ctx = canvas.getContext('2d');\n          \n          const countries = topojson.feature(world, world.objects.countries);\n          const projection = d3.geoEquirectangular().translate([w\/2, h\/2]).scale(w \/ (2 * Math.PI));\n          const path = d3.geoPath(projection, ctx);\n          \n          ctx.fillStyle = '#0f172a'; ctx.fillRect(0, 0, w, h);\n          ctx.fillStyle = '#eab308'; ctx.strokeStyle = '#000'; ctx.lineWidth = 1;\n          ctx.beginPath(); path(countries); ctx.fill(); ctx.stroke();\n\n          ctx.fillStyle = '#fff';\n          for(let i=0; i\u003c30; i++) {\n            ctx.beginPath(); ctx.arc(Math.random() * w, Math.random() * h, 3, 0, Math.PI*2); ctx.fill();\n          }\n          \n          const texture = new THREE.CanvasTexture(canvas);\n          const sphereGeo = new THREE.SphereGeometry(1, 32, 32);\n          const sphereMat = new THREE.MeshBasicMaterial({ map: texture });\n          const globe = new THREE.Mesh(sphereGeo, sphereMat);\n          globeGroup.add(globe);\n          \n          const ringGeo = new THREE.RingGeometry(1.2, 1.22, 64);\n          const ringMat = new THREE.MeshBasicMaterial({ color: 0x22c55e, side: THREE.DoubleSide, transparent:true, opacity:0.5 });\n          const ring = new THREE.Mesh(ringGeo, ringMat);\n          ring.rotation.x = Math.PI \/ 2;\n          globeGroup.add(ring);\n      });\n\n    const animate = () =\u003e {\n      requestAnimationFrame(animate);\n      if(document.getElementById('view-cellular').classList.contains('active')) {\n        globeGroup.rotation.y += 0.005;\n        globeGroup.rotation.x = 0.2; \n        renderer.render(scene, camera);\n      }\n    };\n    animate();\n  }\n\n  \/\/ 5. Terminal Demo Simulator\n  const lines = [\n    \"root@spectre:~# init --tactical\",\n    \"[ OK ] Booting secure kernel...\",\n    \"[ OK ] Mounting encrypted volume...\",\n    \"[INFO] Scanning local networks...\",\n    \"Found 3 BSSIDs in range.\",\n    \"[WARN] Anomalous RF detected on 433MHz\",\n    \"root@spectre:~# run_diagnostic -t 192.168.1.1\",\n    \"Loading modules [||||||||||] 100%\",\n    \"Connection READY.\",\n    \"Optimizing routing rules...\",\n    \"Establishing secure tunnel...\",\n    \"root@spectre:~# _\"\n  ];\n\n  function startTerminal() {\n    const term = document.getElementById('terminal-log');\n    term.innerHTML = '\u003cdiv class=\"term-line\"\u003e\u003cspan class=\"term-cursor\"\u003e\u003c\/span\u003e\u003c\/div\u003e';\n    let termLineIdx = 0;\n\n    termInterval = setInterval(() =\u003e {\n      if(termLineIdx \u003c lines.length) {\n        const cursor = term.querySelector('.term-cursor');\n        if(cursor) cursor.remove();\n\n        const newLine = document.createElement('div');\n        newLine.className = 'term-line';\n        newLine.innerText = lines[termLineIdx];\n        term.appendChild(newLine);\n        \n        const newCursor = document.createElement('span');\n        newCursor.className = 'term-cursor';\n        term.appendChild(newCursor);\n\n        termLineIdx++;\n      } else {\n        clearInterval(termInterval);\n      }\n    }, 800);\n  }\n\n  \/\/ 6. LoRa P2P Chat\n  function initChat() {\n    const box = document.getElementById('chat-messages');\n    const fakeReplies = [\n      \"Node_Beta: Sector 4 is clear.\",\n      \"Ghost_01: Acknowledged.\",\n      \"Base: Weather incoming, secure perimeter.\",\n      \"Node_Beta: RF interference detected on 433MHz.\",\n      \"Ghost_01: Moving to extraction point.\"\n    ];\n\n    chatInterval = setInterval(() =\u003e {\n      if(Math.random() \u003e 0.6) {\n        const msg = document.createElement('div');\n        msg.className = 'chat-msg rx';\n        msg.innerText = fakeReplies[Math.floor(Math.random() * fakeReplies.length)];\n        box.appendChild(msg);\n        box.scrollTop = box.scrollHeight;\n      }\n    }, 4000);\n  }\n\n  function sendChat() {\n    const input = document.getElementById('chat-input');\n    const box = document.getElementById('chat-messages');\n    if(input.value.trim() === '') return;\n    \n    const msg = document.createElement('div');\n    msg.className = 'chat-msg tx';\n    msg.innerText = input.value;\n    box.appendChild(msg);\n    box.scrollTop = box.scrollHeight;\n    input.value = '';\n    \n    setTimeout(() =\u003e {\n       const reply = document.createElement('div');\n       reply.className = 'chat-msg rx';\n       reply.innerText = \"Ghost_01: Copy that.\";\n       box.appendChild(reply);\n       box.scrollTop = box.scrollHeight;\n    }, 1500);\n  }\n\n  \/\/ 7. Signal Suite Scanner\n  function runSignalAction(type) {\n    clearInterval(signalInterval);\n    const log = document.getElementById('signal-log');\n    log.innerHTML = '';\n    \n    let count = 0;\n    if(type === 'scan') {\n      signalInterval = setInterval(() =\u003e {\n        const line = document.createElement('div');\n        const mac = \"00:\" + Math.floor(Math.random()*99) + \":XX:XX:XX:XX\";\n        line.innerText = `[+] Target found: ${mac} - RSSI: -${Math.floor(Math.random()*40 + 50)}dBm`;\n        log.appendChild(line);\n        if(log.children.length \u003e 8) log.removeChild(log.firstChild);\n        count++;\n        if(count \u003e 15) { clearInterval(signalInterval); log.innerHTML += '\u003cdiv style=\"color:#22c55e\"\u003eScan Complete.\u003c\/div\u003e'; }\n      }, 300);\n    } else {\n      signalInterval = setInterval(() =\u003e {\n        const line = document.createElement('div');\n        line.innerHTML = `[TX] Sending Beacon Packets -\u003e \u003cspan style=\"color:#fff\"\u003eTest_AP\u003c\/span\u003e [CH ${Math.floor(Math.random()*11 + 1)}]`;\n        log.appendChild(line);\n        if(log.children.length \u003e 8) log.removeChild(log.firstChild);\n      }, 100);\n    }\n  }\n\n  \/\/ 8. Snake Game\n  let snake = [{x: 10, y: 10}];\n  let dir = {x: 1, y: 0};\n  let food = {x: 5, y: 5};\n  \n  function initSnakeGame() {\n    const canvas = document.getElementById('snake-canvas');\n    if(!canvas) return;\n    const ctx = canvas.getContext('2d');\n    \n    snake = [{x: 10, y: 10}];\n    dir = {x: 1, y: 0};\n    placeFood();\n    \n    snakeInterval = setInterval(() =\u003e {\n      let head = {x: snake[0].x + dir.x, y: snake[0].y + dir.y};\n      \n      if(head.x \u003e= 22) head.x = 0; if(head.x \u003c 0) head.x = 21;\n      if(head.y \u003e= 18) head.y = 0; if(head.y \u003c 0) head.y = 17;\n      \n      snake.unshift(head);\n      \n      if(head.x === food.x \u0026\u0026 head.y === food.y) {\n        placeFood(); \n      } else {\n        snake.pop(); \n      }\n      \n      ctx.fillStyle = '#0f172a'; ctx.fillRect(0, 0, canvas.width, canvas.height);\n      ctx.fillStyle = '#ef4444'; ctx.fillRect(food.x * 10, food.y * 10, 9, 9);\n      ctx.fillStyle = '#a855f7'; snake.forEach(s =\u003e ctx.fillRect(s.x * 10, s.y * 10, 9, 9));\n      \n    }, 120);\n  }\n\n  function placeFood() { food = {x: Math.floor(Math.random()*21), y: Math.floor(Math.random()*17)}; }\n  function changeSnakeDir(x, y) { \n    if(snake.length \u003e 1 \u0026\u0026 dir.x === -x \u0026\u0026 dir.y === -y) return;\n    dir = {x, y}; \n  }\n\n  \/\/ 9. RF Radar\n  function initRFRadar() {\n    const radarBox = document.getElementById('rf-radar-box');\n    radarBox.querySelectorAll('.rf-dot').forEach(e =\u003e e.remove());\n\n    rfInterval = setInterval(() =\u003e {\n      if(Math.random() \u003e 0.4) {\n        const dot = document.createElement('div');\n        dot.className = 'rf-dot';\n        dot.style.left = (20 + Math.random() * 150) + 'px';\n        dot.style.top = (20 + Math.random() * 150) + 'px';\n        radarBox.appendChild(dot);\n        setTimeout(() =\u003e { if(dot.parentElement) dot.remove(); }, 1500);\n      }\n    }, 800);\n  }\n\n  \/\/ 10. Music Player \/ EQ\n  function initMusicUI() {\n    drawEQ();\n  }\n\n  function toggleMusic(playClick) {\n    const btn = document.getElementById('music-play-btn');\n    if(playClick) {\n      isMusicPlaying = !isMusicPlaying;\n    }\n    btn.innerText = isMusicPlaying ? \"⏸\" : \"▶\";\n  }\n\n  function drawEQ() {\n    const canvas = document.getElementById('eq-canvas');\n    if(!canvas) return;\n    const ctx = canvas.getContext('2d');\n    canvas.width = canvas.parentElement.clientWidth;\n    canvas.height = 50;\n\n    function render() {\n      if(!document.getElementById('view-music').classList.contains('active')) return;\n\n      ctx.fillStyle = '#000';\n      ctx.fillRect(0, 0, canvas.width, canvas.height);\n\n      const numBars = Math.floor(canvas.width \/ 8);\n      ctx.fillStyle = '#fb7185';\n\n      for(let i=0; i\u003cnumBars; i++) {\n        let h = 2; \/\/ Reposo\n        if(isMusicPlaying) {\n          h = Math.random() * 40 + 5; \/\/ Bailando\n        }\n        ctx.fillRect(i * 8 + 2, canvas.height - h, 4, h);\n      }\n\n      musicTimeout = setTimeout(() =\u003e { musicAnimFrame = requestAnimationFrame(render); }, 60);\n    }\n    render();\n  }\n\n  \/\/ 11. SD Card Reader\n  function initSDCard() {\n    const list = document.getElementById('sd-file-list');\n    list.innerHTML = '';\n    \n    const files = [\n      { icon: '📁', name: 'logs\/' },\n      { icon: '📁', name: 'modules\/' },\n      { icon: '📁', name: 'music\/' },\n      { icon: '📄', name: 'sys_config.ini' },\n      { icon: '📄', name: 'log_04.txt' },\n      { icon: '📄', name: 'readme.txt' }\n    ];\n\n    let i = 0;\n    sdInterval = setInterval(() =\u003e {\n      if(i \u003c files.length) {\n        const row = document.createElement('div');\n        row.className = 'sd-item';\n        row.innerHTML = `\u003cspan class=\"sd-icon\"\u003e${files[i].icon}\u003c\/span\u003e \u003cspan\u003e${files[i].name}\u003c\/span\u003e`;\n        list.appendChild(row);\n        i++;\n      } else {\n        clearInterval(sdInterval);\n      }\n    }, 150);\n  }\n\n  \/\/ 12. USB OTG\n  function initUSBOTG() {\n    const log = document.getElementById('usb-log');\n    log.innerHTML = '';\n\n    const events = [\n      \"Initializing USB subsystem...\",\n      \"[ OK ] USB Core Loaded\",\n      \"Probing Port 1...\",\n      \"\u003cspan class='usb-success'\u003e[+] Device Found: RTL-SDR v3\u003c\/span\u003e\",\n      \"Probing Port 2...\",\n      \"Port 2 is empty.\",\n      \"Mounting external filesystem...\",\n      \"[ OK ] \/mnt\/usb mapped successfully.\"\n    ];\n\n    let i = 0;\n    usbInterval = setInterval(() =\u003e {\n      if(i \u003c events.length) {\n        const line = document.createElement('div');\n        line.className = 'usb-line';\n        line.innerHTML = events[i];\n        log.appendChild(line);\n        log.scrollTop = log.scrollHeight;\n        i++;\n      } else {\n        clearInterval(usbInterval);\n      }\n    }, 400);\n  }\n\n  \/\/ --- Animaciones Generales de Scroll ---\n  document.addEventListener(\"DOMContentLoaded\", () =\u003e {\n    const cards = document.querySelectorAll('.spectre-card');\n    const elements = [\n      document.getElementById('spectre-banner'),\n      document.getElementById('spectre-prep'),\n      document.getElementById('spectre-screen')\n    ];\n\n    const observer = new IntersectionObserver((entries) =\u003e {\n      entries.forEach((entry, index) =\u003e {\n        if (entry.isIntersecting) {\n          if(entry.target.classList.contains('spectre-card')) {\n             setTimeout(() =\u003e { entry.target.classList.add('is-visible'); }, index * 100); \n          } else {\n             entry.target.classList.add('is-visible');\n          }\n          observer.unobserve(entry.target);\n        }\n      });\n    }, { threshold: 0.1 });\n\n    cards.forEach(card =\u003e observer.observe(card));\n    elements.forEach(el =\u003e { if(el) observer.observe(el); });\n\n    const timeElement = document.querySelector('.spectre-status-bar .time');\n    if(timeElement) {\n      const updateTime = () =\u003e {\n        const now = new Date();\n        timeElement.textContent = now.getHours().toString().padStart(2, '0') + ':' + now.getMinutes().toString().padStart(2, '0');\n      };\n      updateTime();\n      setInterval(updateTime, 60000);\n    }\n  });\n\u003c\/script\u003e\n\n\n\u003c\/body\u003e","brand":"sgpstore","offers":[{"title":"Default Title","offer_id":57731307831628,"sku":null,"price":750.0,"currency_code":"EUR","in_stock":true}],"thumbnail_url":"\/\/cdn.shopify.com\/s\/files\/1\/1057\/9807\/4700\/files\/rn-image_picker_lib_temp_5b755567-e932-4999-afc4-044b0eb8cb0c.png?v=1781652457"},{"product_id":"sgp-watch-1","title":"SGP watch","description":"\u003cbody\u003e\n\n\n    \u003cmeta charset=\"UTF-8\"\u003e\n    \u003cmeta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"\u003e\n    \u003ctitle\u003eSGP WATCH - Diagnostic Hub\u003c\/title\u003e\n    \n    \u003clink rel=\"preconnect\" href=\"https:\/\/fonts.googleapis.com\"\u003e\n    \u003clink rel=\"preconnect\" href=\"https:\/\/fonts.gstatic.com\" crossorigin\u003e\n    \u003clink href=\"https:\/\/fonts.googleapis.com\/css2?family=Inter:wght@400;500;600\u0026amp;family=Space+Grotesk:wght@700;800\u0026amp;family=Share+Tech+Mono\u0026amp;display=swap\" rel=\"stylesheet\"\u003e\n    \n    \u003cscript src=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/tone\/14.8.49\/Tone.js\"\u003e\u003c\/script\u003e\n\n    \u003cstyle\u003e\n        :root {\n            --bg-color: #e0e5ec;\n            --text-main: #2d3748;\n            --text-muted: #718096;\n            --accent: #eab308;\n            --success: #38a169;\n            --danger: #e53e3e;\n            \n            --shadow-light: rgba(255, 255, 255, 0.8);\n            --shadow-dark: rgba(163, 177, 198, 0.6);\n            --neu-out: 9px 9px 16px var(--shadow-dark), -9px -9px 16px var(--shadow-light);\n            --neu-out-sm: 5px 5px 10px var(--shadow-dark), -5px -5px 10px var(--shadow-light);\n            --neu-in: inset 6px 6px 10px var(--shadow-dark), inset -6px -6px 10px var(--shadow-light);\n            \n            --radius-xl: 40px;\n            --radius-lg: 30px;\n            --radius-pill: 100px;\n            \n            \/* SGP OS Colors *\/\n            --os-bg: #000000;\n            --os-green: #00ff00;\n            --os-dim: #005500;\n            --os-text: #88ff88;\n            --os-red: #ff2222;\n        }\n\n        * { box-sizing: border-box; margin: 0; padding: 0; }\n        body { background-color: var(--bg-color); color: var(--text-main); font-family: 'Inter', sans-serif; line-height: 1.6; padding: 20px; overflow-x: hidden; }\n        h1, h2, h3 { font-family: 'Space Grotesk', sans-serif; font-weight: 800; color: var(--text-main); margin-bottom: 15px; letter-spacing: -0.5px; }\n\n        .product-container { max-width: 1000px; margin: 0 auto; padding-bottom: 60px; }\n        .neu-card { background: var(--bg-color); border-radius: var(--radius-xl); box-shadow: var(--neu-out); padding: 40px; margin-bottom: 40px; }\n        .neu-card-sm { background: var(--bg-color); border-radius: var(--radius-lg); box-shadow: var(--neu-out); padding: 25px; display: flex; flex-direction: column; gap: 15px; }\n        .neu-sunken { background: var(--bg-color); border-radius: var(--radius-lg); box-shadow: var(--neu-in); padding: 25px; }\n        \n        .neu-icon { width: 60px; height: 60px; border-radius: 50%; background: var(--bg-color); box-shadow: var(--neu-out); display: flex; align-items: center; justify-content: center; color: var(--accent); font-size: 24px; margin-bottom: 10px; }\n        .svg-icon { width: 28px; height: 28px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }\n\n        .header-section { text-align: center; margin-bottom: 50px; padding-top: 20px; }\n        .badge { display: inline-block; background: var(--bg-color); box-shadow: var(--neu-in); padding: 8px 20px; border-radius: var(--radius-pill); font-size: 13px; font-weight: 600; color: var(--accent); text-transform: uppercase; letter-spacing: 2px; margin-bottom: 20px; }\n        .main-title { font-size: clamp(36px, 6vw, 64px); background: linear-gradient(135deg, #2d3748 0%, #718096 100%); -webkit-background-clip: text; -webkit-text-fill-color: transparent; margin-bottom: 10px; }\n        \n        .hero-image-wrapper { margin: 30px auto; max-width: 350px; border-radius: var(--radius-xl); padding: 15px; background: var(--bg-color); box-shadow: var(--neu-out); }\n        .hero-image-wrapper img { width: 100%; height: auto; border-radius: var(--radius-lg); display: block; }\n\n        .section-title { text-align: center; font-size: 28px; margin-bottom: 40px; margin-top: 60px; }\n        .features-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 30px; margin-bottom: 50px; }\n        .feature-title { font-size: 18px; margin-bottom: 5px; }\n        .feature-desc { color: var(--text-muted); font-size: 15px; }\n        \n        .neu-list { list-style: none; padding: 0; }\n        .neu-list li { display: flex; align-items: center; gap: 15px; padding: 12px 0; border-bottom: 1px solid rgba(163, 177, 198, 0.3); color: var(--text-muted); font-size: 15px; }\n        .neu-list li:last-child { border-bottom: none; }\n        .neu-list .check { color: var(--success); font-weight: bold; font-size: 18px; }\n\n        .disclaimer { margin-top: 60px; text-align: center; }\n        .disclaimer p { font-size: 12px; color: var(--text-muted); margin-top: 10px; }\n        \n        .watch-container { display: flex; justify-content: center; align-items: center; padding: 40px 0; }\n        .watch-case { width: 280px; height: 340px; background: #1a1a1a; border-radius: 40px; position: relative; box-shadow: 20px 20px 60px var(--shadow-dark), -20px -20px 60px var(--shadow-light), inset 5px 5px 15px #333, inset -5px -5px 15px #000; border: 4px solid #2a2a2a; display: flex; justify-content: center; align-items: center; }\n        \n        \/* Physical Buttons *\/\n        .watch-button { position: absolute; right: -12px; width: 12px; background: #222; border-radius: 0 6px 6px 0; box-shadow: 3px 3px 5px var(--shadow-dark); border: 2px solid #111; border-left: none; cursor: pointer; transition: transform 0.1s; }\n        .watch-button:active { transform: translateX(-4px); }\n        .btn-top { top: 60px; height: 35px; }\n        .btn-mid { top: 120px; height: 35px; }\n        .btn-bot { top: 180px; height: 35px; }\n        \n        .watch-button-label { position: absolute; font-size: 11px; color: var(--text-muted); font-weight: bold; pointer-events: none; right: -40px; transform: rotate(90deg); letter-spacing: 2px; white-space: nowrap; }\n        \n        .watch-screen-bezel { width: 240px; height: 280px; background: #000; border-radius: 25px; overflow: hidden; position: relative; box-shadow: inset 0 0 20px rgba(0,0,0,1); }\n        .os-screen { width: 100%; height: 100%; font-family: 'Share Tech Mono', monospace; color: var(--os-green); background: var(--os-bg); position: relative; user-select: none; }\n        \n        .os-header { background: var(--os-green); color: var(--os-bg); padding: 5px 10px; font-weight: bold; font-size: 14px; display: flex; justify-content: space-between; position: sticky; top: 0; z-index: 10; }\n        .os-content { padding: 10px; height: calc(100% - 28px); overflow-y: auto; overflow-x: hidden; scroll-behavior: smooth; }\n        \n        .os-content::-webkit-scrollbar { width: 6px; }\n        .os-content::-webkit-scrollbar-track { background: var(--os-bg); }\n        .os-content::-webkit-scrollbar-thumb { background: var(--os-dim); border-radius: 3px; }\n        .os-content::-webkit-scrollbar-thumb:hover { background: var(--os-green); }\n\n        .os-menu-item { border: 1px solid var(--os-dim); padding: 12px 10px; margin-bottom: 8px; border-radius: 4px; display: flex; justify-content: space-between; align-items: center; cursor: pointer; font-size: 14px; transition: all 0.1s; }\n        .os-menu-item:hover { background: var(--os-dim); color: var(--os-text); }\n        .os-menu-item:active { background: var(--os-green); color: var(--os-bg); }\n        \n        .os-text { color: var(--os-text); }\n        .os-green { color: var(--os-green); }\n        .os-red { color: var(--os-red); }\n        .os-dim { color: var(--os-dim); }\n        \n        .scan-item { border: 1px solid var(--os-dim); margin-bottom: 5px; padding: 5px; font-size: 12px; }\n        \n        @keyframes reveal { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: translateY(0); } }\n        .reveal { animation: reveal 0.6s ease-out forwards; }\n        \n        @keyframes blink { 0%, 100% { opacity:1; } 50% { opacity:0.3; } }\n        @keyframes colorCycle { 0% {background:#f00;} 33% {background:#0f0;} 66% {background:#00f;} 100% {background:#f00;} }\n        @keyframes scanSweep { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }\n        \n        \/* Estilos específicos para DOOM *\/\n        #dosbox-container { width: 100%; height: 100%; background: #000; position: relative; z-index: 20; display: flex; flex-direction: column; justify-content: center; align-items: center;}\n    \u003c\/style\u003e\n\n\n\n\u003cdiv class=\"product-container reveal\"\u003e\n\n    \u003cheader class=\"header-section\"\u003e\n        \u003cdiv class=\"badge\"\u003eAdvanced Wearable Hub\u003c\/div\u003e\n        \u003ch1 class=\"main-title\"\u003eSGP WATCH\u003c\/h1\u003e\n        \u003cp class=\"subtitle\" style=\"font-size: 18px; color: var(--text-muted); font-weight: 500; max-width: 600px; margin: 0 auto;\"\u003eIntegrate. Program. Deploy. Professional hardware disguised as an everyday timepiece.\u003c\/p\u003e\n    \u003c\/header\u003e\n\n    \u003ch2 class=\"section-title\"\u003e💻 Interactive SGP OS Emulator\u003c\/h2\u003e\n\n    \u003cdiv class=\"watch-container\"\u003e\n        \u003cdiv class=\"watch-case\"\u003e\n            \u003c!-- 3 Hardware Buttons --\u003e\n            \u003cdiv class=\"watch-button btn-top\" onclick=\"appMenu()\" title=\"Back \/ Home\"\u003e\u003c\/div\u003e\n            \u003cdiv class=\"watch-button-label\" style=\"top: 70px;\"\u003eBACK\u003c\/div\u003e\n            \n            \u003cdiv class=\"watch-button btn-mid\" onclick=\"scrollMenu(-1)\" title=\"Scroll Up\"\u003e\u003c\/div\u003e\n            \u003cdiv class=\"watch-button-label\" style=\"top: 130px;\"\u003eUP\u003c\/div\u003e\n            \n            \u003cdiv class=\"watch-button btn-bot\" onclick=\"scrollMenu(1)\" title=\"Scroll Down\"\u003e\u003c\/div\u003e\n            \u003cdiv class=\"watch-button-label\" style=\"top: 190px;\"\u003eDOWN\u003c\/div\u003e\n\n            \u003c!-- Screen --\u003e\n            \u003cdiv class=\"watch-screen-bezel\"\u003e\n                \u003cdiv class=\"os-screen\" id=\"os-screen\"\u003e\n                    \u003c!-- OS Content injected here --\u003e\n                \u003c\/div\u003e\n            \u003c\/div\u003e\n        \u003c\/div\u003e\n    \u003c\/div\u003e\n\n    \u003ch2 class=\"section-title\"\u003e🔧 Core Capabilities\u003c\/h2\u003e\n    \n    \u003cdiv class=\"features-grid\"\u003e\n        \u003cdiv class=\"neu-card-sm\"\u003e\n            \u003cdiv class=\"neu-icon\"\u003e\u003csvg class=\"svg-icon\" viewbox=\"0 0 24 24\"\u003e\u003cpath d=\"M18 3a3 3 0 0 0-3 3v12a3 3 0 0 0 3 3 3 3 0 0 0 3-3 3 3 0 0 0-3-3H6a3 3 0 0 0-3 3 3 3 0 0 0 3 3 3 3 0 0 0 3-3V6a3 3 0 0 0-3-3 3 3 0 0 0-3 3 3 3 0 0 0 3 3h12a3 3 0 0 0 3-3 3 3 0 0 0-3-3z\"\u003e\u003c\/path\u003e\u003c\/svg\u003e\u003c\/div\u003e\n            \u003ch3 class=\"feature-title\"\u003eOpen-Source Core\u003c\/h3\u003e\n            \u003cp class=\"feature-desc\"\u003eEquipped with a dual-core Xtensa LX7 processor @ 240MHz, 8MB PSRAM, and 16MB Flash memory. 100% open-source.\u003c\/p\u003e\n        \u003c\/div\u003e\n\n        \u003cdiv class=\"neu-card-sm\"\u003e\n            \u003cdiv class=\"neu-icon\"\u003e\u003csvg class=\"svg-icon\" viewbox=\"0 0 24 24\"\u003e\u003crect x=\"2\" y=\"3\" width=\"20\" height=\"14\" rx=\"2\" ry=\"2\"\u003e\u003c\/rect\u003e\u003cline x1=\"8\" y1=\"21\" x2=\"16\" y2=\"21\"\u003e\u003c\/line\u003e\u003cline x1=\"12\" y1=\"17\" x2=\"12\" y2=\"21\"\u003e\u003c\/line\u003e\u003c\/svg\u003e\u003c\/div\u003e\n            \u003ch3 class=\"feature-title\"\u003e1.69\" LCD Interface\u003c\/h3\u003e\n            \u003cp class=\"feature-desc\"\u003eCrisp 240x280 pixel display with 262K colors, driven by the ST7789V2 chip. Fluid GUI under any condition.\u003c\/p\u003e\n        \u003c\/div\u003e\n\n        \u003cdiv class=\"neu-card-sm\"\u003e\n            \u003cdiv class=\"neu-icon\"\u003e\u003csvg class=\"svg-icon\" viewbox=\"0 0 24 24\"\u003e\u003cpath d=\"M22 12h-4l-3 9L9 3l-3 9H2\"\u003e\u003c\/path\u003e\u003c\/svg\u003e\u003c\/div\u003e\n            \u003ch3 class=\"feature-title\"\u003eKinetic Tracking\u003c\/h3\u003e\n            \u003cp class=\"feature-desc\"\u003eIntegrated QMI8658 sensor (6-axis IMU). Ideal for telemetry, gesture commands, and environmental motion tracking.\u003c\/p\u003e\n        \u003c\/div\u003e\n\n        \u003cdiv class=\"neu-card-sm\"\u003e\n            \u003cdiv class=\"neu-icon\"\u003e\u003csvg class=\"svg-icon\" viewbox=\"0 0 24 24\"\u003e\u003cpath d=\"M5 12.55a11 11 0 0 1 14.08 0\"\u003e\u003c\/path\u003e\u003cpath d=\"M1.42 9a16 16 0 0 1 21.16 0\"\u003e\u003c\/path\u003e\u003ccircle cx=\"12\" cy=\"20\" r=\"1\"\u003e\u003c\/circle\u003e\u003c\/svg\u003e\u003c\/div\u003e\n            \u003ch3 class=\"feature-title\"\u003eSignal Analysis\u003c\/h3\u003e\n            \u003cp class=\"feature-desc\"\u003eDeploy diagnostic capabilities with native support for 2.4 GHz Wi-Fi and Bluetooth 5 (LE) directly from your wrist.\u003c\/p\u003e\n        \u003c\/div\u003e\n        \n        \u003cdiv class=\"neu-card-sm\"\u003e\n            \u003cdiv class=\"neu-icon\"\u003e\u003csvg class=\"svg-icon\" viewbox=\"0 0 24 24\"\u003e\u003crect x=\"1\" y=\"6\" width=\"18\" height=\"12\" rx=\"2\" ry=\"2\"\u003e\u003c\/rect\u003e\u003cline x1=\"23\" y1=\"13\" x2=\"23\" y2=\"11\"\u003e\u003c\/line\u003e\u003cline x1=\"15\" y1=\"6\" x2=\"15\" y2=\"18\"\u003e\u003c\/line\u003e\u003c\/svg\u003e\u003c\/div\u003e\n            \u003ch3 class=\"feature-title\"\u003eExtended Power\u003c\/h3\u003e\n            \u003cp class=\"feature-desc\"\u003eMassive 500+ mAh battery for days of continuous testing, backed by ultra-low power RTC management.\u003c\/p\u003e\n        \u003c\/div\u003e\n\n        \u003cdiv class=\"neu-card-sm\"\u003e\n            \u003cdiv class=\"neu-icon\"\u003e\u003csvg class=\"svg-icon\" viewbox=\"0 0 24 24\"\u003e\u003cpath d=\"M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z\"\u003e\u003c\/path\u003e\u003cpolyline points=\"13 2 13 9 20 9\"\u003e\u003c\/polyline\u003e\u003c\/svg\u003e\u003c\/div\u003e\n            \u003ch3 class=\"feature-title\"\u003eRapid Modding\u003c\/h3\u003e\n            \u003cp class=\"feature-desc\"\u003eUSB Type-C connector and a reserved 12PIN port (GPIO, I2C, UART) to instantly dock external peripherals.\u003c\/p\u003e\n        \u003c\/div\u003e\n\n        \u003c!-- Nuevas capacidades añadidas --\u003e\n        \u003cdiv class=\"neu-card-sm\"\u003e\n            \u003cdiv class=\"neu-icon\"\u003e\u003csvg class=\"svg-icon\" viewbox=\"0 0 24 24\"\u003e\u003ccircle cx=\"12\" cy=\"12\" r=\"10\"\u003e\u003c\/circle\u003e\u003ccircle cx=\"12\" cy=\"12\" r=\"6\"\u003e\u003c\/circle\u003e\u003ccircle cx=\"12\" cy=\"12\" r=\"2\"\u003e\u003c\/circle\u003e\u003c\/svg\u003e\u003c\/div\u003e\n            \u003ch3 class=\"feature-title\"\u003eProximity Radar\u003c\/h3\u003e\n            \u003cp class=\"feature-desc\"\u003eDetects and tracks nearby wireless devices in real-time. Ideal for spatial awareness and locating active Wi-Fi\/BLE emitters.\u003c\/p\u003e\n        \u003c\/div\u003e\n\n        \u003cdiv class=\"neu-card-sm\"\u003e\n            \u003cdiv class=\"neu-icon\"\u003e\u003csvg class=\"svg-icon\" viewbox=\"0 0 24 24\"\u003e\u003cpath d=\"M8 3l4 8 5-5 5 15H2L8 3z\"\u003e\u003c\/path\u003e\u003c\/svg\u003e\u003c\/div\u003e\n            \u003ch3 class=\"feature-title\"\u003eOutdoor \u0026amp; Sports\u003c\/h3\u003e\n            \u003cp class=\"feature-desc\"\u003eFully programmable for mountain excursions and sports telemetry. Log kinetic data, altitude variations, and track your routes.\u003c\/p\u003e\n        \u003c\/div\u003e\n\n        \u003cdiv class=\"neu-card-sm\"\u003e\n            \u003cdiv class=\"neu-icon\"\u003e\u003csvg class=\"svg-icon\" viewbox=\"0 0 24 24\"\u003e\u003cpath d=\"M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z\"\u003e\u003c\/path\u003e\u003cpath d=\"M12 11a2 2 0 1 0 0-4 2 2 0 0 0 0 4z\"\u003e\u003c\/path\u003e\u003c\/svg\u003e\u003c\/div\u003e\n            \u003ch3 class=\"feature-title\"\u003eTactical Security\u003c\/h3\u003e\n            \u003cp class=\"feature-desc\"\u003eThe ultimate compact diagnostic instrument for engineers and IT teams. Run network analysis and monitor environments seamlessly.\u003c\/p\u003e\n        \u003c\/div\u003e\n    \u003c\/div\u003e\n\n    \u003ch2 class=\"section-title\"\u003e⚡ Authorized Operations: Use Cases\u003c\/h2\u003e\n    \n    \u003cdiv class=\"features-grid\"\u003e\n        \u003cdiv class=\"neu-card-sm\"\u003e\n            \u003ch3 class=\"feature-title\" style=\"color: var(--accent);\"\u003e01. Network Analysis\u003c\/h3\u003e\n            \u003cp class=\"feature-desc\"\u003eAuthorized mapping, analysis, and security testing of personal or corporate Wi-Fi\/BLE networks to identify weak points.\u003c\/p\u003e\n        \u003c\/div\u003e\n        \u003cdiv class=\"neu-card-sm\"\u003e\n            \u003ch3 class=\"feature-title\" style=\"color: var(--accent);\"\u003e02. IoT Command Node\u003c\/h3\u003e\n            \u003cp class=\"feature-desc\"\u003eSeamless integration with smart home environments (e.g., Home Assistant, MQTT) for wrist-based device control.\u003c\/p\u003e\n        \u003c\/div\u003e\n        \u003cdiv class=\"neu-card-sm\"\u003e\n            \u003ch3 class=\"feature-title\" style=\"color: var(--accent);\"\u003e03. Kinetic Development\u003c\/h3\u003e\n            \u003cp class=\"feature-desc\"\u003eCreating custom algorithms for sports telemetry, gesture-based remote controls, or fall detection via the built-in IMU.\u003c\/p\u003e\n        \u003c\/div\u003e\n        \u003cdiv class=\"neu-card-sm\"\u003e\n            \u003ch3 class=\"feature-title\" style=\"color: var(--accent);\"\u003e04. Academic Sandbox\u003c\/h3\u003e\n            \u003cp class=\"feature-desc\"\u003eA highly portable laboratory for learning embedded systems, C\/C++, MicroPython, and secure wireless communications.\u003c\/p\u003e\n        \u003c\/div\u003e\n        \u003cdiv class=\"neu-card-sm\"\u003e\n            \u003ch3 class=\"feature-title\" style=\"color: var(--accent);\"\u003e05. Ecosystem Synergy\u003c\/h3\u003e\n            \u003cp class=\"feature-desc\"\u003eFully compatible with our entire range of devices. Connect the SGP Watch to expand your diagnostic capabilities exponentially.\u003c\/p\u003e\n        \u003c\/div\u003e\n        \u003cdiv class=\"neu-card-sm\"\u003e\n            \u003ch3 class=\"feature-title\" style=\"color: var(--accent);\"\u003e06. Maximum Portability\u003c\/h3\u003e\n            \u003cp class=\"feature-desc\"\u003eThe smallest and most discrete tool in our arsenal. Carry immense analytical power wherever you go with full portability.\u003c\/p\u003e\n        \u003c\/div\u003e\n    \u003c\/div\u003e\n\n    \u003cdiv class=\"disclaimer neu-sunken\"\u003e\n        \u003ch4 style=\"color: var(--danger); font-size: 14px; margin-bottom: 5px; text-transform: uppercase;\"\u003e🔒 Responsibility Protocol\u003c\/h4\u003e\n        \u003cp\u003eEngineered exclusively for education, authorized security research, and personal IoT development. Operators must ensure compliance with all applicable local, state, and federal laws. Obtain explicit consent before testing any network infrastructure.\u003c\/p\u003e\n    \u003c\/div\u003e\n\n\u003c\/div\u003e\n\n\u003cscript\u003e\n    let synth;\n    async function playBeep() {\n        if (!synth) {\n            \/\/ Configurar un pitido estilo \"reloj digital clásico\" (onda cuadrada, muy corto)\n            synth = new Tone.Synth({\n                oscillator: { type: \"square\" },\n                envelope: { attack: 0.005, decay: 0.05, sustain: 0.0, release: 0.01 }\n            }).toDestination();\n            synth.volume.value = -15; \/\/ Bajar un poco el volumen para que sea agradable\n        }\n        \/\/ Iniciar el contexto de audio (requerido por los navegadores)\n        await Tone.start();\n        synth.triggerAttackRelease(\"C6\", \"0.05\");\n    }\n\n    const screen = document.getElementById('os-screen');\n    let currentState = 'BOOT';\n    let renderInterval;\n    let mouseListener;\n    let doomAnim; \/\/ Variable para el motor 3D\n    let doomEventHandlers = {}; \/\/ Guardar referencias a eventos para limpiarlos\n\n    \/\/ Purified App List matching the C++ Menu WITHOUT RFID\n    const appsList = [\n        { name: \"DOOM\", id: \"DOOM\" },\n        { name: \"WATCH FACES\", id: \"FACES\" },\n        { name: \"WIFI MOTION\", id: \"WIFI_MOTION\" },\n        { name: \"BIO SAFETY\", id: \"BIO\" },\n        { name: \"GAS MONITOR\", id: \"BIO\" },\n        { name: \"ALTIMETER\", id: \"ALTIMETER\" },\n        { name: \"MOOD LIGHT\", id: \"MOOD\" },\n        { name: \"BLE TESTER\", id: \"BENCH\" },\n        { name: \"REMOTE CTRL\", id: \"REMOTE\" },\n        { name: \"BLE HID DEMO\", id: \"REMOTE\" },\n        { name: \"SGP WIRED\", id: \"TERMINAL\" },\n        { name: \"NETWORK PORTAL\", id: \"TERMINAL\" },\n        { name: \"POINTER DEMO\", id: \"REMOTE\" },\n        { name: \"USB DEV TOOLS\", id: \"USBAUTO\" },\n        { name: \"TAG READER\", id: \"PINTEST\" },\n        { name: \"BEACON TESTER\", id: \"BENCH\" },\n        { name: \"NET DIAGNOSTIC\", id: \"BENCH\" },\n        { name: \"WIFI SCAN\", id: \"SCANNER\" },\n        { name: \"BLE EMULATOR\", id: \"TERMINAL\" },\n        { name: \"BLE DISTANCE\", id: \"RADAR\" },\n        { name: \"SYSTEM\", id: \"SYS_INFO\" },\n        { name: \"DATA STREAM\", id: \"MATRIX\" },\n        { name: \"SPIRIT LEVEL\", id: \"LEVEL\" },\n        { name: \"GRAVITY PHYS\", id: \"SENSOR\" },\n        { name: \"SPECTRE RADAR\", id: \"RADAR\" },\n        { name: \"MAC SCANNER\", id: \"SCANNER\" },\n        { name: \"PROBE ANALYZER\", id: \"TERMINAL\" },\n        { name: \"NET BENCHMARK\", id: \"BENCH\" },\n        { name: \"PACKET MONITOR\", id: \"GRAPH\" },\n        { name: \"ARCADE OPS\", id: \"GAMES\" },\n        { name: \"BLE ULTIMATE\", id: \"BENCH\" },\n        { name: \"BLE BENCHMARK\", id: \"BENCH\" },\n        { name: \"BLE SCANNER\", id: \"SCANNER\" },\n        { name: \"SIGNAL DEFENSE\", id: \"GRAPH\" },\n        { name: \"Q-LABS SENSORS\", id: \"SENSOR\" },\n        { name: \"AUDIO FX\", id: \"AUDIO\" },\n        { name: \"CHRONOS\", id: \"CHRONOS\" },\n        { name: \"SYSTEM INFO\", id: \"SYS_INFO\" }\n    ];\n\n    function scrollMenu(direction) {\n        const content = document.querySelector('.os-content');\n        if (content) {\n            content.scrollBy({ top: direction * 45, behavior: 'smooth' });\n        }\n    }\n\n    function clearScreen() {\n        clearInterval(renderInterval);\n        \n        \/\/ Limpiar animaciones y eventos del motor 3D de DOOM\n        if(doomAnim) { cancelAnimationFrame(doomAnim); doomAnim = null; }\n        if(doomEventHandlers.keydown) document.removeEventListener('keydown', doomEventHandlers.keydown);\n        if(doomEventHandlers.keyup) document.removeEventListener('keyup', doomEventHandlers.keyup);\n        \n        if(mouseListener) {\n            document.removeEventListener('mousemove', mouseListener);\n            mouseListener = null;\n        }\n        screen.innerHTML = '';\n        screen.onclick = null;\n        screen.style.background = 'var(--os-bg)'; \/\/ reset background\n    }\n\n    function renderHeader(title) {\n        const header = document.createElement('div');\n        header.className = 'os-header';\n        header.innerHTML = `\u003cspan\u003e${title}\u003c\/span\u003e\u003cspan\u003e100%\u003c\/span\u003e`;\n        screen.appendChild(header);\n    }\n\n    function appMenu() {\n        clearScreen();\n        currentState = 'MENU';\n        renderHeader(\"SGP OS\");\n        \n        const content = document.createElement('div');\n        content.className = 'os-content';\n        \n        appsList.forEach(app =\u003e {\n            const item = document.createElement('div');\n            item.className = 'os-menu-item';\n            item.innerHTML = `\u003cspan\u003e${app.name}\u003c\/span\u003e\u003cspan class=\"os-green\"\u003e\u003e\u003c\/span\u003e`;\n            item.onclick = (e) =\u003e {\n                e.stopPropagation();\n                currentState = app.id;\n                launchApp(app.id, app.name);\n            };\n            content.appendChild(item);\n        });\n\n        screen.appendChild(content);\n    }\n\n    function launchApp(id, title) {\n        if(id === 'SCANNER') appScanner(title);\n        else if(id === 'DOOM') appDoom(title);\n        else if(id === 'PINTEST') appPinTest(title);\n        else if(id === 'LEVEL') appLevel(title);\n        else if(id === 'BIO') appBio(title);\n        else if(id === 'MATRIX') appMatrix(title);\n        else if(id === 'RADAR') appRadar(title);\n        else if(id === 'USBAUTO') appUsbAuto(title);\n        else if(id === 'FACES') appFaces(title);\n        else if(id === 'GAMES') appGames(title);\n        else if(id === 'WIFI_MOTION') appWiFiMotion(title);\n        else if(id === 'ALTIMETER') appAltimeter(title);\n        else if(id === 'MOOD') appMood(title);\n        else if(id === 'BENCH') appBench(title);\n        else if(id === 'REMOTE') appRemote(title);\n        else if(id === 'TERMINAL') appTerminal(title);\n        else if(id === 'SYS_INFO') appSysInfo(title);\n        else if(id === 'SENSOR') appSensor(title);\n        else if(id === 'GRAPH') appGraph(title);\n        else if(id === 'AUDIO') appAudio(title);\n        else if(id === 'CHRONOS') appChronos(title);\n    }\n\n    function appDoom(title) {\n        clearScreen();\n        \n        \/\/ Usaremos resolución interna 120x120 escalada para rendimiento puro de renderizado por software\n        const w = 120; \n        const h = 120;\n        const canvas = document.createElement('canvas');\n        canvas.width = w;\n        canvas.height = h;\n        canvas.style.width = '100%';\n        canvas.style.height = '100%';\n        canvas.style.imageRendering = 'pixelated'; \/\/ Estilo retro nítido\n        \n        \/\/ Overlay táctil transparente\n        const touchOverlay = document.createElement('div');\n        touchOverlay.style.position = 'absolute';\n        touchOverlay.style.top = '0'; touchOverlay.style.left = '0';\n        touchOverlay.style.width = '100%'; touchOverlay.style.height = '100%';\n        touchOverlay.style.display = 'flex';\n        touchOverlay.style.zIndex = '30';\n        \n        const btnL = document.createElement('div'); btnL.style.flex = '1';\n        const btnM = document.createElement('div'); btnM.style.flex = '1';\n        const btnR = document.createElement('div'); btnR.style.flex = '1';\n        touchOverlay.appendChild(btnL); touchOverlay.appendChild(btnM); touchOverlay.appendChild(btnR);\n\n        const container = document.createElement('div');\n        container.style.position = 'relative';\n        container.style.width = '100%'; container.style.height = '100%';\n        container.appendChild(canvas);\n        container.appendChild(touchOverlay);\n        screen.appendChild(container);\n\n        const ctx = canvas.getContext('2d', { alpha: false });\n        \/\/ Buffer de píxeles para renderizado estilo DOS\n        const imgData = ctx.createImageData(w, h);\n        const data = imgData.data;\n\n        const texWidth = 32;\n        const texHeight = 32;\n        const textures = [];\n        for(let i=0; i\u003c4; i++) {\n            let tex = [];\n            for(let x=0; x\u003ctexWidth; x++) {\n                for(let y=0; y\u003ctexHeight; y++) {\n                    let r=0, g=0, b=0;\n                    if(i===1) { \/\/ 1: Muro de piedra\n                        let noise = Math.random()*30;\n                        r = 90+noise; g = 90+noise; b = 90+noise;\n                        if(x%16===0 || y%16===0) { r-=40; g-=40; b-=40; } \/\/ Juntas\n                    }\n                    else if(i===2) { \/\/ 2: Panel de Advertencia Rojo\n                        if((x+y)%16 \u003c 8) { r=160; g=20; b=20; } else { r=30; g=30; b=30; }\n                    }\n                    else if(i===3) { \/\/ 3: SGP Mainframe\n                        r=10; g=30; b=10;\n                        if(x%8===0 || y%8===0) { g=100; } \/\/ Rejilla\n                        if(Math.random()\u003c0.03) { r=0; g=255; b=0; } \/\/ Luces parpadeantes LED\n                    }\n                    tex[texWidth * y + x] = {r, g, b};\n                }\n            }\n            textures.push(tex);\n        }\n\n        const worldMap = [\n            [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],\n            [1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1],\n            [1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1],\n            [1,0,0,3,3,0,1,0,0,2,2,2,2,0,0,1],\n            [1,0,0,3,0,0,0,0,0,2,0,0,2,0,0,1],\n            [1,0,0,0,0,0,0,0,0,2,0,0,2,0,0,1],\n            [1,0,0,0,0,0,0,0,0,2,2,0,2,0,0,1],\n            [1,1,1,0,1,1,1,0,0,0,0,0,0,0,0,1],\n            [1,0,0,0,0,0,1,0,0,3,3,3,3,0,0,1],\n            [1,0,0,0,0,0,1,0,0,3,0,0,3,0,0,1],\n            [1,0,0,2,0,0,1,0,0,3,0,0,0,0,0,1],\n            [1,0,0,2,0,0,1,0,0,3,0,0,0,0,0,1],\n            [1,0,0,0,0,0,0,0,0,0,0,0,3,0,0,1],\n            [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]\n        ];\n\n        let posX = 2.5, posY = 2.5; \n        let dirX = 1.0, dirY = 0.0; \n        let planeX = 0.0, planeY = 0.66;\n        let time = 0, oldTime = 0;\n        \n        let isFiring = false;\n        let blasterRecoil = 0;\n        let headBob = 0; \/\/ Animación al caminar\n        let isMoving = false;\n        let faceLooking = 0; \/\/ -1 izq, 0 centro, 1 der\n\n        const keys = { w: false, s: false, left: false, right: false, space: false };\n\n        doomEventHandlers.keydown = (e) =\u003e {\n            if(e.key === 'w' || e.key === 'ArrowUp') keys.w = true;\n            if(e.key === 's' || e.key === 'ArrowDown') keys.s = true;\n            if(e.key === 'a' || e.key === 'ArrowLeft') { keys.left = true; faceLooking = -1; }\n            if(e.key === 'd' || e.key === 'ArrowRight') { keys.right = true; faceLooking = 1; }\n            if(e.key === ' ') { keys.space = true; fireBlaster(); }\n        };\n        doomEventHandlers.keyup = (e) =\u003e {\n            if(e.key === 'w' || e.key === 'ArrowUp') keys.w = false;\n            if(e.key === 's' || e.key === 'ArrowDown') keys.s = false;\n            if(e.key === 'a' || e.key === 'ArrowLeft') { keys.left = false; faceLooking = 0; }\n            if(e.key === 'd' || e.key === 'ArrowRight') { keys.right = false; faceLooking = 0; }\n            if(e.key === ' ') keys.space = false;\n        };\n        document.addEventListener('keydown', doomEventHandlers.keydown);\n        document.addEventListener('keyup', doomEventHandlers.keyup);\n\n        btnL.ontouchstart = btnL.onmousedown = (e) =\u003e { e.preventDefault(); keys.left = true; faceLooking = -1; };\n        btnL.ontouchend = btnL.onmouseup = btnL.onmouseleave = () =\u003e { keys.left = false; faceLooking = 0; };\n        btnR.ontouchstart = btnR.onmousedown = (e) =\u003e { e.preventDefault(); keys.right = true; faceLooking = 1; };\n        btnR.ontouchend = btnR.onmouseup = btnR.onmouseleave = () =\u003e { keys.right = false; faceLooking = 0; };\n        btnM.ontouchstart = btnM.onmousedown = (e) =\u003e { e.preventDefault(); keys.w = true; };\n        btnM.ontouchend = btnM.onmouseup = btnM.onmouseleave = () =\u003e { keys.w = false; };\n        btnM.ondblclick = (e) =\u003e { e.preventDefault(); fireBlaster(); };\n\n        function fireBlaster() {\n            if(!isFiring) {\n                isFiring = true;\n                blasterRecoil = 12;\n                playBeep();\n                setTimeout(() =\u003e isFiring = false, 150);\n            }\n        }\n\n        function gameLoop(timestamp) {\n            oldTime = time;\n            time = timestamp;\n            let frameTime = (time - oldTime) \/ 1000.0; \n            if(frameTime \u003e 0.1) frameTime = 0.1;\n            \n            let moveSpeed = frameTime * 3.0; \n            let rotSpeed = frameTime * 2.0;\n\n            isMoving = false;\n            \/\/ Movimiento\n            if (keys.w) {\n                if(worldMap[Math.floor(posX + dirX * moveSpeed)][Math.floor(posY)] === 0) posX += dirX * moveSpeed;\n                if(worldMap[Math.floor(posX)][Math.floor(posY + dirY * moveSpeed)] === 0) posY += dirY * moveSpeed;\n                isMoving = true;\n            }\n            if (keys.s) {\n                if(worldMap[Math.floor(posX - dirX * moveSpeed)][Math.floor(posY)] === 0) posX -= dirX * moveSpeed;\n                if(worldMap[Math.floor(posX)][Math.floor(posY - dirY * moveSpeed)] === 0) posY -= dirY * moveSpeed;\n                isMoving = true;\n            }\n            if (keys.right) {\n                let oldDirX = dirX; dirX = dirX * Math.cos(-rotSpeed) - dirY * Math.sin(-rotSpeed); dirY = oldDirX * Math.sin(-rotSpeed) + dirY * Math.cos(-rotSpeed);\n                let oldPlaneX = planeX; planeX = planeX * Math.cos(-rotSpeed) - planeY * Math.sin(-rotSpeed); planeY = oldPlaneX * Math.sin(-rotSpeed) + planeY * Math.cos(-rotSpeed);\n            }\n            if (keys.left) {\n                let oldDirX = dirX; dirX = dirX * Math.cos(rotSpeed) - dirY * Math.sin(rotSpeed); dirY = oldDirX * Math.sin(rotSpeed) + dirY * Math.cos(rotSpeed);\n                let oldPlaneX = planeX; planeX = planeX * Math.cos(rotSpeed) - planeY * Math.sin(rotSpeed); planeY = oldPlaneX * Math.sin(rotSpeed) + planeY * Math.cos(rotSpeed);\n            }\n\n            \/\/ Actualizar Head Bobbing\n            if (isMoving) headBob += frameTime * 15;\n            else headBob = 0;\n            let pitch = Math.sin(headBob) * 8; \/\/ Sube y baja la cámara\n            let flicker = Math.random() * 0.1; \/\/ Parpadeo de luces\n\n            \/\/ Limpiar Buffer (Cielo y Suelo)\n            for(let i=0; i\u003cw*h; i++) {\n                let y = Math.floor(i \/ w);\n                let r,g,b;\n                if (y \u003c h\/2 + pitch) { r = 40; g = 40; b = 40; } \/\/ Techo gris oscuro\n                else { r = 80 - (y-h\/2); g = 30; b = 30; } \/\/ Suelo degradado rojo oscuro\n                \n                data[i*4] = r; data[i*4+1] = g; data[i*4+2] = b; data[i*4+3] = 255;\n            }\n\n            for (let x = 0; x \u003c w; x++) {\n                let cameraX = 2 * x \/ w - 1; \n                let rayDirX = dirX + planeX * cameraX;\n                let rayDirY = dirY + planeY * cameraX;\n\n                let mapX = Math.floor(posX);\n                let mapY = Math.floor(posY);\n\n                let sideDistX, sideDistY;\n                let deltaDistX = Math.abs(1 \/ rayDirX);\n                let deltaDistY = Math.abs(1 \/ rayDirY);\n                let perpWallDist;\n\n                let stepX, stepY;\n                let hit = 0, side = 0;\n\n                if (rayDirX \u003c 0) { stepX = -1; sideDistX = (posX - mapX) * deltaDistX; } \n                else { stepX = 1; sideDistX = (mapX + 1.0 - posX) * deltaDistX; }\n                if (rayDirY \u003c 0) { stepY = -1; sideDistY = (posY - mapY) * deltaDistY; } \n                else { stepY = 1; sideDistY = (mapY + 1.0 - posY) * deltaDistY; }\n\n                while (hit === 0) {\n                    if (sideDistX \u003c sideDistY) { sideDistX += deltaDistX; mapX += stepX; side = 0; } \n                    else { sideDistY += deltaDistY; mapY += stepY; side = 1; }\n                    if (worldMap[mapX][mapY] \u003e 0) hit = 1;\n                }\n\n                if (side === 0) perpWallDist = (sideDistX - deltaDistX);\n                else perpWallDist = (sideDistY - deltaDistY);\n\n                let lineHeight = Math.floor(h \/ perpWallDist);\n                let drawStart = Math.floor(-lineHeight \/ 2 + h \/ 2 + pitch);\n                if (drawStart \u003c 0) drawStart = 0;\n                let drawEnd = Math.floor(lineHeight \/ 2 + h \/ 2 + pitch);\n                if (drawEnd \u003e= h) drawEnd = h - 1;\n\n                \/\/ Calcular posición exacta de la textura (UV Mapping)\n                let texNum = worldMap[mapX][mapY];\n                let wallX;\n                if (side === 0) wallX = posY + perpWallDist * rayDirY;\n                else wallX = posX + perpWallDist * rayDirX;\n                wallX -= Math.floor(wallX);\n\n                let texX = Math.floor(wallX * texWidth);\n                if(side === 0 \u0026\u0026 rayDirX \u003e 0) texX = texWidth - texX - 1;\n                if(side === 1 \u0026\u0026 rayDirY \u003c 0) texX = texWidth - texX - 1;\n\n                let step = 1.0 * texHeight \/ lineHeight;\n                let texPos = (drawStart - pitch - h \/ 2 + lineHeight \/ 2) * step;\n\n                \/\/ Dinamic Fog\n                let fog = Math.min(1.0, (perpWallDist \/ 9.0) + flicker);\n\n                for (let y = drawStart; y \u003c drawEnd; y++) {\n                    let texY = Math.floor(texPos) \u0026 (texHeight - 1);\n                    texPos += step;\n                    \n                    let color = textures[texNum][texWidth * texY + texX];\n                    let finalR = color.r, finalG = color.g, finalB = color.b;\n\n                    \/\/ Oscurecer paredes E\/O\n                    if(side === 1) { finalR\/=1.5; finalG\/=1.5; finalB\/=1.5; }\n                    \n                    \/\/ Aplicar niebla\n                    finalR = Math.floor(finalR * (1 - fog));\n                    finalG = Math.floor(finalG * (1 - fog));\n                    finalB = Math.floor(finalB * (1 - fog));\n\n                    let pixelIdx = (y * w + x) * 4;\n                    data[pixelIdx] = finalR;\n                    data[pixelIdx+1] = finalG;\n                    data[pixelIdx+2] = finalB;\n                }\n            }\n\n            \/\/ Volcar buffer al canvas\n            ctx.putImageData(imgData, 0, 0);\n\n            \/\/ 1. Interfaz HUD (Caja inferior gris)\n            ctx.fillStyle = \"#444\";\n            ctx.fillRect(0, h - 20, w, 20);\n            ctx.fillStyle = \"#222\";\n            ctx.fillRect(1, h - 19, w - 2, 18);\n            \n            \/\/ Texto HUD\n            ctx.fillStyle = \"#a00\";\n            ctx.font = \"8px 'Share Tech Mono'\";\n            ctx.fillText(\"AMMO\", 5, h - 5);\n            ctx.fillStyle = \"#fff\";\n            ctx.fillText(\"50\", 25, h - 5);\n            \n            ctx.fillStyle = \"#a00\";\n            ctx.fillText(\"HP\", w - 30, h - 5);\n            ctx.fillStyle = \"#fff\";\n            ctx.fillText(\"100%\", w - 18, h - 5);\n\n            \/\/ Carita del Doomguy\n            let faceX = w\/2 - 7;\n            let faceY = h - 17;\n            ctx.fillStyle = \"#e5c298\"; \/\/ Piel\n            ctx.fillRect(faceX, faceY, 14, 14);\n            ctx.fillStyle = \"#000\"; \/\/ Ojos\n            ctx.fillRect(faceX + 3 + (faceLooking*2), faceY + 4, 2, 2);\n            ctx.fillRect(faceX + 9 + (faceLooking*2), faceY + 4, 2, 2);\n            ctx.fillRect(faceX + 4, faceY + 10, 6, 2); \/\/ Boca recta (concentrado)\n\n            \/\/ 2. Arma Escopeta Detallada\n            let blasterX = w \/ 2 - 8;\n            let blasterY = h - 20 - 40 + blasterRecoil + pitch;\n            \n            \/\/ Cañones\n            ctx.fillStyle = \"#333\";\n            ctx.fillRect(blasterX, blasterY, 7, 45); \/\/ Cañón izq\n            ctx.fillRect(blasterX + 9, blasterY, 7, 45); \/\/ Cañón der\n            \/\/ Reflejos metálicos\n            ctx.fillStyle = \"#666\";\n            ctx.fillRect(blasterX + 1, blasterY, 2, 45); \n            ctx.fillRect(blasterX + 10, blasterY, 2, 45);\n            \/\/ Agarre madera oscura\n            ctx.fillStyle = \"#311\";\n            ctx.fillRect(blasterX - 2, blasterY + 30, 20, 15);\n\n            \/\/ Destello de Fuego\n            if(isFiring) {\n                \/\/ Luz de ambiente naranja en paredes\n                ctx.fillStyle = \"rgba(255, 100, 0, 0.2)\";\n                ctx.fillRect(0,0,w,h);\n                \n                \/\/ Sprite de fuego retro\n                ctx.fillStyle = \"yellow\";\n                ctx.beginPath(); ctx.arc(w\/2, blasterY - 5, 12, 0, Math.PI*2); ctx.fill();\n                ctx.fillStyle = \"orange\";\n                ctx.beginPath(); ctx.arc(w\/2 + 5, blasterY - 10, 8, 0, Math.PI*2); ctx.fill();\n                ctx.beginPath(); ctx.arc(w\/2 - 5, blasterY - 10, 8, 0, Math.PI*2); ctx.fill();\n                ctx.fillStyle = \"white\";\n                ctx.beginPath(); ctx.arc(w\/2, blasterY - 5, 5, 0, Math.PI*2); ctx.fill();\n            }\n\n            if(blasterRecoil \u003e 0) blasterRecoil -= 2;\n\n            doomAnim = requestAnimationFrame(gameLoop);\n        }\n\n        doomAnim = requestAnimationFrame(gameLoop);\n    }\n\n    function appScanner(title) {\n        clearScreen();\n        renderHeader(title.substring(0,14));\n        const content = document.createElement('div');\n        content.className = 'os-content';\n        \n        const networks = [\n            { ssid: \"CORP_5G\", mac: \"A1:B2:C3:D4:E5\", rssi: -45 },\n            { ssid: \"GUEST_WIFI\", mac: \"F1:E2:D3:C4:B5\", rssi: -65 },\n            { ssid: \"IOT_HUB\", mac: \"11:22:33:44:55\", rssi: -70 },\n            { ssid: \"PRINTER_NET\", mac: \"99:88:77:66:55\", rssi: -85 },\n            { ssid: \"HIDDEN_AP\", mac: \"AA:BB:CC:DD:EE\", rssi: -90 }\n        ];\n\n        let html = '';\n        networks.forEach(n =\u003e {\n            let color = n.rssi \u003e -60 ? 'var(--os-green)' : (n.rssi \u003e -80 ? 'var(--os-text)' : 'var(--os-red)');\n            html += `\n                \u003cdiv class=\"scan-item\"\u003e\n                    \u003cdiv style=\"display:flex; justify-content:space-between;\"\u003e\n                        \u003cspan class=\"os-text\"\u003e${n.ssid}\u003c\/span\u003e\n                        \u003cspan style=\"color:${color}\"\u003e${n.rssi} dBm\u003c\/span\u003e\n                    \u003c\/div\u003e\n                    \u003cdiv class=\"os-green\" style=\"font-size:10px; margin-top:4px;\"\u003eMAC: ${n.mac}\u003c\/div\u003e\n                \u003c\/div\u003e\n            `;\n        });\n        \n        content.innerHTML = html;\n        screen.appendChild(content);\n    }\n\n    function appPinTest(title) {\n        clearScreen();\n        renderHeader(title.substring(0,14));\n        const content = document.createElement('div');\n        content.className = 'os-content';\n        content.style.textAlign = 'center';\n        content.innerHTML = `\n            \u003cdiv class=\"os-red\" style=\"font-size:10px; margin-top:10px; animation: blink 1s infinite;\"\u003eREADING TAG...\u003c\/div\u003e\n            \u003cdiv id=\"pintest-pin\" class=\"os-green\" style=\"font-size:40px; margin:20px 0;\"\u003e0000\u003c\/div\u003e\n            \u003cdiv style=\"width:100%; height:10px; border:1px solid var(--os-dim); margin-bottom:10px;\"\u003e\n                \u003cdiv id=\"pintest-bar\" style=\"height:100%; width:0%; background:var(--os-green);\"\u003e\u003c\/div\u003e\n            \u003c\/div\u003e\n            \u003cdiv class=\"os-dim\" style=\"font-size:12px;\"\u003eBLOCKS: \u003cspan id=\"pintest-count\"\u003e0\u003c\/span\u003e\/9999\u003c\/div\u003e\n        `;\n        screen.appendChild(content);\n\n        let pin = 0;\n        const pinEl = document.getElementById('pintest-pin');\n        const barEl = document.getElementById('pintest-bar');\n        const countEl = document.getElementById('pintest-count');\n\n        renderInterval = setInterval(() =\u003e {\n            pin += 17; \/\/ Simulate speed\n            if(pin \u003e 9999) pin = 9999;\n            \n            pinEl.innerText = pin.toString().padStart(4, '0');\n            barEl.style.width = (pin \/ 9999 * 100) + '%';\n            countEl.innerText = pin;\n\n            if(pin === 9999) {\n                clearInterval(renderInterval);\n                document.querySelector('.os-red').innerText = \"TEST COMPLETE\";\n                document.querySelector('.os-red').style.color = \"var(--os-green)\";\n                document.querySelector('.os-red').style.animation = \"none\";\n            }\n        }, 50);\n    }\n\n    function appLevel(title) {\n        clearScreen();\n        renderHeader(title.substring(0,14));\n        const content = document.createElement('div');\n        content.className = 'os-content';\n        content.style.position = 'relative';\n        content.style.height = '240px';\n        content.innerHTML = `\n            \u003cdiv style=\"position:absolute; top:50%; left:50%; transform:translate(-50%, -50%); width:120px; height:120px; border-radius:50%; border:2px solid var(--os-dim);\"\u003e\u003c\/div\u003e\n            \u003cdiv style=\"position:absolute; top:50%; left:50%; transform:translate(-50%, -50%); width:60px; height:60px; border-radius:50%; border:2px solid var(--os-green);\"\u003e\u003c\/div\u003e\n            \u003cdiv style=\"position:absolute; top:50%; left:0; width:100%; height:1px; background:var(--os-dim);\"\u003e\u003c\/div\u003e\n            \u003cdiv style=\"position:absolute; top:0; left:50%; width:1px; height:100%; background:var(--os-dim);\"\u003e\u003c\/div\u003e\n            \u003cdiv id=\"level-bubble\" style=\"position:absolute; top:50%; left:50%; transform:translate(-50%, -50%); width:20px; height:20px; border-radius:50%; background:var(--os-green); transition: all 0.1s;\"\u003e\u003c\/div\u003e\n            \u003cdiv class=\"os-dim\" style=\"position:absolute; bottom:0; width:100%; text-align:center; font-size:10px;\"\u003eMove cursor over screen\u003c\/div\u003e\n        `;\n        screen.appendChild(content);\n\n        const bubble = document.getElementById('level-bubble');\n        \n        mouseListener = (e) =\u003e {\n            const rect = screen.getBoundingClientRect();\n            let x = e.clientX - rect.left;\n            let y = e.clientY - rect.top - 28;\n            \n            x = Math.max(40, Math.min(x, 200));\n            y = Math.max(40, Math.min(y, 200));\n\n            if(Math.abs(x - 120) \u003c 10 \u0026\u0026 Math.abs(y - 120) \u003c 10) {\n                bubble.style.background = 'var(--os-green)';\n            } else {\n                bubble.style.background = 'var(--os-red)';\n            }\n\n            bubble.style.left = x + 'px';\n            bubble.style.top = y + 'px';\n        };\n        \n        document.addEventListener('mousemove', mouseListener);\n    }\n\n    function appBio(title) {\n        clearScreen();\n        renderHeader(title.substring(0,14));\n        const content = document.createElement('div');\n        content.className = 'os-content';\n        content.innerHTML = `\n            \u003cdiv style=\"border:1px solid var(--os-red); padding:10px; text-align:center; margin-bottom:20px;\"\u003e\n                \u003cdiv class=\"os-red\" style=\"font-size:18px; font-weight:bold; animation: blink 1s infinite;\"\u003eTOXICITY ALERT\u003c\/div\u003e\n            \u003c\/div\u003e\n            \u003cdiv style=\"display:flex; justify-content:space-between; font-size:12px; margin-bottom:10px;\"\u003e\n                \u003cspan class=\"os-text\"\u003eTEMP: 24.5C\u003c\/span\u003e\n                \u003cspan class=\"os-text\"\u003eHUM: 45%\u003c\/span\u003e\n            \u003c\/div\u003e\n            \u003cdiv class=\"os-dim\" style=\"font-size:12px; margin-bottom:5px;\"\u003eVOC RESISTANCE:\u003c\/div\u003e\n            \u003cdiv class=\"os-red\" style=\"font-size:24px; font-weight:bold; margin-bottom:20px;\"\u003e18.4 KOhm\u003c\/div\u003e\n            \u003cdiv style=\"display:flex; justify-content:space-between; font-size:12px;\"\u003e\n                \u003cspan class=\"os-dim\"\u003ePARTICLE SCAN:\u003c\/span\u003e\n                \u003cspan class=\"os-red\"\u003eDETECTED\u003c\/span\u003e\n            \u003c\/div\u003e\n        `;\n        screen.appendChild(content);\n    }\n\n    function appMatrix(title) {\n        clearScreen();\n        renderHeader(title.substring(0,14));\n        const content = document.createElement('div');\n        content.className = 'os-content';\n        content.style.overflow = 'hidden';\n        content.innerHTML = `\u003cdiv id=\"matrix-rain\" style=\"color:var(--os-green); font-size:14px; line-height:12px; word-break:break-all; font-family:monospace;\"\u003e\u003c\/div\u003e`;\n        screen.appendChild(content);\n        \n        const m = document.getElementById('matrix-rain');\n        const chars = \"0101100101ABCF1000101\";\n        renderInterval = setInterval(() =\u003e {\n            let rain = \"\";\n            for(let i=0; i\u003c300; i++) rain += chars.charAt(Math.floor(Math.random() * chars.length));\n            m.innerText = rain;\n        }, 100);\n    }\n\n    function appRadar(title) {\n        clearScreen();\n        renderHeader(title.substring(0,14));\n        const content = document.createElement('div');\n        content.className = 'os-content';\n        content.innerHTML = `\n            \u003cdiv style=\"width:160px; height:160px; border:2px solid var(--os-dim); border-radius:50%; margin:20px auto; position:relative; overflow:hidden;\"\u003e\n                \u003cdiv style=\"position:absolute; width:100%; height:1px; background:var(--os-dim); top:50%;\"\u003e\u003c\/div\u003e\n                \u003cdiv style=\"position:absolute; width:1px; height:100%; background:var(--os-dim); left:50%;\"\u003e\u003c\/div\u003e\n                \u003cdiv style=\"width:80px; height:80px; border-right:2px solid var(--os-green); position:absolute; bottom:50%; left:0; transform-origin:bottom right; animation: scanSweep 2s linear infinite; background: linear-gradient(to right, rgba(0,255,0,0) 0%, rgba(0,255,0,0.4) 100%);\"\u003e\u003c\/div\u003e\n                \u003cdiv style=\"width:6px; height:6px; background:var(--os-red); border-radius:50%; position:absolute; top:40px; left:50px; box-shadow: 0 0 5px var(--os-red);\"\u003e\u003c\/div\u003e\n                \u003cdiv style=\"width:6px; height:6px; background:var(--os-green); border-radius:50%; position:absolute; bottom:50px; right:40px; box-shadow: 0 0 5px var(--os-green);\"\u003e\u003c\/div\u003e\n                \u003cdiv style=\"width:4px; height:4px; background:var(--os-text); border-radius:50%; position:absolute; top:90px; left:120px;\"\u003e\u003c\/div\u003e\n            \u003c\/div\u003e\n            \u003cdiv class=\"os-green\" style=\"text-align:center; font-size:12px; margin-top:20px; animation: blink 1.5s infinite;\"\u003eSCANNING FREQUENCIES...\u003c\/div\u003e\n        `;\n        screen.appendChild(content);\n    }\n\n    function appUsbAuto(title) {\n        clearScreen();\n        renderHeader(title.substring(0,14));\n        const content = document.createElement('div');\n        content.className = 'os-content';\n        content.innerHTML = `\n            \u003cdiv class=\"os-menu-item\"\u003e\u003e SGP SEND\u003c\/div\u003e\n            \u003cdiv class=\"os-menu-item\"\u003e\u003e SCRIPT RUN\u003c\/div\u003e\n            \u003cdiv class=\"os-menu-item\"\u003e\u003e NOTEPAD LOG\u003c\/div\u003e\n            \u003cdiv class=\"os-menu-item\" style=\"border-color:var(--os-red); color:var(--os-red);\"\u003e\u003e SGP SIGNAL\u003c\/div\u003e\n            \u003cdiv class=\"os-dim\" style=\"font-size:10px; text-align:center; margin-top:20px;\"\u003e[ CONNECT USB DEVICE ]\u003c\/div\u003e\n        `;\n        screen.appendChild(content);\n    }\n\n    function appFaces(title) {\n        clearScreen();\n        const content = document.createElement('div');\n        content.style.height = '100%';\n        content.style.display = 'flex';\n        content.style.flexDirection = 'column';\n        content.style.justifyContent = 'center';\n        content.style.alignItems = 'center';\n        content.style.background = '#000';\n        \n        const now = new Date();\n        const timeStr = now.getHours().toString().padStart(2, '0') + \":\" + now.getMinutes().toString().padStart(2, '0');\n        \n        content.innerHTML = `\n            \u003cdiv style=\"font-size:50px; font-weight:bold; color:#fff; font-family:'Inter', sans-serif;\"\u003e${timeStr}\u003c\/div\u003e\n            \u003cdiv style=\"font-size:14px; color:#aaa; font-family:'Inter', sans-serif; margin-bottom: 20px;\"\u003e22°C SUNNY\u003c\/div\u003e\n            \n            \u003cdiv style=\"position:relative; width:120px; height:120px;\"\u003e\n                \u003csvg width=\"120\" height=\"120\" viewBox=\"0 0 120 120\"\u003e\n                    \u003ccircle cx=\"60\" cy=\"60\" r=\"50\" fill=\"none\" stroke=\"#310\" stroke-width=\"10\"\/\u003e\n                    \u003ccircle cx=\"60\" cy=\"60\" r=\"50\" fill=\"none\" stroke=\"#f03\" stroke-width=\"10\" stroke-dasharray=\"314\" stroke-dashoffset=\"60\" stroke-linecap=\"round\" transform=\"rotate(-90 60 60)\"\/\u003e\n                    \n                    \u003ccircle cx=\"60\" cy=\"60\" r=\"38\" fill=\"none\" stroke=\"#130\" stroke-width=\"10\"\/\u003e\n                    \u003ccircle cx=\"60\" cy=\"60\" r=\"38\" fill=\"none\" stroke=\"#0f0\" stroke-width=\"10\" stroke-dasharray=\"238\" stroke-dashoffset=\"100\" stroke-linecap=\"round\" transform=\"rotate(-90 60 60)\"\/\u003e\n                    \n                    \u003ccircle cx=\"60\" cy=\"60\" r=\"26\" fill=\"none\" stroke=\"#013\" stroke-width=\"10\"\/\u003e\n                    \u003ccircle cx=\"60\" cy=\"60\" r=\"26\" fill=\"none\" stroke=\"#0df\" stroke-width=\"10\" stroke-dasharray=\"163\" stroke-dashoffset=\"80\" stroke-linecap=\"round\" transform=\"rotate(-90 60 60)\"\/\u003e\n                \u003c\/svg\u003e\n            \u003c\/div\u003e\n        `;\n        screen.appendChild(content);\n    }\n    \n    function appGames(title) {\n        clearScreen();\n        renderHeader(title.substring(0,14));\n        const content = document.createElement('div');\n        content.className = 'os-content';\n        content.innerHTML = `\n            \u003cdiv class=\"os-menu-item\"\u003eFLAPPY DRONE\u003c\/div\u003e\n            \u003cdiv class=\"os-menu-item\"\u003ePONG\u003c\/div\u003e\n            \u003cdiv class=\"os-menu-item\"\u003eSNAKE\u003c\/div\u003e\n            \u003cdiv class=\"os-menu-item\"\u003eSPACE INVADERS\u003c\/div\u003e\n            \u003cdiv class=\"os-dim\" style=\"font-size:10px; text-align:center; margin-top:20px;\"\u003eHardware buttons to play\u003c\/div\u003e\n        `;\n        screen.appendChild(content);\n    }\n\n    function appWiFiMotion(title) {\n        clearScreen();\n        renderHeader(title.substring(0,14));\n        const content = document.createElement('div');\n        content.className = 'os-content';\n        content.innerHTML = `\n            \u003cdiv class=\"os-green\" style=\"text-align:center; margin-top:10px;\"\u003eSIGNAL: CORP_5G\u003c\/div\u003e\n            \u003cdiv style=\"height:80px; border:1px solid var(--os-dim); margin:20px 0; position:relative; overflow:hidden;\"\u003e\n                \u003csvg width=\"200%\" height=\"100%\" style=\"position:absolute; left:0; bottom:0;\"\u003e\n                    \u003cpath id=\"wave\" d=\"M0 40 Q 20 20, 40 40 T 80 40 T 120 40 T 160 40 T 200 40\" fill=\"none\" stroke=\"var(--os-green)\" stroke-width=\"2\"\/\u003e\n                \u003c\/svg\u003e\n            \u003c\/div\u003e\n            \u003cdiv class=\"os-dim\" style=\"text-align:center; font-size:16px;\"\u003eSTATUS: \u003cspan class=\"os-green\"\u003eSTABLE\u003c\/span\u003e\u003c\/div\u003e\n        `;\n        screen.appendChild(content);\n        \n        let offset = 0;\n        const wave = document.getElementById('wave');\n        renderInterval = setInterval(() =\u003e {\n            offset -= 5;\n            let d = `M${offset} 40 `;\n            for(let i=0; i\u003c10; i++) {\n                let amp = Math.random() \u003e 0.8 ? Math.random() * 30 : 5; \/\/ Occasional spike\n                d += `Q ${offset + i*40 + 20} ${40 - amp}, ${offset + (i+1)*40} 40 `;\n            }\n            wave.setAttribute('d', d);\n            if(offset \u003c -80) offset = 0;\n        }, 100);\n    }\n\n    function appAltimeter(title) {\n        clearScreen();\n        renderHeader(title.substring(0,14));\n        const content = document.createElement('div');\n        content.className = 'os-content';\n        content.style.textAlign = 'center';\n        content.innerHTML = `\n            \u003cdiv class=\"os-dim\" style=\"font-size:12px; margin-top:30px;\"\u003eCURRENT ALTITUDE\u003c\/div\u003e\n            \u003cdiv class=\"os-green\" style=\"font-size:42px; font-weight:bold; margin:10px 0;\"\u003e642 m\u003c\/div\u003e\n            \u003cdiv class=\"os-text\" style=\"font-size:14px;\"\u003ePRESSURE: 1013.25 hPa\u003c\/div\u003e\n            \u003cdiv class=\"os-dim\" style=\"font-size:10px; margin-top:30px;\"\u003eCalibrated to QNH\u003c\/div\u003e\n        `;\n        screen.appendChild(content);\n    }\n\n    function appMood(title) {\n        clearScreen();\n        screen.style.animation = 'colorCycle 5s infinite';\n        const content = document.createElement('div');\n        content.className = 'os-content';\n        content.style.display = 'flex';\n        content.style.justifyContent = 'center';\n        content.style.alignItems = 'center';\n        content.innerHTML = `\u003cdiv style=\"background:rgba(0,0,0,0.5); padding:10px; border-radius:10px; color:#fff; font-size:12px;\"\u003eMOOD ACTIVE\u003c\/div\u003e`;\n        screen.appendChild(content);\n    }\n\n    function appBench(title) {\n        clearScreen();\n        renderHeader(title.substring(0,14));\n        const content = document.createElement('div');\n        content.className = 'os-content';\n        content.innerHTML = `\n            \u003cdiv class=\"os-red\" style=\"text-align:center; font-size:18px; margin:20px 0; animation:blink 0.5s infinite;\"\u003eTHROUGHPUT TEST\u003c\/div\u003e\n            \u003cdiv style=\"border:1px solid var(--os-dim); height:15px; margin-bottom:10px;\"\u003e\n                \u003cdiv id=\"bench-bar\" style=\"height:100%; width:0%; background:var(--os-red);\"\u003e\u003c\/div\u003e\n            \u003c\/div\u003e\n            \u003cdiv class=\"os-text\" style=\"font-size:12px;\"\u003eTX RATE: \u003cspan id=\"tx-rate\" class=\"os-green\"\u003e0\u003c\/span\u003e pkt\/s\u003c\/div\u003e\n            \u003cdiv class=\"os-dim\" style=\"font-size:10px; margin-top:10px;\"\u003eMode: Local loopback\u003c\/div\u003e\n        `;\n        screen.appendChild(content);\n        \n        let width = 0;\n        renderInterval = setInterval(() =\u003e {\n            width = (width + 5) % 100;\n            document.getElementById('bench-bar').style.width = width + '%';\n            document.getElementById('tx-rate').innerText = Math.floor(Math.random() * 500 + 1000);\n        }, 100);\n    }\n\n    function appRemote(title) {\n        clearScreen();\n        renderHeader(title.substring(0,14));\n        const content = document.createElement('div');\n        content.className = 'os-content';\n        content.innerHTML = `\n            \u003cdiv style=\"display:grid; grid-template-columns: 1fr 1fr 1fr; gap:5px; width:120px; margin:30px auto;\"\u003e\n                \u003cdiv\u003e\u003c\/div\u003e\u003cdiv class=\"os-menu-item\" style=\"justify-content:center;\"\u003eW\u003c\/div\u003e\u003cdiv\u003e\u003c\/div\u003e\n                \u003cdiv class=\"os-menu-item\" style=\"justify-content:center;\"\u003eA\u003c\/div\u003e\n                \u003cdiv class=\"os-menu-item\" style=\"justify-content:center;\"\u003eS\u003c\/div\u003e\n                \u003cdiv class=\"os-menu-item\" style=\"justify-content:center;\"\u003eD\u003c\/div\u003e\n            \u003c\/div\u003e\n            \u003cdiv class=\"os-dim\" style=\"text-align:center; font-size:10px;\"\u003eLINKED TO HOST PC\u003c\/div\u003e\n        `;\n        screen.appendChild(content);\n    }\n\n    function appTerminal(title) {\n        clearScreen();\n        renderHeader(title.substring(0,14));\n        const content = document.createElement('div');\n        content.className = 'os-content';\n        content.style.fontSize = '10px';\n        content.innerHTML = `\u003cdiv id=\"term-out\"\u003e\u003c\/div\u003e`;\n        screen.appendChild(content);\n        \n        const logs = [\n            \"Initializing interface...\", \"Handshake OK.\", \"Fetching device descriptor...\",\n            \"Tx Pwr: +20dBm\", \"Diagnostic mode enabled.\", \"Listening on CH 6...\",\n            \"Logged 14 packets.\", \"Buffer flush complete.\", \"Ready.\"\n        ];\n        let idx = 0;\n        const out = document.getElementById('term-out');\n        renderInterval = setInterval(() =\u003e {\n            if(idx \u003c logs.length) {\n                out.innerHTML += `\u003cdiv\u003e\u003e ${logs[idx]}\u003c\/div\u003e`;\n                idx++;\n            } else {\n                out.innerHTML += `\u003cdiv\u003e\u003cspan class=\"os-green\"\u003e_\u003c\/span\u003e\u003c\/div\u003e`;\n                clearInterval(renderInterval);\n            }\n        }, 400);\n    }\n\n    function appSysInfo(title) {\n        clearScreen();\n        renderHeader(title.substring(0,14));\n        const content = document.createElement('div');\n        content.className = 'os-content';\n        content.innerHTML = `\n            \u003cdiv class=\"os-text\" style=\"font-size:12px; margin-bottom:5px;\"\u003eFW: SGP OS v2.0-PRO\u003c\/div\u003e\n            \u003cdiv class=\"os-text\" style=\"font-size:12px; margin-bottom:5px;\"\u003eCPU: Xtensa LX7 @ 240MHz\u003c\/div\u003e\n            \u003cdiv class=\"os-text\" style=\"font-size:12px; margin-bottom:5px;\"\u003eRAM: 8MB PSRAM\u003c\/div\u003e\n            \u003cdiv class=\"os-green\" style=\"font-size:12px; margin-bottom:15px;\"\u003eBATTERY: 98% (Discharging)\u003c\/div\u003e\n            \u003cdiv class=\"os-dim\" style=\"font-size:10px;\"\u003eMAC: AA:BB:CC:DD:EE:FF\u003c\/div\u003e\n        `;\n        screen.appendChild(content);\n    }\n\n    function appSensor(title) {\n        clearScreen();\n        renderHeader(title.substring(0,14));\n        const content = document.createElement('div');\n        content.className = 'os-content';\n        content.innerHTML = `\n            \u003cdiv style=\"margin-top:20px;\"\u003e\n                \u003cdiv class=\"os-dim\" style=\"font-size:12px;\"\u003eX-AXIS: \u003cspan id=\"s-x\" class=\"os-text\"\u003e0.00\u003c\/span\u003e\u003c\/div\u003e\n                \u003cdiv style=\"width:100%; height:4px; background:var(--os-dim); margin-bottom:10px;\"\u003e\u003cdiv id=\"b-x\" style=\"height:100%; background:var(--os-green); width:50%;\"\u003e\u003c\/div\u003e\u003c\/div\u003e\n                \n                \u003cdiv class=\"os-dim\" style=\"font-size:12px;\"\u003eY-AXIS: \u003cspan id=\"s-y\" class=\"os-text\"\u003e0.00\u003c\/span\u003e\u003c\/div\u003e\n                \u003cdiv style=\"width:100%; height:4px; background:var(--os-dim); margin-bottom:10px;\"\u003e\u003cdiv id=\"b-y\" style=\"height:100%; background:var(--os-green); width:50%;\"\u003e\u003c\/div\u003e\u003c\/div\u003e\n                \n                \u003cdiv class=\"os-dim\" style=\"font-size:12px;\"\u003eZ-AXIS: \u003cspan id=\"s-z\" class=\"os-text\"\u003e1.00\u003c\/span\u003e\u003c\/div\u003e\n                \u003cdiv style=\"width:100%; height:4px; background:var(--os-dim); margin-bottom:10px;\"\u003e\u003cdiv id=\"b-z\" style=\"height:100%; background:var(--os-green); width:100%;\"\u003e\u003c\/div\u003e\u003c\/div\u003e\n            \u003c\/div\u003e\n        `;\n        screen.appendChild(content);\n        \n        renderInterval = setInterval(() =\u003e {\n            let x = (Math.random() - 0.5) * 0.2;\n            let y = (Math.random() - 0.5) * 0.2;\n            document.getElementById('s-x').innerText = x.toFixed(2);\n            document.getElementById('s-y').innerText = y.toFixed(2);\n            document.getElementById('b-x').style.width = (50 + x*100) + '%';\n            document.getElementById('b-y').style.width = (50 + y*100) + '%';\n        }, 200);\n    }\n\n    function appGraph(title) {\n        clearScreen();\n        renderHeader(title.substring(0,14));\n        const content = document.createElement('div');\n        content.className = 'os-content';\n        content.style.display = 'flex';\n        content.style.alignItems = 'flex-end';\n        content.style.gap = '5px';\n        content.style.paddingTop = '40px';\n        content.innerHTML = `\n            \u003cdiv class=\"bar\" style=\"width:30px; background:var(--os-dim); transition:height 0.2s;\"\u003e\u003c\/div\u003e\n            \u003cdiv class=\"bar\" style=\"width:30px; background:var(--os-green); transition:height 0.2s;\"\u003e\u003c\/div\u003e\n            \u003cdiv class=\"bar\" style=\"width:30px; background:var(--os-text); transition:height 0.2s;\"\u003e\u003c\/div\u003e\n            \u003cdiv class=\"bar\" style=\"width:30px; background:var(--os-green); transition:height 0.2s;\"\u003e\u003c\/div\u003e\n            \u003cdiv class=\"bar\" style=\"width:30px; background:var(--os-dim); transition:height 0.2s;\"\u003e\u003c\/div\u003e\n        `;\n        screen.appendChild(content);\n        \n        const bars = content.querySelectorAll('.bar');\n        renderInterval = setInterval(() =\u003e {\n            bars.forEach(b =\u003e b.style.height = (Math.random() * 100 + 20) + 'px');\n        }, 300);\n    }\n\n    function appAudio(title) {\n        clearScreen();\n        renderHeader(title.substring(0,14));\n        const content = document.createElement('div');\n        content.className = 'os-content';\n        content.innerHTML = `\n            \u003cdiv style=\"display:grid; grid-template-columns: 1fr 1fr; gap:10px; margin-top:20px;\"\u003e\n                \u003cdiv class=\"os-menu-item\" style=\"justify-content:center; color:var(--os-red); border-color:var(--os-red);\"\u003eSIREN\u003c\/div\u003e\n                \u003cdiv class=\"os-menu-item\" style=\"justify-content:center;\"\u003eR2D2\u003c\/div\u003e\n                \u003cdiv class=\"os-menu-item\" style=\"justify-content:center;\"\u003eBOMB\u003c\/div\u003e\n                \u003cdiv class=\"os-menu-item\" style=\"justify-content:center;\"\u003eUFO\u003c\/div\u003e\n            \u003c\/div\u003e\n            \u003cdiv class=\"os-dim\" style=\"text-align:center; font-size:10px; margin-top:10px;\"\u003eBUZZER READY\u003c\/div\u003e\n        `;\n        screen.appendChild(content);\n    }\n\n    function appChronos(title) {\n        clearScreen();\n        renderHeader(title.substring(0,14));\n        const content = document.createElement('div');\n        content.className = 'os-content';\n        content.style.textAlign = 'center';\n        content.innerHTML = `\n            \u003cdiv class=\"os-dim\" style=\"font-size:12px; margin-top:30px;\"\u003eTACTICAL TIMER\u003c\/div\u003e\n            \u003cdiv id=\"chrono-time\" class=\"os-green\" style=\"font-size:40px; font-weight:bold; margin:10px 0;\"\u003e00:00:00\u003c\/div\u003e\n            \u003cdiv style=\"display:flex; justify-content:center; gap:10px; margin-top:20px;\"\u003e\n                \u003cdiv class=\"os-menu-item\" style=\"padding:5px 15px;\"\u003eSTART\u003c\/div\u003e\n                \u003cdiv class=\"os-menu-item\" style=\"padding:5px 15px; border-color:var(--os-red); color:var(--os-red);\"\u003eSTOP\u003c\/div\u003e\n            \u003c\/div\u003e\n        `;\n        screen.appendChild(content);\n        \n        let secs = 0;\n        renderInterval = setInterval(() =\u003e {\n            secs++;\n            let h = Math.floor(secs \/ 3600).toString().padStart(2, '0');\n            let m = Math.floor((secs % 3600) \/ 60).toString().padStart(2, '0');\n            let s = (secs % 60).toString().padStart(2, '0');\n            document.getElementById('chrono-time').innerText = `${h}:${m}:${s}`;\n        }, 1000);\n    }\n\n    \/\/ Initialize Menu on Load\n    window.onload = function() {\n        appMenu();\n        \n        \/\/ Añadir el sonido a cualquier interacción (clic) dentro de la carcasa del reloj\n        document.querySelector('.watch-case').addEventListener('mousedown', playBeep);\n        document.querySelector('.watch-case').addEventListener('touchstart', playBeep, {passive: true});\n    };\n\n\u003c\/script\u003e\n\n\u003c\/body\u003e","brand":"sgpstore","offers":[{"title":"Orange","offer_id":57834602070348,"sku":null,"price":199.0,"currency_code":"EUR","in_stock":false},{"title":"Black","offer_id":57834602103116,"sku":null,"price":199.0,"currency_code":"EUR","in_stock":true}],"thumbnail_url":"\/\/cdn.shopify.com\/s\/files\/1\/1057\/9807\/4700\/files\/rn-image_picker_lib_temp_465450ff-354f-4947-b2ec-9a0e5dc61fbb.png?v=1778713734"}],"url":"https:\/\/sgpstore.net\/collections\/productos-fisicos.oembed","provider":"sgpstore","version":"1.0","type":"link"}