1<!DOCTYPE html> 2<html lang="ko"> 3<head> 4 <base href="/"> 5 6 <meta charset="UTF-8"> 7 <meta content="IE=Edge" http-equiv="X-UA-Compatible"> 8 <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover"> 9 <!-- ëë© í¼ë² (2026-05-31, doc/runbook/landing_merchant_pivot.md): 10 ë¹ë¡ê·¸ì¸ / = ëë¤ ë§¤ì¥ ì¬ì¥ë ë¨ì¼ ì¸ì¼ì¦ íì´ì§. 11 ìë¹ì(구매ì/ë°ëì´)ë ë§¤ì¥ QR / ì¹´í¡ ì 물ë§í¬ë¡ ì í ì쪽 ì§í â ëë© ê±°ì¹ì§ ìì. 12 ë©í·OG = ì¬ì¥ë íê². NSFW/ë¹ì ì¥ì ì½ê´Â·ì°ë ¹ì ì± íì´ì§ìë§ (ë©ì¸ ë ¸ì¶ 0). --> 13 <meta name="description" content="StyleVoiceTalk â ëë¤ ë§¤ì¥ë, ëëì´ ìíê¶ì íëë¤. ìëì´ ì¹´í¡ì¼ë¡ ë³´ë¸ ìì± ì ë¬¼ì¿ í°, ë°ì ì¬ëì´ ì°ë¦¬ ê°ê²ë¥¼ ì°¾ììµëë¤. ì¤ì¹ë¹ 0, í ì¤ê° ì¬ì¥ë ê³ì¢ë¡ ì§ì ì ì°."> 14 <meta name="keywords" content="ëë¤ ë§¤ì¥ ìíê¶, ì¹´í ìì± ì ë¬¼ì¿ í°, ë§¤ì¥ ì ë¶ ë§¤ì¶, ìì±í¸ì§ ì¿ í°, ì¹´í ì¬ì¥ë, zero-config ë§¤ì¥ ë±ë¡, í ì¤ ì§ì ì ì°"> 15 16 <!-- Open Graph (SNS 미리보기) â ì¬ì¥ë íê² --> 17 <meta property="og:title" content="StyleVoiceTalk â ëë¤ ë§¤ì¥ë, ëëì´ ìíê¶ì íëë¤"> 18 <meta property="og:description" content="ìëì´ ì¹´í¡ì¼ë¡ ìì± ì ë¬¼ì¿ í°ì ë³´ë´ê³ , ë°ì ì¬ëì´ ì°ë¦¬ ê°ê²ë¥¼ ì°¾ììµëë¤. ì¤ì¹ë¹Â·ìì ì¡ 0, í ì¤ê° ì¬ì¥ë ê³ì¢ë¡ ì§ì ì ì°."> 19 <meta property="og:type" content="website"> 20 <meta property="og:image" content="icons/Icon-512.png"> 21 <meta name="twitter:card" content="summary_large_image"> 22 <!-- 18+ ì½í ì¸ ë ì¸ì¦ í ìì ëíì ë¶ê° í ê¸ë¡ë§ ë ¸ì¶ â ë©ì¸ì ì¼ë° ë±ê¸ --> 23 <meta name="rating" content="general"> 24 25 <meta name="theme-color" content="#1F2540"> 26 27 <!-- ì´ê¸° ë¡ë© ê°ì â 모ë°ì¼ 첫 방문 ë°±ì íë©´ ìµìí. 28 preconnect: TLS/DNS í¸ëì °ì´í¬ë¥¼ íì±ê³¼ ë³íí´ 0.5~1s ì ê°. 29 Flutter ìì°(main.dart.js/canvaskit.wasm) preload ë ì ì preload ê° ìëë¼ 30 ìë ì¸ë¼ì¸ ì¤í¬ë¦½í¸ê° ê²½ë¡ë³ë¡ ì¡°ê±´ë¶ ì£¼ì íë¤ (P1, req_web_build_lightening.md). --> 31 <link rel="preconnect" href="https://www.gstatic.com" crossorigin> 32 <link rel="preconnect" href="https://accounts.google.com" crossorigin> 33 <link rel="preconnect" href="https://dcwufunxyddhtnsmapdl.supabase.co" crossorigin> 34 <!-- supabase: ì ì ëë©ì´ ë¡ê·¸ì¸ ì¸ì (sb-*-auth-token) ê°ì§ì ì¬ì© â ì ì§(preload). --> 35 <link rel="preload" as="script" href="vendor/supabase-2.45.4.min.js"> 36 <!-- kakao SDK: ëë© ì²« paint ë¶íì(/message ê³µì ììë§ ì¬ì©) â prefetch ë¡ ê°ë±. --> 37 <link rel="prefetch" as="script" href="https://t1.kakaocdn.net/kakao_js_sdk/2.7.2/kakao.min.js" crossorigin> 38 <!-- â ï¸ Flutter ìì°(main.dart.js/flutter.js/canvaskit.wasm â 4MB) ì ì preload ì ê±°. 39 ì ì í('/')ì Flutter 를 ë¶í íì§ ìì¼ë¯ë¡(ìë ë¶í¸ ê²ì´í¸ `if (isStaticHome) return`) 40 ëë©ë§ ë³´ê³ ì´ííë 첫 방문ììê² ~4MB 를 무조건 ë°ê² íì§ ìëë¤. ëì ê²½ë¡ë³ ì¡°ê±´ë¶: 41 · ë¹-í(ë¥ë§í¬/ì± ì§ì ) = ì¦ì ê³ ì°ì ìì preload (ë¶í ê°ì, 기존 ëì ë³´ì¡´) 42 · í = ì¦ì ë¤ì´ë¡ë X (ëë© LCP·íì´ë¡ ììê³¼ ëìí ê²½ì íí¼), CTA hover/touch ì 43 í ë²ë§ ì ì°ì ìì ìë°ì â í´ë¦ ì í ê°ì. 44 doc/runbook/req_web_build_lightening.md (P1). --> 45 <!-- ë°°í¬ sha â deploy.sh ê° e91e08b 를 ì¤ì sha ë¡ ì¹í (Fix 1, req_web_stale_bundle_login_return). 46 __vtVer(path): main.dart.js ìí¸ë¦¬í¬ì¸í¸ë¥¼ path?v=<sha> ë¡ ë²ì â iOS Safari ê° ì ë²ë¤ì 47 HTTP ìºììì ì¬ì¬ì©íì§ ëª»íê²(stale ë²ë¤ â ê°ì ì¬ë¡ê·¸ì¸ ë°©ì§). ê°ì ë°°í¬ ë´ ëì¼ URL = ìºì hit. 48 â ï¸ deferred parts(.part.js)ë dart2js ê° encodeURIComponent ë¡ ë¡ë â ?v ë¶ê°. parts ë 49 no-cache + dart2js hash ê²ì¦ì¼ë¡ stale ë°©ì§(stale ì _DeferredScreen ì¬ìë). 미ì¹í/ë¡ì»¬ì ë²ì 미ì ì©. --> 50
50<script> 51 window.__VT_BUILD_SHA = "e91e08b"; 52 window.__vtVer = function (path) { 53 var s = window.__VT_BUILD_SHA || ''; 54 // ì¤ì sha ë hex(+_ts). 미ì¹í placeholder('_'ìì)/í í릿('{'ìì)ì´ë©´ ë²ì 미ì ì©. 55 if (!s || s.charAt(0) === '_' || s.charAt(0) === '{') return path; 56 if (path.indexOf('v=' + s) >= 0) return path; // ì´ë¯¸ ë²ì ë¨(멱ë±) 57 return path + (path.indexOf('?') < 0 ? '?v=' : '&v=') + s; 58 }; 59 </script>
59 60
60<script> 61 (function () { 62 var p = window.location.pathname || '/'; 63 var isStaticHome = (p === '/' || p === ''); 64 function pre(rel, as, href, opts) { 65 var l = document.createElement('link'); 66 l.rel = rel; l.as = as; l.href = href; 67 if (opts && opts.crossorigin) l.crossOrigin = ''; 68 if (opts && opts.type) l.type = opts.type; 69 document.head.appendChild(l); 70 } 71 // main.dart.js preload ë ì¤ì ìí¸ë¦¬í¬ì¸í¸ ë¡ëì ê°ì ?v=<sha> URL ì´ì´ì¼ í¨(ì´ì¤ ë¤ì´ë¡ë ë°©ì§). 72 var mainJs = window.__vtVer ? window.__vtVer('main.dart.js') : 'main.dart.js'; 73 if (!isStaticHome) { 74 pre('preload', 'script', 'flutter.js'); 75 pre('preload', 'script', mainJs); 76 pre('preload', 'fetch', 'canvaskit/canvaskit.wasm', { crossorigin: true, type: 'application/wasm' }); 77 } else { 78 var warmed = false; 79 function warm() { 80 if (warmed) return; warmed = true; 81 pre('prefetch', 'script', 'flutter.js'); 82 pre('prefetch', 'script', mainJs); 83 pre('prefetch', 'fetch', 'canvaskit/canvaskit.wasm', { crossorigin: true, type: 'application/wasm' }); 84 } 85 window.addEventListener('pointerover', warm, { once: true, passive: true }); 86 window.addEventListener('touchstart', warm, { once: true, passive: true }); 87 } 88 })(); 89 </script>
89 90 91 <!-- iOS ìì ìì (ë ¸ì¹/ë¤ì´ë믹 ìì¼ëë ëì) --> 92 <style> 93 :root { 94 --sat: env(safe-area-inset-top); 95 --sar: env(safe-area-inset-right); 96 --sab: env(safe-area-inset-bottom); 97 --sal: env(safe-area-inset-left); 98 } 99 html, body { 100 margin: 0; 101 padding: 0; 102 height: 100%; 103 overflow: hidden; 104 /* Flutter ë¼ì´í¸ í ë§ ë°°ê²½ê³¼ ì¼ì¹ â íì´ë¡ dismiss ì§í í° ê¹ë°ì ë°©ì§. */ 105 background: #FAFAFC; 106 /* iOS ë°ì´ì¤ ì¤í¬ë¡¤ ë°©ì§ */ 107 overscroll-behavior: none; 108 -webkit-overflow-scrolling: touch; 109 touch-action: manipulation !important; 110 } 111 flutter-view { 112 touch-action: manipulation; 113 } 114 body { 115 padding-top: var(--sat); 116 padding-bottom: var(--sab); 117 padding-left: var(--sal); 118 padding-right: var(--sar); 119 } 120 /* iOS í ì¤í¸ í¬ê¸° ì¡°ì ë°©ì§ */ 121 body { 122 -webkit-text-size-adjust: 100%; 123 } 124 /* iOS í íì´ë¼ì´í¸ ì ê±° */ 125 * { 126 -webkit-tap-highlight-color: transparent; 127 } 128 /* âââââââââââââââââââââââââââââââââââââââââââââââââââââââââ 129 ì ì í ë©ì¸ â StyleVoiceTalk ì ì¤ì ëë© íì´ì§. 130 ê²½ë¡ '/' ììë Flutter 를 ë¡ëíì§ ìê³ ì´ ì ì HTML ë§ ë ¸ì¶. 131 ì¹´ë í´ë¦ ì window.location ì¼ë¡ /moment/:id ì´ë â Flutter ë¡ë + 132 ë¡ê·¸ì¸ ê²ì´í¸ â í´ë¹ ëª¨ë¨¼í¸ ì¤ì íë©´. 133 âââââââââââââââââââââââââââââââââââââââââââââââââââââââââ */ 134 #home-static { 135 position: fixed; 136 inset: 0; 137 z-index: 9999; 138 background: #FAFAFC; 139 color: #1F2540; 140 font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Pretendard', sans-serif; 141 overflow-y: auto; 142 -webkit-font-smoothing: antialiased; 143 } 144 @media (prefers-color-scheme: dark) { 145 html, body { background: #14172A; } 146 #home-static { background: #14172A; color: #F2F4FF; } 147 #home-static p.lead { color: rgba(255,255,255,0.7); } 148 #home-static .card { background: #1F2540; border-color: rgba(255,255,255,0.06); } 149 #home-static .card .title { color: #F2F4FF; } 150 #home-static .card .sub { color: rgba(255,255,255,0.6); } 151 #home-static .topbar { border-color: rgba(255,255,255,0.06); } 152 #home-static h2 { color: #F2F4FF; } 153 #home-static .login-btn { background: #FF7AA2; color: #fff; } 154 } 155 #home-static.fading { pointer-events: none; opacity: 0; transition: opacity 0.25s; } 156 #home-static .topbar { 157 display: flex; 158 align-items: center; 159 justify-content: space-between; 160 padding: 14px 20px; 161 border-bottom: 1px solid rgba(31,37,64,0.06); 162 background: inherit; 163 position: sticky; 164 top: 0; 165 backdrop-filter: blur(8px); 166 } 167 #home-static .brand { 168 font-size: 17px; 169 font-weight: 800; 170 letter-spacing: -0.4px; 171 } 172 #home-static .brand b { color: #FF7AA2; } 173 #home-static .login-btn { 174 font: inherit; 175 font-size: 13px; 176 font-weight: 700; 177 padding: 8px 16px; 178 border-radius: 999px; 179 border: none; 180 background: #1F2540; 181 color: #FFFFFF; 182 cursor: pointer; 183 -webkit-tap-highlight-color: transparent; 184 } 185 #home-static .user-chip { 186 display: flex; 187 align-items: center; 188 gap: 8px; 189 padding: 6px 12px 6px 6px; 190 border-radius: 999px; 191 background: rgba(31,37,64,0.06); 192 font-size: 13px; 193 font-weight: 600; 194 color: #1F2540; 195 } 196 #home-static .user-chip .avatar { 197 width: 28px; height: 28px; 198 border-radius: 50%; 199 background: #FF7AA2; 200 color: #fff; 201 font-weight: 800; 202 display: flex; 203 align-items: center; 204 justify-content: center; 205 font-size: 12px; 206 overflow: hidden; 207 } 208 #home-static .user-chip .avatar img { 209 width: 100%; height: 100%; object-fit: cover; 210 } 211 #home-static .user-chip .logout { 212 background: none; 213 border: none; 214 cursor: pointer; 215 color: #5A6181; 216 font-size: 12px; 217 padding: 4px 6px; 218 margin-left: 4px; 219 } 220 @media (prefers-color-scheme: dark) { 221 #home-static .user-chip { background: rgba(255,255,255,0.06); color: #F2F4FF; } 222 #home-static .user-chip .logout { color: rgba(255,255,255,0.6); } 223 } 224 #home-static .wrap { 225 max-width: 880px; 226 margin: 0 auto; 227 padding: 28px 20px 60px; 228 } 229 #home-static h1 { 230 font-size: 30px; 231 font-weight: 800; 232 letter-spacing: -0.7px; 233 margin: 0 0 12px; 234 line-height: 1.25; 235 } 236 #home-static h1 b { color: #FF7AA2; } 237 #home-static p.lead { 238 font-size: 15px; 239 line-height: 1.6; 240 color: #5A6181; 241 margin: 0 0 32px; 242 max-width: 600px; 243 } 244 #home-static h2 { 245 font-size: 17px; 246 font-weight: 700; 247 letter-spacing: -0.3px; 248 margin: 28px 0 14px; 249 color: #1F2540; 250 } 251 /* ìì ë°ëª¨ ë¸ë¡ â ë©ì¸ ì¹´í¼ ìì ë°°ì¹. í ë²ì íëì ì¤ëì¤ë§ ì¬ì. */ 252 #home-static .voice-demo { 253 display: flex; 254 flex-direction: column; 255 gap: 8px; 256 margin: 0 0 16px; 257 } 258 #home-static .voice-demo .demo-row { 259 display: flex; 260 flex-wrap: wrap; 261 gap: 10px; 262 align-items: center; 263 } 264 #home-static .voice-demo .demo-btn { 265 display: inline-flex; 266 align-items: center; 267 gap: 8px; 268 padding: 10px 16px; 269 font: inherit; 270 font-size: 14px; 271 font-weight: 700; 272 letter-spacing: -0.2px; 273 color: #1F2540; 274 background: #fff; 275 border: 1.5px solid rgba(255,122,162,0.45); 276 border-radius: 999px; 277 cursor: pointer; 278 transition: background 0.15s, border-color 0.15s, transform 0.06s; 279 box-shadow: 0 2px 6px rgba(31,37,64,0.05); 280 } 281 #home-static .voice-demo .demo-btn:hover { background: #FFF4F8; border-color: #FF7AA2; } 282 #home-static .voice-demo .demo-btn:active { transform: translateY(1px); } 283 #home-static .voice-demo .demo-btn .play-ico { 284 display: inline-flex; width: 22px; height: 22px; 285 align-items: center; justify-content: center; 286 background: #FF7AA2; color: #fff; border-radius: 50%; 287 font-size: 11px; padding-left: 1px; 288 } 289 #home-static .voice-demo .demo-btn[data-state="playing"] .play-ico { background: #5b3df1; } 290 #home-static .voice-demo .demo-btn[data-state="playing"] { 291 background: #F3EEFF; border-color: #5b3df1; 292 } 293 #home-static .voice-demo .demo-cap { 294 font-size: 12.5px; 295 color: #6B7390; 296 letter-spacing: -0.1px; 297 } 298 @media (max-width: 480px) { 299 #home-static .voice-demo .demo-btn { font-size: 13px; padding: 9px 13px; } 300 #home-static .voice-demo .demo-cap { font-size: 11.5px; } 301 } 302 /* ë¤í¬ í ë§ */ 303 @media (prefers-color-scheme: dark) { 304 #home-static .voice-demo .demo-btn { 305 background: rgba(255,255,255,0.08); 306 color: #fff; 307 border-color: rgba(255,122,162,0.55); 308 } 309 #home-static .voice-demo .demo-btn:hover { background: rgba(255,255,255,0.14); } 310 #home-static .voice-demo .demo-btn[data-state="playing"] { 311 background: rgba(91,61,241,0.18); 312 } 313 #home-static .voice-demo .demo-cap { color: rgba(255,255,255,0.6); } 314 } 315 #home-static .grid { 316 display: grid; 317 grid-template-columns: repeat(auto-fill, minmax(170px, 1fr)); 318 gap: 12px; 319 } 320 #home-static .card { 321 background: #FFFFFF; 322 border: 1px solid rgba(31,37,64,0.07); 323 border-radius: 16px; 324 padding: 16px 14px; 325 min-height: 124px; 326 display: flex; 327 flex-direction: column; 328 gap: 6px; 329 box-shadow: 0 1px 2px rgba(31,37,64,0.04); 330 cursor: pointer; 331 transition: transform 0.15s, box-shadow 0.15s; 332 text-align: left; 333 font: inherit; 334 color: inherit; 335 -webkit-tap-highlight-color: transparent; 336 } 337 #home-static .card:hover { 338 transform: translateY(-2px); 339 box-shadow: 0 6px 18px rgba(31,37,64,0.08); 340 } 341 #home-static .card:active { transform: translateY(0); } 342 #home-static .card .emoji { font-size: 26px; line-height: 1; } 343 #home-static .card .title { 344 font-size: 14.5px; 345 font-weight: 700; 346 letter-spacing: -0.3px; 347 color: #1F2540; 348 margin-top: 4px; 349 } 350 #home-static .card .sub { 351 font-size: 12.5px; 352 color: #5A6181; 353 line-height: 1.4; 354 } 355 #home-static .card .meta { 356 font-size: 11px; 357 color: #8089A8; 358 margin-top: auto; 359 padding-top: 6px; 360 } 361 #home-static .footer { 362 margin-top: 40px; 363 padding-top: 16px; 364 border-top: 1px solid rgba(31,37,64,0.06); 365 font-size: 12px; 366 color: #8089A8; 367 text-align: center; 368 } 369 370 /* âââââââââââââââââââââââââââââââââââââââââââââââââââââââââ 371 2026-05 ë©ì¸ ê°í¸ â ì¼ë° SaaS í¬ì§ì ë (ì ì리 ëíÂ·ëª ì·ëë ·ìì ëí). 372 ì±ì¸ 모ëë ìì ëíì ë¶ê° í ê¸ë¡ë§ ë ¸ì¶, ë©ì¸ ì¹´í¼Â·ê²°ì íë¦ê³¼ ë¶ë¦¬. 373 ì¶ê° ìì: age-banner(=privacy), diff-line, trust-badges, quick-start, 374 pricing, brand-footer. 375 âââââââââââââââââââââââââââââââââââââââââââââââââââââââââ */ 376 /* ìë¨ ë â Privacy ê°ì¡°ì© (í¬ì¸í¸ ë¶í, ë¸ëë 컬ë¬). 377 í´ëì¤ëª .age-banner ë backward-compat ìí´ ì ì§. */ 378 #home-static .age-banner { 379 background: #FF7AA2; 380 color: #1F2540; 381 font-size: 12.5px; 382 font-weight: 700; 383 letter-spacing: -0.2px; 384 text-align: center; 385 padding: 9px 14px; 386 border-bottom: 1px solid rgba(31,37,64,0.08); 387 } 388 @media (prefers-color-scheme: dark) { 389 #home-static .age-banner { 390 background: #FF7AA2; 391 color: #1F2540; 392 border-bottom-color: rgba(0,0,0,0.15); 393 } 394 } 395 #home-static .diff-line { 396 font-size: 13px; 397 color: #8089A8; 398 letter-spacing: -0.2px; 399 margin: 0 0 8px; 400 font-style: italic; 401 } 402 @media (prefers-color-scheme: dark) { 403 #home-static .diff-line { color: rgba(255,255,255,0.55); } 404 } 405 /* ë³¸ì¸ ëª©ì리 ë±ë¡ ë²í¼ â ë°ëª¨ ë²í¼ë¤ê³¼ ê°ì í, ê°ì¡° ìì */ 406 #home-static .voice-demo .demo-btn.demo-btn-add { 407 background: #FFF4F8; 408 border-color: #FF7AA2; 409 color: #1F2540; 410 } 411 #home-static .voice-demo .demo-btn.demo-btn-add .play-ico { 412 background: #1F2540; 413 font-size: 13px; 414 padding-left: 0; 415 } 416 @media (prefers-color-scheme: dark) { 417 #home-static .voice-demo .demo-btn.demo-btn-add { 418 background: rgba(255,122,162,0.18); 419 color: #fff; 420 } 421 #home-static .voice-demo .demo-btn.demo-btn-add .play-ico { 422 background: #FF7AA2; 423 color: #1F2540; 424 } 425 } 426 /* Trust badges â Privacy + 18+ */ 427 #home-static .trust-badges { 428 display: flex; 429 flex-wrap: wrap; 430 gap: 10px; 431 margin: 0 0 20px; 432 } 433 #home-static .trust-badges .tb { 434 display: inline-flex; 435 align-items: center; 436 gap: 8px; 437 padding: 8px 13px; 438 border-radius: 12px; 439 background: rgba(31,37,64,0.05); 440 font-size: 12.5px; 441 color: #1F2540; 442 letter-spacing: -0.2px; 443 } 444 #home-static .trust-badges .tb b { 445 font-weight: 700; 446 color: #1F2540; 447 } 448 #home-static .trust-badges .tb .tb-sub { 449 color: #5A6181; 450 font-weight: 500; 451 margin-left: 4px; 452 font-size: 11.5px; 453 } 454 @media (prefers-color-scheme: dark) { 455 #home-static .trust-badges .tb { 456 background: rgba(255,255,255,0.06); 457 color: #F2F4FF; 458 } 459 #home-static .trust-badges .tb b { color: #F2F4FF; } 460 #home-static .trust-badges .tb .tb-sub { color: rgba(255,255,255,0.6); } 461 } 462 /* Quick start CTA */ 463 #home-static .quick-start { 464 margin: 0 0 28px; 465 } 466 #home-static .quick-start .qs-btn { 467 display: flex; 468 width: 100%; 469 align-items: center; 470 gap: 14px; 471 padding: 14px 18px; 472 background: linear-gradient(135deg, #FFF4F8 0%, #F3EEFF 100%); 473 border: 1.5px solid rgba(255,122,162,0.4); 474 border-radius: 16px; 475 cursor: pointer; 476 text-align: left; 477 font: inherit; 478 color: inherit; 479 transition: transform 0.12s, box-shadow 0.12s; 480 box-shadow: 0 2px 6px rgba(255,122,162,0.08); 481 } 482 #home-static .quick-start .qs-btn:hover { 483 transform: translateY(-1px); 484 box-shadow: 0 6px 16px rgba(255,122,162,0.14); 485 } 486 #home-static .quick-start .qs-emoji { font-size: 28px; line-height: 1; } 487 #home-static .quick-start .qs-text { 488 flex: 1; 489 display: flex; 490 flex-direction: column; 491 gap: 2px; 492 } 493 #home-static .quick-start .qs-title { 494 font-size: 14.5px; 495 font-weight: 700; 496 letter-spacing: -0.3px; 497 color: #1F2540; 498 } 499 #home-static .quick-start .qs-sub { 500 font-size: 12.5px; 501 color: #5A6181; 502 letter-spacing: -0.2px; 503 } 504 #home-static .quick-start .qs-arrow { 505 font-size: 18px; 506 color: #FF7AA2; 507 font-weight: 700; 508 } 509 @media (prefers-color-scheme: dark) { 510 #home-static .quick-start .qs-btn { 511 background: linear-gradient(135deg, rgba(255,122,162,0.18) 0%, rgba(91,61,241,0.18) 100%); 512 border-color: rgba(255,122,162,0.5); 513 } 514 #home-static .quick-start .qs-title { color: #F2F4FF; } 515 #home-static .quick-start .qs-sub { color: rgba(255,255,255,0.7); } 516 } 517 /* Pricing ì¹ì */ 518 #home-static .pricing { 519 display: grid; 520 grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); 521 gap: 12px; 522 margin: 0 0 12px; 523 } 524 #home-static .plan { 525 position: relative; 526 background: #FFFFFF; 527 border: 1px solid rgba(31,37,64,0.08); 528 border-radius: 16px; 529 padding: 18px 16px 16px; 530 box-shadow: 0 1px 2px rgba(31,37,64,0.04); 531 } 532 #home-static .plan.plan-standard { 533 border-color: #FF7AA2; 534 box-shadow: 0 4px 14px rgba(255,122,162,0.18); 535 } 536 #home-static .plan-badge { 537 position: absolute; 538 top: -10px; 539 right: 14px; 540 background: #FF7AA2; 541 color: #fff; 542 font-size: 11px; 543 font-weight: 800; 544 padding: 4px 10px; 545 border-radius: 999px; 546 letter-spacing: -0.2px; 547 } 548 #home-static .plan-name { 549 font-size: 14px; 550 font-weight: 700; 551 color: #5A6181; 552 letter-spacing: -0.3px; 553 margin-bottom: 4px; 554 } 555 #home-static .plan-price { 556 font-size: 24px; 557 font-weight: 800; 558 color: #1F2540; 559 letter-spacing: -0.6px; 560 margin-bottom: 12px; 561 } 562 #home-static .plan-price .period { 563 font-size: 13px; 564 font-weight: 600; 565 color: #8089A8; 566 margin-left: 4px; 567 } 568 #home-static .plan-feat { 569 list-style: none; 570 padding: 0; 571 margin: 0 0 14px; 572 } 573 #home-static .plan-feat li { 574 font-size: 12.5px; 575 color: #1F2540; 576 padding: 4px 0; 577 letter-spacing: -0.2px; 578 } 579 #home-static .plan-cta { 580 display: block; 581 width: 100%; 582 padding: 10px 14px; 583 background: rgba(31,37,64,0.06); 584 color: #1F2540; 585 border: none; 586 border-radius: 10px; 587 font: inherit; 588 font-size: 13px; 589 font-weight: 700; 590 cursor: pointer; 591 transition: background 0.12s; 592 letter-spacing: -0.2px; 593 } 594 #home-static .plan-cta:hover { background: rgba(31,37,64,0.12); } 595 #home-static .plan-cta-primary { 596 background: #FF7AA2; 597 color: #fff; 598 } 599 #home-static .plan-cta-primary:hover { background: #f06998; } 600 #home-static .pricing-note { 601 font-size: 11.5px; 602 color: #8089A8; 603 letter-spacing: -0.2px; 604 margin: 0 0 28px; 605 } 606 @media (prefers-color-scheme: dark) { 607 #home-static .plan { 608 background: #1F2540; 609 border-color: rgba(255,255,255,0.08); 610 } 611 #home-static .plan.plan-standard { 612 bor
612der-color: #FF7AA2; 613 } 614 #home-static .plan-name { color: rgba(255,255,255,0.65); } 615 #home-static .plan-price { color: #F2F4FF; } 616 #home-static .plan-price .period { color: rgba(255,255,255,0.55); } 617 #home-static .plan-feat li { color: #F2F4FF; } 618 #home-static .plan-cta { 619 background: rgba(255,255,255,0.08); 620 color: #F2F4FF; 621 } 622 #home-static .plan-cta:hover { background: rgba(255,255,255,0.14); } 623 #home-static .pricing-note { color: rgba(255,255,255,0.55); } 624 } 625 /* ì¹´ë 18+ ë°°ì§ â meta ë¼ì¸ ììì ê°ì¡° */ 626 #home-static .card .meta .badge-18 { 627 display: inline-block; 628 margin-left: 6px; 629 padding: 1px 6px; 630 border-radius: 4px; 631 background: rgba(255,122,162,0.18); 632 color: #d1487c; 633 font-size: 10.5px; 634 font-weight: 800; 635 letter-spacing: 0; 636 } 637 @media (prefers-color-scheme: dark) { 638 #home-static .card .meta .badge-18 { 639 background: rgba(255,122,162,0.28); 640 color: #FFB8CD; 641 } 642 } 643 /* Brand footer íì¥ */ 644 #home-static .brand-footer { 645 margin-top: 48px; 646 padding: 20px 0 8px; 647 border-top: 1px solid rgba(31,37,64,0.08); 648 text-align: center; 649 } 650 #home-static .brand-footer .footer-row { 651 display: flex; 652 flex-wrap: wrap; 653 gap: 14px; 654 justify-content: center; 655 margin-bottom: 14px; 656 } 657 #home-static .brand-footer .footer-row a { 658 color: #5A6181; 659 font-size: 12px; 660 text-decoration: none; 661 letter-spacing: -0.2px; 662 } 663 #home-static .brand-footer .footer-row a:hover { color: #1F2540; text-decoration: underline; } 664 #home-static .brand-footer .footer-meta { 665 font-size: 11.5px; 666 color: #8089A8; 667 letter-spacing: -0.2px; 668 } 669 @media (prefers-color-scheme: dark) { 670 #home-static .brand-footer { border-color: rgba(255,255,255,0.08); } 671 #home-static .brand-footer .footer-row a { color: rgba(255,255,255,0.6); } 672 #home-static .brand-footer .footer-row a:hover { color: #fff; } 673 #home-static .brand-footer .footer-meta { color: rgba(255,255,255,0.45); } 674 } 675 676 /* âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ 677 ì¬ì¥ë ëë© (2026-05-31 í¼ë² â landing_merchant_pivot.md). 678 ì ì¼í ì²ì¤ = SNS ì ì문 ë³´ê³ ê²ìí´ ë¤ì´ì¨ ëë¤ ë§¤ì¥ ì¬ì¥ë. 679 ìë¹ì(구매ì/ë°ëì´)ë ë§¤ì¥ QR / ì¹´í¡ ì 물ë§í¬ë¡ ì í ì쪽 ì§í. 680 âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ */ 681 #home-static .merchant-landing { padding-top: 8px; } 682 683 /* §2 íì´ë¡ ìì 3ê° â ë°ì¤í¬í 3ì´ / 모ë°ì¼ 1ì´ ì¤ìì´í */ 684 #home-static .hero-videos { margin: 0 0 28px; } 685 #home-static .hero-video-row { 686 display: grid; 687 grid-template-columns: repeat(3, 1fr); 688 gap: 12px; 689 } 690 #home-static .hero-video-slot { 691 position: relative; 692 aspect-ratio: 9 / 16; 693 max-height: 380px; 694 border-radius: 14px; 695 overflow: hidden; 696 background: linear-gradient(135deg, #FFE2EC 0%, #DCD4FB 100%); 697 box-shadow: 0 6px 18px rgba(31,37,64,0.10); 698 cursor: pointer; 699 display: flex; align-items: center; justify-content: center; 700 } 701 #home-static .hero-video-slot video, 702 #home-static .hero-video-slot img.poster { 703 position: absolute; inset: 0; 704 width: 100%; height: 100%; 705 object-fit: cover; 706 } 707 #home-static .hero-video-slot .play-overlay { 708 position: absolute; inset: 0; 709 display: flex; align-items: center; justify-content: center; 710 background: rgba(0,0,0,0.18); 711 transition: opacity 0.2s; 712 pointer-events: none; 713 } 714 #home-static .hero-video-slot .play-overlay .play-ico { 715 width: 52px; height: 52px; border-radius: 50%; 716 background: rgba(255,255,255,0.92); 717 display: flex; align-items: center; justify-content: center; 718 font-size: 22px; color: #5b3df1; 719 box-shadow: 0 4px 14px rgba(0,0,0,0.25); 720 } 721 #home-static .hero-video-slot.playing .play-overlay { opacity: 0; } 722 #home-static .hero-video-slot .slot-cap { 723 position: absolute; left: 0; right: 0; bottom: 0; 724 padding: 10px 12px; 725 background: linear-gradient(180deg, rgba(0,0,0,0) 0%, rgba(0,0,0,0.55) 100%); 726 color: #fff; 727 font-size: 13px; font-weight: 600; 728 letter-spacing: -0.3px; 729 text-shadow: 0 1px 2px rgba(0,0,0,0.4); 730 } 731 /* fallback 컨ì placeholder â ìì 미주ì ì */ 732 #home-static .hero-video-slot.fallback { 733 flex-direction: column; gap: 8px; 734 color: #1F2540; 735 } 736 #home-static .hero-video-slot.fallback .fallback-emoji { font-size: 56px; } 737 #home-static .hero-video-slot.fallback .fallback-text { 738 font-size: 14px; font-weight: 700; letter-spacing: -0.3px; 739 text-align: center; padding: 0 12px; 740 } 741 #home-static .hero-cap { 742 margin: 10px 0 0; 743 text-align: center; 744 font-size: 13px; color: #5A6181; 745 letter-spacing: -0.2px; 746 } 747 #home-static .hero-cap .hero-disclosure { 748 font-size: 11px; color: #8089A8; 749 } 750 @media (prefers-color-scheme: dark) { 751 #home-static .hero-cap { color: rgba(255,255,255,0.6); } 752 #home-static .hero-cap .hero-disclosure { color: rgba(255,255,255,0.45); } 753 #home-static .hero-video-slot.fallback { color: #F2F4FF; } 754 } 755 @media (max-width: 720px) { 756 #home-static .hero-video-row { 757 grid-template-columns: 1fr; 758 gap: 14px; 759 } 760 #home-static .hero-video-slot { max-height: 460px; } 761 } 762 763 /* §2 ì ì íì´ë¡ â ìíê¶ í매 íë¦ ì ëë©ì´ì + ë§ì§ë§ ì¤ì ë°ì ìì (2026-06-21). 764 구 hero-videos(mp4 3ê°, ì ë³´ì ë¬ë ¥ ë¶ì¡±) ëì²´. í° ëª©ì ìì â 1ë¶ ê°ì¤ â â¡ìë ì 물 â 765 â¢ê°ê² 방문·QR â â£ê³ì¢ ì ì° 4ë¨ê³ê° ëê³ , ê°ì í° íë ììì â¤ë°ì ì¬ëì ì§ì§ ë°ì 766 (ì¸ë¡ ì¤ì ìì)ì´ ì¬ìë ë¤ ë£¨í. ë©ì¸=ìì¬ì´ ìíê¶ í매 / ìì±í¸ì§=ë¤. íì´ì§ íí
766¬Â·í¼í 767 í ë§ ì í©, í°ì ê³ ì ë¤í¬ ëë°ì´ì¤, ë ì¼Â·ìº¡ì ì ë¼ì´í¸/ë¤í¬ ì ì. ìì URL=GH_REACTION_VIDEO. */ 768 #home-static .gh-hero { margin: 0 0 24px; } 769 #home-static .gh-rail { display:flex; align-items:flex-start; justify-content:center; gap:0; max-width:540px; margin:0 auto 16px; flex-wrap:wrap; } 770 #home-static .gh-stop { display:flex; flex-direction:column; align-items:center; gap:5px; width:90px; text-align:center; opacity:.4; transition:opacity .4s; cursor:pointer; } 771 #home-static .gh-stop:hover { opacity:.85; } 772 #home-static .gh-stop.on { opacity:1; } 773 #home-static .gh-sic { width:36px; height:36px; border-radius:50%; background:#ECE9F6; border:1px solid #DAD6EC; display:flex; align-items:center; justify-content:center; font-size:18px; transition:.4s; } 774 #home-static .gh-stop.on .gh-sic { background:#FF7AA2; border-color:#FF7AA2; } 775 #home-static .gh-stop.coda.on .gh-sic { background:#5b3df1; border-color:#5b3df1; } 776 #home-static .gh-sa { font-size:12px; font-weight:700; color:#1F2540; letter-spacing:-0.2px; } 777 #home-static .gh-sd { font-size:11px; color:#8089A8; } 778 #home-static .gh-conn { color:#C9CCDD; font-size:15px; margin-top:9px; } 779 #home-static .gh-phone { width:226px; height:392px; margin:0 auto; background:#0E0E12; border:7px solid #20202A; border-radius:32px; position:relative; overflow:hidden; box-shadow:0 12px 30px rgba(31,37,64,.18); } 780 #home-static .gh-phone * { box-sizing:border-box; } 781 #home-static .gh-scene { position:absolute; inset:0; padding:16px 15px 24px; opacity:0; transition:opacity .4s ease; display:flex; flex-direction:column; } 782 #home-static .gh-scene.on { opacity:1; } 783 #home-static .gh-scene.vid { padding:0; } 784 #home-static .gh-shead { display:flex; align-items:center; justify-content:space-between; margin-bottom:12px; } 785 #home-static .gh-st { color:#F4F4F6; font-size:13px; font-weight:700; display:flex; align-items:center; gap:6px; } 786 #home-static .gh-tag { background:rgba(255,122,162,.16); color:#FF9EBB; border:1px solid rgba(255,122,162,.34); border-radius:20px; font-size:10px; padding:3px 8px; } 787 #home-static .gh-card { background:#1B1B22; border:1px solid #2A2A33; border-radius:14px; padding:14px; display:flex; flex-direction:column; align-items:center; gap:8px; } 788 #home-static .gh-row { display:flex; align-items:center; gap:8px; width:100%; color:#D7D7DE; font-size:12.5px; } 789 #home-static .gh-row i { color:#3FBF86; font-size:15px; font-style:normal; } 790 #home-static .gh-denoms { display:flex; gap:6px; flex-wrap:wrap; justify-content:center; margin-top:2px; } 791 #home-static .gh-dn { background:rgba(255,122,162,.14); color:#FFA9C2; border:1px solid rgba(255,122,162,.3); border-radius:8px; font-size:11px; padding:4px 8px; } 792 #home-static .gh-circ { width:44px; height:44px; border-radius:50%; background:linear-gradient(135deg,#FF7AA2,#5b3df1); display:flex; align-items:center; justify-content:center; font-size:21px; } 793 #home-static .gh-mut { color:#9A9AA3; font-size:12px; } 794 #home-static .gh-big { color:#fff; font-size:30px; font-weight:800; } 795 #home-static .gh-amt { color:#F4F4F6; font-size:22px; font-weight:800; } 796 #home-static .gh-chip { background:rgba(255,122,162,.16); color:#FFA9C2; border:1px solid rgba(255,122,162,.34); border-radius:20px; font-size:12px; padding:5px 12px; display:inline-flex; align-items:center; gap:5px; } 797 #home-static .gh-chip.dum { background:rgba(150,160,190,.14); color:#AEB6CC; border-color:rgba(150,160,190,.3); font-size:11px; padding:4px 10px; } 798 #home-static .gh-btn { background:linear-gradient(135deg,#FF7AA2,#5b3df1); color:#fff; border-radius:11px; font-size:13px; font-weight:700; text-align:center; padding:11px; width:100%; display:flex; align-items:center; justify-content:center; gap:6px; } 799 #home-static .gh-qr { width:88px; height:88px; display:grid; grid-template-columns:repeat(7,1fr); gap:2px; margin:2px auto; } 800 #home-static .gh-qr span { background:#33333C; border-radius:1px; } 801 #home-static .gh-qr span.f { background:#F4F4F6; } 802 #home-static .gh-ok { position:absolute; inset:0; background:rgba(14,14,18,.86); display:flex; flex-direction:column; align-items:center; justify-content:center; gap:8px; opacity:0; transition:opacity .4s; } 803 #home-static .gh-scene.on .gh-ok.show { opacity:1; } 804 #home-static .gh-okc { width:54px; height:54px; border-radius:50%; background:#2FA86F; color:#fff; display:flex; align-items:center; justify-content:center; font-size:26px; } 805 #home-static .gh-bars { display:flex; align-items:flex-end; gap:8px; height:48px; margin-top:auto; } 806 #home-static .gh-bars i { flex:1; background:#33333C; border-radius:3px 3px 0 0; } 807 #home-static .gh-bars i.y { background:#FF7AA2; } 808 #home-static .gh-reel { position:absolute; inset:0; background:#15131C; display:flex; align-items:center; justify-content:center; } 809 #home-static .gh-reel video { position:absolute; inset:0; width:100%; height:100%; object-fit:cover; } 810 #home-static .gh-reel .gh-face { font-size:78px; opacity:.5; } 811 #home-static .gh-rbadge { position:absolute; top:12px; right:12px; background:rgba(91,61,241,.92); color:#fff; font-size:10px; padding:3px 9px; border-radius:20px; z-index:2; } 812 #home-static .gh-rplay { position:absolute; width:58px; height:58px; border-radius:50%; background:rgba(255,255,255,.94); color:#5b3df1; display:flex; align-items:center; justify-content:center; font-size:22px; z-index:2; animation:ghpulse 1.6s ease-in-out infinite; }
813 @keyframes ghpulse { 0%,100%{transform:scale(1)} 50%{transform:scale(1.08)} } 814 #home-static .gh-rcap { position:absolute; left:0; right:0; bottom:0; padding:14px; background:linear-gradient(180deg,rgba(0,0,0,0),rgba(0,0,0,.72)); color:#fff; font-size:13px; font-weight:700; text-align:left; z-index:2; } 815 #home-static .gh-rcap small { display:block; color:#D7D7DE; font-weight:400; font-size:10.5px; margin-top:3px; } 816 #home-static .gh-cap { color:#5A6181; font-size:13.5px; text-align:center; min-height:38px; margin:14px auto 0; max-width:430px; line-height:1.5; letter-spacing:-0.2px; } 817 #home-static .gh-prog { width:170px; height:3px; background:#E6E8F0; border-radius:2px; margin:6px auto 0; overflow:hidden; } 818 #home-static .gh-prog i { display:block; height:100%; width:0; background:#FF7AA2; border-radius:2px; } 819 /* §2 ë ë©ì¸ ìë¹ì¤ ë ì¸ í ê¸ â ð ìíê¶ / 𥡠í¬ì¥ì©ê¸° ë§ê°í ì¸. ê°ì í° ëª©ì ·ë ì¼Â· 820 ì ëë©ì´ì ìì§ì ì¬ì¬ì©, scene-set ë§ ì¤ì(2026-06-28). ë§ê°í ì¸ = 2015 ëë¤ëì 821 íì¤í ì¬í´ì(ëì í ì¸ ì í + ì¬ì¥ë ë§ê° ì¬ê³ 매ì¶í). */ 822 #home-static .gh-tabs { display:flex; gap:6px; justify-content:center; background:#ECE9F6; border:1px solid #DAD6EC; border-radius:12px; padding:4px; max-width:340px; margin:0 auto 14px; } 823 #home-static .gh-tab { flex:1; border:0; background:transparent; color:#5A6181; font-size:12.5px; font-weight:700; letter-spacing:-0.2px; padding:8px 6px; border-radius:9px; cursor:pointer; transition:.25s; white-space:nowrap; } 824 #home-static .gh-tab.on { background:linear-gradient(135deg,#FF7AA2,#5b3df1); color:#fff; box-shadow:0 4px 12px rgba(91,61,241,.22); } 825 #home-static .gh-lane { display:none; } 826 #home-static .gh-lane.on { display:block; } 827 @media (prefers-color-scheme: dark) { 828 #home-static .gh-sic { background:#1F2540; border-color:rgba(255,255,255,.08); } 829 #home-static .gh-sa { color:#F2F4FF; } 830 #home-static .gh-conn { color:#3A4060; } 831 #home-static .gh-cap { color:rgba(255,255,255,.6); } 832 #home-static .gh-prog { background:#2A2E44; } 833 #home-static .gh-tabs { background:#1F2540; border-color:rgba(255,255,255,.08); } 834 #home-static .gh-tab { color:rgba(255,255,255,.62); } 835 } 836 @media (max-width: 720px) { 837 #home-static .gh-stop { width:62px; } 838 #home-static .gh-sd { font-size:10px; } 839 #home-static .gh-conn { display:none; } 840 } 841 842 /* §2 íì´ë¡ 2ë¨ â ì¢ ë©ìì§ / ì° ì ëë©ì´ì (í°). ìë¨ ê°ë¡ ë ì¼ì´ ë¤ë¹ ë©ë´ë¡ 843 ì¤ì¸ëë 문ì í´ì(2026-06-21): ë ì¼ì ì°ì¸¡ stage ì í° ìë¡ ë¬¶ê³ ì»´í©í¸í(ë¨ì¼ ë¼ë²¨). */ 844 #home-static .gh-hero-2col { display:flex; gap:36px; align-items:center; margin:8px 0 14px; } 845 #home-static .gh-hero-2col .gh-msg { flex:1 1 0; min-width:0; padding-left:36px; } 846 #home-static .gh-hero-2col .gh-stage { flex:0 0 auto; width:380px; } 847 #home-static .gh-hero-2col .gh-hero { margin:0; } 848 #home-static .gh-hero-2col .gh-msg .merchant-h1 { margin-top:0; } 849 #home-static .gh-stage .gh-rail { max-width:100%; } 850 #home-static .gh-stage .gh-stop { width:64px; } 851 #home-static .gh-stage .gh-sd { display:none; } 852 #home-static .gh-stage .gh-cap { max-width:100%; } 853 @media (max-width: 760px) { 854 #home-static .gh-hero-2col { flex-direction:column; gap:18px; align-items:stretch; } 855 #home-static .gh-hero-2col .gh-msg { padding-left:0; } 856 #home-static .gh-hero-2col .gh-stage { width:100%; } 857 #home-static .gh-stage .gh-stop { width:62px; } 858 } 859 860 /* í¤ëë¼ì¸ + CTA */ 861 #home-static .merchant-h1 { 862 font-size: 38px; line-height: 1.18; 863 font-weight: 800; 864 letter-spacing: -1px; 865 margin: 8px 0 12px; 866 color: #1F2540; 867 } 868 #home-static .merchant-h1 b { color: #FF7AA2; } 869 @media (prefers-color-scheme: dark) { 870 #home-static .merchant-h1 { color: #F2F4FF; } 871 } 872 @media (max-width: 720px) { 873 #home-static .merchant-h1 { font-size: 28px; } 874 } 875 #home-static .merchant-sub { 876 font-size: 17px; line-height: 1.55; 877 color: #404764; 878 margin: 0 0 4px; 879 letter-spacing: -0.4px; 880 } 881 @media (prefers-color-scheme: dark) { 882 #home-static .merchant-sub { color: rgba(255,255,255,0.78); } 883 } 884 #home-static .merchant-bonus { 885 font-size: 13px; 886 color: #8089A8; 887 margin: 0 0 22px; 888 letter-spacing: -0.2px; 889 } 890 #home-static .primary-cta-row { 891 margin: 22px 0 36px; 892 display: flex; justify-content: flex-start; 893 } 894 #home-static .primary-cta { 895 display: inline-flex; align-items: center; gap: 10px; 896 padding: 16px 28px; 897 border: 0; border-radius: 14px; 898 background: linear-gradient(135deg, #FF7AA2 0%, #5b3df1 100%); 899 color: #fff; 900 font-size: 17px; font-weight: 700; 901 letter-spacing: -0.4px; 902 cursor: pointer; 903 box-shadow: 0 8px 22px rgba(91,61,241,0.30); 904 transition: transform 0.15s, box-shadow 0.15s; 905 } 906 #home-static .primary-cta:hover { 907 transform: translateY(-2px); 908 box-shadow: 0 12px 28px rgba(91,61,241,0.36); 909 } 910 #home-static .primary-cta:active { transform: translateY(0); } 911 #home-static .primary-cta .arrow { 912 font-size: 19px; transition: transform 0.15s; 913 } 914 #home-static .primary-cta:hover .arrow { transform: translateX(3px); } 915 #home-static .primary-cta-secondary { 916 background: #1F2540; color: #fff; 917 box-shadow: 0 6px 16px rgba(31,37,64,0.20); 918 } 919 #home-static .primary-cta-secondary:hover { box-shadow: 0 10px 20px rgba(31,37,64,0.28); } 920 921 /* H2 (ì¹ì í¤ë) â ì¬ì¥ë ëë© ì ì© */ 922 #home-static .merchant-h2 { 923 margin: 44px 0 14px; 924 font-size: 22px; font-weight: 800; 925 letter-spacing: -0.5px; 926 color: #1F2540; 927 } 928 @media (prefers-color-scheme: dark) { 929 #home-static .merchant-h2 { color: #F2F4FF; } 930 } 931 932 /* §2-1 íí 4ì¹´ë */ 933 #home-static .benefit-grid { 934 display: grid; 935 grid-template-columns: repeat(2, 1fr); 936 gap: 12px; 937 } 938 @media (max-width: 720px) { 939 #home-static .benefit-grid { grid-template-columns: 1fr; } 940 } 941 #home-static .benefit-card { 942 padding: 18px 16px; 943 border-radius: 14px; 944 background: #FFF; 945 border: 1px solid rgba(31,37,64,0.07); 946 box-shadow: 0 4px 14px rgba(31,37,64,0.05); 947 } 948 @media (prefers-color-scheme: dark) { 949 #home-static .benefit-card { background: #1F2540; border-color: rgba(255,255,255,0.07); } 950 } 951 #home-static .benefit-card .benefit-emoji { 952 font-size: 28px; margin-bottom: 8px; line-height: 1; 953 } 954 #home-static .benefit-card .benefit-title { 955 font-size: 15.5px; font-weight: 700; 956 letter-spacing: -0.4px; 957 color: #1F2540; 958 margin-bottom: 6px; 959 } 960 @media (prefers-color-scheme: dark) { 961 #home-static .benefit-card .benefit-title { color: #F2F4FF; } 962 } 963 #home-static .benefit-card .benefit-sub { 964 font-size: 13.5px; line-height: 1.55; 965 color: #5A6181; 966 letter-spacing: -0.2px; 967 } 968 @media (prefers-color-scheme: dark) { 969 #home-static .benefit-card .benefit-sub { color: rgba(255,255,255,0.65); } 970 } 971 972 /* §2-1b ë§ê°í ì¸ ë¦¬ë(2015 ëë¤ë íì¤í ì¤í 리 ë°´ë) */ 973 #home-static .rescue-lead { 974 max-width: 760px; margin: 2px auto 18px; padding: 16px 20px; 975 background: linear-gradient(135deg, rgba(255,122,162,0.08) 0%, rgba(91,61,241,0.08) 100%); 976 border: 1px solid rgba(91,61,241,0.18); border-radius: 14px; 977 color: #3A4060; font-size: 15px; line-height: 1.62; letter-spacing: -0.2px; text-align: center; 978 } 979 #home-static .rescue-lead b { color: #5b3df1; font-weight: 700; } 980 @media (prefers-color-scheme: dark) { 981 #home-static .rescue-lead { color: rgba(255,255,255,0.72); border-color: rgba(255,255,255,0.10); } 982 #home-static .rescue-lead b { color: #B7A3FF; } 983 } 984 985 /* §2-2 ì 뢰 ì¹´ë */ 986 #home-static .trust-grid { 987 display: grid; 988 grid-template-columns: 1fr; 989 gap: 12px; 990 } 991 #home-static .trust-card { 992 padding: 16px 18px; 993 border-radius: 12px; 994 background: rgba(91,61,241,0.05); 995 border: 1px solid rgba(91,61,241,0.18); 996 } 997 #home-static .trust-card-strong { 998 background: linear-gradient(135deg, rgba(255,122,162,0.10) 0%, rgba(91,61,241,0.10) 100%); 999 border-color: rgba(255,122,162,0.30); 1000 } 1001 @media (prefers-color-scheme: dark) { 1002 #home-static .trust-card { background: rgba(91,61,241,0.12); border-color: rgba(91,61,241,0.30); } 1003 #home-static .trust-card-strong { background: linear-gradient(135deg, rgba(255,122,162,0.16) 0%, rgba(91,61,241,0.16) 100%); } 1004 } 1005 #home-static .trust-card .trust-title { 1006 font-size: 15px; font-weight: 700; 1007 letter-spacing: -0.3px; 1008 color: #1F2540; 1009 margin-bottom: 6px; 1010 } 1011 #home-static .trust-card .trust-title b { color: #5b3df1; } 1012 @media (prefers-color-scheme: dark) { 1013 #home-static .trust-card .trust-title { color: #F2F4FF; } 1014 #home-static .trust-card .trust-title b { color: #B7A3FF; } 1015 } 1016 #home-static .trust-card .trust-sub { 1017 font-size: 13.5px; line-height: 1.55; 1018 color: #5A6181; 1019 letter-spacing: -0.2px; 1020 } 1021 @media (prefers-color-scheme: dark) { 1022 #home-static .trust-card .trust-sub { color: rgba(255,255,255,0.70); } 1023 } 1024 1025 /* §2-3 1ë¶ zero-config ì¹´ë */ 1026 #home-static .onboarding-card {
1027 padding: 22px 22px 26px; 1028 border-radius: 16px; 1029 background: #FAFAFC; 1030 border: 1px dashed rgba(31,37,64,0.20); 1031 } 1032 @media (prefers-color-scheme: dark) { 1033 #home-static .onboarding-card { background: rgba(255,255,255,0.04); border-color: rgba(255,255,255,0.20); } 1034 } 1035 #home-static .onboard-steps { 1036 margin: 0 0 18px; padding-left: 22px; 1037 font-size: 14.5px; line-height: 1.75; 1038 color: #1F2540; 1039 letter-spacing: -0.3px; 1040 } 1041 #home-static .onboard-steps b { color: #5b3df1; } 1042 @media (prefers-color-scheme: dark) { 1043 #home-static .onboard-steps { color: #F2F4FF; } 1044 #home-static .onboard-steps b { color: #B7A3FF; } 1045 } 1046 1047 /* §2-4 íë©´ mockup 3ì¹´ë */ 1048 #home-static .mockup-grid { 1049 display: grid; 1050 grid-template-columns: repeat(3, 1fr); 1051 gap: 12px; 1052 } 1053 @media (max-width: 720px) { 1054 #home-static .mockup-grid { grid-template-columns: 1fr; } 1055 } 1056 #home-static .mockup-card { margin: 0; } 1057 #home-static .mockup-thumb { 1058 aspect-ratio: 4 / 3; 1059 border-radius: 12px; 1060 background: linear-gradient(135deg, #FFE2EC 0%, #DCD4FB 100%); 1061 display: flex; flex-direction: column; align-items: center; justify-content: center; 1062 gap: 8px; 1063 font-size: 48px; 1064 color: #1F2540; 1065 box-shadow: 0 4px 12px rgba(31,37,64,0.06); 1066 } 1067 #home-static .mockup-thumb-reveal { 1068 background: linear-gradient(135deg, #FFE2EC 0%, #FFB8CD 100%); 1069 } 1070 #home-static .mockup-thumb-qr { 1071 background: linear-gradient(135deg, #DCD4FB 0%, #B7A3FF 100%); 1072 } 1073 #home-static .mockup-thumb-dash { 1074 background: linear-gradient(135deg, #C8F0E0 0%, #A8E6CF 100%); 1075 } 1076 #home-static .mockup-thumb .mockup-label { 1077 font-size: 13px; font-weight: 700; 1078 letter-spacing: -0.3px; 1079 } 1080 #home-static .mockup-card figcaption { 1081 margin-top: 10px; 1082 font-size: 13px; line-height: 1.5; 1083 color: #5A6181; 1084 letter-spacing: -0.2px; 1085 text-align: center; 1086 } 1087 @media (prefers-color-scheme: dark) { 1088 #home-static .mockup-card figcaption { color: rgba(255,255,255,0.62); } 1089 } 1090 1091 /* §2-5 ìì± íì¬ í ì¤ */ 1092 #home-static .company-line { 1093 margin: 36px 0 8px; 1094 padding: 14px 18px; 1095 border-radius: 12px; 1096 background: rgba(31,37,64,0.04); 1097 font-size: 13.5px; line-height: 1.6; 1098 color: #5A6181; 1099 letter-spacing: -0.2px; 1100 text-align: center; 1101 } 1102 @media (prefers-color-scheme: dark) { 1103 #home-static .company-line { background: rgba(255,255,255,0.04); color: rgba(255,255,255,0.65); } 1104 } 1105 #home-static .company-line .company-link { 1106 color: #5b3df1; 1107 font-weight: 600; 1108 text-decoration: none; 1109 margin-left: 6px; 1110 } 1111 #home-static .company-line .company-link:hover { text-decoration: underline; } 1112 @media (prefers-color-scheme: dark) { 1113 #home-static .company-line .company-link { color: #B7A3FF; } 1114 } 1115 </style> 1116 1117 <!-- Favicon â ë¸ëë SVG ì°ì , í´ë°± PNG --> 1118 <link rel="icon" type="image/svg+xml" href="favicon.svg"> 1119 <link rel="icon" type="image/png" href="favicon.png"> 1120 1121 <title>StyleVoiceTalk â ëë¤ ë§¤ì¥ë, ëëì´ ìíê¶ì íëë¤</title> 1122</head> 1123<body> 1124 <!-- ê´ë¦¬ì íì´ì§(/ad)ë ìë¹ì¤ì© ì°ì»´ íë©´ ì¤íµ â ì¦ì Flutter ë¡ëë§ ë³´ì¬ì¤. --> 1125
1125<script> 1126 (function() { 1127 var p = window.location.pathname || ''; 1128 if (p === '/ad' || p.startsWith('/ad/') || p === '/ad/' ) { 1129 document.documentElement.setAttribute('data-admin', '1'); 1130 } 1131 })(); 1132 </script>
1132 1133 1134 <!-- âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ 1135 ì¼íì± SW + cache ì 리 (2026-05-05 ì림 ê¸°ë¥ ë¡¤ë°± cleanup). 1136 ì sw.js ê° ì¬ì©ì ë¸ë¼ì°ì ì ë¨ì audio fetch 를 ê°ë¡ì±ë íê·ê° ìì´ 1137 모ë ì¬ì©ìê° í ë²ì© ìë ì 리. localStorage flag ë¡ 1íë§ ì¤í. 1138 âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ --> 1139
1139<script> 1140 (function() { 1141 try { 1142 if (localStorage.getItem('__vt_sw_cleanup_v3')) return; 1143 } catch (_) { return; } 1144 if (!('serviceWorker' in navigator)) { 1145 try { localStorage.setItem('__vt_sw_cleanup_v3', '1'); } catch(_) {} 1146 return; 1147 } 1148 navigator.serviceWorker.getRegistrations().then(function(rs) { 1149 var hadRegs = rs && rs.length > 0; 1150 return Promise.all(rs.map(function(r) { return r.unregister(); })) 1151 .then(function() { 1152 if (window.caches && caches.keys) { 1153 return caches.keys().then(function(ks) { 1154 return Promise.all(ks.map(function(k) { return caches.delete(k); })); 1155 }); 1156 } 1157 }) 1158 .then(function() { 1159 try { localStorage.setItem('__vt_sw_cleanup_v3', '1'); } catch(_) {} 1160 // SW ê° ììë¤ë©´ í ë² hard reload í´ì 깨ëí íê²½ìì ìì 1161 if (hadRegs) { 1162 try { 1163 var u = new URL(location.href); 1164 u.searchParams.set('_swcleanup', Date.now()); 1165 location.replace(u.toString()); 1166 } catch(_) { location.reload(); } 1167 } 1168 }); 1169 }).catch(function() { 1170 try { localStorage.setItem('__vt_sw_cleanup_v3', '1'); } catch(_) {} 1171 }); 1172 })(); 1173 </script>
1173 1174 1175 <!-- âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ 1176 Storage persistence ìì² â Chrome ì ìë evict ì°¨ë¨. 1177 기본ì "best-effort" ë¶ë¥ë¼ ëì¤í¬ ìë° / ì¢ ë£ ì GC ê°ë¥. persist() 1178 granted ëë©´ "persistent" ë¡ ì¹ê²©ëì´ Chrome ì´ ì¬ì©ì ëª ìì ìì 1179 ì ì ê±´ëë¦¬ì§ ìì. moment_history_v1 / vm_replay_* / playlists_v1 1180 ì´ ë¸ë¼ì°ì ì¢ ë£ í ì¬ë¼ì§ë íê· ì°¨ë¨ì©. 1181 (ì림 ê¶í / ë¶ë§í¬ / PWA ì¤ì¹ ì ìë granted ê°ë¥. ê±°ë¶ë¼ë 1182 ìë¬ ìë â best-effort ë¡ ê·¸ë¥ ë ) 1183 âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ --> 1184
1184<script> 1185 (function() { 1186 try { 1187 if (!navigator.storage || !navigator.storage.persist) return; 1188 // ì´ë¯¸ persistent ë©´ skip 1189 if (navigator.storage.persisted) { 1190 navigator.storage.persisted().then(function(already) { 1191 if (already) { 1192 console.log('[storage] already persistent'); 1193 return; 1194 } 1195 navigator.storage.persist().then(function(granted) { 1196 console.log('[storage] persist requested â', granted ? 'GRANTED' : 'best-effort'); 1197 }).catch(function(e) { 1198 console.warn('[storage] persist failed:', e); 1199 }); 1200 }); 1201 } 1202 } catch (e) { 1203 console.warn('[storage] persist check failed:', e); 1204 } 1205 })(); 1206 </script>
1206 1207 1208 <!-- âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ 1209 ìë ì¬ë¡ë í¬í¼ â Flutter 측 VersionCheckService ê° ì ë¹ë ê°ì§ ì 1210 __vtShowReloadOverlay â __vtForceReload ìì¼ë¡ í¸ì¶. 1211 ì¬ì©ììê² ê°ì ìë¡ê³ 침ì ìí¤ì§ ìê³ SW/ìºì ì 리 í hard reload. 1212 âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ --> 1213 <style> 1214 @keyframes __vt_spin { to { transform: rotate(360deg); } } 1215 #vt-reload-overlay { 1216 position: fixed; inset: 0; z-index: 2147483647; 1217 background: rgba(20,16,40,0.55); 1218 display: flex; align-items: center; justify-content: center; 1219 font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif; 1220 backdrop-filter: blur(2px); 1221 -webkit-backdrop-filter: blur(2px); 1222 } 1223 #vt-reload-overlay .card { 1224 background: #fff; padding: 22px 28px; border-radius: 16px; 1225 box-shadow: 0 14px 36px rgba(0,0,0,0.22); 1226 display: flex; gap: 14px; align-items: center; 1227 max-width: 86vw; 1228 } 1229 #vt-reload-overlay .spin { 1230 width: 22px; height: 22px; 1231 border: 3px solid #e6e2f5; border-top-color: #5b3df1; 1232 border-radius: 50%; animation: __vt_spin 0.85s linear infinite; 1233 flex-shrink: 0; 1234 } 1235 #vt-reload-overlay .msg { font-size: 15px; font-weight: 600; color: #1c1730; letter-spacing: -0.2px; } 1236 </style> 1237
1237<script> 1238 (function() { 1239 window.__vtShowReloadOverlay = function(message) { 1240 if (document.getElementById('vt-reload-overlay')) return; 1241 var o = document.createElement('div'); 1242 o.id = 'vt-reload-overlay'; 1243 var card = document.createElement('div'); card.className = 'card'; 1244 var sp = document.createElement('div'); sp.className = 'spin'; 1245 var msg = document.createElement('div'); msg.className = 'msg'; 1246 msg.textContent = message || 'ìµì í ì¬ë¡ë© ì¤ì ëë¤.'; 1247 card.appendChild(sp); card.appendChild(msg); o.appendChild(card); 1248 document.body.appendChild(o); 1249 }; 1250 window.__vtForceReload = function() { 1251 var done = false; 1252 function go() { 1253 if (done) return; done = true; 1254 try { 1255 var u = new URL(location.href); 1256 u.searchParams.set('_v', Date.now()); 1257 location.replace(u.toString()); 1258 } catch(_) { location.reload(); } 1259 } 1260 // SW unregister + Cache Storage ë¹ì°ê¸° (best-effort, 1.5s íììì). 1261 try { 1262 var tasks = []; 1263 if ('serviceWorker' in navigator) { 1264 tasks.push(navigator.serviceWorker.getRegistrations() 1265 .then(function(rs){ return Promise.all(rs.map(function(r){ return r.unregister(); })); }) 1266 .catch(function(){})); 1267 } 1268 if (window.caches && caches.keys) { 1269 tasks.push(caches.keys() 1270 .then(function(ks){ return Promise.all(ks.map(function(k){ return caches.delete(k); })); }) 1271 .catch(function(){})); 1272 } 1273 Promise.all(tasks).then(go); 1274 setTimeout(go, 1500); // ë°±ì íììì 1275 } catch(_) { go(); } 1276 }; 1277 })(); 1278 </script>
1278 1279 1280 <style> 1281 html[data-admin="1"] #home-static { display: none !important; } 1282 /* ë¡ê·¸ì¸ ìí(localStorage ë기 ì²´í¬) â ë¡ê·¸ì¸/ê°ì ë²í¼ ì¦ì ì¨ê¹. */ 1283 html[data-loggedin="1"] #home-static .login-btn { display: none !important; } 1284 /* '/' ê° ìë ê²½ë¡(/moment/:id, /login, /settings ...)ììë ì¬ì¥ë ëë© ì¹ì ì¨ê¸°ê³ 1285 ê°ë²¼ì´ ë¡ë© ì¸ëì¼ì´í°ë§ ë ¸ì¶. flutter-first-frame ì home-static ìì²´ ì ê±°. 1286 2026-05-31 ì¬ì¥ë ëë© í¼ë² í â merchant-h1/sub/bonus, hero-videos, benefit/trust/onboarding/mockup grid, 1287 company-line, primary-cta-row, brand-footer ì ë¶ hide. */ 1288 html[data-route="non-home"] #home-static .wrap > h1, 1289 html[data-route="non-home"] #home-static .wrap > h2, 1290 html[data-route="non-home"] #home-static .wrap > p, 1291 html[data-route="non-home"] #home-static .wrap > .grid, 1292 html[data-route="non-home"] #home-static .wrap > .voice-demo, 1293 html[data-route="non-home"] #home-static .wrap > .trust-badges, 1294 html[data-route="non-home"] #home-static .wrap > .quick-start, 1295 html[data-route="non-home"] #home-static .wrap > .pricing, 1296 html[data-route="non-home"] #home-static .wrap > .pricing-note, 1297 html[data-route="non-home"] #home-static .wrap > .brand-footer, 1298 html[data-route="non-home"] #home-static .wrap > .footer, 1299 html[data-route="non-home"] #home-static .wrap > .hero-videos, 1300 html[data-route="non-home"] #home-static .wrap > .primary-cta-row, 1301 html[data-route="non-home"] #home-static .wrap > .benefit-grid, 1302 html[data-route="non-home"] #home-static .wrap > .trust-grid, 1303 html[data-route="non-home"] #home-static .wrap > .onboarding-card, 1304 html[data-route="non-home"] #home-static .wrap > .mockup-grid { display: none !important; } 1305 html[data-route="non-home"] #home-static .topbar, 1306 html[data-route="non-home"] #home-static .age-banner { display: none !important; } 1307 html[data-route="non-home"] #home-static .wrap { 1308 min-height: 70vh; 1309 display: flex; 1310 flex-direction: column; 1311 align-items: center; 1312 justify-content: center; 1313 gap: 14px; 1314 } 1315 html[data-route="non-home"] #home-static .spinner { 1316 width: 36px; height: 36px; 1317 border-radius: 50%; 1318 border: 3px solid rgba(31,37,64,0.12); 1319 border-top-color: #FF7AA2; 1320 animation: spin 0.9s linear infinite; 1321 } 1322 @media (prefers-color-scheme: dark) { 1323 html[data-route="non-home"] #home-static .spinner { 1324 border-color: rgba(255,255,255,0.12); 1325 border-top-color: #FF7AA2; 1326 } 1327 } 1328 @keyframes spin { to { transform: rotate(360deg); } } 1329 html[data-route="non-home"] #home-static .loading-text { 1330 font-size: 13px; 1331 color: #8089A8; 1332 letter-spacing: -0.2px; 1333 } 1334 /* 첫 ë¡ë íì ë©ìì§ â 7ê° ë©ìì§ê° ìì°¨ íì´ë. ê° ~1.7s, ì´ ~12s 루í. */ 1335 html[data-route="non-home"] #home-static .first-load-msgs { 1336 position: relative; 1337 width: 100%; 1338 max-width: 480px; 1339 height: 22px; 1340 margin-top: 16px; 1341 text-align: center; 1342 } 1343 #home-static .first-load-msgs .msg { 1344 position: absolute; 1345 inset: 0; 1346 font-size: 13.5px; 1347 color: #5A6181; 1348 opacity: 0; 1349 letter-spacing: -0.2px; 1350 } 1351 @media (prefers-color-scheme: dark) { 1352 #home-static .first-load-msgs .msg { color: rgba(255,255,255,0.65); } 1353 } 1354 #home-static .first-load-msgs .msg-1 { animation: vmFadeMsg 12s 0.0s infinite; } 1355 #home-static .first-load-msgs .msg-2 { animation: vmFadeMsg 12s 1.7s infinite; } 1356 #home-static .first-load-msgs .msg-3 { animation: vmFadeMsg 12s 3.4s infinite; } 1357 #home-static .first-load-msgs .msg-4 { animation: vmFadeMsg 12s 5.1s infinite; } 1358 #home-static .first-load-msgs .msg-5 { animation: vmFadeMsg 12s 6.8s infinite; } 1359 #home-static .first-load-msgs .msg-6 { animation: vmFadeMsg 12s 8.5s infinite; } 1360 #home-static .first-load-msgs .msg-7 { animation: vmFadeMsg 12s 10.2s infinite; } 1361 @keyframes vmFadeMsg { 1362 0%, 100% { opacity: 0; transform: translateY(4px); } 1363 4%, 13% { opacity: 1; transform: translateY(0); } 1364 17% { opacity: 0; transform: translateY(-4px); } 1365 } 1366 html:not([data-page="moment"]) #home-static .first-load-msgs { display: none; } 1367 /* ë¹ ë¥¸ ì¬ë¡ë â íì ë©ìì§ + ëª¨ë¨¼í¸ ë¯¸ë¦¬ë³´ê¸° ì¨ê¹, ì¤í¼ë + "ì¤ë¹ ì¤..." ë§. */ 1368 html[data-fast-load="1"] #home-static .first-load-msgs, 1369 html[data-fast-load="1"] #home-static .moment-preview { display: none !important; } 1370 html[data-route="non-home"] #home-static .moment-preview { 1371 display: flex; 1372 flex-direction: column; 1373 align-items: center; 1374 gap: 10px; 1375 max-width: 480px; 1376 text-align: center; 1377 } 1378 html[data-route="non-home"] #home-static .moment-preview .emoji { 1379 font-size: 56px; 1380 line-height: 1; 1381 } 1382 html[data-route="non-home"] #home-static .moment-preview .title { 1383 font-size: 22px; 1384 font-weight: 800; 1385 letter-spacing: -0.4px; 1386 } 1387 html[data-route="non-home"] #home-static .moment-preview .sub { 1388 font-size: 14px; 1389 color: #5A6181; 1390 } 1391 @media (prefers-color-scheme: dark) { 1392 html[data-route="non-home"] #home-static .moment-preview .sub { 1393 color: rgba(255,255,255,0.6); 1394 } 1395 } 1396 html:not([data-page="moment"]) #home-static .moment-preview { display: none; } 1397 html:not([data-route="non-home"]) #home-static .spinner, 1398 html:not([data-route="non-home"]) #home-static .loading-text { display: none; } 1399 </style> 1400
1400<script> 1401 // ê²½ë¡ë³ ì¬ì ì²ë¦¬ â Flutter ë²ë¤ ë¡ë ì´ì ì ë기 ì¤í. 1402 (function() { 1403 var p = window.location.pathname || '/'; 1404 // localStorage ë기 ì²´í¬ â ë¡ê·¸ì¸ ìíë©´ data-loggedin="1" ì¤ì â CSS ê° 1405 // ë¡ê·¸ì¸/ê°ì ë²í¼ ì¦ì ì¨ê¹ (Supabase JS ë¡ë ë기 ëì ê¹ë¹¡ì ë°©ì§). 1406 var hasAuth = false; 1407 try { 1408 for (var i = 0; i < localStorage.length; i++) { 1409 var k = localStorage.key(i); 1410 if (k && k.indexOf('sb-') === 0 && k.indexOf('-auth-token') > 0) { 1411 var raw = localStorage.getItem(k); 1412 if (raw && raw.indexOf('access_token') > 0) { 1413 hasAuth = true; 1414 break; 1415 } 1416 } 1417 } 1418 } catch (_) {} 1419 if (hasAuth) { 1420 document.documentElement.setAttribute('data-loggedin', '1'); 1421 } 1422 // ì´ë¯¸ Flutter ê° í ë² ë¡ëë ì¸ì ì´ë©´ íì ë©ìì§ ì¤íµ â ë¨ì spinner ë§. 1423 try { 1424 if (sessionStorage.getItem('vmFlutterLoaded') === '1') { 1425 document.documentElement.setAttribute('data-fast-load', '1'); 1426 } 1427 } catch (_) {} 1428 // ë¹ë¡ê·¸ì¸ ì¬ì©ìê° ë³´í¸ ê²½ë¡ë¡ ì§ì ì ì ì ì¦ì ì ì íì¼ë¡ 리ëë í¸. 1429 var protectedRe = /^\/(moment|chat|driving|contents|settings|ad)(\/.*)?$/; 1430 if (protectedRe.test(p) && !hasAuth) { 1431 // ìë ê²½ë¡ë¥¼ next ë¡ ë³´ì¡´ â ë¡ê·¸ì¸ í ììì¹ ë³µê· (Fix 3, /ad ë³µê·). 1432 window.location.replace('/?next=' + encodeURIComponent(p + (window.location.search || ''))); 1433 return; 1434 } 1435 if (p !== '/' && p !== '') { 1436 document.documentElement.setAttribute('data-route', 'non-home'); 1437 } 1438 // /chat ë ëª¨ë¨¼í¸ ì¹´ëì ëì¼í ë¡ë© 미리보기 ë ¸ì¶ (ìì ëí ì±í ì¹´ëì©). 1439 if (p === '/chat' || p.indexOf('/chat/') === 0 || p.indexOf('/chat?') === 0) { 1440 document.documentElement.setAttribute('data-page', 'moment'); 1441 document.addEventListener('DOMContentLoaded', function() { 1442 var e = document.getElementById('momentPreviewEmoji'); 1443 var t = document.getElementById('momentPreviewTitle'); 1444 var s = document.getElementById('momentPreviewSub'); 1445 if (e) e.textContent = 'ð¬'; 1446 if (t) t.textContent = 'ìì ëí ì±í '; 1447 if (s) s.textContent = '주ì ìì´ ìì ë¡ê² ëíí기'; 1448 document.title = 'ìì ëí ì±í â StyleVoiceTalk'; 1449 }); 1450 } 1451 // /driving â ìì ëí ìì± (ì´ì 모ë) ì¹´ëì© ë¯¸ë¦¬ë³´ê¸°. 1452 if (p === '/driving' || p.indexOf('/driving/') === 0 || p.indexOf('/driving?') === 0) { 1453 document.documentElement.setAttribute('data-page', 'moment'); 1454 document.addEventListener('DOMContentLoaded', function() { 1455 var e = document.getElementById('momentPreviewEmoji'); 1456 var t = document.getElementById('momentPreviewTitle'); 1457 var s = document.getElementById('momentPreviewSub'); 1458 if (e) e.textContent = 'ðï¸'; 1459 if (t) t.textContent = 'ìì ëí ìì±'; 1460 if (s) s.textContent = 'ì´ì 모ëë¡ ì ì ì°ê³ ìì± ëí'; 1461 document.title = 'ìì ëí ìì± â StyleVoiceTalk'; 1462 }); 1463 } 1464 // /moment/:id ë©´ ëª¨ë¨¼í¸ ì ë³´ë¡ ì ì 미리보기 ì±ì°ê¸° â Flutter ë¡ë© ëì ë¹ íë©´ íí¼. 1465 var mm = p.match(/^\/moment\/([^\/?#]+)/); 1466 if (mm) { 1467 document.documentElement.setAttribute('data-page', 'moment'); 1468 var MOMENTS = { 1469 bedtime_story: ['ð', 'ì기 ì ì´ì¼ê¸°', 'ì ë¤ê¸° ì¢ì ë¤ì í ì´ì¼ê¸° í í¸'], 1470 rain_vibe: ['ð§', 'ë¹ ì¤ë ë ë°ì´ë¸', 'ì°½ë° ë¹ì리ì²ë¼ ììí ì´ì¼ê¸°'], 1471 meditation_breath: ['ð§', 'í í¸í¡ ëª ì', '3ë¶ê° ë°ë¼ íë í¸í¡ ê°ì´ë'], 1472 morning_hello: ['âï¸', 'ì침ì ì¬ë íë§ë', 'ì¤ëì ê¸°ë¶ ì¢ê² ììíë ì§§ì ìì'], 1473 fire_cheer: ['ð¥', 'ë¨ê±°ì´ ìë°ì ', 'ì¹ë¶ ì§ì ì ì¬ë¼ì¤ë ë°ì°¨'], 1474 daily_comfort: ['ð', 'ì¤ë í루 ìë¡ë°ê¸°', 'ì§ì¹ í루 ëì ë£ë ë°ë»í ë§'], 1475 letter_to_me: ['ð', 'ëìê² ì°ë í¸ì§', '과거/미ëì ëìê² í íµ'], 1476 inner_child: ['ð', 'ì´ë¦° ë ë¬ë기', 'ë´ë©´ ìì´ìê² ê±´ë¤ë ë§'], 1477 english_oneline: ['ð', 'ì¤ëì ìì´ í ì¤', 'ë°ë¼ ë§íë©° ìµíë í 문ì¥'], 1478 classic_quote: ['ð', 'ê³ ì í 구ì ', 'ë¹ì ì´ ê³ ë¥¸ 목ìë¦¬ë¡ ë£ë ì¤ë¦½ ëë '], 1479 }; 1480 var info = MOMENTS[mm[1]]; 1481 if (info) { 1482 document.addEventListener('DOMContentLoaded', function() { 1483 var e = document.getElementById('momentPreviewEmoji'); 1484 var t = document.getElementById('momentPreviewTitle'); 1485 var s = document.getElementById('momentPreviewSub'); 1486 if (e) e.textContent = info[0]; 1487 if (t) t.textContent = info[1]; 1488 if (s) s.textContent = info[2]; 1489 document.title = info[1] + ' â StyleVoiceTalk'; 1490 }); 1491 } 1492 } 1493 })(); 1494 </script>
1494 1495 1496 <!-- ì¬ì¥ë ëë© íì´ë¡ ìì â Cloudflare R2 ì¸ë¶ í¸ì¤í (2026-05-31, P2-2). 1497 HF Space ê° .mp4 binary 를 Xet Storage ë¡ë§ ë°ì push reject â R2 ë¡ ë¶ë¦¬. 1498 ì본 íì¼: web/landing/stylevoicetalk_{katalk,qr,dj}.mp4 (ë¡ì»¬ ë°±ì , deploy ì ì¸) 1499 매í: katalk = ì¹´í¡ ë°ì ìê° / qr = ë§¤ì¥ ì¬ì© / dj = ë°ì ì¬ë íì (ì°¨ë³í) 1500 R2 URL ë°ì¼ë©´ ìë ë°°ì´ì ì±ì ë£ê³ ì¬ë°°í¬. ë¹ ë°°ì´ = fallback ìë (ì´ëª¨ì§ placeholder). 1501 ìì R2 URL: 'https://cdn.stylevoicetalk.com/landing/stylevoicetalk_katalk.mp4' --> 1502
1502<script> 1503 window.LANDING_HERO_VIDEOS = [ 1504 { video: 'https://cdn.stylevoicetalk.com/landing/stylevoicetalk_katalk.mp4', caption: 'ì¹´í¡ì¼ë¡ ë°ì ìê°' }, 1505 { video: 'https://cdn.stylevoicetalk.com/landing/stylevoicetalk_qr.mp4', caption: '매ì¥ìì ì¬ì©íë ìê°' }, 1506 { video: 'https://cdn.stylevoicetalk.com/landing/stylevoicetalk_dj.mp4', caption: 'ë°ì ì¬ëì íì ' }, 1507 ]; 1508 </script>
1508 1509 1510 <!-- ì¬ì¥ë ëë© íì´ë¡ ìì ì¬ë¡¯ 3ê° ëì ë ë (2026-05-31 í¼ë²). 1511 window.LANDING_HERO_VIDEOS ë°°ì´ ë¯¸ì£¼ì ì fallback = 컨ì placeholder. 1512 lazy-load + í ì¬ì (ìëì¬ì X, 모ë°ì¼ ë°ì´í° ë³´í¸). 1513 Higgsfield AI ìì + ì°ë¦¬ TTS ìì±í¸ì§ í©ì± íì 주ì ìì¹: 1514 window.LANDING_HERO_VIDEOS = [ 1515 { video: '/landing/hero-1.mp4', poster: '/landing/hero-1.jpg', caption: 'ì¿ í° ë°ì ìê°' }, 1516 { video: '/landing/hero-2.mp4', poster: '/landing/hero-2.jpg', caption: 'ìì±í¸ì§ ë¤ë ¤ì£¼ë ìê°' }, 1517 { video: '/landing/hero-3.mp4', poster: '/landing/hero-3.jpg', caption: 'ë§¤ì¥ ë°©ë¬¸ ìê°' }, 1518 ]; 1519 AI ìì±Â·ì°ì¶ ê³ ì§ë hero-cap ì ë°ì (íìê´ê³ ë²). --> 1520
1520<script> 1521 (function() { 1522 // fallback 컨ì â ìì 미주ì ì / ìì ë¡ë ì¤í¨ ì. 1523 var FALLBACKS = [ 1524 { emoji: 'ð', text: 'ì¹´í¡ì¼ë¡ ë°ì ìì± ì ë¬¼ì¿ í°' }, 1525 { emoji: 'ð¥¹', text: 'ë°ì ì¬ëì íì ' }, 1526 { emoji: 'â', text: '매ì¥ìì ì¬ì©íë ìê°' }, 1527 ]; 1528 function renderSlot(slot, video) { 1529 var div = document.createElement('div'); 1530 div.className = 'hero-video-slot'; 1531 if (!video || !video.video) { 1532 div.classList.add('fallback'); 1533 var em = document.createElement('div'); em.className = 'fallback-emoji'; em.textContent = slot.emoji; 1534 var tx = document.createElement('div'); tx.className = 'fallback-text'; tx.textContent = slot.text; 1535 div.appendChild(em); div.appendChild(tx); 1536 if (slot.text) { 1537 var cap = document.createElement('div'); cap.className = 'slot-cap'; cap.textContent = slot.text; 1538 div.appendChild(cap); 1539 } 1540 return div; 1541 } 1542 // ìì ì¬ë¡¯ 1543 var v = document.createElement('video'); 1544 v.src = video.video; 1545 v.preload = 'metadata'; 1546 v.playsInline = true; 1547 v.muted = true; // ìëì¬ì ì ì± í¸í ìí´ ì´ê¸° muted (í ì unmute) 1548 v.loop = true; 1549 if (video.poster) v.poster = video.poster; 1550 div.appendChild(v); 1551 var overlay = document.createElement('div'); overlay.className = 'play-overlay'; 1552 var ico = document.createElement('div'); ico.className = 'play-ico'; ico.textContent = 'â¶'; 1553 overlay.appendChild(ico); 1554 div.appendChild(overlay); 1555 if (video.caption) { 1556 var cap2 = document.createElement('div'); cap2.className = 'slot-cap'; cap2.textContent = video.caption; 1557 div.appendChild(cap2); 1558 } 1559 div.addEventListener('click', function() { 1560 if (div.classList.contains('playing')) { 1561 v.pause(); div.classList.remove('playing'); 1562 } else { 1563 v.muted = false; // ì¬ì©ì í = ìì± ON 1564 var p = v.play(); 1565 if (p && typeof p.catch === 'function') p.catch(function() {}); 1566 div.classList.add('playing'); 1567 } 1568 }); 1569 v.addEventListener('ended', function() { div.classList.remove('playing'); }); 1570 v.addEventListener('error', function() { 1571 // ìì ë¡ë ì¤í¨ â fallback ì¼ë¡ êµì²´. 1572 div.innerHTML = ''; 1573 div.classList.add('fallback'); 1574 var em = document.createElement('div'); em.className = 'fallback-emoji'; em.textContent = slot.emoji; 1575 var tx = document.createElement('div'); tx.className = 'fallback-text'; tx.textContent = slot.text; 1576 div.appendChild(em); div.appendChild(tx); 1577 }); 1578 return div; 1579 } 1580 function renderRow() { 1581 var row = document.getElementById('heroVideoRow'); 1582 if (!row) return; 1583 row.innerHTML = ''; 1584 var vids = (window.LANDING_HERO_VIDEOS && window.LANDING_HERO_VIDEOS.length) ? 1585 window.LANDING_HERO_VIDEOS.slice(0, 3) : []; 1586 for (var i = 0; i < 3; i++) { 1587 row.appendChild(renderSlot(FALLBACKS[i], vids[i] || null)); 1588 } 1589 } 1590 if (document.readyState === 'loading') { 1591 document.addEventListener('DOMContentLoaded', renderRow); 1592 } else { 1593 renderRow(); 1594 } 1595 })(); 1596 </script>
1596 1597 1598 <!-- ì¹´í ì 물 ì¹´ë ëì ì½ì (ìì²ì §6-8/§6-10, sql/056/057, 2026-05-30). 1599 localStorage ì í í°ì´ ìì¼ë©´ grid 맨 ìì ì¹´ë prepend. 1600 - gift_received_tokens (ë°ì ì¿ í°) â ð ë°ì ì¹´í ì¿ í° 1601 - gift_receipt_tokens (ë³´ë¸ ììì¦) â ð ë³´ë¸ ì¹´í ì¿ í° 1602 ë ì¹´ë 모ë ìì¼ë©´ ë°ì ì¿ í° ë¨¼ì (ë°ëì´ ì°ì íë¦). --> 1603
1603<script> 1604 (function() { 1605 function readTokens(key) { 1606 try { 1607 var raw = localStorage.getItem(key); 1608 if (!raw) return []; 1609 var p = JSON.parse(raw); 1610 return Array.isArray(p) ? p.filter(function(t){ return typeof t === 'string' && t.length >= 16; }) : []; 1611 } catch (_) { return []; } 1612 } 1613 function makeCard(opts) { 1614 var btn = document.createElement('button'); 1615 btn.className = 'card'; 1616 btn.type = 'button'; 1617 btn.setAttribute('data-target', opts.target); 1618 btn.innerHTML = 1619 '<div class="emoji">' + opts.emoji + '</div>' + 1620 '<div class="title">' + opts.title + '</div>' + 1621 '<div class="sub">' + opts.sub + '</div>' + 1622 '<div class="meta">' + opts.meta + '</div>'; 1623 return btn; 1624 } 1625 var received = readTokens('gift_received_tokens'); 1626 var sent = readTokens('gift_receipt_tokens'); 1627 if (received.length === 0 && sent.length === 0) return; 1628 document.addEventListener('DOMContentLoaded', function() { 1629 var grid = document.getElementById('contentsGrid'); 1630 if (!grid) return; 1631 // ë³´ë¸ ì¹´ë 먼ì prepend â ê·¸ ë¤ì ë°ì ì¹´ë prepend = ê²°ê³¼ì ì¼ë¡ ë°ì ì¹´ëê° ë§¨ ì. 1632 if (sent.length > 0) { 1633 grid.insertBefore(makeCard({ 1634 target: '/gift/my-receipts', 1635 emoji: 'ð', 1636 title: 'ë´ê° ë³´ë¸ ì¹´í ì¿ í°', 1637 sub: 'ë°ë ë¶ì´ ì¬ì©íëì§ íì¸ + ë¤ì ê³µì ', 1638 meta: sent.length + 'ì¥ ë°ê¸ · ì¹´í ì 물' 1639 }), grid.firstChild); 1640 } 1641 if (received.length > 0) { 1642 grid.insertBefore(makeCard({ 1643 target: '/gift/my-coupons', 1644 emoji: 'ð', 1645 title: 'ë´ê° ë°ì ì¹´í ì¿ í°', 1646 sub: 'ì¹êµ¬Â·ê°ì¡±ì´ ë³´ë¸ ìì± ì ë¬¼ì¿ í°', 1647 meta: received.length + 'ì¥ ë°ì · 매ì¥ìì ì¬ì©' 1648 }), grid.firstChild); 1649 } 1650 }); 1651 })(); 1652 </script>
1652 1653 1654 <!-- âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ 1655 ì ì í ë©ì¸ â '/' ê²½ë¡ìì Flutter ë¡ë ìì´ ì¦ì ë ¸ì¶. 1656 â 2026-05-31 í¼ë² (doc/runbook/landing_merchant_pivot.md): 1657 ì ì¼í ì²ì¤ = SNS ì ì문 ë³´ê³ ê²ìí´ ë¤ì´ì¨ ëë¤ ë§¤ì¥ ì¬ì¥ë 1ëª . 1658 ìë¹ì(구매ì/ë°ëì´)ë ë§¤ì¥ QR / ì¹´í¡ ì 물ë§í¬ë¡ ì í ì쪽 ì§í (ëë© ì 거침). 1659 â íê· ê°ë: ë¹ì ì¥/NSFW ë°°ë, ìë¹ì ê°ê²©í(Free/Standard/Pro), 1660 ë³´ì´ì¤ A/B, ë´ ëª©ì리 ë±ë¡, 30ì´ ì²« ì¤ëì¤ â 본 ëë© ë ¸ì¶ 0. 1661 ê°ê²©ì ë³ë /pricing ì ì íì´ì§ + ë¡ê·¸ì¸ í ìë¹ì íë©´ìì ë ¸ì¶. 1662 ì¹´ë/CTA í´ë¦ ì data-target ê¸°ë° navigate â 기존 ë¼ì°í í¨í´ ê·¸ëë¡. 1663 âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ --> 1664 <div id="home-static" role="main"> 1665 <header class="topbar"> 1666 <div class="brand">StyleVoice<b>Talk</b></div> 1667 <button id="loginBtn" class="login-btn" type="button" data-target="/contents">ë¡ê·¸ì¸</button> 1668 <div id="userChip" class="user-chip" style="display:none;"></div> 1669 </header> 1670 <div class="wrap merchant-landing"> 1671 <div class="gh-hero-2col"> 1672 <div class="gh-msg"> 1673 <h1 class="merchant-h1">ëë¤ ë§¤ì¥ë,<br>ëëì´ <b>ìíê¶ì íëë¤</b></h1> 1674 <p class="merchant-sub">ìëì´ ì¹´í¡ì¼ë¡ ì 물 â ë°ì ì¬ëì´ ì°ë¦¬ ê°ê²ë¥¼ ì°¾ììµëë¤.</p> 1675 <p class="merchant-bonus">· · ê²ë¤ê° 'ë´ ëª©ì리'ë¡ ì íë ìì±í¸ì§ê¹ì§ í¨ê» ê°ëë¤</p> 1676 <div class="primary-cta-row"> 1677 <button class="primary-cta" type="button" data-target="/cafe-admin"> 1678 ì°ë¦¬ 매ì¥ì 무ë£ë¡ ë기 <span class="arrow">â</span> 1679 </button> 1680 </div> 1681 </div> 1682 <div class="gh-stage"> 1683 <!-- §2 ì ì íì´ë¡ â ë ë©ì¸ ìë¹ì¤ ë ì¸ í ê¸ (2026-06-28 ë§ê°í ì¸ ì¶ê°). 1684 íì¼ë¡ ê°ì í° ëª©ì ·ë ì¼Â·ì ëë©ì´ì ìì§ì ê³µì íë©° scene-set ë§ ì¤ì. 1685 â ð ìíê¶: â 1ë¶ ê°ì¤ â â¡ìë ì 물 â â¢ê°ê² 방문·QR â â£ê³ì¢ ì ì° â 1686 â¤ë°ì ì¬ëì ì§ì§ ë°ì(ì¸ë¡ ì¤ì ìì, GH_REACTION_VIDEO R2 URL, ìì¼ë©´ placeholder). 1687 ⡠𥡠í¬ì¥ì©ê¸° ë§ê°í ì¸ (2015 ëë¤ëì íì¤í â ëì í ì¸ ì í + ì¬ì¥ë ë§ê° ì¬ê³ 매ì¶í): 1688 â 1ë¶ ë±ë¡ â â¡ëë¤ ìë 거리ì ë°ê²¬ â â¢ê³¨ë¼ ë´ì ìì½Â·ê²°ì â â£í¬ì¥ì©ê¸° ì§ì°¸ í½ì â â¤ë¨ê³¨ ì í. 1689 ì¹´í¼ ê°ë(§0-2 rescue): ë¨ì´/ë¨ì ìì í¤ 0 · 'í¬ì¥ì©ê¸°' · 'í ì' · ìê° ëª»ë°ê¸° 0. 1690 AI ìì±Â·ì°ì¶ ê³ ì§(íìê´ê³ ë²) ìì 캡ì ì ë°ì . ìì§ì ìë
1690<script> (ë ì¸-aware). 1691 (구 LANDING_HERO_VIDEOS ë°°ì´ + ë ëë¬ script ë #heroVideoRow ë¶ì¬ë¡ ìë no-op.) --> 1692 <section class="gh-hero" aria-label="ë ë©ì¸ ìë¹ì¤ â ìíê¶ í매 íë¦ê³¼ í¬ì¥ì©ê¸° ë§ê°í ì¸ íë¦ (AI ìì±Â·ì°ì¶ ìì)"> 1693 <div class="gh-tabs" role="tablist" aria-label="ìë¹ì¤ ì í"> 1694 <button class="gh-tab on" type="button" data-lane="gift" role="tab" aria-selected="true">ð ìíê¶ ì 물</button> 1695 <button class="gh-tab" type="button" data-lane="rescue" role="tab" aria-selected="false">𥡠í¬ì¥ì©ê¸° ë§ê°í ì¸</button> 1696 </div> 1697 <div class="gh-lane on" data-lane="gift"> 1698 <div class="gh-rail"> 1699 <div class="gh-stop on"><div class="gh-sic">ðª</div><div class="gh-sa">1ë¶ ê°ì¤</div><div class="gh-sd">ìíê¶ í매</div></div> 1700 <div class="gh-conn">âº</div> 1701 <div class="gh-stop"><div class="gh-sic">ð</div><div class="gh-sa">ìë ì 물</div><div class="gh-sd">구매·ì ì¡</div></div> 1702 <div class="gh-conn">âº</div> 1703 <div class="gh-stop"><div class="gh-sic">ð·</div><div class="gh-sa">ê°ê² 방문</div><div class="gh-sd">QR ì¬ì©</div></div> 1704 <div class="gh-conn">âº</div> 1705 <div class="gh-stop"><div class="gh-sic">ð°</div><div class="gh-sa">ê³ì¢ ì ì°</div><div class="gh-sd">í ì¤ ì§ê¸</div></div> 1706 <div class="gh-conn">âº</div> 1707 <div class="gh-stop coda"><div class="gh-sic">ð¥¹</div><div class="gh-sa">ë°ì ë°ì</div><div class="gh-sd">ì§ì§ íì </div></div> 1708 </div> 1709 <div class="gh-phone" id="ghPhone"> 1710 <div class="gh-scene on"> 1711 <div class="gh-shead"><div class="gh-st">ðª 1ë¶ì´ë©´ í매 ìì</div><span class="gh-tag">ì¬ì¥ë</span></div> 1712 <div class="gh-card" style="margin-bottom:10px"> 1713 <div class="gh-row"><i>â</i> í´ëí° ì¸ì¦ì¼ë¡ ê°ì </div> 1714 <div class="gh-row"><i>â</i> ì¬ì ìë²í¸ ìë ê²ì¦</div> 1715 <div class="gh-row"><i>â</i> ê¶ì¢ ìë ìì±</div> 1716 <div class="gh-denoms"><span class="gh-dn">5ì²</span><span class="gh-dn">1ë§</span><span class="gh-dn">3ë§</span><span class="gh-dn">5ë§</span></div> 1717 </div> 1718 <div style="text-align:center;margin-bottom:10px"><span class="gh-chip">ð·ï¸ ì¤ì¹ë¹ 0 · ìì ì¡ 0</span></div> 1719 <div class="gh-btn" style="margin-top:auto">ðª ìíê¶ í매 ìì</div> 1720 </div> 1721 <div class="gh-scene"> 1722 <div class="gh-shead"><div class="gh-st">ð ìíê¶ ì 물</div><span class="gh-tag">ìë</span></div> 1723 <div class="gh-card" style="margin-bottom:10px"> 1724 <div class="gh-circ">â</div> 1725 <div style="color:#F4F4F6;font-size:13px">ââì¹´í ìíê¶</div> 1726 <div class="gh-amt">5ë§ìê¶</div> 1727 </div> 1728 <div style="text-align:center;margin-bottom:10px"><span class="gh-chip dum">ðï¸ ìì±í¸ì§ ë¤</span></div> 1729 <div class="gh-btn" style="margin-top:auto">ð ì¹´í¡ì¼ë¡ ì 물 ë³´ë´ê¸°</div> 1730 </div> 1731 <div class="gh-scene"> 1732 <div class="gh-shead"><div class="gh-st">ð· ì°ë¦¬ ê°ê² 방문</div><span class="gh-tag">ë°ëì´</span></div> 1733 <div class="gh-mut" style="text-align:center;margin-bottom:8px">ë°ì ìíê¶ì 매ì¥ìì ì¬ì©</div> 1734 <div class="gh-card"><div class="gh-qr" id="ghQr"></div><div class="gh-mut">ââì¹´í 5ë§ìê¶</div></div> 1735 <div class="gh-ok"><div class="gh-okc">â</div><div style="color:#F4F4F6;font-size:14px;font-weight:700">ì¬ì© ìë£</div><div class="gh-mut">ì ìë 1ëª !</div></div> 1736 </div> 1737 <div class="gh-scene"> 1738 <div class="gh-shead"><div class="gh-st">ð ì ì°</div><span class="gh-tag">ì¬ì¥ë</span></div> 1739 <div class="gh-card" style="margin-bottom:10px"><div class="gh-big">+50,000<span style="font-size:15px">ì</span></div><div class="gh-mut">í ì¤ â ì¬ì¥ë ê³ì¢ë¡ ì§ê¸</div></div> 1740 <div style="text-align:center;margin-bottom:6px"><span class="gh-chip">ð¡ï¸ ì ì°ë©´ ë³´ê´ë¶ìì íë¶</span></div> 1741 <div class="gh-bars"><i style="height:40%"></i><i style="height:62%"></i><i style="height:52%"></i><i class="y" style="height:90%"></i></div> 1742 </div> 1743 <div class="gh-scene vid"> 1744 <div class="gh-reel"> 1745 <video class="gh-rvid" muted playsinline preload="metadata" style="display:none"></video> 1746 <div class="gh-face">ð¥¹</div>
1747 <span class="gh-rbadge">ð¬ ì¤ì ìì</span> 1748 <div class="gh-rplay">â¶</div> 1749 <div class="gh-rcap">ì 물 ë°ì ì¬ëì ì§ì§ íì <small>AI ìì±Â·ì°ì¶ ìì · ì¸ë¡ ìì</small></div> 1750 </div> 1751 </div> 1752 </div> 1753 </div><!-- /gh-lane gift --> 1754 <div class="gh-lane" data-lane="rescue"> 1755 <div class="gh-rail"> 1756 <div class="gh-stop on"><div class="gh-sic">ðª</div><div class="gh-sa">1ë¶ ë±ë¡</div><div class="gh-sd">ë©ë´ ì¬ë¦¬ê¸°</div></div> 1757 <div class="gh-conn">âº</div> 1758 <div class="gh-stop"><div class="gh-sic">ð</div><div class="gh-sa">ìë ë°ê²¬</div><div class="gh-sd">거리ì ë ¸ì¶</div></div> 1759 <div class="gh-conn">âº</div> 1760 <div class="gh-stop"><div class="gh-sic">ð</div><div class="gh-sa">ê³¨ë¼ ë´ê¸°</div><div class="gh-sd">ìì½Â·ê²°ì </div></div> 1761 <div class="gh-conn">âº</div> 1762 <div class="gh-stop"><div class="gh-sic">ð¥¡</div><div class="gh-sa">í¬ì¥ í½ì </div><div class="gh-sd">ê° ì¡°ë¦¬</div></div> 1763 <div class="gh-conn">âº</div> 1764 <div class="gh-stop coda"><div class="gh-sic">ð</div><div class="gh-sa">ë¨ê³¨ ì í</div><div class="gh-sd">ì¬ë°©ë¬¸</div></div> 1765 </div> 1766 <div class="gh-phone"> 1767 <div class="gh-scene on"> 1768 <div class="gh-shead"><div class="gh-st">ðª ë¨ë ë©ë´, 1ë¶ ë±ë¡</div><span class="gh-tag">ì¬ì¥ë</span></div> 1769 <div class="gh-card" style="margin-bottom:10px"> 1770 <div class="gh-row"><i>â</i> ì¤ë ë§ê° 'í ì' ì í</div> 1771 <div class="gh-row"><i>â</i> í ì¸ì¨Â·í½ì ìê° ì§ì </div> 1772 <div class="gh-row"><i>â</i> í¬ì¥ì©ê¸° ì§ì°¸ ìë´ ìë</div> 1773 <div class="gh-denoms"><span class="gh-dn">20%</span><span class="gh-dn">30%</span><span class="gh-dn">40%</span><span class="gh-dn">ë°ê°</span></div> 1774 </div> 1775 <div style="text-align:center;margin-bottom:10px"><span class="gh-chip">ð·ï¸ ì¤ì¹ë¹ 0 · ìì ì¡ 0</span></div> 1776 <div class="gh-btn" style="margin-top:auto">𥡠ë§ê°í ì¸ ì¬ë¦¬ê¸°</div> 1777 </div> 1778 <div class="gh-scene"> 1779 <div class="gh-shead"><div class="gh-st">ð ëë¤ ìëì´ ë°ê²¬</div><span class="gh-tag">ìë</span></div> 1780 <div class="gh-card" style="margin-bottom:10px"> 1781 <div class="gh-circ">ð¥¡</div> 1782 <div style="color:#F4F4F6;font-size:13px">ââê°ê² · 320m</div> 1783 <div class="gh-amt">í ì 30% í ì¸</div> 1784 </div> 1785 <div style="text-align:center;margin-bottom:10px"><span class="gh-chip">ð 거리ì · ì°ë¦¬ ë§¤ì¥ ìë¨ ë ¸ì¶</span></div> 1786 <div class="gh-btn" style="margin-top:auto">ë´ì¼ë¬ ê°ê¸° â</div> 1787 </div> 1788 <div class="gh-scene"> 1789 <div class="gh-shead"><div class="gh-st">ð ë©ë´ ë´ì ìì½</div><span class="gh-tag">ìë</span></div> 1790 <div class="gh-card" style="margin-bottom:8px"> 1791 <div class="gh-row"><i>â</i> 먹ì ë©ë´ ê³¨ë¼ ë´ê¸°</div> 1792 <div class="gh-row"><i>â</i> í½ì ìê° ì í</div> 1793 <div class="gh-row"><i>â</i> í ì¤ë¡ 미리 ê²°ì </div> 1794 </div> 1795 <div style="text-align:center;margin-bottom:10px"><span class="gh-chip">𥡠í¬ì¥ì©ê¸°ë ì§ì°¸</span></div> 1796 <div class="gh-btn" style="margin-top:auto">ìì½ ìë£</div> 1797 </div> 1798 <div class="gh-scene"> 1799 <div class="gh-shead"><div class="gh-st">𥡠ìì½ ìê°ì í½ì </div><span class="gh-tag">ìë</span></div> 1800 <div class="gh-mut" style="text-align:center;margin-bottom:8px">ìì½í ìê°ì ê° ì¡°ë¦¬í´ ëë ¤ì</div> 1801 <div class="gh-card"><div class="gh-qr"></div><div class="gh-mut">í½ì ì½ë · ââê°ê²</div></div> 1802 <div class="gh-ok"><div class="gh-okc">â</div><div style="color:#F4F4F6;font-size:14px;font-weight:700">í½ì ìë£</div><div class="gh-mut">í ì, ìë°íê²</div></div> 1803 </div> 1804 <div class="gh-scene"> 1805 <div class="gh-shead"><div class="gh-st">ð ë¨ê³¨ë¡ ë¤ì ì´</div><span class="gh-tag">ì¬ì¥ë</span></div> 1806 <div class="gh-card" style="margin-bottom:10px"><div class="gh-big">ë¨ê³¨<span style="font-size:15px"> ì¬ë°©ë¬¸</span></div><div class="gh-mut">"ë¨ë©´ ì림" 구ë í ëë¤ ìë</div></div> 1807 <div style="text-align:center;margin-bottom:6px"><span class="gh-chip">ð ë§ê°í ì¸ ë¨ë©´ ìë ì림 â ì¬ë°©ë¬¸</span></div> 1808 <div class="gh-bars"><i style="height:38%"></i><i style="height:58%"></i><i style="height:72%"></i><i class="y" style="height:92%"></i></div> 1809 </div> 1810 </div> 1811 </div><!-- /gh-lane rescue --> 1812 <p class="gh-cap" id="ghCap"></p> 1813 <div class="gh-prog"><i id="ghProg"></i></div> 1814 </section> 1815
1815<script> 1816 (function() { 1817 // ë ë©ì¸ ìë¹ì¤ ë ì¸(ð ìíê¶ / 𥡠ë§ê°í ì¸) ê³µì© ì ëë©ì´ì ìì§ (2026-06-28). 1818 // ê°ì í° ëª©ì ·ë ì¼Â·ìº¡ì ·íë¡ê·¸ë ì¤ë¥¼ ì¬ì¬ì©, íì¼ë¡ scene-set ë§ ì¤ì. 1819 // ë ì¸ë³ caps/durs ë§ ë¶ê¸° â ì ë ì¸ ì¶ê°ë CAPS/DURS + .gh-lane ë§í¬ì ë§ ë리면 ë¨. 1820 // ⤠ìíê¶ ì½ë¤ = ë°ì ë°ì ì¸ë¡ ì¤ì ìì (R2 URL, ìì¼ë©´ placeholder + ê³ ì íì´ë¨¸). 1821 var GH_REACTION_VIDEO = 'https://cdn.stylevoicetalk.com/landing/stylevoicetalk_qr.mp4'; 1822 var hero = document.querySelector('.gh-hero'); 1823 if (!hero) return; 1824 // QR í¨í´ â 모ë ë ì¸ì .gh-qr ì±ì 1825 var pat = [1,0,1,1,0,1,1,0,1,0,0,1,0,0,1,1,1,0,1,1,0,1,0,1,0,1,0,1,0,0,1,1,0,1,1,1,0,1,0,1,0,0,1,0,1,1,0,1,1]; 1826 var qrs = hero.querySelectorAll('.gh-qr'); 1827 for (var qi = 0; qi < qrs.length; qi++) { 1828 for (var k = 0; k < 49; k++) { var sp = document.createElement('span'); if (pat[k]) sp.className = 'f'; qrs[qi].appendChild(sp); } 1829 } 1830 var CAPS = { 1831 gift: [ 1832 'ì¤ì¹ë¹Â·ìì ì¡ 0ì â 1ë¶ì´ë©´ ì°ë¦¬ ë§¤ì¥ ìíê¶ í매 ìì', 1833 'ìëì´ ì°ë¦¬ ë§¤ì¥ ìíê¶ì ì¬ì ì 물í´ì (ìì±í¸ì§ë ë¤)', 1834 'ë°ì ì¬ëì´ ì°ë¦¬ ê°ê²ë¡ ìì QR í ë² â ì ìë!', 1835 'í ì¤ê° ì¬ì¥ë ê³ì¢ë¡ ì ì° â ì ì°ë©´ ë³´ê´ë¶ìì íë¶', 1836 'ê·¸ë¦¬ê³ â ì 물 ë°ì ì¬ëì ì§ì§ íì (ì¤ì ìì)' 1837 ], 1838 rescue: [ 1839 'ì¤ë ë§ê° ë©ë´ë¥¼ í ì ë§ê°í ì¸ì¼ë¡ â 1ë¶ ë±ë¡', 1840 'ëë¤ ìëì´ ê±°ë¦¬ìì¼ë¡ ì°ë¦¬ 매ì¥ì ë°ê²¬í´ì (2015 ëë¤ëì íì¤í)', 1841 '먹ì ë©ë´ ê³¨ë¼ ë´ì í½ì ìê° ìì½Â·ê²°ì ', 1842 'ìì½í ìê°ì ê° ì¡°ë¦¬ â í¬ì¥ì©ê¸°ë§ ì§ì°¸íë©´ ë', 1843 'ë¨ê³¨ì´ ëì´ ë¤ì ìµëë¤ â ë§ê° ì¬ê³ ê° ë¨ê³¨ 매ì¶ë¡' 1844 ] 1845 }; 1846 var DURS = { gift: [3400, 3000, 3200, 3000, 5000], rescue: [3400, 3200, 3200, 3200, 3400] }; 1847 var cap = document.getElementById('ghCap'); 1848 var prog = document.getElementById('ghProg'); 1849 var lanes = {}, laneEls = hero.querySelectorAll('.gh-lane'); 1850 for (var L = 0; L < laneEls.length; L++) { 1851 var le = laneEls[L], key = le.getAttribute('data-lane'), phone = le.querySelector('.gh-phone'); 1852 if (!phone) continue; 1853 var rvid = phone.querySelector('.gh-rvid'); 1854 var lane = { 1855 key: key, el: le, phone: phone, 1856 scenes: phone.querySelectorAll('.gh-scene'), 1857 stops: le.querySelectorAll('.gh-rail .gh-stop'), 1858 caps: CAPS[key] || [], durs: DURS[key] || [], 1859 rvid: rvid, hasVideo: !!(GH_REACTION_VIDEO && rvid) 1860 }; 1861 if (lane.hasVideo) { 1862 rvid.src = GH_REACTION_VIDEO; 1863 var face = phone.querySelector('.gh-face'); if (face) face.style.display = 'none'; 1864 var rplay = phone.querySelector('.gh-rplay'); if (rplay) rplay.style.display = 'none'; 1865 (function (ln, fc, rp) { 1866 ln.rvid.addEventListener('error', function () { ln.hasVideo = false; ln.rvid.style.display = 'none'; if (fc) fc.style.display = ''; if (rp) rp.style.display = ''; }); 1867 })(lane, face, rplay); 1868 } 1869 lanes[key] = lane; 1870 } 1871 var active = 'gift', i = 0, timer = null, okT = null; 1872 function clearT() { if (timer) { clearTimeout(timer); timer = null; } if (okT) { clearTimeout(okT); okT = null; } } 1873 function next() { var Ln = lanes[active]; i = (i + 1) % Ln.scenes.length; show(i); } 1874 function show(n) { 1875 clearT(); 1876 var Ln = lanes[active]; 1877 for (var a = 0; a < Ln.scenes.length; a++) Ln.scenes[a].classList.toggle('on', a === n); 1878 for (var b = 0; b < Ln.stops.length; b++) Ln.stops[b].classList.toggle('on', b === n); 1879 if (cap) cap.textContent = Ln.caps[n] || ''; 1880 var d = Ln.durs[n] || 3200;
1881 if (prog) { prog.style.transition = 'none'; prog.style.width = '0'; void prog.offsetWidth; prog.style.transition = 'width ' + d + 'ms linear'; prog.style.width = '100%'; } 1882 // .gh-ok ì¤ë²ë ì´ê° ìë ì¬ì´ë©´ 1.6s í reveal (ì¬ ì¸ë±ì¤ 무ê´) 1883 var allOk = Ln.phone.querySelectorAll('.gh-ok'); 1884 for (var o = 0; o < allOk.length; o++) allOk[o].classList.remove('show'); 1885 var cur = Ln.scenes[n], ok = cur ? cur.querySelector('.gh-ok') : null; 1886 if (ok) okT = setTimeout(function () { ok.classList.add('show'); }, 1600); 1887 // ë¹ëì¤ ì½ë¤ ì¬(.gh-scene.vid) â ìíê¶ ë ì¸ë§ 1888 if (Ln.hasVideo && cur && cur.classList.contains('vid')) { 1889 Ln.rvid.style.display = 'block'; 1890 try { Ln.rvid.currentTime = 0; } catch (e) {} 1891 var p = Ln.rvid.play(); if (p && p.catch) p.catch(function () {}); 1892 Ln.rvid.onended = function () { next(); }; 1893 timer = setTimeout(next, 30000); 1894 } else { 1895 if (Ln.rvid) Ln.rvid.style.display = 'none'; 1896 timer = setTimeout(next, d); 1897 } 1898 } 1899 // rail stop í´ë¦ â í´ë¹ ë ì¸ì¼ë¡ ì í í ì¸ë±ì¤ ì í 1900 Object.keys(lanes).forEach(function (key) { 1901 var Ln = lanes[key]; 1902 for (var c = 0; c < Ln.stops.length; c++) { 1903 (function (idx) { 1904 var st = Ln.stops[idx]; 1905 st.setAttribute('role', 'button'); 1906 st.setAttribute('tabindex', '0'); 1907 st.addEventListener('click', function () { setLane(key, idx); }); 1908 st.addEventListener('keydown', function (ev) { if (ev.key === 'Enter' || ev.key === ' ') { ev.preventDefault(); setLane(key, idx); } }); 1909 })(c); 1910 } 1911 }); 1912 // í ì í 1913 var tabs = hero.querySelectorAll('.gh-tab'); 1914 for (var t = 0; t < tabs.length; t++) { 1915 (function (tab) { tab.addEventListener('click', function () { setLane(tab.getAttribute('data-lane'), 0); }); })(tabs[t]); 1916 } 1917 function setLane(key, idx) { 1918 if (!lanes[key]) return; 1919 active = key; 1920 for (var t2 = 0; t2 < tabs.length; t2++) { 1921 var on = tabs[t2].getAttribute('data-lane') === key; 1922 tabs[t2].classList.toggle('on', on); 1923 tabs[t2].setAttribute('aria-selected', on ? 'true' : 'false'); 1924 } 1925 Object.keys(lanes).forEach(function (k2) { 1926 lanes[k2].el.classList.toggle('on', k2 === key); 1927 if (k2 !== key && lanes[k2].rvid) { try { lanes[k2].rvid.pause(); } catch (e) {} } 1928 }); 1929 i = idx || 0; show(i); 1930 } 1931 function start() { setLane('gift', 0); } 1932 if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', start); else start(); 1933 })(); 1934 </script>
1934 1935 1936 </div> 1937 </div> 1938 1939 <!-- §2-1 ì¬ì¥ëê» ëê° ì¢ë (4 ì¹´ë) --> 1940 <h2 class="merchant-h2">ì¬ì¥ëê» ëê° ì¢ë</h2> 1941 <div class="benefit-grid"> 1942 <div class="benefit-card"> 1943 <div class="benefit-emoji">ð¶</div> 1944 <div class="benefit-title">ì ìëì´ ì ë°ë¡ ì´</div> 1945 <div class="benefit-sub">ì 물 ë°ì ì¬ë = ì ê· ë°©ë¬¸. ë§¤ì¥ ì¸ì§Â·ì ê· ì ì ì ëìì.</div> 1946 </div> 1947 <div class="benefit-card"> 1948 <div class="benefit-emoji">ð°</div> 1949 <div class="benefit-title">ì ê²°ì ë¡ íê¸ì´ 먼ì </div> 1950 <div class="benefit-sub">ìëì´ ë§¤ì¥ìì ì¸ ë ì¬ì¥ë ê³ì¢ë¡ ì ì°. ê²°ì ê¸ì ê·¸ëê¹ì§ í ì¤ê° ìì ë³´ê´.</div> 1951 </div> 1952 <div class="benefit-card"> 1953 <div class="benefit-emoji">ð</div> 1954 <div class="benefit-title">ì¤ì¹ë¹Â·ìì ì¡ 0ì</div> 1955 <div class="benefit-sub">í릴 ëë§ ì¹´ë ììë£(í ì¤) + ì°ë¦¬ ììë£. ê°ì ì í´ëí° ì¸ì¦ 1ë¶.</div> 1956 </div> 1957 <div class="benefit-card"> 1958 <div class="benefit-emoji">ð£</div> 1959 <div class="benefit-title">ìëì´ ììì SNSì ì¬ë¦¼</div> 1960 <div class="benefit-sub">"ë°ì ìì±í¸ì§ê° ë무 ì¢ìì" â ì¬ì¥ë ê´ê³ ë¹ 0ì, ìë°ì ì ì문.</div> 1961 </div> 1962 </div> 1963 1964 <!-- §2-1b ë ë²ì§¸ ë©ì¸ = í¬ì¥ì©ê¸° ë§ê°í ì¸ (2015 ëë¤ëì íì¤í, 2026-06-28). 1965 ì¹´í¼ ê°ë(rescue §0-2): ë¨ì´/ë¨ì ìì/ë²ë¦¬ë¤ í¤ 0 · "í¬ì¥ì©ê¸°" · "í ì" · ìê° ëª»ë°ê¸° 0. 1966 'ë§ê° ì¬ê³ '·'ë§ê° ìê°'(ì¤ë¦½ ë¹ì¦ëì¤ ì©ì´)ë§ ì¬ì©. h2/p/benefit-grid ë .wrap ì§ì â 1967 non-home hide ê·ì¹(.wrap > h2/p/.benefit-grid)ì ì´ë¯¸ 매ì¹, ë³ë hide ì¶ê° ë¶íì. --> 1968 <h2 class="merchant-h2">í¬ì¥ì©ê¸° ë§ê°í ì¸ â ëë¤ë, ì´ë²ì ì ëë¡</h2> 1969 <p class="rescue-lead"> 1970 2015ë ìë©íÂ·ì¿ í¡ì ëë¤ í ì¸ëì´ ë°ì§íê³ ì¬ë¼ì§ ì´ì ë ê°ë¨í©ëë¤ â 1971 <b>ìëì í ì¸íì´ ìì¬ì ê³ , ì¬ì¥ëì ë¨ë ê² ììê±°ë ì.</b> 1972 ì°ë¦¬ë íì¤ì ë§ê² ë¤ì ì§ëë¤: í¬ì¥ì©ê¸°ë¥¼ ìëì´ ê°ì ¸ì¤ë <b>í ì¸íì ë í¬ê²</b>, 1973 ë§ê° ìê° ì¬ê³ 를 í ë²ì í¸ë <b>ì¬ì¥ëì 매ì¶ë¡</b>. 1974 </p> 1975 <div class="benefit-grid"> 1976 <div class="benefit-card"> 1977 <div class="benefit-emoji">ð</div> 1978 <div class="benefit-title">ëë¤ ìëìê² ê±°ë¦¬ì ë ¸ì¶</div> 1979 <div class="benefit-sub">ì±ì ì¼ ëë¤ ìë íë©´ ìë¨ì ì°ë¦¬ 매ì¥ì´. ë§ê° ìê° ì¬ê³ 를 ê°ê¹ì´ ìëë¶í° ì±ìì.</div> 1980 </div> 1981 <div class="benefit-card"> 1982 <div class="benefit-emoji">ð¥¡</div> 1983 <div class="benefit-title">í¬ì¥ì©ê¸° ì§ì°¸ = ë í° í ì¸</div> 1984 <div class="benefit-sub">ìëì´ ì©ê¸°ë¥¼ ê°ì ¸ì¤ë ì¼íì©ê¸°Â·í¬ì¥ ë¶ë´ì´ ë¹ ì ¸ì. ê·¸ë§í¼ í ì¸íì í¤ì 'í ì'ì ìë°íê².</div> 1985 </div> 1986 <div class="benefit-card"> 1987 <div class="benefit-emoji">ð</div> 1988 <div class="benefit-title">í ë² ì¨ ìëì´ ë¨ê³¨ë¡</div> 1989 <div class="benefit-sub">"ë¨ë©´ ì림" 구ë í ëë¤ ìëìê² ë§ê°í ì¸ì ì¬ë¦´ ëë§ë¤ ìë ì림 â ì¬ë°©ë¬¸ 루í.</div> 1990 </div> 1991 <div class="benefit-card"> 1992 <div class="benefit-emoji">ð³</div> 1993 <div class="benefit-title">ìì½Â·ì ê²°ì ë¡ í걸ì 0</div> 1994 <div class="benefit-sub">ìëì´ ë©ë´ ê³¨ë¼ í ì¤ë¡ 미리 ê²°ì ·í½ì ìì½. ìì½í ìê°ì ê° ì¡°ë¦¬ë§ íë©´ ë.</div> 1995 </div> 1996 </div> 1997 1998 <!-- §2-2 ì 뢰 â ê°ì¥ ì¤ì. ëÂ·ë² ì ìíí´? --> 1999 <h2 class="merchant-h2">ëÂ·ë² ê±±ì ìì</h2> 2000 <div class="trust-grid"> 2001 <div class="trust-card trust-card-strong"> 2002 <div class="trust-title">ð¸ í ì¤ê° ì¬ì¥ë ê³ì¢ë¡ <b>ì§ì ì ì°</b></div> 2003 <div class="trust-sub">ê²°ì ëê¸ì ì°ë¦¬ê° ê°ì§ì§ ììµëë¤. í ì¤íì´ë¨¼ì¸ ê° ìì ë³´ê´ â ìëì´ ë§¤ì¥ìì ì¸ ë ì¬ì¥ë ê³ì¢ë¡ ì§ê¸. ì ì°ë©´ íë¶ë ê·¸ ë³´ê´ë¶ìì ì²ë¦¬.</div> 2004 </div> 2005 <div class="trust-card"> 2006 <div class="trust-title">ð íµì í매ì¤ê° ê³ ì§</div> 2007 <div class="trust-sub">ë§¤ì¥ íì´ì§ íë¨ì ì¬ì¥ë ì¬ì ì ì ë³´ê° ìë í기ë©ëë¤. íµì í매ì¤ê°ì(ì í¬) â íµì í매ì ì(ì¬ì¥ë) ë¶ë¦¬ ëª ì.</
2007div> 2008 </div> 2009 <div class="trust-card"> 2010 <div class="trust-title">ð¢ ì°ë¦¬ ì¬ì ì ì ì ê³µê°</div> 2011 <div class="trust-sub">StyleVoiceTalk (ëí ì´ê²½ì² · ë±ë¡ë²í¸ 496-13-02999 · ì©ì¸ì ìì§êµ¬ í¸ìë¡ 47). ìµëª ì´ìì ìëëë¤.</div> 2012 </div> 2013 </div> 2014 2015 <!-- §2-3 1ë¶ zero-config --> 2016 <h2 class="merchant-h2">1ë¶ì´ë©´ ìì</h2> 2017 <div class="onboarding-card"> 2018 <ol class="onboard-steps"> 2019 <li><b>í´ëí° ì¸ì¦</b> ì¼ë¡ ê°ì </li> 2020 <li>ë§¤ì¥ ì´ë¦Â·ì°ë½ì² ì ë ¥ (ì¬ì ìë²í¸ë ìë ê²ì¦)</li> 2021 <li>ê¶ì¢ 4ì¢ ìë ìì± â 5ì² / 1ë§ / 3ë§ / 5ë§ì</li> 2022 <li><b>ë.</b> ìëì´ ë°ë¡ ë§¤ì¥ íì´ì§ìì 구매 ê°ë¥</li> 2023 </ol> 2024 <button class="primary-cta primary-cta-secondary" type="button" data-target="/cafe-admin"> 2025 무ë£ë¡ ê°ì¤í기 <span class="arrow">â</span> 2026 </button> 2027 </div> 2028 2029 <!-- §2-4 ì¤ì íë©´ (ì ì ì´ë¯¸ì§/목ì , ì 뢰 ë³´ê°) --> 2030 <h2 class="merchant-h2">ì¤ì íë©´</h2> 2031 <div class="mockup-grid"> 2032 <figure class="mockup-card"> 2033 <div class="mockup-thumb mockup-thumb-reveal">ð±<span class="mockup-label">ë°ëì´ í¼ì¹¨ íë©´</span></div> 2034 <figcaption>ë°ì ì¬ëì´ ì¹´í¡ ë§í¬ ì´ë©´ â ìì±í¸ì§ + ì¿ í° ì½ë</figcaption> 2035 </figure> 2036 <figure class="mockup-card"> 2037 <div class="mockup-thumb mockup-thumb-qr">ð·<span class="mockup-label">QR ì¬ì©ì²ë¦¬</span></div> 2038 <figcaption>매ì¥ìì ìë QR ì¤ìº â ì¦ì ì¬ì© ìë£ (1ì´)</figcaption> 2039 </figure> 2040 <figure class="mockup-card"> 2041 <div class="mockup-thumb mockup-thumb-dash">ð<span class="mockup-label">ì¬ì¥ë ëìë³´ë</span></div> 2042 <figcaption>í매·ì¬ì©Â·ë¯¸ì¬ì© ìì¡ íëì. í ì¤ ì ì° ë´ì ì§ë§í¬</figcaption> 2043 </figure> 2044 </div> 2045 2046 <!-- §2-5 ìì± ì 문 íì¬ í ì¤ (ë¶ê°ìë¹ì¤ ì 뢰ë§, ê¹ì´ X) --> 2047 <p class="company-line"> 2048 ìì± ì½í ì¸ Â· ìë¶ ë©ìì§ Â· ë§¤ì¥ BGMê¹ì§ â í íì¬ê° ì´ìí©ëë¤. 2049 <a href="/contents" data-target="/contents" class="company-link">ìë¹ì¤ ëë¬ë³´ê¸° â</a> 2050 </p> 2051 2052 <footer class="brand-footer"> 2053 <div class="footer-row"> 2054 <a href="/terms" data-target="/terms">ì´ì©ì½ê´</a> 2055 <a href="/privacy" data-target="/privacy">ê°ì¸ì ë³´ ì²ë¦¬ë°©ì¹¨</a> 2056 <a href="/refund" data-target="/refund">íë¶ì ì± </a> 2057 <a href="/business" data-target="/business">ì¬ì ì ì ë³´</a> 2058 <!-- ìê¸ ìë´ë ë³ë íì´ì§ íì â ì¬ì¥ë ëë© ë ¸ì¶ 0 (íê· ê°ë). 2059 ê°ê²©íë ë¡ê·¸ì¸ í ì½í ì¸ ìë¹ì¤ ì쪽 (Flutter ContentsScreen) ì¼ë¡ ìì¹ ì´ë. --> 2060 <a href="/age-policy" data-target="/age-policy">ì´ì© ì ì± </a> 2061 <a href="/music-credits" data-target="/music-credits">ìì ì ìê¶ ìë´</a> 2062 </div> 2063 <div class="footer-meta"> 2064 © 2026 StyleVoiceTalk · ì¬ì¥ë ì ì°: í ì¤íì´ë¨¼ì¸ ì§ì / ì½í ì¸ ê²°ì : Lemon Squeezy (Stripe MoR) 2065 </div> 2066 </footer> 2067 2068 <!-- non-home hide 모ëììë§ ë ¸ì¶ (Flutter ë¡ë© ì¸ëì¼ì´í°) --> 2069 <div class="moment-preview"> 2070 <div class="emoji" id="momentPreviewEmoji">ð</div> 2071 <div class="title" id="momentPreviewTitle">ì기 ì ì´ì¼ê¸°</div> 2072 <div class="sub" id="momentPreviewSub">ì ë¤ê¸° ì¢ì ë¤ì í ì´ì¼ê¸° í í¸</div> 2073 </div> 2074 <div class="spinner" aria-hidden="true"></div> 2075 <div class="loading-text">ì¤ë¹ ì¤â¦</div> 2076 <div class="first-load-msgs" aria-live="polite"> 2077 <div class="msg msg-1">ì ìë§ ê¸°ë¤ë ¤ 주ì¸ì</div> 2078 <div class="msg msg-2">íë©´ì ì¤ë¹íê³ ììµëë¤</div> 2079 <div class="msg msg-3">ê±°ì ë¤ ëììµëë¤</div> 2080 </div> 2081 </div> 2082 </div> 2083 2084 <!-- Supabase JS â ì ì íìì ì¸ì¦ ìí íì¸ + Google OAuth í¸ë¦¬ê±°. 2085 Flutter ë¡ë(ì½ 10s) ë기 ìì´ ì¹´ë í´ë¦ ì¦ì Google ë¡ê·¸ì¸ íë©´ì¼ë¡ ì§ì . 2086 ìì²´ í¸ì¤í â iPhone Safari ë± ì¼ë¶ íê²½ìì jsdelivr/unpkg CDN ì´ 8s 2087 íììì ìì ìëµ ëª» í´ "ë¡ê·¸ì¸ 모ë ë¡ë ì¤í¨" íê· (2026-05-07). 2088 111KB â ìì²´ ëë©ì¸ (Cloudflare proxy) ìì íì ë¹ ë¥´ê² ëë¬. --> 2089
2089<script src="vendor/supabase-2.45.4.min.js"></script>
2089 2090 <!-- Google Identity Services â One Tap ìë ë¡ê·¸ì¸ í롬íí¸ì©. --> 2091
2091<script src="https://accounts.google.com/gsi/client" async defer></script>
2091 2092 <!-- Kakao JS SDK â `/message` íë©´ [ê³µì í기] + /listen/<care_id> íì´ì§ìì ì¬ì©. 2093 ì´ê¸°íë Flutter ë¶í¸ ì KakaoShare.initIfNeeded(Env.kakaoJsKey) ê° ì²ë¦¬. 2094 /listen ì ì 미ë íì´ì§ë backend ê° ë³ë inline ì¤ëí«ì¼ë¡ init í¸ì¶. --> 2095
2095<script src="https://t1.kakaocdn.net/kakao_js_sdk/2.7.2/kakao.min.js" crossorigin="anonymous" defer></script>
2095 2096 <!-- Toss Payments SDK v2 â ì 물 ê²°ì ìì ¯ (ìì²ì §6). 2097 sandbox·live ê³µíµ SDK. clientKey prefix (test_ck_*/live_ck_*) ë¡ ë¶ê¸°. 2098 SECRET í¤ë ì ë íë¡ í¸ ë ¸ì¶ X â ë°±ìë confirm endpoint ê° ì ë´. --> 2099
2099<script src="https://js.tosspayments.com/v2/standard" defer></script>
2099 2100 <!-- ì¹´ì¹´ì¤ë§µ inline iframe â ë°±ìëê° /api/gift/cafes/{id}/map.html ë ë (ìì²ì §6-12). 2101 Flutter web ì HtmlElementView platform view ììì iframe ì¼ë¡ ìë² ë. 2102 SDK script ë ë°±ìë HTML ììì ë¡ë (autoload + lat/lng init). --> 2103 2104
2104<script> 2105 (function() { 2106 var SUPABASE_URL = 'https://dcwufunxyddhtnsmapdl.supabase.co'; 2107 var SUPABASE_ANON_KEY = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImRjd3VmdW54eWRkaHRuc21hcGRsIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NzY0OTY2OTUsImV4cCI6MjA5MjA3MjY5NX0.Fo0gHlv5cc0i7BPc8fFDmKVmifibcpB0FvdQaHvHqII'; 2108 var _client = null; 2109 2110 // Fix 3 (req_web_stale_bundle_login_return): ë¡ê·¸ì¸ í ë³µê·í next ê²½ë¡. 2111 // open-redirect ë°©ì§ â ì기 ì¤ë¦¬ì§ ì ëê²½ë¡(/ë¡ ìì, // ìë)ë§ íì©. 2112 var _nextDest = (function () { 2113 try { 2114 var n = new URLSearchParams(window.location.search || '').get('next'); 2115 if (n && n.charAt(0) === '/' && n.charAt(1) !== '/') return n; 2116 } catch (_) {} 2117 return null; 2118 })(); 2119 // next ê° ìì¼ë©´ 'ë¡ê·¸ì¸' ë²í¼ 목ì ì§ë¥¼ ê·¸ ê²½ë¡ë¡ (기본 /contents ì¤ë²ë¼ì´ë). 2120 if (_nextDest) { 2121 try { 2122 var _lb = document.getElementById('loginBtn'); 2123 if (_lb) _lb.setAttribute('data-target', _nextDest); 2124 } catch (_) {} 2125 } 2126 2127 function waitForSupabase(maxMs) { 2128 return new Promise(function(resolve) { 2129 var deadline = Date.now() + (maxMs || 3000); 2130 (function check() { 2131 if (window.supabase && window.supabase.createClient) return resolve(true); 2132 if (Date.now() > deadline) return resolve(false); 2133 setTimeout(check, 50); 2134 })(); 2135 }); 2136 } 2137 2138 function getClient() { 2139 if (_client) return _client; 2140 if (!window.supabase || !window.supabase.createClient) return null; 2141 _client = window.supabase.createClient(SUPABASE_URL, SUPABASE_ANON_KEY, { 2142 auth: { persistSession: true, autoRefreshToken: true, detectSessionInUrl: true }, 2143 }); 2144 return _client; 2145 } 2146 2147 async function handleNavigate(dest) { 2148 if (dest === '/login') { 2149 window.location.href = dest; 2150 return; 2151 } 2152 var ready = await waitForSupabase(8000); 2153 if (!ready) { 2154 alert('ë¡ê·¸ì¸ 모ë ë¡ë ì¤í¨ â ë¤í¸ìí¬ë¥¼ íì¸íì¸ì.'); 2155 return; 2156 } 2157 var c = getClient(); 2158 var sessionRes; 2159 try { 2160 sessionRes = await c.auth.getSession(); 2161 } catch (e) { 2162 alert('ì¸ì íì¸ ì¤í¨: ' + (e && e.message ? e.message : e)); 2163 return; 2164 } 2165 if (sessionRes && sessionRes.data && sessionRes.data.session) { 2166 // ì´ë¯¸ ë¡ê·¸ì¸ â ë°ë¡ ì´ë. 2167 window.location.href = dest; 2168 return; 2169 } 2170 // ë¹ë¡ê·¸ì¸ â Google OAuth 를 íì ì°½ì¼ë¡. ë¶ëª¨ì°½ì ì¸ì ê°ì§ í dest ë¡ ì´ë. 2171 // redirectTo 를 ì ì í('/?popupAuth=1')ë¡ ì¤ì â Flutter 미ë¡ë, JS Supabase ê° 2172 // URL hash ì OAuth í í°ì localStorage ì ì ì¥íê³ íì ì´ ìë ì¢ ë£ë¨. 2173 var redirectTo = window.location.origin + '/?popupAuth=1'; 2174 var res; 2175 try { 2176 res = await c.auth.signInWithOAuth({ 2177 provider: 'google', 2178 options: { redirectTo: redirectTo, skipBrowserRedirect: true }, 2179 }); 2180 } catch (e) { 2181 alert('OAuth í¸ì¶ ìì¸: ' + (e && e.message ? e.message : e)); 2182 return; 2183 } 2184 if (!res || res.error || !res.data || !res.data.url) { 2185 alert('Google ë¡ê·¸ì¸ ì¤í¨: ' + (res && res.error ? res.error.message : 'ì ì ìë ì¤ë¥')); 2186 return; 2187 } 2188 // íì ì°½ ì´ê¸° â ê°ì´ë° ë°°ì¹. 2189 var w = 480, h = 640; 2190 var left = (window.screen.width - w) / 2; 2191 var top = (window.screen.height - h) / 2; 2192 var popup = window.open( 2193 res.data.url, 2194 'voiceMomentsAuth', 2195 'width=' + w + ',height=' + h + ',left=' + left + ',top=' + top + ',popup=yes', 2196 ); 2197 if (!popup || popup.closed) { 2198 // íì ì°¨ë¨ â í 리ëë í¸ë¡ í´ë°±. 2199 window.location.href = res.data.url; 2200 return; 2201 } 2202 // ì¸ì ê°ì§ â supabase-js ì ë©ëª¨ë¦¬ ìºìê° localStorage ë³ê²½ì ì¦ì 못 ë³´ë¯ë¡ 2203 // ë ê°ì§ ë°©ì ë³í: (1) storage ì´ë²¤í¸ 리ì¤ë (ë¤ë¥¸ ì°½ ë³ê²½ ì¦ì íµì§) 2204 // (2) localStorage ì§ì í´ë§ (storage ì´ë²¤í¸ ëë½ ëë¹) 2205 var done = false;
2206 function checkLocalStorageSession() { 2207 try { 2208 for (var i = 0; i < localStorage.length; i++) { 2209 var k = localStorage.key(i); 2210 if (!k || k.indexOf('sb-') !== 0 || k.indexOf('-auth-token') < 0) continue; 2211 var raw = localStorage.getItem(k); 2212 if (!raw) continue; 2213 var v = JSON.parse(raw); 2214 var token = v && (v.access_token || 2215 (v.currentSession && v.currentSession.access_token)); 2216 if (token) return true; 2217 } 2218 } catch (_) {} 2219 return false; 2220 } 2221 function finish() { 2222 if (done) return; 2223 done = true; 2224 try { popup.close(); } catch (_) {} 2225 window.location.href = dest; 2226 } 2227 var onStorage = function(ev) { 2228 if (!ev.key) return; 2229 if (ev.key.indexOf('sb-') === 0 && ev.key.indexOf('-auth-token') > 0) { 2230 if (checkLocalStorageSession()) finish(); 2231 } 2232 }; 2233 window.addEventListener('storage', onStorage); 2234 2235 var deadline = Date.now() + 180000; 2236 var poll = setInterval(function() { 2237 if (done || Date.now() > deadline) { 2238 clearInterval(poll); 2239 window.removeEventListener('storage', onStorage); 2240 return; 2241 } 2242 if (popup.closed && !checkLocalStorageSession()) { 2243 // ì¬ì©ì ì·¨ì. 2244 clearInterval(poll); 2245 window.removeEventListener('storage', onStorage); 2246 return; 2247 } 2248 if (checkLocalStorageSession()) { 2249 clearInterval(poll); 2250 window.removeEventListener('storage', onStorage); 2251 finish(); 2252 } 2253 }, 600); 2254 } 2255 2256 document.addEventListener('click', function(ev) { 2257 var t = ev.target.closest('[data-target]'); 2258 if (!t) return; 2259 var dest = t.getAttribute('data-target'); 2260 if (!dest) return; 2261 ev.preventDefault(); 2262 handleNavigate(dest); 2263 }); 2264 2265 // nonce ì í¸ â One Tap ë³´ì ê²ì¦ì©. raw ë Supabase ì ì ë¬, sha256(raw) ë Google ì ì ë¬. 2266 var _oneTapNonce = null; 2267 async function _genNonce() { 2268 var arr = new Uint8Array(32); 2269 window.crypto.getRandomValues(arr); 2270 var raw = Array.from(arr).map(function(b) { 2271 return ('0' + b.toString(16)).slice(-2); 2272 }).join(''); 2273 var enc = new TextEncoder().encode(raw); 2274 var hashBuf = await window.crypto.subtle.digest('SHA-256', enc); 2275 var hashArr = Array.from(new Uint8Array(hashBuf)); 2276 var hashHex = hashArr.map(function(b) { 2277 return ('0' + b.toString(16)).slice(-2); 2278 }).join(''); 2279 return { raw: raw, hashed: hashHex }; 2280 } 2281 2282 // ë¡ê·¸ì¸ë ì¬ì©ì 칩 ë ë â ë¡ê·¸ì¸/ê°ì ë²í¼ ì리ì ì¬ì©ì ì ë³´ + ë¡ê·¸ìì íì. 2283 function _renderUserChip(session) { 2284 var btn = document.getElementById('loginBtn'); 2285 var chip = document.getElementById('userChip'); 2286 if (!chip) return; 2287 var u = (session && session.user) || {}; 2288 var meta = u.user_metadata || {}; 2289 var name = meta.name || meta.full_name || 2290 (u.email ? u.email.split('@')[0] : 'ì¬ì©ì'); 2291 var email = u.email || ''; 2292 var avatar = meta.avatar_url || ''; 2293 var initials = (name && name.charAt(0).toUpperCase()) || '?'; 2294 2295 chip.innerHTML = ''; 2296 var av = document.createElement('div'); 2297 av.className = 'avatar'; 2298 if (avatar) { 2299 var img = document.createElement('img'); 2300 img.src = avatar; 2301 img.alt = ''; 2302 av.appendChild(img); 2303 } else { 2304 av.textContent = initials; 2305 } 2306 var label = document.createElement('span'); 2307 label.textContent = email || name; 2308 var logout = document.createElement('button'); 2309 logout.className = 'logout'; 2310 logout.type = 'button'; 2311 logout.textContent = 'ë¡ê·¸ìì'; 2312 logout.addEventListener('click', async function() { 2313 try { 2314 var cl = getClient(); 2315 if (cl) await cl.auth.signOut(); 2316 } catch (_) {} 2317 window.location.reload(); 2318 }); 2319 chip.appendChild(av); 2320 chip.appendChild(label); 2321 chip.appendChild(logout); 2322 chip.style.display = 'flex'; 2323 if (btn) btn.style.display = 'none'; 2324 } 2325 2326 // Google One Tap â '/' ì ì í ì§ì ì ìëì¼ë¡ ê³ì ì í í롬íí¸ ë ¸ì¶. 2327 // - ë¹ë¡ê·¸ì¸ ìíì´ê³ , popupAuth ì½ë°± íì´ì§ê° ìë ëë§. 2328 // - GIS ê° ID í í°ì ë°ííë©´ supabase.signInWithIdToken ì¼ë¡ ì¸ì ìì±. 2329 (async function() { 2330 var isPopupCallback = (new URLSearchParams(window.location.search)) 2331 .get('popupAuth') === '1'; 2332 if (isPopupCallback) return; 2333 if (window.location.pathname !== '/' && window.location.pathname !== '') return; 2334 var ready = await waitForSupabase(8000); 2335 if (!ready) return; 2336 var c = getClient(); 2337 // ì´ë¯¸ ë¡ê·¸ì¸ â ë¡ê·¸ì¸ ë²í¼ì ì¬ì©ì ì ë³´ 칩ì¼ë¡ êµì²´. 2338 // Supabase ê° localStorage ìì ì¸ì ì ë¡ëíë ë° ì½ê°ì ìê°ì´ íìí ì ìì´ 2339 // onAuthStateChange ë í¨ê» ë±ë¡ â ë¦ê² ë°ê²¬ë¼ë ì¹©ì´ ëíë¨. 2340 // ì¬ì¥ë ëë© í¼ë² (2026-05-31): ë¡ê·¸ì¸ ì¬ì©ì / ì§ì ì â 기존 ìë¹ì í(/contents) ìë redirect. 2341 // ì´ë¯¸ ê°ì ·결ì í ì¬ì©ììê² ë§ì¼í íì´ì§ë¥¼ ë ë³´ì¬ì¤ ì´ì 0 (ìì²ì §6). 2342 // ?landing=force ì¿¼ë¦¬ë¡ ì°í ê°ë¥ (ëë²ê¹ /ì¬ì¥ëì´ ì기 ê°ê² 미리보기 ë±). 2343 var _forceLanding = (new URLSearchParams(window.location.search)).get('landing') === 'force'; 2344 var _isHome = (window.location.pathname === '/' || window.location.pathname === ''); 2345 function _maybeRedirectLoggedIn(session) { 2346 if (!session || !_isHome || _forceLanding) return false;
2347 // chip ì´ì§ ë ë í redirect (ì¬ì©ìê° "ì´ ìë ì´ëëë¤" ëë) 2348 try { _renderUserChip(session); } catch (_) {} 2349 // next ê° ìì¼ë©´ ê·¸ ê²½ë¡ë¡ (ë¡ê·¸ì¸ ìíë¡ /?next=/ad ì§ì ë±), ìì¼ë©´ 기본 /contents. 2350 var _dest = _nextDest || '/contents'; 2351 setTimeout(function() { window.location.href = _dest; }, 250); 2352 return true; 2353 } 2354 c.auth.onAuthStateChange(function(event, session) { 2355 console.log('[home] auth event=' + event + ' hasSession=' + !!session); 2356 if (session) { 2357 if (!_maybeRedirectLoggedIn(session)) _renderUserChip(session); 2358 } 2359 }); 2360 try { 2361 var s = await c.auth.getSession(); 2362 console.log('[home] initial getSession hasSession=' + 2363 !!(s && s.data && s.data.session)); 2364 if (s && s.data && s.data.session) { 2365 if (_maybeRedirectLoggedIn(s.data.session)) return; 2366 _renderUserChip(s.data.session); 2367 return; 2368 } 2369 } catch (e) { 2370 console.warn('[home] getSession exception:', e); 2371 } 2372 // GIS ë¡ë ë기. 2373 var gisDeadline = Date.now() + 8000; 2374 var giwait = setInterval(function() { 2375 if (Date.now() > gisDeadline) { clearInterval(giwait); return; } 2376 if (window.google && window.google.accounts && window.google.accounts.id) { 2377 clearInterval(giwait); 2378 initOneTap(); 2379 } 2380 }, 100); 2381 2382 async function initOneTap() { 2383 try { 2384 _oneTapNonce = await _genNonce(); 2385 window.google.accounts.id.initialize({ 2386 client_id: '1039204727872-0398uf61rt9c5k85ahq50c53mjf125e9.apps.googleusercontent.com', 2387 callback: handleCredential, 2388 auto_select: false, 2389 cancel_on_tap_outside: false, 2390 use_fedcm_for_prompt: true, 2391 nonce: _oneTapNonce.hashed, 2392 }); 2393 window.google.accounts.id.prompt(function(notification) { 2394 try { 2395 if (notification.isNotDisplayed && notification.isNotDisplayed()) { 2396 console.warn('[OneTap] not displayed reason=' + 2397 notification.getNotDisplayedReason()); 2398 } else if (notification.isSkippedMoment && notification.isSkippedMoment()) { 2399 console.warn('[OneTap] skipped reason=' + 2400 notification.getSkippedReason()); 2401 } else if (notification.isDismissedMoment && notification.isDismissedMoment()) { 2402 console.warn('[OneTap] dismissed reason=' + 2403 notification.getDismissedReason()); 2404 } else if (notification.isDisplayed && notification.isDisplayed()) { 2405 console.log('[OneTap] displayed'); 2406 } 2407 } catch (_) {} 2408 }); 2409 } catch (e) { 2410 console.warn('[home] One Tap init failed:', e); 2411 } 2412 } 2413 2414 async function handleCredential(resp) { 2415 if (!resp || !resp.credential) return; 2416 try { 2417 var res = await c.auth.signInWithIdToken({ 2418 provider: 'google', 2419 token: resp.credential, 2420 nonce: _oneTapNonce ? _oneTapNonce.raw : undefined, 2421 }); 2422 if (res && res.error) { 2423 console.warn('[home] supabase signInWithIdToken error:', res.error); 2424 return; 2425 } 2426 // ë¡ê·¸ì¸ ì±ê³µ â next ê° ìì¼ë©´ ê·¸ ê²½ë¡ë¡ ì´ë, ìì¼ë©´ íì ì¹©ë§ ë ¸ì¶. 2427 var s = await c.auth.getSession(); 2428 if (s && s.data && s.data.session) { 2429 if (_nextDest) { window.location.href = _nextDest; return; } 2430 _renderUserChip(s.data.session); 2431 } 2432 } catch (e) { 2433 console.warn('[home] signInWithIdToken exception:', e); 2434 } 2435 } 2436 })(); 2437 2438 // íì OAuth ì½ë°± ì²ë¦¬ â ?popupAuth=1 ë¡ ì´ë¦° ê²½ì° ì¸ì ì ì¥ í ìë ì¢ ë£. 2439 (async function() { 2440 var params = new URLSearchParams(window.location.search || ''); 2441 if (params.get('popupAuth') !== '1') return; 2442 // hash ì access_token ì´ ìëì§ íì¸. 2443 var hasToken = (window.location.hash || '').indexOf('access_token') >= 0; 2444 var ready = await waitForSupabase(8000); 2445 if (!ready) return; 2446 var c = getClient(); 2447 // supabase-js detectSessionInUrl=true ê° hash 를 íì±í´ localStorage ì ì ì¥. 2448 // ì ì¥ì´ ìë£ë ëê¹ì§ ì ì ë기 í ì°½ ë«ê¸°. 2449 var deadline = Date.now() + 8000; 2450 var wait = setInterval(async function() { 2451 if (Date.now() > deadline) { clearInterval(wait); window.close(); return; } 2452 try { 2453 var s = await c.auth.getSession(); 2454 if (s && s.data && s.data.session) { 2455 clearInterval(wait); 2456 // ë¶ëª¨ì°½ì´ storage ì´ë²¤í¸ë¡ ê°ì§ â ììì dest ì´ë. 2457 window.close(); 2458 } 2459 } catch (_) {} 2460 }, 150); 2461 })(); 2462 })(); 2463 </script>
2463 2464 2465
2465<script> 2466 // ìì ë°ëª¨ ë²í¼ â í ë²ì íëë§ ì¬ì, í ê¸ ì ê°ì ë²í¼ ë¤ì í´ë¦íë©´ ì ì§. 2467 // ì¤ëì¤ íì¼ì web/demo/ ëë í 리 (data-src 참조). íì¼ì´ ìì¼ë©´ caption ë³ê²½. 2468 (function() { 2469 var current = null; // { btn, audio } 2470 function stopCurrent() { 2471 if (!current) return; 2472 try { current.audio.pause(); } catch(_) {} 2473 current.btn.setAttribute('data-state', 'idle'); 2474 current.btn.querySelector('.play-ico').textContent = 'â¶'; 2475 current = null; 2476 } 2477 function play(btn) { 2478 var src = btn.getAttribute('data-src'); 2479 if (!src) return; 2480 // í ê¸: ê°ì ë²í¼ì´ë©´ ì ì§. 2481 if (current && current.btn === btn) { stopCurrent(); return; } 2482 stopCurrent(); 2483 var a = new Audio(src); 2484 a.preload = 'auto'; 2485 a.addEventListener('ended', stopCurrent); 2486 a.addEventListener('error', function() { 2487 stopCurrent(); 2488 var cap = document.querySelector('#home-static .voice-demo .demo-cap'); 2489 if (cap) cap.textContent = 'ìì ë°ëª¨ë ê³§ ë¤ì´ìµëë¤ â ê³§ ë§ëì.'; 2490 }); 2491 var p = a.play(); 2492 if (p && p.catch) p.catch(function() { stopCurrent(); }); 2493 btn.setAttribute('data-state', 'playing'); 2494 btn.querySelector('.play-ico').textContent = 'â '; 2495 current = { btn: btn, audio: a }; 2496 } 2497 document.addEventListener('DOMContentLoaded', function() { 2498 var btns = document.querySelectorAll('#home-static .voice-demo .demo-btn'); 2499 btns.forEach(function(b) { 2500 b.addEventListener('click', function(e) { e.preventDefault(); play(b); }); 2501 }); 2502 }); 2503 })(); 2504 </script>
2504 2505 2506 2507 <!-- 2508 Flutter 3.29+ íì¤ ë¶í¸ì¤í¸ë© â (()=>{var _={blink:!0,gecko:!1,webkit:!1,unknown:!1},K=()=>navigator.vendor==="Google Inc."||navigator.userAgent.includes("Edg/")?"blink":navigator.vendor==="Apple Computer, Inc."?"webkit":navigator.vendor===""&&navigator.userAgent.includes("Firefox")?"gecko":"unknown",C=K(),R=()=>typeof ImageDecoder>"u"?!1:C==="blink",B=()=>typeof Intl.v8BreakIterator<"u"&&typeof Intl.Segmenter<"u",z=()=>{let i=[0,97,115,109,1,0,0,0,1,5,1,95,1,120,0];return WebAssembly.validate(new Uint8Array(i))},M=()=>{let i=document.createElement("canvas");return i.width=1,i.height=1,i.getContext("webgl2")!=null?2:i.getContext("webgl")!=null?1:-1},D=()=>window.chrome&&chrome.runtime&&chrome.runtime.id,w={browserEngine:C,hasImageCodecs:R(),hasChromiumBreakIterators:B(),supportsWasmGC:z(),crossOriginIsolated:window.crossOriginIsolated,webGLVersion:M(),isChromeExtension:D()};function c(...i){return new URL(I(...i),document.baseURI).toString()}function I(...i){return i.filter(e=>!!e).map((e,n)=>n===0?S(e):F(S(e))).filter(e=>e.length).join("/")}function F(i){let e=0;for(;e<i.length&&i.charAt(e)==="/";)e++;return i.substring(e)}function S(i){let e=i.length;for(;e>0&&i.charAt(e-1)==="/";)e--;return i.substring(0,e)}function E(i,e){return i.canvasKitBaseUrl?i.canvasKitBaseUrl:e.engineRevision&&!e.useLocalCanvasKit?I("https://www.gstatic.com/flutter-canvaskit",e.engineRevision):"canvaskit"}var v=class{constructor(){this._scriptLoaded=!1}setTrustedTypesPolicy(e){this._ttPolicy=e}async loadEntrypoint(e){let{entrypointUrl:n=c("main.dart.js"),onEntrypointLoaded:t,nonce:r}=e||{};return this._loadJSEntrypoint(n,t,r)}async load(e,n,t,r,a){a??=l=>{l.initializeEngine(t).then(u=>u.runApp())};let{entrypointBaseUrl:s}=t,{entryPointBaseUrl:o}=t;if(!s&&o&&(console.warn("[deprecated] `entryPointBaseUrl` is deprecated and will be removed in a future release. Use `entrypointBaseUrl` instead."),s=o),e.compileTarget==="dart2wasm")return this._loadWasmEntrypoint(e,n,s,a);{let l=e.mainJsPath??"main.dart.js",u=c(s,l);return this._loadJSEntrypoint(u,a,r)}}didCreateEngineInitializer(e){typeof this._didCreateEngineInitializerResolve=="function"&&(this._didCreateEngineInitializerResolve(e),this._didCreateEngineInitializerResolve=null,delete _flutter.loader.didCreateEngineInitializer),typeof this._onEntrypointLoaded=="function"&&this._onEntrypointLoaded(e)}_loadJSEntrypoint(e,n,t){let r=typeof n=="function";if(!this._scriptLoaded){this._scriptLoaded=!0;let a=this._createScriptTag(e,t);if(r)console.debug("Injecting
2508<script> tag. Using callback."),this._onEntrypointLoaded=n,document.head.append(a);else return new Promise((s,o)=>{console.debug("Injecting
2508<script> tag. Using Promises. Use the callback approach instead!"),this._didCreateEngineInitializerResolve=s,a.addEventListener("error",o),document.head.append(a)})}}async _loadWasmEntrypoint(e,n,t,r){if(!this._scriptLoaded){this._scriptLoaded=!0,this._onEntrypointLoaded=r;let{mainWasmPath:a,jsSupportRuntimePath:s}=e,o=c(t,a),l=c(t,s);this._ttPolicy!=null&&(l=this._ttPolicy.createScriptURL(l));let d=(await import(l)).compileStreaming(fetch(o)),p;e.renderer==="skwasm"?p=(async()=>{let h=await n.skwasm;return window._flutter_skwasmInstance=h,{skwasm:h.wasmExports,skwasmWrapper:h,ffi:{memory:h.wasmMemory}}})():p=Promise.resolve({}),await(await(await d).instantiate(await p,{loadDynamicModule:async(h,j)=>{let A=fetch(c(t,h)),L=c(t,j);this._ttPolicy!=null&&(L=this._ttPolicy.createScriptURL(L));let x=import(L);return[await A,await x]}})).invokeMain()}}_createScriptTag(e,n){let t=document.createElement("script");t.type="application/javascript",n&&(t.nonce=n);let r=e;return this._ttPolicy!=null&&(r=this._ttPolicy.createScriptURL(e)),t.src=r,t}};
2508async function T(i,e,n){if(e<0)return i;let t,r=new Promise((a,s)=>{t=setTimeout(()=>{s(new Error(`${n} took more than ${e}ms to resolve. Moving on.`,{cause:T}))},e)});return Promise.race([i,r]).finally(()=>{clearTimeout(t)})}var g=class{setTrustedTypesPolicy(e){this._ttPolicy=e}loadServiceWorker(e){if(!e||!("serviceWorker"in navigator))return Promise.resolve();let n=()=>{console.warn(`Loading the service worker using Flutter bootstrap is deprecated and will stop working in a future release. 2509For more details, see: https://github.com/flutter/flutter/issues/156910`)},t=()=>{let{serviceWorkerVersion:r,serviceWorkerUrl:a=c(`flutter_service_worker.js?v=${r}`),timeoutMillis:s=4e3}=e,o=a;this._ttPolicy!=null&&(o=this._ttPolicy.createScriptURL(o));let l=navigator.serviceWorker.register(o).then(u=>this._getNewServiceWorker(u,r)).then(this._waitForServiceWorkerActivation);return T(l,s,"prepareServiceWorker")};return e.serviceWorkerUrl!=null?(n(),t()):navigator.serviceWorker.getRegistration().then(r=>r?t():Promise.resolve())}async _getNewServiceWorker(e,n){if(!e.active&&(e.installing||e.waiting))return console.debug("Installing/Activating first service worker."),e.installing||e.waiting;if(e.active.scriptURL.endsWith(n))return console.debug("Loading from existing service worker."),e.active;{let t=await e.update();return console.debug("Updating service worker."),t.installing||t.waiting||t.active}}async _waitForServiceWorkerActivation(e){if(!e||e.state==="activated")if(e){console.debug("Service worker already active.");return}else throw new Error("Cannot activate a null service worker!");return new Promise((n,t)=>{e.addEventListener("statechange",()=>{e.state==="activated"&&(console.debug("Activated new service worker."),n())})})}};var y=class{constructor(e,n="flutter-js"){let t=e||[/\.js$/,/\.mjs$/];window.trustedTypes&&(this.policy=trustedTypes.createPolicy(n,{createScriptURL:function(r){if(r.startsWith("blob:"))return r;let a=new URL(r,window.location),s=a.pathname.split("/").pop();if(t.some(l=>l.test(s)))return a.toString();console.error("URL rejected by TrustedTypes policy",n,":",r,"(download prevented)")}}))}};var k=i=>{let e=WebAssembly.compileStreaming(fetch(i));return(n,t)=>((async()=>{let r=await e,a=await WebAssembly.instantiate(r,n);t(a,r)})(),{})};var U=(i,e,n,t)=>(window.flutterCanvasKitLoaded=(async()=>{if(window.flutterCanvasKit)return window.flutterCanvasKit;let r=n.hasChromiumBreakIterators&&n.hasImageCodecs;if(!r&&e.canvasKitVariant=="chromium")throw"Chromium CanvasKit variant specifically requested, but unsupported in this browser";let a=r&&e.canvasKitVariant!=="full",s=t;e.canvasKitVariant=="experimentalWebParagraph"?s=c(s,"experimental_webparagraph"):a&&(s=c(s,"chromium"));let o=c(s,"canvaskit.js");i.flutterTT.policy&&(o=i.flutterTT.policy.createScriptURL(o));let l=k(c(s,"canvaskit.wasm")),u=await import(o);return window.flutterCanvasKit=await u.default({instantiateWasm:l}),window.flutterCanvasKit})(),window.flutterCanvasKitLoaded);var W=async(i,e,n,t)=>{let a=!n.hasImageCodecs||!n.hasChromiumBreakIterators?"skwasm_heavy":e.enableWimp?"wimp":"skwasm",s=c(t,`${a}.js`),o=s;i.flutterTT.policy&&(o=i.flutterTT.policy.createScriptURL(o));let l=k(c(t,`${a}.wasm`));return await(await import(o)).default({skwasmSingleThreaded:e.enableWimp||!n.crossOriginIsolated||n.isChromeExtension||e.forceSingleThreadedSkwasm,instantiateWasm:l,locateFile:(d,p)=>d.endsWith(".ww.js")?URL.createObjectURL(new Blob([` 2510"use strict"; 2511 2512let eventListener; 2513eventListener = (message) => { 2514 const pendingMessages = []; 2515 const data = message.data; 2516 data["instantiateWasm"] = (info,receiveInstance) => { 2517 const instance = new WebAssembly.Instance(data["wasm"], info); 2518 return receiveInstance(instance, data["wasm"]) 2519 }; 2520 import(data.js).then(async (skwasm) => { 2521 await skwasm.default(data); 2522 2523 removeEventListener("message", eventListener); 2524 for (const message of pendingMessages) { 2525 dispatchEvent(message); 2526 } 2527 }); 2528 removeEventListener("message", eventListener); 2529 eventListener = (message) => { 2530 2531 pendingMessages.push(message); 2532 }; 2533 2534 addEventListener("message", eventListener); 2535};
2536addEventListener("message", eventListener); 2537`],{type:"application/javascript"})):c(t,d),mainScriptUrlOrBlob:s})};var P=w.supportsWasmGC,G=P&&w.webGLVersion>0,b=class{async loadEntrypoint(e){let{serviceWorker:n,...t}=e||{},r=new y,a=new g;a.setTrustedTypesPolicy(r.policy),await a.loadServiceWorker(n).catch(o=>{console.warn("Exception while loading service worker:",o)});let s=new v;return s.setTrustedTypesPolicy(r.policy),this.didCreateEngineInitializer=s.didCreateEngineInitializer.bind(s),s.loadEntrypoint(t)}async load({serviceWorkerSettings:e,onEntrypointLoaded:n,nonce:t,config:r}={}){r??={};let a=_flutter.buildConfig;if(!a)throw"FlutterLoader.load requires _flutter.buildConfig to be set";let s=r.wasmAllowList?.[w.browserEngine]??_[w.browserEngine],o=m=>{switch(m){case"skwasm":return G&&s;default:return!0}},l=m=>m.compileTarget==="dart2wasm"&&!P||r.renderer&&r.renderer!=m.renderer?!1:o(m.renderer),u=a.builds.find(l);if(!u)throw"FlutterLoader could not find a build compatible with configuration and environment.";let d={};d.flutterTT=new y,e&&(d.serviceWorkerLoader=new g,d.serviceWorkerLoader.setTrustedTypesPolicy(d.flutterTT.policy),await d.serviceWorkerLoader.loadServiceWorker(e).
2537catch(m=>{console.warn("Exception while loading service worker:",m)}));let p=E(r,a);u.renderer==="canvaskit"?d.canvasKit=U(d,r,w,p):u.renderer==="skwasm"&&(d.skwasm=W(d,r,w,p));let f=new v;return f.setTrustedTypesPolicy(d.flutterTT.policy),this.didCreateEngineInitializer=f.didCreateEngineInitializer.bind(f),f.load(u,d,r,t,n)}};window._flutter||(window._flutter={});window._flutter.loader||(window._flutter.loader=new b);})(); 2538//# sourceMappingURL=flutter.js.map 2539 / if (!window._flutter) { 2540 window._flutter = {}; 2541} 2542_flutter.buildConfig = {"engineRevision":"425cfb54d01a9472b3e81d9e76fd63a4a44cfbcb","builds":[{"compileTarget":"dart2js","renderer":"canvaskit","mainJsPath":"main.dart.js"},{}]}; 2543 ë 2544 ë¹ë ì SDK ê° inline 주ì íë¤ ( _flutter.buildConfig í¬í¨ ). 2545 커ì¤í í¬ì¸í¸: 2546 - canvasKitBaseUrl="canvaskit/" â gstatic CDN (6.8MB cross-origin) ë¤ì´ë¡ë 2547 íí¼, 모ë°ì¼ ì¬í리 첫 ì¤í ì§ì° ë°©ì§. 2548 - serviceWorkerSettings ìëµ â flutter_service_worker.js ë±ë¡ ì¤íµ 2549 (PWA 미ì¬ì© ì ì± ì ë°ë¼ SW ìì²´ ì¬ì© ì í¨). 2550 --> 2551
2551<script> 2552 (()=>{var _={blink:!0,gecko:!1,webkit:!1,unknown:!1},K=()=>navigator.vendor==="Google Inc."||navigator.userAgent.includes("Edg/")?"blink":navigator.vendor==="Apple Computer, Inc."?"webkit":navigator.vendor===""&&navigator.userAgent.includes("Firefox")?"gecko":"unknown",C=K(),R=()=>typeof ImageDecoder>"u"?!1:C==="blink",B=()=>typeof Intl.v8BreakIterator<"u"&&typeof Intl.Segmenter<"u",z=()=>{let i=[0,97,115,109,1,0,0,0,1,5,1,95,1,120,0];return WebAssembly.validate(new Uint8Array(i))},M=()=>{let i=document.createElement("canvas");return i.width=1,i.height=1,i.getContext("webgl2")!=null?2:i.getContext("webgl")!=null?1:-1},D=()=>window.chrome&&chrome.runtime&&chrome.runtime.id,w={browserEngine:C,hasImageCodecs:R(),hasChromiumBreakIterators:B(),supportsWasmGC:z(),crossOriginIsolated:window.crossOriginIsolated,webGLVersion:M(),isChromeExtension:D()};function c(...i){return new URL(I(...i),document.baseURI).toString()}function I(...i){return i.filter(e=>!!e).map((e,n)=>n===0?S(e):F(S(e))).filter(e=>e.length).join("/")}function F(i){let e=0;for(;e<i.length&&i.charAt(e)==="/";)e++;return i.substring(e)}function S(i){let e=i.length;for(;e>0&&i.charAt(e-1)==="/";)e--;return i.substring(0,e)}function E(i,e){return i.canvasKitBaseUrl?i.canvasKitBaseUrl:e.engineRevision&&!e.useLocalCanvasKit?I("https://www.gstatic.com/flutter-canvaskit",e.engineRevision):"canvaskit"}var v=class{constructor(){this._scriptLoaded=!1}setTrustedTypesPolicy(e){this._ttPolicy=e}async loadEntrypoint(e){let{entrypointUrl:n=c("main.dart.js"),onEntrypointLoaded:t,nonce:r}=e||{};return this._loadJSEntrypoint(n,t,r)}async load(e,n,t,r,a){a??=l=>{l.initializeEngine(t).then(u=>u.runApp())};let{entrypointBaseUrl:s}=t,{entryPointBaseUrl:o}=t;if(!s&&o&&(console.warn("[deprecated] `entryPointBaseUrl` is deprecated and will be removed in a future release. Use `entrypointBaseUrl` instead."),s=o),e.compileTarget==="dart2wasm")return this._loadWasmEntrypoint(e,n,s,a);{let l=e.mainJsPath??"main.dart.js",u=c(s,l);return this._loadJSEntrypoint(u,a,r)}}didCreateEngineInitializer(e){typeof this._didCreateEngineInitializerResolve=="function"&&(this._didCreateEngineInitializerResolve(e),this._didCreateEngineInitializerResolve=null,delete _flutter.loader.didCreateEngineInitializer),typeof this._onEntrypointLoaded=="function"&&this._onEntrypointLoaded(e)}_loadJSEntrypoint(e,n,t){let r=typeof n=="function";if(!this._scriptLoaded){this._scriptLoaded=!0;let a=this._createScriptTag(e,t);if(r)console.debug("Injecting
2552<script> tag. Using callback."),this._onEntrypointLoaded=n,document.head.append(a);else return new Promise((s,o)=>{console.debug("Injecting
2552<script> tag. Using Promises. Use the callback approach instead!"),this._didCreateEngineInitializerResolve=s,a.addEventListener("error",o),document.head.append(a)})}}async _loadWasmEntrypoint(e,n,t,r){if(!this._scriptLoaded){this._scriptLoaded=!0,this._onEntrypointLoaded=r;let{mainWasmPath:a,jsSupportRuntimePath:s}=e,o=c(t,a),l=c(t,s);this._ttPolicy!=null&&(l=this._ttPolicy.createScriptURL(l));let d=(await import(l)).compileStreaming(fetch(o)),p;e.renderer==="skwasm"?p=(async()=>{let h=await n.skwasm;return window._flutter_skwasmInstance=h,{skwasm:h.wasmExports,skwasmWrapper:h,ffi:{memory:h.wasmMemory}}})():p=Promise.resolve({}),await(await(await d).instantiate(await p,{loadDynamicModule:async(h,j)=>{let A=fetch(c(t,h)),L=c(t,j);this._ttPolicy!=null&&(L=this._ttPolicy.createScriptURL(L));let x=import(L);return[await A,await x]}})).invokeMain()}}_createScriptTag(e,n){let t=document.createElement("script");t.type="application/javascript",n&&(t.nonce=n);let r=e;return this._ttPolicy!=null&&(r=this._ttPolicy.createScriptURL(e)),t.src=r,t}};
2552async function T(i,e,n){if(e<0)return i;let t,r=new Promise((a,s)=>{t=setTimeout(()=>{s(new Error(`${n} took more than ${e}ms to resolve. Moving on.`,{cause:T}))},e)});return Promise.race([i,r]).finally(()=>{clearTimeout(t)})}var g=class{setTrustedTypesPolicy(e){this._ttPolicy=e}loadServiceWorker(e){if(!e||!("serviceWorker"in navigator))return Promise.resolve();let n=()=>{console.warn(`Loading the service worker using Flutter bootstrap is deprecated and will stop working in a future release. 2553For more details, see: https://github.com/flutter/flutter/issues/156910`)},t=()=>{let{serviceWorkerVersion:r,serviceWorkerUrl:a=c(`flutter_service_worker.js?v=${r}`),timeoutMillis:s=4e3}=e,o=a;this._ttPolicy!=null&&(o=this._ttPolicy.createScriptURL(o));let l=navigator.serviceWorker.register(o).then(u=>this._getNewServiceWorker(u,r)).then(this._waitForServiceWorkerActivation);return T(l,s,"prepareServiceWorker")};return e.serviceWorkerUrl!=null?(n(),t()):navigator.serviceWorker.getRegistration().then(r=>r?t():Promise.resolve())}async _getNewServiceWorker(e,n){if(!e.active&&(e.installing||e.waiting))return console.debug("Installing/Activating first service worker."),e.installing||e.waiting;if(e.active.scriptURL.endsWith(n))return console.debug("Loading from existing service worker."),e.active;{let t=await e.update();return console.debug("Updating service worker."),t.installing||t.waiting||t.active}}async _waitForServiceWorkerActivation(e){if(!e||e.state==="activated")if(e){console.debug("Service worker already active.");return}else throw new Error("Cannot activate a null service worker!");return new Promise((n,t)=>{e.addEventListener("statechange",()=>{e.state==="activated"&&(console.debug("Activated new service worker."),n())})})}};var y=class{constructor(e,n="flutter-js"){let t=e||[/\.js$/,/\.mjs$/];window.trustedTypes&&(this.policy=trustedTypes.createPolicy(n,{createScriptURL:function(r){if(r.startsWith("blob:"))return r;let a=new URL(r,window.location),s=a.pathname.split("/").pop();if(t.some(l=>l.test(s)))return a.toString();console.error("URL rejected by TrustedTypes policy",n,":",r,"(download prevented)")}}))}};var k=i=>{let e=WebAssembly.compileStreaming(fetch(i));return(n,t)=>((async()=>{let r=await e,a=await WebAssembly.instantiate(r,n);t(a,r)})(),{})};var U=(i,e,n,t)=>(window.flutterCanvasKitLoaded=(async()=>{if(window.flutterCanvasKit)return window.flutterCanvasKit;let r=n.hasChromiumBreakIterators&&n.hasImageCodecs;if(!r&&e.canvasKitVariant=="chromium")throw"Chromium CanvasKit variant specifically requested, but unsupported in this browser";let a=r&&e.canvasKitVariant!=="full",s=t;e.canvasKitVariant=="experimentalWebParagraph"?s=c(s,"experimental_webparagraph"):a&&(s=c(s,"chromium"));let o=c(s,"canvaskit.js");i.flutterTT.policy&&(o=i.flutterTT.policy.createScriptURL(o));let l=k(c(s,"canvaskit.wasm")),u=await import(o);return window.flutterCanvasKit=await u.default({instantiateWasm:l}),window.flutterCanvasKit})(),window.flutterCanvasKitLoaded);var W=async(i,e,n,t)=>{let a=!n.hasImageCodecs||!n.hasChromiumBreakIterators?"skwasm_heavy":e.enableWimp?"wimp":"skwasm",s=c(t,`${a}.js`),o=s;i.flutterTT.policy&&(o=i.flutterTT.policy.createScriptURL(o));let l=k(c(t,`${a}.wasm`));return await(await import(o)).default({skwasmSingleThreaded:e.enableWimp||!n.crossOriginIsolated||n.isChromeExtension||e.forceSingleThreadedSkwasm,instantiateWasm:l,locateFile:(d,p)=>d.endsWith(".ww.js")?URL.createObjectURL(new Blob([` 2554"use strict"; 2555 2556let eventListener; 2557eventListener = (message) => { 2558 const pendingMessages = []; 2559 const data = message.data; 2560 data["instantiateWasm"] = (info,receiveInstance) => { 2561 const instance = new WebAssembly.Instance(data["wasm"], info); 2562 return receiveInstance(instance, data["wasm"]) 2563 }; 2564 import(data.js).then(async (skwasm) => { 2565 await skwasm.default(data); 2566 2567 removeEventListener("message", eventListener); 2568 for (const message of pendingMessages) { 2569 dispatchEvent(message); 2570 } 2571 }); 2572 removeEventListener("message", eventListener); 2573 eventListener = (message) => { 2574 2575 pendingMessages.push(message); 2576 }; 2577 2578 addEventListener("message", eventListener); 2579};
2580addEventListener("message", eventListener); 2581`],{type:"application/javascript"})):c(t,d),mainScriptUrlOrBlob:s})};var P=w.supportsWasmGC,G=P&&w.webGLVersion>0,b=class{async loadEntrypoint(e){let{serviceWorker:n,...t}=e||{},r=new y,a=new g;a.setTrustedTypesPolicy(r.policy),await a.loadServiceWorker(n).catch(o=>{console.warn("Exception while loading service worker:",o)});let s=new v;return s.setTrustedTypesPolicy(r.policy),this.didCreateEngineInitializer=s.didCreateEngineInitializer.bind(s),s.loadEntrypoint(t)}async load({serviceWorkerSettings:e,onEntrypointLoaded:n,nonce:t,config:r}={}){r??={};let a=_flutter.buildConfig;if(!a)throw"FlutterLoader.load requires _flutter.buildConfig to be set";let s=r.wasmAllowList?.[w.browserEngine]??_[w.browserEngine],o=m=>{switch(m){case"skwasm":return G&&s;default:return!0}},l=m=>m.compileTarget==="dart2wasm"&&!P||r.renderer&&r.renderer!=m.renderer?!1:o(m.renderer),u=a.builds.find(l);if(!u)throw"FlutterLoader could not find a build compatible with configuration and environment.";let d={};d.flutterTT=new y,e&&(d.serviceWorkerLoader=new g,d.serviceWorkerLoader.setTrustedTypesPolicy(d.flutterTT.policy),await d.serviceWorkerLoader.loadServiceWorker(e).
2581catch(m=>{console.warn("Exception while loading service worker:",m)}));let p=E(r,a);u.renderer==="canvaskit"?d.canvasKit=U(d,r,w,p):u.renderer==="skwasm"&&(d.skwasm=W(d,r,w,p));let f=new v;return f.setTrustedTypesPolicy(d.flutterTT.policy),this.didCreateEngineInitializer=f.didCreateEngineInitializer.bind(f),f.load(u,d,r,t,n)}};window._flutter||(window._flutter={});window._flutter.loader||(window._flutter.loader=new b);})(); 2582//# sourceMappingURL=flutter.js.map 2583 2584 if (!window._flutter) { 2585 window._flutter = {}; 2586} 2587_flutter.buildConfig = {"engineRevision":"425cfb54d01a9472b3e81d9e76fd63a4a44cfbcb","builds":[{"compileTarget":"dart2js","renderer":"canvaskit","mainJsPath":"main.dart.js"},{}]}; 2588 2589 2590 // ì ì í('/')ììë Flutter ìë ë¡ë ì¤íµ â ì¬ì©ìê° ì¹´ë í´ë¦ ì 2591 // window.location ì¼ë¡ ì´ë, ê·¸ë Flutter ê° ë¡ëëê³ ì¸ì¦/ëª¨ë¨¼í¸ ë¼ì°í ì²ë¦¬. 2592 // ë¤ë¥¸ ê²½ë¡(/login, /moment/:id, /ad, /settings ...)ë ì¦ì Flutter ë¡ë. 2593 (function() { 2594 var p = window.location.pathname || '/'; 2595 var isStaticHome = (p === '/' || p === ''); 2596 if (isStaticHome) return; // ì ì í ë ¸ì¶ë§, Flutter 미ë¡ë. 2597 // ìí¸ë¦¬í¬ì¸í¸(main.dart.js)를 ?v=<sha> ë¡ ë²ì â iOS Safari stale ë²ë¤ ë°©ì§ (Fix 1-A). 2598 // buildConfig ë ì flutter build_config í íë¦¿ì´ ì´ë¯¸ _flutter.buildConfig ì ì¸í í¨(load ì ). 2599 // â ì´ ì£¼ìì ì´ì¤ì¤ê´í¸ flutter í í릿 í í°ì ì°ì§ ë§ ê² â flutter build ê° ì¹íí´ ì¤í¬ë¦½í¸ê° 깨ì§(2026-06-20 blank íê·). 2600 // â ï¸ deferred parts ë dart2js encodeURIComponent ë¡ ë¡ë â ì¬ê¸°ì ë²ì X (no-cache+hash ìì ). 2601 try { 2602 var _bc = window._flutter && _flutter.buildConfig; 2603 if (_bc && _bc.builds && window.__vtVer) { 2604 _bc.builds.forEach(function (b) { 2605 if (b && b.mainJsPath && b.mainJsPath.indexOf('?') < 0) { 2606 b.mainJsPath = window.__vtVer(b.mainJsPath); 2607 } 2608 }); 2609 } 2610 } catch (_) {} 2611 _flutter.loader.load({ 2612 config: { canvasKitBaseUrl: "canvaskit/" } 2613 }); 2614 })(); 2615 </script>
2615 2616 2617
2617<script> 2618 // âââââââââââââââââââââââââââââââââââââââââââââââââââââââââ 2619 // ì°ì»´ ì¤ë²ë ì´ dismiss + Flutter gesture warmup. 2620 // 모ë°ì¼ ì¬í리ìì Flutter 첫 íì´ ìì¤ëë 문ì ë°©ì§ì© 2621 // multi-position synthetic pointer ì¬ìë í¨í´. 2622 // âââââââââââââââââââââââââââââââââââââââââââââââââââââââââ 2623 2624 function _dismissLoading() { 2625 var hero = document.getElementById('home-static'); 2626 if (!hero || hero._hiding) return; 2627 hero._hiding = true; 2628 hero.classList.add('fading'); 2629 setTimeout(function() { hero.remove(); }, 250); 2630 } 2631 2632 function _primeFlutterPipeline() { 2633 // Flutter view ì ì¬ë¬ ì¢íì synthetic pointer+touch 를 ì°ì ë°ì¬. 2634 // HTML CTA í ì§í í¸ì¶ëë¯ë¡ ì¬ì©ì ì ì¤ì² 컨í ì¤í¸ ì ì§ â isTrusted 2635 // ê´ë ¨ ì ì½ì´ ìëë¼ë ì¬ì©ì ìëì ìí ì¤íì´ë¼ ìµëí í¨ê³¼ì . 2636 var view = document.querySelector('flutter-view') || document.body; 2637 var W = window.innerWidth, H = window.innerHeight; 2638 // íë©´ ì¬ë¶ë©´ + ì¤ì â hit-test ìºì ê´ë²ì íë¼ì (모ì리 ì¢íë interactive widget ë묾) 2639 var points = [ 2640 [4, 4], [W - 4, 4], 2641 [Math.round(W / 2), Math.round(H / 2)], 2642 [4, H - 4], [W - 4, H - 4], 2643 ]; 2644 2645 points.forEach(function(p, i) { 2646 setTimeout(function() { 2647 var pid = 9000 + i; 2648 var baseInit = { 2649 bubbles: true, cancelable: true, composed: true, 2650 clientX: p[0], clientY: p[1], 2651 pointerType: 'touch', isPrimary: true, pointerId: pid 2652 }; 2653 try { 2654 view.dispatchEvent(new PointerEvent('pointerdown', 2655 Object.assign({ pressure: 0.5 }, baseInit))); 2656 // pointercancel ë¡ tap ìì± ìì´ arena ë§ íë¼ì â ì¤ìë¡ widget onTap ì ë° ì í¨ 2657 view.dispatchEvent(new PointerEvent('pointercancel', 2658 Object.assign({ pressure: 0 }, baseInit))); 2659 } catch (e) { /* 무ì */ } 2660 2661 // iOS Safari ì ì© TouchEvent ë í¨ê» (Touch ìì±ì iOS 13+ ì§ì) 2662 try { 2663 if (typeof Touch !== 'undefined' && typeof TouchEvent !== 'undefined') { 2664 var touch = new Touch({ 2665 identifier: pid, target: view, 2666 clientX: p[0], clientY: p[1], 2667 screenX: p[0], screenY: p[1], 2668 pageX: p[0], pageY: p[1], 2669 radiusX: 1, radiusY: 1, force: 0.5 2670 }); 2671 view.dispatchEvent(new TouchEvent('touchstart', { 2672 bubbles: true, cancelable: true, composed: true, 2673 touches: [touch], targetTouches: [touch], changedTouches: [touch] 2674 })); 2675 view.dispatchEvent(new TouchEvent('touchcancel', { 2676 bubbles: true, cancelable: true, composed: true, 2677 touches: [], targetTouches: [], changedTouches: [touch] 2678 })); 2679 } 2680 } catch (e) { /* 무ì */ } 2681 }, i * 25); 2682 }); 2683 } 2684 2685 // 'vm-ready' ì´ë²¤í¸ â Dart 측 첫 íë©´ ë¹ë ìë£ í dispatch. ì´ê² ê°ì¥ ì íí ìì . 2686 window.addEventListener('vm-ready', function() { 2687 try { sessionStorage.setItem('vmFlutterLoaded', '1'); } catch (_) {} 2688 _dismissLoading(); 2689 setTimeout(_primeFlutterPipeline, 80); 2690 }); 2691 // ìì ì¥ì¹: vm-ready 못 ë°ì¼ë©´ flutter-first-frame + 4s í dismiss. 2692 window.addEventListener('flutter-first-frame', function() { 2693 setTimeout(function() { 2694 _dismissLoading(); 2695 setTimeout(_primeFlutterPipeline, 80); 2696 }, 4000); 2697 }); 2698 2699 // ìì ì¥ì¹: ì ì íì´ ìë ê²½ë¡ìì 20ì´ ë´ first-frame 미ìì ì ê°ì dismiss. 2700 (function() { 2701 var p = window.location.pathname || '/'; 2702 if (p === '/' || p === '') return; // ì ì íì ê·¸ëë¡ ì ì§. 2703 setTimeout(function() { 2704 var hero = document.getElementById('home-static'); 2705 if (hero && !hero._hiding) {
2706 _dismissLoading(); 2707 setTimeout(_primeFlutterPipeline, 80); 2708 } 2709 }, 20000); 2710 })(); 2711 </script>
2711 2712</body> 2713</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.