PageSourceSearch

https://hop.exchange/

html hop.exchange collected 2026-10-03 22:04:34 UTC 865,242 bytes, 25,135 lines download raw bytes

1
2
3
4
5<!DOCTYPE html>
6<html lang="id">
7<head>
8  <meta charset="UTF-8">
9  <meta name="google-site-verification" content="2PgBsSFy3dhCu9weu_WV3xa7iIa5ofFabtNF-duIhZQ" />
10  <meta name="google-site-verification" content="HHAPcPgeS6UggumY_qwn9JzvM_KShp-wCeHh9KK25so" />
11  <meta name="google-site-verification" content="TiNmFhdOPBxmaC1G7ECewVti7C4-dQaUqhvOJuDIPak" />
12  <title>JUDIMPO Situs Judi Mpo Slot 10k dengan Peluang Maxwin Terbaik</title>
13  <meta name="description" content="JUDIMPO merupakan platform judi mpo slot online yang menghadirkan berbagai permainan Slot 10k hari ini. Dengan sistem cepat dan pilihan game lengkap, pemain memiliki peluang meraih maxwin besar di situs terpercaya ini.">
14  <meta name="robots" content="index,follow">
15  <link rel="canonical" href="https://hop.exchange/">
16  <link rel="amphtml" href="https://mpo5000xjudimpo.blackhostapp.com/">
17  <link rel="alternate" href="https://mpo5000xjudimpo.blackhostapp.com/" hreflang="id">
18  <link rel="alternate" href="https://mpo5000xjudimpo.blackhostapp.com/" hreflang="en">
19  <link rel="alternate" href="https://mpo5000xjudimpo.blackhostapp.com/" hreflang="x-default">
20  <link rel="alternate" hreflang="id-ID" href="https://mpo5000xjudimpo.blackhostapp.com/" />
21  <link rel="alternate" hreflang="en-US" href="https://mpo5000xjudimpo.blackhostapp.com/" />
22  <link rel="alternate" hreflang="en-SG" href="https://mpo5000xjudimpo.blackhostapp.com/" />
23    <link rel="preconnect" href="https://www.googletagmanager.com" crossorigin>
vendor: 67 bytes, lines 23-24
23
24  <script async src="https://www.googletagmanager.com/gtag/js?id=
24G-0LSM1YJSPZ
vendor: 48 bytes, lines 24-25
24" nonce="se3iyzEHMc9FQEB4wSyd0w=="></script>
25  
25<script nonce="se3iyzEHMc9FQEB4wSyd0w==">window.dataLayer=window.dataLayer||[];function gtag(){dataLayer.push(arguments)}gtag("consent","default",{ad_storage:"denied",ad_user_data:"denied",ad_personalization:"denied",analytics_storage:"granted",wait_for_update:500});gtag("js",new Date);gtag("config","G-0LSM1YJSPZ",{send_page_view:!0,linker:{domains:["plazait.co.id","www.plazait.co.id"]}});window.ga4Ecomm={viewItem:function(e){if(!window.gtag)return;try{gtag("event","view_item",{currency:e.currency||"IDR",value:e.value||0,items:[{item_id:e.item_id||"",item_name:e.item_name||"",item_brand:e.item_brand||"",item_category:e.item_category||"",price:e.price||0,quantity:1}]})}catch(t){}},addToCart:function(e){if(!window.gtag)return;try{gtag("event","add_to_cart",{currency:e.currency||"IDR",value:(e.price||0)*(e.quantity||1),items:[{item_id:e.item_id||"",item_name:e.item_name||"",item_brand:e.item_brand||"",item_category:e.item_category||"",price:e.price||0,quantity:e.quantity||1}]})}catch(t){}}};</script>
25
26  <meta property="og:locale" content="id_ID">
27  <meta property="og:site_name" content="judimpoofficial">
28  <meta property="og:type" content="product">
29  <meta property="og:title" content="JUDIMPO Situs Judi Mpo Slot 10k dengan Peluang Maxwin Terbaik">
30  <meta property="og:description" content="JUDIMPO merupakan platform judi mpo slot online yang menghadirkan berbagai permainan Slot 10k hari ini. Dengan sistem cepat dan pilihan game lengkap, pemain memiliki peluang meraih maxwin besar di situs terpercaya ini.">
31  <meta property="og:url" content="https://hop.exchange/">
32  <meta property="og:image" content="https://img.tongat.cc/uploads/pasti-jaackpot-judimpo.jpg">
33  <meta property="og:image:alt" content="JUDIMPO Situs Judi Mpo Slot 10k dengan Peluang Maxwin Terbaik">
34<meta property="product:price:amount" content="5000">
35<meta property="product:price:currency" content="IDR">
36<meta property="product:availability" content="out of stock">
37<meta name="twitter:card" content="summary_large_image">
38<meta name="twitter:title" content="JUDIMPO Situs Judi Mpo Slot 10k dengan Peluang Maxwin Terbaik">
39<meta name="twitter:description" content="JUDIMPO merupakan platform judi mpo slot online yang menghadirkan berbagai permainan Slot 10k hari ini. Dengan sistem cepat dan pilihan game lengkap, pemain memiliki peluang meraih maxwin besar di situs terpercaya ini.">
40<meta name="twitter:image" content="https://img.tongat.cc/uploads/pasti-jaackpot-judimpo.jpg">
41
42<script type="application/ld+json">
43      {
44        "@context": "http:\/\/schema.org",
45        "@type": "BreadcrumbList",
46        "itemListElement": [
47          {
48            "@type": "ListItem",
49            "item": {
50              "@id": "https://hop.exchange/",
51              "name": "JUDIMPO Situs Judi Mpo Slot 10k dengan Peluang Maxwin Terbaik"
52            },
53            "position": 1
54          }
55        ]
56      }
57    </script>
57
58    
58<script type="application/ld+json">
59      {
60        "@context": "http:\/\/schema.org",
61        "@type": "Product",
62        "name": "JUDIMPO Situs Judi Mpo Slot 10k dengan Peluang Maxwin Terbaik",
63        "description": "JUDIMPO merupakan platform judi mpo slot online yang menghadirkan berbagai permainan Slot 10k hari ini. Dengan sistem cepat dan pilihan game lengkap, pemain memiliki peluang meraih maxwin besar di situs terpercaya ini.",
64        "image": "https://img.tongat.cc/uploads/pasti-jaackpot-judimpo.jpg",
65        "offers": {
66          "@type": "http:\/\/schema.org\/Offer",
67          "price": 9999,
68          "url": "https://hop.exchange/",
69          "priceCurrency": "IDR",
70          "availability": "http:\/\/schema.org\/InStock"
71        }
72      }
73    </script>
73
74    
74<script type="application/ld+json">
75      {
76        "@context": "http:\/\/schema.org\/",
77        "@type": "WebPage",
78        "speakable": {
79          "@type": "SpeakableSpecification",
80          "cssSelector": [".description"],
81          "xpath": ["\/html\/head\/title"]
82        }
83      }
84    </script>
84
85    <!-- ZS -->
86    <!-- Schema JSON untuk SBO -->
87<script type="application/ld+json">
88{
89"@context": "https://schema.org/",
90"@type": "Product",
91"name": "JUDIMPO Situs Judi Mpo Slot 10k dengan Peluang Maxwin Terbaik",
92"url": "https://hop.exchange/",
93"sku": "Slot1000",
94"image": [
95  "https://img.tongat.cc/uploads/pasti-jaackpot-judimpo.jpg"
96],
97"description": "JUDIMPO merupakan platform judi mpo slot online yang menghadirkan berbagai permainan Slot 10k hari ini. Dengan sistem cepat dan pilihan game lengkap, pemain memiliki peluang meraih maxwin besar di situs terpercaya ini.",
98"brand": {
99  "@type": "Organization",
100  "name": "Slot1000"
101},
102"offers": {
103  "@type": "Offer",
104  "name": "JUDIMPO Situs Judi Mpo Slot 10k dengan Peluang Maxwin Terbaik",
105  "sku": "Slot1000",
106  "price": "9999",
107  "priceCurrency": "IDR",
108  "availability": "https://schema.org/InStock"
109}
110}
111</script>
111
112
113<script type="application/ld+json">
114{
115"@context": "https://schema.org/",
116"@type": "Product",
117"name": "JUDIMPO Situs Judi Mpo Slot 10k dengan Peluang Maxwin Terbaik",
118"image": "https://img.tongat.cc/uploads/pasti-jaackpot-judimpo.jpg",
119"description": "JUDIMPO merupakan platform judi mpo slot online yang menghadirkan berbagai permainan Slot 10k hari ini. Dengan sistem cepat dan pilihan game lengkap, pemain memiliki peluang meraih maxwin besar di situs terpercaya ini.",
120"sku": "Slot1000",
121"offers": {
122  "@type": "Offer",
123  "priceCurrency": "IDR",
124  "url": "https://hop.exchange/",
125  "availability": "https://schema.org/InStock",
126  "price": "9999.00"
127}
128}
129</script>
129
130
131<script type="application/ld+json" id="bv-jsonld-bvloader-summary">
132{
133"@context": "https://schema.org/",
134"@id": "https://hop.exchange/",
135"aggregateRating": {
136  "@type": "AggregateRating",
137  "itemReviewed": {
138    "@type": "IndividualProduct",
139    "name": "Slot1000"
140  },
141  "ratingValue": "5.0",
142  "reviewCount": 954638,
143  "bestRating": 5
144}
145}
146</script>
146
147
148<script type="application/ld+json">
149{
150"@context": "https://schema.org",
151"@type": "BreadcrumbList",
152"itemListElement": [
153  {
154    "@type": "ListItem",
155    "position": 1,
156    "item": {
157      "@id": "https://hop.exchange/",
158      "name": "Slot1000"
159    }
160  },
161  {
162    "@type": "ListItem",
163    "position": 2,
164    "item": {
165      "@id": "https://hop.exchange/",
166      "name": "JUDIMPO Situs Judi Mpo Slot 10k dengan Peluang Maxwin Terbaik"
167    }
168  },
169  {
170    "@type": "ListItem",
171    "position": 3,
172    "item": {
173      "@id": "https://hop.exchange/",
174      "name": "Slot1000"
175    }
176  },
177  {
178    "@type": "ListItem",
179    "position": 4,
180    "item": {
181      "@id": "https://hop.exchange/",
182      "name": "JUDIMPO Situs Judi Mpo Slot 10k dengan Peluang Maxwin Terbaik"
183    }
184  }
185]
186}
187</script>
187
188
189<script type="application/ld+json" id="bv-jsonld-reviews-data">
190{
191  "@context": "https://schema.org",
192  "@type": "Organization",
193  "@id": "https://hop.exchange/",
194  "name": "Slot1000",
195  "alternateName": "Slot1000",
196  "url": "https://hop.exchange/",
197  "review": [
198    {
199      "@type": "Review",
200      "dateCreated": "2026-03-31T12:28:35+00:00",
201      "datePublished": "2026-03-31T12:28:35+00:00",
202      "headline": "Slot1000",
203      "reviewBody": "Tampilan halaman Mpo 5000 cukup sederhana dan mudah dipahami. Informasi mengenai portal digital disusun dengan rapi sehingga saya tidak kesulitan mencari menu yang dibutuhkan.",
204      "reviewRating": {
205        "@type": "Rating",
206        "ratingValue": 5,
207        "bestRating": 5,
208        "worstRating": 1
209      },
210      "author": {
211        "@type": "Person",
212        "name": "game digital – Surabaya"
213      }
214    },
215    {
216      "@type": "Review",
217      "dateCreated": "2026-04--02T18:28:21+00:00",
218      "datePublished": "2026-04-03T18:28:21+00:00",
219      "headline": "GAME MPO ONLINE",
220      "reviewBody": "Saya menyukai tampilan yang responsif karena halaman dapat menyesuaikan layar ponsel. Navigasinya juga tidak terlalu rumit sehingga nyaman digunakan untuk membaca informasi.",
221      "reviewRating": {
222        "@type": "Rating",
223        "ratingValue": 5,
224        "bestRating": 5,
225        "worstRating": 1
226      },
227      "author": {
228        "@type": "Person",
229        "name": "kendaraan yang bisa di-custom total – Semarang"
230      }
231    },
232    {
233      "@type": "Review",
234      "dateCreated": "2026-04-05T19:28:18+00:00",
235      "datePublished": "2026-04-05T19:28:18+00:00",
236      "headline": "GAME MPO ONLINE",
237      "reviewBody": "Informasi mengenai permainan berbasis peluang disampaikan dengan cukup jelas. Saya juga terbantu dengan penjelasan mengenai keamanan akun dan pentingnya menjaga data pribadi.",
238      "reviewRating": {
239        "@type": "Rating",
240        "ratingValue": 5,
241        "bestRating": 5,
242        "worstRating": 1
243      },
244      "author": {
245        "@type": "Person",
246        "name": "di-custom total – Makassar"
247      }
248    }
249  ]
250}
251</script>
vendor: 2 bytes, line 251
251
252<script type="application/ld+json">
253{
254  "@context": "https://schema.org",
255  "@type": "FAQPage",
256  "mainEntity": [
257    {
258  "@type": "Question",
259  "name": "What is JUDIMPO Situs Judi Mpo Slot 10k dengan Peluang Maxwin Terbaik?",
260  "acceptedAnswer": {
261    "@type": "Answer",
262    "text": "JUDIMPO Situs Judi Mpo Slot 10k dengan Peluang Maxwin Terbaik refers to a digital portal providing information about MPO games, available features, and various online entertainment options."
263  }
264},
265{
266  "@type": "Question",
267  "name": "What information can users find on JUDIMPO?",
268  "acceptedAnswer": {
269    "@type": "Answer",
270    "text": "Users can find information about available MPO games, platform features, updates, and different categories of digital entertainment."
271  }
272},
273{
274  "@type": "Question",
275  "name": "Does gacor guarantee winning results?",
276  "acceptedAnswer": {
277    "@type": "Answer",
278    "text": "No. The term gacor is commonly used by gaming communities to describe games perceived as frequently producing favorable results, but it does not guarantee winnings or specific outcomes."
279  }
280},
281{
282  "@type": "Question",
283  "name": "What does Pilihan Game Hoki mean?",
284  "acceptedAnswer": {
285    "@type": "Answer",
286    "text": "Pilihan Game Hoki is a popular term referring to game selections that players consider potentially favorable. However, game outcomes remain uncertain and should not be regarded as guaranteed."
287  }
288},
289{
290  "@type": "Question",
291  "name": "Can JUDIMPO be accessed through mobile devices?",
292  "acceptedAnswer": {
293    "@type": "Answer",
294    "text": "A responsive digital platform can generally be accessed through compatible smartphones, tablets, or computers, depending on the services and technical requirements provided by the platform."
295  }
296}
297  ]
298}
299</script>
299
300  <!-- User Session Data -->
301    <meta name="csrf-token" content="9ce6e4a17f7cc189893df9e47789b13e98829450d516a0cae5ca7b5f43e5dadc">
302  <meta name="user-logged-in" content="false">
303  <meta name="user-id" content="0">
304  
305  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" />
306
307  <link rel="shortcut icon" href="https://img.tongat.cc/uploads/logo-ri.png" type="image/x-icon">
308  <style data-inlined="style.css">
309@font-face {
310    font-family: 'Segoe UI';
311    src: url('/assets/fonts/segoeui.woff2') format('woff2'),
312         url('/assets/fonts/segoeui.woff') format('woff');
313    font-weight: 400;
314    font-style: normal;
315}
316
317:root {
318  --brand-50:#D80B6A;
319  --brand-100:#764EAC;
320  --brand-500:#C77DFF;
321  --brand-600:#C77DFF;
322  --gray-900:#D80B6A;
323  --gray-700:#764EAC;
324  --gray-500:#6F737B;
325  --gray-300:#C5C9CF;
326  --gray-100:#764EAC;
327  --border:#E4E7EB;
328  --radius:8px;
329  --transition: .18s ease;
330  /* font-family: "Inter", system-ui, sans-serif; */
331  font-family: 'Segoe UI', sans-serif;
332}
333
334* { box-sizing: border-box; }
335body { 
336  margin:0; 
337  padding-bottom: 0; /* Reset for desktop */
338  color:var(--gray-900); 
339  background:#fff; 
340}
341img { max-width:100%; display:block; }
342
343.container {
344  width:100%;
345  max-width:1280px;
346  margin:0 auto;
347  padding:10px 0;
348}
349
350.topbar {
351  background:#111;
352  color:#fff;
353  font-size:13px;
354}
355.topbar-inner {
356  display:flex;
357  justify-content:space-between;
358  align-items:center;
359  min-height:36px;
360}
361.topbar a { color:#fff; text-decoration:none; margin-left:12px; }
362
363/* ========== Desktop base (Glassmorphism Modern with Warm Gradient) ========== */
364.navbar {
365  background:linear-gradient(135deg, rgba(255,255,255,0.95) 0%, rgba(255,245,230,0.85) 100%);
366  backdrop-filter:blur(12px);
367  -webkit-backdrop-filter:blur(12px);
368  border-bottom:1px solid rgba(228,231,235,0.6);
369  box-shadow:0 2px 16px -4px rgba(0,0,0,0.08);
370  position:sticky;
371  top:0;
372  z-index:500;
373  transition:all .3s ease;
374}
375
376/* Accent line gradient #E3D05A */
377.navbar::after {
378  content:'';
379  position:absolute;
380  bottom:0;
381  left:0;
382  right:0;
383  height:2px;
384  background:linear-gradient(90deg,transparent 0%, var(--brand-500) 20%, var(--brand-600) 50%, var(--brand-500) 80%, transparent 100%);
385  opacity:0.5;
386}
387
388.nav-inner {
389  display:flex;
390  align-items:center;
391  gap:24px;
392  min-height:70px;
393}
394.nav-inner .search .m-search-ico { display: none; }
395
396/* Secara default (desktop) ikon login disembunyikan; teks muncul */
397.login-btn .login-ico { display:none; }
398.navbar-logo {
399  display: none;
400  background:linear-gradient(135deg, rgba(255,255,255,0.95) 0%, rgba(255,245,230,0.85) 100%);
401  backdrop-filter:blur(12px);
402  -webkit-backdrop-filter:blur(12px);
403  border-bottom:1px solid rgba(228,231,235,0.6);
404  box-shadow:0 2px 16px -4px rgba(0,0,0,0.08);
405  position:sticky;
406  top:0;
407  z-index:500;
408}
409
410/* Hide bottom navigation on desktop - only show on mobile */
411.bottom-nav {
412  display: none;
413}
414
415/* ==============================================================
416   MOBILE ()
417   ============================================================== */
418@media (max-width:640px){
419  .container { padding:10px 16px; }
420  
421  .topbar { display:none !important; }
422
423  /* Add padding bottom for sticky bottom nav */
424  body {
425    padding-bottom: 68px; /* Height of bottom nav + safe area */
426  }
427
428  /* Mobile Top Navbar - Clean & Minimal */
429  .navbar {
430    background:linear-gradient(135deg, rgba(255,255,255,0.97) 0%, rgba(255,245,230,0.9) 100%);
431    backdrop-filter:blur(16px);
432    -webkit-backdrop-filter:blur(16px);
433    box-shadow:0 2px 12px -3px rgba(0,0,0,0.08);
434    border: 0;
435  }
436
437  /* Simple grid layout - Logo, Search, Category */
438  .nav-inner {
439    display:grid;
440    grid-template-columns:1fr;
441    gap:10px;
442    padding:12px 16px 0 12px;
443    min-height:auto;
444  }
445
446  /* Logo centered at top */
447  .nav-inner .logo {
448    justify-self:center;
449    margin:0;
450    display:flex;
451  }
452  .nav-inner .logo img { height:36px; }
453
454  /* Search bar - full width */
455  .nav-inner .search {
456    position:relative;
457    display:flex;
458    align-items:center;
459    gap:0;
460    width:100%;
461    height:44px;
462    background:#fff;
463    border:1.5px solid #e5e7eb;
464    border-radius:12px;
465    padding:0 12px;
466    box-shadow:0 1px 3px rgba(0,0,0,0.04);
467    transition:all .25s;
468  }
469  .nav-inner .search:focus-within {
470    border-color:#C77DFF;
471    box-shadow:0 0 0 3px rgba(245,202,86,0.1);
472  }
473
474  .nav-inner .search-icon-btn {
475    color:#9ca3af;
476    padding:4px;
477    margin-right:4px;
478  }
479  
480  .nav-inner .search-icon-btn svg {
481    width:18px;
482    height:18px;
483  }
484
485  .nav-inner .search input {
486    flex:1;
487    min-width:0;
488    border:none;
489    outline:none;
490    background:transparent;
491    font-size:14px;
492    padding:0 8px;
493    height:100%;
494  }
495  
496  .nav-inner .ai-bot-toggle {
497    padding:6px;
498    margin-left:0;
499  }
500  
501  .nav-inner .ai-bot-toggle .bot-icon {
502    width:20px;
503    height:20px;
504  }
505  
506  .nav-inner .search-suggest {
507    left:0;
508    right:0;
509    width:calc(100vw - 32px);
510    margin-top:6px;
511    border-radius:12px;
512    max-height:70vh;
513  }
514
515  /* Hide desktop nav actions but keep structure for userMenu */
516  .nav-inner .nav-actions {
517    display:flex !important; /* Keep flex to allow userMenu positioning */
518    visibility:hidden; /* Hide visually but keep in DOM */
519    pointer-events:none; /* Disable interactions with hidden elements */
520    position:absolute; /* Remove from flow */
521    right:0;
522    top:0;
523  }
524  
525  /* Re-enable userMenu for logged-in users */
526  .nav-inner .nav-actions #userMenu {
527    visibility:visible !important;
528    pointer-events:auto !important;
529  }
530  
531  .nav-inner .logo { display: none; }
532  .navbar-logo {
533    display: block;
534    /* background:linear-gradient(135deg, rgba(255,255,255,0.97) 0%, rgba(255,245,230,0.9) 100%); */
535    backdrop-filter:blur(16px);
536    -webkit-backdrop-filter:blur(16px);
537    position: static; /* Remove sticky on mobile */
538    box-shadow: none;
539    border-bottom: 0;
540    padding-top: .6rem;
541  }
542  .nav-inner .logo-mobile { display: block; }
543  
544  /* Category menu wrapper will handle visibility */
545
546  /* ==============================================================
547     BOTTOM NAVIGATION - Styles moved to bottom-nav.css
548     ============================================================== */
549  /* All bottom-nav styles now in /assets/css/bottom-nav.css */
550
551  /* Hide desktop elements that now moved to bottom nav */
552  #wishlistBtn,
553  #notifBtn,
554  #loginBtn { display:none !important; }
555  
556  /* Hide desktop user menu on mobile - use bottom sheet instead */
557  .navbar #userMenu { 
558    display:none !important;
559  }
560  
561  .nav-actions .cart-indicator,
562  .nav-actions .compare-indicator {
563    display:none !important;
564  }
565
566  /* Hide category button from bottom nav */
567  #bottomCategoryBtn {
568    display: none !important;
569  }
570  
571  /* User menu button styling for mobile - scoped to navbar only */
572  .navbar #userMenu .login-btn.logged-in {
573    width:40px;
574    height:40px;
575    padding:0;
576    border-radius:50%;
577    display:flex;
578    align-items:center;
579    justify-content:center;
580    background:rgba(255,255,255,0.95);
581    backdrop-filter:blur(12px);
582    -webkit-backdrop-filter:blur(12px);
583    border:1px solid rgba(228,231,235,0.6);
584    box-shadow:0 2px 12px -3px rgba(0,0,0,0.12);
585  }
586  
587  .navbar #userMenu .login-btn.logged-in .login-text { 
588    display:none; 
589  }
590  
591  .navbar #userMenu .login-btn.logged-in .login-ico {
592    display:inline;
593    font-size:20px;
594    line-height:1;
595  }
596  
597  /* User dropdown positioning for mobile */
598  .navbar #userMenu .user-dropdown {
599    position:fixed !important;
600    top:60px !important;
601    right:16px !important;
602    left:auto !important;
603    min-width:200px;
604    background:rgba(255,255,255,0.98);
605    backdrop-filter:blur(20px);
606    -webkit-backdrop-filter:blur(20px);
607    border:1px solid rgba(228,231,235,0.6);
608    box-shadow:0 8px 24px -8px rgba(0,0,0,0.2);
609    z-index:1002 !important;
610    border-radius:12px;
611    padding:8px 0;
612  }
613  
614  /* Force visibility when not hidden attribute */
615  .navbar #userMenu .user-dropdown:not([hidden]) {
616    display:block !important;
617    visibility:visible !important;
618    opacity:1 !important;
619  }
620
621  /* Container untuk kategori dan tombol kategori sejajar */
622  .navbar .container:last-child {
623    display:flex !important;
624    align-items:center !important;
625    padding:4px 16px 6px !important;
626    gap:5px;
627    overflow:visible;
628  }
629  
630  /* Wrapper untuk mega-cats dengan fade gradient (mobile only) */
631  .mega-cats-wrapper {
632    position:relative;
633    flex:1;
634    overflow:hidden;
635    min-height:34px; /* Ensure content is visible */
636    display:flex; /* Ensure wrapper is flex container */
637  }
638  
639  /* Fade gradient indicator di ujung kanan (mobile only) */
640  .mega-cats-fade {
641    position:absolute;
642    top:0;
643    right:0;
644    bottom:0;
645    width:80px; /* Increased from 60px for better visibility */
646    background:linear-gradient(to left, 
647      rgba(255,245,230,1) 0%, 
648      rgba(255,245,230,0.98) 15%,
649      rgba(255,245,230,0.85) 35%, 
650      transparent 100%);
651    pointer-events:none;
652    z-index:5; /* Increased z-index */
653    transition:opacity 0.3s ease;
654  }
655  
656  /* Kategori menu di mobile */
657  .mega-cats.container {
658    display:flex !important;
659    gap:12px;
660    overflow-x:auto;
661    overflow-y:visible;
662    -webkit-overflow-scrolling:touch;
663    scrollbar-width:none;
664    flex:1;
665    padding:0 !important;
666    margin:0 !important;
667    position:relative; /* For z-index stacking */
668    z-index:1; /* Below fade gradient */
669  }
670  .mega-cats.container::-webkit-scrollbar { display:none; }
671
672  /* Styling untuk menu items di mobile */
673  .mega-cats a {
674    font-size:13px;
675    padding:6px 10px;
676    white-space:nowrap;
677    flex-shrink:0;
678    position:relative; /* Ensure proper stacking */
679  }
680  .mega-cats a.active {
681    background:var(--brand-600);
682    color:#fff;
683    font-weight:600;
684    border-radius:6px;
685  }
686  
687  /* Tombol kategori di mobile */
688  .mm-wp {
689    flex-shrink:0;
690  }
691  .mm2-trigger {
692    display:flex;
693    align-items:center;
694    gap:6px;
695    padding:6px 12px;
696    background:var(--gray-100);
697    color:var(--gray-700);
698    text-decoration:none;
699    border-radius:6px;
700    font-size:13px;
701    white-space:nowrap;
702  }
703  
704  .mm2-trigger .label-cat {display: none; }
705  /* Tombol more kategori */
706  .mega-more-btn {
707    border:1px solid var(--border);
708    background:#fff;
709    border-radius:10px;
710    padding:6px 14px;
711    font-size:18px;
712    cursor:pointer;
713  }
714  .mega-cats-more.active > .mega-more-btn {
715    background:var(--brand-600);
716    color:#fff;
717    border-color:var(--brand-600);
718  }
719  .mega-more-dropdown {
720    top:calc(100% + 10px);
721    right:0;
722    min-width:85vw;
723    max-width:90vw;
724    border-radius:16px;
725  }
726  .mega-more-grid {
727    grid-template-columns:repeat(auto-fill,minmax(120px,1fr));
728  }
729  
730  /* ==============================================================
731     MOBILE USER BOTTOM SHEET
732     ============================================================== */
733  .mobile-user-sheet {
734    position:fixed;
735    top:0;
736    left:0;
737    right:0;
738    bottom:0;
739    z-index:10000;
740    pointer-events:none;
741  }
742  
743  .mobile-user-sheet.active {
744    pointer-events:auto;
745  }
746  
747  .mobile-user-sheet-backdrop {
748    position:absolute;
749    top:0;
750    left:0;
751    right:0;
752    bottom:0;
753    background:rgba(0,0,0,0.5);
754    opacity:0;
755    transition:opacity .3s ease;
756  }
757  
758  .mobile-user-sheet.active .mobile-user-sheet-backdrop {
759    opacity:1;
760  }
761  
762  .mobile-user-sheet-content {
763    position:absolute;
764    bottom:0;
765    left:0;
766    right:0;
767    background:#fff;
768    border-radius:20px 20px 0 0;
769    box-shadow:0 -4px 24px rgba(0,0,0,0.15);
770    transform:translateY(100%);
771    transition:transform .3s cubic-bezier(0.4, 0.0, 0.2, 1);
772    padding-bottom:calc(68px + env(safe-area-inset-bottom));
773  }
774  
775  .mobile-user-sheet.active .mobile-user-sheet-content {
776    transform:translateY(0);
777  }
778  
779  .mobile-user-sheet-header {
780    padding:16px 20px 12px;
781    border-bottom:1px solid #e5e7eb;
782  }
783  
784  .mobile-user-sheet-handle {
785    width:40px;
786    height:4px;
787    background:#d1d5db;
788    border-radius:2px;
789    margin:0 auto 16px;
790  }
791  
792  .mobile-user-info {
793    display:flex;
794    align-items:center;
795    gap:12px;
796  }
797  
798  .mobile-user-avatar {
799    width:48px;
800    height:48px;
801    border-radius:50%;
802    background:linear-gradient(135deg, #764EAC, #fff1cc);
803    display:flex;
804    align-items:center;
805    justify-content:center;
806    font-size:24px;
807    flex-shrink:0;
808  }
809  
810  .mobile-user-details {
811    flex:1;
812    min-width:0;
813  }
814  
815  .mobile-user-name {
816    font-size:16px;
817    font-weight:600;
818    color:#111827;
819    margin-bottom:2px;
820    white-space:nowrap;
821    overflow:hidden;
822    text-overflow:ellipsis;
823  }
824  
825  .mobile-user-email {
826    font-size:13px;
827    color:#6b7280;
828    white-space:nowrap;
829    overflow:hidden;
830    text-overflow:ellipsis;
831  }
832  
833  .mobile-user-sheet-body {
834    padding:8px 0;
835  }
836  
837  .mobile-user-sheet-item {
838    display:flex;
839    align-items:center;
840    gap:16px;
841    padding:14px 20px;
842    text-decoration:none;
843    color:#374151;
844    font-size:15px;
845    transition:background .2s;
846    border:none;
847    background:none;
848    width:100%;
849    text-align:left;
850    cursor:pointer;
851  }
852  
853  .mobile-user-sheet-item:active {
854    background:#f3f4f6;
855  }
856  
857  .mobile-user-sheet-icon {
858    font-size:20px;
859    width:24px;
860    text-align:center;
861    flex-shrink:0;
862  }
863  
864  .mobile-user-sheet-label {
865    flex:1;
866    font-weight:500;
867  }
868  
869  .mobile-user-sheet-divider {
870    height:1px;
871    background:#e5e7eb;
872    margin:8px 0;
873  }
874}
875
876/* END NAVBAR */
877
878.logo img { display:block; }
879.search {
880  flex:1;
881  position:relative;
882  display:flex;
883  align-items:center;
884  gap:0;
885  background:#fff;
886  border:1.5px solid #e5e7eb;
887  border-radius:12px;
888  padding:0 16px;
889  height:38px;
890  transition:all 0.3s ease;
891}
892.search:focus-within {
893  border-color:#C77DFF;
894  box-shadow:0 0 0 3px rgba(245,202,86,0.1);
895}
896.search input {
897  flex:1;
898  border:none;
899  outline:none;
900  background:transparent;
901  font-size:15px;
902  padding:0 12px;
903  height:100%;
904  color:#1f2937;
905}
906.search input::placeholder {
907  color:#9ca3af;
908}
909.search-icon-btn {
910  background:transparent;
911  border:none;
912  padding:0;
913  display:flex;
914  align-items:center;
915  justify-content:center;
916  cursor:pointer;
917  color:#6b7280;
918  transition:color 0.2s ease;
919  flex-shrink:0;
920}
921.search-icon-btn:hover {
922  color:#C77DFF;
923}
924.search-suggest {
925  position:absolute;
926  left:0; right:0; top:100%;
927  background:#fff;
928  border:1px solid var(--border);
929  border-radius:var(--radius);
930  padding:8px 0;
931  box-shadow:0 8px 20px rgba(0,0,0,.08);
932  margin-top:4px;
933  font-size:14px;
934  max-height:260px;
935  overflow:auto;
936}
937.search-suggest div {
938  padding:6px 12px;
939  cursor:pointer;
940}
941.search-suggest div:hover { background:var(--gray-100); }
942
943.nav-actions { display:flex; gap:10px; align-items:center; }
944.icon-btn, .login-btn {
945  background:linear-gradient(135deg, rgba(255,255,255,0.95), rgba(249,250,251,0.9));
946  border:1px solid rgba(228,231,235,0.6);
947  padding:8px 12px;
948  border-radius:var(--radius);
949  cursor:pointer;
950  font-size:14px;
951  transition:all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
952  height: 38px;
953  position:relative;
954  box-shadow:
955    0 1px 3px rgba(0,0,0,0.06),
956    0 0 0 1px rgba(255,255,255,0.5) inset;
957  backdrop-filter:blur(8px);
958  -webkit-backdrop-filter:blur(8px);
959}
960.icon-btn:hover, .login-btn:hover { 
961  background:linear-gradient(135deg, rgba(249,250,251,1), rgba(243,244,246,0.95));
962  border-color:rgba(209,213,219,0.8);
963  box-shadow:
964    0 2px 8px rgba(0,0,0,0.08),
965    0 0 0 1px rgba(255,255,255,0.6) inset;
966  transform:translateY(-1px);
967}
968.cart-indicator, .compare-indicator { position:relative; }
969.badge {
970  background:linear-gradient(135deg, #C77DFF, #C77DFF);
971  color:#fff;
972  font-size:10.5px;
973  font-weight:600;
974  padding:2px 6px;
975  border-radius:999px;
976  position:absolute;
977  top:-6px; 
978  right:-6px;
979  min-width:18px;
980  height:18px;
981  display:flex;
982  align-items:center;
983  justify-content:center;
984  box-shadow:
985    0 2px 8px rgba(226,166,66,0.4),
986    0 0 0 2px #fff,
987    0 0 12px -2px rgba(226,166,66,0.6);
988  transition:all 0.3s ease;
989}
990.icon-btn:hover .badge {
991  transform:scale(1.08);
992  box-shadow:
993    0 4px 12px rgba(226,166,66,0.5),
994    0 0 0 2px #fff,
995    0 0 16px -2px rgba(226,166,66,0.7);
996}
997.badge.is-empty { display:none; }
998
999/* User Menu Dropdown */
1000.user-menu {
1001  position:relative;
1002}
1003.user-dropdown {
1004  position:absolute;
1005  top:calc(100% + 8px);
1006  right:0;
1007  background:#fff;
1008  border:1px solid var(--border);
1009  border-radius:12px;
1010  box-shadow:0 10px 40px rgba(0,0,0,0.12);
1011  min-width:200px;
1012  padding:8px 0;
1013  z-index:9999;
1014}
1015
1016/* Ensure dropdown is visible when not hidden */
1017.user-dropdown:not([hidden]) {
1018  display:block !important;
1019  visibility:visible !important;
1020  opacity:1 !important;
1021}
1022
1023/* Mobile: Force user dropdown to be visible above everything */
1024@media (max-width:640px) {
1025  .user-dropdown:not([hidden]) {
1026    position:fixed !important;
1027    z-index:9999 !important;
1028    top:60px !important;
1029    right:16px !important;
1030  }
1031}
1032
1033.dropdown-item {
1034  display:flex;
1035  align-items:center;
1036  gap:12px;
1037  padding:10px 16px;
1038  text-decoration:none;
1039  color:var(--gray-700);
1040  font-size:14px;
1041  transition:var(--transition);
1042  border:none;
1043  background:none;
1044  width:100%;
1045  text-align:left;
1046  cursor:pointer;
1047}
1048.dropdown-item:hover {
1049  background:var(--gray-100);
1050  color:var(--gray-900);
1051}
1052.dropdown-icon {
1053  font-size:16px;
1054  opacity:0.7;
1055}
1056.dropdown-separator {
1057  height:1px;
1058  background:var(--border);
1059  margin:8px 0;
1060}
1061.login-btn.logged-in {
1062  background:linear-gradient(135deg, rgba(255,245,230,0.8), rgba(255,231,204,0.6));
1063  border:1px solid rgba(245,202,86,0.2);
1064  color:var(--brand-700);
1065  max-width:200px; /* Prevent button from getting too wide */
1066  display:inline-flex;
1067  align-items:center;
1068  gap:10px;
1069  padding:4px 12px 4px 4px;
1070  transition:all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
1071  position:relative;
1072  overflow:hidden;
1073  box-shadow:
1074    0 1px 3px rgba(245,202,86,0.08),
1075    0 0 0 1px rgba(255,255,255,0.5) inset,
1076    0 0 12px -6px rgba(245,202,86,0.1);
1077  backdrop-filter:blur(8px);
1078  -webkit-backdrop-filter:blur(8px);
1079}
1080/* Subtle background glow effect */
1081.login-btn.logged-in::before {
1082  content:'';
1083  position:absolute;
1084  top:50%;
1085  left:0;
1086  width:32px;
1087  height:32px;
1088  background:radial-gradient(circle, rgba(245,202,86,0.15), transparent 70%);
1089  transform:translateY(-50%);
1090  opacity:0;
1091  transition:opacity 0.3s ease;
1092}
1093.login-btn.logged-in:hover::before {
1094  opacity:1;
1095}
1096.login-btn.logged-in .user-avatar {
1097  width:32px;
1098  height:32px;
1099  border-radius:50%;
1100  background:linear-gradient(135deg, #764EAC 0%, #fff1cc 50%, #C77DFF 100%);
1101  color:#C77DFF;
1102  font-size:11.5px;
1103  font-weight:700;
1104  display:flex;
1105  align-items:center;
1106  justify-content:center;
1107  flex-shrink:0;
1108  letter-spacing:0.3px;
1109  position:relative;
1110  box-shadow:
1111    0 2px 8px rgba(245,202,86,0.25),
1112    0 1px 3px rgba(0,0,0,0.12),
1113    inset 0 1px 0 rgba(255,255,255,0.5);
1114  transition:all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
1115}
1116/* Ring gradient border */
1117.login-btn.logged-in .user-avatar::before {
1118  content:'';
1119  position:absolute;
1120  inset:-2px;
1121  border-radius:50%;
1122  padding:2px;
1123  background:linear-gradient(135deg, #C77DFF, #fff1cc, #C77DFF);
1124  -webkit-mask:linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
1125  -webkit-mask-composite:xor;
1126  mask:linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
1127  mask-composite:exclude;
1128  opacity:0;
1129  transition:opacity 0.3s ease;
1130}
1131.login-btn.logged-in:hover .user-avatar::before {
1132  opacity:1;
1133}
1134.login-btn.logged-in:hover .user-avatar {
1135  transform:scale(1.08) rotate(-3deg);
1136  box-shadow:
1137    0 4px 12px rgba(245,202,86,0.35),
1138    0 2px 6px rgba(0,0,0,0.15),
1139    inset 0 1px 0 rgba(255,255,255,0.6);
1140}
1141.login-btn.logged-in .login-text {
1142  overflow:hidden;
1143  text-overflow:ellipsis;
1144  white-space:nowrap;
1145  flex:1;
1146  min-width:0;
1147  font-weight:500;
1148  font-size:14px;
1149  transition:color 0.2s ease;
1150}
1151.login-btn.logged-in:hover .login-text {
1152  color:var(--brand-600);
1153}
1154.login-btn.logged-in:hover {
1155  background:linear-gradient(135deg, rgba(255,245,230,0.95), rgba(255,231,204,0.85));
1156  border-color:rgba(245,202,86,0.3);
1157  box-shadow:
1158    0 4px 16px -4px rgba(245,202,86,0.25),
1159    0 0 0 1px rgba(245,202,86,0.1) inset,
1160    0 1px 2px rgba(0,0,0,0.05);
1161  transform:translateY(-1px);
1162}
1163
1164/* Desktop: hide wrapper elements, show menu normally */
1165@media (min-width: 761px) {
1166  .mega-cats-wrapper {
1167    display:contents; /* Remove wrapper from layout */
1168  }
1169  .mega-cats-fade {
1170    display:none !important; /* Hide fade on desktop */
1171  }
1172}
1173
1174.mega-cats {
1175  display:flex;
1176  gap:5px;
1177  /* padding:6px 16px 10px; */
1178  scrollbar-width:none;
1179  position: relative;
1180  z-index: 510;
1181  overflow-x:auto;
1182  -webkit-overflow-scrolling:touch;
1183  flex:1;
1184}
1185.mega-cats::-webkit-scrollbar { 
1186  display:none; 
1187}
1188.mega-cats a {
1189  text-decoration:none;
1190  font-size:14px;
1191  color:var(--gray-700);
1192  padding:6px 10px;
1193  border-radius:6px;
1194  white-space:nowrap;
1195  transition:var(--transition);
1196}
1197.mega-cats a:hover { background:var(--brand-100); color:var(--brand-600); }
1198/*.mega-cats::after {
1199  content:'';
1200  position:absolute;
1201  right:0;
1202  top:0;
1203  width:40px;
1204  height:100%;
1205  background:linear-gradient(to right,rgba(255,255,255,0),#fff);
1206  pointer-events:none;
1207}*/
1208
1209/* Tambahan untuk tombol More & dropdown.
1210   Style dasar .mega-cats dan .mega-cats a tetap pakai definisi Anda. */
1211
1212.mega-cats-more {
1213  position:relative;
1214  display:flex;
1215  align-items:center;
1216}
1217
1218.mega-cats-more.active > .mega-more-btn {
1219  background:var(--brand-600);
1220  color:#fff;
1221}
1222
1223.mega-more-btn {
1224  cursor:pointer;
1225  border:none;
1226  background:var(--gray-100,#f5f5f5);
1227  color:var(--gray-700,#333);
1228  padding:6px 12px;
1229  font-size:16px;
1230  line-height:1;
1231  border-radius:6px;
1232  display:flex;
1233  align-items:center;
1234  justify-content:center;
1235  transition:var(--transition);
1236}
1237.mega-more-btn:hover {
1238  background:var(--brand-100);
1239  color:var(--brand-600);
1240}
1241
1242.mega-more-dropdown {
1243  position:absolute;
1244  top:100%;
1245  right:0;
1246  margin-top:8px;
1247  background:#fff;
1248  border:1px solid var(--gray-200,#e3e6e9);
1249  border-radius:10px;
1250  padding:12px 14px 14px;
1251  min-width:400px;
1252  max-width:520px;
1253  max-height:420px;
1254  box-shadow:0 12px 32px -8px rgba(25,40,65,.25);
1255  z-index: 3000; 
1256}
1257
1258.mega-more-grid {
1259  display:grid;
1260  grid-template-columns:repeat(auto-fill,minmax(120px,1fr));
1261  gap:8px 10px;
1262  overflow-x: hidden;
1263  max-height:380px;
1264  overscroll-behavior:contain;
1265  scrollbar-width:thin;
1266}
1267.mega-more-grid::-webkit-scrollbar {
1268  width:6px;
1269}
1270.mega-more-grid::-webkit-scrollbar-thumb {
1271  background:var(--gray-300,#c7ccd1);
1272  border-radius:3px;
1273}
1274
1275/* Link di dropdown mewarisi style .mega-cats a (warna, padding, radius).
1276   Kita tambahkan state active agar konsisten. */
1277.mega-more-grid a.active {
1278  background:var(--brand-600);
1279  color:#fff;
1280  font-weight:600;
1281}
1282.hero {
1283  background:linear-gradient(135deg,var(--brand-50), #fff);
1284}
1285.hero-inner {
1286  display:grid;
1287  grid-template-columns:repeat(auto-fit,minmax(320px,1fr));
1288  gap:48px;
1289  align-items:center;
1290}
1291.hero-text h1 {
1292  font-size:48px;
1293  line-height:1.1;
1294  margin:0;
1295  font-weight:600;
1296  font-family:"Poppins",sans-serif;
1297}
1298.hero-text .text-brand { color:var(--brand-500); }
1299.lead { font-size:18px; color:var(--gray-700); margin-top:16px; }
1300.hero-cta { margin-top:28px; display:flex; gap:16px; }
1301.hero-bullets { margin-top:28px; display:flex; gap:28px; font-size:14px; color:var(--gray-600); }
1302.hero-box {
1303  background:#fff;
1304  padding:10px;
1305  border-radius:16px;
1306  box-shadow:0 4px 18px rgba(0,0,0,.08);
1307  /* min-height:320px; */
1308  display:flex;
1309  align-items:center;
1310  justify-content:center;
1311}
1312.hero-box img {border-radius: 10px; }
1313
1314@media (max-width:680px) {
1315    .hero-inner { gap: 25px; }    
1316}
1317
1318.usp-section {
1319  position:relative;
1320  background:
1321    linear-gradient(180deg,#FFFDFB 0%, #FFFFFF 60%) ;
1322  border-top:1px solid var(--border);
1323  border-bottom:1px solid var(--border);
1324  padding:10px 0 10px;
1325}
1326
1327.usp-list {
1328  list-style:none;
1329  margin:0;
1330  padding:0;
1331  display:grid;
1332  gap:26px;
1333}
1334
1335.usp-list.variant-soft {
1336  grid-template-columns:repeat(auto-fit,minmax(230px,1fr));
1337}
1338
1339.usp-item {
1340  display:flex;
1341  gap:16px;
1342  align-items:flex-start;
1343  background:#fff;
1344  padding:18px 18px 18px 16px;
1345  border:1px solid rgba(226,226,226,0.7);
1346  border-radius:18px;
1347  position:relative;
1348  overflow:hidden;
1349  isolation:isolate;
1350  box-shadow:0 2px 4px -1px rgba(0,0,0,.04), 0 6px 18px -6px rgba(0,0,0,.08);
1351  transition: .35s cubic-bezier(.16,.8,.32,1);
1352}
1353
1354.usp-item::before {
1355  content:"";
1356  position:absolute;
1357  inset:0;
1358  background:radial-gradient(circle at 18% 22%, rgba(245,202,86,.18), transparent 60%);
1359  opacity:.65;
1360  transition:.5s;
1361  z-index:-1;
1362}
1363
1364.usp-item:hover {
1365  transform:translateY(-6px);
1366  box-shadow:0 10px 26px -8px rgba(0,0,0,.15), 0 3px 8px -2px rgba(0,0,0,.08);
1367  border-color:rgba(245,202,86,.35);
1368}
1369
1370.usp-item:hover::before {
1371  background:radial-gradient(circle at 70% 40%, rgba(245,202,86,.22), transparent 65%);
1372}
1373
1374.usp-icon {
1375  flex:0 0 56px;
1376  width:56px;
1377  height:56px;
1378  border-radius:16px;
1379  display:flex;
1380  align-items:center;
1381  justify-content:center;
1382  background:
1383    linear-gradient(135deg,#764EAC,#fff1cc);
1384  position:relative;
1385  box-shadow:inset 0 0 0 1px rgba(255,255,255,.6), 0 4px 10px -3px rgba(0,0,0,.15);
1386  transition:.45s;
1387}
1388
1389.usp-item:hover .usp-icon {
1390  transform:rotate(-4deg) scale(1.06);
1391  box-shadow:inset 0 0 0 1px rgba(255,255,255,.8), 0 6px 14px -4px rgba(0,0,0,.20);
1392}
1393
1394.usp-icon svg {
1395  width:28px;
1396  height:28px;
1397  display:block;
1398  filter:drop-shadow(0 2px 2px rgba(0,0,0,.18));
1399}
1400
1401.usp-text h3 {
1402  font-size:15px;
1403  font-weight:600;
1404  margin:2px 0 6px;
1405  letter-spacing:.2px;
1406}
1407
1408.usp-text p {
1409  font-size:13px;
1410  line-height:1.3;
1411  margin:0;
1412  color:var(--gray-600);
1413}
1414
1415@media (max-width:680px) {
1416  .usp-section { padding: 5px 0 5px; margin-bottom: 0.75rem;}
1417  .usp-item { padding:16px 14px; }
1418  .usp-icon { width:50px;height:50px;border-radius:14px; }
1419  .usp-text h3 { font-size:14px; margin-bottom:4px; }
1420  .usp-text p { font-size:12.5px; }
1421  .usp-list { gap: 10px; }
1422}
1423
1424.flash { padding:50px 0 30px; background:#fff; }
1425.flash-head {
1426  display:flex; align-items:center;
1427  justify-content:space-between;
1428  margin-bottom:20px;
1429}
1430.flash-head h2 { margin:0; font-size:24px; font-family:"Poppins"; }
1431.flash .countdown {
1432  font-family:monospace;
1433  background:#111;
1434  color:#fff;
1435  padding:8px 14px;
1436  border-radius:8px;
1437  font-size:16px;
1438  letter-spacing:1px;
1439}
1440.flash-scroll {
1441  display:flex;
1442  gap:16px;
1443  overflow-x:auto;
1444  padding-bottom:6px;
1445  scrollbar-width:none;
1446}
1447.flash-scroll::-webkit-scrollbar { display:none; }
1448
1449.products { padding:60px 0; background:#fff; }
1450.products-head {
1451  display:flex; justify-content:space-between; align-items:center;
1452  margin-bottom:24px;
1453  flex-wrap:wrap;
1454  gap:16px;
1455}
1456.products-head h2 { margin:0; font-size:24px; font-family:"Poppins"; }
1457.product-filters input {
1458  padding:8px 12px;
1459  border:1px solid var(--border);
1460  border-radius:8px;
1461  font-size:14px;
1462  width:220px;
1463}
1464
1465.product-grid {
1466  display:grid;
1467  gap:24px;
1468  grid-template-columns:repeat(auto-fill,minmax(180px,1fr));
1469}
1470
1471.prod-card {
1472  background:#fff;
1473  border:1px solid var(--border);
1474  padding:12px;
1475  border-radius:12px;
1476  position:relative;
1477  display:flex;
1478  flex-direction:column;
1479  transition:var(--transition);
1480}
1481.prod-card.small { min-width:160px; }
1482.prod-card:hover { box-shadow:0 8px 20px rgba(0,0,0,.12); transform:translateY(-3px); }
1483.prod-card .img-box {
1484  background:var(--gray-100);
1485  border-radius:10px;
1486  aspect-ratio:1/1;
1487  display:flex;
1488  align-items:center;
1489  justify-content:center;
1490  overflow:hidden;
1491}
1492.prod-card .img-box img { width:100%; height:100%; object-fit:contain; transition:var(--transition); }
1493.prod-card:hover .img-box img { transform:scale(1.04); }
1494.prod-card .name {
1495  font-size:13.5px;
1496  font-weight:500;
1497  margin:10px 0 6px;
1498  min-height:36px;
1499  line-height:1.3;
1500}
1501.price {
1502  display:flex;
1503  gap:6px;
1504  align-items:center;
1505  flex-wrap:wrap;
1506}
1507.price strong { color:var(--brand-600); font-size:14px; }
1508.price .old {
1509  font-size:11px;
1510  color:var(--gray-500);
1511  text-decoration:line-through;
1512}
1513.tag.discount {
1514  position:absolute;
1515  top:8px; left:8px;
1516  background:#C77DFF;
1517  color:#fff;
1518  font-size:11px;
1519  padding:4px 6px;
1520  border-radius:6px;
1521  font-weight:600;
1522}
1523.btn {
1524  border:none;
1525  cursor:pointer;
1526  font-weight:500;
1527  font-size:14px;
1528  padding:12px 22px;
1529  border-radius:10px;
1530  background:var(--gray-900);
1531  color:#fff;
1532  transition:var(--transition);
1533  text-decoration:none;
1534  text-align:center;
1535  display:inline-flex;
1536  align-items:center;
1537  justify-content:center;
1538  gap:6px;
1539}
1540.btn:hover { background:#000; }
1541.btn-primary { background:var(--brand-500); }
1542.btn-primary:hover { background:var(--brand-600); }
1543.btn-outline {
1544  background:#fff;
1545  color:var(--gray-900);
1546  border:1px solid var(--border);
1547}
1548.btn-outline:hover { background:var(--gray-100); }
1549.btn-sm { padding:8px 14px; font-size:13px; }
1550.btn-mini { padding:6px 10px; font-size:12px; }
1551.add-cart { margin-top:auto; background:var(--brand-500); color:#fff; }
1552.add-cart:hover { background:var(--brand-600); }
1553
1554/* ==== FOOTER COMPACT FIX PATCH (final) ==== */
1555
1556/* 1. Pastikan grid aktif */
1557
1558.site-footer.footer-compact .ft-grid {
1559  display:grid;
1560  grid-template-columns:repeat(auto-fit,minmax(240px,1fr));
1561  gap:30px 40px;
1562  align-items:start;
1563}
1564
1565/* 2. Spacing atas bawah dipadatkan */
1566.site-footer.footer-compact .ft-top {
1567  padding:42px 0 26px;
1568}
1569
1570/* 3. Judul & teks */
1571.site-footer.footer-compact .ft-title {
1572  margin:0 0 14px;
1573  font-size:14px;
1574  letter-spacing:.8px;
1575  text-transform:uppercase;
1576  font-weight:600;
1577  color:#82b1c9;
1578}
1579
1580.site-footer.footer-compact .ft-desc,
1581.site-footer.footer-compact .ft-text {
1582  margin:0 0 16px;
1583  font-size:13.5px;
1584  line-height:1.45;
1585  color:#c6d6e0;
1586  max-width:330px;
1587}
1588.site-footer.footer-compact .ft-desc.sm-gap { margin-top:18px; }
1589
1590/* 4. Reset ikon SVG agar tidak membesar */
1591.site-footer.footer-compact svg {
1592  width:20px;
1593  height:20px;
1594  flex:0 0 20px;
1595  display:inline-block;
1596}
1597.site-footer.footer-compact .ft-social svg { width:18px; height:18px; }
1598.site-footer.footer-compact .ft-wa-btn svg { width:18px; height:18px; }
1599
1600/* Jika ada aturan global svg { width:100%; } — paksa override */
1601svg { max-width:100%; }
1602.site-footer.footer-compact svg {
1603  width:20px !important;
1604  height:20px !important;
1605}
1606
1607/* 5. Link list */
1608.site-footer.footer-compact .ft-links {
1609  list-style:none;
1610  margin:0 0 12px;
1611  padding:0;
1612  display:flex;
1613  flex-direction:column;
1614  gap:4px;
1615}
1616.site-footer.footer-compact .ft-links li { margin:0; }
1617.site-footer.footer-compact .ft-links a {
1618  display:flex;
1619  align-items:center;
1620  gap:8px;
1621  font-size:13.5px;
1622  padding:5px 2px;
1623  text-decoration:none;
1624  color:#c6d6e0;
1625  border-radius:8px;
1626  transition:.25s;
1627}
1628.site-footer.footer-compact .ft-links a:hover {
1629  background:rgba(255,255,255,.06);
1630  padding-left:6px;
1631  color:#fff;
1632}
1633
1634.site-footer.footer-compact .ico-s {
1635  width:24px;
1636  height:24px;
1637  background:#103346;
1638  color:#89b8cf;
1639  border-radius:6px;
1640  display:flex;
1641  align-items:center;
1642  justify-content:center;
1643  flex:0 0 24px;
1644  font-size:12px;
1645  transition:.3s;
1646}
1647.site-footer.footer-compact .ft-links a:hover .ico-s {
1648  background:#C77DFF;
1649  color:#fff;
1650  transform:rotate(-4deg);
1651}
1652
1653/* 6. WhatsApp button */
1654.site-footer.footer-compact .ft-wa-btn {
1655  display:inline-flex;
1656  align-items:center;
1657  gap:8px;
1658  background:#fff;
1659  color:#062437;
1660  padding:8px 18px;
1661  font-size:13.5px;
1662  border-radius:22px;
1663  font-weight:500;
1664  text-decoration:none;
1665  box-shadow:0 3px 8px -3px rgba(0,0,0,.45);
1666  transition:.25s;
1667}
1668.site-footer.footer-compact .ft-wa-btn:hover {
1669  transform:translateY(-2px);
1670  box-shadow:0 6px 14px -6px rgba(0,0,0,.55);
1671}
1672
1673/* 7. Sosial */
1674.site-footer.footer-compact .ft-social {
1675  display:flex;
1676  gap:12px;
1677  margin-top:4px;
1678}
1679.site-footer.footer-compact .ft-social a {
1680  width:34px;
1681  height:34px;
1682  background:rgba(255,255,255,.08);
1683  display:flex;
1684  align-items:center;
1685  justify-content:center;
1686  border-radius:10px;
1687  color:#c6d6e0;
1688  transition:.25s;
1689}
1690.site-footer.footer-compact .ft-social a:hover {
1691  background:#C77DFF;
1692  color:#fff;
1693}
1694
1695/* 8. Alamat */
1696.site-footer.footer-compact .ft-address {
1697  font-size:12.5px;
1698  line-height:1.44;
1699  color:#8fa4b1;
1700  max-width:330px;
1701  margin-top:12px;
1702}
1703.site-footer.footer-compact .ft-address .company {
1704  margin:0 0 4px;
1705  font-weight:600;
1706  color:#e5f2f7;
1707  font-size:12.8px;
1708}
1709
1710/* 9. Payments kecil & rapi */
1711.site-footer.footer-compact .ft-payments {
1712  margin-top:14px;
1713  display:flex;
1714  flex-direction:column;
1715  gap:8px;
1716  max-width:350px;
1717}
1718.site-footer.footer-compact .ft-payments .pay-row {
1719  display:flex;
1720  gap:8px;
1721  flex-wrap:wrap;
1722}
1723.site-footer.footer-compact .ft-payments img {
1724  width:46px;
1725  height:32px;
1726  padding:3px 5px;
1727  background:#fff;
1728  border-radius:7px;
1729  object-fit:contain;
1730  box-shadow:0 2px 6px -3px rgba(0,0,0,.45);
1731  transition:.25s;
1732}
1733.site-footer.footer-compact .ft-payments img:hover {
1734  transform:translateY(-3px);
1735  box-shadow:0 5px 12px -6px rgba(0,0,0,.55);
1736}
1737
1738/* 10. Bottom bar */
1739.site-footer.footer-compact .ft-bottom {
1740  border-top:1px solid rgba(255,255,255,.08);
1741  background:#041f31;
1742  padding:12px 0 16px;
1743  margin-top:4px;
1744}
1745.site-footer.footer-compact .ft-copy {
1746  font-size:11.5px;
1747  color:#8fa7b5;
1748  display:flex;
1749  flex-wrap:wrap;
1750  gap:12px;
1751  justify-content:center;
1752  line-height:1.3;
1753  margin:0;
1754}
1755.site-footer.footer-compact .ft-copy span {
1756  position:relative;
1757  padding:0 10px;
1758}
1759.site-footer.footer-compact .ft-copy span+span:before {
1760  content:"";
1761  position:absolute;
1762  left:0;
1763  top:50%;
1764  width:1px;
1765  height:12px;
1766  background:rgba(255,255,255,.14);
1767  transform:translateY(-50%);
1768}
1769@media (max-width:580px){
1770  .site-footer.footer-compact .ft-top { padding:34px 0 18px; }
1771  .site-footer.footer-compact .ft-grid { gap:26px 20px; }
1772  .site-footer.footer-compact .ft-copy span { padding:0; }
1773  .site-footer.footer-compact .ft-copy span+span:before { display:none; }
1774}
1775.copy {
1776  margin-top:40px;
1777  border-top:1px solid #222;
1778  text-align:center;
1779  padding:18px 0;
1780  font-size:12px;
1781  color:#666;
1782}
1783
1784@media (max-width:760px) {
1785  .hero-text h1 { font-size:38px; }
1786  .hero { padding:0px 0 30px; }
1787  .topbar-inner { flex-direction:column; gap:4px; padding:6px 0; }
1788  .nav-inner { flex-wrap:wrap; }
1789  .mega-cats { gap:10px; }
1790  .product-grid { gap:16px; }
1791  .prod-card { padding:10px; }
1792}
1793
1794/* === PLAZA IT DARK #E3D05A FOOTER THEME === */
1795.site-footer.footer-compact {
1796  --ft-bg-0:#051722;
1797  --ft-bg-1:#072534;
1798  --ft-bg-2:#0B2F40;
1799  --ft-bg-3:#103A4E;
1800  --ft-orange:#C77DFF;
1801  --ft-orange-dark:#C77DFF;
1802  --ft-text:#E9F2F6;
1803  --ft-text-sec:#B8CAD3;
1804  --ft-text-muted:#8FA4B1;
1805  --ft-divider:rgba(255,255,255,0.08);
1806  --ft-glow:rgba(245,202,86,0.18);
1807  --ft-glow-fade:rgba(245,202,86,0);
1808  color:var(--ft-text);
1809}
1810
1811/* BASE TEXT / LINKS (override sebelumnya jika perlu) */
1812.site-footer.footer-compact .ft-title { color:#9CC5D7; }
1813.site-footer.footer-compact .ft-links a { color:var(--ft-text-sec); }
1814.site-footer.footer-compact .ft-links a:hover { color:#fff; }
1815.site-footer.footer-compact .ft-address { color:var(--ft-text-muted); }
1816.site-footer.footer-compact .ft-copy { color:#9AB2BD; }
1817
1818/* ICON BACKGROUND (kubu gelap) */
1819.site-footer.footer-compact .ico-s {
1820  background:#0F3647;
1821  color:#9FC7DA;
1822}
1823.site-footer.footer-compact .ft-links a:hover .ico-s {
1824  background:var(--ft-orange);
1825  color:#fff;
1826}
1827
1828/* WhatsApp button biarkan putih agar kontras */
1829.site-footer.footer-compact .ft-wa-btn {
1830  box-shadow:0 4px 12px -5px rgba(0,0,0,.6), 0 0 0 3px rgba(255,255,255,0.05);
1831}
1832.site-footer.footer-compact .ft-wa-btn:hover {
1833  box-shadow:0 8px 20px -8px rgba(0,0,0,.65), 0 0 0 3px rgba(245,202,86,0.25);
1834}
1835
1836/* Payment cards border halus */
1837.site-footer.footer-compact .ft-payments img {
1838  box-shadow:0 2px 6px -3px rgba(0,0,0,.55), 0 0 0 1px rgba(255,255,255,0.05);
1839}
1840.site-footer.footer-compact .ft-payments img:hover {
1841  box-shadow:0 6px 14px -6px rgba(0,0,0,.65), 0 0 0 1px rgba(245,202,86,0.4);
1842}
1843
1844/* ========== VARIANT A: DIAGONAL EMBER (AKTIF) ========== */
1845.site-footer.footer-compact.variant-ember {
1846  background:
1847    radial-gradient(circle at 78% 82%, var(--ft-glow) 0%, var(--ft-glow-fade) 55%),
1848    linear-gradient(140deg,var(--ft-bg-1) 0%, var(--ft-bg-2) 55%, var(--ft-bg-0) 100%);
1849}
1850.site-footer.footer-compact.variant-ember .ft-bottom {
1851  background:rgba(0,0,0,0.25);
1852  backdrop-filter:blur(2px);
1853}
1854
1855/* ========== VARIANT B: TOP BAR #E3D05A ========== */
1856.site-footer.footer-compact.variant-bar {
1857  background:var(--ft-bg-1);
1858  position:relative;
1859}
1860.site-footer.footer-compact.variant-bar::before {
1861  content:"";
1862  position:absolute;
1863  left:0;top:0;
1864  width:100%;height:3px;
1865  background:linear-gradient(90deg,var(--ft-orange-dark),var(--ft-orange));
1866  box-shadow:0 0 12px -2px var(--ft-orange);
1867}
1868.site-footer.footer-compact.variant-bar .ft-bottom {
1869  background:#041c28;
1870}
1871
1872/* ========== VARIANT C: RADIAL GLOW BAWAH ========== */
1873.site-footer.footer-compact.variant-radial {
1874  background:
1875    radial-gradient(circle at 70% 90%, rgba(245,202,86,0.22) 0%, rgba(245,202,86,0.04) 38%, rgba(245,202,86,0) 65%),
1876    linear-gradient(150deg,#052131 0%, #062d3f 50%, #041924 100%);
1877}
1878.site-footer.footer-compact.variant-radial .ft-bottom {
1879  background:#041c29;
1880}
1881
1882/* ========== VARIANT D: LAYERED STRIPES ========== */
1883.site-footer.footer-compact.variant-stripes {
1884  background:
1885    repeating-linear-gradient(180deg, rgba(255,255,255,0.015) 0 38px, rgba(255,255,255,0) 38px 76px),
1886    linear-gradient(130deg,#052636 0%, #062a3c 60%, #041d28 100%);
1887  position:relative;
1888}
1889.site-footer.footer-compact.variant-stripes::after {
1890  content:"";
1891  position:absolute;
1892  left:0;bottom:0;
1893  width:100%;height:110px;
1894  background:linear-gradient(0deg,rgba(0,0,0,.35),rgba(0,0,0,0));
1895  pointer-events:none;
1896}
1897.site-footer.footer-compact.variant-stripes .ft-bottom {
1898  background:#031821;
1899}
1900
1901/* Garis aksen oranye tipis di atas bottom */
1902.site-footer.footer-compact.variant-stripes .ft-bottom {
1903  position:relative;
1904}
1905.site-footer.footer-compact.variant-stripes .ft-bottom::before {
1906  content:"";
1907  position:absolute;
1908  left:0;top:0;
1909  width:100%;height:2px;
1910  background:linear-gradient(90deg,rgba(245,202,86,0),rgba(245,202,86,.65),rgba(245,202,86,0));
1911}
1912
1913/* ========== VARIANT E: GLASS PANEL ========== */
1914.site-footer.footer-compact.variant-glass {
1915  background:linear-gradient(145deg,#051c29 0%, #041620 65%, #03121b 100%);
1916}
1917.site-footer.footer-compact.variant-glass .ft-grid {
1918  position:relative;
1919  padding:32px clamp(10px,2vw,24px);
1920  border-radius:22px;
1921  background:linear-gradient(140deg,rgba(255,255,255,0.06),rgba(255,255,255,0.02));
1922  border:1px solid rgba(255,255,255,0.08);
1923  box-shadow:0 12px 28px -12px rgba(0,0,0,0.45), 0 0 0 1px rgba(255,255,255,0.04) inset;
1924  backdrop-filter:blur(8px);
1925  -webkit-backdrop-filter:blur(8px);
1926}
1927.site-footer.footer-compact.variant-glass .ft-bottom {
1928  background:#02141d;
1929}
1930
1931/* HOVER ACCENTS */
1932.site-footer.footer-compact a {
1933  transition:color .25s, background .25s, box-shadow .25s;
1934}
1935.site-footer.footer-compact .ft-links a:hover {
1936  box-shadow:0 2px 6px -3px rgba(0,0,0,.5),
1937             0 0 0 1px rgba(245,202,86,0.55);
1938}
1939.site-footer.footer-compact .ft-social a {
1940  background:#0E3445;
1941  color:#bcd4dd;
1942}
1943.site-footer.footer-compact .ft-social a:hover {
1944  background:var(--ft-orange);
1945  color:#fff;
1946  box-shadow:0 0 0 3px rgba(245,202,86,0.28);
1947}
1948
1949/* Divider di atas footer (opsional) */
1950.footer-divider-top {
1951  height:1px;
1952  background:linear-gradient(90deg,transparent,rgba(255,255,255,0.15),transparent);
1953  width:100%;
1954  margin:0 0 4px;
1955}
1956
1957/* ==== MOBILE FOOTER COLLAPSE (Non-Homepage Only) ==== */
1958
1959/* Desktop: wrapper tidak mengganggu grid layout */
1960.ft-collapsible-content {
1961  display: contents;
1962}
1963
1964@media (max-width: 768px) {
1965  /* Wrapper untuk konten yang bisa collapse */
1966  .ft-top.ft-collapsible .ft-collapsible-content {
1967    display: block;
1968    max-height: 80px;
1969    overflow: hidden;
1970    position: relative;
1971    transition: max-height 0.4s cubic-bezier(0.4, 0, 0.2, 1);
1972  }
1973  
1974  /* Fade gradient overlay */
1975  .ft-top.ft-collapsible .ft-collapsible-content::after {
1976    content: '';
1977    position: absolute;
1978    bottom: 0;
1979    left: 0;
1980    right: 0;
1981    height: 70px;
1982    background: linear-gradient(to bottom, transparent 0%, rgba(6, 43, 69, 0.6) 40%, #062b45 100%);
1983    pointer-events: none;
1984    opacity: 1;
1985    transition: opacity 0.3s ease;
1986    z-index: 1;
1987  }
1988  
1989  /* State: Expanded */
1990  .ft-top.ft-collapsible.expanded .ft-collapsible-content {
1991    max-height: 1500px;
1992  }
1993  
1994  .ft-top.ft-collapsible.expanded .ft-collapsible-content::after {
1995    opacity: 0;
1996  }
1997  
1998  /* Expand Button - Di luar collapsible, selalu visible */
1999  .ft-expand-btn {
2000    display: flex;
2001    align-items: center;
2002    justify-content: center;
2003    gap: 8px;
2004    width: 100%;
2005    margin: -8px 0 0;
2006    padding: 12px 20px;
2007    background: rgba(255,255,255,0.12);
2008    border: 1px solid rgba(255,255,255,0.25);
2009    border-radius: 10px;
2010    color: #e5f2f7;
2011    font-size: 13.5px;
2012    font-weight: 500;
2013    cursor: pointer;
2014    transition: all 0.3s ease;
2015    outline: none;
2016    position: relative;
2017    z-index: 10;
2018  }
2019  
2020  .ft-expand-btn:hover {
2021    background: rgba(255,255,255,0.18);
2022    border-color: rgba(255,255,255,0.35);
2023    color: #fff;
2024    transform: translateY(-2px);
2025  }
2026  
2027  .ft-expand-btn:active {
2028    transform: scale(0.98);
2029  }
2030  
2031  .ft-expand-btn svg {
2032    width: 18px;
2033    height: 18px;
2034    transition: transform 0.3s ease;
2035    fill: currentColor;
2036  }
2037  
2038  .ft-top.ft-collapsible.expanded .ft-expand-btn {
2039    margin-top: 15px;
2040  }
2041  
2042  .ft-top.ft-collapsible.expanded .ft-expand-btn svg {
2043    transform: rotate(180deg);
2044  }
2045}
2046
2047/* Desktop: hide expand button */
2048@media (min-width: 769px) {
2049  .ft-expand-btn {
2050    display: none !important;
2051  }
2052}
2053
2054/* RESPONSIVE (jika background panel butuh penyesuaian) */
2055@media (max-width:640px){
2056  .site-footer.footer-compact.variant-glass .ft-grid {
2057    padding:26px 18px;
2058  }
2059}
2060
2061</style>
2062  <style data-inlined="bottom-nav.css">
2063/* Mobile Bottom Navigation */
2064.bottom-nav {
2065  position: fixed;
2066  bottom: 0;
2067  left: 0;
2068  right: 0;
2069  background: #ffffff;
2070  border-top: 1px solid #e5e7eb;
2071  z-index: 9998; /* Below chat widget */
2072  box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.05);
2073  display: none; /* Hidden on desktop */
2074}
2075
2076.bottom-nav-inner {
2077  display: flex;
2078  justify-content: space-around;
2079  align-items: center;
2080  padding: 2px 0;
2081  max-width: 640px;
2082  margin: 0 auto;
2083}
2084
2085.bottom-nav-item {
2086  flex: 1;
2087  display: flex;
2088  flex-direction: column;
2089  align-items: center;
2090  justify-content: center;
2091  gap: 4px;
2092  padding: 8px 8px;
2093  background: none;
2094  border: none;
2095  cursor: pointer;
2096  text-decoration: none;
2097  color: #6b7280;
2098  transition: all 0.3s ease;
2099  position: relative;
2100}
2101
2102.bottom-nav-item:hover {
2103  color: #C77DFF;
2104}
2105
2106.bottom-nav-item.active {
2107  flex-direction: row;
2108  gap: 8px;
2109  background: linear-gradient(135deg, #C77DFF 0%, #E3D05A 100%);
2110  color: white;
2111  border-radius: 20px;
2112  padding: 8px 16px;
2113  box-shadow: 0 2px 8px rgba(245,202,86,0.3);
2114}
2115
2116.bottom-nav-item-icon {
2117  width: 24px;
2118  height: 24px;
2119  position: relative;
2120}
2121
2122.bottom-nav-item-icon svg {
2123  width: 100%;
2124  height: 100%;
2125}
2126
2127/* Icon variant switching */
2128.bottom-nav-item .icon-outlined {
2129  display: block;
2130}
2131
2132.bottom-nav-item .icon-filled {
2133  display: none;
2134}
2135
2136.bottom-nav-item.active .icon-outlined {
2137  display: none;
2138}
2139
2140.bottom-nav-item.active .icon-filled {
2141  display: block;
2142}
2143
2144.bottom-nav-item-label {
2145  font-size: 12px;
2146  font-weight: 600;
2147  line-height: 1;
2148  display: none;
2149  white-space: nowrap;
2150}
2151
2152.bottom-nav-item.active .bottom-nav-item-label {
2153  display: block;
2154}
2155
2156/* Avatar styles for bottom-nav */
2157.bottom-nav-avatar-img,
2158.bottom-nav-avatar-initials {
2159  width: 24px;
2160  height: 24px;
2161  border-radius: 50%;
2162  display: block;
2163}
2164
2165.bottom-nav-avatar-img {
2166  object-fit: cover;
2167}
2168
2169.bottom-nav-avatar-initials {
2170  background: linear-gradient(135deg, #E3D05A 0%, #C77DFF 100%);
2171  color: white;
2172  font-size: 10px;
2173  font-weight: 700;
2174  display: flex;
2175  align-items: center;
2176  justify-content: center;
2177  line-height: 1;
2178  letter-spacing: 0.5px;
2179}
2180
2181/* Hide SVG when avatar is shown */
2182.bottom-nav-item-icon:has(.bottom-nav-avatar-img) .bottom-nav-svg-icon,
2183.bottom-nav-item-icon:has(.bottom-nav-avatar-initials) .bottom-nav-svg-icon {
2184  display: none;
2185}
2186
2187/* Active state adjustments for avatar */
2188.bottom-nav-item.active .bottom-nav-avatar-initials {
2189  background: white;
2190  color: #C77DFF;
2191  border: 2px solid rgba(255, 255, 255, 0.8);
2192  box-sizing: border-box;
2193}
2194
2195.bottom-nav-item.active .bottom-nav-avatar-img {
2196  border: 2px solid rgba(255, 255, 255, 0.9);
2197  box-sizing: border-box;
2198}
2199
2200.bottom-nav-item-badge {
2201  position: absolute;
2202  top: -4px;
2203  right: -4px;
2204  background: #C77DFF;
2205  color: white;
2206  border-radius: 10px;
2207  padding: 2px 5px;
2208  font-size: 10px;
2209  font-weight: 600;
2210  min-width: 18px;
2211  height: 18px;
2212  display: flex;
2213  align-items: center;
2214  justify-content: center;
2215  line-height: 1;
2216}
2217
2218/* Show on mobile only */
2219@media (max-width: 640px) {
2220  .bottom-nav {
2221    display: block;
2222  }
2223  
2224  /* Add bottom padding to body to prevent content being hidden */
2225  body {
2226    padding-bottom: 60px;
2227  }
2228}
2229
2230/* Mobile User Sheet - Bottom Sheet for Profile Menu */
2231.mobile-user-sheet {
2232  position: fixed;
2233  bottom: 0;
2234  left: 0;
2235  right: 0;
2236  z-index: 10000;
2237  pointer-events: none;
2238}
2239
2240.mobile-user-sheet:not([hidden]) {
2241  pointer-events: auto;
2242}
2243
2244.mobile-user-sheet-backdrop {
2245  position: fixed;
2246  inset: 0;
2247  background: rgba(0, 0, 0, 0.5);
2248  opacity: 0;
2249  transition: opacity 0.2s ease-out;
2250}
2251
2252.mobile-user-sheet.active .mobile-user-sheet-backdrop {
2253  opacity: 1;
2254}
2255
2256.mobile-user-sheet-content {
2257  position: absolute;
2258  bottom: 0;
2259  left: 0;
2260  right: 0;
2261  background: white;
2262  border-radius: 16px 16px 0 0;
2263  max-height: 80vh;
2264  overflow-y: auto;
2265  transform: translateY(100%);
2266  transition: transform 0.3s ease-out;
2267}
2268
2269.mobile-user-sheet.active .mobile-user-sheet-content {
2270  transform: translateY(0);
2271}
2272
2273.mobile-user-sheet-handle {
2274  width: 40px;
2275  height: 4px;
2276  background: #d1d5db;
2277  border-radius: 2px;
2278  margin: 12px auto 16px;
2279}
2280
2281.mobile-user-sheet-header {
2282  padding: 0 20px 16px;
2283  border-bottom: 1px solid #e5e7eb;
2284}
2285
2286.mobile-user-info {
2287  display: flex;
2288  align-items: center;
2289  gap: 12px;
2290}
2291
2292.mobile-user-avatar {
2293  width: 48px;
2294  height: 48px;
2295  background: linear-gradient(135deg, #764EAC 0%, #fff1cc 50%, #C77DFF 100%);
2296  border-radius: 50%;
2297  display: flex;
2298  align-items: center;
2299  justify-content: center;
2300  font-size: 24px;
2301  color: #C77DFF;
2302  font-weight: 600;
2303}
2304
2305.mobile-user-details {
2306  flex: 1;
2307}
2308
2309.mobile-user-name {
2310  font-weight: 600;
2311  font-size: 16px;
2312  color: #1f2937;
2313  margin-bottom: 4px;
2314}
2315
2316.mobile-user-email {
2317  font-size: 13px;
2318  color: #6b7280;
2319}
2320
2321.mobile-user-sheet-body {
2322  padding: 8px 0;
2323}
2324
2325.mobile-user-sheet-item {
2326  display: flex;
2327  align-items: center;
2328  gap: 12px;
2329  padding: 14px 20px;
2330  background: none;
2331  border: none;
2332  width: 100%;
2333  text-align: left;
2334  cursor: pointer;
2335  text-decoration: none;
2336  color: #374151;
2337  transition: background 0.2s;
2338}
2339
2340.mobile-user-sheet-item:hover {
2341  background: #f9fafb;
2342}
2343
2344.mobile-user-sheet-icon {
2345  font-size: 20px;
2346  width: 24px;
2347  text-align: center;
2348}
2349
2350.mobile-user-sheet-label {
2351  font-size: 15px;
2352  font-weight: 500;
2353}
2354
2355.mobile-user-sheet-divider {
2356  height: 1px;
2357  background: #e5e7eb;
2358  margin: 8px 0;
2359}
2360
2361@keyframes fadeIn {
2362  from {
2363    opacity: 0;
2364  }
2365  to {
2366    opacity: 1;
2367  }
2368}
2369
2370@keyframes slideUp {
2371  from {
2372    transform: translateY(100%);
2373  }
2374  to {
2375    transform: translateY(0);
2376  }
2377}
2378
2379/* Ensure chat widget works well with bottom nav */
2380@media (max-width: 640px) {
2381  .chat-widget {
2382    bottom: 0 !important; /* Chat opens from bottom */
2383  }
2384  
2385  .chat-popup {
2386    /* Chat popup should be above bottom nav */
2387    z-index: 9999;
2388  }
2389}
2390
2391</style>
2392  <style data-inlined="search-suggest.css">
2393.search { 
2394  position: relative; 
2395}
2396
2397/* AI Bot Toggle Button */
2398.ai-bot-toggle {
2399  display: flex;
2400  align-items: center;
2401  justify-content: center;
2402  background: transparent;
2403  border: none;
2404  padding: 8px;
2405  cursor: pointer;
2406  border-radius: 8px;
2407  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
2408  margin-left: 4px;
2409  flex-shrink: 0;
2410  display: none;
2411}
2412
2413.ai-bot-toggle .bot-icon {
2414  color: #9ca3af;
2415  transition: all 0.3s ease;
2416}
2417
2418.ai-bot-toggle:hover .bot-icon {
2419  color: #6b7280;
2420  transform: scale(1.1);
2421}
2422
2423.ai-bot-toggle.active .bot-icon {
2424  color: #C77DFF;
2425  animation: botPulse 2s ease-in-out infinite;
2426}
2427
2428.ai-bot-toggle.active {
2429  background: rgba(245,202,86,0.1);
2430}
2431
2432.ai-bot-toggle.active:hover .bot-icon {
2433  color: #C77DFF;
2434}
2435
2436@keyframes botPulse {
2437  0%, 100% { transform: scale(1); }
2438  50% { transform: scale(1.12); }
2439}
2440
2441/* Search Suggest Box */
2442.search-suggest {
2443  position: absolute;
2444  top: 100%; left: 0; right: 0;
2445  background: #fff;
2446  border: 1px solid #e1e4e8;
2447  border-top: none;
2448  box-shadow: 0 4px 12px rgba(0,0,0,0.08);
2449  max-height: 400px;
2450  overflow-y: auto;
2451  z-index: 100;
2452  padding: 0;
2453  font-size: 14px;
2454  border-radius: 0 0 8px 8px;
2455}
2456
2457.suggest-item {
2458  display: flex;
2459  align-items: center;
2460  gap: 8px;
2461  padding: 10px 16px;
2462  cursor: pointer;
2463  transition: all 0.2s ease;
2464  border-bottom: 1px solid #f1f5f9;
2465}
2466
2467.suggest-item:last-child {
2468  border-bottom: none;
2469}
2470
2471.suggest-item:hover,
2472.suggest-item.active {
2473  background: linear-gradient(90deg, #f8fafc 0%, #f1f5f9 100%);
2474  padding-left: 20px;
2475}
2476
2477.suggest-thumb {
2478  width: 42px;
2479  height: 42px;
2480  object-fit: cover;
2481  border: 1px solid #ddd;
2482  border-radius: 4px;
2483  background: #fafafa;
2484}
2485
2486.suggest-meta { flex: 1; min-width: 0; }
2487
2488.suggest-name {
2489  font-weight: 500;
2490  color: #222;
2491  line-height: 1.2;
2492  white-space: nowrap;
2493  overflow: hidden;
2494  text-overflow: ellipsis;
2495}
2496
2497.suggest-price {
2498  color: #C77DFF;
2499  font-size: 12px;
2500  margin-top: 2px;
2501}
2502
2503/* AI Insights */
2504.suggest-ai-insight {
2505  display: flex;
2506  align-items: center;
2507  gap: 8px;
2508  padding: 8px 12px;
2509  background: linear-gradient(135deg, #f0f9ff 0%, #e0f2fe 100%);
2510  border-bottom: 1px solid #bae6fd;
2511  color: #0369a1;
2512  font-size: 12px;
2513  font-weight: 500;
2514  line-height: 1.4;
2515}
2516
2517.suggest-ai-insight svg {
2518  flex-shrink: 0;
2519  opacity: 0.8;
2520}
2521
2522.suggest-ai-insight span {
2523  flex: 1;
2524}
2525
2526/* AI Progress States */
2527.ai-progress-container {
2528  padding: 20px 16px;
2529  background: linear-gradient(135deg, #fafbff 0%, #f5f7ff 100%);
2530}
2531
2532.ai-progress-header {
2533  display: flex;
2534  align-items: center;
2535  gap: 10px;
2536  margin-bottom: 16px;
2537}
2538
2539.ai-progress-icon {
2540  width: 36px;
2541  height: 36px;
2542  display: flex;
2543  align-items: center;
2544  justify-content: center;
2545  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
2546  border-radius: 50%;
2547  color: #fff;
2548  font-size: 18px;
2549  animation: aiIconSpin 3s linear infinite;
2550}
2551
2552@keyframes aiIconSpin {
2553  0% { transform: rotate(0deg); }
2554  100% { transform: rotate(360deg); }
2555}
2556
2557.ai-progress-text {
2558  flex: 1;
2559}
2560
2561.ai-progress-title {
2562  font-weight: 600;
2563  color: #1e293b;
2564  font-size: 14px;
2565  margin-bottom: 2px;
2566}
2567
2568.ai-progress-subtitle {
2569  font-size: 12px;
2570  color: #64748b;
2571}
2572
2573/* Progress Steps */
2574.ai-progress-steps {
2575  display: flex;
2576  flex-direction: column;
2577  gap: 10px;
2578  margin-top: 16px;
2579}
2580
2581.ai-progress-step {
2582  display: flex;
2583  align-items: center;
2584  gap: 10px;
2585  padding: 8px 12px;
2586  background: #fff;
2587  border-radius: 8px;
2588  border: 1px solid #e2e8f0;
2589  transition: all 0.3s ease;
2590}
2591
2592.ai-progress-step.active {
2593  border-color: #667eea;
2594  background: #f8f9ff;
2595  box-shadow: 0 2px 8px rgba(102, 126, 234, 0.1);
2596}
2597
2598.ai-progress-step.completed {
2599  border-color: #10b981;
2600  background: #f0fdf4;
2601}
2602
2603.ai-step-icon {
2604  width: 20px;
2605  height: 20px;
2606  display: flex;
2607  align-items: center;
2608  justify-content: center;
2609  border-radius: 50%;
2610  font-size: 11px;
2611  flex-shrink: 0;
2612}
2613
2614.ai-progress-step.active .ai-step-icon {
2615  background: #667eea;
2616  color: #fff;
2617  animation: pulse 1.5s ease-in-out infinite;
2618}
2619
2620.ai-progress-step.completed .ai-step-icon {
2621  background: #10b981;
2622  color: #fff;
2623}
2624
2625.ai-progress-step.pending .ai-step-icon {
2626  background: #e2e8f0;
2627  color: #94a3b8;
2628}
2629
2630.ai-step-text {
2631  flex: 1;
2632  font-size: 13px;
2633  color: #475569;
2634  font-weight: 500;
2635}
2636
2637.ai-progress-step.completed .ai-step-text {
2638  color: #059669;
2639}
2640
2641/* AI Analysis Result Banner */
2642.ai-result-banner {
2643  padding: 12px 16px;
2644  background: linear-gradient(135deg, #ecfdf5 0%, #d1fae5 100%);
2645  border-bottom: 1px solid #86efac;
2646  display: flex;
2647  align-items: center;
2648  gap: 10px;
2649}
2650
2651.ai-result-icon {
2652  font-size: 20px;
2653  animation: bounceIn 0.5s ease;
2654}
2655
2656@keyframes bounceIn {
2657  0% { transform: scale(0); opacity: 0; }
2658  50% { transform: scale(1.1); }
2659  100% { transform: scale(1); opacity: 1; }
2660}
2661
2662.ai-result-text {
2663  flex: 1;
2664}
2665
2666.ai-result-title {
2667  font-weight: 600;
2668  color: #065f46;
2669  font-size: 13px;
2670  margin-bottom: 2px;
2671}
2672
2673.ai-result-description {
2674  font-size: 12px;
2675  color: #047857;
2676  opacity: 0.9;
2677}
2678
2679/* Product Items Section Header */
2680.suggest-section-header {
2681  padding: 10px 16px;
2682  background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);
2683  border-bottom: 1px solid #e2e8f0;
2684}
2685
2686.suggest-header-main {
2687  display: flex;
2688  align-items: center;
2689  gap: 6px;
2690  margin-bottom: 4px;
2691}
2692
2693.suggest-header-icon {
2694  font-size: 14px;
2695}
2696
2697.suggest-header-text {
2698  font-size: 12px;
2699  font-weight: 600;
2700  color: #64748b;
2701  text-transform: uppercase;
2702  letter-spacing: 0.5px;
2703}
2704
2705.suggest-header-hint {
2706  font-size: 11px;
2707  color: #94a3b8;
2708  font-weight: 400;
2709  text-transform: none;
2710  letter-spacing: 0;
2711  display: flex;
2712  align-items: center;
2713  gap: 4px;
2714}
2715
2716.suggest-header-hint kbd {
2717  display: inline-block;
2718  padding: 2px 6px;
2719  font-size: 10px;
2720  font-weight: 600;
2721  line-height: 1;
2722  color: #475569;
2723  background: #fff;
2724  border: 1px solid #cbd5e1;
2725  border-radius: 4px;
2726  box-shadow: 0 1px 2px rgba(0,0,0,0.05);
2727  font-family: 'Segoe UI', monospace;
2728}
2729
2730/* Footer Hint */
2731.suggest-footer-hint {
2732  display: flex;
2733  align-items: center;
2734  justify-content: center;
2735  padding: 12px 16px;
2736  background: linear-gradient(135deg, #fef3c7 0%, #C77DFF 100%);
2737  border-top: 1px solid #C77DFF;
2738  color: #ae7e21;
2739  font-size: 12px;
2740  font-weight: 500;
2741  text-align: center;
2742  cursor: default;
2743}
2744
2745.suggest-footer-hint svg {
2746  color: #C77DFF;
2747  flex-shrink: 0;
2748}
2749
2750.suggest-footer-hint kbd {
2751  display: inline-block;
2752  padding: 3px 7px;
2753  margin: 0 3px;
2754  font-size: 11px;
2755  font-weight: 600;
2756  line-height: 1;
2757  color: #765212;
2758  background: #fff;
2759  border: 1px solid #C77DFF;
2760  border-radius: 4px;
2761  box-shadow: 0 1px 3px rgba(245,202,86,0.2);
2762  font-family: 'Segoe UI', monospace;
2763}
2764
2765.suggest-footer-link {
2766  color: #C77DFF;
2767  font-weight: 600;
2768  text-decoration: underline;
2769  text-underline-offset: 2px;
2770  text-decoration-thickness: 1px;
2771  cursor: pointer;
2772  transition: all 0.2s ease;
2773}
2774
2775.suggest-footer-link:hover {
2776  color: #E3D05A;
2777  text-decoration-thickness: 2px;
2778  text-shadow: 0 0 8px rgba(245,202,86,0.3);
2779}
2780
2781/* Loading state */
2782.suggest-loading {
2783  display: flex;
2784  align-items: center;
2785  justify-content: center;
2786  gap: 8px;
2787  padding: 16px 12px;
2788  color: #64748b;
2789  font-size: 13px;
2790}
2791
2792@keyframes pulse {
2793  0%, 100% { opacity: 1; }
2794  50% { opacity: 0.5; }
2795}
2796
2797.suggest-loading {
2798  animation: pulse 1.5s ease-in-out infinite;
2799}
2800
2801/* Responsive Mobile Styles */
2802@media (max-width: 768px) {
2803  .ai-bot-toggle {
2804    padding: 6px;
2805    margin-left: 0;
2806  }
2807  
2808  .ai-bot-toggle .bot-icon {
2809    width: 20px;
2810    height: 20px;
2811  }
2812  
2813  .search-icon-btn {
2814    margin-right: 4px;
2815  }
2816  
2817  .search-icon-btn svg {
2818    width: 18px;
2819    height: 18px;
2820  }
2821  
2822  .search-suggest {
2823    max-height: 350px;
2824  }
2825  
2826  /* Mobile hint adjustments */
2827  .suggest-header-hint {
2828    font-size: 10px;
2829  }
2830  
2831  .suggest-header-hint kbd {
2832    padding: 1px 4px;
2833    font-size: 9px;
2834  }
2835  
2836  .suggest-footer-hint {
2837    padding: 10px 12px;
2838    font-size: 11px;
2839  }
2840  
2841  .suggest-footer-hint svg {
2842    width: 14px;
2843    height: 14px;
2844  }
2845  
2846  .suggest-footer-hint kbd {
2847    padding: 2px 5px;
2848    font-size: 10px;
2849  }
2850  
2851  .ai-progress-container {
2852    padding: 16px 12px;
2853  }
2854  
2855  .ai-progress-icon {
2856    width: 32px;
2857    height: 32px;
2858    font-size: 16px;
2859  }
2860  
2861  .ai-progress-title {
2862    font-size: 13px;
2863  }
2864  
2865  .ai-progress-subtitle {
2866    font-size: 11px;
2867  }
2868  
2869  .ai-progress-step {
2870    padding: 6px 10px;
2871  }
2872  
2873  .ai-step-text {
2874    font-size: 12px;
2875  }
2876  
2877  .suggest-item {
2878    padding: 8px 12px;
2879  }
2880  
2881  .suggest-thumb {
2882    width: 36px;
2883    height: 36px;
2884  }
2885  
2886  .suggest-name {
2887    font-size: 13px;
2888  }
2889  
2890  .suggest-price {
2891    font-size: 11px;
2892  }
2893}
2894
2895@media (max-width: 480px) {
2896  .ai-bot-toggle {
2897    padding: 4px;
2898  }
2899  
2900  .ai-bot-toggle .bot-icon {
2901    width: 18px;
2902    height: 18px;
2903  }
2904  
2905  .search-icon-btn svg {
2906    width: 16px;
2907    height: 16px;
2908  }
2909  
2910  /* Ultra-compact hints for small screens */
2911  .suggest-header-hint {
2912    display: none; /* Hide header hint on very small screens */
2913  }
2914  
2915  .suggest-footer-hint {
2916    padding: 8px 10px;
2917    font-size: 10px;
2918    flex-direction: column;
2919    gap: 4px;
2920  }
2921  
2922  .suggest-footer-hint svg {
2923    display: none; /* Hide icon to save space */
2924  }
2925  
2926  .suggest-footer-hint kbd {
2927    padding: 2px 4px;
2928    font-size: 9px;
2929  }
2930  
2931  .ai-progress-steps {
2932    gap: 8px;
2933  }
2934  
2935  .ai-step-text {
2936    font-size: 11px;
2937  }
2938}
2939
2940/* AI Search Prompt Box */
2941.ai-search-prompt {
2942  padding: 24px;
2943  background: linear-gradient(135deg, #fff5f0 0%, #ffffff 100%);
2944}
2945
2946.ai-prompt-header {
2947  display: flex;
2948  align-items: center;
2949  gap: 12px;
2950  margin-bottom: 16px;
2951}
2952
2953.ai-prompt-icon {
2954  width: 48px;
2955  height: 48px;
2956  background: linear-gradient(135deg, #C77DFF 0%, #C77DFF 100%);
2957  border-radius: 12px;
2958  display: flex;
2959  align-items: center;
2960  justify-content: center;
2961  font-size: 24px;
2962  box-shadow: 0 4px 12px rgba(245,202,86,0.3);
2963}
2964
2965.ai-prompt-text {
2966  flex: 1;
2967}
2968
2969.ai-prompt-title {
2970  font-size: 16px;
2971  font-weight: 700;
2972  color: #1f2937;
2973  margin-bottom: 4px;
2974}
2975
2976.ai-prompt-subtitle {
2977  font-size: 13px;
2978  color: #6b7280;
2979}
2980
2981.ai-prompt-query {
2982  background: white;
2983  border: 2px solid #C77DFF;
2984  border-radius: 8px;
2985  padding: 12px 16px;
2986  margin-bottom: 16px;
2987}
2988
2989.ai-query-label {
2990  font-size: 11px;
2991  font-weight: 600;
2992  color: #C77DFF;
2993  text-transform: uppercase;
2994  letter-spacing: 0.5px;
2995  margin-bottom: 4px;
2996}
2997
2998.ai-query-text {
2999  font-size: 15px;
3000  font-weight: 600;
3001  color: #1f2937;
3002}
3003
3004.ai-search-trigger-btn {
3005  width: 100%;
3006  padding: 14px 20px;
3007  background: linear-gradient(135deg, #C77DFF 0%, #C77DFF 100%);
3008  color: white;
3009  border: none;
3010  border-radius: 10px;
3011  font-size: 15px;
3012  font-weight: 700;
3013  cursor: pointer;
3014  display: flex;
3015  align-items: center;
3016  justify-content: center;
3017  gap: 8px;
3018  transition: all 0.3s ease;
3019  box-shadow: 0 4px 12px rgba(245,202,86,0.4);
3020}
3021
3022.ai-search-trigger-btn:hover {
3023  transform: translateY(-2px);
3024  box-shadow: 0 6px 20px rgba(245,202,86,0.5);
3025}
3026
3027.ai-search-trigger-btn:active {
3028  transform: translateY(0);
3029}
3030
3031.ai-btn-icon {
3032  font-size: 18px;
3033  animation: sparkle 2s ease-in-out infinite;
3034}
3035
3036@keyframes sparkle {
3037  0%, 100% { opacity: 1; transform: scale(1); }
3038  50% { opacity: 0.7; transform: scale(1.2); }
3039}
3040
3041.ai-btn-text {
3042  font-size: 15px;
3043}
3044
3045.ai-prompt-footer {
3046  margin-top: 12px;
3047  text-align: center;
3048  font-size: 12px;
3049  color: #9ca3af;
3050  font-style: italic;
3051}
3052
3053/* ==================== TRENDING SEARCH STYLES ==================== */
3054
3055.search-suggest.trending-mode {
3056  border-top: 3px solid #C77DFF;
3057  max-width: 900px;
3058  min-width: 600px;
3059}
3060
3061/* Two-column container */
3062.trending-container {
3063  display: flex;
3064  gap: 0;
3065  padding: 0 !important;
3066}
3067
3068.trending-column {
3069  flex: 1;
3070  min-width: 0;
3071  padding: 0 !important;
3072}
3073
3074.trending-column.trending-searches {
3075  border-right: 2px solid #e2e8f0; padding: 0 !important;
3076}
3077
3078/* Mobile: stack columns vertically */
3079@media (max-width: 768px) {
3080  .search-suggest.trending-mode {
3081    min-width: auto;
3082    max-width: 100%;
3083  }
3084  
3085  .trending-container {
3086    flex-direction: column;
3087  }
3088  
3089  .trending-column.trending-searches {
3090    border-right: none;
3091    border-bottom: 2px solid #e2e8f0;
3092  }
3093}
3094
3095.trending-header {
3096  display: flex;
3097  align-items: center;
3098  gap: 8px;
3099  padding: 14px 16px;
3100  border-bottom: 1px solid #e2e8f0;
3101  background: linear-gradient(135deg, #C77DFF 0%, #C77DFF 100%);
3102  color: white;
3103  position: sticky;
3104  top: 0;
3105  z-index: 10;
3106}
3107
3108.trending-icon {
3109  font-size: 20px;
3110  animation: trendingPulse 2s infinite;
3111}
3112
3113@keyframes trendingPulse {
3114  0%, 100% { 
3115    transform: scale(1); 
3116    filter: drop-shadow(0 0 0 rgba(245,202,86,0));
3117  }
3118  50% { 
3119    transform: scale(1.15); 
3120    filter: drop-shadow(0 0 8px rgba(255, 255, 255, 0.8));
3121  }
3122}
3123
3124.trending-title {
3125  font-weight: 700;
3126  font-size: 14px;
3127  letter-spacing: 0.3px;
3128}
3129
3130.trending-subtitle {
3131  font-size: 11px;
3132  opacity: 0.9;
3133  margin-left: auto;
3134  font-style: italic;
3135}
3136
3137/* Trending searches item */
3138.trending-item {
3139  display: flex;
3140  align-items: center;
3141  gap: 12px;
3142  padding: 12px 16px;
3143  cursor: pointer;
3144  transition: all 0.2s ease;
3145  border-bottom: 1px solid #f1f5f9;
3146  position: relative;
3147}
3148
3149.trending-item:hover {
3150  background: linear-gradient(90deg, #fff7ed 0%, #ffedd5 100%);
3151  padding-left: 20px;
3152}
3153
3154.trending-item:hover::before {
3155  content: '';
3156  position: absolute;
3157  left: 0;
3158  top: 0;
3159  bottom: 0;
3160  width: 4px;
3161  background: linear-gradient(180deg, #C77DFF 0%, #C77DFF 100%);
3162}
3163
3164.trending-item:last-child {
3165  border-bottom: none;
3166}
3167
3168.trending-rank {
3169  font-size: 20px;
3170  flex-shrink: 0;
3171  width: 32px;
3172  text-align: center;
3173}
3174
3175.trending-query {
3176  flex: 1;
3177  font-size: 14px;
3178  color: #1f2937;
3179  font-weight: 500;
3180  line-height: 1.4;
3181}
3182
3183.trending-category {
3184  font-size: 11px;
3185  color: #C77DFF;
3186  background: #fff7ed;
3187  padding: 3px 10px;
3188  border-radius: 12px;
3189  white-space: nowrap;
3190  font-weight: 500;
3191  border: 1px solid #fff1cc;
3192}
3193
3194/* Trending products item */
3195.trending-product-item {
3196  display: flex;
3197  align-items: center;
3198  gap: 12px;
3199  padding: 12px 16px;
3200  cursor: pointer;
3201  transition: all 0.2s ease;
3202  border-bottom: 1px solid #f1f5f9;
3203  position: relative;
3204}
3205
3206.trending-product-item:hover {
3207  background: linear-gradient(90deg, #fef3c7 0%, #C77DFF 100%);
3208  padding-left: 20px;
3209}
3210
3211.trending-product-item:hover::before {
3212  content: '';
3213  position: absolute;
3214  left: 0;
3215  top: 0;
3216  bottom: 0;
3217  width: 4px;
3218  background: linear-gradient(180deg, #C77DFF 0%, #C77DFF 100%);
3219}
3220
3221.trending-product-item:last-child {
3222  border-bottom: none;
3223}
3224
3225.trending-product-thumb {
3226  width: 48px;
3227  height: 48px;
3228  object-fit: cover;
3229  border-radius: 8px;
3230  border: 1px solid #e5e7eb;
3231  flex-shrink: 0;
3232  background: white;
3233}
3234
3235.trending-product-info {
3236  flex: 1;
3237  min-width: 0;
3238}
3239
3240.trending-product-name {
3241  font-size: 13px;
3242  font-weight: 400;
3243  color: #1f2937;
3244  line-height: 1.4;
3245  margin-bottom: 0;
3246  padding: 0 !important;
3247  overflow: hidden;
3248  text-overflow: ellipsis;
3249  display: -webkit-box;
3250  -webkit-line-clamp: 2;
3251  -webkit-box-orient: vertical;
3252}
3253
3254.trending-product-price {
3255  font-size: 12px;
3256  font-weight: 700;
3257  color: #C77DFF;
3258  padding: 4px 0 !important;
3259}
3260.trending-product { padding: 0;}
3261/* ==================== END TRENDING STYLES ==================== */
3262
3263</style>
3264  <style data-inlined="product-detail.css">
3265/* === PRODUCT DETAIL v3 (Tokopedia-like) — Full stylesheet === */
3266
3267/* Root / Container */
3268.product-single {
3269  --pd-gap: 2rem;
3270  --pd-border: #e2e8f0;
3271  --pd-bg: #ffffff;
3272  --pd-muted: #64748b;
3273  --pd-dark: #0f172a;
3274  --pd-accent: #0d6efd; /* tema utama situs */
3275  --pd-radius: 12px;
3276  --pd-soft: #f8fafc;
3277  --pd-soft-border: #e5e7eb;
3278  --pd-danger: #C77DFF;
3279  --pd-success-bg: #dcfce7;
3280  --pd-success-text: #166534;
3281  --pd-danger-bg: #fee2e2;
3282  --pd-danger-text: #E3D05A;
3283  --pd-shadow: 0 6px 20px -10px rgba(0,0,0,.12);
3284  --pd-transition: .25s cubic-bezier(.4,.0,.2,1);
3285  max-width:1280px;
3286  margin-inline:auto;
3287}
3288
3289/* === Sticky Product Header Bar (muncul saat scroll) === */
3290.pd-sticky-header {
3291  position: fixed;
3292  top: 0;
3293  left: 0;
3294  right: 0;
3295  z-index: 998;
3296  background: rgba(255, 255, 255, 0.98);
3297  backdrop-filter: blur(12px);
3298  -webkit-backdrop-filter: blur(12px);
3299  border-bottom: 1px solid rgba(226, 232, 240, 0.8);
3300  box-shadow: 0 4px 16px -4px rgba(0, 0, 0, 0.08);
3301  transform: translateY(-100%);
3302  opacity: 0;
3303  transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1), 
3304              opacity 0.3s cubic-bezier(0.4, 0, 0.2, 1);
3305  pointer-events: none;
3306}
3307
3308.pd-sticky-header.visible {
3309  transform: translateY(0);
3310  opacity: 1;
3311  pointer-events: auto;
3312}
3313
3314.pd-sticky-header-container {
3315  max-width: 1280px;
3316  margin: 0 auto;
3317  padding: 12px 20px;
3318  display: flex;
3319  align-items: center;
3320  gap: 16px;
3321}
3322
3323.pd-sticky-thumb {
3324  width: 48px;
3325  height: 48px;
3326  flex-shrink: 0;
3327  border-radius: 8px;
3328  border: 1px solid #e2e8f0;
3329  overflow: hidden;
3330  background: #f8fafc;
3331}
3332
3333.pd-sticky-thumb img {
3334  width: 100%;
3335  height: 100%;
3336  object-fit: cover;
3337  display: block;
3338}
3339
3340.pd-sticky-info {
3341  flex: 1;
3342  min-width: 0;
3343  display: flex;
3344  flex-direction: column;
3345  gap: 4px;
3346}
3347
3348.pd-sticky-title {
3349  font-size: 0.9rem;
3350  font-weight: 600;
3351  color: #0f172a;
3352  line-height: 1.3;
3353  white-space: nowrap;
3354  overflow: hidden;
3355  text-overflow: ellipsis;
3356  margin: 0;
3357}
3358
3359.pd-sticky-price-row {
3360  display: flex;
3361  align-items: center;
3362  gap: 8px;
3363  flex-wrap: wrap;
3364}
3365
3366.pd-sticky-price {
3367  font-size: 1.1rem;
3368  font-weight: 700;
3369  color: #0d6efd;
3370  line-height: 1;
3371}
3372
3373.pd-sticky-price-original {
3374  font-size: 0.75rem;
3375  color: #94a3b8;
3376  text-decoration: line-through;
3377  line-height: 1;
3378}
3379
3380.pd-sticky-discount {
3381  background: #C77DFF;
3382  color: #fff;
3383  font-size: 0.65rem;
3384  font-weight: 600;
3385  padding: 2px 6px;
3386  border-radius: 4px;
3387  letter-spacing: 0.3px;
3388  line-height: 1;
3389}
3390
3391.pd-sticky-actions {
3392  display: flex;
3393  gap: 8px;
3394  flex-shrink: 0;
3395  align-items: center;
3396}
3397
3398.pd-sticky-share-btn {
3399  padding: 8px 16px;
3400  border-radius: 8px;
3401  border: 1px solid #e2e8f0;
3402  background: #fff;
3403  color: #64748b;
3404  cursor: pointer;
3405  transition: all 0.2s ease;
3406  display: inline-flex;
3407  align-items: center;
3408  justify-content: center;
3409  flex-shrink: 0;
3410}
3411
3412.pd-sticky-share-btn:hover {
3413  background: #f8fafc;
3414  border-color: #cbd5e1;
3415  color: #0f172a;
3416  transform: translateY(-1px);
3417}
3418
3419.pd-sticky-share-btn:active {
3420  transform: translateY(0);
3421}
3422
3423.pd-sticky-share-btn svg {
3424  display: block;
3425  width: 16px;
3426  height: 16px;
3427}
3428
3429.pd-sticky-btn-chat svg {
3430  width: 16px !important;
3431  height: 16px !important;
3432  max-width: none !important;
3433  margin-right: 4px;
3434  flex-shrink: 0;
3435}
3436
3437.pd-sticky-btn {
3438  padding: 8px 16px;
3439  border-radius: 8px;
3440  font-size: 0.85rem;
3441  font-weight: 600;
3442  cursor: pointer;
3443  transition: all 0.2s ease;
3444  border: 0;
3445  display: inline-flex;
3446  align-items: center;
3447  justify-content: center;
3448  white-space: nowrap;
3449}
3450
3451.pd-sticky-btn-cart {
3452  background: #fff;
3453  color: #0d6efd;
3454  border: 1px solid #0d6efd;
3455}
3456
3457.pd-sticky-btn-cart:hover {
3458  background: rgba(13, 110, 253, 0.06);
3459}
3460
3461.pd-sticky-btn-chat {
3462  background: #fff;
3463  color: #64748b;
3464  border: 1px solid #cbd5e1;
3465  flex: 0.8;
3466}
3467
3468.pd-sticky-btn-chat:hover {
3469  background: #f8fafc;
3470  border-color: #94a3b8;
3471  color: #475569;
3472}
3473
3474.pd-sticky-btn-buy {
3475  background: #0d6efd;
3476  color: #fff;
3477  border: 1px solid #0d6efd;
3478  box-shadow: 0 2px 8px -2px rgba(13, 110, 253, 0.4);
3479}
3480
3481.pd-sticky-btn-buy:hover {
3482  filter: brightness(0.95);
3483}
3484
3485.pd-sticky-btn:disabled {
3486  opacity: 0.5;
3487  cursor: not-allowed;
3488}
3489
3490/* Hide on mobile (use existing FAB instead) */
3491@media (max-width: 880px) {
3492  .pd-sticky-header {
3493    display: none;
3494  }
3495}
3496
3497/* === PRINT STYLES (for PDF Export) === */
3498@media print {
3499  /* Reset & Base */
3500  * {
3501    -webkit-print-color-adjust: exact !important;
3502    print-color-adjust: exact !important;
3503  }
3504  
3505  body {
3506    background: white !important;
3507    margin: 0;
3508    padding: 0;
3509  }
3510  
3511  /* Hide all navigation, buttons, and interactive elements */
3512  nav, header, footer,
3513  nav *, header *, footer *,
3514  .navbar, .navbar *,
3515  .nav-item, .nav-link,
3516  .pd-sticky-header,
3517  .pd-sticky-header.visible,
3518  .pd-breadcrumb,
3519  .pd-sidebar,
3520  .pd-mobile-fab,
3521  .pd-share-btn,
3522  .pd-sticky-share-btn,
3523  #pd-share-btn,
3524  .share-button,
3525  [data-share-btn],
3526  button,
3527  .btn-add-cart,
3528  .btn-buy,
3529  .pd-actions,
3530  .pd-compare-section,
3531  .pd-compare-btn,
3532  .pd-compare-info,
3533  #pd-compare-btn,
3534  .compare-note,
3535  .compare-container,
3536  .compare-dropdown,
3537  .compare-panel,
3538  .compare-wrapper,
3539  [data-compare],
3540  [id*="compare"],
3541  [class*="compare"],
3542  .pd-thumb-gallery,
3543  .pd-installment-card,
3544  .pd-installment-card2,
3545  .inst-alt-banner--compact,
3546  .qoala-banner-card,
3547  .tradein-compact-card,
3548  .pwp-deals-section,
3549  #pwp-deals-section,
3550  .pwp-trigger-badge,
3551  .pd-related-full,
3552  #pd-similar,
3553  .pd-similar-strip,
3554  .pd-scroll-top,
3555  .stock-info-btn,
3556  .stock-popover,
3557  .pd-countdown-modern,
3558  .pd-share-modal-overlay,
3559  [id*="promo-"],
3560  .bottom-nav,
3561  .pd-buy-form,
3562  .pd-buy-card,
3563  .pd-extra-meta,
3564  .pd-reviews-section,
3565  #reviews,
3566  hr,
3567  .divider,
3568  .separator {
3569    display: none !important;
3570    visibility: hidden !important;
3571    opacity: 0 !important;
3572    height: 0 !important;
3573    max-height: 0 !important;
3574    overflow: hidden !important;
3575    margin: 0 !important;
3576    padding: 0 !important;
3577    border: none !important;
3578  }
3579  
3580  /* Extra aggressive reset for any remaining borders */
3581  .pd-info-card *,
3582  .pd-meta-inline *,
3583  .pd-variants * {
3584    border: none !important;
3585    border-top: none !important;
3586    border-bottom: none !important;
3587  }
3588  
3589  /* Layout restructure */
3590  .product-single {
3591    max-width: 100% !important;
3592    margin: 0 !important;
3593    padding: 0 !important;
3594    box-shadow: none !important;
3595  }
3596  
3597  /* Reset all shadows and borders for print */
3598  * {
3599    box-shadow: none !important;
3600  }
3601  
3602  .pd-top-layout {
3603    display: grid !important;
3604    grid-template-columns: 280px 1fr !important;
3605    gap: 24px !important;
3606    margin: 0 0 24px 0 !important;
3607    padding: 0 !important;
3608    page-break-inside: avoid;
3609    align-items: start !important;
3610  }
3611  
3612  /* Print header with logo - centered and larger */
3613  .product-single::before {
3614    content: "" !important;
3615    display: block !important;
3616    width: 150px !important;
3617    height: 50px !important;
3618    background: url('/assets/img/logo.png') no-repeat center !important;
3619    background-size: contain !important;
3620    margin: 0 auto 20px !important;
3621    visibility: visible !important;
3622    opacity: 1 !important;
3623  }
3624  
3625  /* Media card - left column */
3626  .pd-media-card {
3627    border: none !important;
3628    padding: 0 !important;
3629    margin: 0 !important;
3630    text-align: center;
3631    page-break-inside: avoid;
3632  }
3633  
3634  /* Hide desktop image, use mobile slider for both desktop and mobile */
3635  .pd-main-image {
3636    display: none !important;
3637  }
3638  
3639  /* Mobile slider - show first image only in print */
3640  .pd-mobile-slider {
3641    display: block !important;
3642    overflow: visible !important;
3643  }
3644  
3645  .pd-mslide {
3646    display: none !important;
3647  }
3648  
3649  .pd-mslide:first-child {
3650    display: block !important;
3651    border: 1px solid #e2e8f0 !important;
3652    max-width: 280px !important;
3653    margin: 0 auto !important;
3654    border-radius: 8px !important;
3655  }
3656  
3657  .pd-mslide:first-child img {
3658    max-height: 280px !important;
3659    width: 100% !important;
3660    height: auto !important;
3661    object-fit: contain !important;
3662  }
3663  
3664  /* Info card - right column */
3665  .pd-info-card {
3666    border: none !important;
3667    border-top: none !important;
3668    border-bottom: none !important;
3669    padding: 0 !important;
3670    margin: 0 !important;
3671    background: white !important;
3672    box-shadow: none !important;
3673  }
3674  
3675  /* Title */
3676  .pd-title-row {
3677    display: block !important;
3678    margin-bottom: 10px !important;
3679    border: none !important;
3680    border-top: none !important;
3681    border-bottom: none !important;
3682    padding: 0 !important;
3683    box-shadow: none !important;
3684    text-decoration: none !important;
3685  }
3686  
3687  /* Hide share button in print */
3688  .pd-title-row .pd-share-btn,
3689  .pd-title-row #pd-share-btn {
3690    display: none !important;
3691  }
3692  
3693  .pd-title {
3694    font-size: 13pt !important;
3695    color: #000 !important;
3696    margin: 0 0 10px 0 !important;
3697    page-break-after: avoid;
3698    font-weight: 700 !important;
3699    line-height: 1.3 !important;
3700    border: none !important;
3701    border-top: none !important;
3702    border-bottom: none !important;
3703    padding-bottom: 0 !important;
3704    box-shadow: none !important;
3705    text-decoration: none !important;
3706  }
3707  
3708  /* Price and QR container - side by side */
3709  .pd-price-qr-container {
3710    display: flex !important;
3711    gap: 16px !important;
3712    align-items: flex-start !important;
3713    margin-bottom: 14px !important;
3714    box-shadow: none !important;
3715    border: none !important;
3716    text-decoration: none !important;
3717  }
3718  
3719  /* Price block - left side */
3720  .pd-price-block {
3721    flex: 1 !important;
3722    margin: 0 !important;
3723    padding-bottom: 0 !important;
3724    border-bottom: none !important;
3725    box-shadow: none !important;
3726  }
3727  
3728  .pd-price-row {
3729    margin-bottom: 8px !important;
3730    border: none !important;
3731    border-top: none !important;
3732    border-bottom: none !important;
3733    padding: 0 !important;
3734  }
3735  
3736  /* Hide all empty or unnecessary elements in price row */
3737  .pd-price-row > span:empty,
3738  .pd-price-row > .sold-inline,
3739  #pd-sold-inline {
3740    display: none !important;
3741  }
3742  
3743  .pd-price-current {
3744    font-size: 18pt !important;
3745    color: #0d6efd !important;
3746  }
3747  
3748  /* Show price range for variant products in print */
3749  .pd-price-current[data-price-range]::after {
3750    content: attr(data-price-range) !important;
3751    display: block !important;
3752    font-size: 11pt !important;
3753    color: #64748b !important;
3754    margin-top: 4px !important;
3755    font-weight: normal !important;
3756  }
3757  
3758  /* Hide 'Range:' prefix text */
3759  .pd-price-current[data-price-range]::after {
3760    content: attr(data-price-range) !important;
3761  }
3762  
3763  .pd-price-original {
3764    font-size: 12pt !important;
3765    color: #64748b !important;
3766  }
3767  
3768  .pd-discount-badge {
3769    font-size: 10pt !important;
3770    padding: 2px 6px !important;
3771  }
3772  
3773  /* QR Code section - right side beside price */
3774  .pd-qr-print {
3775    display: block !important;
3776    flex: 0 0 100px !important;
3777    margin: 0 !important;
3778    padding: 8px !important;
3779    background: #f8fafc !important;
3780    border-radius: 8px !important;
3781    text-align: center !important;
3782    page-break-inside: avoid !important;
3783    border: 1px solid #cbd5e1 !important;
3784  }
3785  
3786  .pd-qr-label {
3787    font-size: 6.5pt !important;
3788    color: #64748b !important;
3789    margin-bottom: 5px !important;
3790    line-height: 1.2 !important;
3791    font-weight: 600 !important;
3792  }
3793  
3794  .pd-qr-image {
3795    width: 80px !important;
3796    height: 80px !important;
3797    display: block !important;
3798    margin: 0 auto !important;
3799  }
3800  
3801  /* Meta info */
3802  .pd-meta-inline {
3803    display: flex !important;
3804    gap: 12px !important;
3805    margin-bottom: 0 !important;
3806    padding-bottom: 14px !important;
3807    font-size: 10pt !important;
3808    border: none !important;
3809    border-top: none !important;
3810    border-bottom: none !important;
3811    padding-top: 0 !important;
3812    box-shadow: none !important;
3813    text-decoration: none !important;
3814    background: transparent !important;
3815  }
3816  
3817  /* Hide stock badge in print */
3818  .stock-badge,
3819  .stock-info-btn {
3820    display: none !important;
3821  }
3822  
3823  .sku {
3824    color: #64748b !important;
3825  }
3826  
3827  /* Hide sold badge if empty/zero */
3828  .sold-inline {
3829    display: none !important;
3830  }
3831  
3832  /* Hide variant summary section in print */
3833  .pd-variant-combined,
3834  #pd-variant-combined,
3835  .pd-variant-summary,
3836  [data-role="sold-chip"] {
3837    display: none !important;
3838  }
3839  
3840  /* Hide compare section completely in print */
3841  .pd-compare-section,
3842  .pd-compare-btn,
3843  #pd-compare-btn,
3844  .pd-compare-info,
3845  .compare-note,
3846  .compare-text,
3847  .compare-remove {
3848    display: none !important;
3849    visibility: hidden !important;
3850    height: 0 !important;
3851    margin: 0 !important;
3852    padding: 0 !important;
3853    overflow: hidden !important;
3854  }
3855  
3856  /* Variants - show all options with selected highlighted */
3857  .pd-variants {
3858    margin: 0 !important;
3859    padding: 0 !important;
3860    page-break-inside: avoid !important;
3861    border: none !important;
3862    border-top: none !important;
3863    border-bottom: none !important;
3864    box-shadow: none !important;
3865    background: transparent !important;
3866  }
3867  
3868  /* Add 'Variant:' label before variant groups */
3869  .pd-variants::before {
3870    content: "Variant:" !important;
3871    display: block !important;
3872    font-size: 11pt !important;
3873    font-weight: 700 !important;
3874    color: #0f172a !important;
3875    margin-bottom: 10px !important;
3876    border: none !important;
3877    padding: 0 !important;
3878    border-top: none !important;
3879    border-bottom: none !important;
3880  }
3881  
3882  .v-group {
3883    display: flex !important;
3884    align-items: center !important;
3885    gap: 8px !important;
3886    margin-bottom: 8px !important;
3887    line-height: 1 !important;
3888    page-break-inside: avoid !important;
3889    border: none !important;
3890    padding: 0 !important;
3891  }
3892  
3893  .v-group:last-child {
3894    margin-bottom: 0 !important;
3895  }
3896  
3897  .v-label {
3898    font-weight: 700 !important;
3899    margin: 0 !important;
3900    font-size: 9pt !important;
3901    color: #475569 !important;
3902    min-width: 60px !important;
3903    flex-shrink: 0 !important;
3904    border: none !important;
3905    padding: 0 !important;
3906  }
3907  
3908  .v-options {
3909    display: flex !important;
3910    gap: 6px !important;
3911    flex-wrap: wrap !important;
3912    border: none !important;
3913    padding: 0 !important;
3914    margin: 0 !important;
3915  }
3916  
3917  .v-chip {
3918    border: 1px solid #cbd5e1 !important;
3919    padding: 3px 10px !important;
3920    font-size: 9pt !important;
3921    background: #f8fafc !important;
3922    border-radius: 6px !important;
3923    display: inline-flex !important;
3924    align-items: center !important;
3925    page-break-inside: avoid !important;
3926  }
3927  
3928  /* Highlight selected variant with blue background */
3929  .v-chip.selected {
3930    background: #eff6ff !important;
3931    border-color: #2563eb !important;
3932    font-weight: 600 !important;
3933  }
3934  
3935  /* Hide radio inputs */
3936  .v-chip input[type="radio"] {
3937    display: none !important;
3938  }
3939  
3940  /* Hide "Habis" badge in print */
3941  .v-chip .chip-badge {
3942    display: none !important;
3943  }
3944  
3945  /* Short description - HIDDEN in print */
3946  .pd-short-desc {
3947    display: none !important;
3948  }
3949  
3950  /* QR Code section - right side beside price */
3951  .pd-qr-print {
3952    display: block !important;
3953    flex: 0 0 100px !important;
3954    margin: 0 !important;
3955    padding: 8px !important;
3956    background: #f8fafc !important;
3957    border-radius: 8px !important;
3958    text-align: center !important;
3959    page-break-inside: avoid !important;
3960    border: 1px solid #cbd5e1 !important;
3961  }
3962  
3963  .pd-qr-label {
3964    font-size: 6.5pt !important;
3965    color: #64748b !important;
3966    margin-bottom: 5px !important;
3967    line-height: 1.2 !important;
3968    font-weight: 600 !important;
3969  }
3970  
3971  .pd-qr-image {
3972    width: 80px !important;
3973    height: 80px !important;
3974    display: block !important;
3975    margin: 0 auto !important;
3976  }
3977  
3978  /* Full description - below 2 column layout */
3979  .pd-full-description {
3980    border: none !important;
3981    padding: 0 !important;
3982    margin: 24px 0 0 0 !important;
3983    page-break-before: avoid;
3984    grid-column: 1 / -1 !important;
3985  }
3986  
3987  .pd-full-desc-title {
3988    font-size: 13pt !important;
3989    font-weight: 700 !important;
3990    margin: 0 0 12px 0 !important;
3991    color: #000 !important;
3992    border-top: none !important;
3993    border-bottom: none !important;
3994    padding-top: 16px !important;
3995  }
3996  
3997  .pd-full-desc-body {
3998    font-size: 10pt !important;
3999    line-height: 1.6 !important;
4000    color: #334155 !important;
4001  }
4002  
4003  .pd-full-desc-body img {
4004    max-height: 200px !important;
4005    width: auto !important;
4006    page-break-inside: avoid;
4007    display: none !important; /* Hide images in print to save space */
4008  }
4009  
4010  /* Also target #deskripsi img if exists */
4011  #deskripsi img {
4012    max-width: 350px !important;
4013    height: auto !important;
4014  }
4015  
4016  .pd-full-desc-body table {
4017    border-collapse: collapse !important;
4018    width: 100% !important;
4019    margin: 12px 0 !important;
4020    font-size: 9pt !important;
4021  }
4022  
4023  .pd-full-desc-body th,
4024  .pd-full-desc-body td {
4025    border: 1px solid #cbd5e1 !important;
4026    padding: 6px 8px !important;
4027  }
4028  
4029  /* Print footer */
4030  .product-single::after {
4031    content: "Plaza IT - plazait.co.id | Printed: " attr(data-print-date);
4032    display: block;
4033    margin-top: 30px;
4034    padding-top: 16px;
4035    border-top: 1px solid #e2e8f0;
4036    font-size: 9pt;
4037    color: #64748b;
4038    text-align: center;
4039  }
4040  
4041  /* Page breaks */
4042  .pd-media-card,
4043  .pd-price-block,
4044  .pd-full-desc-title {
4045    page-break-after: avoid;
4046  }
4047  
4048  .pd-full-description {
4049    page-break-before: auto;
4050  }
4051}
4052
4053/* === Breadcrumb (truncate last item) === */
4054.pd-breadcrumb{
4055  display:flex;
4056  flex-wrap:nowrap;
4057  align-items:center;
4058  gap:.5rem;
4059  font-size:.72rem;
4060  margin:.7rem 0 1.2rem .5rem;
4061  color:var(--pd-muted);
4062  overflow:hidden;
4063}
4064.pd-breadcrumb a{color:var(--pd-accent);text-decoration:none}
4065.pd-breadcrumb a:hover{text-decoration:underline}
4066.pd-breadcrumb a,
4067.pd-breadcrumb span{flex:0 0 auto}
4068.pd-breadcrumb .current{
4069  flex:1 1 auto;
4070  min-width:0;
4071  white-space:nowrap;
4072  overflow:hidden;
4073  text-overflow:ellipsis;
4074  font-weight:600;
4075  color:var(--pd-dark);
4076  padding-right:2px;
4077}
4078
4079/* === Top layout === */
4080.pd-top-layout{
4081  display:grid;
4082  gap:var(--pd-gap);
4083  grid-template-columns:minmax(260px,340px) minmax(460px,1fr) 300px;
4084  align-items:start;
4085  margin-bottom:2.4rem;
4086}
4087
4088/* === Media column === */
4089.pd-media-card{
4090  background:#fff;
4091  border:1px solid var(--pd-border);
4092  border-radius:var(--pd-radius);
4093  padding:1rem 1rem 1.2rem;
4094}
4095.pd-main-image{margin:0 0 .8rem;border:1px solid var(--pd-soft-border);border-radius:10px;overflow:hidden;background:#fff;position:relative}
4096.pd-main-image img{width:100%;display:block;object-fit:contain;aspect-ratio:1/1}
4097
4098/* Gallery Thumbnails */
4099.pd-thumb-gallery{margin-top:.6rem;display:flex;flex-wrap:wrap;gap:.55rem}
4100.pd-thumb-btn{
4101  border:1px solid var(--pd-soft-border);
4102  background:#fff;
4103  cursor:pointer;
4104  width:64px;height:64px;padding:2px;
4105  display:flex;align-items:center;justify-content:center;
4106  overflow:hidden;border-radius:8px;
4107  transition:border-color .18s ease, box-shadow .18s ease, transform .18s ease;
4108  position:relative;
4109}
4110.pd-thumb-btn img{max-width:100%;max-height:100%;object-fit:contain;display:block}
4111.pd-thumb-btn:hover{border-color:var(--pd-accent)}
4112.pd-thumb-btn.active{border-color:var(--pd-accent);box-shadow:0 0 0 2px rgba(13,110,253,.25)}
4113.pd-thumb-btn:focus-visible{outline:2px solid var(--pd-accent);outline-offset:2px}
4114.pd-thumb-btn:active{transform:scale(.96)}
4115
4116/* === Info column === */
4117.pd-info-card{
4118  background:#fff;border:1px solid var(--pd-border);border-radius:var(--pd-radius);
4119  padding:1.4rem 1.6rem 2rem;
4120}
4121.pd-title{margin:0 0 1rem;font-size:1.2rem;line-height:1.25;font-weight:600;color:var(--pd-dark)}
4122.pd-price-block{margin:0 0 1rem}
4123.pd-price-row{display:flex;flex-wrap:wrap;align-items:center;gap:.75rem;margin:0 0 .35rem}
4124.pd-price-current{font-size:2rem;font-weight:700;color:var(--pd-accent)}
4125.pd-price-original{font-size:.9rem;text-decoration:line-through;color:#94a3b8}
4126.pd-discount-badge{background:var(--pd-danger);color:#fff;font-size:.68rem;padding:4px 8px 3px;font-weight:600;border-radius:6px;letter-spacing:.5px}
4127.pd-meta-inline{display:flex;flex-wrap:wrap;gap:.9rem;align-items:center;font-size:.63rem;letter-spacing:.6px;text-transform:uppercase;font-weight:600}
4128.stock-badge{padding:4px 10px;border-radius:24px;background:var(--pd-soft);color:var(--pd-muted);display:inline-block;line-height:1;vertical-align:middle}
4129.stock-badge.in{background:var(--pd-success-bg);color:var(--pd-success-text)}
4130.stock-badge.out{background:var(--pd-danger-bg);color:var(--pd-danger-text)}
4131.digital-badge{padding:4px 10px;border-radius:24px;background:linear-gradient(135deg,#C77DFF 0%,#764ba2 100%);color:#fff;font-size:.63rem;font-weight:600;letter-spacing:.6px;text-transform:uppercase;display:inline-block;line-height:1;vertical-align:middle;border:none}
4132.sku{color:var(--pd-muted)}
4133.pd-short-desc{font-size:.85rem;line-height:1.5;margin:0 0 1.2rem;color:#334155;overflow-wrap:anywhere}
4134.pd-short-desc p{margin:0 0 .75rem}
4135.pd-short-desc ul,.pd-short-desc ol{margin:.5rem 0 .9rem 1.1rem;font-size:.85rem;line-height:1.45}
4136
4137/* Meta row for sold and rating badges */
4138.pd-meta-row {
4139  display: flex;
4140  align-items: center;
4141  flex-wrap: wrap;
4142  gap: 5px;
4143  margin-top: 8px;
4144  margin-bottom: 4px;
4145}
4146
4147/* Sales (Terjual) badge inline */
4148.sold-inline{
4149  display:inline-block;font-size:.65rem;font-weight:600;color:#475569;
4150  background:#f1f5f9;padding:3px 8px 4px;border-radius:6px;letter-spacing:.4px;margin-left:0;
4151}
4152
4153/* Price row divider */
4154.price-divider {
4155  display: inline-block;
4156  margin: 0 .4rem;
4157  color: #cbd5e1;
4158  font-weight: 400;
4159}
4160
4161/* Rating badge inline */
4162.rating-inline {
4163  display: inline-flex;
4164  align-items: center;
4165  gap: 4px;
4166  padding: 3px 8px 4px;
4167  background: #fff7ed;
4168  border-radius: 6px;
4169  font-size: .65rem;
4170  font-weight: 600;
4171  color: #C77DFF;
4172  text-decoration: none;
4173  transition: all .2s ease;
4174  cursor: pointer;
4175  margin-left: .5rem;
4176  white-space: nowrap;
4177}
4178
4179.rating-inline:hover {
4180  background: #ffedd5;
4181  transform: translateY(-1px);
4182  box-shadow: 0 2px 4px rgba(245,202,86,0.1);
4183}
4184
4185.rating-inline .star-icon {
4186  font-size: .75rem;
4187  color: #C77DFF;
4188  line-height: 1;
4189}
4190
4191.rating-inline .rating-value {
4192  color: #C77DFF;
4193}
4194
4195.rating-inline .rating-badge-count {
4196  color: #E3D05A;
4197  opacity: 0.85;
4198}
4199
4200@media (max-width: 640px) {
4201  .rating-inline {
4202    font-size: .65rem;
4203    padding: 3px 8px 4px;
4204  }
4205  .rating-inline .star-icon {
4206    font-size: .7rem;
4207  }
4208}
4209
4210/* Highlight animation for review section */
4211@keyframes highlightFlash {
4212  0%, 100% { background-color: transparent; }
4213  50% { background-color: rgba(245,202,86,0.1); }
4214}
4215
4216.highlight-flash {
4217  animation: highlightFlash 1.5s ease;
4218}
4219
4220/* === Variant chips === */
4221.pd-variants{margin-top:14px}
4222.v-group{margin-bottom:12px}
4223.v-label{font-weight:600;margin-bottom:6px}
4224.v-options{display:flex;flex-wrap:wrap;gap:8px}
4225.v-chip{
4226  display:inline-flex;align-items:center;gap:8px;
4227  padding:6px 10px;border:1px solid #d6d9de;border-radius:999px;
4228  cursor:pointer;background:#fff;transition:.15s ease;user-select:none
4229}
4230.v-chip:hover{border-color:#9aa3af;box-shadow:0 1px 0 rgba(0,0,0,.04)}
4231.v-chip.selected{border-color:#2563eb;background:#eff6ff}
4232.v-chip.disabled{opacity:.45;cursor:not-allowed}
4233.v-chip.out{border-style:dashed}
4234.v-chip input{display:none}
4235.v-chip .dot{width:14px;
4235height:14px;border-radius:50%;background:var(--dot,#999);box-shadow:inset 0 0 0 1px rgba(0,0,0,.2)}
4236.v-chip .dot--neutral{background:#9aa3af}
4237.v-chip .txt{font-size:.95rem;white-space:nowrap}
4238.v-chip .chip-badge{margin-left:2px;font-size:.72rem;line-height:1;padding:3px 6px;border-radius:6px;background:#fee2e2;color:#E3D05A;border:1px solid #fecaca}
4239.pd-variant-summary{margin-top:8px;color:#475569;font-size:.92rem}
4240.pd-variant-summary .vs-item{display:inline-flex;gap:4px;margin-right:10px}
4241
4242/* === Buy form (di sidebar kanan untuk desktop) === */
4243.pd-buy-form{display:flex;flex-wrap:wrap;align-items:flex-end;gap:1rem 1.4rem;margin:0}
4244.qty-label{display:block;font-size:.6rem;font-weight:600;letter-spacing:.7px;text-transform:uppercase;color:var(--pd-muted);margin-bottom:.35rem}
4245.pd-buy-form input[type=number]{width:90px;padding:.55rem .6rem;border:1px solid var(--pd-soft-border);border-radius:6px;font-size:.85rem}
4246.pd-actions{display:flex;gap:.8rem;flex-wrap:wrap}
4247
4248/* Tombol senada tema */
4249.btn-add-cart,.btn-buy,.btn-chat-icon{
4250  cursor:pointer;border:0;font-weight:700;border-radius:10px;font-size:.9rem;
4251  display:inline-flex;align-items:center;justify-content:center;gap:.4rem;
4252  min-height:44px;padding:0 1rem;transition:var(--pd-transition)
4253}
4254.btn-add-cart{background:var(--brand-500);color:#fff;box-shadow:0 2px 8px -2px rgba(13,110,253,.35)}
4255.btn-add-cart:hover{filter:brightness(.95)}
4256.btn-buy{background:#fff;color:var(--brand-500);border:2px solid var(--brand-500)}
4257.btn-buy:hover{background:rgba(13,110,253,.06)}
4258.btn-chat-icon{background:#fff;color:#C77DFF;border:2px solid #C77DFF;padding:0;width:44px;min-width:44px}
4259.btn-chat-icon:hover{background:rgba(245,202,86,0.06);border-color:#C77DFF}
4260.btn-chat-icon svg{width:20px;height:20px;flex-shrink:0}
4261.btn-add-cart:disabled,.btn-buy:disabled,.btn-chat-icon:disabled{opacity:.5;cursor:not-allowed}
4262
4263/* Buy with Voucher Button - Cleaner, more compact design */
4264.btn-buy-voucher{
4265  cursor:pointer;border:0;font-weight:600;border-radius:10px;
4266  display:inline-flex;align-items:center;justify-content:space-between;gap:10px;
4267  min-height:44px;padding:0 14px 0 12px;transition:all 0.3s ease;
4268  background:linear-gradient(135deg, #7c3aed 0%, #9333ea 100%);
4269  color:#fff;
4270  box-shadow:0 3px 10px rgba(124,58,237,0.3);
4271  position:relative;
4272  overflow:hidden;
4273  flex:1 1 auto
4274}
4275.btn-buy-voucher:hover{
4276  transform:translateY(-2px);
4277  box-shadow:0 5px 16px rgba(124,58,237,0.4)
4278}
4279.btn-buy-voucher:active{
4280  transform:translateY(0);
4281  box-shadow:0 2px 6px rgba(124,58,237,0.3)
4282}
4283.btn-buy-voucher .bv-icon{
4284  font-size:20px;
4285  line-height:1;
4286  flex-shrink:0
4287}
4288.btn-buy-voucher .bv-text{
4289  display:flex;
4290  flex-direction:column;
4291  align-items:flex-start;
4292  gap:2px;
4293  flex:1;
4294  min-width:0;
4295  font-size:14px;
4296  line-height:1.2
4297}
4298.btn-buy-voucher .bv-text small{
4299  font-size:10px;
4300  opacity:0.85;
4301  font-weight:500;
4302  letter-spacing:0.3px;
4303  font-family:monospace
4304}
4305.btn-buy-voucher .bv-save{
4306  font-size:12px;
4307  font-weight:700;
4308  background:rgba(255,255,255,0.25);
4309  padding:4px 8px;
4310  border-radius:6px;
4311  white-space:nowrap;
4312  flex-shrink:0
4313}
4314
4315/* Extra meta (opsional) */
4316.pd-extra-meta{background:var(--pd-soft);border:1px solid var(--pd-border);border-radius:10px;padding:.85rem 1rem;display:grid;gap:.45rem;font-size:.7rem;line-height:1.3}
4317.pd-extra-meta span{font-weight:600;color:var(--pd-muted);margin-right:.3rem}
4318.pd-extra-meta a{color:var(--pd-accent);text-decoration:none}
4319.pd-extra-meta a:hover{text-decoration:underline}
4320
4321/* === Sidebar === */
4322.pd-sidebar{display:flex;flex-direction:column;gap:1.2rem}
4323.pd-side-card{background:#fff;border:1px solid var(--pd-border);border-radius:var(--pd-radius);padding:1rem 1.1rem 1.2rem}
4324.pd-side-card h3{margin:0 0 .7rem;font-size:.8rem;font-weight:700;letter-spacing:.6px;text-transform:uppercase;color:var(--pd-dark)}
4325.pd-side-card ul{list-style:none;margin:0;padding:0;display:grid;gap:.45rem;font-size:.7rem;color:#334155}
4326.pd-side-card li{position:relative;padding-left:13px;line-height:1.25}
4327.pd-side-card li:before{content:'';width:6px;height:6px;background:var(--pd-accent);border-radius:50%;position:absolute;
4327left:0;top:.45rem}
4328.pay-logos{display:flex;gap:.4rem;flex-wrap:wrap;margin:.1rem 0 .4rem}
4329.pay-logos span{font-size:.55rem;background:var(--pd-soft);border:1px solid var(--pd-soft-border);padding:.35rem .55rem;border-radius:6px;font-weight:600;letter-spacing:.5px}
4330
4331/* Buy card hanya desktop (mobile pakai FAB) */
4332.pd-buy-card{display:block}
4333@media (max-width:880px){ .pd-buy-card{display:none} .pd-title-row {padding-right: 0 !important;}}
4334
4335/* === Full Description === */
4336.pd-full-description{background:#fff;border:1px solid var(--pd-border);border-radius:var(--pd-radius);padding:1.6rem 1.9rem .6rem;margin:0 0 .8rem}
4337.pd-full-desc-title{margin:0 0 1.1rem;font-size:1.15rem;font-weight:600;color:var(--pd-dark)}
4338.pd-full-desc-body{font-size:.9rem;line-height:1.6;color:#334155;overflow-wrap:anywhere}
4339.pd-full-desc-body p{margin:0 0 1rem}
4340.pd-full-desc-body ul,.pd-full-desc-body ol{margin:.5rem 0 1rem 1.2rem}
4341.pd-full-desc-body table{width:100%;border-collapse:collapse;margin:1rem 0 1.2rem}
4342.pd-full-desc-body table,.pd-full-desc-body th,.pd-full-desc-body td{border-bottom:1px dotted #cbd5e1;vertical-align: top}
4343.pd-full-desc-body th,.pd-full-desc-body td{padding:.45rem .55rem;text-align:left}
4344.pd-full-desc-body img{max-width:100%;height:auto;display:block;}
4345
4346/* === Related (container) === */
4347.pd-related-full{
4348  background:#fff;border:1px solid var(--pd-border);
4349  border-radius:var(--pd-radius);padding:1.4rem 1.6rem 1.9rem;
4350  margin:0 0 2rem;
4351}
4352.pd-related-title{margin:0 0 1.1rem;font-size:1.05rem;font-weight:600;color:var(--pd-dark)}
4353
4354/* Related Grid (dirapikan: gabung selector agar tidak duplikat) */
4355.pd-related-grid,
4356.pd-related-grid--full{
4357  display:grid !important;
4358  gap:16px !important;
4359  grid-template-columns:repeat(auto-fill,minmax(170px,1fr)) !important;
4360  align-items:stretch;
4361}
4362
4363/* Fallback jika grid tidak didukung */
4364@supports not (display:grid){
4365  .pd-related-grid,
4366  .pd-related-grid--full{display:flex !important;flex-wrap:wrap}
4367  .pd-related-grid .pd-related-card,
4368  .pd-related-grid--full .pd-related-card{flex:0 0 calc(20% - 16px);max-width:calc(20% - 16px)}
4369  @media (max-width:1100px){
4370    .pd-related-grid .pd-related-card,
4371    .pd-related-grid--full .pd-related-card{flex:0 0 calc(25% - 16px);max-width:calc(25% - 16px)}
4372  }
4373  @media (max-width:820px){
4374    .pd-related-grid .pd-related-card,
4375    .pd-related-grid--full .pd-related-card{flex:0 0 calc(33.333% - 16px);max-width:calc(33.333% - 16px)}
4376  }
4377  @media (max-width:580px){
4378    .pd-related-grid .pd-related-card,
4379    .pd-related-grid--full .pd-related-card{flex:0 0 calc(50% - 16px);max-width:calc(50% - 16px)}
4380  }
4381}
4382
4383/* Related Card */
4384.pd-related-card{
4385  display:flex;flex-direction:column;border:1px solid var(--pd-soft-border);
4386  background:#fff;border-radius:10px;text-decoration:none;color:inherit;
4387  overflow:hidden;transition:var(--pd-transition);position:relative;min-width:0;
4388}
4389.pd-related-card:hover{transform:translateY(-4px);box-shadow:var(--pd-shadow)}
4390.pd-related-card .thumb{aspect-ratio:1/1;background:#f1f5f9;overflow:hidden;position:relative}
4391.pd-related-card img{width:100%;height:100%;object-fit:cover;display:block}
4392.mini-disc{position:absolute;top:6px;left:6px;background:#C77DFF;color:#fff;font-size:.55rem;padding:3px 6px 2px;border-radius:4px;font-weight:600}
4393.pd-related-card .info{padding:.55rem .65rem .75rem;display:flex;flex-direction:column;gap:.25rem}
4394.pd-related-card h3{font-size:.68rem;line-height:1.25;margin:0;height:2.5em;overflow:hidden;font-weight:600;color:#334155;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}
4395.pd-related-card .price{font-size:.7rem;font-weight:600;color:var(--pd-accent)}
4396.pd-related-card .sold{display:block;font-size:.6rem;font-weight:600;color:#475569;margin-top:2px;letter-spacing:.3px;background:#f1f5f9;padding:2px 6px 3px;border-radius:5px; width: max-content;}
4397.pd-related-card .price .final {font-size: .82rem; font-weight: 700; color: #0d6efd;}
4398.pd-related-card .price .ori {font-size: .6rem; text-decoration: line-through; color: #94a3b8;font-weight: 500;}
4399
4400/* === Mobile slider (scroll-snap) — gambar utama tetap tampil === */
4401.pd-mobile-slider{display:none}
4402.pd-mobile-slider img{width:100%;display:block;object-fit:contain;aspect-ratio:1/1}
4403
4404/* Gallery counter badge */
4405.pd-gallery-counter{
4406  position:absolute;
4407  bottom:12px;
4408  left:12px;
4409  background:rgba(255,255,255,0.25);
4410  color:#9E9E9E;
4411  padding:4px 10px;
4412  border-radius:10px;
4413  font-size:12px;
4414  font-weight:600;
4415  z-index:100;
4416  backdrop-filter:blur(6px);
4417  -webkit-backdrop-filter:blur(6px);
4418  font-variant-numeric:tabular-nums;
4419  pointer-events:none;
4420  display:none;
4421  box-shadow:0 1px 4px rgba(0,0,0,.15);
4422  line-height:1;
4423  border:1px solid rgba(0,0,0,0.08);
4424}
4425
4426@media (max-width:640px){
4427  .pd-media-card{border: 0;padding: 0 1rem 0;}
4428  .pd-info-card {border: 0; padding: 0 1.3rem 0; }
4429  .pd-side-card {flex: 1 1 !important;}
4430  .pd-top-layout {gap: 0; margin-bottom: 0;}
4431  .pd-variants {margin-bottom: 1.5rem;}
4432  .pd-main-image{display:none}
4433  .pd-gallery-counter{display:block}
4434  .pd-mobile-slider-wrapper{
4435    position:relative;
4436    margin-bottom:.6rem;
4437  }
4438  .pd-mobile-slider{
4439    display:flex;gap:8px;overflow-x:auto;
4440    scroll-snap-type:x mandatory;-webkit-overflow-scrolling:touch;
4441  }
4442  .pd-mslide{
4443    min-width:100%;flex:0 0 100%;scroll-snap-align:center;
4444    border:1px solid var(--pd-soft-border);border-radius:10px;overflow:hidden;background:#fff
4445  }
4446  .pd-thumb-gallery{display:none} /* hide thumbnails on mobile */
4447}
4448
4449/* === Mobile Floating Action Bar === */
4450.pd-mobile-fab{
4451  position:fixed;
4452  left:0;
4453  right:0;
4454  bottom:42px; /* Position above bottom-nav (60px min-height + 6px padding) */
4455  display:none;
4456  align-items:center;
4457  gap:.75rem;
4458  padding:12px 16px;
4459  background:rgba(255,255,255,0.95);
4460  backdrop-filter:blur(20px);
4461  -webkit-backdrop-filter:blur(20px);
4462  border-top:1px solid rgba(228,231,235,0.6);
4463  box-shadow:0 -4px 16px -4px rgba(0,0,0,0.12);
4464  z-index:999; /* Below bottom-nav (1000) */
4465  transition:bottom .3s cubic-bezier(0.4, 0.0, 0.2, 1);
4466}
4467
4468/* When bottom-nav is hidden, move FAB to bottom */
4469body:has(.bottom-nav.hidden) .pd-mobile-fab {
4470  bottom: 0;
4471}
4472.pd-mobile-fab .mf-actions{display:flex;gap:.5rem;width:100%}
4473.mf-btn{
4474  border-radius:10px;
4475  padding:.6rem 1rem;
4476  font-weight:600;
4477  font-size:14px;
4478  cursor:pointer;
4479  transition:all .2s;
4480  -webkit-tap-highlight-color:transparent;
4481  display:inline-flex;
4482  align-items:center;
4483  justify-content:center;
4484  gap:4px;
4485}
4486.mf-buy{
4487  background:#C77DFF;
4488  color:#fff;
4489  border:0;
4490  box-shadow:0 2px 8px rgba(245,202,86,0.3);
4491  flex:1;
4492  flex-direction:column;
4493  padding:.55rem 1rem;
4494  line-height:1;
4495  min-height:44px;
4496  font-family:inherit;
4497}
4498.mf-buy .mf-buy-text{
4499  font-size:11px;
4500  font-weight:600;
4501  opacity:0.95;
4502  font-family:inherit;
4503}
4504.mf-buy .mf-buy-price{
4505  font-size:13px;
4506  font-weight:800;
4507  letter-spacing:-0.3px;
4508  font-family:inherit;
4509  line-height:1;
4510}
4511.mf-buy:active{transform:scale(0.97)}
4512.mf-cart{
4513  background:#fff;
4514  color:#C77DFF;
4515  border:2px solid #C77DFF;
4516  width:44px;
4517  height:44px;
4518  min-height:44px;
4519  padding:0;
4520  flex-shrink:0;
4521  font-family:inherit;
4522}
4523.mf-cart:active{transform:scale(0.95)}
4524.mf-chat{background:#fff;color:#C77DFF;border:2px solid #C77DFF;width:44px;height:44px;min-height:44px;padding:0;flex-shrink:0;font-family:inherit}
4525.mf-chat:active{transform:scale(0.95)}
4526.mf-chat svg{width:20px;height:20px;flex-shrink:0}
4527.mf-share{
4528  background:#fff;
4529  color:#C77DFF;
4530  border:2px solid #C77DFF;
4531  width:44px;
4532  height:44px;
4533  padding:0;
4534  flex-shrink:0;
4535}
4536.mf-share:active{transform:scale(0.95)}
4537.mf-btn:disabled{opacity:.5;cursor:not-allowed}
4538@media (max-width:640px){
4539  .pd-mobile-fab{display:flex}
4540  .product-single{padding-bottom:0;} /* Space for FAB + bottom-nav */
4541}
4542
4543/* === Installment cards === */
4544.pd-installment-card{border:1px solid var(--pd-border);background:#fff;border-radius:var(--pd-radius);padding:1rem 1.1rem 1.25rem;display:flex;flex-direction:column;gap:.85rem}
4545.pd-installment-card h3{margin:0 0 .2rem;font-size:.78rem;font-weight:700;letter-spacing:.6px;text-transform:uppercase;color:var(--pd-dark)}
4546
4547.inst-tabs{display:flex;gap:.4rem}
4548.inst-tab{flex:1 1 0;background:var(--pd-soft);border:1px solid var(--pd-soft-border);padding:.45rem .5rem;font-size:.63rem;font-weight:600;border-radius:6px;cursor:pointer;letter-spacing:.4px;transition:var(--pd-transition)}
4549.inst-tab.active,.inst-tab:hover{background:var(--pd-accent);color:#fff;border-color:var(--pd-accent)}
4550.inst-tab:focus{outline:2px solid var(--pd-accent);outline-offset:2px}
4551
4552.inst-tenors{display:flex;gap:.4rem;flex-wrap:wrap}
4553.tenor-btn{flex:1 0 auto;background:#fff;border:1px solid var(--pd-soft-border);padding:.42rem .55rem;font-size:.6rem;font-weight:600;border-radius:20px;cursor:pointer;transition:.18s;min-width:56px}
4554.tenor-btn.active,.tenor-btn:hover{background:#1d7df0;color:#fff;border-color:#1d7df0}
4555
4556.inst-result{display:flex;flex-direction:column;gap:.45rem;font-size:.63rem}
4557.inst-line{display:flex;justify-content:space-between;align-items:center;padding:.35rem .55rem;background:var(--pd-soft);border:1px solid var(--pd-soft-border);border-radius:6px}
4558.inst-line.highlight{background:#1d7df0;color:#fff;border-color:#1d7df0;font-weight:600}
4559.inst-line .lbl{opacity:.8}
4560.inst-line .val{font-weight:600;letter-spacing:.3px}
4561.inst-footnote{font-size:.53rem;line-height:1.25;color:#64748b;margin-top:.2rem}
4562@media (max-width: 860px){
4563  .pd-installment-card{order:3}
4564  .inst-tabs .inst-tab,.inst-tenors .tenor-btn{font-size:.65rem}
4565  
4566  /* Voucher button responsive - make it simpler */
4567  .btn-buy-voucher{
4568    padding:0 12px;
4569    gap:8px
4570  }
4571  .btn-buy-voucher .bv-icon{
4572    font-size:18px
4573  }
4574  .btn-buy-voucher .bv-text{
4575    font-size:13px
4576  }
4577  .btn-buy-voucher .bv-text small{
4578    font-size:9px
4579  }
4580  .btn-buy-voucher .bv-save{
4581    font-size:11px;
4582    padding:3px 6px
4583  }
4584}
4585
4586/* Installment List v2 (eye-catching) */
4587.pd-installment-card2{
4588  background:linear-gradient(135deg,#ffffff 0%,#f1f7ff 65%,#e8f2ff 100%);
4589  border:1px solid var(--pd-border);border-radius:var(--pd-radius);
4590  padding:1rem 1.05rem 1.2rem;display:flex;flex-direction:column;gap:.5rem;
4591  position:relative;overflow:hidden
4592}
4593.pd-installment-card2:before{
4594  content:'';position:absolute;width:140px;height:140px;
4595  background:radial-gradient(circle at center,rgba(29,125,240,.18),rgba(29,125,240,0));
4596  top:-40px;right:-40px;pointer-events:none
4597}
4598.pd-installment-card2 h3{margin:0;font-size:.8rem;font-weight:700;letter-spacing:.6px;text-transform:uppercase;color:#0f2f54}
4599.pd-installment-card2 .inst-head{display:flex;align-items:center;justify-content:space-between;gap:.5rem}
4600.inst-head-badge{background:#1d7df0;color:#fff;font-size:.55rem;font-weight:600;padding:.25rem .5rem;border-radius:20px;letter-spacing:.4px;box-shadow:0 2px 6px -2px rgba(29,125,240,.6)}
4601
4602.inst-bank-tabs{display:flex;gap:.45rem}
4603.bank-tab{flex:1 1 0;background:#fff;border:1px solid var(--pd-soft-border);padding:.5rem .55rem;font-size:.63rem;font-weight:600;border-radius:7px;cursor:pointer;transition:.18s;letter-spacing:.3px}
4604.bank-tab.active,.bank-tab:hover{background:#1d7df0;color:#fff;border-color:#1d7df0;box-shadow:0 3px 10px -4px rgba(29,125,240,.6)}
4605.bank-tab:focus{outline:2px solid #1d7df0;outline-offset:2px}
4606
4607.inst-month-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:.55rem}
4608.inst-month-item{display:flex;align-items:center;gap:.65rem;background:#fff;border:1px solid var(--pd-soft-border);border-radius:14px;padding:.55rem .7rem;position:relative;overflow:hidden;transition:.25s}
4609.inst-month-item:before{content:'';position:absolute;inset:0;opacity:0;background:linear-gradient(90deg,rgba(29,125,240,.08),rgba(29,125,240,0));transition:.25s}
4610.inst-month-item:hover{transform:translateY(-2px);box-shadow:0 6px 14px -6px rgba(0,40,120,.25)}
4611.inst-month-item:hover:before{opacity:1}
4612.tenor-badge{background:#1d7df0;color:#fff;font-weight:700;min-width:42px;text-align:center;padding:.38rem .4rem;font-size:.8rem;border-radius:10px;box-shadow:0 3px 10px -4px rgba(29,125,240,.6)}
4613.amount{flex:1;font-size:.8rem;font-weight:600;color:#0f2f54;letter-spacing:.3px}
4614.tag{font-size:.55rem;font-weight:600;padding:.28rem .55rem;border-radius:30px;letter-spacing:.4px;text-transform:uppercase;white-space:nowrap}
4615.tag-zero{background:#16a34a;color:#fff;box-shadow:0 2px 8px -3px rgba(16,180,90,.55)}
4616
4617.inst-note{font-size:.6rem;font-weight:600;color:#0f2f54;background:#e0f7ed;border:1px solid #b2ebd2;padding:.4rem .6rem;border-radius:8px;letter-spacing:.3px}
4618.inst-disclaimer{font-size:.52rem;line-height:1.25;color:#64748b;margin-top:-.2rem}
4619
4620@media (max-width:860px){
4621  .pd-installment-card2{order:3}
4622  .tenor-badge{min-width:38px;font-size:.75rem}
4623  .amount{font-size:.78rem}
4624}
4625
4626/* Alt Fintech Banner (compact) */
4627.inst-alt-banner--compact{
4628  background:linear-gradient(142deg,#1d7df0 0%,#3c98ff 55%,#67bdff 100%);
4629  color:#fff;border:0;padding:.95rem .95rem 1.05rem;border-radius:16px;
4630  box-shadow:0 6px 18px -6px rgba(0,70,160,.45);position:relative;overflow:hidden;min-height:auto;
4631}
4632.inst-alt-banner--compact:before,
4633.inst-alt-banner--compact:after{
4634  content:'';position:absolute;border-radius:50%;background:rgba(255,255,255,.15);filter:blur(2px);pointer-events:none;
4635}
4636.inst-alt-banner--compact:before{width:130px;height:130px;top:-50px;right:-35px}
4637.inst-alt-banner--compact:after{width:90px;height:90px;bottom:-40px;left:-30px}
4638.inst-alt-banner--compact .iab-top{margin:0 0 .55rem;display:flex;flex-direction:column;gap:.25rem}
4639.inst-alt-banner--compact .iab-title{font-size:.74rem;font-weight:700;letter-spacing:.7px;line-height:1.15}
4640.inst-alt-banner--compact .iab-sub{font-size:.55rem;font-weight:500;opacity:.95;letter-spacing:.4px}
4641
4642.iab-logos-compact{display:flex;gap:.55rem;align-items:center;margin:0 0 .6rem;flex-wrap:nowrap;justify-content:space-between}
4643.iab-logos-compact .logo-fin{width:30%}
4644.iab-logos-compact .logo{
4645  width:48px;height:48px;border-radius:14px;display:flex;align-items:center;justify-content:center;
4646  font-size:.62rem;font-weight:700;letter-spacing:.3px;position:relative;color:#fff;
4647  box-shadow:0 4px 10px -4px rgba(0,0,0,.35);background:rgba(255,255,255,.15);
4648  backdrop-filter:blur(4px);transition:.25s;text-shadow:0 1px 2px rgba(0,0,0,.4);user-select:none;
4649}
4650.iab-logos-compact .logo:before{
4651  content:'';position:absolute;inset:0;border-radius:inherit;
4652  background:linear-gradient(140deg,rgba(255,255,255,.35),rgba(255,255,255,0));mix-blend-mode:overlay;opacity:.55;pointer-events:none;
4653}
4654.iab-logos-compact .logo:hover{transform:translateY(-3px) scale(1.05);box-shadow:0 8px 18px -6px rgba(0,0,0,.45)}
4655
4656.iab-cta--compact{
4657  display:inline-flex;padding:.45rem .85rem;font-size:.58rem;font-weight:700;background:#fff;color:#0f3c6d;border-radius:30px;text-decoration:none;letter-spacing:.55px;box-shadow:0 4px 12px -5px rgba(0,0,0,.35);transition:.25s;
4658}
4659.iab-cta--compact:hover{transform:translateY(-2px);box-shadow:0 8px 18px -7px rgba(0,0,0,.45)}
4660.iab-footnote--compact{margin-top:.45rem;font-size:.46rem;opacity:.85;letter-spacing:.25px}
4661@media (max-width:860px){
4662  .inst-alt-banner--compact{order:4;margin-top:.4rem;flex:1 1}
4663  .iab-logos-compact .logo{width:46px;height:46px}
4664}
4665
4666/* === Scroll To Top (baru) === */
4667.pd-scroll-top{
4668  position:fixed;
4669  right:20px;
4670  bottom:90px;
4671  width:48px;
4672  height:48px;
4673  border-radius:50%;
4674  background:linear-gradient(135deg, #ffffff 0%, #f8fafc 100%);
4675  color:#0f2f54;
4676  border:1px solid rgba(226, 232, 240, 0.8);
4677  box-shadow:0 8px 20px -8px rgba(0,0,0,.3), 0 2px 6px rgba(0,0,0,.1);
4678  display:flex;
4679  align-items:center;
4680  justify-content:center;
4681  cursor:pointer;
4682  z-index:1105;
4683  opacity:0;
4684  transform:translateY(12px) scale(.92);
4685  transition:all .3s cubic-bezier(0.4, 0, 0.2, 1);
4686  backdrop-filter:blur(8px);
4687  -webkit-backdrop-filter:blur(8px);
4688}
4689.pd-scroll-top:hover{
4690  box-shadow:0 12px 28px -10px rgba(0,0,0,.4), 0 4px 12px rgba(0,0,0,.15);
4691  transform:translateY(0) scale(1);
4692  background:linear-gradient(135deg, #ffffff 0%, #fefefe 100%);
4693  border-color:rgba(226, 232, 240, 1);
4694}
4695.pd-scroll-top:active{
4696  transform:translateY(0) scale(.96);
4697}
4698.pd-scroll-top:focus-visible{outline:2px solid var(--pd-accent);outline-offset:2px}
4699.pd-scroll-top.visible{opacity:1;transform:translateY(0) scale(1)}
4700@media (max-width:640px){
4701  /* Dynamic positioning via JavaScript */
4702  .pd-scroll-top{
4703    right:14px;
4704    bottom:var(--scroll-top-bottom, calc(68px + 18px + env(safe-area-inset-bottom)));
4705  }
4706}
4707
4708/* === Responsive layout tweaks === */
4709@media (max-width:1250px){
4710  .pd-top-layout{grid-template-columns:minmax(260px,330px) 1fr}
4711  .pd-sidebar{grid-column:1 / -1;flex-direction:row;flex-wrap:wrap;gap:1rem}
4712  /* Other cards 2-per-row; buy card always takes full row to avoid height-mismatch gaps */
4713  .pd-side-card{flex:1 1 calc(50% - .5rem)}
4714  .pd-buy-card{flex:0 0 100%}
4715}
4716@media (max-width:880px){
4717  .pd-top-layout{grid-template-columns:1fr}
4718  .pd-sidebar{flex-direction:column; padding: 0 1rem;}
4719  .pd-title{font-size:1.2rem}
4720  .pd-price-current{font-size:1.5rem}
4721}
4722@media (max-width:640px){
4723  /* Related: 2 kolom di mobile */
4724  .pd-related-full{padding:1.2rem;border:0;padding-top: .6rem;margin-bottom:.6rem;}
4725  .pd-related-grid,.pd-related-grid--full{grid-template-columns:repeat(2,1fr) !important;gap:12px !important}
4726}
4727@media (max-width:560px){
4728  .pd-actions{flex-direction:column}
4729  .btn-add-cart,.btn-buy,.btn-buy-voucher{width:100%}
4730  .pd-full-description{padding:1.2rem;border:0;padding-bottom:0;}
4731}
4732@media (max-width:380px){
4733  .pd-related-full{padding:.9rem .7rem 1.1rem}
4734  .pd-related-grid,.pd-related-grid--full{gap:8px !important}
4735  .pd-related-card .info{padding:.4rem .48rem .55rem}
4736}
4737
4738/* === Modern Countdown (Product Detail) === */
4739.pd-countdown-modern{
4740  --cd-bg1:#0ea5e9;          /* sky-500 */
4741  --cd-bg2:#6366f1;          /* indigo-500 */
4742  --cd-text:#0b1220;
4743  --cd-contrast:#ffffff;
4744  --cd-shadow: 0 8px 24px -10px rgba(0,0,0,.25);
4745  --cd-border: rgba(255,255,255,.25);
4746  --cd-box: rgba(255,255,255,.65);
4747  --cd-box-text:#0f172a;
4748  --cd-danger:#C77DFF;
4749
4750  display:flex; gap:.75rem; align-items:center;
4751  background:linear-gradient(135deg,var(--cd-bg1),var(--cd-bg2));
4752  border:1px solid var(--cd-border);
4753  color:var(--cd-contrast);
4754  border-radius:14px;
4755  padding:.6rem .8rem;
4756  box-shadow:var(--cd-shadow);
4757  position:relative;
4758  overflow:hidden;
4759  margin-bottom: 1rem;
4760}
4761
4762.pd-countdown-modern .pd-cd-icon{
4763  width:28px;height:28px;flex:0 0 28px;
4764  display:grid;place-items:center;
4765  background:rgba(255,255,255,.22);
4766  border:1px solid var(--cd-border);
4767  border-radius:10px;
4768  box-shadow: inset 0 1px 0 rgba(255,255,255,.35);
4769}
4770.pd-countdown-modern .pd-cd-icon svg{width:18px;height:18px;fill:#fff;opacity:.95}
4771
4772.pd-countdown-modern .pd-cd-body{display:flex;flex-direction:column;gap:.35rem;min-width:0}
4773
4774.pd-countdown-modern .pd-cd-label{
4775  font-size:.72rem;font-weight:700;letter-spacing:.4px;opacity:.95;line-height:1;
4776  text-shadow:0 1px 0 rgba(0,0,0,.08);
4777}
4778
4779.pd-countdown-modern .pd-cd-time{
4780  display:flex; align-items:end; gap:.35rem; flex-wrap:wrap;
4781  line-height:1;
4782}
4783
4784.pd-countdown-modern .unit{
4785  display:flex; flex-direction:column; align-items:center; gap:.18rem;
4786  min-width:58px;
4787}
4788.pd-countdown-modern .num{
4789  display:inline-flex; align-items:center; justify-content:center;
4790  min-width:58px; height:40px; padding:0 .4rem;
4791  background:var(--cd-box);
4792  color:var(--cd-box-text);
4793  border:1px solid rgba(15,23,42,.08);
4794  border-radius:10px;
4795  font: 800 1.05rem ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
4796  letter-spacing:.5px;
4797  box-shadow: 0 4px 14px -6px rgba(0,0,0,.4), inset 0 1px 0 rgba(255,255,255,.55);
4798}
4799.pd-countdown-modern .unit-label{
4800  font-size:.62rem; font-weight:700; opacity:.9; text-shadow:0 1px 0 rgba(255,255,255,.15);
4801}
4802
4803.pd-countdown-modern .colon{
4804  font-weight:900; font-size:1.05rem; opacity:.95; transform: translateY(-2px);
4805  animation: cdBlink 1.2s infinite steps(2, jump-none);
4806}
4807@keyframes cdBlink { 0%{opacity:1} 50%{opacity:.25} 100%{opacity:1} }
4808
4809.pd-countdown-modern .pd-cd-progress{
4810  display:none;
4811  position:relative;
4812  height:6px; border-radius:999px; overflow:hidden;
4813  background:rgba(255,255,255,.25);
4814  border:1px solid rgba(255,255,255,.28);
4815}
4816.pd-countdown-modern .pd-cd-progress .bar{
4817  height:100%; width:0%; background:linear-gradient(90deg,#22c55e,#a3e635);
4818  box-shadow: 0 2px 8px rgba(0,0,0,.25) inset;
4819  transition:width .35s ease;
4820}
4821
4822/* State saat hampir habis */
4823.pd-countdown-modern.danger{
4824  --cd-bg1:#C77DFF; /* orange-500 */
4825  --cd-bg2:#C77DFF; /* red-500   */
4826}
4827
4828/* Responsive */
4829@media (max-width:640px){
4830  .pd-countdown-modern{
4831    padding:.55rem .65rem; border-radius:12px; gap:.6rem;
4832  }
4833  .pd-countdown-modern .unit{min-width:52px}
4834  .pd-countdown-modern .num{min-width:52px;height:36px;font-size:.98rem}
4835}
4836
4837/* === Modern Countdown polish (shine + compact) === */
4838.pd-countdown-modern{
4839  position:relative;
4840}
4841.pd-countdown-modern::after{
4842  content:"";
4843  position:absolute; inset:-1px;
4844  background: linear-gradient(120deg, rgba(255,255,255,.12), rgba(255,255,255,0) 35%),
4845              radial-gradient(120% 120% at 0% 0%, rgba(255,255,255,.08), rgba(255,255,255,0) 60%);
4846  border-radius: inherit;
4847  pointer-events:none;
4848  mix-blend-mode: screen;
4849  animation: sheen 4.5s ease-in-out infinite;
4850}
4851@keyframes sheen {
4852  0%   { opacity:.35; transform: translateX(-10%) }
4853  50%  { opacity:.15; transform: translateX(4%) }
4854  100% { opacity:.35; transform: translateX(-10%) }
4855}
4856
4857/* Mode compact (aktifkan dengan data-mode="compact" di elemen) */
4858.pd-countdown-modern[data-mode="compact"]{
4859  gap:.55rem; padding:.5rem .6rem; border-radius:12px;
4860}
4861.pd-countdown-modern[data-mode="compact"] .unit{
4862  min-width:46px;
4863}
4864.pd-countdown-modern[data-mode="compact"] .num{
4865  min-width:46px; height:34px; font-size:.92rem;
4866}
4867.pd-countdown-modern[data-mode="compact"] .pd-cd-label{
4868  font-size:.66rem;
4869}
4870.pd-countdown-modern[data-mode="compact"] .pd-cd-icon{
4871  width:24px; height:24px; border-radius:8px;
4872}
4873.pd-countdown-modern[data-mode="compact"] .pd-cd-progress{
4874  height:5px;
4875}
4876
4877/* ============================================================
4878   Sidebar: shared refinements for medium + tablet (641px – 1250px)
4879   Buy card = form & paylater on the same row.
4880   Alt-fintech logos compact (no over-stretching).
4881   ============================================================ */
4882@media (min-width:641px) and (max-width:1250px) {
4883  /* Buy card: put qty/buy buttons and paylater promo inline */
4884  .pd-buy-card {
4885    display: flex !important;
4886    flex-direction: row;
4887    flex-wrap: wrap;
4888    align-items: center;
4889    gap: .6rem .75rem;
4890  }
4891  .pd-buy-card .pd-buy-form { flex: 1 1 0; min-width: 0; }
4892  .pd-buy-card .paylater-promo {
4893    flex: 0 0 auto;
4894    align-self: center;
4895    margin: 0;
4896    max-width: 44%;
4897  }
4898
4899  /* Alt-fintech banner: tighter logos */
4900  .iab-logos-compact {
4901    justify-content: center;
4902    gap: 1.25rem;
4903  }
4904  .iab-logos-compact .logo-fin {
4905    width: auto;
4906    max-height: 28px;
4907    object-fit: contain;
4908  }
4909}
4910
4911/* ============================================================
4912   Tablet layout (641px – 880px)
4913   Restores 2-column grid + horizontal sidebar for mid-size screens.
4914   Overrides the generic ≤880px mobile-collapse rules above.
4915   ============================================================ */
4916@media (min-width:641px) and (max-width:880px) {
4917  /* 2-column grid: image-card | info-card */
4918  .pd-top-layout {
4919    grid-template-columns: minmax(260px, 40%) 1fr;
4920    gap: 1rem;
4921  }
4922
4923  /* Sidebar: full-width horizontal flex row below the two main columns */
4924  .pd-sidebar {
4925    grid-column: 1 / -1;
4926    flex-direction: row;
4927    flex-wrap: wrap;
4928    gap: .75rem;
4929    padding: 0;
4930  }
4931  /* Banner cards fill 2-per-row */
4932  .pd-side-card { flex: 1 1 calc(50% - .375rem); }
4933  /* Buy card: full row (tallest card – avoids white-space gap if shared with shorter banners) */
4934  .pd-buy-card  { display: block !important; flex: 0 0 100%; }
4935
4936  /* Hide installment simulator + alt-fintech banner on tablet (too much vertical space) */
4937  .pd-installment-card2,
4938  .inst-alt-banner--compact { display: none !important; }
4939
4940  /* Restore sticky add-to-cart header (hidden at ≤880px by default) */
4941  .pd-sticky-header { display: flex !important; }
4942
4943  /* Typography – tighten slightly to fit the narrower info column */
4944  .pd-price-current { font-size: 1.65rem; }
4945  .pd-title         { font-size: 1.1rem;  }
4946  .pd-info-card     { padding: 1.1rem 1.2rem 1.5rem; }
4947}
4948</style>
4949  <style data-inlined="product-grid.css">
4950/* Product Grid (Firebird) */
4951
4952.product-archive {
4953  max-width: 1320px;
4954  margin-inline: auto;
4955  padding: 0 0 3rem;
4956  /*font-family: system-ui,-apple-system,Segoe UI,Roboto,Ubuntu,sans-serif;*/
4957}
4958
4959.pa-toolbar {
4960  display: flex;
4961  flex-wrap: wrap;
4962  gap: 1rem;
4963  justify-content: space-between;
4964  align-items: flex-start;
4965}
4966
4967.pa-title {
4968  font-size: 1.4rem;
4969  margin: 0;
4970  font-weight: 600;
4971  line-height: 1.2;
4972  color: #0f172a;
4973}
4974
4975.pa-left {
4976  display: flex;
4977  flex-wrap: wrap;
4978  gap: .75rem;
4979  align-items: center;
4980}
4981
4982.pa-filter-badge {
4983  background: #f1f5f9;
4984  border: 1px solid #e2e8f0;
4985  padding: .45rem .6rem;
4986  border-radius: 8px;
4987  font-size: .7rem;
4988  display: flex;
4989  align-items: center;
4990  gap: .4rem;
4991  line-height: 1;
4992  color: #475569;
4993}
4994.pa-filter-badge strong { color: #0f172a; }
4995.pa-filter-badge .clear {
4996  display:inline-block;
4997  text-decoration:none;
4998  background:#e2e8f0;
4999  color:#475569;
5000  font-weight:600;
5001  padding:0 .35rem .05rem;
5002  border-radius:4px;
5003  transition:.2s;
5004  font-size:.75rem;
5005  line-height:1;
5006}
5007.pa-filter-badge .clear:hover { background:#cbd5e1; color:#1e293b; }
5008
5009.pa-right {
5010  display:flex;
5011  gap:1rem;
5012  flex-wrap:wrap;
5013  align-items:flex-start;
5014  margin-bottom: 0.5rem;
5015}
5016
5017.pa-search {
5018  display:flex;
5019  gap:.5rem;
5020  align-items:center;
5021  background:#fff;
5022  border:1px solid #e2e8f0;
5023  padding:.4rem .5rem;
5024  border-radius:8px;
5025}
5026.pa-search input[type=text] {
5027  border:0;
5028  outline:none;
5029  font-size:.8rem;
5030  padding:.35rem .4rem;
5031  min-width:200px;
5032}
5033.pa-search button {
5034  background:#0d6efd;
5035  border:0;
5036  color:#fff;
5037  font-size:.7rem;
5038  padding:.45rem .75rem;
5039  border-radius:6px;
5040  cursor:pointer;
5041  font-weight:600;
5042  letter-spacing:.3px;
5043  transition:.25s;
5044}
5045.pa-search button:hover { background:#0b5dc4; }
5046
5047.pa-sort {
5048  display:flex;
5049  gap:.4rem;
5050  align-items:center;
5051  font-size:.7rem;
5052  background:#fff;
5053  border:1px solid #e2e8f0;
5054  padding:.4rem .55rem;
5055  border-radius:8px;
5056}
5057.pa-sort select {
5058  font-size:.75rem;
5059  padding:.35rem .5rem;
5060  border:1px solid #cbd5e1;
5061  border-radius:6px;
5062  background:#fff;
5063  outline:none;
5064}
5065
5066.pa-empty {
5067  border:1px dashed #cbd5e1;
5068  padding:3rem 1rem;
5069  text-align:center;
5070  border-radius:12px;
5071  background:#fff;
5072}
5073.pa-empty p {
5074  margin:0 0 1rem;
5075  font-size:.9rem;
5076  color:#475569;
5077}
5078.btn-reset {
5079  display:inline-block;
5080  background:#0d6efd;
5081  color:#fff;
5082  font-size:.7rem;
5083  padding:.55rem 1rem;
5084  border-radius:8px;
5085  text-decoration:none;
5086  font-weight:600;
5087  letter-spacing:.4px;
5088  transition:.25s;
5089}
5090.btn-reset:hover { background:#0a58c7; }
5091
5092/* Grid */
5093.pa-grid {
5094  display:grid;
5095  gap:1rem;
5096  grid-template-columns:repeat(auto-fill, minmax(180px,1fr));
5097  align-items:stretch;
5098}
5099
5100.pa-card {
5101  background:#fff;
5102  border:1px solid #e2e8f0;
5103  border-radius:12px;
5104  display:flex;
5105  flex-direction:column;
5106  text-decoration:none;
5107  color:inherit;
5108  position:relative;
5109  overflow:hidden;
5110  transition:.28s cubic-bezier(.4,0,.2,1);
5111  min-width:0;
5112  padding: 0;
5113}
5114.pa-card:hover {
5115  transform:translateY(-4px);
5116  box-shadow:0 8px 22px -8px rgba(0,0,0,.15);
5117  border-color:#dce2ea;
5118}
5119
5120.pa-card .thumb {
5121  aspect-ratio:1/1;
5122  background:#f1f5f9;
5123  display:flex;
5124  align-items:center;
5125  justify-content:center;
5126  overflow:hidden;
5127  position:relative;
5128}
5129.pa-card img {
5130  width:100%;
5131  height:100%;
5132  object-fit:cover;
5133  display:block;
5134}
5135.badge-disc {
5136  position:absolute;
5137  top:8px;
5138  left:8px;
5139  background:#C77DFF;
5140  color:#fff;
5141  font-size:.6rem;
5142  padding:4px 6px 3px;
5143  border-radius:6px;
5144  font-weight:700;
5145  letter-spacing:.4px;
5146}
5147
5148.pa-card .body {
5149  padding:.65rem .7rem .8rem;
5150  display:flex;
5151  flex-direction:column;
5152  gap:.45rem;
5153  min-height:90px;
5154}
5155
5156.pa-card .title {
5157  font-size:.75rem;
5158  line-height:1.25;
5159  margin:0;
5160  font-weight:600;
5161  color:#1e293b;
5162  height:2.4em;
5163  overflow:hidden;
5164}
5165
5166.pa-card .prices {
5167  display:flex;
5168  flex-wrap:wrap;
5169  align-items:baseline;
5170  gap:.4rem;
5171}
5172.pa-card .prices .final {
5173  font-size:.83rem;
5174  font-weight:700;
5175  color:#0d6efd;
5176}
5177.pa-card .prices .ori {
5178  font-size:.63rem;
5179  text-decoration:line-through;
5180  color:#94a3b8;
5181  font-weight:500;
5182}
5183
5184.pa-card .cat {
5185  margin-top:auto;
5186  font-size:.55rem;
5187  letter-spacing:.6px;
5188  text-transform:uppercase;
5189  background:#f1f5f9;
5190  border:1px solid #e2e8f0;
5191  padding:.28rem .45rem .25rem;
5192  border-radius:20px;
5193  font-weight:600;
5194  color:#475569;
5195  align-self:flex-start;
5196}
5197.pa-card .meta-line {
5198    margin-top:4px;
5199    font-size:.65rem;
5200    color:#475569;
5201}
5202.pa-card .meta-line .sold {
5203    display:inline-block;
5204    background:#f1f5f9;
5205    padding:2px 6px 3px;
5206    border-radius:4px;
5207    font-weight:600;
5208    letter-spacing:.3px;
5209    color:#334155;
5210}
5211
5212/* Pagination */
5213.pa-pagination {
5214  margin-top:2rem;
5215  display:flex;
5216  flex-wrap:wrap;
5217  gap:.4rem;
5218  justify-content:center;
5219  font-size:.7rem;
5220  align-items:center;
5221}
5222.pa-pagination a,
5223.pa-pagination span {
5224  min-width:34px;
5225  height:34px;
5226  display:flex;
5227  align-items:center;
5228  justify-content:center;
5229  border-radius:8px;
5230  text-decoration:none;
5231  font-weight:600;
5232  padding:0 .6rem;
5233  box-sizing:border-box;
5234  border:1px solid #e2e8f0;
5235  background:#fff;
5236  color:#334155;
5237  transition:.25s;
5238}
5239.pa-pagination a:hover {
5240  background:#f1f5f9;
5241  color:#0f172a;
5242}
5243.pa-pagination .current {
5244  background:#0d6efd;
5245  color:#fff;
5246  border-color:#0d6efd;
5247}
5248.pa-pagination .gap {
5249  border:none;
5250  background:transparent;
5251  font-weight:400;
5252  color:#94a3b8;
5253}
5254
5255/* =============== Mobile Filter Bar (Tokopedia-like) =============== */
5256.pa-mobile-filterbar{display:none}
5257@media (max-width: 640px){
5258  /* sembunyikan tombol lama */
5259  .pa-btn-filter{display:none}
5260
5261  .pa-mobile-filterbar{
5262    display:block;
5263    position:sticky;
5264    top:0; /* sesuaikan jika ada header fixed di atas */
5265    z-index:5;
5266    background:#fff;
5267    border-bottom:1px solid #e2e8f0;
5268    padding:.4rem .5rem;
5269    margin:-.4rem -1rem .6rem; /* full-bleed di container mobile */
5270  }
5271  .pa-mobile-filterbar .mf-scroll{
5272    display:flex;align-items:center;gap:.5rem;
5273    overflow-x:auto;
5274    -webkit-overflow-scrolling:touch;
5275    scrollbar-width:none;
5276  }
5277  .pa-mobile-filterbar .mf-scroll::-webkit-scrollbar{display:none}
5278
5279  .mf-chip{
5280    flex:0 0 auto;
5281    background:#fff;
5282    color:#334155;
5283    text-decoration:none;
5284    border:1px solid #e2e8f0;
5285    border-radius:999px;
5286    padding:.44rem .7rem;
5287    font-size:.78rem;
5288    font-weight:600;
5289    letter-spacing:.2px;
5290    white-space:nowrap;
5291  }
5292  .mf-chip:active{transform:scale(.98)}
5293  .mf-chip.active{
5294    background:#eaf2ff;
5295    border-color:#0d6efd;
5296    color:#0d6efd;
5297  }
5298
5299  .mf-filter-btn{
5300    position:relative;
5301    flex:0 0 auto;
5302    width:38px;height:38px;
5303    border-radius:50%;
5304    border:1.5px solid #0d6efd;
5305    background:#fff;
5306    display:inline-flex;align-items:center;justify-content:center;
5307    color:#0d6efd;
5308    cursor:pointer;
5309  }
5310  .mf-filter-btn:active{transform:scale(.96)}
5311  .mf-filter-btn svg{width:18px;height:18px;display:block}
5312  .mf-filter-btn .mf-badge{
5313    position:absolute;top:0;right:-4px;
5314    min-width:18px;height:18px;border-radius:9px;
5315    background:#C77DFF;color:#fff;
5316    font-size:.65rem;font-weight:700;
5317    display:flex;align-items:center;justify-content:center;
5318    padding:0 4px;line-height:1;
5319    box-shadow:0 2px 6px -2px rgba(226,166,66,.6);
5320  }
5321}
5322
5323/* Responsive */
5324@media (max-width: 640px) {
5325  .product-archive { padding: 0 1rem 3rem; }
5326  .pa-grid { grid-template-columns:repeat(auto-fill,minmax(150px,1fr)); }
5327  .pa-search input[type=text]{ min-width:140px; }
5328  .pa-toolbar { flex-direction:column; align-items:stretch; margin-bottom: 0; display: none;}
5329  .pa-right { display: none; }
5330  .pa-sort { width: 100%; justify-content:center; }
5331  .pa-mobile-filterbar { display: flex !important; }
5332}
5333
5334.pa-mobile-filterbar {
5335  display: none;
5336  align-items: center;
5337  gap: 8px;
5338  padding: 8px 0 8px 12px;
5339  background: #fff;
5340  width: 100vw;
5341}
5342.pa-mobile-filterbar .mf-scroll {
5343  display: flex;
5344  gap: 8px;
5345  overflow-x: auto;
5346  -webkit-overflow-scrolling: touch;
5347  scrollbar-width: none; /* Firefox */
5348  flex: 1 1 auto; /* takes remaining width */
5349}
5350.pa-mobile-filterbar .mf-scroll::-webkit-scrollbar { display: none; } /* WebKit */
5351.pa-mobile-filterbar .mf-chip {
5352  flex: 0 0 auto; /* prevent shrinking, keep width based on content */
5353  white-space: nowrap;
5354}
5355.pa-mobile-filterbar .mf-filter-btn {
5356  flex: 0 0 auto; /* do not shrink */
5357  position: relative; /* keep in place, not inside scroller */
5358  display: inline-flex;
5359  align-items: center;
5360  gap: 6px;
5361}
5362
5363/* Optional: ensure on small screens the button stays visible with min width */
5364@media (max-width: 768px) {
5365  .pa-mobile-filterbar .mf-filter-btn {
5366    padding: 6px 10px;
5367  }
5368}
5369
5370/* Product Specification Chips */
5371.pa-card .spec-chips {
5372  font-size: .6rem;
5373  color: #64748b;
5374  font-weight: 500;
5375  letter-spacing: .2px;
5376  margin-top: 2px;
5377  margin-bottom: 4px;
5378  line-height: 1.2;
5379  opacity: 0.9;
5380  max-width: 100%;
5381  overflow: hidden;
5382  text-overflow: ellipsis;
5383  white-space: nowrap;
5384}
5385
5386.pa-card .spec-chips .spec-divider {
5387  color: #94a3b8;
5388  font-weight: 400;
5389  margin: 0 1px;
5390}
5391</style>
5392  <style data-inlined="site-notice.css">
5393/**
5394 * Site Notice Banner - Reusable Notification System
5395 * Dismissible top bar for announcements, holidays, maintenance, etc.
5396 */
5397
5398.holiday-notice {
5399    position: fixed;
5400    top: 0;
5401    left: 0;
5402    right: 0;
5403    z-index: 9999;
5404    background: linear-gradient(135deg, #C77DFF 0%, #C77DFF 100%);
5405    border-bottom: 2px solid rgba(255, 255, 255, 0.2);
5406    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
5407    animation: slideDown 0.4s cubic-bezier(0.4, 0, 0.2, 1);
5408    transform-origin: top;
5409}
5410
5411.holiday-notice.hidden {
5412    animation: slideUp 0.3s cubic-bezier(0.4, 0, 0.2, 1) forwards;
5413}
5414
5415@keyframes slideDown {
5416    from {
5417        transform: translateY(-100%);
5418        opacity: 0;
5419    }
5420    to {
5421        transform: translateY(0);
5422        opacity: 1;
5423    }
5424}
5425
5426@keyframes slideUp {
5427    from {
5428        transform: translateY(0);
5429        opacity: 1;
5430    }
5431    to {
5432        transform: translateY(-100%);
5433        opacity: 0;
5434    }
5435}
5436
5437.holiday-notice-container {
5438    max-width: 1400px;
5439    margin: 0 auto;
5440    padding: 12px 20px;
5441    display: flex;
5442    align-items: center;
5443    justify-content: space-between;
5444    gap: 16px;
5445}
5446
5447.holiday-notice-content {
5448    display: flex;
5449    align-items: center;
5450    gap: 12px;
5451    flex: 1;
5452}
5453
5454.holiday-notice-icon {
5455    font-size: 20px;
5456    line-height: 1;
5457    flex-shrink: 0;
5458}
5459
5460.holiday-notice-text {
5461    color: #ffffff;
5462    font-size: 14px;
5463    font-weight: 500;
5464    line-height: 1.5;
5465    margin: 0;
5466    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
5467}
5468
5469.holiday-notice-emoji {
5470    display: inline-block;
5471    animation: bounce 2s ease-in-out infinite;
5472}
5473
5474@keyframes bounce {
5475    0%, 100% {
5476        transform: translateY(0);
5477    }
5478    50% {
5479        transform: translateY(-4px);
5480    }
5481}
5482
5483.holiday-notice-close {
5484    background: rgba(255, 255, 255, 0.2);
5485    border: 1px solid rgba(255, 255, 255, 0.3);
5486    border-radius: 6px;
5487    padding: 6px;
5488    cursor: pointer;
5489    color: #ffffff;
5490    transition: all 0.2s ease;
5491    flex-shrink: 0;
5492    display: flex;
5493    align-items: center;
5494    justify-content: center;
5495    width: 32px;
5496    height: 32px;
5497}
5498
5499.holiday-notice-close:hover {
5500    background: rgba(255, 255, 255, 0.3);
5501    transform: scale(1.05);
5502}
5503
5504.holiday-notice-close:active {
5505    transform: scale(0.95);
5506}
5507
5508.holiday-notice-close:focus {
5509    outline: 2px solid rgba(255, 255, 255, 0.5);
5510    outline-offset: 2px;
5511}
5512
5513/* Body padding adjustment when banner is visible */
5514body.has-holiday-notice {
5515    padding-top: 52px;
5516}
5517
5518/* Tablet Styles */
5519@media (max-width: 1024px) {
5520    .holiday-notice-container {
5521        padding: 10px 16px;
5522    }
5523    
5524    .holiday-notice-text {
5525        font-size: 13px;
5526    }
5527    
5528    .holiday-notice-icon {
5529        font-size: 18px;
5530    }
5531    
5532    body.has-holiday-notice {
5533        padding-top: 48px;
5534    }
5535}
5536
5537/* Mobile Styles */
5538@media (max-width: 640px) {
5539    .holiday-notice-container {
5540        padding: 10px 12px;
5541        gap: 8px;
5542    }
5543    
5544    .holiday-notice-content {
5545        gap: 8px;
5546    }
5547    
5548    .holiday-notice-text {
5549        font-size: 12px;
5550        line-height: 1.4;
5551    }
5552    
5553    .holiday-notice-icon {
5554        font-size: 16px;
5555    }
5556    
5557    .holiday-notice-close {
5558        width: 28px;
5559        height: 28px;
5560    }
5561    
5562    .holiday-notice-close svg {
5563        width: 16px;
5564        height: 16px;
5565    }
5566    
5567    body.has-holiday-notice {
5568        padding-top: 44px;
5569    }
5570}
5571
5572/* Ensure header doesn't get covered - removed z-index as it conflicts with dropdown stacking */
5573/* .header,
5574.navbar,
5575header {
5576    position: relative;
5577    z-index: 100;
5578} */
5579
5580</style>
5581        <style data-inlined="benchmark.css">
5582/**
5583 * Benchmark Section Styles
5584 * For product detail page benchmark display
5585 */
5586
5587.pd-benchmark-section {
5588    background: #fff;
5589    border-radius: 12px;
5590    padding: 24px;
5591    margin: 32px 0;
5592    box-shadow: 0 2px 8px rgba(0,0,0,0.06);
5593    border: 1px solid #e5e7eb;
5594}
5595
5596.benchmark-header {
5597    margin-bottom: 20px;
5598}
5599
5600.benchmark-title {
5601    font-size: 22px;
5602    font-weight: 700;
5603    color: #1a1a1a;
5604    margin: 0 0 12px 0;
5605    display: flex;
5606    align-items: center;
5607    gap: 8px;
5608}
5609
5610.benchmark-hint {
5611    font-size: 14px;
5612    color: #6b7280;
5613    margin: 0;
5614}
5615
5616/* Preview Badges */
5617.benchmark-preview-badges {
5618    display: flex;
5619    flex-wrap: wrap;
5620    gap: 10px;
5621    margin-top: 12px;
5622}
5623
5624.benchmark-badge {
5625    display: inline-flex;
5626    align-items: center;
5627    gap: 6px;
5628    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
5629    color: #fff;
5630    padding: 8px 16px;
5631    border-radius: 20px;
5632    font-size: 13px;
5633    font-weight: 500;
5634    box-shadow: 0 2px 6px rgba(102, 126, 234, 0.25);
5635    transition: all 0.2s ease;
5636}
5637
5638.benchmark-badge:hover {
5639    transform: translateY(-2px);
5640    box-shadow: 0 4px 12px rgba(102, 126, 234, 0.35);
5641}
5642
5643.benchmark-badge strong {
5644    font-weight: 600;
5645    opacity: 0.9;
5646}
5647
5648/* Load Button */
5649.btn-load-benchmark {
5650    display: flex;
5651    align-items: center;
5652    justify-content: center;
5653    gap: 10px;
5654    width: 100%;
5655    max-width: 420px;
5656    padding: 14px 24px;
5657    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
5658    color: #fff;
5659    border: none;
5660    border-radius: 8px;
5661    font-size: 15px;
5662    font-weight: 600;
5663    cursor: pointer;
5664    transition: all 0.3s ease;
5665    box-shadow: 0 4px 12px rgba(102, 126, 234, 0.3);
5666    margin: 0 auto;
5667}
5668
5669.btn-load-benchmark:hover:not(:disabled) {
5670    transform: translateY(-2px);
5671    box-shadow: 0 6px 16px rgba(102, 126, 234, 0.4);
5672}
5673
5674.btn-load-benchmark:disabled {
5675    opacity: 0.6;
5676    cursor: not-allowed;
5677}
5678
5679.btn-load-benchmark .btn-icon {
5680    font-size: 20px;
5681}
5682
5683.btn-load-benchmark.loading .btn-icon {
5684    animation: spin 1s linear infinite;
5685}
5686
5687@keyframes spin {
5688    from { transform: rotate(0deg); }
5689    to { transform: rotate(360deg); }
5690}
5691
5692/* Benchmark Content */
5693.benchmark-content {
5694    margin-top: 24px;
5695    padding-top: 24px;
5696    border-top: 2px solid #f3f4f6;
5697}
5698
5699.benchmark-loading {
5700    text-align: center;
5701    padding: 40px 20px;
5702    color: #6b7280;
5703}
5704
5705.benchmark-loading-spinner {
5706    width: 48px;
5707    height: 48px;
5708    margin: 0 auto 16px;
5709    border: 4px solid #f3f4f6;
5710    border-top-color: #667eea;
5711    border-radius: 50%;
5712    animation: spin 1s linear infinite;
5713}
5714
5715.benchmark-error {
5716    text-align: center;
5717    padding: 32px 20px;
5718    color: #C77DFF;
5719    background: #fee2e2;
5720    border-radius: 8px;
5721}
5722
5723/* Benchmark Data Display */
5724.benchmark-data-grid {
5725    display: grid;
5726    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
5727    gap: 16px;
5728    margin-bottom: 24px;
5729}
5730
5731.benchmark-card {
5732    background: linear-gradient(135deg, #667eea15 0%, #764ba215 100%);
5733    border: 1px solid #e5e7eb;
5734    border-radius: 10px;
5735    padding: 18px;
5736    text-align: center;
5737    transition: all 0.2s ease;
5738}
5739
5740.benchmark-card:hover {
5741    transform: translateY(-3px);
5742    box-shadow: 0 6px 16px rgba(102, 126, 234, 0.15);
5743}
5744
5745.benchmark-card-label {
5746    font-size: 13px;
5747    color: #6b7280;
5748    font-weight: 500;
5749    margin-bottom: 8px;
5750    text-transform: uppercase;
5751    letter-spacing: 0.5px;
5752}
5753
5754.benchmark-card-value {
5755    font-size: 24px;
5756    font-weight: 700;
5757    color: #1a1a1a;
5758    line-height: 1.2;
5759}
5760
5761.benchmark-card-value.large {
5762    font-size: 28px;
5763}
5764
5765.benchmark-card-subtitle {
5766    font-size: 12px;
5767    color: #9ca3af;
5768    margin-top: 4px;
5769}
5770
5771/* Spec Details */
5772.benchmark-specs {
5773    background: #f9fafb;
5774    border-radius: 10px;
5775    padding: 20px;
5776    margin-top: 20px;
5777}
5778
5779.benchmark-specs-title {
5780    font-size: 16px;
5781    font-weight: 600;
5782    color: #1a1a1a;
5783    margin: 0 0 16px 0;
5784}
5785
5786.benchmark-spec-row {
5787    display: flex;
5788    justify-content: space-between;
5789    padding: 10px 0;
5790    border-bottom: 1px solid #e5e7eb;
5791}
5792
5793.benchmark-spec-row:last-child {
5794    border-bottom: none;
5795}
5796
5797.benchmark-spec-label {
5798    font-size: 14px;
5799    color: #6b7280;
5800    font-weight: 500;
5801}
5802
5803.benchmark-spec-value {
5804    font-size: 14px;
5805    color: #1a1a1a;
5806    font-weight: 600;
5807    text-align: right;
5808}
5809
5810/* Score Badges */
5811.benchmark-score-badge {
5812    display: inline-block;
5813    padding: 6px 14px;
5814    border-radius: 20px;
5815    font-size: 13px;
5816    font-weight: 600;
5817    margin-top: 8px;
5818}
5819
5820.benchmark-score-badge.excellent {
5821    background: #10b981;
5822    color: #fff;
5823}
5824
5825.benchmark-score-badge.good {
5826    background: #3b82f6;
5827    color: #fff;
5828}
5829
5830.benchmark-score-badge.average {
5831    background: #C77DFF;
5832    color: #fff;
5833}
5834
5835.benchmark-score-badge.poor {
5836    background: #C77DFF;
5837    color: #fff;
5838}
5839
5840/* Attribution */
5841.benchmark-attribution {
5842    text-align: center;
5843    margin-top: 24px;
5844    padding-top: 20px;
5845    border-top: 1px solid #e5e7eb;
5846    font-size: 13px;
5847    color: #9ca3af;
5848}
5849
5850.benchmark-attribution a {
5851    color: #667eea;
5852    text-decoration: none;
5853    font-weight: 500;
5854}
5855
5856.benchmark-attribution a:hover {
5857    text-decoration: underline;
5858}
5859
5860/* Responsive */
5861@media (max-width: 768px) {
5862    .pd-benchmark-section {
5863        padding: 16px;
5864        margin: 20px 0;
5865    }
5866    
5867    .benchmark-title {
5868        font-size: 18px;
5869    }
5870    
5871    .benchmark-preview-badges {
5872        flex-direction: column;
5873        gap: 8px;
5874    }
5875    
5876    .benchmark-badge {
5877        justify-content: center;
5878    }
5879    
5880    .btn-load-benchmark {
5881        font-size: 14px;
5882        padding: 12px 20px;
5883    }
5884    
5885    .benchmark-data-grid {
5886        grid-template-columns: 1fr 1fr;
5887        gap: 12px;
5888    }
5889    
5890    .benchmark-card {
5891        padding: 14px;
5892    }
5893    
5894    .benchmark-card-value {
5895        font-size: 20px;
5896    }
5897    
5898    .benchmark-spec-row {
5899        flex-direction: column;
5900        gap: 4px;
5901    }
5902    
5903    .benchmark-spec-value {
5904        text-align: left;
5905    }
5906}
5907
5908@media (max-width: 480px) {
5909    .benchmark-data-grid {
5910        grid-template-columns: 1fr;
5911    }
5912}
5913
5914</style>
5915    <style data-inlined="product-filters.css">
5916/* =========================================================
5917   Product Filters (Desktop + Mobile Drawer)
5918   Light Only + FIX:
5919   - Desktop: f-actions selalu tampil (static bottom)
5920   - Mobile: konten filter dapat discroll
5921   ========================================================= */
5922
5923/* ========== Layout wrapper (tidak mengubah grid produk) ========== */
5924.product-archive.with-filters .pa-layout {
5925  display:flex;
5926  gap:24px;
5927  align-items:flex-start;
5928}
5929.pa-main { flex:1; min-width:0; }
5930
5931/* =========================================================
5932   DESKTOP PANEL
5933   ========================================================= */
5934.pa-filters {
5935  width:300px;
5936  background:linear-gradient(145deg,#ffffff 0%,#f8fafc 55%,#f1f5f9 100%);
5937  border:1px solid #e2e8f0;
5938  padding:18px 18px 12px; /* bottom dikurangi karena f-actions punya padding sendiri */
5939  border-radius:18px;
5940  position:sticky;
5941  top:80px;
5942  height:calc(100vh - 100px); /* tinggi stabil untuk inner scroll */
5943  font-size:14px;
5944  box-shadow:0 1px 2px rgba(0,0,0,.04),0 4px 14px rgba(15,23,42,.08);
5945  backdrop-filter:blur(3px);
5946  -webkit-backdrop-filter:blur(3px);
5947  transition:box-shadow .3s, background .4s;
5948  display:flex;
5949  flex-direction:column;
5950  overflow:hidden; /* cegah double scroll, inner yang scroll */
5951}
5952.pa-filters::before {
5953  content:"";
5954  position:absolute;
5955  inset:0 auto 0 0;
5956  width:7px;
5957  border-radius:18px 0 0 18px;
5958  background:linear-gradient(180deg,#C77DFF 0%,#C77DFF 35%,#1d6ce0 100%);
5959}
5960.pa-filters.active { box-shadow:0 8px 32px -4px rgba(15,23,42,.35); }
5961
5962/* Scroll area (desktop/mode shared) */
5963.filters-scroll {
5964  flex:1;
5965  min-height:0;          /* wajib agar overflow terbaca dalam flex container */
5966  overflow:auto;
5967  padding-right:6px;
5968  margin-right:-6px;      /* kompensasi scrollbar */
5969  scrollbar-width:thin;
5970  overscroll-behavior:contain;
5971}
5972.filters-scroll::-webkit-scrollbar { width:8px; }
5973.filters-scroll::-webkit-scrollbar-thumb {
5974  background:#cbd5e1;
5975  border-radius:20px;
5976  border:2px solid #f1f5f9;
5977}
5978.filters-scroll::-webkit-scrollbar-thumb:hover { background:#94a3b8; }
5979
5980/* Heading */
5981.pa-filters h2 {
5982  margin:0 0 14px;
5983  font-size:20px;
5984  font-weight:700;
5985  letter-spacing:.4px;
5986  line-height:1.15;
5987  background:linear-gradient(90deg,#0f172a,#1d6ce0 60%,#0f172a);
5988  -webkit-background-clip:text;
5989  color:transparent;
5990  background-size:200% 100%;
5991  animation:titleSheen 8s linear infinite;
5992}
5993@keyframes titleSheen {
5994  0%{background-position:0 0}
5995  50%{background-position:100% 0}
5996  100%{background-position:0 0}
5997}
5998
5999/* Form groups */
6000.pa-filters .f-group { margin-bottom:18px; position:relative; }
6001.pa-filters label {
6002  display:block;
6003  font-weight:600;
6004  margin:0 0 6px;
6005  font-size:13px;
6006  color:#0f172a;
6007  letter-spacing:.3px;
6008}
6009
6010/* Inputs / selects */
6011.pa-filters input[type=text],
6012.pa-filters input[type=number],
6013.pa-filters select {
6014  width:100%;
6015  padding:7px 10px;
6016  border:1px solid #cbd5e1;
6017  border-radius:8px;
6018  font-size:13px;
6019  min-height:34px;
6020  background:#ffffff;
6021  box-sizing:border-box;
6022  color:#0f172a;
6023  transition:border-color .25s, box-shadow .25s, background .25s;
6024  -webkit-appearance:none;
6025  -moz-appearance:none;
6026  appearance:none;
6027}
6028.pa-filters select {
6029  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%230f172a' d='M6 9L1 4h10z'/%3E%3C/svg%3E");
6030  background-repeat:no-repeat;
6031  background-position:right 10px center;
6032  background-size:12px;
6033  padding-right:32px;
6034}
6035.pa-filters input[type=text]:hover,
6036.pa-filters input[type=number]:hover,
6037.pa-filters select:hover { border-color:#94b5ec; }
6038.pa-filters input[type=text]:focus,
6039.pa-filters input[type=number]:focus,
6040.pa-filters select:focus {
6041  outline:none;
6042  border-color:#1d6ce0;
6043  box-shadow:0 0 0 3px rgba(29,108,224,.25);
6044  background:#f8fbff;
6045}
6046.pa-filters .range { display:flex; gap:10px; }
6047.pa-filters .range input { flex:1; }
6048.pa-filters .hint { font-size:11px; color:#64748b; margin-top:6px; }
6049
6050/* Spec blocks */
6051.f-specs { margin-top:4px; }
6052.spec-attr {
6053  margin:0 0 14px;
6054  padding:12px 12px 10px;
6055  border:1px solid #e2e8f0;
6056  border-radius:14px;
6057  background:linear-gradient(130deg,#ffffff 0%,#f7faff 85%);
6058  position:relative;
6059  transition:border-color .3s, box-shadow .3s, background .4s;
6060}
6061.spec-attr.collapsed { padding-bottom:8px; }
6062.spec-attr.has-selected {
6063  border-color:#1d6ce0;
6064  box-shadow:0 0 0 2px rgba(29,108,224,.15),0 2px 8px -2px rgba(29,108,224,.35);
6065  background:linear-gradient(135deg,#ffffff 0%,#e9f2ff 100%);
6066}
6067.spec-attr-title {
6068  font-weight:600;
6069  margin:0 0 8px;
6070  font-size:13px;
6071  display:flex;
6072  justify-content:space-between;
6073  align-items:center;
6074  cursor:pointer;
6075  color:#0f172a;
6076  user-select:none;
6077}
6078.spec-attr-title .chevron {
6079  font-size:10px;
6080  transition:transform .25s, opacity .25s;
6081  opacity:.65;
6082}
6083.spec-attr.collapsed .spec-attr-title .chevron {
6084  transform:rotate(-90deg);
6085  opacity:.5;
6086}
6087
6088/* Spec options */
6089.spec-attr-options { display:flex; flex-wrap:wrap; gap:6px; }
6090.spec-attr-options label {
6091  display:inline-flex;
6092  align-items:center;
6093  gap:4px;
6094  font-weight:500;
6095  border:1px solid #d4dde7;
6096  padding:6px 9px;
6097  border-radius:30px;
6098  cursor:pointer;
6099  background:#f3f6fa;
6100  font-size:12px;
6101  line-height:1.1;
6102  transition:background .25s, border-color .25s, color .25s, box-shadow .25s;
6103  position:relative;
6104}
6105.spec-attr-options label:hover { background:#e8f1ff; border-color:#b1cff3; }
6106.spec-attr-options input {
6107  margin:0;
6108  position:absolute;
6109  inset:0;
6110  opacity:0;
6111  cursor:pointer;
6112}
6113.spec-attr-options label:has(input:checked) {
6114  background:linear-gradient(135deg,#1d6ce0 0%,#155ab8 100%);
6115  border-color:#1d6ce0;
6116  color:#ffffff;
6117  box-shadow:0 2px 6px -1px rgba(29,108,224,.55);
6118}
6119.spec-attr-options label:has(input:checked)::after {
6120  content:"";
6121  position:absolute;
6122  right:6px;
6123  top:6px;
6124  width:6px;
6125  height:6px;
6126  background:#fff;
6127  border-radius:50%;
6128  box-shadow:0 0 0 4px rgba(255,255,255,.25),0 0 0 7px rgba(29,108,224,.5);
6129  animation:pulseDot 1.9s ease-out infinite;
6130}
6131@keyframes pulseDot {
6132  0%{transform:scale(.8);opacity:.9}
6133  60%{transform:scale(1.4);opacity:.15}
6134  100%{transform:scale(.8);opacity:.9}
6135}
6136
6137/* Badges */
6138.pa-filter-badges { margin:0 0 18px; display:flex; flex-wrap:wrap; gap:6px; }
6139.pa-filter-badge {
6140  display:inline-flex;
6141  gap:6px;
6142  align-items:center;
6143  background:linear-gradient(135deg,#eef4ff 0%,#e0edff 100%);
6144  border:1px solid #b4cff3;
6145  padding:5px 10px 5px 12px;
6146  border-radius:22px;
6147  margin:2px 4px 0 0;
6148  font-size:11px;
6149  font-weight:500;
6150  line-height:1;
6151  color:#0f172a;
6152  position:relative;
6153  overflow:hidden;
6154}
6155.pa-filter-badge::before {
6156  content:"";
6157  position:absolute;
6158  inset:0;
6159  background:linear-gradient(90deg,rgba(255,255,255,0),rgba(255,255,255,.35),rgba(255,255,255,0));
6160  transform:translateX(-100%);
6161  animation:badgeSheen 6s linear infinite;
6162}
6163@keyframes badgeSheen {
6164  0%{transform:translateX(-100%)}
6165  55%{transform:translateX(120%)}
6166  100%{transform:translateX(120%)}
6167}
6168.pa-filter-badge a.clear {
6169  text-decoration:none;
6170  color:#E3D05A;
6171  font-weight:700;
6172  padding:0 3px;
6173  display:inline-flex;
6174  align-items:center;
6175  justify-content:center;
6176  border-radius:50%;
6177  line-height:1;
6178  transition:background .25s, color .25s;
6179}
6180.pa-filter-badge a.clear:hover { background:#ffeded; color:#E3D05A; }
6181.pa-btn-filter { width: 100%;}
6182
6183/* =========================================================
6184   ACTIONS (DESKTOP) - STATIC BOTTOM
6185   ========================================================= */
6186.f-actions {
6187  margin-top:10px;
6188  display:flex;
6189  gap:12px;
6190  flex-wrap:wrap;
6191  padding:16px 0 4px;
6192  border-top:1px solid #e2e8f0;
6193  background:linear-gradient(180deg,rgba(255,255,255,0) 0%,#f1f5f9 70%);
6194  flex-shrink:0;
6195}
6196.f-actions button {
6197  background:linear-gradient(135deg,#1d6ce0 0%,#155ab8 100%);
6198  color:#fff;
6199  border:none;
6200  padding:10px 20px;
6201  border-radius:12px;
6202  cursor:pointer;
6203  font-size:14px;
6204  font-weight:600;
6205  letter-spacing:.3px;
6206  display:inline-flex;
6207  align-items:center;
6208  gap:6px;
6209  box-shadow:0 4px 14px -2px rgba(29,108,224,.45);
6210  transition:transform .25s, box-shadow .3s;
6211}
6212.f-actions button:hover { transform:translateY(-3px); box-shadow:0 8px 26px -4px rgba(29,108,224,.6); }
6213.f-actions button:active { transform:translateY(-1px) scale(.98); box-shadow:0 4px 14px -4px rgba(29,108,224,.55); }
6214.f-actions .reset {
6215  font-size:12px;
6216  text-decoration:none;
6217  color:#C77DFF;
6218  align-self:center;
6219  font-weight:600;
6220  padding:4px 6px;
6221  border-radius:8px;
6222  transition:background .25s, color .25s;
6223}
6224.f-actions .reset:hover { background:#ffe6e6; color:#E3D05A; text-decoration:underline; }
6225.pa-filters .close-drawer { display: none; }
6226
6227/* Form wrapper: flex container agar inner .filters-scroll bisa scroll di desktop */
6228.filter-form {
6229  flex: 1;
6230  min-height: 0;
6231  display: flex;
6232  flex-direction: column;
6233  overflow: hidden;
6234}
6235
6236/* =========================================================
6237   FILTER TOGGLE (MOBILE TRIGGER)
6238   ========================================================= */
6239.filter-toggle {
6240  display:none;
6241  margin:0 0 14px;
6242  background:linear-gradient(135deg,#1d6ce0 0%,#155ab8 100%);
6243  color:#fff;
6244  border:none;
6245  padding:11px 18px;
6246  font-size:14px;
6247  font-weight:600;
6248  border-radius:14px;
6249  cursor:pointer;
6250  letter-spacing:.4px;
6251  box-shadow:0 4px 14px -2px rgba(29,108,224,.55);
6252  position:relative;
6253  z-index:100;
6254  transition:box-shadow .3s, transform .25s;
6255}
6256.filter-toggle:hover { box-shadow:0 8px 26px -4px rgba(29,108,224,.6); transform:translateY(-2px); }
6257.filter-toggle:active { transform:translateY(0); box-shadow:0 4px 14px -4px rgba(29,108,224,.55); }
6258.filter-toggle .count-badge {
6259  display:inline-block;
6260  background:linear-gradient(135deg,#C77DFF 0%,#C77DFF 55%,#C77DFF 100%);
6261  color:#1d2b44;
6262  font-size:11px;
6263  font-weight:700;
6264  padding:3px 7px 4px;
6265  border-radius:30px;
6266  margin-left:8px;
6267  box-shadow:0 0 0 2px #ffffff,0 0 0 4px #1d6ce0;
6268}
6269
6270/* Overlay (mobile) */
6271.pa-filters-overlay { display:none; }
6272
6273/* =========================================================
6274   MOBILE DRAWER
6275   ========================================================= */
6276@media (max-width:768px){
6277  .product-archive.with-filters .pa-layout { flex-direction:column; gap:12px; }
6278  .filter-toggle { display:inline-flex; align-items:center; gap:6px; }
6279
6280  .pa-filters-overlay {
6281    position:fixed;
6282    inset:0;
6283    background:rgba(0,20,45,.55);
6284    z-index:998;
6285    opacity:0;
6286    transition:opacity .35s;
6287    display:block;
6288    pointer-events:none;
6289    backdrop-filter:blur(2px);
6290  }
6291  .pa-filters-overlay.active { opacity:1; pointer-events:auto; }
6292
6293  .pa-filters {
6294    position:fixed;
6295    top:auto;
6296    left:0; right:0; bottom:0;
6297    max-height:92vh;
6298    height:auto;
6299    width:100%;
6300    border-radius:30px 30px 0 0;
6301    border:1px solid #dbe4ef;
6302    padding:26px 22px 0;
6303    z-index:10000; /* di atas bottom-nav (9998) */
6304    transform:translateY(102%);
6305    transition:transform .55s cubic-bezier(.68,-0.35,.25,1);
6306    box-shadow:0 -4px 40px -6px rgba(15,23,42,.45);
6307    overflow:hidden; /* outer hidden, inner scroll */
6308  }
6309  .pa-filters.active { transform:translateY(0); }
6310
6311  /* Drag handle indicator */
6312  .pa-filters::after {
6313    content:"";
6314    display:block;
6315    position:absolute;
6316    top:10px;
6317    left:50%;
6318    transform:translateX(-50%);
6319    width:36px;
6320    height:4px;
6321    background:#cbd5e1;
6322    border-radius:4px;
6323  }
6324  body.filter-open { overflow:hidden; touch-action:none; }
6325
6326  /* Restore mobile-friendly input sizes (prevent iOS zoom on focus) */
6327  .pa-filters input[type=text],
6328  .pa-filters input[type=number],
6329  .pa-filters select {
6330    font-size:16px;
6331    min-height:44px;
6332    padding:10px 12px;
6333    border-radius:10px;
6334  }
6335  .pa-filters select { padding-right:32px; }
6336
6337  .filters-scroll {
6338    flex:1;
6339    overflow:auto;
6340    padding:0 0 120px; /* ruang di atas bar actions */
6341    margin:0;
6342    -webkit-overflow-scrolling:touch;
6343  }
6344
6345  .pa-filters h2 { font-size:19px; margin-bottom:10px; }
6346
6347  .pa-filters .close-drawer {
6348    display: block;
6349    position:absolute;
6350    right:14px; top:12px;
6351    background:linear-gradient(135deg,#C77DFF 0%,#E3D05A 100%);
6352    color:#fff;
6353    padding:7px 14px;
6354    border:none;
6355    border-radius:10px;
6356    font-size:12px;
6357    font-weight:600;
6358    cursor:pointer;
6359    box-shadow:0 3px 10px -2px rgba(226,166,66,.55);
6360    transition:transform .25s, box-shadow .3s;
6361    z-index: 99;
6362  }
6363  .pa-filters .close-drawer:hover { transform:translateY(-2px); box-shadow:0 6px 18px -4px rgba(226,166,66,.6); }
6364
6365  .spec-attr { border-radius:18px; }
6366  .spec-attr-options label { font-size:11px; padding:5px 9px; }
6367
6368  /* Actions fixed di viewport bawah */
6369  .f-actions {
6370    position:fixed;
6371    left:0; right:0; bottom:0;
6372    margin:0;
6373    border-top:1px solid #d6dee8;
6374    padding:14px 16px calc(16px + env(safe-area-inset-bottom));
6375    background:#ffffffea;
6376    backdrop-filter:blur(6px);
6377    box-shadow:0 -4px 22px -6px rgba(15,23,42,.25);
6378    justify-content:space-between;
6379    z-index:10001; /* di atas pa-filters (10000) dan bottom-nav (9998) */
6380  }
6381
6382  /* Sembunyikan bottom-nav saat filter drawer terbuka */
6383  body.filter-open .bottom-nav {
6384    display: none !important;
6385  }
6386  .f-actions button {
6387    flex:1 1 auto;
6388    justify-content:center;
6389    padding:14px 14px;
6390    font-size:15px;
6391    border-radius:14px;
6392  }
6393  .f-actions .reset {
6394    order:-1;
6395    font-size:12px;
6396    padding:2px 8px;
6397  }
6398}
6399
6400/* Scrollbar (outer panel desktop only kept for compatibility) */
6401.pa-filters::-webkit-scrollbar { width:0; } /* disembunyikan karena inner yang scroll */
6402
6403/* Utilities */
6404.hidden { display:none !important; }
6405.gradient-text {
6406  background:linear-gradient(90deg,#1d6ce0,#155ab8,#1d6ce0);
6407  -webkit-background-clip:text;
6408  color:transparent;
6409  animation:titleSheen 10s linear infinite;
6410}
6411.glow-focus:focus {
6412  outline:none !important;
6413  box-shadow:0 0 0 3px rgba(29,108,224,.4) !important;
6414  border-color:#1d6ce0 !important;
6415}
6416
6417/* Simple fade (opsional) */
6418@keyframes fadeIn {
6419  from { opacity:0; transform:translateY(8px); }
6420  to { opacity:1; transform:translateY(0); }
6421}
6422</style>
6423  <style data-inlined="mega-menu-tiles.css">
6424/* Tile Mega Menu — Modern E-commerce Enhanced (2025) */
6425
6426/* Design Tokens */
6427:root {
6428  --mm2-bg: #ffffff;
6429  --mm2-surface: #ffffff;
6430  --mm2-surface-elevated: rgba(255,255,255,0.98);
6431  --mm2-muted: #f8fafc;
6432  --mm2-border: #e2e8f0;
6433  --mm2-border-strong: #cbd5e1;
6434  --mm2-accent: #6366f1;
6435  --mm2-accent-hover: #4f46e5;
6436  --mm2-accent-10: rgba(99,102,241,.10);
6437  --mm2-accent-20: rgba(99,102,241,.20);
6438  --mm2-fg: #0f172a;
6439  --mm2-fg-muted: #64748b;
6440  --mm2-fg-light: #94a3b8;
6441  
6442  /* Enhanced Shadows - Multi-layer elevation */
6443  --mm2-shadow-sm: 0 2px 8px rgba(15,23,42,.06), 0 1px 2px rgba(15,23,42,.04);
6444  --mm2-shadow-md: 0 8px 24px rgba(15,23,42,.10), 0 2px 8px rgba(15,23,42,.06);
6445  --mm2-shadow-lg: 0 20px 60px rgba(15,23,42,.14), 0 8px 24px rgba(15,23,42,.08);
6446  --mm2-shadow-xl: 0 32px 80px rgba(15,23,42,.18), 0 12px 32px rgba(15,23,42,.10);
6447  --mm2-shadow-hover: 0 16px 40px rgba(15,23,42,.16), 0 6px 16px rgba(15,23,42,.08);
6448  
6449  /* Border Radius */
6450  --mm2-radius-xl: 20px;
6451  --mm2-radius-lg: 16px;
6452  --mm2-radius-md: 12px;
6453  --mm2-radius-sm: 10px;
6454  
6455  --mm2-z: 60;
6456  
6457  /* Animation Timing */
6458  --mm2-transition-fast: 150ms cubic-bezier(0.4, 0, 0.2, 1);
6459  --mm2-transition-base: 250ms cubic-bezier(0.4, 0, 0.2, 1);
6460  --mm2-transition-slow: 350ms cubic-bezier(0.4, 0, 0.2, 1);
6461}
6462
6463.navbar { position: relative; z-index: var(--mm2-z); }
6464
6465/* Trigger Button - Enhanced */
6466.mm2-trigger {
6467  display: inline-flex; align-items: center; gap: 8px;
6468  padding: 10px 14px; border-radius: var(--mm2-radius-md);
6469  border: 1.5px solid var(--mm2-border);
6470  background: var(--mm2-surface); color: var(--mm2-fg);
6471  cursor: pointer; user-select: none;
6472  transition: all var(--mm2-transition-fast);
6473  text-decoration: none;
6474  font-weight: 600;
6475  box-shadow: var(--mm2-shadow-sm);
6476}
6477.mm2-trigger:hover { 
6478  border-color: var(--mm2-accent); 
6479  background: var(--mm2-muted);
6480  box-shadow: var(--mm2-shadow-md);
6481  transform: translateY(-1px);
6482}
6483.mm2-trigger:active { transform: translateY(0); }
6484.mm2-trigger svg {max-width: unset !important; transition: transform var(--mm2-transition-fast); }
6485.mm2-trigger:hover svg { transform: scale(1.05); }
6486
6487/* Backdrop - Enhanced Glassmorphism */
6488.mm2-backdrop {
6489  position: fixed; 
6490  inset: 0;
6491  top: 0;
6492  left: 0;
6493  right: 0;
6494  bottom: 0;
6495  background: rgba(15,23,42,.40);
6496  backdrop-filter: blur(8px) saturate(1.2);
6497  -webkit-backdrop-filter: blur(8px) saturate(1.2);
6498  opacity: 0; 
6499  pointer-events: none;
6500  z-index: 499;
6501  transition: opacity var(--mm2-transition-base);
6502}
6503.mm2-open .mm2-backdrop { opacity: 1; pointer-events: auto; }
6504
6505/* Panel - Glassmorphism Enhanced */
6506.mm2-panel {
6507  position: fixed;
6508  left: 50%;
6509  top: 120px;
6510  transform: translateX(-50%) translateY(-16px);
6511  width: min(1200px, 95vw);
6512  background: var(--mm2-surface-elevated);
6513  backdrop-filter: blur(20px) saturate(1.8);
6514  -webkit-backdrop-filter: blur(20px) saturate(1.8);
6515  border: 1.5px solid var(--mm2-border-strong);
6516  border-radius: var(--mm2-radius-xl);
6517  box-shadow: var(--mm2-shadow-xl);
6518  display: none;
6519  overflow: hidden;
6520  opacity: 0;
6521  z-index: 500;
6522  transition: transform var(--mm2-transition-slow), opacity var(--mm2-transition-base);
6523}
6524.mm2-open .mm2-panel { 
6525  display: block; 
6526  opacity: 1; 
6527  transform: translateX(-50%) translateY(0);
6528}
6529
6530/* View switcher */
6531.mm2-view { display: none; }
6532.mm2-open .mm2-view.is-active { display: block; }
6533
6534/* Top grid (level-1 tiles) - Enhanced */
6535.mm2-top {
6536  padding: 24px;
6537  max-height: 75vh; overflow: auto;
6538}
6539.mm2-grid {
6540  display: grid;
6541  grid-template-columns: repeat(4, minmax(0,1fr));
6542  gap: 14px;
6543}
6544@media (max-width: 1200px) { .mm2-grid { grid-template-columns: repeat(3, minmax(0,1fr)); } }
6545@media (max-width: 960px)  { .mm2-grid { grid-template-columns: repeat(2, minmax(0,1fr)); gap: 12px; } }
6546
6547/* Stagger animation for cards */
6548.mm2-open .mm2-card {
6549  animation: slideInUp 0.3s cubic-bezier(0.4, 0, 0.2, 1) backwards;
6550}
6551.mm2-open .mm2-card:nth-child(1)  { animation-delay: 0.02s; }
6552.mm2-open .mm2-card:nth-child(2)  { animation-delay: 0.04s; }
6553.mm2-open .mm2-card:nth-child(3)  { animation-delay: 0.06s; }
6554.mm2-open .mm2-card:nth-child(4)  { animation-delay: 0.08s; }
6555.mm2-open .mm2-card:nth-child(5)  { animation-delay: 0.10s; }
6556.mm2-open .mm2-card:nth-child(6)  { animation-delay: 0.12s; }
6557.mm2-open .mm2-card:nth-child(7)  { animation-delay: 0.14s; }
6558.mm2-open .mm2-card:nth-child(8)  { animation-delay: 0.16s; }
6559.mm2-open .mm2-card:nth-child(9)  { animation-delay: 0.18s; }
6560.mm2-open .mm2-card:nth-child(10) { animation-delay: 0.20s; }
6561.mm2-open .mm2-card:nth-child(11) { animation-delay: 0.22s; }
6562.mm2-open .mm2-card:nth-child(12) { animation-delay: 0.24s; }
6563.mm2-open .mm2-card:nth-child(n+13) { animation-delay: 0.26s; }
6564
6565@keyframes slideInUp {
6566  from {
6567    opacity: 0;
6568    transform: translateY(12px);
6569  }
6570  to {
6571    opacity: 1;
6572    transform: translateY(0);
6573  }
6574}
6575
6576.mm2-card {
6577  position: relative;
6578  display: flex; gap: 14px; align-items: center;
6579  padding: 16px; border-radius: var(--mm2-radius-md);
6580  background: var(--mm2-surface);
6581  border: 1.5px solid var(--mm2-border);
6582  text-decoration: none; color: var(--mm2-fg);
6583  transition: all var(--mm2-transition-fast);
6584  min-height: 72px;
6585  box-shadow: var(--mm2-shadow-sm);
6586}
6587.mm2-card:hover { 
6588  border-color: var(--mm2-accent);
6589  background: linear-gradient(135deg, rgba(255,255,255,1), rgba(248,250,252,1));
6590  box-shadow: var(--mm2-shadow-hover);
6591  transform: translateY(-3px);
6592}
6593.mm2-card:active { transform: translateY(-1px); }
6594
6595/* Icon with category-specific gradients */
6596.mm2-card .mm2-ico {
6597  width: 48px; height: 48px; border-radius: 12px;
6598  display: inline-flex; align-items: center; justify-content: center;
6599  background: linear-gradient(135deg, #e0e7ff, #fff);
6600  border: 1.5px solid #c7d2fe;
6601  color: #4f46e5;
6602  flex-shrink: 0;
6603  transition: all var(--mm2-transition-fast);
6604  box-shadow: 0 2px 8px rgba(99,102,241,0.1);
6605}
6606.mm2-card:hover .mm2-ico {
6607  transform: scale(1.08) rotate(2deg);
6608  box-shadow: 0 4px 16px rgba(99,102,241,0.2);
6609}
6610.mm2-card .mm2-ico svg { transition: transform var(--mm2-transition-fast); }
6611.mm2-card:hover .mm2-ico svg { transform: scale(1.1); }
6612
6613.mm2-card .mm2-title { 
6614  font-weight: 700; 
6615  font-size: 15px;
6616  letter-spacing: -0.01em;
6617  line-height: 1.3;
6618}
6619.mm2-card .mm2-sub { 
6620  color: var(--mm2-fg-muted); 
6621  font-size: 12.5px; 
6622  margin-top: 3px;
6623  display: flex;
6624  align-items: center;
6625  gap: 4px;
6626  white-space: nowrap;
6627  overflow: hidden;
6628  text-overflow: ellipsis;
6629}
6630.mm2-card .mm2-count {
6631  display: inline-flex;
6632  padding: 2px 8px;
6633  border-radius: 6px;
6634  background: var(--mm2-accent-10);
6635  color: var(--mm2-accent);
6636  font-weight: 600;
6637  font-size: 11px;
6638  margin-left: 4px;
6639}
6640
6641/* Detail view (level-2 + level-3) - Enhanced */
6642.mm2-detail {
6643  position: relative;
6644  padding: 16px 24px 24px;
6645  max-height: 70vh; overflow: auto;
6646}
6647.mm2-detail-header {
6648  display: flex; align-items: center; gap: 14px;
6649  padding: 10px 0 16px; border-bottom: 2px solid var(--mm2-muted); margin-bottom: 16px;
6650}
6651.mm2-back {
6652  display: inline-flex; align-items: center; justify-content: center;
6653  width: 40px; height: 40px; border-radius: 12px;
6654  border: 1.5px solid var(--mm2-border); background: #fff; color: var(--mm2-fg);
6655  cursor: pointer;
6656  transition: all var(--mm2-transition-fast);
6657  box-shadow: var(--mm2-shadow-sm);
6658}
6659.mm2-back:hover {
6660  border-color: var(--mm2-accent);
6661  background: var(--mm2-muted);
6662  transform: translateX(-3px);
6663  box-shadow: var(--mm2-shadow-md);
6664}
6665.mm2-detail-title { 
6666  font-weight: 800; 
6667  font-size: 18px;
6668  letter-spacing: -0.02em;
6669}
6670
6671/* Two-pane layout (desktop) - Enhanced */
6672.mm2-detail-layout {
6673  display: grid;
6674  grid-template-columns: 280px 1fr;
6675  gap: 20px;
6676}
6677
6678/* Left: subnav (level-2 list) - Enhanced */
6679.mm2-subnav {
6680  position: sticky; top: 8px;
6681  align-self: start;
6682  max-height: calc(70vh - 56px);
6683  overflow: auto;
6684  padding-right: 6px;
6685}
6686.mm2-subnav::-webkit-scrollbar { width: 8px; height: 8px; }
6687.mm2-subnav::-webkit-scrollbar-track { background: transparent; }
6688.mm2-subnav::-webkit-scrollbar-thumb { background: #cbd5e1; border-radius: 8px; }
6689.mm2-subnav::-webkit-scrollbar-thumb:hover { background: #94a3b8; }
6690
6691.mm2-subitem {
6692  display: flex; align-items: center; justify-content: flex-start; gap: 10px;
6693  width: 100%;
6694  padding: 12px 14px;
6695  border-radius: 12px;
6696  border: 1.5px solid transparent;
6697  background: transparent;
6698  color: var(--mm2-fg);
6699  cursor: pointer;
6700  text-align: left;
6701  transition: all var(--mm2-transition-fast);
6702  margin-bottom: 6px;
6703  font-weight: 600;
6704  font-size: 14px;
6705  position: relative;
6706}
6707.mm2-subitem::before {
6708  content: '';
6709  position: absolute;
6710  left: 0;
6711  top: 50%;
6712  transform: translateY(-50%);
6713  width: 3px;
6714  height: 0;
6715  background: var(--mm2-accent);
6716  border-radius: 0 2px 2px 0;
6717  transition: height var(--mm2-transition-fast);
6718}
6719.mm2-subitem:hover { 
6720  background: var(--mm2-muted);
6721  color: var(--mm2-accent-hover);
6722}
6723.mm2-subitem.active {
6724  background: linear-gradient(135deg, rgba(99,102,241,0.08), rgba(99,102,241,0.04));
6725  border-color: var(--mm2-accent-20);
6726  color: var(--mm2-accent-hover);
6727  box-shadow: inset 0 0 0 1px rgba(99,102,241,0.1);
6728}
6729.mm2-subitem.active::before {
6730  height: 24px;
6731}
6732
6733/* Right: subcontent (level-3 grid) - Enhanced */
6734.mm2-subcontent { min-height: 240px; }
6735.mm2-links {
6736  display: grid; gap: 12px 14px;
6737  grid-template-columns: repeat(3, minmax(0,1fr));
6738}
6739@media (max-width: 1200px) { .mm2-links { grid-template-columns: repeat(2, minmax(0,1fr)); } }
6740
6741.mm2-link {
6742  display: flex; align-items: center; gap: 12px;
6743  padding: 14px; border: 1.5px solid var(--mm2-border); border-radius: var(--mm2-radius-md);
6744  background: var(--mm2-surface); color: var(--mm2-fg); text-decoration: none;
6745  min-height: 52px;
6746  font-weight: 500;
6747  font-size: 14px;
6748  transition: all var(--mm2-transition-fast);
6749  box-shadow: var(--mm2-shadow-sm);
6750  position: relative;
6751  justify-content: space-between;
6752}
6753.mm2-link:hover { 
6754  background: var(--mm2-muted); 
6755  border-color: var(--mm2-accent);
6756  transform: translateX(4px);
6757  box-shadow: var(--mm2-shadow-md);
6758}
6759.mm2-link-text {
6760  flex: 1;
6761}
6762
6763/* Product Thumbnails */
6764.mm2-thumbs {
6765  display: flex;
6766  gap: 6px;
6767  align-items: center;
6768  margin-left: auto;
6769  flex-shrink: 0;
6770}
6771.mm2-thumb {
6772  width: 36px;
6773  height: 36px;
6774  border-radius: 8px;
6775  object-fit: cover;
6776  border: 1.5px solid var(--mm2-border);
6777  box-shadow: 0 2px 6px rgba(0,0,0,0.08);
6778  transition: all var(--mm2-transition-fast);
6779  background: var(--mm2-muted);
6780}
6781.mm2-link:hover .mm2-thumb {
6782  border-color: var(--mm2-accent);
6783  box-shadow: 0 4px 10px rgba(99,102,241,0.15);
6784  transform: scale(1.08);
6785}
6786
6787/* Thumbnail Skeleton Loader */
6788.mm2-thumb-skeleton {
6789  width: 36px;
6790  height: 36px;
6791  border-radius: 8px;
6792  background: linear-gradient(90deg, #f1f5f9 25%, #e2e8f0 50%, #f1f5f9 75%);
6793  background-size: 200% 100%;
6794  animation: shimmer 1.5s infinite;
6795  border: 1.5px solid var(--mm2-border);
6796}
6797
6798.mm2-badge {
6799  font-size: 11px; padding: 3px 10px; margin-left: auto;
6800  border-radius: 12px; background: var(--mm2-accent-10); color: var(--mm2-accent);
6801  font-weight: 700;
6802  border: 1px solid var(--mm2-accent-20);
6803}
6804
6805/* "See all" highlight card - Enhanced */
6806.mm2-seeall {
6807  border: 2px dashed var(--mm2-accent);
6808  background: linear-gradient(135deg, rgba(99,102,241,.08), rgba(99,102,241,.02));
6809  font-weight: 700;
6810}
6811.mm2-seeall:hover {
6812  background: linear-gradient(135deg, rgba(99,102,241,.14), rgba(99,102,241,.06));
6813  border-style: solid;
6814  transform: translateX(6px) scale(1.02);
6815}
6816
6817/* Mobile panel styles - Enhanced with drag handle & better touch targets */
6818@media (max-width: 960px) {
6819  .mm2-panel {
6820    position: fixed;
6821    left: 0;
6822    right: 0;
6823    bottom: 0;
6824    top: auto;
6825    width: 100%;
6826    max-height: 88vh;
6827    transform: translateX(0) translateY(100%);
6828    border-radius: var(--mm2-radius-xl) var(--mm2-radius-xl) 0 0;
6829    border-bottom: none;
6830  }
6831  .mm2-open .mm2-panel {
6832    transform: translateX(0) translateY(0); z-index: 9999;
6833  }
6834  
6835  /* Enhanced backdrop for mobile */
6836  .mm2-backdrop {
6837    backdrop-filter: blur(6px) saturate(1.2);
6838    -webkit-backdrop-filter: blur(6px) saturate(1.2);
6839  }
6840  
6841  /* Mobile close button - Soft glassmorphism */
6842  .mm2-mobile-close {
6843    position: absolute;
6844    top: 4px;
6845    right: 8px;
6846    width: 28px;
6847    height: 28px;
6848    border-radius: 50%;
6849    border: 1px solid rgba(226, 232, 240, 0.6);
6850    background: rgba(255, 255, 255, 0.85);
6851    backdrop-filter: blur(12px) saturate(1.8);
6852    -webkit-backdrop-filter: blur(12px) saturate(1.8);
6853    color: var(--mm2-fg-muted);
6854    display: inline-flex;
6855    align-items: center;
6856    justify-content: center;
6857    cursor: pointer;
6858    transition: all var(--mm2-transition-fast);
6859    box-shadow: 0 2px 8px rgba(15, 23, 42, 0.08);
6860    z-index: 20;
6861  }
6862  .mm2-mobile-close:hover {
6863    background: rgba(254, 242, 242, 0.95);
6864    border-color: rgba(226,166,66,0.8);
6865    color: #C77DFF;
6866    box-shadow: 0 4px 12px rgba(226,166,66,0.15);
6867  }
6868  .mm2-mobile-close:active {
6869    transform: scale(0.92);
6870  }
6871  
6872  /* Drag handle indicator */
6873  .mm2-top::before,
6874  .mm2-detail::before {
6875    content: '';
6876    position: sticky;
6877    top: 0;
6878    left: 50%;
6879    transform: translateX(-50%);
6880    width: 40px;
6881    height: 4px;
6882    background: var(--mm2-border-strong);
6883    border-radius: 999px;
6884    margin: 12px auto 20px;
6885    display: block;
6886    z-index: 10;
6887    transition: background var(--mm2-transition-fast);
6888  }
6889  .mm2-panel:active .mm2-top::before,
6890  .mm2-panel:active .mm2-detail::before {
6891    background: #94a3b8;
6892  }
6893  
6894  .mm2-top {
6895    padding: 10px;  
6896  }
6897  
6898  .mm2-top, .mm2-detail { 
6899    max-height: min(82vh, 720px);
6900    padding-top: 8px;
6901  }
6902
6903  /* Two-pane collapses: subnav becomes GRID (no horizontal scroll) */
6904  .mm2-detail-layout { display: block; }
6905  .mm2-subnav {
6906    position: static; max-height: none; overflow: visible;
6907    display: grid; gap: 10px; padding: 10px 4px 16px; margin-bottom: 16px;
6908    grid-template-columns: repeat(2, minmax(0,1fr));
6909    border-bottom: 2px solid var(--mm2-muted);
6910  }
6911  .mm2-subitem {
6912    margin: 0; width: 100%; text-align: center;
6913    border-radius: 14px;
6914    background: #fff; border: 1.5px solid var(--mm2-border);
6915    white-space: normal; line-height: 1.3; min-height: 48px;
6916    justify-content: center;
6917    padding: 12px 10px;
6918    font-size: 13.5px;
6919    box-shadow: var(--mm2-shadow-sm);
6920  }
6921  .mm2-subitem::before { display: none; }
6922  .mm2-subitem:hover {
6923    transform: scale(1.02);
6924  }
6925  .mm2-subitem.active {
6926    background: linear-gradient(135deg, var(--mm2-accent), var(--mm2-accent-hover));
6927    border-color: var(--mm2-accent-hover);
6928    color: white;
6929    box-shadow: 0 4px 12px rgba(99,102,241,0.3);
6930    font-weight: 700;
6931  }
6932
6933  /* Level-3 grid tetap 2 kolom dengan spacing lebih baik */
6934  .mm2-links { 
6935    grid-template-columns: repeat(2, minmax(0,1fr));
6936    gap: 10px;
6937  }
6938  
6939  /* Mobile: hide thumbnails untuk save space */
6940  .mm2-thumbs {
6941    display: none;
6942  }
6943  
6944  /* Larger touch targets for mobile */
6945  .mm2-card {
6946    min-height: 80px;
6947    padding: 18px 14px;
6948  }
6949  .mm2-card .mm2-ico {
6950    width: 50px;
6951    height: 50px;
6952  }
6953  .mm2-card .mm2-title {
6954    font-size: 14px;
6955  }
6956  .mm2-card .mm2-sub {
6957    font-size: 11.5px;
6958  }
6959  .mm2-link {
6960    min-height: 56px;
6961    padding: 16px;
6962  }
6963  .mm2-back {
6964    width: 44px;
6965    height: 44px;
6966  }
6967  
6968  /* Grid spacing */
6969  .mm2-grid {
6970    gap: 10px;
6971  }
6972}
6973</style>
6974  <style data-inlined="product-compare.css">
6975/* Product Compare Feature Styles */
6976
6977/* Compare Button in Product Detail - Modern Chip Style */
6978.pd-compare-section {
6979  margin: 0.5rem 0;
6980  display: flex;
6981  align-items: center;
6982  gap: 0.5rem;
6983}
6984
6985.pd-compare-btn {
6986  display: inline-flex;
6987  align-items: center;
6988  gap: 0.4rem;
6989  padding: 0.5rem 0.85rem;
6990  border: 1px solid #cbd5e1;
6991  border-radius: 20px;
6992  background: #fff;
6993  color: #64748b;
6994  font-weight: 600;
6995  font-size: 0.8rem;
6996  cursor: pointer;
6997  transition: all 0.2s ease;
6998  position: relative;
6999  white-space: nowrap;
7000}
7001
7002.pd-compare-btn:hover {
7003  border-color: #3b82f6;
7004  color: #3b82f6;
7005  background: #f0f9ff;
7006  transform: translateY(-1px);
7007  box-shadow: 0 2px 6px rgba(59, 130, 246, 0.15);
7008}
7009
7010.pd-compare-btn.added {
7011  border-color: #16a34a;
7012  color: #16a34a;
7013  background: #f0fdf4;
7014}
7015
7016.pd-compare-btn .compare-remove {
7017  display: none;
7018}
7019
7020.pd-compare-btn.added .compare-text {
7021  display: none;
7022}
7023
7024.pd-compare-btn.added .compare-remove {
7025  display: flex !important;
7026  align-items: center;
7027  gap: 0.25rem;
7028  font-weight: 600;
7029  font-size: 0.9rem;
7030  color: #C77DFF !important;
7031  opacity: 1 !important;
7032  visibility: visible !important;
7033  z-index: 1;
7034  position: relative;
7035}
7036
7037.pd-compare-btn.added .compare-remove[hidden] {
7038  display: flex !important;
7039}
7040
7041/* Force visibility for added state */
7042.pd-compare-btn.added .compare-remove {
7043  display: flex !important;
7044}
7045
7046[hidden].compare-remove {
7047  display: none !important;
7048}
7049
7050.pd-compare-btn.added [hidden].compare-remove {
7051  display: flex !important;
7052}
7053
7054/* Ensure the added state text is always visible */
7055.pd-compare-btn.added {
7056  border-color: #C77DFF !important;
7057  color: #C77DFF !important;
7058  background: #fef2f2 !important;
7059}
7060
7061.pd-compare-btn.added .compare-remove svg {
7062  color: #C77DFF !important;
7063}
7064
7065.pd-compare-btn.added:hover {
7066  border-color: #15803d;
7067  color: #15803d;
7068  background: #dcfce7;
7069  transform: translateY(-1px);
7070  box-shadow: 0 2px 6px rgba(22, 163, 74, 0.2);
7071}
7072
7073.pd-compare-btn .compare-icon {
7074  width: 16px;
7075  height: 16px;
7076  flex-shrink: 0;
7077}
7078
7079.pd-compare-info {
7080  display: inline-flex;
7081  align-items: center;
7082}
7083
7084.compare-note {
7085  color: #94a3b8;
7086  font-size: 0.7rem;
7087  font-weight: 500;
7088  transition: color 0.2s ease;
7089}
7090
7091.pd-compare-btn.added + .pd-compare-info .compare-note {
7092  color: #16a34a;
7093  font-weight: 600;
7094}
7095
7096/* Compare Badge in Navigation */
7097.compare-indicator {
7098  position: relative;
7099}
7100
7101.compare-indicator .badge {
7102  position: absolute;
7103  top: -8px;
7104  right: -8px;
7105  min-width: 18px;
7106  height: 18px;
7107  padding: 0 5px;
7108  background: #C77DFF;
7109  color: white;
7110  border-radius: 9px;
7111  font-size: 11px;
7112 
7113
7114/* Floating Compare Badge (Sticky) */
7115.compare-floating-badge {
7116  position: fixed;
7117  right: 16px;
7118  bottom: calc(20px + 60px); /* Above scroll-to-top button */
7119  width: auto;
7120  min-width: 56px;
7121  height: 56px;
7122  padding: 0 16px;
7123  border-radius: 28px;
7124  background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%);
7125  color: #fff;
7126  box-shadow: 0 8px 24px -8px rgba(59, 130, 246, 0.5);
7127  cursor: pointer;
7128  z-index: 1104;
7129  opacity: 0;
7130  transform: translateY(8px) scale(0.9);
7131  transition: opacity 0.3s ease, transform 0.3s ease, box-shadow 0.2s ease;
7132  display: flex;
7133  align-items: center;
7134  justify-content: center;
7135  gap: 8px;
7136  font-weight: 600;
7137  font-size: 0.85rem;
7138  pointer-events: none;
7139}
7140
7141.compare-floating-badge.visible {
7142  opacity: 1;
7143  transform: translateY(0) scale(1);
7144  pointer-events: auto;
7145}
7146
7147.compare-floating-badge:hover {
7148  box-shadow: 0 12px 32px -10px rgba(59, 130, 246, 0.6);
7149  transform: translateY(-2px) scale(1.02);
7150}
7151
7152.compare-floating-badge:active {
7153  transform: translateY(0) scale(0.98);
7154}
7155
7156.compare-floating-badge .cfb-icon {
7157  width: 20px;
7158  height: 20px;
7159  flex-shrink: 0;
7160}
7161
7162.compare-floating-badge .cfb-count {
7163  font-size: 0.9rem;
7164  font-weight: 700;
7165  min-width: 20px;
7166  text-align: center;
7167  background: rgba(255, 255, 255, 0.25);
7168  padding: 2px 8px;
7169  border-radius: 12px;
7170  line-height: 1;
7171  display: flex;
7172  align-items: center;
7173  justify-content: center;
7174  height: 24px;
7175}
7176
7177.compare-floating-badge .cfb-text {
7178  display: none;
7179}
7180
7181@media (min-width: 641px) {
7182  .compare-floating-badge .cfb-text {
7183    display: block;
7184    white-space: nowrap;
7185  }
7186}
7187
7188@media (max-width: 640px) {
7189  .compare-floating-badge {
7190    right: 14px;
7191    bottom: calc(var(--scroll-top-bottom, calc(68px + 18px + env(safe-area-inset-bottom))) + 60px);
7192    min-width: 48px;
7193    height: 48px;
7194    padding: 0 12px;
7195    border-radius: 24px;
7196  }
7197  
7198  .compare-floating-badge .cfb-icon {
7199    width: 18px;
7200    height: 18px;
7201  }
7202  
7203  .compare-floating-badge .cfb-count {
7204    font-size: 0.8rem;
7205    padding: 2px 6px;
7206    height: 20px;
7207  }
7208} font-weight: 600;
7209  display: flex;
7210  align-items: center;
7211  justify-content: center;
7212  transform: scale(0);
7213  transition: transform 0.2s ease;
7214}
7215
7216.compare-indicator .badge.active {
7217  transform: scale(1);
7218}
7219
7220/* Compare Sidebar */
7221.compare-sidebar {
7222  position: fixed;
7223  top: 0;
7224  right: -400px;
7225  width: 400px;
7226  height: 100vh;
7227  background: #ffffff;
7228  box-shadow: -4px 0 20px rgba(0, 0, 0, 0.1);
7229  z-index: 9999;
7230  display: flex;
7231  flex-direction: column;
7232  transition: right 0.3s ease;
7233}
7234
7235.compare-sidebar.open {
7236  right: 0;
7237}
7238
7239.compare-overlay {
7240  position: fixed;
7241  top: 0;
7242  left: 0;
7243  width: 100%;
7244  height: 100%;
7245  background: rgba(0, 0, 0, 0.5);
7246  z-index: 9998;
7247  opacity: 0;
7248  visibility: hidden;
7249  transition: all 0.3s ease;
7250}
7251
7252.compare-overlay.active {
7253  opacity: 1;
7254  visibility: visible;
7255}
7256
7257.compare-header {
7258  display: flex;
7259  align-items: center;
7260  justify-content: space-between;
7261  padding: 1.25rem;
7262  border-bottom: 1px solid #e2e8f0;
7263  background: #f8fafc;
7264}
7265
7266.compare-title {
7267  display: flex;
7268  align-items: center;
7269  gap: 0.5rem;
7270  font-size: 1rem;
7271  font-weight: 600;
7272  color: #1e293b;
7273  margin: 0;
7274}
7275
7276.compare-count {
7277  color: #64748b;
7278  font-weight: 400;
7279}
7280
7281.compare-close {
7282  display: flex;
7283  align-items: center;
7284  justify-content: center;
7285  width: 32px;
7286  height: 32px;
7287  border: none;
7288  border-radius: 6px;
7289  background: transparent;
7290  color: #64748b;
7291  cursor: pointer;
7292  transition: all 0.2s ease;
7293}
7294
7295.compare-close:hover {
7296  background: #e2e8f0;
7297  color: #374151;
7298}
7299
7300.compare-content {
7301  flex: 1;
7302  overflow-y: auto;
7303  padding: 1rem;
7304}
7305
7306.compare-empty {
7307  display: flex;
7308  flex-direction: column;
7309  align-items: center;
7310  justify-content: center;
7311  height: 100%;
7312  text-align: center;
7313  padding: 2rem 1rem;
7314}
7315
7316.compare-empty h5 {
7317  margin: 1rem 0 0.5rem;
7318  color: #374151;
7319}
7320
7321.compare-empty p {
7322  color: #64748b;
7323  font-size: 0.875rem;
7324  line-height: 1.5;
7325}
7326
7327.compare-list {
7328  display: flex;
7329  flex-direction: column;
7330  gap: 0.75rem;
7331}
7332
7333.compare-item {
7334  display: flex;
7335  align-items: center;
7336  gap: 0.75rem;
7337  padding: 0.75rem;
7338  border: 1px solid #e2e8f0;
7339  border-radius: 8px;
7340  background: #ffffff;
7341  transition: all 0.2s ease;
7342}
7343
7344.compare-item:hover {
7345  border-color: #cbd5e1;
7346  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
7347}
7348
7349.compare-item-image {
7350  flex-shrink: 0;
7351  width: 48px;
7352  height: 48px;
7353  border-radius: 6px;
7354  overflow: hidden;
7355  border: 1px solid #e2e8f0;
7356}
7357
7358.compare-item-image img {
7359  width: 100%;
7360  height: 100%;
7361  object-fit: cover;
7362}
7363
7364.compare-item-info {
7365  flex: 1;
7366  min-width: 0;
7367}
7368
7369.compare-item-name {
7370  font-weight: 500;
7371  font-size: 0.875rem;
7372  color: #1e293b;
7373  margin-bottom: 0.25rem;
7374  line-height: 1.3;
7375  display: -webkit-box;
7376  -webkit-line-clamp: 2;
7377  -webkit-box-orient: vertical;
7378  overflow: hidden;
7379}
7380
7381.compare-item-price {
7382  font-weight: 600;
7383  font-size: 0.8rem;
7384  color: #059669;
7385}
7386
7387.compare-item-remove {
7388  flex-shrink: 0;
7389  display: flex;
7390  align-items: center;
7391  justify-content: center;
7392  width: 28px;
7393  height: 28px;
7394  border: none;
7395  border-radius: 4px;
7396  background: transparent;
7397  color: #C77DFF;
7398  cursor: pointer;
7399  transition: all 0.2s ease;
7400}
7401
7402.compare-item-remove:hover {
7403  background: #fef2f2;
7404  color: #E3D05A;
7405}
7406
7407.compare-actions {
7408  padding: 1rem;
7409  border-top: 1px solid #e2e8f0;
7410  display: flex;
7411  gap: 0.75rem;
7412}
7413
7414.compare-actions .btn {
7415  flex: 1;
7416  padding: 0.75rem 1rem;
7417  border-radius: 6px;
7418  font-weight: 600;
7419  font-size: 0.875rem;
7420  display: flex;
7421  align-items: center;
7422  justify-content: center;
7423  gap: 0.5rem;
7424  cursor: pointer;
7425  transition: all 0.2s ease;
7426}
7427
7428.btn-outline-danger {
7429  border: 1px solid #C77DFF;
7430  background: transparent;
7431  color: #C77DFF;
7432}
7433
7434.btn-outline-danger:hover {
7435  background: #C77DFF;
7436  color: white;
7437}
7438
7439.btn-primary {
7440  border: 1px solid #3b82f6;
7441  background: #3b82f6;
7442  color: white;
7443}
7444
7445.btn-primary:hover {
7446  background: #2563eb;
7447  border-color: #2563eb;
7448}
7449
7450.btn-primary:disabled {
7451  opacity: 0.5;
7452  cursor: not-allowed;
7453}
7454
7455.btn-primary:disabled:hover {
7456  background: #3b82f6;
7457  border-color: #3b82f6;
7458}
7459
7460/* AI Comparison Modal */
7461.ai-compare-modal {
7462  position: fixed;
7463  top: 0;
7464  left: 0;
7465  width: 100%;
7466  height: 100%;
7467  z-index: 10000;
7468  display: none;
7469  align-items: center;
7470  justify-content: center;
7471}
7472
7473.ai-compare-modal.open {
7474  display: flex;
7475}
7476
7477.ai-compare-modal .modal-backdrop {
7478  position: absolute;
7479  top: 0;
7480  left: 0;
7481  width: 100%;
7482  height: 100%;
7483  background: rgba(0, 0, 0, 0.6);
7484  backdrop-filter: blur(4px);
7485}
7486
7487.modal-container {
7488  position: relative;
7489  width: 90%;
7490  max-width: 1000px;
7491  max-height: 90vh;
7492  background: #ffffff;
7493  border-radius: 12px;
7494  box-shadow: 0 20px 40px rgba(0, 0, 0, 0.15);
7495  display: flex;
7496  flex-direction: column;
7497  overflow: hidden;
7498}
7499
7500.modal-header {
7501  display: flex;
7502  align-items: center;
7503  justify-content: space-between;
7504  padding: 1.5rem 2rem;
7505  border-bottom: 1px solid #e2e8f0;
7506  background: #f8fafc;
7507}
7508
7509.modal-title {
7510  display: flex;
7511  align-items: center;
7512  gap: 0.75rem;
7513  font-size: 1.25rem;
7514  font-weight: 600;
7515  color: #1e293b;
7516  margin: 0;
7517}
7518
7519.modal-close {
7520  display: flex;
7521  align-items: center;
7522  justify-content: center;
7523  width: 36px;
7524  height: 36px;
7525  border: none;
7526  border-radius: 8px;
7527  background: transparent;
7528  color: #64748b;
7529  cursor: pointer;
7530  transition: all 0.2s ease;
7531}
7532
7533.modal-close:hover {
7534  background: #e2e8f0;
7535  color: #374151;
7536}
7537
7538.modal-content {
7539  flex: 1;
7540  overflow-y: auto;
7541  padding: 2rem;
7542}
7543
7544/* AI Loading State */
7545.ai-loading {
7546  display: flex;
7547  flex-direction: column;
7548  align-items: center;
7549  justify-content: center;
7550  padding: 3rem 2rem;
7551  text-align: center;
7552}
7553
7554.loading-animation {
7555  margin-bottom: 1rem;
7556}
7557
7558.typing-indicator {
7559  display: flex;
7560  align-items: center;
7561  justify-content: center;
7562  gap: 4px;
7563  margin-bottom: 1rem;
7564}
7565
7566.typing-indicator span {
7567  width: 8px;
7568  height: 8px;
7569  background: #3b82f6;
7570  border-radius: 50%;
7571  animation: typing 1.4s infinite ease-in-out;
7572}
7573
7574.typing-indicator span:nth-child(2) {
7575  animation-delay: 0.2s;
7576}
7577
7578.typing-indicator span:nth-child(3) {
7579  animation-delay: 0.4s;
7580}
7581
7582@keyframes typing {
7583  0%, 80%, 100% {
7584    opacity: 0.3;
7585    transform: scale(0.8);
7586  }
7587  40% {
7588    opacity: 1;
7589    transform: scale(1);
7590  }
7591}
7592
7593.ai-loading p {
7594  font-weight: 500;
7595  color: #1e293b;
7596  margin-bottom: 0.5rem;
7597}
7598
7599.ai-loading small {
7600  color: #64748b;
7601}
7602
7603/* AI Error State */
7604.ai-error {
7605  display: flex;
7606  flex-direction: column;
7607  align-items: center;
7608  justify-content: center;
7609  padding: 3rem 2rem;
7610  text-align: center;
7611}
7612
7613.ai-error h4 {
7614  margin: 1rem 0 0.5rem;
7615  color: #C77DFF;
7616}
7617
7618.ai-error p {
7619  color: #64748b;
7620  margin-bottom: 1.5rem;
7621}
7622
7623/* AI Results */
7624.ai-results > div {
7625  margin-bottom: 2rem;
7626}
7627
7628.ai-summary-card,
7629.ai-comparison-table,
7630.ai-detailed-analysis,
7631.ai-recommendations,
7632.ai-tips {
7633  background: #f8fafc;
7634  border: 1px solid #e2e8f0;
7635  border-radius: 12px;
7636  padding: 1.5rem;
7637}
7638
7639.ai-results h4 {
7640  display: flex;
7641  align-items: center;
7642  gap: 0.5rem;
7643  font-size: 1.1rem;
7644  font-weight: 600;
7645  color: #1e293b;
7646  margin-bottom: 1rem;
7647}
7648
7649.summary-text {
7650  font-size: 1rem;
7651  line-height: 1.6;
7652  color: #374151;
7653  margin-bottom: 1rem;
7654}
7655
7656.winner-badge {
7657  padding: 1rem;
7658  background: linear-gradient(135deg, #10b981 0%, #059669 100%);
7659  color: white;
7660  border-radius: 8px;
7661}
7662
7663.winner-badge strong {
7664  display: block;
7665  margin-bottom: 0.25rem;
7666}
7667
7668.winner-badge small {
7669  opacity: 0.9;
7670  font-size: 0.875rem;
7671}
7672
7673/* Comparison Table */
7674.comparison-grid {
7675  display: grid;
7676  gap: 1rem;
7677  margin-top: 1rem;
7678}
7679
7680.comparison-category {
7681  background: white;
7682  border: 1px solid #e2e8f0;
7683  border-radius: 8px;
7684  overflow: hidden;
7685}
7686
7687.category-header {
7688  background: #f1f5f9;
7689  padding: 0.75rem 1rem;
7690  font-weight: 600;
7691  color: #1e293b;
7692  border-bottom: 1px solid #e2e8f0;
7693}
7694
7695.category-products {
7696  display: grid;
7697  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
7698  gap: 1px;
7699  background: #e2e8f0;
7700}
7701
7702.product-score {
7703  background: white;
7704  padding: 1rem;
7705  text-align: center;
7706}
7707
7708.score-value {
7709  display: inline-flex;
7710  align-items: center;
7711  gap: 0.25rem;
7712  margin-bottom: 0.5rem;
7713}
7714
7715.score-stars {
7716  color: #C77DFF;
7717}
7718
7719.score-note {
7720  font-size: 0.8rem;
7721  color: #64748b;
7722  line-height: 1.3;
7723}
7724
7725/* Product name header in comparison table */
7726.product-name-header {
7727  margin-bottom: 0.5rem;
7728}
7729
7730.product-name-header strong {
7731  font-size: .8rem; /* h5 size (18px) */
7732  font-weight: 600;
7733  color: #1e293b;
7734  line-height: 1.3;
7735  display: block;
7736  word-break: break-word;
7737}
7738
7739.product-price {
7740  font-size: 0.8rem;
7741  font-weight: 600;
7742  color: #059669;
7743}
7744
7745/* Detailed Analysis */
7746.products-analysis {
7747  display: grid;
7748  gap: 1rem;
7749  margin-top: 1rem;
7750}
7751
7752.product-analysis {
7753  background: white;
7754  border: 1px solid #e2e8f0;
7755  border-radius: 8px;
7756  padding: 1rem;
7757}
7758
7759.product-analysis h5 {
7760  color: #1e293b;
7761  margin-bottom: 0.75rem;
7762  font-weight: 600;
7763}
7764
7765.analysis-section {
7766  margin-bottom: 0.75rem;
7767}
7768
7769.analysis-section:last-child {
7770  margin-bottom: 0;
7771}
7772
7773.analysis-section h6 {
7774  font-size: 0.875rem;
7775  font-weight: 600;
7776  margin-bottom: 0.5rem;
7777}
7778
7779.analysis-section h6.strengths {
7780  color: #059669;
7781}
7782
7783.analysis-section h6.weaknesses {
7784  color: #C77DFF;
7785}
7786
7787.analysis-section h6.best-for {
7788  color: #7c3aed;
7789}
7790
7791.analysis-section ul {
7792  list-style: none;
7793  padding: 0;
7794  margin: 0;
7795}
7796
7797.analysis-section li {
7798  display: flex;
7799  align-items: flex-start;
7800  gap: 0.5rem;
7801  margin-bottom: 0.25rem;
7802  font-size: 0.875rem;
7803  line-height: 1.4;
7804}
7805
7806.analysis-section li:before {
7807  content: "•";
7808  color: #64748b;
7809  font-weight: bold;
7810  margin-top: 0.1rem;
7811}
7812
7813.best-for-text {
7814  font-size: 0.875rem;
7815  color: #374151;
7816  font-style: italic;
7817}
7818
7819/* Recommendations */
7820.recommendations-grid {
7821  display: grid;
7822  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
7823  gap: 1rem;
7824  margin-top: 1rem;
7825}
7826
7827.recommendation-card {
7828  background: white;
7829  border: 1px solid #e2e8f0;
7830  border-radius: 8px;
7831  padding: 1rem;
7832  text-align: center;
7833}
7834
7835.recommendation-card h5 {
7836  font-size: 1rem;
7837  margin-bottom: 0.75rem;
7838  color: #1e293b;
7839}
7840
7841.recommendation-card p {
7842  font-size: 0.875rem;
7843  color: #374151;
7844  line-height: 1.5;
7845}
7846
7847/* Tips */
7848.tips-list {
7849  list-style: none;
7850  padding: 0;
7851  margin: 1rem 0 0 0;
7852}
7853
7854.tips-list li {
7855  display: flex;
7856  align-items: flex-start;
7857  gap: 0.75rem;
7858  margin-bottom: 0.75rem;
7859  font-size: 0.9rem;
7860  line-height: 1.5;
7861  color: #374151;
7862}
7863
7864.tips-list li:before {
7865  content: "💡";
7866  font-size: 1rem;
7867  margin-top: 0.1rem;
7868}
7869
7870/* Modal Footer */
7871.modal-footer {
7872  display: flex;
7873  justify-content: space-between;
7874  align-items: center;
7875  padding: 1.5rem 2rem;
7876  border-top: 1px solid #e2e8f0;
7877  background: #f8fafc;
7878}
7879
7880.btn-outline-secondary {
7881  border: 1px solid #64748b;
7882  background: transparent;
7883  color: #64748b;
7884  padding: 0.75rem 1.5rem;
7885  border-radius: 6px;
7886  font-weight: 600;
7887  display: flex;
7888  align-items: center;
7889  gap: 0.5rem;
7890  cursor: pointer;
7891  transition: all 0.2s ease;
7892}
7893
7894.btn-outline-secondary:hover {
7895  background: #64748b;
7896  color: white;
7897}
7898
7899/* Responsive for chip button */
7900@media (max-width: 880px) {
7901  .pd-compare-section {
7902    margin: 1rem 0;
7903    display: block;
7904  }
7905
7906  .pd-compare-btn {
7907    width: 100%;
7908    font-size: 0.85rem;
7909    padding: 0.65rem 1rem;
7910    border-radius: 10px;
7911    justify-content: center;
7912    min-height: 44px;
7913  }
7914  
7915  .pd-compare-btn .compare-icon {
7916    width: 16px;
7917    height: 16px;
7918  }
7919
7920  .pd-compare-info {
7921    margin-top: 0.5rem;
7922    display: block;
7923    text-align: center;
7924  }
7925
7926  .compare-note {
7927    font-size: 0.7rem;
7928    display: block;
7929  }
7930}
7931
7932/* Responsive Design */
7933@media (max-width: 768px) {
7934  .compare-sidebar {
7935    width: 100%;
7936    right: -100%;
7937    /* Fix for mobile viewport height changes */
7938    height: 100vh;
7939    height: 100dvh; /* Dynamic viewport height for modern browsers */
7940  }
7941  
7942  .compare-actions {
7943    /* Ensure actions are always visible */
7944    position: sticky;
7945    bottom: 0;
7946    background: white;
7947    border-top: 2px solid #e2e8f0;
7948    box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.1);
7949    z-index: 10;
7950  }
7951  
7952  .compare-actions .btn {
7953    /* Larger touch targets for mobile */
7954    min-height: 48px;
7955    font-size: 0.9rem;
7956    font-weight: 700;
7957  }
7958  
7959  .modal-container {
7960    width: 95%;
7961    max-height: 95vh;
7962    max-height: 95dvh; /* Dynamic viewport height */
7963  }
7964  
7965  .modal-header,
7966  .modal-content,
7967  .modal-footer {
7968    padding: 1rem;
7969  }
7970  
7971  .recommendations-grid {
7972    grid-template-columns: 1fr;
7973  }
7974  
7975  .category-products {
7976    grid-template-columns: 1fr;
7977  }
7978  
7979  .modal-footer {
7980    flex-direction: column;
7981    gap: 0.75rem;
7982  }
7983  
7984  .modal-footer .btn {
7985    width: 100%;
7986  }
7987  
7988  /* Ensure compare button is visible on mobile */
7989  .pd-compare-section {
7990    display: block !important;
7991    visibility: visible !important;
7992    opacity: 1 !important;
7993    margin: 1rem 0;
7994    padding: 0;
7995    position: relative !important;
7996    z-index: 1 !important;
7997    max-width: 100%;
7998    overflow: hidden;
7999  }
8000  
8001  .pd-compare-btn {
8002    display: flex !important;
8003    visibility: visible !important;
8004    opacity: 1 !important;
8005    width: 100%;
8006    padding: 0.75rem 1rem;
8007    font-size: 0.9rem;
8008    min-height: 48px; /* Minimum touch target for mobile */
8009    border: 2px solid #e2e8f0 !important;
8010    background: #fff !important;
8011    position: relative !important;
8012    z-index: 2 !important;
8013    box-sizing: border-box;
8014    white-space: normal !important; /* Allow text wrapping on mobile */
8015    flex-wrap: wrap;
8016    gap: 0.5rem;
8017  }
8018  
8019  .pd-compare-btn .compare-text {
8020    display: inline !important;
8021    visibility: visible !important;
8022    font-weight: 600;
8023    color: #475569 !important;
8024  }
8025  
8026  .pd-compare-btn .compare-remove {
8027    display: none !important; /* Hidden by default */
8028  }
8029  
8030  .pd-compare-btn.added .compare-remove {
8031    display: flex !important; /* Only show when added */
8032    flex-wrap: wrap;
8033    align-items: center;
8034    gap: 0.4rem;
8035    white-space: normal !important;
8036    word-break: break-word;
8037  }
8038  
8039  .pd-compare-btn .compare-icon {
8040    display: inline-block !important;
8041    width: 18px;
8042    height: 18px;
8043    flex-shrink: 0;
8044  }
8045  
8046  .pd-compare-info {
8047    margin-top: 0.5rem;
8048  }
8049  
8050  .compare-note {
8051    font-size: 0.85rem !important;
8052    display: block !important;
8053    visibility: visible !important;
8054    color: #64748b !important;
8055  }
8056}
8057
8058/* iOS Safari specific fixes */
8059@media (max-width: 480px) {
8060  #compareBtn { 
8061    width:46px;
8062    height:46px;
8063  }
8064  
8065  .pd-compare-section {
8066    -webkit-transform: translateZ(0);
8067    transform: translateZ(0);
8068  }
8069  
8070  .pd-compare-btn {
8071    -webkit-appearance: none !important;
8072    appearance: none !important;
8073    -webkit-tap-highlight-color: transparent;
8074    touch-action: manipulation;
8075  }
8076  
8077  /* Fix sidebar height for iOS address bar */
8078  .compare-sidebar {
8079    /* Use fixed positioning that accounts for iOS address bar */
8080    height: 100vh;
8081    height: -webkit-fill-available; /* iOS Safari compatibility */
8082    min-height: 100vh;
8083    min-height: -webkit-fill-available;
8084  }
8085  
8086  /* Ensure compare actions stay at bottom */
8087  .compare-actions {
8088    position: sticky;
8089    bottom: 0;
8090    background: white;
8091    border-top: 2px solid #e2e8f0;
8092    box-shadow: 0 -4px 12px rgba(0, 0, 0, 0.15);
8093    padding: 1.25rem 1rem;
8094    z-index: 20;
8095  }
8096  
8097  .compare-actions .btn {
8098    min-height: 52px; /* Larger for easier tapping */
8099    font-size: 1rem;
8100    font-weight: 700;
8101    border-radius: 8px;
8102  }
8103  
8104  /* Adjust content padding to account for sticky actions */
8105  .compare-content {
8106    padding-bottom: 6rem; /* Extra space for sticky actions */
8107  }
8108}
8109
8110/* High-resolution mobile devices (iPhone 12 Pro, etc.) */
8111@media (-webkit-min-device-pixel-ratio: 2) and (max-width: 430px) {
8112  .pd-compare-section {
8113    display: block !important;
8114  }
8115  
8116  .pd-compare-btn {
8117    display: flex !important;
8118    min-height: 44px;
8119    font-size: 16px; /* Prevent zoom on iOS */
8120  }
8121  
8122  /* Enhanced fixes for iPhone 12 Pro and similar devices */
8123  .compare-sidebar {
8124    /* Ensure full height coverage */
8125    height: 100vh;
8126    height: 100dvh; /* Dynamic viewport height */
8127    height: -webkit-fill-available; /* iOS fallback */
8128    max-height: 100vh;
8129    max-height: 100dvh;
8130    max-height: -webkit-fill-available;
8131    overflow: hidden; /* Prevent scroll issues */
8132  }
8133  
8134  .compare-content {
8135    /* Flexible content area */
8136    flex: 1;
8137    overflow-y: auto;
8138    -webkit-overflow-scrolling: touch;
8139    padding: 1rem 1rem 8rem 1rem; /* Extra bottom padding */
8140  }
8141  
8142  .compare-actions {
8143    /* Force actions to stay visible */
8144    position: fixed;
8145    bottom: 0;
8146    left: 0;
8147    right: 0;
8148    width: 100%;
8149    background: white;
8150    border-top: 2px solid #e2e8f0;
8151    box-shadow: 0 -4px 20px rgba(0, 0, 0, 0.2);
8152    padding: 1rem;
8153    z-index: 9999;
8154    display: flex !important;
8155    gap: 0.75rem;
8156  }
8157  
8158  .compare-actions .btn {
8159    flex: 1;
8160    min-height: 30px; /* Extra large for high-DPI screens */
8161    font-size: .8rem;
8162    font-weight: 600;
8163    border-radius: 12px;
8164    display: flex !important;
8165    align-items: center;
8166    justify-content: center;
8167    gap: 0.5rem;
8168  }
8169  
8170  /* Ensure AI analyze button is always visible and prominent */
8171  #compareAnalyze {
8172    background: #3b82f6 !important;
8173    border-color: #3b82f6 !important;
8174    color: white !important;
8175    box-shadow: 0 4px 12px rgba(59, 130, 246, 0.3);
8176  }
8177  
8178  #compareAnalyze:not(:disabled) {
8179    background: #2563eb !important;
8180    border-color: #2563eb !important;
8181    transform: scale(1.02);
8182  }
8183  
8184  #compareAnalyze:disabled {
8185    opacity: 0.6 !important;
8186    background: #9ca3af !important;
8187    border-color: #9ca3af !important;
8188  }
8189}
8190
8191/* AI Disclaimer Styles */
8192.ai-disclaimer {
8193  display: flex;
8194  align-items: flex-start;
8195  gap: 0.75rem;
8196  padding: 1rem;
8197  background: #fef3c7;
8198  border: 1px solid #C77DFF;
8199  border-radius: 8px;
8200  margin: 0;
8201}
8202
8203.disclaimer-icon {
8204  font-size: 1.25rem;
8205  flex-shrink: 0;
8206  margin-top: 0.125rem;
8207}
8208
8209.disclaimer-text {
8210  font-size: 0.85rem;
8211  line-height: 1.4;
8212  color: #ae7e21;
8213}
8214
8215.disclaimer-text strong {
8216  color: #765212;
8217  font-weight: 600;
8218}
8219
8220/* Compare Disclaimer in Sidebar */
8221.compare-disclaimer {
8222  margin-top: 1rem;
8223  padding: 1rem;
8224  background: #f0f9ff;
8225  border: 1px solid #0ea5e9;
8226  border-radius: 8px;
8227}
8228
8229.compare-disclaimer h6 {
8230  display: flex;
8231  align-items: center;
8232  gap: 0.5rem;
8233  font-size: 0.875rem;
8234  font-weight: 600;
8235  color: #0c4a6e;
8236  margin-bottom: 0.5rem;
8237}
8238
8239.compare-disclaimer p {
8240  font-size: 0.8rem;
8241  line-height: 1.4;
8242  color: #075985;
8243  margin-bottom: 0.5rem;
8244}
8245
8246.compare-disclaimer p:last-child {
8247  margin-bottom: 0;
8248}
8249
8250.compare-disclaimer ul {
8251  list-style: none;
8252  padding: 0;
8253  margin: 0.5rem 0 0 0;
8254}
8255
8256.compare-disclaimer li {
8257  display: flex;
8258  align-items: flex-start;
8259  gap: 0.5rem;
8260  margin-bottom: 0.25rem;
8261  font-size: 0.75rem;
8262  line-height: 1.3;
8263  color: #075985;
8264}
8265
8266.compare-disclaimer li:before {
8267  content: "•";
8268  color: #0ea5e9;
8269  font-weight: bold;
8270  margin-top: 0.1rem;
8271  flex-shrink: 0;
8272}
8273
8274/* Mobile Browser Address Bar Fixes */
8275@supports (height: 100dvh) {
8276  /* Modern browsers with dynamic viewport support */
8277  @media (max-width: 768px) {
8278    .compare-sidebar {
8279      height: 100dvh !important;
8280      max-height: 100dvh !important;
8281    }
8282    
8283    .modal-container {
8284      max-height: 95dvh !important;
8285    }
8286  }
8287}
8288
8289@supports (height: -webkit-fill-available) {
8290  /* iOS Safari specific support */
8291  @media (max-width: 768px) {
8292    .compare-sidebar {
8293      height: -webkit-fill-available !important;
8294      max-height: -webkit-fill-available !important;
8295    }
8296  }
8297}
8298
8299/* Fallback for older browsers */
8300@media (max-width: 768px) and (orientation: portrait) {
8301  .compare-sidebar {
8302    /* Fixed height that works across different mobile browsers */
8303    min-height: 600px;
8304    height: calc(100vh - env(keyboard-inset-height, 0px));
8305    height: calc(100vh - env(safe-area-inset-bottom, 0px));
8306  }
8307  
8308  /* Ensure actions are always accessible */
8309  .compare-actions {
8310    position: sticky !important;
8311    bottom: env(safe-area-inset-bottom, 0px) !important;
8312    margin-bottom: 0 !important;
8313    padding-bottom: calc(1rem + env(safe-area-inset-bottom, 0px)) !important;
8314  }
8315}
8316
8317/* PWA and fullscreen app support */
8318@media (display-mode: standalone) {
8319  .compare-sidebar {
8320    height: 100vh !important;
8321    height: 100dvh !important;
8322  }
8323}
8324
8325/* Utilities */
8326.btn-sm {
8327  padding: 0.5rem 0.75rem;
8328  font-size: 0.8rem;
8329}
8330
8331[hidden] {
8332  display: none !important;
8333}
8334
8335/* ===== UX ENHANCEMENTS ===== */
8336
8337/* Compare Button Highlight Animation */
8338.pulse-highlight {
8339  animation: pulse-glow 2s ease-in-out 3;
8340  box-shadow: 0 0 0 0 rgba(59, 130, 246, 0.7);
8341}
8342
8343@keyframes pulse-glow {
8344  0% {
8345    box-shadow: 0 0 0 0 rgba(59, 130, 246, 0.7);
8346  }
8347  50% {
8348    box-shadow: 0 0 0 10px rgba(59, 130, 246, 0);
8349  }
8350  100% {
8351    box-shadow: 0 0 0 0 rgba(59, 130, 246, 0);
8352  }
8353}
8354
8355/* Flying Product Animation */
8356.flying-product {
8357  position: fixed;
8358  z-index: 9999;
8359  pointer-events: none;
8360}
8361
8362.flying-product img {
8363  border-radius: 8px;
8364  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
8365}
8366
8367/* Sticky Compare Bar - REMOVED (using only fly-to-navbar animation) */
8368
8369/* Inline Compare Preview - REMOVED (keeping it simple and clean) */
8370</style>
8371  <style data-inlined="product-card-actions.css">
8372/**
8373 * Product Card Quick Actions - 3 Dot Menu + Bottom Sheet
8374 * Tokopedia-inspired design
8375 */
8376
8377/* ===== 3 Dot Button on Product Card ===== */
8378.prod-card {
8379    position: relative;
8380}
8381
8382.prod-card-actions-btn {
8383    position: absolute;
8384    top: 8px;
8385    right: 8px;
8386    width: 32px;
8387    height: 32px;
8388    border-radius: 50%;
8389    background: rgba(255, 255, 255, 0.95);
8390    border: 1px solid rgba(0, 0, 0, 0.08);
8391    display: inline-flex;
8392    align-items: center;
8393    justify-content: center;
8394    cursor: pointer;
8395    z-index: 3;
8396    transition: all 0.2s ease;
8397    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
8398    -webkit-tap-highlight-color: transparent;
8399}
8400
8401.prod-card-actions-btn:hover {
8402    background: #fff;
8403    border-color: rgba(0, 0, 0, 0.15);
8404    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
8405    transform: scale(1.05);
8406}
8407
8408.prod-card-actions-btn:active {
8409    transform: scale(0.95);
8410}
8411
8412.prod-card-actions-btn svg {
8413    width: 20px;
8414    height: 20px;
8415    color: #64748b;
8416    display: block;
8417}
8418
8419/* Desktop: Show on hover */
8420@media (min-width: 641px) {
8421    .prod-card-actions-btn {
8422        opacity: 0;
8423        pointer-events: none;
8424    }
8425    
8426    .prod-card:hover .prod-card-actions-btn {
8427        opacity: 1;
8428        pointer-events: auto;
8429    }
8430}
8431
8432/* Mobile: Always visible but smaller */
8433@media (max-width: 640px) {
8434    .prod-card-actions-btn {
8435        width: 28px;
8436        height: 28px;
8437        top: 6px;
8438        right: 6px;
8439        opacity: 95%;
8440    }
8441    
8442    .prod-card-actions-btn svg {
8443        width: 18px;
8444        height: 18px;
8445    }
8446}
8447
8448/* ===== Bottom Sheet Overlay ===== */
8449.pca-overlay {
8450    position: fixed;
8451    inset: 0;
8452    background: rgba(15, 23, 42, 0.6);
8453    backdrop-filter: blur(4px);
8454    z-index: 99998;
8455    opacity: 0;
8456    visibility: hidden;
8457    transition: all 0.3s ease;
8458}
8459
8460.pca-overlay.active {
8461    opacity: 1;
8462    visibility: visible;
8463}
8464
8465/* ===== Bottom Sheet Container ===== */
8466.pca-bottom-sheet {
8467    position: fixed;
8468    bottom: 0;
8469    left: 0;
8470    right: 0;
8471    background: #fff;
8472    border-radius: 20px 20px 0 0;
8473    box-shadow: 0 -4px 24px rgba(0, 0, 0, 0.15);
8474    z-index: 99999;
8475    max-width: 600px;
8476    margin: 0 auto;
8477    transform: translateY(100%);
8478    transition: transform 0.3s cubic-bezier(0.25, 0.46, 0.45, 0.94);
8479}
8480
8481.pca-bottom-sheet.active {
8482    transform: translateY(0);
8483}
8484
8485/* Drag Handle */
8486.pca-sheet-handle {
8487    width: 40px;
8488    height: 4px;
8489    background: #cbd5e1;
8490    border-radius: 999px;
8491    margin: 12px auto 8px;
8492}
8493
8494/* Product Preview */
8495.pca-sheet-product {
8496    display: flex;
8497    gap: 12px;
8498    padding: 12px 20px;
8499    border-bottom: 1px solid #f1f5f9;
8500}
8501
8502.pca-product-image {
8503    width: 60px;
8504    height: 60px;
8505    border-radius: 8px;
8506    object-fit: cover;
8507    flex-shrink: 0;
8508    border: 1px solid #e2e8f0;
8509}
8510
8511.pca-product-info {
8512    flex: 1;
8513    min-width: 0;
8514}
8515
8516.pca-product-name {
8517    font-size: 14px;
8518    font-weight: 600;
8519    color: #0f172a;
8520    margin: 0 0 4px 0;
8521    display: -webkit-box;
8522    -webkit-line-clamp: 2;
8523    -webkit-box-orient: vertical;
8524    overflow: hidden;
8525    line-height: 1.3;
8526}
8527
8528.pca-product-price {
8529    font-size: 15px;
8530    font-weight: 700;
8531    color: #0ea5e9;
8532    margin: 0;
8533}
8534
8535.pca-product-stock {
8536    font-size: 12px;
8537    color: #64748b;
8538    margin: 2px 0 0 0;
8539}
8540
8541.pca-product-stock.in {
8542    color: #16a34a;
8543}
8544
8545.pca-product-stock.low {
8546    color: #C77DFF;
8547}
8548
8549.pca-product-stock.out {
8550    color: #C77DFF;
8551}
8552
8553/* Action Menu */
8554.pca-sheet-actions {
8555    padding: 8px 0 20px;
8556}
8557
8558.pca-action-item {
8559    display: flex;
8560    align-items: center;
8561    gap: 16px;
8562    padding: 16px 20px;
8563    background: transparent;
8564    border: 0;
8565    width: 100%;
8566    cursor: pointer;
8567    transition: background-color 0.15s ease;
8568    -webkit-tap-highlight-color: transparent;
8569}
8570
8571.pca-action-item:hover {
8572    background: #f8fafc;
8573}
8574
8575.pca-action-item:active {
8576    background: #f1f5f9;
8577}
8578
8579.pca-action-item:disabled {
8580    opacity: 0.4;
8581    cursor: not-allowed;
8582}
8583
8584.pca-action-item:disabled:hover {
8585    background: transparent;
8586}
8587
8588.pca-action-icon {
8589    width: 24px;
8590    height: 24px;
8591    color: #475569;
8592    flex-shrink: 0;
8593}
8594
8595.pca-action-content {
8596    flex: 1;
8597    text-align: left;
8598}
8599
8600.pca-action-label {
8601    font-size: 15px;
8602    font-weight: 600;
8603    color: #0f172a;
8604    margin: 0 0 2px 0;
8605}
8606
8607.pca-action-desc {
8608    font-size: 12px;
8609    color: #64748b;
8610    margin: 0;
8611}
8612
8613.pca-action-badge {
8614    display: inline-flex;
8615    align-items: center;
8616    justify-content: center;
8617    min-width: 20px;
8618    height: 20px;
8619    padding: 0 6px;
8620    background: #0ea5e9;
8621    color: #fff;
8622    font-size: 11px;
8623    font-weight: 700;
8624    border-radius: 999px;
8625    margin-left: auto;
8626}
8627
8628.pca-action-badge.compare {
8629    background: #8b5cf6;
8630}
8631
8632/* Action Item Colors */
8633.pca-action-item.cart .pca-action-icon {
8634    color: #0ea5e9;
8635}
8636
8637.pca-action-item.compare .pca-action-icon {
8638    color: #8b5cf6;
8639}
8640
8641.pca-action-item.compare.active {
8642    background: rgba(139, 92, 246, 0.05);
8643}
8644
8645.pca-action-item.compare.active .pca-action-label {
8646    color: #8b5cf6;
8647}
8648
8649.pca-action-item.compare.active .pca-action-icon {
8650    color: #8b5cf6;
8651}
8652
8653.pca-action-item.share .pca-action-icon {
8654    color: #64748b;
8655}
8656
8657/* Loading State */
8658.pca-action-item.loading {
8659    pointer-events: none;
8660}
8661
8662.pca-action-item.loading .pca-action-icon {
8663    animation: spin 1s linear infinite;
8664}
8665
8666@keyframes spin {
8667    from { transform: rotate(0deg); }
8668    to { transform: rotate(360deg); }
8669}
8670
8671/* Success State Animation */
8672.pca-action-item.success .pca-action-icon {
8673    animation: checkmark 0.5s ease;
8674}
8675
8676@keyframes checkmark {
8677    0% { transform: scale(0); }
8678    50% { transform: scale(1.2); }
8679    100% { transform: scale(1); }
8680}
8681
8682/* ===== Safe Area for Mobile Devices ===== */
8683@supports (padding-bottom: env(safe-area-inset-bottom)) {
8684    .pca-sheet-actions {
8685        padding-bottom: calc(20px + env(safe-area-inset-bottom));
8686    }
8687}
8688
8689/* ===== Responsive Tweaks ===== */
8690@media (max-width: 640px) {
8691    .pca-bottom-sheet {
8692        border-radius: 16px 16px 0 0;
8693    }
8694    
8695    .pca-sheet-product {
8696        padding: 10px 16px;
8697    }
8698    
8699    .pca-product-image {
8700        width: 50px;
8701        height: 50px;
8702    }
8703    
8704    .pca-product-name {
8705        font-size: 13px;
8706    }
8707    
8708    .pca-product-price {
8709        font-size: 14px;
8710    }
8711    
8712    .pca-action-item {
8713        padding: 14px 16px;
8714        gap: 12px;
8715    }
8716    
8717    .pca-action-icon {
8718        width: 22px;
8719        height: 22px;
8720    }
8721    
8722    .pca-action-label {
8723        font-size: 14px;
8724    }
8725}
8726
8727/* ===== Animation for Flying Product ===== */
8728.flying-product {
8729    position: fixed;
8730    pointer-events: none;
8731    z-index: 99999;
8732    animation: fadeOut 0.8s ease forwards;
8733}
8734
8735@keyframes fadeOut {
8736    to {
8737        opacity: 0;
8738        transform: scale(0.5);
8739    }
8740}
8741
8742/* ===== Desktop Dropdown (Alternative) ===== */
8743@media (min-width: 1024px) {
8744    /* Optional: Could add desktop dropdown menu here */
8745    /* For now, using bottom sheet for consistency */
8746}
8747
8748/* ===== Print Styles ===== */
8749@media print {
8750    .prod-card-actions-btn,
8751    .pca-overlay,
8752    .pca-bottom-sheet {
8753        display: none !important;
8754    }
8755}
8756
8757</style>
8758  <style data-inlined="modal.css">
8759/* Modern Modal Dialog for Cart Operations */
8760.modal-overlay {
8761  position: fixed;
8762  top: 0;
8763  left: 0;
8764  right: 0;
8765  bottom: 0;
8766  background: rgba(0, 0, 0, 0.5);
8767  backdrop-filter: blur(4px);
8768  display: flex;
8769  align-items: center;
8770  justify-content: center;
8771  z-index: 9999;
8772  opacity: 0;
8773  visibility: hidden;
8774  transition: all 0.2s ease;
8775}
8776
8777.modal-overlay.show {
8778  opacity: 1;
8779  visibility: visible;
8780}
8781
8782.modal-dialog {
8783  background: white;
8784  border-radius: 16px;
8785  box-shadow: 0 25px 50px rgba(0, 0, 0, 0.15);
8786  max-width: 400px;
8787  width: 90%;
8788  max-height: 90vh;
8789  overflow-y: auto;
8790  transform: scale(0.95);
8791  transition: transform 0.2s ease;
8792}
8793
8794.modal-overlay.show .modal-dialog {
8795  transform: scale(1);
8796}
8797
8798.modal-header {
8799  padding: 24px 24px 16px;
8800  border-bottom: 1px solid #f1f5f9;
8801}
8802
8803.modal-title {
8804  font-size: 20px;
8805  font-weight: 700;
8806  color: #0f172a;
8807  margin: 0;
8808  display: flex;
8809  align-items: center;
8810  gap: 12px;
8811}
8812
8813.modal-body {
8814  padding: 16px 24px 24px;
8815}
8816
8817.modal-message {
8818  font-size: 16px;
8819  line-height: 1.5;
8820  color: #475569;
8821  margin: 0;
8822}
8823
8824.modal-actions {
8825  display: flex;
8826  gap: 12px;
8827  margin-top: 24px;
8828}
8829
8830.modal-btn {
8831  flex: 1;
8832  padding: 12px 16px;
8833  border: none;
8834  border-radius: 8px;
8835  font-size: 14px;
8836  font-weight: 600;
8837  cursor: pointer;
8838  transition: all 0.2s ease;
8839  text-align: center;
8840}
8841
8842.modal-btn-secondary {
8843  background: #f8fafc;
8844  color: #64748b;
8845  border: 1px solid #e2e8f0;
8846}
8847
8848.modal-btn-secondary:hover {
8849  background: #f1f5f9;
8850  border-color: #cbd5e1;
8851}
8852
8853.modal-btn-danger {
8854  background: #C77DFF;
8855  color: white;
8856}
8857
8858.modal-btn-danger:hover {
8859  background: #C77DFF;
8860}
8861
8862.modal-btn-primary {
8863  background: #3b82f6;
8864  color: white;
8865}
8866
8867.modal-btn-primary:hover {
8868  background: #2563eb;
8869}
8870
8871.modal-icon {
8872  font-size: 24px;
8873  width: 32px;
8874  height: 32px;
8875  display: flex;
8876  align-items: center;
8877  justify-content: center;
8878  border-radius: 8px;
8879}
8880
8881.modal-icon.danger {
8882  background: #fef2f2;
8883  color: #C77DFF;
8884}
8885
8886.modal-icon.warning {
8887  background: #fffbeb;
8888  color: #C77DFF;
8889}
8890
8891.modal-icon.success {
8892  background: #f0fdf4;
8893  color: #22c55e;
8894}
8895
8896.modal-icon.info {
8897  background: #eff6ff;
8898  color: #3b82f6;
8899}
8900
8901/* Mobile responsive */
8902@media (max-width: 640px) {
8903  .modal-dialog {
8904    margin: 16px;
8905    max-width: none;
8906    width: auto;
8907  }
8908  
8909  .modal-header,
8910  .modal-body {
8911    padding-left: 20px;
8912    padding-right: 20px;
8913  }
8914  
8915  .modal-actions {
8916    flex-direction: column;
8917  }
8918  
8919  .modal-btn {
8920    flex: none;
8921  }
8922}
8923</style>
8924      
8925        <style data-inlined="reviews-points.css">
8926/**
8927 * Reviews & Points System - Styles
8928 * Product reviews, rating display, and point redemption UI
8929 */
8930
8931/* ===================================
8932   PRODUCT REVIEWS
8933   =================================== */
8934
8935.product-tabs {
8936  display: flex;
8937  border-bottom: 2px solid #e5e7eb;
8938  margin: 24px 0 16px;
8939  gap: 8px;
8940}
8941
8942.tab-btn {
8943  padding: 12px 20px;
8944  border: none;
8945  background: none;
8946  cursor: pointer;
8947  font-size: 15px;
8948  font-weight: 500;
8949  color: #6b7280;
8950  border-bottom: 3px solid transparent;
8951  transition: all 0.2s ease;
8952  position: relative;
8953  top: 2px;
8954}
8955
8956.tab-btn:hover {
8957  color: #111827;
8958}
8959
8960.tab-btn.active {
8961  color: #2563eb;
8962  border-bottom-color: #2563eb;
8963}
8964
8965.tab-content {
8966  padding: 20px 0;
8967}
8968
8969/* Review Statistics */
8970.review-stats {
8971  display: grid;
8972  grid-template-columns: 200px 1fr;
8973  gap: 32px;
8974  padding: 24px;
8975  background: #f9fafb;
8976  border-radius: 12px;
8977  margin-bottom: 24px;
8978}
8979
8980.rating-summary {
8981  text-align: center;
8982}
8983
8984.avg-rating {
8985  display: block;
8986  font-size: 48px;
8987  font-weight: 700;
8988  color: #111827;
8989  line-height: 1;
8990}
8991
8992.rating-summary .stars {
8993  font-size: 24px;
8994  color: #C77DFF;
8995  margin: 8px 0;
8996}
8997
8998.total-reviews {
8999  display: block;
9000  font-size: 14px;
9001  color: #6b7280;
9002  margin-top: 4px;
9003}
9004
9005.rating-breakdown {
9006  display: flex;
9007  flex-direction: column;
9008  gap: 8px;
9009}
9010
9011.rating-bar {
9012  display: flex;
9013  align-items: center;
9014  gap: 12px;
9015}
9016
9017.rating-label {
9018  font-size: 14px;
9019  color: #374151;
9020  width: 32px;
9021  text-align: right;
9022}
9023
9024.bar-container {
9025  flex: 1;
9026  height: 8px;
9027  background: #e5e7eb;
9028  border-radius: 4px;
9029  overflow: hidden;
9030}
9031
9032.bar-fill {
9033  height: 100%;
9034  background: linear-gradient(90deg, #C77DFF 0%, #C77DFF 100%);
9035  transition: width 0.3s ease;
9036}
9037
9038.rating-count {
9039  font-size: 14px;
9040  color: #6b7280;
9041  width: 40px;
9042  text-align: right;
9043}
9044
9045/* Review Filters */
9046.review-filters {
9047  display: flex;
9048  justify-content: space-between;
9049  align-items: center;
9050  margin-bottom: 20px;
9051}
9052
9053.review-sort {
9054  padding: 8px 12px;
9055  border: 1px solid #d1d5db;
9056  border-radius: 8px;
9057  font-size: 14px;
9058  background: white;
9059}
9060
9061.write-review-btn {
9062  padding: 10px 20px;
9063  background: #2563eb;
9064  color: white;
9065  border: none;
9066  border-radius: 8px;
9067  font-weight: 500;
9068  cursor: pointer;
9069  transition: background 0.2s;
9070}
9071
9072.write-review-btn:hover {
9073  background: #1d4ed8;
9074}
9075
9076/* Review List */
9077.reviews-list {
9078  display: flex;
9079  flex-direction: column;
9080  gap: 16px;
9081}
9082
9083.review-item {
9084  padding: 20px;
9085  background: white;
9086  border: 1px solid #e5e7eb;
9087  border-radius: 12px;
9088  transition: box-shadow 0.2s;
9089}
9090
9091.review-item:hover {
9092  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
9093}
9094
9095.review-header {
9096  display: flex;
9097  justify-content: space-between;
9098  align-items: flex-start;
9099  margin-bottom: 8px;
9100}
9101
9102.review-author {
9103  display: flex;
9104  align-items: center;
9105  gap: 8px;
9106}
9107
9108.review-author strong {
9109  font-size: 15px;
9110  color: #111827;
9111}
9112
9113.verified-badge {
9114  display: inline-flex;
9115  align-items: center;
9116  gap: 4px;
9117  font-size: 12px;
9118  color: #059669;
9119  background: #d1fae5;
9120  padding: 2px 8px;
9121  border-radius: 4px;
9122  font-weight: 500;
9123}
9124
9125.anonymous-badge {
9126  display: inline-flex;
9127  align-items: center;
9128  font-size: 12px;
9129  color: #6b7280;
9130  background: #f3f4f6;
9131  padding: 2px 6px;
9132  border-radius: 4px;
9133  margin-left: 4px;
9134  cursor: help;
9135}
9136
9137.review-rating .stars {
9138  font-size: 16px;
9139  color: #C77DFF;
9140}
9141
9142.review-date {
9143  font-size: 13px;
9144  color: #9ca3af;
9145  margin-bottom: 12px;
9146}
9147
9148.review-text {
9149  font-size: 15px;
9150  line-height: 1.6;
9151  color: #374151;
9152  margin-bottom: 12px;
9153}
9154
9155.review-images {
9156  display: flex;
9157  gap: 8px;
9158  margin-bottom: 12px;
9159  flex-wrap: wrap;
9160}
9161
9162.review-img {
9163  width: 80px;
9164  height: 80px;
9165  object-fit: cover;
9166  border-radius: 8px;
9167  cursor: pointer;
9168  transition: transform 0.2s;
9169}
9170
9171.review-img:hover {
9172  transform: scale(1.05);
9173}
9174
9175.review-actions {
9176  display: flex;
9177  gap: 12px;
9178  padding-top: 12px;
9179  border-top: 1px solid #f3f4f6;
9180}
9181
9182.btn-helpful {
9183  display: flex;
9184  align-items: center;
9185  gap: 6px;
9186  padding: 6px 12px;
9187  background: #f9fafb;
9188  border: 1px solid #e5e7eb;
9189  border-radius: 6px;
9190  font-size: 13px;
9191  color: #6b7280;
9192  cursor: pointer;
9193  transition: all 0.2s;
9194}
9195
9196.btn-helpful:hover {
9197  background: #f3f4f6;
9198  color: #111827;
9199  border-color: #d1d5db;
9200}
9201
9202.btn-helpful.voted {
9203  background: #dbeafe;
9204  color: #1d4ed8;
9205  border-color: #93c5fd;
9206}
9207
9208.helpful-icon {
9209  font-size: 14px;
9210}
9211
9212.no-reviews {
9213  text-align: center;
9214  padding: 60px 20px;
9215  color: #9ca3af;
9216  font-size: 15px;
9217}
9218
9219.load-more-btn {
9220  display: block;
9221  margin: 24px auto 0;
9222  padding: 12px 32px;
9223  background: white;
9224  border: 1px solid #d1d5db;
9225  border-radius: 8px;
9226  font-size: 14px;
9227  font-weight: 500;
9228  color: #374151;
9229  cursor: pointer;
9230  transition: all 0.2s;
9231}
9232
9233.load-more-btn:hover {
9234  background: #f9fafb;
9235  border-color: #9ca3af;
9236}
9237
9238/* ===================================
9239   POINT BALANCE WIDGET (LEGACY - kept for backward compatibility)
9240   =================================== */
9241
9242.point-balance-card {
9243  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
9244  color: white;
9245  padding: 24px;
9246  border-radius: 16px;
9247  margin-bottom: 24px;
9248  box-shadow: 0 10px 25px rgba(102, 126, 234, 0.3);
9249}
9250
9251.point-header {
9252  display: flex;
9253  justify-content: space-between;
9254  align-items: center;
9255  margin-bottom: 12px;
9256}
9257
9258.point-header h3 {
9259  font-size: 18px;
9260  font-weight: 600;
9261  margin: 0;
9262  display: flex;
9263  align-items: center;
9264  gap: 8px;
9265}
9266
9267.point-header .balance {
9268  font-size: 32px;
9269  font-weight: 700;
9270}
9271
9272.point-value {
9273  font-size: 14px;
9274  opacity: 0.9;
9275  margin: 8px 0 16px;
9276}
9277
9278.point-stats {
9279  display: flex;
9280  gap: 20px;
9281  font-size: 13px;
9282  opacity: 0.85;
9283  margin-bottom: 16px;
9284}
9285
9286.btn-view-history {
9287  display: inline-block;
9288  padding: 10px 20px;
9289  background: rgba(255, 255, 255, 0.2);
9290  color: white;
9291  text-decoration: none;
9292  border-radius: 8px;
9293  font-size: 14px;
9294  font-weight: 500;
9295  transition: background 0.2s;
9296}
9297
9298.btn-view-history:hover {
9299  background: rgba(255, 255, 255, 0.3);
9300}
9301
9302/* ===================================
9303   CHECKOUT POINT REDEMPTION
9304   =================================== */
9305
9306.checkout-points {
9307  padding: 16px;
9308  background: #fef3c7;
9309  border: 2px solid #C77DFF;
9310  border-radius: 12px;
9311  margin-bottom: 16px;
9312}
9313
9314.points-header {
9315  display: flex;
9316  align-items: center;
9317  gap: 10px;
9318  margin-bottom: 12px;
9319}
9320
9321.points-header input[type="checkbox"] {
9322  width: 18px;
9323  height: 18px;
9324  cursor: pointer;
9325}
9326
9327.points-header label {
9328  font-size: 15px;
9329  color: #765212;
9330  cursor: pointer;
9331  margin: 0;
9332}
9333
9334#points-slider {
9335  padding: 16px;
9336  background: white;
9337  border-radius: 8px;
9338  margin-top: 12px;
9339}
9340
9341#points-slider label {
9342  display: block;
9343  font-size: 14px;
9344  color: #374151;
9345  margin-bottom: 8px;
9346  font-weight: 500;
9347}
9348
9349#points-amount {
9350  width: 100%;
9351  margin-bottom: 8px;
9352}
9353
9354#points-display {
9355  display: flex;
9356  justify-content: space-between;
9357  font-size: 14px;
9358  color: #111827;
9359  margin-top: 8px;
9360}
9361
9362#points-display .discount-amount {
9363  color: #059669;
9364  font-weight: 600;
9365}
9366
9367.price-row.point-discount {
9368  color: #059669;
9369  font-weight: 500;
9370}
9371
9372/* ===================================
9373   REVIEWABLE ORDERS
9374   =================================== */
9375
9376.reviewable-orders {
9377  background: white;
9378  border: 1px solid #e5e7eb;
9379  border-radius: 12px;
9380  padding: 20px;
9381  margin-bottom: 24px;
9382}
9383
9384.reviewable-orders h3 {
9385  font-size: 18px;
9386  margin-bottom: 16px;
9387  color: #111827;
9388}
9389
9390.order-card {
9391  display: flex;
9392  gap: 16px;
9393  padding: 16px;
9394  background: #f9fafb;
9395  border-radius: 8px;
9396  margin-bottom: 12px;
9397}
9398
9399.order-card:last-child {
9400  margin-bottom: 0;
9401}
9402
9403.order-card img {
9404  width: 80px;
9405  height: 80px;
9406  object-fit: cover;
9407  border-radius: 8px;
9408}
9409
9410.order-info {
9411  flex: 1;
9412}
9413
9414.order-info h4 {
9415  font-size: 15px;
9416  margin: 0 0 4px;
9417  color: #111827;
9418}
9419
9420.order-info p {
9421  font-size: 13px;
9422  color: #6b7280;
9423  margin: 0 0 12px;
9424}
9425
9426.btn-review {
9427  padding: 8px 16px;
9428  background: #059669;
9429  color: white;
9430  border: none;
9431  border-radius: 6px;
9432  font-size: 14px;
9433  font-weight: 500;
9434  cursor: pointer;
9435  transition: background 0.2s;
9436}
9437
9438.btn-review:hover {
9439  background: #047857;
9440}
9441
9442/* ===================================
9443   TOAST NOTIFICATIONS
9444   =================================== */
9445
9446.review-toast {
9447  position: fixed;
9448  bottom: 24px;
9449  right: 24px;
9450  padding: 14px 20px;
9451  background: #111827;
9452  color: white;
9453  border-radius: 8px;
9454  font-size: 14px;
9455  line-height: 1.4;
9456  box-shadow: 0 10px 25px rgba(0, 0, 0, 0.2);
9457  transform: translateY(100px);
9458  opacity: 0;
9459  transition: all 0.3s ease;
9460  z-index: 10000;
9461  max-width: 400px;
9462  word-wrap: break-word;
9463}
9464
9465.review-toast.show {
9466  transform: translateY(0);
9467  opacity: 1;
9468}
9469
9470/* Mobile: Position above bottom-nav */
9471@media (max-width: 768px) {
9472  .review-toast {
9473    bottom: 80px; /* Above bottom-nav (50px height + padding + safe margin) */
9474    right: 16px;
9475    left: 16px;
9476    max-width: calc(100% - 32px);
9477  }
9478}
9479
9480.review-toast.toast-success {
9481  background: #059669;
9482}
9483
9484.review-toast.toast-error {
9485  background: #C77DFF;
9486}
9487
9488.review-toast.toast-info {
9489  background: #2563eb;
9490}
9491
9492/* ===================================
9493   RESPONSIVE
9494   =================================== */
9495
9496@media (max-width: 768px) {
9497  .point-balance-card {
9498    border-radius: 0;
9499  }
9500  
9501  .review-stats {
9502    grid-template-columns: 70px 1fr;
9503    gap: 20px;
9504    padding: 16px;
9505  }
9506
9507  .rating-summary {
9508    text-align: center;
9509  }
9510  
9511  .rating-summary .avg-rating {
9512    font-size: 32px;
9513  }
9514  
9515  .rating-summary .stars {
9516    font-size: 18px;
9517    margin: 4px 0;
9518  }
9519  
9520  .total-reviews {
9521    font-size: 11px;
9522  }
9523  
9524  /* Rating breakdown - more compact */
9525  .rating-breakdown {
9526    gap: 2px;
9527  }
9528  
9529  .rating-breakdown .rating-bar {
9530    gap: 4px;
9531  }
9532  
9533  .rating-breakdown .rating-label {
9534    font-size: 11px;
9535    width: 16px;
9536    min-width: 16px;
9537    text-align: left;
9538  }
9539  
9540  .rating-breakdown .bar-container {
9541    height: 6px;
9542  }
9543  
9544  .rating-breakdown .rating-count {
9545    font-size: 11px;
9546    width: 16px;
9547    min-width: 16px;
9548  }
9549  
9550  .review-header {
9551    flex-direction: column;
9552    gap: 8px;
9553    align-items: flex-start;
9554  }
9555  
9556  .review-rating {
9557    order: -1;
9558    margin-bottom: 4px;
9559  }
9560  
9561  .review-rating .stars {
9562    font-size: 14px;
9563  }
9564
9565  .review-filters {
9566    flex-direction: column;
9567    gap: 12px;
9568    align-items: stretch;
9569  }
9570
9571  .review-sort {
9572    width: 100%;
9573  }
9574
9575  .point-header .balance {
9576    font-size: 24px;
9577  }
9578
9579  .point-stats {
9580    flex-direction: column;
9581    gap: 8px;
9582  }
9583
9584  .order-card {
9585    flex-direction: column;
9586  }
9587
9588  .order-card img {
9589    width: 100%;
9590    height: 200px;
9591  }
9592}
9593
9594/* ===================================
9595   LOADING & ERROR STATES
9596   =================================== */
9597
9598.review-loading {
9599  text-align: center;
9600  padding: 40px;
9601  color: #9ca3af;
9602  font-size: 14px;
9603}
9604
9605.review-error {
9606  text-align: center;
9607  padding: 40px;
9608  color: #C77DFF;
9609  font-size: 14px;
9610  background: #fee2e2;
9611  border-radius: 8px;
9612}
9613
9614.review-empty {
9615  text-align: center;
9616  padding: 10px;
9617  color: #6b7280;
9618  font-size: 14px;
9619}
9620
9621/* ===================================
9622   REVIEWABLE ORDERS LIST
9623   =================================== */
9624
9625.reviewable-orders-list {
9626  display: flex;
9627  flex-direction: column;
9628  gap: 16px;
9629}
9630
9631.reviewable-order-item {
9632  display: grid;
9633  grid-template-columns: 80px 1fr auto;
9634  gap: 16px;
9635  padding: 16px;
9636  background: #fff;
9637  border: 1px solid #e5e7eb;
9638  border-radius: 12px;
9639  align-items: center;
9640  transition: box-shadow 0.2s;
9641}
9642
9643.reviewable-order-item:hover {
9644  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
9645}
9646
9647.reviewable-order-item .roi-image {
9648  width: 80px;
9649  height: 80px;
9650  object-fit: cover;
9651  border-radius: 8px;
9652  border: 1px solid #e5e7eb;
9653}
9654
9655.reviewable-order-item .roi-info {
9656  display: flex;
9657  flex-direction: column;
9658  gap: 4px;
9659}
9660
9661.reviewable-order-item .roi-info h4 {
9662  margin: 0;
9663  font-size: 15px;
9664  font-weight: 600;
9665  color: #111827;
9666  line-height: 1.4;
9667}
9668
9669.reviewable-order-item .roi-meta {
9670  margin: 0;
9671  font-size: 13px;
9672  color: #6b7280;
9673}
9674
9675.reviewable-order-item .btn-write-review {
9676  white-space: nowrap;
9677  padding: 10px 20px;
9678  font-size: 14px;
9679}
9680
9681@media (max-width: 640px) {
9682  .reviewable-order-item {
9683    grid-template-columns: 60px 1fr;
9684    gap: 12px;
9685  }
9686  
9687  .reviewable-order-item .roi-image {
9688    width: 60px;
9689    height: 60px;
9690  }
9691  
9692  .reviewable-order-item .btn-write-review {
9693    grid-column: 1 / -1;
9694    width: 100%;
9695  }
9696}
9697
9698/* ===================================
9699   REVIEW SUBMISSION MODAL
9700   =================================== */
9701
9702/* Modal Overlay Background */
9703#review-modal-overlay {
9704  position: fixed;
9705  top: 0;
9706  left: 0;
9707  right: 0;
9708  bottom: 0;
9709  background: rgba(0, 0, 0, 0.6) !important;
9710  backdrop-filter: blur(8px);
9711  display: flex;
9712  align-items: center;
9713  justify-content: center;
9714  z-index: 99999 !important;
9715  padding: 20px;
9716}
9717
9718.review-modal {
9719  max-width: 600px !important;
9720  width: 90% !important;
9721  background: white;
9722  border-radius: 16px !important;
9723  box-shadow: 0 25px 50px rgba(0, 0, 0, 0.25);
9724  max-height: 90vh;
9725  display: flex;
9726  flex-direction: column;
9727  overflow: hidden !important;
9728}
9729
9730#review-modal-overlay .modal-content,
9731.review-modal .modal-content {
9732  padding: 0 !important;
9733  flex: initial !important;
9734  overflow-y: visible !important;
9735}
9736
9737.review-modal .modal-header {
9738  display: flex;
9739  justify-content: space-between;
9740  align-items: center;
9741  padding: 20px 24px;
9742  border-bottom: 1px solid #e5e7eb;
9743}
9744
9745.review-modal .modal-title {
9746  margin: 0;
9747  font-size: 20px;
9748  font-weight: 700;
9749  color: #111827;
9750}
9751
9752.review-modal .modal-close {
9753  background: none;
9754  border: none;
9755  cursor: pointer;
9756  padding: 4px;
9757  color: #6b7280;
9758  transition: color 0.2s;
9759  display: flex;
9760  align-items: center;
9761  justify-content: center;
9762}
9763
9764.review-modal .modal-close:hover {
9765  color: #111827;
9766}
9767
9768.review-modal .modal-body {
9769  padding: 24px;
9770  max-height: calc(90vh - 140px);
9771  overflow-y: auto;
9772}
9773
9774/* Custom Scrollbar for Modal */
9775.review-modal .modal-body::-webkit-scrollbar {
9776  width: 8px;
9777}
9778
9779.review-modal .modal-body::-webkit-scrollbar-track {
9780  background: #f1f5f9;
9781  border-radius: 4px;
9782}
9783
9784.review-modal .modal-body::-webkit-scrollbar-thumb {
9785  background: linear-gradient(180deg, #3b82f6 0%, #2563eb 100%);
9786  border-radius: 4px;
9787}
9788
9789.review-modal .modal-body::-webkit-scrollbar-thumb:hover {
9790  background: linear-gradient(180deg, #2563eb 0%, #1d4ed8 100%);
9791}
9792
9793/* Firefox Scrollbar */
9794.review-modal .modal-body {
9795  scrollbar-width: thin;
9796  scrollbar-color: #3b82f6 #f1f5f9;
9797}
9798
9799.review-modal .modal-footer {
9800  display: flex;
9801  gap: 12px;
9802  margin-top: 24px;
9803  padding-top: 20px;
9804  border-top: 1px solid #f1f5f9;
9805}
9806
9807.review-product-info {
9808  display: flex;
9809  gap: 16px;
9810  padding: 16px;
9811  background: #f9fafb;
9812  border-radius: 8px;
9813  margin-bottom: 24px;
9814}
9815
9816.review-product-thumb {
9817  width: 80px;
9818  height: 80px;
9819  object-fit: cover;
9820  border-radius: 6px;
9821  border: 1px solid #e5e7eb;
9822}
9823
9824.review-product-details h4 {
9825  margin: 0 0 8px 0;
9826  font-size: 16px;
9827  font-weight: 600;
9828  color: #111827;
9829}
9830
9831.review-product-details p {
9832  margin: 0;
9833  font-size: 13px;
9834  color: #6b7280;
9835}
9836
9837/* Star Rating Input */
9838.star-rating-input {
9839  display: inline-flex;
9840  gap: 8px;
9841  margin-right: 12px;
9842  vertical-align: middle;
9843}
9844
9845.star-btn {
9846  background: none;
9847  border: none;
9848  font-size: 32px;
9849  color: #d1d5db;
9850  cursor: pointer;
9851  transition: all 0.2s;
9852  padding: 0;
9853  line-height: 1;
9854}
9855
9856.star-btn:hover,
9857.star-btn.active {
9858  color: #C77DFF;
9859  transform: scale(1.1);
9860}
9861
9862.rating-label {
9863  display: inline-block;
9864  font-size: 15px;
9865  color: #6b7280;
9866  margin: 0;
9867  vertical-align: middle;
9868  min-width: 150px;
9869}
9870
9871/* Form Elements */
9872.review-form .form-group {
9873  margin-bottom: 20px;
9874}
9875
9876.review-form .form-label {
9877  display: block;
9878  font-size: 14px;
9879  font-weight: 600;
9880  color: #374151;
9881  margin-bottom: 8px;
9882}
9883
9884.review-form .form-control {
9885  width: 100%;
9886  padding: 12px;
9887  border: 1px solid #d1d5db;
9888  border-radius: 8px;
9889  font-size: 14px;
9890  font-family: inherit;
9891  transition: border-color 0.2s;
9892}
9893
9894.review-form .form-control:focus {
9895  outline: none;
9896  border-color: #2563eb;
9897  box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.1);
9898}
9899
9900.review-form .form-hint {
9901  font-size: 13px;
9902  color: #6b7280;
9903  margin-top: 8px;
9904}
9905
9906/* Image Upload */
9907.btn-upload-trigger {
9908  display: inline-flex;
9909  align-items: center;
9910  gap: 8px;
9911  padding: 10px 16px;
9912  background: #f9fafb;
9913  border: 2px dashed #d1d5db;
9914  border-radius: 8px;
9915  color: #374151;
9916  cursor: pointer;
9917  font-size: 14px;
9918  font-weight: 500;
9919  transition: all 0.2s;
9920}
9921
9922.btn-upload-trigger:hover {
9923  background: #f3f4f6;
9924  border-color: #2563eb;
9925  color: #2563eb;
9926}
9927
9928.image-preview-grid {
9929  display: grid;
9930  grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
9931  gap: 12px;
9932  margin-top: 16px;
9933}
9934
9935.image-preview-item {
9936  position: relative;
9937  aspect-ratio: 1;
9938  border-radius: 8px;
9939  overflow: hidden;
9940  border: 1px solid #e5e7eb;
9941}
9942
9943.image-preview-item img {
9944  width: 100%;
9945  height: 100%;
9946  object-fit: cover;
9947}
9948
9949.remove-image {
9950  position: absolute;
9951  top: 4px;
9952  right: 4px;
9953  background: rgba(0, 0, 0, 0.7);
9954  border: none;
9955  color: white;
9956  width: 24px;
9957  height: 24px;
9958  border-radius: 50%;
9959  cursor: pointer;
9960  display: flex;
9961  align-items: center;
9962  justify-content: center;
9963  transition: background 0.2s;
9964}
9965
9966.remove-image:hover {
9967  background: rgba(0, 0, 0, 0.9);
9968}
9969
9970/* Point Reward Info */
9971.point-reward-info {
9972  background: linear-gradient(135deg, #fef3c7 0%, #C77DFF 100%);
9973  border: 2px solid #C77DFF;
9974  border-radius: 12px;
9975  padding: 16px;
9976  margin: 20px 0;
9977}
9978
9979.pri-header {
9980  display: flex;
9981  align-items: center;
9982  gap: 8px;
9983  font-size: 16px;
9984  font-weight: 700;
9985  color: #ae7e21;
9986  margin-bottom: 12px;
9987}
9988
9989.pri-list {
9990  list-style: none;
9991  padding: 0;
9992  margin: 0 0 12px 0;
9993}
9994
9995.pri-list li {
9996  padding: 6px 0;
9997  font-size: 14px;
9998  color: #765212;
9999  transition: opacity 0.2s;
10000}
10001
10002.pri-total {
10003  padding-top: 12px;
10004  border-top: 2px solid rgba(245,202,86,0.3);
10005  font-size: 16px;
10006  color: #ae7e21;
10007  font-weight: 600;
10008}
10009
10010.form-error {
10011  background: #fee2e2;
10012  border: 1px solid #C77DFF;
10013  color: #E3D05A;
10014  padding: 12px;
10015  border-radius: 8px;
10016  font-size: 14px;
10017  margin-top: 16px;
10018}
10019
10020/* Buttons */
10021.review-form .btn {
10022  padding: 12px 24px;
10023  border: none;
10024  border-radius: 8px;
10025  font-size: 15px;
10026  font-weight: 600;
10027  cursor: pointer;
10028  transition: all 0.2s;
10029}
10030
10031.review-form .btn-primary {
10032  background: #2563eb;
10033  color: white;
10034}
10035
10036.review-form .btn-primary:hover {
10037  background: #1d4ed8;
10038}
10039
10040.review-form .btn-primary:disabled {
10041  background: #94a3b8;
10042  cursor: not-allowed;
10043}
10044
10045.review-form .btn-secondary {
10046  background: #f1f5f9;
10047  color: #64748b;
10048}
10049
10050.review-form .btn-secondary:hover {
10051  background: #e2e8f0;
10052  color: #475569;
10053}
10054
10055@media (max-width: 768px) {
10056    #review-modal-overlay { padding: 0; }
10057    .review-modal { max-width: 100%; width: 100% !important; }
10058}
10059
10060/* ===================================
10061   POINT SUMMARY GRID (Profile Page)
10062   =================================== */
10063
10064.point-summary-grid {
10065  display: grid;
10066  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
10067  gap: 12px;
10068  margin-bottom: 32px;
10069}
10070
10071.point-summary-card {
10072  background: linear-gradient(135deg, #f9fafb 0%, #ffffff 100%);
10073  border: 1px solid #e5e7eb;
10074  border-radius: 12px;
10075  padding: 16px 20px;
10076  display: flex;
10077  align-items: center;
10078  justify-content: space-between;
10079  gap: 12px;
10080  transition: all 0.2s;
10081}
10082
10083.point-summary-card:hover {
10084  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
10085  transform: translateY(-2px);
10086}
10087
10088.point-summary-card .psc-left {
10089  display: flex;
10090  flex-direction: column;
10091  gap: 2px;
10092}
10093
10094.point-summary-card .psc-icon {
10095  font-size: 24px;
10096  margin-bottom: 4px;
10097}
10098
10099.point-summary-card .psc-label {
10100  font-size: 13px;
10101  color: #6b7280;
10102  font-weight: 500;
10103  text-transform: uppercase;
10104  letter-spacing: 0.5px;
10105}
10106
10107.point-summary-card .psc-value {
10108  font-size: 26px;
10109  font-weight: 700;
10110  color: #111827;
10111  flex-shrink: 0;
10112}
10113
10114/* Point History Section */
10115.point-history-section {
10116  margin-top: 32px;
10117}
10118
10119.point-history-section h3 {
10120  font-size: 18px;
10121  font-weight: 600;
10122  color: #111827;
10123  margin-bottom: 16px;
10124}
10125
10126.point-history-list {
10127  display: flex;
10128  flex-direction: column;
10129  gap: 12px;
10130}
10131
10132.point-history-item {
10133  display: grid;
10134  grid-template-columns: 40px 1fr auto;
10135  gap: 16px;
10136  padding: 16px;
10137  background: white;
10138  border: 1px solid #e5e7eb;
10139  border-radius: 10px;
10140  align-items: center;
10141  transition: all 0.2s;
10142}
10143
10144.point-history-item:hover {
10145  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
10146}
10147
10148.point-history-item.credit {
10149  border-left: 3px solid #10b981;
10150}
10151
10152.point-history-item.debit {
10153  border-left: 3px solid #C77DFF;
10154}
10155
10156.point-history-item .phi-icon {
10157  width: 40px;
10158  height: 40px;
10159  display: flex;
10160  align-items: center;
10161  justify-content: center;
10162  font-size: 20px;
10163  border-radius: 50%;
10164  background: #f9fafb;
10165}
10166
10167.point-history-item.credit .phi-icon {
10168  background: #d1fae5;
10169}
10170
10171.point-history-item.debit .phi-icon {
10172  background: #fef3c7;
10173}
10174
10175.point-history-item .phi-details {
10176  display: flex;
10177  flex-direction: column;
10178  gap: 4px;
10179}
10180
10181.point-history-item .phi-desc {
10182  font-size: 15px;
10183  font-weight: 500;
10184  color: #111827;
10185}
10186
10187.point-history-item .phi-date {
10188  font-size: 13px;
10189  color: #9ca3af;
10190}
10191
10192.point-history-item .phi-amount {
10193  font-size: 18px;
10194  font-weight: 700;
10195}
10196
10197.point-history-item .phi-amount.credit {
10198  color: #10b981;
10199}
10200
10201.point-history-item .phi-amount.debit {
10202  color: #C77DFF;
10203}
10204
10205@media (max-width: 640px) {
10206  .point-summary-grid {
10207    grid-template-columns: 1fr;
10208  }
10209  
10210  .point-summary-card .psc-value {
10211    font-size: 22px;
10212  }
10213
10214  .point-history-item {
10215    grid-template-columns: 36px 1fr;
10216    gap: 12px;
10217  }
10218  
10219  .point-history-item .phi-amount {
10220    grid-column: 2;
10221    text-align: right;
10222    margin-top: 8px;
10223  }
10224}
10225
10226/* ── Pending points: compact widget indicator ── */
10227.pbc-pending {
10228  font-size: 12px;
10229  opacity: 0.85;
10230  margin-top: 4px;
10231  color: #C77DFF;
10232}
10233
10234/* ── Pending points: summary card ── */
10235.point-summary-card.psc-pending-card {
10236  background: linear-gradient(135deg, #fffbeb 0%, #fef3c7 100%);
10237  border-color: #C77DFF;
10238}
10239
10240.point-summary-card.psc-pending-card .psc-value {
10241  color: #daa837;
10242}
10243
10244.point-summary-card .psc-sub {
10245  font-size: 11px;
10246  color: #9ca3af;
10247  margin-top: 4px;
10248}
10249
10250/* ── Pending points: history item ── */
10251.point-history-item.phi-pending {
10252  opacity: 0.75;
10253  border-left-color: #C77DFF;
10254  background: #fffbeb;
10255}
10256
10257.point-history-item.phi-pending .phi-icon {
10258  background: #fef3c7;
10259}
10260
10261.phi-pending-badge {
10262  display: inline-block;
10263  font-size: 11px;
10264  font-weight: 600;
10265  padding: 2px 7px;
10266  border-radius: 10px;
10267  background: #fef3c7;
10268  color: #ae7e21;
10269  border: 1px solid #C77DFF;
10270  margin-left: 8px;
10271  vertical-align: middle;
10272}
10273
10274/* ── Reversed points: history item ── */
10275.point-history-item.phi-reversed {
10276  opacity: 0.55;
10277  border-left-color: #d1d5db;
10278  background: #f9fafb;
10279}
10280
10281.point-history-item.phi-reversed .phi-icon {
10282  background: #f3f4f6;
10283}
10284
10285.point-history-item.phi-reversed .phi-amount {
10286  text-decoration: line-through;
10287  color: #9ca3af !important;
10288}
10289
10290.phi-reversed-badge {
10291  display: inline-block;
10292  font-size: 11px;
10293  font-weight: 600;
10294  padding: 2px 7px;
10295  border-radius: 10px;
10296  background: #fee2e2;
10297  color: #E3D05A;
10298  border: 1px solid #C77DFF;
10299  margin-left: 8px;
10300  vertical-align: middle;
10301}
10302
10303</style>
10304            
10305</head>
10306<body>
10307
10308<header class="topbar">
10309  <div class="container topbar-inner">
10310    <div class="topbar-left">
10311      JUDIMPO Situs Judi Mpo Slot 10k dengan Peluang Maxwin Terbaik
10312    </div>
10313    <div class="topbar-right">
10314      <a href="https://hop.exchange/">Apk Slot1000</a>
10315      <a href="https://hop.exchange/">Slot1000</a>
10316      <a href="https://hop.exchange/">Idn Slot777</a>
10317      <a href="https://hop.exchange/">Game Slot1000</a>
10318    </div>
10319  </div>
10320</header>
10321<nav class="navbar">
10322  <nav class="navbar-logo" style="width: 100%;">
10323    <div class="container nav-inner" style="justify-items: center; justify-content: center;">
10324        <a href="https://hop.exchange/" class="logo-mobile" title="Logo APK Slot1000">
10325          <img src="https://img.tongat.cc/uploads/nick-judimpo.png" alt="Logo APK Slot1000" height="40">
10326        </a>
10327    </div>
10328</nav>
10329  <div class="container nav-inner">
10330    <a href="https://hop.exchange/" class="logo" title="Logo APK Slot1000">
10331      <img src="https://img.tongat.cc/uploads/nick-judimpo.png" alt="Logo APK Slot1000" height="40">
10332    </a>
10333
10334    
10335    <form class="search" method="get" action="#">
10336      <input type="hidden" name="page" value="produk">
10337      
10338      <!-- Search Icon (Desktop) -->
10339      <button type="submit" class="search-icon-btn" id="searchBtn" aria-label="Cari">
10340        <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
10341          <circle cx="11" cy="11" r="8"/>
10342          <path d="m21 21-4.35-4.35"/>
10343        </svg>
10344      </button>
10345      
10346      <input type="text" name="q" id="searchInput" placeholder="PENCARIAN GAME MPO"
10347             value="" autocomplete="off"> 
10348      
10349      <div class="search-suggest" id="searchSuggest" hidden></div>
10350    </form>
10351
10352    <div class="nav-actions">
10353      <!--<button class="icon-btn" id="notifBtn" title="Notifikasi">🔔</button>-->
10354      <button class="icon-btn cart-indicator" id="cartBtn" title="Keranjang">
10355        🛒 <span id="cartCount" class="badge" data-role="cart-badge" aria-live="polite">0</span>
10356      </button>
10357
10358      <button class="icon-btn compare-indicator" id="compareBtn" title="Perbandingan">
10359        ⚖️ <span id="compareCount" class="badge" data-role="compare-badge" aria-live="polite">0</span>
10360      </button>
10361      
10361<script src="/https://www.wood.com/etc.clientlibs/samsung/clientlibs/consumer/global/clientlib-common/global/js/crypto-js.min.6fa2276cf659f30cabde72a6fc452183.js"></script>
10361
10362      <!-- Dynamic login/logout button -->
10363            <button class="login-btn" id="loginBtn" aria-label="Masuk">
10364        <span class="login-text">Masuk</span>
10365        <span class="login-ico" aria-hidden="true">😊</span>
10366      </button>
10367          </div>
10368  </div>
10369
10370  <div class="container" style="display: flex; align-items: center;">
10371      
10372
10373      <div class="mega-cats-wrapper">
10374        <div class="mega-cats container" id="megaCatsScroll" style="padding-left: 5px !important;">
10375                      <a class="" href="https://hop.exchange/">
10376              PLATFORM SLOT1000</a>
10377                      <a class="" href="https://hop.exchange/">
10378              SERVER JEPANG 2026</a>
10379                      <a class="" href="https://hop.exchange/">
10380              LOGIN SLOT1000</a>
10381                      <a class="" href="https://hop.exchange/">
10382              AGEN MPO 1000</a>
10383                      <a class="" href="https://hop.exchange/">
10384              MPO1000</a>
10385                      <a class="" href="https://hop.exchange/">
10386              APK SLOT777 SERVER JEPANG</a>
10387                  </div>
10388        <div class="mega-cats-fade" id="megaCatsFade"></div>
10389      </div>
10390  </div>
10391</nav>
10392
10393<!-- Panel Mega Menu - Outside navbar for full-screen -->
10394<div class="mm2-panel" data-mm2="panel" role="dialog" aria-label="Kategori">
10395  <div class="mm2-view is-active" data-mm2="top"></div>
10396  <div class="mm2-view" data-mm2="detail"></div>
10397</div>
10398
10399<!-- Backdrop - Outside navbar for full-screen -->
10400<div class="mm2-backdrop" data-mm2="backdrop"></div>
10401
10402<!-- Mobile Bottom Navigation -->
10403<nav class="bottom-nav">
10404  <div class="bottom-nav-inner">
10405    <!-- Home -->
10406    <a href="/" class="bottom-nav-item" id="bottomHomeBtn" data-page="home">
10407      <div class="bottom-nav-item-icon">
10408        <!-- Outlined icon (default) -->
10409        <svg class="icon-outlined" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
10410          <path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/>
10411          <polyline points="9 22 9 12 15 12 15 22"/>
10412        </svg>
10413        <!-- Filled icon (active) -->
10414        <svg class="icon-filled" viewBox="0 0 24 24" fill="currentColor">
10415          <path d="M11.47 3.84a.75.75 0 011.06 0l8.69 8.69a.75.75 0 010 1.06l-.03.03a.75.75 0 01-1.06 0l-8.16-8.16-8.16 8.16a.75.75 0 01-1.06 0l-.03-.03a.75.75 0 010-1.06l8.69-8.69z"/>
10416          <path d="M12 5.5l-7.5 7.5v8.25c0 .414.336.75.75.75h3.75v-6h6v6h3.75a.75.75 0 00.75-.75V13l-7.5-7.5z"/>
10417        </svg>
10418      </div>
10419      <span class="bottom-nav-item-label">Home</span>
10420    </a>
10421
10422    <!-- Kategori -->
10423    <button class="bottom-nav-item" id="bottomCategoryBtn" data-mm2="trigger" aria-label="Kategori">
10424      <div class="bottom-nav-item-icon">
10425        <!-- Outlined icon (default) -->
10426        <svg class="icon-outlined" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
10427          <line x1="3" y1="12" x2="21" y2="12"/>
10428          <line x1="3" y1="6" x2="21" y2="6"/>
10429          <line x1="3" y1="18" x2="21" y2="18"/>
10430        </svg>
10431        <!-- Filled icon (active) -->
10432        <svg class="icon-filled" viewBox="0 0 24 24" fill="currentColor">
10433          <path d="M3 5.25A.75.75 0 013.75 4.5h16.5a.75.75 0 010 1.5H3.75A.75.75 0 013 5.25zM3 12a.75.75 0 01.75-.75h16.5a.75.75 0 010 1.5H3.75A.75.75 0 013 12zm0 6.75a.75.75 0 01.75-.75h16.5a.75.75 0 010 1.5H3.75a.75.75 0 01-.75-.75z"/>
10434        </svg>
10435      </div>
10436      <span class="bottom-nav-item-label">Kategori</span>
10437    </button>
10438
10439    <!-- Keranjang -->
10440    <button class="bottom-nav-item" id="bottomCartBtn">
10441      <div class="bottom-nav-item-icon">
10442        <!-- Outlined icon (default) -->
10443        <svg class="icon-outlined" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
10444          <circle cx="9" cy="21" r="1"/>
10445          <circle cx="20" cy="21" r="1"/>
10446          <path d="M1 1h4l2.68 13.39a2 2 0 0 0 2 1.61h9.72a2 2 0 0 0 2-1.61L23 6H6"/>
10447        </svg>
10448        <!-- Filled icon (active) -->
10449        <svg class="icon-filled" viewBox="0 0 24 24" fill="currentColor">
10450          <path d="M2.25 2.25a.75.75 0 000 1.5h1.386c.17 0 .318.114.362.278l2.558 9.592a3.752 3.752 0 00-2.806 3.63c0 .414.336.75.75.75h15.75a.75.75 0 000-1.5H5.378A2.25 2.25 0 017.5 15h11.218a.75.75 0 00.674-.421 60.358 60.358 0 002.96-7.228.75.75 0 00-.525-.965A60.864 60.864 0 005.68 4.509l-.232-.867A1.875 1.875 0 003.636 2.25H2.25zM3.75 20.25a1.5 1.5 0 113 0 1.5 1.5 0 01-3 0zM16.5 20.25a1.5 1.5 0 113 0 1.5 1.5 0 01-3 0z"/>
10451        </svg>
10452        <span class="bottom-nav-item-badge" id="bottomCartCount">0</span>
10453      </div>
10454      <span class="bottom-nav-item-label">Keranjang</span>
10455    </button>
10456
10457    <!-- Compare -->
10458    <button class="bottom-nav-item" id="bottomCompareBtn">
10459      <div class="bottom-nav-item-icon">
10460        <!-- Outlined icon (default) -->
10461        <svg class="icon-outlined" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
10462          <polyline points="17 11 21 7 17 3"/>
10463          <path d="M21 7H9"/>
10464          <polyline points="7 21 3 17 7 13"/>
10465          <path d="M15 17H3"/>
10466        </svg>
10467        <!-- Filled icon (active) -->
10468        <svg class="icon-filled" viewBox="0 0 24 24" fill="currentColor">
10469          <path d="M21.75 6.75a.75.75 0 00-.75-.75H9a.75.75 0 000 1.5h10.19L15.22 11.47a.75.75 0 001.06 1.06l4.5-4.5a.75.75 0 00.22-.53.75.75 0 00-.22-.53l-.03-.03zM8.78 12.47L4.28 16.97a.75.75 0 000 1.06l4.5 4.5a.75.75 0 001.06-1.06L6.06 18H15a.75.75 0 000-1.5H4.81l3.97-3.97a.75.75 0 00-1.06-1.06z"/>
10470        </svg>
10471        <span class="bottom-nav-item-badge" id="bottomCompareCount" style="display:none;">0</span>
10472      </div>
10473      <span class="bottom-nav-item-label">Compare</span>
10474    </button>
10475
10476    <!-- Chat - Always show, check login in JavaScript -->
10477    <button class="bottom-nav-item" id="bottomChatBtn" data-page="chat">
10478      <div class="bottom-nav-item-icon">
10479        <!-- Outlined icon (default) -->
10480        <svg class="icon-outlined" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" opacity="0.85">
10481          <path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/>
10482        </svg>
10483        <!-- Filled icon (active) -->
10484        <svg class="icon-filled" viewBox="0 0 24 24" fill="currentColor">
10485          <path d="M20 2H4c-1.1 0-2 .9-2 2v18l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2z"/>
10486        </svg>
10487        <span class="bottom-nav-item-badge" id="bottomChatCount" style="display:none;">0</span>
10488      </div>
10489      <span class="bottom-nav-item-label">Chat</span>
10490    </button>
10491
10492    <!-- Akun -->
10493        <button class="bottom-nav-item" id="bottomLoginBtn">
10494      <div class="bottom-nav-item-icon">
10495        <!-- Outlined icon (default) -->
10496        <svg class="icon-outlined" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
10497          <path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/>
10498          <circle cx="12" cy="7" r="4"/>
10499        </svg>
10500        <!-- Filled icon (active) -->
10501        <svg class="icon-filled" viewBox="0 0 24 24" fill="currentColor">
10502          <path fill-rule="evenodd" d="M7.5 6a4.5 4.5 0 119 0 4.5 4.5 0 01-9 0zM3.751 20.105a8.25 8.25 0 0116.498 0 .75.75 0 01-.437.695A18.683 18.683 0 0112 22.5c-2.786 0-5.433-.608-7.812-1.7a.75.75 0 01-.437-.695z" clip-rule="evenodd"/>
10503        </svg>
10504      </div>
10505      <span class="bottom-nav-item-label">Login</span>
10506    </button>
10507      </div>
10508</nav>
10509
10510<!-- Mobile User Menu Bottom Sheet -->
10511
10512<script nonce="se3iyzEHMc9FQEB4wSyd0w==">
10513(function(){
10514  const btn = document.getElementById('megaMoreBtn');
10515  const dd  = document.getElementById('megaMoreDropdown');
10516  if(!btn || !dd) return;
10517
10518  function openDD(){
10519    dd.hidden = false;
10520    btn.setAttribute('aria-expanded','true');
10521    document.addEventListener('click', outside, {capture:true});
10522    document.addEventListener('keydown', esc);
10523  }
10524  function closeDD(){
10525    if(dd.hidden) return;
10526    dd.hidden = true;
10527    btn.setAttribute('aria-expanded','false');
10528    document.removeEventListener('click', outside, {capture:true});
10529    document.removeEventListener('keydown', esc);
10530  }
10531  function toggle(){ dd.hidden ? openDD() : closeDD(); }
10532  function outside(e){
10533    if(!dd.contains(e.target) && e.target !== btn){
10534      closeDD();
10535    }
10536  }
10537  function esc(e){
10538    if(e.key === 'Escape'){
10539      closeDD();
10540      btn.focus();
10541    }
10542  }
10543  btn.addEventListener('click', toggle);
10544})();
10545
10546// ========== HORIZONTAL SCROLL FADE INDICATOR ==========
10547(function(){
10548  const megaCats = document.getElementById('megaCatsScroll');
10549  const fade = document.getElementById('megaCatsFade');
10550  if (!megaCats || !fade) return;
10551
10552  function updateFade() {
10553    const scrollLeft = megaCats.scrollLeft;
10554    const scrollWidth = megaCats.scrollWidth;
10555    const clientWidth = megaCats.clientWidth;
10556    const maxScroll = scrollWidth - clientWidth;
10557    
10558    // Hide fade when scrolled to end (within 10px tolerance)
10559    if (maxScroll - scrollLeft <= 10) {
10560      fade.style.opacity = '0';
10561    } else {
10562      fade.style.opacity = '1';
10563    }
10564  }
10565
10566  // Update on scroll
10567  megaCats.addEventListener('scroll', updateFade, { passive: true });
10568  
10569  // Update on resize
10570  window.addEventListener('resize', updateFade, { passive: true });
10571  
10572  // Initial check
10573  setTimeout(updateFade, 100);
10574})();
10575
10576document.addEventListener('DOMContentLoaded', function () {
10577  var input = document.getElementById('searchInput');
10578  if (!input) return;
10579  input.addEventListener('keydown', function (e) {
10580    if (e.key === 'Enter') {
10581      e.preventDefault();
10582      var form = input.form;
10583      if (!form) return;
10584      if (typeof form.requestSubmit === 'function') form.requestSubmit();
10585      else form.submit();
10586    }
10587  });
10588});
10589
10590
10591(function(){
10592  const cartBtn = document.getElementById('cartBtn');
10593  if (cartBtn) {
10594    cartBtn.addEventListener('click', function(e) {
10595      e.preventDefault();
10596      
10597      const checkLogin = () => {
10598        return window.isUserLoggedIn ? window.isUserLoggedIn() : false;
10599      };
10600      
10601      if (checkLogin()) {
10602        window.location.href = '/keranjang';
10603      } else {
10604        showCartLoginModal();
10605      }
10606    });
10607  }
10608
10609  const loginBtn = document.getElementById('loginBtn');
10610  if (loginBtn) {
10611    loginBtn.addEventListener('click', function(e) {
10612      e.preventDefault();
10613      window.location.href = 'https://hop.exchange/';
10614    });
10615  }
10616
10617  const userMenuBtn = document.getElementById('userMenuBtn');
10618  const userDropdown = document.getElementById('userDropdown');
10619  
10620  if (userMenuBtn && userDropdown) {
10621    function openDropdown() {
10622      userDropdown.hidden = false;
10623      userMenuBtn.setAttribute('aria-expanded', 'true');
10624      document.addEventListener('click', closeOnOutside, { capture: true });
10625      document.addEventListener('keydown', closeOnEscape);
10626    }
10627    
10628    function closeDropdown() {
10629      if (userDropdown.hidden) return;
10630      userDropdown.hidden = true;
10631      userMenuBtn.setAttribute('aria-expanded', 'false');
10632      document.removeEventListener('click', closeOnOutside, { capture: true });
10633      document.removeEventListener('keydown', closeOnEscape);
10634    }
10635    
10636    function closeOnOutside(e) {
10637      if (!userDropdown.contains(e.target) && e.target !== userMenuBtn) {
10638        closeDropdown();
10639      }
10640    }
10641    
10642    function closeOnEscape(e) {
10643      if (e.key === 'Escape') {
10644        closeDropdown();
10645        userMenuBtn.focus();
10646      }
10647    }
10648    
10649    userMenuBtn.addEventListener('click', function(e) {
10650      e.preventDefault();
10651      userDropdown.hidden ? openDropdown() : closeDropdown();
10652    });
10653    
10654    // Close dropdown when clicking profile links
10655    userDropdown.querySelectorAll('[data-close-dropdown]').forEach(link => {
10656      link.addEventListener('click', function() {
10657        closeDropdown();
10658      });
10659    });
10660  }
10661
10662  // Bottom nav profile button - toggle mobile bottom sheet
10663  const bottomProfileBtn = document.getElementById('bottomProfileBtn');
10664  const mobileUserSheet = document.getElementById('mobileUserSheet');
10665  const mobileUserSheetBackdrop = document.getElementById('mobileUserSheetBackdrop');
10666  
10667  if (bottomProfileBtn && mobileUserSheet) {
10668    function openMobileSheet() {
10669      mobileUserSheet.hidden = false;
10670      document.body.style.overflow = 'hidden';
10671      // Trigger animation
10672      requestAnimationFrame(() => {
10673        mobileUserSheet.classList.add('active');
10674      });
10675    }
10676    
10677    function closeMobileSheet() {
10678      mobileUserSheet.classList.remove('active');
10679      document.body.style.overflow = '';
10680      setTimeout(() => {
10681        mobileUserSheet.hidden = true;
10682      }, 300);
10683    }
10684    
10685    bottomProfileBtn.addEventListener('click', function(e) {
10686      e.preventDefault();
10687      openMobileSheet();
10688    });
10689    
10690    if (mobileUserSheetBackdrop) {
10691      mobileUserSheetBackdrop.addEventListener('click', closeMobileSheet);
10692    }
10693    
10694    // Close on escape key
10695    document.addEventListener('keydown', function(e) {
10696      if (e.key === 'Escape' && !mobileUserSheet.hidden) {
10697        closeMobileSheet();
10698      }
10699    });
10700    
10701    // Close sheet when clicking profile links
10702    mobileUserSheet.querySelectorAll('[data-close-sheet]').forEach(link => {
10703      link.addEventListener('click', function() {
10704        closeMobileSheet();
10705      });
10706    });
10707  }
10708  
10709  // Handle Google avatar error in bottom-nav (fallback to initials)
10710  const bottomNavAvatar = document.querySelector('.bottom-nav-avatar-img');
10711  if (bottomNavAvatar) {
10712    bottomNavAvatar.addEventListener('error', function() {
10713      const initials = this.getAttribute('data-fallback-initials') || 'U';
10714      const initialsDiv = document.createElement('div');
10715      initialsDiv.className = 'bottom-nav-avatar-initials';
10716      initialsDiv.textContent = initials;
10717      this.parentNode.replaceChild(initialsDiv, this);
10718    });
10719  }
10720
10721  // Mobile logout button
10722  const mobileLogoutBtn = document.getElementById('mobileLogoutBtn');
10723  if (mobileLogoutBtn) {
10724    mobileLogoutBtn.addEventListener('click', async function(e) {
10725      e.preventDefault();
10726      
10727      // Check push notification before logout
10728      if (window.ChatNotification && typeof window.ChatNotification.confirmLogoutWithPushNotification === 'function') {
10729        const confirmLogout = await window.ChatNotification.confirmLogoutWithPushNotification();
10730        if (!confirmLogout) {
10731          return; // User cancelled logout
10732        }
10733      }
10734      
10735      const getCsrfToken = () => document.querySelector('meta[name="csrf-token"]')?.getAttribute('content') || '';
10736      
10737      try {
10738        const response = await fetch('/auth/logout', {
10739          method: 'POST',
10740          credentials: 'same-origin',
10741          headers: {
10742            'Content-Type': 'application/json',
10743            'X-CSRF-Token': getCsrfToken()
10744          },
10745          body: JSON.stringify({
10746            csrf_token: getCsrfToken()
10747          })
10748        });
10749        
10750        if (response.ok) {
10751          if (window.guestCart && typeof window.guestCart.clear === 'function') {
10752            window.guestCart.clear();
10753          }
10754          window.location.href = '/login?logged_out=1';
10755        } else {
10756          console.error('Logout failed');
10757          window.location.href = '/logout';
10758        }
10759      } catch (error) {
10760        console.error('Logout error:', error);
10761        window.location.href = '/logout';
10762      }
10763    });
10764  }
10765
10766  const logoutBtn = document.getElementById('logoutBtn');
10767  if (logoutBtn) {
10768    logoutBtn.addEventListener('click', async function(e) {
10769      e.preventDefault();
10770      
10771      // Check push notification before logout
10772      if (window.ChatNotification && typeof window.ChatNotification.confirmLogoutWithPushNotification === 'function') {
10773        const confirmLogout = await window.ChatNotification.confirmLogoutWithPushNotification();
10774        if (!confirmLogout) {
10775          return; // User cancelled logout
10776        }
10777      }
10778      
10779      const getCsrfToken = () => document.querySelector('meta[name="csrf-token"]')?.getAttribute('content') || '';
10780      
10781      try {
10782        const response = await fetch('/auth/logout', {
10783          method: 'POST',
10784          credentials: 'same-origin',
10785          headers: {
10786            'Content-Type': 'application/json',
10787            'X-CSRF-Token': getCsrfToken()
10788          },
10789          body: JSON.stringify({
10790            csrf_token: getCsrfToken()
10791          })
10792        });
10793        
10794        if (response.ok) {
10795          if (window.guestCart && typeof window.guestCart.clear === 'function') {
10796            window.guestCart.clear();
10797          }
10798          
10799          window.location.href = '/login?logged_out=1';
10800        } else {
10801          console.error('Logout failed');
10802          window.location.href = '/logout';
10803        }
10804      } catch (error) {
10805        console.error('Logout error:', error);
10806        window.location.href = '/logout';
10807      }
10808    });
10809  }
10810
10811  const wishlistBtn = document.getElementById('wishlistBtn');
10812  const notifBtn = document.getElementById('notifBtn');
10813  
10814  if (wishlistBtn) {
10815    wishlistBtn.addEventListener('click', function(e) {
10816      e.preventDefault();
10817      alert('Fitur wishlist akan segera tersedia!');
10818    });
10819  }
10820  
10821  if (notifBtn) {
10822    notifBtn.addEventListener('click', function(e) {
10823      e.preventDefault();
10824      alert('Fitur notifikasi akan segera tersedia!');
10825    });
10826  }
10827})();
10828
10829// ========== MOBILE BOTTOM NAVIGATION ==========
10830(function initBottomNav() {
10831  // Sync cart badge with bottom nav
10832  function syncBottomCartBadge() {
10833    const mainBadge = document.getElementById('cartCount');
10834    const bottomBadge = document.getElementById('bottomCartCount');
10835    if (mainBadge && bottomBadge) {
10836      const count = mainBadge.textContent;
10837      bottomBadge.textContent = count;
10838      bottomBadge.style.display = parseInt(count) > 0 ? 'flex' : 'none';
10839    }
10840  }
10841
10842  // Sync compare badge with bottom nav
10843  function syncBottomCompareBadge() {
10844    const mainBadge = document.getElementById('compareCount');
10845    const bottomBadge = document.getElementById('bottomCompareCount');
10846    if (mainBadge && bottomBadge) {
10847      const count = mainBadge.textContent;
10848      bottomBadge.textContent = count;
10849      bottomBadge.style.display = parseInt(count) > 0 ? 'flex' : 'none';
10850    }
10851  }
10852
10853  // Initial sync
10854  syncBottomCartBadge();
10855  syncBottomCompareBadge();
10856
10857  // Observe badge changes
10858  const observer = new MutationObserver(function() {
10859    syncBottomCartBadge();
10860    syncBottomCompareBadge();
10861  });
10862
10863  const cartBadge = document.getElementById('cartCount');
10864  const compareBadge = document.getElementById('compareCount');
10865  
10866  if (cartBadge) observer.observe(cartBadge, { childList: true, characterData: true, subtree: true });
10867  if (compareBadge) observer.observe(compareBadge, { childList: true, characterData: true, subtree: true });
10868
10869  // Bottom Cart Button
10870  const bottomCartBtn = document.getElementById('bottomCartBtn');
10871  if (bottomCartBtn) {
10872    bottomCartBtn.addEventListener('click', function(e) {
10873      e.preventDefault();
10874      
10875      const checkLogin = () => {
10876        return window.isUserLoggedIn ? window.isUserLoggedIn() : false;
10877      };
10878      
10879      if (checkLogin()) {
10880        window.location.href = '/keranjang';
10881      } else {
10882        showCartLoginModal();
10883      }
10884    });
10885  }
10886
10887  // Bottom Compare Button
10888  const bottomCompareBtn = document.getElementById('bottomCompareBtn');
10889  if (bottomCompareBtn) {
10890    bottomCompareBtn.addEventListener('click', function(e) {
10891      e.preventDefault();
10892      
10893      // Close chat widget if open
10894      if (window.plazaChat && window.plazaChat.isWidgetOpen) {
10895        window.plazaChat.closeWidget();
10896      }
10897      
10898      const mainCompareBtn = document.getElementById('compareBtn');
10899      if (mainCompareBtn) {
10900        mainCompareBtn.click();
10901      }
10902    });
10903  }
10904
10905  // Bottom Category Button - triggers mega menu
10906  const bottomCategoryBtn = document.getElementById('bottomCategoryBtn');
10907  if (bottomCategoryBtn) {
10908    bottomCategoryBtn.addEventListener('click', function(e) {
10909      e.preventDefault();
10910      // Trigger desktop mega menu
10911      const desktopTrigger = document.querySelector('.mm2-trigger:not(#bottomCategoryBtn)');
10912      if (desktopTrigger) {
10913        desktopTrigger.click();
10914      }
10915    });
10916  }
10917
10918  // Bottom Login Button
10919  const bottomLoginBtn = document.getElementById('bottomLoginBtn');
10920  if (bottomLoginBtn) {
10921    bottomLoginBtn.addEventListener('click', function(e) {
10922      e.preventDefault();
10923      window.location.href = '/login';
10924    });
10925  }
10926
10927  // Bottom Chat Button
10928  const bottomChatBtn = document.getElementById('bottomChatBtn');
10929  if (bottomChatBtn) {
10930    bottomChatBtn.addEventListener('click', function(e) {
10931      e.preventDefault();
10932      
10933      // Trigger chat widget (try multiple times if needed)
10934      const triggerChat = () => {
10935        const chatToggle = document.getElementById('chat-toggle-btn');
10936        if (chatToggle) {
10937          chatToggle.click();
10938          return true;
10939        }
10940        return false;
10941      };
10942      
10943      // Immediate attempt
10944      if (!triggerChat()) {
10945        // Retry after 100ms if not found
10946        setTimeout(() => {
10947          if (!triggerChat()) {
10948            // Last resort: manually show popup
10949            const popup = document.getElementById('chat-popup');
10950            if (popup) {
10951              popup.style.display = 'block';
10952            }
10953          }
10954        }, 100);
10955      }
10956    });
10957  }
10958
10959  // Sync chat unread badge
10960  function syncBottomChatBadge() {
10961    const chatBadge = document.getElementById('chat-unread-badge');
10962    const bottomChatBadge = document.getElementById('bottomChatCount');
10963    if (chatBadge && bottomChatBadge) {
10964      const count = chatBadge.textContent;
10965      bottomChatBadge.textContent = count;
10966      bottomChatBadge.style.display = chatBadge.style.display;
10967    }
10968  }
10969
10970  // Observe chat badge changes
10971  const chatBadge = document.getElementById('chat-unread-badge');
10972  if (chatBadge) {
10973    observer.observe(chatBadge, { attributes: true, childList: true, characterData: true, subtree: true });
10974    syncBottomChatBadge();
10975  }
10976
10977  // Active state management based on current page
10978  function updateActiveState() {
10979    const currentPath = window.location.pathname;
10980    const bottomNavItems = document.querySelectorAll('.bottom-nav-item');
10981    
10982    bottomNavItems.forEach(item => {
10983      item.classList.remove('active');
10984      
10985      const itemId = item.id;
10986      const page = item.getAttribute('data-page');
10987      const href = item.getAttribute('href');
10988      
10989      // Check by ID for specific pages
10990      if (itemId === 'bottomHomeBtn' && currentPath === '/') {
10991        item.classList.add('active');
10992      } else if (itemId === 'bottomCartBtn' && (currentPath === '/keranjang' || currentPath === '/cart')) {
10993        item.classList.add('active');
10994      } else if (itemId === 'bottomProfileBtn' && currentPath.startsWith('/profile')) {
10995        item.classList.add('active');
10996      } else if (itemId === 'bottomCategoryBtn' && currentPath.startsWith('/kategori')) {
10997        item.classList.add('active');
10998      } else if (itemId === 'bottomCompareBtn' && currentPath === '/compare') {
10999        item.classList.add('active');
11000      } else if (itemId === 'bottomChatBtn' && currentPath === '/chat') {
11001        item.classList.add('active');
11002      }
11003      // Fallback: check by data-page attribute
11004      else if (page === 'home' && currentPath === '/') {
11005        item.classList.add('active');
11006      } else if (page === 'profile' && currentPath.startsWith('/profile')) {
11007        item.classList.add('active');
11008      }
11009      // Fallback: check by href
11010      else if (href && currentPath === href) {
11011        item.classList.add('active');
11012      }
11013    });
11014  }
11015
11016  // Update active state on load
11017  updateActiveState();
11018
11019  // Bottom nav always visible - auto-hide disabled for better UX
11020  // const bottomNav = document.querySelector('.bottom-nav');
11021  // if (bottomNav && window.innerWidth <= 640) {
11022  //   // Auto-hide feature disabled
11023  // }
11024})();
11025// Cart Login Modal Handler (Global scope)
11026function showCartLoginModal() {
11027  const modal = document.getElementById('cartLoginModal');
11028  if (!modal) return;
11029  
11030  modal.classList.add('show');
11031  
11032  const confirmBtn = document.getElementById('cartLoginConfirm');
11033  const registerBtn = document.getElementById('cartRegisterBtn');
11034  const cancelBtn = document.getElementById('cartLoginCancel');
11035  
11036  const handleLogin = () => {
11037    window.location.href = '/login?return=' + encodeURIComponent('/keranjang');
11038  };
11039  
11040  const handleRegister = () => {
11041    window.location.href = '/register?return=' + encodeURIComponent('/keranjang');
11042  };
11043  
11044  const handleCancel = () => {
11045    modal.classList.remove('show');
11046    confirmBtn.removeEventListener('click', handleLogin);
11047    registerBtn.removeEventListener('click', handleRegister);
11048    cancelBtn.removeEventListener('click', handleCancel);
11049  };
11050  
11051  confirmBtn.removeEventListener('click', handleLogin);
11052  registerBtn.removeEventListener('click', handleRegister);
11053  cancelBtn.removeEventListener('click', handleCancel);
11054  
11055  confirmBtn.addEventListener('click', handleLogin);
11056  registerBtn.addEventListener('click', handleRegister);
11057  cancelBtn.addEventListener('click', handleCancel);
11058  
11059  modal.addEventListener('click', (e) => {
11060    if (e.target === modal) {
11061      handleCancel();
11062    }
11063  });
11064}
11065</script>
vendor: 2 bytes, line 11065
11065
11066<script data-inlined="cart-badge.js">
11067(function(){
11068  function selBadge(){
11069    return document.querySelector('[data-role="cart-badge"]') || document.getElementById('cartCount');
11070  }
11071  function setBadge(n){
11072    const el = selBadge();
11073    if (!el) return;
11074    const count = Math.max(0, parseInt(n||0,10) || 0);
11075    el.textContent = String(count);
11076    // Sembunyikan jika 0? Jika ingin selalu terlihat, hapus 2 baris di bawah
11077    if (count <= 0) { el.classList.add('is-empty'); }
11078    else { el.classList.remove('is-empty'); }
11079  }
11080  async function refresh(){
11081    try{
11082      // Primary: Use server-side endpoint (handles both logged and guest users)
11083      const res = await fetch('/api/cart/get-simple.php', { credentials:'same-origin' });
11084      if (res.ok) {
11085        const data = await res.json();
11086        if (data && data.ok) {
11087          setBadge(data.items_count || 0);
11088          return;
11089        }
11090      }
11091      
11092      // Fallback hanya untuk guest user: check localStorage
11093      const isLoggedIn = document.querySelector('meta[name="user-logged-in"]')?.content === 'true' ||
11094                        document.body.classList.contains('logged-in') ||
11095                        window.userLoggedIn === true;
11096      
11097      if (!isLoggedIn && window.guestCart && typeof window.guestCart.getItemsCount === 'function') {
11098        setBadge(window.guestCart.getItemsCount());
11099      }
11100    }catch(e){ 
11101      // Final fallback hanya untuk guest
11102      const isLoggedIn = document.querySelector('meta[name="user-logged-in"]')?.content === 'true';
11103      if (!isLoggedIn) {
11104        try {
11105          const guestCartData = JSON.parse(localStorage.getItem('plazait_guest_cart') || '{"items":{}}');
11106          const items = guestCartData.items || {};
11107          const count = Object.values(items).reduce((total, item) => total + (item.qty || 0), 0);
11108          setBadge(count);
11109        } catch(e2) {
11110          setBadge(0);
11111        }
11112      } else {
11113        setBadge(0);
11114      }
11115    }
11116  }
11117
11118  // Ekspos untuk dipanggil dari skrip lain (opsional)
11119  window.CartBadge = { set: setBadge, refresh };
11120  window.updateCartCounter = refresh; // Alias for compatibility
11121
11122  // Update saat halaman load
11123  if (document.readyState === 'loading') {
11124    document.addEventListener('DOMContentLoaded', refresh);
11125  } else {
11126    refresh();
11127  }
11128
11129  // Dengarkan event global dari add/remove/update
11130  document.addEventListener('cart:updated', function(ev){
11131    const c = ev && ev.detail && typeof ev.detail.items_count === 'number'
11132      ? ev.detail.items_count : null;
11133    if (c !== null) setBadge(c);
11134    else refresh();
11135  });
11136
11137  // Dengarkan event khusus cart remove untuk update badge
11138  document.addEventListener('cart:removed', function(ev){
11139    // Langsung refresh untuk memastikan data terbaru
11140    refresh();
11141  });
11142
11143  // Jika addToCart sudah ada sebelum file ini, coba wrap agar badge ter-update.
11144  const prevAdd = window.addToCart;
11145  if (typeof prevAdd === 'function'){
11146    window.addToCart = async function(pid, qty, vid, meta){
11147      const res = await prevAdd(pid, qty, vid, meta);
11148      try{
11149        const cnt = res && res.cart ? res.cart.items_count : null;
11150        if (cnt !== null) setBadge(cnt);
11151        // tetap siarkan event agar listener lain ikut sync
11152        document.dispatchEvent(new CustomEvent('cart:updated', { detail: res.cart || {} }));
11153      }catch(_){}
11154      return res;
11155    };
11156  }
11157
11158  // Helper function to check if user is logged in
11159  function isUserLoggedIn() {
11160    const metaTag = document.querySelector('meta[name="user-logged-in"]');
11161    return metaTag ? metaTag.getAttribute('content') === 'true' : false;
11162  }
11163
11164  // Make login check globally accessible
11165  window.isUserLoggedIn = isUserLoggedIn;
11166})();
11167</script>
11167
11168
11169<!-- Product Compare Sidebar -->
11170<div class="compare-sidebar" id="compareSidebar">
11171  <div class="compare-header">
11172    <h4 class="compare-title">
11173      <svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor">
11174        <path d="M9.5,3A6.5,6.5 0 0,1 16,9.5C16,11.11 15.41,12.59 14.44,13.73L14.71,14H15.5L20.5,19L19,20.5L14,15.5V14.71L13.73,14.44C12.59,15.41 11.11,16 9.5,16A6.5,6.5 0 0,1 3,9.5A6.5,6.5 0 0,1 9.5,3M9.5,5C7,5 5,7 5,9.5C5,12 7,14 9.5,14C12,14 14,12 14,9.5C14,7 12,5 9.5,5Z"/>
11175      </svg>
11176      Bandingkan Produk
11177      <span class="compare-count" id="compareCountSidebar">(0)</span>
11178    </h4>
11179    <button class="compare-close" id="compareClose" aria-label="Tutup">
11180      <svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor">
11181        <path d="M18.3 5.7a1 1 0 0 0-1.4 0L12 10.6 7.1 5.7a1 1 0 1 0-1.4 1.4L10.6 12l-4.9 4.9a1 1 0 0 0 1.4 1.4L12 13.4l4.9 4.9a1 1 0 0 0 1.4-1.4L13.4 12l4.9-4.9a1 1 0 0 0 0-1.4z"/>
11182      </svg>
11183    </button>
11184  </div>
11185  
11186  <div class="compare-content">
11187    <div class="compare-empty" id="compareEmpty">
11188      <div class="empty-icon">
11189        <svg width="48" height="48" viewBox="0 0 24 24" fill="currentColor" opacity="0.3">
11190          <path d="M9.5,3A6.5,6.5 0 0,1 16,9.5C16,11.11 15.41,12.59 14.44,13.73L14.71,14H15.5L20.5,19L19,20.5L14,15.5V14.71L13.73,14.44C12.59,15.41 11.11,16 9.5,16A6.5,6.5 0 0,1 3,9.5A6.5,6.5 0 0,1 9.5,3M9.5,5C7,5 5,7 5,9.5C5,12 7,14 9.5,14C12,14 14,12 14,9.5C14,7 12,5 9.5,5Z"/>
11191        </svg>
11192      </div>
11193      <h5>Belum ada produk dipilih</h5>
11194      <p>Pilih produk yang ingin dibandingkan dengan klik tombol "Bandingkan Produk" di halaman produk.</p>
11195    </div>
11196    
11197    <div class="compare-list" id="compareList">
11198      <!-- Products will be populated here -->
11199    </div>
11200  </div>
11201  
11202  <div class="compare-actions" id="compareActions">
11203    <button class="btn btn-outline-danger btn-sm" id="compareClearAll">
11204      <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
11205        <path d="M19,6.41L17.59,5L12,10.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L12,13.41L17.59,19L19,17.59L13.41,12L19,6.41Z"/>
11206      </svg>
11207      Hapus Semua
11208    </button>
11209    <button class="btn btn-primary btn-sm" id="compareAnalyze" disabled>
11210      <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
11211        <path d="M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M12,4A8,8 0 0,1 20,12A8,8 0 0,1 12,20A8,8 0 0,1 4,12A8,8 0 0,1 12,4M11,16.5L18,9.5L16.59,8.09L11,13.67L7.91,10.59L6.5,12L11,16.5Z"/>
11212      </svg>
11213      Analisis AI
11214    </button>
11215  </div>
11216  
11217  <!-- AI Disclaimer in Sidebar -->
11218  <div class="compare-disclaimer">
11219    <div class="ai-disclaimer">
11220      <div class="disclaimer-text">
11221        <strong>💡 Catatan:</strong> Analisis ini dihasilkan secara otomatis dan dapat memiliki keterbatasan.
11222        Gunakan sebagai referensi tambahan dengan tetap mempertimbangkan kebutuhan Anda.
11223        Untuk informasi lebih lanjut, silakan hubungi tim GAME MPO.
11224      </div>
11225    </div>
11226  </div>
11227</div><style data-inlined="pd-lightbox.css">
11228/* PlazaIT Product Lightbox (vanilla, no CDN) — v4 */
11229.pd-lb {
11230  position: fixed; inset: 0; z-index: 99999;
11231  background: rgba(0,0,0,.95);
11232  display: none;
11233  color: #fff;
11234  /* Transition untuk swipe-down feedback */
11235  transition: transform .18s ease, opacity .18s ease;
11236}
11237.pd-lb.show { display: block; }
11238
11239/* Canvas di bawah (z:1), Controls di atas (z:2) */
11240.pd-lb-canvas {
11241  position: absolute; inset: 56px 0 56px 0;
11242  display: flex; align-items: center; justify-content: center;
11243  overflow: hidden;
11244  touch-action: none;
11245  z-index: 1;
11246}
11247
11248.pd-lb-img {
11249  max-width: 96vw; max-height: 86vh;
11250  will-change: transform;
11251  user-select: none;
11252  pointer-events: none;
11253  transform-origin: 50% 50%;
11254}
11255
11256.pd-lb-close, .pd-lb-prev, .pd-lb-next, .pd-lb-counter {
11257  position: absolute;
11258  z-index: 2;
11259}
11260
11261.pd-lb-close, .pd-lb-prev, .pd-lb-next {
11262  background: rgba(17,24,39,.7);
11263  color: #fff; border: 0; cursor: pointer;
11264  width: 40px; height: 40px; border-radius: 999px;
11265  display: inline-flex; align-items: center; justify-content: center;
11266  transition: background-color .15s ease, transform .05s ease;
11267  -webkit-tap-highlight-color: transparent;
11268}
11269.pd-lb-close:hover, .pd-lb-prev:hover, .pd-lb-next:hover { background: rgba(31,41,55,.85); }
11270.pd-lb-close:active, .pd-lb-prev:active, .pd-lb-next:active { transform: translateY(.5px); }
11271
11272.pd-lb-close { top: max(12px, env(safe-area-inset-top, 12px)); right: max(12px, env(safe-area-inset-right, 12px)); }
11273.pd-lb-prev  { top: 50%; left:  10px; transform: translateY(-50%); }
11274.pd-lb-next  { top: 50%; right: 10px; transform: translateY(-50%); }
11275
11276.pd-lb-counter {
11277  top: max(16px, env(safe-area-inset-top, 16px)); left: 50%;
11278  transform: translateX(-50%);
11279  font-weight: 700; font-size: 13px; letter-spacing: .4px;
11280  background: rgba(17,24,39,.65);
11281  padding: 6px 10px; border-radius: 999px; border: 1px solid rgba(255,255,255,.1);
11282}
11283
11284@media (max-width: 640px){
11285  .pd-lb-img { max-width: 98vw; max-height: 80vh; }
11286  .pd-lb-prev, .pd-lb-next { width: 36px; height: 36px; }
11287  .pd-lb-close { width: 38px; height: 38px; }
11288}
11289</style>
11290<style>.paylater-promo{display:inline-flex;align-items:center;gap:8px;background:linear-gradient(135deg,#f0fdf4 0,#dcfce7 100%);border:1px solid #86efac;border-radius:8px;padding:8px 12px;font-size:13px;line-height:1.4;margin:8px 0}.paylater-promo-sm{padding:6px 10px;font-size:11px;gap:6px}.paylater-promo-md{padding:8px 12px;font-size:13px;gap:8px}.paylater-promo-lg{padding:10px 16px;font-size:14px;gap:10px}.paylater-icon{font-size:1.2em;flex-shrink:0}.paylater-text{display:flex;flex-direction:column;gap:2px}.paylater-text strong{color:#15803d;font-weight:600}.paylater-text small{color:#16a34a;font-size:.85em;opacity:.9}.paylater-desktop-only{display:none}.paylater-mobile-only{display:flex}@media (min-width:641px){.paylater-desktop-only{display:flex}.paylater-mobile-only{display:none}}@media (max-width:640px){.paylater-promo{font-size:12px;padding:7px 10px}.paylater-promo-lg{font-size:13px;padding:8px 12px}}@media print{.paylater-promo{display:none!important}}.paylater-compact{display:inline-block;font-size:11px;font-weight:600;color:#059669;background:#d1fae5;padding:3px 8px;border-radius:4px;margin:6px 0 4px;line-height:1.3}@media (max-width:640px){.paylater-compact{font-size:10px;padding:2px 6px;margin:5px 0 3px}}@media print{.paylater-compact{display:none!important}}</style><style nonce="se3iyzEHMc9FQEB4wSyd0w==">.pd-voucher-minimal{margin:10px 0;display:flex;flex-direction:column;gap:6px}.pdv-min-item{display:flex;align-items:center;gap:8px;padding:0;height:32px;transition:all .2s ease}.pdv-min-hidden{display:none}.pdv-min-disabled{opacity:.5}.pdv-badge-btn{display:inline-flex;align-items:center;gap:8px;background:linear-gradient(135deg,#667eea 0,#764ba2 100%);border:none;border-radius:8px;padding:3px;cursor:pointer;transition:all .2s ease;width:auto}.pdv-badge-btn:hover:not(:disabled){transform:translateY(-1px);box-shadow:0 4px 12px rgba(102,126,234,.3)}.pdv-badge-btn:disabled{opacity:.6;cursor:not-allowed}.pdv-badge-icon{color:#fff;flex-shrink:0}.pdv-badge-text{font-size:14px;font-weight:700;color:#fff;white-space:nowrap}.pdv-badge-code{font-family:'Courier New',monospace;font-size:13px;font-weight:700;color:#fff;background:rgba(255,255,255,.2);padding:4px 8px;border-radius:4px;border:none;white-space:nowrap}.pdv-min-copy,.pdv-min-more{padding:4px 12px;font-size:12px;font-weight:600;border-radius:5px;border:1px solid #e2e8f0;background:#fff;color:#667eea;cursor:pointer;transition:all .2s ease;white-space:nowrap}.pdv-min-copy:hover:not(:disabled),.pdv-min-more:hover{background:#667eea;color:#fff;border-color:#667eea}.pdv-min-copy:disabled{opacity:.4;cursor:not-allowed}.pdv-min-copy.copied{background:#22c55e;color:#fff;border-color:#22c55e}.pdv-min-more{margin-left:auto}.modal-close{position:absolute;top:20px;right:20px;background:none;border:none;cursor:pointer;color:#64748b;padding:4px;transition:color .2s ease}.modal-close:hover{color:#1e293b}.modal-body{margin-bottom:8px}.voucher-modal-content{text-align:center}.voucher-modal-badge{display:inline-flex;flex-direction:row;align-items:center;gap:6px;background:linear-gradient(135deg,#667eea 0,#764ba2 100%);border-radius:10px;padding:8px 16px;margin-bottom:12px}.vmb-value{font-size:18px;font-weight:700;color:#fff;line-height:1}.vmb-label{font-size:18px;font-weight:700;color:#fff;text-transform:uppercase;letter-spacing:.5px}.voucher-modal-code{font-family:'Courier New',monospace;font-size:14px;font-weight:700;color:#667eea;background:rgba(102,126,234,.1);padding:6px 12px;border-radius:6px;border:2px dashed rgba(102,126,234,.3);display:inline-block;margin-bottom:10px}.voucher-modal-name{font-size:14px;font-weight:600;color:#1e293b;margin-bottom:16px}.voucher-modal-details{text-align:left;background:#f8fafc;border-radius:8px;padding:12px;margin-bottom:16px}.vmd-item{display:flex;align-items:flex-start;gap:8px;padding:6px 0;font-size:13px;color:#64748b;border-bottom:1px solid #e2e8f0}.vmd-item:last-child{border-bottom:none}.vmd-item svg{color:#667eea;flex-shrink:0;margin-top:2px}.vmd-item strong{color:#1e293b}.modal-actions{padding:20px}.modal-btn-primary{background:linear-gradient(135deg,#667eea 0,#764ba2 100%);color:#fff}.modal-btn-primary:hover{opacity:.9;transform:translateY(-1px)}@media (max-width:640px){.pdv-min-item{gap:6px}.pdv-badge-btn{padding:3px;gap:6px}.pdv-badge-text{font-size:13px}.pdv-badge-code{font-size:12px;padding:3px 6px}.pdv-min-copy,.pdv-min-more{padding:3px 10px;font-size:11px}.modal-dialog{max-width:95%;margin:20px}.vmb-value{font-size:16px}.vmb-label{font-size:16px}.voucher-modal-code{font-size:13px;padding:5px 10px}}</style><style nonce="se3iyzEHMc9FQEB4wSyd0w==">.promo-endyear-mini-banner{display:flex;align-items:center;gap:12px;padding:12px 16px;background:rgba(255,255,255,.8);backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);border:2px solid rgba(245,202,86,.2);border-radius:12px;margin:16px 0;box-shadow:0 4px 16px rgba(0,0,0,.08);transition:all .3s ease}.promo-endyear-mini-banner:hover{transform:translateY(-2px);box-shadow:0 6px 20px rgba(0,0,0,.12);border-color:rgba(245,202,86,.4)}.pey-icon{font-size:32px;line-height:1;flex-shrink:0}.pey-content{flex:1;min-width:0}.pey-content strong{display:block;font-size:14px;font-weight:700;color:#C77DFF;margin-bottom:2px}
11290.pey-content span{display:block;font-size:13px;color:#64748b;line-height:1.4}.pey-link{flex-shrink:0;padding:8px 16px;background:linear-gradient(135deg,#C77DFF,#C77DFF);color:#fff;text-decoration:none;font-size:13px;font-weight:700;border-radius:8px;white-space:nowrap;transition:all .2s ease;box-shadow:0 2px 8px rgba(245,202,86,.25)}.pey-link:hover{transform:translateX(2px);box-shadow:0 4px 12px rgba(245,202,86,.35)}@media(max-width:640px){.promo-endyear-mini-banner{flex-wrap:wrap;gap:8px;padding:10px 12px}.pey-icon{font-size:28px;align-self:flex-start}.pey-content{flex:1;min-width:0}.pey-content strong{font-size:12px}.pey-content span{font-size:11px;line-height:1.3}.pey-link{width:100%;flex-basis:100%;font-size:11px;padding:6px 12px;text-align:center}}@media print{.promo-endyear-mini-banner{display:none!important}}</style>
11291<style nonce="se3iyzEHMc9FQEB4wSyd0w==">
11292.pd-title-row{position:relative;margin-bottom:12px;padding-right:52px}.pd-title{margin:0!important}.pd-share-btn{position:absolute;top:0;right:0;width:40px;height:40px;display:inline-flex;align-items:center;justify-content:center;border-radius:10px;border:1px solid #e2e8f0;background:#fff;color:#64748b;cursor:pointer;transition:all .2s ease;-webkit-tap-highlight-color:transparent}.pd-share-btn:hover{background:#f8fafc;border-color:#cbd5e1;color:#0f172a;transform:translateY(-1px)}.pd-share-btn:active{transform:translateY(0)}.pd-share-btn svg{display:block}
11293
11294.pd-share-modal-overlay{position:fixed;inset:0;background:rgba(15,23,42,.75);backdrop-filter:blur(4px);z-index:99999;display:none;align-items:center;justify-content:center;padding:0;animation:fadeIn .2s ease}.pd-share-modal-overlay.show{display:flex}.pd-share-modal{background:#fff;border-radius:20px;box-shadow:0 25px 50px -12px rgba(0,0,0,.25);max-width:480px;width:100%;max-height:90vh;overflow:hidden;display:flex;flex-direction:column;animation:slideUp .3s cubic-bezier(.16,1,.3,1)}@keyframes fadeIn{from{opacity:0}to{opacity:1}}@keyframes slideUp{from{opacity:0;transform:translateY(20px) scale(.95)}to{opacity:1;transform:translateY(0) scale(1)}}
11295
11296.pd-share-header{display:flex;align-items:center;justify-content:space-between;padding:20px 24px;border-bottom:1px solid #f1f5f9}.pd-share-title{font-size:18px;font-weight:700;color:#0f172a;margin:0}.pd-share-close{width:32px;height:32px;border-radius:8px;border:0;background:transparent;color:#64748b;display:inline-flex;align-items:center;justify-content:center;cursor:pointer;transition:all .15s ease}.pd-share-close:hover{background:#f1f5f9;color:#0f172a}.pd-share-body{padding:24px;overflow-y:auto}
11297
11298.pd-share-preview{display:flex;gap:12px;padding:16px;background:#f8fafc;border-radius:12px;margin-bottom:24px}.pd-share-preview-img{width:64px;height:64px;border-radius:8px;object-fit:cover;flex-shrink:0;border:1px solid #e2e8f0}.pd-share-preview-info{flex:1;min-width:0}.pd-share-preview-name{font-size:14px;font-weight:600;color:#0f172a;margin:0 0 4px 0;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.pd-share-preview-price{font-size:16px;font-weight:700;color:#0ea5e9;margin:0}
11299
11300.pd-share-label{font-size:13px;font-weight:600;color:#475569;margin:0 0 12px 0;text-transform:uppercase;letter-spacing:.5px}.pd-share-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:12px;margin-bottom:24px}.pd-share-option{display:flex;flex-direction:column;align-items:center;gap:8px;padding:16px 8px;border:1.5px solid #e2e8f0;border-radius:12px;background:#fff;cursor:pointer;transition:all .2s ease;text-decoration:none;color:inherit}.pd-share-option:hover{border-color:#94a3b8;background:#f8fafc;transform:translateY(-2px)}.pd-share-option:active{transform:translateY(0)}
11301
11302.pd-share-icon{width:40px;height:40px;border-radius:10px;display:inline-flex;align-items:center;justify-content:center;position:relative}.pd-share-icon svg{width:24px;height:24px;display:block}.pd-share-icon-whatsapp{background:linear-gradient(135deg,#25D366 0%,#128C7E 100%);color:#fff}.pd-share-icon-facebook{background:linear-gradient(135deg,#1877F2 0%,#0c63d4 100%);color:#fff}.pd-share-icon-twitter{background:linear-gradient(135deg,#1DA1F2 0%,#0d8bd9 100%);color:#fff}.pd-share-icon-telegram{background:linear-gradient(135deg,#0088cc 0%,#0077b3 100%);color:#fff}.pd-share-icon-email{background:linear-gradient(135deg,#C77DFF 0%,#E3D05A 100%);color:#fff}.pd-share-icon-copy{background:linear-gradient(135deg,#C77DFF 0%,#C77DFF 100%);color:#fff}.pd-share-icon-pdf{background:linear-gradient(135deg,#C77DFF 0%,#C77DFF 100%);color:#fff}.pd-share-name{font-size:12px;font-weight:600;color:#475569;text-align:center}
11303
11304.pd-share-copy-section{background:#f8fafc;padding:16px;border-radius:12px}.pd-share-copy-input-wrap{display:flex;gap:8px}.pd-share-copy-input{flex:1;padding:12px 14px;border:1px solid #e2e8f0;border-radius:10px;font-size:14px;color:#0f172a;background:#fff;font-family:'Segoe UI',system-ui,sans-serif}.pd-share-copy-input:focus{outline:0;border-color:#0ea5e9;box-shadow:0 0 0 3px rgba(14,165,233,.1)}.pd-share-copy-btn{padding:12px 20px;border:0;border-radius:10px;background:linear-gradient(135deg,#0ea5e9 0%,#0284c7 100%);color:#fff;font-size:14px;font-weight:600;cursor:pointer;transition:all .2s ease;white-space:nowrap;display:inline-flex;align-items:center;gap:6px}.pd-share-copy-btn:hover{background:linear-gradient(135deg,#0284c7 0%,#0369a1 100%);transform:translateY(-1px);box-shadow:0 4px 12px rgba(14,165,233,.3)}
11304.pd-share-copy-btn:active{transform:translateY(0)}.pd-share-copy-btn svg{width:16px;height:16px}.pd-share-copy-btn.copied{background:linear-gradient(135deg,#22c55e 0%,#16a34a 100%);pointer-events:none}
11305
11306@media(max-width:640px){.pd-share-modal{border-radius:20px 20px 0 0;margin-top:auto;max-height:85vh}.pd-share-grid{grid-template-columns:repeat(3,1fr)}.pd-share-header{padding:16px 20px}.pd-share-body{padding:20px}.pd-share-btn{width:36px;height:36px}.pd-share-btn svg{width:18px;height:18px}}@media(max-width:480px){.pd-share-grid{grid-template-columns:repeat(3,1fr);gap:10px}.pd-share-option{padding:12px 6px}.pd-share-icon{width:36px;height:36px}.pd-share-icon svg{width:20px;height:20px}.pd-share-name{font-size:11px}}
11307
11308.mf-share{background:#fff;color:#C77DFF;border:2px solid #C77DFF;display:inline-flex;align-items:center;justify-content:center}.mf-share:active{transform:scale(.95)}.mf-share svg{display:block}
11309
11310@media(max-width:640px){.pd-share-btn{display:none!important}}
11311
11312.stock-badge.in{background:#e6f9ec;color:#15803d;border-radius:999px;padding:4px 10px;font-weight:700}.stock-badge.out{background:#C77DFF;color:#14b1d7;border-radius:999px;padding:4px 10px;font-weight:700}
11313
11314.stock-info-btn{--c:#0ea5e9;--b:#bae6fd;--bg:#f0f9ff;--bg-h:#e0f2fe;--b-h:#0ea5e9;margin-left:0;display:inline-flex;align-items:center;justify-content:center;gap:0.5rem;padding:4px 10px;border-radius:999px;border:1.5px solid var(--b);background:var(--bg);color:var(--c);cursor:pointer;font-size:12px;font-weight:600;transition:all .2s ease;-webkit-tap-highlight-color:transparent}.stock-info-btn:hover{background:var(--bg-h);border-color:var(--b-h);color:#0284c7;transform:translateY(-1px);box-shadow:0 2px 8px rgba(14,165,233,.15)}.stock-info-btn:active{transform:translateY(0)}.stock-info-btn:focus-visible{outline:0;box-shadow:0 0 0 3px rgba(14,165,233,.2)}.stock-info-btn svg{width:14px;height:14px;flex-shrink:0}.stock-info-btn .btn-text{white-space:nowrap}
11315
11316.stock-popover{position:absolute;z-index:9999;min-width:280px;max-width:92vw;background:#0b1220;color:#eef3ff;border:1px solid rgba(255,255,255,.08);border-radius:14px;box-shadow:0 20px 40px rgba(12,12,20,.45);padding:12px 12px 8px;display:none}.stock-popover.show{display:block}.stock-popover::before{content:"";position:absolute;top:-8px;left:24px;width:14px;height:14px;background:#0b1220;border-left:1px solid rgba(255,255,255,.08);border-top:1px solid rgba(255,255,255,.08);transform:rotate(45deg)}.sp-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:8px}.sp-title{font-weight:800;font-size:14px}.sp-close{background:transparent;border:0;color:#98a2b3;cursor:pointer}
11317
11318.sp-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:8px}.sp-item{display:grid;grid-template-columns:1fr auto 32px;column-gap:12px;align-items:center;padding:10px 10px;min-height:44px;border-radius:10px;background:rgba(255,255,255,.03)}.sp-left{display:flex;align-items:center;gap:10px}.sp-dot{width:10px;height:10px;border-radius:999px;background:var(--dot,#60a5fa);display:inline-block}.sp-label{font-weight:600;font-size:13px}
11319
11320
11321.sp-qty{grid-column:2;justify-self:end;min-width:40px;text-align:right;font-weight:800;font-size:13px;color:#cfe4ff;font-variant-numeric:tabular-nums}
11322
11323.sp-wa{
11324  grid-column:3; justify-self:end;
11325  width:32px; height:32px; min-width:32px; min-height:32px;
11326  box-sizing:border-box;
11327  padding:0; line-height:0; text-decoration:none; outline:0;
11328  display:inline-flex; align-items:center; justify-content:center;
11329  border-radius:999px; border:1px solid rgba(37,211,102,.60);  /* 1px untuk hasil “crisp” */
11330  background:rgba(37,211,102,.08); color:#25D366;
11331  transition:background-color .15s ease, border-color .15s ease, transform .05s ease;
11332  -webkit-tap-highlight-color:transparent;
11333}
11334.sp-wa:hover{background:rgba(37,211,102,.16);border-color:rgba(37,211,102,.75)}
11335.sp-wa:active{transform:translateY(.5px) scale(.98)}
11336
11337.sp-wa svg{width:18px;height:18px;display:block;vertical-align:middle}
11338.stock-popover a{text-decoration:none}
11339
11340#deskripsi img{max-width:450px!important;height:unset!important}@media(max-width:640px){.stock-popover{position:fixed;left:0;right:0;bottom:max(12px,env(safe-area-inset-bottom,12px));margin:0 10px;padding:14px 12px 10px;border-radius:16px}.stock-popover::before{display:none}.stock-info-btn{padding:4px 8px;gap:4px;border:0;background:transparent}.stock-info-btn:hover{background:transparent;box-shadow:none;transform:none}.stock-info-btn .btn-text{display:none}.stock-info-btn svg{width:16px;height:16px}.sp-item{grid-template-columns:1fr auto 36px}.sp-wa{width:36px;height:36px;min-width:36px;min-height:36px}.sp-wa svg{width:19px;height:19px}}
11341
11342.stock-dot{position:absolute;bottom:8px;right:8px;width:8px;height:8px;border-radius:50%;box-shadow:0 1px 3px rgba(0,0,0,0.4);z-index:2;cursor:help}.stock-dot.ready{background:#10b981}.stock-dot.low{background:#C77DFF}.stock-dot.out{background:#C77DFF}.stock-dot:hover{transform:scale(1.2);transition:transform 0.2s ease}@media(max-width:640px){.stock-dot{width:7px;height:7px;bottom:6px;right:6px}}
11343
11344.pd-related-card .spec-chips{font-size:11px;color:#64748b;margin:4px 0 6px 0;line-height:1.3;font-weight:500}.pd-related-card .spec-chips .spec-divider{margin:0 4px;opacity:0.6}@media(max-width:640px){.pd-related-card .spec-chips{font-size:10px;margin:3px 0 5px 0}#deskripsi img{max-width:300px!important;height:unset!important;justify-self:center!important}}
11345
11346.pwp-trigger-badge{display:inline-flex;align-items:center;gap:4px;padding:3px 8px 4px;background:linear-gradient(135deg,#C77DFF 0%,#C77DFF 100%);color:#765212;border-radius:6px;font-size:.65rem;font-weight:600;border:0}.pwp-trigger-badge svg{flex-shrink:0;width:12px;height:12px}
11347.pwp-deals-section{margin:0;padding:12px;background:linear-gradient(135deg,#fef3c7 0%,#C77DFF 100%);border-radius:12px;border:2px solid #C77DFF}.pwp-deals-header{display:flex;gap:10px;margin-bottom:10px}.pwp-icon{flex-shrink:0;color:#C77DFF;width:18px;height:18px}.pwp-text .pwp-title{margin:0 0 2px 0;font-size:14px;font-weight:700;color:#765212}
11347.pwp-text .pwp-subtitle{margin:0;font-size:11px;color:#ae7e21;opacity:0.9}.pwp-deals-loading{text-align:center;padding:40px 0;color:#ae7e21}.pwp-spinner{width:40px;height:40px;border:3px solid #C77DFF;border-top-color:#C77DFF;border-radius:50%;animation:spin 0.8s linear infinite;margin:0 auto 12px}@keyframes spin{to{transform:rotate(360deg)}}
11348.pwp-deals-grid{display:flex;flex-direction:column;gap:6px}.pwp-deal-card{background:#fff;border-radius:6px;overflow:hidden;border:1px solid #C77DFF;display:flex;align-items:center;padding:8px;gap:10px}.pwp-deal-card:hover{background:#fef3c7}.pwp-deal-thumb{flex-shrink:0;width:50px;height:50px;background:#f8fafc;overflow:hidden;border-radius:4px}.pwp-deal-thumb img{width:100%;height:100%;object-fit:cover}.pwp-deal-badge{background:#C77DFF;color:#fff;padding:2px 5px;border-radius:3px;font-size:9px;font-weight:700;margin-left:auto}.pwp-deal-info{flex:1;display:flex;flex-direction:column;gap:4px}.pwp-deal-name{font-size:12px;font-weight:600;color:#0f172a;margin:0;line-height:1.2}.pwp-deal-prices{display:flex;align-items:center;gap:6px;flex-wrap:wrap}.pwp-deal-price{font-size:14px;font-weight:800;color:#C77DFF;white-space:nowrap}.pwp-deal-original{font-size:11px;color:#64748b;text-decoration:line-through;white-space:nowrap}.pwp-cart-note{margin-top:8px;padding:6px 10px;background:#e0f2fe;border-left:2px solid#0ea5e9;font-size:11px;color:#0c4a6e;border-radius:4px}
11349@media(max-width:640px){.pwp-deals-section{margin:12px 0;padding:10px;border-radius:10px}.pwp-deals-header{gap:8px}.pwp-text .pwp-title{font-size:13px}.pwp-text .pwp-subtitle{font-size:10px}.pwp-deal-card{padding:6px;gap:8px}.pwp-deal-thumb{width:45px;height:45px}.pwp-deal-name{font-size:11px}.pwp-deal-price{font-size:13px}.pwp-deal-original{font-size:10px}}
11350
11351.preorder-badge{display:inline-flex;align-items:center;gap:5px;padding:6px 12px;background:linear-gradient(135deg,#8b5cf6 0%,#7c3aed 100%);color:#fff;border-radius:8px;font-size:13px;font-weight:700;border:0;box-shadow:0 2px 8px rgba(139,92,246,.25)}.preorder-badge svg{width:16px;height:16px;flex-shrink:0}.preorder-info{margin:12px 0;padding:14px;background:linear-gradient(135deg,#f5f3ff 0%,#ede9fe 100%);border:1.5px solid #c4b5fd;border-radius:12px}.preorder-info-header{display:flex;align-items:center;gap:8px;margin-bottom:10px}.preorder-info-icon{width:20px;height:20px;color:#7c3aed;flex-shrink:0}.preorder-info-title{font-size:14px;font-weight:700;color:#5b21b6;margin:0}.preorder-info-items{display:flex;flex-direction:column;gap:8px}.preorder-info-row{display:flex;align-items:center;justify-content:space-between;font-size:13px}.preorder-info-label{color:#6b21a8;font-weight:600}.preorder-info-value{color:#5b21b6;font-weight:700}.preorder-info-value.highlight{color:#C77DFF;font-size:14px}.preorder-info-note{margin-top:10px;padding:8px 10px;background:#fef3c7;border-left:2px solid #C77DFF;font-size:12px;color:#765212;border-radius:6px;line-height:1.4}@media(max-width:640px){.preorder-badge{font-size:12px;padding:5px 10px}.preorder-info{margin:10px 0;padding:12px}.preorder-info-title{font-size:13px}.preorder-info-row{font-size:12px}.preorder-info-note{font-size:11px;padding:6px 8px}}
11352</style>
11353
11354<div class="pd-sticky-header" id="pd-sticky-header"><div class="pd-sticky-header-container"><div class="pd-sticky-thumb"><img src="https://img.tongat.cc/uploads/pasti-jaackpot-judimpo.jpg" alt="GAME MPO" id="pd-sticky-thumb-img"></div><div class="pd-sticky-info"><h2 class="pd-sticky-title" id="pd-sticky-title">JUDIMPO Situs Judi Mpo Slot 10k dengan Peluang Maxwin Terbaik</h2><div class="pd-sticky-price-row"><span class="pd-sticky-price" id="pd-sticky-price">Rp 20.000,-</span><span class="pd-sticky-price-original" id="pd-sticky-price-original">Rp 1.000.000</span><span class="pd-sticky-discount" id="pd-sticky-discount">-99.5%</span></div></div><div class="pd-sticky-actions"><button type="button" class="pd-sticky-share-btn" id="pd-sticky-share-btn" aria-label="Bagikan produk" title="Bagikan"><svg viewBox="0 0 24 24" width="16" height="16" aria-hidden="true"><path fill="currentColor" d="M18 16.08c-.76 0-1.44.3-1.96.77L8.91 12.7c.05-.23.09-.46.09-.7s-.04-.47-.09-.7l7.05-4.11c.54.5 1.25.81 2.04.81 1.66 0 3-1.34 3-3s-1.34-3
11354-3-3-3 1.34-3 3c0 .24.04.47.09.7L8.04 9.81C7.5 9.31 6.79 9 6 9c-1.66 0-3 1.34-3 3s1.34 3 3 3c.79 0 1.5-.31 2.04-.81l7.12 4.16c-.05.21-.08.43-.08.65 0 1.61 1.31 2.92 2.92 2.92s2.92-1.31 2.92-2.92-1.31-2.92-2.92-2.92z"/></svg></button><button type="button" class="pd-sticky-btn pd-sticky-btn-chat" id="pd-sticky-chat"><svg viewBox="0 0 640 640" fill="currentColor" aria-hidden="true"><path d="M320 128C241 128 175.3 185.3 162.3 260.7C171.6 257.7 181.6 256 192 256L208 256C234.5 256 256 277.5 256 304L256 400C256 426.5 234.5 448 208 448L192 448C139 448 96 405 96 352L96 288C96 164.3 196.3 64 320 64C443.7 64 544 164.3 544 288L544 456.1C544 522.4 490.2 576.1 423.9 576.1L336 576L304 576C277.5 576 256 554.5 256 528C256 501.5 277.5 480 304 480L336 480C362.5 480 384 501.5 384 528L384 528L424 528C463.8 528 496 495.8 496 456L496 435.1C481.9 443.3 465.5 447.9 448 447.9L432 447.9C405.5 447.9 384 426.4 384 399.9L384 303.9C384 277.4 405.5 255.9 432 255.9L448 255.9C458.4 255.9 468.3 257.5 477.7 260.6C464.7 185.3 399.1 127.9 320 127.9z"/></svg>Tanya</button><button type="button" class="pd-sticky-btn pd-sticky-btn-cart" id="pd-sticky-add-cart" disabled>+ Keranjang</button><button type="button" class="pd-sticky-btn pd-sticky-btn-buy" id="pd-sticky-buy" disabled>Beli Sekarang</button></div></div></div>
11355
11356<main class="product-single product-single--v3"><nav class="pd-breadcrumb" aria-label="breadcrumb"><a href="https://hop.exchange/">MPO5000</a><span>-</span><a href="https://hop.exchange/">LOGIN GAME MPO</a><span>-</span><a href="https://hop.exchange/">APK JUDIMPO</a><span>-</span><a href="https://hop.exchange/">SLOT BCA 5000</a><span>-</span><a href="https://hop.exchange/">LOGIN MPO SLOT</a><span>-</span><span class="current">JUDIMPO Situs Judi Mpo Slot 10k dengan Peluang Maxwin Terbaik
11357
11358</span></nav>
11359
11360<div class="pd-top-layout"><section class="pd-media-card"><figure class="pd-main-image" id="pd-main-figure"><img id="pd-main-img" src="https://img.tongat.cc/uploads/pasti-jaackpot-judimpo.jpg" alt="di-custom total GAME MPO" data-slug="" loading="eager">
11361</figure>
11362
11363<div class="pd-mobile-slider-wrapper">
11364<div class="pd-mobile-slider" id="pd-mobile-slider" aria-label="Galeri gambar (geser)"><div class="pd-mslide"><img src="https://img.tongat.cc/uploads/pasti-jaackpot-judimpo.jpg" alt="GAME MPO ONLINE" loading="eager"></div><div class="pd-mslide"><img src="https://img.tongat.cc/uploads/pasti-jaackpot-judimpo.jpg" alt="GAME MPO ONLINE" loading="lazy"></div><div class="pd-mslide"><img src="https://img.tongat.cc/uploads/pasti-jaackpot-judimpo.jpg" alt="GAME MPO ONLINE" loading="lazy"></div><div class="pd-mslide"><img src="https://img.tongat.cc/uploads/pasti-jaackpot-judimpo.jpg" alt="GAME MPO ONLINE" loading="lazy"></div><div class="pd-mslide"><img src="https://img.tongat.cc/uploads/pasti-jaackpot-judimpo.jpg" alt="GAME MPO ONLINE" loading="lazy"></div><div class="pd-mslide"><img src="https://img.tongat.cc/uploads/pasti-jaackpot-judimpo.jpg" alt="GAME MPO ONLINE" loading="lazy"></div></div><div class="pd-gallery-counter" id="pd-gallery-counter">1/6</div></div>
11365<div class="pd-thumb-gallery" id="pd-thumb-gallery" aria-label="Galeri gambar produk"><button type="button" class="pd-thumb-btn active" data-full="https://img.tongat.cc/uploads/pasti-jaackpot-judimpo.jpg" data-alt="GAME MPO ONLINE" data-slug="" aria-label="Gambar 1"><img src="https://img.tongat.cc/uploads/pasti-jaackpot-judimpo.jpg" alt="GAME MPO ONLINE" loading="lazy"></button><button type="button" class="pd-thumb-btn " data-full="https://img.tongat.cc/uploads/pasti-jaackpot-judimpo.jpg" data-alt="GAME MPO ONLINE" data-slug="https://img.tongat.cc/uploads/pasti-jaackpot-judimpo.jpg" aria-label="Gambar 2"><img src="https://img.tongat.cc/uploads/pasti-jaackpot-judimpo.jpg" alt="GAME MPO ONLINE" loading="lazy"></button><button type="button" class="pd-thumb-btn " data-full="https://img.tongat.cc/uploads/pasti-jaackpot-judimpo.jpg" data-alt="GAME MPO ONLINE" data-slug="lenovo-legion-go-8asp2-83n0000rid-ryzen-z2-extreme-amd-radeon-graphics-eclipse-b-1761796941-223.webp" aria-label="Gambar 3"><img src="https://img.tongat.cc/uploads/pasti-jaackpot-judimpo.jpg" alt="GAME MPO ONLINE" loading="lazy"></button><button type="button" class="pd-thumb-btn " data-full="https://img.tongat.cc/uploads/pasti-jaackpot-judimpo.jpg" data-alt
11365="GAME MPO ONLINE" data-slug="lenovo-legion-go-8asp2-83n0000rid-ryzen-z2-extreme-amd-radeon-graphics-eclipse-b-1761796941-776.webp" aria-label="Gambar 4"><img src="https://img.tongat.cc/uploads/pasti-jaackpot-judimpo.jpg" alt="GAME MPO ONLINE" loading="lazy"></button><button type="button" class="pd-thumb-btn " data-full="https://img.tongat.cc/uploads/pasti-jaackpot-judimpo.jpg" data-alt="GAME MPO ONLINE" data-slug="lenovo-legion-go-8asp2-83n0000rid-ryzen-z2-extreme-amd-radeon-graphics-eclipse-b-1761796941-634.webp" aria-label="Gambar 5"><img src="https://img.tongat.cc/uploads/pasti-jaackpot-judimpo.jpg" alt="GAME MPO ONLINE" loading="lazy"></button><button type="button" class="pd-thumb-btn " data-full="https://img.tongat.cc/uploads/pasti-jaackpot-judimpo.jpg" data-alt="GAME MPO ONLINE" data-slug="lenovo-legion-go-8asp2-83n0000rid-ryzen-z2-extreme-amd-radeon-graphics-eclipse-b-1761796941-892.webp" aria-label="Gambar 6"><img src="https://img.tongat.cc/uploads/pasti-jaackpot-judimpo.jpg" alt="GAME MPO ONLINE" loading="lazy"></button></div></section><section class="pd-info-card"><div id="pd-variant-combined" class="pd-variant-combined" hidden></div><div class="pd-title-row">
11366        <h1 class="pd-title" id="pd-title">JUDIMPO Situs Judi Mpo Slot 10k dengan Peluang Maxwin Terbaik</h1><button type="button" class="pd-share-btn" id="pd-share-btn" aria-label="Bagikan produk" title="Bagikan"><svg viewBox="0 0 24 24" width="20" height="20" aria-hidden="true"><path fill="currentColor" d="M18 16.08c-.76 0-1.44.3-1.96.77L8.91 12.7c.05-.23.09-.46.09-.7s-.04-.47-.09-.7l7.05-4.11c.54.5 1.25.81 2.04.81 1.66 0 3-1.34 3-3s-1.34-3-3-3-3 1.34-3 3c0 .24.04.47.09.7L8.04 9.81C7.5 9.31 6.79 9 6 9c-1.66 0-3 1.34-3 3s1.34 3 3 3c.79 0 1.5-.31 2.04-.81l7.12 4.16c-.05.21-.08.43-.08.65 0 1.61 1.31 2.92 2.92 2.92s2.92-1.31 2.92-2.92-1.31-2.92-2.92-2.92z"/></svg></button></div>
11367<div id="pd-price-anchor">
11368</div>
11369<div class="pd-price-qr-container">
11370        <div class="pd-price-block" id="pd-price-block">
11371                <div class="pd-price-row">
11372                        <span class="pd-price-current" id="pd-price-current" >Rp 5.000</span>
11373                        <span class="pd-price-original" id="pd-price-original">Rp 50.000</span>
11374                        <span class="pd-discount-badge" id="pd-discount-badge">-90%</span></div>
11375                        <div class="pd-meta-row">
11376                                <span class="sold-inline" id="pd-sold-inline" data-role="sold-chip">Terjual Terjual 5</span>
11377                                <span class="pwp-trigger-badge" id="pwp-trigger-badge" hidden>
11378                                        <svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor">
11379                                                <path d="M21.41 11.58l-9-9C12.05 2.22 11.55 2 11 2H4c-1.1 0-2 .9-2 2v7c0 .55.22 1.05.59 1.42l9 9c.36.36.86.58 1.41.58.55 0 1.05-.22 1.41-.59l7-7c.37-.36.59-.86.59-1.41 0-.55-.23-1.06-.59-1.42zM5.5 7C4.67 7 4 6.33 4 5.5S4.67 4 5.5 4 7 4.67 7 5.5 6.33 7 5.5 7z"/></svg>Bisa PWP</span></div>
11380                                                <div class="pd-meta-inline"><span class="stock-badge out" id="pd-stock-badge">GAME MPO</span>
11381                                                        <span class="sku">SKU: <span id="pd-sku">GAME MPO SITUS</span></span></div>
11382<div class="paylater-promo paylater-promo-sm paylater-mobile-only">
11383    <span class="paylater-icon">💳</span>
11384    <span class="paylater-text">
11385        <strong>GAME MPO</strong>
11386        <small>ONLINE</small>
11387    </span>
11388</div>
11389
11390<div class="stock-popover" id="pd-stock-popover" role="dialog" aria-hidden="true" aria-label="Informasi stok cabang"><div class="sp-head"><div class="sp-title">Stok Cabang</div><button type="button" class="sp-close" id="pd-stock-popover-close" aria-label="Tutup"><svg width="18" height="18" viewBox="0 0 24 24"><path fill="currentColor" d="M18.3 5.71L12 12.01l-6.3-6.3-1.4 1.41 6.3 6.3-6.3 6.3 1.4 1.41 6.3-6.3 6.3 6.3 1.41-1.41-6.3-6.3 6.3-6.3z"/></svg></button></div><ul class="sp-list">
11391<li class="sp-item"><div class="sp-left"><span class="sp-dot" style="--dot:#60a5fa;"></span><span class="sp-label">Asia Mega Mas</span></div><span class="sp-qty" id="sp-qty-meg">0</span><a class="sp-wa" href="https://wa.me/6281380009898?text=Halo%2C%20saya%20ingin%20tanya%20stok%20di%20Asia%20Mega%20Mas%20untuk%20produk%20https%3A%2F%2Fplazait.co.id%2Fproduct%2Flenovo-legion-go-8as
11391p2-83n0000rid-ryzen-z2-extreme-amd-radeon-graphics-eclipse-black" target="_blank" rel="noopener" aria-label="WhatsApp Asia Mega Mas"><svg class="ico-wa" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path fill="currentColor" d="M17.472 14.382c-.297-.149-1.758-.867-2.029-.967-.273-.099-.471-.148-.669.149-.198.297-.767.966-.94 1.164-.173.198-.347.223-.644.074-.297-.149-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.297-.347.446-.52.149-.173.198-.297.298-.495.099-.198.05-.372-.025-.521-.075-.149-.669-1.612-.916-2.206-.242-.579-.487-.5-.669-.51l-.57-.01c-.198 0-.52.074-.792.372s-1.04 1.016-1.04 2.479 1.065 2.876 1.213 3.074c.149.198 2.095 3.2 5.076 4.487.709.306 1.262.489 1.694.626.712.226 1.36.194 1.872.118.571-.085 1.758-.718 2.006-1.411.248-.694.248-1.29.173-1.411-.074-.123-.272-.198-.57-.347m-5.421 7.403h-.002a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.263c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.884-9.887 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.158 11.892c0 2.096.547 4.142 1.588 5.945L0 24l6.305-1.654a11.86 11.86 0 005.67 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 00-3.485-8.413"/></svg></a></li>
11392                
11393                    <li class="sp-item">
11394                      <div class="sp-left">
11395                        <span class="sp-dot" style="--dot:#34d399;"></span>
11396                        <span class="sp-label">Medan Fair</span>
11397                      </div>
11398                      <span class="sp-qty" id="sp-qty-mdf">0</span>
11399                      <a class="sp-wa"
11400                         href="https://wa.me/6285388992009?text=Halo%2C%20saya%20ingin%20tanya%20stok%20di%20Medan%20Fair%20untuk%20produk%20https%3A%2F%2Fplazait.co.id%2Fproduct%2Flenovo-legion-go-8asp2-83n0000rid-ryzen-z2-extreme-amd-radeon-graphics-eclipse-black"
11401                         target="_blank" rel="noopener" aria-label="WhatsApp Medan Fair">
11402                        <svg class="ico-wa" viewBox="0 0 24 24" aria-hidden="true" focusable="false">
11403                            <path fill="currentColor" d="M17.472 14.382c-.297-.149-1.758-.867-2.029-.967-.273-.099-.471-.148-.669.149-.198.297-.767.966-.94 1.164-.173.198-.347.223-.644.074-.297-.149-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.297-.347.446-.52.149-.173.198-.297.298-.495.099-.198.05-.372-.025-.521-.075-.149-.669-1.612-.916-2.206-.242-.579-.487-.5-.669-.51l-.57-.01c-.198 0-.52.074-.792.372s-1.04 1.016-1.04 2.479 1.065 2.876 1.213 3.074c.149.198 2.095 3.2 5.076 4.487.709.306 1.262.489 1.694.626.712.226 1.36.194 1.872.118.571-.085 1.758-.718 2.006-1.411.248-.694.248-1.29.173-1.411-.074-.123-.272-.198-.57-.347m-5.421 7.403h-.002a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.263c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.884-9.887 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.158 11.892c0 2.096.547 4.142 1.588 5.945L0 24l6.305-1.654a11.86 11.86 0 005.67 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 00-3.485-8.413"/>
11404                          </svg>
11405                      </a>
11406                    </li>
11407                
11408                    <li class="sp-item">
11409                      <div class="sp-left">
11410                        <span class="sp-dot" style="--dot:#C77DFF;"></span>
11411                        <span class="sp-label">Banda Aceh</span>
11412                      </div>
11413                      <span class="sp-qty" id="sp-qty-bda">0</span>
11414                      <a class="sp-wa"
11415                         href="https://wa.me/628116833411?text=Halo%2C%20saya%20ingin%20tanya%20stok%20di%20Banda%20Aceh%20untuk%20produk%20https%3A%2F%2Fplazait.co.id%2Fproduct%2Flenovo-legion-go-8asp2-83n0000rid-ryzen-z2-extreme-amd-radeon-graphics-eclipse-black"
11416                         target="_blank" rel="noopener" aria-label="WhatsApp Banda Aceh">
11417                        <svg class="ico-wa" viewBox="0 0 24 24" aria-hidden="true" focusable="false">
11418                            <path fill="currentColor" d="M17.472 14.382c-.297-.149-1.758-.867-2.029-.967-.273-.099-.471-.148-.669.149-.198.297-.767.966-.94 1.164-.173.198-.347.223-.644.074-.297-.149-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.297-.347.446-.52.149-.173.198-.297.298-.495.099-.198.05-.372-.025-.521-.075-.149-.669-1.612-.916-2.206-.242-.579-.487-.5-.669-.51l-.57-.01c-.198 0-.52.074-.792.372s-1.04 1.016-1.04 2.479 1.065 2.876 1.213 3.074c.149.198 2.095 3.2 5.076 4.487.709.306 1.262.489 1.694.626.712.226 1.36.194 1.872.118.571-.085 1.758-.718 2.006-1.411.248-.694.248-1.29.173-1.411-.074-.123-.272-.198-.57-.347m-5.421 7.403h-.002a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.263c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.884-9.887 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.158 11.892c0 2.096.547 4.142 1.588 5.945L0 24l6.305-1.654a11.86 11.86 0 005.67 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 00-3.485-8.413"/>
11419                          </svg>
11420                      </a>
11421                    </li>
11422                  </ul>
11423                </div>
11424
11425                            </div>
11426            <div class="pd-qr-print" style="display:none;"><div class="pd-qr-label">Scan untuk lihat produk:</div><img src="https://api.qrserver.com/v1/create-qr-code/?size=120x120&data=https%3A%2F%2Fplazait.co.id%2Fproduct%2Flenovo-legion-go-8asp2-83n0000rid-ryzen-z2-extreme-amd-radeon-graphics-eclipse-black" alt="QR Code" class="pd-qr-image"></div>
11427            </div>
11428                                    <div id="pd-variants-anchor"></div>
11429
11430                        
11431
11432            <div class="pd-compare-section">
11433                <button type="button" class="pd-compare-btn" id="pd-compare-btn" data-product-id="325">
11434                    <svg class="compare-icon" width="18" height="18" viewBox="0 0 24 24" fill="currentColor">
11435                        <path d="M21,9L17,5V8H10V10H17V13M7,11L3,15L7,19V16H14V14H7V11Z"/>
11436                    </svg>
11437                    <span class="compare-text">Bandingkan Produk</span>
11438                    <span class="compare-remove" hidden>
11439                        <svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor">
11440                            <path d="M19,6.41L17.59,5L12,10.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L12,13.41L17.59,19L19,17.59L13.41,12L19,6.41Z"/>
11441                        </svg>
11442                        Hapus dari Perbandingan
11443                    </span>
11444                </button>
11445                <div class="pd-compare-info">
11446                    <small class="compare-note" id="compare-note">Bandingkan hingga 5 produk dengan bantuan AI</small>
11447                </div>
11448            </div>
11449            
11450            <div class="pd-short-desc"><p><strong>INFORMASI GAME MPO 5000:</strong></p><ul><li>Minimal Deposit: Rp.5.000,-</li><li>Jenis Permainan: Mpo Slot Bca</li><li>Metode Pembayaran: Bank, QRIS, E-Wallet</li><li>Mata Uang: IDR (Indonesian Rupiah)</li><li>Jam Operasional: 24 Jam Nonstop</li><li>Total Rating: 399.999.999</li><li>Rating: ⭐⭐⭐⭐⭐</li><li>Daftar Buruan: <a href="https://mpo5000xjudimpo.blackhostapp.com/">Klik Disini</a></li></ul></div><div class="capzrao-v1 mini">
11451<div class="capzrao">
11452
11453  <!-- HEADER -->
11454<div class="capzrao-v3 mini">
11455                    <div class="Masa-Kini-yang-Selalu-v3">
11456                        <h2 class="capzrao-title-v3">🎯 PREDIKSI MPO SLOT 1000 RESMI (SIMULASI) 🎯</h2>
11457
11458                        <div class="capzrao-controls-v3">
11459                            <label>
11460                                PASARAN
11461                                <select id="marketFilter">
11462                                    <option value="ALL">ALL PASARAN</option>
11463                                </select>
11464                            </label>
11465
11466                            <label>
11467                                TIPE
11468                                <select id="typeFilter">
11469                                    <option value="4D">4D</option>
11470                                    <option value="3D">3D</option>
11471                                    <option value="2D">2D</option>
11472                                </select>
11473                            </label>
11474
11475                            <label>
11476                                MIN CONF
11477                                <input id="minConf" type="number" min="50" max="99" step="1" value="70">
11478                            </label>
11479
11480                            <button id="btncapzraoRandom" type="button">
11481                                <span class="icon">🎲</span> GENERATE
11482                            </button>
11483                        </div>
11484
11485                        <div class="capzrao-main-result-v3" id="capzraoResult">
11486                            <div class="capzrao-status-v3" id="capzraoStatus">— READY —</div>
11487
11488                            <div class="capzrao-highlight-box">
11489                                <div class="capzrao-col-left">
11490                                    <div class="k">Pasaran Rekomendasi</div>
11491                                    <div class="v-game" id="rMarket">-</div>
11492
11493                                    <div class="provider-info">
11494                                        <span class="k-small">Tipe:</span>
11495                                        <span class="v-small" id="rType">-</span>
11496                                        <span class="k-small" style="margin-left:10px;">Conf:</span>
11497                                        <span class="v-small" id="rConf">-</span>
11498                                    </div>
11499                                </div>
11500
11501                                <div class="capzrao-col-right">
11502                                    <div class="k-rtp">Angka Utama</div>
11503                                    <div class="v-rtp-huge" id="rAngka">-</div>
11504                                </div>
11505                            </div>
11506
11507                            <div class="capzrao-details-v3">
11508                                <div class="capzrao-detail-item">
11509                                    <div class="k-detail">BBFS</div>
11510                                    <div class="v-detail" id="rBBFS">-</div>
11511                                </div>
11512                                <div class="capzrao-detail-item">
11513                                    <div class="k-detail">Angka Ikut</div>
11514                                    <div class="v-detail" id="rIkut">-</div>
11515                                </div>
11516                                <div class="capzrao-detail-item">
11517                                    <div class="k-detail">Shio</div>
11518                                    <div class="v-detail" id="rShio">-</div>
11519                                </div>
11520                            </div>
11521
11522                            <div class="capzrao-tip-v3" id="rTip">
11523                                Tips: Ini simulasi hiburan. Tetap bijak & disiplin.
11524                            </div>
11525                        </div>
11526
11527                        <div class="capzrao-alts-v3">
11528                            <div class="capzrao-alts-title-v3">3 Alternatif Angka</div>
11529                            <div class="capzrao-alt-list-v3" id="capzraoAltList"></div>
11530                        </div>
11531
11532                        <div class="capzrao-note-v3">
11533                            Disclaimer: Hasil di halaman ini random (simulasi), bukan acuan hasil resmi.
11534                        </div>
11535                    </div>
11536                </div>
11537
11538                <style>
11539                    @import url("https://fonts.googleapis.com/css2?family=Orbitron:wght@600;700;800&display=swap");
11540
11541                    /* ===============================
11542   WRAPPER
11543================================ */
11544                    .capzrao-v3 {
11545                        display: flex;
11546                        justify-content: center;
11547                        padding: 16px 10px;
11548                        font-family: "Orbitron", "Poppins", system-ui, sans-serif;
11549                    }
11550
11551                    /* ===============================
11552   MACHINE CORE (#E3D05A ELEGANT)
11553================================ */
11554                    .Masa-Kini-yang-Selalu-v3 {
11555                        position: relative;
11556                        width: 100%;
11557                        max-width: 520px;
11558                        padding: 16px;
11559                        border-radius: 16px;
11560                        overflow: hidden;
11561                        isolation: isolate;
11562                        background: radial-gradient(circle at 15% 0%, rgba(163,100,34,1), transparent 48%), radial-gradient(circle at 85% 100%, rgba(201,131,42,0.18), transparent 55%), linear-gradient(123deg, #000000, #000000);
11563                        border: 1px solid rgba(201,131,42,1);
11564                        box-shadow: inset 0 0 18px rgba(201,131,42,1), 0 0 18px rgba(201,131,42,1);
11565                        color: #dbdbdb;
11566                    }
11567
11568                    /* HUD SWEEP */
11569                    .Masa-Kini-yang-Selalu-v3::before {
11570                        content: "";
11571                        position: absolute;
11572                        inset: 0;
11573                        background: linear-gradient(120deg, transparent 40%, rgba(226,166,66,.10), transparent 65%);
11574                        animation: hudSweep 7s linear infinite;
11575                        pointer-events: none;
11576                        opacity: .8;
11577                    }
11578
11579                    /* ===============================
11580   TITLE
11581================================ */
11582                    .capzrao-title-v3 {
11583                        text-align: center;
11584                        margin: 0 0 12px;
11585                        font-size: 15px;
11586                        font-weight: 900;
11587                        letter-spacing: 1px;
11588                        text-shadow: 0 0 6px rgba(163,100,34,90%);
11589                    }
11590
11591                    /* ===============================
11592   CONTROLS
11593================================ */
11594                    .capzrao-controls-v3 {
11595                        display: grid;
11596                        grid-template-columns: 1fr 1fr;
11597                        gap: 10px;
11598                        padding: 12px;
11599                        border-radius: 14px;
11600
11601                        background: rgba(0, 0, 0, 0.4);
11602                        border: 1px solid rgba(226,166,66,0.45);
11603                        box-shadow: inset 0 0 14px rgba(201,131,42,22%);
11604                    }
11605
11606                    .capzrao-controls-v3 label {
11607                        display: grid;
11608                        gap: 6px;
11609                        font-size: 10px;
11610                        letter-spacing: .8px;
11611                        text-transform: uppercase;
11612                        color: #E3D05A;
11613                    }
11614
11615                    .capzrao-controls-v3 select,
11616                    .capzrao-controls-v3 input {
11617                        background: rgba(0 0 0 / 92%);
11618                        color: #c5c5c5;
11619                        border: 1px solid rgba(201,131,42,1);
11620                        border-radius: 10px;
11621                        padding: 7px 9px;
11622                        font-weight: 700;
11623                        font-size: 12px;
11624                        outline: none;
11625                        box-shadow: inset 0 0 10px rgba(201,131,42,1);
11626                    }
11627
11628                    /* BUTTON */
11629                    #btncapzraoRandom {
11630                        grid-column: span 2;
11631                        display: flex;
11632                        align-items: center;
11633                        justify-content: center;
11634                        gap: 8px;
11635
11636                        background: linear-gradient(145deg, #E3D05A, #E3D05A);
11637                        border: none;
11638                        color: #000000;
11639                        font-weight: 900;
11640                        letter-spacing: .8px;
11641                        border-radius: 14px;
11642                        cursor: pointer;
11643                        padding: 10px 12px;
11644                        font-size: 12px;
11645
11646                        box-shadow: 0 0 16px rgba(226,166,66,0.75);
11647                        transition: .2s ease;
11648                    }
11649
11650                    #btncapzraoRandom:active {
11651                        transform: scale(.98);
11652                    }
11653
11654                    #btncapzraoRandom:disabled {
11655                        opacity: .75;
11656                        cursor: not-allowed;
11657                    }
11658
11659                    /* ===============================
11660   MAIN RESULT
11661================================ */
11662                    .capzrao-main-result-v3 {
11663                        margin-top: 12px;
11664                        padding: 12px;
11665                        border-radius: 14px;
11666
11667                        background: rgba(18,12,8,0.78);
11668                        border: 1px solid rgba(226,166,66,1);
11669                        box-shadow: inset 0 0 16px rgba(226,166,66,1);
11670                    }
11671
11672                    .capzrao-status-v3 {
11673                        text-align: center;
11674                        font-weight: 800;
11675                        letter-spacing: .8px;
11676                        color: #E3D05A;
11677                        margin-bottom: 10px;
11678                        font-size: 11px;
11679                    }
11680
11681                    .capzrao-highlight-box {
11682                        display: flex;
11683                        justify-content: space-between;
11684                        gap: 12px;
11685                        padding-bottom: 10px;
11686                        margin-bottom: 10px;
11687                        border-bottom: 1px dashed rgba(226,166,66,0.3);
11688                    }
11689
11690                    .k,
11691                    .k-rtp {
11692                        font-size: 10px;
11693                        color: #c7c7c7;
11694                        text-transform: uppercase;
11695                    }
11696
11697                    .v-game {
11698                        font-size: 14px;
11699                        font-weight: 900;
11700                        color: #ffffff;
11701                        margin-top: 6px;
11702                        line-height: 1.2;
11703                    }
11704
11705                    .provider-info {
11706                        margin-top: 8px;
11707                        font-size: 11px;
11708                        color: #d9d9d9;
11709                        opacity: .95;
11710                    }
11711
11712                    .k-small {
11713                        color: #E3D05A;
11714                        font-size: 10px;
11715                    }
11716
11717                    .v-small {
11718                        color: #fff0f0;
11719                        font-weight: 900;
11720                    }
11721
11722                    .v-rtp-huge {
11723                        font-size: 2.4em;
11724                        font-weight: 900;
11725                        color: #C77DFF;
11726                        text-shadow: 0 0 10px rgba(0 0 0);
11727                        line-height: 1;
11728                        letter-spacing: 1px;
11729                    }
11730
11731                    /* DETAILS */
11732                    .capzrao-details-v3 {
11733                        display: grid;
11734                        grid-template-columns: repeat(3, 1fr);
11735                        gap: 8px;
11736                        background: rgba(0, 0, 0, .30);
11737                        padding: 10px;
11738                        border-radius: 12px;
11739                    }
11740
11741                    .k-detail {
11742                        font-size: 9px;
11743                        color: #E3D05A;
11744                        text-transform: uppercase;
11745                    }
11746
11747                    .v-detail {
11748                        font-size: 12px;
11749                        font-weight: 800;
11750                        color: #ffffff;
11751                        margin-top: 4px;
11752                        letter-spacing: .8px;
11753                    }
11754
11755                    .capzrao-tip-v3 {
11756                        margin-top: 10px;
11757                        font-size: 10px;
11758                        color: #d9d9d9;
11759                        opacity: .9;
11760                        text-align: center;
11761                    }
11762
11763                    /* ALTS */
11764                    .capzrao-alts-v3 {
11765                        margin-top: 12px;
11766                        padding: 12px;
11767                        border-radius: 14px;
11768                        background: rgba(0, 0, 0, .40);
11769                        border: 1px solid rgba(226,166,66,1);
11770                    }
11771
11772                    .capzrao-alts-title-v3 {
11773                        font-weight: 900;
11774                        color: #E3D05A;
11775                        margin-bottom: 10px;
11776                        font-size: 12px;
11777                    }
11778
11779                    .capzrao-alt-list-v3 {
11780                        display: grid;
11781                        grid-template-columns: 1fr;
11782                        gap: 8px;
11783                    }
11784
11785                    .capzrao-alt-item {
11786                        background: rgba(18,12,8,.86);
11787                        border-radius: 12px;
11788                        padding: 10px;
11789                        border-left: 3px solid rgba(163,100,34,90%);
11790                    }
11791
11792                    .capzrao-alt-item .g {
11793                        font-weight: 900;
11794                        color: #c5c5c5;
11795                        font-size: 12px;
11796                    }
11797
11798                    .capzrao-alt-item .p {
11799                        font-size: 10px;
11800                        color: #E3D05A;
11801                        margin-top: 4px;
11802                    }
11803
11804                    .capzrao-alt-item .r {
11805                        margin-top: 6px;
11806                        font-weight: 900;
11807                        color: #C77DFF;
11808                        letter-spacing: .8px;
11809                        font-size: 12px;
11810                    }
11811
11812                    .capzrao-note-v3 {
11813                        margin-top: 10px;
11814                        font-size: 10px;
11815                        color: #d9d9d9;
11816                        opacity: .85;
11817                        text-align: center;
11818                    }
11819
11820                    /* MOBILE */
11821                    @media(max-width:420px) {
11822                        .capzrao-highlight-box {
11823                            flex-direction: column
11824                        }
11825
11826                        .capzrao-details-v3 {
11827                            grid-template-columns: 1fr
11828                        }
11829                    }
11830
11831                    /* ANIM */
11832                    @keyframes hudSweep {
11833                        0% {
11834                            transform: translateX(-110%)
11835                        }
11836
11837                        100% {
11838                            transform: translateX(110%)
11839                        }
11840                    }
11841
11842                    @keyframes pulse {
11843                        0% {
11844                            opacity: .55
11845                        }
11846
11847                        50% {
11848                            opacity: 1
11849                        }
11850
11851                        100% {
11852                            opacity: .55
11853                        }
11854                    }
11855                </style>
11856
11857                
11857<script>
11858                    /* ===============================
11859                       DATASET GAME MPO (SIMULASI)
11860                    ================================ */
11861                    const capzrao_MARKETS = [
11862                        { market: "Singapore", code: "SGP", open: "17:45", zone: "WIB" },
11863                        { market: "Hongkong", code: "HK", open: "22:45", zone: "WIB" },
11864                        { market: "Sydney", code: "SDY", open: "13:45", zone: "WIB" },
11865                        { market: "Macau", code: "MC", open: "16:00", zone: "WIB" },
11866                        { market: "Cambodia", code: "KHM", open: "10:45", zone: "WIB" },
11867                        { market: "Japan", code: "JP", open: "11:30", zone: "WIB" }
11868                    ];
11869
11870                    const SHIO = ["Tikus", "Kerbau", "Macan", "Kelinci", "Naga", "Ular", "Kuda", "Kambing", "Monyet", "Ayam", "Anjing", "Babi"];
11871
11872                    const $ = (q) => document.querySelector(q);
11873                    const randInt = (min, max) => Math.floor(Math.random() * (max - min + 1)) + min;
11874
11875                    function uniqueMarkets() {
11876                        return capzrao_MARKETS.map(m => m.market);
11877                    }
11878
11879                    function genDigits(len) {
11880                        let s = "";
11881                        for (let i = 0; i < len; i++) s += String(randInt(0, 9));
11882                        return s;
11883                    }
11884
11885                    function genBBFS() {
11886                        const pool = [...Array(10)].map((_, i) => i);
11887                        const out = [];
11888                        for (let i = 0; i < 7; i++) {
11889                            const idx = randInt(0, pool.length - 1);
11890                            out.push(pool.splice(idx, 1)[0]);
11891                        }
11892                        return out.join("");
11893                    }
11894
11895                    function genIkut() {
11896                        const pool = [...Array(10)].map((_, i) => i);
11897                        const out = [];
11898                        for (let i = 0; i < 4; i++) {
11899                            const idx = randInt(0, pool.length - 1);
11900                            out.push(pool.splice(idx, 1)[0]);
11901                        }
11902                        return out.join(" • ");
11903                    }
11904
11905                    function simulateConfidence() {
11906                        return randInt(60, 96);
11907                    }
11908
11909                    function applyFilters() {
11910                        const m = $("#marketFilter").value;
11911                        const minC = parseFloat($("#minConf").value || "0");
11912
11913                        return capzrao_MARKETS
11914                            .filter(x => (m === "ALL" || x.market === m))
11915                            .map(x => ({ ...x, conf: simulateConfidence() }))
11916                            .filter(x => x.conf >= minC);
11917                    }
11918
11919                    function pickRandom(arr, n = 1) {
11920                        const copy = [...arr];
11921                        const out = [];
11922                        for (let i = 0; i < n && copy.length; i++) {
11923                            const idx = randInt(0, copy.length - 1);
11924                            out.push(copy.splice(idx, 1)[0]);
11925                        }
11926                        return out;
11927                    }
11928
11929                    function formatAngka(type) {
11930                        if (type === "4D") return genDigits(4);
11931                        if (type === "3D") return genDigits(3);
11932                        return genDigits(2);
11933                    }
11934
11935                    function renderMain(item, type) {
11936                        $("#rMarket").textContent = `${item.market} (${item.code}) • Open ${item.open} ${item.zone}`;
11937                        $("#rType").textContent = type;
11938                        $("#rConf").textContent = `${item.conf}%`;
11939
11940                        $("#rAngka").textContent = formatAngka(type);
11941                        $("#rBBFS").textContent = genBBFS();
11942                        $("#rIkut").textContent = genIkut();
11943                        $("#rShio").textContent = SHIO[randInt(0, SHIO.length - 1)];
11944                        $("#rTip").textContent = "Tips: Ini simulasi hiburan. Tetap bijak & disiplin.";
11945                    }
11946
11947                    function renderAlts(list, type) {
11948                        const wrap = $("#capzraoAltList");
11949                        wrap.innerHTML = "";
11950                        list.forEach(x => {
11951                            const el = document.createElement("div");
11952                            el.className = "capzrao-alt-item";
11953                            el.innerHTML = `
11954      <div class="g">${x.market} (${x.code})</div>
11955      <div class="p">Tipe ${type} • Conf <strong>${x.conf}%</strong></div>
11956      <div class="r">Angka: <strong>${formatAngka(type)}</strong></div>
11957    `;
11958                            wrap.appendChild(el);
11959                        });
11960                    }
11961
11962                    function spinButton(btn, on) {
11963                        if (on) {
11964                            btn.disabled = true;
11965                            btn.dataset.text = btn.innerHTML;
11966                            btn.innerHTML = `<span class="icon">🔄</span> PROCESS...`;
11967                        } else {
11968                            btn.disabled = false;
11969                            btn.innerHTML = btn.dataset.text || `<span class="icon">🎲</span> GENERATE`;
11970                        }
11971                    }
11972
11973                    /* ===============================
11974                       INIT
11975                    ================================ */
11976                    (function init() {
11977                        const sel = $("#marketFilter");
11978                        uniqueMarkets().forEach(m => {
11979                            const o = document.createElement("option");
11980                            o.value = m; o.textContent = m;
11981                            sel.appendChild(o);
11982                        });
11983
11984                        $("#btncapzraoRandom").addEventListener("click", (e) => {
11985                            const btn = e.currentTarget;
11986                            const type = $("#typeFilter").value;
11987                            const filtered = applyFilters();
11988                            const st = $("#capzraoStatus");
11989
11990                            if (!filtered.length) {
11991                                st.textContent = "— NO MATCH —";
11992                                st.style.color = "white";
11993                                renderAlts([], type);
11994                                $("#rMarket").textContent = "-";
11995                                $("#rType").textContent = type;
11996                                $("#rConf").textContent = "-";
11997                                $("#rAngka").textContent = "-";
11998                                $("#rBBFS").textContent = "-";
11999                                $("#rIkut").textContent = "-";
12000                                $("#rShio").textContent = "-";
12001                                return;
12002                            }
12003
12004                            spinButton(btn, true);
12005                            st.textContent = "— GENERATING —";
12006                            st.style.animation = "pulse .6s linear infinite";
12007                            st.style.color = "white";
12008
12009                            const t0 = setInterval(() => {
12010                                const temp = pickRandom(filtered, 1)[0];
12011                                $("#rMarket").textContent = `${temp.market} (${temp.code}) • Open ${temp.open} ${temp.zone}`;
12012                                $("#rType").textContent = type;
12013                                $("#rConf").textContent = `${temp.conf}%`;
12014                                $("#rAngka").textContent = formatAngka(type);
12015                                $("#rBBFS").textContent = genBBFS();
12016                                $("#rIkut").textContent = genIkut();
12017                                $("#rShio").textContent = SHIO[randInt(0, SHIO.length - 1)];
12018                            }, 85);
12019
12020                            setTimeout(() => {
12021                                clearInterval(t0);
12022
12023                                const picks = pickRandom(filtered, 4);
12024                                renderMain(picks[0], type);
12025                                renderAlts(picks.slice(1), type);
12026
12027                                st.textContent = "— READY —";
12028                                st.style.animation = "";
12029                                st.style.color = "gold";
12030                                spinButton(btn, false);
12031                            }, 1200);
12032                        });
12033
12034                        renderAlts([], "4D");
12035                    })();
12036                </script>
12036
12037
12038<script defer src="https://static.cloudflareinsights.com/beacon.min.js/v8c78df7c7c0f484497ecbca7046644da1771523124516" integrity="sha512-8DS7rgIrAmghBFwoOTujcf6D9rXvH8xm8JQ1Ja01h9QX8EzXldiszufYa4IFfKdLUKTTrnSFXLDkUEOTrZQ8Qg==" data-cf-beacon='{"version":"2024.11.0","token":"1909e908a10849b7af66d8986368283e","r":1,"server_timing":{"name":{"cfCacheStatus":true,"cfEdge":true,"cfExtPri":true,"cfL4":true,"cfOrigin":true,"cfSpeedBrain":true},"location_startswith":null}}' crossorigin="anonymous"></script>
vendor: 2 bytes, line 12038
12038
12039<script defer src="https://static.cloudflareinsights.com/beacon.min.js/v833ccba57c9e4d2798f2e76cebdd09a11778172276447" integrity="sha512-57MDmcccJXYtNnH+ZiBwzC4jb2rvgVCEokYN+L/nLlmO8rfYT/gIpW2A569iJ/3b+0UEasghjuZH/ma3wIs/EQ==" data-cf-beacon='{"version":"2024.11.0","token":"f591dd59004a48eeafbe4ab22ac1a9da","r":1,"server_timing":{"name":{"cfCacheStatus":true,"cfEdge":true,"cfExtPri":true,"cfL4":true,"cfOrigin":true,"cfSpeedBrain":true},"location_startswith":null}}' crossorigin="anonymous"></script>
vendor: 2 bytes, line 12039
12039
12040<script defer src="https://static.cloudflareinsights.com/beacon.min.js/v833ccba57c9e4d2798f2e76cebdd09a11778172276447" integrity="sha512-57MDmcccJXYtNnH+ZiBwzC4jb2rvgVCEokYN+L/nLlmO8rfYT/gIpW2A569iJ/3b+0UEasghjuZH/ma3wIs/EQ==" data-cf-beacon='{"version":"2024.11.0","token":"e160a7c7e3074d01bd34414603c53b23","r":1,"server_timing":{"name":{"cfCacheStatus":true,"cfEdge":true,"cfExtPri":true,"cfL4":true,"cfOrigin":true,"cfSpeedBrain":true},"location_startswith":null}}' crossorigin="anonymous"></script>
vendor: 2 bytes, line 12040
12040
12041<script defer src="https://static.cloudflareinsights.com/beacon.min.js/v833ccba57c9e4d2798f2e76cebdd09a11778172276447" integrity="sha512-57MDmcccJXYtNnH+ZiBwzC4jb2rvgVCEokYN+L/nLlmO8rfYT/gIpW2A569iJ/3b+0UEasghjuZH/ma3wIs/EQ==" data-cf-beacon='{"version":"2024.11.0","token":"7d1313fe7e8b4cc3ac480817ec77c2a1","r":1,"server_timing":{"name":{"cfCacheStatus":true,"cfEdge":true,"cfExtPri":true,"cfL4":true,"cfOrigin":true,"cfSpeedBrain":true},"location_startswith":null}}' crossorigin="anonymous"></script>
vendor: 2 bytes, line 12041
12041
12042<script defer src="https://static.cloudflareinsights.com/beacon.min.js/v833ccba57c9e4d2798f2e76cebdd09a11778172276447" integrity="sha512-57MDmcccJXYtNnH+ZiBwzC4jb2rvgVCEokYN+L/nLlmO8rfYT/gIpW2A569iJ/3b+0UEasghjuZH/ma3wIs/EQ==" data-cf-beacon='{"version":"2024.11.0","token":"7d1313fe7e8b4cc3ac480817ec77c2a1","r":1,"server_timing":{"name":{"cfCacheStatus":true,"cfEdge":true,"cfExtPri":true,"cfL4":true,"cfOrigin":true,"cfSpeedBrain":true},"location_startswith":null}}' crossorigin="anonymous"></script>
vendor: 2 bytes, line 12042
12042
12043<script defer src="https://static.cloudflareinsights.com/beacon.min.js/v833ccba57c9e4d2798f2e76cebdd09a11778172276447" integrity="sha512-57MDmcccJXYtNnH+ZiBwzC4jb2rvgVCEokYN+L/nLlmO8rfYT/gIpW2A569iJ/3b+0UEasghjuZH/ma3wIs/EQ==" data-cf-beacon='{"version":"2024.11.0","token":"57cb2e82efc64548a4a6bee0c0fb1166","r":1,"server_timing":{"name":{"cfCacheStatus":true,"cfEdge":true,"cfExtPri":true,"cfL4":true,"cfOrigin":true,"cfSpeedBrain":true},"location_startswith":null}}' crossorigin="anonymous"></script>
vendor: 2 bytes, line 12043
12043
12044<script defer src="https://static.cloudflareinsights.com/beacon.min.js/v833ccba57c9e4d2798f2e76cebdd09a11778172276447" integrity="sha512-57MDmcccJXYtNnH+ZiBwzC4jb2rvgVCEokYN+L/nLlmO8rfYT/gIpW2A569iJ/3b+0UEasghjuZH/ma3wIs/EQ==" data-cf-beacon='{"version":"2024.11.0","token":"51df3b17a746455f940c0b561e8c0c0b","r":1,"server_timing":{"name":{"cfCacheStatus":true,"cfEdge":true,"cfExtPri":true,"cfL4":true,"cfOrigin":true,"cfSpeedBrain":true},"location_startswith":null}}' crossorigin="anonymous"></script>
12044
12045
12046<style>
12047body{background:#ebf2fc; font-family:Poppins,sans-serif; color:white;}
12048.capzrao{
12049max-width: 520px;
12050    margin: auto;
12051    padding: 15px;
12052    border-radius: 12px;
12053    background: #E3D05A;
12054    border: 2px solid #E3D05A;
12055    box-shadow: 0 0 20px #C77DFF;
12056}
12057
12058.capzrao-header{
12059  font-weight:900;
12060  text-align:center;
12061  color:#C77DFF;
12062  text-shadow:0 0 12px #5f90d9;
12063  margin-bottom:12px;
12064}
12065
12066.capzrao-controls{
12067  display:grid;
12068  grid-template-columns:1fr 1fr;
12069  gap:10px;
12070  margin-bottom:12px;
12071}
12072.capzrao-controls label{
12073  display:flex; flex-direction:column;
12074  font-size:11px; color:#C77DFF;
12075}
12076.capzrao-controls select,
12077.capzrao-controls input{
12078  padding:8px;
12079  border-radius:8px;
12080  border:1px solid #C77DFF;
12081  background:#120809;
12082  color:white;
12083}
12084#btnGenerate{
12085  grid-column:span 2;
12086  padding:12px;
12087  background:#5f90d9;
12088  border:none;
12089  color:black;
12090  font-weight:900;
12091  cursor:pointer;
12092  margin-top:5px;
12093  box-shadow:0 0 15px #C77DFF;
12094}
12095
12096.capzrao-result{
12097  margin-top:12px;
12098  padding:12px;
12099  border-radius:10px;
12100  background:rgba(226,166,66,0.05);
12101  border:1px solid #C77DFF;
12102}
12103
12104.capzrao-main div, .capzrao-details div{
12105  margin:5px 0;
12106}
12107
12108#rPrediction{
12109  font-size:24px;
12110  font-weight:900;
12111  color:#5f90d9;
12112}
12113
12114.capzrao-alts{
12115  margin-top:10px;
12116}
12117.capzrao-alts h4{margin-bottom:6px;}
12118#capzraoAltList div{
12119  background:#120809;
12120  padding:6px 10px;
12121  margin:3px 0;
12122  border-radius:8px;
12123  border-left:3px solid #5f90d9;
12124}
12125  .bank-tab.active, .bank-tab:hover {
12126    background: #C77DFF;
12127    color: #fff;
12128    border-color: #C77DFF;
12129    box-shadow: 0 3px 10px -4px rgb(226 166 66 / 60%);
12130}
12131
12132.capzrao-disclaimer{
12133  font-size:10px;
12134  margin-top:8px;
12135  text-align:center;
12136  color:#C77DFF;
12137}
12138</style>
12139
12140<script>
12141const leagues = ["Premier League","La Liga","Serie A"];
12142const tips = ["Analisis statistik tim","Performa terakhir","Cek head-to-head"];
12143function rand(arr){return arr[Math.floor(Math.random()*arr.length)];}
12144
12145var _bgBtn=document.getElementById("btnGenerate");if(_bgBtn)_bgBtn.onclick=function(){
12146  const type = document.getElementById("betTypeFilter").value;
12147  const league = rand(leagues);
12148
12149  let pred;
12150  if(type==="1X2") pred=rand(["1","X","2"]);
12151  else if(type==="OVER_UNDER") pred=rand(["Over","Under"]);
12152  else pred=rand(["Home -1","Away +1","Draw"]);
12153
12154  document.getElementById("rLeague").innerText=league;
12155  document.getElementById("rPrediction").innerText=pred;
12156  document.getElementById("rBetType").innerText=type;
12157  document.getElementById("rConf").innerText=Math.floor(Math.random()*40+60)+"%";
12158  document.getElementById("rTip").innerText=rand(tips);
12159  document.getElementById("rOdds").innerText=(Math.random()*3+1).toFixed(2);
12160
12161  // alternatif
12162  const alt=document.getElementById("capzraoAltList"); alt.innerHTML="";
12163  for(let i=0;i<3;i++){let d=document.createElement("div"); d.innerText=rand(["1","X","2"]); alt.appendChild(d);}
12164  
12165  document.getElementById("capzraoStatus").innerText="— READY —";
12166}
12167</script>
12167
12168
12169
12170                        
12171            <div class="pwp-deals-section" id="pwp-deals-section" hidden data-product-id="325" data-variant-id="0" data-category-path="Komputer &amp; Laptop/Laptop/Gaming"><div class="pwp-deals-header"><svg class="pwp-icon" width="20" height="20" viewBox="0 0 24 24" fill="currentColor"><path d="M21.41 11.58l-9-9C12.05 2.22 11.55 2 11 2H4c-1.1 0-2 .9-2 2v7c0 .55.22 1.05.59 1.42l9 9c.36.36.86.58 1.41.58.55 0 1.05-.22 1.41-.59l7-7c.37-.36.59-.86.59-1.41 0-.55-.23-1.06-.59-1.42zM5.5 7C4.67 7 4 6.33 4 5.5S4.67 4 5.5 4 7 4.67 7 5.5 6.33 7 5.5 7z"/></svg><div class="pwp-text"><h3 class="pwp-title">Penawaran Spesial PWP (Purchase with Purchase)</h3><p class="pwp-subtitle">Beli produk ini dan dapatkan produk pilihan dengan harga spesial</p></div></div><div class="pwp-deals-loading"><div class="pwp-spinner"></div><p>Memuat penawaran...</p></div><div class="pwp-deals-grid" id="pwp-deals-grid"></div><p class="pwp-cart-note">💡 Produk PWP dapat ditambahkan di halaman keranjang setelah produk ini dimasukkan</p></div>
12172        </div>
12173        </div>
12174        </section>
12175
12176        <aside class="pd-sidebar">
12177            <div class="pd-side-card pd-buy-card">
12178                <form class="pd-buy-form" id="pd-buy-form" data-pid="325">
12179                    <input type="hidden" name="variant_id" id="pd-variant-id" value="0">
12180                    <div>
12181                        <label for="qty" class="qty-label">Qty</label>
12182                        <input type="number" id="qty" name="qty" value="0" min="1"
12183                               max="0"
12184                               disabled>
12185                    </div>
12186                    <div class="pd-actions">
12187                        <button type="submit" class="btn-add-cart" id="btn-add-cart" disabled>+ Keranjang</button>
12188                        <button type="button" class="btn-buy" id="btn-buy" data-id="278426" disabled >Beli</button>
12189                        <button type="button" class="btn-chat-icon" id="btn-chat-icon" aria-label="Tanya Produk" title="Tanya Produk"><svg viewBox="0 0 640 640" fill="currentColor"><path d="M320 128C241 128 175.3 185.3 162.3 260.7C171.6 257.7 181.6 256 192 256L208 256C234.5 256 256 277.5 256 304L256 400C256 426.5 234.5 448 208 448L192 448C139 448 96 405 96 352L96 288C96 164.3 196.3 64 320 64C443.7 64 544 164.3 544 288L544 456.1C544 522.4 490.2 576.1 423.9 576.1L336 576L304 576C277.5 576 256 554.5 256 528C256 501.5 277.5 480 304 480L336 480C362.5 480 384 501.5 384 528L384 528L424 528C463.8 528 496 495.8 496 456L496 435.1C481.9 443.3 465.5 447.9 448 447.9L432 447.9C405.5 447.9 384 426.4 384 399.9L384 303.9C384 277.4 405.5 255.9 432 255.9L448 255.9C458.4 255.9 468.3 257.5 477.7 260.6C464.7 185.3 399.1 127.9 320 127.9z"/></svg></button>
12190                                            </div>
12191                </form>
12192                <div class="paylater-promo paylater-promo-md paylater-desktop-only">
12193    <span class="paylater-icon">💳</span>
12194    <span class="paylater-text">
12195        <strong>Mtode Pembayaaran Sah Mpo5000</strong>
12196        <small>Remi Daftar Game Mpo5000</small>
12197    </span>
12198</div>            </div>
12199
12200                        
12201                        <div class="pd-side-card qoala-banner-card">
12202                <div class="qoala-banner">
12203                    <div class="qoala-banner-content">
12204                        <div class="qoala-icon">
12205                            <center><img src="https://img.tongat.cc/uploads/logo-ri.png" alt="GAME MPO" class="qoala-shield-img"></center>
12206                        </div>
12207                        <div class="qoala-text">
12208                            <div class="qoala-title">Login GAME MPO</div>
12209                            <div class="qoala-subtitle">Verified</div>
12210                        </div>
12211                    </div>
12212                    <a href="https://mpo5000xjudimpo.blackhostapp.com/" class="qoala-cta"
12213                       data-ga-event="qoala_banner_click"
12214                       data-product-id="325"
12215                       data-product-name="GAME MPO"
12216                       data-category-path="Komputer &amp; Laptop/Laptop/Gaming" target="_blank">Info</a>
12217                </div>
12218<style>
12219.qoala-banner-card{padding:0;overflow:hidden}
12220
12221.qoala-banner{
12222  background:linear-gradient(135deg, #E3D05A 0%, #E3D05A 100%);
12223  padding:12px 16px;
12224  display:flex;
12225  align-items:center;
12226  justify-content:space-between;
12227  color:white;
12228  text-decoration:none;
12229  min-height:60px;
12230}
12231
12232.qoala-banner-content{
12233  display:flex;
12234  align-items:center;
12235  gap:12px;
12236}
12237
12238.qoala-icon{
12239  display:flex;
12240  align-items:center;
12241  justify-content:center;
12242}
12243
12244.qoala-shield-img{
12245  width:36px;
12246  height:36px;
12247  object-fit:contain;
12248  opacity:0.9;
12249}
12250
12251.qoala-title{
12252  font-weight:600;
12253  font-size:14px;
12254  line-height:1.2;
12255}
12256
12257.qoala-subtitle{
12258  font-size:12px;
12259  opacity:0.9;
12260  line-height:1.2;
12261}
12262
12263.qoala-cta{
12264  background:rgba(255,255,255,0.15);
12265  color:white;
12266  padding:6px 12px;
12267  border-radius:6px;
12268  font-size:12px;
12269  font-weight:600;
12270  text-decoration:none;
12271  transition:background 0.2s ease;
12272  border:1px solid rgba(226,166,66,0.4);
12273}
12274
12275.qoala-cta:hover{
12276  background:rgba(226,166,66,0.25);
12277  color:white;
12278}
12279
12280@media(max-width:768px){
12281  .qoala-banner{padding:10px 12px}
12282  .qoala-title{font-size:17px}
12283  .qoala-subtitle{font-size:11px}
12284}
12285</style>
12286            </div>
12287            
12288                        <div class="pd-side-card pd-installment-card2"
12289                 id="inst-card"
12290                 data-base-price="20789000"
12291                 data-zero-smart="0">
12292                <div class="inst-head">
12293                    <h3>Promo & Fitur GAME MPO</h3>
12294                                    </div>
12295
12296                <div class="inst-bank-tabs" role="tablist" aria-label="Bank">
12297                    <button type="button" class="bank-tab active" data-bank="Lucky Draw" aria-selected="true">Lucky Draw</button>
12298                    <button type="button" class="bank-tab" data-bank="Lomba Panjat Tur
12298nover" aria-selected="false">Lomba Panjat Turnover</button>
12299                    <button type="button" class="bank-tab" data-bank="Prediksi Jitu" aria-selected="false">Prediksi Jitu</button>
12300                </div>
12301
12302                <ul class="inst-month-list" id="inst-month-list" aria-label="Daftar cicilan per bulan"></ul>
12303                <div class="inst-note" id="inst-zero-note" style="display:none;">0% Cicilan khusus bank terpilih*</div>
12304            </div>
12305            
12306            <!-- MECHA BLUE FINAL BOSS REVIEW SLIDER -->
12307<div class="tnt-review-mecha">
12308
12309<div class="tnt-header">
12310<h2>REVIEW PEMAIN MPO SLOT BCA SITUS JUDIMPO</h2>
12311
12312</div>
12313
12314<div class="tnt-slider" id="tntSlider">
12315
12316<div class="tnt-slide active">
12317  <div class="tnt-name">game digital — Batam</div>
12318  <div class="tnt-comment">"Tampilan halaman Mpo 5000 cukup sederhana dan mudah dipahami. Informasi mengenai portal digital disusun dengan rapi sehingga saya tidak kesulitan mencari menu yang dibutuhkan."</div>
12319</div>
12320
12321<div class="tnt-slide">
12322  <div class="tnt-name">kendaraan yang bisa di-custom total — Pekanbaru</div>
12323  <div class="tnt-comment">"Saya menyukai tampilan yang responsif karena halaman dapat menyesuaikan layar ponsel. Navigasinya juga tidak terlalu rumit sehingga nyaman digunakan untuk membaca informasi."</div>
12324</div>
12325
12326<div class="tnt-slide">
12327  <div class="tnt-name">di-custom total — Jakarta</div>
12328  <div class="tnt-comment">"Informasi mengenai permainan berbasis peluang disampaikan dengan cukup jelas. Saya juga terbantu dengan penjelasan mengenai keamanan akun dan pentingnya menjaga data pribadi."</div>
12329</div>
12330<div class="tnt-slide">
12331  <div class="tnt-name">bisa di-custom total — Medan</div>
12332  <div class="tnt-comment">"Pengalaman membuka portal melalui perangkat iPhone terasa praktis. Tampilan yang sederhana membuat halaman lebih mudah dipahami tanpa terlalu banyak elemen yang mengganggu."</div>
12333</div>
12334<div class="tnt-slide">
12335  <div class="tnt-name">digital dengan kendaraan — Medan</div>
12336  <div class="tnt-comment">"Bagi pengguna yang baru mengenal Mpo 5000, penjelasan mengenai fitur dan istilah digital cukup membantu. Saya lebih mudah memahami fungsi setiap bagian setelah membaca informasinya."</div>
12337</div>
12338
12339
12340
12341</div>
12342</div>
12343
12344</aside>
12345</div>
12346
12347<style>
12348.tnt-review-mecha{
12349  background: radial-gradient(circle at center, #C77DFF, #C77DFF);
12350  border: 2px solid #E3D05A;
12351  border-radius: 14px;
12352  padding: 20px;
12353  color: #dbdbdb;
12354  font-family: 'Orbitron', sans-serif;
12355  position: relative;
12356  overflow: hidden;
12357  box-shadow: 0 0 25px #E3D05A, inset 0 0 20px rgba(226,166,66,0.2);
12358}
12359
12360/* scanline */
12361.tnt-review-mecha::before{
12362  content:"";
12363  position:absolute;
12364  inset:0;
12365  background: repeating-linear-gradient(
12366    to bottom,
12367    rgba(226,166,66,0.08),
12368    rgba(226,166,66,0.08) 1px,
12369    transparent 2px,
12370    transparent 4px
12371  );
12372  pointer-events:none;
12373}.bank-tab.active, .bank-tab:hover
12374  
12375
12376.tnt-header h2{
12377  font-size: 18px;
12378  color:#000000;
12379  text-shadow:0 0 10px #C77DFF, 0 0 20px #E3D05A;
12380  margin-bottom:5px;
12381}
12382
12383.tnt-header p{
12384  font-size:12px;
12385  opacity:0.85;
12386  margin-bottom:15px;
12387}
12388
12389.tnt-slider{
12390  position:relative;
12391  height:90px;
12392}
12393
12394.tnt-slide{
12395  position:absolute;
12396  width:100%;
12397  opacity:0;
12398  transform:translateX(40px);
12399  transition:all .6s ease;
12400}
12401  .tenor-badge {
12402    background: #C77DFF;
12403    color: #fff;
12404    font-weight: 700;
12405    min-width: 42px;
12406    text-align: center;
12407    padding: .38rem .4rem;
12408    font-size: .8rem;
12409    border-radius: 10px;
12410    box-shadow: 0 3px 10px -4px rgb(226,166,66);
12411}
12412
12413.tnt-slide.active{
12414  opacity:1;
12415  transform:translateX(0);
12416}
12417
12418.tnt-name{
12419font-size: 14px;
12420    color: #000000;
12421    margin-bottom: 5px;
12422    text-shadow: 0 0 6px #120809;
12423}
12424
12425.tnt-comment{
12426  font-size:13px;
12427  line-height:1.5;
12428}
12429
12430/* glowing border animation */
12431@keyframes pulseGlow{
12432  0%{box-shadow:0 0 10px #C77DFF;}
12433  50%{box-shadow:0 0 25px #C77DFF;}
12434  100%{box-shadow:0 0 10px #C77DFF;}
12435}
12436
12437.tnt-review-mecha{
12438  animation:pulseGlow 2.5s infinite;
12439}
12440</style>
12441
12442<script>
12443let slides = document.querySelectorAll('.tnt-slide');
12444let index = 0;
12445
12446setInterval(()=>{
12447  slides[index].classList.remove('active');
12448  index = (index + 1) % slides.length;
12449  slides[index].classList.add('active');
12450}, 3000);
12451</script>
12451
12452
12453        <div class="artikel-glow-capzrao">
12454
12455  <div class="artikel-shine"></div>
12456
12457  <h1>JUDIMPO Situs Judi Mpo Slot 10k dengan Peluang Maxwin Terbaik</h1>
12458 <p>JUDIMPO hadir sebagai salah satu platform judi online terdepan yang menggunakan sistem MPO (Multi-Provider Online) modern, dirancang khusus untuk memberikan pengalaman bermain slot yang mulus, aman, dan memuaskan. Sebagai situs yang dikenal luas oleh para pecinta slot online , Judimpo secara konsisten menghadirkan berbagai pilihan permainan slot gacor hari ini dari provider-provider ternama dunia yang telah memiliki lisensi resmi.</p>
12459 <p>Keunggulan utama dari JUDIMPO terletak pada infrastruktur teknologinya yang canggih, menawarkan sistem transaksi yang super cepat—baik untuk proses deposit maupun penarikan dana (withdraw ) —serta layanan pelanggan ( customer service ) profesional yang siap membantu selama 24 jam penuh.</p>
12460 <p>Dengan pilihan game yang sangat lengkap, mulai dari tema klasik hingga video slot modern dengan tingkat Return to Player (RTP) tinggi, setiap pemain memiliki kesempatan emas untuk meraih kemenangan maksimal atau maxwin dengan lebih mudah. akhiri dengan JUDIMPO sekarang juga, nikmati sensasi bermain tanpa hambatan, dan buktikan sendiri peluang maxwin terbesar di situs judi mpo slot terpercaya ini!</p>
12461</div>
12462
12463<style>
12464.artikel-glow-capzrao{
12465      max-width: 820px;
12466    margin: 40px auto;
12467    padding: 36px;
12468    box-sizing: border-box;
12469    position: relative;
12470    overflow: hidden;
12471    border-radius: 30px;
12472    font-family: Arial, sans-serif;
12473    color: #ffffff;
12474    background: radial-gradient(circle at top left, rgba(201,131,42,1), transparent 20%), radial-gradient(circle at bottom right, rgb(43,27,14), transparent 28%), linear-gradient(135deg, #E3D05A, #E3D05A, #E3D05A);
12475    border: 2px solid rgba(255, 255, 255, .55);
12476    box-shadow: 0 0 25px rgb(201,131,42), 0 0 55px rgb(226,166,66), 0 20px 45px rgba(0, 0, 0, .25), inset 0 0 35px rgba(163,100,34,1);
12477}
12478
12479.artikel-glow-capzrao:before{
12480  content:"";
12481  position:absolute;
12482  inset:10px;
12483  border-radius:24px;
12484  border:1px solid rgba(255,255,255,.32);
12485  pointer-events:none;
12486}
12487
12488.artikel-shine{
12489  position:absolute;
12490  top:-120px;
12491  left:-180px;
12492  width:280px;
12493  height:650px;
12494  background:linear-gradient(120deg,transparent,rgba(255,255,255,.55),transparent);
12495  transform:rotate(25deg);
12496  animation:artikelShine 4.5s infinite;
12497  pointer-events:none;
12498}
12499
12500@keyframes artikelShine{
12501  0%{left:-220px;}
12502  55%{left:110%;}
12503  100%{left:110%;}
12504}
12505
12506.artikel-glow-capzrao h1,
12507.artikel-glow-capzrao h2{
12508  position:relative;
12509  color:#000000;
12510  text-align:center;
12511  line-height:1.35;
12512  text-shadow:
12513    0 0 8px rgba(201,131,42,95%),
12514    0 0 18px rgba(201,131,42,1),
12515    0 2px 8px rgba(163,100,34,1);
12516}
12517
12518.artikel-glow-capzrao h1{
12519  font-size:31px;
12520  margin:0 0 20px;
12521}
12522
12523.artikel-glow-capzrao h2{
12524  font-size:24px;
12525  margin:28px 0 14px;
12526}
12527
12528.artikel-glow-capzrao p{
12529  position:relative;
12530  margin:0 0 16px;
12531  color:#f8ffff;
12532  font-size:15px;
12533  line-height:1.85;
12534  text-align:justify;
12535  text-shadow:0 1px 4px rgba(0,0,0,.28);
12536}
12537
12538.artikel-glow-capzrao a{
12539  color:#000000;
12540  font-weight:800;
12541  text-shadow:0 0 8px rgba(163,100,34,1);
12542}
12543
12544.artikel-glow-capzrao img{
12545  position:relative;
12546  display:block;
12547  max-width:100%;
12548  margin:16px auto 24px;
12549  border-radius:16px;
12550  border:1px solid rgba(255,255,255,.55);
12551  box-shadow:
12552    0 0 18px rgba(255,255,255,.55),
12553    0 12px 28px rgba(0,0,0,.28);
12554}
12555
12556.artikel-highlight{
12557  position:relative;
12558  margin:24px 0;
12559  padding:22px;
12560  border-radius:22px;
12561  background:rgba(255,255,255,.20);
12562  border:1px solid rgba(255,255,255,.45);
12563  box-shadow:
12564    inset 0 1px 0 rgba(255,255,255,.65),
12565    inset 0 0 22px rgba(255,255,255,.14),
12566    0 10px 25px rgba(0,0,0,.18);
12567  backdrop-filter:blur(8px);
12568}
12569
12570.artikel-highlight:before{
12571  content:"";
12572  position:absolute;
12573  left:0;
12574  right:0;
12575  top:0;
12576  height:45%;
12577  border-radius:22px 22px 0 0;
12578  background:linear-gradient(rgba(255,255,255,.35),rgba(255,255,255,.04));
12579  pointer-events:none;
12580}
12581
12582.artikel-glow-capzrao ul{
12583  position:relative;
12584  margin:15px 0 0 20px;
12585  padding:0;
12586}
12587
12588.artikel-glow-capzrao li{
12589  margin-bottom:11px;
12590  padding:10px 12px;
12591  border-radius:12px;
12592  background:rgba(255,255,255,.16);
12593  color:#ffffff;
12594  line-height:1.6;
12595  box-shadow:inset 0 0 10px rgba(255,255,255,.08);
12596}
12597
12598@media(max-width:600px){
12599  .artikel-glow-capzrao{
12600    margin:25px 12px;
12601    padding:25px;
12602    border-radius:24px;
12603  }
12604
12605  .artikel-glow-capzrao h1{
12606    font-size:24px;
12607  }
12608
12609  .artikel-glow-capzrao h2{
12610    font-size:21px;
12611  }
12612}
12613</style>
12614
12615<div class="capzrao-faq-rainbow">
12616  <div class="capzrao-shine"></div>
12617
12618  <div class="capzrao-faq-top">
12619    <span>★ PREMIUM FAQ ★</span>
12620    <h2>PERTANYAAN UMUM MENGENAI APK SLOT1000</h2>
12621    
12622  </div>
12623
12624  <div class="capzrao-rainbow-item">
12625    <button type="button">What is JUDIMPO Situs Judi Mpo Slot 10k dengan Peluang Maxwin Terbaik?</button>
12626    <div class="capzrao-rainbow-answer">
12627      <p>JUDIMPO Situs Judi Mpo Slot 10k dengan Peluang Maxwin Terbaik refers to a digital portal providing information about MPO games, available features, and various online entertainment options.</p>
12628    </div>
12629  </div>
12630
12631  <div class="capzrao-rainbow-item">
12632    <button type="button">What information can users find on JUDIMPO?</button>
12633    <div class="capzrao-rainbow-answer">
12634      <p>Users can find information about available MPO games, platform features, updates, and different categories of digital entertainment.</p>
12635    </div>
12636  </div>
12637
12638  <div class="capzrao-rainbow-item">
12639    <button type="button">Does gacor guarantee winning results?</button>
12640    <div class="capzrao-rainbow-answer">
12641      <p>No. The term gacor is commonly used by gaming communities to describe games perceived as frequently producing favorable results, but it does not guarantee winnings or specific outcomes.</p>
12642    </div>
12643  </div>
12644
12645  <div class="capzrao-rainbow-item">
12646    <button type="button">What does Pilihan Game Hoki mean?</button>
12647    <div class="capzrao-rainbow-answer">
12648      <p>Pilihan Game Hoki is a popular term referring to game selections that players consider potentially favorable. However, game outcomes remain uncertain and should not be regarded as guaranteed.</p>
12649    </div>
12650  </div>
12651  <div class="capzrao-rainbow-item">
12652    <button type="button">Can JUDIMPO be accessed through mobile devices?</button>
12653    <div class="capzrao-rainbow-answer">
12654      <p>A responsive digital platform can generally be accessed through compatible smartphones, tablets, or computers, depending on the services and technical requirements provided by the platform.</p>
12655    </div>
12656  </div>
12657</div>
12658
12659<style>
12660.capzrao-faq-rainbow{
12661      max-width: 760px;
12662    margin: 40px auto;
12663    padding: 30px;
12664    box-sizing: border-box;
12665    position: relative;
12666    overflow: hidden;
12667    border-radius: 32px;
12668    font-family: Arial, sans-serif;
12669    background: radial-gradient(circle at 15% 10%, rgba(201,131,42,1), transparent 18%), radial-gradient(circle at 85% 15%, rgb(201,131,42), transparent 25%), radial-gradient(circle at 20% 90%, rgb(201,131,42), transparent 25%), linear-gradient(135deg, #E3D05A, #E3D05A, #E3D05A, #E3D05A);
12670    border: 2px solid rgba(201,131,42,1);
12671    box-shadow: 0 0 25px rgb(201,131,42), 0 0 55px rgba(226,166,66,1), inset 0 0 35px rgba(163,100,34,1);
12672}
12673
12674.capzrao-shine{
12675  position:absolute;
12676  top:-90px;
12677  left:-120px;
12678  width:260px;
12679  height:520px;
12680  background:linear-gradient(120deg,transparent,rgba(255,255,255,.55),transparent);
12681  transform:rotate(25deg);
12682  animation:capzraoShine 4s infinite;
12683  pointer-events:none;
12684}
12685
12686@keyframes capzraoShine{
12687  0%{left:-180px;}
12688  55%{left:110%;}
12689  100%{left:110%;}
12690}
12691
12692.capzrao-faq-top{
12693  position:relative;
12694  text-align:center;
12695  margin-bottom:24px;
12696}
12697
12698.capzrao-faq-top span{
12699  display:inline-block;
12700  padding:8px 22px;
12701  border-radius:999px;
12702  background:rgba(201,131,42,0%);
12703  color:#dbdbdb;
12704  font-size:12px;
12705  font-weight:900;
12706  letter-spacing:2px;
12707  border:1px solid rgba(215 215 215 / 62%);
12708  box-shadow:inset 0 0 14px rgba(255,255,255,.25);
12709}
12710
12711.capzrao-faq-top h2{
12712  margin:16px 0 8px;
12713  color:#000000;
12714  font-size:34px;
12715  line-height:1.15;
12716  text-shadow:
12717    0 0 10px rgba(201,131,42,1),
12718    0 0 22px rgba(201,131,42,1);
12719}
12720
12721.capzrao-faq-top p{
12722  margin:0;
12723  color:#f3ffff;
12724  font-size:14px;
12725}
12726
12727.capzrao-rainbow-item{
12728  position:relative;
12729  overflow:hidden;
12730  margin-bottom:14px;
12731  border-radius:20px;
12732  background:rgba(255,255,255,.20);
12733  border:1px solid rgba(255,255,255,.48);
12734  box-shadow:
12735    inset 0 1px 0 rgba(255,255,255,.6),
12736    0 10px 25px rgba(0,0,0,.18);
12737  backdrop-filter:blur(10px);
12738}
12739
12740.capzrao-rainbow-item:before{
12741  content:"";
12742  position:absolute;
12743  top:0;
12744  left:0;
12745  right:0;
12746  height:45%;
12747  background:linear-gradient(rgba(255,255,255,.32),rgba(255,255,255,.04));
12748  pointer-events:none;
12749}
12750
12751.capzrao-rainbow-item button{
12752  width:100%;
12753  padding:18px 58px 18px 20px;
12754  border:0;
12755  background: #E3D05A;
12756  color:#dbdbdb;
12757  text-align:left;
12758  cursor:pointer;
12759  font-size:15px;
12760  font-weight:900;
12761  position:relative;
12762  z-index:2;
12763  text-shadow:0 2px 6px rgba(0,0,0,.35);
12764}
12765
12766.capzrao-rainbow-item button:after{
12767  content:"+";
12768  position:absolute;
12769  right:18px;
12770  top:50%;
12771  transform:translateY(-50%);
12772  width:34px;
12773  height:34px;
12774  border-radius:50%;
12775  background:linear-gradient(135deg,#E3D05A, #E3D05A);
12776  color:#d1d1d1;
12777  text-align:center;
12778  line-height:34px;
12779  font-size:24px;
12780  font-weight:900;
12781  box-shadow:
12782    0 0 14px rgba(255,255,255,.8),
12783    inset 0 -4px 8px rgba(0,0,0,.18);
12784}
12785
12786.capzrao-rainbow-item.active button:after{
12787  content:"−";
12788  background:linear-gradient(135deg,#C77DFF, #4d2e14);
12789}
12790
12791.capzrao-rainbow-answer{
12792  max-height:0;
12793  overflow:hidden;
12794  transition:max-height .35s ease;
12795  position:relative;
12796  z-index:2;
12797}
12798
12799.capzrao-rainbow-item.active .capzrao-rainbow-answer{
12800  max-height:170px;
12801}
12802
12803.capzrao-rainbow-answer p{
12804  margin:0;
12805  padding:0 20px 18px;
12806  color:#dbdbdb;
12807  font-size:14px;
12808  line-height:1.7;
12809  text-shadow:0 2px 5px rgba(0 0 0);
12810}
12811
12812@media(max-width:600px){
12813  .capzrao-faq-rainbow{
12814    margin:25px 12px;
12815    padding:22px;
12816    border-radius:24px;
12817  }
12818
12819  .capzrao-faq-top h2{
12820    font-size:26px;
12821  }
12822}
12823</style>
12824
12825<script>
12826document.querySelectorAll(".capzrao-rainbow-item button").forEach(function(btn){
12827  btn.addEventListener("click", function(){
12828    this.parentElement.classList.toggle("active");
12829  });
12830});
12831</script>
12831
12832<style>
12833@import url('https://fonts.googleapis.com/css2?family=Orbitron:wght@500;700;900&display=swap');
12834
12835.cyber-mecha {
12836  max-width: 800px;
12837  margin: 40px auto;
12838
12839  /* deep luxury #E3D05A */
12840  background: radial-gradient(circle at top, #14b1d7, #14b1d7 70%);
12841
12842  border-radius: 16px;
12843  border: 1px solid rgba(226,166,66,0.35);
12844
12845  box-shadow:
12846    0 0 25px rgba(163,100,34,0.35),
12847    inset 0 0 20px rgba(226,166,66,0.10);
12848
12849  padding: 25px;
12850  font-family: 'Orbitron', sans-serif;
12851  color: #f7e6e6;
12852  position: relative;
12853  overflow: hidden;
12854}
12855
12856/* scanline overlay */
12857.cyber-mecha::before {
12858  content: "";
12859  position: absolute;
12860  inset: 0;
12861  background: repeating-linear-gradient(
12862    to bottom,
12863    rgba(226,166,66,0.03),
12864    rgba(226,166,66,0.03) 1px,
12865    transparent 1px,
12866    transparent 3px
12867  );
12868  pointer-events: none;
12869}
12870
12871.pd-full-desc-title {
12872  text-align: center;
12873  font-size: 22px;
12874
12875  /* elegant muted #E3D05A */
12876  color: #C77DFF;
12877
12878  letter-spacing: 2px;
12879  text-shadow: 0 0 10px rgba(226,166,66,0.4);
12880  margin-bottom: 20px;
12881}
12882
12883.mecha-header h3 {
12884  text-align: center;
12885  font-size: 18px;
12886  color: #C77DFF;
12887  text-shadow: 0 0 8px rgba(226,166,66,0.5);
12888  margin-bottom: 15px;
12889}
12890
12891.mecha-image img {
12892  width: 100%;
12893  border-radius: 10px;
12894  border: 1px solid rgba(226,166,66,0.4);
12895  box-shadow: 0 0 20px rgba(226,166,66,0.25);
12896  margin-bottom: 20px;
12897}
12898
12899.mecha-content p {
12900  font-size: 14px;
12901  line-height: 1.8;
12902  margin-bottom: 14px;
12903  color: #f3dede;
12904}
12905
12906.glow {
12907  color: #C77DFF;
12908  text-shadow: 0 0 6px rgba(226,166,66,0.5);
12909  font-weight: 600;
12910}
12911
12912.glow-strong {
12913  color: #C77DFF;
12914  text-shadow:
12915    0 0 10px rgba(226,166,66,0.6),
12916    0 0 20px rgba(226,166,66,0.4);
12917  font-weight: 700;
12918}
12919
12920.final-line {
12921  margin-top: 18px;
12922  padding: 10px;
12923  border: 1px solid rgba(226,166,66,0.35);
12924  background: rgba(43,27,14,0.25);
12925  border-radius: 8px;
12926  text-align: center;
12927  color: #ffd0d0;
12928}
12929</style>
12930    
12931    
12932    
12933        <section class="pd-related-full">
12934        <h2 class="pd-related-title">Produk Terkait</h2>
12935        <div class="pd-related-grid pd-related-grid--full">
12936                        <a class="pd-related-card" href="https://hop.exchange/">
12937                <div class="thumb">
12938                    <img src="https://img.tongat.cc/uploads/pasti-jaackpot-judimpo.jpg" alt="GAME MPO">
12939                    <span class="mini-disc">-2%</span>                </div>
12940                <div class="info">
12941                    <h3>APk Resmi Judimpo</h3>
12942                    <div class="spec-chips">I5 <span class="spec-divider">|</span> 16GB <span class="spec-divider">|</span> 512GB <span class="spec-divider">|</span> RTX3050</div>                    <span class="price">
12943                        <span class="final">Rp 11.500.000</span>
12944                                                  <span class="ori">Rp 12.799.000</span>
12945                                            </span>
12946                    <span class="sold">Terjual 200+</span>                    <span class="stock-dot low" title="Stok Terbatas"></span>
12947                </div>
12948            </a>
12949                        <a class="pd-related-card" href="https://hop.exchange/">
12950                <div class="thumb">
12951                    <img src="https://img.tongat.cc/uploads/pasti-jaackpot-judimpo.jpg" alt="di-custom total GAME MPO">
12952                    <span class="mini-disc">-1%</span>                </div>
12953                <div class="info">
12954                    <h3>Agen Game Mpo Play</h3>
12955                    <div class="spec-chips">I7 <span class="spec-divider">|</span> 16GB <span class="spec-divider">|</span> 512GB <span class="spec-divider">|</span> RTX5050</div>                    <span class="price">
12956                        <span class="final">Rp 22.887.000</span>
12957                                                  <span class="ori">Rp 21.999.000</span>
12958                                            </span>
12959                    <span class="sold">Terjual 20+</span>                    <span class="stock-dot out" title="Habis"></span>
12960                </div>
12961            </a>
12962                        <a class="pd-related-card" href="https://hop.exch
12962ange/">
12963                <div class="thumb">
12964                    <img src="https://img.tongat.cc/uploads/pasti-jaackpot-judimpo.jpg" alt="GAME MPO ONLINE">
12965                    <span class="mini-disc">-1%</span>                </div>
12966                <div class="info">
12967                    <h3>Login Game Mpo 5000</h3>
12968                    <div class="spec-chips">R7AI <span class="spec-divider">|</span> 16GB <span class="spec-divider">|</span> 1TB <span class="spec-divider">|</span> RTX5060</div>                    <span class="price">
12969                        <span class="final">Rp 23.600.000</span>
12970                                                  <span class="ori">Rp 21.399.000</span>
12971                                            </span>
12972                    <span class="sold">Terjual 6</span>                    <span class="stock-dot ready" title="Ready"></span>
12973                </div>
12974            </a>
12975                        <a class="pd-related-card" href="https://hop.exchange/">
12976                <div class="thumb">
12977                    <img src="https://img.tongat.cc/uploads/pasti-jaackpot-judimpo.jpg" alt="GAME MPO 4D">
12978                    <span class="mini-disc">-1%</span>                </div>
12979                <div class="info">
12980                    <h3>Login Judimpo</h3>
12981                    <div class="spec-chips">R5AI <span class="spec-divider">|</span> 16GB <span class="spec-divider">|</span> 1TB <span class="spec-divider">|</span> RTX5060</div>                    <span class="price">
12982                        <span class="final">Rp 18.800.000</span>
12983                                                  <span class="ori">Rp 19.799.000</span>
12984                                            </span>
12985                    <span class="sold">Terjual 5</span>                    <span class="stock-dot ready" title="Ready"></span>
12986                </div>
12987            </a>
12988                        <a class="pd-related-card" href="https://hop.exchange/">
12989                <div class="thumb">
12990                    <img src="https://img.tongat.cc/uploads/pasti-jaackpot-judimpo.jpg" alt="di-custom total GAME MPO 4D">
12991                    <span class="mini-disc">-1%</span>                </div>
12992                <div class="info">
12993                    <h3>Pusat Game Mpo</h3>
12994                    <div class="spec-chips">I7 <span class="spec-divider">|</span> 16GB <span class="spec-divider">|</span> 512GB <span class="spec-divider">|</span> RTX5050</div>                    <span class="price">
12995                        <span class="final">Rp 28.600.080</span>
12996                                                  <span class="ori">Rp 27.999.000</span>
12997                                            </span>
12998                    <span class="sold">Terjual 6</span>                    <span class="stock-dot low" title="Stok Terbatas"></span>
12999                </div>
13000            </a>
13001                        <a class="pd-related-card" href="https://hop.exchange/">
13002                <div class="thumb">
13003                    <img src="https://img.tongat.cc/uploads/pasti-jaackpot-judimpo.jpg" alt="GAME MPO ONLINE">
13004                    <span class="mini-disc">-1%</span>                </div>
13005                <div class="info">
13006                    <h3>Agen Slot Mpo</h3>
13007                    <div class="spec-chips">CORE5 <span class="spec-divider">|</span> 16GB <span class="spec-divider">|</span> 512GB <span class="spec-divider">|</span> RTX4050</div>                    <span class="price">
13008                        <span class="final">Rp 17.888.000</span>
13009                                                  <span class="ori">Rp 18.499.000</span>
13010                                            </span>
13011                                        <span class="stock-dot low" title="Stok Terbatas"></span>
13012                </div>
13013            </a>
13014                        
13015                    </div>
13016    </section>
13017    
13018    <div class="pd-mobile-fab" id="pd-mobile-fab" data-pid="325" data-price="20789000" data-voucher-code="" data-voucher-value="0"><div class="mf-actions"><button type="button" class="mf-btn mf-share" id="mf-share" aria-label="Bagikan"><svg viewBox="0 0 24 24" width="18" height="18" aria-hidden="true">
13018<path fill="currentColor" d="M18 16.08c-.76 0-1.44.3-1.96.77L8.91 12.7c.05-.23.09-.46.09-.7s-.04-.47-.09-.7l7.05-4.11c.54.5 1.25.81 2.04.81 1.66 0 3-1.34 3-3s-1.34-3-3-3-3 1.34-3 3c0 .24.04.47.09.7L8.04 9.81C7.5 9.31 6.79 9 6 9c-1.66 0-3 1.34-3 3s1.34 3 3 3c.79 0 1.5-.31 2.04-.81l7.12 4.16c-.05.21-.08.43-.08.65 0 1.61 1.31 2.92 2.92 2.92s2.92-1.31 2.92-2.92-1.31-2.92-2.92-2.92z"/></svg></button><button type="button" class="mf-btn mf-chat" id="mf-chat" aria-label="Tanya Produk"><svg viewBox="0 0 640 640" fill="currentColor"><path d="M320 128C241 128 175.3 185.3 162.3 260.7C171.6 257.7 181.6 256 192 256L208 256C234.5 256 256 277.5 256 304L256 400C256 426.5 234.5 448 208 448L192 448C139 448 96 405 96 352L96 288C96 164.3 196.3 64 320 64C443.7 64 544 164.3 544 288L544 456.1C544 522.4 490.2 576.1 423.9 576.1L336 576L304 576C277.5 576 256 554.5 256 528C256 501.5 277.5 480 304 480L336 480C362.5 480 384 501.5 384 528L384 528L424 528C463.8 528 496 495.8 496 456L496 435.1C481.9 443.3 465.5 447.9 448 447.9L432 447.9C405.5 447.9 384 426.4 384 399.9L384 303.9C384 277.4 405.5 255.9 432 255.9L448 255.9C458.4 255.9 468.3 257.5 477.7 260.6C464.7 185.3 399.1 127.9 320 127.9z"/></svg></button><button type="button" class="mf-btn mf-cart" id="mf-cart" disabled aria-label="Tambah ke keranjang"><svg viewBox="0 0 24 24" width="18" height="18" aria-hidden="true"><path fill="currentColor" d="M7 18c-1.1 0-1.99.9-1.99 2S5.9 22 7 22s2-.9 2-2-.9-2-2-2zM1 2v2h2l3.6 7.59-1.35 2.45c-.16.28-.25.61-.25.96 0 1.1.9 2 2 2h12v-2H7.42c-.14 0-.25-.11-.25-.25l.03-.12.9-1.63h7.45c.75 0 1.41-.41 1.75-1.03l3.58-6.49c.08-.14.12-.31.12-.48 0-.55-.45-1-1-1H5.21l-.94-2H1zm16 16c-1.1 0-1.99.9-1.99 2s.89 2 1.99 2 2-.9 2-2-.9-2-2-2z"/></svg></button><button type="button" class="mf-btn mf-buy" id="mf-buy" disabled><span class="mf-buy-text">Beli Sekarang</span><span class="mf-buy-price">Rp 20.789.000</span></button></div></div>
13019
13020    <button type="button"
13021            class="pd-scroll-top"
13022            id="pd-scroll-top"
13023            aria-label="Kembali ke atas"
13024            title="Kembali ke atas">
13025        <svg viewBox="0 0 24 24" width="20" height="20" aria-hidden="true">
13026            <path fill="currentColor" d="M7.41 14.59 12 10l4.59 4.59L18 13.17l-6-6-6 6z"/>
13027        </svg>
13028    </button>
13029</main>
13030
13031<div class="pd-share-modal-overlay" id="pd-share-modal-overlay"><div class="pd-share-modal"><div class="pd-share-header"><h2 class="pd-share-title">Bagikan Produk</h2><button type="button" class="pd-share-close" id="pd-share-close" aria-label="Tutup"><svg width="20" height="20" viewBox="0 0 24 24"><path fill="currentColor" d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/></svg></button></div><div class="pd-share-body"><div class="pd-share-preview"><img src="https://img.tongat.cc/uploads/pasti-jaackpot-judimpo.jpg" alt="GAME MPO" class="pd-share-preview-img"><div class="pd-share-preview-info"><h3 class="pd-share-preview-name">GAME MPO</h3><p class="pd-share-preview-price">Rp 20.789.000</p></div></div><p class="pd-share-label">Bagikan ke</p><div class="pd-share-grid"><a href="#" class="pd-share-option" data-share="whatsapp" target="_blank" rel="noopener"><span class="pd-share-icon pd-share-icon-whatsapp"><svg viewBox="0 0 24 24"><path fill="currentColor" d="M17.472 14.382c-.297-.149-1.758-.867-2.029-.967-.273-.099-.471-.148-.669.149-.198.297-.767.966-.94 1.164-.173.198-.347.223-.644.074-.297-.149-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.297-.347.446-.52.149-.173.198-.297.298-.495.099-.198.05-.372-.025-.521-.075-.149-.669-1.612-.916-2.206-.242-.579-.487-.5-.669-.51l-.57-.01c-.198 0-.52.074-.792.372s-1.04 1.016-1.04 2.479 1.065 2.876 1.213 3.074c.149.198 2.095 3.2 5.076 4.487.709.306 1.262.489 1.694.626.712.226 1.36.194 1.872.118.571-.085 1.758-.718 2.006-1.411.248-.694.248-1.29.173-1.411-.074-.123-.272-.198-.57-.347m-5.421 7.403h-.002a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.263c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.884-9.887 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.158 11.892c0 2.096.547 4.142 1.588 5.945L0 24l6.305-1.654a11.86 11.86 0 005.67 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 00-3.485-8.413"/></svg></span><span class="pd-share-name">WhatsApp</span></a><a href="#" class="pd-share-option" data-share="facebook" target="_blank" rel="noopener"><span class="pd-share-icon pd-share-icon-facebook"><svg viewBox="0 0 24 24">
13031<path fill="currentColor" d="M24 12.073c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.99 4.388 10.954 10.125 11.854v-8.385H7.078v-3.47h3.047V9.43c0-3.007 1.792-4.669 4.533-4.669 1.312 0 2.686.235 2.686.235v2.953H15.83c-1.491 0-1.956.925-1.956 1.874v2.25h3.328l-.532 3.47h-2.796v8.385C19.612 23.027 24 18.062 24 12.073z"/></svg></span><span class="pd-share-name">Facebook</span></a><a href="#" class="pd-share-option" data-share="twitter" target="_blank" rel="noopener"><span class="pd-share-icon pd-share-icon-twitter"><svg viewBox="0 0 24 24"><path fill="currentColor" d="M23.953 4.57a10 10 0 01-2.825.775 4.958 4.958 0 002.163-2.723c-.951.555-2.005.959-3.127 1.184a4.92 4.92 0 00-8.384 4.482C7.69 8.095 4.067 6.13 1.64 3.162a4.822 4.822 0 00-.666 2.475c0 1.71.87 3.213 2.188 4.096a4.904 4.904 0 01-2.228-.616v.06a4.923 4.923 0 003.946 4.827 4.996 4.996 0 01-2.212.085 4.936 4.936 0 004.604 3.417 9.867 9.867 0 01-6.102 2.105c-.39 0-.779-.023-1.17-.067a13.995 13.995 0 007.557 2.209c9.053 0 13.998-7.496 13.998-13.985 0-.21 0-.42-.015-.63A9.935 9.935 0 0024 4.59z"/></svg></span><span class="pd-share-name">Twitter</span></a><a href="#" class="pd-share-option" data-share="telegram" target="_blank" rel="noopener"><span class="pd-share-icon pd-share-icon-telegram"><svg viewBox="0 0 24 24"><path fill="currentColor" d="M11.944 0A12 12 0 0 0 0 12a12 12 0 0 0 12 12 12 12 0 0 0 12-12A12 12 0 0 0 12 0a12 12 0 0 0-.056 0zm4.962 7.224c.1-.002.321.023.465.14a.506.506 0 0 1 .171.325c.016.093.036.306.02.472-.18 1.898-.962 6.502-1.36 8.627-.168.9-.499 1.201-.82 1.23-.696.065-1.225-.46-1.9-.902-1.056-.693-1.653-1.124-2.678-1.8-1.185-.78-.417-1.21.258-1.91.177-.184 3.247-2.977 3.307-3.23.007-.032.014-.15-.056-.212s-.174-.041-.249-.024c-.106.024-1.793 1.14-5.061 3.345-.48.33-.913.49-1.302.48-.428-.008-1.252-.241-1.865-.44-.752-.245-1.349-.374-1.297-.789.027-.216.325-.437.893-.663 3.498-1.524 5.83-2.529 6.998-3.014 3.332-1.386 4.025-1.627 4.476-1.635z"/></svg></span><span class="pd-share-name">Telegram</span></a><a href="#" class="pd-share-option" data-share="email"><span class="pd-share-icon pd-share-icon-email"><svg viewBox="0 0 24 24"><path fill="currentColor" d="M20 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm0 4l-8 5-8-5V6l8 5 8-5v2z"/></svg></span><span class="pd-share-name">Email</span></a><button type="button" class="pd-share-option" data-share="copy"><span class="pd-share-icon pd-share-icon-copy"><svg viewBox="0 0 24 24"><path fill="currentColor" d="M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z"/></svg></span><span class="pd-share-name">Salin Link</span></button><button type="button" class="pd-share-option" data-share="pdf"><span class="pd-share-icon pd-share-icon-pdf"><svg viewBox="0 0 24 24"><path fill="currentColor" d="M14 2H6c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V8l-6-6zm4 18H6V4h7v5h5v11zM8 15.5h1.5c.83 0 1.5-.67 1.5-1.5v-1c0-.83-.67-1.5-1.5-1.5H8v4zm6 0h1c1.1 0 2-.9 2-2v-2c0-1.1-.9-2-2-2h-1v6zm-4.5-1.5H8v-1h1.5v1zM14 13h1v1h-1v-1z"/></svg></span><span class="pd-share-name">Export PDF</span></button></div><div class="pd-share-copy-section"><div class="pd-share-copy-input-wrap"><input type="text" class="pd-share-copy-input" id="pd-share-url-input" value="https://hop.exchange/" readonly><button type="button" class="pd-share-copy-btn" id="pd-share-copy-url-btn"><svg viewBox="0 0 24 24" width="16" height="16"><path fill="currentColor" d="M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z"/></svg><span class="pd-share-copy-text">Salin</span></button></div></div></div></div></div>
13032
13033<style>.toast-root{position:fixed;left:50%;bottom:18px;transform:translateX(-50%);display:flex;flex-direction:column;gap:10px;z-index:99999;pointer-events:none;max-width:min(92vw,540px)}.toast{display:grid;grid-template-columns:28px 1fr auto;gap:12px;background:#0b1220;color:#eef3ff;border:1px solid rgba(255,255,255,.08);padding:12px 14px;border-radius:12px;box-shadow:0 10px 30px rgba(10,10,20,.35);pointer-events:auto;overflow:hidden}.toast .ico{align-self:start;margin-top:2px}.toast .ttl{font-weight:700;line-height:1.25;font-size:14px;margin-bottom:4px}.toast .msg{opacity:.95;line-height:1.45;font-size:13px}.toast .actions{display:flex;gap:8px;align-self:center}.toast .btn{background:#0ea5e9;color:#fff;border:0;border-radius:999px;padding:8px 12px;font-size:12px;font-weight:700;cursor:pointer}.toast .btn.alt{background:transparent;color:#8fb5ff;border:1px solid rgba(143,181,255,.35)}.toast .close{background:transparent;border:0;color:#98a2b3;cursor:pointer;padding:4px;margin-left:6px}.toast.success{border-left:4px solid #22c55e}.toast.info{border-left:4px solid #0ea5e9}.toast.warn{border-left:4px solid #C77DFF}.toast .progress{position:absolute;
13033left:0;bottom:0;height:3px;background:linear-gradient(90deg,#60a5fa,#22c55e);width:100%;transform-origin:left;animation:toastBar linear forwards}@keyframes toastBar{from{transform:scaleX(1)}to{transform:scaleX(0)}}@media(max-width:640px){.toast{grid-template-columns:24px 1fr auto;padding:12px}.toast .btn{padding:7px 10px}}</style>
13034<style>
13035.toast .msg { word-break: break-word; overflow-wrap: anywhere; }
13036
13037.toast-root { bottom: max(12px, env(safe-area-inset-bottom, 12px)); }
13038
13039@media (max-width: 540px) {
13040  .toast-root {
13041    left: 0; right: 0; transform: none;
13042    padding: 0 12px;
13043    bottom: calc(max(12px, env(safe-area-inset-bottom, 12px)) + var(--fab-offset, 72px));
13044    max-width: none;
13045  }
13046  .toast {
13047    grid-template-columns: 1fr; /* 1 kolom */
13048    position: relative;
13049    padding: 14px 14px 12px 14px;
13050    border-radius: 16px;
13051  }
13052  .toast .ico {
13053    position: absolute; left: 14px; top: 14px;
13054    margin: 0; transform: translateY(1px);
13055  }
13056  .toast .cnt { padding-left: 34px; }
13057  .toast .ttl { font-size: 15px; margin-bottom: 6px; }
13058  .toast .msg { font-size: 13px; opacity: .96; }
13059  .toast .actions {
13060    margin-top: 12px; gap: 10px; width: 100%;
13061    display: grid; grid-template-columns: 1fr 1fr;
13062  }
13063  .toast .btn { width: 100%; min-width: 0; padding: 10px 0; }
13064  .toast .close { position: absolute; right: 6px; top: 6px; }
13065}
13066</style>
13067
13068<script nonce="se3iyzEHMc9FQEB4wSyd0w==">
13069(function adjustToastFabOffset(){
13070  const root = document.getElementById('toastRoot');
13071  if (!root) return;
13072
13073  function isVisible(el){
13074    if (!el) return false;
13075    const cs = getComputedStyle(el);
13076    if (cs.display === 'none' || cs.visibility === 'hidden' || cs.opacity === '0') return false;
13077    const r = el.getBoundingClientRect();
13078    return r.width > 0 && r.height > 0;
13079  }
13080
13081  function update(){
13082    const fab = document.getElementById('pd-mobile-fab');
13083    let extra = 16;
13084    if (isVisible(fab)) {
13085      const h = Math.round(fab.getBoundingClientRect().height) || 56;
13086      extra = h + 16; // FAB height + margin
13087    }
13088    root.style.setProperty('--fab-offset', extra + 'px');
13089  }
13090
13091  window.addEventListener('resize', update, { passive: true });
13092  const fab = document.getElementById('pd-mobile-fab');
13093  if (window.ResizeObserver && fab) {
13094    const ro = new ResizeObserver(update);
13095    ro.observe(fab);
13096  }
13097  
13098  update();
13099})();
13100</script>
13100
13101<div class="toast-root" id="toastRoot" aria-live="polite" aria-atomic="true"></div>
13102
13103<script nonce="se3iyzEHMc9FQEB4wSyd0w==">(function(){const root=document.getElementById('toastRoot');function svgIcon(kind){if(kind==='success')return '<svg width="24" height="24" viewBox="0 0 24 24" fill="#22c55e"><path d="M9 16.2l-3.5-3.5 1.4-1.4L9 13.4l7.7-7.7 1.4 1.4z"/></svg>';if(kind==='warn')return '<svg width="24" height="24" viewBox="0 0 24 24" fill="#f59e0b"><path d="M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z"/></svg>';return '<svg width="24" height="24" viewBox="0 0 24 24" fill="#0ea5e9"><path d="M11 7h2v2h-2zm0 4h2v6h-2z"/><path d="M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10 10-4.5 10-10S17.5 2 12 2z" fill="none" stroke="#0ea5e9"/></svg>'}
13104window.showToast=function(opts){const o=Object.assign({title:'',message:'',type:'info',duration:4000,actions:[]},opts||{});const el=document.createElement('div');el.className='toast '+(o.type||'info');el.setAttribute('role','status');el.style.position='relative';const acts=(o.actions||[]).map(a=>{const lab=a.label||'OK';const cls='btn'+(a.variant==='alt'?' alt':'');return `<button type="button" class="${cls}" data-act="${lab}">${lab}</button>`}).join('');el.innerHTML=`<div class="ico" aria-hidden="true">${svgIcon(o.type)}</div><div class="cnt">${o.title?`<div class="ttl">${o.title}</div>`:''}${o.message?`<div class="msg">${o.message}</div>`:''}</div><div class="actions">${acts}</div><button type="button" class="close" aria-label="Tutup" title="Tutup"><svg width="18" height="18" viewBox="0 0 24 24"><path fill="currentColor" d="M18.3 5.71L12 12.01l-6.3-6.3-1.4 1.41 6.3 6.3-6.3 6.3 1.4 1.41 6.3-6.3 6.3 6.3 1.41-1.41-6.3-6.3 6.3-6.3z"/></svg></button><div class="progress" style="animation-duration:${Math.max(1500,o.duration)}ms"></div>`;
13105
13106    const close = ()=> {
13107      if (!el.parentNode) return;
13108      el.style.transition = 'transform .2s ease, opacity .2s ease';
13109      el.style.opacity = '0'; el.style.transform = 'translateY(10px)';
13110      setTimeout(()=>{ if (el.parentNode) el.parentNode.removeChild(el); }, 220);
13111    };
13112
13113    el.querySelector('.close').addEventListener('click', close);
13114    el.querySelectorAll('.actions .btn').forEach(btn=>{
13115      btn.addEventListener('click', ()=>{
13116        const lab = btn.getAttribute('data-act');
13117        try {
13118          (o.actions||[]).forEach(a=>{ if (a.label===lab && typeof a.onClick==='function') a.onClick(); });
13119        } catch(_){}
13120        close();
13121      });
13122    });
13123
13124    root.appendChild(el);
13125    setTimeout(close, o.duration);
13126    return el;
13127  };
13128})();
13129
13130const _0x1a2b=[{"url":"https://img.tongat.cc/uploads/pasti-jaackpot-judimpo.jpg","alt":"Lenovo Legion Go 8ASP2 - 83N0000RID /AMD Ryzen Z2 Extreme/32GB/1TB SSD/AMD Radeon Graphics/8.8\" WUXGA OLED Touch/Win 11 Home/Eclipse Black/3Y","slug":""},{"url":"https://img.tongat.cc/uploads/pasti-jaackpot-judimpo.jpg","alt":"Lenovo Lenovo Legion Go 8ASP2 - 83N0000RID /AMD Ryzen Z2 Extreme/32GB/1TB SSD/AMD Radeon Graphics/8.8\" WUXGA OLED Touch/Wi...","slug":"https://img.tongat.cc/uploads/pasti-jaackpot-judimpo.jpg"},{"url":"https://img.tongat.cc/uploads/pasti-jaackpot-judimpo.jpg","alt":"Lenovo Lenovo Legion Go 8ASP2 - 83N0000RID /AMD Ryzen Z2 Extreme/32GB/1TB SSD/AMD Radeon Graphics/8.8\" WUXGA OLED Touch/Wi...","slug":"lenovo-legion-go-8asp2-83n0000rid-ryzen-z2-extreme-amd-radeon-graphics-eclipse-b-1761796941-223.webp"},{"url":"https://img.tongat.cc/uploads/pasti-jaackpot-judimpo.jpg","alt":"Lenovo Lenovo Legion Go 8ASP2 - 83N0000RID /AMD Ryzen Z2 Extreme/32GB/1TB SSD/AMD Radeon Graphics/8.8\" WUXGA OLED Touch/Wi...","slug":"lenovo-legion-go-8asp2-83n0000rid-ryzen-z2-extreme-amd-radeon-graphics-eclipse-b-1761796941-776.webp"},{"url":"https://img.tongat.cc/uploads/pasti-jaackpot-judimpo.jpg","alt":"Lenovo Lenovo Legion Go 8ASP2 - 83N0000RID /AMD Ryzen Z2 Extreme/32GB/1TB SSD/AMD Radeon Graphics/8.8\" WUXGA OLED Touch/Wi...","slug":"lenovo-legion-go-8asp2-83n0000rid-ryzen-z2-extreme-amd-radeon-graphics-eclipse-b-1761796941-634.webp"},{"url":"https://img.tongat.cc/uploads/pasti-jaackpot-judimpo.jpg","alt":"Lenovo Lenovo Legion Go 8ASP2 - 83N0000RID /AMD Ryzen Z2 Extreme/32GB/1TB SSD/AMD Radeon Graphics/8.8\" WUXGA OLED Touch/Wi...","slug":"lenovo-legion-go-8as
13130p2-83n0000rid-ryzen-z2-extreme-amd-radeon-graphics-eclipse-b-1761796941-892.webp"}],_0x3c4d="Lenovo Legion Go 8ASP2 - 83N0000RID /AMD Ryzen Z2 Extreme/32GB/1TB SSD/AMD Radeon Graphics/8.8\" WUXGA OLED Touch/Win 11 Home/Eclipse Black/3Y",_0x5e6f="SB0B3T";function getVariantSummaryText(){const a=document.getElementById('pd-variant-summary');if(!a)return '';const b=Array.from(a.querySelectorAll('.vs-item strong')).map(c=>c.textContent.trim()).filter(Boolean);return b.length?b.join(' / '):''}
13131function encodeVariantHash(id){if(!id||id<=0)return '';const xor=id^0x4A5D;return xor.toString(36)}
13132function decodeVariantHash(hash){if(!hash)return 0;const xor=parseInt(hash,36);return isNaN(xor)?0:xor^0x4A5D}
13133
13134function showSuccessToast(productId,qty,variantId){const variantText=getVariantSummaryText();const skuText=(function(){const el=document.getElementById('pd-sku');return el?el.textContent.trim():PD_SKU})();showToast({type:'warn',title:'Fitur Segera Hadir',message:`<strong>${escapeHtml(PD_NAME)}</strong>${variantText?` · <em>${escapeHtml(variantText)}</em>`:''}<br>SKU: ${escapeHtml(skuText)} · Qty: ${qty}`,duration:5000,actions:[{label:'Lihat Keranjang',onClick:()=>{}},{label:'Lanjut Belanja',variant:'alt',onClick:()=>{}}]});try{if(window.ga4Ecomm){const qtySend=qty||1;window.ga4Ecomm.addToCart({currency:'IDR',price:20789000,quantity:qtySend,item_id:"SB0B3T",item_name:"Lenovo Legion Go 8ASP2 - 83N0000RID /AMD Ryzen Z2 Extreme/32GB/1TB SSD/AMD Radeon Graphics/8.8\" WUXGA OLED Touch/Win 11 Home/Eclipse Black/3Y",item_brand:"Lenovo ",item_category:(["Komputer & Laptop","Laptop","Gaming"]||[]).join(' / ')})}}catch(_){}return false}function showErrorToast(){showToast({type:'error',title:'Gagal Menambah ke Keranjang',message:'Terjadi kesalahan saat memproses permintaan. Silakan coba lagi.',duration:5000})}
13135
13136function executeBuyNowLegacy(id,variantId){const a=getVariantSummaryText(),b=(function(){const c=document.getElementById('pd-sku');return c?c.textContent.trim():_0x5e6f})();
13137
13138    let willRedirect = false;
13139    try {
13140        if (window.addToCart) {
13141            window.addToCart(id, 1, variantId);
13142            willRedirect = false;
13143        }
13144    } catch(_){}
13145
13146    if (willRedirect) {
13147        showToast({
13148            type: 'info',
13149            title: 'Menuju Keranjang',
13150            message: `<strong>${escapeHtml(PD_NAME)}</strong>${variantText?` · <em>${escapeHtml(variantText)}</em>`:''}<br>SKU: ${escapeHtml(skuText)} · Qty: 1`,
13151            duration: 1800
13152        });
13153        setTimeout(()=>{ window.location.href='/keranjang'; }, 1200);
13154    } else {
13155        showToast({
13156            type: 'warn',
13157            title: 'Fitur Beli Langsung Segera Hadir',
13158            message: `Sementara ini Anda bisa menambahkan produk ke keranjang terlebih dahulu.<br><strong>${escapeHtml(PD_NAME)}</strong>${variantText?` · <em>${escapeHtml(variantText)}</em>`:''}`,
13159            duration: 6000,
13160            actions: [
13161                { label: '+ Keranjang', onClick: ()=> { try{ if (window.addToCart) window.addToCart(id,1,variantId); }catch(_){} } },
13162                { label: 'Hubungi CS', variant: 'alt', onClick: ()=> { window.open('https://wa.me/6281380009898','_blank'); } }
13163            ]
13164        });
13165    }
13166}
13167
13168document.addEventListener('DOMContentLoaded',function(){var a=document.getElementById('pd-buy-form');if(a){a.addEventListener('submit',function(e){var b=parseInt(a.getAttribute('data-pid'),10)||0;if(window.addToCartSubmit){return window.addToCartSubmit(e,b)}})}});document.addEventListener('DOMContentLoaded',function(){var a=document.getElementById('btn-buy');if(a){a.addEventListener('click',function(){var b=a.getAttribute('data-id');buyNow(b)})}});
13169
13170function _0x2m3n(s){return String(s||'').replace(/[&<>"']/g,m=>({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#039;'}[m]))}
13171
13172(function initGallery(){const mainImg=document.getElementById('pd-main-img');const gallery=document.getElementById('pd-thumb-gallery');if(!mainImg||!gallery)return;gallery.addEventListener('click',function(ev){const btn=ev.target.closest('.pd-thumb-btn');if(!btn)return;const full=btn.getAttribute('data-full');if(full){mainImg.src=full;const alt=btn.getAttribute('data-alt')||'';if(alt)mainImg.alt=alt;const slug=btn.getAttribute('data-slug')||'';if(slug)mainImg.dataset.slug=slug;gallery.querySelectorAll('.pd-thumb-btn').forEach(b=>b.classList.remove('active'));btn.classList.add('active')}})})();
13173
13174(function initMobileSliderCounter(){const slider=document.getElementById('pd-mobile-slider');const counter=document.getElementById('pd-gallery-counter');if(!slider||!counter)return;let ticking=false;slider.addEventListener('scroll',function(){if(!ticking){window.requestAnimationFrame(function(){const slides=slider.querySelectorAll('.pd-mslide');if(!slides.length)return;const containerRect=slider.getBoundingClientRect();const containerCenter=containerRect.left+containerRect.width/2;let currentIdx=0;let minDist=Infinity;
13174slides.forEach((slide,idx)=>{const slideRect=slide.getBoundingClientRect();const slideCenter=slideRect.left+slideRect.width/2;const dist=Math.abs(slideCenter-containerCenter);if(dist<minDist){minDist=dist;currentIdx=idx}});counter.textContent=(currentIdx+1)+'/'+slides.length;ticking=false});ticking=true}},{passive:true})})();
13175
13176/* ================= Simulasi Cicilan ================= */
13177(function initInstallmentList(){const card=document.getElementById('inst-card');if(!card)return;function getBasePrice(){return parseInt(card.getAttribute('data-base-price')||'0',10)||0}function setBasePrice(v){card.setAttribute('data-base-price',String(parseInt(v||'0',10)||0))}const zeroEligible=card.getAttribute('data-zero-smart')==='1';window.initMobile=zeroEligible;const listEl=document.getElementById('inst-month-list');const zeroNote=document.getElementById('inst-zero-note');const tenors=[3,6,12];const rates={BRI:{3:0.975,6:0.975,12:0.975},Mandiri:{3:0.984,6:0.9725,12:0.96},BCA:{3:0.97,6:0.94,12:0.91}};function formatRupiah(num){return 'Rp '+(Math.round(num)).toString().replace(/\B(?=(\d{3})+(?!\d))/g,'.')}function activeBank(){const tab=card.querySelector('.bank-tab.active');return tab?tab.dataset.bank:'BRI'}
13178
13179function _0x4o5p(bank){const a=getBasePrice();listEl.innerHTML='';const b=rates[bank]||{};let c=false;tenors.forEach(m=>{let d=b[m]??1;if(zeroEligible&&(bank==='BRI'||bank==='Mandiri')){d=1;c=true}const e=a/d;const f=m>0?Math.ceil((e/m)/100)*100:0;const g=document.createElement('li');g.className='inst-month-item';g.innerHTML=`<span class="tenor-badge">${m}x</span><span class="amount">${formatRupiah(f)} / bln</span>${zeroEligible&&(bank==='BRI'||bank==='Mandiri')?'<span class="tag tag-zero">0%</span>':''}`;listEl.appendChild(g)});zeroNote.style.display=c?'block':'none'}
13180
13181card.addEventListener('click',function(ev){const a=ev.target.closest('.bank-tab');if(!a)return;card.querySelectorAll('.bank-tab').forEach(b=>{b.classList.remove('active');b.setAttribute('aria-selected','false')});a.classList.add('active');a.setAttribute('aria-selected','true');_0x4o5p(a.dataset.bank)});
13182
13183window.instSetBasePrice=function(newPrice){setBasePrice(newPrice);_0x4o5p(activeBank())};_0x4o5p(activeBank());
13184})();
13185
13186/* ====== Fokus gambar varian ====== */
13187function _0x6q7r(s){return String(s||'').toLowerCase().replace(/[^a-z0-9]+/g,'')}function _0x8s9t(u){try{return new URL(u,window.location.origin).pathname.split('/').pop().toLowerCase()}catch(e){try{return(u||'').split('/').pop().toLowerCase()}catch(_){return ''}}}
13188function _0xau1v(url,altOpt){const a=document.getElementById('pd-main-img'),b=document.getElementById('pd-thumb-gallery'),c=document.getElementById('pd-mobile-slider');if(a&&url){a.src=url;if(altOpt)a.alt=altOpt}if(b){const d=_0x8s9t(url);let e=null;b.querySelectorAll('.pd-thumb-btn').forEach(btn=>{const f=btn.getAttribute('data-full')||'',g=_0x8s9t(f)===d;if(g)e=btn;btn.classList.toggle('active',g)});if(e){const h=e.getAttribute('data-alt')||'',i=e.getAttribute('data-slug')||'';if(h&&a)a.alt=h;if(i&&a)a.dataset.slug=i}}
13189  if (c){
13190    const targetName = _0x8s9t(url);
13191    const slideImg = Array.from(c.querySelectorAll('img')).find(im => _0x8s9t(im.src) === targetName);
13192    if (slideImg){
13193      
13194      try {
13195        const container = c;
13196        const imgRect = slideImg.getBoundingClientRect();
13197        const contRect = container.getBoundingClientRect();
13198        const offsetLeft = slideImg.offsetLeft - container.offsetLeft;
13199        const center = offsetLeft - (container.clientWidth - slideImg.clientWidth) / 2;
13200        container.scrollTo({ left: Math.max(0, center), behavior: 'smooth' });
13201      } catch(_){
13202        
13203        slideImg.scrollIntoView({ behavior:'smooth', inline:'center', block:'nearest' });
13204      }
13205    }
13206  }
13207}
13208function findImageForVariant(variant){
13209  if (!variant || !variant.attrs) return null;
13210  const tokens = [];
13211  try{
13212    Object.values(variant.attrs).forEach(v=>{
13213      if (!v) return;
13214      const raw = String(v);
13215      tokens.push(raw);
13216      tokens.push(normalize(raw));
13217    });
13218  }catch(_){}
13219  if (variant.sku){
13220    tokens.push(String(variant.sku));
13221    tokens.push(normalize(String(variant.sku)));
13222  }
13223  if (variant.image_url) {
13224      tokens.push(String(variant.image_url));
13225  }
13226  let best = null;
13227  let bestScore = -1;
13228
13229  for (const g of (galleryData||[])){
13230    const slugN = normalize(g.slug||'');
13231    const altN  = normalize(g.alt||'');
13232    const file  = _0x8s9t(g.url||'');
13233    const fileN = normalize(file);
13234    const imgU  = g.url;
13235
13236    for (const t of tokens){
13237      const tN = normalize(t);
13238      if (!tN) continue;
13239
13240      let score = -1;
13241      if (imgU === tN) score = 300;
13242      if (slugN && slugN === tN) score = 300;
13243      else if (fileN && fileN.includes(tN)) score = 200;
13244      else if (altN && altN.includes(tN)) score = 120;
13245
13246      if (score > bestScore){
13247        bestScore = score;
13248        best = g;
13249      }
13250      if (bestScore >= 300) break;
13251    }
13252    if (bestScore >= 300) break;
13253  }
13254  return bestScore >= 120 ? best : null;
13255}
13256function _0xey3z(variant){const a=_0xcw2x(variant);if(a&&a.url){_0xau1v(a.url,a.alt||'')}}
13257
13258/* ====== Layout mobile ====== */
13259(function _0xg04h(){const a=document.querySelector('.pd-media-card'),b=document.getElementById('pd-price-block'),c=document.getElementById('pd-price-anchor'),d=document.querySelector('.pd-info-card'),e=document.getElementById('pd-title'),f=document.getElementById('pd-variant-combined'),g=document.getElementById('pd-variants'),h=document.getElementById('pd-variants-anchor'),i=document.getElementById('pd-variant-summary'),j=document.getElementById('pd-summary-anchor'),titleRow=document.querySelector('.pd-title-row'),promoBanner=document.querySelector('.promo-endyear-mini-banner'),compareSection=document.querySelector('.pd-compare-section');if(!a||!b||!c||!d||!e)return;
13260
13261    let pricePlaced = false;
13262    let varPlaced = false;
13263    let titlePlaced = false;
13264    let promoPlaced = false;
13265    const mq = window.matchMedia('(max-width: 640px)');
13266
13267    function apply(){
13268        if (mq.matches) {
13269            if (!titlePlaced && a && titleRow && d.contains(titleRow)) { try{a.appendChild(titleRow);titlePlaced=true;}catch(_){} }
13270            if (!pricePlaced && a && b) { try{a.appendChild(b);pricePlaced=true;}catch(_){} }
13271            if (!varPlaced && f && d && e) {
13272                try{
13273                    f.hidden = false;
13274                    if (i && !f.contains(i)) f.appendChild(i);
13275                    if (g && !f.contains(g)) f.appendChild(g);
13276                    if(d.contains(e))d.insertBefore(f, e);
13277                    varPlaced = true;
13278                }catch(_){}
13279            }
13280            if (!promoPlaced && promoBanner && compareSection && compareSection.parentNode) {
13281                try{
13282                    compareSection.parentNode.insertBefore(promoBanner, compareSection);
13283                    promoPlaced = true;
13284                }catch(_){}
13285            }
13286        } else {
13287            if (titlePlaced && titleRow && d) {
13288                try{
13289                    const vcombined = document.getElementById('pd-variant-combined');
13290                    if (vcombined && d.contains(vcombined)) {
13291                        d.insertBefore(titleRow, vcombined);
13292                    } else {
13293                        d.insertBefore(titleRow, d.firstChild);
13294                    }
13295                    titlePlaced=false;
13296                }catch(_){}
13297            }
13298            if (pricePlaced && b && c && c.parentNode) {
13299                try{c.parentNode.insertBefore(b, c.nextSibling);pricePlaced=false;}catch(_){}
13300            }
13301            if (varPlaced) {
13302                try{
13303                    if (i && j && j.parentNode && !j.parentNode.contains(i)) j.parentNode.insertBefore(i, j.nextSibling);
13304                    if (g && h && h.parentNode && !h.parentNode.contains(g)) h.parentNode.insertBefore(g, h.nextSibling);
13305                    if (f) { f.hidden = true; f.innerHTML = ''; }
13306                    varPlaced = false;
13307                }catch(_){}
13308            }
13309            if (promoPlaced && promoBanner && b) {
13310                try{
13311                    b.appendChild(promoBanner);
13312                    promoPlaced = false;
13313                }catch(_){}
13314            }
13315        }
13316    }
13317
13318    mq.addEventListener ? mq.addEventListener('change', apply) : mq.addListener(apply);
13319    apply();
13320
13321    const fab = document.getElementById('pd-mobile-fab');
13322    if (fab) {
13323        const pid = parseInt(fab.getAttribute('data-pid')||'0',10) || 325;
13324        const btnCart = document.getElementById('mf-cart');
13325
13326        if (btnCart) btnCart.addEventListener('click', function(){
13327            const varInput = document.getElementById('pd-variant-id');
13328            const variantId = varInput ? parseInt(varInput.value||'0',10) : 0;
13329            try { if (window.addToCart) addToCart(pid, 1, variantId); } catch(_){}
13330            const variantText = getVariantSummaryText();
13331            const skuText = (function(){ const el=document.getElementById('pd-sku'); return el?el.textContent.trim():PD_SKU; })();
13332            showToast({
13333                type: 'success',
13334                title: 'Berhasil ditambahkan ke Keranjang',
13335                message: `<strong>${escapeHtml(PD_NAME)}</strong>${variantText?` · <em>${escapeHtml(variantText)}</em>`:''}<br>SKU: ${escapeHtml(skuText)} · Qty: 1`,
13336                duration: 5000,
13337                actions: [
13338                    { label: 'Lihat Keranjang', onClick: ()=> { window.location.href = '/keranjang'; } },
13339                    { label: 'Lanjut Belanja', variant: 'alt', onClick: ()=>{} }
13340                ]
13341            });
13342        });
13343    }
13344})();
13345
13346/* ====== Auto-hide installment banner if sidebar too tall (Desktop only) ====== */
13347(function(){
13348    function adjustSidebarBanner() {
13349        if (window.innerWidth <= 768) return;
13350        const sidebar = document.querySelector('.pd-sidebar');
13351        const infoCard = document.querySelector('.pd-info-card');
13352        const banner = document.querySelector('.pd-side-card.inst-alt-banner.inst-alt-banner--compact');
13353        if (!sidebar || !infoCard || !banner) return;
13354        const sidebarHeight = sidebar.offsetHeight;
13355        const infoCardHeight = infoCard.offsetHeight;
13356        if (sidebarHeight > infoCardHeight) {
13357            banner.style.display = 'none';
13358        } else {
13359            banner.style.display = '';
13360        }
13361    }
13362    if (document.readyState === 'loading') {
13363        document.addEventListener('DOMContentLoaded', adjustSidebarBanner);
13364    } else {
13365        adjustSidebarBanner();
13366    }
13367    let resizeTimer;
13368    window.addEventListener('resize', function() {
13369        clearTimeout(resizeTimer);
13370        resizeTimer = setTimeout(adjustSidebarBanner, 250);
13371    });
13372    const pwpSection = document.getElementById('pwp-deals-section');
13373    if (pwpSection) {
13374        const observer = new MutationObserver(function(mutations) {
13375            let shouldRecheck = false;
13376            mutations.forEach(function(mutation) {
13377                if (mutation.type === 'attributes' && mutation.attributeName === 'hidden') {
13378                    shouldRecheck = true;
13379                } else if (mutation.type === 'childList' && mutation.addedNodes.length > 0) {
13380                    shouldRecheck = true;
13381                }
13382            });
13383            if (shouldRecheck) {
13384                setTimeout(adjustSidebarBanner, 100);
13385            }
13386        });
13387        observer.observe(pwpSection, {
13388            attributes: true,
13389            childList: true,
13390            subtree: true
13391        });
13392    }
13393    window.adjustSidebarBanner = adjustSidebarBanner;
13394})();
13395
13396/* ====== Global constants ====== */
13397const IS_DIGITAL=false;
13398const IS_PREORDER=false;
13399
13400/* ====== Variants state (REVISED) ====== */
13401(function initVariants(){
13402const _0x7g8h=[];window.variants=_0x7g8h;
13403window.isPreorderProduct=false;
13404    const attrOrder = [];
13405
13406    if (!variants.length || !attrOrder.length) return;
13407
13408    function comboKey(sel){
13409        return attrOrder.map(a => a + '=' + (sel[a] ?? '')).join('|');
13410    }
13411
13412    const variantMap = {};
13413    variants.forEach(v=>{
13414        const key = comboKey(v.attrs);
13415        variantMap[key] = v;
13416    });
13417
13418    function readSelection(){
13419        const sel = {};
13420        attrOrder.forEach(a=>{
13421            const r = document.querySelector(`.v-group[data-attr="${CSS.escape(a)}"] input[type=radio]:checked`);
13422            sel[a] = r ? r.value : '';
13423        });
13424        return sel;
13425    }
13426
13427    function findVariant(sel){
13428        return variantMap[comboKey(sel)] || null;
13429    }
13430
13431    function autoFillMissing(sel){
13432        let changed = false;
13433        for (const a of attrOrder) {
13434            if (sel[a]) continue;
13435            const possible = [];
13436            const seen = new Set();
13437            variants.forEach(v=>{
13438                let ok = true;
13439                for (const a2 of attrOrder) {
13440                    if (a2 === a) continue;
13441                    if (sel[a2] && v.attrs[a2] !== sel[a2]) { ok = false; break; }
13442                }
13443                if (ok) {
13444                    const val = v.attrs[a];
13445                    if (!seen.has(val)) { seen.add(val); possible.push(val); }
13446                }
13447            });
13448            if (possible.length === 1) {
13449                const val = possible[0];
13450                const input = document.querySelector(`.v-group[data-attr="${CSS.escape(a)}"] input[type=radio][value="${CSS.escape(val)}"]`);
13451                if (input && !input.checked) { input.checked = true; sel[a] = val; changed = true; }
13452            }
13453        }
13454        return changed;
13455    }
13456
13457    function rupiah(n){
13458        n = parseInt(n||0,10)||0;
13459        return 'Rp ' + n.toString().replace(/\B(?=(\d{3})+(?!\d))/g,'.');
13460    }
13461    
13462    function focusGalleryByUrl(imageUrl) {
13463        const isMobile = window.matchMedia && window.matchMedia('(max-width: 640px)').matches;
13464          if (isMobile) {
13465            _0xau1v(imageUrl);
13466            return;
13467          }
13468        
13469          const gallery = document.getElementById('pd-thumb-gallery');
13470          const targetName = _0x8s9t(imageUrl);
13471        
13472          if (gallery) {
13473            const btns = Array.from(gallery.querySelectorAll('.pd-thumb-btn'));
13474            const btn = btns.find(b => _0x8s9t(b.getAttribute('data-full') || '') === targetName);
13475            if (btn) { btn.click(); return; }
13476          }
13477          
13478          _0xau1v(imageUrl);
13479    }
13480    
13481
13482function formatStockLabel(n){n=parseInt(n||0,10)||0;return(n>10)?'10+':String(n)}
13483function updateBranchPopover(v){try{if(!v)return;const a=document.getElementById('sp-qty-meg'),b=document.getElementById('sp-qty-mdf'),c=document.getElementById('sp-qty-bda');if(a)a.textContent=formatStockLabel(Math.max(0,v.smm|0));if(b)b.textContent=formatStockLabel(Math.max(0,v.smf|0));if(c)c.textContent=formatStockLabel(Math.max(0,v.sba|0))}catch(_){}}
13484
13485    function calcVoucherDisc(type,value,price,maxDisc){if(type==='PERCENTAGE'){let d=(price*value)/100;if(maxDisc>0&&d>maxDisc)d=maxDisc;return Math.round(d)}return Math.round(value)}
13486
13487    function applyVariant(v, focusImage = true){
13488        const elCur  = document.getElementById('pd-price-current');
13489        const elOri  = document.getElementById('pd-price-original');
13490        const elDisc = document.getElementById('pd-discount-badge');
13491        const elSku  = document.getElementById('pd-sku');
13492        const elStock= document.getElementById('pd-stock-badge');
13493        const elQty  = document.getElementById('qty');
13494        const btnAdd = document.getElementById('btn-add-cart');
13495        const btnBuy = document.getElementById('btn-buy');
13496        const hidVar = document.getElementById('pd-variant-id');
13497
13498        const mfCart= document.getElementById('mf-cart');
13499        const mfBuy = document.getElementById('mf-buy');
13500        const fab = document.getElementById('pd-mobile-fab');
13501
13502        if (hidVar) hidVar.value = v ? v.id : 0;
13503        if (elCur) elCur.textContent = rupiah(v ? v.final : 0);
13504        if (elSku && v && v.sku) elSku.textContent = v.sku;
13505
13506        if (v && v.ori > v.final) {
13507            if (elOri) { elOri.style.display='inline'; elOri.textContent = rupiah(v.ori); }
13508            if (elDisc) { elDisc.style.display='inline'; elDisc.textContent = '-' + (v.disc||0) + '%'; }
13509        } else {
13510            if (elOri) elOri.style.display='none';
13511            if (elDisc) elDisc.style.display='none';
13512        }
13513
13514        const stock = v ? (parseInt(v.stock||0,10)||0) : 0;
13515        let effectiveStock = stock;
13516        let isActivePreorder = false;
13517        if (window.isPreorderProduct && v && 'preorder_remaining' in v && v.preorder_remaining !== null) {
13518            effectiveStock = parseInt(v.preorder_remaining, 10);
13519            if (isNaN(effectiveStock)) effectiveStock = 0;
13520            isActivePreorder = true;
13521        }
13522        if (elStock){
13523            elStock.classList.remove('in','out');
13524            if (effectiveStock>0){ 
13525                elStock.classList.add('in'); 
13526                elStock.textContent = IS_DIGITAL ? 'Tersedia' : (isActivePreorder ? 'Sisa Slot: ' + effectiveStock : 'Stok: ' + formatStockLabel(effectiveStock)); 
13527            } else { 
13528                elStock.classList.add('out'); 
13529                elStock.textContent = 'Habis'; 
13530            }
13531        }
13532        if (elQty){
13533            elQty.max = String(effectiveStock>0?effectiveStock:0);
13534            if (effectiveStock<=0) { elQty.value = '0'; elQty.disabled = true; }
13535            else { if (parseInt(elQty.value||'1',10) < 1) elQty.value='1'; elQty.disabled=false; }
13536        }
13537        
13538        const shouldDisable = !(v && effectiveStock>0);
13539        const updateButtons = () => {
13540            const btnAddCart = document.getElementById('btn-add-cart');
13541            const btnBuyNow = document.getElementById('btn-buy');
13542            const mobileCart = document.getElementById('mf-cart');
13543            const mobileBuy = document.getElementById('mf-buy');
13544            [btnAddCart, btnBuyNow, mobileCart, mobileBuy].forEac
13544h(btn => {
13545                if (!btn) return;
13546                if (shouldDisable) {
13547                    btn.disabled = true;
13548                    btn.setAttribute('disabled', 'disabled');
13549                    btn.classList.add('stock-disabled');
13550                    btn.setAttribute('data-stock-blocked', 'true');
13551                    btn.setAttribute('data-stock-reason', window.isPreorderProduct ? 'Pre-order habis' : 'Stok habis');
13552                } else {
13553                    btn.disabled = false;
13554                    btn.removeAttribute('disabled');
13555                    btn.classList.remove('stock-disabled');
13556                    btn.removeAttribute('data-stock-blocked');
13557                    btn.removeAttribute('data-stock-reason');
13558                }
13559            });
13560        };
13561        updateButtons();
13562        setTimeout(updateButtons, 10);
13563        setTimeout(updateButtons, 50);
13564        setTimeout(updateButtons, 100);
13565        if (mfBuy && v) {
13566            const voucherBtn = document.getElementById('btn-buy-voucher');
13567            const voucherCode = fab ? fab.dataset.voucherCode : '';
13568            let voucherDiscount = 0;
13569            
13570            if (voucherBtn && voucherCode) {
13571                const vType = voucherBtn.dataset.voucherType;
13572                const vValue = parseFloat(voucherBtn.dataset.voucherValue) || 0;
13573                const vMax = parseFloat(voucherBtn.dataset.voucherMax) || 0;
13574                const finalPrice = v.final || 0;
13575                if (vType && vValue > 0) {
13576                    voucherDiscount = calcVoucherDisc(vType, vValue, finalPrice, vMax);
13577                    if (fab) fab.dataset.voucherValue = voucherDiscount.toString();
13578                }
13579            }
13580            
13581            const finalPrice = v.final || 0;
13582            const textEl = mfBuy.querySelector('.mf-buy-text');
13583            const priceEl = mfBuy.querySelector('.mf-buy-price');
13584            
13585            if (effectiveStock > 0) {
13586                    if (IS_PREORDER) {
13587                        if (textEl) textEl.textContent = 'Pre Order Sekarang';
13588                        if (priceEl) priceEl.textContent = rupiah(finalPrice);
13589                    } else if (voucherCode && voucherDiscount > 0) {
13590                        if (textEl) textEl.textContent = 'Beli dengan Voucher';
13591                        if (priceEl) priceEl.textContent = rupiah(Math.max(0, finalPrice - voucherDiscount));
13592                    } else {
13593                        if (textEl) textEl.textContent = 'Beli Sekarang';
13594                        if (priceEl) priceEl.textContent = rupiah(finalPrice);
13595                    }
13596                } else {
13597                    if (textEl) textEl.textContent = 'Stok Habis';
13598                    if (priceEl) priceEl.textContent = rupiah(finalPrice);
13599                }
13600            }
13601        
13602        const isMobile = window.initMobile ?? 0;
13603        if (window.instSetBasePrice) window.instSetBasePrice(v ? (isMobile == '1' ? v.ori : v.final) : 0);
13604        if (window.updateSoldBySku) window.updateSoldBySku(v.sku);
13605        updateBranchPopover(v);
13606        if (v && v.image_url && focusImage) focusGalleryByUrl(v.image_url);
13607        if (v) {
13608            window.dispatchEvent(new CustomEvent('pd-variant-changed', {
13609                detail: {
13610                    price: v.final,
13611                    originalPrice: v.ori,
13612                    discount: v.disc,
13613                    stock: effectiveStock,
13614                    sku: v.sku,
13615                    variant_id: v.id
13616                }
13617            }));
13618            
13619            const encodedHash = encodeVariantHash(v.id);
13620            if (encodedHash && window.history && window.history.replaceState) {
13621                const newHash = '#v=' + encodedHash;
13622                const newUrl = window.location.pathname + window.location.search + newHash;
13623                window.history.replaceState(null, '', newUrl);
13624            }
13625        }
13626    }
13627
13628    let sel = readSelection();
13629    if (autoFillMissing(sel)) sel = readSelection();
13630
13631    let v = findVariant(sel);
13632    if (!v) {
13633        const candidates = variants.filter(variant=>{
13634            return attrOrder.every(a=>{
13635                if (!sel[a]) return true;
13636                return variant.attrs[a] === sel[a];
13637            });
13638        });
13639        if (candidates.length >= 1) {
13640            v = candidates[0];
13641            attrOrder.forEach(a=> sel[a] = v.attrs[a]);
13642            attrOrder.forEach(a=>{
13643                const val = sel[a];
13644                const input = document.querySelector(`.v-group[data-attr="${CSS.escape(a)}"] input[type=radio][value="${CSS.escape(val)}"]`);
13645                if (input) input.checked = true;
13646            });
13647        }
13648    }
13649
13650    const initSel = readSelection();
13651    const initVar = findVariant(initSel) || variants[0] || null;
13652    if (document.readyState === 'loading') {
13653        document.addEventListener('DOMContentLoaded', () => applyVariant(initVar, false));
13654    } else {
13655        applyVariant(initVar, false);
13656    }
13657    
13658function updateSummary(sel){Object.entries(sel).forEach(([a,val])=>{const el=document.getElementById('vs-'+a);if(el)el.textContent=val||'-'})}
13659    function refreshOptions(sel){
13660        attrOrder.forEach(a=>{
13661            const group = document.querySelector(`.v-group[data-attr="${CSS.escape(a)}"]`);
13662            if (!group) return;
13663            const chips = group.querySelectorAll('.v-chip');
13664            chips.forEach(ch=>{
13665                const val = ch.getAttribute('data-value');
13666                const possible = variants.some(v=>{
13667                    if (v.attrs[a] !== val) return false;
13668                    for (const a2 of attrOrder) {
13669                        if (a2 === a) continue;
13670                        if (sel[a2] && v.attrs[a2] !== sel[a2]) return false;
13671                    }
13672                    return true;
13673                });
13674                const input = ch.querySelector('input[type=radio]');
13675                const disabled = !possible;
13676                if (input) input.disabled = disabled;
13677                ch.classList.toggle('disabled', disabled);
13678
13679                let candidateVariant = null;
13680                if (possible) {
13681                    candidateVariant = variants.find(v=>{
13682                        if (v.attrs[a] !== val) return false;
13683                        for (const a2 of attrOrder) {
13684                            if (a2 === a) continue;
13685                            if (sel[a2] && v.attrs[a2] !== sel[a2]) return false;
13686                        }
13687                        return true;
13688                    });
13689                }
13690                const outOfStock = candidateVariant ? (window.isPreorderProduct && candidateVariant.preorder_remaining !== null ? candidateVariant.preorder_remaining <= 0 : candidateVariant.stock <= 0) : false;
13691                ch.classList.toggle('out', !disabled && outOfStock);
13692                const badge = ch.querySelector('.chip-badge');
13693                if (badge) badge.hidden = !(candidateVariant && outOfStock);
13694            });
13695            group.querySelectorAll('.v-chip').forEach(ch=>{
13696                const input = ch.querySelector('input[type=radio]');
13697                ch.classList.toggle('selected', input && input.checked);
13698            });
13699        });
13700    }
13701    updateSummary(sel);
13702    refreshOptions(sel);
13703    document.querySelectorAll('.v-chip').forEach(chip=>{const input=chip.querySelector('input[type=radio]');if(input&&input.checked){chip.classList.add('selected');}});
13704
13705    const container = document.getElementById('pd-variants');
13706    container && container.addEventListener('change', function(ev){
13707        const radio = ev.target.closest('input[type=radio]');
13708        if (!radio) return;
13709        sel = readSelection();
13710        if (autoFillMissing(sel)) sel = readSelection();
13711        const chosen = findVariant(sel);
13712        applyVariant(chosen || null, true);
13713        
13714        updateSummary(sel);
13715        refreshOptions(sel);
13716    });
13717    
13718window.applyVariant=applyVariant;
13719})();
13720
13721(function cleanBrokenDescImages(){
13722    const containers = [
13723        document.querySelector('.pd-full-desc-body'),
13724        document.querySelector('.pd-short-desc')
13725    ].filter(Boolean);
13726
13727    containers.forEach(root => {
13728        const imgs = root.querySelectorAll('img');
13729        imgs.forEach(img => {
13730            if (img.complete && img.naturalWidth === 0) {
13731                img.remove();
13732                return;
13733            }
13734            img.addEventListener('error', () => {
13735                img.remove();
13736            }, { once:true });
13737        });
13738    });
13739})();
13740
13741/* ====== Scroll To Top ====== */
13742(function _0xi25j(){const a=document.getElementById('pd-scroll-top');if(!a)return;function b(){if(window.matchMedia('(max-width:640px)').matches){const d=document.querySelector('.bottom-nav'),e=document.querySelector('.pd-mobile-fab');if(!d&&!e){setTimeout(b,100);return}const f=d&&window.getComputedStyle(d).display!=='none'&&window.getComputedStyle(d).visibility!=='hidden',g=e&&window.getComputedStyle(e).display!=='none'&&window.getComputedStyle(e).visibility!=='hidden';let h;if(f&&g){h='calc(68px + 54px + env(safe-area-inset-bottom))'}else if(g){h='calc(68px + 8px + env(safe-area-inset-bottom))'}else if(f){h='calc(60px + env(safe-area-inset-bottom))'}else{h='calc(20px + env(safe-area-inset-bottom))'}a.style.setProperty('--scroll-top-bottom',h)}else{a.style.removeProperty('--scroll-top-bottom')}}function c(){const d=window.pageYOffset||document.documentElement.scrollTop||0,e=d>300;a.classList.toggle('visible',e);a.setAttribute('aria-hidden',e?'false':'true');b()}window.addEventListener('scroll',c,{passive:!0});window.addEventListener('resize',b,{passive:!0});setTimeout(b,100);c();a.addEventListener('click',function(){window.scrollTo({top:0,behavior:'smooth'})})})();
13743
13744/* Format stok 10+ */
13745function _0xk67l(n){n=parseInt(n||0,10)||0;return n>10?'10+':String(n)}
13746
13747/* Toggle popover stok per cabang */
13748(function _0xm89n(){const a=document.getElementById('pd-stock-info-btn'),b=document.getElementById('pd-stock-popover'),c=document.getElementById('pd-stock-popover-close');if(!a||!b)return;function d(){if(window.matchMedia('(min-width: 641px)').matches){const e=document.getElementById('pd-stock-badge');if(!e)return;const f=e.getBoundingClientRect(),g=window.pageXOffset||document.documentElement.scrollLeft||0,h=window.pageYOffset||document.documentElement.scrollTop||0;b.style.left=(f.left+g-10)+'px';b.style.top=(f.bottom+h+10)+'px'}else{b.style.left='';b.style.top=''}}
13749function e(){d();b.classList.add('show');a.setAttribute('aria-expanded','true');b.setAttribute('aria-hidden','false');document.addEventListener('click',g,{capture:true});window.addEventListener('resize',d,{passive:true});window.addEventListener('scroll',d,{passive:true})}function f(){b.classList.remove('show');a.setAttribute('aria-expanded','false');b.setAttribute('aria-hidden','true');document.removeEventListener('click',g,{capture:true});window.removeEventListener('resize',d);window.removeEventListener('scroll',d)}function g(h){if(b.contains(h.target)||a.contains(h.target))return;f()}
13750a.addEventListener('click',function(h){h.preventDefault();b.classList.contains('show')?f():e()});if(c)c.addEventListener('click',f)})();
13751
13752/* ===== Share Product Modal ===== */
13753(function(){const a=document.getElementById('pd-share-btn'),z=document.getElementById('mf-share'),b=document.getElementById('pd-share-modal-overlay'),c=document.getElementById('pd-share-close'),d=document.getElementById('pd-share-copy-url-btn'),e=document.getElementById('pd-share-url-input');if((!a&&!z)||!b)return;const f="https://hop.exchange/",g="Lenovo Legion Go 8ASP2 - 83N0000RID /AMD Ryzen Z2 Extreme/32GB/1TB SSD/AMD Radeon Graphics/8.8\" WUXGA OLED Touch/Win 11 Home/Eclipse Black/3Y",h="Rp 20.789.000";const discountPercent=1;let i='';if(discountPercent>0){i=`🔥 Lagi Promo Nih! Diskon ${discountPercent}%\n\n✨ ${g}\n💰 Cuma ${h} aja!\n\n🛒 Buruan cek sebelum kehabisan!\n👉 `}else{i=`✨ Ada barang bagus nih!\n\n📦 ${g}\n💸 Harga: ${h}\n\n🛍️ Yuk, langsung cek!\n👉 `}function j(){b.classList.add('show');document.body.style.overflow='hidden'}function k(){b.classList.remove('show');document.body.style.overflow=''}if(a)a.addEventListener('click',j);if(z)z.addEventListener('click',j);if(c)c.addEventListener('click',k);b.addEventListener('click',function(l){if(l.target===b)k()});document.addEventListener('keydown',function(l){if(l.key==='Escape'&&b.classList.contains('show'))k()});b.addEventListener('click',function(l){const m=l.target.closest('[data-share]');if(!m)return;const n=m.getAttribute('data-share'),o=encodeURIComponent(f),p=e
13753ncodeURIComponent(i),q=encodeURIComponent(g);let r='';switch(n){case 'whatsapp':r=`https://wa.me/?text=${p}${o}`;break;case 'facebook':r=`https://www.facebook.com/sharer/sharer.php?u=${o}`;break;case 'twitter':r=`https://twitter.com/intent/tweet?text=${p}${o}`;break;case 'telegram':r=`https://t.me/share/url?url=${o}&text=${p}`;break;case 'email':r=`mailto:?subject=${encodeURIComponent('🔥 Cek Produk Keren Ini!')}&body=${p}${o}`;window.location.href=r;k();return;case 'copy':s();return;case 'pdf':const ps=document.querySelector('.product-single');if(ps){ps.setAttribute('data-print-date',new Date().toLocaleDateString('id-ID',{year:'numeric',month:'long',day:'numeric'}))}k();setTimeout(function(){window.print();try{if(window.ga4Ecomm&&window.ga4Ecomm.trackEvent)window.ga4Ecomm.trackEvent('share',{method:'pdf_export',content_type:'product',item_id:"SB0B3T"})}catch(_){}},300);return}if(r){window.open(r,'_blank','noopener,noreferrer');try{if(window.ga4Ecomm&&window.ga4Ecomm.trackEvent)window.ga4Ecomm.trackEvent('share',{method:n,content_type:'product',item_id:"SB0B3T"})}catch(_){}}});function s(){if(!e)return;e.select();e.setSelectionRange(0,99999);try{if(navigator.clipboard&&navigator.clipboard.writeText){navigator.clipboard.writeText(f).then(function(){t()}).catch(function(){document.execCommand('copy');t()})}else{document.execCommand('copy');t()}}catch(u){console.error('Failed to copy:',u)}}function t(){if(!d)return;const v=d.innerHTML;d.classList.add('copied');d.innerHTML='<svg viewBox="0 0 24 24" width="16" height="16"><path fill="currentColor" d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/></svg><span class="pd-share-copy-text">Tersalin!</span>';if(window.showToast)showToast({type:'success',title:'✨ Link Tersalin!',message:'Link produk berhasil disalin. Yuk bagikan ke teman!',duration:3000});setTimeout(function(){d.classList.remove('copied');d.innerHTML=v},2000)}if(d)d.addEventListener('click',s);if(navigator.share){const shareHandler=function(w){w.preventDefault();navigator.share({title:g,text:i+f,url:f}).catch(function(x){console.log('Native share cancelled or failed:',x)})};if(a)a.addEventListener('dblclick',shareHandler);if(z)z.addEventListener('dblclick',shareHandler)}})();
13754
13755/* ===== Embedding variants (server → client) ===== */
13756(function(){
13757  window.__PD_VARIANTS_WITH_BRANCH__ = [];
13758})();
13759
13760/* ===== Helper: update angka popover ===== */
13761function updateStockPopoverForVariant(v){
13762  try{
13763    const elMeg = document.getElementById('sp-qty-meg');
13764    const elMdf = document.getElementById('sp-qty-mdf');
13765    const elBda = document.getElementById('sp-qty-bda');
13766
13767    if (typeof v?.smm === 'number' && elMeg) elMeg.textContent = formatStockLabel(Math.max(0, v.smm|0));
13768    if (typeof v?.smf === 'number' && elMdf) elMdf.textContent = formatStockLabel(Math.max(0, v.smf|0));
13769    if (typeof v?.sba === 'number' && elBda) elBda.textContent = formatStockLabel(Math.max(0, v.sba|0));
13770  }catch(_){}
13771}
13772
13773/* ===== applyVariant: 10+ dan update popover ===== */
13774(function patchApplyVariant(){
13775  if (typeof applyVariant !== 'function') return;
13776  const original = applyVariant;
13777  window.applyVariant = function(v){
13778    original(v);
13779    
13780    try {
13781      const elStock = document.getElementById('pd-stock-badge');
13782      if (elStock){
13783        let txt = elStock.textContent || '';
13784        let m = txt.match(/\d+/);
13785        if (m) {
13786          const n = parseInt(m[0]||'0',10)||0;
13787          elStock.textContent = (n>0) ? ('Stok: ' + formatStockLabel(n)) : 'Habis';
13788        }
13789      }
13790    } catch(_){}
13791if(window.__PD_VARIANTS_WITH_BRANCH__&&v){const vv=window.__PD_VARIANTS_WITH_BRANCH__.find(x=>x.id===v.id)||v;updateStockPopoverForVariant(vv)}
13792  };
13793})();
13794
13795(function initCurrentVariantBranch(){
13796  const list = window.__PD_VARIANTS_WITH_BRANCH__ || [];
13797  if (!list.length) return;
13798  const hid = document.getElementById('pd-variant-id');
13799  const vid = hid ? parseInt(hid.value||'0',10) : 0;
13800  const current = list.find(x => x.id === vid) || list[0] || null;
13801  if (current) updateStockPopoverForVariant(current);
13802})();
13803
13804(function(){
13805    if (!window.ga4Ecomm) return;
13806    const catSegs = ["Komputer & Laptop","Laptop","Gaming"];
13807    window.ga4Ecomm.viewItem({
13808      currency: 'IDR',
13809      value: 20789000,
13810      item_id: "SB0B3T",
13811      item_name: "Lenovo Legion Go 8ASP2 - 83N0000RID /AMD Ryzen Z2 Extreme/32GB/1TB SSD/AMD Radeon Graphics/8.8\" WUXGA OLED Touch/Win 11 Home/Eclipse Black/3Y",
13812      item_brand: "Lenovo ",
13813      item_category: catSegs && catSegs.length ? catSegs.join(' / ') : ''
13814    });
13815  })();
13816  
13817(function patchApplyVariantFocus(){
13818  if (typeof applyVariant !== 'function') return;
13819  const original = applyVariant;
13820  window.applyVariant = function(v, focusImage = true){
13821    
13822    original(v, focusImage);
13823    
13824    if (focusImage && v && v.image_url) {
13825      _0xau1v(v.image_url);
13826    }
13827  };
13828})();
13829
13830(function() {
13831  var soldMap = [];
13832  var soldTotalLabel = "Terjual 2";
13833
13834  function formatSoldLabel(qty) {
13835    if (qty >= 1000000) {
13836      var v = Math.floor((qty / 100000) ) / 10;
13837      return 'Terjual ' + (String(v).replace('.', ',')) + 'jt+';
13838    }
13839    if (qty >= 1000) {
13840      var v2 = Math.floor((qty / 100) ) / 10;
13841      return 'Terjual ' + (String(v2).replace('.', ',')) + 'rb+';
13842    }
13843    if (qty >= 100) {
13844      var v2 = Math.floor((qty / 100) ) * 100;
13845      return 'Terjual ' + (String(v2).replace('.', ',')) + '+';
13846    }
13847    if (qty >= 10) {
13848      var v2 = Math.floor((qty / 10) ) * 10;
13849      return 'Terjual ' + (String(v2).replace('.', ',')) + '+';
13850    }
13851    return 'Terjual ' + (qty.toLocaleString('id-ID'));
13852  }
13853
13854  function updateSoldLabel(labelText) {
13855    var el = document.querySelector('#pd-sold-inline, [data-role="sold-chip"]');
13856    if (el) el.textContent = labelText;
13857  }
13858
13859  window.updateSoldBySku = function(sku) {
13860    if (!sku || typeof sku !== 'string') {
13861      updateSoldLabel(soldTotalLabel);
13862      return;
13863    }
13864    var qty = soldMap[sku] || 0;
13865    updateSoldLabel(formatSoldLabel(qty));
13866  };
13867
13868    updateSoldLabel(soldTotalLabel);
13869  })();
13870
13871(function(){const h=document.getElementById('pd-sticky-header');if(!h)return;const p=document.getElementById('pd-price-anchor');const ac=document.getElementById('pd-sticky-add-cart');const by=document.getElementById('pd-sticky-buy');let lt=window.scrollY;let tk=false;function u(){if(!p)return;const r=p.getBoundingClientRect();const s=window.scrollY;if(r.top<0){h.classList.add('visible')}else{h.classList.remove('visible')}lt=s;tk=false}function rt(){if(!tk){window.requestAnimationFrame(u);tk=true}}window.addEventListener('scroll',rt,{passive:true});u();function sy(){const ma=document.getElementById('btn-add-cart');const mb=document.getElementById('btn-buy');if(ac&&ma){ac.disabled=ma.disabled}if(by&&mb){by.disabled=mb.disabled}}sy();const ob=new MutationObserver(sy);const ma=document.getElementById('btn-add-cart');const mb=document.getElementById('btn-buy');if(ma)ob.observe(ma,{attributes:true,attributeFilter:['disabled']});if(mb)ob.observe(mb,{attributes:true,attributeFilter:['disabled']});const ss=document.getElementById('pd-sticky-share-btn');const ms=document.getElementById('pd-share-btn');if(ss&&ms){ss.addEventListener('click',function(e){e.preventDefault();ms.click()})}if(ac){ac.addEventListener('click',function(e){e.preventDefault();if(ac.disabled)return;const m=document.getElementById('btn-add-cart');if(m&&!m.disabled){m.click()}})}if(by){by.addEventListener('click',function(e){e.preventDefault();if(by.disabled)return;const m=document.getElementById('btn-buy');if(m&&!m.disabled&&window.buyNow){window.buyNow(e)}})}
13872function getChatProductData(){const varInput=document.getElementById('pd-variant-id');const variantId=varInput?parseInt(varInput.value||'0',10):0;const variantSummary=getVariantSummaryText();const priceEl=document.getElementById('pd-price-current');const currentPrice=priceEl?priceEl.textContent.trim():'Rp 20.789.000';const pd={id:325,name:"Lenovo Legion Go 8ASP2 - 83N0000RID \/AMD Ryzen Z2 Extreme\/32GB\/1TB SSD\/AMD Radeon Graphics\/8.8\" WUXGA OLED Touch\/Win 11 Home\/Eclipse Black\/3Y",price:currentPrice,image:"\/uploads\/products\/lenovo-legion-go-8asp2-83n0000rid.webp",url:window.location.href};if(variantId>0){pd.variant_id=variantId}if(variantSummary){pd.variant_summary=variantSummary}return pd}
13873const ch=document.getElementById('pd-sticky-chat');if(ch){ch.addEventListener('click',function(e){e.preventDefault();if(!window.plazaChat){console.warn('Chat widget not loaded');return}window.plazaChat.attachProduct(getChatProductData());window.plazaChat.openWidget()})}const dch=document.getElementById('btn-chat-icon');if(dch){dch.addEventListener('click',function(e){e.preventDefault();if(!window.plazaChat){console.warn('Chat widget not loaded');return}window.plazaChat.attachProduct(getChatProductData());window.plazaChat.openWidget()})}const mch=document.getElementById('mf-chat');if(mch){mch.addEventListener('click',function(e){e.preventDefault();if(!window.plazaChat){console.warn('Chat widget not loaded');return}window.plazaChat.attachProduct(getChatProductData());window.plazaChat.openWidget()})}window.addEventListener('pd-variant-changed',function(e){const d=e.detail||{};if(d.price!==undefined){const sp=document.getElementById('pd-sticky-price');if(sp){sp.textContent=formatRupiah(d.price)}}if(d.originalPrice!==undefined&&d.originalPrice>d.price){const so=document.getElementById('pd-sticky-price-original');if(so){so.textContent=formatRupiah(d.originalPrice);so.style.display=''}}else{const so=document.getElementById('pd-sticky-price-original');if(so){so.style.display='none'}}if(d.discount!==undefined&&d.discount>0){const sd=document.getElementById('pd-sticky-discount');if(sd){sd.textContent='-'+d.discount+'%';sd.style.display=''}}else{const sd=document.getElementById('pd-sticky-discount');if(sd){sd.style.display='none'}}const hs=d.stock>0;if(ac){ac.disabled=!hs}if(by){by.disabled=!hs}});
13873function formatRupiah(n){return'Rp'+Math.floor(n).toLocaleString('id-ID')}})();
13874
13875(function(){const t=document.getElementById('pdv-toggle-btn');const v=document.getElementById('pd-voucher-section');if(t&&v){const h=v.querySelectorAll('.pdv-min-hidden');const n=h.length;t.addEventListener('click',function(){const e=t.classList.toggle('expanded');h.forEach(function(i){if(e){i.classList.remove('pdv-min-hidden')}else{i.classList.add('pdv-min-hidden')}});t.textContent=e?'Tutup':'+'+n})}const m=document.getElementById('voucher-detail-modal');const mc=document.getElementById('voucher-modal-close');const ma=document.getElementById('voucher-modal-cancel');const mcp=document.getElementById('voucher-modal-copy');if(m){const bb=document.querySelectorAll('.pdv-badge-btn');bb.forEach(function(btn){btn.addEventListener('click',function(){if(btn.disabled)return;const c=btn.getAttribute('data-voucher-code');const nm=btn.getAttribute('data-voucher-name');const dl=btn.getAttribute('data-discount-label');const bl=btn.getAttribute('data-badge-label');const mp=parseInt(btn.getAttribute('data-min-purchase'));const md=parseInt(btn.getAttribute('data-max-discount'));const vu=btn.getAttribute('data-valid-until');document.getElementById('voucher-modal-badge').innerHTML='<span class="vmb-value">'+dl+'</span><span class="vmb-label">'+bl+'</span>';document.getElementById('voucher-modal-code').textContent=c;document.getElementById('voucher-modal-name').textContent=nm;const me=document.getElementById('voucher-modal-min');if(mp>0){me.style.display='';document.getElementById('voucher-modal-min-val').textContent=fr(mp)}else{me.style.display='none'}const xe=document.getElementById('voucher-modal-max');if(md>0){xe.style.display='';document.getElementById('voucher-modal-max-val').textContent=fr(md)}else{xe.style.display='none'}if(vu){const d=new Date(vu);const ft=d.toLocaleDateString('id-ID',{day:'numeric',month:'long',year:'numeric',hour:'2-digit',minute:'2-digit'});document.getElementById('voucher-modal-valid-val').textContent=ft}mcp.setAttribute('data-code',c);m.classList.add('show');document.body.style.overflow='hidden'})});function cm(){m.classList.remove('show');document.body.style.overflow=''}if(mc)mc.addEventListener('click',cm);if(ma)ma.addEventListener('click',cm);m.addEventListener('click',function(e){if(e.target===m)cm()});if(mcp){mcp.addEventListener('click',function(){const c=mcp.getAttribute('data-code');if(!c)return;if(navigator.clipboard&&navigator.clipboard.writeText){navigator.clipboard.writeText(c).then(function(){smc()}).catch(function(err){fc(c)})}else{fc(c)}})}}const b=document.querySelectorAll('.pdv-min-copy');b.forEach(function(btn){btn.addEventListener('click',function(){if(btn.disabled)return;const code=btn.getAttribute('data-code');if(!code)return;if(navigator.clipboard&&navigator.clipboard.writeText){navigator.clipboard.writeText(code).then(function(){sc(btn)}).catch(function(err){fc(code,btn)})}else{fc(code,btn)}})});function fc(text,btn){const tx=document.createElement('textarea');tx.value=text;tx.style.position='fixed';tx.style.opacity='0';document.body.appendChild(tx);tx.select();try{document.execCommand('copy');if(btn)sc(btn);else smc()}catch(err){}document.body.removeChild(tx)}function sc(btn){const o=btn.textContent;btn.classList.add('copied');btn.textContent='✓ Tersalin';setTimeout(function(){btn.classList.remove('copied');btn.textContent=o},2000)}function smc(){const o=mcp.textContent;mcp.textContent='✓ Kode Tersalin';mcp.style.background='#22c55e';setTimeout(function(){mcp.textContent=o;mcp.style.background=''},2000)}function fr(a){return'Rp'+Math.floor(a).toLocaleString('id-ID')}})();
13876</script>
vendor: 2 bytes, line 13876
13876
13877<script nonce="se3iyzEHMc9FQEB4wSyd0w==">
13878window.PD_ID=325;window.PD_NAME=_0x3c4d;window.PD_SKU=_0x5e6f;window.PD_CATEGORY_PATH="Komputer & Laptop/Laptop/Gaming";window.PD_BEST_VOUCHER=null;
13879window.IS_DIGITAL=IS_DIGITAL;
13880window.isPreorderProduct=false;
13881window.PD_PREORDER_DATA=null;
13882</script>
13882
13883
13884<script data-inlined="pd-lightbox.js">
13885// PlazaIT Product Lightbox (vanilla, no CDN) — v4 (swipe-down to close)
13886(function(){
13887  const state = {
13888    items: [],
13889    open: false,
13890    idx: 0,
13891    scale: 1,
13892    minScale: 1,
13893    maxScale: 4,
13894    tx: 0, ty: 0,
13895    isDragging: false,
13896    dragStartX: 0, dragStartY: 0,
13897    baseTx: 0, baseTy: 0,
13898    touchStartX: 0, touchStartY: 0,
13899    lastTap: 0,
13900    swipeMode: 'none', // 'none' | 'h' | 'v'
13901    totalDx: 0, totalDy: 0
13902  };
13903
13904  let root, imgEl, counterEl, btnPrev, btnNext, btnClose, canvas;
13905
13906  const ORIGIN = (location.origin || (location.protocol + '//' + location.host));
13907
13908  function absUrl(u){
13909    if (!u) return '';
13910    try {
13911      if (/^https?:\/\//i.test(u)) return u;
13912      return new URL(u, ORIGIN).href;
13913    } catch(_) { return u; }
13914  }
13915  function fileName(u){
13916    try { return new URL(u, ORIGIN).pathname.split('/').pop().toLowerCase(); }
13917    catch(_){ return String(u||'').split('/').pop().toLowerCase(); }
13918  }
13919
13920  function buildItems(){
13921    const gd = (window.galleryData || []).filter(Boolean);
13922    if (gd.length){
13923      state.items = gd.map(g => ({
13924        src: absUrl(g.url), alt: g.alt || '', slug: g.slug || '', w: g.w || 1200, h: g.h || 1200
13925      })).filter(it => !!it.src);
13926      return;
13927    }
13928    const thumbs = document.querySelectorAll('.pd-thumb-btn');
13929    state.items = Array.from(thumbs).map(btn => {
13930      const raw = btn.getAttribute('data-full') || '';
13931      return { src: absUrl(raw), alt: btn.getAttribute('data-alt') || '', slug: btn.getAttribute('data-slug') || '', w: 1200, h: 1200 };
13932    }).filter(it => !!it.src);
13933  }
13934
13935  function ensureUI(){
13936    if (root) return;
13937    root = document.createElement('div');
13938    root.className = 'pd-lb';
13939    root.id = 'pd-lightbox';
13940    root.setAttribute('role','dialog');
13941    root.setAttribute('aria-modal','true');
13942    root.setAttribute('aria-hidden','true');
13943    root.setAttribute('tabindex','-1');
13944
13945    // Canvas terlebih dulu (z-index di CSS membuat tombol di atas)
13946    root.innerHTML = `
13947      <div class="pd-lb-canvas"><img class="pd-lb-img" id="pd-lb-img" alt=""></div>
13948      <button class="pd-lb-close" aria-label="Tutup" title="Tutup">&times;</button>
13949      <button class="pd-lb-prev" aria-label="Sebelumnya" title="Sebelumnya">&#10094;</button>
13950      <button class="pd-lb-next" aria-label="Berikutnya" title="Berikutnya">&#10095;</button>
13951      <div class="pd-lb-counter" id="pd-lb-counter">1 / 1</div>
13952    `;
13953    document.body.appendChild(root);
13954
13955    imgEl     = root.querySelector('#pd-lb-img');
13956    counterEl = root.querySelector('#pd-lb-counter');
13957    btnPrev   = root.querySelector('.pd-lb-prev');
13958    btnNext   = root.querySelector('.pd-lb-next');
13959    btnClose  = root.querySelector('.pd-lb-close');
13960    canvas    = root.querySelector('.pd-lb-canvas');
13961
13962    // Button clicks
13963    btnPrev.addEventListener('click', (e)=>{ e.stopPropagation(); prev(); });
13964    btnNext.addEventListener('click', (e)=>{ e.stopPropagation(); next(); });
13965    btnClose.addEventListener('click', (e)=>{ e.stopPropagation(); close(); });
13966
13967    // Klik backdrop untuk tutup
13968    root.addEventListener('click', (e)=>{ if (e.target === root) close(); });
13969
13970    // Keyboard global
13971    document.addEventListener('keydown', (e)=>{
13972      if (!state.open) return;
13973      if (e.key === 'Escape') { e.preventDefault(); close(); }
13974      if (e.key === 'ArrowRight') { e.preventDefault(); next(); }
13975      if (e.key === 'ArrowLeft')  { e.preventDefault(); prev(); }
13976    });
13977
13978    // Wheel zoom (desktop)
13979    root.addEventListener('wheel', (e)=>{
13980      if (!state.open) return;
13981      e.preventDefault();
13982      const delta = -Math.sign(e.deltaY) * 0.2;
13983      zoomAt(delta, e.clientX, e.clientY);
13984    }, { passive: false });
13985
13986    // Drag pan (mouse)
13987    canvas.addEventListener('mousedown', (e)=>{
13988      if (state.scale <= 1) return;
13989      state.isDragging = true;
13990      state.dragStartX = e.clientX;
13991      state.dragStartY = e.clientY;
13992      state.baseTx = state.tx;
13993      state.baseTy = state.ty;
13994      e.preventDefault();
13995    });
13996    window.addEventListener('mousemove', (e)=>{
13997      if (!state.isDragging) return;
13998      const dx = e.clientX - state.dragStartX;
13999      const dy = e.clientY - state.dragStartY;
14000      setTranslate(state.baseTx + dx, state.baseTy + dy);
14001    });
14002    window.addEventListener('mouseup', ()=>{ state.isDragging = false; });
14003
14004    // Touch: swipe navigate (H), swipe-down close (V), double-tap zoom, drag pan
14005    canvas.addEventListener('touchstart', (e)=>{
14006      if (!state.open) return;
14007      if (e.touches.length === 1) {
14008        const t = e.touches[0];
14009        state.touchStartX = t.clientX;
14010        state.touchStartY = t.clientY;
14011        state.totalDx = 0;
14012        state.totalDy = 0;
14013        state.swipeMode = 'none';
14014
14015        state.isDragging = state.scale > 1;
14016        state.dragStartX = t.clientX;
14017        state.dragStartY = t.clientY;
14018        state.baseTx = state.tx;
14019        state.baseTy = state.ty;
14020
14021        // Double-tap toggle zoom
14022        const now = Date.now();
14023        if (now - state.lastTap < 300) {
14024          if (state.scale > 1) resetTransform(); else zoomAt(+1, t.clientX, t.clientY, 2);
14025          state.lastTap = 0;
14026          e.preventDefault();
14027          return;
14028        }
14029        state.lastTap = now;
14030      }
14031    }, { passive: true });
14032
14033    canvas.addEventListener('touchmove', (e)=>{
14034      if (!state.open) return;
14035
14036      // Drag pan saat zoom
14037      if (state.isDragging && e.touches.length === 1 && state.scale > 1) {
14038        e.preventDefault();
14039        const t = e.touches[0];
14040        const dx = t.clientX - state.dragStartX;
14041        const dy = t.clientY - state.dragStartY;
14042        setTranslate(state.baseTx + dx, state.baseTy + dy);
14043        return;
14044      }
14045
14046      // Gesture saat scale <= 1
14047      if (state.scale <= 1 && e.touches.length === 1) {
14048        const t = e.touches[0];
14049        const dx = t.clientX - state.touchStartX;
14050        const dy = t.clientY - state.touchStartY;
14051        state.totalDx = dx; state.totalDy = dy;
14052
14053        // Tentukan mode swipe di awal gerakan
14054        if (state.swipeMode === 'none') {
14055          const absX = Math.abs(dx), absY = Math.abs(dy);
14056          if (absY > 12 && absY > absX * 1.3) {
14057            state.swipeMode = 'v'; // swipe vertical (untuk close)
14058          } else if (absX > 12 && absX > absY * 1.3) {
14059            state.swipeMode = 'h'; // swipe horizontal (ganti slide)
14060          }
14061        }
14062
14063        if (state.swipeMode === 'v') {
14064          // Ikuti jari, kurangi opacity untuk feedback
14065          e.preventDefault();
14066          setRootDrag(dy);
14067        } else if (state.swipeMode === 'h') {
14068          // Biarkan sampai touchend untuk menentukan next/prev (tidak perlu preventDefault di sini)
14069        }
14070      }
14071    }, { passive: false });
14072
14073    canvas.addEventListener('touchend', (e)=>{
14074      if (!state.open) return;
14075
14076      if (state.scale <= 1) {
14077        const dx = state.totalDx;
14078        const dy = state.totalDy;
14079
14080        if (state.swipeMode === 'v') {
14081          const TH = 80; // threshold jarak piksel untuk menutup
14082          if (Math.abs(dy) > TH) {
14083            // Animasi keluar arah swipe
14084            animateClose(dy);
14085          } else {
14086            // Snap back
14087            resetRootDrag(true);
14088          }
14089        } else if (state.swipeMode === 'h') {
14090          if (Math.abs(dx) > 50) { dx < 0 ? next() : prev(); }
14091        }
14092      }
14093
14094      state.isDragging = false;
14095      state.swipeMode = 'none';
14096      state.totalDx = 0;
14097      state.totalDy = 0;
14098    });
14099  }
14100
14101  function setImage(idx){
14102    if (!state.items.length) return;
14103    state.idx = (idx + state.items.length) % state.items.length;
14104    const it = state.items[state.idx];
14105    imgEl.src = it.src;
14106    imgEl.alt = it.alt || '';
14107    counterEl.textContent = (state.idx + 1) + ' / ' + state.items.length;
14108    resetTransform();
14109    preloadNeighbors();
14110  }
14111
14112  function resetTransform(){
14113    state.scale = 1;
14114    state.tx = 0; state.ty = 0;
14115    applyTransform();
14116  }
14117
14118  function setTranslate(tx, ty){
14119    state.tx = tx; state.ty = ty;
14120    applyTransform();
14121  }
14122
14123  function applyTransform(){
14124    imgEl.style.transform = `translate3d(${state.tx}px, ${state.ty}px, 0) scale(${state.scale})`;
14125  }
14126
14127  function zoomAt(delta, clientX, clientY, snapTo){
14128    const old = state.scale;
14129    let next = (typeof snapTo === 'number') ? snapTo : (old + delta);
14130    next = Math.max(state.minScale, Math.min(state.maxScale, next));
14131
14132    if (next !== old) {
14133      const rect = imgEl.getBoundingClientRect();
14134      const cx = clientX - rect.left - rect.width/2;
14135      const cy = clientY - rect.top  - rect.height/2;
14136      state.tx -= cx * (next/old - 1);
14137      state.ty -= cy * (next/old - 1);
14138      state.scale = next;
14139      applyTransform();
14140    }
14141  }
14142
14143  function preloadNeighbors(){
14144    if (state.items.length < 2) return;
14145    const nextIdx = (state.idx + 1) % state.items.length;
14146    const prevIdx = (state.idx - 1 + state.items.length) % state.items.length;
14147    [nextIdx, prevIdx].forEach(i=>{
14148      const img = new Image(); img.src = state.items[i].src;
14149    });
14150  }
14151
14152  // ----- Swipe-down visual helpers -----
14153  function setRootDrag(dy){
14154    const damped = dy * 0.6; // redam gerakan agar lembut
14155    const abs = Math.abs(dy);
14156    const fade = Math.max(0, Math.min(1, 1 - abs / 300)); // transparansi sesuai jarak
14157    root.style.transform = `translate3d(0, ${damped}px, 0)`;
14158    root.style.opacity = String(0.95 * fade + 0.05); // jangan jadi 0 total sebelum close
14159  }
14160  function resetRootDrag(withAnim){
14161    if (withAnim) {
14162      root.style.transition = 'transform .18s ease, opacity .18s ease';
14163      root.style.transform = 'translate3d(0,0,0)';
14164      root.style.opacity = '1';
14165      setTimeout(()=>{ root.style.transition = ''; }, 190);
14166    } else {
14167      root.style.transition = '';
14168      root.style.transform = '';
14169      root.style.opacity = '';
14170    }
14171  }
14172  function animateClose(dy){
14173    root.style.transition = 'transform .18s ease, opacity .18s ease';
14174    const off = (dy > 0 ? window.innerHeight : -window.innerHeight);
14175    root.style.transform = `translate3d(0, ${off}px, 0)`;
14176    root.style.opacity = '0';
14177    setTimeout(()=>{ root.style.transition = ''; close(); }, 180);
14178  }
14179
14180  function setSiblingsInert(makeInert){
14181    // Inert semua saudara root (elemen lain di body) agar fokus tidak lari
14182    const nodes = Array.from(document.body.children).filter(el => el !== root);
14183    nodes.forEach(el=>{
14184      if (makeInert) {
14185        if (!el.hasAttribute('inert')) el.setAttribute('inert','');
14186      } else {
14187        if (el.hasAttribute('inert')) el.removeAttribute('inert');
14188      }
14189    });
14190  }
14191
14192  function open(idx){
14193    if (!state.items.length) buildItems();
14194    if (!state.items.length) return;
14195    ensureUI();
14196
14197    // Reset efek drag visual
14198    resetRootDrag(false);
14199
14200    document.body.style.overflow = 'hidden';
14201    root.classList.add('show');
14202    root.removeAttribute('aria-hidden'); // hindari aria-hidden saat fokus child
14203    setSiblingsInert(true);
14204
14205    state.open = true;
14206    setImage(typeof idx === 'number' ? idx : 0);
14207
14208    // Fokuskan dialog agar keyboard pasti tertangkap
14209    try { root.focus(); } catch(_){}
14210  }
14211
14212  function close(){
14213    state.open = false;
14214    root.classList.remove('show');
14215    root.setAttribute('aria-hidden','true');
14216    setSiblingsInert(false);
14217    document.body.style.overflow = '';
14218
14219    // Bersihkan transform/opacity
14220    resetRootDrag(false);
14221  }
14222
14223  function next(){ setImage(state.idx + 1); }
14224  function prev(){ setImage(state.idx - 1); }
14225
14226  function findIndexByUrl(url){
14227    const target = fileName(absUrl(url));
14228    const idx = state.items.findIndex(it => fileName(it.src) === target);
14229    return idx >= 0 ? idx : 0;
14230  }
14231
14232  function initPdLightbox(){
14233    buildItems();
14234    ensureUI();
14235
14236    // Klik gambar utama → buka LB di index yang sama
14237    const mainImg = document.getElementById('pd-main-img');
14238    if (mainImg) {
14239      mainImg.style.cursor = 'zoom-in';
14240      mainImg.addEventListener('click', ()=>{
14241        open(findIndexByUrl(mainImg.src));
14242      });
14243    }
14244
14245    // Klik gambar slider mobile → buka LB di gambar yang diketuk
14246    const slider = document.getElementById('pd-mobile-slider');
14247    if (slider) {
14248      slider.addEventListener('click', (e)=>{
14249        const im = e.target && e.target.tagName === 'IMG' ? e.target : e.target.closest('img');
14250        if (!im) return;
14251        open(findIndexByUrl(im.src));
14252      });
14253    }
14254
14255    // (Opsional) double-click pada thumbnail untuk buka langsung
14256    const thumbs = document.querySelectorAll('.pd-thumb-btn');
14257    thumbs.forEach((btn)=>{
14258      let last = 0;
14259      btn.addEventListener('click', ()=>{
14260        const now = Date.now();
14261        if (now - last < 300) {
14262          const src = btn.getAttribute('data-full') || '';
14263          open(findIndexByUrl(absUrl(src)));
14264          last = 0;
14265        } else {
14266          last = now;
14267        }
14268      });
14269    });
14270
14271    // Ekspos API
14272    window.PDLightbox = { open, close, next, prev, findIndexByUrl };
14273  }
14274
14275  if (document.readyState === 'loading') {
14276    document.addEventListener('DOMContentLoaded', initPdLightbox);
14277  } else {
14278    initPdLightbox();
14279  }
14280})();
14281</script>
vendor: 2 bytes, line 14281
14281
14282<script data-inlined="cart.js">
14283(function(){
14284  function $(s,ctx=document){ return ctx.querySelector(s); }
14285  function esc(s){ return String(s||'').replace(/[&<>"']/g, m=>({ '&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#039;' }[m])); }
14286  
14287  // CSRF token helper
14288  function getCsrfToken() {
14289    const metaTag = document.querySelector('meta[name="csrf-token"]');
14290    return metaTag ? metaTag.getAttribute('content') : '';
14291  }
14292  
14293  function guessPdMeta(){
14294    const name = (window.PD_NAME !== undefined) ? String(window.PD_NAME) : ($('#pd-title')?.textContent || '');
14295    const sku  = (function(){ const el=$('#pd-sku'); return el ? el.textContent.trim() : (window.PD_SKU||''); })();
14296    // SECURITY FIX: Remove price from client-side metadata (will be validated server-side)
14297    const imgEl = $('#pd-main-img');
14298    const image_url = imgEl ? (imgEl.getAttribute('src') || '') : '';
14299    return { name, sku, image_url }; // price removed for security
14300  }
14301
14302  async function addToCart(productId, qty=1, variantId=0, metaOpt){
14303    const meta = Object.assign(guessPdMeta(), metaOpt||{});
14304    const payload = {
14305      product_id: parseInt(productId||0,10) || 0,
14306      qty: parseInt(qty||1,10) || 1,
14307      variant_id: parseInt(variantId||0,10) || 0,
14308      meta
14309    };
14310    
14311    // Check if user is logged in
14312    const isLoggedIn = document.querySelector('meta[name="user-logged-in"]')?.content === 'true' ||
14313                      document.body.classList.contains('logged-in') ||
14314                      window.userLoggedIn === true ||
14315                      document.body.dataset.userLoggedIn === 'true';
14316    
14317    // Skip localStorage untuk logged user - mereka pakai database
14318    if (!isLoggedIn && window.guestCart) {
14319      try {
14320        window.guestCart.add(payload.product_id, payload.qty, payload.variant_id, meta);
14321      } catch (e) {
14322        console.warn('Failed to add to localStorage cart:', e);
14323      }
14324    }
14325    
14326    const res = await fetch('/api/cart/add.php', {
14327      method: 'POST',
14328      headers: { 
14329        'Content-Type':'application/json',
14330        'X-CSRF-Token': getCsrfToken()
14331      },
14332      credentials: 'same-origin',
14333      body: JSON.stringify({
14334        ...payload,
14335        csrf_token: getCsrfToken()
14336      }),
14337    });
14338    const data = await res.json().catch(()=>({ ok:false, error:'Gagal menambahkan ke keranjang' }));
14339    if (!res.ok || !data.ok) {
14340      const msg = data && data.error ? data.error : 'Gagal menambahkan ke keranjang';
14341      throw new Error(msg);
14342    }
14343
14344    // Update badge di navbar dengan data dari response
14345    try {
14346      const el = document.querySelector('[data-role="cart-badge"]') || document.getElementById('cartCount');
14347      if (el && data.cart && typeof data.cart.items_count === 'number') {
14348        el.textContent = String(data.cart.items_count);
14349        el.classList.toggle('is-empty', data.cart.items_count <= 0);
14350      }
14351    } catch(_){}
14352
14353    // Siarkan event global (dipakai cart-badge.js dan halaman lain)
14354    try {
14355      document.dispatchEvent(new CustomEvent('cart:updated', { detail: data.cart || {} }));
14356    } catch(_){}
14357
14358    // Update CartBadge dengan data dari response (lebih reliable)
14359    try { 
14360      if (window.CartBadge && window.CartBadge.set) {
14361        window.CartBadge.set(data.cart.items_count||0);
14362      }
14363    } catch(_){}
14364
14365    // Tambahan: refresh cart counter setelah delay kecil untuk memastikan data tersinkronisasi
14366    setTimeout(() => {
14367      if (window.updateCartCounter) {
14368        window.updateCartCounter();
14369      }
14370    }, 100);
14371
14372    return data;
14373  }
14374
14375  // Function to update cart counter from server
14376  async function updateCartCounter(){
14377    try {
14378      const res = await fetch('/api/cart/get.php', { credentials:'same-origin' });
14379      const data = await res.json().catch(()=>({ok:false}));
14380      if (data.ok && typeof data.items_count === 'number') {
14381        const el = document.querySelector('[data-role="cart-badge"]') || document.getElementById('cartCount');
14382        if (el) {
14383          el.textContent = String(data.items_count);
14384          el.classList.toggle('is-empty', data.items_count <= 0);
14385        }
14386        // Dispatch event
14387        try {
14388          document.dispatchEvent(new CustomEvent('cart:updated', { detail: { items_count: data.items_count } }));
14389        } catch(_){}
14390      }
14391    } catch (err) {
14392      console.log('Could not update cart counter:', err);
14393    }
14394  }
14395
14396  // Function to manually merge guest cart (if needed)
14397  async function mergeGuestCart(){
14398    try {
14399      const res = await fetch('/api/cart/merge-guest.php', {
14400        method: 'POST',
14401        headers: { 
14402          'Content-Type': 'application/json',
14403          'X-CSRF-Token': getCsrfToken()
14404        },
14405        credentials: 'same-origin',
14406        body: JSON.stringify({ csrf_token: getCsrfToken() })
14407      });
14408      const data = await res.json().catch(()=>({ok:false}));
14409      
14410      if (data.ok && data.merged_items > 0) {
14411        console.log(`Guest cart merged: ${data.merged_items} items`);
14412        // Update cart counter after merge
14413        await updateCartCounter();
14414        return data;
14415      }
14416      return data;
14417    } catch (err) {
14418      console.log('Could not merge guest cart:', err);
14419      return { ok: false, error: err.message };
14420    }
14421  }
14422
14423  window.addToCart = addToCart;
14424  window.updateCartCounter = updateCartCounter;
14425  window.mergeGuestCart = mergeGuestCart;
14426
14427  // Optional: auto-bind untuk tombol apapun yang punya data-addtocart
14428  document.addEventListener('click', async (e)=>{
14429    const btn = e.target.closest('[data-addtocart]');
14430    if (!btn) return;
14431    e.preventDefault();
14432    if (btn.disabled) return;
14433
14434    const pid = parseInt(btn.getAttribute('data-pid')||'0',10);
14435    const vid = parseInt(btn.getAttribute('data-vid')||'0',10);
14436    const qty = parseInt(btn.getAttribute('data-qty')||'1',10) || 1;
14437
14438    try {
14439      const data = await addToCart(pid, qty, vid);
14440      if (window.showToast) {
14441        const meta = guessPdMeta();
14442        window.showToast({
14443          type:'success',
14444          title:'Berhasil ditambahkan',
14445          message:`<strong>${esc(meta.name)}</strong>${meta.sku?` · <em>SKU: ${esc(meta.sku)}</em>`:''}<br>Qty: ${qty}`,
14446          duration: 3800,
14447          actions: [
14448            { label:'Lihat Keranjang', onClick: ()=> { window.location.href='/keranjang'; } },
14449            { label:'Lanjut Belanja', variant:'alt', onClick: ()=>{} }
14450          ]
14451        });
14452      }
14453    } catch (err) {
14454      if (window.showToast) {
14455        window.showToast({ type:'warn', title:'Gagal', message: String(err?.message||'Gagal menambahkan'), duration: 4200 });
14456      } else {
14457        console.error(err);
14458      }
14459    }
14460  });
14461})();
14462</script>
vendor: 2 bytes, line 14462
14462
14463<script data-inlined="stock-validator-vanilla.js">
14464/**
14465 * Stock Validation - Vanilla JS Version
14466 * 
14467 * This script provides client-side stock validation without jQuery dependency
14468 * - Works with native JavaScript and fetch API
14469 * - Graceful fallback for older browsers
14470 * - Same functionality as jQuery version
14471 */
14472
14473window.StockValidator = (function() {
14474    'use strict';
14475
14476    const config = {
14477        apiEndpoint: '/api/stock/check.php',
14478        modalSelector: '#stock-modal-overlay',  // We create our own modal
14479        loadingClass: 'loading-stock',
14480        disabledClass: 'stock-disabled',
14481        debug: true  // Enable debug logging
14482    };
14483
14484    /**
14485     * Cross-browser event listener helper
14486     */
14487    function addEventListener(element, event, handler) {
14488        if (element.addEventListener) {
14489            element.addEventListener(event, handler);
14490        } else if (element.attachEvent) {
14491            element.attachEvent('on' + event, handler);
14492        }
14493    }
14494
14495    /**
14496     * Get stock information from embedded variant data (instant, no AJAX needed)
14497     */
14498    function getStockFromEmbeddedData(variantId) {
14499        // Check if embedded variant data exists
14500        if (!window.__PD_VARIANTS_WITH_BRANCH__ || !Array.isArray(window.__PD_VARIANTS_WITH_BRANCH__)) {
14501            return null;
14502        }
14503        
14504        const variants = window.__PD_VARIANTS_WITH_BRANCH__;
14505        
14506        // SPECIAL CASE: Simple product (no variants) - empty array means simple product
14507        if (variants.length === 0) {
14508            // For simple products, we cannot determine stock from embedded data
14509            // Return null to force API validation
14510            return null;
14511        }
14512        
14513        // If no variant specified, check base product stock (all variants)
14514        if (!variantId || variantId <= 0) {
14515            // For base product, check if ANY variant has stock
14516            const isPreorder = window.isPreorderProduct || false;
14517            let hasAnyStock = false;
14518            let totalStock = 0;
14519            
14520            if (isPreorder) {
14521                // For pre-order, check preorder_remaining
14522                hasAnyStock = variants.some(v => {
14523                    if ('preorder_remaining' in v && v.preorder_remaining !== null) {
14524                        return v.preorder_remaining > 0;
14525                    }
14526                    return v.stock > 0;
14527                });
14528                totalStock = variants.reduce((sum, v) => {
14529                    if ('preorder_remaining' in v && v.preorder_remaining !== null) {
14530                        return sum + (v.preorder_remaining || 0);
14531                    }
14532                    return sum + (v.stock || 0);
14533                }, 0);
14534            } else {
14535                hasAnyStock = variants.some(v => v.stock > 0);
14536                totalStock = variants.reduce((sum, v) => sum + (v.stock || 0), 0);
14537            }
14538            
14539            return {
14540                hasStock: hasAnyStock,
14541                stock: totalStock,
14542                sku: 'Base Product',
14543                variant: null
14544            };
14545        }
14546        
14547        // Find specific variant
14548        const variant = variants.find(v => v.id === variantId);
14549        
14550        if (!variant) {
14551            return {
14552                hasStock: false,
14553                stock: 0,
14554                sku: 'Unknown Variant',
14555                variant: null
14556            };
14557        }
14558        
14559        // For pre-order products, check preorder_remaining instead of stock
14560        const isPreorder = window.isPreorderProduct || false;
14561        let hasStock = false;
14562        let availableStock = 0;
14563        
14564        if (isPreorder && 'preorder_remaining' in variant && variant.preorder_remaining !== null) {
14565            availableStock = parseInt(variant.preorder_remaining, 10);
14566            if (isNaN(availableStock)) availableStock = 0;
14567            hasStock = availableStock > 0;
14568        } else {
14569            availableStock = variant.stock || 0;
14570            hasStock = availableStock > 0;
14571        }
14572        
14573        return {
14574            hasStock: hasStock,
14575            stock: availableStock,
14576            sku: variant.sku,
14577            variant: variant
14578        };
14579    }
14580
14581    /**
14582     * Cross-browser AJAX helper
14583     */
14584    function makeRequest(url, options) {
14585        return new Promise((resolve, reject) => {
14586            // Try fetch first (modern browsers)
14587            if (typeof fetch !== 'undefined') {
14588                const fetchOptions = {
14589                    method: options.method || 'POST',
14590                    headers: {
14591                        'Content-Type': 'application/x-www-form-urlencoded',
14592                    },
14593                    body: options.data ? new URLSearchParams(options.data).toString() : null
14594                };
14595
14596                fetch(url, fetchOptions)
14597                    .then(response => {
14598                        if (!response.ok) {
14599                            throw new Error(`HTTP ${response.status}`);
14600                        }
14601                        return response.json();
14602                    })
14603                    .then(resolve)
14604                    .catch(reject);
14605            } else {
14606                // Fallback to XMLHttpRequest
14607                const xhr = new XMLHttpRequest();
14608                xhr.open(options.method || 'POST', url);
14609                xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
14610                
14611                xhr.onload = function() {
14612                    if (xhr.status >= 200 && xhr.status < 300) {
14613                        try {
14614                            resolve(JSON.parse(xhr.responseText));
14615                        } catch (e) {
14616                            reject(new Error('Invalid JSON response'));
14617                        }
14618                    } else {
14619                        reject(new Error(`HTTP ${xhr.status}`));
14620                    }
14621                };
14622                
14623                xhr.onerror = function() {
14624                    reject(new Error('Network error'));
14625                };
14626                
14627                const data = options.data ? new URLSearchParams(options.data).toString() : null;
14628                xhr.send(data);
14629            }
14630        });
14631    }
14632
14633    /**
14634     * Check stock via AJAX
14635     */
14636    function checkStock(productId, variantId, qty) {
14637        return makeRequest(config.apiEndpoint, {
14638            method: 'POST',
14639            data: {
14640                product_id: productId,
14641                variant_id: variantId || 0,
14642                qty: qty || 1
14643            }
14644        });
14645    }
14646
14647    /**
14648     * Create and show stock alert modal using modal.css structure
14649     */
14650    function showStockModal(stockInfo, action = 'add to cart') {
14651        let title, message, type, iconClass;
14652
14653        // Handle both string and object formats
14654        if (typeof stockInfo === 'string') {
14655            title = 'Stok Tidak Tersedia';
14656            message = stockInfo;
14657            type = 'warning';
14658            iconClass = 'warning';
14659        } else if (stockInfo && typeof stockInfo === 'object') {
14660            if (!stockInfo.is_active) {
14661                title = 'Produk Tidak Tersedia';
14662                message = 'Maaf, produk ini sudah tidak aktif atau telah dihapus dari katalog.';
14663                type = 'danger';
14664                iconClass = 'danger';
14665            } else if (!stockInfo.is_in_stock) {
14666                title = 'Stok Habis';
14667                message = `<strong>${stockInfo.product_name || 'Produk ini'}</strong> sedang habis stok. Silakan pilih varian lain atau tunggu restock.`;
14668                if (stockInfo.sku) {
14669                    message += `<br><small style="color: #64748b;">SKU: ${stockInfo.sku}</small>`;
14670                }
14671                type = 'warning';
14672                iconClass = 'warning';
14673            } else if (!stockInfo.can_add_to_cart) {
14674                title = 'Stok Tidak Mencukupi';
14675                message = `Stok <strong>${stockInfo.product_name || 'produk'}</strong> tidak mencukupi.<br>`;
14676                message += `Tersedia: <strong>${stockInfo.available_stock}</strong>, diminta: <strong>${stockInfo.requested_qty}</strong><br>`;
14677                message += `Silakan kurangi jumlah atau pilih varian lain.`;
14678                type = 'warning';
14679                iconClass = 'warning';
14680            } else {
14681                title = 'Stok Tidak Tersedia';
14682                message = stockInfo.message || 'Produk ini tidak dapat ditambahkan ke keranjang saat ini.';
14683                type = 'warning';
14684                iconClass = 'warning';
14685            }
14686        } else {
14687            title = 'Stok Tidak Tersedia';
14688            message = 'Produk ini tidak dapat ditambahkan ke keranjang saat ini.';
14689            type = 'warning';
14690            iconClass = 'warning';
14691        }
14692
14693        // Create modal HTML using modal.css structure
14694        const modalHTML = `
14695            <div class="modal-overlay" id="stock-modal-overlay">
14696                <div class="modal-dialog">
14697                    <div class="modal-header">
14698                        <div class="modal-icon ${iconClass}">
14699                            ${getIconSVG(iconClass)}
14700                        </div>
14701                        <h3 class="modal-title">${title}</h3>
14702                    </div>
14703                    <div class="modal-body">
14704                        <p class="modal-message">${message}</p>
14705                        <div class="modal-actions">
14706                            <button type="button" class="modal-btn modal-btn-secondary" data-action="close">
14707                                Tutup
14708                            </button>
14709                            <button type="button" class="modal-btn modal-btn-primary" data-action="reload">
14710                                Muat Ulang
14711                            </button>
14712                        </div>
14713                    </div>
14714                </div>
14715            </div>
14716        `;
14717
14718        // Remove existing modal if any
14719        const existingModal = document.getElementById('stock-modal-overlay');
14720        if (existingModal) {
14721            existingModal.remove();
14722        }
14723
14724        // Add modal to body
14725        document.body.insertAdjacentHTML('beforeend', modalHTML);
14726        
14727        // Show modal with animation
14728        const modal = document.getElementById('stock-modal-overlay');
14729        setTimeout(() => {
14730            modal.classList.add('show');
14731        }, 10);
14732
14733        // Add event listeners to modal buttons
14734        const closeBtn = modal.querySelector('[data-action="close"]');
14735        const reloadBtn = modal.querySelector('[data-action="reload"]');
14736        
14737        if (closeBtn) {
14738            addEventListener(closeBtn, 'click', closeStockModal);
14739        }
14740        
14741        if (reloadBtn) {
14742            addEventListener(reloadBtn, 'click', function() {
14743                closeStockModal();
14744                window.location.reload();
14745            });
14746        }
14747
14748        // Close modal when clicking overlay
14749        addEventListener(modal, 'click', function(event) {
14750            if (event.target === modal) {
14751                closeStockModal();
14752            }
14753        });
14754
14755        // Auto-close after 8 seconds
14756        setTimeout(() => {
14757            closeStockModal();
14758        }, 8000);
14759    }
14760
14761    /**
14762     * Get icon SVG based on type
14763     */
14764    function getIconSVG(type) {
14765        const icons = {
14766            danger: '<svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z"/></svg>',
14767            warning: '<svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor">
14767<path d="M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z"/></svg>',
14768            success: '<svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z"/></svg>',
14769            info: '<svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z"/></svg>'
14770        };
14771        return icons[type] || icons.info;
14772    }
14773
14774    /**
14775     * Close stock modal
14776     */
14777    function closeStockModal() {
14778        const modal = document.getElementById('stock-modal-overlay');
14779        if (modal) {
14780            modal.classList.remove('show');
14781            setTimeout(() => {
14782                modal.remove();
14783            }, 200);
14784        }
14785    }
14786
14787    // Make closeStockModal globally available
14788    if (typeof window !== 'undefined') {
14789        window.closeStockModal = closeStockModal;
14790    }
14791
14792    /**
14793     * Get element data attribute with fallback
14794     */
14795    function getDataAttribute(element, attr) {
14796        if (element.dataset) {
14797            return element.dataset[attr];
14798        } else {
14799            return element.getAttribute('data-' + attr);
14800        }
14801    }
14802
14803    /**
14804     * Validate stock before cart action
14805     */
14806    async function validateBeforeCart(productId, variantId, qty, action = 'add') {
14807        try {
14808            // SMART VALIDATION: For simple products, check if we already have cached stock info
14809            // If buttons are enabled and cached info shows stock available, skip API validation
14810            if (window._currentStockInfo && window._currentStockInfo.can_add_to_cart) {
14811        
14812                return true;
14813            }
14814            
14815            // For variant products or when cached info is not available, do API validation
14816            const stockInfo = await checkStock(productId, variantId, qty);
14817            
14818            if (!stockInfo.ok) {
14819                showStockModal({ 
14820                    message: stockInfo.error || 'Gagal mengecek stok',
14821                    is_active: false 
14822                }, action);
14823                return false;
14824            }
14825
14826            if (!stockInfo.can_add_to_cart) {
14827                showStockModal(stockInfo, action);
14828                return false;
14829            }
14830
14831            return true; // Stock available, proceed
14832
14833        } catch (error) {
14834            console.error('Stock validation error:', error);
14835            showStockModal({ 
14836                message: 'Terjadi kesalahan saat mengecek stok. Silakan coba lagi.',
14837                is_active: false 
14838            }, action);
14839            return false;
14840        }
14841    }
14842
14843    /**
14844     * Handle button click with stock validation
14845     */
14846    function handleButtonClick(event, action) {
14847        const button = event.target;
14848        
14849        
14850        // FIRST CHECK: Is button marked as stock-blocked? (Anti-tampering)
14851        if (button.hasAttribute('data-stock-blocked')) {
14852            event.preventDefault();
14853            event.stopImmediatePropagation();
14854            
14855            const reason = button.getAttribute('data-stock-reason') || 'Stok tidak tersedia';
14856            showStockModal(reason);
14857            
14858            // Show security warning
14859            if (window.showToast) {
14860                window.showToast({
14861                    type: 'warning',
14862                    title: 'Aksi Tidak Diizinkan',
14863                    message: 'Produk ini sedang habis stok. Silakan pilih varian lain.',
14864                    duration: 3000
14865                });
14866            }
14867            return false;
14868        }
14869        
14870        // SECOND CHECK: Real-time stock validation against cached stock info
14871        if (window._currentStockInfo && !window._currentStockInfo.can_add_to_cart) {
14872            event.preventDefault();
14873            event.stopImmediatePropagation();
14874            
14875            showStockModal(window._currentStockInfo.message || 'Stok tidak tersedia');
14876            
14877            // Re-enforce button disabling
14878            button.disabled = true;
14879            button.style.opacity = '0.5';
14880            button.style.cursor = 'not-allowed';
14881            button.setAttribute('data-stock-blocked', 'true');
14882            
14883            return false;
14884        }
14885        
14886        // Skip if already processing
14887        if (button.classList.contains(config.loadingClass)) {
14888            event.preventDefault();
14889            return false;
14890        }
14891
14892        // Get product data from button attributes or form
14893        let productId = parseInt(getDataAttribute(button, 'productId') || getDataAttribute(button, 'product-id') || 0);
14894        let variantId = parseInt(getDataAttribute(button, 'variantId') || getDataAttribute(button, 'variant-id') || 0);
14895        let qty = parseInt(getDataAttribute(button, 'qty') || 1);
14896
14897        // Try to get from global variables (set by product detail page)
14898        if (productId <= 0 && typeof window.PD_ID !== 'undefined') {
14899            productId = parseInt(window.PD_ID || 0);
14900        }
14901
14902        // Try to get from parent form if not in button
14903        if (productId <= 0) {
14904            const form = button.closest ? button.closest('form') : null;
14905            if (form) {
14906                const pidAttr = form.getAttribute('data-pid');
14907                const pidInput = form.querySelector('[name="product_id"]');
14908                const vidInput = form.querySelector('[name="variant_id"]');
14909                const qtyInput = form.querySelector('[name="qty"]');
14910                
14911                if (pidAttr) productId = parseInt(pidAttr);
14912                if (pidInput) productId = parseInt(pidInput.value || 0);
14913                if (vidInput) variantId = parseInt(vidInput.value || 0);
14914                if (qtyInput) qty = parseInt(qtyInput.value || 1);
14915            }
14916        }
14917
14918        // CRITICAL: Always get current variant from selector (overrides button attributes)
14919        // This ensures we validate against the currently selected variant, not cached button data
14920        const variantSelector = document.getElementById('pd-variant-id');
14921        if (variantSelector) {
14922            const currentVariantId = parseInt(variantSelector.value || 0);
14923            if (currentVariantId > 0) {
14924                variantId = currentVariantId;
14925            }
14926        }
14927
14928
14929        if (productId <= 0) {
14930            return true; // Let default handler deal with it
14931        }
14932
14933        // Prevent default and validate stock
14934        event.preventDefault();
14935        event.stopPropagation();
14936        
14937        // Show loading state
14938        button.classList.add(config.loadingClass);
14939        const originalDisabled = button.disabled;
14940        button.disabled = true;
14941        
14942        
14943        validateBeforeCart(productId, variantId, qty, action)
14944            .then(isValid => {
14945                if (isValid) {
14946                    // Stock OK, proceed with original action
14947                    if (action === 'cart' && typeof window.addToCart === 'function') {
14948                        window.addToCart(productId, qty, variantId);
14949                    } else if (action === 'buy' && typeof window.buyNow === 'function') {
14950                        // Call buyNow from pd-buynow.js without parameters (it gets data internally)
14951                        window.buyNow();
14952                    } else {
14953                        // Add fallback cart/buy logic here if needed
14954                    }
14955                }
14956            })
14957            .catch(error => {
14958            })
14959            .finally(() => {
14960                // Remove loading state
14961                button.classList.remove(config.loadingClass);
14962                button.disabled = originalDisabled;
14963            });
14964
14965        return false;
14966    }
14967
14968    /**
14969     * Handle mobile button click with stock validation
14970     */
14971    function handleMobileButtonClick(event, action) {
14972        const button = event.target;
14973        
14974        
14975        // FIRST CHECK: Is button marked as stock-blocked? (Anti-tampering)
14976        if (button.hasAttribute('data-stock-blocked')) {
14977            event.preventDefault();
14978            event.stopImmediatePropagation();
14979            
14980            const reason = button.getAttribute('data-stock-reason') || 'Stok tidak tersedia';
14981            showStockModal(reason);
14982            
14983            // Show security warning
14984            if (window.showToast) {
14985                window.showToast({
14986                    type: 'warning',
14987                    title: 'Aksi Tidak Diizinkan',
14988                    message: 'Produk ini sedang habis stok. Silakan pilih varian lain.',
14989                    duration: 3000
14990                });
14991            }
14992            return false;
14993        }
14994        
14995        // SECOND CHECK: Real-time stock validation against cached stock info
14996        if (window._currentStockInfo && !window._currentStockInfo.can_add_to_cart) {
14997            event.preventDefault();
14998            event.stopImmediatePropagation();
14999            
15000            showStockModal(window._currentStockInfo.message || 'Stok tidak tersedia');
15001            
15002            // Re-enforce button disabling
15003            button.disabled = true;
15004            button.style.opacity = '0.5';
15005            button.style.cursor = 'not-allowed';
15006            button.setAttribute('data-stock-blocked', 'true');
15007            
15008            return false;
15009        }
15010        
15011        // Skip if already processing
15012        if (button.classList.contains(config.loadingClass)) {
15013            event.preventDefault();
15014            return false;
15015        }
15016
15017        // Get product data from mobile FAB container
15018        let productId = 0;
15019        let variantId = 0;
15020        let qty = 1;
15021
15022        // Try to get from mobile FAB data-pid
15023        const mobileFab = document.getElementById('pd-mobile-fab');
15024        if (mobileFab) {
15025            const pidAttr = getDataAttribute(mobileFab, 'pid');
15026            if (pidAttr) productId = parseInt(pidAttr);
15027        }
15028
15029        // Try to get from global variables (set by product detail page)
15030        if (productId <= 0 && typeof window.PD_ID !== 'undefined') {
15031            productId = parseInt(window.PD_ID || 0);
15032        }
15033
15034        // CRITICAL: Always get current variant from selector (real-time)
15035        // This ensures we validate against the currently selected variant
15036        const variantSelector = document.getElementById('pd-variant-id');
15037        if (variantSelector) {
15038            variantId = parseInt(variantSelector.value || 0);
15039        }
15040
15041        // Try to get quantity from quantity input
15042        const qtySelector = document.querySelector('[name="qty"]');
15043        if (qtySelector) {
15044            qty = parseInt(qtySelector.value || 1);
15045        }
15046        
15047        // Ensure minimum quantity is 1
15048        qty = Math.max(1, qty);
15049
15050
15051        if (productId <= 0) {
15052            return true; // Let default handler deal with it
15053        }
15054
15055        // Event already prevented at interceptor level, just proceed with validation
15056        
15057        // Show loading state
15058        button.classList.add(config.loadingClass);
15059        const originalDisabled = button.disabled;
15060        const originalText = button.textContent;
15061        button.disabled = true;
15062        button.textContent = action === 'cart' ? 'Validasi...' : 'Validasi...';
15063        
15064        
15065        // PREEMPTIVE BLOCKING: Set blocking flags BEFORE validation to prevent race conditions
15066        if (window.addToCart && typeof window.addToCart === 'function') {
15067            window.addToCart._stockValidatorBlocked = true;
15068        }
15069        
15070        // Also preemptively block other cart functions
15071        const originalAddToCartSubmit = window.addToCartSubmit;
15072        const originalPdAddToCartSubmit = window._pdAddToCartSubmit;
15073        
15074        // Temporarily block ALL cart functions during validation
15075        window.addToCartSubmit = (...args) => {
15076            return Promise.resolve(false);
15077        };
15078        
15079        if (originalPdAddToCartSubmit) {
15080            window._pdAddToCartSubmit = (...args) => {
15081                return Promise.resolve(false);
15082            };
15083        }
15084        
15085        validateBeforeCart(productId, variantId, qty, action)
15086            .then(isValid => {
15087                if (isValid) {
15088                    // Stock OK, proceed with original action
15089                    
15090                    if (action === 'cart') {
15091                        // For mobile cart, we need to recreate the original behavior
15092                        // Strategy: Try multiple methods to ensure cart add + toast success
15093                        
15094                        
15095                        let cartAddSuccess = false;
15096                        let errorMessage = '';
15097                        
15098                        // Method 1: Try original addToCart function
15099                        const originalAddToCart = window.addToCart && window.addToCart._original;
15100                        if (originalAddToCart && !cartAddSuccess) {
15101                            try {
15102                                const result = originalAddToCart(productId, qty, variantId);
15103                                
15104                                // Handle both sync and async returns
15105                                if (result && typeof result.then === 'function') {
15106                                    result.then(() => {
15107                                        cartAddSuccess = true;
15108                                    }).catch(err => {
15109                                        errorMessage = err.message || 'addToCart failed';
15110                                    });
15111                                } else {
15112                                    cartAddSuccess = true;
15113                                }
15114                            } catch (error) {
15115                                errorMessage = error.message || 'addToCart exception';
15116                            }
15117                        }
15118                        
15119                        // Method 2: Try pd-addtocart.js function (backup method)
15120                        if (typeof window._pdAddToCartSubmit === 'function' && !cartAddSuccess) {
15121                            try {
15122                                
15123                                // Create fake form for pd-addtocart.js
15124                                const fakeForm = document.createElement('form');
15125                                const qtyInput = document.createElement('input');
15126                                qtyInput.name = 'qty';
15127                                qtyInput.value = qty;
15128                                fakeForm.appendChild(qtyInput);
15129                                
15130                                // Set variant selector value for pd-addtocart to read
15131                                const variantSelector = document.getElementById('pd-variant-id');
15132                                if (variantSelector) {
15133                                    variantSelector.value = variantId;
15134                                }
15135                                
15136                                const fakeEvent = { 
15137                                    preventDefault: () => {},
15138                                    target: fakeForm
15139                                };
15140                                
15141                                // Call pd-addtocart.js function (this should handle toast internally)
15142                                const result = window._pdAddToCartSubmit(fakeEvent, productId);
15143                                if (result && typeof result.then === 'function') {
15144                                    result.then(() => {
15145                                        cartAddSuccess = true;
15146                                    });
15147                                } else {
15148                                    cartAddSuccess = true;
15149                                }
15150                            } catch (error) {
15151                            }
15152                        }
15153                        
15154                        // Method 3: Direct addToCart call (fallback)
15155                        if (typeof window.addToCart === 'function' && !cartAddSuccess) {
15156                            try {
15157                                const result = window.addToCart(productId, qty, variantId);
15158                                if (result && typeof result.then === 'function') {
15159                                    result.then(() => {
15160                                        cartAddSuccess = true;
15161                                    });
15162                                } else {
15163                                    cartAddSuccess = true;
15164                                }
15165                            } catch (error) {
15166                            }
15167                        }
15168                        
15169                        // Always show success toast for mobile (regardless of which method worked)
15170                        // This ensures user gets feedback for successful cart addition
15171                        setTimeout(() => {
15172                            if (window.showToast) {
15173                                
15174                                // Get product details for toast
15175                                const getVariantSummaryText = () => {
15176                                    const vs = document.getElementById('pd-variant-summary');
15177                                    if (!vs) return '';
15178                                    const items = Array.from(vs.querySelectorAll('.vs-item strong'))
15179                                        .map(el => el.textContent.trim())
15180                                        .filter(Boolean);
15181                                    return items.length ? items.join(' / ') : '';
15182                                };
15183                                
15184                                const escapeHtml = (s) => String(s||'').replace(/[&<>"']/g, m=>({
15185                                    '&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#039;'
15186                                }[m]));
15187                                
15188                                const variantText = getVariantSummaryText();
15189                                const skuText = (function(){ 
15190                                    const el = document.getElementById('pd-sku'); 
15191                                    return el ? el.textContent.trim() : (window.PD_SKU || 'N/A'); 
15192                                })();
15193                                const productName = window.PD_NAME || 'Product';
15194                                
15195                                window.showToast({
15196                                    type: 'success',
15197                                    title: 'Berhasil ditambahkan ke Keranjang',
15198                                    message: `<strong>${escapeHtml(productName)}</strong>${variantText ? ` · <em>${escapeHtml(variantText)}</em>` : ''}<br>SKU: ${escapeHtml(skuText)}
15198 · Qty: ${qty}`,
15199                                    duration: 5000,
15200                                    actions: [
15201                                        { 
15202                                            label: 'Lihat Keranjang', 
15203                                            onClick: () => { window.location.href = '/keranjang'; }
15204                                        },
15205                                        { 
15206                                            label: 'Lanjut Belanja', 
15207                                            variant: 'alt', 
15208                                            onClick: () => {} 
15209                                        }
15210                                    ]
15211                                });
15212                            } else {
15213                            }
15214                        }, 100); // Small delay to ensure cart operation completes first
15215                        
15216                    } else if (action === 'buy') {
15217                        // For mobile buy, call buyNow
15218                        if (typeof window.buyNow === 'function') {
15219                            window.buyNow();
15220                        }
15221                    }
15222                } else {
15223                    // Stock validation FAILED - absolutely NO cart function calls allowed
15224                    
15225                    // DO NOT CALL ANY CART FUNCTIONS - only show modal (already handled by validateBeforeCart)
15226                }
15227                
15228                // Always restore functions after validation (success or failure)
15229                setTimeout(() => {
15230                    // Remove blocking flag
15231                    if (window.addToCart && typeof window.addToCart === 'function') {
15232                        window.addToCart._stockValidatorBlocked = false;
15233                    }
15234                    
15235                    // Restore other functions
15236                    if (originalAddToCartSubmit && typeof originalAddToCartSubmit === 'function') {
15237                        window.addToCartSubmit = originalAddToCartSubmit;
15238                    }
15239                    if (originalPdAddToCartSubmit && typeof originalPdAddToCartSubmit === 'function') {
15240                        window._pdAddToCartSubmit = originalPdAddToCartSubmit;
15241                    }
15242                    
15243                }, 1000); // Shorter timeout since we want to restore quickly after success
15244            })
15245            .catch(error => {
15246                // On error, also block the action
15247            })
15248            .finally(() => {
15249                // Remove loading state
15250                button.classList.remove(config.loadingClass);
15251                button.disabled = originalDisabled;
15252                button.textContent = originalText;
15253            });
15254
15255        return false;
15256    }
15257
15258    /**
15259     * Intercept cart buttons
15260     */
15261    function interceptCartButtons() {
15262
15263        
15264        // CRITICAL: Remove existing mobile cart handlers from product-detail.php
15265        setTimeout(() => {
15266            const mobileCartBtn = document.getElementById('mf-cart');
15267            if (mobileCartBtn) {
15268                // Clone the button to remove ALL existing event listeners
15269                const newBtn = mobileCartBtn.cloneNode(true);
15270                mobileCartBtn.parentNode.replaceChild(newBtn, mobileCartBtn);
15271
15272                
15273                // Add our own handler to the new button
15274                newBtn.addEventListener('click', function(event) {
15275                    event.preventDefault();
15276                    event.stopPropagation();
15277                    event.stopImmediatePropagation();
15278                    handleMobileButtonClick(event, 'cart');
15279                    return false;
15280                }, true);
15281            }
15282        }, 50);
15283        
15284        // Note: Add to cart buttons are now handled via form submission override (addToCartSubmit)
15285        // This provides better integration with existing pd-addtocart.js toast system
15286
15287        // Buy now buttons - updated selectors (desktop + mobile)
15288        addEventListener(document, 'click', function(event) {
15289            const target = event.target;
15290            
15291            // Desktop buy buttons
15292            if (target.classList.contains('btn-buy') ||           // Product detail buy button
15293                target.classList.contains('btn-buy-now') || 
15294                target.classList.contains('buy-now-btn') || 
15295                target.id === 'btn-buy' ||                        // Specific ID match
15296                getDataAttribute(target, 'action') === 'buy-now' ||
15297                getDataAttribute(target, 'action') === 'buy') {
15298                
15299                handleButtonClick(event, 'buy');
15300            }
15301            
15302            // Mobile buy buttons
15303            else if (target.classList.contains('mf-buy') ||       // Mobile fab buy button
15304                     target.id === 'mf-buy') {                   // Mobile buy button ID
15305                
15306                handleMobileButtonClick(event, 'buy');
15307            }
15308            
15309            // Mobile cart buttons - ENHANCED BLOCKING
15310            else if (target.classList.contains('mf-cart') ||      // Mobile fab cart button
15311                     target.id === 'mf-cart') {                  // Mobile cart button ID
15312                
15313                
15314                // Immediately prevent all event propagation
15315                event.preventDefault();
15316                event.stopPropagation();
15317                event.stopImmediatePropagation();
15318                
15319                handleMobileButtonClick(event, 'cart');
15320                
15321                // Return false to ensure no other handlers run
15322                return false;
15323            }
15324        }, true);
15324 // Use capturing phase to ensure we intercept before other handlers
15325        
15326        // Additional protection: Override addToCart function to add mobile button state checking
15327        const originalAddToCart = typeof window.addToCart === 'function' ? window.addToCart : null;
15328        if (originalAddToCart) {
15329            window.addToCart = async function(...args) {
15330                // Check if this call is coming from a mobile button that's currently being validated
15331                const mobileCartBtn = document.getElementById('mf-cart');
15332                if (mobileCartBtn && mobileCartBtn.classList.contains('loading-stock')) {
15333                    return Promise.reject(new Error('Mobile validation in progress - cart action blocked'));
15334                }
15335                
15336                // Check if functions are temporarily blocked (during stock failure)
15337                if (window.addToCart._stockValidatorBlocked) {
15338                    return Promise.reject(new Error('Stock validation failed - cart action blocked'));
15339                }
15340                
15341                // Allow normal calls
15342                return originalAddToCart.apply(this, args);
15343            };
15344            
15345            // Store reference to original for restoration
15346            window.addToCart._original = originalAddToCart;
15347        }
15348    }
15349
15350    /**
15351     * Setup global click interceptor for security
15352     * This catches ALL clicks on cart/buy buttons and validates stock BEFORE any other handler
15353     */
15354    function setupGlobalClickInterceptor() {
15355        // Add capture-phase listener to catch clicks before other handlers
15356        document.addEventListener('click', function(event) {
15357            const target = event.target;
15358            
15359            // Check if this is a cart/buy button
15360            const isCartButton = target.matches('.btn-add-cart, .mf-cart, #mf-cart, #btn-add-cart') ||
15361                                target.closest('.btn-add-cart, .mf-cart, #mf-cart, #btn-add-cart');
15362            const isBuyButton = target.matches('.btn-buy-now, .mf-buy, #mf-buy, #btn-buy') ||
15363                               target.closest('.btn-buy-now, .mf-buy, #mf-buy, #btn-buy');
15364                               
15365            if (!isCartButton && !isBuyButton) {
15366                return; // Not our target, allow normal processing
15367            }
15368            
15369            const button = isCartButton ? 
15370                (target.matches('.btn-add-cart, .mf-cart, #mf-cart, #btn-add-cart') ? target : target.closest('.btn-add-cart, .mf-cart, #mf-cart, #btn-add-cart')) :
15371                (target.matches('.btn-buy-now, .mf-buy, #mf-buy, #btn-buy') ? target : target.closest('.btn-buy-now, .mf-buy, #mf-buy, #btn-buy'));
15372            
15373            // IMMEDIATE BLOCK: Prevent any processing first
15374            event.preventDefault();
15375            event.stopImmediatePropagation();
15376            
15377            // SECURITY CHECK 1: Is button marked as stock-blocked?
15378            if (button && button.hasAttribute('data-stock-blocked')) {
15379                
15380                const reason = button.getAttribute('data-stock-reason') || 'Stok tidak tersedia';
15381                showStockModal(reason);
15382                
15383                // Show security alert
15384                if (window.showToast) {
15385                    window.showToast({
15386                        type: 'error',
15387                        title: 'Aksi Diblokir',
15388                        message: 'Produk ini sedang habis stok dan tidak dapat ditambahkan ke keranjang.',
15389                        duration: 4000
15390                    });
15391                }
15392                
15393                return false;
15394            }
15395            
15396            // SECURITY CHECK 2: Real-time validation against cached stock info
15397            if (window._currentStockInfo && !window._currentStockInfo.can_add_to_cart) {
15398                
15399                showStockModal(window._currentStockInfo.message || 'Stok tidak tersedia');
15400                
15401                // Re-enforce button disabling
15402                if (button) {
15403                    button.disabled = true;
15404                    button.style.opacity = '0.5';
15405                    button.style.cursor = 'not-allowed';
15406                    button.setAttribute('data-stock-blocked', 'true');
15407                    button.setAttribute('data-stock-reason', window._currentStockInfo.message || 'Stok tidak tersedia');
15408                }
15409                
15410                return false;
15411            }
15412            
15413            // SECURITY CHECK 3: Smart client-side validation
15414            const productId = window.PD_ID ? parseInt(window.PD_ID) : 0;
15415            const variantSelector = document.getElementById('pd-variant-id');
15416            const variantId = variantSelector ? parseInt(variantSelector.value || 0
15416) : 0;
15417            
15418            if (productId > 0) {
15419                // SMART VALIDATION: If we already have cached stock info showing stock is available,
15420                // and buttons are enabled, proceed immediately without re-validation
15421                if (window._currentStockInfo && window._currentStockInfo.can_add_to_cart && 
15422                    button && !button.disabled && !button.hasAttribute('data-stock-blocked')) {
15423                    
15424                    // Allow the action to proceed immediately with toast
15425                    if (isCartButton) {
15426                        // Trigger cart action with proper toast handling
15427                        if (typeof window._pdAddToCartSubmit === 'function') {
15428                            // Use pd-addtocart.js function for proper toast handling
15429                            const form = document.getElementById('pd-buy-form') || button.closest('form');
15430                            if (form) {
15431                                const fakeEvent = { 
15432                                    target: form,
15433                                    preventDefault: () => {}
15434                                };
15435                                window._pdAddToCartSubmit(fakeEvent, productId);
15436                            }
15437                        } else if (typeof window.addToCartSubmit === 'function') {
15438                            // Fallback to addToCartSubmit
15439                            const form = document.getElementById('pd-buy-form') || button.closest('form');
15440                            if (form) {
15441                                const fakeEvent = { 
15442                                    target: form,
15443                                    preventDefault: () => {}
15444                                };
15445                                window.addToCartSubmit(fakeEvent, productId);
15446                            }
15447                        } else if (typeof window.addToCart === 'function') {
15448                            // Direct addToCart call
15449                            window.addToCart(productId, 1, variantId);
15450                        }
15451                    } else if (isBuyButton) {
15452                        // Trigger buy action
15453                        if (typeof window.buyNow === 'function') {
15454                            window.buyNow();
15455                        }
15456                    }
15457                    
15458                    return false; // Action completed
15459                }
15460                
15461                // Get stock info from embedded variant data (for variant products)
15462                const stockInfo = getStockFromEmbeddedData(variantId);
15463                
15464                if (stockInfo && stockInfo.hasStock) {
15465                    
15466                    // Update global stock cache
15467                    window._currentStockInfo = {
15468                        can_add_to_cart: true,
15469                        is_in_stock: true,
15470                        available_stock: stockInfo.stock,
15471                        message: 'Stok tersedia'
15472                    };
15473                    
15474                    // IMPORTANT: Check if button was explicitly blocked by variant logic (e.g., pre-order exhausted)
15475                    // If data-stock-blocked is set, respect it and don't enable the button
15476                    const isExplicitlyBlocked = button.getAttribute('data-stock-blocked') === 'true';
15477                    
15478                    if (!isExplicitlyBlocked) {
15479                        // Remove stock blocking if it was set and enable button
15480                        button.removeAttribute('data-stock-blocked');
15481                        button.removeAttribute('data-stock-reason');
15482                        button.disabled = false;
15483                        button.style.opacity = '';
15484                        button.style.cursor = '';
15485                        button.classList.remove(config.disabledClass);
15486                    } else {
15487                        // Button is blocked by variant logic, show reason
15488                        const reason = button.getAttribute('data-stock-reason') || 'Tidak tersedia';
15489                        console.log('Button blocked by variant logic:', reason);
15490                        e.preventDefault();
15491                        e.stopPropagation();
15492                        return false;
15493                    }
15494                    
15495                    // Allow the action to proceed immediately with toast
15496                    if (isCartButton) {
15497                        // Trigger cart action with proper toast handling
15498                        if (typeof window._pdAddToCartSubmit === 'function') {
15499                            // Use pd-addtocart.js function for proper toast handling
15500                            const form = document.getElementById('pd-buy-form') || button.closest('form');
15501                            if (form) {
15502                                const fakeEvent = { 
15503                                    target: form,
15504                                    preventDefault: () => {}
15505                                };
15506                                window._pdAddToCartSubmit(fakeEvent, productId);
15507                            }
15508                        } else if (typeof window.addToCartSubmit === 'function') {
15509                            // Fallback to addToCartSubmit
15510                            const form = document.getElementById('pd-buy-form') || button.closest('form');
15511                            if (form) {
15512                                const fakeEvent = { 
15513                                    target: form,
15514                                    preventDefault: () => {}
15515                                };
15516                                window.addToCartSubmit(fakeEvent, productId);
15517                            }
15518                        } else if (typeof window.addToCart === 'function') {
15519                            // Direct addToCart call
15520                            window.addToCart(productId, 1, variantId);
15521                        }
15522                    } else if (isBuyButton) {
15523                        // Trigger buy action
15524                        if (typeof window.buyNow === 'function') {
15525                            window.buyNow();
15526                        }
15527                    }
15528                } else if (stockInfo && !stockInfo.hasStock) {
15529                    
15530                    // Update global stock cache
15531                    window._currentStockInfo = {
15532                        can_add_to_cart: false,
15533                        is_in_stock: false,
15534                        available_stock: stockInfo.stock,
15535                        message: `Stok tidak tersedia${stockInfo.sku ? ` untuk ${stockInfo.sku}` : ''}`
15536                    };
15537                    
15538                    // Force block button
15539                    button.disabled = true;
15540                    button.style.opacity = '0.5';
15541                    button.style.cursor = 'not-allowed';
15542                    button.setAttribute('data-stock-blocked', 'true');
15543                    button.setAttribute('data-stock-reason', window._currentStockInfo.message);
15544                    
15545                    // Show modal with variant info
15546                    const modalMessage = stockInfo ? 
15547                        `Varian yang dipilih (${stockInfo.sku}) sedang habis stok. Silakan pilih varian lain.` :
15548                        'Produk ini sedang habis stok. Silakan pilih varian lain.';
15549                    
15550                    showStockModal(modalMessage);
15551                    
15552                    // Show security warning
15553                    if (window.showToast) {
15554                        window.showToast({
15555                            type: 'warning',
15556                            title: 'Stok Tidak Tersedia',
15557                            message: 'Varian yang dipilih sedang habis stok. Silakan pilih varian lain.',
15558                            duration: 3000
15559                        });
15560                    }
15561                } else {
15562                    // stockInfo is null (simple product) - this means embedded data is not available
15563                    // For simple products, if buttons are enabled, we should proceed (trust the API response from updateStockDisplay)
15564                    if (button && !button.disabled && !button.hasAttribute('data-stock-blocked')) {
15565                        
15566                        // Allow the action to proceed immediately with toast
15567                        if (isCartButton) {
15568                            // Trigger cart action with proper toast handling
15569                            if (typeof window._pdAddToCartSubmit === 'function') {
15570                                // Use pd-addtocart.js function for proper toast handling
15571                                const form = document.getElementById('pd-buy-form') || button.closest('form');
15572                                if (form) {
15573                                    const fakeEvent = { 
15574                                        target: form,
15575                                        preventDefault: () => {}
15576                                    };
15577                                    window._pdAddToCartSubmit(fakeEvent, productId);
15578                                }
15579                            } else if (typeof window.addToCartSubmit === 'function') {
15580                                // Fallback to addToCartSubmit
15581                                const form = document.getElementById('pd-buy-form') || button.closest('form');
15582                                if (form) {
15583                                    const fakeEvent = { 
15584                                        target: form,
15585                                        preventDefault: () => {}
15586                                    };
15587                                    window.addToCartSubmit(fakeEvent, productId);
15588                                }
15589                            } else if (typeof window.addToCart === 'function') {
15590                                // Direct addToCart call
15591                                window.addToCart(productId, 1, variantId);
15592                            }
15593                        } else if (isBuyButton) {
15594                            // Trigger buy action
15595                            if (typeof window.buyNow === 'function') {
15596                                window.buyNow();
15597                            }
15598                        }
15599                    } else {
15600                        // Button is disabled, don't allow action
15601                        showStockModal('Produk ini sedang tidak tersedia.');
15602                    }
15603                }
15604            } else {
15605                // No product ID, block action
15606                showStockModal('Data produk tidak valid.');
15607            }
15608            
15609            return false; // Always block at capture phase
15610            
15611        }, true); // Use capture phase to run BEFORE other listeners
15612        
15613
15614    }
15615
15616    /**
15617     * Initialize button data attributes from current page
15618     */
15619    function initializeButtonAttributes() {
15620        // Get product data from page globals or form
15621        let productId = 0, variantId = 0;
15622        
15623        // Try to get from global variables (set by PHP)
15624        if (window.PD_ID) productId = parseInt(window.PD_ID);
15625        
15626        // Try to get from form
15627        const form = document.getElementById('pd-buy-form');
15628        if (form) {
15629            const pidAttr = form.getAttribute('data-pid');
15630            if (pidAttr) productId = parseInt(pidAttr);
15631            
15632            const varInput = document.getElementById('pd-variant-id');
15633            if (varInput) variantId = parseInt(varInput.value || 0);
15634        }
15635        
15636        // Try to get from mobile FAB
15637        const mobileFab = document.getElementById('pd-mobile-fab');
15638        if (mobileFab && productId <= 0) {
15639            const pidAttr = getDataAttribute(mobileFab, 'pid');
15640            if (pidAttr) productId = parseInt(pidAttr);
15641        }
15642        
15643        // Set attributes on desktop buttons
15644        const desktopButtons = document.querySelectorAll('.btn-add-cart, .btn-buy-now, #btn-add-cart, #btn-buy, #btn-buy-voucher');
15645        desktopButtons.forEach(button => {
15646            if (productId > 0) {
15647                button.setAttribute('data-product-id', productId);
15648                if (variantId > 0) {
15649                    button.setAttribute('data-variant-id', variantId);
15650                }
15651            }
15652        });
15653        
15654        // Set attributes on mobile buttons
15655        const mobileButtons = document.querySelectorAll('.mf-cart, .mf-buy, #mf-cart, #mf-buy');
15656        mobileButtons.forEach(button => {
15657            if (productId > 0) {
15658                button.setAttribute('data-product-id', productId);
15659                if (variantId > 0) {
15660                    button.setAttribute('data-variant-id', variantId);
15661                }
15662            }
15663        });
15664        
15665
15666        
15667        // Initial stock display update on page load
15668        if (productId > 0) {
15669            setTimeout(() => {
15670                updateStockDisplay(productId, variantId);
15671
15672            }, 100);
15673        }
15674    }
15675
15676    /**
15677     * Update button attributes when variant changes
15678     */
15679    function updateButtonAttributesForVariant(variantId) {
15680        const productId = window.PD_ID ? parseInt(window.PD_ID) : 0;
15681        
15682        if (productId <= 0) return;
15683        
15684        // Update desktop buttons
15685        const desktopButtons = document.querySelectorAll('.btn-add-cart, .btn-buy-now, #btn-add-cart, #btn-buy, #btn-buy-voucher');
15686        desktopButtons.forEach(button => {
15687            button.setAttribute('data-product-id', productId);
15688            if (variantId > 0) {
15689                button.setAttribute('data-variant-id', variantId);
15690            } else {
15691                button.removeAttribute('data-variant-id');
15692            }
15693        });
15694        
15695        // Update mobile buttons
15696        const mobileButtons = document.querySelectorAll('.mf-cart, .mf-buy, #mf-cart, #mf-buy');
15697        mobileButtons.forEach(button => {
15698            button.setAttribute('data-product-id', productId);
15699            if (variantId > 0) {
15700                button.setAttribute('data-variant-id', variantId);
15701            } else {
15702                button.removeAttribute('data-variant-id');
15703            }
15704        });
15705        
15706
15707    }
15708
15709    /**
15710     * Setup variant change integration with existing product-detail.php handlers
15711     */
15712    function setupVariantChangeIntegration() {
15713        // Strategy: Hook into existing applyVariant function instead of adding new listener
15714        // This prevents conflicts with existing variant change functionality (gallery, pricing, etc.)
15715        
15716        // Method 1: Hook into existing applyVariant function
15717        setTimeout(() => {
15718            if (typeof window.applyVariant === 'function') {
15719                const originalApplyVariant = window.applyVariant;
15720                window.applyVariant = function(v, focusImage) {
15721                    // Call original function first
15722                    const result = originalApplyVariant.call(this, v, focusImage);
15723                    
15724                // Then add our stock validator logic
15725                const variantId = v ? (v.id || v.ID || 0) : 0;
15726                
15727                // Update button attributes for stock validator
15728                updateButtonAttributesForVariant(variantId);
15729                
15730                // Update stock display using embedded data (instant)
15731                const productId = window.PD_ID ? parseInt(window.PD_ID) : 0;
15732                if (productId > 0) {
15733                    updateStockDisplay(productId, variantId);
15734                }                    return result;
15735                };
15736                
15737
15738            } else {
15739
15740                setupVariantObserver();
15741            }
15742        }, 500);
15743        
15744        // Method 2: Direct observation of hidden input value changes (fallback)
15745        setTimeout(() => {
15746            setupVariantObserver();
15747        }, 1000);
15748    }
15749
15750    /**
15751     * Setup variant observer as fallback when applyVariant hook fail
15751s
15752     */
15753    function setupVariantObserver() {
15754        const variantInput = document.getElementById('pd-variant-id');
15755        if (variantInput) {
15756            let lastVariantId = parseInt(variantInput.value || '0');
15757            
15758            // Use MutationObserver to watch for value changes
15759            if (window.MutationObserver) {
15760                const observer = new MutationObserver((mutations) => {
15761                    mutations.forEach((mutation) => {
15762                        if (mutation.type === 'attributes' && mutation.attributeName === 'value') {
15763                            const newVariantId = parseInt(variantInput.value || '0');
15764                            if (newVariantId !== lastVariantId) {
15765                    
15766                                updateButtonAttributesForVariant(newVariantId);
15767                                
15768                                // Update stock display with embedded data
15769                                const productId = window.PD_ID ? parseInt(window.PD_ID) : 0;
15770                                if (productId > 0) {
15771                                    updateStockDisplay(productId, newVariantId);
15772                                }
15773                                
15774                                lastVariantId = newVariantId;
15775                            }
15776                        }
15777                    });
15778                });
15779                
15780                observer.observe(variantInput, { 
15781                    attributes: true, 
15782                    attributeFilter: ['value'] 
15783                });
15784                
15785
15786            }
15787            
15788            // Additional polling as ultimate fallback
15789            setInterval(() => {
15790                const currentVariantId = parseInt(variantInput.value || '0');
15791                if (currentVariantId !== lastVariantId) {
15792        
15793                    updateButtonAttributesForVariant(currentVariantId);
15794                    
15795                    // Update stock display with embedded data
15796                    const productId = window.PD_ID ? parseInt(window.PD_ID) : 0;
15797                    if (productId > 0) {
15798                        updateStockDisplay(productId, currentVariantId);
15799                    }
15800                    
15801                    lastVariantId = currentVariantId;
15802                }
15803            }, 1000);
15804            
15805
15806        }
15807    }
15808
15809    /**
15810     * Update stock display and enforce stock-based button blocking using embedded data
15811     */
15812    function updateStockDisplay(productId, variantId = 0) {
15813
15814        
15815        // Get stock info from embedded data (instant)
15816        const embeddedStockInfo = getStockFromEmbeddedData(variantId);
15817        
15818        let stockInfo;
15819        if (embeddedStockInfo) {
15820            // Convert embedded data to standard format
15821            stockInfo = {
15822                can_add_to_cart: embeddedStockInfo.hasStock,
15823                is_in_stock: embeddedStockInfo.hasStock,
15824                available_stock: embeddedStockInfo.stock,
15825                message: embeddedStockInfo.hasStock ? 'Stok tersedia' : `Stok habis${embeddedStockInfo.sku ? ` untuk ${embeddedStockInfo.sku}` : ''}`,
15826                product_name: window.PD_NAME || 'Produk',
15827                sku: embeddedStockInfo.sku
15828            };
15829            
15830
15831        } else {
15832            // Fallback to API call if embedded data not available
15833
15834            checkStock(productId, variantId, 1)
15835                .then(apiStockInfo => {
15836                    updateStockDisplayWithInfo(apiStockInfo, productId, variantId);
15837                })
15838                .catch(error => {
15839                    console.error('Failed to update stock display via API:', error);
15840                });
15841            return;
15842        }
15843        
15844        updateStockDisplayWithInfo(stockInfo, productId, variantId);
15845    }
15846
15847    /**
15848     * Update stock display with provided stock info
15849     */
15850    function updateStockDisplayWithInfo(stockInfo, productId, variantId) {
15851        // Store current stock status globally for blocking checks
15852        window._currentStockInfo = stockInfo;
15853        
15854        // Update stock indicators
15855        const stockIndicators = document.querySelectorAll('.stock-indicator');
15856        stockIndicators.forEach(indicator => {
15857            if (stockInfo.is_in_stock) {
15858                indicator.classList.add('in-stock');
15859                indicator.classList.remove('out-of-stock');
15860            } else {
15861                indicator.classList.add('out-of-stock');
15862                indicator.classList.remove('in-stock');
15863            }
15864        });
15865        
15866        // Update stock count
15867        const stockCounts = document.querySelectorAll('.stock-count');
15868        stockCounts.forEach(count => {
15869            count.textContent = stockInfo.available_stock || 0;
15870        });
15871        
15872        // CRITICAL: For digital products, DO NOT modify button states here
15873        // PHP already handles button disable/enable based on LICENSE_POOL count
15874        // Only physical products need JavaScript stock validation
15875        const isDigitalProduct = window.IS_DIGITAL === true || window.IS_DIGITAL === 'true';
15876        
15877        if (isDigitalProduct) {
15878            // For digital products: ONLY update global stock info, don't touch buttons
15879            // Let PHP-rendered disabled state remain authoritative
15880            console.log('[Stock Validator] Digital product detected - skipping button state modification');
15881            return; // Exit early, preserve PHP-set button states
15882        }
15883        
15884        // ENHANCED: Force disable buttons for out-of-stock with anti-tampering (PHYSICAL PRODUCTS ONLY)
15885        const allButtons = document.querySelectorAll('.btn-add-cart, .btn-buy-now, .mf-cart, .mf-buy, #btn-add-cart, #btn-buy, #btn-buy-voucher, #mf-cart, #mf-buy');
15886        allButtons.forEach(button => {
15887            if (stockInfo.can_add_to_cart) {
15888                // STOCK AVAILABLE - ENABLE BUTTONS
15889                button.classList.remove(config.disabledClass);
15890                button.disabled = false;
15891                button.style.opacity = '';
15892                button.style.cursor = '';
15893                
15894                // CRITICAL: Remove stock blocking attributes when stock becomes available
15895                button.removeAttribute('data-stock-blocked');
15896                button.removeAttribute('data-stock-reason');
15897                
15898
15899            } else {
15900                // OUT OF STOCK - FORCE DISABLE WITH ANTI-TAMPERING
15901                button.classList.add(config.disabledClass);
15902                button.disabled = true;
15903                button.style.opacity = '0.5';
15904                button.style.cursor = 'not-allowed';
15905                
15906                // Mark as stock-blocked to prevent re-enabling
15907                button.setAttribute('data-stock-blocked', 'true');
15908                button.setAttribute('data-stock-reason', stockInfo.message || 'Stok tidak tersedia');
15909                
15910
15911            }
15912        });
15913        
15914        // Start aggressive button monitoring for out-of-stock variants
15915        if (!stockInfo.can_add_to_cart) {
15916            enforceStockDisabling(productId, variantId);
15917        }
15918        
15919
15920    }
15921
15922    /**
15923     * Aggressively enforce button disabling for out-of-stock items
15924     * CRITICAL: For digital products, DO NOT modify button states (PHP is authoritative)
15925     */
15926    function enforceStockDisabling(productId, variantId) {
15927        // CRITICAL: Skip enforcement for digital products - PHP handles button states
15928        const isDigitalProduct = window.IS_DIGITAL === true || window.IS_DIGITAL === 'true';
15929        if (isDigitalProduct) {
15930            console.log('[Stock Validator] Digital product - skipping button enforcement');
15931            return; // Exit early, let PHP-rendered disabled state remain
15932        }
15933        
15934        const monitorInterval = setInterval(() => {
15935            // Check if variant changed
15936            const currentVariantSelector = document.getElementById('pd-variant-id');
15937            const currentVariantId = currentVariantSelector ? parseInt(currentVariantSelector.value || 0) : 0;
15938            
15939            if (currentVariantId !== variantId) {
15940                // Variant changed, stop monitoring this variant
15941                clearInterval(monitorInterval);
15942
15943                return;
15944            }
15945            
15946            // Check current stock status using embedded data (real-time check)
15947            const currentStockInfo = getStockFromEmbeddedData(currentVariantId);
15948            
15949            if (currentStockInfo && !currentStockInfo.hasStock) {
15950                // Still out of stock - continue monitoring for tampering
15951                const buttons = document.querySelectorAll('.btn-add-cart, .btn-buy-now, .mf-cart, .mf-buy, #btn-add-cart, #btn-buy, #btn-buy-voucher, #mf-cart, #mf-buy');
15952                buttons.forEach(button => {
15953                    // Check if button was manually enabled (inspect attack)
15954                    if (!button.disabled || button.style.opacity !== '0.5') {
15955                        
15956                        // Force re-disable
15957                        button.disabled = true;
15958                        button.style.opacity = '0.5';
15959                        button.style.cursor = 'not-allowed';
15960                        button.setAttribute('data-stock-blocked', 'true');
15961                        button.setAttribute('data-stock-reason', `Stok tidak tersedia${currentStockInfo.sku ? ` untuk ${currentStockInfo.sku}` : ''}`);
15962                        
15963                        // Show warning toast
15964                        if (window.showToast) {
15965                            window.showToast({
15966                                type: 'warning',
15967                                title: 'Aksi Tidak Diizinkan',
15968                                message: 'Produk ini sedang habis stok. Silakan pilih varian lain.',
15969                                duration: 3000
15970                            });
15971                        }
15972                    }
15973                });
15974            } else {
15975                // Stock available OR embedded data shows stock - stop monitoring
15976                clearInterval(monitorInterval);
15977
15978                // For PHYSICAL products only, enable buttons
15979                // For DIGITAL products, skip (PHP is authoritative)
15980                const isDigitalProduct = window.IS_DIGITAL === true || window.IS_DIGITAL === 'true';
15981                
15982                if (!isDigitalProduct && currentStockInfo && currentStockInfo.hasStock) {
15983                    const buttons = document.querySelectorAll('.btn-add-cart, .btn-buy-now, .mf-cart, .mf-buy, #btn-add-cart, #btn-buy, #btn-buy-voucher, #mf-cart, #mf-buy');
15984                    buttons.forEach(button => {
15985                        button.disabled = false;
15986                        button.style.opacity = '';
15987                        button.style.cursor = '';
15988                        button.removeAttribute('data-stock-blocked');
15989                        button.removeAttribute('data-stock-reason');
15990                        button.classList.remove(config.disabledClass);
15991                    });
15992
15993                }
15994            }
15995        }, 500); // Check every 500ms for tampering attempts
15996        
15997        // Auto-stop monitoring after 30 seconds to prevent memory leaks
15998        setTimeout(() => {
15999            clearInterval(monitorInterval);
16000
16001        }, 30000);
16002    }
16003
16004    /**
16005     * Override addToCartSubmit function to add stock validation
16006     * This function now works with pd-addtocart.js integration
16007     */
16008    function overrideAddToCartSubmitFunction() {
16009        // Check if pd-addtocart.js is already loaded
16010        const pdAddToCartExists = typeof window.addToCartSubmit === 'function' && 
16011                                  window.addToCartSubmit.toString().includes('showToast');
16012        
16013        if (pdAddToCartExists) {
16014
16015            
16016            // Store the pd-addtocart.js function
16017            const pdAddToCartSubmit = window.addToCartSubmit;
16018            window._pdAddToCartSubmit = pdAddToCartSubmit;
16019            
16020            // Override with stock validation that calls pd-addtocart.js
16021            window.addToCartSubmit = async function(e, productId) {
16022                
16023                // Don't prevent default here - let pd-addtocart handle it if stock is valid
16024                
16025                try {
16026                    // Extract product data from form (same way as pd-addtocart.js)
16027                    const form = e.target;
16028                    const qty = parseInt(form.querySelector('[name=qty]')?.value || '1', 10) || 1;
16029                    
16030                    // CRITICAL: Always get current variant from selector (real-time)
16031                    let variantId = 0;
16032                    const variantSelector = document.getElementById('pd-variant-id');
16033                    if (variantSelector) {
16034                        variantId = parseInt(variantSelector.value || '0', 10) || 0;
16035                    }
16036                    
16037                    if (!productId || productId <= 0) {
16038                        return pdAddToCartSubmit(e, productId);
16039                    }
16040
16041
16042                    // Validate stock before proceeding
16043                    const isValid = await validateBeforeCart(productId, variantId, qty, 'cart');
16044                    
16045                    if (isValid) {
16046                        // Stock OK, call pd-addtocart.js function (it will handle toast)
16047                        return pdAddToCartSubmit(e, productId);
16048                    } else {
16049                        // Prevent the form submission
16050                        e.preventDefault();
16051                        // Stock validation failed, modal already shown by validateBeforeCart
16052                        return false;
16053                    }
16054                    
16055                } catch (error) {
16056                    e.preventDefault();
16057                    // On error, show modal and don't proceed
16058                    showStockModal({ 
16059                        message: 'Terjadi kesalahan saat memvalidasi stok. Silakan coba lagi.',
16060                        is_active: false 
16061                    }, 'cart');
16062                    return false;
16063                }
16064            };
16065        } else {
16066            // Original logic for when pd-addtocart.js is not present
16067            const originalAddToCartSubmit = typeof window.addToCartSubmit === 'function' ? window.addToCartSubmit : null;
16068            
16069            if (originalAddToCartSubmit) {
16070                window._originalAddToCartSubmit = originalAddToCartSubmit;
16071            }
16072            
16073            // Override with stock validation
16074            window.addToCartSubmit = async function(e, productId) {
16075                
16076                e.preventDefault();
16077                
16078                try {
16079                    const form = e.target;
16080                    const qty = parseInt(form.querySelector('[name=qty]')?.value || '1', 10) || 1;
16081                    
16082                    // CRITICAL: Always get current variant from selector (real-time)
16083                    let variantId = 0;
16084                    const variantSelector = document.getElementById('pd-variant-id');
16085                    if (variantSelector) {
16086                        variantId = parseInt(variantSelector.value || '0', 10) || 0;
16087                    }
16088                    
16089                    if (!productId || productId <= 0) {
16090                        if (originalAddToCartSubmit) return originalAddToCartSubmit(e, productId);
16091                        return false;
16092                    }
16093
16094
16095                    const isValid = await validateBeforeCart(productId, variantId, qty, 'cart');
16096                    
16097                    if (isValid) {
16098                        if (originalAddToCartSubmit) {
16099                            return originalAddToCartSubmit(e, productId);
16100                        } else {
16101                            if (typeof window.addToCart === 'function') {
16102                                await window.addToCart(productId, qty, variantId);
16103                            }
16104                        }
16105                    } else {
16106                    }
16107                    
16108                } catch (error) {
16109                    showStockModal({ 
16110                        message: 'Terjadi kesalahan saat memvalidasi stok. Silakan coba lagi.',
16111                        is_active: false 
16112                    }, 'cart');
16113                }
16114                
16115                return false;
16116            };
16117        }
16118
16119
16120    }
16121
16122    /**
16123     * Override buyNow function to add stock validation
16124     */
16125    function overrideBuyNowFunction() {
16126        // Store original buyNow function if it exists
16127        const originalBuyNow = typeof window.buyNow === 'function' ? window.buyNow : null;
16128        
16129        // Override with stock validation
16130        window.buyNow = async function(e) {
16131            
16132            try {
16133                // Get product data (same way as pd-buynow.js)
16134                const form = document.getElementById('pd-buy-form');
16135                if (!form) {
16136                    if (originalBuyNow) return originalBuyNow(e);
16137                    return;
16138                }
16139
16140                const productId = parseInt(form.dataset.pid || '0', 10);
16141                const qty = parseInt(form.querySelector('[name=qty]')?.value || '1', 10) || 1;
16142                
16143                // CRITICAL: Always get current variant from selector (real-time)
16144                let variantId = 0;
16145                const variantSelector = document.getElementById('pd-variant-id');
16146                if (variantSelector) {
16147                    variantId = parseInt(variantSelector.value || '0', 10) || 0;
16148                }
16149                
16150                if (!productId || productId <= 0) {
16151                    if (originalBuyNow) return originalBuyNow(e);
16152                    return;
16153                }
16154
16155
16156                // Validate stock before proceeding
16157                const isValid = await validateBeforeCart(productId, variantId, qty, 'buy');
16158                
16159                if (isValid) {
16160                    // Stock OK, call original buyNow function
16161                    if (originalBuyNow) {
16162                        return originalBuyNow(e);
16163                    } else {
16164                    }
16165                } else {
16166                    // Stock validation failed, modal already shown by validateBeforeCart
16167                }
16168                
16169            } catch (error) {
16170                // On error, show modal and don't proceed
16171                showStockModal({ 
16172                    message: 'Terjadi kesalahan saat memvalidasi stok. Silakan coba lagi.',
16173                    is_active: false 
16174                }, 'buy');
16175            }
16176        };
16177
16178
16179    }
16180
16181    /**
16182     * Initialize stock validation
16183     */
16184    function init() {
16185        // Wait for DOM ready
16186        if (document.readyState === 'loading') {
16187            addEventListener(document, 'DOMContentLoaded', function() {
16188        initializeButtonAttributes();
16189        setupVariantChangeIntegration(); // Setup variant change integration
16190        interceptCartButtons();
16191        setupGlobalClickInterceptor(); // Setup global click security interceptor                // Override functions after other scripts load
16192                // Use multiple timeouts to catch late-loading scripts like pd-addtocart.js
16193                setTimeout(() => {
16194                    overrideAddToCartSubmitFunction();
16195                    overrideBuyNowFunction();
16196                }, 100);
16197                
16198                setTimeout(() => {
16199                    // Re-check and re-override if pd-addtocart.js loaded later
16200                    overrideAddToCartSubmitFunction();
16201                }, 500);
16202                
16203                setTimeout(() => {
16204                    // Final check for very late loading scripts
16205                    overrideAddToCartSubmitFunction();
16206                }, 1000);
16207                
16208
16209            });
16210        } else {
16211            initializeButtonAttributes();
16212            setupVariantChangeIntegration(); // Setup variant change integration
16213            interceptCartButtons();
16214            setupGlobalClickInterceptor(); // Setup global click security interceptor
16215            
16216            // Override functions after other scripts load
16217            // Use multiple timeouts to catch late-loading scripts like pd-addtocart.js
16218            setTimeout(() => {
16219                overrideAddToCartSubmitFunction();
16220                overrideBuyNowFunction();
16221            }, 100);
16222            
16223            setTimeout(() => {
16224                // Re-check and re-override if pd-addtocart.js loaded later
16225                overrideAddToCartSubmitFunction();
16226            }, 500);
16227            
16228            setTimeout(() => {
16229                // Final check for very late loading scripts
16230                overrideAddToCartSubmitFunction();
16231            }, 1000);
16232            
16233
16234        }
16235    }
16236
16237    // Public API
16238    return {
16239        init: init,
16240        checkStock: checkStock,
16241        validateBeforeCart: validateBeforeCart,
16242        updateStockDisplay: updateStockDisplay,
16243        showStockModal: showStockModal,
16244        config: config
16245    };
16246})();
16247
16248// Auto-initialize
16249if (typeof window !== 'undefined') {
16250    StockValidator.init();
16251}
16252
16253</script>
vendor: 2 bytes, line 16253
16253
16254<script data-inlined="pd-addtocart.js">
16255(function(){
16256  function esc(s){ return String(s||'').replace(/[&<>"']/g, m=>({ '&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#039;' }[m])); }
16257  function getVariantSummaryText(){
16258    const vs = document.getElementById('pd-variant-summary');
16259    if (!vs) return '';
16260    const items = Array.from(vs.querySelectorAll('.vs-item strong')).map(el => el.textContent.trim()).filter(Boolean);
16261    return items.length ? items.join(' / ') : '';
16262  }
16263  window.addToCartSubmit = async function(e, productId){
16264    e.preventDefault();
16265    try {
16266      const form = e.target;
16267      const qty = parseInt(form.querySelector('[name=qty]')?.value || '1', 10) || 1;
16268      const variantId = parseInt(document.getElementById('pd-variant-id')?.value || '0', 10) || 0;
16269      await (window.addToCart ? window.addToCart(productId, qty, variantId) : Promise.reject(new Error('addToCart tidak tersedia')));
16270
16271      if (window.PlazaAnalytics) {
16272        window.PlazaAnalytics.track('add_to_cart', { slug: String(window._pit_slug || '') });
16273      }
16274
16275      const name = (window.PD_NAME !== undefined) ? String(window.PD_NAME) : (document.getElementById('pd-title')?.textContent || '');
16276      const sku  = (function(){ const el=document.getElementById('pd-sku'); return el?el.textContent.trim(): (window.PD_SKU||''); })();
16277      const variantText = getVariantSummaryText();
16278
16279      if (window.showToast) {
16280        window.showToast({
16281          type: 'success',
16282          title: 'Berhasil ditambahkan ke Keranjang',
16283          message: `<strong>${esc(name)}</strong>${variantText?` · <em>${esc(variantText)}</em>`:''}<br>SKU: ${esc(sku)} · Qty: ${qty}`,
16284          duration: 5000,
16285          actions: [
16286            { label: 'Lihat Keranjang', onClick: ()=> { window.location.href = '/keranjang'; } },
16287            { label: 'Lanjut Belanja', variant: 'alt', onClick: ()=>{} }
16288          ]
16289        });
16290      }
16291    } catch (err) {
16292      if (window.showToast) {
16293        window.showToast({ type:'warn', title:'Gagal menambahkan', message: String(err?.message||'Terjadi kesalahan'), duration: 4500 });
16294      } else {
16295        console.error(err);
16296      }
16297    }
16298    return false;
16299  };
16300})();
16301</script>
vendor: 2 bytes, line 16301
16301
16302<script data-inlined="pd-buynow.js">
16303(function(){
16304  
16305  // CSRF Token Helper
16306  function getCsrfToken() {
16307    return document.querySelector('meta[name="csrf-token"]')?.getAttribute('content') || '';
16308  }
16309  
16310  // Utility functions
16311  function esc(s){ return String(s||'').replace(/[&<>"']/g, m=>({ '&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#039;' }[m])); }
16312  
16313  function getVariantSummaryText(){
16314    const vs = document.getElementById('pd-variant-summary');
16315    if (!vs) return '';
16316    const items = Array.from(vs.querySelectorAll('.vs-item strong')).map(el => el.textContent.trim()).filter(Boolean);
16317    return items.length ? items.join(' / ') : '';
16318  }
16319
16320  function getCurrentProductData(){
16321    const form = document.getElementById('pd-buy-form');
16322    if (!form) return null;
16323
16324    const productId = parseInt(form.dataset.pid || '0', 10);
16325    const qty = parseInt(form.querySelector('[name=qty]')?.value || '1', 10) || 1;
16326    const variantId = parseInt(document.getElementById('pd-variant-id')?.value || '0', 10) || 0;
16327    
16328    if (!productId || productId <= 0) {
16329      throw new Error('Product ID tidak valid');
16330    }
16331
16332    if (qty <= 0) {
16333      throw new Error('Quantity harus lebih dari 0');
16334    }
16335
16336    return { productId, qty, variantId };
16337  }
16338
16339  function createBuyNowPayload(productId, qty, variantId) {
16340    // Get product metadata
16341    const name = (window.PD_NAME !== undefined) ? String(window.PD_NAME) : (document.getElementById('pd-title')?.textContent || '');
16342    
16343    // Get correct price, SKU, and weight from selected variant data instead of DOM elements
16344    let price = 0;
16345    let sku = '';
16346    let weight = 0;
16347    let dimensions = null;
16348    
16349    if (variantId > 0 && typeof window.variants !== 'undefined' && Array.isArray(window.variants)) {
16350      // Find the selected variant in the variants array
16351      const selectedVariant = window.variants.find(v => v.id === variantId);
16352      if (selectedVariant) {
16353        price = selectedVariant.final || 0;
16354        sku = selectedVariant.sku || '';
16355        weight = selectedVariant.weight || 0;
16356        
16357        // Include dimensions if available
16358        if (selectedVariant.length_cm || selectedVariant.width_cm || selectedVariant.height_cm) {
16359          dimensions = {
16360            length_cm: selectedVariant.length_cm || 0,
16361            width_cm: selectedVariant.width_cm || 0,
16362            height_cm: selectedVariant.height_cm || 0
16363          };
16364        }
16365        
16366        // Debug info to verify fix is working
16367        if (window.console && window.console.debug) {
16368          console.debug('BuyNow: Using variant data', {
16369            variantId: variantId,
16370            price: price,
16371            sku: sku,
16372            weight: weight,
16373            dimensions: dimensions,
16374            variantData: selectedVariant
16375          });
16376        }
16377      }
16378    }
16379    
16380    // Fallback to DOM elements if variant data not found
16381    if (price === 0) {
16382      const priceTxt = document.getElementById('pd-price-current')?.textContent || '';
16383      price = parseInt(String(priceTxt).replace(/[^\d]/g,''), 10) || 0;
16384      
16385      if (window.console && window.console.debug) {
16386        console.debug('BuyNow: Using DOM price fallback', { 
16387          priceTxt: priceTxt, 
16388          price: price,
16389          variantId: variantId,
16390          reason: variantId > 0 ? 'variant_data_not_found' : 'no_variant_selected'
16391        });
16392      }
16393    }
16394    
16395    if (!sku) {
16396      const skuEl = document.getElementById('pd-sku');
16397      sku = skuEl ? skuEl.textContent.trim() : (window.PD_SKU || '');
16398    }
16399    
16400    const imgEl = document.getElementById('pd-main-img');
16401    const image_url = imgEl ? (imgEl.getAttribute('src') || '') : '';
16402
16403    const variantText = getVariantSummaryText();
16404    
16405    // Get pre-order data if product is pre-order
16406    const preorderData = window.PD_PREORDER_DATA || null;
16407    
16408    return {
16409      product_id: productId,
16410      qty: qty,
16411      variant_id: variantId,
16412      meta: {
16413        name,
16414        sku,
16415        price,
16416        image_url,
16417        variant_text: variantText,
16418        weight: weight,
16419        dimensions: dimensions
16420      },
16421      is_preorder: preorderData ? 'Y' : 'N',
16422      preorder_estimated_arrival: preorderData ? preorderData.estimated_arrival : null,
16423      preorder_note: preorderData ? preorderData.note : ''
16424    };
16425  }
16426
16427  /**
16428   * Main Buy Now function
16429   * Performs validation and redirects to checkout with buy_now mode
16430   */
16431  window.buyNow = async function(e) {
16432    if (e) e.preventDefault();
16433    
16434    try {
16435      // Check user login status
16436      const isLoggedIn = document.querySelector('meta[name="user-logged-in"]')?.content === 'true' ||
16437                        document.body.classList.contains('logged-in') ||
16438                        window.userLoggedIn === true ||
16439                        document.body.dataset.userLoggedIn === 'true';
16440      
16441      if (!isLoggedIn) {
16442        // Redirect to login with return URL to current page
16443        const currentUrl = encodeURIComponent(window.location.pathname + window.location.search);
16444        window.location.href = '/login?return=' + currentUrl;
16445        return;
16446      }
16447
16448      // Get current product data
16449      const { productId, qty, variantId } = getCurrentProductData();
16450      
16451      // Create payload for buy now
16452      const payload = createBuyNowPayload(productId, qty, variantId);
16453      
16454      // Store buy now data in sessionStorage for checkout page
16455      sessionStorage.setItem('buyNowData', JSON.stringify(payload));
16456
16457      // Track add_to_cart (buy now counts as purchase intent)
16458      if (window.PlazaAnalytics) {
16459        window.PlazaAnalytics.track('add_to_cart', { slug: String(window._pit_slug || '') });
16460      }
16461
16462      // Redirect to checkout with buy_now mode
16463      window.location.href = '/checkout?mode=buy_now';
16464      
16465    } catch (err) {
16466      console.error('Buy Now error:', err);
16467      
16468      if (window.showToast) {
16469        window.showToast({ 
16470          type: 'warn', 
16471          title: 'Gagal memproses', 
16472          message: String(err?.message || 'Terjadi kesalahan saat memproses pembelian'), 
16473          duration: 4500 
16474        });
16475      } else {
16476        alert(err.message || 'Terjadi kesalahan saat memproses pembelian');
16477      }
16478    }
16479  };
16480
16481  /**
16482   * Alternative Buy Now with confirmation dialog
16483   */
16484  window.buyNowWithConfirm = async function(e) {
16485    if (e) e.preventDefault();
16486    
16487    try {
16488      const { productId, qty, variantId } = getCurrentProductData();
16489      
16490      const name = (window.PD_NAME !== undefined) ? String(window.PD_NAME) : (document.getElementById('pd-title')?.textContent || '');
16491      const variantText = getVariantSummaryText();
16492      const priceTxt = document.getElementById('pd-price-current')?.textContent || 'Rp0';
16493      
16494      const confirmMessage = `Lanjut ke checkout?\n\nProduk: ${name}${variantText ? `\nVariant: ${variantText}` : ''}\nQty: ${qty}\nHarga: ${priceTxt}`;
16495      
16496      if (!confirm(confirmMessage)) {
16497        return;
16498      }
16499      
16500      // Proceed with buy now
16501      await window.buyNow(e);
16502      
16503    } catch (err) {
16504      console.error('Buy Now with confirm error:', err);
16505      alert(err.message || 'Terjadi kesalahan');
16506    }
16507  };
16508
16509  /**
16510   * Attach event listener for Buy with Voucher button
16511   */
16512  function setupBuyButtons() {
16513    // Setup desktop buy button (regular buy now without voucher)
16514    const buyBtn = document.getElementById('btn-buy');
16515    if (buyBtn) {
16516      buyBtn.addEventListener('click', function(e) {
16517        e.preventDefault();
16518        if (buyBtn.disabled) return;
16519        if (window.buyNow) {
16520          window.buyNow(e);
16521        }
16522      });
16523    }
16524    
16525    // Setup desktop buy with voucher button
16526    const voucherBtn = document.getElementById('btn-buy-voucher');
16527    if (voucherBtn) {
16528      voucherBtn.addEventListener('click', function(e) {
16529        e.preventDefault();
16530        
16531        // Validate stock availability before proceeding
16532        if (this.disabled || this.getAttribute('data-stock-blocked') === 'true') {
16533          const stockReason = this.getAttribute('data-stock-reason') || 'Stok tidak tersedia';
16534          
16535          if (window.showToast) {
16536            window.showToast({
16537              type: 'warn',
16538              title: 'Stok Tidak Tersedia',
16539              message: stockReason,
16540              duration: 3500
16541            });
16542          } else {
16543            alert(stockReason);
16544          }
16545          return;
16546        }
16547        
16548        const voucherCode = this.dataset.voucherCode;
16549        if (voucherCode) {
16550          window.buyNowWithVoucher(e, voucherCode);
16551        }
16552      });
16553    }
16554    
16555  }
16556  
16557  // CRITICAL: Attach mobile button handler at DOCUMENT level with CAPTURE phase
16558  // This is the ONLY way to guarantee it fires regardless of other scripts
16559  document.addEventListener('click', function(e) {
16560    // Check if click is on mobile buy button or its children
16561    const target = e.target.closest('#mf-buy');
16562    if (!target) return; // Not our button
16563    
16564    e.preventDefault();
16565    e.stopPropagation();
16566    e.stopImmediatePropagation();
16567    
16568    if (target.disabled) return;
16569    
16570    // Get voucher code from parent FAB's data attribute
16571    const mobileFab = document.getElementById('pd-mobile-fab');
16572    const voucherCode = mobileFab ? (mobileFab.getAttribute('data-voucher-code') || '') : '';
16573    
16574    if (voucherCode && voucherCode.trim() !== '' && window.buyNowWithVoucher) {
16575      window.buyNowWithVoucher(e, voucherCode);
16576    } else if (window.buyNow) {
16577      window.buyNow(e);
16578    }
16579  }, true); // CAPTURE PHASE - fires BEFORE any bubble phase handlers
16580  
16581  // Execute immediately if DOM already loaded, otherwise wait
16582  if (document.readyState === 'loading') {
16583    document.addEventListener('DOMContentLoaded', setupBuyButtons);
16584  } else {
16585    setupBuyButtons();
16586  }
16587
16588  /**
16589   * Buy Now with Auto-Applied Voucher
16590   * Applies voucher to session before redirecting to checkout (like cart does)
16591   * 
16592   * @param {Event} e - Click event
16593   * @param {string} voucherCode - Voucher code to apply
16594   */
16595  window.buyNowWithVoucher = async function(e, voucherCode) {
16596    if (e) e.preventDefault();
16597    
16598    console.log('[buyNowWithVoucher] Called with voucher code:', voucherCode);
16599    
16600    try {
16601      // CRITICAL: Check stock availability first
16602      const voucherBtn = document.getElementById('btn-buy-voucher');
16603      if (voucherBtn) {
16604        if (voucherBtn.disabled || voucherBtn.getAttribute('data-stock-blocked') === 'true') {
16605          const stockReason = voucherBtn.getAttribute('data-stock-reason') || 'Stok tidak tersedia';
16606          
16607          if (window.showToast) {
16608            window.showToast({
16609              type: 'warn',
16610              title: 'Stok Tidak Tersedia',
16611              message: stockReason,
16612              duration: 3500
16613            });
16614          } else {
16615            alert(stockReason);
16616          }
16617          return;
16618        }
16619      }
16620      
16621      // Check login status first
16622      const isLoggedIn = document.querySelector('meta[name="user-logged-in"]')?.content === 'true' ||
16623                        document.body.classList.contains('logged-in') ||
16624                        window.userLoggedIn === true ||
16625                        document.body.dataset.userLoggedIn === 'true';
16626      
16627      console.log('[buyNowWithVoucher] User logged in:', isLoggedIn);
16628      
16629      if (!isLoggedIn) {
16630        const currentUrl = encodeURIComponent(window.location.pathname + window.location.search);
16631        window.location.href = '/login?return=' + currentUrl;
16632        return;
16633      }
16634
16635      // Get current product data
16636      const { productId, qty, variantId } = getCurrentProductData();
16637      const payload = createBuyNowPayload(productId, qty, variantId);
16638      
16639      console.log('[buyNowWithVoucher] Product data:', { productId, qty, variantId });
16640      
16641      // Get category path for voucher validation
16642      const categoryPath = window.PD_CATEGORY_PATH || '';
16643      
16644      // Step 1: Clear any existing voucher first (important for clean state)
16645      console.log('[buyNowWithVoucher] Step 1: Clearing existing voucher...');
16646      try {
16647        await fetch('/api/voucher/remove.php', {
16648          method: 'POST',
16649          headers: { 
16650            'X-CSRF-Token': getCsrfToken()
16651          },
16652          body: JSON.stringify({
16653            csrf_token: getCsrfToken()
16654          }),
16655          credentials: 'same-origin'
16656        });
16657      } catch (e) {
16658        // Ignore error if no voucher exists
16659        console.debug('No existing voucher to remove or removal failed');
16660      }
16661      
16662      // Step 2: Apply voucher to session (like cart does)
16663      console.log('[buyNowWithVoucher] Step 2: Applying voucher to session...');
16664      const applyRes = await fetch('/api/voucher/apply.php', {
16665        method: 'POST',
16666        headers: { 
16667          'Content-Type': 'application/json',
16668          'X-CSRF-Token': getCsrfToken()
16669        },
16670        credentials: 'same-origin',
16671        body: JSON.stringify({
16672          csrf_token: getCsrfToken(),
16673          code: voucherCode,
16674          items: [{
16675            pid: productId,
16676            price: payload.meta.price,
16677            qty: qty,
16678            category_path: categoryPath
16679          }],
16680          shipping_cost: null // Will be calculated in checkout
16681        })
16682      });
16683      
16684      const applyData = await applyRes.json();
16685      
16686      console.log('[buyNowWithVoucher] Voucher apply response:', applyData);
16687      
16688      if (!applyData.success) {
16689        // Voucher invalid - show error and fallback to regular buy now
16690        console.warn('[buyNowWithVoucher] Voucher application failed:', applyData.message);
16691        if (window.showToast) {
16692          window.showToast({
16693            type: 'error',
16694            title: 'Voucher Tidak Valid',
16695            message: applyData.message || 'Voucher tidak dapat diterapkan untuk produk ini',
16696            duration: 4000
16697          });
16698        } else {
16699          alert(applyData.message || 'Voucher tidak dapat diterapkan');
16700        }
16701        
16702        // Fallback to regular buy now without voucher
16703        console.log('Voucher failed, proceeding with regular buy now');
16704        return window.buyNow(e);
16705      }
16706      
16707      // Step 3: Store buy now data in sessionStorage
16708      console.log('[buyNowWithVoucher] Step 3: Storing buy now data in sessionStorage');
16709      sessionStorage.setItem('buyNowData', JSON.stringify(payload));
16710      
16711      // Step 4: Redirect to checkout
16712      // Voucher sudah di session, checkout akan auto-load via loadAppliedVoucher()
16713      console.log('[buyNowWithVoucher] Step 4: Redirecting to checkout with voucher applied');
16714      window.location.href = '/checkout?mode=buy_now';
16715      
16716    } catch (err) {
16717      console.error('Buy Now with Voucher error:', err);
16718      
16719      if (window.showToast) {
16720        window.showToast({
16721          type: 'error',
16722          title: 'Terjadi Kesalahan',
16723          message: 'Gagal memproses pembelian dengan voucher. Silakan coba lagi.',
16724          duration: 3000
16725        });
16726      } else {
16727        alert('Gagal memproses pembelian. Silakan coba lagi.');
16728      }
16729    }
16730  };
16731})();
16732</script>
vendor: 2 bytes, line 16732
16732
16733<script data-inlined="pd-voucher-recalc.js">
16734/**
16735 * Product Detail - Voucher Discount Recalculation
16736 * 
16737 * Handles dynamic voucher discount recalculation when variant price changes
16738 * Supports both PERCENTAGE and FIXED_AMOUNT voucher types
16739 */
16740
16741(function() {
16742  'use strict';
16743
16744  /**
16745   * Calculate voucher discount based on type and price
16746   * 
16747   * @param {string} type - Voucher type: 'PERCENTAGE' or 'FIXED_AMOUNT'
16748   * @param {number} value - Voucher value (percentage or fixed amount)
16749   * @param {number} price - Current variant price
16750   * @param {number} maxDiscount - Maximum discount for percentage vouchers (0 = no limit)
16751   * @return {number} Calculated discount amount
16752   */
16753  function calculateVoucherDiscount(type, value, price, maxDiscount) {
16754    if (type === 'PERCENTAGE') {
16755      // Calculate percentage discount
16756      let discount = (price * value) / 100;
16757      
16758      // Apply max discount cap if set
16759      if (maxDiscount > 0 && discount > maxDiscount) {
16760        discount = maxDiscount;
16761      }
16762      
16763      return Math.round(discount);
16764    } else {
16765      // FIXED_AMOUNT - discount doesn't change with price
16766      return Math.round(value);
16767    }
16768  }
16769
16770  /**
16771   * Format number as Rupiah without 'Rp' prefix
16772   * 
16773   * @param {number} num - Number to format
16774   * @return {string} Formatted number (e.g., "20.000")
16775   */
16776  function formatNumber(num) {
16777    return Math.round(num).toString().replace(/\B(?=(\d{3})+(?!\d))/g, '.');
16778  }
16779
16780  /**
16781   * Update voucher button discount label
16782   * 
16783   * @param {number} newPrice - New variant price
16784   */
16785  function updateVoucherDiscount(newPrice) {
16786    const voucherBtn = document.getElementById('btn-buy-voucher');
16787    if (!voucherBtn) return;
16788
16789    // Get voucher data from button attributes
16790    const voucherType = voucherBtn.dataset.voucherType;
16791    const voucherValue = parseFloat(voucherBtn.dataset.voucherValue) || 0;
16792    const voucherMax = parseFloat(voucherBtn.dataset.voucherMax) || 0;
16793
16794    if (!voucherType || voucherValue === 0) return;
16795
16796    // Calculate new discount
16797    const newDiscount = calculateVoucherDiscount(voucherType, voucherValue, newPrice, voucherMax);
16798
16799    // Update the discount label
16800    const saveLabel = voucherBtn.querySelector('.bv-save');
16801    if (saveLabel) {
16802      saveLabel.textContent = '-Rp' + formatNumber(newDiscount);
16803    }
16804
16805    // Also update mobile FAB voucher display if exists
16806    updateMobileFabVoucher(newDiscount);
16807  }
16808
16809  /**
16810   * Update mobile FAB voucher value
16811   * 
16812   * @param {number} discountAmount - New discount amount
16813   */
16814  function updateMobileFabVoucher(discountAmount) {
16815    const fab = document.getElementById('pd-mobile-fab');
16816    if (fab) {
16817      fab.dataset.voucherValue = discountAmount.toString();
16818    }
16819  }
16820
16821  /**
16822   * Listen to variant change events and recalculate discount
16823   */
16824  function initVoucherRecalculation() {
16825    window.addEventListener('pd-variant-changed', function(e) {
16826      const detail = e.detail || {};
16827      const newPrice = detail.price || 0;
16828
16829      if (newPrice > 0) {
16830        updateVoucherDiscount(newPrice);
16831      }
16832    });
16833  }
16834
16835  // Initialize when DOM is ready
16836  if (document.readyState === 'loading') {
16837    document.addEventListener('DOMContentLoaded', initVoucherRecalculation);
16838  } else {
16839    initVoucherRecalculation();
16840  }
16841
16842})();
16843
16844</script>
vendor: 2 bytes, line 16844
16844
16845<script nonce="se3iyzEHMc9FQEB4wSyd0w==">document.addEventListener('DOMContentLoaded',function(){if(typeof ProductReviews!=='undefined'){ProductReviews.init(325);}const r=document.getElementById('pd-rating-inline');if(r){r.addEventListener('click',function(e){e.preventDefault();const s=document.getElementById('reviews');if(s){s.scrollIntoView({behavior:'smooth',block:'start'});s.classList.add('highlight-flash');setTimeout(()=>{s.classList.remove('highlight-flash')},1500)}});}});</script>
16845
16846
16847<script nonce="se3iyzEHMc9FQEB4wSyd0w==">
16848(function(){function _0x9i0j(el){if(typeof gtag==='function'){gtag('event','qoala_insurance_click',{event_category:'Insurance',event_label:'Qoala Banner Click - Product Detail',link_url:'/plazait-protect',page_location:window.location.href,product_id:parseInt(el.getAttribute('data-product-id'))||0,product_name:el.getAttribute('data-product-name')||'',category_path:el.getAttribute('data-category-path')||'',custom_map:{custom_parameter_1:'qoala_banner_product_detail'}})}}
16849
16850function _0x1k2l(){var a=document.querySelector('.qoala-cta[data-ga-event="qoala_banner_click"]');if(a){a.addEventListener('click',function(e){_0x9i0j(this)})}}if(document.readyState==='loading'){document.addEventListener('DOMContentLoaded',_0x1k2l)}else{_0x1k2l()}})();
16851
16852(function(){const pwpSection=document.getElementById('pwp-deals-section');const pwpBadge=document.getElementById('pwp-trigger-badge');if(!pwpSection)return;const productId=parseInt(pwpSection.getAttribute('data-product-id'))||0;const variantId=parseInt(pwpSection.getAttribute('data-variant-id'))||0;const categoryPath=pwpSection.getAttribute('data-category-path')||'';if(!productId)return;function formatRupiah(n){return'Rp'+Math.floor(n).toLocaleString('id-ID')}function loadPWPDeals(){const url=`/api/pwp/get_by_product.php?product_id=${productId}${variantId?`&variant_id=${variantId}`:''}${categoryPath?`&category_path=${encodeURIComponent(categoryPath)}`:''}`;fetch(url).then(r=>r.json()).then(data=>{if(data.success&&data.promotions&&data.promotions.length>0){renderPWPDeals(data.promotions);pwpSection.hidden=false;if(pwpBadge)pwpBadge.hidden=false;setTimeout(function(){if(typeof window.adjustSidebarBanner==='function'){window.adjustSidebarBanner()}},150)}else{pwpSection.hidden=true;if(pwpBadge)pwpBadge.hidden=true}}).catch(err=>{console.error('PWP load error:',err);pwpSection.hidden=true;if(pwpBadge)pwpBadge.hidden=true})}function renderPWPDeals(promotions){const loading=pwpSection.querySelector('.pwp-deals-loading');const grid=document.getElementById('pwp-deals-grid');if(loading)loading.hidden=true;if(!grid)return;grid.innerHTML='';promotions.forEach(promo=>{promo.bundled_products.forEach(product=>{const card=document.createElement('div');card.className='pwp-deal-card';const discount=product.discount>0?product.discount:0;const discountPercent=product.regular_price>0?Math.round((discount/product.regular_price)*100):0;const imgUrl=product.image_url?`/uploads/products/${product.image_url}`:'/assets/img/no-image.png';card.innerHTML=`<div class="pwp-deal-thumb"><img src="${imgUrl}" alt="${escapeHtml(product.name)}" loading="lazy"></div><div class="pwp-deal-info"><h4 class="pwp-deal-name">${escapeHtml(product.name)}</h4><div class="pwp-deal-prices"><span class="pwp-deal-price">${formatRupiah(product.pwp_price)}</span>${product.regular_price>product.pwp_price?`<span class="pwp-deal-original">${formatRupiah(product.regular_price)}</span>`:''}</div></div>${discountPercent>0?`<span class="pwp-deal-badge">-${discountPercent}%</span>`:''}`;grid.appendChild(card)})})}function escapeHtml(str){const div=document.createElement('div');div.textContent=str||'';return div.innerHTML}loadPWPDeals();window.addEventListener('pd-variant-changed',function(e){const detail=e.detail||{};const newVid=detail.variant_id||0;const currentVid=parseInt(pwpSection.getAttribute('data-variant-id'))||0;if(newVid!==currentVid){pwpSection.setAttribute('data-variant-id',newVid);loadPWPDeals()}})})();
16853</script>
16853<footer class="site-footer footer-compact variant-stripes" role="contentinfo">
16854  <div class="ft-top ft-collapsible" id="ftTop">
16855    <div class="container ft-grid">
16856
16857      <div class="ft-col ft-help">
16858        <h4 class="ft-title">Butuh Bantuan?</h4>
16859        <p class="ft-desc">Hubungi kami melalui Official WhatsApp interaktif sekarang.</p>
16860        <a class="ft-wa-btn" href="https://wa.me/+6287725361707" target="_blank" rel="nofollow noopener">
16861          <span class="ico" aria-hidden="true">
16862            <svg viewBox="0 0 24 24" width="18" height="18"><path fill="#25D366" d="M12.04 2c-5.52 0-10 4.43-10 9.9 0 1.75.47 3.45 1.38 4.94L2 22l5.3-1.38c1.43.78 3.05 1.19 4.7 1.19 5.52 0 10-4.43 10-9.9S17.56 2 12.04 2Zm5.86 13.9c-.25.7-1.23 1.28-1.7 1.33-.45.06-1.02.08-1.65-.1-.38-.12-.88-.29-1.52-.56-2.66-1.15-4.4-3.83-4.53-4.01-.13-.18-1.08-1.44-1.08-2.75 0-1.31.68-1.95.92-2.22.25-.27.54-.33.72-.33.18 0 .36.01.52.01.17 0 .39-.06.62.47.25.6.85 2.07.92 2.22.07.15.12.33.02.53-.1.2-.15.33-.3.5-.15.17-.32.39-.46.53-.15.15-.3.31-.13.6.18.3.8 1.31 1.73 2.12 1.19 1.03 2.17 1.36 2.48 1.5.31.14.49.12.67-.07.18-.18.77-.82.98-1.1.21-.27.42-.23.7-.14.27.09 1.72.81 2.02.95.3.14.5.22.58.35.08.13.08.72-.17 1.42Z"/></svg>
16863          </span>
16864          Kirim Pesan
16865        </a>
16866
16867        <p class="ft-desc sm-gap">Ikuti kami:</p>
16868        <div class="ft-social">
16869          <a aria-label="Facebook" href="https://facebook.com/judimpoofficial"><svg viewBox="0 0 24 24" width="18" height="18"><path fill="currentColor" d="M13.5 22v-8.2h2.7l.4-3.2h-3.1V8c0-.9.3-1.5 1.6-1.5H17V3.7c-.3 0-1.2-.1-2.2-.1-2.2 0-3.8 1.3-3.8 3.9v2.2H8v3.2h3v8.1h2.5Z"/></svg></a>
16870          <a aria-label="Instagram" href="https://instagram.com/judimpoofficial/"><svg viewBox="0 0 24 24" width="18" height="18"><path fill="currentColor" d="M7.8 2h8.4A5.8 5.8 0 0 1 22 7.8v8.4A5.8 5.8 0 0 1 16.2 22H7.8A5.8 5.8 0 0 1 2 16.2V7.8A5.8 5.8 0 0 1 7.8 2Zm0 2A3.8 3.8 0 0 0 4 7.8v8.4A3.8 3.8 0 0 0 7.8 20h8.4a3.8 3.8 0 0 0 3.8-3.8
16870V7.8A3.8 3.8 0 0 0 16.2 4H7.8Zm9.9 1.7a1.1 1.1 0 1 1 0 2.3 1.1 1.1 0 0 1 0-2.3ZM12 7a5 5 0 1 1 0 10 5 5 0 0 1 0-10Zm0 2a3 3 0 1 0 0 6 3 3 0 0 0 0-6Z"/></svg></a>
16871          <a aria-label="TikTok" href="https://www.tiktok.com/@mpojudy"><svg viewBox="0 0 24 24" width="18" height="18"><path fill="currentColor" d="M18.9 7.4a6.4 6.4 0 0 1-3.2-1.2v6.3a5.47 5.47 0 1 1-5.5-5.5c.2 0 .4 0 .6.02v2.37a2.92 2.92 0 0 0-.6-.07 2.8 2.8 0 1 0 2.8 2.8V2h2.3a4.6 4.6 0 0 0 4.5 4.1v2.3Z"/></svg></a>
16872        </div>
16873      </div>
16874
16875            <!-- Collapsible Content Wrapper (Non-Homepage Only) -->
16876      <div class="ft-collapsible-content" id="ftCollapsible">
16877      
16878      <div class="ft-col">
16879        <h4 class="ft-title">Tentang GAME MPO</h4>
16880        <ul class="ft-links">
16881          <li><a href="https://hop.exchange/">Tentang GAME MPO</a></li>
16882          <li><a href="https://hop.exchange/">Kontak GAME MPO</a></li>
16883          <li><a href="https://hop.exchange/">Lokasi Toko</a></li>
16884          <li><a href="https://hop.exchange/">FAQ</a></li>
16885        </ul>
16886        <div class="ft-address">
16887          <p class="company">GAME MPO</p>
16888                      <p>JL. Cengkareng Barat No. 56, Jakarta Timur</p>
16889                      <p>Kec. Jakarta, Kota Jakarta, DKI JAKARTA, 11752</p>
16890                  </div>
16891      </div>
16892
16893      <div class="ft-col">
16894        <h4 class="ft-title">Informasi</h4>
16895        <ul class="ft-links">
16896          <li><a href="/syarat-dan-ketentuan">Syarat &amp; Ketentuan</a></li>
16897          <li><a href="/kebijakan-privasi">Kebijakan Privasi</a></li>
16898          <li><a href="/kebijakan-cookie">Kebijakan Cookie</a></li>
16899          <li><a href="/pengiriman-dan-pengembalian">Pengiriman &amp; Pengembalian</a></li>
16900          <li><a href="/pembayaran-dan-cicilan">Pembayaran &amp; Cicilan</a></li>
16901          <li><a href="/garansi-dan-layanan">Garansi &amp; Layanan</a></li>
16902        </ul>
16903
16904        <div class="ft-payments payments-small" aria-label="Metode Pembayaran">
16905          <div class="pay-row">
16906            <img src="https://imgmahasuhu.io/images/2026/05/20/wopslot-mandiri.png" alt="Mandiri" loading="lazy">
16907            <img src="https://imgmahasuhu.io/images/2026/05/20/wopslot-bni.gif" alt="BNI" loading="lazy">
16908            <img src="https://imgmahasuhu.io/images/2026/05/20/wopslot-bri.gif" alt="BRI" loading="lazy">
16909            <img src="https://imgmahasuhu.io/images/2026/05/20/wopslot-qris.gif" alt="QRIS" loading="lazy">
16910            <img src="https://imgmahasuhu.io/images/2026/05/20/wopslot-bca.gif" alt="BCA" loading="lazy">
16911          </div>
16912        </div>
16913      </div>
16914
16915            </div>
16916      <!-- End Collapsible Content -->
16917      
16918      <!-- Expand Button (Mobile Only) -->
16919      <button class="ft-expand-btn" id="ftExpandBtn" aria-label="Lihat semua informasi footer">
16920        <span class="expand-text">Selengkapnya</span>
16921        <svg viewBox="0 0 24 24" width="18" height="18" fill="currentColor">
16922          <path d="M7.41 8.59L12 13.17l4.59-4.58L18 10l-6 6-6-6 1.41-1.41z"/>
16923        </svg>
16924      </button>
16925      
16926    </div>
16927  </div>
16928  <div class="ft-bottom">
16929    <div class="container ft-bottom-inner">
16930      <div class="ft-copy">
16931        <span>GAME MPO &copy; <span id="yearNow">2026</span></span>
16932        <span>GAME MPO OFFICIAL. All rights reserved.</span>
16933      </div>
16934    </div>
16935  </div>
16936  
16937          <style nonce="se3iyzEHMc9FQEB4wSyd0w==">
16938            /* Chat Widget Styles - Lightweight & Minimal */
16939            .chat-widget {
16940                position: fixed;
16941                bottom: 20px;
16942                right: 20px;
16943                z-index: 9999;
16944                font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
16945            }
16946            
16947            /* Hide floating button on mobile - use bottom nav instead */
16948            @media (max-width: 640px) {
16949                .chat-toggle-btn {
16950                    display: none !important;
16951                }
16952                
16953                /* Ensure popup is still visible on mobile even when button is hidden */
16954                .chat-widget {
16955                    display: block !important;
16956                }
16957                
16958                .chat-popup {
16959                    display: none; /* Hidden by default, shown via JS */
16960                }
16961                
16962                .chat-popup[style*="display: block"],
16963                .chat-popup[style*="display:block"] {
16964                    display: block !important;
16965                }
16966            }
16967            
16968            .chat-toggle-btn {
16969                width: 60px;
16970                height: 60px;
16971                border-radius: 50%;
16972                background: linear-gradient(135deg, #C77DFF 0%, #C77DFF 100%);
16973                border: none;
16974                color: white;
16975                cursor: pointer;
16976                box-shadow: 0 4px 12px rgba(245,202,86,0.3);
16977                position: relative;
16978                transition: transform 0.2s, box-shadow 0.2s;
16979            }
16980            
16981            .chat-toggle-btn:hover {
16982                transform: scale(1.05);
16983                box-shadow: 0 6px 20px rgba(245,202,86,0.4);
16984            }
16985            
16986            #chat-toggle-btn .chat-icon {
16987                position: absolute;
16988                top: 50%;
16989                left: 50%;
16990                transform: translate(-50%, -50%);
16991                width: 28px !important;
16992                height: 28px !important;
16993            }
16994            
16995            .chat-unread-badge {
16996                position: absolute;
16997                top: -5px;
16998                right: -5px;
16999                background: #C77DFF;
17000                color: white;
17001                border-radius: 12px;
17002                padding: 2px 6px;
17003                font-size: 11px;
17004                font-weight: 600;
17005                min-width: 20px;
17006                text-align: center;
17007            }
17008            
17009            .chat-popup {
17010                position: absolute;
17011                bottom: 80px;
17012                right: 0;
17013                width: 380px;
17014                max-width: calc(100vw - 40px);
17015                height: 500px;
17016                max-height: calc(100vh - 120px);
17017                background: white;
17018                border-radius: 12px;
17019                box-shadow: 0 10px 40px rgba(0,0,0,0.2);
17020                display: flex;
17021                flex-direction: column;
17022                overflow: hidden;
17023            }
17024            
17025            .chat-popup-header {
17026                background: linear-gradient(135deg, #C77DFF 0%, #C77DFF 100%);
17027                color: white;
17028                padding: 16px 20px;
17029                display: flex;
17030                justify-content: space-between;
17031                align-items: center;
17032                flex-shrink: 0;
17033            }
17034            
17035            .chat-header-title {
17036                display: flex;
17037                flex-direction: column;
17038                gap: 2px;
17039                min-height: 0;
17040            }
17041            
17042            .chat-popup-header h3 {
17043                margin: 0;
17044                font-size: 18px;
17045                font-weight: 600;
17046                line-height: 1.2;
17047            }
17048            
17049            .chat-operating-hours {
17050                font-size: 11px;
17051                opacity: 0.9;
17052                font-weight: 400;
17053                display: flex;
17054                align-items: center;
17055                gap: 4px;
17056                line-height: 1.2;
17057            }
17058            
17059            .chat-operating-hours svg {
17060                width: 12px;
17061                height: 12px;
17062                opacity: 0.8;
17063                flex-shrink: 0;
17064            }
17065            
17066            .chat-header-actions {
17067                display: flex;
17068                align-items: center;
17069                gap: 8px;
17070            }
17071            
17072            /* Notification Toggle Button */
17073            .btn-notif-toggle {
17074                background: none;
17075                border: none;
17076                color: white;
17077                font-size: 18px;
17078                cursor: pointer;
17079                padding: 4px 8px;
17080                transition: all 0.2s;
17081                opacity: 0.8;
17082            }
17083            
17084            .btn-notif-toggle:hover {
17085                opacity: 1;
17086                transform: scale(1.1);
17087            }
17088            
17089            /* Icon states */
17090            .btn-notif-toggle[data-status="not-subscribed"] svg {
17091                opacity: 0.7;
17092            }
17093            
17094            .btn-notif-toggle[data-status="not-subscribed"]:hover svg {
17095                opacity: 1;
17096            }
17097            
17098            .btn-notif-toggle[data-status="subscribed"] svg {
17099                opacity: 1;
17100                animation: bellRing 2s ease-in-out;
17101            }
17102            
17103            .btn-notif-toggle[data-status="blocked"] svg {
17104                color: #C77DFF;
17105            }
17106            
17107            .btn-notif-toggle[data-status="not-supported"] {
17108                display: none !important;
17109            }
17110            
17111            @keyframes bellRing {
17112                0%, 100% { transform: rotate(0deg); }
17113                10%, 30% { transform: rotate(-10deg); }
17114                20%, 40% { transform: rotate(10deg); }
17115            }
17116            
17117            /* Notification Info Bar */
17118            .chat-notif-info-bar {
17119                position: absolute;
17120                top: 64px;
17121                left: 0;
17122                right: 0;
17123                background: linear-gradient(to right, #e3f2fd, #f5f5f5);
17124                border-bottom: 1px solid #bbdefb;
17125                padding: 8px 12px;
17126                display: flex;
17127                align-items: center;
17128                gap: 8px;
17129                font-size: 12px;
17130                color: #616161;
17131                z-index: 10;
17132                animation: slideDown 0.3s ease;
17133            }
17134            
17135            .chat-notif-info-bar svg {
17136                flex-shrink: 0;
17137            }
17138            
17139            .chat-notif-info-bar .small {
17140                flex: 1;
17141                line-height: 1.4;
17142            }
17143            
17144            .chat-notif-info-bar .btn-dismiss {
17145                background: none;
17146                border: none;
17147                color: #9e9e9e;
17148                cursor: pointer;
17149                padding: 0 4px;
17150                font-size: 16px;
17151                transition: color 0.2s;
17152            }
17153            
17154            .chat-notif-info-bar .btn-dismiss:hover {
17155                color: #616161;
17156            }
17157            
17158            @keyframes slideDown {
17159                from {
17160                    max-height: 0;
17161                    opacity: 0;
17162                }
17163                to {
17164                    max-height: 50px;
17165                    opacity: 1;
17166                }
17167            }
17168            
17169            .chat-close-btn {
17170                background: none;
17171                border: none;
17172                color: white;
17173                font-size: 28px;
17174                line-height: 1;
17175                cursor: pointer;
17176                padding: 0;
17177                width: 30px;
17178                height: 30px;
17179            }
17180            
17181            .chat-popup-body {
17182                flex: 1 1 auto;
17183                display: flex;
17184                flex-direction: column;
17185                min-height: 0;
17186                overflow: hidden;
17187                height: calc(100% - 64px);
17188                position: relative;
17189                transition: padding-top 0.3s ease;
17190            }
17191            
17192            /* Add padding when info bar is visible */
17193            .chat-popup-body.has-info-bar {
17194                padding-top: 40px;
17195            }
17196            
17197            .chat-view {
17198                flex: 1 1 auto;
17199                display: none;
17200                flex-direction: column;
17201                min-height: 0;
17202                overflow: hidden;
17203            }
17204            
17205            #chat-list-view {
17206                display: flex;
17207            }
17208            
17209            #chat-messages-view {
17210                display: none;
17211            }
17212            
17213            #chat-messages-view.active {
17214                display: flex;
17215                flex-direction: column;
17216            }
17217            
17218            #chat-new-view {
17219                display: none;
17220            }
17221            
17222            #chat-new-view.active {
17223                display: flex;
17224            }
17225            
17226            .chat-conversations-list {
17227                flex: 1;
17228                overflow-y: auto;
17229                padding: 0;
17230                background: white;
17231            }
17232            
17233            /* Custom Scrollbar for Conversations List */
17234            .chat-conversations-list::-webkit-scrollbar {
17235                width: 6px;
17236            }
17237            
17238            .chat-conversations-list::-webkit-scrollbar-track {
17239                background: #f1f1f1;
17240            }
17241            
17242            .chat-conversations-list::-webkit-scrollbar-thumb {
17243                background: #C77DFF;
17244                border-radius: 3px;
17245            }
17246            
17247            .chat-conversations-list::-webkit-scrollbar-thumb:hover {
17248                background: #C77DFF;
17249            }
17250            
17251            /* Firefox */
17252            .chat-conversations-list {
17253                scrollbar-width: thin;
17254                scrollbar-color: #C77DFF #f1f1f1;
17255            }
17256            
17257            .chat-conversation-item {
17258                padding: 12px 16px;
17259                cursor: pointer;
17260                display: flex;
17261                gap: 12px;
17262                align-items: flex-start;
17263                transition: background 0.15s ease;
17264                color: #3a270a;
17265                border-bottom: 1px solid #f0f0f0;
17266            }
17267            
17268            .chat-conversation-item:hover {
17269                background: #f5f5f5;
17270            }
17271            
17272            .chat-conversation-item.active {
17273                background: #FFF5EB;
17274            }
17275            
17276            /* WhatsApp-like Avatar */
17277            .conversation-avatar {
17278                width: 48px;
17279                height: 48px;
17280                border-radius: 50%;
17281                background: linear-gradient(135deg, #C77DFF 0%, #C77DFF 100%);
17282                flex-shrink: 0;
17283                display: flex;
17284                align-items: center;
17285                justify-content: center;
17286                color: white;
17287                font-weight: 600;
17288                font-size: 18px;
17289            }
17290            
17291            .conversation-avatar svg {
17292                width: 24px;
17293                height: 24px;
17294            }
17295            
17296            /* WhatsApp-like Content */
17297            .conversation-content {
17298                flex: 1;
17299                min-width: 0;
17300                display: flex;
17301                flex-direction: column;
17302                gap: 4px;
17303            }
17304            
17305            .conversation-header {
17306                display: flex;
17307                justify-content: space-between;
17308                align-items: center;
17309                gap: 8px;
17310            }
17311            
17312            .conversation-name {
17313                font-weight: 600;
17314                font-size: 15px;
17315                color: #111;
17316                white-space: nowrap;
17317                overflow: hidden;
17318                text-overflow: ellipsis;
17319            }
17320            
17321            .conversation-time {
17322                font-size: 12px;
17323                color: #7d8166;
17324                flex-shrink: 0;
17325            }
17326            
17327            .conversation-preview {
17328                display: flex;
17329                justify-content: space-between;
17330                align-items: center;
17331                gap: 8px;
17332            }
17333            
17334            .conversation-message {
17335                font-size: 14px;
17336                color: #667781;
17337                white-space: nowrap;
17338                overflow: hidden;
17339                text-overflow: ellipsis;
17340                margin: 0;
17341                flex: 1;
17342            }
17343            
17344            .conversation-unread {
17345                background: #25D366;
17346                color: white;
17347                border-radius: 12px;
17348                padding: 2px 8px;
17349                font-size: 12px;
17350                font-weight: 600;
17351                min-width: 20px;
17352                text-align: center;
17353                flex-shrink: 0;
17354            }
17355            
17356            /* Active item styling */
17357            .chat-conversation-item.active .conversation-name {
17358                color: #C77DFF;
17359            }
17360            
17361            .chat-conversation-item.active .conversation-time {
17362                color: #C77DFF;
17363            }
17364            
17365            .chat-new-btn {
17366                margin: 12px;
17367                padding: 12px;
17368                background: linear-gradient(135deg, #C77DFF 0%, #C77DFF 100%);
17369                color: white;
17370                border: none;
17371                border-radius: 8px;
17372                cursor: pointer;
17373                font-weight: 500;
17374                font-size: 14px;
17375                display: flex;
17376                align-items: center;
17377                justify-content: center;
17378                gap: 8px;
17379                transition: all 0.2s;
17380                flex-shrink: 0;
17381            }
17382            
17383            .chat-new-btn:hover {
17384                transform: translateY(-1px);
17385                box-shadow: 0 4px 8px rgba(245,202,86,0.3);
17386            }
17387            
17388            .chat-conversation-title {
17389                flex: 1;
17390                font-weight: 600;
17391                font-size: 16px;
17392                color: #1f2937;
17393            }
17394            
17395            .chat-messages-container {
17396                flex: 1;
17397                overflow-y: auto;
17398                padding: 16px;
17399                display: flex;
17400                flex-direction: column;
17401                gap: 8px;
17402                min-height: 0;
17403                background: #E5DDD5;
17404            }
17405            
17406            /* Custom Scrollbar for Messages Container */
17407            .chat-messages-container::-webkit-scrollbar {
17408                width: 6px;
17409            }
17410            
17411            .chat-messages-container::-webkit-scrollbar-track {
17412                background: rgba(0, 0, 0, 0.05);
17413            }
17414            
17415            .chat-messages-container::-webkit-scrollbar-thumb {
17416                background: rgba(245,202,86,0.6);
17417                border-radius: 3px;
17418            }
17419            
17420            .chat-messages-container::-webkit-scrollbar-thumb:hover {
17421                background: #C77DFF;
17422            }
17423            
17424            /* Firefox */
17425            .chat-messages-container {
17426                scrollbar-width: thin;
17427                scrollbar-color: rgba(245,202,86,0.6) rgba(0, 0, 0, 0.05);
17428            }
17429            
17430            /* WhatsApp Group-like Messages */
17431            .chat-message {
17432                display: flex;
17433                margin-bottom: 4px;
17434                animation: fadeIn 0.2s ease;
17435            }
17436            
17437            @keyframes fadeIn {
17438                from { opacity: 0; transform: translateY(10px); }
17439                to { opacity: 1; transform: translateY(0); }
17440            }
17441            
17442            .chat-message.mine {
17443                justify-content: flex-end;
17444            }
17445            
17446            .chat-message-bubble {
17447                max-width: 80%;
17448                padding: 6px 8px 8px 10px;
17449                border-radius: 8px;
17450                position: relative;
17451                box-shadow: 0 1px 0.5px rgba(0,0,0,0.13);
17452            }
17453            
17454            /* Bubble from others (Admin/CS) */
17455            .chat-message:not(.mine) .chat-message-bubble {
17456                background: #FFFFFF;
17457                border-radius: 0 8px 8px 8px;
17458            }
17459            
17460            /* Bubble tail for others */
17461            .chat-message:not(.mine) .chat-message-bubble::before {
17462                content: '';
17463                position: absolute;
17464                top: 0;
17465                left: -8px;
17466                width: 0;
17467                height: 0;
17468                border-style: solid;
17469                border-width: 0 8px 13px 0;
17470                border-color: transparent #FFFFFF transparent transparent;
17471            }
17472            
17473            /* Bubble from user (mine) */
17474            .chat-message.mine .chat-message-bubble {
17475                background: #e4f5d0; /* Light blue for user messages */
17476                border-radius: 8px 0 8px 8px;
17477            }
17478            
17479            /* Bubble tail for mine */
17480            .chat-message.mine .chat-message-bubble::before {
17481                content: '';
17482                position: absolute;
17483                top: 0;
17484                right: -8px;
17485                width: 0;
17486                height: 0;
17487                border-style: solid;
17488                border-width: 0 0 13px 8px;
17489                border-color: transparent transparent transparent #eaf5d0;
17490            }
17491            
17492            .message-sender {
17493                font-size: 12.5px;
17494                font-weight: 600;
17495                color: #C77DFF !important;
17496                margin-bottom: 4px;
17497            }
17498            
17499            .chat-message.mine .message-sender {
17500                display: none;
17501            }
17502            
17503            /* Message text */
17504            .message-text {
17505                font-size: 14px;
17506                line-height: 19px;
17507                color: #ffffff !important;
17508                word-wrap: break-word;
17509                white-space: pre-wrap;
17510                margin-bottom: 4px;
17511            }
17512            
17513            /* Message metadata (time + status) */
17514            .message-meta {
17515                display: flex;
17516                align-items: center;
17517                justify-content: flex-end;
17518                gap: 4px;
17519                margin-top: 2px;
17520            }
17521            
17522            .message-time {
17523                font-size: 11px;
17524                color: #728166 !important;
17525                line-height: 15px;
17526            }
17527            
17528            /* Use multiple selectors to override global styles */
17529            .chat-message-bubble .message-status,
17530            .message-meta .message-status,
17531            .chat-message .message-status {
17532                width: 16px !important;
17533                height: 16px !important;
17534                min-width: 16px !important;
17535                min-height: 16px !important;
17536                max-width: 16px !important;
17537                max-height: 16px !important;
17538                flex-shrink: 0;
17539                color: #728166 !important;
17540                fill: currentColor !important;
17541            }
17542            
17543            .chat-message:not(.mine) .message-status {
17544                display: none;
17545            }
17546            
17547            /* Loading dots animation */
17548            @keyframes loadingDots {
17549                0%, 20% { content: '.'; }
17550                40% { content: '..'; }
17551                60%, 100% { content: '...'; }
17552            }
17553            
17554            .message-status.loading::after {
17555                content: '...';
17556                animation: loadingDots 1.5s infinite;
17557                font-size: 16px;
17558                line-height: 16px;
17559            }
17560            
17561            .message-status.loading path {
17562                display: none;
17563            }
17564            
17565            .message-status.failed {
17566                color: #C77DFF !important;
17567                cursor: pointer;
17568            }
17569            
17570            .message-status.sent {
17571                color: #667781 !important;
17572            }
17573            
17574            .chat-new-form {
17575                flex: 1;
17576                overflow-y: auto;
17577                padding: 16px;
17578                display: flex;
17579                flex-direction: column;
17580            }
17581            
17582            .chat-new-form form {
17583                display: flex;
17584                flex-direction: column;
17585                gap: 16px;
17586                flex: 1;
17587            }
17588            
17589            .chat-new-form .form-group {
17590                display: flex;
17591                flex-direction: column;
17592                gap: 6px;
17593            }
17594            
17595            .chat-new-form label {
17596                font-size: 14px;
17597                font-weight: 500;
17598                color: #374151;
17599            }
17600            
17601            .chat-new-form .form-control {
17602                width: 100%;
17603                padding: 10px 12px;
17604                border: 1px solid #d1d5db;
17605                border-radius: 8px;
17606                font-size: 14px;
17607                font-family: inherit;
17608                transition: border-color 0.2s;
17609                box-sizing: border-box;
17610            }
17611            
17612            .chat-new-form .form-control:focus {
17613                outline: none;
17614                border-color: #C77DFF;
17615                box-shadow: 0 0 0 3px rgba(245,202,86,0.1);
17616            }
17617            
17618            .chat-new-form textarea.form-control {
17619                resize: vertical;
17620                min-height: 100px;
17621            }
17622            
17623            .chat-new-form .btn {
17624                padding: 12px 20px;
17625                border: none;
17626                border-radius: 8px;
17627                font-size: 15px;
17628                font-weight: 500;
17629                cursor: pointer;
17630                transition: all 0.2s;
17631                text-align: center;
17632            }
17633            
17634            .chat-new-form .btn-primary {
17635                background: linear-gradient(135deg, #C77DFF 0%, #C77DFF 100%);
17636                color: white;
17637            }
17638            
17639            .chat-new-form .btn-primary:hover {
17640                transform: translateY(-1px);
17641                box-shadow: 0 4px 8px rgba(245,202,86,0.3);
17642            }
17643            
17644            .chat-new-form .btn-primary:active {
17645                transform: scale(0.98);
17646            }
17647            
17648            .chat-new-form .btn-block {
17649                width: 100%;
17650                margin-top: auto;
17651            }
17652            
17653            .chat-message-form {
17654                padding: 12px;
17655                border-top: 1px solid #e5e7eb;
17656                display: flex;
17657                flex-wrap: wrap;
17658                gap: 8px;
17659                align-items: flex-end;
17660                flex-shrink: 0;
17661                background: white;
17662            }
17663            
17664            .chat-product-card {
17665                flex: 1 1 100%;
17666                max-width: 100%;
17667                display: flex;
17668                gap: 12px;
17669                padding: 12px;
17670                background: #f3f4f6;
17671                border-radius: 8px;
17672                margin-bottom: 4px;
17673                border: 1px solid #e5e7eb;
17674            }
17675            
17676            .chat-product-card img {
17677                width: 60px;
17678                height: 60px;
17679                object-fit: cover;
17680                border-radius: 6px;
17681                flex-shrink: 0;
17682            }
17683            
17684            .chat-product-card-content {
17685                flex: 1;
17686                min-width: 0;
17687            }
17688            
17689            .chat-product-card-name {
17690                font-weight: 500;
17691                font-size: 14px;
17692                color: #1f2937;
17693                margin-bottom: 4px;
17694                white-space: nowrap;
17695                overflow: hidden;
17696                text-overflow: ellipsis;
17697            }
17698            
17699            .chat-product-card-variant {
17700                font-size: 12px;
17701                color: #74806b;
17702                margin-bottom: 4px;
17703            }
17704            
17705            .chat-product-card-price {
17706                font-size: 13px;
17707                color: #8bea66;
17708                font-weight: 600;
17709            }
17710            
17711            .chat-product-card-remove {
17712                align-self: flex-start;
17713                background: none;
17714                border: none;
17715                color: #9ca3af;
17716                cursor: pointer;
17717                padding: 4px;
17718                font-size: 18px;
17719                line-height: 1;
17720                transition: color 0.2s;
17721            }
17722            
17723            .chat-product-card-remove:hover {
17724                color: #C77DFF;
17725            }
17726            
17727            /* Product card in messages (read-only display) */
17728            .message-product-card {
17729                display: flex;
17730                gap: 10px;
17731                padding: 10px;
17732                background: rgba(255, 255, 255, 0.5);
17733                border-radius: 8px;
17734                margin-bottom: 6px;
17735                border: 1px solid rgba(0, 0, 0, 0.08);
17736                align-items: center;
17737            }
17738            
17739            .chat-message.mine .message-product-card {
17740                background: rgba(255, 255, 255, 0.7);
17741            }
17742            
17743            .message-product-card img {
17744                width: 50px;
17745                height: 50px;
17746                object-fit: cover;
17747                border-radius: 6px;
17748                flex-shrink: 0;
17749            }
17750            
17751            .message-product-info {
17752                flex: 1;
17753                min-width: 0;
17754            }
17755            
17756            .message-product-name {
17757                font-weight: 500;
17758                font-size: 13px;
17759                color: #3a270a;
17760                margin-bottom: 2px;
17761                overflow: hidden;
17762                text-overflow: ellipsis;
17763                display: -webkit-box;
17764                -webkit-line-clamp: 2;
17765                -webkit-box-orient: vertical;
17766                line-height: 1.3;
17767            }
17768            
17769            .message-product-variant {
17770                font-size: 11px;
17771                color: #78806b;
17772                margin-bottom: 2px;
17773            }
17774            
17775            .message-product-price {
17776                font-size: 12px;
17777                color: #c7ea66;
17778                font-weight: 600;
17779            }
17780            
17781            .message-product-link {
17782                flex-shrink: 0;
17783                width: 32px;
17784                height: 32px;
17785                display: flex;
17786                align-items: center;
17787                justify-content: center;
17788                background: rgba(102, 126, 234, 0.1);
17789                border-radius: 6px;
17790                color: #c7ea66;
17791                text-decoration: none;
17792                transition: all 0.2s;
17793            }
17794            
17795            .message-product-link:hover {
17796                background: #b7ea66;
17797                color: white;
17798            }
17799            
17800            .message-product-link svg {
17801                width: 16px;
17802                height: 16px;
17803            }
17804            
17805            .chat-message-input {
17806                flex: 1;
17807                border: 1px solid #d1d5db;
17808                border-radius: 20px;
17809                padding: 10px 16px;
17810                resize: none;
17811                max-height: 100px;
17812                font-family: inherit;
17813                font-size: 14px;
17814                line-height: 1.5;
17815                box-sizing: border-box;
17816                overflow-y: hidden;
17817            }
17818            
17819            .chat-message-input:focus {
17820                outline: none;
17821                border-color: #C77DFF;
17822                box-shadow: 0 0 0 3px rgba(245,202,86,0.1);
17823            }
17824            
17825            .chat-send-btn {
17826                width: 40px;
17827                height: 40px;
17828                border-radius: 50%;
17829                background: linear-gradient(135deg, #C77DFF 0%, #C77DFF 100%);
17830                border: none;
17831                color: white;
17832                cursor: pointer;
17833                flex-shrink: 0;
17834                display: flex;
17835                align-items: center;
17836                justify-content: center;
17837                transition: all 0.2s;
17838            }
17839            
17840            .chat-send-btn:hover {
17841                transform: scale(1.05);
17842                box-shadow: 0 2px 8px rgba(245,202,86,0.3);
17843            }
17844            
17845            .chat-send-btn:active {
17846                transform: scale(0.95);
17847            }
17848            
17849            .chat-loading {
17850                text-align: center;
17851                padding: 20px;
17852                color: #6b7280;
17853            }
17854            
17855            /* Date Separator (WhatsApp-style) */
17856            .date-separator {
17857                display: flex;
17858                align-items: center;
17859                gap: 12px;
17860                margin: 24px 0 16px;
17861                opacity: 0;
17862                animation: fadeInSeparator 0.3s ease forwards;
17863            }
17864
17865            @keyframes fadeInSeparator {
17866                from {
17867                    opacity: 0;
17868                    transform: translateY(-10px);
17869                }
17870                to {
17871                    opacity: 1;
17872                    transform: translateY(0);
17873                }
17874            }
17875
17876            .date-separator-line {
17877                flex: 1;
17878                height: 1px;
17879                background: linear-gradient(90deg, transparent, rgba(0, 0, 0, 0.1) 50%, transparent);
17880            }
17881
17882            .date-separator-text {
17883                flex-shrink: 0;
17884                padding: 4px 12px;
17885                background: #e9ecef;
17886                color: #6c757d;
17887                font-size: 11px;
17888                font-weight: 600;
17889                text-transform: uppercase;
17890                letter-spacing: 0.5px;
17891                border-radius: 12px;
17892                box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
17893            }
17894            
17895            /* Mobile responsive */
17896            @media (max-width: 640px) {
17897                .chat-popup {
17898                    position: fixed !important; /* Override absolute positioning */
17899                    bottom: 45px !important; /* Above bottom nav */
17900                    right: 0 !important;
17901                    left: 0 !important;
17902                    width: 100% !important;
17903                    max-width: 100% !important;
17904                    /* Use dvh (dynamic viewport height) for browser UI awareness */
17905                    height: calc(100dvh - 45px) !important;
17906                    max-height: calc(100dvh - 45px) !important;
17907                    /* Fallback for browsers that don't support dvh */
17908                    height: calc(var(--viewport-height, 100vh) - 45px) !important;
17909                    max-height: calc(var(--viewport-height, 100vh) - 45px) !important;
17910                    border-radius: 0 !important;
17911                    z-index: 9999 !important;
17912                }
17913                
17914                .chat-popup-header {
17915                    border-radius: 0;
17916                }
17917                
17918                .chat-messages-container,
17919                .chat-conversations-list {
17920                    /* Adjust for mobile keyboard using dynamic viewport */
17921                    max-height: calc(100dvh - 190px);
17922                    /* Fallback for browsers that don't support dvh */
17923                    max-height: calc(var(--viewport-height, 100vh) - 190px);
17924                }
17925            }
17926        </style>
17927                <!-- Chat Widget Button -->
17928        <div id="chat-widget" class="chat-widget" 
17929             data-user-id=""
17930             data-is-logged-in="false"
17931             data-csrf-token="df5d776748b1ed8c8dd0d987bae99b1ee3dea6c6dcbe0eedb1bea766c56d569a">
17932            <button id="chat-toggle-btn" class="chat-toggle-btn" aria-label="Toggle chat">
17933                <svg class="chat-icon" width="28" height="28" viewBox="0 0 640 640" fill="currentColor">
17934                    <path d="M320 128C241 128 175.3 185.3 162.3 260.7C171.6 257.7 181.6 256 192 256L208 256C234.5 256 256 277.5 256 304L256 400C256 426.5 234.5 448 208 448L192 448C139 448 96 405 96 352L96 288C96 164.3 196.3 64 320 64C443.7 64 544 164.3 544 288L544 456.1C544 522.4 490.2 576.1 423.9 576.1L336 576L304 576C277.5 576 256 554.5 256 528C256 501.5 277.5 480 304 480L336 480C362.5 480 384 501.5 384 528L384 528L424 528C463.8 528 496 495.8 496 456L496 435.1C481.9 443.3 465.5 447.9 448 447.9L432 447.9C405.5 447.9 384 426.4 384 399.9L384 303.9C384 277.4 405.5 255.9 432 255.9L448 255.9C458.4 255.9 468.3 257.5 477.7 260.6C464.7 185.3 399.1 127.9 320 127.9z"/>
17935                </svg>
17936                <span id="chat-unread-badge" class="chat-unread-badge" style="display: none;">0</span>
17937            </button>
17938            
17939            <div id="chat-popup" class="chat-popup" style="display: none;">
17940                <div class="chat-popup-header">
17941                    <div class="chat-header-title">
17942                        <h3>Bantuan</h3>
17943                        <span id="chatOperatingHours" class="chat-operating-hours" style="display: none;"></span>
17944                    </div>
17945                    <div class="chat-header-actions">
17946                        <button id="chatNotifToggle" class="btn-notif-toggle" data-status="not-supported" title="Push notification" style="display: none;">
17947                            <svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor">
17948                                <path d="M12 22c1.1 0 2-.9 2-2h-4c0 1.1.89 2 2 2zm6-6v-5c0-3.07-1.64-5.64-4.5-6.32V4c0-.83-.67-1.5-1.5-1.5s-1.5.67-1.5 1.5v.68C7.63 5.36 6 7.92 6 11v5l-2 2v1h16v-1l-2-2z"/>
17949                            </svg>
17950                        </button>
17951                        <button id="chat-close-btn" class="chat-close-btn" aria-label="Close chat">
17951×</button>
17952                    </div>
17953                </div>
17954                
17955                <!-- Notification Info Bar (conditional) -->
17956                <div class="chat-notif-info-bar" id="chatNotifInfoBar" style="display:none;">
17957                    <svg width="14" height="14" viewBox="0 0 24 24" fill="#ffc107">
17958                        <path d="M9 21c0 .55.45 1 1 1h4c.55 0 1-.45 1-1v-1H9v1zm3-19C8.14 2 5 5.14 5 9c0 2.38 1.19 4.47 3 5.74V17c0 .55.45 1 1 1h6c.55 0 1-.45 1-1v-2.26c1.81-1.27 3-3.36 3-5.74 0-3.86-3.14-7-7-7zm2.85 11.1l-.85.6V16h-4v-2.3l-.85-.6C7.8 12.16 7 10.63 7 9c0-2.76 2.24-5 5-5s5 2.24 5 5c0 1.63-.8 3.16-2.15 4.1z"/>
17959                    </svg>
17960                    <span class="small">Aktifkan notifikasi untuk pemberitahuan balasan</span>
17961                    <button class="btn-dismiss" onclick="ChatNotification.dismissInfo()">✕</button>
17962                </div>
17963                
17964                <div class="chat-popup-body">
17965                    <!-- Conversations List View -->
17966                    <div id="chat-list-view" class="chat-view">
17967                        <div id="chat-conversations-list" class="chat-conversations-list">
17968                            <div class="chat-loading">Memuat...</div>
17969                            <!-- Conversation Item Structure (rendered by JS):
17970                            <div class="chat-conversation-item">
17971                                <div class="conversation-avatar">
17972                                    <svg>...</svg>
17973                                </div>
17974                                <div class="conversation-content">
17975                                    <div class="conversation-header">
17976                                        <span class="conversation-name">Admin Support</span>
17977                                        <span class="conversation-time">10:30</span>
17978                                    </div>
17979                                    <div class="conversation-preview">
17980                                        <p class="conversation-message">Terima kasih telah menghubungi kami...</p>
17981                                        <span class="conversation-unread">2</span>
17982                                    </div>
17983                                </div>
17984                            </div>
17985                            -->
17986                        </div>
17987                        <button id="chat-new-btn" class="chat-new-btn">
17988                            <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
17989                                <line x1="12" y1="5" x2="12" y2="19"></line>
17990                                <line x1="5" y1="12" x2="19" y2="12"></line>
17991                            </svg>
17992                            Percakapan Baru
17993                        </button>
17994                    </div>
17995                    
17996                    <!-- Chat Messages View -->
17997                    <div id="chat-messages-view" class="chat-view" style="display: none;">
17998                        <div id="chat-messages-container" class="chat-messages-container">
17999                            <div class="chat-loading">Memuat pesan...</div>
18000                            <!-- Message Structure (rendered by JS):
18001                            <div class="chat-message"> (or .chat-message.mine)
18002                                <div class="chat-message-bubble">
18003                                    <div class="message-sender">Admin Support</div> (only for non-mine)
18004                                    <div class="message-text">Halo, ada yang bisa dibantu?</div>
18005                                    <div class="message-meta">
18006                                        <span class="message-time">10:30</span>
18007                                        <svg class="message-status">...</svg> (only for mine)
18008                                    </div>
18009                                </div>
18010                            </div>
18011                            -->
18012                        </div>
18013                        
18014                        <form id="chat-message-form" class="chat-message-form">
18015                            <input type="hidden" id="chat-current-conversation-id" value="">
18016                            <textarea 
18017                                id="chat-message-input" 
18018                                class="chat-message-input" 
18019                                placeholder="Ketik pesan..."
18020                                rows="1"
18021                                maxlength="5000"
18022                            ></textarea>
18023                            <button type="submit" class="chat-send-btn" aria-label="Send message">
18024                                <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
18025                                    <line x1="22" y1="2" x2="11" y2="
1802513"></line>
18026                                    <polygon points="22 2 15 22 11 13 2 9 22 2"></polygon>
18027                                </svg>
18028                            </button>
18029                        </form>
18030                    </div>
18031                    
18032                    <!-- New Chat View -->
18033                    <div id="chat-new-view" class="chat-view" style="display: none;">
18034                        <div class="chat-messages-header">
18035                            <button id="chat-new-back-btn" class="chat-back-btn" aria-label="Back to list">
18036                                <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
18037                                    <path d="M19 12H5M12 19l-7-7 7-7"/>
18038                                </svg>
18039                            </button>
18040                            <div class="chat-conversation-title">Percakapan Baru</div>
18041                        </div>
18042                        
18043                        <div class="chat-new-form">
18044                            <form id="chat-start-form">
18045                                <div class="form-group">
18046                                    <label for="chat-new-subject">Subjek</label>
18047                                    <input 
18048                                        type="text" 
18049                                        id="chat-new-subject" 
18050                                        class="form-control" 
18051                                        placeholder="Bantuan Pelanggan"
18052                                        maxlength="255"
18053                                    >
18054                                </div>
18055                                <div class="form-group">
18056                                    <label for="chat-new-message">Pesan</label>
18057                                    <textarea 
18058                                        id="chat-new-message" 
18059                                        class="form-control" 
18060                                        rows="4" 
18061                                        placeholder="Tulis pertanyaan Anda..."
18062                                        required
18063                                        maxlength="5000"
18064                                    ></textarea>
18065                                </div>
18066                                <button type="submit" class="btn btn-primary btn-block">Kirim</button>
18067                            </form>
18068                        </div>
18069                    </div>
18070                </div>
18071            </div>
18072        </div>
18073        
18074        <!-- Login Required Modal -->
18075        <div class="modal-overlay" id="chatLoginModal">
18076            <div class="modal-dialog">
18077                <div class="modal-header">
18078                    <h3 class="modal-title">
18079                        <div class="modal-icon info">
18080                            <svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor">
18081                                <path d="M11,9H13V7H11M12,20C7.59,20 4,16.41 4,12C4,7.59 7.59,4 12,4C16.41,4 20,7.59 20,12C20,16.41 16.41,20 12,20M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M11,17H13V11H11V17Z"/>
18082                            </svg>
18083                        </div>
18084                        Login Diperlukan
18085                    </h3>
18086                </div>
18087                <div class="modal-body">
18088                    <p class="modal-message">Anda harus login terlebih dahulu untuk menggunakan fitur chat bantuan pelanggan.</p>
18089                    <div class="modal-actions">
18090                        <button class="modal-btn modal-btn-secondary" id="chatLoginCancel">Batal</button>
18091                        <button class="modal-btn modal-btn-primary" id="chatLoginConfirm">Login Sekarang</button>
18092                    </div>
18093                </div>
18094            </div>
18095        </div>
18096        
18096<script src="https://plazait.co.id/assets/js/chat-widget.js" nonce="se3iyzEHMc9FQEB4wSyd0w=="></script>
18096<script data-inlined="chat-notification.js">
18097/**
18098 * Customer Chat Push Notification Manager
18099 * Handles browser push notification subscription for customers
18100 * Version: 1.0.0
18101 * Date: 2026-01-19
18102 */
18103
18104const ChatNotification = {
18105    // State
18106    status: 'not-supported', // not-supported, not-subscribed, subscribed, blocked
18107    subscription: null,
18108    vapidPublicKey: null, // Will be loaded from server
18109    
18110    /**
18111     * Initialize notification manager
18112     */
18113    async init() {
18114        // Check if user is logged in (only for logged-in users)
18115        if (!this.isUserLoggedIn()) {
18116            this.updateUI('not-supported');
18117            return;
18118        }
18119        
18120        // Check browser support
18121        if (!this.isSupported()) {
18122            this.updateUI('not-supported');
18123            return;
18124        }
18125        
18126        // Load VAPID key from server
18127        await this.loadVapidKey();
18128        
18129        if (!this.vapidPublicKey) {
18130            this.updateUI('not-supported');
18131            return;
18132        }
18133        
18134        // Register service worker if needed
18135        await this.registerServiceWorker();
18136        
18137        // Check current permission
18138        const permission = Notification.permission;
18139        
18140        if (permission === 'denied') {
18141            this.updateUI('blocked');
18142        } else if (permission === 'granted') {
18143            // Check if already subscribed
18144            const isSubscribed = await this.checkSubscriptionStatus();
18145            this.updateUI(isSubscribed ? 'subscribed' : 'not-subscribed');
18146        } else {
18147            // Default: not subscribed yet
18148            this.updateUI('not-subscribed');
18149            this.showInfoBar();
18150        }
18151    },
18152    
18153    /**
18154     * Check if user is logged in
18155     */
18156    isUserLoggedIn() {
18157        const metaTag = document.querySelector('meta[name="user-logged-in"]');
18158        return metaTag ? metaTag.getAttribute('content') === 'true' : false;
18159    },
18160    
18161    /**
18162     * Check if browser supports push notifications
18163     */
18164    isSupported() {
18165        return (
18166            'serviceWorker' in navigator &&
18167            'PushManager' in window &&
18168            'Notification' in window
18169        );
18170    },
18171    
18172    /**
18173     * Load VAPID public key from server
18174     */
18175    async loadVapidKey() {
18176        try {
18177            const response = await fetch('/api/chat/notifications/vapid_key', {
18178                method: 'GET',
18179                headers: {
18180                    'Accept': 'application/json'
18181                }
18182            });
18183            
18184            if (!response.ok) {
18185                return false;
18186            }
18187            
18188            const data = await response.json();
18189            if (data.success && data.data?.public_key) {
18190                this.vapidPublicKey = data.data.public_key;
18191                return true;
18192            }
18193            
18194            return false;
18195            
18196        } catch (error) {
18197            console.error('[ChatNotification] Error loading VAPID key:', error);
18198            return false;
18199        }
18200    },
18201    
18202    /**
18203     * Register service worker
18204     */
18205    async registerServiceWorker() {
18206        if (!('serviceWorker' in navigator)) return null;
18207        
18208        try {
18209            const registration = await navigator.serviceWorker.register('/sw-push.js', {
18210                scope: '/'
18211            });
18212            return registration;
18213        } catch (error) {
18214            return null;
18215        }
18216    },
18217    
18218    /**
18219     * Check subscription status from server
18220     */
18221    async checkSubscriptionStatus() {
18222        try {
18223            const response = await fetch('/api/chat/notifications/status', {
18224                method: 'GET',
18225                credentials: 'include',
18226                headers: {
18227                    'Accept': 'application/json'
18228                }
18229            });
18230            
18231            if (!response.ok) {
18232                return false;
18233            }
18234            
18235            const data = await response.json();
18236            return data.data?.subscribed || false;
18237            
18238        } catch (error) {
18239            console.error('[ChatNotification] Error checking subscription:', error);
18240            return false;
18241        }
18242    },
18243    
18244    /**
18245     * Update UI based on status
18246     */
18247    updateUI(status) {
18248        this.status = status;
18249        const btn = document.getElementById('chatNotifToggle');
18250        
18251        if (!btn) {
18252            // Retry after a short delay (button might not be in DOM yet)
18253            setTimeout(() => this.updateUI(status), 100);
18254            return;
18255        }
18256        
18257        btn.setAttribute('data-status', status);
18258        
18259        // Show/hide button based on support
18260        if (status === 'not-supported') {
18261            btn.style.display = 'none';
18262        } else {
18263            btn.style.display = 'block';
18264        }
18265        
18266        // Update SVG icon (bell vs bell-slash)
18267        const svg = btn.querySelector('svg');
18268        if (svg) {
18269            if (status === 'subscribed') {
18270                // Bell icon (active)
18271                svg.innerHTML = '<path d="M12 22c1.1 0 2-.9 2-2h-4c0 1.1.89 2 2 2zm6-6v-5c0-3.07-1.64-5.64-4.5-6.32V4c0-.83-.67-1.5-1.5-1.5s-1.5.67-1.5 1.5v.68C7.63 5.36 6 7.92 6 11v5l-2 2v1h16v-1l-2-2z"/>';
18272            } else {
18273                // Bell slash icon (inactive/blocked)
18274                svg.innerHTML = '<path d="M20 18.69L7.84 6.14 5.27 3.49 4 4.76l2.8 2.8v.01c-.52.99-.8 2.16-.8 3.42v5l-2 2v1h13.73l2 2L21 19.72l-1-1.03zM12 22c1.1 0 2-.9 2-2h-4c0 1.1.89 2 2 2zm6-7.32V11c0-3.08-1.64-5.64-4.5-6.32V4c0-.83-.67-1.5-1.5-1.5s-1.5.67-1.5 1.5v.68c-.15.03-.29.08-.42.12-.1.03-.2.07-.3.11h-.01c-.01 0-.01 0-.02.01-.23.09-.46.2-.68.31 0 0-.01 0-.01.01L18 14.68z"/>';
18275            }
18276        }
18277        
18278        // Update tooltip
18279        const tooltips = {
18280            'not-subscribed': 'Klik untuk aktifkan notifikasi',
18281            'subscribed': 'Notifikasi aktif',
18282            'blocked': 'Notifikasi diblokir'
18283        };
18284        
18285        if (tooltips[status]) {
18286            btn.title = tooltips[status];
18287        }
18288        
18289        // Hide info bar if subscribed or blocked
18290        if (status === 'subscribed' || status === 'blocked') {
18291            this.hideInfoBar();
18292        }
18293    },
18294    
18295    /**
18296     * Show info bar (if not dismissed)
18297     */
18298    showInfoBar() {
18299        if (localStorage.getItem('chat_notif_info_dismissed')) {
18300            return;
18301        }
18302        
18303        const infoBar = document.getElementById('chatNotifInfoBar');
18304        const popupBody = document.getElementById('chat-popup')?.querySelector('.chat-popup-body');
18305        
18306        if (infoBar) {
18307            infoBar.style.display = 'flex';
18308
18309            // Bind dismiss button here so it's always attached when bar is visible
18310            const btn = infoBar.querySelector('#chatNotifDismissBtn');
18311            if (btn && !btn._dismissBound) {
18312                btn._dismissBound = true;
18313                btn.addEventListener('click', () => {
18314                    infoBar.style.display = 'none';
18315                    localStorage.setItem('chat_notif_info_dismissed', '1');
18316                    if (popupBody) popupBody.classList.remove('has-info-bar');
18317                });
18318            }
18319        }
18320        
18321        if (popupBody) {
18322            popupBody.classList.add('has-info-bar');
18323        }
18324    },
18325    
18326    /**
18327     * Hide info bar
18328     */
18329    hideInfoBar() {
18330        const infoBar = document.getElementById('chatNotifInfoBar');
18331        const popupBody = document.getElementById('chat-popup')?.querySelector('.chat-popup-body');
18332        
18333        if (infoBar) {
18334            infoBar.style.display = 'none';
18335        }
18336        
18337        if (popupBody) {
18338            popupBody.classList.remove('has-info-bar');
18339        }
18340    },
18341    
18342    /**
18343     * Dismiss info bar permanently
18344     */
18345    dismissInfo() {
18346        this.hideInfoBar();
18347        localStorage.setItem('chat_notif_info_dismissed', '1');
18348    },
18349    
18350    /**
18351     * Handle bell icon click
18352     */
18353    async handleToggleClick() {
18354        if (this.status === 'not-subscribed') {
18355            await this.subscribe();
18356        } else if (this.status === 'subscribed') {
18357            await this.unsubscribe();
18358        } else if (this.status === 'blocked') {
18359            this.showUnblockHelp();
18360        }
18361    },
18362    
18363    /**
18364     * Subscribe to push notifications
18365     */
18366    async subscribe() {
18367        try {
18368            // Request permission
18369            const permission = await Notification.requestPermission();
18370            
18371            if (permission === 'denied') {
18372                this.updateUI('blocked');
18373                this.showToast('Notifikasi diblokir', 'error');
18374                return;
18375            }
18376            
18377            if (permission !== 'granted') {
18378                return;
18379            }
18380            
18381            // Get service worker registration
18382            const registration = await navigator.serviceWorker.ready;
18383            
18384            // Subscribe to push
18385            const subscription = await registration.pushManager.subscribe({
18386                userVisibleOnly: true,
18387                applicationServerKey: this.urlBase64ToUint8Array(this.vapidPublicKey)
18388            });
18389            
18390            // Send subscription to server
18391            const response = await fetch('/api/chat/notifications/subscribe', {
18392                method: 'POST',
18393                credentials: 'include',
18394                headers: {
18395                    'Content-Type': 'application/json',
18396                    'Accept': 'application/json'
18397                },
18398                body: JSON.stringify(subscription.toJSON())
18399            });
18400            
18401            if (!response.ok) {
18402                throw new Error('Failed to save subscription');
18403            }
18404            
18405            const result = await response.json();
18406            
18407            this.subscription = subscription;
18408            this.updateUI('subscribed');
18409            this.hideInfoBar();
18410            this.showToast('Notifikasi berhasil diaktifkan!', 'success');
18411            
18412            // Send test notification
18413            setTimeout(() => this.sendTestNotification(), 1000);
18414            
18415        } catch (error) {
18416            console.error('[ChatNotification] Subscribe error:', error);
18417            this.showToast('Gagal mengaktifkan notifikasi', 'error');
18418        }
18419    },
18420    
18421    /**
18422     * Unsubscribe from push notifications
18423     */
18424    async unsubscribe() {
18425        try {
18426            // Confirm first
18427            if (!confirm('Nonaktifkan notifikasi chat?')) {
18428                return;
18429            }
18430            
18431            // Get current subscription
18432            const registration = await navigator.serviceWorker.ready;
18433            const subscription = await registration.pushManager.getSubscription();
18434            
18435            if (subscription) {
18436                // Unsubscribe from browser
18437                await subscription.unsubscribe();
18438                
18439                // Tell server
18440                await fetch('/api/chat/notifications/unsubscribe', {
18441                    method: 'POST',
18442                    credentials: 'include',
18443                    headers: {
18444                        'Content-Type': 'application/json',
18445                        'Accept': 'application/json'
18446                    },
18447                    body: JSON.stringify(subscription.toJSON())
18448                });
18449            }
18450            
18451            this.subscription = null;
18452            this.updateUI('not-subscribed');
18453            this.showInfoBar();
18454            this.showToast('Notifikasi dinonaktifkan', 'info');
18455            
18456        } catch (error) {
18457            console.error('[ChatNotification] Unsubscribe error:', error);
18458            this.showToast('Gagal menonaktifkan notifikasi', 'error');
18459        }
18460    },
18461    
18462    /**
18463     * Send test notification
18464     */
18465    async sendTestNotification() {
18466        try {
18467            const response = await fetch('/api/chat/notifications/send_test', {
18468                method: 'POST',
18469                credentials: 'include',
18470                headers: {
18471                    'Accept': 'application/json'
18472                }
18473            });
18474            
18475            if (response.ok) {
18476                // Test notification sent successfully
18477            }
18478        } catch (error) {
18479            // Test notification failed silently
18480        }
18481    },
18482    
18483    /**
18484     * Show unblock help modal/message
18485     */
18486    showUnblockHelp() {
18487        const message = `
18488            Notifikasi diblokir oleh browser.\n\n
18489            Untuk mengaktifkan:\n
18490            1. Klik ikon gembok/info di address bar\n
18491            2. Cari "Notifications" atau "Notifikasi"\n
18492            3. Ubah menjadi "Allow" atau "Izinkan"\n
18493            4. Refresh halaman ini
18494        `.trim().replace(/\s+/g, ' ');
18495        
18496        alert(message);
18497    },
18498    
18499    /**
18500     * Show toast notification
18501     */
18502    showToast(message, type = 'info') {
18503        // Simple toast implementation
18504        const toast = document.createElement('div');
18505        toast.className = `chat-toast chat-toast-${type}`;
18506        toast.textContent = message;
18507        toast.style.cssText = `
18508            position: fixed;
18509            bottom: 80px;
18510            right: 20px;
18511            background: ${type === 'success' ? '#4caf50' : type === 'error' ? '#C77DFF' : '#2196f3'};
18512            color: white;
18513            padding: 12px 20px;
18514            border-radius: 4px;
18515            box-shadow: 0 2px 8px rgba(0,0,0,0.2);
18516            z-index: 10000;
18517            animation: slideInUp 0.3s ease;
18518        `;
18519        
18520        document.body.appendChild(toast);
18521        
18522        setTimeout(() => {
18523            toast.style.animation = 'slideOutDown 0.3s ease';
18524            setTimeout(() => toast.remove(), 300);
18525        }, 3000);
18526    },
18527    
18528    /**
18529     * Convert VAPID key to Uint8Array
18530     */
18531    urlBase64ToUint8Array(base64String) {
18532        const padding = '='.repeat((4 - base64String.length % 4) % 4);
18533        const base64 = (base64String + padding)
18534            .replace(/\-/g, '+')
18535            .replace(/_/g, '/');
18536        
18537        const rawData = window.atob(base64);
18538        const outputArray = new Uint8Array(rawData.length);
18539        
18540        for (let i = 0; i < rawData.length; ++i) {
18541            outputArray[i] = rawData.charCodeAt(i);
18542        }
18543        return outputArray;
18544    },
18545    
18546    /**
18547     * Check if push notification is currently active
18548     * @returns {Promise<boolean>}
18549     */
18550    async isPushActive() {
18551        try {
18552            // Check browser subscription
18553            if (!('serviceWorker' in navigator)) return false;
18554            
18555            const registration = await navigator.serviceWorker.getRegistration();
18556            if (!registration) return false;
18557            
18558            const subscription = await registration.pushManager.getSubscription();
18559            if (!subscription) return false;
18560            
18561            // Also check server status
18562            const serverStatus = await this.checkSubscriptionStatus();
18563            
18564            return serverStatus;
18565        } catch (error) {
18566            return false;
18567        }
18568    },
18569    
18570    /**
18571     * Show logout confirmation if push notification is active
18572     * Call this before logout action
18573     * @returns {Promise<boolean>} true if user confirms logout, false if cancelled
18574     */
18575    async confirmLogoutWithPushNotification() {
18576        const isActive = await this.isPushActive();
18577        
18578        if (!isActive) {
18579            // No active push, proceed with logout
18580            return true;
18581        }
18582        
18583        // Show modal confirmation using modal.css
18584        return new Promise((resolve) => {
18585            // Create modal HTML
18586            const modalHTML = `
18587                <div class="modal-overlay" id="logoutConfirmModal">
18588                    <div class="modal-dialog">
18589                        <div class="modal-header">
18590                            <h3 class="modal-title">
18591                                <span class="modal-icon warning">⚠️</span>
18592                                Konfirmasi Logout
18593                            </h3>
18594                        </div>
18595                        <div class="modal-body">
18596                            <p class="modal-message">
18597                                Anda memiliki <strong>notifikasi push yang aktif</strong>.<br><br>
18598                                Setelah logout, Anda tidak akan menerima notifikasi chat lagi di perangkat ini.<br><br>
18599                                Apakah Anda yakin ingin melanjutkan logout?
18600                            </p>
18601                        </div>
18602                        <div class="modal-actions" style="padding: 0 20px 20px;">
18603                            <button class="modal-btn modal-btn-secondary" id="logoutCancelBtn">
18604                                Batal
18605                            </button>
18606                            <button class="modal-btn modal-btn-danger" id="logoutConfirmBtn">
18607                                Lanjutkan Logout
18608                            </button>
18609                        </div>
18610                    </div>
18611                </div>
18612            `;
18613            
18614            // Append to body
18615            const modalContainer = document.createElement('div');
18616            modalContainer.innerHTML = modalHTML;
18617            document.body.appendChild(modalContainer.firstElementChild);
18618            
18619            const modal = document.getElementById('logoutConfirmModal');
18620            const confirmBtn = document.getElementById('logoutConfirmBtn');
18621            const cancelBtn = document.getElementById('logoutCancelBtn');
18622            
18623            // Show modal with animation
18624            requestAnimationFrame(() => {
18625                modal.classList.add('show');
18626            });
18627            
18628            // Handle confirm
18629            const handleConfirm = () => {
18630                cleanup();
18631                resolve(true);
18632            };
18633            
18634            // Handle cancel
18635            const handleCancel = () => {
18636                cleanup();
18637                resolve(false);
18638            };
18639            
18640            // Cleanup function
18641            const cleanup = () => {
18642                modal.classList.remove('show');
18643                setTimeout(() => {
18644                    modal.remove();
18645                }, 200);
18646                confirmBtn.removeEventListener('click', handleConfirm);
18647                cancelBtn.removeEventListener('click', handleCancel);
18648                modal.removeEventListener('click', handleBackdropClick);
18649            };
18650            
18651            // Handle backdrop click
18652            const handleBackdropClick = (e) => {
18653                if (e.target === modal) {
18654                    handleCancel();
18655                }
18656            };
18657            
18658            // Add event listeners
18659            confirmBtn.addEventListener('click', handleConfirm);
18660            cancelBtn.addEventListener('click', handleCancel);
18661            modal.addEventListener('click', handleBackdropClick);
18662        });
18663    }
18664};
18665
18666// Add CSS animations
18667const chatNotifStyle = document.createElement('style');
18668chatNotifStyle.textContent = `
18669    @keyframes slideInUp {
18670        from {
18671            transform: translateY(100%);
18672            opacity: 0;
18673        }
18674        to {
18675            transform: translateY(0);
18676            opacity: 1;
18677        }
18678    }
18679    
18680    @keyframes slideOutDown {
18681        from {
18682            transform: translateY(0);
18683            opacity: 1;
18684        }
18685        to {
18686            transform: translateY(100%);
18687            opacity: 0;
18688        }
18689    }
18690`;
18691document.head.appendChild(chatNotifStyle);
18692
18693// Auto-initialize when DOM is ready
18694if (document.readyState === 'loading') {
18695    document.addEventListener('DOMContentLoaded', () => ChatNotification.init());
18696} else {
18697    ChatNotification.init();
18698}
18699
18700// Expose to window for access from other scripts
18701window.ChatNotification = ChatNotification;
18702
18703</script>
18703  
18704    <!-- Footer Collapse Toggle Script -->
18705  
18705<script nonce="se3iyzEHMc9FQEB4wSyd0w==">
18706  document.addEventListener('DOMContentLoaded', function() {
18707    const ftTop = document.getElementById('ftTop');
18708    const expandBtn = document.getElementById('ftExpandBtn');
18709    
18710    if (ftTop && expandBtn) {
18711      const expandText = expandBtn.querySelector('.expand-text');
18712      
18713      expandBtn.addEventListener('click', function() {
18714        ftTop.classList.toggle('expanded');
18715        const isExpanded = ftTop.classList.contains('expanded');
18716        if (expandText) {
18717          expandText.textContent = isExpanded ? 'Sembunyikan' : 'Selengkapnya';
18718        }
18719      });
18720    }
18721  });
18722  </script>
18722
18723  </footer>
18724
18725<!-- Compare Sidebar Overlay -->
18726<div class="compare-overlay" id="compareOverlay"></div>
18727
18728<!-- Floating Compare Badge (Sticky) -->
18729<button class="compare-floating-badge" id="compareFloatingBadge" aria-label="Lihat produk yang dibandingkan" style="display:none;">
18730  <svg class="cfb-icon" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
18731    <path d="M9.01 14H2v2h7.01v3L13 15l-3.99-4v3zm5.98-1v-3H22V8h-7.01V5L11 9l3.99 4z"/>
18732  </svg>
18733  <span class="cfb-text">Bandingkan</span>
18734  <span class="cfb-count" id="cfbCount">0</span>
18735</button>
18736
18737<!-- AI Comparison Modal -->
18738<div class="ai-compare-modal" id="aiCompareModal">
18739  <div class="modal-backdrop"></div>
18740  <div class="modal-container">
18741    <div class="modal-header">
18742      <h3 class="modal-title">
18743        <svg width="24" height="24" viewBox="0 0 24 24" fill="currentColor">
18744          <path d="M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M12,4A8,8 0 0,1 20,12A8,8 0 0,1 12,20A8,8 0 0,1 4,12A8,8 0 0,1 12,4M11,16.5L18,9.5L16.59,8.09L11,13.67L7.91,10.59L6.5,12L11,16.5Z"/>
18745        </svg>
18746        Analisis AI: Perbandingan Produk
18747      </h3>
18748      <button class="modal-close" id="aiCompareModalClose" aria-label="Tutup">
18749        <svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor">
18750          <path d="M18.3 5.7a1 1 0 0 0-1.4 0L12 10.6 7.1 5.7a1 1 0 1 0-1.4 1.4L10.6 12l-4.9 4.9a1 1 0 0 0 1.4 1.4L12 13.4l4.9 4.9a1 1 0 0 0 1.4-1.4L13.4 12l4.9-4.9a1 1 0 0 0 0-1.4z"/>
18751        </svg>
18752      </button>
18753    </div>
18754    
18755    <div class="modal-content">
18756      <!-- Loading State -->
18757      <div class="ai-loading" id="aiLoading">
18758        <div class="loading-animation">
18759          <div class="typing-indicator">
18760            <span></span>
18761            <span></span>
18762            <span></span>
18763          </div>
18764          <p>AI sedang menganalisis produk...</p>
18765          <small>Proses ini membutuhkan waktu 10-30 detik</small>
18766        </div>
18767      </div>
18768      
18769      <!-- Error State -->
18770      <div class="ai-error" id="aiError" hidden>
18771        <div class="error-icon">
18772          <svg width="48" height="48" viewBox="0 0 24 24" fill="#C77DFF">
18773            <path d="M12,2C17.53,2 22,6.47 22,12C22,17.53 17.53,22 12,22C6.47,22 2,17.53 2,12C2,6.47 6.47,2 12,2M15.59,7L12,10.59L8.41,7L7,8.41L10.59,12L7,15.59L8.41,17L12,13.41L15.59,17L17,15.59L13.41,12L17,8.41L15.59,7Z"/>
18774          </svg>
18775        </div>
18776        <h4>Analisis AI Gagal</h4>
18777        <p id="aiErrorMessage">Terjadi kesalahan saat memproses analisis.</p>
18778        <button class="btn btn-outline-primary" id="aiRetry">Coba Lagi</button>
18779      </div>
18780      
18781      <!-- Analysis Results -->
18782      <div class="ai-results" id="aiResults" hidden>
18783        <!-- Summary Section -->
18784        <div class="ai-summary-card">
18785          <h4>
18786            <svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor">
18787              <path d="M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M11,16.5L6.5,12L7.91,10.59L11,13.67L16.59,8.09L18,9.5L11,16.5Z"/>
18788            </svg>
18789            Ringkasan Analisis
18790          </h4>
18791          <p id="aiSummary" class="summary-text"></p>
18792          <div class="winner-badge" id="winnerBadge">
18793            <strong>Rekomendasi Terbaik:</strong> <span id="winnerProduct"></span>
18794            <small id="winnerReason"></small>
18795          </div>
18796        </div>
18797        
18798        <!-- Comparison Table -->
18799        <div class="ai-comparison-table">
18800          <h4>
18801            <svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor">
18802              <path d="M3,3H21V5H3V3M3,7H21V9H3V7M3,11H21V13H3V11M3,15H21V17H3V15M3,19H21V21H3V19Z"/>
18803            </svg>
18804            Perbandingan Detail
18805          </h4>
18806          <div id="comparisonTable" class="comparison-grid"></div>
18807        </div>
18808        
18809        <!-- Detailed Analysis -->
18810        <div class="ai-detailed-analysis">
18811          <h4>
18812            <svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor">
18813              <path d="M14,2A8,8 0 0,1 22,10A8,8 0 0,1 14,18A8,8 0 0,1 6,10A8,8 0 0,1 14,2M14,4A6,6 0 0,0 8,10A6,6 0 0,0 14,16A6,6 0 0,0 20,10A6,6 0 0,0 14,4M14,6A4,4 0 0,1 18,10A4,4 0 0,1 14,14A4,4 0 0,1 10,10A4,4 0 0,1 14,6M14,8A2,2 0 0,0 12,10A2,2 0 0,0 14,12A2,2 0 0,0 16,10A2,2 0 0,0 14,8Z"/>
18814            </svg>
18815            Analisis Mendalam
18816          </h4>
18817          <div id="detailedAnalysis" class="products-analysis"></div>
18818        </div>
18819        
18820        <!-- Recommendations -->
18821        <div class="ai-recommendations">
18822          <h4>
18823            <svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor">
18824              <path d="M12,17.27L18.18,21L16.54,13.97L22,9.24L14.81,8.62L12,2L9.19,8.62L2,9.24L7.45,13.97L5.82,21L12,17.27Z"/>
18825            </svg>
18826            Rekomendasi Berdasarkan Kebutuhan
18827          </h4>
18828          <div class="recommendations-grid">
18829            <div class="recommendation-card">
18830              <h5>💰 Budget Conscious</h5>
18831              <p id="budgetRecommendation"></p>
18832            </div>
18833            <div class="recommendation-card">
18834              <h5>⚡ Performance Focused</h5>
18835              <p id="performanceRecommendation"></p>
18836            </div>
18837            <div class="recommendation-card">
18838              <h5>⚖️ Balanced Choice</h5>
18839              <p id="balancedRecommendation"></p>
18840            </div>
18841          </div>
18842        </div>
18843        
18844        <!-- Buying Tips -->
18845        <div class="ai-tips">
18846          <h4>
18847            <svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor">
18848              <path d="M11,18H13V16H11V18M12,6A4,4 0 0,0 8,10H10A2,2 0 0,1 12,8A2,2 0 0,1 14,10C14,12 11,11.75 11,15H13C13,12.75 16,12.5 16,10A4,4 0 0,0 12,6
18848M5,3H19A2,2 0 0,1 21,5V19A2,2 0 0,1 19,21H5A2,2 0 0,1 3,19V5A2,2 0 0,1 5,3Z"/>
18849            </svg>
18850            Tips Pembelian
18851          </h4>
18852          <ul id="buyingTips" class="tips-list"></ul>
18853        </div>
18854      </div>
18855    </div>
18856  </div>
18857</div>
18858
18859<!-- Cart Login Modal -->
18860<div class="modal-overlay" id="cartLoginModal">
18861  <div class="modal-dialog">
18862    <div class="modal-header">
18863      <h3 class="modal-title">
18864        <div class="modal-icon info">
18865          <svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor">
18866            <path d="M17,18A2,2 0 0,1 19,20A2,2 0 0,1 17,22C15.89,22 15,21.1 15,20C15,18.89 15.89,18 17,18M1,2H4.27L5.21,4H20A1,1 0 0,1 21,5C21,5.17 20.95,5.34 20.88,5.5L17.3,11.97C16.96,12.58 16.3,13 15.55,13H8.1L7.2,14.63L7.17,14.75A0.25,0.25 0 0,0 7.42,15H19V17H7C5.89,17 5,16.1 5,15C5,14.65 5.09,14.32 5.24,14.04L6.6,11.59L3,4H1V2M7,18A2,2 0 0,1 9,20A2,2 0 0,1 7,22C5.89,22 5,21.1 5,20C5,18.89 5.89,18 7,18M16,11L18.78,6H6.14L8.5,11H16Z"/>
18867          </svg>
18868        </div>
18869        Login untuk Melanjutkan
18870      </h3>
18871    </div>
18872    <div class="modal-body">
18873      <p class="modal-message" style="margin-bottom: 16px;">Silakan login atau daftar untuk mengakses keranjang belanja dan menyelesaikan pesanan Anda.</p>
18874      <div style="background: #f8fafc; border-radius: 8px; padding: 12px; margin-bottom: 20px;">
18875        <p style="font-size: 14px; color: #765212; margin: 0; line-height: 1.6;">
18876          <strong style="color: #2a2a0f;">Keuntungan dengan akun:</strong><br>
18877          ✓ Simpan keranjang belanja Anda<br>
18878          ✓ Lacak status pesanan secara real-time<br>
18879          ✓ Checkout lebih cepat dengan data tersimpan<br>
18880          ✓ Dapatkan notifikasi promo & diskon eksklusif
18881        </p>
18882      </div>
18883      <div class="modal-actions">
18884        <button class="modal-btn modal-btn-secondary" id="cartLoginCancel">Batal</button>
18885        <button class="modal-btn modal-btn-primary" id="cartLoginConfirm" style="background: #C77DFF; border-color: #C77DFF;">Login</button>
18886        <button class="modal-btn modal-btn-primary" id="cartRegisterBtn" style="background: #C77DFF; border-color: #C77DFF;">Daftar</button>
18887      </div>
18888    </div>
18889  </div>
18890</div>
18891
18892
18893<script data-inlined="app.js">
18894(function initLiveSearch(){
18895  function setup() {
18896    const searchInput = document.getElementById('searchInput');
18897    const suggest = document.getElementById('searchSuggest');
18898    const searchBtn = document.getElementById('searchBtn');
18899    const aiToggleBtn = document.getElementById('aiToggleBtn');
18900    
18901    if (!searchInput || !suggest || !aiToggleBtn) {
18902      console.log('[LiveSearch] Elemen belum ada, retry...');
18903      return false;
18904    }
18905
18906    let debounceTimer = null;
18907    let lastQuery = '';
18908    let currentIndex = -1;
18909    let currentAbortController = null;
18910    let isAIModeEnabled = false; // AI mode OFF by default
18911    let isAIProcessing = false; // Flag to prevent closing suggest box during AI processing
18912    
18913    // Trending cache
18914    let trendingCache = null;
18915    let trendingLoading = false;
18916    
18917    // Trending products cache
18918    let trendingProductsCache = null;
18919    let trendingProductsLoading = false;
18920    
18921    const MIN_LEN = 2;
18922    const DEBOUNCE = 300;
18923    const AI_TIMEOUT = 15000; // 15 seconds timeout for AI endpoint
18924
18925    // Load AI mode preference from localStorage
18926    const savedAIMode = localStorage.getItem('plazait_ai_search_mode');
18927    if (savedAIMode === 'enabled') {
18928      isAIModeEnabled = false;
18929      aiToggleBtn.classList.remove('active');
18930    }
18931    
18932    // Update placeholder based on AI mode
18933    function updatePlaceholder() {
18934      if (isAIModeEnabled) {
18935        searchInput.placeholder = '🤖 Coba: "laptop HP core i3 untuk kerja" atau "tinta epson l3210"';
18936      } else {
18937        // Static placeholder for typing animation
18938        searchInput.placeholder = '';
18939      }
18940    }
18941    
18942    // Typing animation for placeholder
18943    let typingTimeout = null;
18944    let currentProductIndex = 0;
18945    let currentCharIndex = 0;
18946    let isTyping = false;
18947    let isDeleting = false;
18948    
18949    const popularProducts = [
18950      'Oppo A6',
18951      'Asus Ryzen 3',
18952      'Starlink V4',
18953      'HP Victus',
18954      'Lenovo RTX 5060',
18955      'ROG Strix',
18956      'iPhone 13',
18957      'Xpad 20',
18958      'Xiaomi 14',
18959      'Epson L3210',
18960      'Realme C85',
18961      'Brother T720',
18962      'Mouse Logitech'
18963    ];
18964    
18965    function typeWriter() {
18966      if (isAIModeEnabled || document.activeElement === searchInput) {
18967        return; // Skip typing if AI mode is on or input is focused
18968      }
18969      
18970      const currentProduct = popularProducts[currentProductIndex];
18971      
18972      if (!isDeleting) {
18973        // Typing forward
18974        if (currentCharIndex < currentProduct.length) {
18975          searchInput.placeholder = currentProduct.substring(0, currentCharIndex + 1);
18976          currentCharIndex++;
18977          typingTimeout = setTimeout(typeWriter, 100); // Typing speed
18978        } else {
18979          // Finished typing, wait before deleting
18980          typingTimeout = setTimeout(() => {
18981            isDeleting = true;
18982            typeWriter();
18983          }, 2000); // Pause before deleting
18984        }
18985      } else {
18986        // Deleting backward
18987        if (currentCharIndex > 0) {
18988          searchInput.placeholder = currentProduct.substring(0, currentCharIndex - 1);
18989          currentCharIndex--;
18990          typingTimeout = setTimeout(typeWriter, 50); // Deleting speed (faster)
18991        } else {
18992          // Finished deleting, move to next product
18993          isDeleting = false;
18994          currentProductIndex = (currentProductIndex + 1) % popularProducts.length;
18995          typingTimeout = setTimeout(typeWriter, 500); // Pause before typing next
18996        }
18997      }
18998    }
18999    
19000    function startTypingAnimation() {
19001      if (!isAIModeEnabled && !typingTimeout) {
19002        currentCharIndex = 0;
19003        isDeleting = false;
19004        typeWriter();
19005      }
19006    }
19007    
19008    function stopTypingAnimation() {
19009      if (typingTimeout) {
19010        clearTimeout(typingTimeout);
19011        typingTimeout = null;
19012      }
19013    }
19014    
19015    // Set initial placeholder
19016    updatePlaceholder();
19017    
19018    // Start typing animation for normal mode
19019    if (!isAIModeEnabled) {
19020      startTypingAnimation();
19021    }
19022
19023    function esc(str){
19024      if (str === null || str === undefined) return '';
19025      return String(str)
19026        .replace(/&/g,'&amp;')
19027        .replace(/</g,'&lt;')
19028        .replace(/>/g,'&gt;')
19029        .replace(/"/g,'&quot;')
19030        .replace(/'/g,'&#39;');
19031    }
19032
19033    function clearSuggest(){
19034      suggest.innerHTML = '';
19035      suggest.hidden = true;
19036      suggest.classList.remove('open', 'trending-mode');
19037      currentIndex = -1;
19038    }
19039
19040    // ==================== TRENDING FUNCTIONS ====================
19041    
19042    async function fetchTrending() {
19043      if (trendingCache) return trendingCache;
19044      if (trendingLoading) return null;
19045      
19046      trendingLoading = true;
19047      
19048      try {
19049        const res = await fetch('/api/trending_searches.php?timeframe=7d&limit=8');
19050        const data = await res.json();
19051        
19052        if (data.ok && Array.isArray(data.data)) {
19053          trendingCache = data.data;
19054          console.log('[Trending] Loaded', trendingCache.length, 'items');
19055          return trendingCache;
19056        }
19057      } catch (err) {
19058        console.error('[Trending] Fetch error:', err);
19059      } finally {
19060        trendingLoading = false;
19061      }
19062      
19063      return null;
19064    }
19065    
19066    async function fetchTrendingProducts() {
19067      if (trendingProductsCache) return trendingProductsCache;
19068      if (trendingProductsLoading) return null;
19069      
19070      trendingProductsLoading = true;
19071      
19072      try {
19073        const res = await fetch('/api/trending_products.php?timeframe=7d&limit=6');
19074        const data = await res.json();
19075        
19076        if (data.ok && Array.isArray(data.data)) {
19077          trendingProductsCache = data.data;
19078          console.log('[Trending Products] Loaded', trendingProductsCache.length, 'items');
19079          return trendingProductsCache;
19080        }
19081      } catch (err) {
19082        console.error('[Trending Products] Fetch error:', err);
19083      } finally {
19084        trendingProductsLoading = false;
19085      }
19086      
19087      return null;
19088    }
19089    
19090    function renderTrendingSuggestions(trends, products) {
19091      if ((!trends || trends.length === 0) && (!products || products.length === 0)) {
19092        clearSuggest();
19093        return;
19094      }
19095      
19096      let html = `<div class="trending-container">`;
19097      
19098      // Left column: Trending searches
19099      if (trends && trends.length > 0) {
19100        html += `
19101          <div class="trending-column trending-searches">
19102            <div class="trending-header">
19103              <span class="trending-icon">🔥</span>
19104              <span class="trending-title">Pencarian Trending</span>
19105            </div>
19106        `;
19107        
19108        html += trends.map((t, idx) => {
19109          const categoryHint = t.category_hint ? `<span class="trending-category">${esc(t.category_hint)}</span>` : '';
19110          return `
19111            <div class="trending-item" data-query="${esc(t.query)}" data-index="${idx}">
19112              <span class="trending-rank">
19113                <img src="/assets/img/uptrend.image" alt="trending" width="16" height="16" style="vertical-align: middle;">
19114              </span>
19115              <span class="trending-query">${esc(t.query)}</span>
19116              ${categoryHint}
19117            </div>
19118          `;
19119        }).join('');
19120        
19121        html += `</div>`;
19122      }
19123      
19124      // Right column: Trending products
19125      if (products && products.length > 0) {
19126        html += `
19127          <div class="trending-column trending-products">
19128            <div class="trending-header">
19129              <span class="trending-icon">⭐</span>
19130              <span class="trending-title">Produk Populer</span>
19131            </div>
19132        `;
19133        
19134        html += products.map((p, idx) => {
19135          return `
19136            <div class="trending-product-item" data-product-id="${esc(p.id)}" data-slug="${esc(p.slug)}" data-query="${esc(p.top_query || '')}" data-index="${idx}">
19137              <img src="${esc(p.image)}" alt="${esc(p.name)}" class="trending-product-thumb">
19138              <div class="trending-product-info">
19139                <div class="trending-product-name">${esc(p.name)}</div>
19140                <div class="trending-product-price">${esc(p.price_label)}</div>
19141              </div>
19142            </div>
19143          `;
19144        }).join('');
19145        
19146        html += `</div>`;
19147      }
19148      
19149      html += `</div>`;
19150      
19151      suggest.innerHTML = html;
19152      suggest.hidden = false;
19153      suggest.classList.add('open', 'trending-mode');
19154      suggest.style.display = 'block';
19155      
19156      console.log('[Trending] Rendered', trends?.length || 0, 'searches and', products?.length || 0, 'products');
19157    }
19158    
19159    function trackSearchClick(query, productId) {
19160      fetch('/api/track_search_click.php', {
19161        method: 'POST',
19162        headers: { 'Content-Type': 'application/json' },
19163        body: JSON.stringify({
19164          query: query,
19165          product_id: productId,
19166          click_type: 'suggestion'
19167        })
19168      }).catch(() => {}); // silent fail
19169    }
19170    
19171    function trackTrendingClick(query) {
19172      fetch('/api/track_search_click.php', {
19173        method: 'POST',
19174        headers: { 'Content-Type': 'application/json' },
19175        body: JSON.stringify({
19176          query: query,
19177          click_type: 'trending'
19178        })
19179      }).catch(() => {});
19180    }
19181    
19182    function trackTrendingProductClick(productId, query) {
19183      fetch('/api/track_search_click.php', {
19184        method: 'POST',
19185        headers: { 'Content-Type': 'application/json' },
19186        body: JSON.stringify({
19187          query: query || 'trending_product',
19188          product_id: productId,
19189          click_type: 'trending_product'
19190        })
19191      }).catch(() => {});
19192    }
19193    
19194    function trackSearchSubmit(query) {
19195      fetch('/api/track_search_click.php', {
19196        method: 'POST',
19197        headers: { 'Content-Type': 'application/json' },
19198        body: JSON.stringify({
19199          query: query,
19200          click_type: 'submit'
19201        })
19202      }).catch(() => {});
19203    }
19204    
19205    function logFinalSearch(query) {
19206      // Log the final search to analytics (not during typing)
19207      fetch('/api/search_products.php?q=' + encodeURIComponent(query) + '&log=1', {
19208        headers: { 'Accept': 'application/json' }
19209      }).catch(() => {});
19210    }
19211
19212    // ==================== END TRENDING FUNCTIONS ====================
19213
19214    function clearSuggest(){
19215      suggest.innerHTML = '';
19216      suggest.hidden = true;
19217      suggest.classList.remove('open', 'trending-mode');
19218      currentIndex = -1;
19219    }
19220
19221    // AI Toggle Handler
19222    aiToggleBtn.addEventListener('click', (e) => {
19223      e.preventDefault();
19224      e.stopPropagation();
19225      
19226      isAIModeEnabled = !isAIModeEnabled;
19227      
19228      if (isAIModeEnabled) {
19229        aiToggleBtn.classList.add('active');
19230        localStorage.setItem('plazait_ai_search_mode', 'enabled');
19231        updatePlaceholder(); // Update placeholder text
19232        stopTypingAnimation(); // Stop typing animation in AI mode
19233        
19234        // Show AI prompt if there's a query
19235        const query = searchInput.value.trim();
19236        if (query.length >= MIN_LEN) {
19237          showAISearchPrompt(query);
19238        } else {
19239          showAIActivationMessage();
19240        }
19241      } else {
19242        aiToggleBtn.classList.remove('active');
19243        localStorage.setItem('plazait_ai_search_mode', 'disabled');
19244        updatePlaceholder(); // Update placeholder text
19245        startTypingAnimation(); // Start typing animation in normal mode
19246        clearSuggest();
19247        
19248        // Switch to normal search if there's a query
19249        const query = searchInput.value.trim();
19250        if (query.length >= MIN_LEN) {
19251          performSearch(query);
19252        }
19253      }
19254    });
19255
19256    function showAIActivationMessage() {
19257      suggest.innerHTML = `
19258        <div class="ai-progress-container">
19259          <div class="ai-progress-header">
19260            <div class="ai-progress-icon">✨</div>
19261            <div class="ai-progress-text">
19262              <div class="ai-progress-title">AI Search Mode Activated!</div>
19263              <div class="ai-progress-subtitle">Ketik query Anda untuk pencarian cerdas</div>
19264            </div>
19265          </div>
19266        </div>
19267      `;
19268      suggest.hidden = false;
19269      suggest.classList.add('open');
19270      suggest.style.display = 'block';
19271    }
19272
19273    function renderAIInsights(insights){
19274      if (!insights) return '';
19275      
19276      // Generate AI summary via backend endpoint
19277      const summary = insights.ai_summary || generateAISummary(insights);
19278      
19279      if (!summary) return '';
19280      
19281      return `
19282        <div class="ai-result-banner">
19283          <div class="ai-result-icon">✨</div>
19284          <div class="ai-result-text">
19285            <div class="ai-result-title">AI Assistant</div>
19286            <div class="ai-result-description">${summary}</div>
19287          </div>
19288        </div>
19289      `;
19290    }
19291    
19292    function generateAISummary(insights) {
19293      // Fallback client-side summary generation if backend doesn't provide ai_summary
19294      const productName = insights.product_name || '';
19295      const categoryPath = insights.category_path || '';
19296      const priceRange = insights.price_range || {};
19297      const intent = insights.intent || '';
19298      
19299      let summary = '';
19300      
19301      // Parse category for natural display
19302      let categoryDisplay = '';
19303      if (categoryPath) {
19304        const categoryParts = categoryPath.split('/');
19305        categoryDisplay = categoryParts[categoryParts.length - 1] || categoryParts[categoryParts.length - 2] || categoryPath;
19306      }
19307      
19308      // Intent-based opening
19309      if (intent === 'cek_stok') {
19310        summary = `Berikut ketersediaan stok untuk <strong>${esc(productName)}</strong>. `;
19311      } else if (intent === 'rekomendasi_produk') {
19312        summary = `Berikut rekomendasi produk <strong>${esc(categoryDisplay || productName)}</strong> yang kami pilihkan untuk Anda. `;
19313      } else {
19314        // Default: cari_harga or general
19315        if (productName && categoryDisplay) {
19316          summary = `Kami menemukan <strong>${esc(productName)}</strong> di kategori ${esc(categoryDisplay)}`;
19317        } else if (productName) {
19318          summary = `Kami menemukan produk <strong>${esc(productName)}</strong>`;
19319        } else if (categoryDisplay) {
19320          summary = `Kami menemukan produk ${esc(categoryDisplay)}`;
19321        }
19322        
19323        // Add price context
19324        if (priceRange.min > 0 && priceRange.max > 0) {
19325          const minPrice = new Intl.NumberFormat('id-ID', { style: 'currency', currency: 'IDR', minimumFractionDigits: 0 }).format(priceRange.min);
19326          const maxPrice = new Intl.NumberFormat('id-ID', { style: 'currency', currency: 'IDR', minimumFractionDigits: 0 }).format(priceRange.max);
19327          summary += ` dengan kisaran harga ${minPrice} - ${maxPrice}`;
19328        } else if (priceRange.min > 0) {
19329          const minPrice = new Intl.NumberFormat('id-ID', { style: 'currency', currency: 'IDR', minimumFractionDigits: 0 }).format(priceRange.min);
19330          summary += ` dengan harga mulai ${minPrice}`;
19331        } else if (priceRange.max > 0) {
19332          const maxPrice = new Intl.NumberFormat('id-ID', { style: 'currency', currency: 'IDR', minimumFractionDigits: 0 }).format(priceRange.max);
19333          summary += ` dengan harga maksimal ${maxPrice}`;
19334        }
19335        
19336        summary += ' yang sesuai dengan kebutuhan Anda.';
19337      }
19338      
19339      return summary || esc(insights.explanation || '');
19340    }
19341
19342    function showAIProgressSteps() {
19343      return `
19344        <div class="ai-progress-container">
19345          <div class="ai-progress-header">
19346            <div class="ai-progress-icon">🤖</div>
19347            <div class="ai-progress-text">
19348              <div class="ai-progress-title">AI sedang menganalisis...</div>
19349              <div class="ai-progress-subtitle">Memproses query Anda dengan kecerdasan buatan</div>
19350            </div>
19351          </div>
19352          <div class="ai-progress-steps">
19353            <div class="ai-progress-step active">
19354              <div class="ai-step-icon">1</div>
19355              <div class="ai-step-text">Memahami maksud pencarian...</div>
19356            </div>
19357            <div class="ai-progress-step pending">
19358              <div class="ai-step-icon">2</div>
19359              <div class="ai-step-text">Mengekstrak parameter pencarian...</div>
19360            </div>
19361            <div class="ai-progress-step pending">
19362              <div class="ai-step-icon">3</div>
19363              <div class="ai-step-text">Mencari produk yang relevan...</div>
19364            </div>
19365          </div>
19366        </div>
19367      `;
19368    }
19369
19370    function updateAIProgressStep(step) {
19371      const steps = suggest.querySelectorAll('.ai-progress-step');
19372      
19373      steps.forEach((stepEl, idx) => {
19374        const icon = stepEl.querySelector('.ai-step-icon');
19375        
19376        if (idx < step) {
19377          stepEl.classList.remove('active', 'pending');
19378          stepEl.classList.add('completed');
19379          icon.textContent = '✓';
19380        } else if (idx === step) {
19381          stepEl.classList.remove('pending', 'completed');
19382          stepEl.classList.add('active');
19383        }
19384      });
19385    }
19386
19387    function renderSuggest(items, aiInsights){
19388      if (!items.length){
19389        clearSuggest();
19390        return;
19391      }
19392      
19393      let html = '';
19394      
19395      // Show AI insights if available
19396      if (aiInsights && aiInsights.explanation) {
19397        html += renderAIInsights(aiInsights);
19398      }
19399      
19400      // Section header for products with hint
19401      html += `
19402        <div class="suggest-section-header">
19403          <div class="suggest-header-main">
19404            <span class="suggest-header-icon">📦</span>
19405            <span class="suggest-header-text">Produk yang ditemukan (${items.length})</span>
19406          </div>
19407          <div class="suggest-header-hint">Tekan <kbd>Enter</kbd> untuk lihat semua hasil</div>
19408        </div>
19409      `;
19410      
19411      // Render product items
19412      html += items.map((it, idx)=>{
19413        // Normalisasi & fallback
19414        const id    = it.id != null ? it.id : '';
19415        const name  = esc(it.name);
19416        const slug  = esc(it.slug != null ? it.slug : it.id);
19417        const img   = esc(it.image || '/assets/img/no-image.png');
19418        const price = esc(it.price_label || '');
19419
19420       const url = '/product/' + encodeURIComponent(slug);
19421
19422        return `
19423          <div class="suggest-item" data-index="${idx}" data-url="${url}" data-id="${esc(id)}">
19424            <img src="${img}" alt="${name}" class="suggest-thumb">
19425            <div class="suggest-meta">
19426              <div class="suggest-name">${name}</div>
19427              <div class="suggest-price">${price}</div>
19428            </div>
19429          </div>
19430        `;
19431      }).join('');
19432      
19433      // Footer hint for more results - only show if 10 items (means there might be more)
19434      if (items.length >= 10) {
19435        html += `
19436          <div class="suggest-footer-hint">
19437            <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="vertical-align: -3px; margin-right: 6px;">
19438              <path d="M9.29 6.71a.996.996 0 0 0 0 1.41L13.17 12l-3.88 3.88a.996.996 0 1 0 1.41 1.41l4.59-4.59a.996.996 0 0 0 0-1.41L10.7 6.7c-.38-.39-1.02-.39-1.41.01z"/>
19439            </svg>
19440            <span>Lihat hasil lengkap dengan menekan <kbd>Enter</kbd> atau <a href="#" class="suggest-footer-link" id="footerSearchLink">klik di sini</a></span>
19441          </div>
19442        `;
19443      }
19444      
19445      suggest.innerHTML = html;
19446      suggest.hidden = false;
19447      suggest.classList.add('open');
19448      suggest.style.display = 'block';
19449      suggest.style.visibility = 'visible';
19450      suggest.style.opacity = '1';
19451    }
19452
19453    function fetchRemote(q, shouldLog = false){
19454      // Cancel previous request if any
19455      if (currentAbortController) {
19456        currentAbortController.abort();
19457      }
19458      currentAbortController = new AbortController();
19459
19460      // Always use standard search for normal mode
19461      // Only add log=1 parameter when shouldLog is true (intentional search)
19462      const logParam = shouldLog ? '&log=1' : '';
19463      const url = '/api/search_products.php?q=' + encodeURIComponent(q) + logParam;
19464      const fetchOptions = {
19465        headers: {'Accept':'application/json'},
19466        signal: currentAbortController.signal
19467      };
19468
19469      return fetch(url, fetchOptions)
19470        .then(r=>r.json())
19471        .then(j=>{
19472          if (j.ok && Array.isArray(j.data)) {
19473            return j;
19474          }
19475          return { ok: false, data: [] };
19476        })
19477        .catch(err=>{
19478          if (err.name === 'AbortError') {
19479            return { ok: false, data: [] };
19480          }
19481          return { ok:false, data:[] };
19482        });
19483    }
19484
19485    function showNoResults(q, aiInsights) {
19486      suggest.innerHTML = `
19487        <div style="padding: 32px 24px; text-align: center; color: #64748b;">
19488          <div style="font-size: 56px; margin-bottom: 16px; opacity: 0.6;">🔍</div>
19489          <div style="font-size: 16px; font-weight: 600; color: #334155; margin-bottom: 8px;">
19490            Tidak ada hasil untuk "${esc(q)}"
19491          </div>
19492          ${aiInsights && aiInsights.explanation ? `
19493            <div style="font-size: 13px; margin: 16px auto; padding: 12px 16px; background: #f1f5f9; border-radius: 8px; max-width: 400px; color: #475569;">
19494              <strong style="color: #667eea;">🤖 AI memahami:</strong><br>
19495              ${esc(aiInsights.explanation)}
19496            </div>
19497          ` : ''}
19498          <div style="font-size: 13px; margin-top: 16px; opacity: 0.8;">
19499            Coba kata kunci lain atau hubungi kami untuk bantuan
19500          </div>
19501        </div>
19502      `;
19503      suggest.hidden = false;
19504      suggest.classList.add('open');
19505      suggest.style.display = 'block';
19506    }
19507
19508    function showErrorMessage() {
19509      suggest.innerHTML = `
19510        <div style="padding: 32px 24px; text-align: center; color: #C77DFF;">
19511          <div style="font-size: 48px; margin-bottom: 12px;">⚠️</div>
19512          <div style="font-size: 14px; font-weight: 600; margin-bottom: 8px;">
19513            Pencarian tidak tersedia
19514          </div>
19515          <div style="font-size: 12px; opacity: 0.8;">
19516            Silakan coba lagi dalam beberapa saat
19517          </div>
19518        </div>
19519      `;
19520      suggest.hidden = false;
19521      suggest.classList.add('open');
19522      suggest.style.display = 'block';
19523    }
19524
19525    function showAIErrorState(q) {
19526      suggest.innerHTML = `
19527        <div class="ai-progress-container">
19528          <div class="ai-progress-header">
19529            <div class="ai-progress-icon" style="background: linear-gradient(135deg, #C77DFF 0%, #C77DFF 100%);">⚡</div>
19530            <div class="ai-progress-text">
19531              <div class="ai-progress-title">AI sedang memproses...</div>
19532              <div class="ai-progress-subtitle">Menganalisis query: "${esc(q)}"</div>
19533            </div>
19534          </div>
19535          <div style="padding: 16px; margin-top: 12px; background: #fef3c7; border-radius: 8px; border-left: 3px solid #C77DFF;">
19536            <div style="font-size: 13px; color: #ae7e21; line-height: 1.6;">
19537              <strong style="display: block; margin-bottom: 4px;">💡 Sedang mencari produk terbaik untuk Anda</strong>
19538              AI kami sedang menganalisis database untuk menemukan hasil yang paling relevan.
19539              Mohon tunggu sebentar...
19540            </div>
19541          </div>
19542          <div style="padding: 12px 16px; margin-top: 12px; text-align: center;">
19543            <button onclick="location.reload()" style="padding: 8px 16px; background: #C77DFF; color: white; border: none; border-radius: 6px; cursor: pointer; font-size: 13px; font-weight: 600;">
19544              🔄 Refresh & Coba Lagi
19545            </button>
19546          </div>
19547        </div>
19548      `;
19549      suggest.hidden = false;
19550      suggest.classList.add('open');
19551      suggest.style.display = 'block';
19552    }
19553
19554    function triggerAISearch(q) {
19555      lastQuery = q; // Update lastQuery to prevent re-triggering
19556      isAIProcessing = true; // Set flag to prevent suggest box from closing
19557      
19558      // Show AI progress UI - keep suggest box visible
19559      suggest.innerHTML = showAIProgressSteps();
19560      suggest.hidden = false;
19561      suggest.classList.add('open');
19562      suggest.style.display = 'block';
19563      
19564      setTimeout(() => updateAIProgressStep(1), 1000);
19565      setTimeout(() => updateAIProgressStep(2), 2500);
19566
19567      // Cancel previous request if any
19568      if (currentAbortController) {
19569        currentAbortController.abort();
19570      }
19571      currentAbortController = new AbortController();
19572
19573      const url = '/api/search_ai.php?q=' + encodeURIComponent(q);
19574      const fetchOptions = {
19575        headers: {'Accept':'application/json'},
19576        signal: currentAbortController.signal
19577      };
19578      
19579      // Add timeout
19580      const timeoutId = setTimeout(() => {
19581        currentAbortController.abort();
19582        
19583        // Show fallback loading state
19584        suggest.innerHTML = `
19585          <div class="ai-progress-container">
19586            <div class="ai-progress-header">
19587              <div class="ai-progress-icon">⏳</div>
19588              <div class="ai-progress-text">
19589                <div class="ai-progress-title">AI timeout - switching to standard search</div>
19590                <div class="ai-progress-subtitle">Mencari dengan metode tradisional...</div>
19591              </div>
19592            </div>
19593          </div>
19594        `;
19595        
19596        // Fallback to traditional search
19597        fetch('/api/search_products.php?q=' + encodeURIComponent(q), {
19598          headers: { 'Accept': 'application/json' }
19599        })
19600          .then(r => r.json())
19601          .then(j => {
19602            isAIProcessing = false; // Reset flag
19603            if (j.ok && Array.isArray(j.data) && j.data.length) {
19604              renderSuggest(j.data, null);
19605            } else {
19606              showNoResults(q, null);
19607            }
19608          })
19609          .catch(() => {
19610            isAIProcessing = false; // Reset flag
19611            showAIErrorState(q);
19612          });
19613      }, AI_TIMEOUT);
19614
19615      fetch(url, fetchOptions)
19616        .then(r => r.json())
19617        .then(j => {
19618          clearTimeout(timeoutId);
19619          isAIProcessing = false; // Reset flag when done
19620          
19621          if (j.ok && Array.isArray(j.data)) {
19622            if (j.data.length > 0) {
19623              renderSuggest(j.data, j.ai_insights || null);
19624            } else {
19625              showNoResults(q, j.ai_insights || null);
19626            }
19627          } else {
19628            showAIErrorState(q);
19629          }
19630        })
19631        .catch(err => {
19632          clearTimeout(timeoutId);
19633          isAIProcessing = false; // Reset flag on error
19634          if (err.name !== 'AbortError') {
19635            showAIErrorState(q);
19636          }
19637        });
19638    }
19639
19640    function performSearch(q){
19641      if (q.length < MIN_LEN){
19642        clearSuggest();
19643        return;
19644      }
19645      if (q === lastQuery) return;
19646      lastQuery = q;
19647      
19648      // Normal mode only - AI mode uses triggerAISearch()
19649      fetchRemote(q).then(j=>{
19650        if (j.ok && Array.isArray(j.data)){
19651          if (j.data.length > 0) {
19652            renderSuggest(j.data, null);
19653          } else {
19654            showNoResults(q, null);
19655          }
19656        } else {
19657          clearSuggest();
19658        }
19659      }).catch(() => {
19660        clearSuggest();
19661      });
19662    }
19663
19664    function debounce(){
19665      const q = searchInput.value.trim();
19666      clearTimeout(debounceTimer);
19667      
19668      // If empty, show trending suggestions and products
19669      if (q.length === 0) {
19670        debounceTimer = setTimeout(async () => {
19671          const trends = trendingCache || await fetchTrending();
19672          const products = trendingProductsCache || await fetchTrendingProducts();
19673          if ((trends && trends.length > 0) || (products && products.length > 0)) {
19674            renderTrendingSuggestions(trends, products);
19675          } else {
19676            clearSuggest();
19677          }
19678        }, 100);
19679        return;
19680      }
19681      
19682      // For AI mode, just show search prompt (no auto search)
19683      if (isAIModeEnabled && q.length >= MIN_LEN) {
19684        showAISearchPrompt(q);
19685      } else if (!isAIModeEnabled && q.length >= MIN_LEN) {
19686        // Normal mode: auto search with debounce
19687        debounceTimer = setTimeout(()=> performSearch(q), DEBOUNCE);
19688      } else {
19689        clearSuggest();
19690      }
19691    }
19692
19693    function showAISearchPrompt(q) {
19694      suggest.innerHTML = `
19695        <div class="ai-search-prompt">
19696          <div class="ai-prompt-header">
19697            <div class="ai-prompt-icon">🤖</div>
19698            <div class="ai-prompt-text">
19699              <div class="ai-prompt-title">Pencarian AI Siap!</div>
19700              <div class="ai-prompt-subtitle">Klik tombol di bawah untuk mencari dengan AI</div>
19701            </div>
19702          </div>
19703          <div class="ai-prompt-query">
19704            <div class="ai-query-label">
19704Query Anda:</div>
19705            <div class="ai-query-text">"${esc(q)}"</div>
19706          </div>
19707          <button class="ai-search-trigger-btn" data-query="${esc(q)}">
19708            <span class="ai-btn-icon">✨</span>
19709            <span class="ai-btn-text">Cari dengan AI</span>
19710          </button>
19711          <div class="ai-prompt-footer">
19712            AI akan menganalisis query Anda untuk hasil yang lebih relevan
19713          </div>
19714        </div>
19715      `;
19716      suggest.hidden = false;
19717      suggest.classList.add('open');
19718      suggest.style.display = 'block';
19719    }
19720
19721    function moveHighlight(dir){
19722      if (suggest.hidden) return;
19723      const items = suggest.querySelectorAll('.suggest-item');
19724      if (!items.length) return;
19725      currentIndex += dir;
19726      if (currentIndex < 0) currentIndex = items.length - 1;
19727      if (currentIndex >= items.length) currentIndex = 0;
19728      items.forEach(it=> it.classList.remove('active'));
19729      const active = items[currentIndex];
19730      if (active){
19731        active.classList.add('active');
19732        active.scrollIntoView({block:'nearest'});
19733      }
19734    }
19735
19736    function activate(){
19737      const active = suggest.querySelector('.suggest-item.active');
19738      if (!active) return;
19739      window.location.href = active.getAttribute('data-url');
19740    }
19741
19742    searchInput.addEventListener('input', debounce);
19743    
19744    // Stop typing animation when focused & load trending if empty
19745    searchInput.addEventListener('focus', async () => {
19746      stopTypingAnimation();
19747      
19748      const q = searchInput.value.trim();
19749      
19750      // If empty, show trending suggestions and products
19751      if (q.length === 0) {
19752        const trends = trendingCache || await fetchTrending();
19753        const products = trendingProductsCache || await fetchTrendingProducts();
19754        if ((trends && trends.length > 0) || (products && products.length > 0)) {
19755          renderTrendingSuggestions(trends, products);
19756        }
19757        return;
19758      }
19759      
19760      // If AI mode and has query, show AI prompt
19761      if (isAIModeEnabled && q.length >= MIN_LEN && suggest.hidden) {
19762        showAISearchPrompt(q);
19763      }
19764    });
19765    
19766    // Resume typing animation when blurred (if suggest is closed)
19767    searchInput.addEventListener('blur', () => {
19768      // Add delay to allow click events to fire first
19769      setTimeout(() => {
19770        if (!isAIModeEnabled && suggest.hidden && searchInput.value.trim() === '') {
19771          startTypingAnimation();
19772        }
19773      }, 200);
19774    });
19775    
19776    searchInput.addEventListener('keydown', e=>{
19777      switch(e.key){
19778        case 'ArrowDown': moveHighlight(1); e.preventDefault(); break;
19779        case 'ArrowUp': moveHighlight(-1); e.preventDefault(); break;
19780        case 'Enter':
19781          if (!suggest.hidden){
19782            activate();
19783            e.preventDefault();
19784          } else {
19785            // Direct enter without suggestion - track search submit and log final search
19786            const q = searchInput.value.trim();
19787            if (q.length >= MIN_LEN) {
19788              trackSearchSubmit(q);
19789              logFinalSearch(q);
19790            }
19791          }
19792          break;
19793        case 'Escape': clearSuggest(); break;
19794      }
19795    });
19796
19797    suggest.addEventListener('click', e=>{
19798      // Check if footer link clicked
19799      const footerLink = e.target.closest('#footerSearchLink');
19800      if (footerLink) {
19801        e.preventDefault();
19802        const q = searchInput.value.trim();
19803        if (q.length >= MIN_LEN) {
19804          trackSearchSubmit(q);
19805          logFinalSearch(q);
19806          window.location.href = '/product/search/?q=' + encodeURIComponent(q);
19807        }
19808        return;
19809      }
19810      
19811      // Check if AI search button clicked
19812      const aiBtn = e.target.closest('.ai-search-trigger-btn');
19813      if (aiBtn) {
19814        const query = aiBtn.getAttribute('data-query');
19815        if (query) {
19816          triggerAISearch(query);
19817        }
19818        return;
19819      }
19820      
19821      // Handle trending item click
19822      const trendingItem = e.target.closest('.trending-item');
19823      if (trendingItem) {
19824        const query = trendingItem.getAttribute('data-query');
19825        if (query) {
19826          searchInput.value = query;
19827          trackTrendingClick(query);
19828          logFinalSearch(query); // Log final search when user clicks trending
19829          performSearch(query);
19830        }
19831        return;
19832      }
19833      
19834      // Handle trending product click
19835      const trendingProduct = e.target.closest('.trending-product-item');
19836      if (trendingProduct) {
19837        const productId = trendingProduct.getAttribute('data-product-id');
19838        const slug = trendingProduct.getAttribute('data-slug');
19839        const query = trendingProduct.getAttribute('data-query');
19840        
19841        if (productId && slug) {
19842          trackTrendingProductClick(productId, query);
19843          window.location.href = '/product/' + encodeURIComponent(slug);
19844        }
19845        return;
19846      }
19847      
19848      // Handle product item click
19849      const it = e.target.closest('.suggest-item');
19850      if (!it) return;
19851      
19852      const productId = it.getAttribute('data-id');
19853      trackSearchClick(lastQuery, productId);
19854      logFinalSearch(lastQuery); // Log final search when user clicks on suggestion
19855      
19856      window.location.href = it.getAttribute('data-url');
19857    });
19858
19859    document.addEventListener('click', e=>{
19860      // Don't close suggest box if AI is processing
19861      if (isAIProcessing) return;
19862      
19863      if (e.target === searchInput || e.target === aiToggleBtn || 
19864          suggest.contains(e.target) || aiToggleBtn.contains(e.target)) return;
19865      clearSuggest();
19866    });
19867
19868    if (searchBtn){
19869      searchBtn.addEventListener('click', ()=>{
19870        const q = searchInput.value.trim();
19871        if (q.length >= MIN_LEN){
19872          // Track search submit and log final search
19873          trackSearchSubmit(q);
19874          logFinalSearch(q);
19875          window.location.href = '/product/search/?q=' + encodeURIComponent(q);
19876        }
19877      });
19878    }
19879
19880    // Pastikan style dasar muncul
19881    if (!suggest.classList.contains('wired')) {
19882      suggest.classList.add('wired');
19883      suggest.style.position = 'absolute';
19884      suggest.style.zIndex = '9999';
19885      suggest.style.background = '#fff';
19886      suggest.style.border = '1px solid #ccc';
19887      suggest.style.boxShadow = '0 4px 12px rgba(0,0,0,0.12)';
19888      suggest.style.maxHeight = '360px';
19889      suggest.style.overflowY = 'auto';
19890    }
19891
19892    return true;
19893  }
19894
19895  if (!setup()) {
19896    if (document.readyState === 'loading') {
19897      document.addEventListener('DOMContentLoaded', setup);
19898    } else {
19899      setTimeout(setup, 80);
19900    }
19901  }
19902})();
19903</script>
vendor: 2 bytes, line 19903
19903
19904<script data-inlined="site-notice.js">
19905/**
19906 * Site Notice Banner - Interactive Behavior
19907 * Handles dismiss functionality with localStorage persistence
19908 * Supports dynamic notice IDs for different campaigns
19909 */
19910
19911(function() {
19912    'use strict';
19913
19914    const STORAGE_KEY = 'plazait_site_notice_dismissed';
19915    
19916    const banner = document.getElementById('holidayNotice');
19917    const closeBtn = document.getElementById('holidayNoticeClose');
19918    
19919    if (!banner || !closeBtn) return;
19920
19921    // Get notice ID from data attribute
19922    const noticeId = banner.dataset.noticeId;
19923    if (!noticeId) {
19924        console.warn('Notice ID not found. Banner will not persist dismiss state.');
19925    }
19926
19927    /**
19928     * Check if banner was previously dismissed
19929     */
19930    function wasDismissed() {
19931        if (!noticeId) return false;
19932        
19933        try {
19934            const dismissed = localStorage.getItem(STORAGE_KEY);
19935            return dismissed === noticeId;
19936        } catch (e) {
19937            console.warn('localStorage not available:', e);
19938            return false;
19939        }
19940    }
19941
19942    /**
19943     * Mark banner as dismissed
19944     */
19945    function markDismissed() {
19946        if (!noticeId) return;
19947        
19948        try {
19949            localStorage.setItem(STORAGE_KEY, noticeId);
19950        } catch (e) {
19951            console.warn('Could not save to localStorage:', e);
19952        }
19953    }
19954
19955    /**
19956     * Hide banner with animation
19957     */
19958    function hideBanner() {
19959        banner.classList.add('hidden');
19960        document.body.classList.remove('has-holiday-notice');
19961        
19962        // Remove from DOM after animation
19963        setTimeout(() => {
19964            banner.remove();
19965        }, 300);
19966        
19967        markDismissed();
19968        
19969        // Analytics tracking (optional)
19970        if (window.gtag) {
19971            window.gtag('event', 'banner_dismiss', {
19972                'event_category': 'Site Notice',
19973                'event_label': noticeId || 'unknown',
19974            });
19975        }
19976    }
19977
19978    /**
19979     * Initialize banner
19980     */
19981    function init() {
19982        // Check if already dismissed
19983        if (wasDismissed()) {
19984            banner.remove();
19985            return;
19986        }
19987        
19988        // Add body class for layout adjustment
19989        document.body.classList.add('has-holiday-notice');
19990        
19991        // Close button click
19992        closeBtn.addEventListener('click', hideBanner);
19993        
19994        // Keyboard support for close button
19995        closeBtn.addEventListener('keydown', (e) => {
19996            if (e.key === 'Enter' || e.key === ' ') {
19997                e.preventDefault();
19998                hideBanner();
19999            }
20000        });
20001        
20002        // Optional: Auto-hide after certain time (disabled by default)
20003        // setTimeout(hideBanner, 30000); // 30 seconds
20004    }
20005
20006    // Initialize when DOM is ready
20007    if (document.readyState === 'loading') {
20008        document.addEventListener('DOMContentLoaded', init);
20009    } else {
20010        init();
20011    }
20012
20013})();
20014
20015</script>
vendor: 2 bytes, line 20015
20015
20016<script data-inlined="guest-cart.js">
20017/**
20018 * Guest Cart Manager - localStorage based cart for guest users
20019 * 
20020 * Manages shopping cart items in browser localStorage for users who are not logged in.
20021 * Provides seamless transition to database when user logs in.
20022 */
20023
20024class GuestCart {
20025    constructor() {
20026        this.storageKey = 'plazait_guest_cart';
20027        this.apiBase = '/api/cart';
20028        
20029        // Initialize cart structure
20030        this.cart = this.loadFromStorage();
20031        
20032        // Bind methods
20033        this.add = this.add.bind(this);
20034        this.remove = this.remove.bind(this);
20035        this.update = this.update.bind(this);
20036        this.clear = this.clear.bind(this);
20037        this.getItems = this.getItems.bind(this);
20038        this.mergeToDatabase = this.mergeToDatabase.bind(this);
20039    }
20040    
20041    /**
20042     * Load cart from localStorage
20043     */
20044    loadFromStorage() {
20045        try {
20046            const stored = localStorage.getItem(this.storageKey);
20047            if (stored) {
20048                const parsed = JSON.parse(stored);
20049                if (parsed && typeof parsed === 'object' && parsed.items) {
20050                    return parsed;
20051                }
20052            }
20053        } catch (error) {
20054            // Silent error handling
20055        }
20056        
20057        return {
20058            items: {},
20059            updated_at: Date.now(),
20060            version: '1.0'
20061        };
20062    }
20063    
20064    /**
20065     * Save cart to localStorage
20066     */
20067    saveToStorage() {
20068        try {
20069            this.cart.updated_at = Date.now();
20070            localStorage.setItem(this.storageKey, JSON.stringify(this.cart));
20071            
20072            // Dispatch custom event for cart updates
20073            window.dispatchEvent(new CustomEvent('guestCartUpdated', {
20074                detail: {
20075                    itemsCount: this.getItemsCount(),
20076                    linesCount: this.getLinesCount(),
20077                    items: this.cart.items
20078                }
20079            }));
20080            
20081            return true;
20082        } catch (error) {
20083            return false;
20084        }
20085    }
20086    
20087    /**
20088     * Generate cart item key
20089     */
20090    generateKey(productId, variantId = 0) {
20091        return `p${productId}v${variantId}`;
20092    }
20093    
20094    /**
20095     * Add item to guest cart
20096     */
20097    add(productId, qty = 1, variantId = 0, meta = {}) {
20098        const key = this.generateKey(productId, variantId);
20099        
20100        // Validate inputs
20101        if (!productId || productId <= 0 || !qty || qty <= 0) {
20102            throw new Error('Invalid product ID or quantity');
20103        }
20104        
20105        qty = Math.max(1, Math.min(999, parseInt(qty)));
20106        
20107        // Initialize item if not exists
20108        if (!this.cart.items[key]) {
20109            this.cart.items[key] = {
20110                pid: parseInt(productId),
20111                vid: parseInt(variantId) || 0,
20112                qty: 0,
20113                name: meta.name || '',
20114                sku: meta.sku || '',
20115                price: parseInt(meta.price) || 0,
20116                image_url: meta.image_url || '',
20117                product_url: meta.product_url || '/product/' + parseInt(productId),
20118                added_at: Date.now()
20119            };
20120        }
20121        
20122        // Update quantity
20123        this.cart.items[key].qty = Math.max(1, Math.min(999, this.cart.items[key].qty + qty));
20124        
20125        // Update metadata if provided
20126        if (meta.name) this.cart.items[key].name = meta.name;
20127        if (meta.sku) this.cart.items[key].sku = meta.sku;
20128        if (meta.price) this.cart.items[key].price = parseInt(meta.price);
20129        if (meta.image_url) this.cart.items[key].image_url = meta.image_url;
20130        if (meta.product_url) this.cart.items[key].product_url = meta.product_url;
20131        
20132        this.saveToStorage();
20133        
20134        return {
20135            key,
20136            item: this.cart.items[key],
20137            itemsCount: this.getItemsCount(),
20138            linesCount: this.getLinesCount()
20139        };
20140    }
20141    
20142    /**
20143     * Remove item from guest cart
20144     */
20145    remove(productId, variantId = 0) {
20146        const key = this.generateKey(productId, variantId);
20147        
20148        if (this.cart.items[key]) {
20149            delete this.cart.items[key];
20150            this.saveToStorage();
20151            
20152            return true;
20153        }
20154        
20155        return false;
20156    }
20157    
20158    /**
20159     * Update item quantity
20160     */
20161    update(productId, qty, variantId = 0) {
20162        const key = this.generateKey(productId, variantId);
20163        
20164        if (!this.cart.items[key]) {
20165            return false;
20166        }
20167        
20168        qty = parseInt(qty);
20169        if (qty <= 0) {
20170            return this.remove(productId, variantId);
20171        }
20172        
20173        this.cart.items[key].qty = Math.max(1, Math.min(999, qty));
20174        this.saveToStorage();
20175        
20176        return true;
20177    }
20178    
20179    /**
20180     * Clear entire cart
20181     */
20182    clear() {
20183        this.cart = {
20184            items: {},
20185            updated_at: Date.now(),
20186            version: '1.0'
20187        };
20188        
20189        this.saveToStorage();
20190        
20191        return true;
20192    }
20193    
20194    /**
20195     * Get all cart items
20196     */
20197    getItems() {
20198        return this.cart.items;
20199    }
20200    
20201    /**
20202     * Get cart items as array
20203     */
20204    getItemsArray() {
20205        return Object.values(this.cart.items);
20206    }
20207    
20208    /**
20209     * Get total items count (sum of quantities)
20210     */
20211    getItemsCount() {
20212        return Object.values(this.cart.items).reduce((total, item) => total + (item.qty || 0), 0);
20213    }
20214    
20215    /**
20216     * Get lines count (number of different items)
20217     */
20218    getLinesCount() {
20219        return Object.keys(this.cart.items).length;
20220    }
20221    
20222    /**
20223     * Get cart summary
20224     */
20225    getSummary() {
20226        const itemsCount = this.getItemsCount();
20227        const linesCount = this.getLinesCount();
20228        const totalValue = Object.values(this.cart.items).reduce(
20229            (total, item) => total + ((item.qty || 0) * (item.price || 0)), 0
20230        );
20231        
20232        return {
20233            itemsCount,
20234            linesCount,
20235            totalValue,
20236            updatedAt: this.cart.updated_at
20237        };
20238    }
20239    
20240    /**
20241     * Check if cart has items
20242     */
20243    isEmpty() {
20244        return this.getLinesCount() === 0;
20245    }
20246    
20247    /**
20248     * Merge guest cart to database after user login
20249     */
20250    async mergeToDatabase() {
20251        const items = this.cart.items;
20252        
20253        if (Object.keys(items).length === 0) {
20254            return { ok: true, merged_count: 0, message: 'No items to merge' };
20255        }
20256        
20257        try {
20258            // Use new endpoint that handles localStorage format
20259            const response = await fetch(`${this.apiBase}/merge-localStorage.php`, {
20260                method: 'POST',
20261                headers: {
20262                    'Content-Type': 'application/json',
20263                },
20264                credentials: 'same-origin',
20265                body: JSON.stringify({
20266                    items: items  // Send localStorage format directly
20267                })
20268            });
20269            
20270            const result = await response.json();
20271            
20272            if (result.ok) {
20273                // Clear localStorage cart after successful merge
20274                this.clear();
20275                
20276                // Update cart counter
20277                if (window.updateCartCounter) {
20278                    try {
20279                        await window.updateCartCounter();
20280                    } catch (e) {
20281                        // Silent error handling
20282                    }
20283                }
20284                
20285                // Dispatch merge completion event
20286                window.dispatchEvent(new CustomEvent('guestCartMerged', {
20287                    detail: result
20288                }));
20289                
20290                return result;
20291            } else {
20292                throw new Error(result.error || 'Failed to merge cart');
20293            }
20294            
20295        } catch (error) {
20296            throw error;
20297        }
20298    }
20299    
20300    /**
20301     * Export cart data (for debugging or backup)
20302     */
20303    export() {
20304        return {
20305            ...this.cart,
20306            summary: this.getSummary()
20307        };
20308    }
20309    
20310    /**
20311     * Import cart data (for restore or testing)
20312     */
20313    import(cartData) {
20314        if (cartData && typeof cartData === 'object' && cartData.items) {
20315            this.cart = {
20316                items: cartData.items,
20317                updated_at: cartData.updated_at || Date.now(),
20318                version: cartData.version || '1.0'
20319            };
20320            
20321            this.saveToStorage();
20322            return true;
20323        }
20324        
20325        return false;
20326    }
20327}
20328
20329// Create global instance
20330window.guestCart = new GuestCart();
20331
20332// Auto-merge on page load if user is logged in
20333document.addEventListener('DOMContentLoaded', async function() {
20334    // Multiple ways to check if user is logged in
20335    const isLoggedIn = document.querySelector('meta[name="user-logged-in"]')?.content === 'true' ||
20336                      document.body.classList.contains('logged-in') ||
20337                      window.userLoggedIn === true ||
20338                      document.body.dataset.userLoggedIn === 'true';
20339    
20340    if (isLoggedIn && !window.guestCart.isEmpty()) {
20341        // Small delay to ensure page is fully loaded
20342        setTimeout(async () => {
20343            try {
20344                const result = await window.guestCart.mergeToDatabase();
20345            } catch (error) {
20346                // Silent error handling
20347            }
20348        }, 500);
20349    }
20350});
20351
20352// Also listen for login events (if login happens via AJAX)
20353window.addEventListener('userLoggedIn', async function() {
20354    if (!window.guestCart.isEmpty()) {
20355        try {
20356            await window.guestCart.mergeToDatabase();
20357        } catch (error) {
20358            // Silent error handling
20359        }
20360    }
20361});
20362</script>
vendor: 2 bytes, line 20362
20362
20363<script data-inlined="cart.js">
20364(function(){
20365  function $(s,ctx=document){ return ctx.querySelector(s); }
20366  function esc(s){ return String(s||'').replace(/[&<>"']/g, m=>({ '&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#039;' }[m])); }
20367  
20368  // CSRF token helper
20369  function getCsrfToken() {
20370    const metaTag = document.querySelector('meta[name="csrf-token"]');
20371    return metaTag ? metaTag.getAttribute('content') : '';
20372  }
20373  
20374  function guessPdMeta(){
20375    const name = (window.PD_NAME !== undefined) ? String(window.PD_NAME) : ($('#pd-title')?.textContent || '');
20376    const sku  = (function(){ const el=$('#pd-sku'); return el ? el.textContent.trim() : (window.PD_SKU||''); })();
20377    // SECURITY FIX: Remove price from client-side metadata (will be validated server-side)
20378    const imgEl = $('#pd-main-img');
20379    const image_url = imgEl ? (imgEl.getAttribute('src') || '') : '';
20380    return { name, sku, image_url }; // price removed for security
20381  }
20382
20383  async function addToCart(productId, qty=1, variantId=0, metaOpt){
20384    const meta = Object.assign(guessPdMeta(), metaOpt||{});
20385    const payload = {
20386      product_id: parseInt(productId||0,10) || 0,
20387      qty: parseInt(qty||1,10) || 1,
20388      variant_id: parseInt(variantId||0,10) || 0,
20389      meta
20390    };
20391    
20392    // Check if user is logged in
20393    const isLoggedIn = document.querySelector('meta[name="user-logged-in"]')?.content === 'true' ||
20394                      document.body.classList.contains('logged-in') ||
20395                      window.userLoggedIn === true ||
20396                      document.body.dataset.userLoggedIn === 'true';
20397    
20398    // Skip localStorage untuk logged user - mereka pakai database
20399    if (!isLoggedIn && window.guestCart) {
20400      try {
20401        window.guestCart.add(payload.product_id, payload.qty, payload.variant_id, meta);
20402      } catch (e) {
20403        console.warn('Failed to add to localStorage cart:', e);
20404      }
20405    }
20406    
20407    const res = await fetch('/api/cart/add.php', {
20408      method: 'POST',
20409      headers: { 
20410        'Content-Type':'application/json',
20411        'X-CSRF-Token': getCsrfToken()
20412      },
20413      credentials: 'same-origin',
20414      body: JSON.stringify({
20415        ...payload,
20416        csrf_token: getCsrfToken()
20417      }),
20418    });
20419    const data = await res.json().catch(()=>({ ok:false, error:'Gagal menambahkan ke keranjang' }));
20420    if (!res.ok || !data.ok) {
20421      const msg = data && data.error ? data.error : 'Gagal menambahkan ke keranjang';
20422      throw new Error(msg);
20423    }
20424
20425    // Update badge di navbar dengan data dari response
20426    try {
20427      const el = document.querySelector('[data-role="cart-badge"]') || document.getElementById('cartCount');
20428      if (el && data.cart && typeof data.cart.items_count === 'number') {
20429        el.textContent = String(data.cart.items_count);
20430        el.classList.toggle('is-empty', data.cart.items_count <= 0);
20431      }
20432    } catch(_){}
20433
20434    // Siarkan event global (dipakai cart-badge.js dan halaman lain)
20435    try {
20436      document.dispatchEvent(new CustomEvent('cart:updated', { detail: data.cart || {} }));
20437    } catch(_){}
20438
20439    // Update CartBadge dengan data dari response (lebih reliable)
20440    try { 
20441      if (window.CartBadge && window.CartBadge.set) {
20442        window.CartBadge.set(data.cart.items_count||0);
20443      }
20444    } catch(_){}
20445
20446    // Tambahan: refresh cart counter setelah delay kecil untuk memastikan data tersinkronisasi
20447    setTimeout(() => {
20448      if (window.updateCartCounter) {
20449        window.updateCartCounter();
20450      }
20451    }, 100);
20452
20453    return data;
20454  }
20455
20456  // Function to update cart counter from server
20457  async function updateCartCounter(){
20458    try {
20459      const res = await fetch('/api/cart/get.php', { credentials:'same-origin' });
20460      const data = await res.json().catch(()=>({ok:false}));
20461      if (data.ok && typeof data.items_count === 'number') {
20462        const el = document.querySelector('[data-role="cart-badge"]') || document.getElementById('cartCount');
20463        if (el) {
20464          el.textContent = String(data.items_count);
20465          el.classList.toggle('is-empty', data.items_count <= 0);
20466        }
20467        // Dispatch event
20468        try {
20469          document.dispatchEvent(new CustomEvent('cart:updated', { detail: { items_count: data.items_count } }));
20470        } catch(_){}
20471      }
20472    } catch (err) {
20473      console.log('Could not update cart counter:', err);
20474    }
20475  }
20476
20477  // Function to manually merge guest cart (if needed)
20478  async function mergeGuestCart(){
20479    try {
20480      const res = await fetch('/api/cart/merge-guest.php', {
20481        method: 'POST',
20482        headers: { 
20483          'Content-Type': 'application/json',
20484          'X-CSRF-Token': getCsrfToken()
20485        },
20486        credentials: 'same-origin',
20487        body: JSON.stringify({ csrf_token: getCsrfToken() })
20488      });
20489      const data = await res.json().catch(()=>({ok:false}));
20490      
20491      if (data.ok && data.merged_items > 0) {
20492        console.log(`Guest cart merged: ${data.merged_items} items`);
20493        // Update cart counter after merge
20494        await updateCartCounter();
20495        return data;
20496      }
20497      return data;
20498    } catch (err) {
20499      console.log('Could not merge guest cart:', err);
20500      return { ok: false, error: err.message };
20501    }
20502  }
20503
20504  window.addToCart = addToCart;
20505  window.updateCartCounter = updateCartCounter;
20506  window.mergeGuestCart = mergeGuestCart;
20507
20508  // Optional: auto-bind untuk tombol apapun yang punya data-addtocart
20509  document.addEventListener('click', async (e)=>{
20510    const btn = e.target.closest('[data-addtocart]');
20511    if (!btn) return;
20512    e.preventDefault();
20513    if (btn.disabled) return;
20514
20515    const pid = parseInt(btn.getAttribute('data-pid')||'0',10);
20516    const vid = parseInt(btn.getAttribute('data-vid')||'0',10);
20517    const qty = parseInt(btn.getAttribute('data-qty')||'1',10) || 1;
20518
20519    try {
20520      const data = await addToCart(pid, qty, vid);
20521      if (window.showToast) {
20522        const meta = guessPdMeta();
20523        window.showToast({
20524          type:'success',
20525          title:'Berhasil ditambahkan',
20526          message:`<strong>${esc(meta.name)}</strong>${meta.sku?` · <em>SKU: ${esc(meta.sku)}</em>`:''}<br>Qty: ${qty}`,
20527          duration: 3800,
20528          actions: [
20529            { label:'Lihat Keranjang', onClick: ()=> { window.location.href='/keranjang'; } },
20530            { label:'Lanjut Belanja', variant:'alt', onClick: ()=>{} }
20531          ]
20532        });
20533      }
20534    } catch (err) {
20535      if (window.showToast) {
20536        window.showToast({ type:'warn', title:'Gagal', message: String(err?.message||'Gagal menambahkan'), duration: 4200 });
20537      } else {
20538        console.error(err);
20539      }
20540    }
20541  });
20542})();
20543</script>
vendor: 2 bytes, line 20543
20543
20544<script data-inlined="mega-menu-tiles.js">
20545// Tile Mega Menu — Enhanced 2025 (Stagger animations, product counts, loading states)
20546// Includes safe-area hover handling (no backdrop flicker)
20547
20548(function(){
20549  const trigger   = document.querySelector('[data-mm2="trigger"]');
20550  const panel     = document.querySelector('[data-mm2="panel"]');
20551  const topView   = document.querySelector('[data-mm2="top"]');
20552  const detailView= document.querySelector('[data-mm2="detail"]');
20553  const backdrop  = document.querySelector('[data-mm2="backdrop"]');
20554  if (!trigger || !panel || !topView || !detailView) return;
20555
20556  const apiUrl = '/api/categories_tree.php?top=16&child=18&grand=14';
20557  const isDesktop = () => window.matchMedia('(min-width: 961px)').matches;
20558
20559  let data = [];
20560  let hoverTimer, closeTimer;
20561  let isLoading = false;
20562
20563  const esc = s => (s+'').replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
20564  
20565  // Mobile close button HTML
20566  const mobileCloseBtn = () => `
20567    <button type="button" class="mm2-mobile-close" data-mm2="close" aria-label="Tutup menu">
20568      <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
20569        <line x1="18" y1="6" x2="6" y2="18"></line>
20570        <line x1="6" y1="6" x2="18" y2="18"></line>
20571      </svg>
20572    </button>
20573  `;
20574  
20575  // Category-specific gradient colors (16 unique combinations)
20576  const categoryGradients = [
20577    { from: '#e0e7ff', to: '#fff', border: '#c7d2fe', color: '#4f46e5' },  // Indigo
20578    { from: '#dbeafe', to: '#fff', border: '#bfdbfe', color: '#1e40af' },  // Blue
20579    { from: '#d1fae5', to: '#fff', border: '#a7f3d0', color: '#059669' },  // Green
20580    { from: '#fef3c7', to: '#fff', border: '#fde68a', color: '#d97706' },  // Amber
20581    { from: '#fce7f3', to: '#fff', border: '#fbcfe8', color: '#db2777' },  // Pink
20582    { from: '#e9d5ff', to: '#fff', border: '#d8b4fe', color: '#9333ea' },  // Purple
20583    { from: '#ffedd5', to: '#fff', border: '#fed7aa', color: '#C77DFF' },  // Orange
20584    { from: '#ccfbf1', to: '#fff', border: '#99f6e4', color: '#0d9488' },  // Teal
20585    { from: '#fef9c3', to: '#fff', border: '#fef08a', color: '#ca8a04' },  // Yellow
20586    { from: '#ffe4e6', to: '#fff', border: '#fecdd3', color: '#C77DFF' },  // Rose
20587    { from: '#e0f2fe', to: '#fff', border: '#bae6fd', color: '#0284c7' },  // Sky
20588    { from: '#f3e8ff', to: '#fff', border: '#e9d5ff', color: '#a855f7' },  // Violet
20589    { from: '#dcfce7', to: '#fff', border: '#bbf7d0', color: '#16a34a' },  // Emerald
20590    { from: '#fef2f2', to: '#fff', border: '#fecaca', color: '#C77DFF' },  // Red
20591    { from: '#eff6ff', to: '#fff', border: '#dbeafe', color: '#2563eb' },  // Blue-600
20592    { from: '#f5f3ff', to: '#fff', border: '#ede9fe', color: '#7c3aed' },  // Violet-600
20593  ];
20594  
20595  const icon = () => `<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 7h5l2 3h11v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"></path><path d="M3 7V5a2 2 0 0 1 2-2h4l2 2h6a2 2 0 0 1 2 2v3"></path></svg>`;
20596
20597  // Recent (optional future use)
20598  const REC_KEY='mm2_recent';
20599  const saveRecent=(path,label)=>{ try{
20600    let list=JSON.parse(localStorage.getItem(REC_KEY)||'[]').filter(x=>x&&x.path!==path);
20601    list.unshift({path,label,t:Date.now()}); localStorage.setItem(REC_KEY, JSON.stringify(list.slice(0,8)));
20602  }catch{} };
20603
20604  function isToSafeArea(e){
20605    const t = e && e.relatedTarget ? e.relatedTarget : null;
20606    if (!t) return false;
20607    return (trigger.contains(t) || panel.contains(t) || (backdrop && backdrop.contains(t)));
20608  }
20609
20610  function open(){ 
20611    document.body.classList.add('mm2-open'); 
20612    showTop(); 
20613    // Add entrance animation class
20614    setTimeout(() => panel.classList.add('mm2-animated'), 10);
20615  }
20616  function close(){ 
20617    document.body.classList.remove('mm2-open');
20618    panel.classList.remove('mm2-animated');
20619  }
20620  function showTop(){ 
20621    topView.classList.add('is-active'); 
20622    detailView.classList.remove('is-active'); 
20623  }
20624  
20625  // Loading skeleton
20626  function showLoading() {
20627    const skeletons = Array.from({length: 12}, (_, i) => `
20628      <div class="mm2-card mm2-skeleton" style="animation-delay: ${i * 0.02}s">
20629        <span class="mm2-ico skeleton-box"></span>
20630        <span style="flex: 1;">
20631          <div class="skeleton-line" style="width: 60%; height: 16px; margin-bottom: 6px;"></div>
20632          <div class="skeleton-line" style="width: 40%; height: 12px;"></div>
20633        </span>
20634      </div>
20635    `).join('');
20636    topView.innerHTML = `<div class="mm2-top"><div class="mm2-grid">${skeletons}</div></div>`;
20637  }
20638  
20639  // Count total products in a category tree
20640  function countProducts(node) {
20641    let count = node.product_count || 0;
20642    if (Array.isArray(node.children)) {
20643      node.children.forEach(child => {
20644        count += countProducts(child);
20645      });
20646    }
20647    return count;
20648  }
20649  
20650  // Cache for fetched thumbnails to avoid duplicate requests
20651  const thumbnailCache = new Map();
20652  
20653  // Fetch product thumbnails for a category
20654  function fetchCategoryThumbnails(categoryPath) {
20655    // Check cache first
20656    if (thumbnailCache.has(categoryPath)) {
20657      injectThumbnails(categoryPath, thumbnailCache.get(categoryPath));
20658      return;
20659    }
20660    
20661    const url = `/api/category_products_preview.php?path=${encodeURIComponent(categoryPath)}&limit=2`;
20662    
20663    fetch(url)
20664      .then(r => {
20665        if (!r.ok) throw new Error('Network error');
20666        return r.json();
20667      })
20668      .then(data => {
20669        if (data.success && data.products && data.products.length > 0) {
20670          thumbnailCache.set(categoryPath, data.products);
20671          injectThumbnails(categoryPath, data.products);
20672        } else {
20673          // No products, remove skeleton
20674          removeThumbSkeletons(categoryPath);
20675        }
20676      })
20677      .catch(err => {
20678        console.warn('Failed to load thumbnails for', categoryPath, err);
20679        removeThumbSkeletons(categoryPath);
20680      });
20681  }
20682  
20683  // Inject thumbnails into the DOM
20684  function injectThumbnails(categoryPath, products) {
20685    const links = detailView.querySelectorAll(`[data-cat-path="${categoryPath}"]`);
20686    links.forEach(link => {
20687      const thumbsContainer = link.querySelector('.mm2-thumbs');
20688      if (!thumbsContainer) return;
20689      
20690      const thumbsHtml = products.slice(0, 2).map(p => 
20691        `<img src="${esc(p.img)}" alt="${esc(p.name)}" class="mm2-thumb" title="${esc(p.name)}" loading="lazy">`
20692      ).join('');
20693      
20694      thumbsContainer.innerHTML = thumbsHtml;
20695      thumbsContainer.removeAttribute('data-loading');
20696    });
20697  }
20698  
20699  // Remove skeleton loaders when no products
20700  function removeThumbSkeletons(categoryPath) {
20701    const links = detailView.querySelectorAll(`[data-cat-path="${categoryPath}"]`);
20702    links.forEach(link => {
20703      const thumbsContainer = link.querySelector('.mm2-thumbs');
20704      if (thumbsContainer) {
20705        thumbsContainer.remove();
20706      }
20707    });
20708  }
20709
20710  function showDetail(node){
20711    const title = node.label.split('/')[0];
20712    const children = Array.isArray(node.children) ? node.children : [];
20713    const hasChildren = children.length > 0;
20714
20715    const subnav = hasChildren ? `
20716      <nav class="mm2-subnav" role="tablist">
20717        ${children.map((c2,i)=>{
20718          const t = c2.label.split('/').slice(-1)[0];
20719          return `<button class="mm2-subitem${i===0?' active':''}" role="tab" data-idx="${i}" aria-selected="${i===0?'true':'false'}">${esc(t)}</button>`;
20720        }).join('')}
20721      </nav>` : '';
20722
20723    const subcontent = `<div class="mm2-subcontent" data-mm2="subcontent"></div>`;
20724
20725    detailView.innerHTML = `
20726      <div class="mm2-detail">
20727        <div class="mm2-detail-header">
20728          <button class="mm2-back" type="button" data-mm2="back" aria-label="Kembali">
20729            <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="15 18 9 12 15 6"></polyline></svg>
20730          </button>
20731          <div class="mm2-detail-title">${esc(title)}</div>
20732        </div>
20733
20734        ${hasChildren ? `
20735          <div class="mm2-detail-layout">
20736            ${subnav}
20737            ${subcontent}
20738          </div>` : `
20739          <div class="mm2-links">
20740            <a class="mm2-link mm2-seeall" href="/product/kategori/?kategori_path=${encodeURIComponent(node.path)}" data-mm2="nav" data-path="${esc(node.path)}" data-label="${esc(node.label)}">
20741              <strong>Lihat semua ${esc(title)}</strong>
20742            </a>
20743          </div>
20744        `}
20745      </div>
20746    `;
20747
20748    topView.classList.remove('is-active');
20749    detailView.classList.add('is-active');
20750
20751    if (hasChildren) {
20752      const subEl  = detailView.querySelector('.mm2-subnav');
20753      const contEl = detailView.querySelector('[data-mm2="subcontent"]');
20754      let activeIdx = 0;
20755
20756      const renderSubgrid = (idx) => {
20757        const c2 = children[idx]; if (!c2) { contEl.innerHTML=''; return; }
20758        const title2 = c2.label.split('/').slice(-1)[0];
20759        const l3 = Array.isArray(c2.children) ? c2.children : [];
20760        const l3Html = l3.map(c3 => `
20761          <a class="mm2-link" href="/product/kategori/?kategori_path=${encodeURIComponent(c3.path)}" data-mm2="nav" data-path="${esc(c3.path)}" data-label="${esc(c3.label)}" data-cat-path="${esc(c3.path)}">
20762            <span class="mm2-link-text">${esc(c3.label.split('/').slice(-1)[0])}</span>
20763            <span class="mm2-thumbs" data-loading="true">
20764              <span class="mm2-thumb-skeleton"></span>
20765              <span class="mm2-thumb-skeleton"></span>
20766            </span>
20767          </a>`).join('');
20768
20769        contEl.innerHTML = `
20770          <div class="mm2-links">
20771            <a class="mm2-link mm2-seeall" href="/product/kategori/?kategori_path=${encodeURIComponent(c2.path)}" data-mm2="nav" data-path="${esc(c2.path)}" data-label="${esc(c2.label)}">
20772              <strong>Lihat semua ${esc(title2)}</strong>
20773            </a>
20774            ${l3Html}
20775          </div>
20776        `;
20777        
20778        // Fetch product thumbnails for each level-3 category (desktop only)
20779        if (isDesktop()) {
20780          setTimeout(() => {
20781            l3.forEach(c3 => {
20782              fetchCategoryThumbnails(c3.path);
20783            });
20784          }, 100);
20785        }
20786      };
20787
20788      renderSubgrid(activeIdx);
20789
20790      // Desktop: hover ganti konten; Mobile & Desktop: click pilih
20791      subEl.addEventListener('mousemove', (e)=>{
20792        if (!isDesktop()) return;
20793        const it = e.target.closest('.mm2-subitem'); if (!it) return;
20794        const idx = +it.dataset.idx; if (!Number.isInteger(idx) || idx===activeIdx) return;
20795        subEl.querySelectorAll('.mm2-subitem').forEach(el=>el.classList.remove('active'));
20796        it.classList.add('active');
20797        subEl.querySelectorAll('.mm2-subitem').forEach(el=>el.setAttribute('aria-selected', el===it ? 'true':'false'));
20798        activeIdx = idx;
20799        renderSubgrid(activeIdx);
20800      });
20801
20802      subEl.addEventListener('click', (e)=>{
20803        const it = e.target.closest('.mm2-subitem'); if (!it) return;
20804        const idx = +it.dataset.idx; if (!Number.isInteger(idx)) return;
20805        subEl.querySelectorAll('.mm2-subitem').forEach(el=>el.classList.remove('active'));
20806        it.classList.add('active');
20807        subEl.querySelectorAll('.mm2-subitem').forEach(el=>el.setAttribute('aria-selected', el===it ? 'true':'false'));
20808        activeIdx = idx;
20809        renderSubgrid(activeIdx);
20810      });
20811
20812      // Delegate link clicks to add recent
20813      detailView.addEventListener('click', (e)=>{
20814        const nav = e.target.closest('[data-mm2="nav"]');
20815        if (nav) { saveRecent(nav.dataset.path, nav.dataset.label); }
20816      });
20817    }
20818  }
20819
20820  function buildTop(){
20821    const html = data.map((n, idx) => {
20822      const title = n.label.split('/')[0];
20823      const childCount = (n.children||[]).length;
20824      const productCount = countProducts(n);
20825      const gradient = categoryGradients[idx % categoryGradients.length];
20826      
20827      // Dynamic subtitle based on content - shorter for mobile
20828      let sub = '';
20829      if (productCount > 0) {
20830        sub = `${productCount} produk`;
20831        if (childCount > 0) sub += ` · ${childCount} kat`;
20832      } else if (childCount > 0) {
20833        sub = `${childCount} kategori`;
20834      } else {
20835        sub = 'Lihat semua';
20836      }
20837      
20838      const iconStyle = `background: linear-gradient(135deg, ${gradient.from}, ${gradient.to}); border-color: ${gradient.border}; color: ${gradient.color};`;
20839      
20840      return `<a href="/product/kategori/?kategori_path=${encodeURIComponent(n.path)}" class="mm2-card" data-mm2="card" data-path="${esc(n.path)}" data-label="${esc(n.label)}">
20841        <span class="mm2-ico" style="${iconStyle}">${icon()}</span>
20842        <span style="flex: 1;">
20843          <div class="mm2-title">${esc(title)}</div>
20844          <div class="mm2-sub">${esc(sub)}</div>
20845        </span>
20846      </a>`;
20847    }).join('');
20848    const closeBtnHtml = !isDesktop() ? mobileCloseBtn() : '';
20849    topView.innerHTML = `<div class="mm2-top">${closeBtnHtml}<div class="mm2-grid">${html}</div></div>`;
20850  }
20851
20852  // Open/close with safe-area
20853  trigger.addEventListener('click', (e)=>{ e.preventDefault(); document.body.classList.contains('mm2-open') ? close() : open(); });
20854  trigger.addEventListener('pointerenter', ()=>{ if (isDesktop()) { clearTimeout(closeTimer); hoverTimer=setTimeout(open, 80); }});
20855  trigger.addEventListener('pointerleave', (e)=>{ if (isDesktop() && !isToSafeArea(e)) { clearTimeout(hoverTimer); closeTimer=setTimeout(close, 200); }});
20856  panel.addEventListener('pointerenter', ()=>{ if (isDesktop()) clearTimeout(closeTimer); });
20857  panel.addEventListener('pointerleave', (e)=>{ if (isDesktop() && !isToSafeArea(e)) closeTimer=setTimeout(close, 200); });
20858  backdrop?.addEventListener('pointerenter', ()=>{ clearTimeout(closeTimer); });
20859  backdrop?.addEventListener('click', close);
20860  document.addEventListener('keydown', (e)=>{ if (e.key==='Escape') close(); });
20861
20862  // Card click → open detail (unless cmd/ctrl to open link)
20863  panel.addEventListener('click', (e)=>{
20864    const closeBtn = e.target.closest('[data-mm2="close"]'); if (closeBtn) { e.preventDefault(); close(); return; }
20865    const back = e.target.closest('[data-mm2="back"]'); if (back) { e.preventDefault(); showTop(); return; }
20866    const card = e.target.closest('[data-mm2="card"]');
20867    if (card && !e.metaKey && !e.ctrlKey) {
20868      e.preventDefault();
20869      const n = data.find(d => d.path === card.dataset.path);
20870      if (n) showDetail(n);
20871    }
20872    const nav = e.target.closest('[data-mm2="nav"]');
20873    if (nav) { saveRecent(nav.dataset.path, nav.dataset.label); }
20874  });
20875
20876  // Swipe-down gesture for mobile (bottom sheet close)
20877  if (!isDesktop()) {
20878    let startY = 0, currentY = 0, isDragging = false, startTime = 0;
20879    const SWIPE_THRESHOLD = 80;
20880    const VELOCITY_THRESHOLD = 0.3;
20881
20882    panel.addEventListener('touchstart', (e) => {
20883      if (!document.body.classList.contains('mm2-open')) return;
20884      const touch = e.touches[0];
20885      const scrollableContent = e.target.closest('.mm2-top, .mm2-detail');
20886      
20887      // Prevent drag if content is scrolled
20888      if (scrollableContent && scrollableContent.scrollTop > 5) return;
20889      
20890      // Only start drag from top area or handle
20891      const rect = panel.getBoundingClientRect();
20892      if (touch.clientY - rect.top > 60) return;
20893      
20894      startY = touch.clientY;
20895      currentY = startY;
20896      startTime = Date.now();
20897      isDragging = true;
20898    }, { passive: true });
20899
20900    panel.addEventListener('touchmove', (e) => {
20901      if (!isDragging) return;
20902      const touch = e.touches[0];
20903      currentY = touch.clientY;
20904      const deltaY = currentY - startY;
20905      
20906      // Only allow downward swipe
20907      if (deltaY > 0) {
20908        const opacity = Math.max(0.4, 1 - (deltaY / 300));
20909        panel.style.transform = `translateX(0) translateY(${deltaY}px)`;
20910        panel.style.opacity = opacity;
20911      }
20912    }, { passive: true });
20913
20914    const endDrag = () => {
20915      if (!isDragging) return;
20916      const deltaY = currentY - startY;
20917      const deltaTime = Date.now() - startTime;
20918      const velocity = deltaY / deltaTime;
20919      
20920      // Close if swiped down enough or fast swipe
20921      if (deltaY > SWIPE_THRESHOLD || velocity > VELOCITY_THRESHOLD) {
20922        close();
20923      }
20924      
20925      // Reset position
20926      panel.style.transform = '';
20927      panel.style.opacity = '';
20928      isDragging = false;
20929    };
20930
20931    panel.addEventListener('touchend', endDrag, { passive: true });
20932    panel.addEventListener('touchcancel', endDrag, { passive: true });
20933  }
20934
20935  // Fetch data with loading state
20936  if (!isLoading) {
20937    isLoading = true;
20938    showLoading();
20939    
20940    fetch(apiUrl, { headers: { 'Accept': 'application/json' }})
20941      .then(r => {
20942        if (!r.ok) throw new Error('Network response was not ok');
20943        return r.json();
20944      })
20945      .then(j => { 
20946        data = Array.isArray(j.data) ? j.data : []; 
20947        if (!data.length) {
20948          topView.innerHTML = `<div class="mm2-top"><div style="text-align:center;padding:40px;color:var(--mm2-fg-muted);">
20949            <p>Tidak ada kategori tersedia</p>
20950          </div></div>`;
20951          return;
20952        }
20953        buildTop();
20954        isLoading = false;
20955      })
20956      .catch(err => {
20957        console.error('Failed to load categories:', err);
20958        topView.innerHTML = `<div class="mm2-top"><div style="text-align:center;padding:40px;color:var(--mm2-fg-muted);">
20959          <p>Gagal memuat kategori. Silakan coba lagi.</p>
20960        </div></div>`;
20961        isLoading = false;
20962      });
20963  }
20964})();
20965
20966// Add skeleton animation styles
20967const style = document.createElement('style');
20968style.textContent = `
20969.mm2-skeleton {
20970  pointer-events: none;
20971  animation: pulse 1.5s cubic-bezier(0.4, 0, 0.6, 1) infinite;
20972}
20973.skeleton-box, .skeleton-line {
20974  background: linear-gradient(90deg, #f1f5f9 25%, #e2e8f0 50%, #f1f5f9 75%);
20975  background-size: 200% 100%;
20976  animation: shimmer 1.5s infinite;
20977  border-radius: 8px;
20978}
20979@keyframes pulse {
20980  0%, 100% { opacity: 1; }
20981  50% { opacity: 0.6; }
20982}
20983@keyframes shimmer {
20984  0% { background-position: 200% 0; }
20985  100% { background-position: -200% 0; }
20986}
20987`;
20988document.head.appendChild(style);
20989</script>
20989
20990    
20990<script data-inlined="benchmark.js">
20991/**
20992 * Benchmark Data Loader
20993 * Handles AJAX fetch and display of benchmark data
20994 */
20995
20996(function() {
20997    'use strict';
20998    
20999    // Wait for DOM ready
21000    if (document.readyState === 'loading') {
21001        document.addEventListener('DOMContentLoaded', initBenchmark);
21002    } else {
21003        initBenchmark();
21004    }
21005    
21006    function initBenchmark() {
21007        const section = document.querySelector('.pd-benchmark-section');
21008        if (!section) return;
21009        
21010        const button = document.getElementById('btn-load-benchmark');
21011        const content = document.getElementById('benchmark-content');
21012        const productId = section.dataset.productId;
21013        
21014        if (!button || !content || !productId) return;
21015        
21016        let isLoading = false;
21017        let dataLoaded = false;
21018        
21019        button.addEventListener('click', function() {
21020            if (isLoading || dataLoaded) return;
21021            
21022            loadBenchmarkData(productId, button, content);
21023        });
21024    }
21025    
21026    function loadBenchmarkData(productId, button, container) {
21027        // Update button state
21028        button.disabled = true;
21029        button.classList.add('loading');
21030        const originalText = button.querySelector('.btn-text').textContent;
21031        button.querySelector('.btn-text').textContent = 'Memuat data...';
21032        
21033        // Show loading state
21034        container.style.display = 'block';
21035        container.innerHTML = `
21036            <div class="benchmark-loading">
21037                <div class="benchmark-loading-spinner"></div>
21038                <p>Mengambil data benchmark...</p>
21039            </div>
21040        `;
21041        
21042        // Fetch data
21043        fetch('/api/benchmark/fetch.php?product_id=' + productId)
21044            .then(function(response) {
21045                if (!response.ok) {
21046                    throw new Error('HTTP error ' + response.status);
21047                }
21048                return response.json();
21049            })
21050            .then(function(result) {
21051                if (result.success && result.data) {
21052                    renderBenchmarkData(result.data, container);
21053                    button.style.display = 'none'; // Hide button after successful load
21054                } else {
21055                    throw new Error(result.error || 'Data tidak tersedia');
21056                }
21057            })
21058            .catch(function(error) {
21059                console.error('Benchmark fetch error:', error);
21060                container.innerHTML = `
21061                    <div class="benchmark-error">
21062                        <p><strong>⚠️ Data Benchmark Tidak Tersedia</strong></p>
21063                        <p style="font-size: 14px; margin-top: 8px;">
21064                            ${error.message || 'Terjadi kesalahan saat memuat data'}
21065                        </p>
21066                        <button type="button" onclick="location.reload()" 
21067                                style="margin-top: 16px; padding: 8px 20px; background: #667eea; color: #fff; border: none; border-radius: 6px; cursor: pointer;">
21068                            Coba Lagi
21069                        </button>
21070                    </div>
21071                `;
21072                
21073                // Reset button
21074                button.disabled = false;
21075                button.classList.remove('loading');
21076                button.querySelector('.btn-text').textContent = originalText;
21077            });
21078    }
21079    
21080    function renderBenchmarkData(data, container) {
21081        let html = '<div class="benchmark-data-wrapper">';
21082        
21083        // Chipset info if available
21084        if (data.chipset) {
21085            html += `
21086                <div style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 10px 16px; border-radius: 8px; margin-bottom: 12px;">
21087                    <div style="font-size: 11px; opacity: 0.85; margin-bottom: 2px;">Chipset</div>
21088                    <div style="font-size: 15px; font-weight: 600;">${escapeHtml(data.chipset)}</div>
21089                </div>
21090            `;
21091        }
21092        
21093        // Main benchmark scores
21094        if (data.antutu || data.geekbench_multi || data.overall_score) {
21095            html += '<div class="benchmark-data-grid">';
21096            
21097            if (data.antutu) {
21098                html += `
21099                    <div class="benchmark-card">
21100                        <div class="benchmark-card-label">ANTUTU</div>
21101                        <div class="benchmark-card-value large">${formatNumber(data.antutu)}</div>
21102                        ${getScoreBadge(data.antutu, 'antutu')}
21103                    </div>
21104                `;
21105            }
21106            
21107            if (data.geekbench_multi) {
21108                html += `
21109                    <div class="benchmark-card">
21110                        <div class="benchmark-card-label">GEEKBENCH MULTI</div>
21111                        <div class="benchmark-card-value">${formatNumber(data.geekbench_multi)}</div>
21112                        ${data.geekbench_single ? '<div class="benchmark-card-subtitle">Single: ' + formatNumber(data.geekbench_single) + '</div>' : ''}
21113                    </div>
21114                `;
21115            }
21116            
21117            if (data.gaming_score) {
21118                html += `
21119                    <div class="benchmark-card">
21120                        <div class="benchmark-card-label">GAMING</div>
21121                        <div class="benchmark-card-value">${data.gaming_score}<span style="font-size: 14px; opacity: 0.6;">/100</span></div>
21122                    </div>
21123                `;
21124            }
21125            
21126            if (data.battery_score) {
21127                html += `
21128                    <div class="benchmark-card">
21129                        <div class="benchmark-card-label">BATTERY</div>
21130                        <div class="benchmark-card-value">${data.battery_score}<span style="font-size: 14px; opacity: 0.6;">/100</span></div>
21131                    </div>
21132                `;
21133            }
21134            
21135            if (data.overall_score) {
21136                html += `
21137                    <div class="benchmark-card">
21138                        <div class="benchmark-card-label">OVERALL</div>
21139                        <div class="benchmark-card-value">${data.overall_score}<span style="font-size: 14px; opacity: 0.6;">/100</span></div>
21140                    </div>
21141                `;
21142            }
21143            
21144            html += '</div>';
21145        }
21146        
21147        // AI Performance Description
21148        if (data.notes) {
21149            html += `
21150                <div style="background: #f8f9fa; border-left: 3px solid #667eea; padding: 10px 14px; border-radius: 6px; margin-top: 12px;">
21151                    <div style="font-size: 11px; font-weight: 600; color: #667eea; margin-bottom: 6px;">💡 Analisis Performa</div>
21152                    <div style="font-size: 13px; color: #4a5568; line-height: 1.5;">${escapeHtml(data.notes)}</div>
21153                </div>
21154            `;
21155        }
21156        
21157        // Attribution
21158        html += `
21159            <div class="benchmark-attribution">
21160                <p style="font-size: 11px; margin: 8px 0 0 0; color: #888;">Data benchmark dianalisis menggunakan AI dari spesifikasi produk</p>
21161                ${data.fetched_at ? '<p style="font-size: 10px; margin: 4px 0 0 0; color: #aaa;">Terakhir diperbarui: ' + formatDate(data.fetched_at) + '</p>' : ''}
21162            </div>
21163        `;
21164        
21165        html += '</div>';
21166        
21167        container.innerHTML = html;
21168    }
21169    
21170    function formatNumber(num) {
21171        if (!num) return '-';
21172        return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, '.');
21173    }
21174    
21175    function escapeHtml(text) {
21176        if (!text) return '';
21177        const div = document.createElement('div');
21178        div.textContent = text;
21179        return div.innerHTML;
21180    }
21181    
21182    function formatDate(dateStr) {
21183        try {
21184            const date = new Date(dateStr);
21185            const options = { year: 'numeric', month: 'long', day: 'numeric' };
21186            return date.toLocaleDateString('id-ID', options);
21187        } catch (e) {
21188            return dateStr;
21189        }
21190    }
21191    
21192    function getScoreBadge(score, type) {
21193        let category = '';
21194        let label = '';
21195        
21196        if (type === 'antutu') {
21197            if (score >= 500000) {
21198                category = 'excellent';
21199                label = 'Flagship';
21200            } else if (score >= 350000) {
21201                category = 'good';
21202                label = 'High-End';
21203            } else if (score >= 200000) {
21204                category = 'average';
21205                label = 'Mid-Range';
21206            } else {
21207                category = 'average';
21208                label = 'Entry-Level';
21209            }
21210        }
21211        
21212        if (label) {
21213            return '<div class="benchmark-score-badge ' + category + '">' + label + '</div>';
21214        }
21215        
21216        return '';
21217    }
21218})();
21219
21220</script>
21220
21221  
21221<script data-inlined="product-compare.js">
21222(function() {
21223  'use strict';
21224  
21225  // State management
21226  let compareList = [];
21227  let isAnalyzing = false;
21228  let currentAnalysis = null;
21229  
21230  // DOM elements
21231  const compareBtn = document.getElementById('compareBtn');
21232  const compareSidebar = document.getElementById('compareSidebar');
21233  const compareOverlay = document.getElementById('compareOverlay');
21234  const compareClose = document.getElementById('compareClose');
21235  const compareModal = document.getElementById('aiCompareModal');
21236  const compareModalClose = document.getElementById('aiCompareModalClose');
21237  
21238  // Initialize
21239  document.addEventListener('DOMContentLoaded', async function() {
21240    await initializeCompare();
21241    setupEventListeners();
21242  });
21243  
21244  /**
21245   * Initialize compare functionality
21246   */
21247  async function initializeCompare() {
21248    // Load compare list first before setting up buttons
21249    await loadCompareList();
21250    
21251    // Setup product detail compare button if exists
21252    const productCompareBtn = document.getElementById('pd-compare-btn');
21253    
21254    if (productCompareBtn) {
21255      setupProductCompareButton(productCompareBtn);
21256    }
21257    
21258    // Check for existing compare list and update UI
21259    if (compareList.length > 0) {
21260      // Only update badge and buttons, no sticky bar
21261    }
21262  }
21263  
21264  /**
21265   * Setup event listeners
21266   */
21267  function setupEventListeners() {
21268    // Navigation compare button
21269    if (compareBtn) {
21270      compareBtn.addEventListener('click', toggleCompareSidebar);
21271    }
21272    
21273    // Sidebar controls
21274    if (compareClose) {
21275      compareClose.addEventListener('click', closeCompareSidebar);
21276    }
21277    
21278    if (compareOverlay) {
21279      compareOverlay.addEventListener('click', closeCompareSidebar);
21280    }
21281    
21282    // Sidebar actions
21283    const clearAllBtn = document.getElementById('compareClearAll');
21284    if (clearAllBtn) {
21285      clearAllBtn.addEventListener('click', clearAllProducts);
21286    }
21287    
21288    const analyzeBtn = document.getElementById('compareAnalyze');
21289    if (analyzeBtn) {
21290      analyzeBtn.addEventListener('click', startAIAnalysis);
21291    }
21292    
21293    // Modal controls
21294    if (compareModalClose) {
21295      compareModalClose.addEventListener('click', closeModal);
21296    }
21297    
21298    const modalBackdrop = compareModal?.querySelector('.modal-backdrop');
21299    if (modalBackdrop) {
21300      modalBackdrop.addEventListener('click', closeModal);
21301    }
21302    
21303    // Modal actions
21304    const retryBtn = document.getElementById('aiRetry');
21305    if (retryBtn) {
21306      retryBtn.addEventListener('click', startAIAnalysis);
21307    }
21308    
21309    // Removed share and add to cart buttons - replaced with AI disclaimer
21310  }
21311  
21312  /**
21313   * Setup product detail compare button
21314   */
21315  function setupProductCompareButton(button) {
21316    const productId = parseInt(button.dataset.productId);
21317    if (!productId) return;
21318    
21319    // Check if product is already in compare list
21320    updateProductCompareButtonState(button, productId);
21321    
21322    button.addEventListener('click', async function() {
21323      // Get current variant ID (if any)
21324      const variantIdElement = document.getElementById('pd-variant-id');
21325      const variantId = variantIdElement ? parseInt(variantIdElement.value) || 0 : 0;
21326      
21327      // Update button's variant data for current selection
21328      button.dataset.variantId = variantId.toString();
21329      
21330      await toggleProductInCompare(productId, button, variantId);
21331    });
21332  }
21333  
21334  /**
21335   * Toggle product in compare list
21336   */
21337  async function toggleProductInCompare(productId, button, variantId = 0) {
21338    // Check by product ID (variants of same product treated as same item)
21339    const isInCompare = compareList.some(p => parseInt(p.id) === parseInt(productId));
21340    
21341    try {
21342      if (isInCompare) {
21343        await removeFromCompare(productId);
21344        showToast('Produk dihapus dari perbandingan', 'success');
21345      } else {
21346        await addToCompare(productId, variantId);
21347        showToast('Produk ditambahkan ke perbandingan', 'success');
21348        
21349        // Trigger fly-to-compare animation
21350        triggerFlyToCompareAnimation(button);
21351      }
21352      
21353      updateProductCompareButtonState(button, productId);
21354      updateCompareBadge();
21355      updateAllCompareButtons();
21356      
21357    } catch (error) {
21358      showToast(error.message || 'Terjadi kesalahan', 'error');
21359    }
21360  }
21361  
21362  /**
21363   * Update product compare button state
21364   */
21365  function updateProductCompareButtonState(button, productId) {
21366    // Ensure both IDs are compared as integers
21367    const isInCompare = compareList.some(p => parseInt(p.id) === parseInt(productId));
21368    button.classList.toggle('added', isInCompare);
21369    
21370    // Handle visibility of text elements
21371    const compareText = button.querySelector('.compare-text');
21372    const compareRemove = button.querySelector('.compare-remove');
21373    const compareNote = document.getElementById('compare-note');
21374    
21375    if (compareText) {
21376      compareText.style.display = isInCompare ? 'none' : 'inline';
21377    }
21378    
21379    if (compareRemove) {
21380      if (isInCompare) {
21381        compareRemove.removeAttribute('hidden');
21382        compareRemove.style.display = 'flex';
21383      } else {
21384        compareRemove.setAttribute('hidden', '');
21385        compareRemove.style.display = 'none';
21386      }
21387    }
21388    
21389    // Update info note
21390    if (compareNote) {
21391      if (isInCompare) {
21392        const currentCount = compareList.length;
21393        compareNote.textContent = `Produk sudah ada di daftar perbandingan (${currentCount}/5). Klik tombol untuk menghapus.`;
21394      } else {
21395        compareNote.textContent = 'Bandingkan hingga 5 produk dengan bantuan AI';
21396      }
21397    }
21398    
21399    // Inline compare preview removed - keeping it simple
21400  }
21401  
21402  /**
21403   * Add product to compare list
21404   */
21405  async function addToCompare(productId, variantId = 0) {
21406    const requestData = { product_id: productId };
21407    if (variantId > 0) {
21408      requestData.variant_id = variantId;
21409    }
21410    
21411    const response = await fetch('/api/compare/add.php', {
21412      method: 'POST',
21413      headers: {
21414        'Content-Type': 'application/json',
21415      },
21416      body: JSON.stringify(requestData),
21417      credentials: 'same-origin'
21418    });
21419    
21420    const result = await response.json();
21421    
21422    if (!result.success) {
21423      throw new Error(result.error || 'Gagal menambahkan produk');
21424    }
21425    
21426    // Send Google Analytics event for add to compare
21427    if (typeof gtag === 'function') {
21428      gtag('event', 'add_to_compare', {
21429        event_category: 'Product Compare',
21430        event_label: 'Product Added to Compare',
21431        product_id: productId,
21432        variant_id: variantId || 0,
21433        custom_map: {
21434          custom_parameter_1: 'compare_add_product'
21435        }
21436      });
21437    }
21438    
21439    await loadCompareList();
21440    return result;
21441  }
21442  
21443  /**
21444   * Remove product from compare list
21445   */
21446  async function removeFromCompare(productId) {
21447    const response = await fetch('/api/compare/remove.php', {
21448      method: 'POST',
21449      headers: {
21450        'Content-Type': 'application/json',
21451      },
21452      body: JSON.stringify({ product_id: productId }),
21453      credentials: 'same-origin'
21454    });
21455    
21456    const result = await response.json();
21457    
21458    if (!result.success) {
21459      throw new Error(result.error || 'Gagal menghapus produk');
21460    }
21461    
21462    // Send Google Analytics event for remove from compare
21463    if (typeof gtag === 'function') {
21464      gtag('event', 'remove_from_compare', {
21465        event_category: 'Product Compare',
21466        event_label: 'Product Removed from Compare',
21467        product_id: productId,
21468        custom_map: {
21469          custom_parameter_1: 'compare_remove_product'
21470        }
21471      });
21472    }
21473    
21474    await loadCompareList();
21475    return result;
21476  }
21477  
21478  /**
21479   * Clear all products from compare list
21480   */
21481  async function clearAllProducts() {
21482    if (compareList.length === 0) return;
21483    
21484    // Show confirmation modal
21485    const confirmed = await showConfirmModal({
21486      title: 'Hapus Semua Produk',
21487      message: 'Apakah Anda yakin ingin menghapus semua produk dari daftar perbandingan?',
21488      confirmText: 'Hapus Semua',
21489      cancelText: 'Batal',
21490      type: 'danger'
21491    });
21492    
21493    if (!confirmed) return;
21494    
21495    try {
21496      const response = await fetch('/api/compare/clear.php', {
21497        method: 'POST',
21498        credentials: 'same-origin'
21499      });
21500      
21501      const result = await response.json();
21502      
21503      if (!result.success) {
21504        throw new Error(result.error || 'Gagal menghapus produk');
21505      }
21506      
21507      // Send Google Analytics event for clear all products
21508      if (typeof gtag === 'function') {
21509        gtag('event', 'compare_clear_all', {
21510          event_category: 'Product Compare',
21511          event_label: 'Clear All Products',
21512          products_count: compareList.length,
21513          custom_map: {
21514            custom_parameter_1: 'compare_clear_action'
21515          }
21516        });
21517      }
21518      
21519      await loadCompareList();
21520      showToast('Semua produk dihapus dari perbandingan', 'success');
21521      
21522    } catch (error) {
21523      showToast(error.message || 'Terjadi kesalahan', 'error');
21524    }
21525  }
21526  
21527  /**
21528   * Load compare list from server
21529   */
21530  async function loadCompareList() {
21531    try {
21532      const response = await fetch('/api/compare/get.php', {
21533        credentials: 'same-origin'
21534      });
21535      
21536      const result = await response.json();
21537      
21538      if (result.success) {
21539        compareList = result.products || [];
21540        updateCompareSidebar();
21541        updateCompareBadge();
21542        updateAllCompareButtons();
21543      }
21544      
21545    } catch (error) {
21546      // Silently handle error - compare functionality will work with empty list
21547    }
21548  }
21549  
21550  /**
21551   * Update compare sidebar content
21552   */
21553  function updateCompareSidebar() {
21554    const emptyState = document.getElementById('compareEmpty');
21555    const listContainer = document.getElementById('compareList');
21556    const actionsContainer = document.getElementById('compareActions');
21557    const countElement = document.getElementById('compareCountSidebar');
21558    
21559    if (!emptyState || !listContainer || !actionsContainer || !countElement) return;
21560    
21561    // Update count
21562    countElement.textContent = `(${compareList.length})`;
21563    
21564    if (compareList.length === 0) {
21565      emptyState.style.display = 'block';
21566      listContainer.style.display = 'none';
21567      actionsContainer.style.display = 'none';
21568    } else {
21569      emptyState.style.display = 'none';
21570      listContainer.style.display = 'block';
21571      actionsContainer.style.display = 'flex';
21572      
21573      // Render product list
21574      listContainer.innerHTML = compareList.map(product => {
21575        // Display variant name if available
21576        let displayName = product.name;
21577        if (product.combination_name) {
21578          displayName += ` (${product.combination_name})`;
21579        }
21580        
21581        // Use variant price if available
21582        let displayPrice = product.price;
21583        if (product.variant_price !== undefined && product.variant_price !== null) {
21584          displayPrice = product.variant_price;
21585        }
21586        
21587        return `
21588          <div class="compare-item" data-product-id="${product.id}">
21589            <div class="compare-item-image">
21590              <img src="${product.image_url}" alt="${escapeHtml(displayName)}" loading="lazy">
21591            </div>
21592            <div class="compare-item-info">
21593              <div class="compare-item-name">${escapeHtml(displayName)}</div>
21594              <div class="compare-item-price">${formatPrice(displayPrice)}</div>
21595            </div>
21596            <button class="compare-item-remove" data-product-id="${product.id}" aria-label="Hapus">
21597              <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
21598                <path d="M19,6.41L17.59,5L12,10.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L12,13.41L17.59,19L19,17.59L13.41,12L19,6.41Z"/>
21599              </svg>
21600            </button>
21601          </div>
21602        `;
21603      }).join('');
21604      
21605      // Setup event listeners for remove buttons
21606      setupRemoveButtons();
21607      
21608      // Update analyze button state
21609      const analyzeBtn = document.getElementById('compareAnalyze');
21610      if (analyzeBtn) {
21611        analyzeBtn.disabled = compareList.length < 2;
21612      }
21613    }
21614  }
21615  
21616  /**
21617   * Setup remove buttons event listeners
21618   */
21619  function setupRemoveButtons() {
21620    const removeButtons = document.querySelectorAll('.compare-item-remove');
21621    removeButtons.forEach(button => {
21622      button.addEventListener('click', async (e) => {
21623        e.preventDefault();
21624        const productId = parseInt(button.dataset.productId);
21625        if (productId) {
21626          await removeProduct(productId);
21627        }
21628      });
21629    });
21630  }
21631
21632  /**
21633   * Update all compare buttons on the page
21634   */
21635  function updateAllCompareButtons() {
21636    // Update product detail compare button
21637    const productBtn = document.getElementById('pd-compare-btn');
21638    if (productBtn) {
21639      const productId = parseInt(productBtn.dataset.productId);
21640      if (productId) {
21641        updateProductCompareButtonState(productBtn, productId);
21642      }
21643    }
21644    
21645    // Update any other compare buttons on the page
21646    const allCompareButtons = document.querySelectorAll('[data-product-id][class*="compare"]');
21647    allCompareButtons.forEach(button => {
21648      const productId = parseInt(button.dataset.productId);
21649      if (productId && button.id !== 'pd-compare-btn') {
21650        updateProductCompareButtonState(button, productId);
21651      }
21652    });
21653  }
21654
21655  /**
21656   * Update compare badge
21657   */
21658  function updateCompareBadge() {
21659    const badge = document.getElementById('compareCount');
21660    if (!badge) return;
21661    
21662    const oldCount = parseInt(badge.textContent) || 0;
21663    const newCount = compareList.length;
21664    
21665    badge.textContent = newCount;
21666    badge.classList.toggle('active', newCount > 0);
21667    
21668    // Animate badge if count increased
21669    if (newCount > oldCount) {
21670      animateCompareBadge();
21671      highlightCompareButton();
21672    }
21673    
21674    // Sticky bar removed - keeping only fly-to-navbar animation
21675  }
21676  
21677  /**
21678   * Animate compare badge when new product added
21679   */
21680  function animateCompareBadge() {
21681    const badge = document.getElementById('compareCount');
21682    if (!badge) return;
21683    
21684    badge.style.transform = 'scale(1.3)';
21685    badge.style.transition = 'transform 0.3s ease';
21686    
21687    setTimeout(() => {
21688      badge.style.transform = 'scale(1)';
21689    }, 300);
21690  }
21691  
21692  /**
21693   * Highlight compare button temporarily
21694   */
21695  function highlightCompareButton() {
21696    const compareBtn = document.getElementById('compareBtn');
21697    if (!compareBtn) return;
21698    
21699    compareBtn.classList.add('pulse-highlight');
21700    
21701    setTimeout(() => {
21702      compareBtn.classList.remove('pulse-highlight');
21703    }, 3000);
21704  }
21705  
21706  /**
21707   * Trigger fly-to-compare animation
21708   */
21709  function triggerFlyToCompareAnimation(sourceButton) {
21710    if (!sourceButton) {
21711      return;
21712    }
21713    
21714    // Check if mobile view (bottom nav) or desktop (top nav)
21715    const isMobile = window.innerWidth <= 768;
21716    
21717    // Get source position
21718    const sourceRect = sourceButton.getBoundingClientRect();
21719    
21720    // Calculate target position
21721    let targetTop, targetLeft;
21722    
21723    if (isMobile) {
21724      // Mobile: fly to fixed bottom position (bottom nav area)
21725      // Use fixed coordinates regardless of bottom nav visibility
21726      targetTop = window.innerHeight - 80; // Just above bottom nav area
21727      targetLeft = window.innerWidth / 2 - 30; // Center horizontally
21728    } else {
21729      // Desktop: fly to top navbar compare button
21730      const targetElement = document.getElementById('compareBtn');
21731      if (!targetElement) {
21732        return;
21733      }
21734      const targetRect = targetElement.getBoundingClientRect();
21735      targetTop = targetRect.top + 10;
21736      targetLeft = targetRect.left + 10;
21737    }
21738    
21739    // Get product image for animation - try multiple selectors
21740    let productImage = document.querySelector('#pd-main-img, .product-gallery img, .pd-image img, .product-image img, .product-main-image img, img[alt*="produk"], img[src*="product"]');
21741    
21742    // Create animated element
21743    const flyingElement = document.createElement('div');
21744    flyingElement.className = 'flying-product';
21745    
21746    if (productImage) {
21747      flyingElement.innerHTML = `<img src="${productImage.src}" alt="Flying product">`;
21748      flyingElement.querySelector('img').style.cssText = `
21749        width: 100%;
21750        height: 100%;
21751        object-fit: cover;
21752        border-radius: 8px;
21753        box-shadow: 0 4px 12px rgba(0,0,0,0.3);
21754      `;
21755    } else {
21756      // Fallback: colored div with icon
21757      flyingElement.innerHTML = `<div class="flying-fallback">📦</div>`;
21758      flyingElement.querySelector('.flying-fallback').style.cssText = `
21759        width: 100%;
21760        height: 100%;
21761        background: #3b82f6;
21762        border-radius: 8px;
21763        display: flex;
21764        align-items: center;
21765        justify-content: center;
21766        font-size: 24px;
21767        box-shadow: 0 4px 12px rgba(0,0,0,0.3);
21768      `;
21769    }
21770    
21771    flyingElement.style.cssText = `
21772      position: fixed;
21773      top: ${sourceRect.top}px;
21774      left: ${sourceRect.left}px;
21775      width: 60px;
21776      height: 60px;
21777      z-index: 9999;
21778      pointer-events: none;
21779      opacity: 1;
21780      transform: scale(1);
21781    `;
21782    
21783    document.body.appendChild(flyingElement);
21784    
21785    // Use Web Animations API for more reliable animation
21786    flyingElement.animate([
21787      // Keyframe 1: Initial state
21788      {
21789        top: `${sourceRect.top}px`,
21790        left: `${sourceRect.left}px`,
21791        transform: 'scale(1)',
21792        opacity: 1
21793      },
21794      // Keyframe 2: Final state
21795      {
21796        top: `${targetTop}px`,
21797        left: `${targetLeft}px`,
21798        transform: 'scale(0.3)',
21799        opacity: 0
21800      }
21801    ], {
21802      duration: 800,
21803      easing: 'cubic-bezier(0.25, 0.46, 0.45, 0.94)',
21804      fill: 'forwards'
21805    });
21806    
21807    // Clean up after animation completes
21808    setTimeout(() => {
21809      if (flyingElement.parentNode) {
21810        flyingElement.parentNode.removeChild(flyingElement);
21811      }
21812    }, 850);
21813  }
21814  
21815  // Sticky compare bar functions removed - using only fly-to-navbar animation
21816  
21817  /**
21818   * Toggle compare sidebar
21819   */
21820  function toggleCompareSidebar() {
21821    if (!compareSidebar) return;
21822    
21823    const isOpen = compareSidebar.classList.contains('open');
21824    
21825    if (isOpen) {
21826      closeCompareSidebar();
21827    } else {
21828      openCompareSidebar();
21829    }
21830  }
21831  
21832  /**
21833   * Open compare sidebar
21834   */
21835  function openCompareSidebar() {
21836    if (!compareSidebar || !compareOverlay) return;
21837    
21838    compareSidebar.classList.add('open');
21839    compareOverlay.classList.add('active');
21840    document.body.style.overflow = 'hidden';
21841    
21842    // Send Google Analytics event for compare sidebar open
21843    if (typeof gtag === 'function') {
21844      gtag('event', 'compare_sidebar_open', {
21845        event_category: 'Product Compare',
21846        event_label: 'Compare Sidebar Opened',
21847        products_count: compareList.length,
21848        custom_map: {
21849          custom_parameter_1: 'compare_sidebar_view'
21850        }
21851      });
21852    }
21853  }
21854  
21855  /**
21856   * Close compare sidebar
21857   */
21858  function closeCompareSidebar() {
21859    if (!compareSidebar || !compareOverlay) return;
21860    
21861    compareSidebar.classList.remove('open');
21862    compareOverlay.classList.remove('active');
21863    document.body.style.overflow = '';
21864  }
21865  
21866  /**
21867   * Start AI analysis
21868   */
21869  async function startAIAnalysis() {
21870    if (compareList.length < 2) {
21871      showToast('Minimal 2 produk diperlukan untuk analisis AI', 'warning');
21872      return;
21873    }
21874    
21875    if (isAnalyzing) return;
21876    
21877    // Send Google Analytics event for AI Analysis start
21878    if (typeof gtag === 'function') {
21879      gtag('event', 'ai_analysis_start', {
21880        event_category: 'Product Compare',
21881        event_label: 'AI Analysis Button Click',
21882        products_count: compareList.length,
21883        product_ids: compareList.map(p => p.id).join(','),
21884        custom_map: {
21885          custom_parameter_1: 'compare_ai_analysis'
21886        }
21887      });
21888    }
21889    
21890    // Check if products are in similar categories
21891    const mismatchInfo = await checkProductCategoryMismatch();
21892    if (mismatchInfo.shouldWarn) {
21893      const categoryList = Array.from(mismatchInfo.categories).join(', ');
21894      const confirmed = await showConfirmModal({
21895        title: 'Produk Berbeda Kategori',
21896        message: `Produk yang Anda pilih berasal dari kategori yang berbeda: ${categoryList}. AI tetap bisa menganalisis, tapi perbandingan mungkin kurang relevan. Lanjutkan analisis?`,
21897        confirmText: 'Ya, Analisis Tetap',
21898        cancelText: 'Batal',
21899        type: 'warning'
21900      });
21901      
21902      if (!confirmed) return;
21903    }
21904    
21905    openModal();
21906    showLoadingState();
21907    isAnalyzing = true;
21908    
21909    try {
21910      const response = await fetch('/api/compare/ai-analysis.php', {
21911        method: 'POST',
21912        credentials: 'same-origin'
21913      });
21914      
21915      const result = await response.json();
21916      
21917      if (!result.success) {
21918        throw new Error(result.error || 'Analisis AI gagal');
21919      }
21920      
21921      currentAnalysis = result;
21922      showAnalysisResults(result);
21923      
21924      // Send Google Analytics event for successful AI Analysis
21925      if (typeof gtag === 'function') {
21926        gtag('event', 'ai_analysis_success', {
21927          event_category: 'Product Compare',
21928          event_label: 'AI Analysis Completed',
21929          products_count: compareList.length,
21930          analysis_type: 'product_comparison',
21931          custom_map: {
21932            custom_parameter_1: 'compare_ai_success'
21933          }
21934        });
21935      }
21936      
21937    } catch (error) {
21938      showErrorState(error.message);
21939      
21940      // Send Google Analytics event for failed AI Analysis
21941      if (typeof gtag === 'function') {
21942        gtag('event', 'ai_analysis_error', {
21943          event_category: 'Product Compare',
21944          event_label: 'AI Analysis Failed',
21945          products_count: compareList.length,
21946          error_message: error.message,
21947          custom_map: {
21948            custom_parameter_1: 'compare_ai_error'
21949          }
21950        });
21951      }
21952    } finally {
21953      isAnalyzing = false;
21954    }
21955  }
21956  
21957  /**
21958   * Show modal
21959   */
21960  function openModal() {
21961    if (!compareModal) return;
21962    compareModal.classList.add('open');
21963    document.body.style.overflow = 'hidden';
21964  }
21965  
21966  /**
21967   * Close modal
21968   */
21969  function closeModal() {
21970    if (!compareModal) return;
21971    compareModal.classList.remove('open');
21972    document.body.style.overflow = '';
21973  }
21974  
21975  /**
21976   * Show loading state
21977   */
21978  function showLoadingState() {
21979    const loading = document.getElementById('aiLoading');
21980    const error = document.getElementById('aiError');
21981    const results = document.getElementById('aiResults');
21982    
21983    if (loading) loading.style.display = 'block';
21984    if (error) error.hidden = true;
21985    if (results) results.hidden = true;
21986  }
21987  
21988  /**
21989   * Show error state
21990   */
21991  function showErrorState(message) {
21992    const loading = document.getElementById('aiLoading');
21993    const error = document.getElementById('aiError');
21994    const results = document.getElementById('aiResults');
21995    const errorMessage = document.getElementById('aiErrorMessage');
21996    
21997    if (loading) loading.style.display = 'none';
21998    if (error) error.hidden = false;
21999    if (results) results.hidden = true;
22000    if (errorMessage) errorMessage.textContent = message;
22001  }
22002  
22003  /**
22004   * Show analysis results
22005   */
22006  function showAnalysisResults(analysis) {
22007    const loading = document.getElementById('aiLoading');
22008    const error = document.getElementById('aiError');
22009    const results = document.getElementById('aiResults');
22010    
22011    if (loading) loading.style.display = 'none';
22012    if (error) error.hidden = true;
22013    if (results) results.hidden = false;
22014    
22015    const data = analysis.data;
22016    
22017    // Update summary
22018    const summaryElement = document.getElementById('aiSummary');
22019    if (summaryElement) summaryElement.textContent = data.summary || '';
22020    
22021    const winnerProduct = document.getElementById('winnerProduct');
22022    const winnerReason = document.getElementById('winnerReason');
22023    if (winnerProduct && winnerReason && data.winner_overall) {
22024      const winner = compareList.find(p => parseInt(p.id) === parseInt(data.winner_overall));
22025      winnerProduct.textContent = winner ? winner.name : 'Tidak diketa
22025hui';
22026      winnerReason.textContent = data.winner_reason || '';
22027    }
22028    
22029    // Update comparison table
22030    updateComparisonTable(data.comparison_table);
22031    
22032    // Update detailed analysis
22033    updateDetailedAnalysis(data.detailed_analysis);
22034    
22035    // Update recommendations
22036    updateRecommendations(data.recommendations);
22037    
22038    // Update buying tips
22039    updateBuyingTips(data.buying_tips);
22040  }
22041  
22042  /**
22043   * Update comparison table
22044   */
22045  function updateComparisonTable(comparisonData) {
22046    const container = document.getElementById('comparisonTable');
22047    if (!container || !comparisonData?.categories) return;
22048    
22049    // First, create product header row with names
22050    const productHeaderHtml = `
22051      <div class="comparison-category">
22052        <div class="category-header">Produk</div>
22053        <div class="category-products">
22054          ${compareList.map(product => `
22055            <div class="product-score">
22056              <div class="product-name-header">
22057                <strong>${escapeHtml(product.name)}</strong>
22058              </div>
22059              <div class="product-price">
22060                ${formatPrice(product.price)}
22061              </div>
22062            </div>
22063          `).join('')}
22064        </div>
22065      </div>
22066    `;
22067    
22068    // Then create comparison categories
22069    const categoriesHtml = comparisonData.categories.map(category => `
22070      <div class="comparison-category">
22071        <div class="category-header">${escapeHtml(category.name)}</div>
22072        <div class="category-products">
22073          ${compareList.map(product => {
22074            const productData = category.products?.[product.id];
22075            return `
22076              <div class="product-score">
22077                <div class="score-value">
22078                  <span class="score-stars">${'★'.repeat(productData?.score || 0)}${'☆'.repeat(5 - (productData?.score || 0))}</span>
22079                  <span>${productData?.score || 0}/5</span>
22080                </div>
22081                <div class="score-note">${escapeHtml(productData?.note || '')}</div>
22082              </div>
22083            `;
22084          }).join('')}
22085        </div>
22086      </div>
22087    `).join('');
22088    
22089    container.innerHTML = productHeaderHtml + categoriesHtml;
22090  }
22091  
22092  /**
22093   * Update detailed analysis
22094   */
22095  function updateDetailedAnalysis(analysisData) {
22096    const container = document.getElementById('detailedAnalysis');
22097    if (!container || !analysisData) return;
22098    
22099    container.innerHTML = compareList.map(product => {
22100      const productAnalysis = analysisData[product.id];
22101      if (!productAnalysis) return '';
22102      
22103      // Use product name from API response if available, fallback to local name
22104      const productName = productAnalysis.product_name || product.name;
22105      
22106      return `
22107        <div class="product-analysis">
22108          <h5>${escapeHtml(productName)}</h5>
22109          
22110          ${productAnalysis.strengths ? `
22111            <div class="analysis-section">
22112              <h6 class="strengths">✅ Kelebihan</h6>
22113              <ul>
22114                ${productAnalysis.strengths.map(strength => 
22115                  `<li>${escapeHtml(strength)}</li>`
22116                ).join('')}
22117              </ul>
22118            </div>
22119          ` : ''}
22120          
22121          ${productAnalysis.weaknesses ? `
22122            <div class="analysis-section">
22123              <h6 class="weaknesses">❌ Kekurangan</h6>
22124              <ul>
22125                ${productAnalysis.weaknesses.map(weakness => 
22126                  `<li>${escapeHtml(weakness)}</li>`
22127                ).join('')}
22128              </ul>
22129            </div>
22130          ` : ''}
22131          
22132          ${productAnalysis.best_for ? `
22133            <div class="analysis-section">
22134              <h6 class="best-for">🎯 Cocok Untuk</h6>
22135              <p class="best-for-text">${escapeHtml(productAnalysis.best_for)}</p>
22136            </div>
22137          ` : ''}
22138        </div>
22139      `;
22140    }).filter(Boolean).join('');
22141  }
22142  
22143  /**
22144   * Update recommendations
22145   */
22146  function updateRecommendations(recommendations) {
22147    if (!recommendations) return;
22148    
22149    const budgetEl = document.getElementById('budgetRecommendation');
22150    const performanceEl = document.getElementById('performanceRecommendation');
22151    const balancedEl = document.getElementById('balancedRecommendation');
22152    
22153    if (budgetEl && recommendations.budget_conscious) {
22154      const product = compareList.find(p => parseInt(p.id) === parseInt(recommendations.budget_conscious));
22155      budgetEl.textContent = product ? product.name : 'Tidak tersedia';
22156    }
22157    
22158    if (performanceEl && recommendations.performance_focused) {
22159      const product = compareList.find(p => parseInt(p.id) === parseInt(recommendations.performance_focused));
22160      performanceEl.textContent = product ? product.name : 'Tidak tersedia';
22161    }
22162    
22163    if (balancedEl && recommendations.balanced) {
22164      const product = compareList.find(p => parseInt(p.id) === parseInt(recommendations.balanced));
22165      balancedEl.textContent = product ? product.name : 'Tidak tersedia';
22166    }
22167  }
22168  
22169  /**
22170   * Check if products are from different categories
22171   */
22172  async function checkProductCategoryMismatch() {
22173    if (compareList.length < 2) {
22174      return { shouldWarn: false, categories: new Set() };
22175    }
22176    
22177    // Get the root categories from each product
22178    const rootCategories = new Set();
22179    const productCategories = [];
22180    
22181    for (const product of compareList) {
22182      // Extract root category from the product's category_path if available
22183      const rootCategory = await getProductRootCategory(product);
22184      if (rootCategory) {
22185        rootCategories.add(rootCategory);
22186        productCategories.push({
22187          product: product.name,
22188          category: rootCategory
22189        });
22190      }
22191    }
22192    
22193    // If we have more than 1 different root categories, show warning
22194    const shouldWarn = rootCategories.size > 1 && compareList.length >= 2;
22195    
22196    return {
22197      shouldWarn: shouldWarn,
22198      categories: rootCategories,
22199      productCategories: productCategories
22200    };
22201  }
22202  
22203  /**
22204   * Get product root category from category_path or fallback to name detection
22205   */
22206  async function getProductRootCategory(product) {
22207    // First try to get from category_path if available
22208    if (product.category_path) {
22209      const rootCategory = product.category_path.split('/')[0];
22210      return rootCategory;
22211    }
22212    
22213    // If no category_path, try to fetch from product detail or use name detection
22214    const detectedCategory = detectProductCategory(product.name);
22215    return detectedCategory;
22216  }
22217
22218  /**
22219   * Detect product category from name (fallback method)
22220   */
22221  function detectProductCategory(productName) {
22222    const name = productName.toLowerCase();
22223    
22224    // Map keywords to actual root categories from the API structure
22225    const categoryMappings = {
22226      // Komputer & Laptop
22227      'Komputer & Laptop': ['laptop', 'notebook', 'macbook', 'thinkpad', 'gaming laptop', 'desktop', 'pc', 'mini pc', 'all-in-one', 'server'],
22228      
22229      // Printer & Scanner  
22230      'Printer & Scanner': ['printer', 'epson printer', 'canon printer', 'hp printer', 'brother printer', 'scanner', 'laser printer', 'inkjet', 'dot matrix'],
22231      
22232      // Gadget
22233      'Gadget': ['smartphone', 'iphone', 'samsung phone', 'xiaomi', 'oppo', 'vivo', 'realme', 'tablet', 'ipad', 'android tablet'],
22234      
22235      // Periferal
22236      'Periferal': ['monitor', 'lcd monitor', 'led monitor', 'gaming monitor', 'keyboard', 'mouse', 'gaming keyboard', 'mechanical keyboard', 'webcam'],
22237      
22238      // Audio
22239      'Audio': ['headset', 'headphone', 'earphone', 'gaming headset', 'speaker', 'mikrofon', 'sound card'],
22240      
22241      // Jaringan
22242      'Jaringan': ['router', 'wifi', 'access point', 'switch', 'modem', 'network'],
22243      
22244      // Penyimpanan
22245      'Penyimpanan': ['ssd', 'hdd', 'nvme', 'solid state', 'hard disk', 'flash drive', 'usb drive', 'memory card'],
22246      
22247      // Komponen PC
22248      'Komponen PC': ['ram', 'memory', 'ddr4', 'ddr5', 'processor', 'cpu', 'intel', 'amd', 'motherboard', 'graphics card', 'gpu', 'psu', 'power supply', 'casing'],
22249      
22250      // UPS & Power
22251      'UPS & Power': ['ups', 'uninterruptible', 'stabilizer', 'power supply'],
22252      
22253      // Proyektor
22254      'Proyektor': ['proyektor', 'projector', 'layar proyektor'],
22255      
22256      // Security System
22257      'Security System': ['cctv', 'security camera', 'surveillance'],
22258      
22259      // Aksesoris
22260      'Aksesoris': ['charger laptop', 'adaptor', 'converter', 'dock', 'hub', 'kabel', 'cable', 'power bank', 'tas laptop'],
22261      
22262      // Software
22263      'Software': ['software', 'lisensi', 'license', 'antivirus'],
22264      
22265      // Perlengkapan Kantor
22266      'Perlengkapan Kantor': ['fingerprint', 'finger print', 'atk', 'alat tulis']
22267    };
22268    
22269    // Check which root category matches
22270    for (const [rootCategory, keywords] of Object.entries(categoryMappings)) {
22271      for (const keyword of keywords) {
22272        if (name.includes(keyword)) {
22273          return rootCategory;
22274        }
22275      }
22276    }
22277    
22278    return null;
22279  }
22280
22281  /**
22282   * Update buying tips
22283   */
22284  function updateBuyingTips(tips) {
22285    const container = document.getElementById('buyingTips');
22286    if (!container || !Array.isArray(tips)) return;
22287    
22288    container.innerHTML = tips.map(tip => 
22289      `<li>${escapeHtml(tip)}</li>`
22290    ).join('');
22291  }
22292  
22293  // Removed share and cart functions - replaced with AI disclaimer in UI
22294  
22295  /**
22296   * Remove product from compare (public method)
22297   */
22298  async function removeProduct(productId) {
22299    try {
22300      await removeFromCompare(productId);
22301      showToast('Produk dihapus dari perbandingan', 'success');
22302      
22303      // Update all compare buttons
22304      updateAllCompareButtons();
22305      
22306    } catch (error) {
22307      showToast(error.message || 'Terjadi kesalahan', 'error');
22308    }
22309  }
22310  
22311  /**
22312   * Utility functions
22313   */
22314  function escapeHtml(text) {
22315    const div = document.createElement('div');
22316    div.textContent = text;
22317    return div.innerHTML;
22318  }
22319  
22320  function formatPrice(price) {
22321    return 'Rp ' + parseInt(price).toLocaleString('id-ID');
22322  }
22323  
22324  /**
22325   * Show confirmation modal using the existing modal.css design
22326   */
22327  function showConfirmModal(options = {}) {
22328    return new Promise((resolve) => {
22329      const {
22330        title = 'Konfirmasi',
22331        message = 'Apakah Anda yakin?',
22332        confirmText = 'Ya',
22333        cancelText = 'Tidak',
22334        type = 'warning'
22335      } = options;
22336      
22337      // Create modal HTML
22338      const modalHTML = `
22339        <div class="modal-overlay" id="confirmModal">
22340          <div class="modal-dialog">
22341            <div class="modal-header">
22342              <h3 class="modal-title">
22343                <div class="modal-icon ${type}">
22344                  ${getModalIcon(type)}
22345                </div>
22346                ${escapeHtml(title)}
22347              </h3>
22348            </div>
22349            <div class="modal-body">
22350              <p class="modal-message">${escapeHtml(message)}</p>
22351              <div class="modal-actions">
22352                <button type="button" class="modal-btn modal-btn-secondary" id="confirmCancel">
22353                  ${escapeHtml(cancelText)}
22354                </button>
22355                <button type="button" class="modal-btn modal-btn-${type === 'danger' ? 'danger' : 'primary'}" id="confirmOk">
22356                  ${escapeHtml(confirmText)}
22357                </button>
22358              </div>
22359            </div>
22360          </div>
22361        </div>
22362      `;
22363      
22364      // Add to DOM
22365      document.body.insertAdjacentHTML('beforeend', modalHTML);
22366      const modal = document.getElementById('confirmModal');
22367      const cancelBtn = document.getElementById('confirmCancel');
22368      const okBtn = document.getElementById('confirmOk');
22369      
22370      // Show modal
22371      requestAnimationFrame(() => {
22372        modal.classList.add('show');
22373      });
22374      
22375      // Handle events
22376      function cleanup() {
22377        modal.remove();
22378      }
22379      
22380      function handleCancel() {
22381        modal.classList.remove('show');
22382        setTimeout(() => {
22383          cleanup();
22384          resolve(false);
22385        }, 200);
22386      }
22387      
22388      function handleConfirm() {
22389        modal.classList.remove('show');
22390        setTimeout(() => {
22391          cleanup();
22392          resolve(true);
22393        }, 200);
22394      }
22395      
22396      cancelBtn.addEventListener('click', handleCancel);
22397      okBtn.addEventListener('click', handleConfirm);
22398      
22399      // Close on overlay click
22400      modal.addEventListener('click', (e) => {
22401        if (e.target === modal) {
22402          handleCancel();
22403        }
22404      });
22405      
22406      // Close on escape
22407      document.addEventListener('keydown', function escapeHandler(e) {
22408        if (e.key === 'Escape') {
22409          document.removeEventListener('keydown', escapeHandler);
22410          handleCancel();
22411        }
22412      });
22413      
22414      // Focus on confirm button
22415      setTimeout(() => okBtn.focus(), 100);
22416    });
22417  }
22418  
22419  /**
22420   * Get icon for modal type
22421   */
22422  function getModalIcon(type) {
22423      const icons = {
22424        danger: '🚨 ',
22425        warning: '⚠️',
22426        success: '✅',
22427        info: 'ℹ️'
22428      };
22429      return icons[type] || icons.info;
22430    }
22431
22432
22433  function showToast(message, type = 'info') {
22434    // Integration with existing toast system or create simple one
22435    
22436    // Simple alert fallback - replace with proper toast system
22437    if (type === 'error') {
22438      alert('Error: ' + message);
22439    }
22440  }
22441  
22442  // Inline compare preview functions removed - keeping it simple and clean
22443  
22444  /**
22445   * Get current product ID from page
22446   */
22447  function getCurrentProductId() {
22448    const button = document.getElementById('pd-compare-btn');
22449    return button ? parseInt(button.dataset.productId) : null;
22450  }
22451  
22452  // hideStickyCompareBar function removed - no longer using sticky bar
22453
22454  // Public API
22455  window.productCompare = {
22456    removeProduct: removeProduct,
22457    addToCompare: addToCompare,
22458    loadCompareList: loadCompareList,
22459    getCompareList: function() { return compareList; },
22460    openSidebar: openCompareSidebar,
22461    startAnalysis: startAIAnalysis,
22462    // Helper function to add from external sources with variant support
22463    addProductWithVariant: async function(productId, variantId = 0) {
22464      return await addToCompare(productId, variantId);
22465    }
22466  };
22467
22468})();
22469
22470
22471
22472</script>
vendor: 2 bytes, line 22472
22472
22473<script data-inlined="product-card-actions.js">
22474/**
22475 * Product Card Quick Actions
22476 * Bottom sheet menu for quick add to cart & compare
22477 * Integrates with existing product-compare.js and cart.js
22478 */
22479
22480(function() {
22481  'use strict';
22482  
22483  let activeSheet = null;
22484  let activeProductData = null;
22485  
22486  // DOM elements (will be created dynamically)
22487  let overlay = null;
22488  let bottomSheet = null;
22489  
22490  /**
22491   * Initialize on DOM ready
22492   */
22493  document.addEventListener('DOMContentLoaded', function() {
22494    createBottomSheet();
22495    attachEventListeners();
22496  });
22497  
22498  /**
22499   * Create bottom sheet HTML structure
22500   */
22501  function createBottomSheet() {
22502    // Create overlay
22503    overlay = document.createElement('div');
22504    overlay.className = 'pca-overlay';
22505    overlay.addEventListener('click', closeBottomSheet);
22506    
22507    // Create bottom sheet
22508    bottomSheet = document.createElement('div');
22509    bottomSheet.className = 'pca-bottom-sheet';
22510    bottomSheet.innerHTML = `
22511      <div class="pca-sheet-handle"></div>
22512      <div class="pca-sheet-product" id="pca-product-preview">
22513        <!-- Product info will be inserted here -->
22514      </div>
22515      <div class="pca-sheet-actions">
22516        <button type="button" class="pca-action-item cart" id="pca-add-cart">
22517          <svg class="pca-action-icon" viewBox="0 0 24 24" fill="currentColor">
22518            <path d="M17,18A2,2 0 0,1 19,20A2,2 0 0,1 17,22C15.89,22 15,21.1 15,20C15,18.89 15.89,18 17,18M1,2H4.27L5.21,4H20A1,1 0 0,1 21,5C21,5.17 20.95,5.34 20.88,5.5L17.3,11.97C16.96,12.58 16.3,13 15.55,13H8.1L7.2,14.63L7.17,14.75A0.25,0.25 0 0,0 7.42,15H19V17H7C5.89,17 5,16.1 5,15C5,14.65 5.09,14.32 5.24,14.04L6.6,11.59L3,4H1V2M7,18A2,2 0 0,1 9,20A2,2 0 0,1 7,22C5.89,22 5,21.1 5,20C5,18.89 5.89,18 7,18M16,11L18.78,6H6.14L8.5,11H16Z"/>
22519          </svg>
22520          <div class="pca-action-content">
22521            <div class="pca-action-label">Tambah ke Keranjang</div>
22522            <div class="pca-action-desc">Lanjut belanja produk lain</div>
22523          </div>
22524        </button>
22525        
22526        <button type="button" class="pca-action-item compare" id="pca-add-compare">
22527          <svg class="pca-action-icon" viewBox="0 0 24 24" fill="currentColor">
22528            <path d="M21,9L17,5V8H10V10H17V13M7,11L3,15L7,19V16H14V14H7V11Z"/>
22529          </svg>
22530          <div class="pca-action-content">
22531            <div class="pca-action-label">Bandingkan Produk</div>
22532            <div class="pca-action-desc">Analisis dengan AI</div>
22533          </div>
22534          <span class="pca-action-badge compare" id="pca-compare-count" style="display:none;">0</span>
22535        </button>
22536      </div>
22537    `;
22538    
22539    // Append to body
22540    document.body.appendChild(overlay);
22541    document.body.appendChild(bottomSheet);
22542    
22543    // Setup action buttons
22544    document.getElementById('pca-add-cart').addEventListener('click', handleAddToCart);
22545    document.getElementById('pca-add-compare').addEventListener('click', handleAddToCompare);
22546    
22547    // Prevent clicks inside bottom sheet from closing it
22548    bottomSheet.addEventListener('click', function(e) {
22549      e.stopPropagation();
22550    });
22551  }
22552  
22553  /**
22554   * Attach event listeners to all 3-dot buttons
22555   */
22556  function attachEventListeners() {
22557    // Use event delegation for dynamically loaded product cards
22558    document.addEventListener('click', function(e) {
22559      const btn = e.target.closest('.prod-card-actions-btn');
22560      if (btn) {
22561        e.preventDefault();
22562        e.stopPropagation();
22563        handleActionsButtonClick(btn);
22564      }
22565    });
22566    
22567    // Handle ESC key
22568    document.addEventListener('keydown', function(e) {
22569      if (e.key === 'Escape' && activeSheet) {
22570        closeBottomSheet();
22571      }
22572    });
22573  }
22574  
22575  /**
22576   * Handle 3-dot button click
22577   */
22578  function handleActionsButtonClick(button) {
22579    // Get product ID directly from button
22580    const productId = parseInt(button.dataset.productId) || 0;
22581    if (!productId) {
22582      console.error('Product ID not found on button:', button);
22583      showToast('Data produk tidak ditemukan', 'error');
22584      return;
22585    }
22586    
22587    // Find parent card for additional data
22588    const card = button.closest('.prod-card, .pa-card');
22589    if (!card) {
22590      console.error('Product card not found');
22591      showToast('Data produk tidak ditemukan', 'error');
22592      return;
22593    }
22594    
22595    // Extract product data from card
22596    const productData = extractProductData(card, productId);
22597    if (!productData) {
22598      showToast('Data produk tidak ditemukan', 'error');
22599      return;
22600    }
22601    
22602    activeProductData = productData;
22603    openBottomSheet(productData);
22604  }
22605  
22606  /**
22607   * Extract product data from card element
22608   */
22609  function extractProductData(card, productId) {
22610    try {
22611      // Product ID already passed from button
22612      if (!productId) {
22613        console.error('Product ID not provided');
22614        return null;
22615      }
22616      // Product ID already passed from button
22617      if (!productId) {
22618        console.error('Product ID not provided');
22619        return null;
22620      }
22621      
22622      const id = productId;
22623      
22624      // Get product name
22625      const nameEl = card.querySelector('.prod-name, .title');
22626      const name = nameEl ? nameEl.textContent.trim() : 'Produk';
22627      
22628      // Get product image
22629      const imgEl = card.querySelector('.thumb img, img');
22630      const image = imgEl ? imgEl.src : '/assets/img/placeholder.png';
22631      
22632      // Get product price and detect variants
22633      const priceEl = card.querySelector('.prod-price-final, .final, .prod-price');
22634      let price = 0;
22635      let hasVariants = false;
22636      let priceDisplay = '';
22637      
22638      if (priceEl) {
22639        // Get text content and clean it
22640        let priceText = priceEl.textContent.trim();
22641        priceDisplay = priceText;
22642        
22643        // Check if it's a range (indicates product has variants)
22644        if (priceText.includes('-')) {
22645          hasVariants = true;
22646          // Take the first price for calculation
22647          priceText = priceText.split('-')[0].trim();
22648        }
22649        
22650        // Remove all non-numeric characters
22651        priceText = priceText.replace(/[^0-9]/g, '');
22652        price = parseInt(priceText) || 0;
22653      }
22654      
22655      // Get stock status
22656      const stockDot = card.querySelector('.stock-dot');
22657      let stockStatus = 'unknown';
22658      let stockLabel = 'Cek stok';
22659      
22660      if (stockDot) {
22661        if (stockDot.classList.contains('ready')) {
22662          stockStatus = 'in';
22663          stockLabel = 'Stok tersedia';
22664        } else if (stockDot.classList.contains('low')) {
22665          stockStatus = 'low';
22666          stockLabel = 'Stok terbatas';
22667        } else if (stockDot.classList.contains('out')) {
22668          stockStatus = 'out';
22669          stockLabel = 'Stok habis';
22670        }
22671      }
22672      
22673      // Get category path (if available)
22674      const categoryPath = card.dataset.category || '';
22675      
22676      // Get URL
22677      let url = '#';
22678      if (card.tagName === 'A') {
22679        url = card.href;
22680      } else {
22681        const link = card.querySelector('a[href*="/product/"]');
22682        if (link) url = link.href;
22683      }
22684      
22685      return {
22686        id: id,
22687        name: name,
22688        image: image,
22689        price: price,
22690        priceDisplay: priceDisplay,
22691        hasVariants: hasVariants,
22692        stockStatus: stockStatus,
22693        stockLabel: stockLabel,
22694        categoryPath: categoryPath,
22695        url: url
22696      };
22697    } catch (error) {
22698      console.error('Error extracting product data:', error);
22699      return null;
22700    }
22701  }
22702  
22703  /**
22704   * Open bottom sheet
22705   */
22706  function openBottomSheet(productData) {
22707    if (!overlay || !bottomSheet) return;
22708    
22709    // Update product preview
22710    updateProductPreview(productData);
22711    
22712    // Update cart button based on variant status
22713    updateCartButtonForVariant(productData);
22714    
22715    // Update compare button state
22716    updateCompareButtonState(productData.id);
22717    
22718    // Show overlay and sheet
22719    overlay.classList.add('active');
22720    bottomSheet.classList.add('active');
22721    document.body.style.overflow = 'hidden';
22722    
22723    activeSheet = true;
22724    
22725    // Google Analytics
22726    if (typeof gtag === 'function') {
22727      gtag('event', 'quick_actions_open', {
22728        event_category: 'Product Card',
22729        event_label: 'Quick Actions Menu Opened',
22730        product_id: productData.id,
22731        product_name: productData.name
22732      });
22733    }
22734  }
22735  
22736  /**
22737   * Close bottom sheet
22738   */
22739  function closeBottomSheet() {
22740    if (!overlay || !bottomSheet) return;
22741    
22742    overlay.classList.remove('active');
22743    bottomSheet.classList.remove('active');
22744    document.body.style.overflow = '';
22745    
22746    activeSheet = false;
22747    activeProductData = null;
22748  }
22749  
22750  /**
22751   * Update product preview in bottom sheet
22752   */
22753  function updateProductPreview(productData) {
22754    const preview = document.getElementById('pca-product-preview');
22755    if (!preview) return;
22756    
22757    // Use full price display (shows range for variants)
22758    const priceDisplay = productData.priceDisplay || formatPrice(productData.price);
22759    
22760    preview.innerHTML = `
22761      <img src="${escapeHtml(productData.image)}" 
22762           alt="${escapeHtml(productData.name)}" 
22763           class="pca-product-image"
22764           loading="lazy">
22765      <div class="pca-product-info">
22766        <h4 class="pca-product-name">${escapeHtml(productData.name)}</h4>
22767        <p class="pca-product-price">${escapeHtml(priceDisplay)}</p>
22768        <p class="pca-product-stock ${productData.stockStatus}">${productData.stockLabel}</p>
22769      </div>
22770    `;
22771  }
22772  
22773  /**
22774   * Update cart button for variant products
22775   */
22776  function updateCartButtonForVariant(productData) {
22777    const cartBtn = document.getElementById('pca-add-cart');
22778    if (!cartBtn) return;
22779    
22780    if (productData.hasVariants) {
22781      // Product has variants - change to "View Detail"
22782      cartBtn.dataset.hasVariants = 'true';
22783      cartBtn.dataset.productUrl = productData.url;
22784      
22785      // Update icon to eye/external
22786      const iconSvg = cartBtn.querySelector('svg');
22787      if (iconSvg) {
22788        iconSvg.innerHTML = '<path d="M12,9A3,3 0 0,0 9,12A3,3 0 0,0 12,15A3,3 0 0,0 15,12A3,3 0 0,0 12,9M12,17A5,5 0 0,1 7,12A5,5 0 0,1 12,7A5,5 0 0,1 17,12A5,5 0 0,1 12,17M12,4.5C7,4.5 2.73,7.61 1,12C2.73,16.39 7,19.5 12,19.5C17,19.5 21.27,16.39 23,12C21.27,7.61 17,4.5 12,4.5Z"/>';
22789      }
22790      
22791      // Update text
22792      const label = cartBtn.querySelector('.pca-action-label');
22793      const desc = cartBtn.querySelector('.pca-action-desc');
22794      if (label) label.textContent = 'Lihat Detail Produk';
22795      if (desc) desc.textContent = 'Pilih varian terlebih dahulu';
22796      
22797    } else {
22798      // Single product - normal cart button
22799      cartBtn.dataset.hasVariants = 'false';
22800      
22801      // Restore cart icon
22802      const iconSvg = cartBtn.querySelector('svg');
22803      if (iconSvg) {
22804        iconSvg.innerHTML = '<path d="M17,18A2,2 0 0,1 19,20A2,2 0 0,1 17,22C15.89,22 15,21.1 15,20C15,18.89 15.89,18 17,18M1,2H4.27L5.21,4H20A1,1 0 0,1 21,5C21,5.17 20.95,5.34 20.88,5.5L17.3,11.97C16.96,12.58 16.3,13 15.55,13H8.1L7.2,14.63L7.17,14.75A0.25,0.25 0 0,0 7.42,15H19V17H7C5.89,17 5,16.1 5,15C5,14.65 5.09,14.32 5.24,14.04L6.6,11.59L3,4H1V2M7,18A2,2 0 0,1 9,20A2,2 0 0,1 7,22C5.89,22 5,21.1 5,20C5,18.89 5.89,18 7,18M16,11L18.78,6H6.14L8.5,11H16Z"/>';
22805      }
22806      
22807      // Restore text
22808      const label = cartBtn.querySelector('.pca-action-label');
22809      const desc = cartBtn.querySelector('.pca-action-desc');
22810      if (label) label.textContent = 'Tambah ke Keranjang';
22811      if (desc) desc.textContent = 'Lanjut belanja produk lain';
22812    }
22813  }
22814  
22815  /**
22816   * Update compare button state
22817   */
22818  function updateCompareButtonState(productId) {
22819    const compareBtn = document.getElementById('pca-add-compare');
22820    const compareBadge = document.getElementById('pca-compare-count');
22821    
22822    if (!compareBtn) return;
22823    
22824    // Check if product is in compare list (using global compareList if available)
22825    let isInCompare = false;
22826    let compareCount = 0;
22827    
22828    // Try to get compare list from product-compare.js via window.productCompare
22829    if (typeof window.productCompare !== 'undefined' && typeof window.productCompare.getCompareList === 'function') {
22830      const compareList = window.productCompare.getCompareList();
22831      compareCount = compareList.length;
22832      isInCompare = compareList.some(p => parseInt(p.id) === parseInt(productId));
22833    } else {
22834      // Fallback: check badge count
22835      const mainBadge = document.getElementById('compareCount');
22836      if (mainBadge) {
22837        compareCount = parseInt(mainBadge.textContent) || 0;
22838      }
22839    }
22840    
22841    // Update button state
22842    if (isInCompare) {
22843      compareBtn.classList.add('active');
22844      compareBtn.querySelector('.pca-action-label').textContent = 'Hapus dari Perbandingan';
22845      compareBtn.querySelector('.pca-action-desc').textContent = 'Sudah ada di daftar';
22846    } else {
22847      compareBtn.classList.remove('active');
22848      compareBtn.querySelector('.pca-action-label').textContent = 'Bandingkan Produk';
22849      compareBtn.querySelector('.pca-action-desc').textContent = 'Analisis dengan AI';
22850    }
22851    
22852    // Update badge
22853    if (compareBadge && compareCount > 0) {
22854      compareBadge.textContent = compareCount;
22855      compareBadge.style.display = 'inline-flex';
22856    } else if (compareBadge) {
22857      compareBadge.style.display = 'none';
22858    }
22859  }
22860  
22861  /**
22862   * Handle add to cart
22863   */
22864  async function handleAddToCart() {
22865    if (!activeProductData) return;
22866    
22867    const button = document.getElementById('pca-add-cart');
22868    if (!button) return;
22869    
22870    // If product has variants, redirect to detail page
22871    if (activeProductData.hasVariants) {
22872      window.location.href = activeProductData.url;
22873      return;
22874    }
22875    
22876    // Check stock
22877    if (activeProductData.stockStatus === 'out') {
22878      showToast('Produk sedang habis', 'warning');
22879      return;
22880    }
22881    
22882    // Show loading state
22883    button.classList.add('loading');
22884    button.disabled = true;
22885    
22886    // CSRF Token Helper
22887    function getCsrfToken() {
22888      return document.querySelector('meta[name="csrf-token"]')?.getAttribute('content') || '';
22889    }
22890    
22891    try {
22892      // Call cart API with proper format
22893      const response = await fetch('/api/cart/add.php', {
22894        method: 'POST',
22895        headers: {
22896          'Content-Type': 'application/json',
22897          'X-CSRF-Token': getCsrfToken()
22898        },
22899        body: JSON.stringify({
22900          csrf_token: getCsrfToken(),
22901          product_id: activeProductData.id,
22902          qty: 1, // Use 'qty' not 'quantity'
22903          variant_id: 0, // Default variant
22904          meta: {
22905            name: activeProductData.name,
22906            image_url: activeProductData.image
22907          }
22908        }),
22909        credentials: 'same-origin'
22910      });
22911      
22912      const result = await response.json();
22913      
22914      // Check both response status and result.ok
22915      if (!response.ok || !result.ok) {
22916        throw new Error(result.error || result.message || 'Gagal menambahkan ke keranjang');
22917      }
22918      
22919      // Success animation
22920      button.classList.remove('loading');
22921      button.classList.add('success');
22922      
22923      // Update cart badge
22924      updateCartBadge();
22925
22926      // PlazaAnalytics tracking
22927      if (window.PlazaAnalytics) {
22928        const _slug = (activeProductData.url || '').replace(/.*\/product\//, '');
22929        window.PlazaAnalytics.track('add_to_cart', { slug: _slug });
22930      }
22931
22932      // Show success toast
22933      showToast('Produk ditambahkan ke keranjang', 'success');
22934      
22935      // Google Analytics
22936      if (typeof gtag === 'function') {
22937        gtag('event', 'add_to_cart', {
22938          event_category: 'Ecommerce',
22939          event_label: 'Quick Add to Cart',
22940          items: [{
22941            item_id: activeProductData.id,
22942            item_name: activeProductData.name,
22943            price: activeProductData.price,
22944            quantity: 1
22945          }]
22946        });
22947      }
22948      
22949      // Close sheet after short delay
22950      setTimeout(() => {
22951        closeBottomSheet();
22952        button.classList.remove('success');
22953        button.disabled = false;
22954      }, 1000);
22955      
22956    } catch (error) {
22957      console.error('Add to cart error:', error);
22958      button.classList.remove('loading');
22959      button.disabled = false;
22960      showToast(error.message || 'Terjadi kesalahan', 'error');
22961    }
22962  }
22963  
22964  /**
22965   * Handle add to compare
22966   */
22967  async function handleAddToCompare() {
22968    if (!activeProductData) return;
22969    
22970    const button = document.getElementById('pca-add-compare');
22971    if (!button) return;
22972    
22973    // Check if already in compare
22974    const isActive = button.classList.contains('active');
22975    
22976    // Check 5-product limit before adding
22977    if (!isActive) {
22978      const mainBadge = document.getElementById('compareCount');
22979      const currentCount = mainBadge ? parseInt(mainBadge.textContent) || 0 : 0;
22980      
22981      if (currentCount >= 5) {
22982        showToast('Maksimal 5 produk untuk perbandingan', 'warning');
22983        return;
22984      }
22985    }
22986    
22987    // Show loading state
22988    button.classList.add('loading');
22989    button.disabled = true;
22990    
22991    try {
22992      if (isActive) {
22993        // Remove from compare
22994        await removeFromCompare(activeProductData.id);
22995        showToast('Produk dihapus dari perbandingan', 'success');
22996      } else {
22997        // Add to compare
22998        await addToCompare(activeProductData.id);
22999        showToast('Produk ditambahkan ke perbandingan', 'success');
23000        
23001        // Trigger fly animation
23002        triggerFlyToCompareAnimation();
23003      }
23004      
23005      // Success animation
23006      button.classList.remove('loading');
23007      button.classList.add('success');
23008      
23009      // Update compare button state
23010      updateCompareButtonState(activeProductData.id);
23011      
23012      // Close sheet after short delay
23013      setTimeout(() => {
23014        closeBottomSheet();
23015        button.classList.remove('success');
23016        button.disabled = false;
23017      }, 800);
23018      
23019    } catch (error) {
23020      console.error('Compare error:', error);
23021      button.classList.remove('loading');
23022      button.disabled = false;
23023      showToast(error.message || 'Terjadi kesalahan', 'error');
23024    }
23025  }
23026  
23027  /**
23028   * Add to compare (calls existing API)
23029   */
23030  async function addToCompare(productId) {
23031    const response = await fetch('/api/compare/add.php', {
23032      method: 'POST',
23033      headers: {
23034        'Content-Type': 'application/json',
23035      },
23036      body: JSON.stringify({
23037        product_id: productId,
23038        variant_id: 0
23039      }),
23040      credentials: 'same-origin'
23041    });
23042    
23043    const result = await response.json();
23044    
23045    if (!result.success) {
23046      throw new Error(result.error || 'Gagal menambahkan produk');
23047    }
23048    
23049    // Trigger compare list reload if function exists
23050    if (typeof window.productCompare !== 'undefined' && typeof window.productCompare.loadCompareList === 'function') {
23051      await window.productCompare.loadCompareList();
23052    }
23053    
23054    return result;
23055  }
23056  
23057  /**
23058   * Remove from compare (calls existing API)
23059   */
23060  async function removeFromCompare(productId) {
23061    const response = await fetch('/api/compare/remove.php', {
23062      method: 'POST',
23063      headers: {
23064        'Content-Type': 'application/json',
23065      },
23066      body: JSON.stringify({
23067        product_id: productId
23068      }),
23069      credentials: 'same-origin'
23070    });
23071    
23072    const result = await response.json();
23073    
23074    if (!result.success) {
23075      throw new Error(result.error || 'Gagal menghapus produk');
23076    }
23077    
23078    // Trigger compare list reload if function exists
23079    if (typeof window.productCompare !== 'undefined' && typeof window.productCompare.loadCompareList === 'function') {
23080      await window.productCompare.loadCompareList();
23081    }
23082    
23083    return result;
23084  }
23085  
23086  /**
23087   * Update cart badge
23088   */
23089  function updateCartBadge() {
23090    // Try to call global cart update function if exists
23091    if (typeof window.updateCartBadge === 'function') {
23092      window.updateCartBadge();
23093    } else {
23094      // Fallback: increment badge manually
23095      const badge = document.getElementById('cartCount');
23096      if (badge) {
23097        const currentCount = parseInt(badge.textContent) || 0;
23098        badge.textContent = currentCount + 1;
23099        badge.classList.add('active');
23100      }
23101    }
23102  }
23103  
23104  /**
23105   * Trigger fly to compare animation
23106   */
23107  function triggerFlyToCompareAnimation() {
23108    const compareBtn = document.getElementById('compareBtn');
23109    if (!compareBtn || !activeProductData) return;
23110    
23111    // Create flying element
23112    const flyingElement = document.createElement('div');
23113    flyingElement.className = 'flying-product';
23114    flyingElement.style.cssText = `
23115      position: fixed;
23116      width: 60px;
23117      height: 60px;
23118      z-index: 99999;
23119      pointer-events: none;
23120    `;
23121    
23122    flyingElement.innerHTML = `
23123      <img src="${activeProductData.image}" 
23124           style="width:100%;height:100%;object-fit:cover;border-radius:8px;box-shadow:0 4px 12px rgba(0,0,0,0.3);">
23125    `;
23126    
23127    // Position at bottom sheet
23128    const sheetRect = bottomSheet.getBoundingClientRect();
23129    const targetRect = compareBtn.getBoundingClientRect();
23130    
23131    flyingElement.style.top = `${sheetRect.top + 20}px`;
23132    flyingElement.style.left = `${sheetRect.left + 20}px`;
23133    
23134    document.body.appendChild(flyingElement);
23135    
23136    // Animate to target
23137    requestAnimationFrame(() => {
23138      flyingElement.style.transition = 'all 0.8s cubic-bezier(0.25, 0.46, 0.45, 0.94)';
23139      flyingElement.style.top = `${targetRect.top + 10}px`;
23140      flyingElement.style.left = `${targetRect.left + 10}px`;
23141      flyingElement.style.transform = 'scale(0.3)';
23142      flyingElement.style.opacity = '0';
23143    });
23144    
23145    // Clean up
23146    setTimeout(() => {
23147      if (flyingElement.parentNode) {
23148        flyingElement.parentNode.removeChild(flyingElement);
23149      }
23150    }, 800);
23151  }
23152  
23153  /**
23154   * Format price as Rupiah
23155   */
23156  function formatPrice(price) {
23157    if (!price || price === 0) return 'Rp 0';
23158    return 'Rp ' + parseInt(price).toLocaleString('id-ID');
23159  }
23160  
23161  /**
23162   * Escape HTML
23163   */
23164  function escapeHtml(text) {
23165    const div = document.createElement('div');
23166    div.textContent = text;
23167    return div.innerHTML;
23168  }
23169  
23170  /**
23171   * Show toast notification (uses global showToast if available)
23172   */
23173  function showToast(message, type = 'info') {
23174    if (typeof window.showToast === 'function') {
23175      window.showToast({
23176        title: type === 'success' ? 'Berhasil' : type === 'error' ? 'Gagal' : 'Info',
23177        message: message,
23178        type: type,
23179        duration: 3000
23180      });
23181    } else {
23182      // Fallback: console log
23183      console.log(`[${type.toUpperCase()}] ${message}`);
23184    }
23185  }
23186  
23187  /**
23188   * Expose functions for external access
23189   */
23190  window.ProductCardActions = {
23191    openSheet: openBottomSheet,
23192    closeSheet: closeBottomSheet,
23193    updateCompareState: updateCompareButtonState
23194  };
23195  
23196})();
23197
23198</script>
23198
23199    
23199<script data-inlined="product-reviews.js">
23200/**
23201 * Product Reviews - Frontend JavaScript
23202 * Handles review display, submission, and helpful voting
23203 */
23204
23205const ProductReviews = (function() {
23206  'use strict';
23207
23208  let currentPage = 1;
23209  let currentSort = 'helpful';
23210  let productId = null;
23211  let isLoading = false;
23212
23213  /**
23214   * Public API: Initialize reviews for a product
23215   */
23216  function init(pid) {
23217    productId = pid;
23218    
23219    if (!productId) {
23220      console.warn('Product ID not provided to ProductReviews.init()');
23221      return;
23222    }
23223
23224    initializeReviewTab();
23225    loadReviews();
23226  }
23227
23228  /**
23229   * Initialize review tab functionality
23230   */
23231  function initializeReviewTab() {
23232    // Tab switching
23233    const tabButtons = document.querySelectorAll('.tab-btn');
23234    tabButtons.forEach(btn => {
23235      btn.addEventListener('click', function() {
23236        const tabName = this.dataset.tab;
23237        switchTab(tabName);
23238      });
23239    });
23240
23241    // Sort dropdown
23242    const sortSelect = document.getElementById('review-sort');
23243    if (sortSelect) {
23244      sortSelect.addEventListener('change', function() {
23245        currentSort = this.value;
23246        currentPage = 1;
23247        loadReviews();
23248      });
23249    }
23250
23251    // Load more button
23252    const loadMoreBtn = document.getElementById('load-more-reviews');
23253    if (loadMoreBtn) {
23254      loadMoreBtn.addEventListener('click', function() {
23255        currentPage++;
23256        loadReviews(true); // Append mode
23257      });
23258    }
23259
23260    // Write review button
23261    const writeReviewBtn = document.getElementById('write-review-btn');
23262    if (writeReviewBtn) {
23263      writeReviewBtn.addEventListener('click', showReviewModal);
23264    }
23265  }
23266
23267  /**
23268   * Switch between product tabs
23269   */
23270  function switchTab(tabName) {
23271    // Update button states
23272    document.querySelectorAll('.tab-btn').forEach(btn => {
23273      btn.classList.toggle('active', btn.dataset.tab === tabName);
23274    });
23275
23276    // Update content visibility
23277    document.querySelectorAll('.tab-content').forEach(content => {
23278      content.style.display = content.id === `${tabName}-tab` ? 'block' : 'none';
23279    });
23280  }
23281
23282  /**
23283   * Load reviews from API
23284   */
23285  async function loadReviews(append = false) {
23286    if (isLoading) return;
23287    isLoading = true;
23288
23289    const container = document.getElementById('reviews-list');
23290    const loadMoreBtn = document.getElementById('load-more-reviews');
23291
23292    // Check if review section exists (product might not have reviews section)
23293    if (!container) {
23294      console.log('Review section not found - product may not have reviews yet');
23295      isLoading = false;
23296      return;
23297    }
23298
23299    try {
23300      if (!append) {
23301        container.innerHTML = '<div class="review-loading">Memuat ulasan...</div>';
23302      } else {
23303        loadMoreBtn.disabled = true;
23304        loadMoreBtn.textContent = 'Memuat...';
23305      }
23306
23307      const response = await fetch(`/api/reviews/list.php?product_id=${productId}&sort=${currentSort}&page=${currentPage}&limit=10`);
23308      const data = await response.json();
23309
23310      if (!data.success) {
23311        throw new Error(data.message || 'Gagal memuat ulasan');
23312      }
23313
23314      // Update statistics (only on initial load)
23315      if (!append && data.stats) {
23316        updateReviewStats(data.stats);
23317      }
23318
23319      // Render reviews
23320      if (!append) {
23321        container.innerHTML = '';
23322      }
23323
23324      const reviews = data.reviews || [];
23325      
23326      if (reviews.length === 0 && !append) {
23327        container.innerHTML = '<div class="no-reviews">Belum ada ulasan untuk produk ini. Jadilah yang pertama!</div>';
23328      } else {
23329        reviews.forEach(review => {
23330          container.appendChild(createReviewElement(review));
23331        });
23332      }
23333
23334      // Update load more button
23335      if (loadMoreBtn) {
23336        if (data.pagination.has_more) {
23337          loadMoreBtn.style.display = 'block';
23338          loadMoreBtn.disabled = false;
23339          loadMoreBtn.textContent = 'Muat Lebih Banyak';
23340        } else {
23341          loadMoreBtn.style.display = 'none';
23342        }
23343      }
23344
23345    } catch (error) {
23346      console.error('Load reviews error:', error);
23347      container.innerHTML = '<div class="review-error">Gagal memuat ulasan. Silakan coba lagi.</div>';
23348    } finally {
23349      isLoading = false;
23350    }
23351  }
23352
23353  /**
23354   * Update review statistics display
23355   */
23356  function updateReviewStats(stats) {
23357    const avgRatingEl = document.getElementById('avg-rating');
23358    const totalReviewsEl = document.getElementById('total-reviews');
23359    const ratingBarsContainer = document.getElementById('rating-bars');
23360
23361    if (avgRatingEl) {
23362      avgRatingEl.textContent = stats.average_rating.toFixed(1);
23363    }
23364
23365    if (totalReviewsEl) {
23366      totalReviewsEl.textContent = `${stats.total_reviews} ulasan`;
23367    }
23368
23369    // Update rating breakdown bars
23370    if (ratingBarsContainer) {
23371      ratingBarsContainer.innerHTML = '';
23372      stats.rating_breakdown.forEach(item => {
23373        const bar = document.createElement('div');
23374        bar.className = 'rating-bar';
23375        bar.innerHTML = `
23376          <span class="rating-label">${item.rating}★</span>
23377          <div class="bar-container">
23378            <div class="bar-fill" style="width: ${item.percentage}%"></div>
23379          </div>
23380          <span class="rating-count">${item.count}</span>
23381        `;
23382        ratingBarsContainer.appendChild(bar);
23383      });
23384    }
23385
23386    // Update tab count
23387    const reviewTab = document.querySelector('[data-tab="reviews"]');
23388    if (reviewTab && stats.total_reviews > 0) {
23389      reviewTab.textContent = `Ulasan (${stats.total_reviews})`;
23390    }
23391  }
23392
23393  /**
23394   * Create review element
23395   */
23396  function createReviewElement(review) {
23397    const div = document.createElement('div');
23398    div.className = 'review-item';
23399    div.dataset.reviewId = review.ID;
23400
23401    // Build stars
23402    const stars = '★'.repeat(review.RATING) + '☆'.repeat(5 - review.RATING);
23403
23404    // Build images if available
23405    let imagesHtml = '';
23406    if (review.images && review.images.length > 0) {
23407      imagesHtml = '<div class="review-images">';
23408      review.images.forEach(img => {
23409        imagesHtml += `<img src="${escapeHtml(img)}" alt="Review image" class="review-img" loading="lazy">`;
23410      });
23411      imagesHtml += '</div>';
23412    }
23413
23414    // Verified purchase badge
23415    const verifiedBadge = review.IS_VERIFIED_PURCHASE === 'Y' 
23416      ? '<span class="verified-badge">✓ Pembelian Terverifikasi</span>' 
23417      : '';
23418    
23419    // Use DISPLAY_NAME if available (for anonymous reviews), otherwise use FULL_NAME
23420    const displayName = review.DISPLAY_NAME || review.FULL_NAME || 'Anonymous';
23421    const anonymousIndicator = review.IS_ANONYMOUS === 'Y' 
23422      ? '<span class="anonymous-badge" title="Nama pengguna disamark
23422an untuk privasi">🔒</span>' 
23423      : '';
23424
23425    div.innerHTML = `
23426      <div class="review-header">
23427        <div class="review-author">
23428          <strong>${escapeHtml(displayName)}</strong>
23429          ${anonymousIndicator}
23430          ${verifiedBadge}
23431        </div>
23432        <div class="review-rating">
23433          <span class="stars">${stars}</span>
23434        </div>
23435      </div>
23436      <div class="review-date">${review.created_ago}</div>
23437      <div class="review-text">${escapeHtml(review.REVIEW_TEXT).replace(/\n/g, '<br>')}</div>
23438      ${imagesHtml}
23439      <div class="review-actions">
23440        <button class="btn-helpful" data-review-id="${review.ID}">
23441          <span class="helpful-icon">👍</span>
23442          <span class="helpful-text">Membantu (${review.HELPFUL_COUNT || 0})</span>
23443        </button>
23444      </div>
23445    `;
23446
23447    // Add helpful button listener
23448    const helpfulBtn = div.querySelector('.btn-helpful');
23449    helpfulBtn.addEventListener('click', () => markAsHelpful(review.ID));
23450
23451    return div;
23452  }
23453
23454  /**
23455   * Get CSRF token from meta tag
23456   */
23457  function getCsrfToken() {
23458    const metaTag = document.querySelector('meta[name="csrf-token"]');
23459    return metaTag ? metaTag.getAttribute('content') : '';
23460  }
23461
23462  /**
23463   * Mark review as helpful
23464   */
23465  async function markAsHelpful(reviewId) {
23466    // Check if logged in
23467    const isLoggedIn = document.body.classList.contains('logged-in') || 
23468                      document.querySelector('meta[name="user-logged-in"]')?.content === 'true';
23469
23470    if (!isLoggedIn) {
23471      showModal({
23472        title: 'Login Diperlukan',
23473        message: 'Silakan login terlebih dahulu untuk memberikan vote pada ulasan ini.',
23474        icon: 'info',
23475        buttons: [
23476          { text: 'Batal', className: 'modal-btn-secondary' },
23477          { text: 'Login', className: 'modal-btn-primary', callback: () => window.location.href = '/login' }
23478        ]
23479      });
23480      return;
23481    }
23482
23483    // Get current button element
23484    const reviewItem = document.querySelector(`[data-review-id="${reviewId}"]`);
23485    const helpfulBtn = reviewItem?.querySelector('.btn-helpful');
23486    
23487    if (!helpfulBtn) return;
23488    
23489    // Disable button during request
23490    helpfulBtn.disabled = true;
23491    const originalText = helpfulBtn.querySelector('.helpful-text').textContent;
23492
23493    try {
23494      const response = await fetch('/api/reviews/helpful.php', {
23495        method: 'POST',
23496        headers: { 
23497          'Content-Type': 'application/json',
23498          'X-CSRF-Token': getCsrfToken()
23499        },
23500        credentials: 'same-origin',
23501        body: JSON.stringify({ 
23502          csrf_token: getCsrfToken(),
23503          review_id: reviewId 
23504        })
23505      });
23506
23507      const data = await response.json();
23508
23509      if (data.success) {
23510        // Update button count immediately based on action
23511        const currentCount = parseInt(originalText.match(/\d+/)?.[0] || 0);
23512        const newCount = data.action === 'added' ? currentCount + 1 : currentCount - 1;
23513        helpfulBtn.querySelector('.helpful-text').textContent = `Membantu (${newCount})`;
23514        
23515        // Show success message
23516        showToast(data.message, 'success');
23517        
23518        // Re-enable button
23519        helpfulBtn.disabled = false;
23520      } else {
23521        showToast(data.message, 'error');
23522        helpfulBtn.disabled = false;
23523      }
23524
23525    } catch (error) {
23526      console.error('Mark helpful error:', error);
23527      showToast('Gagal memberikan vote. Silakan coba lagi.', 'error');
23528      helpfulBtn.disabled = false;
23529    }
23530  }
23531
23532  /**
23533   * Show review submission modal (placeholder)
23534   */
23535  function showReviewModal() {
23536    // TODO: Implement review modal
23537    // For now, redirect to account page
23538    window.location.href = '/account/orders';
23539  }
23540
23541  /**
23542   * Show toast notification
23543   */
23544  function showToast(message, type = 'info') {
23545    const toast = document.createElement('div');
23546    toast.className = `review-toast toast-${type}`;
23547    toast.textContent = message;
23548    
23549    document.body.appendChild(toast);
23550    
23551    setTimeout(() => {
23552      toast.classList.add('show');
23553    }, 100);
23554    
23555    setTimeout(() => {
23556      toast.classList.remove('show');
23557      setTimeout(() => toast.remove(), 300);
23558    }, 3000);
23559  }
23560
23561  /**
23562   * Show modal dialog
23563   * @param {Object} options - Modal options
23564   * @param {string} options.title - Modal title
23565   * @param {string} options.message - Modal message
23566   * @param {string} options.icon - Icon type (info, success, warning, danger)
23567   * @param {Array} options.buttons - Array of button objects {text, className, callback}
23568   */
23569  function showModal(options) {
23570    const {
23571      title = 'Konfirmasi',
23572      message = '',
23573      icon = 'info',
23574      buttons = [{ text: 'OK', className: 'modal-btn-primary' }]
23575    } = options;
23576
23577    // Icon emoji mapping
23578    const iconEmojis = {
23579      info: 'ℹ️',
23580      success: '✓',
23581      warning: '⚠️',
23582      danger: '✕'
23583    };
23584
23585    // Create modal HTML
23586    const modalHTML = `
23587      <div class="modal-overlay" id="helpful-vote-modal" style="display: flex !important; align-items: center !important; justify-content: center !important;">
23588        <div class="modal-dialog">
23589          <div class="modal-header">
23590            <h3 class="modal-title">
23591              <span class="modal-icon ${icon}">${iconEmojis[icon] || iconEmojis.info}</span>
23592              ${escapeHtml(title)}
23593            </h3>
23594          </div>
23595          <div class="modal-body">
23596            <p class="modal-message">${escapeHtml(message)}</p>
23597            <div class="modal-actions">
23598              ${buttons.map((btn, index) => 
23599                `<button class="modal-btn ${btn.className || 'modal-btn-secondary'}" data-index="${index}">${escapeHtml(btn.text)}</button>`
23600              ).join('')}
23601            </div>
23602          </div>
23603        </div>
23604      </div>
23605    `;
23606
23607    // Append to body
23608    const tempDiv = document.createElement('div');
23609    tempDiv.innerHTML = modalHTML;
23610    const modal = tempDiv.firstElementChild;
23611    document.body.appendChild(modal);
23612
23613    // Add event listeners to buttons
23614    buttons.forEach((btn, index) => {
23615      const btnElement = modal.querySelector(`[data-index="${index}"]`);
23616      btnElement.addEventListener('click', () => {
23617        closeModal(modal);
23618        if (btn.callback && typeof btn.callback === 'function') {
23619          btn.callback();
23620        }
23621      });
23622    });
23623
23624    // Close on overlay click
23625    modal.addEventListener('click', (e) => {
23626      if (e.target === modal) {
23627        closeModal(modal);
23628      }
23629    });
23630
23631    // Show modal with animation
23632    setTimeout(() => modal.classList.add('show'), 10);
23633  }
23634
23635  /**
23636   * Close modal dialog
23637   */
23638  function closeModal(modal) {
23639    modal.classList.remove('show');
23640    setTimeout(() => modal.remove(), 200);
23641  }
23642
23643  /**
23644   * Escape HTML for XSS protection
23645   */
23646  function escapeHtml(text) {
23647    const div = document.createElement('div');
23648    div.textContent = text;
23649    return div.innerHTML;
23650  }
23651
23652  /**
23653   * Get product ID from URL
23654   */
23655  function getProductIdFromUrl() {
23656    const match = window.location.pathname.match(/\/product\/(\d+)/);
23657    return match ? match[1] : null;
23658  }
23659
23660  // Public API
23661  return {
23662    init: init
23663  };
23664
23665})();
23666
23667</script>
23667
23668    
23668<script data-inlined="review-submission.js">
23669/**
23670 * Review Submission Modal & Handler
23671 * Handles review form display, validation, and submission
23672 */
23673
23674(function() {
23675    'use strict';
23676
23677    let currentProductId = null;
23678    let currentOrderId = null;
23679    let currentSoRefId = null;
23680    let selectedRating = 0;
23681    let uploadedImages = [];
23682
23683    // Get CSRF token from meta tag
23684    function getCsrfToken() {
23685        const metaTag = document.querySelector('meta[name="csrf-token"]');
23686        return metaTag ? metaTag.getAttribute('content') : '';
23687    }
23688
23689    // Initialize
23690    function init() {
23691        createReviewModal();
23692        attachEventListeners();
23693        loadReviewableOrders();
23694    }
23695
23696    // Create review modal HTML
23697    function createReviewModal() {
23698        const modalHTML = `
23699            <div class="modal-overlay" id="review-modal-overlay" style="display:none;">
23700                <div class="modal-content review-modal">
23701                    <div class="modal-header">
23702                        <h3 class="modal-title">Tulis Ulasan</h3>
23703                        <button type="button" class="modal-close" id="review-modal-close" aria-label="Tutup">
23704                            <svg width="20" height="20" viewBox="0 0 24 24">
23705                                <path fill="currentColor" d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/>
23706                            </svg>
23707                        </button>
23708                    </div>
23709                    
23710                    <div class="modal-body">
23711                        <form id="review-form" class="review-form">
23712                            <!-- Product Info -->
23713                            <div class="review-product-info" id="review-product-info">
23714                                <img id="review-product-image" src="" alt="" class="review-product-thumb">
23715                                <div class="review-product-details">
23716                                    <h4 id="review-product-name"></h4>
23717                                    <p id="review-product-sku"></p>
23718                                </div>
23719                            </div>
23720
23721                            <!-- Rating -->
23722                            <div class="form-group">
23723                                <label class="form-label">Rating <span style="color:#C77DFF;">*</span></label>
23724                                <div class="star-rating-input" id="star-rating-input">
23725                                    <button type="button" class="star-btn" data-rating="1">★</button>
23726                                    <button type="button" class="star-btn" data-rating="2">★</button>
23727                                    <button type="button" class="star-btn" data-rating="3">★</button>
23728                                    <button type="button" class="star-btn" data-rating="4">★</button>
23729                                    <button type="button" class="star-btn" data-rating="5">★</button>
23730                                </div>
23731                                <p class="rating-label" id="rating-label">Pilih rating Anda</p>
23732                            </div>
23733
23734                            <!-- Review Text -->
23735                            <div class="form-group">
23736                                <label class="form-label" for="review-text">Ulasan Anda <span style="color:#C77DFF;">*</span></label>
23737                                <textarea 
23738                                    id="review-text" 
23739                                    name="review_text"
23740                                    class="form-control" 
23741                                    rows="6" 
23742                                    placeholder="Ceritakan pengalaman Anda dengan produk ini..."
23743                                    minlength="20"
23744                                    maxlength="5000"
23745                                    required></textarea>
23746                                <p class="form-hint">
23747                                    <span id="review-char-count">0</span>/5000 karakter
23748                                    <span style="color:#059669;font-weight:500;">
23749                                        💰 +1,000 point untuk ulasan ≥ 100 karakter
23750                                    </span>
23751                                </p>
23752                            </div>
23753
23754                            <!-- Image Upload -->
23755                            <div class="form-group">
23756                                <label class="form-label">Upload Foto (Opsional)</label>
23757                                <div class="image-upload-container">
23758                                    <input type="file" 
23759                                           id="review-images" 
23760                                           name="images[]" 
23761                                           accept="image/jpeg,image/jpg,image/png,image/webp"
23762                                           multiple
23763                                           style="display:none;">
23764                                    <button type="button" class="btn-upload-trigger" id="upload-trigger">
23765                                        <svg width="24" height="24" viewBox="0 0 24 24">
23766                                            <path fill="currentColor" d="M19 7v2.99s-1.99.01-2 0V7h-3s.01-1.99 0-2h3V2h2v3h3v2h-3zm-3 4V8h-3V5H5c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2v-8h-3zM5 19l3-4 2 3 3-4 4 5H5z"/>
23767                                        </svg>
23768                                        <span>Pilih Foto</span>
23769                                    </button>
23770                                    <p class="form-hint">
23771                                        Max 5 foto, format JPG/PNG/WebP, max 2MB per foto
23772                                        <span style="color:#059669;font-weight:500;">
23773                                            💰 +2,000 point untuk ulasan dengan foto
23774                                        </span>
23775                                    </p>
23776                                </div>
23777                                <div class="image-preview-grid" id="image-preview-grid"></div>
23778                            </div>
23779
23780                            <!-- Point Reward Info -->
23781                            <div class="point-reward-info">
23782                                <div class="pri-header">
23783                                    <span>🎁</span>
23784                                    <span>Dapatkan Point Reward</span>
23785                                </div>
23786                                <ul class="pri-list">
23787                                    <li>✅ Ulasan dasar: <strong>5,000 point</strong></li>
23788                                    <li id="pri-long-text" style="opacity:0.5;">📝 Ulasan panjang (≥100 kata): <strong>+1,000 point</strong></li>
23789                                    <li id="pri-images" style="opacity:0.5;">📸 Dengan foto: <strong>+2,000 point</strong></li>
23790                                </ul>
23791                                <div class="pri-total">
23792                                    Total Reward: <strong id="pri-total-points">5,000 point</strong>
23793                                </div>
23794                            </div>
23795
23796                            <!-- Privacy Option -->
23797                            <div class="form-group" style="margin-top:20px;padding:15px;background:#f8fafc;border-radius:8px;">
23798                                <label class="checkbox-label" style="display:flex;align-items:center;cursor:pointer;margin:0;">
23799                                    <input type="checkbox" 
23800                                           id="review-anonymous" 
23801                                           name="is_anonymous"
23802                                           style="margin-right:8px;width:18px;height:18px;cursor:pointer;">
23803                                    <span style="font-size:14px;">
23804                                        <strong>🔒 Sembunyikan nama saya</strong>
23805                                        <span style="color:#64748b;display:block;font-size:13px;margin-top:4px;" id="review-anonymous-preview">
23806                                            Nama Anda akan ditampilkan de
23806ngan disamarkan untuk menjaga privasi
23807                                        </span>
23808                                    </span>
23809                                </label>
23810                            </div>
23811
23812                            <!-- Error Alert -->
23813                            <div class="form-error" id="review-form-error" style="display:none;"></div>
23814
23815                            <!-- Submit Buttons -->
23816                            <div class="modal-footer">
23817                                <button type="button" class="btn btn-secondary" id="review-cancel">Batal</button>
23818                                <button type="submit" class="btn btn-primary" id="review-submit">
23819                                    Kirim Ulasan
23820                                </button>
23821                            </div>
23822                        </form>
23823                    </div>
23824                </div>
23825            </div>
23826        `;
23827
23828        document.body.insertAdjacentHTML('beforeend', modalHTML);
23829    }
23830
23831    // Attach event listeners
23832    function attachEventListeners() {
23833        // Modal triggers - event delegation
23834        document.addEventListener('click', function(e) {
23835            const btn = e.target.closest('.btn-write-review');
23836            if (btn) {
23837                e.preventDefault();
23838                openReviewModal(
23839                    btn.dataset.productId,
23840                    btn.dataset.orderId,
23841                    btn.dataset.productName,
23842                    btn.dataset.productImage,
23843                    btn.dataset.productSku,
23844                    btn.dataset.soRefId || null
23845                );
23846            }
23847        });
23848
23849        // Close modal
23850        setTimeout(() => {
23851            const closeBtn = document.getElementById('review-modal-close');
23852            const cancelBtn = document.getElementById('review-cancel');
23853            const overlay = document.getElementById('review-modal-overlay');
23854
23855            if (closeBtn) {
23856                closeBtn.addEventListener('click', closeReviewModal);
23857            }
23858            if (cancelBtn) {
23859                cancelBtn.addEventListener('click', closeReviewModal);
23860            }
23861            if (overlay) {
23862                overlay.addEventListener('click', function(e) {
23863                    if (e.target === overlay) closeReviewModal();
23864                });
23865            }
23866        }, 100);
23867
23868        // Star rating
23869        setTimeout(() => {
23870            const starButtons = document.querySelectorAll('.star-btn');
23871            starButtons.forEach(btn => {
23872                btn.addEventListener('click', function(e) {
23873                    e.preventDefault();
23874                    const rating = parseInt(this.dataset.rating);
23875                    setRating(rating);
23876                });
23877            });
23878        }, 100);
23879
23880        // Character count
23881        setTimeout(() => {
23882            const textarea = document.getElementById('review-text');
23883            if (textarea) {
23884                textarea.addEventListener('input', function() {
23885                    updateCharCount();
23886                    calculatePotentialPoints();
23887                });
23888            }
23889        }, 100);
23890
23891        // Image upload
23892        setTimeout(() => {
23893            const uploadTrigger = document.getElementById('upload-trigger');
23894            const fileInput = document.getElementById('review-images');
23895            
23896            if (uploadTrigger && fileInput) {
23897                uploadTrigger.addEventListener('click', () => fileInput.click());
23898                fileInput.addEventListener('change', handleImageSelection);
23899            }
23900        }, 100);
23901
23902        // Form submit
23903        setTimeout(() => {
23904            const form = document.getElementById('review-form');
23905            if (form) {
23906                form.addEventListener('submit', handleSubmit);
23907            }
23908        }, 100);
23909    }
23910
23911    // Open review modal
23912    function openReviewModal(productId, orderId, productName, productImage, productSku, soRefId = null) {
23913        const overlay = document.getElementById('review-modal-overlay');
23914        if (!overlay) {
23915            console.error('Modal overlay not found!');
23916            return;
23917        }
23918        
23919        currentProductId = productId;
23920        currentOrderId = orderId;
23921        currentSoRefId = soRefId;
23922        selectedRating = 0;
23923        uploadedImages = [];
23924
23925        // Set product info
23926        const nameEl = document.getElementById('review-product-name');
23927        const imageEl = document.getElementById('review-product-image');
23928        const skuEl = document.getElementById('review-product-sku');
23929        
23930        if (nameEl) nameEl.textContent = productName;
23931        if (imageEl) imageEl.src = productImage || '/assets/img/no-image.png';
23932        if (skuEl) skuEl.textContent = 'SKU: ' + productSku;
23933
23934        // Update privacy preview with actual user name
23935        updatePrivacyPreview();
23936
23937        // Reset form
23938        const form = document.getElementById('review-form');
23939        const previewGrid = document.getElementById('image-preview-grid');
23940        const errorEl = document.getElementById('review-form-error');
23941        
23942        if (form) form.reset();
23943        if (previewGrid) previewGrid.innerHTML = '';
23944        if (errorEl) errorEl.style.display = 'none';
23945        
23946        setRating(0);
23947        updateCharCount();
23948        calculatePotentialPoints();
23949
23950        // Show modal
23951        overlay.style.display = 'flex';
23952        overlay.classList.add('show');
23953        document.body.style.overflow = 'hidden';
23954    }
23955
23956    // Close review modal
23957    function closeReviewModal() {
23958        const overlay = document.getElementById('review-modal-overlay');
23959        if (overlay) {
23960            overlay.classList.remove('show');
23961            setTimeout(() => {
23962                overlay.style.display = 'none';
23963            }, 200); // Wait for fade animation
23964        }
23965        document.body.style.overflow = '';
23966    }
23967
23968    // Set star rating
23969    function setRating(rating) {
23970        selectedRating = rating;
23971        const stars = document.querySelectorAll('.star-btn');
23972        const labels = ['', 'Sangat Buruk', 'Buruk', 'Cukup', 'Bagus', 'Sangat Bagus'];
23973        
23974        stars.forEach((star, index) => {
23975            if (index < rating) {
23976                star.classList.add('active');
23977            } else {
23978                star.classList.remove('active');
23979            }
23980        });
23981
23982        document.getElementById('rating-label').textContent = labels[rating] || 'Pilih rating Anda';
23983    }
23984
23985    // Update character count
23986    function updateCharCount() {
23987        const textarea = document.getElementById('review-text');
23988        const count = textarea.value.length;
23989        document.getElementById('review-char-count').textContent = count;
23990    }
23991
23992    // Calculate potential points
23993    function calculatePotentialPoints() {
23994        const textarea = document.getElementById('review-text');
23995        if (!textarea) return;
23996        
23997        const charCount = textarea.value.trim().length;
23998        const hasImages = uploadedImages.length > 0;
23999
24000        let totalPoints = 5000;
24001        let longTextActive = charCount >= 100;
24002        let imagesActive = hasImages;
24003
24004        if (longTextActive) totalPoints += 1000;
24005        if (imagesActive) totalPoints += 2000;
24006
24007        // Update UI
24008        const longTextEl = document.getElementById('pri-long-text');
24009        const imagesEl = document.getElementById('pri-images');
24010        const totalEl = document.getElementById('pri-total-points');
24011        
24012        if (longTextEl) longTextEl.style.opacity = longTextActive ? '1' : '0.5';
24013        if (imagesEl) imagesEl.style.opacity = imagesActive ? '1' : '0.5';
24014        if (totalEl) totalEl.textContent = totalPoints.toLocaleString('id-ID') + ' point';
24015    }
24016
24017    // Handle image selection
24018    function handleImageSelection(e) {
24019        const files = Array.from(e.target.files);
24020        
24021        if (files.length > 5) {
24022            showError('Maksimal 5 foto yang dapat diupload');
24023            e.target.value = ''; // Reset input
24024            return;
24025        }
24026
24027        uploadedImages = [];
24028        const previewGrid = document.getElementById('image-preview-grid');
24029        previewGrid.innerHTML = '';
24030
24031        files.forEach((file, index) => {
24032            // Validate file type
24033            if (!file.type.match(/image\/(jpeg|jpg|png|webp)/)) {
24034                showError('Format file harus JPG, PNG, atau WebP');
24035                return;
24036            }
24037
24038            // Validate file size (2MB)
24039            if (file.size > 2 * 1024 * 1024) {
24040                showError('Ukuran file maksimal 2MB');
24041                return;
24042            }
24043
24044            uploadedImages.push(file);
24045
24046            // Create preview
24047            const reader = new FileReader();
24048            reader.onload = function(e) {
24049                const previewHTML = `
24050                    <div class="image-preview-item">
24051                        <img src="${e.target.result}" alt="Preview ${index + 1}">
24052                        <button type="button" class="remove-image" data-index="${index}" aria-label="Hapus">
24053                            <svg width="16" height="16" viewBox="0 0 24 24">
24054                                <path fill="currentColor" d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/>
24055                            </svg>
24056                        </button>
24057                    </div>
24058                `;
24059                previewGrid.insertAdjacentHTML('beforeend', previewHTML);
24060            };
24061            reader.readAsDataURL(file);
24062        });
24063
24064        calculatePotentialPoints();
24065
24066        // Attach remove handlers
24067        setTimeout(() => {
24068            document.querySelectorAll('.remove-image').forEach(btn => {
24069                btn.addEventListener('click', function() {
24070                    const index = parseInt(this.dataset.index);
24071                    removeImage(index);
24072                });
24073            });
24074        }, 100);
24075    }
24076
24077    // Remove image
24078    function removeImage(index) {
24079        uploadedImages.splice(index, 1);
24080        
24081        const previewGrid = document.getElementById('image-preview-grid');
24082        previewGrid.innerHTML = '';
24083
24084        uploadedImages.forEach((file, idx) => {
24085            const reader = new FileReader();
24086            reader.onload = function(e) {
24087                const previewHTML = `
24088                    <div class="image-preview-item">
24089                        <img src="${e.target.result}" alt="Preview ${idx + 1}">
24090                        <button type="button" class="remove-image" data-index="${idx}" aria-label="Hapus">
24091                            <svg width="16" height="16" viewBox="0 0 24 24">
24092                                <path fill="currentColor" d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/>
24093                            </svg>
24094                        </button>
24095                    </div>
24096                `;
24097                previewGrid.insertAdjacentHTML('beforeend', previewHTML);
24098            };
24099            reader.readAsDataURL(file);
24100        });
24101
24102        calculatePotentialPoints();
24103
24104        setTimeout(() => {
24105            document.querySelectorAll('.remove-image').forEach(btn => {
24106                btn.addEventListener('click', function() {
24107                    const idx = parseInt(this.dataset.index);
24108                    removeImage(idx);
24109                });
24110            });
24111        }, 100);
24112    }
24113
24114    // Handle form submission
24115    async function handleSubmit(e) {
24116        e.preventDefault();
24117
24118        // Validate
24119        if (selectedRating === 0) {
24120            showError('Silakan pilih rating terlebih dahulu');
24121            return;
24122        }
24123
24124        const reviewText = document.getElementById('review-text').value.trim();
24125        if (reviewText.length < 20) {
24126            showError('Ulasan minimal 20 karakter');
24127            return;
24128        }
24129
24130        const submitBtn = document.getElementById('review-submit');
24131        submitBtn.disabled = true;
24132        
24133        try {
24134            // Step 1: Upload images if any
24135            let imageUrls = [];
24136            if (uploadedImages.length > 0) {
24137                submitBtn.textContent = 'Mengupload foto...';
24138                imageUrls = await uploadImages();
24139                if (!imageUrls) {
24140                    // Upload failed
24141                    submitBtn.disabled = false;
24142                    submitBtn.textContent = 'Kirim Ulasan';
24143                    return;
24144                }
24145            }
24146
24147            // Step 2: Submit review with image URLs
24148            submitBtn.textContent = 'Mengirim ulasan...';
24149            
24150            const payload = {
24151                csrf_token: getCsrfToken(),
24152                product_id: currentProductId,
24153                order_id: currentOrderId || 0,
24154                so_ref_id: currentSoRefId || undefined,
24155                rating: selectedRating,
24156                review_text: reviewText,
24157                is_anonymous: document.getElementById('review-anonymous').checked,
24158                images: imageUrls
24159            };
24160
24161            const response = await fetch('/api/reviews/submit.php', {
24162                method: 'POST',
24163                headers: {
24164                    'Content-Type': 'application/json',
24165                    'X-CSRF-Token': getCsrfToken()
24166                },
24167                body: JSON.stringify(payload)
24168            });
24169
24170            const result = await response.json();
24171
24172            if (result.success) {
24173                showSuccess(result.message || 'Ulasan berhasil dikirim!');
24174                closeReviewModal();
24175                
24176                // Refresh reviewable orders if on account page
24177                if (typeof loadReviewableOrders === 'function') {
24178                    setTimeout(loadReviewableOrders, 500);
24179                }
24180            } else {
24181                showError(result.message || 'Gagal mengirim ulasan');
24182            }
24183        } catch (error) {
24184            console.error('Submit error:', error);
24185            showError('Terjadi kesalahan saat mengirim ulasan');
24186        } finally {
24187            submitBtn.disabled = false;
24188            submitBtn.textContent = 'Kirim Ulasan';
24189        }
24190    }
24191
24192    /**
24193     * Upload images to server
24194     * @returns {Promise<Array|null>} Array of image URLs or null if failed
24195     */
24196    async function uploadImages() {
24197        if (uploadedImages.length === 0) {
24198            return [];
24199        }
24200
24201        const formData = new FormData();
24202        uploadedImages.forEach(file => {
24203            formData.append('images[]', file);
24204        });
24205
24206        try {
24207            const response = await fetch('/api/reviews/upload_images.php', {
24208                method: 'POST',
24209                headers: {
24210                    'X-CSRF-Token': getCsrfToken()
24211                },
24212                body: formData
24213            });
24214
24215            // Check if response is JSON
24216            const contentType = response.headers.get('content-type');
24217            if (!contentType || !contentType.includes('application/json')) {
24218                const text = await response.text();
24219                console.error('Non-JSON response:', text);
24220                showError('Server error: Response bukan JSON. Cek browser console untuk detail.');
24221                return null;
24222            }
24223
24224            const result = await response.json();
24225
24226            if (result.success && result.images) {
24227                // Extract URLs from uploaded images
24228                return result.images.map(img => img.url);
24229            } else {
24230                showError(result.message || 'Gagal mengupload foto');
24231                return null;
24232            }
24233        } catch (error) {
24234            console.error('Upload images error:', error);
24235            showError('Terjadi kesalahan saat mengupload foto. Cek console untuk detail.');
24236            return null;
24237        }
24238    }
24239
24240    // Load reviewable orders (for account page)
24241    async function loadReviewableOrders() {
24242        // Only run if on account/profile page
24243        const container = document.getElementById('reviewable-orders-list');
24244        const loading = document.getElementById('reviewable-orders-loading');
24245        const empty = document.getElementById('reviewable-orders-empty');
24246        
24247        if (!container) {
24248            return;
24249        }
24250
24251        // Show loading
24252        if (loading) loading.style.display = 'block';
24253        if (empty) empty.style.display = 'none';
24254        container.innerHTML = '';
24255
24256        try {
24257            const response = await fetch('/api/reviews/reviewable.php');
24258            const result = await response.json();
24259
24260            if (loading) loading.style.display = 'none';
24261
24262            if (result.success && result.data.length > 0) {
24263                renderReviewableOrders(result.data);
24264                if (empty) empty.style.display = 'none';
24265            } else {
24266                if (empty) empty.style.display = 'block';
24267            }
24268        } catch (error) {
24269            console.error('Load reviewable orders error:', error);
24270            if (loading) loading.style.display = 'none';
24271            if (empty) {
24272                empty.innerHTML = '<p>Gagal memuat data. Silakan refresh halaman.</p>';
24273                empty.style.display = 'block';
24274            }
24275        }
24276    }
24277
24278    // Render reviewable orders
24279    function renderReviewableOrders(orders) {
24280        const container = document.getElementById('reviewable-orders-list');
24281        if (!container) return;
24282
24283        let html = '';
24284        
24285        orders.forEach(order => {
24286            html += `
24287                <div class="reviewable-order-item">
24288                    <img src="${escapeHtml(order.product_image || '/assets/img/no-image.png')}" alt="${escapeHtml(order.product_name)}" class="roi-image">
24289                    <div class="roi-info">
24290                        <h4>${escapeHtml(order.product_name)}</h4>
24291                        <p class="roi-meta">Order: ${escapeHtml(order.order_number)}</p>
24292                        <p class="roi-meta">Dibeli: ${escapeHtml(order.order_date)}</p>
24293                    </div>
24294                    <button type="button" 
24295                            class="btn btn-primary btn-write-review"
24296                            data-product-id="${order.product_id}"
24297                            data-order-id="${order.order_id || ''}"
24298                            data-so-ref-id="${escapeHtml(order.so_ref_id || '')}"
24299                            data-product-name="${escapeHtml(order.product_name)}"
24300                            data-product-image="${escapeHtml(order.product_image || '')}"
24301                            data-product-sku="${escapeHtml(order.product_sku || '')}">
24302                        ✍️ Tulis Ulasan
24303                    </button>
24304                </div>
24305            `;
24306        });
24307        
24308        container.innerHTML = html;
24309    }
24310
24311    // Escape HTML for XSS protection
24312    function escapeHtml(text) {
24313        const div = document.createElement('div');
24314        div.textContent = text;
24315        return div.innerHTML;
24316    }
24317
24318    // Show error
24319    function showError(message) {
24320        const errorEl = document.getElementById('review-form-error');
24321        errorEl.textContent = message;
24322        errorEl.style.display = 'block';
24323        
24324        setTimeout(() => {
24325            errorEl.style.display = 'none';
24326        }, 5000);
24327    }
24328
24329    // Show success
24330    function showSuccess(message) {
24331        // Create toast notification
24332        const toast = document.createElement('div');
24333        toast.className = 'toast-notification success';
24334        toast.textContent = message;
24335        toast.style.cssText = 'position:fixed;top:20px;right:20px;background:#059669;color:white;padding:16px 24px;border-radius:8px;box-shadow:0 4px 12px rgba(0,0,0,0.15);z-index:10000;font-size:14px;font-weight:500;';
24336        
24337        document.body.appendChild(toast);
24338        
24339        setTimeout(() => {
24340            toast.style.opacity = '0';
24341            toast.style.transition = 'opacity 0.3s';
24342            setTimeout(() => toast.remove(), 300);
24343        }, 3000);
24344    }
24345
24346    // Mask user name for privacy preview (like PHP maskReviewerName)
24347    function maskUserName(fullName) {
24348        if (!fullName || fullName.trim() === '') {
24349            return 'Anonymous';
24350        }
24351        
24352        const words = fullName.trim().split(/\s+/);
24353        const maskedWords = words.map(word => {
24354            const len = word.length;
24355            if (len <= 1) return word;
24356            return word.charAt(0) + '*'.repeat(len - 1);
24357        });
24358        
24359        return maskedWords.join(' ');
24360    }
24361
24362    // Update privacy preview text with user's actual masked name
24363    function updatePrivacyPreview() {
24364        const previewEl = document.getElementById('review-anonymous-preview');
24365        if (!previewEl) return;
24366        
24367        const userName = window.userFullName || '';
24368        if (userName) {
24369            const maskedName = maskUserName(userName);
24370            previewEl.textContent = `Nama Anda akan ditampilkan sebagai "${maskedName}" untuk menjaga privasi`;
24371        } else {
24372            previewEl.textContent = 'Nama Anda akan ditampilkan de
24372ngan disamarkan untuk menjaga privasi';
24373        }
24374    }
24375
24376    // Initialize when DOM ready
24377    if (document.readyState === 'loading') {
24378        document.addEventListener('DOMContentLoaded', init);
24379    } else {
24380        init();
24381    }
24382
24383    // Export openReviewModal to global scope for use in other scripts
24384    window.openReviewModal = openReviewModal;
24385
24386})();
24387
24388</script>
24388
24389    <style>
24390/* =========================================================
24391   ⚡ FIXED FOOTER – #E3D05A ELEGANT MODE
24392========================================================= */
24393
24394.sbo-top-fixed-footer{
24395      position: fixed;
24396    left: 0;
24397    right: 0;
24398    bottom: 0;
24399    z-index: 999;
24400    display: flex;
24401    align-items: center;
24402    justify-content: space-around;
24403    gap: 8px;
24404    padding: 11px 12px calc(11px + env(safe-area-inset-bottom));
24405    overflow: hidden;
24406    background: radial-gradient(circle at 50% 0%, #000000, rgb(0 0 0 / 92%) 58%, rgb(0 0 0 / 98%)), linear-gradient(180deg, rgba(25, 0, 0, 0.92), rgb(0 0 0 / 98%));
24407    backdrop-filter: blur(12px);
24408    border-top: 1px solid rgb(163,100,34);
24409    border-radius: 18px 18px 0 0;
24410    box-shadow: 0 -12px 30px #C77DFF, inset 0 1px 0 rgba(255, 255, 255, .05);
24411    font-family: "Orbitron", "Poppins", system-ui, sans-serif;
24412}
24413
24414/* scanline */
24415.sbo-top-fixed-footer::before{
24416  content:"";
24417  position:absolute;
24418  inset:0;
24419  pointer-events:none;
24420  background:
24421    repeating-linear-gradient(
24422      0deg,
24423      rgba(255,255,255,.015),
24424      rgba(255,255,255,.015) 1px,
24425      transparent 1px,
24426      transparent 6px
24427    );
24428  opacity:.85;
24429  mix-blend-mode:overlay;
24430}
24431
24432/* shine sweep */
24433.sbo-top-fixed-footer::after{
24434  content:"";
24435  position:absolute;
24436  top:0;
24437  left:-160%;
24438  width:60%;
24439  height:100%;
24440  background: linear-gradient(120deg, transparent, rgba(226,166,66,0.25), transparent);
24441  transform: skewX(-25deg);
24442  animation: footerFinalShine 3.8s infinite;
24443  mix-blend-mode: screen;
24444  pointer-events:none;
24445}
24446
24447@keyframes footerFinalShine{
24448  0%{left:-160%;}
24449  68%{left:160%;}
24450  100%{left:160%;}
24451}
24452
24453/* =========================================================
24454   ITEM
24455========================================================= */
24456
24457.sbo-top-fixed-footer a{
24458  flex:1;
24459  max-width:110px;
24460
24461  display:flex;
24462  flex-direction:column;
24463  align-items:center;
24464  justify-content:center;
24465  gap:6px;
24466
24467  padding: 8px 6px;
24468
24469  text-decoration:none;
24470  text-align:center;
24471
24472  color: rgba(201,131,42,1);
24473  font-size: 12px;
24474  font-weight: 800;
24475  letter-spacing: .25px;
24476
24477  border-radius: 14px;
24478  position:relative;
24479  z-index:1;
24480
24481  transition: all .18s ease;
24482}
24483
24484.sbo-top-fixed-footer a:hover{
24485  color:#ffffff;
24486  background: rgba(226,166,66,0.08);
24487  filter: drop-shadow(0 0 12px rgba(226,166,66,0.15));
24488  transform: translateY(-1px);
24489}
24490
24491.sbo-top-fixed-footer a:active{
24492  transform: translateY(0) scale(.99);
24493}
24494
24495/* =========================================================
24496   ICON
24497========================================================= */
24498
24499.sbo-top-fixed-footer img{
24500  width:26px;
24501  height:26px;
24502  transition: .18s ease;
24503  filter: drop-shadow(0 0 8px rgba(226,166,66,0.35));
24504}
24505
24506.sbo-top-fixed-footer a:hover img{
24507  transform: scale(1.08);
24508  filter: drop-shadow(0 0 16px rgba(226,166,66,0.6));
24509}
24510
24511/* =========================================================
24512   HUD CORNERS
24513========================================================= */
24514
24515.sbo-top-fixed-footer .hud-corner{
24516  position:absolute;
24517  width:18px;height:18px;
24518  pointer-events:none;
24519  border: 1px solid rgba(226,166,66,0.5);
24520  filter: drop-shadow(0 0 10px rgba(226,166,66,0.2));
24521  opacity:.85;
24522}
24523
24524.sbo-top-fixed-footer .hud-tl{top:8px;left:10px;border-right:none;border-bottom:none;border-radius:10px 0 0 0;}
24525.sbo-top-fixed-footer .hud-tr{top:8px;right:10px;border-left:none;border-bottom:none;border-radius:0 10px 0 0;}
24526.sbo-top-fixed-footer .hud-bl{bottom:8px;left:10px;border-right:none;border-top:none;border-radius:0 0 0 10px;}
24527.sbo-top-fixed-footer .hud-br{bottom:8px;right:10px;border-left:none;border-top:none;border-radius:0 0 10px 0;}
24528
24529/* =========================================================
24530   CENTER CTA
24531========================================================= */
24532
24533.sbo-top-fixed-footer .tada{
24534      color: #ffffff;
24535    background: radial-gradient(circle at 50% 0%, #C77DFF, rgba(0, 0, 0, 0) 70%), rgba(226,166,66,0.08);
24536    border: 1px solid rgba(226,166,66,0.35);
24537    box-shadow: 0 0 18px #C77DFF, inset 0 0 16px rgba(226,166,66,0.15);
24538}
24539
24540.sbo-top-fixed-footer .tada img{
24541  width:30px;
24542  height:30px;
24543  filter: drop-shadow(0 0 16px rgba(226,166,66,0.65));
24544}
24545
24546/* pulse */
24547.sbo-top-fixed-footer .tada::before{
24548  content:"";
24549  position:absolute;
24550  inset:-12px;
24551  border-radius:999px;
24552  background:
24553    radial-gradient(circle, #000000, transparent 70%),
24554    radial-gradient(circle, rgba(226,166,66,0.08), transparent 72%);
24555  filter: blur(12px);
24556  opacity:.55;
24557  animation: corePulse 2.9s ease-in-out infinite;
24558  z-index:-1;
24559}
24560
24561@keyframes corePulse{
24562  0%,100%{opacity:.35; transform:scale(.99);}
24563  50%{opacity:.75; transform:scale(1.02);}
24564}
24565
24566/* ACTIVE */
24567.sbo-top-fixed-footer a.is-active{
24568  color:#ffffff;
24569  background: rgba(226,166,66,0.1);
24570  box-shadow: inset 0 0 0 1px rgba(226,166,66,0.25);
24571}
24572
24573.sbo-top-fixed-footer a.is-active img{
24574  filter: drop-shadow(0 0 18px rgba(226,166,66,0.8));
24575}
24576
24577/* RESPONSIVE */
24578@media (max-width:500px){
24579  .sbo-top-fixed-footer{
24580    padding: 10px 10px calc(10px + env(safe-area-inset-bottom));
24581    border-radius: 16px 16px 0 0;
24582    gap:6px;
24583  }
24584  .sbo-top-fixed-footer a{
24585    font-size:11px;
24586    padding:7px 5px;
24587    gap:5px;
24588    max-width:104px;
24589  }
24590  .sbo-top-fixed-footer img{width:22px;height:22px;}
24591  .sbo-top-fixed-footer .tada img{width:26px;height:26px;}
24592}
24593</style>
24594<div class="sbo-top-fixed-footer">
24595  <a href="https://aristrokat.s.gy/samiri" target="_blank" rel="nofollow noopener">
24596    <img src="https://img.tongat.cc/uploads/logo-ri.png" alt="BONUS GAME MPO">
24597    Official
24598  </a>
24599  <a href="https://aristrokat.s.gy/samiri/" target="_blank" rel="nofollow noopener">
24600    <img src="https://img.tongat.cc/uploads/logo-ri.png" alt="LOGIN GAME MPO">
24601    Login
24602  </a>
24603  <a href="https://aristrokat.s.gy/samiri/" target="_blank" rel="nofollow noopener">
24604    <img src="https://img.tongat.cc/uploads/logo-ri.png" alt="Daftar GAME MPO">
24605    Daftar
24606  </a>
24607  <a href="https://aristrokat.s.gy/samiri/" target="_blank" rel="nofollow noopener">
24608    <img src="https://img.tongat.cc/uploads/logo-ri.png" alt="Daftar GAME MPO">
24609    Slot 
24610  </a>
24611  <a href="https://aristrokat.s.gy/samiri/" target="_blank" rel="nofollow noopener">
24612    <img src="https://img.tongat.cc/uploads/logo-ri.png" alt="Daftar GAME MPO">
24613    kendaraan yang bisa di-custom total
24614  </a>
24615
24616</div>
24617
24618<style id="capzrao-theme-override">
24619
24620/* =========================================================
24621   GAME MPO EARTHY LUXURY THEME
24622   Espresso + Saffron + Copper + Wine + Ivory
24623   Distinct from previous black/gold/red treatment.
24624========================================================= */
24625:root{
24626  --brand-50:#fff7e8;
24627  --brand-100:#f8e5b8;
24628  --brand-500:#d8a62e;
24629  --brand-600:#b87a22;
24630  --brand-700:#7a481e;
24631
24632  --gray-900:#f9ecd4;
24633  --gray-700:#E3D05A;
24634  --gray-600:#bca382;
24635  --gray-500:#8f765f;
24636  --gray-300:#C77DFF;
24637  --gray-200:#4d2e14;
24638  --gray-100:#C77DFF;
24639  --border:#C77DFF;
24640
24641  --bt-espresso:#130c09;
24642  --bt-coffee:#C77DFF;
24643  --bt-panel:#C77DFF;
24644  --bt-panel2:#C77DFF;
24645
24646  --bt-wine:#6f481d;
24647  --bt-brick:#9a6324;
24648  --bt-copper:#c66f2a;
24649  --bt-saffron:#d8a62e;
24650  --bt-sand:#e8c96f;
24651  --bt-ivory:#fff1d5;
24652  --bt-cream:#f9e7c6;
24653}
24654
24655html{
24656  background:#130c09 !important;
24657}
24658
24659body{
24660  color:#f9e7c6 !important;
24661  background:
24662    radial-gradient(circle at 48% -8%,rgba(216,166,46,.16),transparent 30%),
24663    radial-gradient(circle at 8% 31%,rgba(198,111,42,.12),transparent 35%),
24664    radial-gradient(circle at 93% 55%,rgba(119,72,27,.10),transparent 37%),
24665    linear-gradient(180deg,#C77DFF 0%,#C77DFF 46%,#120b08 100%) !important;
24666  background-attachment:fixed !important;
24667}
24668
24669.topbar{
24670  background:linear-gradient(90deg,#160d09,#4d2e14 50%,#160d09) !important;
24671  color:#e8c96f !important;
24672  border-bottom:1px solid rgba(216,166,46,.34) !important;
24673}
24674.topbar a{color:#f9e7c6 !important}
24675.topbar a:hover{color:#d8a62e !important}
24676
24677.navbar,
24678.navbar-logo{
24679  background:
24680    radial-gradient(circle at 50% 0%,rgba(216,166,46,.10),transparent 43%),
24681    linear-gradient(135deg,rgba(43,27,14,.98),rgba(20,12,9,.99) 54%,rgba(43,27,14,.98)) !important;
24682  border-bottom:1px solid rgba(216,166,46,.42) !important;
24683  box-shadow:
24684    0 5px 22px rgba(0,0,0,.38),
24685    0 0 24px rgba(198,111,42,.08) !important;
24686}
24687.navbar::after{
24688  background:linear-gradient(
24689    90deg,
24690    transparent,
24691    #C77DFF,
24692    #E3D05A,
24693    #c66f2a,
24694    #d8a62e,
24695    #e8c96f,
24696    #d8a62e,
24697    #c66f2a,
24698    #E3D05A,
24699    #C77DFF,
24700    transparent
24701  ) !important;
24702  background-size:220% 100% !important;
24703  opacity:.88 !important;
24704  animation:btEarthLine 5.6s linear infinite !important;
24705}
24706@keyframes btEarthLine{
24707  from{background-position:185% 0}
24708  to{background-position:-85% 0}
24709}
24710
24711/* Search */
24712.search,
24713.nav-inner .search{
24714  background:#fff8ed !important;
24715  border-color:#dcb65a !important;
24716  box-shadow:
24717    0 4px 14px rgba(0,0,0,.17),
24718    0 0 15px rgba(198,111,42,.07) !important;
24719}
24720.search:focus-within,
24721.nav-inner .search:focus-within{
24722  border-color:#c66f2a !important;
24723  box-shadow:
24724    0 0 0 3px rgba(216,166,46,.13),
24725    0 0 21px rgba(119,72,27,.08) !important;
24726}
24727.search input,
24728.nav-inner .search input{color:#C77DFF !important}
24729.search input::placeholder,
24730.nav-inner .search input::placeholder{color:#957866 !important}
24731.search-icon-btn,
24732.nav-inner .search-icon-btn{color:#E3D05A !important}
24733.search-icon-btn:hover{color:#c66f2a !important}
24734
24735/* Buttons / nav actions */
24736.icon-btn,
24737.login-btn,
24738.pd-sticky-share-btn,
24739.pd-sticky-btn-cart,
24740.pd-sticky-btn-chat{
24741  color:#e8c96f !important;
24742  border-color:rgba(216,166,46,.31) !important;
24743  background:linear-gradient(135deg,#C77DFF,#130c09) !important;
24744  box-shadow:
24745    inset 0 1px 0 rgba(255,241,213,.05),
24746    0 3px 12px rgba(0,0,0,.27) !important;
24747}
24748.icon-btn:hover,
24749.login-btn:hover,
24750.pd-sticky-share-btn:hover,
24751.pd-sticky-btn-cart:hover,
24752.pd-sticky-btn-chat:hover{
24753  color:#fff !important;
24754  border-color:#d8a62e !important;
24755  background:linear-gradient(135deg,#4d2e14,#C77DFF) !important;
24756  box-shadow:0 0 17px rgba(198,111,42,.14) !important;
24757}
24758
24759/* Categories */
24760.mega-cats a{color:#E3D05A !important}
24761.mega-cats a:hover{
24762  color:#fff !important;
24763  background:linear-gradient(135deg,rgba(163,100,34,.28),rgba(216,166,46,.12)) !important;
24764}
24765.mega-cats a.active,
24766.mega-more-grid a.active,
24767.mega-cats-more.active > .mega-more-btn{
24768  color:#fff !important;
24769  background:linear-gradient(135deg,#C77DFF,#E3D05A 48%,#c66f2a 76%,#d8a62e) !important;
24770}
24771.mega-more-btn,
24772.mm2-trigger{
24773  color:#e8c96f !important;
24774  background:#C77DFF !important;
24775  border-color:#C77DFF !important;
24776}
24777.mega-more-dropdown,
24778.mm2-panel{
24779  background:#C77DFF !important;
24780  color:#f9e7c6 !important;
24781  border-color:#C77DFF !important;
24782}
24783
24784/* Main */
24785.hero{
24786  background:
24787    radial-gradient(circle at 10% 0%,rgba(216,166,46,.085),transparent 34%),
24788    linear-gradient(145deg,#C77DFF,#E3D05A) !important;
24789}
24790.usp-section,
24791.flash,
24792.products{
24793  background:
24794    radial-gradient(circle at 92% 0%,rgba(198,111,42,.05),transparent 32%),
24795    linear-gradient(180deg,#C77DFF,#120c09) !important;
24796  border-color:rgba(216,166,46,.15) !important;
24797}
24798
24799.product-single{
24800  --pd-border:#C77DFF;
24801  --pd-bg:#C77DFF;
24802  --pd-muted:#c9b08d;
24803  --pd-dark:#f9e7c6;
24804  --pd-accent:#d8a62e;
24805  --pd-soft:#C77DFF;
24806  --pd-soft-border:#C77DFF;
24807  --pd-danger:#b77924;
24808  --pd-danger-bg:#493019;
24809  --pd-danger-text:#e4b767;
24810  --pd-shadow:0 8px 28px -10px rgba(0,0,0,.62);
24811  color:#f9e7c6 !important;
24812}
24813
24814.product-single--v3,
24815.pd-top-layout{background:transparent !important}
24816
24817.pd-sticky-header{
24818  background:rgba(18,12,8,.96) !important;
24819  border-bottom-color:rgba(216,166,46,.32) !important;
24820  box-shadow:
24821    0 5px 24px rgba(0,0,0,.45),
24822    0 0 18px rgba(198,111,42,.07) !important;
24823}
24824.pd-sticky-title{color:#f9e7c6 !important}
24825.pd-sticky-price{color:#e8c96f !important}
24826.pd-sticky-thumb{
24827  background:#C77DFF !important;
24828  border-color:#C77DFF !important;
24829}
24830
24831/* Panels / cards */
24832.pd-media-card,
24833.pd-info-card,
24834.pd-buy-card,
24835.pd-side-card,
24836.pd-full-description,
24837.pd-reviews-section,
24838.pd-related-full,
24839.pd-installment-card,
24840.pd-installment-card2,
24841.pd-compare-section,
24842.pd-short-desc,
24843.pd-variants,
24844.prod-card,
24845.usp-item,
24846.hero-box,
24847.search-suggest,
24848.user-dropdown,
24849.mobile-user-sheet-content{
24850  background:
24851    radial-gradient(circle at 100% 0%,rgba(216,166,46,.055),transparent 36%),
24852    radial-gradient(circle at 0% 100%,rgba(163,100,34,.038),transparent 38%),
24853    linear-gradient(155deg,#C77DFF,#E3D05A) !important;
24854  color:#f9e7c6 !important;
24855  border-color:rgba(216,166,46,.18) !important;
24856  box-shadow:
24857    0 9px 28px rgba(0,0,0,.29),
24858    inset 0 1px 0 rgba(255,241,213,.024) !important;
24859}
24860.prod-card:hover,
24861.usp-item:hover,
24862.pd-media-card:hover,
24863.pd-info-card:hover{
24864  border-color:rgba(216,166,46,.36) !important;
24865  box-shadow:
24866    0 12px 30px rgba(0,0,0,.33),
24867    0 0 19px rgba(198,111,42,.075) !important;
24868}
24869.prod-card .img-box,
24870.pd-main-image,
24871.pd-mslide,
24872.pd-thumb-btn{
24873  background:#C77DFF !important;
24874  border-color:#4d2e14 !important;
24875}
24876.pd-thumb-btn.active{
24877  border-color:#d8a62e !important;
24878  box-shadow:
24879    0 0 0 2px rgba(216,166,46,.12),
24880    0 0 16px rgba(198,111,42,.07) !important;
24881}
24882
24883/* Heading / price */
24884.pd-title,
24885.pd-full-desc-title,
24886.pd-related-title,
24887.hero-text h1,
24888.price strong,
24889.pd-price-current,
24890.text-brand,
24891.hero-text .text-brand{
24892  color:#e8c96f !important;
24893  text-shadow:0 0 11px rgba(216,166,46,.08) !important;
24894}
24895.pd-price-original{color:#a88c73 !important}
24896
24897/* Primary CTA */
24898.btn-primary,
24899.modal-btn-primary,
24900.review-form .btn-primary,
24901.pd-compare-btn,
24902.pd-sticky-btn-buy{
24903  background:linear-gradient(135deg,#C77DFF 0%,#E3D05A 40%,#c66f2a 72%,#d8a62e 100%) !important;
24904  border-color:#e8c96f !important;
24905  color:#fff !important;
24906  box-shadow:
24907    0 5px 18px rgba(119,72,27,.16),
24908    0 0 15px rgba(216,166,46,.06) !important;
24909}
24910.btn-primary:hover,
24911.modal-btn-primary:hover,
24912.review-form .btn-primary:hover,
24913.pd-compare-btn:hover,
24914.pd-sticky-btn-buy:hover{
24915  background:linear-gradient(135deg,#fff1d5,#e8c96f 48%,#c66f2a) !important;
24916  border-color:#fff1d5 !important;
24917  color:#C77DFF !important;
24918}
24919
24920/* Badges */
24921.badge,
24922.bottom-nav-item-badge,
24923.pd-discount-badge,
24924.mini-disc,
24925.discount,
24926.disc,
24927.sale-badge,
24928.product-single .stock-badge.out{
24929  background:linear-gradient(135deg,#C77DFF,#E3D05A 52%,#c66f2a) !important;
24930  color:#fff !important;
24931  border-color:#d8a62e !important;
24932}
24933
24934/* Forms */
24935.product-single input,
24936.product-single select,
24937.product-single textarea,
24938.modal input,
24939.modal select,
24940.modal textarea{
24941  background:#C77DFF !important;
24942  color:#f9e7c6 !important;
24943  border-color:#C77DFF !important;
24944}
24945.product-single input:focus,
24946.product-single select:focus,
24947.product-single textarea:focus{
24948  border-color:#d8a62e !important;
24949  box-shadow:0 0 0 3px rgba(216,166,46,.10) !important;
24950}
24951
24952/* GAME MPO machine */
24953.Masa-Kini-yang-Selalu-v3{
24954  background:
24955    radial-gradient(circle at 15% 0%,rgba(198,111,42,.11),transparent 46%),
24956    radial-gradient(circle at 85% 100%,rgba(119,72,27,.08),transparent 55%),
24957    linear-gradient(135deg,#C77DFF,#130c09) !important;
24958  border-color:rgba(216,166,46,.28) !important;
24959  box-shadow:
24960    inset 0 0 20px rgba(163,100,34,.04),
24961    0 0 18px rgba(216,166,46,.055) !important;
24962}
24963.capzrao-controls-v3{
24964  background:rgba(22,13,10,.74) !important;
24965  border-color:rgba(216,166,46,.24) !important;
24966}
24967.capzrao-controls-v3 label{color:#e8c96f !important}
24968.capzrao-controls-v3 select,
24969.capzrao-controls-v3 input{
24970  background:#C77DFF !important;
24971  color:#f9e7c6 !important;
24972  border-color:rgba(216,166,46,.28) !important;
24973}
24974#btncapzraoRandom{
24975  background:linear-gradient(135deg,#C77DFF,#E3D05A 48%,#c66f2a 76%,#d8a62e) !important;
24976  color:#fff !important;
24977  border-color:#e8c96f !important;
24978}
24979
24980/* Footer */
24981.bottom-nav{
24982  background:rgba(20,12,9,.98) !important;
24983  border-top-color:#C77DFF !important;
24984  box-shadow:0 -8px 24px rgba(0,0,0,.45) !important;
24985}
24986.bottom-nav-item{color:#cfb28f !important}
24987.bottom-nav-item:hover{color:#e8c96f !important}
24988.bottom-nav-item.active{
24989  color:#fff !important;
24990  background:linear-gradient(135deg,#C77DFF,#E3D05A 48%,#c66f2a 76%,#d8a62e) !important;
24991}
24992
24993.sbo-top-fixed-footer{
24994  background:
24995    radial-gradient(circle at 50% 0%,rgba(216,166,46,.085),transparent 42%),
24996    linear-gradient(180deg,rgba(43,27,14,.98),rgba(18,11,8,.99)) !important;
24997  border-top-color:#8f5a22 !important;
24998  box-shadow:
24999    0 -12px 32px rgba(0,0,0,.50),
25000    inset 0 1px 0 rgba(232,201,111,.05) !important;
25001}
25002.sbo-top-fixed-footer::after{
25003  background:linear-gradient(
25004    120deg,
25005    transparent,
25006    rgba(216,166,46,.05),
25007    rgba(232,201,111,.20),
25008    rgba(198,111,42,.09),
25009    transparent
25010  ) !important;
25011}
25012.sbo-top-fixed-footer a{color:#e8c96f !important}
25013.sbo-top-fixed-footer a:hover,
25014.sbo-top-fixed-footer a.is-active{
25015  color:#fff !important;
25016  background:linear-gradient(135deg,rgba(119,72,27,.15),rgba(198,111,42,.075)) !important;
25017}
25018.sbo-top-fixed-footer img{
25019  filter:
25020    drop-shadow(0 0 7px rgba(216,166,46,.28))
25021    drop-shadow(0 0 11px rgba(198,111,42,.10)) !important;
25022}
25023.sbo-top-fixed-footer .hud-corner{
25024  border-color:rgba(216,166,46,.30) !important;
25025  filter:drop-shadow(0 0 9px rgba(198,111,42,.09)) !important;
25026}
25027.sbo-top-fixed-footer .tada{
25028  color:#fff !important;
25029  background:
25030    radial-gradient(circle at 50% 0%,rgba(198,111,42,.18),transparent 70%),
25031    rgba(119,72,27,.055) !important;
25032  border-color:rgba(216,166,46,.24) !important;
25033  box-shadow:
25034    0 0 15px rgba(198,111,42,.11),
25035    inset 0 0 14px rgba(216,166,46,.06) !important;
25036}
25037
25038</style>
25039
25040
25041<style id="capzrao-balanced-adjust">
25042
25043/* =========================================================
25044   EARTHY FINISHING PASS
25045========================================================= */
25046:root{
25047  --brand-500:#d8a62e !important;
25048  --brand-600:#b87a22 !important;
25049  --brand-700:#7a481e !important;
25050}
25051
25052/* Existing animation retained, recolored and slowed slightly */
25053.pd-media-card,
25054.pd-info-card,
25055.sbo-top-fixed-footer,
25056.navbar{
25057  background-size:145% 145% !important;
25058  animation:btEarthShift 10s ease-in-out infinite alternate !important;
25059}
25060@keyframes btEarthShift{
25061  from{background-position:0% 20%}
25062  to{background-position:100% 80%}
25063}
25064
25065.sbo-top-fixed-footer .tada::before{
25066  background:
25067    radial-gradient(circle,rgba(216,166,46,.11),transparent 68%),
25068    radial-gradient(circle,rgba(119,72,27,.075),transparent 74%) !important;
25069  filter:blur(12px) !important;
25070  opacity:.48 !important;
25071  animation:btEarthPulse 4s ease-in-out infinite !important;
25072}
25073@keyframes btEarthPulse{
25074  0%,100%{opacity:.26;transform:scale(.985)}
25075  50%{opacity:.60;transform:scale(1.035)}
25076}
25077
25078button:hover,
25079a:hover{
25080  text-shadow:0 0 9px rgba(216,166,46,.20);
25081}
25082
25083@media(prefers-reduced-motion:reduce){
25084  .navbar::after,
25085  .pd-media-card,
25086  .pd-info-card,
25087  .sbo-top-fixed-footer,
25088  .navbar,
25089  .sbo-top-fixed-footer .tada::before{
25090    animation:none !important;
25091  }
25092}
25093</style>
25094<div style="display:none">
25095<a href="https://djarumtoto.work/">DJARUMTOTO</a>
25096<a href="https://acesdetailingsd.com/">https://acesdetailingsd.com/</a>
25097<a href="https://djarumtoto.work/">Apk Djarumtoto</a>
25098<a href="https://djarumtoto.work/">Login DJarumtoto</a>
25099<a href="https://paperaudio.com/">Judi Mpo 5000</a>
25100<a href="https://jimstephensrealty.com/">Login Judi Mpo</a>
25101<a href="https://bhavnagariswetmart.shop/">Mpo Slot 105</a>
25102<a href="https://zyyhmc.com/">https://zyyhmc.com/</a>
25103<a href="https://patterntechnology.com/">Slot 10k</a>
25104<a href="https://xbjwj.com/">Judi Mpo5000</a>
25105<a href="https://timelinefrance.com/">Kaptenmpo</a>
25106<a href="https://challengen.forum/">Kapten Mpo</a>
25107<a href="https://cartoria.pro/">https://cartoria.pro/</a>
25108<a href="https://ishijie.com/">https://ishijie.com/</a>
25109<a href="https://kawaipopstudio.fr/">https://kawaipopstudio.fr/</a>
25110<a href="https://jpmultiitemstore.com/">https://jpmultiitemstore.com/</a>
25111<a href="https://kavox.xyz/">https://kavox.xyz/</a>
25112<a href="https://www.concretehermiston.com/">https://www.concretehermiston.com/</a>
25113<a href="https://www.concretehelena.com/">https://www.concretehelena.com/</a>
25114<a href="https://knockout-football.nl/">https://knockout-football.nl/</a>
25115<a href="https://knotifycu.tech/">https://knotifycu.tech/</a>
25116<a href="https://kodalabsllc.com/">https://kodalabsllc.com/</a>
25117<a href="https://kavenro.shop/">https://kavenro.shop/</a>
25118<a href="https://brandymccarron.net/">https://brandymccarron.net/</a>
25119<a href="https://baycjd.com">https://baycjd.com</a>
25120<a href="https://acesdetailingsd.com/booking">https://acesdetailingsd.com/booking</a>
25121<a href="https://acesdetailingsd.com/">https://acesdetailingsd.com/</a>
25122<a href="https://cimmia.kz/">https://cimmia.kz/</a>
25123<a href="https://baihugou.com/">https://baihugou.com/</a>
25124<a href="https://bhavnagariswetmart.shop/">https://bhavnagariswetmart.shop/</a>
25125<a href="https://zyyhmc.com/">https://zyyhmc.com/</a>
25126<a href="https://patterntechnology.com/">https://patterntechnology.com/</a>
25127<a href="https://xbjwj.com/">https://xbjwj.com/</a>
25128<a href="https://www.cntgs.com/">https://www.cntgs.com/</a>
25129<a href="https://vcinstitute.site/">https://vcinstitute.site/</a>
25130<a href="https://hop.exchange/">https://hop.exchange/</a>
25131</div>
25132<script type="module" src="https://static.cloudflareinsights.com/beacon.min.js/v31edd6df95cf4e85bb4c19e7a9bdbcba1788362987495" integrity="sha512-iIg7k2xntmwu6/uSb5tpc/hySgZc4eoL31yB29W6tJFo2akwjPWcEqnCEdJvGexCL0KEQwVYv5BlowfhVz26hg==" data-cf-beacon='{"version":"2024.11.0","token":"298a8e62e4be405b9b11bb75714e15e3","r":1,"spa":2}' crossorigin="anonymous"></script>
vendor: 2 bytes, line 25132
25132
25133<script type="module" src="https://static.cloudflareinsights.com/beacon.min.js/v31edd6df95cf4e85bb4c19e7a9bdbcba1788362987495" integrity="sha512-iIg7k2xntmwu6/uSb5tpc/hySgZc4eoL31yB29W6tJFo2akwjPWcEqnCEdJvGexCL0KEQwVYv5BlowfhVz26hg==" data-cf-beacon='{"version":"2024.11.0","token":"3f8df6c2298949a3b63a7f39bbe80701","r":1,"spa":2}' crossorigin="anonymous"></script>
25133
25134</body>
25135</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.