PageSourceSearch

https://www.betting-forum.com/js/bf_livescore/app.js?_v=c2657d5c

js betting-forum.com collected 2026-09-24 09:11:07 UTC 61,907 bytes, 1,259 lines download raw bytes

1(function(window, document, _undefined) {
2    "use strict";
3    
4// Helper to render bells correctly
5window.bfGetBellSvg = window.bfGetBellSvg || function(isActive) {
6    const iconClass = isActive ? 'fa--xf fas fa-bell' : 'fa--xf far fa-bell';
7    return '<i class="' + iconClass + ' bf-ls-icon" data-xf-init="icon" aria-hidden="true"></i>';
8};
9
10    if (!window.bfLiveScoreInitialized) {
11        window.bfLiveScoreInitialized = true;
12
13        document.addEventListener('click', function(e) {
14            var followBtn = e.target.closest('.bf-ls-follow-btn');
15            if (followBtn) {
16                e.preventDefault(); 
17                e.stopPropagation(); 
18                
19                if (followBtn.classList.contains('disabled') || followBtn.hasAttribute('disabled')) {
20                    return;
21                }
22                var container = followBtn.closest('.bf-ls-item-container');
23                if (container && parseInt(container.getAttribute('data-status')) >= 3) {
24                    return;
25                }
26                
27                if (!XF.config.userId || parseInt(XF.config.userId, 10) === 0) {
28                    var loginUrl = XF.canonicalizeUrl('login');
29                    if (XF.loadOverlay) { XF.loadOverlay(loginUrl); } 
30                    else if (XF.Overlay) { new XF.Overlay(loginUrl).show(); }
31                    else { window.location = loginUrl; }
32                    return; 
33                }
34
35                var matchId = followBtn.getAttribute('data-match-id');
36                var wasActive = followBtn.classList.contains('active');
37                var allButtons = document.querySelectorAll('.bf-ls-follow-btn[data-match-id="' + matchId + '"]');
38                var newState = !wasActive;
39                var newLabel = newState ? 'Unfollow this match' : 'Follow this match';
40                var newAria = newState ? 'true' : 'false';
41
42                allButtons.forEach(function(btn) {
43                    if (newState) { btn.classList.add('active'); } else { btn.classList.remove('active'); }
44                    btn.setAttribute('aria-pressed', newAria);
45                    btn.setAttribute('aria-label', newLabel);
46                    btn.setAttribute('title', newLabel);
47
48                    if (window.bfGetBellSvg) {
49                        btn.innerHTML = window.bfGetBellSvg(newState);
50                        XF.activate(btn);
51                    }
52                });
53                
54                if (XF.config.userId && parseInt(XF.config.userId, 10) > 0) {
55                    var storedFollows = [];
56                    try { storedFollows = JSON.parse(localStorage.getItem('bfLiveScore_follows')) || []; } catch(e) {}
57                    var idx = storedFollows.indexOf(matchId);
58                    if (newState) { if (idx === -1) storedFollows.push(matchId); } else { if (idx > -1) storedFollows.splice(idx, 1); }
59                    localStorage.setItem('bfLiveScore_follows', JSON.stringify(storedFollows));
60                }
61
62                XF.ajax('POST', XF.canonicalizeUrl('score/follow'), { match_id: matchId }, function(data) {}, {
63                    error: function() {
64                        allButtons.forEach(function(btn) { 
65                            if (wasActive) {
66                                btn.classList.add('active');
67                                btn.setAttribute('aria-pressed', 'true');
68                            } else {
69                                btn.classList.remove('active');
70                                btn.setAttribute('aria-pressed', 'false');
71                            }
72                        });
73                        XF.alert('Action failed.');
74                    }
75                });
76                return;
77            }
78
79            if (e.target.closest('.bf-ls-modal')) return;
80
81            var flagTrigger = e.target.closest('.bf-ls-flag-trigger');
82            if (flagTrigger) {
83                var country = flagTrigger.getAttribute('data-country');
84                var code = flagTrigger.getAttribute('data-country-code');
85                if (country && window.bfLiveScoreAppInstance) {
86                    window.bfLiveScoreAppInstance.activateCountryFilter(country, code);
87                }
88                return;
89            }
90
91            var scoreBox = e.target.closest('.bf-ls-portal-score, .bf-ls-widget-score');
92            if (!scoreBox) return;
93
94            var itemContainer = scoreBox.closest('.bf-ls-item-container');
95            if (!itemContainer) return;
96
97            var details = null;
98            try { details = itemContainer.querySelector(':scope > .bf-ls-details-hidden'); } 
99            catch(err) { for (var i = 0; i < itemContainer.children.length; i++) { if (itemContainer.children[i].classList.contains('bf-ls-details-hidden')) { details = itemContainer.children[i]; break; } } }
100            
101            if (!details) {
102                 var headerRow = itemContainer.querySelector('.bf-ls-header-row');
103                 var timeline = itemContainer.querySelector('.bf-ls-timeline');
104                 if (headerRow && timeline) {
105                     var tempDiv = document.createElement('div');
106                     tempDiv.appendChild(headerRow.cloneNode(true));
107                     tempDiv.appendChild(timeline.cloneNode(true));
108                     details = tempDiv;
109                 }
110            }
111
112            if (!details || !details.innerHTML.trim()) return;
113            var overlay = document.getElementById('bf-ls-global-overlay');
114            if (overlay) {
115                var body = overlay.querySelector('.bf-ls-modal-body');
116                if (body) { 
117                    e.preventDefault(); 
118                    
119                    // 1. MAKE VISIBLE FIRST (Critical for XF 2.3 Icons)
120                    overlay.classList.add('active'); 
121                    document.body.style.overflow = 'hidden';
122
123                    // 2. SET CONTENT
124                    body.innerHTML = details.innerHTML; 
125                    
126                    var lazyImages = body.querySelectorAll('img[data-src]');
127                    lazyImages.forEach(function(img) {
128                        img.src = img.getAttribute('data-src');
129                        img.removeAttribute('data-src');
130                    });
131                    
132                    // 3. ACTIVATE ICONS (Now that they are visible)
133                    XF.activate(body);
134
135                    window.bfLsLastFocus = document.activeElement;
136                    
137                    var closeBtn = overlay.querySelector('.bf-ls-modal-close');
138                    if (closeBtn) closeBtn.focus();
139                }
140            }
141        });
142    }
143    
144    XF.BFLiveScoreApp = XF.Element.newHandler({
145        options: { url: null, mode: 'widget', filter: '' },
146        activeCountryFilter: null,
147        currentMode: 'static', 
148        currentOffset: 0, 
149	timeOffset: 0, // <--- 1. NEW PROPERTY
150
151        // <--- 2. NEW HELPER FUNCTION
152        getCorrectedDate: function() {
153            // Returns a Date object adjusted to match Server Time
154            return new Date(Date.now() + this.timeOffset);
155        },
156        // -----------------------
157        
158        escapeHtml: function(text) {
159            if (!text) return '';
160            return String(text).replace(/[&<>"']/g, function(m) {
161                return {'&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#039;'}[m];
162            });
163        },
164
165        init: function() {
166            window.bfLiveScoreAppInstance = this;
167            if (!this.options.url) return;
168            
169	// <--- 3. ADD THIS BLOCK HERE
170            var serverTs = parseInt(this.target.getAttribute('data-server-time'), 10);
171            if (serverTs) {
172                // Calculate difference: Server Time (ms) - Client System Time (ms)
173                this.timeOffset = (serverTs * 1000) - Date.now();
174                console.log("BF LiveScore: Time Sync Offset:", this.timeOffset, "ms");
175            }
176            // ---------------------------
177
178            this.convertTimes(); 
179            var self = this;
180
181            // --- GLOBAL CLICK HANDLER FOR HEADERS (Fixes Today Tab) ---
182            this.target.addEventListener('click', function(e) {
183                // Check if we clicked a Header
184                var header = e.target.closest('.bf-ls-portal-header[data-group-toggle="true"]');
185                if (header) {
186                    // Ignore if clicking the flag/filter icon
187                    if (e.target.closest('.bf-ls-flag-trigger')) return;
188
189                    header.classList.toggle('collapsed');
190                    var next = header.nextElementSibling;
191                    if (next && next.classList.contains('bf-ls-group-container')) {
192                        next.classList.toggle('collapsed');
193                    }
194                }
195            });
196            // ---------------------------------------------------------
197
198            document.addEventListener('bf-livescore-update', function(e) {
199                if (e.detail) {
200                    self.applyPatch(e.detail);
201                }
202            });
203
204            if (this.options.mode === 'portal' || this.options.mode === 'full_widget') { 
205                this.setupTabs(); 
206                this.setupOddsToggle(); 
207                this.setupSoundToggle();
208                this.setupFilterChip();
209                
210                var activeTab = this.target.querySelector('.bf-ls-tab.active');
211                var tabType = activeTab ? activeTab.getAttribute('data-tab') : 'all';
212                
213                if (tabType !== 'live') {
214                    var wrapper = this.target.querySelector('.bf-ls-date-scroll-wrapper');
215                    if (wrapper) {
216                        wrapper.style.display = 'flex';
217                        wrapper.classList.add('active');
218                        this.generateDateButtons(); 
219                    }
220                }
221
222                if (XF.config.userId && parseInt(XF.config.userId) > 0) {
223                    var savedCountry = localStorage.getItem('bfLiveScore_filter_country');
224                    var savedCode = localStorage.getItem('bfLiveScore_filter_code');
225                    if (savedCountry) {
226                        this.activateCountryFilter(savedCountry, savedCode);
227                    }
228                }
229            }
230            // --- DYNAMIC POLLING LOOP START ---
231            var poll = function() {
232                var now = self.getCorrectedDate();
233                var totalMins = (now.getUTCHours() * 60) + now.getUTCMinutes();
234                
235                var delay = 8000; // FAST (Default) - Changed to 8s
236
237                if (totalMins >= 180 && totalMins < 660) {
238                    delay = 25000; // SLOWEST (03:00 - 11:00 UTC)
239                } else if (totalMins >= 1 && totalMins < 180) {
240                    delay = 11000; // MEDIUM (00:01 - 03:00 UTC)
241                }
242
243                setTimeout(function() {
244                    self.refresh(false);
245                    poll(); 
246                }, delay);
247            };
248            poll(); // Kickstart the loop
249            // --- DYNAMIC POLLING LOOP END ---
250            
251            document.addEventListener('visibilitychange', function() {
252                if (document.visibilityState === 'visible') {
253                    console.log('Tab active: Forcing LiveScore update...');
254                    // FIX: Pass 'true' as second arg to suppress sound on wake-up
255                    self.refresh(true, true);
256                }
257            });
258            
259            // PASTE YOUR NEW BLOCK HERE:
260var hasContent = this.target.querySelector('.bf-ls-item-container'); // Check for matches
261
262if (this.options.mode === 'widget' || this.options.mode === 'full_widget') { 
263    if (hasContent) {
264        console.log("BF LiveScore: SSR Content found. Skipping initial fetch.");
265    } else {
266        this.refresh(true); 
267    }
268}
269
270	// --- Init Filter Check (To hide tomorrow's matches) ---
271
272            if (this.options.mode === 'portal' && this.currentOffset === 0) {
273
274                 this.filterRows(tabType);
275
276            }
277
278        },
279        
280        convertTimes: function() {
281            this.target.querySelectorAll('.bf-ls-local-time').forEach(function(el) {
282                var ts = parseInt(el.getAttribute('data-timestamp'));
283                if (ts) {
284                    var d = new Date(ts * 1000);
285                    var hh = String(d.getHours()).padStart(2,'0');
286                    var mn = String(d.getMinutes()).padStart(2,'0');
287                    el.textContent = hh + ':' + mn;
288                    el.classList.remove('bf-ls-local-time'); 
289                }
290            });
291        },
292        
293        setupOddsToggle: function() {
294            var self = this;
295            var checkbox = this.target.querySelector('.bf-ls-odds-checkbox');
296            if (!checkbox || checkbox.dataset.init) return;
297            checkbox.dataset.init = '1';
298            var stored = 'false';
299            try { stored = localStorage.getItem('bfLiveScore_showOdds'); } catch(e) {}
300            checkbox.checked = (stored === 'true');
301            if (checkbox.checked) this.target.classList.add('bf-show-odds');
302            checkbox.addEventListener('change', function() {
303                if (this.checked) {
304                    self.target.classList.add('bf-show-odds');
305                    try { localStorage.setItem('bfLiveScore_showOdds', 'true'); } catch(e) {}
306                } else {
307                    self.target.classList.remove('bf-show-odds');
308                    try { localStorage.setItem('bfLiveScore_showOdds', 'false'); } catch(e) {}
309                }
310            });
311        },
312
313        setupSoundToggle: function() {
314            var self = this;
315            var toggle = this.target.querySelector('.bf-ls-sound-toggle, .bf-ls-sound-btn');
316            if (!toggle) return;
317            
318            var isSoundOn = false;
319            try { isSoundOn = (localStorage.getItem('bfLiveScore_muted') === 'false'); } catch(e) {}
320            
321            var svgs = {
322                on: '<i class="fa--xf fas fa-volume-up" data-xf-init="icon" aria-hidden="true"></i>',
323                off: '<i class="fa--xf fas fa-volume-mute" data-xf-init="icon" aria-hidden="true"></i>'
324            };
325            
326            var updateIcon = function(active) {
327                if (active) {
328                    toggle.classList.add('active');
329                    toggle.innerHTML = svgs.on;
330                } else {
331                    toggle.classList.remove('active');
332                    toggle.innerHTML = svgs.off;
333                }
334                XF.activate(toggle);
335            };
336            
337            updateIcon(isSoundOn);
338            
339            toggle.addEventListener('click', function() {
340                var active = this.classList.contains('active');
341                if (active) {
342                    updateIcon(false);
343                    try { localStorage.setItem('bfLiveScore_muted', 'true'); } catch(e) {}
344                } else {
345                    updateIcon(true);
346                    self.playSound(); 
347                    try { localStorage.setItem('bfLiveScore_muted', 'false'); } catch(e) {}
348                }
349            });
350        },
351
352        playSound: function() {
353            if (localStorage.getItem('bfLiveScore_muted') !== 'false') return;
354            var audio = this.target.querySelector('.bf-ls-goal-audio');
355            if (audio) {
356                audio.pause(); 
357                audio.currentTime = 0; 
358                audio.volume = 0.5;
359                var p = audio.play();
360                if (p !== undefined) { p.catch(function(e) { console.log("Audio blocked"); }); }
361            }
362        },
363        
364        setupTabs: function() {
365            var self = this;
366            var tabs = this.target.querySelectorAll('.bf-ls-tab');
367            
368            tabs.forEach(function(tab) {
369                tab.addEventListener('click', function(e) {
370                    var type = this.getAttribute('data-tab');
371                    tabs.forEach(t => { t.classList.remove('active'); t.setAttribute('aria-selected', 'false'); });
372                    this.classList.add('active');
373                    this.setAttribute('aria-selected', 'true');
374
375                    var dateWrapper = self.target.querySelector('.bf-ls-date-scroll-wrapper');
376                    
377                    var staticContent = self.target.querySelector('.bf-ls-content');
378                    var dynamicContent = self.target.querySelector('.bf-ls-schedule-content');
379
380                    if (type === 'live') {
381                        if (dateWrapper) dateWrapper.style.display = 'none';
382                        if (staticContent) staticContent.style.display = 'block';
383                        if (dynamicContent) dynamicContent.style.display = 'none';
384                        
385                        self.currentOffset = 0;
386                        var dateBtns = self.target.querySelectorAll('.bf-ls-date-btn');
387                        dateBtns.forEach(b => b.classList.remove('active'));
388                        var todayBtn = self.target.querySelector('.bf-ls-date-btn[data-offset="0"]');
389                        if (todayBtn) todayBtn.classList.add('active');
390
391                        self.currentMode = 'static';
392                        self.filterRows('live');
393                    } 
394                    else {
395                        if (dateWrapper) {
396                            dateWrapper.style.display = 'flex';
397                            dateWrapper.classList.add('active');
398                            self.generateDateButtons(); 
399                        }
400                        
401                        if (self.currentOffset === 0) {
402                            if (staticContent) staticContent.style.display = 'block';
403                            if (dynamicContent) dynamicContent.style.display = 'none';
404                            self.currentMode = 'static';
405                            self.filterRows(type);
406                        } else {
407                             if (staticContent) staticContent.style.display = 'none';
408                             if (dynamicContent) dynamicContent.style.display = 'block';
409                             self.currentMode = 'schedule';
410                             
411                             var activeBtn = dateWrapper.querySelector('.bf-ls-date-btn.active');
412                             if (activeBtn) {
413                                 self.loadScheduleDate(activeBtn.getAttribute('data-date'));
414                             }
415                        }
416                    }
417                });
418            });
419        },
420
421        generateDateButtons: function() {
422            var wrapper = this.target.querySelector('.bf-ls-date-scroll-wrapper');
423            if (!wrapper) return;
424            wrapper.innerHTML = '';
425            
426            var start = -2; 
427            var end = 4;
428            var today = this.getCorrectedDate();
429
430            for (var i = start; i <= end; i++) {
431                var d = new Date(today);
432                d.setDate(today.getDate() + i);
433                
434                var yyyy = d.getFullYear();
435                var mm = String(d.getMonth() + 1).padStart(2, '0');
436                var dd = String(d.getDate()).padStart(2, '0');
437                var dateStr = yyyy + '-' + mm + '-' + dd;
438                
439                var label = '';
440                if (i === 0) {
441                    label = 'Today';
442                } else {
443                    var monthNames = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
444                    label = monthNames[d.getMonth()] + ' ' + d.getDate();
445                }
446
447                var btn = document.createElement('div');
448                btn.className = 'bf-ls-date-btn';
449                
450                if (i === this.currentOffset) {
451                    btn.classList.add('active');
452                } else if (this.currentOffset < start || this.currentOffset > end) {
453                    if (i === 0) { 
454                        btn.classList.add('active'); 
455                        this.currentOffset = 0;
456                    }
457                }
458                
459                btn.textContent = label;
460                btn.setAttribute('data-date', dateStr);
461                btn.setAttribute('data-offset', i);
462                
463                var self = this;
464                btn.addEventListener('click', function() {
465                    wrapper.querySelectorAll('.bf-ls-date-btn').forEach(b => b.classList.remove('active'));
466                    this.classList.add('active');
467                    
468                    var offset = parseInt(this.getAttribute('data-offset'));
469                    self.currentOffset = offset; 
470                    
471                    if (offset === 0) {
472                        self.currentMode = 'static';
473                        var staticContent = self.target.querySelector('.bf-ls-content');
474                        var dynamicContent = self.target.querySelector('.bf-ls-schedule-content');
475                        if (staticContent) staticContent.style.display = 'block';
476                        if (dynamicContent) dynamicContent.style.display = 'none';
477                        
478                        var activeTab = self.target.querySelector('.bf-ls-tab.active');
479                        if (activeTab) self.filterRows(activeTab.getAttribute('data-tab'));
480                    } else {
481                        self.currentMode = 'schedule'; 
482                        var staticContent = self.target.querySelector('.bf-ls-content');
483                        var dynamicContent = self.target.querySelector('.bf-ls-schedule-content');
484                        if (staticContent) staticContent.style.display = 'none';
485                        if (dynamicContent) dynamicContent.style.display = 'block';
486                        
487                        self.loadScheduleDate(this.getAttribute('data-date'));
488                    }
489                });
490                
491                wrapper.appendChild(btn);
492            }
493        },
494
495        loadScheduleDate: function(dateStr) {
496            var self = this;
497            var container = this.target.querySelector('.bf-ls-schedule-content');
498            if (!container) return;
499            
500            container.innerHTML = '<div style="padding:20px; text-align:center; color:#999;">Loading ' + dateStr + '...</div>';
501            
502            if (typeof window.bfLoadScheduleForDate === 'function') {
503                window.bfLoadScheduleForDate(dateStr).then(function(fixtures) {
504                    self.renderScheduleMatches(fixtures);
505                }).catch(function() {
506                    container.innerHTML = '<div style="padding:20px; text-align:center; color:#c0392b;">Failed to load schedule.</div>';
507                });
508            } else {
509                container.innerHTML = '<div style="padding:20px; text-align:center; color:#999;">Schedule loader not ready.</div>';
510            }
511        },
512
513        renderScheduleMatches: function(fixtures) {
514            var container = this.target.querySelector('.bf-ls-schedule-content');
515            if (!container) return;
516            if (!fixtures || fixtures.length === 0) {
517                container.innerHTML = '<div style="padding:30px; text-align:center; color:#999;">No matches found for this date.</div>';
518                return;
519            }
520
521            // 1. Sort matches (Priority > Country > League > Status > Time)
522            fixtures.sort((a, b) => {
523                const rawPA = a.league_priority != null ? parseInt(a.league_priority) : 3;
524                const rawPB = b.league_priority != null ? parseInt(b.league_priority) : 3;
525                
526                // NEUTRALIZE TIER 4 (Closed) -> TREAT AS TIER 3 (Open)
527                // This keeps them mixed alphabetically
528                const pA = (rawPA === 4) ? 3 : rawPA;
529                const pB = (rawPB === 4) ? 3 : rawPB;
530
531                if (pA !== pB) return pA - pB;
532                
533                // Group by Country/League first
534                const cA = (a.country || "").toUpperCase();
535                const cB = (b.country || "").toUpperCase();
536                if (cA !== cB) return cA.localeCompare(cB);
537
538                const lA = (a.league || "").toUpperCase();
539                const lB = (b.league || "").toUpperCase();
540                if (lA !== lB) return lA.localeCompare(lB);
541
542                // Then Status (Live > Upcoming > Finished)
543                const sA = parseInt(a.status_weight || 2);
544                const sB = parseInt(b.status_weight || 2);
545                if (sA !== sB) return sA - sB;
546
547                return (a.timestamp || 0) - (b.timestamp || 0);
548            });
549
550            var activeTab = this.target.querySelector('.bf-ls-tab.active');
551            var type = activeTab ? activeTab.getAttribute('data-tab') : 'all';
552            
553            var isLiveTab = (type === 'live');
554
555            var html = '';
556            var visibleCount = 0;
557            
558            var self = this;
559            var currentGroupHtml = '';
560            var groupHeaderHtml = '';
561            var groupPriority = 3; 
562            var lastHeaderKey = '';
563
564	    var closeGroup = function() {
565            if (!groupHeaderHtml) return;
566
567                // CHANGED: Collapse Priority 4 (Your List) and 5 (Bottom)
568                var isClosedTier = (groupPriority >= 4);
569                
570                var startCollapsed = (isClosedTier && !isLiveTab) ? ' collapsed' : '';
571                
572                html += '<div class="bf-ls-portal-header' + startCollapsed + '" data-group-toggle="true">';
573                html += groupHeaderHtml;
574                // --- FIX: ADDED data-xf-init="icon" SO XF LOADS THE SVG ---
575                html += '<i class="fa--xf fas fa-chevron-up bf-ls-header-arrow" data-xf-init="icon" aria-hidden="true"></i>'; 
576                html += '</div>';
577
578                html += '<div class="bf-ls-group-container' + startCollapsed + '">';
579                html += currentGroupHtml;
580                html += '</div>';
581
582                currentGroupHtml = '';
583                groupHeaderHtml = '';
584            };
585
586            var storedFollows = [];
587            if (XF.config.userId && parseInt(XF.config.userId, 10) > 0) {
588                try { storedFollows = JSON.parse(localStorage.getItem('bfLiveScore_follows')) || []; } catch(e) {}
589            }
590            var followedSet = new Set(storedFollows.map(String));
591
592            fixtures.forEach(function(m) {
593                var statusWeight = parseInt(m.status_weight || 2);
594                var country = m.country || '';
595
596                var show = false;
597                if (type === 'all') show = true; 
598                else if (type === 'live') show = (statusWeight === 1);
599                else if (type === 'upcoming') show = (statusWeight === 2);
600                else if (type === 'finished') show = (statusWeight === 3 || statusWeight === 4);
601                else if (type === 'today' || type === 'yesterday') show = true; 
602                
603		// 1. Apply BBCode Filter (Global Filter)
604                if (show && self.options.filter) {
605                    var filterVal = self.options.filter.toLowerCase();
606                    var mCountry = (m.country || '').toLowerCase();
607                    var mLeague = (m.league || '').toLowerCase();
608                    // Match PHP logic: Contains in Country OR League
609                    if (mCountry.indexOf(filterVal) === -1 && mLeague.indexOf(filterVal) === -1) {
610                        show = false;
611                    }
612                }
613
614                // 2. Apply UI Flag Filter (User Clicked Flag)
615
616                if (show && self.activeCountryFilter) { 
617                    if (country !== self.activeCountryFilter) show = false; 
618                }
619                
620                if (!show) return; 
621                visibleCount++;
622
623                var leagueName = m.league || 'Unknown League';
624                var cCode = m.country_code || (country ? country.substring(0,3).toUpperCase() : '');
625                var isFinished = (statusWeight === 3 || statusWeight === 4);
626                
627                var currentHeaderKey = country + '|' + leagueName;
628
629                if (currentHeaderKey !== lastHeaderKey) {
630                    closeGroup();
631                    
632                    var headerInner = '';
633                    if (cCode) {
634                        var lowerCode = cCode.toLowerCase();
635                        headerInner += '<span class="bf-ls-flag-trigger" data-country="' + self.escapeHtml(country) + '" data-country-code="' + self.escapeHtml(cCode) + '" title="Filter by ' + self.escapeHtml(country) + '">';
636                        headerInner += '<span class="fi fi-' + lowerCode + ' bf-icon-flag" style="vertical-align:middle; margin-right:4px; border-radius:2px;"></span></span>';
637                    }
638                    headerInner += '<span>' + (country ? self.escapeHtml(country) + ': ' : '') + self.escapeHtml(leagueName) + '</span>';
639                    
640                    groupHeaderHtml = headerInner;
641                    groupPriority = m.league_priority != null ? parseInt(m.league_priority) : 3;
642                    lastHeaderKey = currentHeaderKey;
643                }
644
645                // --- BUILD MATCH ROW ---
646                var rowHtml = '<div class="bf-ls-item-container" data-match-id="' + (m.id) + '" data-status="' + statusWeight + '" data-country="' + country + '">';
647                
648                var isFollowed = followedSet.has(String(m.id));
649                var followClass = isFollowed ? 'active' : '';
650                var ariaPressed = isFollowed ? 'true' : 'false';
651                var bellSvg = window.bfGetBellSvg(isFollowed);
652                var btnTitle = isFinished ? 'Match Finished' : (isFollowed ? 'Unfollow this match' : 'Follow this match');
653                var extraClass = isFinished ? ' is-finished' : '';
654                if (isFinished) extraClass += ' disabled';
655
656                var timeDisplay = '';
657                if (statusWeight === 2 && m.timestamp) {
658                    var d = new Date(m.timestamp * 1000);
659                    var hh = String(d.getHours()).padStart(2,'0');
660                    var mn = String(d.getMinutes()).padStart(2,'0');
661                    timeDisplay = hh + ':' + mn;
662                }
663                else if (m.time_display) {
664                     var isLive = (parseInt(m.status_weight) === 1);
665                     timeDisplay = (isLive ? '<span class="bf-ls-live-dot"></span> ' : '') + m.time_display;
666                } 
667                else if (m.timestamp) {
668                    var d = new Date(m.timestamp * 1000);
669                    var hh = String(d.getHours()).padStart(2,'0');
670                    var mn = String(d.getMinutes()).padStart(2,'0');
671                    timeDisplay = hh + ':' + mn;
672                }
673                if (!m.time_display && ['PST', 'CANC', 'ABD', 'SUSP', 'INT', 'WO', 'AWD'].includes(m.status)) {
674                    timeDisplay = m.status;
675                }
676
677                var scoreDisplay = m.score || '-';
678                var hasOdds = (m.odds && (m.odds['1'] || m.odds['X'] || m.odds['2']));
679                var cardClass = 'bf-ls-match-card' + (hasOdds ? ' has-odds' : '');
680
681                rowHtml += '<div class="' + cardClass + '">';
682                rowHtml += '<div class="bf-ls-card-top">';
683                rowHtml += '<button type="button" class="bf-ls-follow-btn ' + followClass + extraClass + '" ';
684                rowHtml += 'data-match-id="' + (m.id) + '" aria-pressed="' + ariaPressed + '" ';
685                if (isFinished) { rowHtml += 'disabled '; }
686                rowHtml += 'aria-label="' + btnTitle + '" title="' + btnTitle + '">' + bellSvg + '</button>';
687
688                rowHtml += '<div class="bf-ls-portal-time">' + timeDisplay + '</div>';
689                
690                rowHtml += '<div class="bf-ls-portal-teams">';
691                rowHtml += '<span class="bf-ls-portal-team home" title="' + self.escapeHtml(m.home) + '">' + self.escapeHtml(m.home) + '</span>';
692                rowHtml += '<span class="bf-ls-portal-score">' + scoreDisplay + '</span>';
693                rowHtml += '<span class="bf-ls-portal-team away" title="' + self.escapeHtml(m.away) + '">' + self.escapeHtml(m.away) + '</span>';
694                rowHtml += '</div>'; 
695                
696                if (parseInt(m.status_weight) === 1) {
697                    rowHtml += '<a href="' + (m.affiliate_link||'#') + '" target="_blank" class="bf-ls-bet-btn">BET</a>';
698                }
699
700                rowHtml += '</div>'; 
701                
702                if (!isFinished && hasOdds) {
703                     rowHtml += '<div class="bf-ls-odds-row"><div class="bf-ls-odds-inner">'; 
704                     var renderOdd = function(label) {
705                        var o = (m.odds && m.odds[label]) ? m.odds[label] : null;
706                        if (o && o.val) {
707                             var moveClass = o.move ? (' move-' + o.move) : '';
708                             return '<a href="' + (o.link || '#') + '" target="_blank" class="bf-ls-odd-btn' + moveClass + '" title="Best odds from ' + (o.bookie || '') + '">' +
709                                    '<span class="bf-ls-odd-label">' + label + '</span>' +
710                                    '<span class="bf-ls-odd-val">' + o.val + 
711                                    (o.pct ? ' <span class="bf-ls-odd-change">' + o.pct + '</span>' : '') + 
712                                    '</span></a>';
713                        } else { return '<div class="bf-ls-odd-btn disabled"></div>'; }
714                     };
715                     rowHtml += renderOdd('1') + renderOdd('X') + renderOdd('2');
716                     rowHtml += '</div></div>';
717                }
718                rowHtml += '</div>'; 
719                
720                rowHtml += '<div class="bf-ls-details-hidden" style="display:none">';
721                rowHtml += '<div class="bf-ls-header-row"><div class="bf-ls-header-team home"><span>' + m.home + '</span>';
722                if (m.home_logo) rowHtml += '<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" data-src="' + m.home_logo + '" class="bf-ls-header-logo" width="40" height="40" decoding="async" />';
723                rowHtml += '</div><div class="bf-ls-header-score"><span class="bf-ls-time-val">' + timeDisplay + '</span><span class="bf-ls-score-val">' + scoreDisplay + '</span>';
724                if (m.ht_score) rowHtml += '<span class="bf-ls-time-val" style="font-size:12px; margin-top:5px; opacity:0.6">(HT ' + m.ht_score + ')</span>';
725                rowHtml += '</div><div class="bf-ls-header-team away">';
726                if (m.away_logo) rowHtml += '<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" data-src="' + m.away_logo + '" class="bf-ls-header-logo" width="40" height="40" decoding="async" />';
727                rowHtml += '<span>' + m.away + '</span></div></div>';
728
729                // --- TIMELINE EVENTS REWRITE ---
730                rowHtml += '<div class="bf-ls-timeline">';
731                if (m.events && m.events.length > 0) {
732                    m.events.forEach(function(ev) {
733                        var isHome = (parseInt(ev.team_id) === parseInt(m.home_id));
734                        
735                        // Parse detail for special markers
736                        var detail = ev.detail || '';
737                        var isPenalty = (detail.indexOf('Penalty') !== -1 && ev.type === 'goal');
738                        var isOwnGoal = (detail.indexOf('Own') !== -1 && ev.type === 'goal');
739                        var isMissedPenalty = (detail.indexOf('Missed') !== -1);
740                        var isRedCard = (detail.indexOf('Red') !== -1);
741
742                        // Build Icon HTML
743                        var iconHtml = '';
744                        if (ev.type === 'goal') {
745                            if (isMissedPenalty) {
746                                iconHtml = '<i class="fa--xf fas fa-times-circle bf-icon bf-icon-miss" title="Missed Penalty" data-xf-init="icon"></i>';
747                            } else {
748                                iconHtml = '<i class="fa--xf fas fa-futbol bf-icon" style="color:var(--xf-textColor)" data-xf-init="icon"></i>';
749                            }
750                        } else if (ev.type === 'card') {
751                            var colorClass = isRedCard ? 'bf-icon-red' : 'bf-icon-yellow';
752                            iconHtml = '<i class="fa--xf fas fa-square bf-icon ' + colorClass + '" data-xf-init="icon"></i>';
753                        } else if (ev.type === 'var') {
754                             iconHtml = '<i class="fa--xf fas fa-video bf-icon bf-icon-var" data-xf-init="icon"></i>';
755                        }
756
757                        // Start Row
758                        rowHtml += '<div class="bf-ls-timeline-row">';
759                        
760                        // HOME COLUMN
761                        rowHtml += '<div class="bf-ls-t-home">';
762                        if (isHome) {
763                            if (ev.type === 'subst') {
764                                // Substitution Layout (In Top / Out Bottom)
765                                rowHtml += '<div class="bf-sub-container">';
766                                rowHtml += '<div class="bf-sub-row bf-sub-in">' + ev.player + ' <i class="fa--xf fas fa-arrow-up" style="color:#2ecc71; margin-left:6px;" data-xf-init="icon"></i></div>';
767                                if (ev.assist) {
768                                    rowHtml += '<div class="bf-sub-row bf-sub-out">' + ev.assist + ' <i class="fa--xf fas fa-arrow-down" style="color:#e74c3c; margin-left:6px;" data-xf-init="icon"></i></div>';
769                                }
770                                rowHtml += '</div>';
771                            } else {
772                                // Standard Event
773                                rowHtml += '<span class="bf-event-text">' + ev.player;
774                                if (isPenalty) rowHtml += ' <span class="bf-event-detail">(P)</span>';
775                                if (isOwnGoal) rowHtml += ' <span class="bf-event-detail">(OG)</span>';
776                                rowHtml += '</span> ' + iconHtml;
777                            }
778                        }
779                        rowHtml += '</div>';
780
781                        // TIME COLUMN
782                        rowHtml += '<div class="bf-ls-t-time">' + (ev.time||'') + '</div>';
783
784                        // AWAY COLUMN
785                        rowHtml += '<div class="bf-ls-t-away">';
786                        if (!isHome) {
787                            if (ev.type === 'subst') {
788                                // Substitution Layout
789                                rowHtml += '<div class="bf-sub-container">';
790                                rowHtml += '<div class="bf-sub-row bf-sub-in"><i class="fa--xf fas fa-arrow-up" style="color:#2ecc71; margin-right:6px;" data-xf-init="icon"></i> ' + ev.player + '</div>';
791                                if (ev.assist) {
792                                    rowHtml += '<div class="bf-sub-row bf-sub-out">
792<i class="fa--xf fas fa-arrow-down" style="color:#e74c3c; margin-right:6px;" data-xf-init="icon"></i> ' + ev.assist + '</div>';
793                                }
794                                rowHtml += '</div>';
795                            } else {
796                                // Standard Event
797                                rowHtml += iconHtml + ' <span class="bf-event-text">' + ev.player;
798                                if (isPenalty) rowHtml += ' <span class="bf-event-detail">(P)</span>';
799                                if (isOwnGoal) rowHtml += ' <span class="bf-event-detail">(OG)</span>';
800                                rowHtml += '</span>';
801                            }
802                        }
803                        rowHtml += '</div>'; // End Away
804
805                        rowHtml += '</div>'; // End Row
806                    });
807                } else { 
808                    rowHtml += '<div style="padding:20px; text-align:center; opacity:0.6">No events recorded.</div>'; 
809                }
810                rowHtml += '</div></div>'; 
811                rowHtml += '</div>'; 
812                currentGroupHtml += rowHtml;
813            });
814
815            closeGroup();
816
817            if (visibleCount === 0) {
818                container.innerHTML = '<div style="padding:30px; text-align:center; color:#999;">No matches found for this selection.</div>';
819            } else {
820                container.innerHTML = html;
821                
822                container.querySelectorAll('img[data-src]').forEach(function(img) {
823                    img.src = img.getAttribute('data-src');
824                    img.removeAttribute('data-src');
825                });
826                
827                // This triggers XF to scan the new HTML for 'data-xf-init="icon"' and render the SVGs
828                XF.activate(container);
829
830                if (self.activeCountryFilter) {
831                    self.filterRows(type);
832                }
833            }
834        },
835
836        setupFilterChip: function() {
837            var self = this;
838            var chip = this.target.querySelector('.bf-ls-filter-chip');
839            
840            // 1. Reset the chip element to clear any previous listeners (prevents duplicates)
841            if (chip) {
842                var newChip = chip.cloneNode(true);
843                chip.parentNode.replaceChild(newChip, chip);
844                chip = newChip;
845            }
846
847            if (!chip) return;
848
849            // 2. Select the close button (newly created inside the chip)
850            var closeBtn = chip.querySelector('.bf-filter-close');
851
852            // 3. Define the Close Action
853            var closeAction = function(e) {
854                // Stop the click from bubbling up
855                e.preventDefault();
856                e.stopPropagation();
857                
858                // Clear the filter logic
859                self.activeCountryFilter = null;
860                if (XF.config.userId && parseInt(XF.config.userId, 10) > 0) {
861                    localStorage.removeItem('bfLiveScore_filter_country');
862                    localStorage.removeItem('bfLiveScore_filter_code');
863                }
864                
865                // Hide chip
866                chip.style.display = 'none';
867                
868                // Refresh rows to show all matches again
869                var activeTab = self.target.querySelector('.bf-ls-tab.active');
870                var tabType = activeTab ? activeTab.getAttribute('data-tab') : 'all';
871                self.filterRows(tabType);
872            };
873
874            // 4. Mobile Check (Width <= 560px)
875            if (window.innerWidth <= 560) {
876                // MOBILE: Click ANYWHERE on the chip
877                chip.addEventListener('click', closeAction);
878            } else {
879                // DESKTOP: Click only the 'X' button
880                if (closeBtn) {
881                    closeBtn.addEventListener('click', closeAction);
882                }
883            }
884        },
885        
886        activateCountryFilter: function(country, code) {
887            this.activeCountryFilter = country;
888            if (XF.config.userId && parseInt(XF.config.userId, 10) > 0) {
889                localStorage.setItem('bfLiveScore_filter_country', country);
890                localStorage.setItem('bfLiveScore_filter_code', code || country.substring(0,3).toUpperCase());
891            }
892
893            var chip = this.target.querySelector('.bf-ls-filter-chip');
894            if (chip) {
895                chip.innerHTML = '<span class="bf-filter-label-full">' + country + '</span>' +
896                                 '<span class="bf-filter-label-short">' + (code || country.substring(0,3).toUpperCase()) + '</span>' +
897                                 '<span class="bf-filter-close" title="Clear Filter">&times;</span>';
898                chip.style.display = 'inline-flex';
899                this.setupFilterChip();
900            }
901
902            var activeTab = this.target.querySelector('.bf-ls-tab.active');
903            var tabType = activeTab ? activeTab.getAttribute('data-tab') : 'all';
904            this.filterRows(tabType);
905        },
906        
907        filterRows: function(type) {
908            var containerSelector = (this.currentMode === 'schedule') ? '.bf-ls-schedule-content' : '.bf-ls-content';
909            var container = this.target.querySelector(containerSelector);
910            if (!container) return;
911            
912            var self = this;
913            var totalVisible = 0;
914
915	 // --- NEW: Calculate Local Today String (YYYY-MM-DD) ---
916
917            var now = this.getCorrectedDate();
918
919            var localTodayStr = now.getFullYear() + '-' + String(now.getMonth() + 1).padStart(2, '0') + '-' + String(now.getDate()).padStart(2, '0');
920
921            // -------------------------------------------------------
922
923            // Iterate over GROUPS, not just matches
924            var groups = container.querySelectorAll('.bf-ls-group-container');
925            
926            groups.forEach(function(group) {
927                var groupMatches = group.querySelectorAll('.bf-ls-item-container');
928                var visibleInGroup = 0;
929                
930                groupMatches.forEach(function(el) {
931                    var status = parseInt(el.getAttribute('data-status') || 0);
932                    var rowCountry = el.getAttribute('data-country');
933		    var ts = parseInt(el.getAttribute('data-timestamp') || 0);
934                    var show = false;
935
936                    if (type === 'all') show = true; 
937                    else if (type === 'live') show = (status === 1);
938                    else if (type === 'upcoming') show = (status === 2);
939                    else if (type === 'finished') show = (status === 3 || status === 4);
940		    
941                    // =================================================================
942                    // === THIS IS THE MISSING BLOCK THAT HIDES "TOMORROW" MATCHES ===
943                    // =================================================================
944                    if (self.currentMode === 'static' && self.currentOffset === 0 && ts > 0) {
945                        // If it's NOT Live (Status 1), strictly enforce the date
946                        if (status !== 1) {
947                            var d = new Date(ts * 1000);
948                            var matchDateStr = d.getFullYear() + '-' + String(d.getMonth() + 1).padStart(2, '0') + '-' + String(d.getDate()).padStart(2, '0');
949                            
950                            // If the match date is NOT strictly today, hide it.
951                            if (matchDateStr !== localTodayStr) {
952                                show = false;
953                            }
954                        }
955                    }
956                    // =================================================================
957
958                    if (show && self.activeCountryFilter) {
959                        if (rowCountry !== self.activeCountryFilter) show = false;
960                    }
961                    
962                    el.style.display = show ? '' : 'none';
963                    if (show) visibleInGroup++;
964                });
965
966                var header = group.previousElementSibling; // The header is immediately before the group
967                
968                if (visibleInGroup > 0) {
969                    totalVisible += visibleInGroup;
970                    group.style.display = ''; // Make sure group div is visible
971                    if (header) header.style.display = '';
972                    
973                   
974                } else {
975                    // Hide the entire group if no matches match filter
976                    group.style.display = 'none'; 
977                    if (header) header.style.display = 'none';
978                }
979            });
980
981            var noDataMsg = this.target.querySelector('.bf-ls-no-data');
982            if (noDataMsg) {
983                noDataMsg.style.display = (totalVisible === 0) ? 'block' : 'none';
984            }
985        },
986
987        refresh: function(force, suppressSound) {
988            if (!document.body.contains(this.target)) return;
989            if (this.currentMode === 'schedule' || this.currentOffset !== 0) return;
990
991            // REMOVED: We want to poll the server to trigger the API fetcher
992            // if (!force && window.bfCentrifugeClient && window.bfCentrifugeClient.state === 'connected') {
993            //    console.log("BF LiveScore: Socket active, skipping poll.");
994            //    return;
995            // }
996
997            var self = this;
998            
999            var oldScores = {};
1000            this.target.querySelectorAll('.bf-ls-item-container').forEach(function(el) {
1001                var mid = el.getAttribute('data-match-id');
1002                var score = el.getAttribute('data-home-score');
1003                if (mid && score) {
1004                    oldScores[mid] = score;
1005                }
1006            });
1007            
1008            var now = Date.now();
1009            if (force || !this.lastFullRefresh || (now - this.lastFullRefresh > 120000)) {
1010                this.lastFullRefresh = now;
1011                this.fetchDynamic(oldScores, suppressSound);
1012            } else {
1013                XF.ajax('GET', XF.canonicalizeUrl('score/patch'), {}, function(data) {
1014                    if (data.updates && data.updates.length > 0) {
1015                        self.applyPatch(data.updates);
1016                    }
1017                }, { skipDefaultError: true, global: false });
1018            }
1019        },
1020
1021	 getScoreSum: function(str) {
1022
1023            if (!str || str.indexOf('-') === -1) return -1;
1024
1025            var parts = str.split('-');
1026
1027            if (parts.length !== 2) return -1;
1028
1029            var h = parseInt(parts[0], 10);
1030
1031            var a = parseInt(parts[1], 10);
1032
1033            if (isNaN(h) || isNaN(a)) return -1;
1034
1035            return h + a;
1036
1037        },
1038
1039        applyPatch: function(updates) {
1040            var self = this;
1041            var missingMatches = 0; 
1042
1043            updates.forEach(function(m) {
1044                var row = self.target.querySelector('.bf-ls-item-container[data-match-id="' + m.id + '"]');
1045                if (row) {
1046                    // 1. Update Score
1047                    var scoreEl = row.querySelector('.bf-ls-portal-score, .bf-ls-widget-score');
1048                    if (scoreEl && scoreEl.textContent !== m.score) {
1049			 var oldScoreText = scoreEl.textContent;
1050
1051                        var oldSum = self.getScoreSum(oldScoreText);
1052
1053                        var newSum = self.getScoreSum(m.score);
1054                        scoreEl.textContent = m.score;
1055                        row.setAttribute('data-home-score', m.score);
1056                         
1057                        // Only trigger if Total Goals INCREASED (Prevents VAR reversals & Kickoff sounds)
1058
1059                        if (oldSum > -1 && newSum > oldSum && m.score.indexOf('-') > -1) {
1060                            self.triggerGoalAnimation(row, scoreEl);
1061                        }
1062                    }
1063                    
1064                    // 2. Update Time (SAFEGUARD ADDED)
1065                    // Only update time if the match is NOT 'Upcoming' (Status 2).
1066                    // This prevents "15:00" being overwritten by "VS" during odds updates.
1067                    if (parseInt(m.status) !== 2) { 
1068                        var timeEl = row.querySelector('.bf-ls-portal-time, .bf-ls-widget-time');
1069                        if (timeEl) {
1070                            var isReallyLive = (m.status == 1 && m.time !== 'FT' && m.time !== 'AET' && m.time !== 'PEN');
1071                            timeEl.innerHTML = (isReallyLive ? '<span class="bf-ls-live-dot"></span>' : '') + m.time;
1072                        }
1073                    }
1074                } else {
1075                    missingMatches++;
1076                }
1077            });
1078           
1079
1080            if (missingMatches > 0) {
1081                console.log("BF LiveScore: Received updates for " + missingMatches + " missing matches. Forcing HTML fetch.");
1082                self.refresh(true); 
1083            }
1084        },
1085        
1086        fetchDynamic: function(oldScores, suppressSound) {
1087            var self = this;
1088            XF.ajax('GET', this.options.url, { filter: this.options.filter, mode: this.options.mode }, function(data) {
1089                if (data.html && data.html.content) {
1090                    self.applyContent(data.html.content, oldScores, suppressSound);
1091                }
1092            });
1093        },
1094        
1095        applyContent: function(htmlContent, oldScores, suppressSound) {
1096            var self = this;
1097            if (self.currentMode === 'schedule' || self.currentOffset !== 0) return;
1098
1099            var contentBox = self.target.querySelector('.bf-ls-content');
1100            if (contentBox) {
1101                // --- STATE MEMORY FIX: Capture EXACT State (True/False) ---
1102                // Previously, we only captured "Open" headers. 
1103                // Now, we capture true (collapsed) or false (open) for EVERY header.
1104                var headerStates = {};
1105                contentBox.querySelectorAll('.bf-ls-portal-header').forEach(function(h) {
1106                    var key = h.innerText.trim();
1107                    headerStates[key] = h.classList.contains('collapsed');
1108                });
1109                // -----------------------------
1110
1111                contentBox.innerHTML = htmlContent;
1112                
1113                // --- STATE RESTORE FIX: Force previous state ---
1114                contentBox.querySelectorAll('.bf-ls-portal-header').forEach(function(h) {
1115                    var key = h.innerText.trim();
1116                    
1117                    // Only override if we saw this header before
1118                    if (headerStates.hasOwnProperty(key)) {
1119                        var shouldBeCollapsed = headerStates[key];
1120                        var next = h.nextElementSibling;
1121                        
1122                        if (shouldBeCollapsed) {
1123                            h.classList.add('collapsed');
1124                            if (next && next.classList.contains('bf-ls-group-container')) {
1125                                next.classList.add('collapsed');
1126                            }
1127                        } else {
1128                            h.classList.remove('collapsed');
1129                            if (next && next.classList.contains('bf-ls-group-container')) {
1130                                next.classList.remove('collapsed');
1131                            }
1132                        }
1133                    }
1134                });
1135                // -------------------------------
1136                
1137                try { self.convertTimes(); } catch(e) {}
1138
1139                try {
1140                    var storedFollows = [];
1141                    if (XF.config.userId && parseInt(XF.config.userId, 10) > 0) {
1142                        try { storedFollows = JSON.parse(localStorage.getItem('bfLiveScore_follows')) || []; } catch(e) {}
1143                    }
1144                    var followedSet = new Set(storedFollows.map(String));
1145                    
1146                    var goalDetected = false;
1147
1148                    contentBox.querySelectorAll('.bf-ls-item-container').forEach(function(container) {
1149                        var mid = container.getAttribute('data-match-id');
1150                        var btn = container.querySelector('.bf-ls-follow-btn');
1151                        
1152                        if (btn && followedSet.has(mid)) {
1153                             btn.classList.add('active');
1154                             btn.setAttribute('aria-pressed', 'true');
1155                             if (window.bfGetBellSvg) {
1156                                 btn.innerHTML = window.bfGetBellSvg(true);
1157                                 XF.activate(btn); 
1158                             }
1159                        }
1160                        
1161                        if (oldScores && oldScores[mid]) {
1162                             var newScore = container.getAttribute('data-home-score');
1163                             
1164                             if (newScore && newScore !== oldScores[mid]) {
1165                                  // Mathematical Check for Goal Increase
1166
1167                                 var oldSum = self.getScoreSum(oldScores[mid]);
1168
1169                                 var newSum = self.getScoreSum(newScore);
1170
1171
1172
1173                                 if (oldSum > -1 && newSum > oldSum && newScore.indexOf('-') > -1) {
1174                                     self.triggerGoalAnimation(container, container.querySelector('.bf-ls-portal-score, .bf-ls-widget-score'));
1175                                     // --- FIX APPLIED HERE ---
1176                                     // Only allow sound if we are NOT suppressing it (e.g. on tab wake-up)
1177                                     if (!suppressSound) {
1178                                         goalDetected = true;
1179                                     }
1180                                     // ------------------------
1181                                 }
1182                             }
1183                        } 
1184                        else {
1185                            if (window['bfGoalTimer_' + mid]) {
1186                                var card = container.querySelector('.bf-ls-match-card');
1187                                if (card) card.classList.add('bf-recent-goal');
1188                            }
1189                        }
1190                    });     			
1191               
1192                    if (goalDetected) self.playSound();
1193
1194                } catch(e) { console.error(e); }
1195                
1196                try {
1197                    var activeTab = self.target.querySelector('.bf-ls-tab.active');
1198                    if (activeTab) {
1199                        self.filterRows(activeTab.getAttribute('data-tab'));
1200                    } else {
1201                        self.filterRows('all'); 
1202                    }
1203                } catch(e) {}
1204            }
1205        },
1206
1207        triggerGoalAnimation: function(row, scoreEl) {
1208            var self = this;
1209            var card = row.querySelector('.bf-ls-match-card');
1210            if (!card) return;
1211
1212            card.classList.remove('bf-goal-anim');
1213            void card.offsetWidth; 
1214            card.classList.add('bf-goal-anim');
1215
1216            var originalScore = scoreEl.textContent;
1217            scoreEl.textContent = "GOAL!";
1218            scoreEl.classList.add('bf-goal-text-anim');
1219
1220            setTimeout(function() {
1221                scoreEl.textContent = originalScore;
1222                scoreEl.classList.remove('bf-goal-text-anim');
1223            }, 3000);
1224
1225            var mid = row.getAttribute('data-match-id');
1226            if (window['bfGoalTimer_' + mid]) clearTimeout(window['bfGoalTimer_' + mid]);
1227
1228            setTimeout(function() {
1229                var currentCard = self.target.querySelector('.bf-ls-item-container[data-match-id="' + mid + '"] .bf-ls-match-card');
1230                if (currentCard) currentCard.classList.add('bf-recent-goal');
1231            }, 3000);
1232
1233            window['bfGoalTimer_' + mid] = setTimeout(function() {
1234                var currentCard = self.target.querySelector('.bf-ls-item-container[data-match-id="' + mid + '"] .bf-ls-match-card');
1235                if (currentCard) currentCard.classList.remove('bf-recent-goal');
1236                delete window['bfGoalTimer_' + mid];
1237            }, 63000);
1238
1239            this.playSound();
1240        }
1241    });
1242
1243    XF.Element.register('bf-livescore-app', 'XF.BFLiveScoreApp');
1244})(window, document);
1245
1246(function(){
1247  try {
1248    var css = ".bf-ls-date-scroll-wrapper .bf-ls-date-btn.active, .bf-ls-date-scroll-wrapper .bf-ls-date-btn.active:hover { background: hsla(var(--xf-paletteColor5)) !important; border-color: hsla(var(--xf-paletteColor5)) !important; color: hsla(var(--xf-paletteColor1)) !important; box-shadow: 0 2px 4px rgba(0,0,0,0.3) !important; font-weight:700 !important; } " +
1249              ".bf-filter-label-short { display: none; } " + 
1250              "@media (max-width: 800px) { .bf-filter-label-full { display: none; } .bf-filter-label-short { display: inline; } }";
1251    var id = 'bf-ls-date-btn-runtime-style';
1252    if (!document.getElementById(id)) {
1253      var s = document.createElement('style');
1254      s.id = id;
1255      s.textContent = css;
1256      document.head.appendChild(s);
1257    }
1258  } catch (e) {}
1259})();

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.