PageSourceSearch

https://swvasun.com/SWVAsun

html swvasun.com collected 2026-09-29 05:14:50 UTC 85,506 bytes, 1,555 lines download raw bytes

1<!doctype html>
2<html lang="en">
3
4<head>
5    <!-- Performance Optimizations -->
6    <link rel="preconnect" href="https://cdn.jsdelivr.net" crossorigin>
7    <link rel="preconnect" href="https://code.jquery.com" crossorigin>
8    <link rel="dns-prefetch" href="https://cdn.jsdelivr.net">
9    <link rel="dns-prefetch" href="https://code.jquery.com">
10    <link rel="dns-prefetch" href="https://maxcdn.bootstrapcdn.com">
11    <link rel="preload" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" as="style">
12    <!-- Required meta tags -->
13    <meta charset="utf-8">
14    <title>Free Online Newspaper Subscrption (VIA e-mail)</title>
15    <meta name="viewport" content="width=device-width, initial-scale=1">
16    
17     
18    <meta name="keywords" content="SWVA sun, Local News, Swva Sports, Breaking News, Obituaries, Public Notices"> 
19    <meta name="description" content="SWVA Local Online Newspaper"> 
20    
21    <link rel="shortcut icon" href="/favicon.ico?v=1790187371">
22    
22<script type="text/javascript" language="javascript" src="/lib/bl2.js"></script>
22
23
24    <!-- bootstrap -->
25    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
26    
26<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
26
27    <link type="text/css" rel="stylesheet" href="https://bulletlink.com/bootstrap.css">
28    <!-- /bootstrap -->
29
30    <!-- jQuery -->
31    
31<script src="https://code.jquery.com/jquery-1.7.min.js" integrity="sha256-/05Jde9AMAT4/o5ZAI23rUf1SxDYTHLrkOco0eyRV84=" crossorigin="anonymous"></script>
31
32
33    <!-- system -->
34    
34<script type="text/javascript" language="javascript" src="/settings.js?v=1790187371"></script>
34
35    
35<script>function SParameters(){return '1';}</script>
35
36    
36<script type="text/javascript" language="javascript" src="/articles.js?v=1790187371"></script>
36
37    
37<script type="text/javascript" language="javascript" src="/ads.js?v=1790187371"></script>
37
38    
38<script type="text/javascript" language="javascript" src="/menus.js?v=1790187371"></script>
38
39    
39<script type="text/javascript" language="javascript" src="/sections.js?v=1790187371"></script>
39
40    
40<script type="text/javascript" language="javascript" src="/polls.js?v=1790187371"></script>
40
41    
41<script type="text/javascript" language="javascript" src="/menu_horizontal.js?v=1790187371"></script>
41
42    <!-- /system -->
43
44    <!-- fontAwesome-->
45    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" />
46    <!-- /fontAwesome-->
47
48    <!-- general -->
49    
49<script type="text/javascript" language="javascript" src="/jscript1.js?v=1790187371"></script>
49
50    <link type="text/css" rel="stylesheet" href="/custom.css?v=1790187371">
51    
51<script type="text/javascript" language="javascript" src="/custom.js?v=1790187371"></script>
51
52    <!-- /general -->
53
54    <!--StartMH-->
55    <!--MetaSharing-->
56    <!--EndMH-->
57
58    <!-- live-Builder --> 
59    
59<script type="text/javascript" src="/ufields.js"></script>
59
60    <!-- /live-Builder -->
61    <meta property="og:image" content="https://swvasun.com/logo.jpg"/>
62<!-- Google tag (gtag.js) -->
vendor: 65 bytes, lines 62-63
62
63<script async src="https://www.googletagmanager.com/gtag/js?id=
63G-WJW2XMLVK9
vendor: 19 bytes, line 63
63" defer></script>
64<script>
vendor: 130 bytes, lines 65-68
65window.dataLayer = window.dataLayer || [];
66function gtag(){dataLayer.push(arguments);}
67gtag('js', new Date());
68gtag('config', '
68G-WJW2XMLVK9
vendor: 5 bytes, line 68
68');
69</script>
vendor: 2 bytes, line 69
69
70<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-1521277811821952"
71crossorigin="anonymous" defer></script>
71
72<meta name="google-site-verification" content="ZWleqlOYPt0wm05jtSHIjposIojO4ID1mzFoLwoHm8M" />
73<!-- This site is converting visitors into subscribers and customers with OptinMonster - https://optinmonster.com -->
74<script>(function(d,u,ac){var s=d.createElement('script');s.type='text/javascript';s.src='https://a.omappapi.com/app/js/api.min.js';s.async=true;s.dataset.user=u;s.dataset.account=ac;d.getElementsByTagName('head')[0].appendChild(s);})(document,171153,185538);</script>
74
75<!-- / https://optinmonster.com -->
76    
77<style>:root{--cms-theme-color: #555;}</style><link rel="stylesheet" href="/sys-popup.css?v=1790187371"><style id="universal-submit-spinner">
78.form-submit-spinner{display:inline-block;width:16px;height:16px;border:2px solid rgba(255,255,255,.4);border-top-color:#fff;border-radius:50%;animation:frmSpin .7s linear infinite;vertical-align:middle;margin-right:6px}
79@keyframes frmSpin{to{transform:rotate(360deg)}}
80</style></head>
81
82<body id="blbodymain" class="blbody" data-submenu="{{SubMenuId}}"><a href="https://swvasun.com/cdn-cgi/content?id=WuBjsqb.v4iyJkJzrDQ0RfjWLhkAnJ_eCuZWIbLPDEc-1790658886.1171563-1.2.1.1-Mne10IxvPPqCQZbkGRJaJSUEs0zTqzhJJg_FVpTgHM4BQpgY8LP2WoE3Dn3TR5k1" aria-hidden="true" rel="nofollow noopener" style="display: none !important; visibility: hidden !important"></a>
83    <div class="mainbody">
84
85<!-- Popup - start -->
86<div class="Ad22"><div data-cms-block="adgroup-22" data-cms-block-label="Advertisement 22" data-cms-el="adgroup" data-cms-adgroup="22">
86<script type="text/javascript" language="JavaScript">AdGroup22();</script>
86</div></div>
87<script>
88if (readCookie("subs-popup-" + ReadSubmenu())) {
89 // document.querySelector("iframe[src*='&pform={{NewsViaEmail2}}']").closest("#f_Popup4").classList.add("d-none");
90 // document.body.style.overflow = "visible";
91} else {
92  createCookie("subs-popup-" + ReadSubmenu(), "Yes");
93}
94</script>
94
95<!-- Popup - end -->
96
97        <!-- stycky ads-->
98        <span class="cus-sticky-ads"><div data-cms-block="adgroup-1" data-cms-block-label="Advertisement 1" data-cms-el="adgroup" data-cms-adgroup="1">
98<script type="text/javascript" language="JavaScript">AdGroup1();</script>
98</div><div data-cms-block="adgroup-2" data-cms-block-label="Advertisement 2" data-cms-el="adgroup" data-cms-adgroup="2">
98<script type="text/javascript" language="JavaScript">AdGroup2();</script>
98</div><div data-cms-block="adgroup-3" data-cms-block-label="Advertisement 3" data-cms-el="adgroup" data-cms-adgroup="3">
98<script type="text/javascript" language="JavaScript">AdGroup3();</script>
98</div></span>
99        <!-- /stycky ads-->
100        <div class="container-xxl mt-2">
101            <!-- top-links -->
102            <div class="row mb-3 border-bottom pb-2 border-2">
103                <div class="bl-top-links col-sm-4 float-start">
104                    <div class="float-start">
105                        <!-- search-->
106                        
106<script type="text/javascript" language="JavaScript">GetGoogleCustomSearch();</script>
106
107                        <a class="search-link text-decoration-none text-black fs-6 fw-bold me-3 border rounded p-1 px-2 bl-toplink-1-133-searchlink" href="javascript:void(0)" data-bs-toggle="tooltip" data-bs-placement="right" title="Click to Search Articles..."><i class="fa fa-search" aria-hidden="true"></i> SEARCH</a>
108                        <div class="search_content">
109                            <div class="search_box"><gcse:searchbox></gcse:searchbox></div>
110                            <div class="search_results"><gcse:searchresults></gcse:searchresults></div>
111                            <div class="search_remove">
112                                <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="currentColor" class="bi bi-x-lg" viewBox="0 0 16 16">
113                                    <path fill-rule="evenodd" d="M13.854 2.146a.5.5 0 0 1 0 .708l-11 11a.5.5 0 0 1-.708-.708l11-11a.5.5 0 0 1 .708 0Z"/>
114                                    <path fill-rule="evenodd" d="M2.146 2.146a.5.5 0 0 0 0 .708l11 11a.5.5 0 0 0 .708-.708l-11-11a.5.5 0 0 0-.708 0Z"/>
115                              </svg>
116                            </div>
117                        </div>
118                        
118<script>
119                            document.getElementsByClassName('search-link')[0].addEventListener("click", function() {
120                                document.getElementById("gsc-i-id1").setAttribute("placeholder", "Search for...");
121                                document.getElementsByClassName('search_content')[0].classList.add("search-flex");
122                                document.getElementsByClassName('search_remove')[0].style.display = "block";
123                                document.getElementsByClassName('gsc-results-close-btn')[0].addEventListener("click", function() {
124                                    document.getElementsByClassName('search_content')[0].classList.remove("search-flex");
125                                });
126                            });
127                            document.getElementsByClassName('search_remove')[0].addEventListener("click", function() {
128                                document.getElementsByClassName('search_content')[0].classList.remove("search-flex");
129                                document.getElementsByClassName('search_remove')[0].style.display = "none";                            });
130                        </script>
130
131                        <style>
132                            .gsc-adBlock {display: none !important;}
133                            #gsc-i-id1{color:#000!important}
134                            #gsc-i-id1::placeholder{color:#555!important;opacity:1;font-size:inherit!important}
135                            .search_content{display:flex;display:-webkit-flex;-ms-display:flex;align-items:center;-webkit-align-items:center;-ms-align-items:center;justify-content:center;-webkit-justify-content:center;-ms-justify-content:center;background-color:rgba(255,255,255,.98);height:100%;position:fixed;top:100%;opacity:0;left:0;width:100%;z-index:2147483647;transition: 400ms linear;}
136                            .search-flex{top: 0;opacity: 1;display:flex;display:-webkit-flex;-ms-display:flex;align-items:center;-webkit-align-items:center;-ms-align-items:center;justify-content:center;-webkit-justify-content:center;-ms-justify-content:center;transition: 300ms linear;}
137                            .search_remove{cursor:pointer;user-select:none;position:absolute;top:10px;left:3%;}
138                            .search_remove:hover{color:gray}
139                            .gsc-control-cse.gsc-control-cse-en{background-color:transparent;border-width:0;position:absolute}.search_box{border-bottom:2px solid #000;width:70%;padding-bottom:6px}
140                            .gsib_b,.gsst_a{display:none!important}
141                            .gscb_a{display:none!important}
142                            .gsc-input{background-image:none!important}
143                            .gsc-input{background-color:transparent!important}
144                            .gsc-input-box{background-color:transparent!important;border-bottom:0 solid #ff4500!important;border-width:0!important}
145                            .gsc-input{border-width:0!important;color:#fff!important;font-size:20px!important}
146                            .gsc-adBlock{display:none!important}
147                            .search-icon-desk{cursor:pointer}
148                            .search-icon-desk{float:right;height:54px;margin-right:10px}
149                            .search-icon-desk i{border:1px solid #ddd;border-radius:4px;color:#000;display:block;line-height:35px;margin-top:9px;padding:0 12px}
150                            .search-icon-desk i:hover{color:#79655d}
151                            .gsc-results-wrapper-overlay.gsc-results-wrapper-visible {width: 100%;left: 0;top: 0;height: 100%;}
152                            .gcsc-branding {display: none;}
153                            .gsc-search-button.gsc-search-button-v2{padding:0 18px;line-height:35px;display:inline-block!important;background:#ddd;border-radius:5px;border-color:#555}
154                            .gsc-search-button{width:auto!important;float:right!important}.gsc-search-button.gsc-search-button-v2:hover{background:#ddd!important}
155                            .gsc-search-button-v2 svg{fill:#000!important}
156                            .gsc-search-button.gsc-search-button-v2:hover{background:#05a2d3!important;border-color:#006899!important}
157                            .gsc-search-button.gsc-search-button-v2:hover svg{fill:#fff!important}
158                        </style>
159                        <!-- /search-->
160                        <a class="text-decoration-none text-black fs-6 me-3 bl-toplink-1-133-link" href="/about-us-p374-25.htm">ABOUT</a>
161                        <a class="text-decoration-none text-black fs-6 me-3 bl-toplink-1-133-link" href="/ContactUs">CONTACT</a>
162                        <a class="text-decoration-none text-black fs-6 me-3 bl-toplink-1-133-link" href="/SWVAsun">SIGN ME UP</a>
163                         
164
165                    </div>
166                </div>
167                <div class="cus-social-links col-sm-4 float-sm-end d-flex justify-content-center d-sm-inline-block">
168                    <div class="float-sm-start">
169                        <a class="text-decoration-none text-dark rounded ms-3 fs-4 d-inline-block lh-1 cus-social-1-133-icon" href="https://www.facebook.com/swvasun/" target="_blank"><i class="fa fa-facebook-square" aria-hidden="true"></i></a>
170                        <a class="text-decoration-none text-dark rounded ms-3 fs-4 d-inline-block lh-1 cus-social-1-133-icon" href="https://twitter.com/swvasun" target="_blank"><svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" class="bi bi-twitter-x" viewBox="0 0 16 16" style="padding: 3px;background: #212529;fill: #fff;border-radius: 4px;display: inline-block;transform: translateY(-2px);" width="20" height="22"><path d="M12.6.75h2.454l-5.36 6.142L16 15.25h-4.937l-3.867-5.07-4.425 5.07H.316l5.733-6.57L0 .75h5.063l3.495 4.633L12.601.75Zm-.86 13.028h1.36L4.323 2.145H2.865z"></path></svg></a>
171                        <a class="text-decoration-none text-dark rounded ms-3 fs-4 d-inline-block lh-1 cus-social-1-133-icon" href="https://www.linkedin.com/company/swva-media-llc/" target="_blank"><i class="fa fa-linkedin-square" aria-hidden="true"></i></a>
172                        <a class="text-decoration-none text-dark rounded ms-3 fs-4 d-inline-block lh-1 cus-social-1-133-icon" href="https://youtube.com/@southwestvirginiasun8601" target="_blank"><i class="fa fa-youtube-play" aria-hidden="true"></i></a>
173                    </div>
174                </div>
175            </div>
176            <!-- /top-links -->
177            <!-- logo-->
178            <!-- Logo + AdGroup16 (centered) -->
179<div class="row mb-3 align-items-center">
180  <!-- Left section: Logo + Ad16 -->
181  <div class="col-md-12 text-center">
182    <div class="mb-2">
183      <div data-cms-el="logo">
183<script type="text/javascript" language="JavaScript">GetLogo();</script>
183</div>
184    </div>
185    <div>
186      <div data-cms-block="adgroup-16" data-cms-block-label="Advertisement 16" data-cms-el="adgroup" data-cms-adgroup="16">
186<script type="text/javascript" language="JavaScript">AdGroup16();</script>
186</div>
187    </div>
188  </div>
189
190  <!-- Right section: Ad29 -->
191
192</div>
193
194
195            <div class="row mb-3">
196                <div class="col-12 px-0 d-flex justify-content-center  border-top border-bottom border-2">
197                    
197<script type="text/javascript" language="JavaScript">
198                        GetMenuH();
199                    </script>
199
200                </div>
201            </div>
202            <!-- /menu -->
203<div class="cus-column-133-row row mb-3 border-bottom">
204                <div class="cus-column-133-1 col-lg-9 pe-lg-3">
205<div data-cms-popup-root="1"><style>
206#CustomForm {background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='32' viewBox='0 0 16 32'%3E%3Cg fill='%23c9d1cb' fill-opacity='0.16'%3E%3Cpath fill-rule='evenodd' d='M0 24h4v2H0v-2zm0 4h6v2H0v-2zm0-8h2v2H0v-2zM0 0h4v2H0V0zm0 4h2v2H0V4zm16 20h-6v2h6v-2zm0 4H8v2h8v-2zm0-8h-4v2h4v-2zm0-20h-6v2h6V0zm0 4h-4v2h4V4zm-2 12h2v2h-2v-2zm0-8h2v2h-2V8zM2 8h10v2H2V8zm0 8h10v2H2v-2zm-2-4h14v2H0v-2zm4-8h6v2H4V4zm0 16h6v2H4v-2zM6 0h2v2H6V0zm0 24h2v2H6v-2z'/%3E%3C/g%3E%3C/svg%3E");background-attachment: fixed;}
207.form-check-label:hover {color: #0d6efd;cursor: pointer;}
208.cus-form-loader .cus-form-loading {display: block !important;}
209.cus-form-loader .formbody fieldset, .cus-form-loader .system_text.footer_text {opacity: 0.5;pointer-events: none;}
210#cus-form-button-loader {display:none;}
211.cus-form-loader footer, .cus-form-loader button {cursor: no-drop;}
212.fast-spin {-webkit-animation: fa-spin 1s infinite linear;animation: fa-spin 1s infinite linear;}
213.cus-form-loader #SUBMIT1 {display:none;}
214.cus-form-loader #cus-form-button-loader {display:inline-block;}
215.form-floating > .form-control:focus ~ label {color: #0d6efd !important;}
216.form-control:not(:disabled):not([readonly])::file-selector-button {position: absolute;right: 0;border-radius: 5px !important;}
217.input-file-preview {display: none;}
218.input-file-preview img {max-width: 30%;max-height: 200px;border: 1px solid #ced4da;border-radius: 5px;padding: 5px;box-sizing: border-box;cursor: zoom-in;}
219.w-96 {width: 96% !important;}
220.p-valid {color: green;}
221.p-valid:before {position: relative;left: -10px;content: "✔";}
222.p-invalid {color: red;}
223.p-invalid:before {position: relative;left: -10px;content: "✖";font-size: 0.875rem !important;}
224.open-eye, .close-eye {position: absolute;right: 2%;top: 50%;transform: translate(0,-50%);cursor: pointer;}
225.open-eye i:hover, .close-eye i:hover {color: gray !important;}
226.cus-form-help:before {content: "\f05a";font-family: FontAwesome;padding-left: 0.5rem;padding-right: 0.5rem;}
227.cus-form-help {display: none;}
228.cus-form-help:empty {display: none !important;}
229.form-control:focus ~ .cus-form-help {display: block;}
230.formdivider.formdivider_custom {border-left: 5px solid #ffc107;}
231.form-floating > .form-control {caret-color: #0d6efd;}
232</style>
233<style id="force-form-styles" data-version="2026-01-26-v2">
234      textarea, textarea.form-control, textarea.formfieldinput { min-height: 120px !important; height: 120px !important; }
235
236      /* Enhanced Spinner Styles - More visible and animated */
237      .form-spinner-ring { 
238        display: inline-block; 
239        width: 18px; 
240        height: 18px; 
241        border: 3px solid rgba(255,255,255,0.4); 
242        border-top-color: #fff; 
243        border-radius: 50%; 
244        animation: formSpin 0.7s linear infinite; 
245        margin-right: 8px; 
246        vertical-align: middle; 
247      }
248      @keyframes formSpin { 
249        0% { transform: rotate(0deg); }
250        100% { transform: rotate(360deg); } 
251      }
252      
253      /* Submit Button Loading State */
254      button.btn-loading, input.btn-loading {
255        position: relative;
256        pointer-events: none;
257        opacity: 0.85;
258      }
259      button.btn-loading::after {
260        content: '';
261        position: absolute;
262        width: 18px;
263        height: 18px;
264        top: 50%;
265        left: 12px;
266        margin-top: -9px;
267        border: 3px solid rgba(255,255,255,0.4);
268        border-top-color: #fff;
269        border-radius: 50%;
270        animation: formSpin 0.7s linear infinite;
271      }
272      
273      /* Form Overlay during submission */
274      .form-loading-overlay {
275        position: absolute;
276        top: 0;
277        left: 0;
278        right: 0;
279        bottom: 0;
280        background: rgba(255,255,255,0.7);
281        display: flex;
282        align-items: center;
283        justify-content: center;
284        z-index: 9999;
285        border-radius: inherit;
286      }
287      .form-loading-overlay .spinner-container {
288        display: flex;
289        flex-direction: column;
290        align-items: center;
291        gap: 12px;
292        padding: 30px;
293        background: white;
294        border-radius: 12px;
295        box-shadow: 0 4px 20px rgba(0,0,0,0.15);
296      }
297      .form-loading-overlay .spinner-large {
298        width: 40px;
299        height: 40px;
300        border: 4px solid #e0e0e0;
301        border-top-color: #007bff;
302        border-radius: 50%;
303        animation: formSpin 0.8s linear infinite;
304      }
305      .form-loading-overlay .loading-text {
306        color: #333;
307        font-size: 14px;
308        font-weight: 500;
309      }
310      
311      /* Bootstrap 5 Floating Label Fix - Force proper behavior */
312      .form-floating > .form-control:focus ~ label,
313      .form-floating > .form-control:not(:placeholder-shown) ~ label,
314      .form-floating > .form-select ~ label {
315        opacity: 0.65 !important;
316        transform: scale(0.85) translateY(-0.5rem) translateX(0.15rem) !important;
317      }
318      .form-floating > .form-control::placeholder {
319        color: transparent !important;
320      }
321      .form-floating > label {
322        position: absolute !important;
323        top: 0 !important;
324        left: 0 !important;
325        height: 100% !important;
326        padding: 1rem 0.75rem !important;
327        pointer-events: none !important;
328        border: 1px solid transparent !important;
329        transform-origin: 0 0 !important;
330        transition: opacity 0.1s ease-in-out, transform 0.1s ease-in-out !important;
331      }
332    </style>
333<style>.grecaptcha-badge{visibility:hidden!important;position:fixed!important;bottom:14px!important;right:14px!important;}</style>
334<script src="/iframe-resizer-master/js/iframeResizer.contentWindow.js"></script>
vendor: 1 bytes, line 334
334
335<script type="text/javascript" language="javascript" src="https://swvasun.com/lib/bl.js"></script>
vendor: 1 bytes, line 335
335
336<script>
337function ChangeInputFocus(obj, evt, cname) {
338/*if (evt.type == "focus")
339obj.className = cname;
340else if (evt.type == "blur")
341/*obj.className = cname;*/
342}
343</script>
vendor: 1 bytes, line 343
343
344<script src="https://recaptcha.net/recaptcha/api.js?render=6LdXmfgUAAAAAJNuEHBxVCY0w9eA73hvaWsdgPlM"></script>
vendor: 1 bytes, line 344
344
345<script>
346(function(){
347  function setToken(t){
348    var els = document.querySelectorAll('.g-recaptcha-token');
349    for (var i = 0; i < els.length; i++) els[i].value = t;
350  }
351  function refresh(){
352    if (typeof grecaptcha === 'undefined') return;
353    grecaptcha.ready(function(){
354      grecaptcha.execute('6LdXmfgUAAAAAJNuEHBxVCY0w9eA73hvaWsdgPlM', {action: 'submit'}).then(setToken);
355    });
356  }
357  // Submit-time minter. Login pages call this in their submit handler and await it,
358  // so the request always carries a freshly-minted token instead of reading the
359  // pre-filled hidden field — which may still be empty when a user with saved
360  // credentials presses Enter before the page-load mint resolves (-> recaptcha_missing,
361  // a hard block). Resolves to a fresh token, or falls back to whatever's already in
362  // the field (and never hangs the form: 3s timeout, and resolves if grecaptcha is
363  // unavailable). Also updates the hidden field so FormData-based submits pick it up.
364  window.cmsMintCaptchaToken = function(){
365    return new Promise(function(resolve){
366      var els = document.querySelectorAll('.g-recaptcha-token');
367      var fallback = (els[0] && els[0].value) || '';
368      var done = false;
369      var to = setTimeout(function(){ if(!done){ done = true; resolve(fallback); } }, 3000);
370      function fin(v){ if(done) return; done = true; clearTimeout(to); setToken(v); resolve(v); }
371      function attempt(){
372        if (typeof grecaptcha === 'undefined' || !grecaptcha.execute) return false;
373        try {
374          grecaptcha.ready(function(){
375            grecaptcha.execute('6LdXmfgUAAAAAJNuEHBxVCY0w9eA73hvaWsdgPlM', {action: 'submit'})
376              .then(function(t){ fin(t || fallback); })
377              .catch(function(){ fin(fallback); });
378          });
379          return true;
380        } catch(_) { return false; }
381      }
382      // grecaptcha may still be loading -- common when the form is rendered
383      // inside a popup, where api.js was injected only moments ago. Poll until
384      // it's ready (or the 3s timeout fires) instead of bailing immediately.
385      if (!attempt()) {
386        var iv = setInterval(function(){
387          if (done) { clearInterval(iv); return; }
388          if (attempt()) clearInterval(iv);
389        }, 150);
390      }
391    });
392  };
393  refresh();
394  setTimeout(refresh, 5000);
395  setInterval(refresh, 120000);
396})();
397</script>
397
398<div class="formbody">
399<div class="body p-2">
400<!--FormError-->
401<!--FormMessage-->
402<form class="custom-form p-3 mx-0 border rounded" enctype="multipart/form-data" autocomplete="off" id="CustomForm" method="post" name="CustomForm" onsubmit="return unifiedSubmitForm(event)">
403<div aria-hidden="true" style="position:absolute;left:-9999px;top:-9999px;height:0;width:0;overflow:hidden;">
404  <label for="website_url_hp">Website (leave blank)</label>
405  <input type="text" name="website_url" id="website_url_hp" tabindex="-1" autocomplete="off" value="">
406</div>
407<input type="hidden" name="token" class="g-recaptcha-token" value="">
408<!--FKeys-->
409<input type="hidden" name="SystemEmailSubject" value="SWVAsun.com: Online Newspaper Subscription"> 
410<input type="hidden" name="SystemEmailConfirmMessage" value="Your message has been forwarded to appropriate personnel. Thank you."> 
411<input type="hidden" name="SystemEmailFormat" value="HTML"> 
412<input type="hidden" name="SystemEmailTo" value="[email protected]"> 
413<input type="hidden" name="SystemEmailCC" value="">
414<center class="fw-bold mb-3 fs-3 text-secondary">Free Online Newspaper Subscrption (VIA e-mail)</center>
415<fieldset>
416<div class="system_text Header_text mb-5 text-center"><html><head></head><body><html><head></head><center style="box-sizing: border-box; font-family: system-ui, -apple-system, " segoe=""  ui",="" roboto,="" "="" helvetica=""  neue",="" arial,="" noto=""  sans",="" liberation=""  sans-serif,="" apple="" color=""  emoji",="" ui=""  symbol",="" emoji";="" background-color:=""  #ffffff;="" 1rem=""  !important;="" font-size:=""  calc(1.="" 3rem=""  +="" 0.6vw)="" font-weight:="" 700="" color:=""  #="" 6c757d=""  !important;"=""><br /></center><fieldset style="box-sizing: border-box; color: #212529;" segoe=""  ui",="" roboto,="" "="" helvetica=""  neue",="" arial,="" noto=""  sans",="" liberation=""  sans-serif,="" apple="" color=""  emoji",="" ui=""  symbol",="" emoji";="" font-size:=""  16px;="" background-color:=""  #ffffff;"=""><div style="box-sizing: border-box; text-align: center !important;"><h1 style="box-sizing: border-box; font-size: calc(1.375rem + 1.5vw);"><center style="box-sizing: border-box;"><u style="font-size: 18pt;"><span style="font-size: 14pt;">SWVAsun.com is your new online hometown newspaper.</span></u></center></h1><div><center style="box-sizing: border-box;"><u style="font-size: 18pt;"><span style="font-size: 14pt;"><strong></strong></span></u></center></div><br style="box-sizing: border-box;" /><center style="box-sizing: border-box;"></center></div></fieldset>
417<!-- Form Script v2026-01-26-v2 -->
418<!-- Modern Popup Modal for Messages -->
419<div id="form-message-modal" style="display:none; position:fixed; inset:0; background:rgba(0,0,0,0.7); z-index:99999; align-items:center; justify-content:center; padding:20px;">
420  <div style="background:#fff; min-width:320px; max-width:400px; border-radius:12px; padding:24px; box-shadow:0 25px 50px -12px rgba(0,0,0,0.5);">
421    <div id="form-message-text" style="margin-bottom:20px; font-size:15px; color:#333; text-align:center; line-height:1.5;"></div>
422    <button id="form-message-ok" style="width:100%; padding:12px 20px; font-size:14px; font-weight:600; background:#007bff; color:white; border:none; border-radius:8px; cursor:pointer; transition:all 0.2s ease;" onmouseover="this.style.background='#0056b3'" onmouseout="this.style.background='#007bff'">OK</button>
423  </div>
424</div>
425
426<script>
427// Resolve the URL to POST the form to. On a normal page load the form lives at
428// its own URL, so window.location.pathname is correct. But when the form is
429// opened inside a popup (sys-popup.js), the page URL is the HOST page, not the
430// form's URL -- sys-popup stamps the real form path onto the form as
431// data-form-action, which we prefer when present.
432function cmsResolvePostUrl(form) {
433  var f = form || document.querySelector('form');
434  var a = f && f.getAttribute && f.getAttribute('data-form-action');
435  return a || window.location.pathname;
436}
437
438// Modern message popup function
439// onClose callback is called when user clicks OK (useful for resetting button on error)
440function showFormMessage(text, isSuccess = false, onClose = null) {
441  const modal = document.getElementById('form-message-modal');
442  const modalMsg = document.getElementById('form-message-text');
443  const modalOk = document.getElementById('form-message-ok');
444  
445  if (modal && modalMsg && modalOk) {
446    modalMsg.innerHTML = isSuccess 
447      ? '<div style="display:flex;align-items:center;justify-content:center;gap:12px;margin-bottom:20px;"><div style="width:50px;height:50px;background:linear-gradient(135deg,#28a745,#20c997);border-radius:50%;display:flex;align-items:center;justify-content:center;box-shadow:0 4px 15px rgba(40,167,69,0.3);flex-shrink:0;"><span style="color:white;font-size:28px;font-weight:bold;">✓</span></div><span style="color:#28a745;font-size:28px;font-weight:600;">Success</span></div>' + text
448      : text;
449    modal.style.display = 'flex';
450    modalOk.onclick = function() { 
451      modal.style.display = 'none';
452      if (isSuccess) {
453        (window.top || window).location.href = '/';
454      } else if (onClose) {
455        onClose();
456      }
457    };
458    // Also close on backdrop click
459    modal.onclick = function(e) {
460      if (e.target === modal) {
461        modal.style.display = 'none';
462        if (isSuccess) {
463          (window.top || window).location.href = '/';
464        } else if (onClose) {
465          onClose();
466        }
467      }
468    };
469  } else {
470    // Fallback to alert if modal not found
471    alert(text);
472    if (isSuccess) {
473      (window.top || window).location.href = '/';
474    } else if (onClose) {
475      onClose();
476    }
477  }
478}
479
480// Accept.js card input modal for Authorize.net
481async function showAcceptJsCardInput(clientConfig, form, originalFormData, paymentResult) {
482  console.log('[forms] Loading Accept.js for card tokenization');
483  
484  // Load Accept.js script dynamically
485  if (!window.Accept) {
486    await new Promise((resolve, reject) => {
487      const script = document.createElement('script');
488      script.src = clientConfig.jsUrl;
489      script.onload = resolve;
490      script.onerror = () => reject(new Error('Failed to load Accept.js'));
491      document.head.appendChild(script);
492    });
493  }
494  
495  // Create card input modal
496  const modalHtml = `
497    <div id="acceptjs-modal" style="position:fixed;inset:0;background:rgba(0,0,0,0.7);z-index:99999;display:flex;align-items:center;justify-content:center;padding:20px;">
498      <div style="background:#fff;max-width:400px;width:100%;border-radius:12px;padding:30px;box-shadow:0 25px 50px -12px rgba(0,0,0,0.5);">
499        <h3 style="margin:0 0 20px;color:#333;">Payment Information</h3>
500        <p style="margin:0 0 20px;color:#666;">Amount: <strong>$${paymentResult.amount}</strong></p>
501        
502        <div style="margin-bottom:15px;">
503          <label style="display:block;margin-bottom:5px;font-weight:600;color:#333;">Card Number *</label>
504          <input type="text" id="ajs-card-number" placeholder="4111 1111 1111 1111" maxlength="19"
505                 style="width:100%;padding:12px;border:1px solid #ccc;border-radius:4px;font-size:16px;box-sizing:border-box;">
506        </div>
507        
508        <div style="display:flex;gap:15px;margin-bottom:15px;">
509          <div style="flex:1;">
510            <label style="display:block;margin-bottom:5px;font-weight:600;color:#333;">Exp Month *</label>
511            <select id="ajs-exp-month" style="width:100%;padding:12px;border:1px solid #ccc;border-radius:4px;font-size:16px;">
512              <option value="">MM</option>
513              ${[...Array(12)].map((_,i) => '<option value="'+String(i+1).padStart(2,'0')+'">'+String(i+1).padStart(2,'0')+'</option>').join('')}
514            </select>
515          </div>
516          <div style="flex:1;">
517            <label style="display:block;margin-bottom:5px;font-weight:600;color:#333;">Exp Year *</label>
518            <select id="ajs-exp-year" style="width:100%;padding:12px;border:1px solid #ccc;border-radius:4px;font-size:16px;">
519              <option value="">YYYY</option>
520              ${[...Array(15)].map((_,i) => { const y=new Date().getFullYear()+i; return '<option value="'+y+'">'+y+'</option>'; }).join('')}
521            </select>
522          </div>
523          <div style="width:100px;">
524            <label style="display:block;margin-bottom:5px;font-weight:600;color:#333;">CVV *</label>
525            <input type="text" id="ajs-cvv" placeholder="123" maxlength="4"
526                   style="width:100%;padding:12px;border:1px solid #ccc;border-radius:4px;font-size:16px;box-sizing:border-box;">
527          </div>
528        </div>
529        
530        <div id="ajs-error" style="color:#dc3545;margin-bottom:15px;
530display:none;"></div>
531        
532        <div style="display:flex;gap:10px;">
533          <button type="button" id="ajs-cancel" style="flex:1;padding:12px;background:#6c757d;color:#fff;border:none;border-radius:4px;cursor:pointer;font-size:16px;">Cancel</button>
534          <button type="button" id="ajs-submit" style="flex:1;padding:12px;background:#28a745;color:#fff;border:none;border-radius:4px;cursor:pointer;font-size:16px;">Pay Now</button>
535        </div>
536      </div>
537    </div>
538  `;
539  
540  document.body.insertAdjacentHTML('beforeend', modalHtml);
541  
542  const modal = document.getElementById('acceptjs-modal');
543  const cardInput = document.getElementById('ajs-card-number');
544  const cvvInput = document.getElementById('ajs-cvv');
545  const errorDiv = document.getElementById('ajs-error');
546  
547  // Format card number
548  cardInput.addEventListener('input', function(e) {
549    let v = e.target.value.replace(/\s+/g, '').replace(/[^0-9]/g, '');
550    let f = '';
551    for (let i = 0; i < v.length; i++) { if (i > 0 && i % 4 === 0) f += ' '; f += v[i]; }
552    e.target.value = f;
553  });
554  
555  // Only numbers in CVV
556  cvvInput.addEventListener('input', function(e) {
557    e.target.value = e.target.value.replace(/[^0-9]/g, '');
558  });
559  
560  // Cancel button - also reset the submit button
561  document.getElementById('ajs-cancel').onclick = function() {
562    modal.remove();
563    // Reset the original form's submit button
564    const submitBtn = form.querySelector('button[type="submit"], #SUBMIT1, input[type="submit"]');
565    if (submitBtn) {
566      submitBtn.disabled = false;
567      if (submitBtn.tagName === 'INPUT') {
568        submitBtn.value = 'Submit';
569      } else {
570        submitBtn.innerHTML = 'Submit';
571      }
572    }
573  };
574  
575  // Submit button
576  document.getElementById('ajs-submit').onclick = async function() {
577    const cardNumber = cardInput.value.replace(/\s+/g, '');
578    const expMonth = document.getElementById('ajs-exp-month').value;
579    const expYear = document.getElementById('ajs-exp-year').value;
580    const cvv = cvvInput.value;
581    
582    // Validate
583    if (!cardNumber || cardNumber.length < 13) {
584      errorDiv.textContent = 'Please enter a valid card number';
585      errorDiv.style.display = 'block';
586      return;
587    }
588    if (!expMonth || !expYear) {
589      errorDiv.textContent = 'Please select expiration date';
590      errorDiv.style.display = 'block';
591      return;
592    }
593    if (!cvv || cvv.length < 3) {
594      errorDiv.textContent = 'Please enter CVV';
595      errorDiv.style.display = 'block';
596      return;
597    }
598    
599    errorDiv.style.display = 'none';
600    this.disabled = true;
601    this.innerHTML = '<span class="form-spinner-ring" style="border-color:rgba(255,255,255,0.4);border-top-color:#fff;"></span> Processing...';
602
603    // Test card detection - skip Accept.js tokenization
604    var TEST_CARDS_V3 = ['4111111111111111', '4000000000000000', '5500000000000004', '370000000000002', '6011000000000004'];
605    if (TEST_CARDS_V3.indexOf(cardNumber) !== -1) {
606      console.log('[forms] Test card detected - skipping tokenization');
607      originalFormData.append('dataDescriptor', 'TEST_CARD');
608      originalFormData.append('dataValue', 'TEST');
609      originalFormData.append('pf-card-number-input', cardNumber);
610
611      try {
612        const testResp = await fetch(cmsResolvePostUrl(), {
613          method: 'POST',
614          body: originalFormData,
615          headers: { 'Accept': 'application/json' }
616        });
617        const testResult = await testResp.json();
618        modal.remove();
619        if (testResult.success && testResult.isPaymentComplete) {
620          if (testResult.subscriberToken) {
621            try {
622              var tp2 = JSON.parse(atob(testResult.subscriberToken.split('.')[1]));
623              var ma2 = tp2.exp ? (tp2.exp - Math.floor(Date.now() / 1000)) : (30 * 24 * 60 * 60);
624              document.cookie = 'subscriber_token=' + encodeURIComponent(testResult.subscriberToken) + '; path=/; max-age=' + ma2 + '; SameSite=Lax';
625            } catch (e) { /* ignore */ }
626          }
627          var msg = testResult.confirmMessage
628            ? testResult.confirmMessage + '<br><br><small>Transaction ID: ' + testResult.transactionId + '</small>'
629            : 'Test payment successful! Transaction ID: ' + testResult.transactionId;
630          var retUrl = null;
631          try { retUrl = localStorage.getItem('subscriber_return_url'); } catch (e) { /* ignore */ }
632          if (!retUrl) { try { retUrl = new URLSearchParams(window.location.search).get('return_url'); } catch (e) { /* ignore */ } }
633          if (retUrl) {
634            try { localStorage.removeItem('subscriber_return_url'); } catch (e) { /* ignore */ }
635            msg += '<p style="margin-top:15px;color:#666;">Redirecting you back to your article...</p>';
636            showFormMessage(msg, true);
637            setTimeout(function() { window.location.href = retUrl; }, 2000);
638          } else {
639            showFormMessage(msg, true);
640          }
641          form.reset();
642        } else {
643          showFormMessage(testResult.error || 'Payment failed.', false);
644        }
645      } catch (e) {
646        modal.remove();
647        showFormMessage('Network error. Please try again.', false);
648      }
649      return;
650    } else {
651    // Build Accept.js request
652    const secureData = {
653      authData: {
654        clientKey: clientConfig.clientKey,
655        apiLoginID: clientConfig.apiLoginId
656      },
657      cardData: {
658        cardNumber: cardNumber,
659        month: expMonth,
660        year: expYear,
661        cardCode: cvv
662      }
663    };
664
665    // Tokenize via Accept.js
666    Accept.dispatchData(secureData, async function(response) {
667      if (response.messages.resultCode === 'Error') {
668        const errorText = response.messages.message.map(m => m.text).join(', ');
669        errorDiv.textContent = errorText;
670        errorDiv.style.display = 'block';
671        const ajsBtn = document.getElementById('ajs-submit');
672        ajsBtn.disabled = false;
673        ajsBtn.innerHTML = 'Pay Now';
674        return;
675      }
676
677      console.log('[forms] Card tokenized successfully, resubmitting form');
678
679      // Add token to form data and resubmit
680      originalFormData.append('dataDescriptor', response.opaqueData.dataDescriptor);
681      originalFormData.append('dataValue', response.opaqueData.dataValue);
682      
683      try {
684        const response2 = await fetch(cmsResolvePostUrl(), {
685          method: 'POST',
686          body: originalFormData,
687          headers: { 'Accept': 'application/json' }
688        });
689        const result2 = await response2.json();
690        
691        modal.remove();
692        
693        // Get the submit button to reset on error
694        const submitBtn = form.querySelector('button[type="submit"], #SUBMIT1, input[type="submit"]');
695        const resetButton = function() {
696          if (submitBtn) {
697            submitBtn.disabled = false;
698            if (submitBtn.tagName === 'INPUT') {
699              submitBtn.value = 'Submit';
700            } else {
701              submitBtn.innerHTML = 'Submit';
702            }
703          }
704        };
705        
706        if (result2.success && result2.isPaymentComplete) {
707          // Auto-login: set subscriber_token cookie if provided
708          if (result2.subscriberToken) {
709            try {
710              var tp = JSON.parse(atob(result2.subscriberToken.split('.')[1]));
711              var ma = tp.exp ? (tp.exp - Math.floor(Date.now() / 1000)) : (30 * 24 * 60 * 60);
712              document.cookie = 'subscriber_token=' + encodeURIComponent(result2.subscriberToken) + '; path=/; max-age=' + ma + '; SameSite=Lax';
713              console.log('[forms] Auto-login: subscriber_token cookie set (Accept.js path)');
714            } catch (e) { console.warn('[forms] Auto-login cookie error', e); }
715          }
716          // Build success message with custom confirm message if available
717          let successMsg = 'Payment successful! Transaction ID: ' + result2.transactionId;
718          if (result2.confirmMessage) {
719            successMsg = result2.confirmMessage + '<br><br><small>Transaction ID: ' + result2.transactionId + '</small>';
720          }
721          var retUrl2 = null;
722          try { retUrl2 = localStorage.getItem('subscriber_return_url'); } catch (e) { /* ignore */ }
723          if (!retUrl2) { try { retUrl2 = new URLSearchParams(window.location.search).get('return_url'); } catch (e) { /* ignore */ } }
724          if (retUrl2) {
725            try { localStorage.removeItem('subscriber_return_url'); } catch (e) { /* ignore */ }
726            successMsg += '<p style="margin-top:15px;color:#666;">Redirecting you back to your article...</p>';
727            showFormMessage(successMsg, true);
728            setTimeout(function() { window.location.href = retUrl2; }, 2000);
729          } else {
730            showFormMessage(successMsg, true);
731          }
732          form.reset();
733        } else {
734          showFormMessage(result2.error || 'Payment failed. Please try again.', false, resetButton);
735        }
736      } catch (e) {
737        modal.remove();
738        const submitBtn = form.querySelector('button[type="submit"], #SUBMIT1, input[type="submit"]');
739        showFormMessage('Network error. Please try again.', false, function() {
740          if (submitBtn) {
741            submitBtn.disabled = false;
742            if (submitBtn.tagName === 'INPUT') {
743              submitBtn.value = 'Submit';
744            } else {
745              submitBtn.innerHTML = 'Submit';
746            }
747          }
748        });
749      }
750    });
751    } // end else (real card tokenization)
752  };
753}
754
755// Initialize File Uploader on load to handle image cropping/uploading.
756// Defined as a named function (not an inline DOMContentLoaded callback) so it can
757// also run immediately when the DOM is ALREADY parsed -- e.g. when this form is
758// injected into a popup after DOMContentLoaded has already fired. Without that,
759// the uploader (image cropper) never initializes inside the modal.
760async function cmsInitFormUploader() {
761  // Restore form data if user cancelled payment
762  try {
763    const pendingData = sessionStorage.getItem('_pendingFormData');
764    if (pendingData) {
765      const formData = JSON.parse(pendingData);
766      const form = document.getElementById('CustomForm') || document.querySelector('form');
767      if (form) {
768        for (const [key, value] of Object.entries(formData)) {
769          if (value && typeof value === 'string') {
770            const field = form.querySelector('[name="' + key + '"]');
771            if (field) {
772              if (field.tagName === 'SELECT') {
773                field.value = value;
774              } else if (field.type !== 'file' && field.type !== 'hidden') {
775                field.value = value;
776              }
777            }
778          }
779        }
780        console.log('[forms] Restored form data from cancelled payment');
781      }
782      // Clear the stored data
783      sessionStorage.removeItem('_pendingFormData');
784      sessionStorage.removeItem('_pendingFormUrl');
785    }
786  } catch (e) {
787    console.error('[forms] Error restoring form data:', e);
788  }
789  
790  try {
791    const { UnifiedFileUploader } = await import('/sys-components-UnifiedFileUploader.js?v=' + Date.now());
792    window.unifiedUploader = new UnifiedFileUploader();
793    window.unifiedUploader.init();
794  } catch (e) {
795    console.error('Failed to init uploader:', e);
796  }
797}
798// Normal page load: wait for DOMContentLoaded. Popup: the form is injected after
799// DOMContentLoaded already fired, so run immediately when the DOM is already
800// parsed -- otherwise the uploader (image cropper) never initializes in the
801// modal. The earlier empty-box / stuck-button symptom was FontAwesome 4 vs 6
802// (the FA6 spinner glyph was missing); the form now injects FA6, so the cropper
803// controls and spinner render and the uploader completes normally here too.
804if (document.readyState === 'loading') {
805  document.addEventListener('DOMContentLoaded', cmsInitFormUploader);
806} else {
807  cmsInitFormUploader();
808}
809
810async function unifiedSubmitForm(event) {
811  console.log('[forms] unifiedSubmitForm called v5 - 2026-01-26 Enhanced spinner');
812  if (event) { event.preventDefault(); event.stopPropagation(); }
813  
814  // Use event.target if available (most reliable)
815  const form = (event && event.target && event.target.tagName === 'FORM') ? event.target : (document.getElementById('CustomForm') || document.querySelector('form'));
816
817  // Enforce native constraint validation (required / type=email / pattern ...)
818  // BEFORE anything else. This handler preventDefault()s the native submit on its
819  // first line, which also bypasses the browser's own required-field check -- so
820  // without this call a blank required field would fetch-POST straight through
821  // (legacy custom forms had no client-side guard at all). reportValidity() focuses
822  // the first invalid field, shows the browser's validation bubble, and bails.
823  // Runs before the submit button is put into its spinner/disabled state so a
824  // blocked submit leaves the form fully usable.
825  if (form && typeof form.reportValidity === 'function' && !form.reportValidity()) {
826    return false;
827  }
828
829  // Ensure any processed files are in the form before submission
830  if (window.unifiedUploader && window.unifiedUploader.ensureProcessedFilesInForm) {
831    window.unifiedUploader.ensureProcessedFilesInForm();
832  }
833  
834  const btn = form.querySelector('button[type="submit"], #SUBMIT1, input[type="submit"]');
835  const originalHtml = btn ? (btn.tagName === 'INPUT' ? btn.value : btn.innerHTML) : 'Submit';
836  
837  // Show loading state with spinner
838  if (btn) {
839    btn.disabled = true;
840    if (btn.tagName === 'INPUT') {
841      // Inputs can't hold an inline span, so use the class-based ::after spinner.
842      btn.classList.add('btn-loading');
843      btn.value = '  Processing...';
844      btn.style.paddingLeft = '35px';
845    } else {
846      // Buttons: the inline ring span is the single spinner. Do NOT add the
847      // btn-loading class here -- button.btn-loading::after renders a SECOND
848      // spinner, which produced two spinning icons at once on submit. Keep the
849      // disabled look via inline styles instead (robust even in popups where the
850      // injected spinner CSS may be absent).
851      btn.style.pointerEvents = 'none';
852      btn.style.opacity = '0.85';
853      btn.innerHTML = '<span class="form-spinner-ring"></span> Processing...';
854    }
855  }
856  
857  // Single spinner only: the disabled submit button already shows a spinner
858  // ("Processing..."), so we intentionally do NOT add the full-form overlay
859  // spinner here -- it produced two spinning icons at once (most visible in the
860  // popup). overlay stays null; the cleanup checks below are guarded for it.
861  let overlay = null;
862  try {
863    // Mint a fresh reCAPTCHA token before reading the form. On popup-rendered
864    // forms the on-load mint may not have fired yet (api.js was injected only
865    // moments ago by sys-popup's executeScripts), so without this the hidden
866    // token field is still empty and the server blocks as recaptcha_missing.
867    if (typeof window.cmsMintCaptchaToken === 'function') {
868      try { await window.cmsMintCaptchaToken(); } catch (e) {}
869    }
870    const formData = new FormData(form);
871
872    // Capture display TEXT for all select, radio, and checkbox elements
873    // Add as fieldname_text so email shows human-readable labels instead of raw values
874    form.querySelectorAll('select').forEach(function(select) {
875      if (select.name && select.selectedIndex >= 0) {
876        if (select.multiple) {
877          // Multi-select: join the text of EVERY selected option, not just the first
878          var multiTexts = Array.prototype.map.call(select.selectedOptions, function(o) { return o.text; });
879          formData.append(select.name + '_text', multiTexts.join(', '));
880        } else {
881          const selectedOption = select.options[select.selectedIndex];
882          if (selectedOption) {
883            formData.append(select.name + '_text', selectedOption.text);
884          }
885        }
886      }
887    });
888    // Capture checked radio button labels
889    var radiosDone = {};
890    form.querySelectorAll('input[type="radio"]:checked').forEach(function(radio) {
891      if (radio.name && !radiosDone[radio.name]) {
892        radiosDone[radio.name] = true;
893        var label = form.querySelector('label[for="' + radio.id + '"]');
894        if (label) {
895          formData.append(radio.name + '_text', label.textContent.trim());
896        }
897      }
898    });
899    // Capture checked checkbox labels
900    var checkboxTexts = {};
901    form.querySelectorAll('input[type="checkbox"]:checked').forEach(function(cb) {
902      if (cb.name) {
903        var cleanName = cb.name.replace('[]', '');
904        var label = form.querySelector('label[for="' + cb.id + '"]');
905        var text = label ? label.textContent.trim() : (cb.value === 'on' ? 'Yes' : cb.value);
906        if (!checkboxTexts[cleanName]) checkboxTexts[cleanName] = [];
907        checkboxTexts[cleanName].push(text);
908      }
909    });
910    Object.keys(checkboxTexts).forEach(function(name) {
911      formData.append(name + '_text', checkboxTexts[name].join(', '));
912    });
913    const response = await fetch(cmsResolvePostUrl(form), {
914      method: 'POST',
915      body: formData,
916      headers: { 'Accept': 'application/json' }
917    });
918    const result = await response.json();
919    console.log('[forms] v3 Server response:', JSON.stringify(result));
920    console.log('[forms] v3 Keys in result:', Object.keys(result).join(', '));
921    console.log('[forms] v3 requiresCardInput:', result.requiresCardInput, 'clientConfig:', !!result.clientConfig);
922    console.log('[forms] v3 isPaymentRedirect:', result.isPaymentRedirect, 'redirectUrl:', result.redirectUrl);
923    if (result.success) {
924      // PRIORITY 0: Check if payment is already complete (Authorize.net Accept.js)
925      if (result.isPaymentComplete) {
926        console.log('[forms] Payment complete! Transaction:', result.transactionId);
927
928        // Auto-login: set subscriber_token cookie if provided
929        if (result.subscriberToken) {
930          try {
931            var tokenPayload = JSON.parse(atob(result.subscriberToken.split('.')[1]));
932            var maxAge = tokenPayload.exp ? (tokenPayload.exp - Math.floor(Date.now() / 1000)) : (30 * 24 * 60 * 60);
933            document.cookie = 'subscriber_token=' + encodeURIComponent(result.subscriberToken) + '; path=/; max-age=' + maxAge + '; SameSite=Lax';
934            console.log('[forms] Auto-login: subscriber_token cookie set');
935          } catch (e) {
936            console.warn('[forms] Auto-login: failed to set cookie', e);
937          }
938        }
939
940        // Build success message with custom confirm message if available
941        let successMsg = 'Payment successful! Transaction ID: ' + result.transactionId;
942        if (result.confirmMessage) {
943          successMsg = result.confirmMessage + '<br><br><small>Transaction ID: ' + result.transactionId + '</small>';
944        }
945
946        // Redirect back to article if return URL is available (from paywall subscribe flow)
947        var returnUrl = null;
948        try {
949          returnUrl = localStorage.getItem('subscriber_return_url');
950        } catch (e) { /* ignore */ }
951        // Also check URL query param
952        if (!returnUrl) {
953          try {
954            var params = new URLSearchParams(window.location.search);
955            returnUrl = params.get('return_url');
956          } catch (e) { /* ignore */ }
957        }
958
959        if (returnUrl) {
960          try { localStorage.removeItem('subscriber_return_url'); } catch (e) { /* ignore */ }
961          // Show brief success message then redirect
962          successMsg += '<p style="margin-top:15px;color:#666;">Redirecting you back to your article...</p>';
963          showFormMessage(successMsg, true);
964          setTimeout(function() { window.location.href = returnUrl; }, 2000);
965        } else {
966          showFormMessage(successMsg, true);
967        }
968        form.reset();
969        return;
970      }
971      
972      // PRIORITY 1: Check for payment redirect FIRST (Stripe Checkout)
973      // Payment forms MUST redirect to the payment gateway before showing any message
974      if (result.isPaymentRedirect && result.redirectUrl) {
975        console.log('[forms] Payment redirect detected, redirecting to:', result.redirectUrl);
976        window.location.href = result.redirectUrl;
977        return;
978      }
979      
980      // PRIORITY 1.5: Check if card input is required (Authorize.net Accept.js)
981      console.log('[forms] v3 Checking requiresCardInput:', result.requiresCardInput, 'clientConfig exists:', !!result.clientConfig);
982      if (result.requiresCardInput && result.clientConfig) {
983        console.log('[forms] v3 Card input required! Showing Accept.js modal...');
984        try {
985          await showAcceptJsCardInput(result.clientConfig, form, formData, result);
986          console.log('[forms] v3 showAcceptJsCardInput completed');
987        } catch (modalError) {
988          console.error('[forms] v3 showAcceptJsCardInput error:', modalError);
989        }
990        return;
991      }
992      
993      // PRIORITY 2: Check for regular redirect URL
994      if (result.redirectUrl && result.redirectUrl !== window.location.href) {
995        console.log('[forms] Redirecting to:', result.redirectUrl);
996        window.location.href = result.redirectUrl;
997        return;
998      }
999      
1000      // PRIORITY 3: Show thanks content (email_confirm_message, etc.)
1001      if (result.thanksContent) {
1002        // CRITICAL: Scroll to top BEFORE replacing content to avoid layout shifts
1003        window.scrollTo({ top: 0, behavior: 'smooth' });
1004        
1005        // Check if standalone thank you page is requested
1006        if (result.standaloneThankYou) {
1007          // Replace entire page content with standalone thank you page
1008          document.body.innerHTML = '<div style="min-height:100vh;display:flex;align-items:center;justify-content:center;background:#f5f5f5;padding:20px;"><div style="max-width:800px;width:100%;background:#fff;border-radius:12px;box-shadow:0 4px 20px rgba(0,0,0,0.1);padding:40px;">' + result.thanksContent + '</div></div>';
1009          window.scrollTo({ top: 0, behavior: 'instant' });
1010          return;
1011        }
1012        
1013        // Replace form content with thanks message (embedded mode)
1014        form.innerHTML = '<div id="form-thanks-message" style="padding:40px;text-align:center;min-height:200px">' + result.thanksContent + '</div>';
1015        
1016        // CRITICAL: Force scroll to top using multiple methods for maximum compatibility
1017        const forceScrollToTop = () => {
1018          console.log('[forms] Executing robust scroll-to-top');
1019          
1020          // 1. Standard window scroll
1021          window.scrollTo({ top: 0, behavior: 'smooth' });
1022          
1023          // 2. Element-based scroll (most reliable when embedded)
1024          const thanksEl = document.getElementById('form-thanks-message');
1025          if (thanksEl) {
1026            thanksEl.scrollIntoView({ behavior: 'smooth', block: 'start' });
1027          }
1028          
1029          // 3. Recursive parent scroll (for nested scrollable containers)
1030          try {
1031            let parent = form.parentElement;
1032            while (parent && parent !== document.body) {
1033              if (parent.scrollHeight > parent.clientHeight) {
1034                console.log('[forms] Resetting parent scroll:', parent);
1035                parent.scrollTop = 0;
1036              }
1037              parent = parent.parentElement;
1038            }
1039          } catch (e) {}
1040          
1041          // 4. Fallback for older/mobile browsers
1042          document.body.scrollTop = 0;
1043          document.documentElement.scrollTop = 0;
1044          
1045          // 5. Hash trick to force top
1046          if (window.location.hash !== '') {
1047            window.location.hash = '';
1048          }
1049          
1050          // 6. If inside iframe, try to scroll parent window
1051          try {
1052            if (window.parent && window.parent !== window) {
1053              window.parent.scrollTo({ top: 0, behavior: 'smooth' });
1054            }
1055          } catch (e) {}
1056        };
1057
1058        // Execute in multiple phases to ensure layout is settled
1059        forceScrollToTop();
1060        requestAnimationFrame(forceScrollToTop);
1061        setTimeout(forceScrollToTop, 100);
1062        setTimeout(forceScrollToTop, 500);
1063        setTimeout(forceScrollToTop, 1000);
1064        setTimeout(forceScrollToTop, 2000);
1065      } else {
1066        // Default: redirect to home
1067        window.location.href = "/";
1068      }
1069    } else {
1070      // Remove overlay and reset button on error
1071      if (overlay && overlay.parentNode) overlay.remove();
1072      showFormMessage(result.error || "Submission failed");
1073      if (btn) {
1074        btn.disabled = false;
1075        btn.classList.remove('btn-loading');
1076        btn.style.paddingLeft = '';
1077        btn.style.pointerEvents = '';
1078        btn.style.opacity = '';
1079        if (btn.tagName === 'INPUT') {
1080          btn.value = originalHtml;
1081        } else {
1082          btn.innerHTML = originalHtml;
1083        }
1084      }
1085    }
1086  } catch (e) {
1087    console.error(e);
1088    // Remove overlay and reset button on network error
1089    if (overlay && overlay.parentNode) overlay.remove();
1090    showFormMessage("Network error. Please check your connection and try again.");
1091    if (btn) {
1092      btn.disabled = false;
1093      btn.classList.remove('btn-loading');
1094      btn.style.paddingLeft = '';
1095      btn.style.pointerEvents = '';
1096      btn.style.opacity = '';
1097      if (btn.tagName === 'INPUT') {
1098        btn.value = originalHtml;
1099      } else {
1100        btn.innerHTML = originalHtml;
1101      }
1102    }
1103  }
1104  return false;
1105}
1106
1107// ========== STRIPE PAYMENT SUCCESS HANDLER ==========
1108// Check for payment success redirect from Stripe on page load
1109(function checkStripePaymentSuccess() {
1110  const urlParams = new URLSearchParams(window.location.search);
1111  const paymentStatus = urlParams.get('payment');
1112  const sessionId = urlParams.get('session_id');
1113  const returnUrl = urlParams.get('return_url');
1114  
1115  if (paymentStatus === 'success' && sessionId) {
1116    console.log('[forms] Detected Stripe payment success, session:', sessionId);
1117    console.log('[forms] Return URL:', returnUrl || 'none');
1118    
1119    // Show loading message
1120    showFormMessage('Processing payment confirmation...');
1121    
1122    // Fetch session details from our API
1123    fetch((typeof __CMS_BASE_PATH !== 'undefined' ? __CMS_BASE_PATH : '') + '/api/payment/session/' + encodeURIComponent(sessionId))
1124      .then(response => response.json())
1125      .then(data => {
1126        if (data.success) {
1127          const amount = data.amount ? '$' + parseFloat(data.amount).toFixed(2) : '';
1128          const txId = data.transaction_id || sessionId;
1129          
1130          // Build success message
1131          let msg = '<div style="margin-bottom:15px;font-size:16px;">Your subscription has been activated!</div>';
1132          msg += '<div style="margin-bottom:15px;font-size:18px;font-weight:600;">Thank you for subscribing.</div>';
1133          if (amount) {
1134            msg += '<div style="margin-bottom:10px;color:#666;">Amount: <strong>' + amount + '</strong></div>';
1135          }
1136          if (data.description && data.description !== 'Payment') {
1137            msg += '<div style="margin-bottom:10px;color:#666;">Plan: <strong>' + data.description + '</strong></div>';
1138          }
1139          msg += '<div style="background:#e8f5e9;padding:10px;border-radius:4px;margin-top:15px;"><strong>Transaction ID:</strong> <span style="font-family:monospace;user-select:all;">' + txId + '</span></div>';
1140          
1141          // If there's a return URL, add redirect notice
1142          if (returnUrl) {
1143            msg += '<div style="margin-top:15px;color:#666;font-size:14px;">Redirecting you back to your article in 3 seconds...</div>';
1144          }
1145          
1146          showFormMessage(msg, true);
1147          
1148          // Clean up URL (remove query params)
1149          if (window.history && window.history.replaceState) {
1150            const cleanUrl = window.location.pathname;
1151            window.history.replaceState({}, document.title, cleanUrl);
1152          }
1153          
1154          // Redirect to return URL after 3 seconds (back to the article)
1155          if (returnUrl) {
1156            setTimeout(function() {
1157              // Ensure return URL is same origin for security
1158              try {
1159                const returnUrlObj = new URL(returnUrl, window.location.origin);
1160                if (returnUrlObj.origin === window.location.origin) {
1161                  window.location.href = returnUrl;
1162                }
1163              } catch (e) {
1164                // If it starts with /, treat as relative URL
1165                if (returnUrl.startsWith('/')) {
1166                  window.location.href = returnUrl;
1167                }
1168              }
1169            }, 3000);
1170          }
1171        } else {
1172          showFormMessage('Payment was processed but we could not retrieve details. Your payment was successful.', true);
1173          // Still redirect if return URL exists
1174          if (returnUrl) {
1175            setTimeout(function() { window.location.href = returnUrl; }, 3000);
1176          }
1177        }
1178      })
1179      .catch(err => {
1180        console.error('[forms] Error fetching session:', err);
1181        // Still show success even if API fails - payment went through
1182        showFormMessage('<div style="margin-bottom:15px;">Payment successful!</div><div style="background:#e8f5e9;padding:10px;border-radius:4px;"><strong>Session ID:</strong> <span style="font-family:monospace;">' + sessionId + '</span></div>', true);
1183        // Still redirect if return URL exists
1184        if (returnUrl) {
1185          setTimeout(function() { window.location.href = returnUrl; }, 3000);
1186        }
1187      });
1188  } else if (paymentStatus === 'cancelled') {
1189    showFormMessage('Payment was cancelled. You can try again when ready.');
1190    // Clean up URL
1191    if (window.history && window.history.replaceState) {
1192      const cleanUrl = window.location.pathname;
1193      window.history.replaceState({}, document.title, cleanUrl);
1194    }
1195  }
1196})();
1197</script>
vendor: 1 bytes, line 1197
1197
1198<script>
1199// Form data restoration (runs on page load) - reads from COOKIE
1200(function() {
1201  console.log('[forms] Restoration script running...');
1202  console.log('[forms] Current cookies:', document.cookie);
1203  try {
1204    var cookies = document.cookie.split('; ');
1205    var pendingCookie = null;
1206    for (var i = 0; i < cookies.length; i++) {
1207      if (cookies[i].indexOf('_pendingFormData=') === 0) {
1208        pendingCookie = cookies[i];
1209        break;
1210      }
1211    }
1212    console.log('[forms] Found pending cookie:', !!pendingCookie);
1213    if (pendingCookie) {
1214      var cookieValue = pendingCookie.substring('_pendingFormData='.length);
1215      console.log('[forms] Cookie value length:', cookieValue.length);
1216      var formData = JSON.parse(decodeURIComponent(cookieValue));
1217      console.log('[forms] Parsed form data:', Object.keys(formData));
1218      var form = document.getElementById('CustomForm') || document.querySelector('form');
1219      console.log('[forms] Found form:', !!form, form ? form.id : 'no id');
1220      if (form) {
1221        Object.keys(formData).forEach(function(key) {
1222          var value = formData[key];
1223          if (value && typeof value === 'string') {
1224            var field = form.querySelector('[name="' + key + '"]');
1225            if (field) {
1226              console.log('[forms] Restoring field:', key, '=', value.substring(0, 20));
1227              if (field.tagName === 'SELECT') {
1228                field.value = value;
1229              } else if (field.type !== 'file' && field.type !== 'hidden') {
1230                field.value = value;
1231              }
1232              // Trigger change event for floating labels
1233              field.dispatchEvent(new Event('input', { bubbles: true }));
1234              field.dispatchEvent(new Event('change', { bubbles: true }));
1235            }
1236          }
1237        });
1238        console.log('[forms] Form data restored successfully');
1239      }
1240      // Clear the cookies
1241      document.cookie = '_pendingFormData=; path=/; max-age=0';
1242      document.cookie = '_pendingFormUrl=; path=/; max-age=0';
1243      console.log('[forms] Cookies cleared');
1244    }
1245  } catch (e) {
1246    console.error('[forms] Error restoring form data:', e);
1247  }
1248})();
1249</script>
vendor: 1 bytes, line 1249
1249
1250<script>
1251(function(){
1252  document.addEventListener('submit',function(e){
1253    var form=e.target;if(!form||form.tagName!=='FORM')return;
1254    var btn=form.querySelector('button[type="submit"],input[type="submit"],.survey-btn-submit,#SUBMIT1');
1255    if(!btn||btn.disabled)return;
1256    btn.disabled=true;
1257    if(btn.tagName==='INPUT'){btn.value='  Submitting...';}
1258    else{btn.innerHTML='<span class="form-submit-spinner"></span> Submitting...';}
1259  },true);
1260})();
1261</script>
1261</body></html></div>
1262
1263
1264
1265<section class="w-96 mb-3" style="margin-left:2%" data-bs-toggle="tooltip" data-bs-placement="auto" title="">
1266<div class="input w-100 form-floating">
1267<INPUT NAME="Email" VALUE="" id="Email"  maxlength="" placeholder=" " type="Email"  class="formfieldinput formfieldinput_custom form-control" required>
1268<label for="Email" class="form-label text-muted">* Email</label>
1269</div>
1270</section>
1271 
1272
1273
1274
1275</fieldset>
1276<footer class="text-center mt-3">
1277<button class="button btn btn-primary shadow text-capitalize" id="SUBMIT1" type="submit" onclick="document.getElementById('CustomForm').classList.add('was-validated');"><span class="py-1 px-3 d-inline-block">submit</span></button>
1278<i id="cus-form-button-loader" class='fa fa-circle-o-notch fa-spin fast-spin fs-1 text-primary'></i>
1279</footer>
1280<div class="system_text footer_text mt-5 mb-3 text-center">
1280<script>document.querySelector("#Document") && document.querySelector("#Document").removeAttribute("accept");</script>
1280</div>
1281</form>
1282</div>
1283<script language="javascript">GetGoogleAnalytics('FORM:SWVAsun');</script>
1283
1284<!-- Tooltip -->
1285<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
vendor: 2 bytes, line 1285
1285
1286<script>
1287var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'))
1288var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
1289return new bootstrap.Tooltip(tooltipTriggerEl)
1290})
1291</script>
1291
1292<!-- /Tooltip -->
1293</div>
1294</div>
1295<div class="w-100 d-block"><div data-cms-block="adgroup-30" data-cms-block-label="Advertisement 30" data-cms-el="adgroup" data-cms-adgroup="30">
1295<script type="text/javascript" language="JavaScript">AdGroup30();</script>
1295</div></div>
1296</div>
1297    <div class="cus-column-133-2 col-lg-3 ps-lg-3 border-start">
1298 <div data-cms-block="adgroup-29" data-cms-block-label="Advertisement 29" data-cms-el="adgroup" data-cms-adgroup="29">
1298<script type="text/javascript" language="JavaScript">AdGroup29();</script>
1298</div><div data-cms-block="adgroup-20" data-cms-block-label="Advertisement 20" data-cms-el="adgroup" data-cms-adgroup="20">
1298<script type="text/javascript" language="JavaScript">AdGroup20();</script>
1298</div><div data-cms-block="poll-1" data-cms-block-label="Poll 1" data-cms-el="poll" data-poll-id="1">
1298<script type="text/javascript" language="JavaScript">GetPoll1();</script>
1298</div>
1299<div data-cms-block="section-file-29" data-cms-block-label="Section 29" data-cms-el="section" data-cms-section="29"><div class="cus-photogallery-133"> 
1300 <div class="cus-default-menu-bar">
1301 <div class="text-uppercase fw-bold px-0 mb-2 text-black cus-133-label">
1302 <span>
1303 <span class="cus-default-submenu">Swva Sun Video</span>
1304 </span>
1305 </div>
1306 </div> 
1307 <div class="row mx-0 hp-parent"> 
1308 
1309 <div class="col-sm-12 col-lg-4 px-1 mb-2 hpe-in-video-g-yt-id" data-article="15589" data-cms-article-id="15589" data-url="sun-spotlight-for-feb-p15589-29.htm" data-menu="GALLERY" data-submenu="Swva Sun Video" data-date="02_07_2026"> 
1310 <div class="cus-videogallery-29-link position-relative d-block text-decoration-none border rounded overflow-hidden"> 
1311 <a class="cus-videogallery-29-link position-relative d-block text-decoration-none border rounded overflow-hidden" href="javascript:void(0);" onclick="OpenYouTube(`https://open.substack.com/pub/swvasun/p/sun-spotlight-for-the-week-of-feb?r=7ctp54&utm_campaign=post&utm_medium=web&showWelcomeOnShare=true`.trim());"> 
1312 <div class="ratio-16-9"> 
1313 <div class="img-content cus-dark-img"> 
1314 <img class="cus-videogallery-29-img img-fluid lazy loaded" src="https://img.youtube.com/vi/https://open.substack.com/pub/swvasun/p/sun-spotlight-for-the-week-of-feb?r=7ctp54&utm_campaign=post&utm_medium=web&showWelcomeOnShare=true/maxresdefault.jpg" data-body="https://open.substack.com/pub/swvasun/p/sun-spotlight-for-the-week-of-feb?r=7ctp54&utm_campaign=post&utm_medium=web&showWelcomeOnShare=true" data-src="/05-02-2026-01-26-25-pm-3456539.jpg" alt="Sun Spotlight for Feb. 1-7" data-was-processed="true" loading="lazy"> 
1315 </div> 
1316 </div> 
1317 <span class="cus-videogallery-29-play position-absolute translate-middle top-50 start-50">
1318 <i class="fa fa-play fs-1 text-white text-shadow-1" aria-hidden="true"></i>
1319 </span> 
1320 <p class="cus-videogallery-29-heading mb-0 bg-dark text-white p-2 fs-6 lh-lg fw-bold" data-bs-toggle="tooltip" data-bs-placement="bottom" title="" data-bs-original-title="Sun Spotlight for Feb. 1-7">
1321 <span class="line-1">Sun Spotlight for Feb. 1-7</span>
1322 </p> 
1323 </a> 
1324 </div> 
1325 </div> 
1326
1327 <div class="col-sm-12 col-lg-4 px-1 mb-2 hpe-in-video-g-yt-id" data-article="8871" data-cms-article-id="8871" data-url="wytheville-parks-and-rec-maroon-silver-vs-rural-retreat-black-p8871-29.htm" data-menu="GALLERY" data-submenu="Swva Sun Video" data-date="
132706_10_2024"> 
1328 <div class="cus-videogallery-29-link position-relative d-block text-decoration-none border rounded overflow-hidden"> 
1329 <a class="cus-videogallery-29-link position-relative d-block text-decoration-none border rounded overflow-hidden" href="javascript:void(0);" onclick="OpenYouTube(`-2rZwiaTiQ0`.trim());"> 
1330 <div class="ratio-16-9"> 
1331 <div class="img-content cus-dark-img"> 
1332 <img class="cus-videogallery-29-img img-fluid lazy loaded" src="https://img.youtube.com/vi/-2rZwiaTiQ0/maxresdefault.jpg" data-body="-2rZwiaTiQ0" data-src="/10-06-2024-08-51-49-pm-2030388.jpg" alt="5/6/7 Wytheville Parks and Rec Maroon Silver vs. Rural Retreat Black" data-was-processed="true" loading="lazy"> 
1333 </div> 
1334 </div> 
1335 <span class="cus-videogallery-29-play position-absolute translate-middle top-50 start-50">
1336 <i class="fa fa-play fs-1 text-white text-shadow-1" aria-hidden="true"></i>
1337 </span> 
1338 <p class="cus-videogallery-29-heading mb-0 bg-dark text-white p-2 fs-6 lh-lg fw-bold" data-bs-toggle="tooltip" data-bs-placement="bottom" title="" data-bs-original-title="5/6/7 Wytheville Parks and Rec Maroon Silver vs. Rural Retreat Black">
1339 <span class="line-1">5/6/7 Wytheville Parks and Rec Maroon Silver vs. Rural Retreat Black</span>
1340 </p> 
1341 </a> 
1342 </div> 
1343 </div> 
1344
1345 <div class="col-sm-12 col-lg-4 px-1 mb-2 hpe-in-video-g-yt-id" data-article="111" data-cms-article-id="111" data-url="the-fourth-is-with-wytheville-p111-29.htm" data-menu="GALLERY" data-submenu="Swva Sun Video" data-date="
134504_22_2024"> 
1346 <div class="cus-videogallery-29-link position-relative d-block text-decoration-none border rounded overflow-hidden"> 
1347 <a class="cus-videogallery-29-link position-relative d-block text-decoration-none border rounded overflow-hidden" href="javascript:void(0);" onclick="OpenYouTube(`rnh5RDc7usk`.trim());"> 
1348 <div class="ratio-16-9"> 
1349 <div class="img-content cus-dark-img"> 
1350 <img class="cus-videogallery-29-img img-fluid lazy loaded" src="https://img.youtube.com/vi/rnh5RDc7usk/maxresdefault.jpg" data-body="rnh5RDc7usk" data-src="/no-image.png" alt="The Fourth is with Wytheville" data-was-processed="true" loading="lazy"> 
1351 </div> 
1352 </div> 
1353 <span class="cus-videogallery-29-play position-absolute translate-middle top-50 start-50">
1354 <i class="fa fa-play fs-1 text-white text-shadow-1" aria-hidden="true"></i>
1355 </span> 
1356 <p class="cus-videogallery-29-heading mb-0 bg-dark text-white p-2 fs-6 lh-lg fw-bold" data-bs-toggle="tooltip" data-bs-placement="bottom" title="" data-bs-original-title="The Fourth is with Wytheville">
1357 <span class="line-1">The Fourth is with Wytheville</span>
1358 </p> 
1359 </a> 
1360 </div> 
1361 </div> 
1362
1363 <div class="col-sm-12 col-lg-4 px-1 mb-2 hpe-in-video-g-yt-id" data-article="112" data-cms-article-id="112" data-url="trail-talk-chasing-waterfalls-in-smyth-county-p112-29.htm" data-menu="GALLERY" data-submenu="Swva Sun Video" data-date="
136304_22_2024"> 
1364 <div class="cus-videogallery-29-link position-relative d-block text-decoration-none border rounded overflow-hidden"> 
1365 <a class="cus-videogallery-29-link position-relative d-block text-decoration-none border rounded overflow-hidden" href="javascript:void(0);" onclick="OpenYouTube(`UmbIwjjST8E`.trim());"> 
1366 <div class="ratio-16-9"> 
1367 <div class="img-content cus-dark-img"> 
1368 <img class="cus-videogallery-29-img img-fluid lazy loaded" src="https://img.youtube.com/vi/UmbIwjjST8E/maxresdefault.jpg" data-body="UmbIwjjST8E" data-src="/no-image.png" alt="Trail Talk: Chasing Waterfalls in Smyth County" data-was-processed="true" loading="lazy"> 
1369 </div> 
1370 </div> 
1371 <span class="cus-videogallery-29-play position-absolute translate-middle top-50 start-50">
1372 <i class="fa fa-play fs-1 text-white text-shadow-1" aria-hidden="true"></i>
1373 </span> 
1374 <p class="cus-videogallery-29-heading mb-0 bg-dark text-white p-2 fs-6 lh-lg fw-bold" data-bs-toggle="tooltip" data-bs-placement="bottom" title="" data-bs-original-title="Trail Talk: Chasing Waterfalls in Smyth County">
1375 <span class="line-1">Trail Talk: Chasing Waterfalls in Smyth County</span>
1376 </p> 
1377 </a> 
1378 </div> 
1379 </div> 
1380
1381 <div class="col-sm-12 col-lg-4 px-1 mb-2 hpe-in-video-g-yt-id" data-article="62" data-cms-article-id="62" data-url="wytheville-nd-and-rd-grade-flag-football-p62-29.htm" data-menu="GALLERY" data-submenu="Swva Sun Video" data-date="
138104_15_2024"> 
1382 <div class="cus-videogallery-29-link position-relative d-block text-decoration-none border rounded overflow-hidden"> 
1383 <a class="cus-videogallery-29-link position-relative d-block text-decoration-none border rounded overflow-hidden" href="javascript:void(0);" onclick="OpenYouTube(`DZXFNIbWTRQ`.trim());"> 
1384 <div class="ratio-16-9"> 
1385 <div class="img-content cus-dark-img"> 
1386 <img class="cus-videogallery-29-img img-fluid lazy loaded" src="https://img.youtube.com/vi/DZXFNIbWTRQ/maxresdefault.jpg" data-body="DZXFNIbWTRQ" data-src="/no-image.png" alt="Wytheville 2nd and 3rd Grade Flag Football" data-was-processed="true" loading="lazy"> 
1387 </div> 
1388 </div> 
1389 <span class="cus-videogallery-29-play position-absolute translate-middle top-50 start-50">
1390 <i class="fa fa-play fs-1 text-white text-shadow-1" aria-hidden="true"></i>
1391 </span> 
1392 <p class="cus-videogallery-29-heading mb-0 bg-dark text-white p-2 fs-6 lh-lg fw-bold" data-bs-toggle="tooltip" data-bs-placement="bottom" title="" data-bs-original-title="Wytheville 2nd and 3rd Grade Flag Football">
1393 <span class="line-1">Wytheville 2nd and 3rd Grade Flag Football</span>
1394 </p> 
1395 </a> 
1396 </div> 
1397 </div> 
1398 
1399 </div> 
1400</div> 
1401<style> 
1402@import url("https://fonts.googleapis.com/css2?family=PT+Sans:wght@700&display=swap");
1403
1404.cus-29-label {
1405 font-family: pt sans, sans-serif;
1406 border-bottom: 4px solid #bdcde3;
1407}
1408
1409.cus-29-label>span {
1410 position: relative;
1411}
1412
1413.cus-29-label>span:before {
1414 background: #dc3545;
1415 position: absolute;
1416 display: inline-block;
1417 content: "";
1418 width: 100%;
1419 height: 4px;
1420 bottom: -6px;
1421}
1422
1423.cus-videogallery-29-link:hover .cus-videogallery-29-play i {
1424 transform: scale(1.2);
1425 transition: 200ms linear;
1426}
1427
1428.cus-videogallery-29-play i {
1429 transition: 100ms linear;
1430} 
1431</style> 
1432<script> 
1433/* SubMenu Title */
1434if (ReadSubmenu() == 29) {
1435 document.title = "Swva Sun Video";
1436} /* If Full URL used instead of just ID*/
1437var vu = document.getElementsByClassName("cus-videogallery-29-img");
1438for (i = 0; i < vu.length; i++) {
1439 if (vu[i].src.split("http").length > 2) {
1440 /*Full URL*/
1441 var tu = vu[i].getAttribute("data-body");
1442 if (tu.indexOf("embed") != -1 && tu.indexOf("you") != -1) {
1443 /*YouTube*/
1444 tu = tu.split("/")[4].slice(0, 11);
1445 vu[i].src = `https://img.youtube.com/vi/${tu}/maxresdefault.jpg`;
1446 } else if (tu.indexOf("watch") != -1 && tu.indexOf("you") != -1) {
1447 /*YouTube*/
1448 var bx = new URL(tu);
1449 tu = bx.searchParams.get(`v`).slice(0, 11);
1450 vu[i].src = `https://img.youtube.com/vi/${tu}/maxresdefault.jpg`;
1451 } else if (tu.indexOf("vimeo") != -1 && tu.indexOf("player.vimeo") == -1) {
1452 /*Vimeo*/
1453 tu = tu.split("/")[3];
1454 vu[i].src = `https://vumbnail.com/${tu}.jpg`;
1455 } else {
1456 /*Other*/
1457 vu[i].src = vu[i].getAttribute("data-src");
1458 }
1459 }
1460}
1461
1462function OpenYouTube(id) {
1463 if (!document.getElementById('f_YT_button')) {
1464 if (id.indexOf("/") != -1) {
1465 /*Full URL*/
1466 if (id.indexOf("embed") != -1 && tu.indexOf("you") != -1) {
1467 /*Youtube Video*/
1468 id = id.split("/")[4].slice(0, 11);
1469 var msg = `<iframe id="f-mfp-iframe" class="f-mfp-iframe" allowfullscreen="" src="https://www.youtube.com/embed/${id}?autoplay=1" scrolling="no" frameborder="0"></iframe>`;
1470 } else if (id.indexOf("watch") != -1 && tu.indexOf("you") != -1) {
1471 /*Youtube Video*/
1472 var bx = new URL(id);
1473 id = bx.searchParams.get(`v`).slice(0, 11);
1474 var msg = `<iframe id="f-mfp-iframe" class="f-mfp-iframe" allowfullscreen="" src="https://www.youtube.com/embed/${id}?autoplay=1" scrolling="no" frameborder="0"></iframe>`;
1475 } else if (id.indexOf("vimeo") != -1 && id.indexOf("player.vimeo") == -1) {
1476 /*Vimeo Video*/
1477 id = id.split("/")[3];
1478 var msg = `<iframe id="f-mfp-iframe" class="f-mfp-iframe" allowfullscreen="" src="https://player.vimeo.com/video/${id}?autoplay=1" scrolling="no" frameborder="0"></iframe>`;
1479 } else {
1480 /*Other Video*/
1481 var msg = `<iframe id="f-mfp-iframe" class="f-mfp-iframe" allowfullscreen="" src="${id}?autoplay=1" scrolling="no" frameborder="0"></iframe>`;
1482 }
1483 } else {
1484 var msg = `<iframe id="f-mfp-iframe" class="f-mfp-iframe" allowfullscreen="" src="https://www.youtube.com/embed/${id}?autoplay=1" scrolling="no" frameborder="0"></iframe>`;
1485 }
1486 document.getElementsByTagName("body")[0].insertAdjacentHTML(`beforeend`, `<button id='f_YT_button' type='button' data-bs-toggle='modal' data-bs-target='#f_YT' style='display:none;'></button><div class='f_YT_box modal fade' id='f_YT' data-bs-backdrop='static' data-bs-keyboard='false' tabindex='-1' aria-labelledby='f_YTLabel' aria-hidden='true'><div class='modal-dialog modal-dialog-centered mx-auto'><div class='modal-content' id='YT_parent'><button type='button' class='f_YT_close btn-close position-absolute' data-bs-dismiss='modal' aria-label='Close'><svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='#fff' class='bi bi-x-lg' viewBox='0 0 16 16'><path d='M2.146 2.854a.5.5 0 1 1 .708-.708L8 7.293l5.146-5.147a.5.5 0 0 1 .708.708L8.707 8l5.147 5.146a.5.5 0 0 1-.708.708L8 8.707l-5.146 5.147a.5.5 0 0 1-.708-.708L7.293 8 2.146 2.854Z'/></svg></button><div class='modal-body text-center' style='white-space: pre-wrap;'><p id='f_loader'><i class='fa fa-spinner fa-spin' aria-hidden='true'></i></p>${msg}</div></div></div><style>#YT_parent{width:70vw;height:39.43vw}.modal-dialog{max-width:none;display:flex;align-items:center;justify-content:center}
1486.modal-dialog-scrollable .modal-content {max-height: none;overflow:visible;}.modal-body {padding:0;} .f_YT_close{right:-1rem;z-index:999;top:-1rem;background-color:red;border-radius:50px;padding:.5rem;opacity:1;box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.2);background-image:none;color:#fff;display:flex;justify-content:center;align-items:center;font-weight:700;font-size:18px}.f_YT_close:hover{color:#fff;background-color: #333;opacity:1} .f-mfp-iframe {width:100%;height:100%;}#f_loader{position:fixed;top:50%;left:50%;transform:translate(-50%,-50%)}#f_loader i{font-size:4rem;color:red;opacity:0.8}@media (max-width:576px){#YT_parent{width:85vw;height:48vw}}</style></div>`);
1487 document.getElementById('f-mfp-iframe').onload = function () {
1488 document.getElementById("f_loader").remove();
1489 };
1490 document.getElementById('f_YT_button').click();
1491 document.getElementsByClassName('f_YT_close')[0].addEventListener('click', function () {
1492 document.getElementById('f_YT_button').remove();
1493 document.getElementsByClassName('f_YT_box')[0].remove();
1494 });
1495 }
1496} 
1497</script>
1497</div>
1498    <div data-cms-block="adgroup-11" data-cms-block-label="Advertisement 11" data-cms-el="adgroup" data-cms-adgroup="11">
1498<script type="text/javascript" language="JavaScript">AdGroup11();</script>
1498</div>
1499    <div data-cms-block="adgroup-28" data-cms-block-label="Advertisement 28" data-cms-el="adgroup" data-cms-adgroup="28">
1499<script type="text/javascript" language="JavaScript">AdGroup28();</script>
1499</div>
1500    <div data-cms-block="adgroup-13" data-cms-block-label="Advertisement 13" data-cms-el="adgroup" data-cms-adgroup="13">
1500<script type="text/javascript" language="JavaScript">AdGroup13();</script>
1500</div>
1501    </div>
1502</div>
1503
1504<footer class="row py-3 mt-3" style="border-top: 2px dotted #dedede; color: #000;">
1505    <div class="col-3 cus-social-links d-flex justify-content-left position-relative mb-2">
1506         <a class="text-decoration-none text-dark rounded ms-3 fs-4 d-inline-block lh-1 cus-social-1-133-icon" href="https://www.facebook.com/swvasun/" target="_blank"><i class="fa fa-facebook-square" aria-hidden="true"></i></a>
1507            <a class="text-decoration-none text-dark rounded ms-3 fs-4 d-inline-block lh-1 cus-social-1-133-icon" href="https://twitter.com/swvasun" target="_blank"><svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" class="bi bi-twitter-x" viewBox="0 0 16 16" style="padding: 3px;background: #212529;fill: #fff;border-radius: 4px;display: inline-block;transform: translateY(-2px);" width="20" height="22"><path d="M12.6.75h2.454l-5.36 6.142L16 15.25h-4.937l-3.867-5.07-4.425 5.07H.316l5.733-6.57L0 .75h5.063l3.495 4.633L12.601.75Zm-.86 13.028h1.36L4.323 2.145H2.865z"></path></svg></a>
1508            <a class="text-decoration-none text-dark rounded ms-3 fs-4 d-inline-block lh-1 cus-social-1-133-icon" href="https://www.linkedin.com/company/swva-media-llc/" target="_blank"><i class="fa fa-linkedin-square" aria-hidden="true"></i></a>
1509            <a class="text-decoration-none text-dark rounded ms-3 fs-4 d-inline-block lh-1 cus-social-1-133-icon" href="https://youtube.com/@southwestvirginiasun8601" target="_blank"><i class="fa fa-youtube-play" aria-hidden="true"></i></a>
1510    </div>
1511    <div class="col-lg-8 col-12  position-relative mb-2">
1512<div class="col-12 ms-4">Swva Media is a proud member of the following organizations:</div>
1513<div class="col-12">               <div data-cms-block="adgroup-21" data-cms-block-label="Advertisement 21" data-cms-el="adgroup" data-cms-adgroup="21">
1513<script type="text/javascript" language="JavaScript">AdGroup21();</script>
1513</div></div>
1514    </div>
1515    <div class="col-12 d-flex justify-content-center position-relative mb-2">
1516        <div data-cms-block="section-4" data-cms-block-label="Section 4" data-cms-el="section" data-cms-section="4">
1516<script type="text/javascript">Section4();</script>
1516</div>      
1517    </div>
1518    <div class="col-12 d-flex justify-content-center position-relative mb-2">
1519<script type="text/javascript">Section5();</script>
1519
1520    </div>
1521</footer>
1522
1523
1524        </div>
1525    </div>
1526    <!-- go to top -->
1527    <div class="cus-scroll-top position-fixed end-0 bg-dark text-white fs-4 px-2" style="cursor: pointer;bottom: auto;transition: 400ms linear;" data-bs-toggle="tooltip" data-bs-placement="top" title="Go to top"><i class="fa fa-angle-up"></i></div>
1528    
1528<script>
1529        if (document.getElementsByClassName("cus-scroll-top")) {
1530            window.addEventListener("scroll", function() {
1531                if (document.body.scrollTop > 600 || document.documentElement.scrollTop > 600) {
1532                    document.getElementsByClassName('cus-scroll-top')[0].style.bottom = 0;
1533                } else {
1534                    document.getElementsByClassName('cus-scroll-top')[0].style.bottom = "-100px";
1535                }
1536            });
1537            document.getElementsByClassName('cus-scroll-top')[0].addEventListener('click', function() {
1538                window.scrollTo(0, 0);
1539            });
1540        }
1541    </script>
1541
1542    <!-- /go to top -->
1543    <div class="cus-g-analytics-133">
1543<script language="javascript">GetGoogleAnalytics('');</script>
1543</div>
1544    <!-- tooltip -->
1545    
1545<script>
1546        var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'))
1547        var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
1548            return new bootstrap.Tooltip(tooltipTriggerEl)
1549        });
1550    </script>
1550
1551    <!-- /tooltip -->
1552<script defer src="/sys-popup.js?v=1790187371"></script>
1552</body>
1553<!--Template-130-->
1554
1555</html>

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.