PageSourceSearch

https://tritops.co.kr/js/metrics_z2xs.js

js tritops.co.kr collected 2026-10-06 02:47:31 UTC 109,852 bytes, 2,170 lines download raw bytes

1var __UVW1={id:'kobet-org'};
2/**
3 * Site widget
4 * Loaded via <script> on affiliate sites.
5 * Expects window.__UVW1 = { id: "site_id" } to be set before this script runs.
6 */
7(function () {
8  'use strict';
9
10  var SITE_ID = (typeof __UVW1 !== 'undefined' && __UVW1.id) ? __UVW1.id : null;
11  if (!SITE_ID) return;
12
13  var API_BASE = '/widget-api';
14
15  /* Click tracking helpers — set from config */
16  var _CP = 's';   // click param name (randomized per site)
17  var _CS = {};     // click source map  (randomized per site)
18  var COUNTRY_NAMES = {
19    GB:'the UK',UK:'the UK',AU:'Australia',NZ:'New Zealand',CA:'Canada',
20    DE:'Germany',AT:'Austria',CH:'Switzerland',FI:'Finland',NO:'Norway',
21    SE:'Sweden',DK:'Denmark',NL:'the Netherlands',BE:'Belgium',IE:'Ireland',
22    FR:'France',ES:'Spain',IT:'Italy',PT:'Portugal',PL:'Poland',
23    CZ:'Czech Republic',HU:'Hungary',RO:'Romania',GR:'Greece',
24    BR:'Brazil',MX:'Mexico',CL:'Chile',AR:'Argentina',PE:'Peru',CO:'Colombia',
25    JP:'Japan',KR:'South Korea',IN:'India',ZA:'South Africa',
26    US:'the US',TR:'Turkey',RU:'Russia',UA:'Ukraine'
27  };
28  /* Loader overlay */
29  var _loader = null;
30  function showLoader() {
31    if (_loader) { _loader.style.display = 'flex'; return; }
32    _loader = document.createElement('div');
33    _loader.style.cssText = 'position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.5);z-index:999999;display:flex;align-items:center;justify-content:center;';
34    var spin = document.createElement('div');
35    spin.style.cssText = 'width:48px;height:48px;border:4px solid rgba(255,255,255,0.3);border-top-color:#fff;border-radius:50%;animation:uvw1-spin .6s linear infinite;';
36    var st = document.createElement('style');
37    st.textContent = '@keyframes uvw1-spin{to{transform:rotate(360deg)}}';
38    document.head.appendChild(st);
39    _loader.appendChild(spin);
40    document.body.appendChild(_loader);
41    window.addEventListener('pageshow', function() { if (_loader) _loader.style.display = 'none'; });
42  }
43
44  function goOpen(src) {
45    showLoader();
46    var p = _CP + '=' + (_CS[src] || src);
47    fetch(API_BASE + '/click/' + SITE_ID + '?' + p)
48      .then(function(r) { return r.json(); })
49      .then(function(d) { if (d.u) window.location.href = d.u; })
50      .catch(function() { if (_loader) _loader.style.display = 'none'; });
51  }
52  function goSet(el, src) { el.style.cursor = 'pointer'; el.onclick = function(e) { e.preventDefault(); goOpen(src); }; }
53  function goTrack(src) { var p = _CP + '=' + (_CS[src] || src); fetch(API_BASE + '/click/' + SITE_ID + '?' + p).catch(function(){}); }
54
55  /* ============================================================
56     STYLES — injected once into <head>
57     ============================================================ */
58  function injectStyles() {
59    /* Google Font — Press Start 2P for retro slot machine */
60    var fontLink = document.createElement('link');
61    fontLink.rel = 'stylesheet';
62    fontLink.href = 'https://fonts.googleapis.com/css2?family=VT323&display=swap';
63    document.head.appendChild(fontLink);
64
65    var css = '' +
66      /* ---- Header button ---- */
67      '.uvw1-header-btn{' +
68        'position:absolute;z-index:9990;box-sizing:border-box;padding:8px 20px;border:none;border-radius:20px;height:38px;' +
69        'color:#fff;font-weight:600;font-size:15px;cursor:pointer;' +
70        'text-decoration:none;white-space:nowrap;' +
71        'display:flex;justify-content:center;align-items:center;' +
72        'overflow:hidden;background-size:300% 300%;' +
73        'animation:uvw1-gradientShift 4s ease infinite,uvw1-pulse 5s ease-in-out infinite !important;' +
74        'box-shadow:0 2px 5px rgba(0,0,0,.2);transition:all .3s ease;' +
75        'font-family:Arial,Helvetica,sans-serif;' +
76        'text-shadow:0 1px 2px rgba(0,0,0,.2);' +
77      '}' +
78      '.uvw1-header-btn:hover{transform:translateY(-50%) translateY(-2px);box-shadow:0 4px 8px rgba(0,0,0,.3);}' +
79      '@keyframes uvw1-gradientShift{0%{background-position:0% 50%}50%{background-position:100% 50%}100%{background-position:0% 50%}}' +
80      '@keyframes uvw1-pulse{0%,100%{transform:translateY(-50%) scale(1)}5%{transform:translateY(-50%) scale(1.05)}10%{transform:translateY(-50%) scale(1)}15%{transform:translateY(-50%) scale(1.05)}20%,100%{transform:translateY(-50%) scale(1)}}' +
81
82      /* ---- Sticky footer text accents ---- */
83      '.uvw1-sticky-brand{color:#ffd700;font-weight:800;text-decoration:none;text-shadow:0 0 10px rgba(255,215,0,.4),0 0 20px rgba(255,215,0,.15);' +
84        'animation:uvw1-brandGlow 2.5s ease-in-out infinite;letter-spacing:.5px;cursor:pointer;}' +
85      '.uvw1-sticky-brand:hover{text-decoration:none;}' +
86      '@keyframes uvw1-brandGlow{0%,100%{text-shadow:0 0 10px rgba(255,215,0,.4),0 0 20px rgba(255,215,0,.15)}' +
87        '50%{text-shadow:0 0 14px rgba(255,215,0,.6),0 0 28px rgba(255,215,0,.25)}}' +
88      '.uvw1-sticky-warn{color:#ff9a9a;font-weight:700;}' +
89      '.uvw1-sticky-highlight{color:#7dffb3;font-weight:700;text-shadow:0 0 8px rgba(125,255,179,.35);}' +
90
91      /* ---- Sticky footer ---- */
92      '.uvw1-footer{' +
93        'position:fixed;bottom:0;left:0;right:0;z-index:9998;width:100%;' +
94        'font-family:Helvetica Neue,Helvetica,Arial,sans-serif;' +
95        'background:linear-gradient(to right,#1a365d,#4a3880);' +
96        'border-top:1px solid rgba(59,130,246,.5);' +
97        'transform:translateY(0);transition:transform .4s ease-out;color:#fff;' +
98      '}' +
99      '.uvw1-footer.uvw1-hidden{transform:translateY(100%);transition:none;}' +
100      '.uvw1-footer.uvw1-hiding{transform:translateY(100%);transition:transform .4s ease-out;}' +
101      '.uvw1-footer.uvw1-visible{transition:transform .4s ease-out;}' +
102      /* Collapsed transitions */
103      '.uvw1-footer .uvw1-footer-logos{transition:opacity .3s ease;}' +
104      '.uvw1-footer .uvw1-stars,' +
105      '.uvw1-footer .uvw1-mobile-text,' +
106      '.uvw1-footer .uvw1-footer-text,' +
107      '.uvw1-footer .uvw1-footer-close{transition:opacity .3s ease,max-height .3s ease;overflow:hidden;}
107' +
108      /* Collapsed: hide logos */
109      '.uvw1-footer.uvw1-collapsed .uvw1-footer-logos{opacity:0!important;width:0!important;margin:0!important;pointer-events:none;}' +
110      /* Collapsed: hide stars, text, close */
111      '.uvw1-footer.uvw1-collapsed .uvw1-stars,' +
112      '.uvw1-footer.uvw1-collapsed .uvw1-mobile-text,' +
113      '.uvw1-footer.uvw1-collapsed .uvw1-footer-text,' +
114      '.uvw1-footer.uvw1-collapsed .uvw1-footer-close{' +
115        'opacity:0!important;max-height:0!important;margin:0!important;padding:0!important;pointer-events:none;' +
116      '}' +
117      '.uvw1-footer.uvw1-collapsed .uvw1-footer-inner{padding:8px 20px;transition:padding .3s ease;}' +
118      '.uvw1-footer.uvw1-collapsed .uvw1-footer-row{margin-bottom:0;justify-content:center;transition:margin .3s ease;}' +
119      '.uvw1-footer.uvw1-collapsed .uvw1-brand-info{margin-left:0;margin-right:15px;}' +
120      '.uvw1-footer.uvw1-collapsed .uvw1-brand-name{font-size:16px;font-weight:600;}' +
121      '.uvw1-footer.uvw1-collapsed .uvw1-footer-btn.uvw1-desktop-only{padding:10px 25px;margin-right:0;}' +
122      /* Inner container */
123      '.uvw1-footer-inner{padding:12px 20px;position:relative;max-width:1000px;margin:0 auto;box-sizing:border-box;}' +
124      /* Close button */
125      '.uvw1-footer-close{' +
126        'position:absolute;top:5px;right:10px;background:rgba(255,255,255,.1);border:none;' +
127        'color:rgba(255,255,255,.7);cursor:pointer;font-size:20px;line-height:.8;' +
128        'padding:2px 8px;z-index:10;border-radius:4px;transition:background .2s,color .2s;' +
129      '}' +
130      '.uvw1-footer-close:hover{background:rgba(255,255,255,.2);color:#fff;}' +
131      /* Footer row */
132      '.uvw1-footer-row{display:flex;align-items:center;justify-content:flex-start;margin-bottom:10px;padding-top:2px;}' +
133      /* Logos section */
134      '.uvw1-footer-logos{display:flex;align-items:center;margin-left:25px;}' +
135      /* Logo cards */
136      '.uvw1-logo-card{' +
137        'width:60px;height:42px;border-radius:10px;display:flex;align-items:center;justify-content:center;' +
138        'font-weight:bold;font-size:16px;text-align:center;position:relative;' +
139        'box-shadow:0 2px 8px rgba(0,0,0,.15);background-color:#333;color:#f0f0f0;' +
140      '}' +
141      '.uvw1-logo-card.uvw1-logo-old{opacity:.5;}' +
142      '.uvw1-logo-card.uvw1-logo-old img{opacity:.7!important;}' +
143      '.uvw1-logo-card img{max-width:100%;max-height:100%;object-fit:contain;}' +
144      /* Badges */
145      '.uvw1-badge-x{' +
146        'position:absolute;top:-6px;left:-6px;width:16px;height:16px;background-color:#f44336;' +
147        'border-radius:50%;display:flex;align-items:center;justify-content:center;' +
148        'font-weight:bold;font-size:10px;color:white;box-shadow:0 2px 4px rgba(0,0,0,.2);' +
149      '}' +
150      '.uvw1-badge-ok{' +
151        'position:absolute;top:-6px;right:-6px;width:16px;height:16px;background-color:#4CAF50;' +
152        'border-radius:50%;display:flex;align-items:center;justify-content:center;' +
153        'font-size:10px;color:white;box-shadow:0 2px 4px rgba(0,0,0,.2);' +
154      '}' +
155      /* Arrow between logos */
156      '.uvw1-footer-arrow{margin:0 12px;color:#93c5fd;font-size:16px;animation:uvw1-arrowPulse 1.5s ease-in-out infinite;}' +
157      '@keyframes uvw1-arrowPulse{0%,100%{transform:translateX(0);opacity:.7}50%{transform:translateX(3px);opacity:1}}' +
158      /* Brand info */
159      '.uvw1-brand-info{margin-left:22px;}' +
160      '.uvw1-brand-name{color:white;font-weight:800;font-size:16px;margin:0;text-shadow:0 1px 3px rgba(0,0,0,.5);text-decoration:none;}' +
161      '.uvw1-brand-name:hover{text-decoration:none;}' +
162      '.uvw1-stars{color:#f59e0b;font-size:12px;margin:2px 0 0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif!important;}' +
163      '.uvw1-star{display:inline-block;color:#f59e0b;animation:uvw1-starTwinkle 2.5s ease-in-out infinite;}' +
164      '.uvw1-star:nth-child(1){animation-delay:0s}' +
165      '.uvw1-star:nth-child(2){animation-delay:.2s}' +
166      '.uvw1-star:nth-child(3){animation-delay:.4s}' +
167      '.uvw1-star:nth-child(4){animation-delay:.6s}' +
168      '.uvw1-star:nth-child(5){animation-delay:.8s}' +
169      '@keyframes uvw1-starTwinkle{0%,100%{opacity:.6;transform:scale(1)}50%{opacity:1;transform:scale(1.1)}}' +
170      /* Footer text */
171      '.uvw1-footer-text{color:rgba(255,255,255,.95);font-size:13px;line-height:1.4;flex:1;margin:0 15px;max-width:400px;}
171' +
172      '.uvw1-footer-text.uvw1-desktop-only{display:none;}' +
173      /* Mobile text row */
174      '.uvw1-mobile-text{display:flex;align-items:center;justify-content:space-between;}' +
175      /* CTA button */
176      '.uvw1-footer-btn{' +
177        'font-weight:bold;padding:12px 20px;border-radius:6px;border:none;cursor:pointer;' +
178        'text-transform:uppercase;font-size:15px;white-space:normal;text-align:center;flex-shrink:0;' +
179        'color:#fff;text-shadow:0 1px 2px rgba(0,0,0,.3);' +
180        'box-shadow:0 2px 15px rgba(0,0,0,.3);' +
181        'transition:transform .3s ease,box-shadow .3s ease;' +
182        'background-size:300% 300%;' +
183        'animation:uvw1-gradientShift 4s ease infinite,uvw1-footerPulse 5s ease-in-out infinite;' +
184        'word-break:normal;overflow-wrap:break-word;letter-spacing:-.3px;line-height:1.1;' +
185      '}' +
186      '.uvw1-footer-btn:hover{transform:translateY(-2px);box-shadow:0 4px 20px rgba(0,0,0,.4);}' +
187      '@keyframes uvw1-footerPulse{0%,100%{transform:scale(1)}5%{transform:scale(1.05)}10%{transform:scale(1)}15%{transform:scale(1.05)}20%,100%{transform:scale(1)}}' +
188      /* Button arrow */
189      '.uvw1-btn-arrow{display:inline-block;margin-left:8px;font-size:1.3em;font-weight:bold;vertical-align:middle;line-height:1;position:relative;top:-3px;animation:uvw1-btnArrowPulse 1.2s ease-in-out infinite;}' +
190      '@keyframes uvw1-btnArrowPulse{0%,100%{transform:translateX(0)}50%{transform:translateX(4px)}}' +
191
192      /* ---- Floating gift icon ---- */
193      '.uvw1-float-icon{position:fixed;right:15px;top:50%;transform:translateY(-50%);z-index:9990;cursor:pointer;display:none;}' +
194      '.uvw1-float-icon.uvw1-visible{display:block;animation:uvw1-iconAppear .5s cubic-bezier(.34,1.56,.64,1);}' +
195      '.uvw1-float-icon.uvw1-winner{animation:uvw1-iconPulse 2s ease-in-out infinite;}' +
196      '@keyframes uvw1-iconAppear{from{transform:translateY(-50%) scale(0) rotate(-180deg);opacity:0}
196to{transform:translateY(-50%) scale(1) rotate(0);opacity:1}}' +
197      '@keyframes uvw1-iconPulse{0%,100%{transform:translateY(-50%) scale(1)}50%{transform:translateY(-50%) scale(1.15)}}' +
198      '.uvw1-float-icon img{width:55px;height:auto;display:block;filter:drop-shadow(0 4px 8px rgba(0,0,0,.4));transition:transform .2s,filter .2s;animation:uvw1-iconWiggle 5s ease-in-out infinite;}' +
199      '@keyframes uvw1-iconWiggle{0%,85%,100%{transform:rotate(0) scale(1)}88%{transform:rotate(-8deg) scale(1.05)}91%{transform:rotate(8deg) scale(1.05)}94%{transform:rotate(-5deg) scale(1.02)}97%{transform:rotate(3deg) scale(1.01)}}' +
200      '.uvw1-float-icon:hover img{transform:scale(1.1);filter:drop-shadow(0 6px 12px rgba(0,0,0,.5));animation:none;}' +
201
202      /* ---- Popup overlay ---- */
203      '.uvw1-overlay{position:fixed;inset:0;background:rgba(0,0,0,.85);backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);display:none;align-items:flex-start;justify-content:center;z-index:9999;opacity:0;transition:opacity .4s;padding:20px;overflow-y:auto;-webkit-overflow-scrolling:touch;}' +
204      '.uvw1-overlay.uvw1-show{display:flex;opacity:1;}' +
205      '.uvw1-popup-wrap{position:relative;max-width:420px;width:100%;flex-shrink:0;margin:auto;animation:uvw1-popupIn .5s cubic-bezier(.34,1.56,.64,1);}' +
206      '@keyframes uvw1-popupIn{from{transform:scale(.8) translateY(50px);opacity:0}to{transform:scale(1) translateY(0);opacity:1}}' +
207
208      /* Close button */
209      '.uvw1-popup-close{position:absolute;top:-7px;right:-7px;width:28px;height:28px;' +
210        "background:linear-gradient(180deg,#3a3a4a,#2a2a3a);border:2px solid #555;border-radius:50%;color:#ffd700;font-family:'VT323',monospace;font-size:18px;line-height:28px;" +
211        'text-align:center;cursor:pointer;display:flex;align-items:center;justify-content:center;z-index:10;opacity:0;visibility:hidden;text-shadow:0 0 8px #ffd700;' +
212        'box-shadow:0 3px 6px rgba(0,0,0,.5),inset 0 1px 0 rgba(255,255,255,.1);transition:opacity .3s,visibility .3s,transform .1s;}' +
213      '.uvw1-popup-close.uvw1-visible{opacity:1;visibility:visible;}' +
214      '.uvw1-popup-close:hover{transform:scale(1.1);text-shadow:0 0 12px #ffd700;border-color:#ffd700;background:linear-gradient(180deg,#4a4a5a,#3a3a4a);}' +
215
216      /* Machine body */
217      '.uvw1-machine{background:linear-gradient(180deg,#4a4a5a 0%,#3a3a4a 5%,#2a2a3a 50%,#1a1a2a 95%,#0a0a1a 100%);border-radius:20px;' +
218        'box-shadow:0 20px 60px rgba(0,0,0,.8),inset 0 2px 0 rgba(255,255,255,.1),inset 0 -2px 0 rgba(0,0,0,.3);border:4px solid #555;border-top-color:#777;border-bottom-color:#333;overflow:hidden;}' +
219
220      /* Brand switch LED panel */
221      '.uvw1-brand-panel{background:linear-gradient(180deg,#0a0a12,#050508);padding:12px 20px;margin:10px;border-radius:8px;border:2px solid #333;' +
222        'box-shadow:inset 0 0 20px rgba(0,0,0,.8),0 2px 4px rgba(0,0,0,.3),0 0 15px rgba(100,150,255,.1);}' +
223      ".uvw1-brand-title{display:flex;align-items:center;justify-content:center;gap:8px;margin-bottom:12px;font-family:'VT323',monospace;font-size:18px;color:#ccc;text-transform:uppercase;letter-spacing:1px;white-space:nowrap;overflow:hidden;}" +
224      '.uvw1-brand-title-flag{font-size:18px;position:relative;top:2px;}' +
225      '.uvw1-brand-logos{display:flex;align-items:center;justify-content:center;gap:18px;}' +
226      '.uvw1-brand-logo-wrap{display:flex;align-items:center;position:relative;}' +
227      '.uvw1-brand-logo-wrap.uvw1-old{overflow:visible;}' +
228      ".uvw1-brand-blocked{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%) rotate(-15deg);font-family:'VT323','Courier New',monospace;font-size:14px;line-height:1;color:#fff;background:rgba(180,30,30,.85);padding:0 4px 1px;border-radius:2px;text-transform:uppercase;letter-spacing:.5px;white-space:nowrap;box-shadow:0 2px 6px rgba(0,0,0,.3);z-index:2;}" +
229      '.uvw1-brand-logo-img{max-height:50px;max-width:120px;object-fit:contain;}' +
230      '.uvw1-old .uvw1-brand-logo-img{filter:grayscale(1) opacity(.4);}' +
231      '.uvw1-new .uvw1-brand-logo-img{filter:drop-shadow(0 0 8px rgba(100,255,100,.6));cursor:pointer;}' +
232      ".uvw1-brand-arrow{font-family:'VT323',monospace;font-size:24px;color:#ffd700;text-shadow:0 0 8px #ffd700,0 0 15px rgba(255,215,0,.5);animation:uvw1-arrowPulseP .8s ease-in-out infinite;}" +
233      '@keyframes uvw1-arrowPulseP{0%,100%{transform:translateX(0);opacity:1}50%{transform:translateX(4px);opacity:.8}}' +
234
235      /* Game area */
236      '.uvw1-game-area{background:linear-gradient(180deg,#0a0a12,#050508);margin:15px;border-radius:10px;border:3px solid #333;border-top-color:#444;border-bottom-color:#222;' +
237        'box-shadow:inset 0 0 40px rgba(0,0,0,.9),0 4px 8px rgba(0,0,0,.5),0 0 20px rgba(100,150,255,.1);padding:12px;overflow:visible;}' +
238
239      /* Ticker */
240      '.uvw1-ticker-wrap{padding:6px 10px;overflow:hidden;position:relative;margin-bottom:5px;border-bottom:1px solid rgba(255,140,0,.2);}' +
241      ".uvw1-ticker-wrap::before,.uvw1-ticker-wrap::after{content:'';position:absolute;top:0;bottom:0;width:30px;z-index:2;}" +
242      '.uvw1-ticker-wrap::before{left:0;background:linear-gradient(90deg,#0a0a12 30%,transparent);}' +
243      '.uvw1-ticker-wrap::after{right:0;background:linear-gradient(-90deg,#0a0a12 30%,transparent);}' +
244      ".uvw1-ticker-text{font-family:'VT323',monospace;font-size:24px;color:#ff8c00;letter-spacing:1px;text-shadow:0 0 4px #ff8c00;white-space:nowrap;display:inline-block;animation:uvw1-marquee 15s linear infinite;will-change:transform;transform:translateZ(0);}" +
245      '@keyframes uvw1-marquee{0%{transform:translateX(0)}100%{transform:translateX(-50%)}}' +
246
247      /* Reels */
248      '.uvw1-reels-wrap{margin-bottom:12px;padding:10px;background:rgba(0,0,0,.4);border-radius:10px;box-shadow:0 0 20px rgba(100,150,255,.15),inset 0 0 15px rgba(0,0,0,.5);display:flex;justify-content:center;gap:10px;}' +
249      '.uvw1-reel{width:85px;height:95px;overflow:hidden;background:#050505;border-radius:6px;border:3px solid #333;border-top-color:#222;border-bottom-color:#444;position:relative;box-shadow:0 4px 8px rgba(0,0,0,.5),inset 0 0 30px rgba(0,0,0,.9);}' +
250      ".uvw1-reel::after{content:'';position:absolute;inset:0;background:linear-gradient(180deg,rgba(0,0,0,.7) 0%,transparent 30%,transparent 70%,rgba(0,0,0,.7) 100%);z-index:3;pointer-events:none;}" +
251      '.uvw1-reel.uvw1-cracked{animation:uvw1-reelShake .5s ease-out;}' +
252      '.uvw1-reel.uvw1-cracked .uvw1-reel-sym{animation:uvw1-bgPulse .4s ease-in-out infinite;}' +
253      '@keyframes uvw1-reelShake{0%,100%{transform:translateX(0)}10%{transform:translateX(-4px) rotate(-1deg)}20%{transform:translateX(4px) rotate(1deg)}30%{transform:translateX(-4px) rotate(-1deg)}40%{transform:translateX(4px) rotate(1deg)}50%{transform:translateX(-2px)}60%{transform:translateX(2px)}70%{transform:translateX(-1px)}80%{transform:translateX(1px)}}' +
254      '@keyframes uvw1-bgPulse{0%,100%{background:linear-gradient(180deg,#ff9999,#ffaaaa 20%,#ffcccc 50%,#ffaaaa 80%,#ff9999)}50%{background:linear-gradient(180deg,#e8e8f0,#f5f5ff 20%,#fff 50%,#f5f5ff 80%,#e8e8f0)}}' +
255      '.uvw1-reel-strip{display:flex;flex-direction:column;transition:transform .1s linear;}' +
256      '.uvw1-reel-strip.uvw1-spinning{transition:none;filter:blur(2px);}' +
257      '.uvw1-reel-strip.uvw1-stopping{transition:transform .6s cubic-bezier(.25,.1,.25,1),filter .3s;filter:blur(0);}' +
258      '.uvw1-reel-sym{width:100%;height:95px;display:flex;align-items:center;justify-content:center;font-size:48px;' +
259        'background:linear-gradient(180deg,#e8e8f0,#f5f5ff 20%,#fff 50%,#f5f5ff 80%,#e8e8f0);border-bottom:1px solid #ccc;border-top:1px solid #fff;box-shadow:inset 0 0 20px rgba(200,220,255,.5);}' +
260
261      /* Hearts/Lives */
262      '.uvw1-hearts{display:flex;justify-content:center;align-items:center;gap:8px;padding:12px 0;}' +
263      ".uvw1-hearts-label{font-family:'VT323',monospace;font-size:18px;color:#fff;margin-right:8px;text-shadow:0 0 5px #fff;}" +
264      ".uvw1-heart{width:28px;height:28px;background:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAOtwAADrcBHI9bQQAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAKLSURBVFiF1ZbBaxNBFMZ/m8RabcGahlA8FD1IvfRSvIhHoQdPHnr1UnLVq96LiBaE/gFV+xcoeCgNCCKIYKFUeylUsDGXRqNpklojyeZ5mNnd2c1mE0JI2g+GGd6b9/bt+76dHWjFIiARIx8S4yDfIXYxGBCLSDYQWMb6NXBjAhJ3IQkQB7H9e9iCfx+gDPwAZrV5B0jfhAtzcBbgOnAGaIIc6xzLUNmDGvARuBMsxgYkDSIRI+NvqQNB+4L7t0Ee6zHnxdlO4ImgQABWQG6D1QCuzcyotxsbE2zb4vBQyOViADmQOljfgVs6yVtgGhgBmQ5QVgI50LZXqP7nQV4a+wSQdbN1DhqNhoiILC01g60tGVSUOtDmjCeaivtG7FAoMMWTaPHGjJqmpuIUixBoK8BEIFE3GAcqwI4KtWDAIqzq+YrxQm4Hak5V8ThkMspo226lBsJsUT7X5ih+0nC6BYw6gfU6rK465rAHtXt4x/1NPZ83nAOlwKmkadjcAmqOppJJ2NhQY2EhTGdR2ovcP6rnScPWSkEiAfPzypjN9pWCEeAvcM6wDZSCWGAGf8U2EEsDhT4+tAC80OtHwJFaNoF4sJihwDwJy8BFAfmqO5MCmejxHPgC1IGfIL+0TTx/Oaoo90q21eVPJmw81T+eeyf9Stb6M4J3qOsWy5BKQewS8NDzt6XgG0hW+94Dv4E/SnBFI7cPUd80qGBrFsVpJ3wG1vV6BTjwCm7b6aFT0C3W0ELaDxHcMy24B37BrXWTeOgdCBNhGHadxba+lB7h3a0rqBOu4BfoLl2gkwjDIABX8T7q58BejzlPDQUmPgGXqzD+Rl9uqnCMYmG/j7V1xCae4jd7TTJ0Cv4DKZdBhaN0klIAAAAASUVORK5CYII=') center/contain no-repeat;image-rendering:pixelated;transition:all .3s;}" +
265      '.uvw1-heart.uvw1-active{animation:uvw1-heartBeat .8s ease-in-out infinite;filter:drop-shadow(0 0 10px #ff0040);}' +
266      '.uvw1-heart.uvw1-used{opacity:.85;filter:grayscale(1) brightness(1.1) drop-shadow(0 0 6px #ff0040);transform:scale(.75);}' +
267      '.uvw1-heart.uvw1-burning{animation:uvw1-heartBurn .8s ease-out forwards;}' +
268      '.uvw1-heart.uvw1-win{animation:uvw1-heartWin .3s ease-in-out infinite;filter:drop-shadow(0 0 12px #ffd700) brightness(1.3) hue-rotate(40deg);}' +
269
270      /* Heart particles */
271      '.uvw1-heart-particle{position:fixed;width:8px;height:8px;background:#ff0040;border-radius:50%;pointer-events:none;z-index:10001;box-shadow:0 0 6px #ff0040,0 0 10px #ff4444;animation:uvw1-particleExplode .6s ease-out forwards;}' +
272      '.uvw1-heart-particle:nth-child(odd){background:#ff4466;}' +
273      '.uvw1-heart-particle:nth-child(3n){background:#ff6688;width:6px;height:6px;}
273' +
274      '@keyframes uvw1-particleExplode{0%{transform:translate(0,0) scale(1);opacity:1}100%{transform:translate(var(--tx),var(--ty)) scale(0);opacity:0}}' +
275      '@keyframes uvw1-heartBeat{0%,100%{transform:scale(1)}50%{transform:scale(1.15)}}' +
276      '@keyframes uvw1-heartBurn{0%{transform:scale(1);filter:drop-shadow(0 0 10px #ff0040) brightness(1);opacity:1}20%{transform:scale(1.3);filter:drop-shadow(0 0 20px #ff4444) drop-shadow(0 0 30px #ff0000) brightness(1.5)}40%{transform:scale(1.1) rotate(-10deg);filter:drop-shadow(0 0 15px #ff6600) brightness(1.3)}60%{transform:scale(.85) rotate(5deg);filter:drop-shadow(0 0 10px #ff3300) grayscale(.3) brightness(1)}80%{transform:scale(.8);filter:grayscale(.8) brightness(1.1);opacity:.9}100%{transform:scale(.75);filter:grayscale(1) brightness(1.1) drop-shadow(0 0 6px #ff0040);opacity:.85}}' +
277      '@keyframes uvw1-heartWin{0%,100%{transform:scale(1)}50%{transform:scale(1.2)}}' +
278      ".uvw1-hearts-count{font-family:'VT323',monospace;font-size:18px;color:#ffaa00;margin-left:12px;text-shadow:0 0 5px #ffaa00;}" +
279
280      /* Message area */
281      '.uvw1-msg-area{margin-top:8px;border-top:1px solid rgba(255,255,255,.1);padding-top:5px;}' +
282      ".uvw1-msg{text-align:center;padding:0 15px;font-family:'VT323',monospace;font-size:18px;font-weight:bold;height:36px;line-height:36px;color:#666;}" +
283      '.uvw1-dots{display:none;justify-content:center;align-items:center;gap:6px;height:36px;}' +
284      '.uvw1-dots.uvw1-active{display:flex;}' +
285      '.uvw1-dot{width:6px;height:6px;background:#fff;opacity:.3;animation:uvw1-dotBlink .8s steps(1) infinite;}' +
286      '.uvw1-dot:nth-child(1){animation-delay:0s}.uvw1-dot:nth-child(2){animation-delay:.25s}.uvw1-dot:nth-child(3){animation-delay:.5s}' +
287      '@keyframes uvw1-dotBlink{0%,50%{opacity:.3}25%{opacity:1;box-shadow:0 0 6px #fff}}' +
288      '.uvw1-msg.uvw1-press-spin{color:#ffd700;text-shadow:0 0 10px #ffd700,0 0 20px rgba(255,215,0,.5);line-height:1.4;height:auto;}' +
289      '.uvw1-msg.uvw1-press-spin .uvw1-arrow-down{display:inline-block;font-size:22px;animation:uvw1-arrowDown .6s ease-in-out infinite;}' +
290      '@keyframes uvw1-arrowDown{0%,100%{transform:translateY(0);opacity:1}50%{transform:translateY(4px);opacity:.6}}' +
291      '.uvw1-msg.uvw1-try-again{color:#ff8c00;text-shadow:0 0 4px #ff8c00;animation:uvw1-msgBlink .5s ease-in-out 3;}' +
292      '.uvw1-msg.uvw1-winner-msg{color:#fff;font-size:20px;text-shadow:0 0 5px rgba(255,255,255,.6);animation:uvw1-msgWin .3s ease-in-out infinite;}' +
293      '@keyframes uvw1-msgBlink{0%,100%{opacity:1}50%{opacity:.5}}' +
294      '@keyframes uvw1-msgWin{0%,100%{transform:scale(1)}50%{transform:scale(1.02)}}' +
295
296      /* Prize section */
297      '.uvw1-prize-section{padding:5px 15px 7px;text-align:center;display:none;}' +
298      '.uvw1-prize-section.uvw1-revealed{display:block;animation:uvw1-prizeReveal .5s ease-out;}' +
299      '@keyframes uvw1-prizeReveal{from{transform:scale(.8);opacity:0}to{transform:scale(1);opacity:1}}' +
300      ".uvw1-prize-value{font-family:'VT323',monospace;font-size:32px;font-weight:bold;color:#ffdd00;text-shadow:0 0 8px #ffdd00,0 0 15px rgba(255,221,0,.4);animation:uvw1-ledGlow 2s ease-in-out infinite;white-space:nowrap;}" +
301      '.uvw1-prize-detail-span{font-size:32px;color:#ffcc00;text-shadow:0 0 8px #ffcc00;}' +
302      ".uvw1-prize-sub{font-family:'VT323',monospace;font-size:16px;color:#888;margin-top:6px;}" +
303      '@keyframes uvw1-ledGlow{0%,100%{text-shadow:0 0 15px #ffdd00,0 0 30px rgba(255,221,0,.5)}50%{text-shadow:0 0 25px #ffdd00,0 0 50px rgba(255,221,0,.8)}}' +
304
305      /* Buttons */
306      ".uvw1-slot-btn{width:90%;margin:0 auto 15px;padding:12px 16px;font-family:'VT323',monospace;font-size:18px;font-weight:bold;color:#fff;" +
307        'border:3px solid #666;border-top-color:#888;border-left-color:#777;border-bottom-color:#444;border-right-color:#555;border-radius:8px;cursor:pointer;text-transform:uppercase;text-decoration:none;' +
308        'letter-spacing:1px;display:flex;align-items:center;justify-content:center;gap:10px;text-shadow:0 2px 3px rgba(0,0,0,.6);transition:all .08s;}
308' +
309      '.uvw1-spin-btn{background:radial-gradient(ellipse at 50% 30%,#ff7788,#ff3344 40%,#dd1122 80%,#bb0011);' +
310        'box-shadow:inset 0 3px 6px rgba(255,255,255,.3),inset 0 -3px 6px rgba(0,0,0,.4),0 4px 0 #880011,0 6px 10px rgba(0,0,0,.5),0 0 15px rgba(255,50,50,.4),0 0 30px rgba(255,50,50,.2);' +
311        'border-color:#ff5566;animation:uvw1-spinPulse 1s ease-in-out infinite;}' +
312      '@keyframes uvw1-spinPulse{0%,100%{transform:scale(1);box-shadow:inset 0 3px 6px rgba(255,255,255,.3),inset 0 -3px 6px rgba(0,0,0,.4),0 4px 0 #880011,0 6px 10px rgba(0,0,0,.5),0 0 15px rgba(255,50,50,.4),0 0 30px rgba(255,50,50,.2)}50%{transform:scale(1.03);box-shadow:inset 0 3px 6px rgba(255,255,255,.4),inset 0 -3px 6px rgba(0,0,0,.3),0 4px 0 #880011,0 6px 10px rgba(0,0,0,.5),0 0 25px rgba(255,50,50,.5),0 0 45px rgba(255,50,50,.3)}}' +
313      '.uvw1-spin-btn:hover:not(:disabled){background:radial-gradient(ellipse at 50% 30%,#ff8899,#ff5566 40%,#ee2233 80%,#cc1122);}' +
314      '.uvw1-spin-btn:active:not(:disabled){box-shadow:inset 0 3px 8px rgba(0,0,0,.5),0 1px 0 #333,0 2px 5px rgba(0,0,0,.4);transform:translateY(3px);animation:none;}' +
315      '.uvw1-spin-btn:disabled{background:radial-gradient(ellipse at 50% 30%,#555,#444 40%,#333 80%,#222);border-color:#444;color:#666;cursor:not-allowed;animation:none;' +
316        'box-shadow:inset 0 3px 6px rgba(255,255,255,.1),inset 0 -3px 6px rgba(0,0,0,.4),0 4px 0 #222,0 6px 10px rgba(0,0,0,.5);}' +
317      '.uvw1-claim-btn{display:none;margin-top:0;font-size:24px;padding:14px 18px;' +
318        'background:radial-gradient(ellipse at 50% 30%,#ffaa44,#ff8800 40%,#dd6600 80%,#bb4400);' +
319        'box-shadow:inset 0 3px 6px rgba(255,255,255,.4),inset 0 -3px 6px rgba(0,0,0,.4),0 4px 0 #884400,0 6px 15px rgba(0,0,0,.5),0 0 20px rgba(255,140,0,.4),0 0 40px rgba(255,140,0,.2);' +
320        'color:#fff;text-shadow:0 2px 4px rgba(0,0,0,.9),0 0 10px rgba(0,0,0,.5);border-color:#ffaa44;animation:uvw1-claimPulse .8s ease-in-out infinite;text-decoration:none;}' +
321      '.uvw1-claim-btn.uvw1-show{display:flex;}' +
322      '.uvw1-claim-btn:hover{background:radial-gradient(ellipse at 50% 30%,#ffcc66,#ffaa44 40%,#ff8800 80%,#dd6600);' +
323        'box-shadow:inset 0 3px 6px rgba(255,255,255,.5),inset 0 -3px 6px rgba(0,0,0,.3),0 4px 0 #995500,0 6px 15px rgba(0,0,0,.5),0 0 30px rgba(255,140,0,.6),0 0 60px rgba(255,140,0,.3);}' +
324      '.uvw1-claim-btn:active{box-shadow:inset 0 3px 8px rgba(0,0,0,.5),0 1px 0 #333,0 2px 5px rgba(0,0,0,.4);transform:translateY(3px);animation:none;}' +
325      '@keyframes uvw1-claimPulse{0%,100%{transform:scale(1);box-shadow:inset 0 3px 6px rgba(255,255,255,.4),inset 0 -3px 6px rgba(0,0,0,.4),0 4px 0 #884400,0 6px 15px rgba(0,0,0,.5),0 0 20px rgba(255,140,0,.4),0 0 40px rgba(255,140,0,.2)}50%{transform:scale(1.05);box-shadow:inset 0 3px 6px rgba(255,255,255,.5),inset 0 -3px 6px rgba(0,0,0,.3),0 4px 0 #884400,0 6px 15px rgba(0,0,0,.5),0 0 35px rgba(255,140,0,.6),0 0 60px rgba(255,140,0,.4)}}' +
326
327      /* Machine winner state */
328      '.uvw1-machine.uvw1-winner{animation:uvw1-machineShake .5s ease-in-out;}' +
329      '.uvw1-machine.uvw1-winner .uvw1-reel-sym{background:linear-gradient(180deg,#fff8e0,#fffef5 20%,#fffff0 50%,#fffef5 80%,#fff8e0);' +
330        'box-shadow:inset 0 0 25px rgba(255,215,0,.4),0 0 15px rgba(255,215,0,.6);animation:uvw1-symbolGlow .3s ease-in-out infinite alternate;}' +
331      '.uvw1-machine.uvw1-winner .uvw1-game-area{box-shadow:inset 0 0 30px rgba(0,0,0,.6),0 0 30px rgba(255,215,0,.5),0 0 50px rgba(255,180,0,.3);}' +
332      '@keyframes uvw1-symbolGlow{from{box-shadow:inset 0 0 25px rgba(255,215,0,.3),0 0 10px rgba(255,215,0,.4)}to{box-shadow:inset 0 0 30px rgba(255,215,0,.5),0 0 20px rgba(255,215,0,.8)}}' +
333      '@keyframes uvw1-machineShake{0%,100%{transform:translateX(0)}20%{transform:translateX(-5px) rotate(-1deg)}40%{transform:translateX(5px) rotate(1deg)}60%{transform:translateX(-5px) rotate(-1deg)}80%{transform:translateX(5px) rotate(1deg)}}' +
334
335      /* Coin fall */
336      '.uvw1-coin-fall{position:fixed;top:-30px;z-index:10000;animation:uvw1-coinFall 3s ease-out forwards;}' +
337      '@keyframes uvw1-coinFall{from{transform:translateY(0) rotate(0);opacity:1}to{transform:translateY(100vh) rotate(720deg);opacity:0}
337}' +
338
339      /* Timer */
340      '.uvw1-timer{display:none;align-items:center;justify-content:center;gap:6px;margin:5px 0;}' +
341      '.uvw1-timer.uvw1-show{display:flex;}' +
342      ".uvw1-timer-label{font-family:'VT323',monospace;font-size:16px;color:#888;}" +
343      '.uvw1-timer-value{color:#ff6666;text-shadow:0 0 8px rgba(255,100,100,.6);}' +
344      '.uvw1-timer.uvw1-urgent .uvw1-timer-value{color:#ff3333;animation:uvw1-urgentBlink .5s ease-in-out infinite;}' +
345      '@keyframes uvw1-urgentBlink{0%,100%{opacity:1;text-shadow:0 0 10px #ff3333}50%{opacity:.7;text-shadow:0 0 5px #ff3333}}' +
346
347      /* ---- Banner popup ---- */
348      '.uvw1-banner{position:relative;border-radius:18px;overflow:hidden;width:100%;' +
349        'box-shadow:0 0 30px rgba(255,215,0,.15),0 20px 60px rgba(0,0,0,.7);border:1px solid rgba(255,215,0,.2);}' +
350      '.uvw1-banner-bg{position:absolute;inset:0;background-size:cover;background-position:center;z-index:0;}' +
351      '.uvw1-banner-bg::after{content:"";position:absolute;inset:0;background:linear-gradient(180deg,rgba(0,0,0,.45) 0%,rgba(0,0,0,.7) 40%,rgba(0,0,0,.92) 100%);}' +
352
353      /* Warning strip */
354      '.uvw1-banner-warning{position:relative;z-index:1;background:linear-gradient(135deg,rgba(180,40,40,.35),rgba(120,30,30,.15));' +
355        'border-bottom:1px solid rgba(255,80,80,.15);padding:14px 20px;text-align:center;}' +
356      '.uvw1-banner-warn-icon{display:inline-block;width:18px;height:18px;background:#d44;border-radius:50%;color:#fff;font-size:12px;font-weight:900;' +
357        'line-height:18px;text-align:center;margin-right:6px;vertical-align:middle;flex-shrink:0;}' +
358      '@keyframes uvw1-warnPulse{0%,100%{box-shadow:0 0 0 0 rgba(204,51,51,.6)}50%{box-shadow:0 0 0 6px rgba(204,51,51,0)}}' +
359      '.uvw1-banner-restricted{color:#ff8a8a;font-size:14px;font-weight:600;line-height:1.5;display:inline;}' +
360      '.uvw1-banner-restricted .uvw1-banner-oldname{color:#fff;font-weight:800;}' +
361
362      /* Content area */
363      '.uvw1-banner-body{position:relative;z-index:1;display:flex;flex-direction:column;align-items:center;padding:22px 24px 24px;text-align:center;}' +
364      '.uvw1-banner-recommend{color:rgba(255,255,255,.45);font-size:11px;text-transform:uppercase;letter-spacing:2px;margin-bottom:18px;}' +
365
366      /* Logo with glow + pulse */
367      '.uvw1-banner-logo-wrap{position:relative;margin-bottom:14px;padding-bottom:14px;border-bottom:1px solid rgba(255,255,255,.08);}' +
368      '.uvw1-banner-logo-wrap::before{content:"";position:absolute;inset:-20px;background:radial-gradient(ellipse,rgba(255,215,0,.15) 0%,transparent 70%);z-index:0;animation:uvw1-logoGlow 3s ease-in-out infinite;}' +
369      '.uvw1-banner-logo{position:relative;z-index:1;max-height:55px;max-width:190px;object-fit:contain;filter:drop-shadow(0 2px 10px rgba(0,0,0,.4));animation:uvw1-logoPulse 3s ease-in-out infinite;}' +
370      '@keyframes uvw1-logoGlow{0%,100%{opacity:.6;transform:scale(1)}50%{opacity:1;transform:scale(1.1)}}' +
371      '@keyframes uvw1-logoPulse{0%,100%{transform:scale(1);filter:drop-shadow(0 2px 10px rgba(0,0,0,.4))}50%{transform:scale(1.03);filter:drop-shadow(0 0 18px rgba(255,215,0,.3))}}' +
372
373      /* Bonus card */
374      '.uvw1-banner-bonus{background:linear-gradient(135deg,rgba(255,255,255,.07),rgba(255,255,255,.02));' +
375        'border:1px solid rgba(255,255,255,.08);border-radius:12px;padding:16px 20px;margin-bottom:20px;width:100%;box-sizing:border-box;}' +
376      '.uvw1-banner-bonus-label{font-size:11px;color:rgba(255,255,255,.45);text-transform:uppercase;letter-spacing:2.5px;margin-bottom:8px;font-weight:600;}' +
377      ".uvw1-banner-prize-line{font-size:20px;font-weight:800;color:#fff;font-family:'Arial Black',Arial,sans-serif;line-height:1.3;}" +
378      ".uvw1-banner-prize-line .uvw1-banner-pct{color:#ffd700;text-shadow:0 0 20px rgba(255,215,0,.4);}" +
379      '.uvw1-banner-sub{font-size:11px;color:rgba(255,215,0,.6);margin-top:10px;text-transform:uppercase;letter-spacing:1.5px;font-weight:600;}' +
380      '.uvw1-banner-exclusive{margin-top:12px;font-size:10px;color:rgba(255,255,255,.35);letter-spacing:.5px;}' +
381      '.uvw1-banner-timer{margin-top:14px;width:100%;}' +
382      '.uvw1-banner-timer-text{font-size:10px;color:rgba(255,255,255,.35);letter-spacing:.5px;margin-bottom:5px;}' +
383      '.uvw1-banner-timer-text span{color:rgba(255,255,255,.6);font-variant-numeric:tabular-nums;}' +
384      '.uvw1-banner-timer-bar{width:100%;height:3px;background:rgba(255,255,255,.08);border-radius:2px;overflow:hidden;}
384' +
385      '.uvw1-banner-timer-fill{height:100%;background:linear-gradient(90deg,#22c55e,#16a34a);border-radius:2px;width:0%;}' +
386
387      /* CTA button */
388      '.uvw1-banner-btn{display:block;width:100%;padding:15px 20px;border-radius:12px;border:none;cursor:pointer;font-size:16px;font-weight:800;' +
389        'color:#fff;text-decoration:none;text-transform:uppercase;letter-spacing:1.5px;text-align:center;box-sizing:border-box;position:relative;overflow:hidden;' +
390        'background:linear-gradient(135deg,#22c55e,#16a34a,#15803d);background-size:200% 200%;' +
391        'animation:uvw1-bannerBtnShift 3s ease infinite,uvw1-bannerBtnPulse 2s ease-in-out infinite;' +
392        'box-shadow:0 4px 20px rgba(34,197,94,.3);transition:transform .2s,box-shadow .2s;}' +
393      '.uvw1-banner-btn::after{content:"";position:absolute;top:0;left:-100%;width:60%;height:100%;' +
394        'background:linear-gradient(105deg,transparent 30%,rgba(255,255,255,.25) 50%,transparent 70%);animation:uvw1-btnShine 3s ease-in-out infinite;}' +
395      '.uvw1-banner-btn:hover{transform:translateY(-2px);box-shadow:0 8px 30px rgba(34,197,94,.4);}' +
396      '@keyframes uvw1-bannerBtnShift{0%,100%{background-position:0% 50%}50%{background-position:100% 50%}}' +
397      '@keyframes uvw1-bannerBtnPulse{0%,100%{box-shadow:0 4px 20px rgba(34,197,94,.3)}50%{box-shadow:0 4px 28px rgba(34,197,94,.5)}}' +
398      '@keyframes uvw1-btnShine{0%,70%{left:-100%}100%{left:150%}}' +
399
400      /* Close button — small, inside banner */
401      '.uvw1-banner-close{position:absolute;top:8px;right:8px;width:22px;height:22px;' +
402        'background:rgba(0,0,0,.3);border:none;border-radius:50%;color:rgba(255,255,255,.5);font-size:14px;line-height:1;' +
403        'cursor:pointer;display:flex;align-items:center;justify-content:center;z-index:10;padding-bottom:4px;' +
404        'opacity:0;transition:opacity .3s,color .2s;}' +
405      '.uvw1-banner-close.uvw1-visible{opacity:1;}' +
406      '.uvw1-banner-close:hover{color:#fff;}' +
407
408      /* Entrance animation */
409      '@keyframes uvw1-bannerIn{from{opacity:0;transform:scale(.92) translateY(20px)}to{opacity:1;transform:scale(1) translateY(0)}}' +
410      '.uvw1-popup-wrap .uvw1-banner{animation:uvw1-bannerIn .4s cubic-bezier(.16,1,.3,1) forwards;}' +
411
412      /* ---- Responsive: banner mobile ---- */
413      '@media(max-width:480px){' +
414        '.uvw1-banner-warning{padding:16px 28px;}' +
415      '}' +
416
417      /* ---- Wallet sticky footer ---- */
418      '.uvw1-wallet{position:fixed;bottom:0;left:0;right:0;z-index:9990;transform:translateY(100%);transition:transform .5s cubic-bezier(.4,0,.2,1);}' +
419      '.uvw1-wallet.uvw1-show{transform:translateY(0);}' +
420      '.uvw1-wallet-inner{background:linear-gradient(to right,#1a365d,#4a3880);border-top:1px solid rgba(59,130,246,.5);padding:14px 20px 12px;display:flex;align-items:center;justify-content:center;gap:16px;flex-wrap:nowrap;}' +
421      '.uvw1-wallet-close{position:absolute;top:6px;right:8px;background:none;border:none;color:rgba(255,255,255,.4);font-size:16px;cursor:pointer;padding:2px 6px;transition:color .2s;}' +
422      '.uvw1-wallet-close:hover{color:#fff;}' +
423      '.uvw1-wallet-icon{font-size:28px;flex-shrink:0;animation:uvw1-walletPulse 2s ease-in-out infinite;}' +
424      '@keyframes uvw1-walletPulse{0%,100%{transform:scale(1)}50%{transform:scale(1.1)}}' +
425      '.uvw1-wallet-info{display:flex;flex-direction:column;gap:2px;min-width:0;}' +
426      '.uvw1-wallet-bonus{line-height:1.3;}' +
427      '.uvw1-wallet-bonus-label{color:rgba(255,255,255,.8);font-size:12px;font-weight:600;letter-spacing:.5px;}' +
428      '.uvw1-wallet-bonus-value{color:#ffd700;font-size:20px;font-weight:800;text-shadow:0 0 8px rgba(255,215,0,.3);}' +
429      '.uvw1-wallet-hurry{color:#ff6b6b;font-size:11px;font-weight:700;letter-spacing:.5px;animation:uvw1-hurryBlink 1.5s ease-in-out infinite;}' +
430      '@keyframes uvw1-hurryBlink{0%,100%{opacity:1}50%{opacity:.4}}' +
431      '.uvw1-wallet.uvw1-urgent .uvw1-wallet-inner{animation:uvw1-walletUrgent 1s ease-in-out infinite;}' +
432      '@keyframes uvw1-walletUrgent{0%,100%{border-top-color:rgba(255,68,68,.5)}50%{border-top-color:rgba(255,68,68,.15)}}' +
433      '.uvw1-wallet-btn{flex-shrink:0;padding:10px 24px;border-radius:10px;border:none;cursor:pointer;font-size:16px;font-weight:900;color:#fff;text-transform:uppercase;letter-spacing:1px;' +
434        'background:rgba(255,255,255,.06);box-shadow:0 1px 8px var(--glow,rgba(34,197,94,.2));transition:transform .2s,box-shadow .5s;position:relative;overflow:hidden;}
434' +
435      '.uvw1-wallet-btn::before{content:"";position:absolute;top:0;left:0;bottom:0;width:var(--progress,100%);' +
436        'background:linear-gradient(90deg,var(--fill-start,#22c55e),var(--fill-end,#16a34a));' +
437        'transition:width 1s linear,background .5s;z-index:0;' +
438        'box-shadow:inset 0 1px 0 rgba(255,255,255,.2),inset 0 -1px 0 rgba(0,0,0,.15);' +
439        '-webkit-mask:linear-gradient(#000,#000) left/calc(100% - 4px) 100% no-repeat,' +
440          'radial-gradient(circle 4px at left,#000 98%,transparent) right/4px 8px repeat-y;' +
441        'mask:linear-gradient(#000,#000) left/calc(100% - 4px) 100% no-repeat,' +
442          'radial-gradient(circle 4px at left,#000 98%,transparent) right/4px 8px repeat-y;' +
443        'animation:uvw1-flameEdge .8s linear infinite;}' +
444      '.uvw1-wallet-btn::after{content:"";position:absolute;top:0;left:-100%;width:60%;height:100%;' +
445        'background:linear-gradient(105deg,transparent 30%,rgba(255,255,255,.25) 50%,transparent 70%);animation:uvw1-btnShine 3s ease-in-out infinite;z-index:1;}' +
446      '.uvw1-wallet-btn:hover{transform:translateY(-1px);}' +
447      '.uvw1-wallet-btn span,.uvw1-wallet-btn .uvw1-btn-arrow{position:relative;z-index:2;text-shadow:0 1px 3px rgba(0,0,0,.4);}' +
448      '@keyframes uvw1-btnPulseGlow{0%,100%{box-shadow:0 1px 6px var(--glow,rgba(34,197,94,.2))}50%{box-shadow:0 1px 10px var(--glow,rgba(34,197,94,.35)),0 0 16px var(--glow,rgba(34,197,94,.15))}}' +
449      '@keyframes uvw1-flameEdge{0%{-webkit-mask-position:left top,right 0;mask-position:left top,right 0}100%{-webkit-mask-position:left top,right -8px;mask-position:left top,right -8px}}' +
450
451      /* ---- Responsive: wallet mobile ---- */
452      '@media(max-width:849px){' +
453        '.uvw1-wallet-inner{padding:12px 15px 10px;gap:8px;flex-wrap:wrap;}' +
454        '.uvw1-wallet-icon{font-size:24px;}' +
455        '.uvw1-wallet-info{flex-basis:100%;text-align:center;min-width:0;}' +
456        '.uvw1-wallet-bonus-value{font-size:18px;}' +
457        '.uvw1-wallet-bonus-label{margin-bottom:3px;}' +
458        '.uvw1-wallet-btn{flex-basis:100%;padding:12px 20px;font-size:17px;font-weight:900;border-radius:8px;}' +
459      '}' +
460
461      /* ---- Responsive: footer mobile ---- */
462      '@media(max-width:849px){' +
463        '.uvw1-footer-inner{display:flex;flex-direction:column;padding:12px 15px;position:relative;}' +
464        '.uvw1-footer-content{flex:1;display:flex;flex-direction:column;justify-content:center;}' +
465        '.uvw1-footer-close{top:3px;right:3px;font-size:16px;padding:2px 6px;}' +
466        '.uvw1-footer-row{margin-bottom:0;flex-wrap:nowrap;justify-content:center;padding-right:25px;}' +
467        '.uvw1-footer-logos{margin-left:0;}' +
468        '.uvw1-footer-arrow{margin:0 10px;}' +
469        '.uvw1-brand-info{margin-left:18px;}' +
470        '.uvw1-logo-card{width:55px;height:40px;}' +
471        '.uvw1-mobile-text{display:block;margin-top:8px;}' +
472        '.uvw1-footer-text.uvw1-in-mobile{display:block;text-align:center;font-size:12px;line-height:1.3;margin:0;max-width:none;}' +
473        '.uvw1-footer-btn:not(.uvw1-desktop-only){' +
474          'position:static;width:100%;box-sizing:border-box;margin-top:10px;padding:12px 20px;' +
475          'display:flex;align-items:center;justify-content:center;' +
476          'font-size:15px;font-weight:700;letter-spacing:.5px;line-height:1.2;border-radius:8px;' +
477        '}' +
478        '.uvw1-footer-btn:not(.uvw1-desktop-only) .uvw1-btn-arrow{top:-2px;}' +
479        '.uvw1-footer-btn.uvw1-desktop-only{display:none!important;}' +
480        '.uvw1-footer .uvw1-footer-row,.uvw1-footer .uvw1-mobile-text{' +
481          'transition:transform .5s cubic-bezier(.4,0,.2,1),opacity .5s cubic-bezier(.4,0,.2,1)!important;' +
482          'transform:translateY(0)!important;opacity:1!important;' +
483        '}' +
484        '.uvw1-footer.uvw1-collapsed .uvw1-footer-row,' +
485        '.uvw1-footer.uvw1-collapsed .uvw1-mobile-text{' +
486          'transform:translateY(-20px)!important;opacity:0!important;height:0!important;' +
487          'overflow:hidden!important;margin:0!important;padding:0!important;pointer-events:none!important;' +
488          'transition:transform .5s cubic-bezier(.4,0,.2,1),opacity .5s cubic-bezier(.4,0,.2,1),height .5s cubic-bezier(.4,0,.2,1)!important;' +
489        '}' +
490        '.uvw1-footer.uvw1-collapsed .uvw1-footer-btn:not(.uvw1-desktop-only){margin:0!important;}' +
491      '}' +
492      '@media(min-width:850px){' +
493        '.uvw1-footer-inner{padding:10px 15px;display:flex;align-items:center;}' +
494        '.uvw1-footer-btn:not(.uvw1-desktop-only){display:none!important;}' +
495        '.uvw1-footer-content{margin-bottom:0;flex:1;justify-content:space-between;display:flex;align-items:center;}' +
496        '.uvw1-mobile-text{display:none;}' +
497        '.uvw1-footer-text.uvw1-desktop-only{display:block!important;margin-left:25px;margin-right:20px;max-width:450px;font-size:12px;}' +
498        '.uvw1-footer-btn.uvw1-desktop-only{display:block!important;margin-right:30px;padding-top:14px;}' +
499        '.uvw1-footer-row{margin-bottom:0;flex:1;}' +
500        '.uvw1-brand-info{min-width:120px;flex-shrink:0;margin-right:0;}' +
501      '}' +
502      '@supports(padding-bottom:env(safe-area-inset-bottom)){.uvw1-footer{padding-bottom:env(safe-area-inset-bottom);}}' +
503      '@media(max-width:480px){' +
504        '.uvw1-overlay{padding:10px;}' +
505        '.uvw1-popup-wrap{max-width:100%;}' +
506        '.uvw1-machine{border-radius:16px;border-width:3px;}' +
507        '.uvw1-popup-close{right:5px;top:-5px;}' +
508        '.uvw1-reel{width:90px;height:100px;}' +
509        '.uvw1-reel-sym{height:100px;font-size:50px;}
509' +
510        '.uvw1-reels-wrap{gap:8px;margin-top:5px;}' +
511        '.uvw1-brand-panel{padding:12px 15px;margin:8px;}' +
512        '.uvw1-brand-title{font-size:14px;gap:6px;margin-bottom:10px;}' +
513        '.uvw1-brand-title-flag{font-size:16px;}' +
514        '.uvw1-brand-logos{gap:14px;}' +
515        '.uvw1-brand-logo-img{max-height:42px;max-width:100px;}' +
516        '.uvw1-brand-arrow{font-size:20px;}' +
517        '.uvw1-game-area{margin:10px;padding:10px;overflow:visible;}' +
518        '.uvw1-prize-section{margin-top:5px;padding:5px 10px 10px;}' +
519        '.uvw1-prize-value{font-size:28px;text-shadow:0 0 5px rgba(255,204,0,.4);}' +
520        '.uvw1-prize-detail-span{font-size:28px;text-shadow:0 0 5px rgba(255,204,0,.4);}' +
521        '.uvw1-prize-sub{font-size:14px;margin-top:6px;}' +
522        '.uvw1-ticker-wrap{padding:5px 0;}' +
523        '.uvw1-ticker-text{font-size:18px!important;letter-spacing:.5px;}' +
524        '.uvw1-slot-btn{padding:14px 16px;font-size:16px;border-width:3px;text-shadow:0 1px 1px rgba(0,0,0,.4);}' +
525        '.uvw1-claim-btn{font-size:20px;}' +
526        '.uvw1-msg{font-size:16px;height:36px;line-height:36px;}' +
527        '.uvw1-dots{height:36px;}' +
528        '.uvw1-msg-area{padding-top:4px;}' +
529        '.uvw1-hearts{padding:12px 10px;overflow:visible;isolation:isolate;gap:12px;}' +
530        '.uvw1-hearts-label{font-size:16px;margin-right:6px;}' +
531        '.uvw1-hearts-count{font-size:16px;margin-left:8px;}' +
532        '.uvw1-heart{width:22px;height:22px;will-change:transform,filter,opacity;transform:translateZ(0);position:relative;z-index:5;}' +
533        '.uvw1-heart.uvw1-active{filter:drop-shadow(0 0 6px #ff0040);}' +
534        '.uvw1-heart.uvw1-used{filter:grayscale(1) brightness(1.1) drop-shadow(0 0 6px #ff0040);opacity:.85;transform:scale(.85);}' +
535        '.uvw1-heart.uvw1-win{filter:drop-shadow(0 0 8px #ffd700) brightness(1.2) hue-rotate(40deg);}' +
536        '.uvw1-timer{margin-top:12px;}' +
537        '.uvw1-timer-label{font-size:14px;}' +
538        '.uvw1-float-icon{right:10px;}' +
539      '}' +
540      '@media(max-width:360px){' +
541        '.uvw1-reel{width:80px;height:90px;}' +
542        '.uvw1-reel-sym{height:90px;font-size:44px;}' +
543        '.uvw1-reels-wrap{gap:5px;margin-top:5px;}' +
544        '.uvw1-prize-value{font-size:24px;}' +
545        '.uvw1-prize-detail-span{font-size:24px;}' +
546      '}' +
547
548      /* ---- Bonus notification popup ---- */
549      '.uvw1-notif{position:relative;border-radius:16px;overflow:hidden;width:100%;' +
550        'box-shadow:0 0 40px rgba(255,215,0,.2),0 20px 60px rgba(0,0,0,.7);border:1px solid rgba(255,215,0,.25);}' +
551      '.uvw1-popup-wrap .uvw1-notif{animation:uvw1-notifIn .5s cubic-bezier(.16,1,.3,1) forwards;}' +
552      '@keyframes uvw1-notifIn{from{opacity:0;transform:scale(.85) translateY(30px)}to{opacity:1;transform:scale(1) translateY(0)}}' +
553
554      /* Title bar */
555      '.uvw1-notif-title{position:relative;z-index:1;background:linear-gradient(135deg,rgba(255,215,0,.15),rgba(255,215,0,.05));' +
556        'border-bottom:1px solid rgba(255,215,0,.2);padding:14px 20px;text-align:center;' +
557        'display:flex;align-items:center;justify-content:center;gap:8px;}' +
558      '.uvw1-notif-icon{font-size:22px;animation:uvw1-giftBounce 2s ease-in-out infinite;}' +
559      '@keyframes uvw1-giftBounce{0%,100%{transform:scale(1) rotate(0)}25%{transform:scale(1.15) rotate(-8deg)}50%{transform:scale(1) rotate(0)}75%{transform:scale(1.15) rotate(8deg)}}' +
560      '.uvw1-notif-text{font-size:15px;font-weight:700;color:#ffd700;letter-spacing:.5px;text-shadow:0 0 12px rgba(255,215,0,.2);}' +
561
562      /* Body */
563      '.uvw1-notif-body{position:relative;z-index:1;padding:20px 24px 24px;display:flex;flex-direction:column;align-items:center;text-align:center;}' +
564
565      /* Social proof */
566      '.uvw1-notif-social{display:flex;align-items:center;justify-content:center;gap:4px;margin-bottom:18px;' +
567        'font-size:12px;color:rgba(255,255,255,.5);letter-spacing:.3px;}' +
568      '.uvw1-notif-social-count{color:#22c55e;font-weight:700;font-size:13px;}' +
569      '.uvw1-notif-social-flag{font-size:14px;}' +
570
571      /* Close */
572      '.uvw1-notif-close{position:absolute;top:8px;right:8px;width:22px;height:22px;' +
573        'background:rgba(0,0,0,.3);border:none;border-radius:50%;color:rgba(255,255,255,.5);font-size:14px;line-height:1;' +
574        'cursor:pointer;display:flex;align-items:center;justify-content:center;z-index:10;padding-bottom:4px;' +
575        'opacity:0;transition:opacity .3s,color .2s;}' +
576      '.uvw1-notif-close.uvw1-visible{opacity:1;}' +
577      '.uvw1-notif-close:hover{color:#fff;}' +
578
579      /* Responsive */
580      '@media(max-width:480px){' +
581        '.uvw1-notif-title{padding:12px 16px;}
581' +
582        '.uvw1-notif-text{font-size:13px;}' +
583        '.uvw1-notif-body{padding:16px 18px 20px;}' +
584      '}' +
585
586      /* ---- Float button ---- */
587      '.uvw1-float-btn{' +
588        'position:fixed;z-index:9997;border:none;border-radius:30px;' +
589        'color:#fff;font-weight:900;font-size:15px;letter-spacing:.5px;cursor:pointer;' +
590        '-webkit-text-stroke:.8px currentColor;paint-order:stroke fill;' +
591        'text-transform:uppercase;white-space:nowrap;' +
592        'padding:14px 32px;' +
593        'box-shadow:0 4px 20px rgba(0,0,0,.35);' +
594        'transition:transform .2s,box-shadow .2s,opacity .4s;' +
595        'font-family:Arial,Helvetica,sans-serif;' +
596        'animation:uvw1-floatPulse 2.5s ease-in-out infinite;' +
597      '}' +
598      '.uvw1-float-btn{display:flex;align-items:center;gap:10px;}' +
599      '.uvw1-float-arrow{font-size:18px;display:inline-block;animation:uvw1-arrowBounce 1.2s ease-in-out infinite;}' +
600      '.uvw1-float-btn:hover{transform:translateX(-50%) scale(1.06) !important;box-shadow:0 6px 28px rgba(0,0,0,.45);}' +
601      '@keyframes uvw1-floatPulse{0%,100%{box-shadow:0 4px 20px rgba(0,0,0,.35)}50%{box-shadow:0 4px 28px rgba(0,0,0,.5)}}' +
602      '@keyframes uvw1-arrowBounce{0%,100%{transform:translateX(0)}50%{transform:translateX(6px)}}' +
603      /* Mobile: full-width sticky bottom */
604      '@media(max-width:850px){' +
605        '.uvw1-float-btn{' +
606          'left:10px !important;right:10px !important;bottom:10px !important;' +
607          'transform:none !important;width:auto !important;' +
608          'justify-content:center;' +
609          'border-radius:12px;padding:16px 20px;font-size:16px;' +
610        '}' +
611        '.uvw1-float-btn:hover{transform:none !important;}' +
612      '}' +
613      /* Desktop: centered bottom */
614      '@media(min-width:851px){' +
615        '.uvw1-float-btn{' +
616          'bottom:24px;left:50%;transform:translateX(-50%);' +
617        '}' +
618      '}' +
619    '';
620
621    var style = document.createElement('style');
622    style.textContent = css;
623    document.head.appendChild(style);
624  }
625
626  /* ============================================================
627     HELPERS
628     ============================================================ */
629  function escHtml(s) {
630    var d = document.createElement('div');
631    d.appendChild(document.createTextNode(s));
632    return d.innerHTML;
633  }
634
635  /* ============================================================
636     VARIANT SELECTION (A/B)
637     ============================================================ */
638  function selectVariant(variants) {
639    if (!variants || variants.length === 0) return null;
640    /* For now, return first. Later: weighted random. */
641    return variants[0];
642  }
643
644
645  /* ============================================================
646     DETECT SITE ACCENT COLOR
647     ============================================================ */
648  function detectSiteColor() {
649    var el;
650    var color;
651
652    /* Try <h1> */
653    el = document.querySelector('h1');
654    if (el) {
655      color = window.getComputedStyle(el).color;
656      if (color && color !== 'rgb(0, 0, 0)' && color !== 'rgba(0, 0, 0, 0)') {
657        return rgbToHex(color);
658      }
659    }
660
661    /* Try .header */
662    el = document.querySelector('.header');
663    if (el) {
664      color = window.getComputedStyle(el).backgroundColor;
665      if (color && color !== 'rgba(0, 0, 0, 0)' && color !== 'rgb(255, 255, 255)') {
666        return rgbToHex(color);
667      }
668    }
669
670    return '#3CB200';
671  }
672
673  function rgbToHex(rgb) {
674    if (!rgb) return '#3CB200';
675    if (rgb.charAt(0) === '#') return rgb;
676    var parts = rgb.match(/\d+/g);
677    if (!parts || parts.length < 3) return '#3CB200';
678    var r = parseInt(parts[0], 10);
679    var g = parseInt(parts[1], 10);
680    var b = parseInt(parts[2], 10);
681    return '#' + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
682  }
683
684  /* Helper: lighten color for gradient */
685  function lightenColor(hex, percent) {
686    hex = hex.replace('#', '');
687    var r = parseInt(hex.substring(0, 2), 16);
688    var g = parseInt(hex.substring(2, 4), 16);
689    var b = parseInt(hex.substring(4, 6), 16);
690    r = Math.min(255, Math.floor(r + (255 - r) * percent / 100));
691    g = Math.min(255, Math.floor(g + (255 - g) * percent / 100));
692    b = Math.min(255, Math.floor(b + (255 - b) * percent / 100));
693    return '#' + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
694  }
695
696  /* Helper: darken color for gradient */
697  function darkenColor(hex, percent) {
698    hex = hex.replace('#', '');
699    var r = parseInt(hex.substring(0, 2), 16);
700    var g = parseInt(hex.substring(2, 4), 16);
701    var b = parseInt(hex.substring(4, 6), 16);
702    r = Math.max(0, Math.floor(r * (1 - percent / 100)));
703    g = Math.max(0, Math.floor(g * (1 - percent / 100)));
704    b = Math.max(0, Math.floor(b * (1 - percent / 100)));
705    return '#' + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
706  }
707
708  /* ============================================================
709     HEADER BUTTON
710     ============================================================ */
711  function renderHeaderButton(variant, color) {
712    var cfg = variant.headerButton;
713    var header = document.querySelector('header');
714    if (!header) return;
715
716    header.style.position = 'relative';
717
718    var btn = document.createElement('span');
719    btn.className = 'uvw1-header-btn';
720    if (!cfg.showBanner) goSet(btn, 'header');
721    btn.textContent = cfg.text || 'PLAY NOW';
722    btn.style.color = cfg.textColor || '#fff';
723
724    var grad = 'linear-gradient(45deg, ' + color + ', ' + lightenColor(color, 15) + ', ' + color + ', ' + darkenColor(color, 20) + ')';
725    btn.style.background = grad;
726    btn.style.backgroundSize = '300% 300%';
727
728    /* Desktop positioning */
729    var dsk = cfg.desktop || {};
730    var mob = cfg.mobile || {};
731    btn.style.top = '50%';
732    btn.style.right = dsk.right || '0px';
733
734    /* Inject responsive positioning */
735    var posStyle = document.createElement('style');
736    posStyle.textContent =
737      '@media(max-width:850px){' +
738        '.uvw1-header-btn{' +
739          'right:' + (mob.right || '0px') + ' !important;' +
740          'padding:8px 18px !important;font-size:14px !important;max-width:140px;height:38px;' +
741        '}' +
742      '}';
743    document.head.appendChild(posStyle);
744
745    if (cfg.showBanner) {
746      btn.addEventListener('click', function (e) {
747        e.preventDefault();
748        goTrack('header_open');
749        showHeaderBanner(variant, { source: 'header_banner' });
750      });
751    }
752
753    header.appendChild(btn);
754  }
755
756  /* ============================================================
757     HEADER BANNER (countdown redirect)
758     ============================================================ */
759  function showHeaderBanner(variant, opts) {
760    opts = opts || {};
761    var cfg = variant.popup || {};
762    var tr = (cfg.translations) || {};
763    var flag = {'GB':'UK'}[cfg.countryCode] || cfg.countryCode || '';
764    var countryCode = flag;
765    var flagEmoji = cfg.countryFlag || '';
766    var localNames = (tr.countryNames) || {};
767    var localAdj = (tr.countryAdj) || {};
768    var countryName = localNames[cfg.countryCode] || COUNTRY_NAMES[cfg.countryCode] || countryCode;
769    var countryAdj = localAdj[cfg.countryCode] || countryName;
770    var siteName = variant.siteName || '';
771    var brandName = variant.brandName || 'Casino';
772    var COUNTDOWN = 15;
773
774    var restrictedTpl, restrictedText, recommendText;
775    if (opts.walletMode) {
776      var walletAvailTpl = tr.walletAvail || '{flag} For {country_adj} players, bonuses are processed through our partner:';
777      restrictedText = walletAvailTpl.replace('{flag}', flagEmoji).replace('{country_adj}', countryAdj).replace('{country}', countryName);
778      recommendText = '';
779    } else {
780      restrictedTpl = tr.bannerRestricted || '{old_brand} is now closed for {flag} {country_adj} players';
781      restrictedText = restrictedTpl.replace('{old_brand}', siteName).replace('{new_brand}', brandName).replace('{flag}', flagEmoji).replace('{country_adj}', countryAdj).replace('{country}', countryName);
782      recommendText = (tr.bannerRecommend || 'Play through our partner:').replace('{new_brand}', brandName);
783    }
784    var bonusLabel = tr.bannerBonusLabel || 'WELCOME BONUS';
785    var exclusiveTpl = tr.bannerExclusive || '{flag} Exclusive for {country_adj} players only';
786    var exclusiveText = exclusiveTpl.replace('{flag}', flagEmoji).replace('{country_adj}', countryAdj).replace('{country}', countryName);
787
788    /* Overlay */
789    var overlay = document.createElement('div');
790    overlay.className = 'uvw1-overlay';
791
792    var popupWrap = document.createElement('div');
793    popupWrap.className = 'uvw1-popup-wrap';
794
795    var banner = document.createElement('div');
796    banner.className = 'uvw1-banner';
797
798    /* Background */
799    var bgDiv = document.createElement('div');
800    bgDiv.className = 'uvw1-banner-bg';
801    if (variant.brandBg) {
802      bgDiv.style.backgroundImage = 'url(' + variant.brandBg + ')';
803    } else if (variant.brandBgColor) {
804      bgDiv.style.background = 'linear-gradient(180deg, ' + variant.brandBgColor + ' 0%, ' + variant.brandBgColor + ' 30%, #0a0a1a 100%)';
805    } else {
806      bgDiv.style.background = 'linear-gradient(180deg, #0d0d1a 0%, #1a1a3e 40%, #0f1f3d 100%)';
807    }
808    banner.appendChild(bgDiv);
809
810    /* Close */
811    var closeBtn = document.createElement('button');
812    closeBtn.className = 'uvw1-banner-close uvw1-visible';
813    closeBtn.innerHTML = '&times;';
814    banner.appendChild(closeBtn);
815
816    /* Warning strip */
817    var warning = document.createElement('div');
818    warning.className = 'uvw1-banner-warning';
819    function safeBr(s) { return escHtml(s).replace(/&lt;br&gt;/gi, '<br>').replace(/\|/g, '<br>'); }
820
821    if (opts.walletMode) {
822      warning.style.cssText = 'padding:14px 24px;background:linear-gradient(135deg,rgba(255,215,0,.12),rgba(255,215,0,.05));border-bottom:1px solid rgba(255,215,0,.2);text-align:center;';
823      var availEl = document.createElement('div');
824      availEl.style.cssText = 'font-size:15px;color:#ffd700;font-weight:700;letter-spacing:.5px;text-shadow:0 0 12px rgba(255,215,0,.2);';
825      availEl.textContent = restrictedText;
826      warning.appendChild(availEl);
827    } else {
828      warning.style.cssText = 'padding:16px 24px;background:linear-gradient(135deg,rgba(200,30,30,.35),rgba(140,20,20,.2));border-bottom:1px solid rgba(255,60,60,.2);text-align:center;';
829      var warnIcon = document.createElement('span');
830      warnIcon.className = 'uvw1-banner-warn-icon';
831      warnIcon.style.cssText = 'width:20px;height:20px;font-size:12px;line-height:20px;background:#c33;margin-right:8px;vertical-align:middle;animation:uvw1-warnPulse 1.5s ease-in-out infinite;';
832      warnIcon.textContent = '!';
833      warning.appendChild(warnIcon);
834      var restrictedEl = document.createElement('span');
835      restrictedEl.style.cssText = 'font-size:15px;font-weight:600;color:#ff9a9a;';
836      var parts = restrictedText.split(siteName);
837      if (siteName && parts.length > 1) {
838        restrictedEl.innerHTML = safeBr(parts[0]) + '<span style="color:#fff;font-weight:800;">' + escHtml(siteName) + '</span>' + safeBr(parts.slice(1).join(siteName));
839      } else {
840        restrictedEl.innerHTML = safeBr(restrictedText);
841      }
842      warning.appendChild(restrictedEl);
843    }
844    banner.appendChild(warning);
845
846    /* Body */
847    var body = document.createElement('div');
848    body.className = 'uvw1-banner-body';
849
850    if (recommendText) {
851      var recommendEl = document.createElement('div');
852      recommendEl.className = 'uvw1-banner-recommend';
853      recommendEl.style.cssText = 'font-size:16px;color:#ffd700;letter-spacing:1.5px;margin-bottom:18px;font-weight:700;text-shadow:0 0 10px rgba(255,215,0,.2);';
854      recommendEl.textContent = recommendText;
855      body.appendChild(recommendEl);
856    }
857
858    /* Bonus card */
859    var bonusDiv = document.createElement('div');
860    bonusDiv.className = 'uvw1-banner-bonus';
861
862    if (variant.brandLogo) {
863      var logoWrap = document.createElement('div');
864      logoWrap.className = 'uvw1-banner-logo-wrap';
865      logoWrap.style.paddingTop = '10px';
866      logoWrap.style.marginBottom = '18px';
867      logoWrap.style.paddingBottom = '18px';
868      var logo = document.createElement('img');
869      logo.className = 'uvw1-banner-logo';
870      logo.src = variant.brandLogo;
871      logo.alt = brandName;
872      logoWrap.appendChild(logo);
873      bonusDiv.appendChild(logoWrap);
874    }
875
876    var prizeVal = cfg.prize || '100%';
877    var prizeEl = document.createElement('div');
878    prizeEl.className = 'uvw1-banner-prize-line';
879    prizeEl.innerHTML = '<span class="uvw1-banner-pct">' + escHtml(prizeVal) + '</span>' + (cfg.prizeDetail ? ' ' + escHtml(cfg.prizeDetail) : '');
880    bonusDiv.appendChild(prizeEl);
881
882    if (cfg.prizeSub) {
883      var subEl = document.createElement('div');
884      subEl.className = 'uvw1-banner-sub';
885      subEl.textContent = cfg.prizeSub;
886      bonusDiv.appendChild(subEl);
887    }
888
889    body.appendChild(bonusDiv);
890
891    /* CTA button with countdown */
892    var affSrc = opts.source || 'header_banner';
893    var btnBase = cfg.claimText || (tr.claim || 'PLAY NOW');
894    var btn = document.createElement('span');
895    btn.className = 'uvw1-banner-btn';
896    btn.style.cursor = 'pointer';
897
898    btn.innerHTML = escHtml(btnBase) + ' <span class="uvw1-btn-arrow">&raquo;</span>';
899
900    btn.addEventListener('click', function (e) {
901      e.preventDefault();
902      clearInterval(timer);
903      goOpen(affSrc);
904    });
905
906    body.appendChild(btn);
907
908    /* Timer bar + text */
909    var timerWrap = document.createElement('div');
910    timerWrap.className = 'uvw1-banner-timer';
911
912    var timerText = document.createElement('div');
913    timerText.className = 'uvw1-banner-timer-text';
914    var countdown = COUNTDOWN;
915    var redirectTpl = tr.bannerRedirect || 'redirecting to {brand} in {time}...';
916    function updateTimer() {
917      var txt = redirectTpl.replace('{brand}', brandName).replace('{time}', countdown + 's');
918      timerText.innerHTML = escHtml(txt).replace(countdown + 's', '<span>' + countdown + 's</span>');
919    }
920    updateTimer();
921    timerWrap.appendChild(timerText);
922
923    var timerBar = document.createElement('div');
924    timerBar.className = 'uvw1-banner-timer-bar';
925    var timerFill = document.createElement('div');
926    timerFill.className = 'uvw1-banner-timer-fill';
927    timerBar.appendChild(timerFill);
928    timerWrap.appendChild(timerBar);
929
930    body.appendChild(timerWrap);
931
932    /* Start progress bar — double rAF to ensure 0% is painted first */
933    requestAnimationFrame(function () {
934      requestAnimationFrame(function () {
935        timerFill.style.transition = 'width ' + COUNTDOWN + 's linear';
936        timerFill.style.width = '100%';
937      });
938    });
939
940    var timer = setInterval(function () {
941      countdown--;
942      if (countdown <= 0) {
943        clearInterval(timer);
944        goOpen(affSrc);
945        return;
946      }
947      updateTimer();
948    }, 1000);
949
950    /* Exclusive footnote (skip in wallet mode — already stated at top) */
951    if (!opts.walletMode) {
952      var exclusiveEl = document.createElement('div');
953      exclusiveEl.className = 'uvw1-banner-exclusive';
954      exclusiveEl.textContent = exclusiveText;
955      body.appendChild(exclusiveEl);
956    }
957
958    banner.appendChild(body);
959    popupWrap.appendChild(banner);
960    overlay.appendChild(popupWrap);
961    document.body.appendChild(overlay);
962
963    function hideOverlay() {
964      overlay.classList.remove('uvw1-show');
965      document.body.style.overflow = '';
966      setTimeout(function () { overlay.remove(); }, 400);
967    }
968
969    closeBtn.addEventListener('click', function () {
970      clearInterval(timer);
971      hideOverlay();
972      if (opts.onClose) opts.onClose();
973    });
974
975    /* Show immediately */
976    requestAnimationFrame(function () {
977      overlay.classList.add('uvw1-show');
978      document.body.style.overflow = 'hidden';
979    });
980  }
981
982  /* Highlight brand name + "currently unavailable" in sticky text */
983  function highlightStickyText(text, brandName) {
984    var safe = escHtml(text);
985    /* Remove ⚡ emojis around brand, wrap brand in styled span */
986    if (brandName) {
987      var eBrand = escHtml(brandName);
988      var brandTag = '<span class="uvw1-sticky-brand uvw1-go" style="cursor:pointer">' + eBrand + '</span>';
989      safe = safe.replace(new RegExp('\\u26a1\\s*' + eBrand.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') + '\\s*\\u26a1', 'g'), brandTag);
990      /* Fallback if no ⚡ */
991      if (safe.indexOf('uvw1-sticky-brand') < 0) {
992        safe = safe.replace(eBrand, brandTag);
993      }
994    }
995    /* Highlight "currently unavailable" */
996    safe = safe.replace(/(currently unavailable|now unavailable|temporarily unavailable)/gi,
997      '<span class="uvw1-sticky-warn">$1</span>');
998    /* **bold highlight** markers → green accent */
999    safe = safe.replace(/\*\*(.+?)\*\*/g, '<span class="uvw1-sticky-highlight">$1</span>');
1000    /* | → line break */
1001    safe = safe.replace(/\|/g, '<br>');
1002    return safe;
1003  }
1004
1005  /* ============================================================
1006     STICKY FOOTER
1007     ============================================================ */
1008  function renderStickyFooter(variant, color) {
1009    var cfg = variant.stickyFooter;
1010    var RESHOW_DELAY = 10000;
1011    var INITIAL_DELAY = 1500;
1012    var DESKTOP_BREAKPOINT = 850;
1013
1014    var btnText = cfg.buttonText || 'Play Now';
1015    var btnTextColor = cfg.buttonTextColor || 'white';
1016    var btnGrad = 'linear-gradient(45deg,' + color + ',' + lightenColor(color, 10) + ',' + color + ',' + darkenColor(color, 15) + ')';
1017
1018    /* Main footer bar */
1019    var footer = document.createElement('div');
1020    footer.className = 'uvw1-footer uvw1-hidden';
1021
1022    /* Close button */
1023    var closeBtn = document.createElement('button');
1024    closeBtn.className = 'uvw1-footer-close';
1025    closeBtn.innerHTML = '<span style="position:relative;top:-2px;display:inline-block">&times;</span>';
1026    footer.appendChild(closeBtn);
1027
1028    /* Inner container */
1029    var inner = document.createElement('div');
1030    inner.className = 'uvw1-footer-inner';
1031
1032    /* Content wrapper */
1033    var content = document.createElement('div');
1034    content.className = 'uvw1-footer-content';
1035
1036    /* Top row: logos + brand + desktop-text + desktop-btn */
1037    var row = document.createElement('div');
1038    row.className = 'uvw1-footer-row';
1039
1040    /* Logos section */
1041    var logos = document.createElement('div');
1042    logos.className = 'uvw1-footer-logos';
1043
1044    /* Old logo card (site logo, greyed out) */
1045    var oldCard = document.createElement('div');
1046    oldCard.className = 'uvw1-logo-card uvw1-logo-old';
1047    var oldImg = document.createElement('img');
1048    oldImg.src = variant.siteLogo || '/logo.png';
1049    oldImg.alt = 'Logo';
1050    oldImg.onerror = function () { this.style.display = 'none'; };
1051    oldCard.appendChild(oldImg);
1052    var badgeX = document.createElement('div');
1053    badgeX.className = 'uvw1-badge-x';
1054    badgeX.textContent = '\u2715';
1055    oldCard.appendChild(badgeX);
1056    logos.appendChild(oldCard);
1057
1058    /* Animated arrow between logos */
1059    var arrowEl = document.createElement('div');
1060    arrowEl.className = 'uvw1-footer-arrow';
1061    arrowEl.textContent = '\u2192';
1062    logos.appendChild(arrowEl);
1063
1064    /* New logo card (brand logo) — clickable */
1065    var newCard = document.createElement('span');
1066    newCard.className = 'uvw1-logo-card';
1067    goSet(newCard, 'sticky');
1068    newCard.style.cssText = 'cursor:pointer;';
1069    if (variant.brandLogo) {
1070      var newImg = document.createElement('img');
1071      newImg.src = variant.brandLogo;
1072      newImg.alt = variant.brandName || 'Brand';
1073      newImg.onerror = function () { this.style.display = 'none'; };
1074      newCard.appendChild(newImg);
1075    }
1076    var badgeOk = document.createElement('div');
1077    badgeOk.className = 'uvw1-badge-ok';
1078    badgeOk.textContent = '\uD83D\uDC4D';
1079    newCard.appendChild(badgeOk);
1080    logos.appendChild(newCard);
1081
1082    row.appendChild(logos);
1083
1084    /* Brand info (name + star rating) */
1085    var brandInfo = document.createElement('div');
1086    brandInfo.className = 'uvw1-brand-info';
1087
1088    var brandNameEl = document.createElement('span');
1089    brandNameEl.className = 'uvw1-brand-name';
1090    goSet(brandNameEl, 'sticky');
1091    brandNameEl.textContent = variant.brandName || '';
1092    brandInfo.appendChild(brandNameEl);
1093
1094    var starsEl = document.createElement('div');
1095    starsEl.className = 'uvw1-stars';
1096    for (var si = 0; si < 5; si++) {
1097      var star = document.createElement('span');
1098      star.className = 'uvw1-star';
1099      star.textContent = '\u2605';
1100      starsEl.appendChild(star);
1101    }
1102    brandInfo.appendChild(starsEl);
1103
1104    row.appendChild(brandInfo);
1105
1106    /* Desktop-only text */
1107    var deskText = document.createElement('div');
1108    deskText.className = 'uvw1-footer-text uvw1-desktop-only';
1109    deskText.innerHTML = highlightStickyText(cfg.text || '', variant.brandName);
1110    row.appendChild(deskText);
1111
1112    /* Desktop-only CTA button */
1113    var deskBtn = document.createElement('span');
1114    goSet(deskBtn, 'sticky');
1115    deskBtn.className = 'uvw1-footer-btn uvw1-desktop-only';
1116    deskBtn.style.background = btnGrad;
1117    deskBtn.style.backgroundSize = '300% 300%';
1118    deskBtn.style.color = btnTextColor;
1119    if (btnTextColor === 'black') deskBtn.style.textShadow = 'none';
1120    deskBtn.innerHTML = btnText + ' <span class="uvw1-btn-arrow">&raquo;</span>';
1121    row.appendChild(deskBtn);
1122
1123    content.appendChild(row);
1124
1125    /* Mobile text row */
1126    var mobileTextRow = document.createElement('div');
1127    mobileTextRow.className = 'uvw1-mobile-text';
1128    var mobileText = document.createElement('div');
1129    mobileText.className = 'uvw1-footer-text uvw1-in-mobile';
1130    mobileText.innerHTML = highlightStickyText(cfg.text || '', variant.brandName);
1131    mobileTextRow.appendChild(mobileText);
1132    content.appendChild(mobileTextRow);
1133
1134    inner.appendChild(content);
1135
1136    /* Mobile CTA button */
1137    var mobileBtn = document.createElement('span');
1138    goSet(mobileBtn, 'sticky');
1139    mobileBtn.className = 'uvw1-footer-btn';
1140    mobileBtn.style.background = btnGrad;
1141    mobileBtn.style.backgroundSize = '300% 300%';
1142    mobileBtn.style.color = btnTextColor;
1143    if (btnTextColor === 'black') mobileBtn.style.textShadow = 'none';
1144    mobileBtn.innerHTML = btnText + ' <span class="uvw1-btn-arrow">&raquo;</span>';
1145    inner.appendChild(mobileBtn);
1146
1147    footer.appendChild(inner);
1148    document.body.appendChild(footer);
1149
1150    /* Bind click on brand name in text */
1151    footer.querySelectorAll('.uvw1-go').forEach(function(el) { goSet(el, 'sticky'); });
1152
1153    /* State management */
1154    function isDesktop() { return window.innerWidth >= DESKTOP_BREAKPOINT; }
1155
1156    function showBanner() {
1157      footer.classList.remove('uvw1-hidden');
1158      footer.classList.remove('uvw1-hiding');
1159      footer.classList.remove('uvw1-collapsed');
1160      footer.classList.add('uvw1-visible');
1161    }
1162
1163    function hideBannerSmooth() {
1164      footer.classList.remove('uvw1-visible');
1165      footer.classList.remove('uvw1-collapsed');
1166      footer.classList.add('uvw1-hiding');
1167    }
1168
1169    function collapseBanner() {
1170      footer.classList.add('uvw1-collapsed');
1171    }
1172
1173    closeBtn.addEventListener('click', function (e) {
1174      e.preventDefault();
1175      e.stopPropagation();
1176      if (isDesktop()) {
1177        hideBannerSmooth();
1178      } else {
1179        collapseBanner();
1180      }
1181      setTimeout(showBanner, RESHOW_DELAY);
1182    });
1183
1184    /* Show after initial delay */
1185    setTimeout(showBanner, INITIAL_DELAY);
1186  }
1187
1188  /* ============================================================
1189     SLOT POPUP (Vegas-style slot machine)
1190     ============================================================ */
1191  function renderPopup(variant) {
1192    var cfg = variant.popup;
1193    var tr = cfg.translations || {};
1194    var SYMBOLS = ['\uD83C\uDF52', '\uD83D\uDC8E', '\uD83C\uDF53', '\uD83C\uDF40', '\u2B50', '\uD83C\uDFB0', '\uD83D\uDCB0', '\uD83D\uDC51'];
1195    var SYMBOL_HEIGHT = 95;
1196    var TOTAL_SPINS = 3;
1197    var CLAIM_TIMER_SECONDS = 300;
1198    var STORAGE_KEY = 'uvw1_slot_' + SITE_ID;
1199
1200    var spinCount = 0;
1201    var isSpinning = false;
1202    var gameFinished = false;
1203    var autoSpinTimer = null;
1204    var claimTimerRef = null;
1205
1206    /* Near-miss outcomes */
1207    var NEAR_MISS_1 = [2, 2, 3];
1208    var NEAR_MISS_2 = [1, 3, 1];
1209    var WIN_RESULT = [0, 0, 0];
1210
1211    /* ---- State management ---- */
1212    function getState() {
1213      try { var s = localStorage.getItem(STORAGE_KEY); return s ? JSON.parse(s) : null; } catch (e) { return null; }
1214    }
1215    function saveState(obj) {
1216      try { localStorage.setItem(STORAGE_KEY, JSON.stringify(obj)); } catch (e) { /* */ }
1217    }
1218
1219    /* ---- Create DOM elements (only once) ---- */
1220    /* Floating gift icon */
1221    var floatIcon = document.createElement('div');
1222    floatIcon.className = 'uvw1-float-icon';
1223    var floatImg = document.createElement('img');
1224    floatImg.src = '/widget-assets/popup-images/gift.png';
1225    floatImg.alt = 'Bonus';
1226    floatIcon.appendChild(floatImg);
1227    document.body.appendChild(floatIcon);
1228
1229    /* Overlay */
1230    var overlay = document.createElement('div');
1231    overlay.className = 'uvw1-overlay';
1232
1233    /* Popup wrapper */
1234    var popupWrap = document.createElement('div');
1235    popupWrap.className = 'uvw1-popup-wrap';
1236
1237    /* Close button */
1238    var closeBtn = document.createElement('button');
1239    closeBtn.className = 'uvw1-popup-close';
1240    closeBtn.textContent = 'X';
1241    popupWrap.appendChild(closeBtn);
1242
1243    /* Machine body */
1244    var machine = document.createElement('div');
1245    machine.className = 'uvw1-machine';
1246
1247    /* Brand panel */
1248    var brandPanel = document.createElement('div');
1249    brandPanel.className = 'uvw1-brand-panel';
1250
1251    var flag = cfg.countryFlag || '';
1252    var brandName = variant.brandName || 'Casino';
1253
1254    var brandTitle = document.createElement('div');
1255    brandTitle.className = 'uvw1-brand-title';
1256    var countryCode = {'GB':'UK'}[cfg.countryCode] || cfg.countryCode || '';
1257    var localNames = tr.countryNames || {};
1258    var countryName = localNames[countryCode] || COUNTRY_NAMES[countryCode] || countryCode;
1259    var availText = (tr.availableIn || '{brand} available in {country}').replace('{brand}', brandName).replace('{country}', countryName || '');
1260    brandTitle.innerHTML = '<span class="uvw1-brand-title-flag">' + flag + '</span><span>' + escHtml(availText) + '</span>';
1261    brandPanel.appendChild(brandTitle);
1262
1263    var brandLogos = document.createElement('div');
1264    brandLogos.className = 'uvw1-brand-logos';
1265
1266    /* Old brand logo */
1267    var oldWrap = document.createElement('div');
1268    oldWrap.className = 'uvw1-brand-logo-wrap uvw1-old';
1269    if (variant.siteLogo) {
1270      var oldLogo = document.createElement('img');
1271      oldLogo.className = 'uvw1-brand-logo-img';
1272      oldLogo.src = variant.siteLogo;
1273      oldLogo.alt = 'Old';
1274      oldLogo.onerror = function () { this.style.display = 'none'; };
1275      oldWrap.appendChild(oldLogo);
1276    }
1277    var blockedLabel = document.createElement('span');
1278    blockedLabel.className = 'uvw1-brand-blocked';
1279    blockedLabel.textContent = tr.blocked || 'BLOCKED';
1280    oldWrap.appendChild(blockedLabel);
1281    brandLogos.appendChild(oldWrap);
1282
1283    /* Arrow between brands */
1284    var brandArrow = document.createElement('div');
1285    brandArrow.className = 'uvw1-brand-arrow';
1286    brandArrow.textContent = '>';
1287    brandLogos.appendChild(brandArrow);
1288
1289    /* New brand logo */
1290    var newWrap = document.createElement('div');
1291    newWrap.className = 'uvw1-brand-logo-wrap uvw1-new';
1292    if (variant.brandLogo) {
1293      var newLink = document.createElement('span');
1294      goSet(newLink, 'slot');
1295      newLink.style.display = 'inline-block';
1296      var newLogo = document.createElement('img');
1297      newLogo.className = 'uvw1-brand-logo-img';
1298      newLogo.src = variant.brandLogo;
1299      newLogo.alt = brandName;
1300      newLink.appendChild(newLogo);
1301      newWrap.appendChild(newLink);
1302    }
1303    brandLogos.appendChild(newWrap);
1304    brandPanel.appendChild(brandLogos);
1305    machine.appendChild(brandPanel);
1306
1307    /* Game area */
1308    var gameArea = document.createElement('div');
1309    gameArea.className = 'uvw1-game-area';
1310
1311    /* Ticker */
1312    var tickerWrap = document.createElement('div');
1313    tickerWrap.className = 'uvw1-ticker-wrap';
1314    var tickerText = document.createElement('div');
1315    tickerText.className = 'uvw1-ticker-text';
1316    var tickStr = '\u2605 ' + (tr.ticker || 'SPIN AND WIN YOUR WELCOME BONUS AT') + ' ' + brandName.toUpperCase() + ' \u2605 ';
1317    tickerText.textContent = tickStr + tickStr + tickStr + tickStr;
1318    tickerWrap.appendChild(tickerText);
1319    gameArea.appendChild(tickerWrap);
1320
1321    /* Reels */
1322    var reelsWrap = document.createElement('div');
1323    reelsWrap.className = 'uvw1-reels-wrap';
1324
1325    var reelContainers = [];
1326    var reelStrips = [];
1327
1328    for (var ri = 0; ri < 3; ri++) {
1329      var reel = document.createElement('div');
1330      reel.className = 'uvw1-reel';
1331      var strip = document.createElement('div');
1332      strip.className = 'uvw1-reel-strip';
1333      /* Build symbols: full set + 4 extra for seamless scrolling */
1334      var symHtml = '';
1335      for (var si = 0; si < SYMBOLS.length + 4; si++) {
1336        symHtml += '<div class="uvw1-reel-sym">' + SYMBOLS[si % SYMBOLS.length] + '</div>';
1337      }
1338      strip.innerHTML = symHtml;
1339      reel.appendChild(strip);
1340      reelsWrap.appendChild(reel);
1341      reelContainers.push(reel);
1342      reelStrips.push(strip);
1343    }
1344    gameArea.appendChild(reelsWrap);
1345
1346    /* Hearts / lives */
1347    var heartsDiv = document.createElement('div');
1348    heartsDiv.className = 'uvw1-hearts';
1349
1350    var heartsLabel = document.createElement('span');
1351    heartsLabel.className = 'uvw1-hearts-label';
1352    heartsLabel.textContent = (tr.spinsLeft || 'SPINS') + ':';
1353    heartsDiv.appendChild(heartsLabel);
1354
1355    var heartEls = [];
1356    for (var hi = 0; hi < TOTAL_SPINS; hi++) {
1357      var heart = document.createElement('span');
1358      heart.className = 'uvw1-heart';
1359      if (hi === 0) heart.classList.add('uvw1-active');
1360      heartsDiv.appendChild(heart);
1361      heartEls.push(heart);
1362    }
1363
1364    var heartsCount = document.createElement('span');
1365    heartsCount.className = 'uvw1-hearts-count';
1366    heartsCount.textContent = TOTAL_SPINS + ' ' + (tr.left || 'LEFT');
1367    heartsDiv.appendChild(heartsCount);
1368    gameArea.appendChild(heartsDiv);
1369
1370    /* Message area */
1371    var msgArea = document.createElement('div');
1372    msgArea.className = 'uvw1-msg-area';
1373
1374    var dots = document.createElement('div');
1375    dots.className = 'uvw1-dots';
1376    dots.innerHTML = '<div class="uvw1-dot"></div><div class="uvw1-dot"></div><div class="uvw1-dot"></div>';
1377    msgArea.appendChild(dots);
1378
1379    var msg = document.createElement('div');
1380    msg.className = 'uvw1-msg';
1381    msgArea.appendChild(msg);
1382    gameArea.appendChild(msgArea);
1383
1384    /* Prize section */
1385    var prizeSection = document.createElement('div');
1386    prizeSection.className = 'uvw1-prize-section';
1387
1388    var prizeValue = document.createElement('div');
1389    prizeValue.className = 'uvw1-prize-value';
1390    var prizeMain = cfg.prize || '100%';
1391    var prizeDetail = cfg.prizeDetail || '';
1392    prizeValue.innerHTML = prizeMain + (prizeDetail ? ' <span class="uvw1-prize-detail-span">' + prizeDetail + '</span>' : '');
1393    prizeSection.appendChild(prizeValue);
1394
1395    var prizeSub = document.createElement('div');
1396    prizeSub.className = 'uvw1-prize-sub';
1397    prizeSub.textContent = cfg.prizeSub || (tr.firstDeposit || 'ON YOUR FIRST DEPOSIT');
1398    prizeSection.appendChild(prizeSub);
1399
1400    gameArea.appendChild(prizeSection);
1401    machine.appendChild(gameArea);
1402
1403    /* Buttons area */
1404    var btnsArea = document.createElement('div');
1405    btnsArea.style.cssText = 'padding:5px 20px 15px;';
1406
1407    var spinBtn = document.createElement('button');
1408    spinBtn.className = 'uvw1-slot-btn uvw1-spin-btn';
1409    spinBtn.textContent = tr.spin || 'SPIN';
1410    btnsArea.appendChild(spinBtn);
1411
1412    var claimBtn = document.createElement('span');
1413    claimBtn.className = 'uvw1-slot-btn uvw1-claim-btn';
1414    claimBtn.style.cursor = 'pointer';
1415    claimBtn.textContent = cfg.claimText || ((tr.claimAt || 'CLAIM AT') + ' ' + brandName);
1416    claimBtn.addEventListener('click', function () {
1417      saveState({ shown: true, won: true });
1418      goOpen('slot');
1419    });
1420    btnsArea.appendChild(claimBtn);
1421
1422    var timerDiv = document.createElement('div');
1423    timerDiv.className = 'uvw1-timer';
1424    timerDiv.innerHTML = '<span class="uvw1-timer-label">' + (tr.offerExpires || 'Offer expires in') + ' <span class="uvw1-timer-value"></span></span>';
1425    btnsArea.appendChild(timerDiv);
1426
1427    machine.appendChild(btnsArea);
1428    popupWrap.appendChild(machine);
1429    overlay.appendChild(popupWrap);
1430    document.body.appendChild(overlay);
1431
1432    /* ---- Reel helpers ---- */
1433    function randomizeReels() {
1434      reelStrips.forEach(function (strip) {
1435        var idx = 3 + Math.floor(Math.random() * 4);
1436        strip.style.transform = 'translateY(-' + (idx * SYMBOL_HEIGHT) + 'px)';
1437      });
1438    }
1439
1440    function spinReel(strip, finalIdx, stopDelay) {
1441      return new Promise(function (resolve) {
1442        var totalHeight = SYMBOLS.length * SYMBOL_HEIGHT;
1443        var startTime = null;
1444        var spinning = true;
1445
1446        strip.classList.add('uvw1-spinning');
1447        strip.classList.remove('uvw1-stopping');
1448
1449        function animate(ts) {
1450          if (!spinning) return;
1451          if (!startTime) startTime = ts;
1452          var pos = ((ts - startTime) * 1.8) % totalHeight;
1453          strip.style.transform = 'translateY(-' + pos + 'px)';
1454          requestAnimationFrame(animate);
1455        }
1456        requestAnimationFrame(animate);
1457
1458        setTimeout(function () {
1459          spinning = false;
1460          strip.classList.remove('uvw1-spinning');
1461          strip.classList.add('uvw1-stopping');
1462          strip.style.transform = 'translateY(-' + (finalIdx * SYMBOL_HEIGHT) + 'px)';
1463          setTimeout(function () {
1464            strip.classList.remove('uvw1-stopping');
1465            resolve();
1466          }, 600);
1467        }, stopDelay);
1468      });
1469    }
1470
1471    /* ---- Heart explosion particles ---- */
1472    function explodeHeart(heartEl) {
1473      var rect = heartEl.getBoundingClientRect();
1474      var cx = rect.left + rect.width / 2;
1475      var cy = rect.top + rect.height / 2;
1476      for (var pi = 0; pi < 8; pi++) {
1477        var p = document.createElement('div');
1478        p.className = 'uvw1-heart-particle';
1479        var angle = (pi / 8) * Math.PI * 2;
1480        var dist = 20 + Math.random() * 30;
1481        p.style.left = cx + 'px';
1482        p.style.top = cy + 'px';
1483        p.style.setProperty('--tx', Math.cos(angle) * dist + 'px');
1484        p.style.setProperty('--ty', Math.sin(angle) * dist + 'px');
1485        document.body.appendChild(p);
1486        (function (el) {
1487          setTimeout(function () { if (el.parentNode) el.parentNode.removeChild(el); }, 700);
1488        })(p);
1489      }
1490    }
1491
1492    /* ---- Spin logic ---- */
1493    function spin() {
1494      if (isSpinning || gameFinished) return;
1495      if (autoSpinTimer) { clearTimeout(autoSpinTimer); autoSpinTimer = null; }
1496
1497      isSpinning = true;
1498      spinCount++;
1499      spinBtn.disabled = true;
1500      msg.textContent = '';
1501      msg.className = 'uvw1-msg';
1502      msg.style.display = 'none';
1503      dots.classList.add('uvw1-active');
1504
1505      reelContainers.forEach(function (r) { r.classList.remove('uvw1-cracked'); });
1506
1507      heartEls.forEach(function (h, i) {
1508        h.classList.remove('uvw1-active', 'uvw1-used', 'uvw1-win', 'uvw1-burning');
1509        if (i < spinCount - 1) h.classList.add('uvw1-used');
1510        else if (i === spinCount - 1) h.classList.add('uvw1-active');
1511      });
1512
1513      var isWin = spinCount >= 3;
1514      var indices = isWin ? WIN_RESULT : (spinCount === 1 ? NEAR_MISS_1 : NEAR_MISS_2);
1515
1516      Promise.all([
1517        spinReel(reelStrips[0], indices[0], 1500),
1518        spinReel(reelStrips[1], indices[1], 2700),
1519        spinReel(reelStrips[2], indices[2], 3900)
1520      ]).then(function () {
1521        isSpinning = false;
1522        dots.classList.remove('uvw1-active');
1523        msg.style.display = 'block';
1524
1525        if (isWin) {
1526          handleWin();
1527        } else {
1528          handleNearMiss(indices);
1529        }
1530      });
1531    }
1532
1533    function handleNearMiss(indices) {
1534      spinBtn.disabled = false;
1535      var remaining = TOTAL_SPINS - spinCount;
1536      heartsCount.textContent = remaining === 1 ? (tr.last || 'LAST!') : remaining + ' ' + (tr.left || 'LEFT');
1537
1538      if (spinCount === 1) {
1539        msg.innerHTML = (tr.soClose || 'SO CLOSE!') + ' 2 ' + (tr.livesLeft || 'lives left!');
1540        spinBtn.textContent = tr.tryAgain || 'TRY AGAIN';
1541        reelContainers[2].classList.add('uvw1-cracked');
1542      } else {
1543        msg.innerHTML = tr.lastChance || 'LAST CHANCE!';
1544        spinBtn.textContent = tr.finalSpin || 'FINAL SPIN';
1545        reelContainers[1].classList.add('uvw1-cracked');
1546      }
1547      msg.className = 'uvw1-msg uvw1-try-again';
1548
1549      /* Burn heart with particles */
1550      heartEls[spinCount - 1].classList.remove('uvw1-active');
1551      explodeHeart(heartEls[spinCount - 1]);
1552      heartEls[spinCount - 1].classList.add('uvw1-burning');
1553      if (spinCount < TOTAL_SPINS) heartEls[spinCount].classList.add('uvw1-active');
1554
1555      /* Auto-spin countdown */
1556      startAutoSpin();
1557    }
1558
1559    function startAutoSpin() {
1560      var countdown = 3;
1561      function tick() {
1562        if (countdown > 0) {
1563          spinBtn.textContent = (tr.autoSpin || 'AUTO SPIN IN') + ' ' + countdown + '...';
1564          countdown--;
1565          autoSpinTimer = setTimeout(tick, 1000);
1566        } else {
1567          autoSpinTimer = null;
1568          spin();
1569        }
1570      }
1571      tick();
1572    }
1573
1574    function handleWin() {
1575      gameFinished = true;
1576      machine.classList.add('uvw1-winner');
1577      heartEls.forEach(function (h) {
1578        h.classList.remove('uvw1-active', 'uvw1-used', 'uvw1-burning');
1579        h.classList.add('uvw1-win');
1580      });
1581      heartsCount.textContent = tr.win || 'YOU WIN!';
1582      heartsCount.style.color = '#fff';
1583      msg.textContent = tr.youWon || 'YOU WON!';
1584      msg.className = 'uvw1-msg uvw1-winner-msg';
1585      spinBtn.style.display = 'none';
1586      claimBtn.classList.add('uvw1-show');
1587      prizeSection.classList.add('uvw1-revealed');
1588      createCoins();
1589      startClaimTimer();
1590      saveState({ shown: true, won: true });
1591    }
1592
1593    function startClaimTimer() {
1594      if (claimTimerRef) clearTimeout(claimTimerRef);
1595      var seconds = CLAIM_TIMER_SECONDS;
1596      timerDiv.classList.add('uvw1-show');
1597      var valEl = timerDiv.querySelector('.uvw1-timer-value');
1598
1599      function tick() {
1600        var m = Math.floor(seconds / 60);
1601        var s = seconds % 60;
1602        valEl.textContent = m + ':' + (s < 10 ? '0' : '') + s;
1603        if (seconds <= 60) timerDiv.classList.add('uvw1-urgent');
1604        if (seconds > 0) {
1605          seconds--;
1606          claimTimerRef = setTimeout(tick, 1000);
1607        } else {
1608          timerDiv.classList.remove('uvw1-show');
1609        }
1610      }
1611      tick();
1612    }
1613
1614    function createCoins() {
1615      for (var ci = 0; ci < 30; ci++) {
1616        (function (i) {
1617          setTimeout(function () {
1618            var coin = document.createElement('div');
1619            coin.className = 'uvw1-coin-fall';
1620            coin.textContent = '$';
1621            var sz = Math.random() * 8 + 18;
1622            coin.style.cssText = 'left:' + (Math.random() * 100) + 'vw;width:' + sz + 'px;height:' + sz + 'px;border-radius:50%;' +
1623              'background:linear-gradient(145deg,#ffe066,#ffd700 50%,#b8860b);border:2px solid #aa7700;' +
1624              'display:flex;align-items:center;justify-content:center;font-size:' + (sz * 0.55) + 'px;font-weight:bold;color:#8B6914;' +
1625              'animation-duration:' + (Math.random() * 2 + 2) + 's';
1626            document.body.appendChild(coin);
1627            setTimeout(function () { if (coin.parentNode) coin.parentNode.removeChild(coin); }, 4000);
1628          }, i * 50);
1629        })(ci);
1630      }
1631    }
1632
1633    /* ---- Restore win state ---- */
1634    function restoreWinState() {
1635      gameFinished = true;
1636      spinCount = 3;
1637      machine.classList.add('uvw1-winner');
1638      heartEls.forEach(function (h) {
1639        h.classList.remove('uvw1-active', 'uvw1-used');
1640        h.classList.add('uvw1-win');
1641      });
1642      reelStrips.forEach(function (strip) {
1643        strip.style.transform = 'translateY(0)';
1644      });
1645      heartsCount.textContent = tr.win || 'YOU WIN!';
1646      heartsCount.style.color = '#fff';
1647      msg.textContent = tr.youWon || 'YOU WON!';
1648      msg.className = 'uvw1-msg uvw1-winner-msg';
1649      msg.style.display = 'block';
1650      dots.classList.remove('uvw1-active');
1651      spinBtn.style.display = 'none';
1652      claimBtn.classList.add('uvw1-show');
1653      prizeSection.classList.add('uvw1-revealed');
1654      closeBtn.classList.add('uvw1-visible');
1655      startClaimTimer();
1656    }
1657
1658    /* ---- Show / hide popup ---- */
1659    function showPopup() {
1660      var state = getState();
1661      overlay.classList.add('uvw1-show');
1662      document.body.style.overflow = 'hidden';
1663      floatIcon.classList.remove('uvw1-visible');
1664      goTrack('slot_open');
1665
1666      /* Measure actual symbol height */
1667      var symEl = machine.querySelector('.uvw1-reel-sym');
1668      if (symEl) SYMBOL_HEIGHT = symEl.offsetHeight;
1669
1670      if (state && state.won) {
1671        restoreWinState();
1672      } else {
1673        randomizeReels();
1674        msg.innerHTML = '<span class="uvw1-arrow-down">\u25BC</span> ' + (tr.pressSpin || 'PRESS TO WIN YOUR BONUS!') + ' <span class="uvw1-arrow-down">\u25BC</span>';
1675        msg.className = 'uvw1-msg uvw1-press-spin';
1676        msg.style.display = 'block';
1677        setTimeout(function () { closeBtn.classList.add('uvw1-visible'); }, 3000);
1678      }
1679
1680      if (!state || !state.shown) {
1681        saveState({ shown: true, won: false });
1682      }
1683    }
1684
1685    function hidePopup() {
1686      overlay.classList.remove('uvw1-show');
1687      document.body.style.overflow = '';
1688      if (claimTimerRef) clearTimeout(claimTimerRef);
1689      if (autoSpinTimer) { clearTimeout(autoSpinTimer); autoSpinTimer = null; }
1690      var state = getState();
1691      showFloatIcon(state && state.won);
1692    }
1693
1694    function showFloatIcon(isWinner) {
1695      floatIcon.classList.add('uvw1-visible');
1696      if (isWinner) {
1697        floatIcon.classList.add('uvw1-winner');
1698      }
1699    }
1700
1701    /* ---- Event listeners ---- */
1702    spinBtn.addEventListener('click', function () {
1703      if (autoSpinTimer) { clearTimeout(autoSpinTimer); autoSpinTimer = null; }
1704      spin();
1705    });
1706
1707    closeBtn.addEventListener('click', hidePopup);
1708
1709    floatIcon.addEventListener('click', showPopup);
1710
1711    /* ---- Initial state ---- */
1712    var initState = getState();
1713    showFloatIcon(initState && initState.won);
1714
1715    if (!initState || !initState.shown) {
1716      setTimeout(showPopup, 120000);
1717    }
1718
1719    /* ---- Text fitting ---- */
1720    function fitText(el, maxSize, minSize) {
1721      if (!el || !el.parentElement) return;
1722      var parent = el.parentElement;
1723      var fs = maxSize;
1724      el.style.fontSize = fs + 'px';
1725      while (el.scrollWidth > parent.clientWidth && fs > minSize) {
1726        fs -= 0.5;
1727        el.style.fontSize = fs + 'px';
1728      }
1729    }
1730
1731    var titleSpan = brandTitle.querySelector('span:last-child');
1732    if (titleSpan) {
1733      var isMob = window.innerWidth <= 480;
1734      fitText(titleSpan, isMob ? 14 : 18, isMob ? 8 : 10);
1735    }
1736    fitText(prizeValue, (window.innerWidth <= 480) ? 28 : 32, (window.innerWidth <= 480) ? 16 : 18);
1737  }
1738
1739  /* ============================================================
1740     WALLET STICKY FOOTER
1741     ============================================================ */
1742  function renderWalletFooter(variant, color) {
1743    var cfg = variant.stickyFooter;
1744    var popup = variant.popup || {};
1745    var tr = popup.translations || {};
1746    var WALLET_DURATION = 120; /* 2 minutes in seconds */
1747    var INITIAL_DELAY = 2000;
1748    var RESHOW_DELAY = 15000;
1749    var STORAGE_KEY = 'uvw1_wallet_' + SITE_ID;
1750
1751    var countryCode = {'GB':'UK'}[popup.countryCode] || popup.countryCode || '';
1752    var flagEmoji = popup.countryFlag || '';
1753    var prizeVal = popup.prize || '100%';
1754    var prizeDetail = popup.prizeDetail || '';
1755    var bonusText = prizeVal + (prizeDetail ? ' ' + prizeDetail : '');
1756
1757    var walletBonusLabel = tr.walletBonus || '{country} Exclusive';
1758    var walletExpiresLabel = tr.walletExpires || 'Expires in';
1759    var walletClaimLabel = tr.walletClaim || 'CLAIM';
1760    var walletModalText = (tr.walletModal || 'For {flag} {country} players, claiming is processed through:')
1761      .replace('{flag}', flagEmoji).replace('{country}', countryCode);
1762
1763    function getState() {
1764      try { var s = localStorage.getItem(STORAGE_KEY); return s ? JSON.parse(s) : null; } catch (e) { return null; }
1765    }
1766    function saveState(obj) {
1767      try { localStorage.setItem(STORAGE_KEY, JSON.stringify(obj)); } catch (e) { /* */ }
1768    }
1769
1770    /* Main wallet bar */
1771    var wallet = document.createElement('div');
1772    wallet.className = 'uvw1-wallet';
1773
1774    var inner = document.createElement('div');
1775    inner.className = 'uvw1-wallet-inner';
1776    inner.style.position = 'relative';
1777
1778    /* Close button */
1779    var closeBtn = document.createElement('button');
1780    closeBtn.className = 'uvw1-wallet-close';
1781    closeBtn.innerHTML = '&times;';
1782    inner.appendChild(closeBtn);
1783
1784    /* Info block */
1785    var info = document.createElement('div');
1786    info.className = 'uvw1-wallet-info';
1787
1788    var bonusEl = document.createElement('div');
1789    bonusEl.className = 'uvw1-wallet-bonus';
1790    var labelText = walletBonusLabel.replace('{flag}', flagEmoji).replace('{country}', countryCode);
1791    if (flagEmoji && labelText.indexOf(flagEmoji) < 0) labelText = flagEmoji + ' ' + labelText;
1792    var walletHurry = tr.walletHurry || 'Hurry!';
1793    bonusEl.innerHTML = '<div class="uvw1-wallet-bonus-label">' + escHtml(labelText) + ' — <span class="uvw1-wallet-hurry">' + escHtml(walletHurry) + '</span></div><div class="uvw1-wallet-bonus-value">' + escHtml(bonusText) + '</div>';
1794    info.appendChild(bonusEl);
1795
1796    inner.appendChild(info);
1797
1798    /* Claim button (doubles as progress bar via ::before) */
1799    var btn = document.createElement('button');
1800    btn.className = 'uvw1-wallet-btn';
1801    btn.innerHTML = '<span>' + walletClaimLabel + '</span> <span class="uvw1-btn-arrow">&raquo;</span>';
1802    inner.appendChild(btn);
1803
1804    wallet.appendChild(inner);
1805
1806    document.body.appendChild(wallet);
1807
1808    /* Timer logic */
1809    var state = getState();
1810    var remaining = WALLET_DURATION;
1811    if (state && state.remaining > 0) {
1812      remaining = state.remaining;
1813    }
1814
1815    function formatTime(sec) {
1816      var m = Math.floor(sec / 60);
1817      var s = sec % 60;
1818      return (m < 10 ? '0' : '') + m + ':' + (s < 10 ? '0' : '') + s;
1819    }
1820
1821    function updateTimer() {
1822      var pct = (remaining / WALLET_DURATION) * 100;
1823      btn.style.setProperty('--progress', pct + '%');
1824
1825      /* Dynamic color: green → yellow → orange → red */
1826      var t = 1 - (remaining / WALLET_DURATION); /* 0=full, 1=empty */
1827      var sec = remaining;
1828      if (sec > 105) { /* 2:00–1:45 green 15s */
1829        btn.style.setProperty('--fill-start', '#22c55e');
1830        btn.style.setProperty('--fill-end', '#16a34a');
1831        btn.style.setProperty('--glow', 'rgba(34,197,94,.35)');
1832      } else if (sec > 75) { /* 1:45–1:15 yellow 30s */
1833        btn.style.setProperty('--fill-start', '#eab308');
1834        btn.style.setProperty('--fill-end', '#f59e0b');
1835        btn.style.setProperty('--glow', 'rgba(234,179,8,.4)');
1836      } else if (sec > 45) { /* 1:15–0:45 orange 30s */
1837        btn.style.setProperty('--fill-start', '#f97316');
1838        btn.style.setProperty('--fill-end', '#ea580c');
1839        btn.style.setProperty('--glow', 'rgba(249,115,22,.4)');
1840      } else { /* 0:45–0:00 red 45s */
1841        btn.style.setProperty('--fill-start', '#ef4444');
1842        btn.style.setProperty('--fill-end', '#dc2626');
1843        btn.style.setProperty('--glow', 'rgba(239,68,68,.5)');
1844      }
1845
1846      /* Pulse glow animation in last 2 minutes */
1847      if (remaining <= 120 && !btn.style.animationName) {
1848        btn.style.animation = 'uvw1-btnPulseGlow 1.5s ease-in-out infinite';
1849      }
1850
1851      btn.innerHTML = '<span>' + walletClaimLabel + ' ' + formatTime(remaining) + '</span> <span class="uvw1-btn-arrow">&raquo;</span>';
1852      if (remaining <= 60 && !wallet.classList.contains('uvw1-urgent')) {
1853        wallet.classList.add('uvw1-urgent');
1854      }
1855    }
1856    updateTimer();
1857
1858    var timerInterval = null;
1859    function startTimer() {
1860      timerInterval = setInterval(function () {
1861        remaining--;
1862        if (remaining <= 0) {
1863          remaining = 0;
1864          clearInterval(timerInterval);
1865          /* Auto-open modal as last chance */
1866          goTrack('wallet_open');
1867          showHeaderBanner(variant, { walletMode: true, source: 'wallet', onClose: function () {
1868            /* Reset timer after modal close */
1869            remaining = WALLET_DURATION;
1870            wallet.classList.remove('uvw1-urgent');
1871            btn.style.animation = '';
1872            updateTimer();
1873            saveState({ remaining: remaining });
1874            startTimer();
1875          }});
1876        }
1877        updateTimer();
1878        saveState({ remaining: remaining });
1879      }, 1000);
1880    }
1881
1882    /* Show / hide */
1883    function showWallet() {
1884      wallet.classList.add('uvw1-show');
1885      startTimer();
1886    }
1887
1888    function hideWallet() {
1889      wallet.classList.remove('uvw1-show');
1890      if (timerInterval) clearInterval(timerInterval);
1891      setTimeout(function () {
1892        showWallet();
1893      }, RESHOW_DELAY);
1894    }
1895
1896    closeBtn.addEventListener('click', hideWallet);
1897
1898    /* CTA click → show header banner modal */
1899    btn.addEventListener('click', function () {
1900      if (timerInterval) clearInterval(timerInterval);
1901      goTrack('wallet_open');
1902      showHeaderBanner(variant, { walletMode: true, source: 'wallet', onClose: function () {
1903        if (remaining > 0) startTimer();
1904      }});
1905    });
1906
1907    /* Initial show */
1908    setTimeout(showWallet, INITIAL_DELAY);
1909  }
1910
1911  /* ============================================================
1912     BONUS NOTIFICATION POPUP (compact card with social proof)
1913     ============================================================ */
1914  function renderBonusPopup(variant, color) {
1915    var cfg = variant.popup;
1916    var tr = cfg.translations || {};
1917    var STORAGE_KEY = 'uvw1_bonus_' + SITE_ID;
1918
1919    function getState() {
1920      try { var s = localStorage.getItem(STORAGE_KEY); return s ? JSON.parse(s) : null; } catch (e) { return null; }
1921    }
1922    function saveState(obj) {
1923      try { localStorage.setItem(STORAGE_KEY, JSON.stringify(obj)); } catch (e) { /* */ }
1924    }
1925
1926    var brandName = variant.brandName || 'Casino';
1927    var siteName = variant.siteName || '';
1928    var flagEmoji = cfg.countryFlag || '';
1929    var countryCode = {'GB':'UK'}[cfg.countryCode] || cfg.countryCode || '';
1930    var localNames = (tr.countryNames) || {};
1931    var localAdj = (tr.countryAdj) || {};
1932    var countryName = localNames[cfg.countryCode] || COUNTRY_NAMES[cfg.countryCode] || countryCode;
1933    var countryAdj = localAdj[cfg.countryCode] || countryName;
1934
1935    /* Social proof count — seeded by day so it's stable within a day */
1936    var dayOfYear = Math.floor((new Date() - new Date(new Date().getFullYear(), 0, 1)) / 86400000);
1937    var socialCount = 800 + ((dayOfYear * 137 + dayOfYear * dayOfYear * 13) % 1701);
1938
1939    /* Translated strings */
1940    var titleTpl = tr.bonusTitle || '{flag} Exclusive partner bonus for {country_adj} players!';
1941    var titleText = titleTpl.replace('{flag}', '').replace('{new_brand}', brandName).replace('{old_brand}', siteName).replace('{country_adj}', countryAdj).replace('{country}', countryName).trim();
1942    var socialTpl = tr.bonusSocial || '{count} {country_adj} players claimed today';
1943    var socialText = socialTpl.replace('{count}', socialCount.toLocaleString()).replace('{country_adj}', countryAdj).replace('{country}', countryName);
1944    var btnText = cfg.claimText || (tr.claim || 'CLAIM YOUR BONUS');
1945
1946    /* Floating gift icon */
1947    var floatIcon = document.createElement('div');
1948    floatIcon.className = 'uvw1-float-icon';
1949    var floatImg = document.createElement('img');
1950    floatImg.src = '/widget-assets/popup-images/gift.png';
1951    floatImg.alt = 'Bonus';
1952    floatIcon.appendChild(floatImg);
1953    document.body.appendChild(floatIcon);
1954
1955    /* Overlay */
1956    var overlay = document.createElement('div');
1957    overlay.className = 'uvw1-overlay';
1958
1959    var popupWrap = document.createElement('div');
1960    popupWrap.className = 'uvw1-popup-wrap';
1961
1962    /* Notification card */
1963    var notif = document.createElement('div');
1964    notif.className = 'uvw1-notif';
1965
1966    /* Background */
1967    var bgDiv = document.createElement('div');
1968    bgDiv.className = 'uvw1-banner-bg';
1969    if (variant.brandBg) {
1970      bgDiv.style.backgroundImage = 'url(' + variant.brandBg + ')';
1971    } else if (variant.brandBgColor) {
1972      bgDiv.style.background = 'linear-gradient(180deg, ' + variant.brandBgColor + ' 0%, ' + variant.brandBgColor + ' 30%, #0a0a1a 100%)';
1973    } else {
1974      bgDiv.style.background = 'linear-gradient(180deg, #0d0d1a 0%, #1a1a3e 40%, #0f1f3d 100%)';
1975    }
1976    notif.appendChild(bgDiv);
1977
1978    /* Close button */
1979    var closeBtn = document.createElement('button');
1980    closeBtn.className = 'uvw1-notif-close';
1981    closeBtn.innerHTML = '&times;';
1982    notif.appendChild(closeBtn);
1983
1984    /* Title bar */
1985    var titleBar = document.createElement('div');
1986    titleBar.className = 'uvw1-notif-title';
1987    var giftIcon = document.createElement('span');
1988    giftIcon.className = 'uvw1-notif-icon';
1989    giftIcon.textContent = '\uD83C\uDF81';
1990    titleBar.appendChild(giftIcon);
1991    var titleEl = document.createElement('span');
1992    titleEl.className = 'uvw1-notif-text';
1993    titleEl.innerHTML = titleText.replace(/\|/g, '<br>');
1994    titleBar.appendChild(titleEl);
1995    notif.appendChild(titleBar);
1996
1997    /* Body */
1998    var body = document.createElement('div');
1999    body.className = 'uvw1-notif-body';
2000
2001    /* Brand logo */
2002    if (variant.brandLogo) {
2003      var logoWrap = document.createElement('div');
2004      logoWrap.className = 'uvw1-banner-logo-wrap';
2005      logoWrap.style.paddingTop = '6px';
2006      logoWrap.style.marginBottom = '14px';
2007      logoWrap.style.paddingBottom = '0';
2008      logoWrap.style.borderBottom = 'none';
2009      var logo = document.createElement('img');
2010      logo.className = 'uvw1-banner-logo';
2011      logo.src = variant.brandLogo;
2012      logo.alt = brandName;
2013      logoWrap.appendChild(logo);
2014      body.appendChild(logoWrap);
2015    }
2016
2017    /* Bonus card */
2018    var bonusDiv = document.createElement('div');
2019    bonusDiv.className = 'uvw1-banner-bonus';
2020
2021    var prizeVal = cfg.prize || '100%';
2022    var prizeEl = document.createElement('div');
2023    prizeEl.className = 'uvw1-banner-prize-line';
2024    prizeEl.innerHTML = '<span class="uvw1-banner-pct">' + escHtml(prizeVal) + '</span>' + (cfg.prizeDetail ? ' ' + escHtml(cfg.prizeDetail) : '');
2025    bonusDiv.appendChild(prizeEl);
2026
2027    if (cfg.prizeSub) {
2028      var subEl = document.createElement('div');
2029      subEl.className = 'uvw1-banner-sub';
2030      subEl.textContent = cfg.prizeSub;
2031      bonusDiv.appendChild(subEl);
2032    }
2033
2034    body.appendChild(bonusDiv);
2035
2036    /* Social proof line */
2037    var socialDiv = document.createElement('div');
2038    socialDiv.className = 'uvw1-notif-social';
2039    if (flagEmoji) {
2040      var socialFlag = document.createElement('span');
2041      socialFlag.className = 'uvw1-notif-social-flag';
2042      socialFlag.textContent = flagEmoji;
2043      socialDiv.appendChild(socialFlag);
2044    }
2045    var socialEl = document.createElement('span');
2046    socialEl.innerHTML = '<span class="uvw1-notif-social-count">
2046' + escHtml(socialCount.toLocaleString()) + '</span> ' + escHtml(socialText.replace(socialCount.toLocaleString(), '').trim());
2047    socialDiv.appendChild(socialEl);
2048    body.appendChild(socialDiv);
2049
2050    /* CTA button */
2051    var btn = document.createElement('span');
2052    btn.className = 'uvw1-banner-btn';
2053    btn.style.cursor = 'pointer';
2054    btn.innerHTML = escHtml(btnText) + ' <span class="uvw1-btn-arrow">&raquo;</span>';
2055    btn.addEventListener('click', function () {
2056      saveState({ shown: true, clicked: true });
2057      goOpen('bonus');
2058    });
2059    body.appendChild(btn);
2060
2061    notif.appendChild(body);
2062    popupWrap.appendChild(notif);
2063    overlay.appendChild(popupWrap);
2064    document.body.appendChild(overlay);
2065
2066    /* Show / hide */
2067    function showPopup() {
2068      overlay.classList.add('uvw1-show');
2069      document.body.style.overflow = 'hidden';
2070      floatIcon.classList.remove('uvw1-visible');
2071      goTrack('bonus_open');
2072      setTimeout(function () { closeBtn.classList.add('uvw1-visible'); }, 2000);
2073      saveState({ shown: true });
2074    }
2075
2076    function hidePopup() {
2077      overlay.classList.remove('uvw1-show');
2078      document.body.style.overflow = '';
2079      floatIcon.classList.add('uvw1-visible');
2080    }
2081
2082    closeBtn.addEventListener('click', hidePopup);
2083    floatIcon.addEventListener('click', showPopup);
2084
2085    /* Initial state */
2086    var initState = getState();
2087    floatIcon.classList.add('uvw1-visible');
2088
2089    if (!initState || !initState.shown) {
2090      setTimeout(showPopup, 120000);
2091    }
2092  }
2093
2094  /* ============================================================
2095     FLOAT BUTTON (direct redirect, no popup)
2096     ============================================================ */
2097  function renderFloatButton(variant, color) {
2098    var cfg = variant.floatButton;
2099    var btn = document.createElement('button');
2100    btn.className = 'uvw1-float-btn';
2101    btn.style.color = cfg.textColor || '#fff';
2102    btn.style.background = 'linear-gradient(135deg, ' + lightenColor(color, 15) + ', ' + color + ', ' + darkenColor(color, 20) + ')';
2103    btn.style.backgroundSize = '200% 200%';
2104
2105    var textSpan = document.createElement('span');
2106    textSpan.textContent = cfg.text || 'PLAY NOW';
2107    btn.appendChild(textSpan);
2108
2109    var arrow = document.createElement('span');
2110    arrow.className = 'uvw1-float-arrow';
2111    arrow.innerHTML = '&#x279C;';
2112    btn.appendChild(arrow);
2113
2114    goSet(btn, 'float_btn');
2115
2116    document.body.appendChild(btn);
2117  }
2118
2119  /* ============================================================
2120     INIT
2121     ============================================================ */
2122  injectStyles();
2123
2124  fetch(API_BASE + '/config/' + SITE_ID)
2125    .then(function (r) {
2126      if (!r.ok) throw new Error('Config fetch failed: ' + r.status);
2127      return r.json();
2128    })
2129    .then(function (config) {
2130      if (!config || !config.variants || config.variants.length === 0) return;
2131
2132      /* Init click tracking from config */
2133      if (config.clickParam) _CP = config.clickParam;
2134      if (config.clickSources) _CS = config.clickSources;
2135
2136      var variant = selectVariant(config.variants);
2137      if (!variant) return;
2138
2139      var color = (variant.headerButton && variant.headerButton.color) || detectSiteColor();
2140
2141      if (variant.headerButton && variant.headerButton.enabled) {
2142        renderHeaderButton(variant, color);
2143      }
2144
2145      if (variant.stickyFooter && variant.stickyFooter.enabled) {
2146        if (variant.stickyFooter.type === 'wallet') {
2147          renderWalletFooter(variant, color);
2148        } else {
2149          renderStickyFooter(variant, color);
2150        }
2151      }
2152
2153      if (variant.floatButton && variant.floatButton.enabled) {
2154        renderFloatButton(variant, color);
2155      }
2156
2157      if (variant.popup && variant.popup.enabled) {
2158        if (variant.popup.type === 'bonus') {
2159          renderBonusPopup(variant, color);
2160        } else {
2161          renderPopup(variant);
2162        }
2163      }
2164    })
2165    .catch(function (err) {
2166      if (typeof console !== 'undefined') {
2167        console.warn('Widget init error:', err);
2168      }
2169    });
2170})();

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.