1<!DOCTYPE html> 2<html lang="en"> 3 <head> 4 <meta charset="UTF-8" /> 5 <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1, user-scalable=no, viewport-fit=cover" /> 6
6<script> 7 // Mobile landscape â iPad layout. 8 // Small phones in landscape (e.g. iPhone SE 667Ã375) have physical 9 // width < 768, so Tailwind's `md:` breakpoint never engages and they 10 // get the cramped mobile layout. Force the viewport to 820px wide in 11 // that case so the browser renders the iPad/tablet layout instead. 12 // We touch the viewport meta directly so this works before React mounts. 13 (function() { 14 var meta = document.querySelector('meta[name="viewport"]'); 15 if (!meta) return; 16 var PORTRAIT = 'width=device-width, initial-scale=1.0, maximum-scale=1, user-scalable=no, viewport-fit=cover'; 17 var LANDSCAPE_TABLET = 'width=820, initial-scale=1.0, maximum-scale=1, user-scalable=no, viewport-fit=cover'; 18 function apply() { 19 // Use screen.width/height which reflect physical device dimensions, 20 // not the (possibly already-zoomed) viewport innerWidth. 21 var sw = window.screen && window.screen.width || window.innerWidth; 22 var sh = window.screen && window.screen.height || window.innerHeight; 23 var landscape = window.matchMedia('(orientation: landscape)').matches; 24 // Smallest dimension is the true physical width on phones. 25 var minDim = Math.min(sw, sh); 26 var isPhoneSizedLandscape = landscape && minDim < 768; 27 var desired = isPhoneSizedLandscape ? LANDSCAPE_TABLET : PORTRAIT; 28 if (meta.getAttribute('content') !== desired) { 29 meta.setAttribute('content', desired); 30 } 31 } 32 apply(); 33 window.addEventListener('orientationchange', function() { setTimeout(apply, 50); }); 34 window.addEventListener('resize', apply); 35 })(); 36 </script>
36 37 <meta name="theme-color" content="#120E0A" /> 38 <meta name="apple-mobile-web-app-capable" content="yes" /> 39 <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" /> 40 <meta name="apple-mobile-web-app-title" content="HomeCasa" /> 41 <meta name="description" content="HomeCasa⢠â The Intelligence Layer for Homes. Available exclusively through Certified Design Partners." /> 42 <meta property="og:title" content="HomeCasa⢠â The Intelligence Layer for Homes" /> 43 <meta property="og:description" content="The Intelligence Layer for Homes. Designed. Integrated. Orchestrated. Available exclusively through Certified Design Partners." /> 44 <meta property="og:type" content="website" /> 45 <meta property="og:url" content="https://mycasa.replit.app/" /> 46 <meta property="og:image" content="https://mycasa.replit.app/og-image.png?v=7" /> 47 <meta property="og:image:width" content="1200" /> 48 <meta property="og:image:height" content="630" /> 49 <meta name="twitter:card" content="summary_large_image" /> 50 <meta name="twitter:title" content="HomeCasa⢠â The Intelligence Layer for Homes" /> 51 <meta name="twitter:description" content="The Intelligence Layer for Homes. Available exclusively through Certified Design Partners." /> 52 <meta name="twitter:image" content="https://mycasa.replit.app/og-image.png?v=7" /> 53 <link rel="icon" type="image/png" href="/favicon.png?v=4" /> 54 <link rel="icon" type="image/png" sizes="192x192" href="/icon-192.png?v=4" /> 55 <link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png?v=4" /> 56 <link rel="manifest" href="/manifest.json?v=4" /> 57 <link rel="preconnect" href="https://fonts.googleapis.com"> 58 <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> 59 <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet"> 60 <title>HomeCasa⢠â The Intelligence Layer for Homes</title> 61
61<script type="module" crossorigin src="/assets/index-CShcmsL3.js"></script>
61 62 <link rel="stylesheet" crossorigin href="/assets/index-kla4FAcD.css"> 63 </head> 64 <body> 65 <div id="root"> 66 <div id="loading-indicator" style="display:flex;flex-direction:column;align-items:center;justify-content:center;min-height:100vh;font-family:system-ui,sans-serif;background:#120E0A;"> 67 <div style="width:40px;height:40px;border:3px solid rgba(201,165,90,0.15);border-top-color:rgba(201,165,90,0.7);border-radius:50%;animation:spin 1s linear infinite;"></div> 68 <p style="margin-top:16px;color:rgba(201,165,90,0.5);font-size:13px;letter-spacing:0.1em;">Loading HomeCasa...</p> 69 </div> 70 <style>@keyframes spin{to{transform:rotate(360deg)}}</style> 71 </div> 72
72<script> 73 // Global error handler for older browsers 74 window.onerror = function(msg, url, line, col, error) { 75 var root = document.getElementById('root'); 76 if (root) { 77 root.innerHTML = '<div style="padding:20px;text-align:center;font-family:system-ui;max-width:400px;margin:0 auto;background:#120E0A;min-height:100vh;display:flex;flex-direction:column;align-items:center;justify-content:center;"><h2 style="color:rgba(201,165,90,0.9);font-size:20px;">Something went wrong</h2><p style="color:rgba(245,235,220,0.5);word-break:break-all;font-size:14px;margin:16px 0;">' + msg + '</p><button onclick="location.reload()" style="padding:12px 24px;background:rgba(201,165,90,0.15);color:rgba(201,165,90,0.9);border:1px solid rgba(201,165,90,0.3);border-radius:8px;font-size:16px;">Reload App</button><p style="margin-top:16px;"><a href="/compatibility" style="color:rgba(201,165,90,0.6);font-size:14px;">Check Device Compatibility</a></p></div>'; 78 } 79 return false; 80 }; 81 </script>
81 82
82<script> 83 (function() { 84 if (!('serviceWorker' in navigator)) return; 85 var isProd = location.hostname === 'mycasa.replit.app' || location.hostname === 'homecasa.ai' || location.hostname === 'www.homecasa.ai'; 86 if (!isProd) { 87 navigator.serviceWorker.getRegistrations().then(function(regs) { 88 regs.forEach(function(r) { r.unregister(); }); 89 }); 90 caches.keys().then(function(names) { 91 names.forEach(function(name) { caches.delete(name); }); 92 }); 93 return; 94 } 95 var reloading = false; 96 window.addEventListener('load', function() { 97 navigator.serviceWorker.register('/sw.js', { updateViaCache: 'none' }) 98 .then(function(registration) { 99 console.log('SW registered:', registration); 100 registration.update(); 101 if (registration.waiting) { 102 registration.waiting.postMessage('SKIP_WAITING'); 103 } 104 registration.addEventListener('updatefound', function() { 105 var newWorker = registration.installing; 106 if (newWorker) { 107 newWorker.addEventListener('statechange', function() { 108 if (newWorker.state === 'installed' && navigator.serviceWorker.controller) { 109 newWorker.postMessage('SKIP_WAITING'); 110 } 111 }); 112 } 113 }); 114 115 // Poll for updates every 5 minutes so long-lived sessions 116 // pick up new deploys without a manual refresh. 117 setInterval(function() { 118 registration.update().catch(function() {}); 119 }, 5 * 60 * 1000); 120 121 // Also check when the tab becomes visible again (e.g. user 122 // returns from background) and when the network reconnects. 123 document.addEventListener('visibilitychange', function() { 124 if (document.visibilityState === 'visible') { 125 registration.update().catch(function() {}); 126 } 127 }); 128 window.addEventListener('online', function() { 129 registration.update().catch(function() {}); 130 }); 131 }) 132 .catch(function(error) { 133 console.log('SW registration failed:', error); 134 }); 135 }); 136 navigator.serviceWorker.addEventListener('controllerchange', function() { 137 if (!reloading) { 138 reloading = true; 139 window.location.reload(); 140 } 141 }); 142 143 // Auto-recover from stale-chunk failures ("Importing a module script 144 // failed", "Failed to fetch dynamically imported module", etc.). 145 // These happen when the service worker cached an old index.html that 146 // points at JS chunks that no longer exist on the server. We clear 147 // caches + unregister SW + reload, all silently. A sessionStorage 148 // guard prevents an infinite recovery loop. 149 function isChunkLoadError(msg) { 150 if (!msg) return false; 151 msg = String(msg); 152 return /Importing a module script failed/i.test(msg) 153 || /Failed to fetch dynamically imported module/i.test(msg) 154 || /error loading dynamically imported module/i.test(msg) 155 || /ChunkLoadError/i.test(msg) 156 || /Loading chunk \d+ failed/i.test(msg) 157 || /Loading CSS chunk/i.test(msg); 158 } 159 var RECOVERY_KEY = '__hc_chunk_recovery_at'; 160 function attemptChunkRecovery(reason) { 161 try { 162 var last = parseInt(sessionStorage.getItem(RECOVERY_KEY) || '0', 10); 163 // Don't loop: if we recovered less than 60s ago, give up and let 164 // the real error surface so the user can see it. 165 if (Date.now() - last < 60000) { 166 console.warn('[ChunkRecovery] Skipping â recovered recently. Reason:', reason); 167 return; 168 } 169 sessionStorage.setItem(RECOVERY_KEY, String(Date.now())); 170 } catch (e) {} 171 console.warn('[ChunkRecovery] Stale chunk detected, clearing caches and reloading:', reason); 172 var done = function() { 173 try { window.location.reload(); } catch (e) {} 174 }; 175 var tasks = []; 176 try { 177 if ('serviceWorker' in navigator) { 178 tasks.push(navigator.serviceWorker.getRegistrations().then(function(regs) { 179 return Promise.all(regs.map(function(r) { return r.unregister(); })); 180 }).catch(function() {})); 181 } 182 if (typeof caches !== 'undefined' && caches.keys) { 183 tasks.push(caches.keys().then(function(names) { 184 return Promise.all(names.map(function(n) { return caches.delete(n); })); 185 }).catch(function() {})); 186 } 187 } catch (e) {} 188 Promise.all(tasks).then(done, done); 189 // Hard timeout in case the above hangs 190 setTimeout(done, 2500); 191 } 192 window.addEventListener('error', function(ev) { 193 var msg = (ev && (ev.message || (ev.error && ev.error.message))) || ''; 194 var src = ev && ev.target && (ev.target.src || ev.target.href); 195 // Module script load failures often surface as a script element 196 // error event with no message â detect by tag + src ending in .js 197 if (isChunkLoadError(msg)) { 198 attemptChunkRecovery(msg); 199 return; 200 } 201 if (ev && ev.target && ev.target.tagName === 'SCRIPT' && src && /\.js(\?|$)/.test(src)) { 202 attemptChunkRecovery('script load failed: ' + src); 203 } 204 }, true); 205 window.addEventListener('unhandledrejection', function(ev) { 206 var reason = ev && ev.reason; 207 var msg = reason && (reason.message || reason.toString && reason.toString()); 208 if (isChunkLoadError(msg)) { 209 attemptChunkRecovery(msg); 210 } 211 }); 212 })(); 213 </script>
213 214 </body> 215</html>
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.