1<!doctype html> 2<html lang="en"> 3 <head>
4<script> 5window.dataLayer=window.dataLayer||[]; 6(function(){ 7 var pathname=window.location.pathname||'/'; 8 if(!pathname||pathname===''){pathname='/';} 9 var search=window.location.search||''; 10 var page_path=pathname+search; 11 try{ 12 var k='vinobuzz:session-landing-page'; 13 if(!sessionStorage.getItem(k)){sessionStorage.setItem(k,pathname);} 14 var attrKey='vinobuzz:session-utm'; 15 if(!sessionStorage.getItem(attrKey)&&search.length>1){ 16 var sp=new URLSearchParams(search); 17 var keys=['utm_source','utm_medium','utm_campaign','utm_term','utm_content','fbclid','gclid']; 18 var attrs={}; 19 for(var i=0;i<keys.length;i++){ 20 var v=sp.get(keys[i]); 21 if(v)attrs[keys[i]]=v; 22 } 23 if(Object.keys(attrs).length){sessionStorage.setItem(attrKey,JSON.stringify(attrs));} 24 } 25 }catch(e){} 26 window.dataLayer.push({ 27 event:'page_view', 28 page_path:page_path, 29 page_location:window.location.href, 30 page_title:document.title||'' 31 }); 32 window.__vbInitialPageViewSent=1; 33 window.__vbInitialPagePath=page_path; 34})(); 35</script>
35 36<!-- Google Tag Manager (deferred until after load â keeps connections free for app JS) -->
37<script>(function(w,d,s,l,i){ 38function vbLoadGtm(){ 39 if(w.__vbGtmLoaded)return; 40 w.__vbGtmLoaded=1; 41 w[l]=w[l]||[];w[l].push({'gtm.start':new Date().getTime(),event:'gtm.js'}); 42 var f=d.getElementsByTagName(s)[0],j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:''; 43 j.async=true;j.src='https://www.googletagmanager.com/gtm.js?id='+i+dl; 44 j.onload=function(){w.__vbGtmReady=1;}; 45 f.parentNode.insertBefore(j,f); 46} 47if(d.readyState==='complete'){setTimeout(vbLoadGtm,0);} 48else{w.addEventListener('load',function(){setTimeout(vbLoadGtm,0);});} 49})(window,document,'script','dataLayer','GTM-T6G7NZVH');</script>
49 50<!-- End Google Tag Manager --> 51 <meta charset="UTF-8" /> 52 <!-- 53 VB-403: `viewport-fit=cover` is REQUIRED before `env(safe-area-inset-*)` 54 reports anything. Without it iOS Safari resolves every inset to 0. 55 56 Device measurements that pinned this down: win=775, visualViewport=775, 57 overlay height=775, action row bottom=775: geometrically perfect, and 58 still visually cut. So the viewport really is 775px tall and Safari 59 simply paints its bottom toolbar over the last ~104px of it. No viewport 60 unit reports that band (100svh also returned 775); only the safe-area 61 insets do, and they were inert. 62 63 The app already ships 32 `env(safe-area-inset-*)` rules, so it was always 64 written expecting this flag. It was just never set. 65 --> 66 <meta 67 name="viewport" 68 content="width=device-width, initial-scale=1.0, viewport-fit=cover, interactive-widget=resizes-content" 69 /> 70 <!-- 71 VB-403: must match the MobileTopNav surface (@vb-white) so the iOS/Android 72 status-bar strip above the header has no seam. Was a stale brand red. 73 --> 74 <meta name="theme-color" content="#ffffff" /> 75 <meta name="mobile-web-app-capable" content="yes" /> 76 <meta name="apple-mobile-web-app-capable" content="yes" /> 77 <meta name="apple-mobile-web-app-status-bar-style" content="default" /> 78 <meta name="apple-mobile-web-app-title" content="VinoBuzz" /> 79 80 <!-- 81 URL-specific SEO tags are marked data-rh so react-helmet-async (PageSeo) 82 can replace them on product/news pages. Tags without data-rh are left alone 83 (VB-344). Keep homepage values here as the no-JS / first-paint fallback. 84 --> 85 <title>VinoBuzz | Hong Kong's AI wine marketplace</title> 86 <meta 87 data-rh="true" 88 name="description" 89 content="We will match you to a perfect bottle of wine in 10 seconds. No wine knowledge needed." 90 /> 91 92 <!-- Open Graph / Facebook / WhatsApp --> 93 <meta 94 data-rh="true" 95 property="og:title" 96 content="VinoBuzz | Hong Kong's AI wine marketplace" 97 /> 98 <meta 99 data-rh="true" 100 property="og:description" 101 content="We will match you to a perfect bottle of wine in 10 seconds. No wine knowledge needed." 102 /> 103 <meta data-rh="true" property="og:url" content="https://vinobuzz.ai/" /> 104 <meta data-rh="true" property="og:type" content="website" /> 105 <meta 106 data-rh="true" 107 property="og:image" 108 content="https://vinobuzz.ai/images/share-cover.jpg" 109 /> 110 <meta property="og:image:width" content="1200" /> 111 <meta property="og:image:height" content="630" /> 112 <meta property="og:site_name" content="VinoBuzz" /> 113 114 <!-- Twitter --> 115 <meta data-rh="true" name="twitter:card" content="summary_large_image" /> 116 <meta 117 data-rh="true" 118 name="twitter:title" 119 content="VinoBuzz | Hong Kong's AI wine marketplace" 120 /> 121 <meta 122 data-rh="true" 123 name="twitter:description" 124 content="We will match you to a perfect bottle of wine in 10 seconds. No wine knowledge needed." 125 /> 126 <meta 127 data-rh="true" 128 name="twitter:image" 129 content="https://vinobuzz.ai/images/share-cover.jpg" 130 /> 131 132 <!-- Geo --> 133 <meta name="geo.region" content="HK" /> 134 <meta name="geo.placename" content="Hong Kong" /> 135 136 <!-- JSON-LD Structured Data for Google --> 137
137<script type="application/ld+json"> 138 { 139 "@context": "https://schema.org", 140 "@type": ["WebSite", "Organization"], 141 "name": "VinoBuzz", 142 "url": "https://vinobuzz.ai/", 143 "description": "Hong Kong's AI wine marketplace. We match you to a perfect bottle of wine in 10 seconds. No wine knowledge needed.", 144 "image": "https://vinobuzz.ai/images/share-cover.jpg", 145 "areaServed": "HK", 146 "foundingDate": "2025" 147 } 148 </script>
148 149 150 <link rel="preconnect" href="https://fonts.googleapis.com" /> 151 <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> 152 <link 153 rel="preload" 154 as="style" 155 href="https://fonts.googleapis.com/css2?family=Inter:ital,wght@0,400;0,500;0,600;0,700;0,900;1,400;1,500;1,600;1,700;1,900&display=swap" 156 onload="this.onload=null;this.rel='stylesheet'" 157 /> 158 <noscript> 159 <link 160 rel="stylesheet" 161 href="https://fonts.googleapis.com/css2?family=Inter:ital,wght@0,400;0,500;0,600;0,700;0,900;1,400;1,500;1,600;1,700;1,900&display=swap" 162 /> 163 </noscript> 164 <link 165 rel="preload" 166 as="style" 167 href="https://fonts.googleapis.com/css2?family=DM+Serif+Display:ital@0;1&display=swap" 168 onload="this.onload=null;this.rel='stylesheet'" 169 /> 170 <noscript> 171 <link 172 rel="stylesheet" 173 href="https://fonts.googleapis.com/css2?family=DM+Serif+Display:ital@0;1&display=swap" 174 /> 175 </noscript> 176 <link 177 rel="preload" 178 as="style" 179 href="https://at.alicdn.com/t/c/font_5035550_yqrz2olm19e.css" 180 onload="this.onload=null;this.rel='stylesheet'" 181 /> 182 <noscript> 183 <link 184 rel="stylesheet" 185 href="https://at.alicdn.com/t/c/font_5035550_yqrz2olm19e.css" 186 /> 187 </noscript> 188 <link data-rh="true" rel="canonical" href="https://vinobuzz.ai/" /> 189 <link data-rh="true" rel="alternate" hreflang="en" href="https://vinobuzz.ai/" /> 190 <link data-rh="true" rel="alternate" hreflang="zh-HK" href="https://vinobuzz.ai/" /> 191 <link data-rh="true" rel="alternate" hreflang="zh-CN" href="https://vinobuzz.ai/" /> 192 <link data-rh="true" rel="alternate" hreflang="x-default" href="https://vinobuzz.ai/" /> 193 194 <link rel="icon" href="/favicon.svg" type="image/svg+xml" /> 195 <link rel="icon" href="/favicon.ico" sizes="any" /> 196 <link rel="apple-touch-icon" href="/apple-touch-icon.png" /> 197 <link rel="modulepreload" crossorigin href="/assets/index-CKwGbCRx.js"> 198
198<script type="module" fetchpriority="high" crossorigin src="/assets/index-CKwGbCRx.js"></script>
198 199 <link rel="modulepreload" crossorigin href="/assets/vendor-react-pit1hxJu.js"> 200 <link rel="modulepreload" crossorigin href="/assets/vendor-utils-6gUtyQDY.js"> 201 <link rel="modulepreload" crossorigin href="/assets/vendor-antd-CqVW8ePw.js"> 202 <link rel="modulepreload" crossorigin href="/assets/vendor-mobx-BhCQBO_F.js"> 203 <link rel="stylesheet" crossorigin href="/assets/index-Cchj8vy4.css"> 204 205<!-- Meta Pixel Code -->
206<script>
vendor: 399 bytes, lines 206-215
206 207!function(f,b,e,v,n,t,s) 208{if(f.fbq)return;n=f.fbq=function(){n.callMethod? 209n.callMethod.apply(n,arguments):n.queue.push(arguments)}; 210if(!f._fbq)f._fbq=n;n.push=n;n.loaded=!0;n.version='2.0'; 211n.queue=[];t=b.createElement(e);t.async=!0; 212t.src=v;s=b.getElementsByTagName(e)[0]; 213s.parentNode.insertBefore(t,s)}(window, document,'script', 214'https://connect.facebook.net/en_US/fbevents.js'); 215fbq('init', '
2152200485414046101
vendor: 30 bytes, lines 215-216
215'); 216fbq('track', 'PageView');
217</script>
217 218<!-- End Meta Pixel Code --><link rel="manifest" href="/manifest.webmanifest"></head> 219 <body> 220<noscript><img height="1" width="1" style="display:none" 221src="https://www.facebook.com/tr?id=2200485414046101&ev=PageView&noscript=1" 222/></noscript> 223<!-- Google Tag Manager (noscript) -->
vendor: 68 bytes, lines 223-224
223 224<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=
224GTM-T6G7NZVH
vendor: 83 bytes, lines 224-225
224" 225height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
226<!-- End Google Tag Manager (noscript) --> 227 <div id="root"> 228 <div id="vb-boot-splash" aria-live="polite" aria-busy="true"> 229 <style> 230 #vb-boot-splash { 231 box-sizing: border-box; 232 display: flex; 233 flex-direction: column; 234 align-items: center; 235 justify-content: center; 236 gap: 16px; 237 min-height: 100vh; 238 margin: 0; 239 padding: 24px; 240 font-family: 241 Inter, 242 system-ui, 243 -apple-system, 244 "Segoe UI", 245 Roboto, 246 Helvetica, 247 Arial, 248 sans-serif; 249 background: #ffffff; 250 color: rgba(0, 0, 0, 0.87); 251 } 252 #vb-boot-splash p { 253 margin: 0; 254 font-size: 15px; 255 letter-spacing: 0.01em; 256 } 257 #vb-boot-splash .vb-boot-spinner { 258 width: 32px; 259 height: 32px; 260 border: 3px solid rgba(242, 117, 10, 0.25); 261 border-top-color: #f2750a; 262 border-radius: 50%; 263 animation: vb-boot-spin 0.8s linear infinite; 264 } 265 @keyframes vb-boot-spin { 266 to { 267 transform: rotate(360deg); 268 } 269 } 270 </style> 271 <div class="vb-boot-spinner" aria-hidden="true"></div> 272 <p>Loading VinoBuzzâ¦</p> 273 </div> 274 </div> 275
276<script> 277(function(){ 278 var COUNT="vb_stale_chunk_reload",TIME="vb_stale_chunk_reload_t",FRESH="vb_stale_chunk_fresh",MAX=2,WIN=15000,WATCH=45000,READY="data-vb-app"; 279 function isAppReady(){return document.documentElement.getAttribute(READY)==="ready";} 280 function clearSoftRecovery(){try{sessionStorage.removeItem(COUNT);sessionStorage.removeItem(TIME);}catch(e){}} 281 function hasTriedFresh(){try{return sessionStorage.getItem(FRESH)==="1";}catch(e){return false;}} 282 function markFresh(){try{sessionStorage.setItem(FRESH,"1");}catch(e){}} 283 function forceFreshReload(keepFresh){ 284 clearSoftRecovery(); 285 if(!keepFresh){try{sessionStorage.removeItem(FRESH);}catch(e){}} 286 var done=function(){location.reload();}; 287 if("serviceWorker" in navigator){ 288 navigator.serviceWorker.getRegistrations().then(function(regs){ 289 return Promise.all(regs.map(function(r){return r.unregister();})); 290 }).catch(function(){}).then(function(){ 291 if("caches" in window){ 292 return caches.keys().then(function(keys){ 293 return Promise.all(keys.map(function(k){return caches.delete(k);})); 294 }).catch(function(){}); 295 } 296 }).then(done); 297 return; 298 } 299 done(); 300 } 301 function tryRecover(){ 302 try{ 303 if(hasTriedFresh())return false; 304 var now=Date.now(),n=+(sessionStorage.getItem(COUNT)||0),t=+(sessionStorage.getItem(TIME)||0); 305 if(now-t>WIN){n=0;sessionStorage.setItem(TIME,String(now));} 306 if(n<MAX){sessionStorage.setItem(COUNT,String(n+1));location.reload();return true;} 307 markFresh(); 308 forceFreshReload(true); 309 return true; 310 }catch(e){} 311 return false; 312 } 313 function isStillBooting(root){ 314 if(isAppReady())return false; 315 if(!root||!root.hasChildNodes())return true; 316 return root.children.length===1&&!!root.querySelector("#vb-boot-splash"); 317 } 318 function showSlowLoadHint(){ 319 var splash=document.getElementById("vb-boot-splash"); 320 if(!splash||isAppReady())return; 321 var hint=splash.querySelector(".vb-boot-hint"); 322 if(hint)return; 323 hint=document.createElement("p"); 324 hint.className="vb-boot-hint"; 325 hint.style.cssText="margin:8px 0 0;font-size:13px;opacity:0.75"; 326 hint.textContent="Still loading â large download on slow networks can take up to a minute."; 327 splash.appendChild(hint); 328 } 329 function showFallback(){ 330 var root=document.getElementById("root"); 331 if(!root||!isStillBooting(root))return; 332 root.innerHTML='<div style="padding:24px;max-width:480px;margin:0 auto;font-family:system-ui,sans-serif;text-align:center"><h1 style="font-size:1.25rem;margin:0 0 12px">Something went wrong</h1><p style="color:#666;margin:0 0 20px">VinoBuzz could not start after updating. Please try again.</p><button type="button" id="vb-fresh-reload-btn" style="padding:10px 20px;font-size:16px;cursor:pointer">Try again</button></div>'; 333 var freshBtn=root.querySelector("#vb-fresh-reload-btn"); 334 if(freshBtn){freshBtn.onclick=function(){forceFreshReload(false);};} 335 } 336 function handleBootFailure(){ 337 if(isAppReady())return; 338 if(!tryRecover()){showFallback();} 339 } 340 document.querySelectorAll('script[type="module"][src]').forEach(function(el){ 341 el.addEventListener("error",function(){handleBootFailure();}); 342 }); 343 window.addEventListener("load",function(){ 344 setTimeout(showSlowLoadHint,15000); 345 setTimeout(function(){ 346 if(isStillBooting(document.getElementById("root"))){handleBootFailure();} 347 },WATCH); 348 }); 349})(); 350</script>
350</body> 351</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.