1<!DOCTYPE html> 2<html lang="en" dir="ltr"> 3<head> 4 <meta charset="utf-8"> 5 <meta name="viewport" content="width=device-width, initial-scale=1"> 6 <meta name="csrf-token" content="bO1LIggE4bt7GXGlBzfIKeHZrPgJ24CDBMlezc4P"> 7 <title> 8 Products - HeadRandom 9 </title> 10 <meta name="description" content="Just another HeadRandom site"> 11 12 <!-- Google Fonts - Inter --> 13 <link rel="preconnect" href="https://fonts.googleapis.com"> 14 <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> 15 <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet"> 16 <link rel="stylesheet" href="https://headrandom.com/assets/vendor/font-awesome-6.4.0/css/all.min.css"> 17 18 <!-- App Config JS injection (Ecommerce) --> 19
19<script> 20 window.AppConfig = { 21 redirectCartAfterAdd: true 22 }; 23 </script>
23 24 25 <link rel="preload" as="style" href="https://headrandom.com/build/assets/app-D0RbOawZ.css" /><link rel="preload" as="style" href="https://headrandom.com/build/assets/landing-blocks-C2kjGC7q.css" /><link rel="preload" as="style" href="https://headrandom.com/build/assets/ecommerce-bridge-C7NPz8I-.css" /><link rel="modulepreload" as="script" href="https://headrandom.com/build/assets/ecommerce-bridge-DBFb2GHh.js" /><link rel="modulepreload" as="script" href="https://headrandom.com/build/assets/useCurrency-Cr94BVzg.js" /><link rel="modulepreload" as="script" href="https://headrandom.com/build/assets/cartStore-DudLg2VQ.js" /><link rel="modulepreload" as="script" href="https://headrandom.com/build/assets/runtime-dom.esm-bundler-DpfbrSka.js" /><link rel="modulepreload" as="script" href="https://headrandom.com/build/assets/_plugin-vue_export-helper-DlAUqK2U.js" /><link rel="stylesheet" href="https://headrandom.com/build/assets/app-D0RbOawZ.css" /><link rel="stylesheet" href="https://headrandom.com/build/assets/landing-blocks-C2kjGC7q.css" /><link rel="stylesheet" href="https://headrandom.com/build/assets/ecommerce-bridge-C7NPz8I-.css" />
25<script type="module" src="https://headrandom.com/build/assets/ecommerce-bridge-DBFb2GHh.js"></script>
vendor: 1 bytes, line 25
25
26<script> 27 window.addEventListener('load', () => window.setTimeout(() => { 28 const makeLink = (asset) => { 29 const link = document.createElement('link') 30 31 Object.keys(asset).forEach((attribute) => { 32 link.setAttribute(attribute, asset[attribute]) 33 }) 34 35 return link 36 } 37 38 const loadNext = (assets, count) => window.setTimeout(() => { 39 if (count > assets.length) { 40 count = assets.length 41 42 if (count === 0) { 43 return 44 } 45 } 46 47 const fragment = new DocumentFragment 48 49 while (count > 0) { 50 const link = makeLink(assets.shift()) 51 fragment.append(link) 52 count-- 53 54 if (assets.length) { 55 link.onload = () => loadNext(assets, 1) 56 link.onerror = () => loadNext(assets, 1) 57 } 58 } 59 60 document.head.append(fragment) 61 }) 62 63 loadNext([], 3) 64 })) 65</script>
65 66 <!-- Theme Styles --> 67 <link rel="stylesheet" href="https://headrandom.com/themes/flexiwhite/css/style.css?v=1790892926"> 68 69 <!-- Theme Mode Initialization (Prevents FOUC) --> 70
70<script> 71 (function() { 72 try { 73 const themeMode = localStorage.getItem('theme_mode'); 74 const colorTheme = localStorage.getItem('color-theme'); 75 const defaultMode = 'light'; 76 let isDark = false; 77 78 if (themeMode) { 79 if (themeMode === 'system') { 80 isDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches; 81 } else { 82 isDark = themeMode === 'dark'; 83 } 84 } else if (colorTheme) { 85 isDark = colorTheme === 'dark'; 86 } else { 87 isDark = defaultMode === 'dark'; 88 } 89 90 if (isDark) { 91 document.documentElement.classList.add('dark'); 92 } else { 93 document.documentElement.classList.remove('dark'); 94 } 95 } catch (e) {} 96 })(); 97 </script>
97 98 99 100 <!-- Language Direction CSS --> 101 <style> 102 html[dir="rtl"] { 103 direction: rtl; 104 } 105 html[dir="ltr"] { 106 direction: ltr; 107 } 108 109 :root { 110 --color-primary: #2563eb; 111 --color-secondary: #64748b; 112 --color-accent: #10b981; 113 --color-border: #d1d5db; 114 --theme-surface-color: #ffffff; 115 --theme-heading-font-family: Inter, sans-serif; 116 --theme-heading-font-weight: 700; 117 --theme-heading-line-height: 1.3; 118 --theme-heading-letter-spacing: 0em; 119 --theme-heading-color: #111827; 120 --theme-heading-h1-size: 36px; 121 --theme-heading-h2-size: 28px; 122 --theme-heading-h3-size: 22px; 123 --theme-heading-h4-size: 18px; 124 --theme-heading-h5-size: 16px; 125 --theme-heading-h6-size: 14px; 126 --theme-body-font-family: Inter, sans-serif; 127 --theme-body-font-size: 16px; 128 --theme-body-line-height: 1.3; 129 --theme-body-color: #1f2937; 130 --theme-body-muted-color: #6b7280; 131 --theme-body-background-color: #ffffff; 132 --theme-link-color: #2563eb; 133 --theme-link-hover-color: #1e40af; 134 --theme-container-max-width: 1366px; 135 --theme-reading-max-width: 768px; 136 --theme-button-radius: 12px; 137 --theme-card-radius: 12px; 138 --theme-card-shadow: var(--shadow-md); 139 --theme-card-shadow-hover: var(--shadow-xl); 140 } 141 html.dark, html.dark body, :root.dark { 142 --theme-link-color: #4299e1 !important; 143 --theme-link-hover-color: #63b3ed !important; 144 } 145 </style> 146 147 <link rel="stylesheet" href="https://headrandom.com/themes/flexiwhite/css/shop.css?v=1790892925"> 148 149 150 <style id="polycms-core-theme-vars"> 151:root { 152 --theme-link-color: #2563eb; 153 --theme-link-hover-color: #1e40af; 154 --color-primary: #2563eb; 155} 156html.dark, html.dark body, :root.dark { 157 --theme-link-color: #4299e1 !important; 158 --theme-link-hover-color: #63b3ed !important; 159} 160</style> 161<meta name="description" content="Just another HeadRandom site"> 162<meta name="robots" content="index,follow"> 163<meta name="publisher" content="HeadRandom"> 164<meta http-equiv="content-language" content="en"> 165<link rel="canonical" href="https://headrandom.com/products"> 166<meta property="og:title" content="| HeadRandom"> 167<meta property="og:description" content="Just another HeadRandom site"> 168<meta property="og:type" content="website"> 169<meta property="og:url" content="https://headrandom.com/products"> 170<meta property="og:site_name" content="HeadRandom"> 171<meta property="og:locale" content="en"> 172<meta property="og:image" content="https://headrandom.com/assets/defaults/polycms-logo.png"> 173<meta name="twitter:card" content="summary_large_image"> 174<meta name="twitter:title" content="| HeadRandom"> 175<meta name="twitter:description" content="Just another HeadRandom site"> 176<meta name="twitter:image" content="https://headrandom.com/assets/defaults/polycms-logo.png">
177<script type="application/ld+json">{"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"https://headrandom.com#organization","name":"HeadRandom","url":"https://headrandom.com","logo":"https://headrandom.com/assets/defaults/polycms-logo.png"},{"@type":"WebSite","@id":"https://headrandom.com#website","url":"https://headrandom.com","name":"HeadRandom","publisher":{"@id":"https://headrandom.com#organization"}},{"@type":"CollectionPage","@id":"https://headrandom.com/products#webpage","url":"https://headrandom.com/products","name":"| HeadRandom","description":"Just another HeadRandom site","inLanguage":"en","isPartOf":{"@id":"https://headrandom.com#website"}}]}</script>
177 178<link rel="icon" type="image/png" href="/assets/defaults/polycms-logo.png"> 179<link rel="apple-touch-icon" href="/assets/defaults/polycms-logo.png"> 180<link rel="stylesheet" href="https://headrandom.com/build/assets/poly-animations-B5xIPW-i.css">
181<script type="speculationrules">{"prefetch":[{"source":"document","where":{"and":[{"href_matches":"/*"},{"not":{"href_matches":"/admin/*"}},{"not":{"href_matches":"/*admin*"}},{"not":{"href_matches":"/api/*"}},{"not":{"href_matches":"/*login*"}},{"not":{"href_matches":"/*register*"}},{"not":{"href_matches":"/*account*"}},{"not":{"href_matches":"/*auth*"}},{"not":{"href_matches":"/*logout*"}},{"not":{"href_matches":"/*cart*"}},{"not":{"href_matches":"/*checkout*"}},{"not":{"href_matches":"/*password*"}}]},"eagerness":"conservative"}]}</script>
181 182 183</head> 184<body class="theme-flexiwhite" dir="ltr"> 185 186 187 188 189 190 <div id="polycms-topbar" class="polycms-topbar" style="display: none;"> 191 <div class="polycms-topbar-container"> 192 193 <div class="polycms-topbar-left"> 194 </div> 195 196 197 <div class="polycms-topbar-right"> 198 199 <!-- Language Switcher --> 200 <div class="topbar-switcher-dropdown" id="topbar-language-dropdown"> 201 <button class="topbar-switcher-btn" onclick="toggleTopbarDropdown('topbar-language-content')" title="Switch Language"> 202 <span class="topbar-switcher-icon"> 203 <svg width="16" height="16"><use href="/icons/heroicons.svg#GlobeAltIcon"/></svg> 204 </span> 205 <span class="topbar-switcher-label">EN</span> 206 </button> 207 <div class="topbar-switcher-panel" id="topbar-language-content"> 208 <div class="topbar-switcher-body"> 209 <button class="topbar-switcher-item is-active" onclick="switchTopbarLanguage('en')"> 210 <span class="topbar-switcher-item-content"> 211 <span>English</span> 212 </span> 213 <svg width="16" height="16" class="topbar-switcher-check"><use href="/icons/heroicons.svg#CheckCircleIcon"/></svg> 214 </button> 215 <button class="topbar-switcher-item " onclick="switchTopbarLanguage('vi')"> 216 <span class="topbar-switcher-item-content"> 217 <span>Vietnamese</span> 218 </span> 219 </button> 220 </div> 221 </div> 222 </div> 223 224 <!-- Currency Switcher --> 225 <div class="topbar-switcher-dropdown" id="topbar-currency-dropdown"> 226 <button class="topbar-switcher-btn" onclick="toggleTopbarDropdown('topbar-currency-content')" title="Switch Currency"> 227 <span class="topbar-switcher-icon"> 228 <svg width="16" height="16"><use href="/icons/heroicons.svg#BanknotesIcon"/></svg> 229 </span> 230 <span class="topbar-switcher-chevron"> 231 <svg width="16" height="16"><use href="/icons/heroicons.svg#ChevronDownIcon"/></svg> 232 </span> 233 </button> 234 <div class="topbar-switcher-panel" id="topbar-currency-content"> 235 <div class="topbar-switcher-body"> 236 <button class="topbar-switcher-item is-active" onclick="switchTopbarCurrency(JSON.parse('{\u0022code\u0022:\u0022USD\u0022,\u0022symbol\u0022:\u0022$\u0022,\u0022rate\u0022:1,\u0022is_default\u0022:true,\u0022decimals\u0022:2,\u0022symbol_position\u0022:\u0022before\u0022,\u0022space_between\u0022:false,\u0022thousands_separator\u0022:\u0022,\u0022,\u0022decimal_separator\u0022:\u0022.\u0022}'))"> 237 <span class="topbar-switcher-item-content"> 238 <span>USD - $</span> 239 </span> 240 <svg width="16" height="16" class="topbar-switcher-check"><use href="/icons/heroicons.svg#CheckCircleIcon"/></svg> 241 </button> 242 <button class="topbar-switcher-item " onclick="switchTopbarCurrency(JSON.parse('{\u0022code\u0022:\u0022VND\u0022,\u0022symbol\u0022:\u0022\\u20ab\u0022,\u0022rate\u0022:25000,\u0022is_default\u0022:false,\u0022decimals\u0022:2,\u0022symbol_position\u0022:\u0022after\u0022,\u0022space_between\u0022:true,\u0022thousands_separator\u0022:\u0022,\u0022,\u0022decimal_separator\u0022:\u0022.\u0022}'))">
243 <span class="topbar-switcher-item-content"> 244 <span>VND - â«</span> 245 </span> 246 </button> 247 </div> 248 </div> 249 </div> 250 251 <!-- Cache Switcher Dropdown --> 252 <div class="topbar-switcher-dropdown" id="topbar-cache-dropdown" style="display: none;"> 253 <button class="topbar-switcher-btn" onclick="toggleTopbarDropdown('topbar-cache-content')" title="Cache Control"> 254 <span class="topbar-switcher-icon"> 255 <svg width="16" height="16"><use href="/icons/heroicons.svg#ArchiveBoxIcon"/></svg> 256 </span> 257 <span class="topbar-switcher-label">Cache</span> 258 <span class="topbar-switcher-chevron"> 259 <svg width="16" height="16"><use href="/icons/heroicons.svg#ChevronDownIcon"/></svg> 260 </span> 261 </button> 262 <div class="topbar-switcher-panel" id="topbar-cache-content" style="width: 250px;"> 263 <div class="topbar-switcher-body" style="padding: 8px 0;"> 264 <!-- Cache Status Toggle (Link/Form) --> 265 <div class="topbar-cache-item flex items-center justify-between" style="padding: 6px 12px; display: flex; justify-content: space-between; align-items: center; border-bottom: 1px solid var(--poly-tb-border);"> 266 <span style="font-weight: 500; font-size: 12px; color: var(--poly-tb-text);">System Cache</span> 267 <label class="topbar-switch" style="position: relative; display: inline-block; width: 34px; height: 20px;"> 268 <input type="checkbox" id="frontend-cache-toggle" onchange="toggleFrontendCache(this.checked)" style="opacity: 0; width: 0; height: 0;"> 269 <span class="topbar-slider" style="position: absolute; cursor: pointer; top: 0; left: 0; right: 0; bottom: 0; transition: .3s; border-radius: 20px;"></span> 270 </label> 271 </div> 272 273 <!-- Clear All --> 274 <button class="topbar-switcher-item" onclick="triggerFrontendClearCache('all')" style="color: #ef4444 !important; width: 100%; text-align: left; padding: 8px 12px; display: flex; align-items: center; gap: 6px;"> 275 <svg width="16" height="16" class="w-4 h-4"><use href="/icons/heroicons.svg#TrashIcon"/></svg> 276 <span>Clear All Caches</span> 277 </button> 278 279 <!-- Fix Permissions --> 280 <button class="topbar-switcher-item" onclick="triggerFrontendClearCache('fix-permissions')" style="width: 100%; text-align: left; padding: 8px 12px; display: flex; align-items: center; gap: 6px; color: var(--poly-tb-text);"> 281 <svg width="16" height="16" class="w-4 h-4"><use href="/icons/heroicons.svg#WrenchIcon"/></svg> 282 <span>Fix Permissions</span> 283 </button> 284 285 <div style="height: 1px; background: var(--poly-tb-border); margin: 4px 0;"></div> 286 <div style="padding: 4px 12px; font-size: 10px; font-weight: bold; color: var(--poly-tb-text-muted); text-transform: uppercase;">Clear Specific</div> 287 288 <!-- Individual Caches --> 289 <button class="topbar-switcher-item" onclick="triggerFrontendClearCache('page_current')" style="width: 100%; text-align: left; padding: 8px 12px; display: flex; align-items: center; gap: 6px; color: #3b82f6 !important; font-weight: 500;"> 290 <svg width="16" height="16" viewBox="0 0 20 20" fill="currentColor" class="w-3.5 h-3.5"><path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z" clip-rule="evenodd"/></svg>
291 <span>Clear Current Page Cache</span> 292 </button> 293 <button class="topbar-switcher-item" onclick="triggerFrontendClearCache('application')" style="width: 100%; text-align: left; padding: 8px 12px; display: flex; align-items: center; color: var(--poly-tb-text);"> 294 <span>Application Cache</span> 295 </button> 296 <button class="topbar-switcher-item" onclick="triggerFrontendClearCache('view')" style="width: 100%; text-align: left; padding: 8px 12px; display: flex; align-items: center; color: var(--poly-tb-text);"> 297 <span>View Cache</span> 298 </button> 299 <button class="topbar-switcher-item" onclick="triggerFrontendClearCache('config')" style="width: 100%; text-align: left; padding: 8px 12px; display: flex; align-items: center; color: var(--poly-tb-text);"> 300 <span>Config Cache</span> 301 </button> 302 <button class="topbar-switcher-item" onclick="triggerFrontendClearCache('route')" style="width: 100%; text-align: left; padding: 8px 12px; display: flex; align-items: center; color: var(--poly-tb-text);"> 303 <span>Route Cache</span> 304 </button> 305 306 <div style="height: 1px; background: var(--poly-tb-border); margin: 4px 0;"></div> 307 308 <!-- Settings --> 309 <a href="/admin/settings/cache" class="topbar-switcher-item" style="width: 100%; text-align: left; padding: 8px 12px; display: flex; align-items: center; justify-content: space-between; color: var(--poly-tb-text);"> 310 <span>Cache Settings</span> 311 <svg width="16" height="16" class="w-3 h-3"><use href="/icons/heroicons.svg#ChevronRightIcon"/></svg> 312 </a> 313 </div> 314 </div> 315 </div> 316 317 <!-- Theme Toggle Button --> 318 <button id="topbar-theme-toggle" class="topbar-button theme-toggle-btn" title="Toggle theme" onclick="handleThemeToggle()" style="padding: 0; width: auto;"> 319 <span id="theme-toggle-light-icon" class="topbar-icon" style="display: none;"> 320 <svg width="16" height="16"><use href="/icons/heroicons.svg#SunIcon"/></svg> 321 </span> 322 <span id="theme-toggle-dark-icon" class="topbar-icon" style="display: none;"> 323 <svg width="16" height="16"><use href="/icons/heroicons.svg#MoonIcon"/></svg> 324 </span> 325 </button> 326 </div> 327 </div> 328</div> 329 330<style> 331 /* Global MacOS Style Scrollbars */ 332 ::-webkit-scrollbar {
333 width: 14px; 334 height: 14px; 335 } 336 ::-webkit-scrollbar-track { 337 background: transparent; 338 } 339 ::-webkit-scrollbar-thumb { 340 background-color: rgba(156, 163, 175, 0.4); 341 border: 4px solid transparent; 342 background-clip: padding-box; 343 border-radius: 9999px; 344 } 345 ::-webkit-scrollbar-thumb:hover { 346 background-color: rgba(156, 163, 175, 0.7); 347 } 348 html.dark ::-webkit-scrollbar-thumb, .dark ::-webkit-scrollbar-thumb { 349 background-color: rgba(156, 163, 175, 0.3); 350 } 351 html.dark ::-webkit-scrollbar-thumb:hover, .dark ::-webkit-scrollbar-thumb:hover { 352 background-color: rgba(156, 163, 175, 0.5); 353 } 354 html { 355 scrollbar-width: thin; 356 scrollbar-color: rgba(156, 163, 175, 0.4) transparent; 357 } 358 html.dark, .dark { 359 scrollbar-color: rgba(156, 163, 175, 0.3) transparent; 360 } 361 362 :root { 363 --poly-tb-bg: #ffffff; 364 --poly-tb-text: #1f2937; 365 --poly-tb-text-muted: #6b7280; 366 --poly-tb-link: #4b5563; 367 --poly-tb-link-hover: #2563eb; 368 --poly-tb-hover-bg: #f3f4f6; 369 --poly-tb-hover-bg-subtle: #f9fafb; 370 --poly-tb-border: #e5e7eb; 371 --poly-tb-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); 372 --poly-tb-dropdown-bg: #ffffff; 373 --poly-tb-dropdown-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); 374 --poly-tb-dropdown-border: #e5e7eb; 375 --poly-tb-primary: #3b82f6; 376 --poly-tb-primary-hover: #2563eb; 377 } 378 379 html.dark, .dark { 380 --poly-tb-bg: #1f2937; 381 --poly-tb-text: #ffffff; 382 --poly-tb-text-muted: #9ca3af; 383 --poly-tb-link: #d1d5db; 384 --poly-tb-link-hover: #60a5fa; 385 --poly-tb-hover-bg: rgba(255, 255, 255, 0.1); 386 --poly-tb-hover-bg-subtle: rgba(255, 255, 255, 0.05); 387 --poly-tb-border: rgba(255, 255, 255, 0.08); 388 --poly-tb-shadow: 0 1px 2px rgba(0, 0, 0, 0.1); 389 --poly-tb-dropdown-bg: #1f2937; 390 --poly-tb-dropdown-shadow: 0 4px 12px rgba(0, 0, 0, 0.25); 391 --poly-tb-dropdown-border: rgba(255, 255, 255, 0.08); 392 --poly-tb-primary: #3b82f6; 393 --poly-tb-primary-hover: #2563eb; 394 } 395 396 .topbar-switch { 397 position: relative; 398 display: inline-block; 399 width: 34px; 400 height: 20px; 401 } 402 .topbar-switch input { 403 opacity: 0; 404 width: 0; 405 height: 0; 406 } 407 .topbar-slider { 408 position: absolute; 409 cursor: pointer; 410 top: 0; 411 left: 0; 412 right: 0; 413 bottom: 0; 414 background-color: var(--poly-tb-border); 415 transition: .3s; 416 border-radius: 20px; 417 } 418 .topbar-slider:before { 419 position: absolute; 420 content: ""; 421 height: 14px; 422 width: 14px; 423 left: 3px; 424 bottom: 3px; 425 background-color: white; 426 transition: .3s; 427 border-radius: 50%; 428 } 429 input:checked + .topbar-slider { 430 background-color: var(--poly-tb-primary); 431 } 432 input:checked + .topbar-slider:before { 433 transform: translateX(14px); 434 } 435 436 #polycms-topbar.polycms-topbar { 437 position: fixed; 438 top: 0; 439 left: 0; 440 right: 0; 441 z-index: 99999; 442 background: var(--poly-tb-bg); 443 color: var(--poly-tb-text); 444 font-size: 13px; 445 line-height: 32px; 446 height: 32px; 447 box-shadow: var(--poly-tb-shadow); 448 border-bottom: 1px solid var(--poly-tb-border); 449 font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; 450 -webkit-font-smoothing: antialiased; 451 overflow: visible; 452 } 453 454 .polycms-topbar-container { 455 width: 100%; 456 display: flex; 457 justify-content: space-between; 458 align-items: center; 459 padding: 0 16px; 460 height: 32px; 461 box-sizing: border-box; 462 } 463 464 .polycms-topbar-left, 465 .polycms-topbar-right { 466 display: flex; 467 align-items: center; 468 gap: 16px; 469 height: 32px; 470 } 471 472 /* Unified styling for all topbar items */ 473 .polycms-topbar a, 474 .polycms-topbar button,
475 .polycms-topbar .topbar-button { 476 display: inline-flex !important; 477 align-items: center !important; 478 padding: 0 12px !important; 479 gap: 6px !important; 480 color: var(--poly-tb-link) !important; 481 text-decoration: none !important; 482 border-radius: 3px !important; 483 transition: all 0.15s ease !important; 484 background: transparent !important; 485 border: none !important; 486 cursor: pointer !important; 487 font-size: 13px !important; 488 font-weight: 400 !important; 489 font-family: inherit !important; 490 white-space: nowrap !important; 491 box-sizing: border-box !important; 492 line-height: 28px !important; 493 height: 28px !important; 494 margin-top: 0; 495 margin-bottom: 0; 496 vertical-align: middle; 497 } 498 499 .polycms-topbar a:hover, 500 .polycms-topbar button:hover { 501 color: var(--poly-tb-link-hover) !important; 502 background: var(--poly-tb-hover-bg) !important; 503 } 504 505 .polycms-topbar .topbar-highlight { 506 background: var(--poly-tb-primary) !important; 507 color: #ffffff !important; 508 font-weight: 500 !important; 509 } 510
511 .polycms-topbar .topbar-highlight:hover { 512 background: var(--poly-tb-primary-hover) !important; 513 color: #ffffff !important; 514 } 515 516 /* Icon unified styling */ 517 .polycms-topbar .topbar-icon { 518 display: inline-flex; 519 align-items: center !important; 520 justify-content: center !important; 521 width: 16px !important; 522 height: 16px !important; 523 line-height: 1 !important; 524 } 525 526 .polycms-topbar .topbar-icon svg { 527 width: 16px !important; 528 height: 16px !important; 529 display: block !important; 530 } 531 532 .theme-toggle-btn { 533 padding: 0 8px !important; 534 width: auto !important; 535 margin-left: 4px !important; 536 height: 24px !important; 537 } 538 539 .polycms-topbar .topbar-dropdown { 540 position: relative; 541 display: flex; 542 align-items: center; 543 height: 32px; 544 } 545 546 .polycms-topbar .topbar-dropdown:not(.submenu) > a::after { 547 content: ''; 548 display: inline-block; 549 width: 0; 550 height: 0; 551 margin-left: 6px; 552 vertical-align: middle;
553 border-top: 4px solid var(--poly-tb-text-muted); 554 border-right: 4px solid transparent; 555 border-bottom: 0px; 556 border-left: 4px solid transparent; 557 transition: border-color 150ms ease; 558 } 559 560 .polycms-topbar .topbar-dropdown:not(.submenu):hover > a::after { 561 border-top-color: var(--poly-tb-link-hover); 562 } 563 564 .polycms-topbar .topbar-dropdown-content { 565 display: none; 566 opacity: 0; 567 visibility: hidden; 568 position: absolute; 569 top: 100%; 570 margin-top: 0; 571 background: var(--poly-tb-bg) !important; 572 min-width: 210px; 573 box-shadow: var(--poly-tb-dropdown-shadow); 574 border-radius: 0 0 6px 6px; 575 padding: 6px 0; 576 z-index: 100000; 577 border: 1px solid var(--poly-tb-dropdown-border); 578 border-top: none; 579 } 580 581 .polycms-topbar .topbar-dropdown.submenu > a::after { 582 display: none !important; 583 } 584 585 .polycms-topbar .topbar-dropdown:hover > .topbar-dropdown-content, 586 .polycms-topbar .to
586pbar-dropdown.touch-open > .topbar-dropdown-content { 587 display: flex !important; 588 flex-direction: column !important; 589 opacity: 1 !important; 590 visibility: visible !important; 591 } 592 593 /* Flyout for submenus in Blade topbar */ 594 .polycms-topbar .topbar-dropdown.submenu { 595 width: 100% !important; 596 height: auto !important; 597 } 598 599 .polycms-topbar .topbar-dropdown.submenu > .topbar-dropdown-content { 600 top: 0 !important; 601 left: 100% !important; 602 border-top: 1px solid var(--poly-tb-dropdown-border) !important; 603 border-radius: 0 6px 6px 6px !important; 604 margin-top: -6px !important; 605 margin-left: 0 !important; 606 } 607 608 .polycms-topbar .topbar-dropdown-item.has-arrow { 609 display: flex !important; 610 align-items: center !important; 611 justify-content: flex-start !important; 612 gap: 8px !important; 613 } 614 615 .polycms-topbar .submenu-arrow { 616 width: 12px; 617 height: 12px; 618 margin-left: auto; 619 opacity: 0.5; 620 transition: transform 150ms ease; 621 } 622 623 .polycms-topbar-right .submenu-arrow { 624 /* If momentum is left, the arrow might need to rotate, but for now fixed like Vue */ 625 } 626
627 .polycms-topbar .topbar-dropdown-item.has-arrow:hover .submenu-arrow { 628 color: var(--poly-tb-link-hover); 629 opacity: 1; 630 } 631 632 /* Dynamic Alignment Classes (Zig-Zag / Snake Logic) */ 633 .polycms-topbar .topbar-dropdown.align-right > .topbar-dropdown-content { 634 left: auto !important; 635 right: 100% !important; 636 margin-right: 2px !important; 637 } 638 639 .polycms-topbar .topbar-dropdown.align-below > .topbar-dropdown-content { 640 top: 100% !important; 641 left: 0 !important; 642 right: auto !important; 643 margin-top: 12px !important; 644 position: absolute !important; 645 border-top: 1px solid var(--poly-tb-dropdown-border) !important; 646 border-radius: 6px !important; 647 } 648 649 /* Hover Stability Bridges (Prevent menu closing when moving mouse) */ 650 .polycms-topbar .topbar-dropdown-content::before { 651 content: ''; 652 position: absolute; 653 z-index: -1; 654 background: transparent; 655 } 656 657 /* Standard Flyout Bridge (Left side) */
658 .polycms-topbar .topbar-dropdown.submenu:not(.align-right):not(.align-below) > .topbar-dropdown-content::before { 659 top: 0; 660 bottom: 0; 661 left: -14px; 662 width: 14px; 663 } 664 665 /* Flipped Flyout Bridge (Right side) */ 666 .polycms-topbar .topbar-dropdown.submenu.align-right:not(.align-below) > .topbar-dropdown-content::before { 667 top: 0; 668 bottom: 0; 669 right: -14px; 670 width: 14px; 671 left: auto; 672 } 673 674 /* Drop-below Bridge (Top side) */ 675 .polycms-topbar .topbar-dropdown.align-below > .topbar-dropdown-content::before { 676 left: 0; 677 right: 0; 678 top: -14px !important; 679 bottom: auto !important; 680 height: 14px !important; 681 width: 100% !important; 682 } 683 684 /* Arrow rotation for flipped submenus */ 685 .polycms-topbar .topbar-dropdown.align-right > a .submenu-arrow { 686 transform: rotate(180deg); 687 } 688 689 .polycms-topbar-right .topbar-dropdown-content { 690 right: 0; 691 left: auto; 692 } 693 694 .polycms-topbar-left .topbar-dropdown-content { 695 left: 0; 696 right: auto; 697 } 698
699 .polycms-topbar .topbar-dropdown-item { 700 display: flex !important; 701 align-items: center !important; 702 padding: 8px 16px !important; 703 color: var(--poly-tb-link) !important; 704 width: 100% !important; 705 height: auto !important; 706 margin: 0 !important; 707 border-radius: 0 !important; 708 text-align: left !important; 709 } 710 711 .polycms-topbar .topbar-dropdown-item:hover { 712 background: var(--poly-tb-hover-bg) !important; 713 color: var(--poly-tb-link-hover) !important; 714 } 715 716 .polycms-topbar .topbar-dropdown-item.active { 717 color: var(--poly-tb-link-hover) !important; 718 background: var(--poly-tb-hover-bg-subtle) !important; 719 } 720 721 body.polycms-topbar-active { 722 padding-top: 32px !important; 723 } 724 body.polycms-topbar-active header { 725 top: 32px !important; 726 } 727 728 @media (max-width: 1023px) { 729 .polycms-topbar .topbar-dropdown.touch-open > .topbar-dropdown-content { 730 position: fixed !important; 731 top: 38px !important; 732 left: 8px !important; 733 right: 8px !important; 734 width: auto !important; 735 max-width: none !important; 736 min-width: 0 !important; 737 max-height: calc(100vh - 52px) !important; 738 overflow-y: auto !important; 739 border-radius: 12px !important; 740 box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.25), 0 8px 10px -6px rgba(0, 0, 0, 0.25) !important; 741 border: 1px solid var(--poly-tb-dropdown-border) !important; 742 z-index: 100005 !important; 743 background: var(--poly-tb-bg) !important; 744 } 745
746 .polycms-topbar .topbar-dropdown.submenu.touch-open > .topbar-dropdown-content { 747 position: relative !important; 748 top: auto !important; 749 left: auto !important; 750 right: auto !important; 751 width: 100% !important; 752 box-shadow: none !important; 753 border: none !important; 754 padding-left: 12px !important; 755 background: rgba(125, 125, 125, 0.05) !important; 756 border-radius: 0 !important; 757 } 758 759 .polycms-topbar .topbar-dropdown.touch-open > a { 760 background: var(--poly-tb-hover-bg) !important; 761 color: var(--poly-tb-link-hover) !important; 762 } 763 764 .polycms-topbar .topbar-dropdown-item { 765 padding: 12px 16px !important; 766 font-size: 13px !important; 767 min-height: 42px !important; 768 border-bottom: 1px solid rgba(156, 163, 175, 0.08) !important; 769 } 770 } 771 772 @media (max-width: 768px) { 773 #polycms-topbar.polycms-topbar { 774 height: 36px; 775 line-height: 36px; 776 overflow: visible; 777 } 778 .polycms-topbar-container { 779 height: 36px; 780 padding: 0 8px; 781 overflow-x: auto; 782 overflow-y: hidden; 783 -webkit-overflow-scrolling: touch; 784 scrollbar-width: none; 785 -ms-overflow-style: none; 786 } 787 .polycms-topbar-container::-webkit-scrollbar {
788 display: none; 789 } 790 .polycms-topbar-left, 791 .polycms-topbar-right { 792 gap: 4px; 793 height: 36px; 794 flex-shrink: 0; 795 } 796 .polycms-topbar a, 797 .polycms-topbar button, 798 .polycms-topbar .topbar-button { 799 padding: 0 8px !important; 800 font-size: 12px !important; 801 height: 28px !important; 802 line-height: 28px !important; 803 } 804 .topbar-switcher-dropdown .topbar-switcher-panel { 805 right: 0 !important; 806 left: auto !important; 807 max-width: 90vw; 808 } 809 body.polycms-topbar-active { 810 padding-top: 36px !important; 811 } 812 body.polycms-topbar-active header { 813 top: 36px !important; 814 } 815 } 816 817 /* ===== Switcher styles (Language / Currency) â matches Vue components ===== */ 818 .topbar-switcher-dropdown { 819 position: relative; 820 display: inline-flex; 821 align-items: center; 822 height: 32px; 823 } 824
825 .polycms-topbar .topbar-switcher-btn { 826 padding: 0 8px !important; 827 height: 32px !important; 828 display: inline-flex !important; 829 align-items: center !important; 830 gap: 4px !important; 831 background: transparent !important; 832 border: none !important; 833 border-radius: 3px !important; 834 color: var(--poly-tb-link) !important; 835 cursor: pointer !important; 836 transition: all 0.15s ease !important; 837 font-family: inherit !important; 838 font-size: 12px !important; 839 font-weight: 600 !important; 840 text-transform: uppercase !important; 841 white-space: nowrap !important; 842 line-height: 32px !important; 843 margin-left: 2px; 844 } 845 846 .polycms-topbar .topbar-switcher-btn:hover, 847 .polycms-topbar .topbar-switcher-btn.active { 848 color: var(--poly-tb-link-hover) !important; 849 background: var(--poly-tb-hover-bg) !important; 850 } 851 852 .topbar-switcher-icon { 853 display: inline-flex; 854 align-items: center; 855 justify-content: center; 856 width: 14px; 857 height: 14px; 858 flex-shrink: 0; 859 } 860 861 .topbar-switcher-icon svg { 862 width: 14px !important; 863 height: 14px !important; 864 display: block !important; 865 fill: none !important; 866 } 867 868 .topbar-switcher-label { 869 font-size: 12px; 870 font-weight: 600; 871 text-transform: uppercase; 872 } 873 874 .topbar-switcher-chevron { 875 display: inline-flex; 876 align-items: center; 877 margin-left: 2px; 878 } 879 880 .topbar-switcher-chevron svg { 881 width: 10px !important; 882 height: 10px !important; 883 fill: none !important; 884 transition: transform 0.2s ease; 885 } 886 887 .topbar-switcher-panel { 888 display: none; 889 position: absolute; 890 top: 100%; 891 right: 0; 892 margin-top: 4px; 893 background: var(--poly-tb-bg); 894 min-width: 200px; 895 border: 1px solid var(--poly-tb-dropdown-border); 896 border-radius: 6px; 897 box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.3); 898 z-index: 100001; 899 overflow: hidden; 900 } 901 902 .topbar-switcher-header { 903 padding: 12px 16px; 904 font-weight: 600; 905 color: var(--poly-tb-text-muted); 906 border-bottom: 1px solid var(--poly-tb-hover-bg-subtle); 907 text-transform: uppercase; 908 letter-spacing: 0.025em; 909 font-size: 11px; 910 } 911 912 .topbar-switcher-body { 913 padding: 4px 0; 914 } 915
916 .polycms-topbar .topbar-switcher-panel .topbar-switcher-item { 917 display: flex !important; 918 align-items: center !important; 919 justify-content: space-between !important; 920 width: 100% !important; 921 padding: 12px 16px !important; 922 background: transparent !important; 923 border: none !important; 924 color: var(--poly-tb-link) !important; 925 font-size: 14px !important; 926 font-family: inherit !important; 927 cursor: pointer !important; 928 transition: all 0.15s ease !important; 929 text-align: left !important; 930 line-height: 1.4 !important; 931 height: auto !important; 932 border-radius: 0 !important; 933 margin: 0 !important; 934 gap: 0 !important; 935 } 936 937 .polycms-topbar .topbar-switcher-panel .topbar-switcher-item:hover { 938 background: var(--poly-tb-hover-bg-subtle) !important; 939 color: var(--poly-tb-link-hover) !important; 940 } 941 942 .polycms-topbar .topbar-switcher-panel .topbar-switcher-item.is-active { 943 color: var(--poly-tb-link-hover) !important; 944 background: var(--poly-tb-hover-bg-subtle) !important; 945 } 946 947 .topbar-switcher-item-content { 948 display: flex; 949 align-items: center; 950 gap: 8px; 951 } 952 953 .topbar-switcher-flag { 954 font-size: 16px; 955 } 956 957 .topbar-switcher-check { 958 width: 16px; 959 height: 16px; 960 color: var(--poly-tb-primary); 961 flex-shrink: 0; 962 fill: none !important; 963 } 964</style> 965
966<script> 967 window.showTopbarToast = function(message, type = 'success') { 968 let container = document.getElementById('topbar-toast-container'); 969 if (!container) { 970 container = document.createElement('div'); 971 container.id = 'topbar-toast-container'; 972 container.style.cssText = 'position: fixed; bottom: 20px; right: 20px; z-index: 1000000; display: flex; flex-direction: column; gap: 10px; pointer-events: none;'; 973 document.body.appendChild(container); 974 } 975 976 const toast = document.createElement('div'); 977 toast.className = 'topbar-toast ' + type; 978 979 const bgColor = type === 'success' ? 'rgba(16, 185, 129, 0.95)' : 'rgba(239, 68, 68, 0.95)'; 980 const icon = type === 'success' ? 'â' : 'â'; 981 982 toast.style.cssText = 'min-width: 250px; padding: 12px 16px; border-radius: 8px; background: ' + bgColor + '; backdrop-filter: blur(8px); color: #ffffff; font-family: inherit; font-size: 13px; font-weight: 500; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); display: flex; align-items: center; gap: 10px; pointer-events: auto; transform: translateX(120%); transition: all 0.3s cubic-bezier(0.68, -0.55, 0.27, 1.55); opacity: 0;'; 983 984 toast.innerHTML = '<span style="display: inline-flex; align-items: center; justify-content: center; width: 20px; height: 20px; background: rgba(255,255,255,0.2); border-radius: 50%; font-weight: bold; font-size: 11px;">' + icon + '</span><span style="flex: 1;">' + message + '</span>'; 985 986 container.appendChild(toast); 987 988 requestAnimationFrame(() => { 989 toast.style.transform = 'translateX(0)'; 990 toast.style.opacity = '1'; 991 }); 992 993 setTimeout(() => { 994 toast.style.transform = 'translateX(120%)'; 995 toast.style.opacity = '0'; 996 setTimeout(() => { 997 toast.remove(); 998 }, 300); 999 }, 3000); 1000 }; 1001 1002 window.showTopbarConfirm = function(title, message, onConfirm) { 1003 let modal = document.getElementById('topbar-confirm-modal'); 1004 if (modal) { 1005 modal.remove(); 1006 } 1007 1008 modal = document.createElement('div'); 1009 modal.id = 'topbar-confirm-modal'; 1010 modal.style.cssText = 'position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(15, 23, 42, 0.6); backdrop-filter: blur(4px); z-index: 2000000; display: flex; align-items: center; justify-content: center; opacity: 0; transition: opacity 0.25s ease;'; 1011 1012 const card = document.createElement('div'); 1013 card.style.cssText = 'background: var(--poly-tb-dropdown-bg, #ffffff); border: 1px solid var(--poly-tb-dropdown-border, #e5e7eb); border-radius: 12px; width: 90%; max-width: 400px; padding: 24px; box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04); transform: scale(0.95); transition: transform 0.25s cubic-bezier(0.34, 1.56, 0.64, 1); color: var(--poly-tb-text, #1f2937); font-family: inherit;'; 1014 1015 card.innerHTML = '<div style="font-weight: 600; font-size: 16px; margin-bottom: 8px;">' + title + '</div><div style="font-size: 14px; color: var(--poly-tb-text-muted, #6b7280); margin-bottom: 20px; line-height: 1.5;">' + message + '</div><div style="display: flex; justify-content: flex-end; gap: 12px;"><button id="topbar-confirm-cancel" style="padding: 8px 16px; border-radius: 6px; font-size: 13px; font-weight: 500; background: var(--poly-tb-hover-bg, #f3f4f6); color: var(--poly-tb-text, #1f2937); border: none; cursor: pointer; transition: background 0.15s ease;">Cancel</button><button id="topbar-confirm-ok" style="padding: 8px 16px; border-radius: 6px; font-size: 13px; font-weight: 500; background: #ef4444; color: #ffffff; border: none; cursor: pointer; transition: background 0.15s ease;">Clear All</button></div>'; 1016 1017 modal.appendChild(card); 1018 document.body.appendChild(modal); 1019 1020 requestAnimationFrame(() => { 1021 modal.style.opacity = '1'; 1022 card.style.transform = 'scale(1)'; 1023 }); 1024 1025 const closeModal = () => { 1026 modal.style.opacity = '0'; 1027 card.style.transform = 'scale(0.95)'; 1028 setTimeout(() => { 1029 modal.remove(); 1030 }, 250); 1031 }; 1032 1033 modal.querySelector('#topbar-confirm-cancel').onclick = closeModal; 1034 modal.querySelector('#topbar-confirm-ok').onclick = () => { 1035 closeModal(); 1036 if (typeof onConfirm === 'function') { 1037 onConfirm(); 1038 } 1039 }; 1040 1041 modal.onclick = (e) => { 1042 if (e.target === modal) { 1043 closeModal(); 1044 } 1045 }; 1046 }; 1047 1048 window.toggleTopbarDropdown = function(id) { 1049 const content = document.getElementById(id); 1050 const allDropdowns = document.querySelectorAll('.topbar-switcher-panel'); 1051 1052 allDropdowns.forEach(dropdown => { 1053 if (dropdown.id !== id) { 1054 dropdown.style.display = 'none'; 1055 } 1056 }); 1057 1058 if (content) { 1059 content.style.display = content.style.display === 'block' ? 'none' : 'block'; 1060 content.style.opacity = '1'; 1061 content.style.visibility = 'visible'; 1062 } 1063 }; 1064 1065 window.loadFrontendCacheStatus = function() { 1066 const token = localStorage.getItem('auth_token'); 1067 const headers = { 1068 'Accept': 'application/json', 1069 'X-CSRF-TOKEN': 'bO1LIggE4bt7GXGlBzfIKeHZrPgJ24CDBMlezc4P' 1070 }; 1071 if (token) headers['Authorization'] = `Bearer ${token}`; 1072 1073 fetch('/api/v1/settings/group/cache_optimization', { headers }) 1074 .then(res => res.json()) 1075 .then(data => { 1076 const settings = data?.data || {};
1077 const enabled = settings.polycms_cache_enabled?.value !== 'no'; 1078 const toggle = document.getElementById('frontend-cache-toggle'); 1079 if (toggle) { 1080 toggle.checked = enabled; 1081 } 1082 }) 1083 .catch(err => console.error('Failed to load cache status:', err)); 1084 }; 1085 1086 window.toggleFrontendCache = function(isChecked) { 1087 const token = localStorage.getItem('auth_token'); 1088 const headers = { 1089 'Content-Type': 'application/json', 1090 'Accept': 'application/json', 1091 'X-CSRF-TOKEN': 'bO1LIggE4bt7GXGlBzfIKeHZrPgJ24CDBMlezc4P' 1092 }; 1093 if (token) headers['Authorization'] = `Bearer ${token}`; 1094 1095 const newValue = isChecked ? 'yes' : 'no'; 1096 1097 fetch('/api/v1/settings/group/cache_optimization', { 1098 method: 'PUT', 1099 headers, 1100 body: JSON.stringify({ 1101 settings: { 1102 polycms_cache_enabled: { value: newValue, type: 'string', group: 'cache_optimization' } 1103 } 1104 }) 1105 }) 1106 .then(res => res.json()) 1107 .then(data => { 1108 showTopbarToast('Cache status updated successfully!', 'success'); 1109 }) 1110 .catch(err => { 1111 console.error('Failed to update cache status:', err); 1112 showTopbarToast('Failed to update cache status.', 'error'); 1113 document.getElementById('frontend-cache-toggle').checked = !isChecked; 1114 }); 1115 }; 1116 1117 window.triggerFrontendClearCache = function(type) { 1118 const token = localStorage.getItem('auth_token'); 1119 const headers = { 1120 'Content-Type': 'application/json', 1121 'Accept': 'application/json', 1122 'X-CSRF-TOKEN': 'bO1LIggE4bt7GXGlBzfIKeHZrPgJ24CDBMlezc4P' 1123 }; 1124 if (token) headers['Authorization'] = `Bearer ${token}`; 1125 1126 const proceed = () => { 1127 const url = type === 'fix-permissions' 1128 ? '/api/v1/system/cache/fix-permissions' 1129 : '/api/v1/system/cache/clear'; 1130 1131 const method = 'POST'; 1132 const payloadData = { types: [type] }; 1133 if (type === 'page_current') { 1134 payloadData.current_url = window.location.href; 1135 } 1136 const body = type === 'fix-permissions' 1137 ? null 1138 : JSON.stringify(payloadData); 1139 1140 fetch(url, { method, headers, body }) 1141 .then(res => res.json()) 1142 .then(data => { 1143 showTopbarToast(data.message || 'Action completed successfully.', 'success'); 1144 if (type === 'page_current') { 1145 setTimeout(() => window.location.reload(), 600); 1146 } 1147 }) 1148 .catch(err => { 1149 console.error('Action failed:', err); 1150 showTopbarToast('Action failed.', 'error'); 1151 }); 1152 }; 1153 1154 if (type === 'all') { 1155 window.showTopbarConfirm('Clear Caches', 'Are you sure you want to clear all caches?', proceed); 1156 } else { 1157 proceed(); 1158 } 1159 }; 1160 1161 // Load initial cache status when document is ready 1162 document.addEventListener('DOMContentLoaded', function() { 1163 const topbar = document.getElementById('polycms-topbar'); 1164 if (topbar && window.getComputedStyle(topbar).display !== 'none') { 1165 window.loadFrontendCacheStatus(); 1166 } 1167 }); 1168 1169 window.switchTopbarLanguage = function(code) { 1170 let url = new URL(window.location.href); 1171 url.searchParams.set('lang', code); 1172 window.location.href = url.toString(); 1173 }; 1174 1175 window.switchTopbarCurrency = function(currency) { 1176 const authToken = localStorage.getItem('auth_token'); 1177 const headers = { 1178 'Content-Type': 'application/json', 1179 'Accept': 'application/json', 1180 'X-CSRF-TOKEN': '"bO1LIggE4bt7GXGlBzfIKeHZrPgJ24CDBMlezc4P"' 1181 }; 1182 if (authToken) headers['Authorization'] = `Bearer ${authToken}`; 1183 1184 fetch('/api/v1/settings/group/ecommerce', { 1185 method: 'PUT', 1186 headers: headers, 1187 body: JSON.stringify({ 1188 settings: { 1189 ecommerce_currency: currency.code, 1190 ecommerce_currency_symbol: currency.symbol, 1191 currency_decimals: currency.decimals, 1192 currency_symbol_position: currency.symbol_position, 1193 currency_thousands_separator: currency.thousands_separator, 1194 currency_decimal_separator: currency.decimal_separator,
1195 currency_space: currency.space_between 1196 } 1197 }) 1198 }).then(() => window.location.reload()); 1199 }; 1200 1201 window.switchTopbarTemplate = function(entityType, entityId, templateTheme) { 1202 const authToken = localStorage.getItem('auth_token'); 1203 const headers = { 1204 'Content-Type': 'application/json', 1205 'Accept': 'application/json', 1206 'X-CSRF-TOKEN': '"bO1LIggE4bt7GXGlBzfIKeHZrPgJ24CDBMlezc4P"' 1207 }; 1208 if (authToken) headers['Authorization'] = `Bearer ${authToken}`; 1209 1210 fetch('/api/v1/themes/switch-template', { 1211 method: 'POST', 1212 headers: headers, 1213 body: JSON.stringify({ 1214 entity_type: entityType, 1215 entity_id: entityId, 1216 template_theme: templateTheme 1217 }) 1218 }) 1219 .then(response => { 1220 if (response.ok) { 1221 window.location.reload(); 1222 } else { 1223 alert('Failed to switch template: ' + response.statusText); 1224 } 1225 }) 1226 .catch(error => { 1227 console.error('Error switching template:', error); 1228 alert('Error switching template'); 1229 }); 1230 }; 1231 1232 // Close dropdowns when clicking outside 1233 document.addEventListener('click', function(event) { 1234 if (!event.target.closest('.topbar-switcher-dropdown')) { 1235 document.querySelectorAll('.topbar-switcher-panel').forEach(d => { 1236 d.style.display = 'none'; 1237 }); 1238 } 1239 }); 1240 1241 (function() { 1242 // Permalink structure from server 1243 const permalinkStructure = {"posts":{"archive":"blog","single":""},"pages":{"single":""},"products":{"archive":"products","single":"products"},"categories":{"single":""},"product_categories":{"single":"product-categories"},"product_brands":{"single":"product-brands"},"tags":{"post":"tags","product":"product-tags"},"users":{"single":"author"},"projects":{"archive":"projects","single":"projects","category":"project-categories"}}; 1244 const iconAliases = {"dashboard":"Squares2x2Icon","home":"HomeIcon","pencil":"PencilIcon","paint-brush":"PaintBrushIcon","user-circle":"UserCircleIcon","user":"UserIcon","logout":"ArrowLeftOnRectangleIcon","log-out":"ArrowLeftOnRectangleIcon","sign-out":"ArrowLeftOnRectangleIcon","document":"DocumentTextIcon","page":"DocumentTextIcon","product":"CubeIcon","product-category":"RectangleGroupIcon","product-brand":"TagIcon","brand":"TagIcon","category":"FolderIcon","shopping-cart":"ShoppingCartIcon","refresh":"ArrowPathIcon","key":"KeyIcon","link":"LinkIcon","menu":"Bars3Icon","globe":"GlobeAltIcon","cog":"Cog6ToothIcon","settings":"Cog6ToothIcon","archive":"ArchiveBoxIcon","bell":"BellIcon","check":"CheckCircleIcon","sync":"ArrowPathIcon","delete":"TrashIcon","trash":"TrashIcon","edit":"PencilSquareIcon","search":"MagnifyingGlassIcon","box":"ArchiveBoxIcon","plus":"PlusIcon","close":"XMarkIcon","x":"XMarkIcon","star":"StarIcon","heart":"HeartIcon","mail":"EnvelopeIcon","email":"EnvelopeIcon","phone":"PhoneIcon","camera":"CameraIcon","photo":"PhotoIcon","image":"PhotoIcon","calendar":"CalendarIcon","clock":"ClockIcon","cloud":"CloudIcon","folder":"FolderIcon","tag":"TagIcon","bookmark":"BookmarkIcon","flag":"FlagIcon","printer":"PrinterIcon","share":"ShareIcon","download":"ArrowDownTrayIcon","upload":"ArrowUpTrayIcon","play":"PlayIcon","pause":"PauseIcon","stop":"StopIcon","power":"PowerIcon","wifi":"WifiIcon","signal":"SignalIcon","gift":"GiftIcon","fire":"FireIcon","bolt":"BoltIcon","sun":"SunIcon","moon":"MoonIcon","map":"MapIcon","map-pin":"MapPinIcon","location":"MapPinIcon","truck":"TruckIcon","server":"ServerIcon","code":"CodeBracketIcon","terminal":"CommandLineIcon","wrench":"WrenchIcon","tools":"WrenchScrewdriverIcon","puzzle":"PuzzlePieceIcon","rocket":"RocketLaunchIcon","shield":"ShieldCheckIcon","lock":"LockClosedIcon","unlock":"LockOpenIcon","eye":"EyeIcon","film":"FilmIcon","chart":"ChartBarIcon","clipboard":"ClipboardIcon","newspaper":"NewspaperIcon","ticket":"TicketIcon","banknotes":"BanknotesIcon","chevron-down":"ChevronDownIcon","chevron-up":"ChevronUpIcon","chevron-left":"ChevronLeftIcon","chevron-right":"ChevronRightIcon","bars":"Bars3Icon","cube":"CubeIcon"}; 1245 1246 // Function to detect route from current path 1247 function detectRouteFromPath(pathname) { 1248 const path = pathname.replace(/^\/+|\/+$/g, ''); // Remove leading/trailing slashes 1249 let segments = path.split('/').filter(s => s); 1250 1251 const routeInfo = { route: null, params: {} }; 1252 1253 if (segments.length === 0) { 1254 routeInfo.route = 'home'; 1255 return routeInfo; 1256 } 1257 1258 // Remove language prefix if present 1259 const activeLangs = ["en","vi"]; 1260 if (segments.length > 0 && activeLangs.includes(segments[0])) { 1261 segments = segments.slice(1); 1262 } 1263 1264 if (segments.length === 0) { 1265 routeInfo.route = 'home'; 1266 return routeInfo; 1267 } 1268 1269 // Get permalink bases (trim and split) 1270 const docsPrefixVal = "docs"; 1271 const docsPrefixBase = (docsPrefixVal || 'docs').trim().split('/').filter(s => s); 1272 const showcasePrefixVal = 'shipcode'; 1273 const showcasePrefixBase = (showcasePrefixVal || 'shipcode').trim().split('/').filter(s => s);
1274 const postsSingleBase = (permalinkStructure?.posts?.single || 'posts').trim().split('/').filter(s => s); 1275 const pagesBase = (permalinkStructure?.pages?.single || '').trim().split('/').filter(s => s); 1276 const productsSingleBase = (permalinkStructure?.products?.single || 'products').trim().split('/').filter(s => s); 1277 const projectsSingleBase = (permalinkStructure?.projects?.single || 'projects').trim().split('/').filter(s => s); 1278 const categoryBase = (permalinkStructure?.categories?.single || 'categories').trim().split('/').filter(s => s); 1279 const productCategoryBase = (permalinkStructure?.product_categories?.single || 'product-categories').trim().split('/').filter(s => s); 1280 const postTagBase = (permalinkStructure?.tags?.post || 'tags').trim().split('/').filter(s => s); 1281 const productTagBase = (permalinkStructure?.tags?.product || 'product-tags').trim().split('/').filter(s => s); 1282 1283 // Helper function to check if segments match a base 1284 function matchesBase(segments, baseArray) { 1285 if (baseArray.length === 0) return false; 1286 if (segments.length < baseArray.length) return false; 1287 return baseArray.every((base, idx) => segments[idx] === base); 1288 } 1289 1290 // Check routes in priority order (more specific first) 1291 // 0. Check for FlexiDocs custom wiki routes 1292 if (docsPrefixBase.length > 0 && matchesBase(segments, docsPrefixBase)) { 1293 const docsSegments = segments.slice(docsPrefixBase.length); 1294 if (docsSegments.length === 2) { 1295 routeInfo.route = 'theme.flexidocs.show'; 1296 routeInfo.params = { categorySlug: docsSegments[0], postSlug: docsSegments[1] }; 1297 return routeInfo; 1298 } else if (docsSegments.length === 1) { 1299 routeInfo.route = 'theme.flexidocs.category'; 1300 routeInfo.params = { slug: docsSegments[0] }; 1301 return routeInfo; 1302 } 1303 } 1304 1305 // 0b. Check for FlexiEmpty showcase pages: /{showcasePrefix}/{slug} 1306 if (showcasePrefixBase.length > 0 && matchesBase(segments, showcasePrefixBase) && segments[showcasePrefixBase.length]) { 1307 routeInfo.route = 'theme.flexiempty.showcase'; 1308 routeInfo.params = { slug: segments[showcasePrefixBase.length] }; 1309 return routeInfo; 1310 } 1311 1312 // 1a. Check for product-categories.show: /{productCategoryBase}/{slug} 1313 if (productCategoryBase.length > 0 && matchesBase(segments, productCategoryBase) && segments[productCategoryBase.length]) { 1314 routeInfo.route = 'product-categories.show'; 1315 routeInfo.params = { slug: segments[productCategoryBase.length] }; 1316 return routeInfo; 1317 } 1318 1319 // 1b. Check for categories.show: /{categoryBase}/{slug} 1320 if (categoryBase.length > 0 && matchesBase(segments, categoryBase) && segments[categoryBase.length]) { 1321 routeInfo.route = 'categories.show'; 1322 routeInfo.params = { slug: segments[categoryBase.length] }; 1323 return routeInfo; 1324 } 1325 1326 // 2. Check for tags.show (post tags): /{postTagBase}/{slug} 1327 if (postTagBase.length > 0 && matchesBase(segments, postTagBase) && segments[postTagBase.length]) { 1328 routeInfo.route = 'tags.show'; 1329 routeInfo.params = { slug: segments[postTagBase.length] }; 1330 return routeInfo; 1331 } 1332 1333 // 3. Check for product-tags.show: /{productTagBase}/{slug} 1334 if (productTagBase.length > 0 && matchesBase(segments, productTagBase) && segments[productTagBase.length]) { 1335 routeInfo.route = 'product-tags.show'; 1336 routeInfo.params = { slug: segments[productTagBase.length] }; 1337 return routeInfo; 1338 } 1339 1340 // 4. Check for posts.show: /{postsSingleBase}/{slug} 1341 if (postsSingleBase.length > 0 && matchesBase(segments, postsSingleBase) && segments[postsSingleBase.length]) { 1342 routeInfo.route = 'posts.show'; 1343 routeInfo.params = { slug: segments[postsSingleBase.length] }; 1344 return routeInfo; 1345 } 1346 1347 // 5. Check for products.show: /{productsSingleBase}/{slug} 1348 if (productsSingleBase.length > 0 && matchesBase(segments, productsSingleBase) && segments[productsSingleBase.length]) { 1349 routeInfo.route = 'products.show'; 1350 routeInfo.params = { slug: segments[productsSingleBase.length] }; 1351 return routeInfo; 1352 } 1353 1354 // 5b. Check for projects.show.page: /{projectsSingleBase}/{slug} 1355 if (projectsSingleBase.length > 0 && matchesBase(segments, projectsSingleBase) && segments[projectsSingleBase.length]) { 1356 const projectSlug = segments[projectsSingleBase.length]; 1357 routeInfo.route = 'projects.show.page'; 1358 routeInfo.params = { slug: projectSlug }; 1359 return routeInfo; 1360 } 1361 1362 // 6. Check for pages.show: /{slug} (if no base) or /{pagesBase}/{slug} 1363 // Pages should be checked last as it's the fallback 1364 if (pagesBase.length === 0) { 1365 // No base, single segment could be a page (but check it's not reserved) 1366 if (segments.length === 1) { 1367 routeInfo.route = 'pages.show'; 1368 routeInfo.params = { slug: segments[0] }; 1369 return routeInfo; 1370 } 1371 } else { 1372 // Has base, check if matches
1373 if (matchesBase(segments, pagesBase) && segments[pagesBase.length]) { 1374 routeInfo.route = 'pages.show'; 1375 routeInfo.params = { slug: segments[pagesBase.length] }; 1376 return routeInfo; 1377 } 1378 } 1379 1380 // Debug logging 1381 if (window.console && console.debug) { 1382 console.debug('Topbar: Route detection', { 1383 pathname: pathname, 1384 segments: segments, 1385 permalinkStructure: permalinkStructure, 1386 detectedRoute: routeInfo.route, 1387 detectedSlug: routeInfo.params.slug 1388 }); 1389 } 1390 1391 return routeInfo; 1392 } 1393 1394 // Server-side auth status 1395 const isWebAuth = false; 1396 1397 // Check if user is authenticated and show topbar 1398 function checkAuthAndShowTopbar() { 1399 // Case 1: Session Auth (Customer / Web Guard) 1400 if (isWebAuth) { 1401 const topbar = document.getElementById('polycms-topbar'); 1402 if (topbar) { 1403 document.body.classList.add('polycms-topbar-active'); 1404 adjustStickyHeaders(); 1405 if (typeof window.loadFrontendCacheStatus === 'function') { 1406 window.loadFrontendCacheStatus(); 1407 } 1408 } 1409 return; 1410 } 1411 1412 // Case 2: API Token Auth (Admin / SPA) 1413 const authToken = localStorage.getItem('auth_token'); 1414 if (!authToken) { 1415 return; // No token, user not logged in 1416 } 1417 1418 // Check if user is authenticated by calling API 1419 fetch('/api/v1/auth/me', { 1420 headers: { 1421 'Authorization': `Bearer ${authToken}`, 1422 'Accept': 'application/json', 1423 } 1424 }) 1425 .then(response => { 1426 if (response.ok) { 1427 return response.json(); 1428 } 1429 throw new Error('Not authenticated'); 1430 }) 1431 .then(data => { 1432 // User is authenticated, fetch menu items and show topbar 1433 if (data && data.data) { 1434 const roles = data.data.roles || []; 1435 const permissions = data.data.permissions || []; 1436 const canManageCache = roles.includes('admin') || roles.includes('editor') || permissions.includes('manage cache'); 1437 1438 const cacheToggle = document.getElementById('topbar-cache-dropdown'); 1439 if (cacheToggle) { 1440 cacheToggle.style.display = canManageCache ? 'flex' : 'none'; 1441 } 1442 // Detect current route and params from URL 1443 const currentPath = window.location.pathname; 1444 const routeInfo = detectRouteFromPath(currentPath); 1445 1446 // Debug logging 1447 if (console && console.debug) { 1448 console.debug('Topbar: Detected route info', { 1449 pathname: currentPath, 1450 route: routeInfo.route, 1451 params: routeInfo.params 1452 }); 1453 } 1454 1455 // Build API URL with route info and current locale 1456 const apiUrl = new URL('/api/v1/topbar/menu', window.location.origin); 1457 1458 const activeLangs = ["en","vi"]; 1459 const pathSegments = currentPath.replace(/^\/+|\/+$/g, '').split('/').filter(s => s); 1460 let currentLocale = "en"; 1461 if (pathSegments.length > 0 && activeLangs.includes(pathSegments[0])) { 1462 currentLocale = pathSegments[0]; 1463 } 1464 apiUrl.searchParams.set('locale', currentLocale); 1465 1466 if (routeInfo.route) { 1467 apiUrl.searchParams.set('route', routeInfo.route); 1468 if (routeInfo.params && Object.keys(routeInfo.params).length > 0) { 1469 apiUrl.searchParams.set('route_params', JSON.stringify(routeInfo.params)); 1470 } 1471 } 1472 1473 // Fetch menu items from API 1474 fetch(apiUrl.toString(), { 1475 headers: { 1476 'Authorization': `Bearer ${authToken}`, 1477 'Accept': 'application/json', 1478 } 1479 }) 1480 .then(response => { 1481 if (response.ok) { 1482 return response.json(); 1483 } 1484 throw new Error('Failed to fetch menu'); 1485 }) 1486 .then(menuData => { 1487 if (menuData && menuData.data && Array.isArray(menuData.data)) { 1488 const leftMenu = document.querySelector('#polycms-topbar .polycms-topbar-left'); 1489 const rightMenu = document.querySelector('#polycms-topbar .polycms-topbar-right'); 1490 1491 if (menuData.data && menuData.data.length > 0) { 1492 // Always render dynamic menu items for authenticated admin on cached pages 1493 renderMenuItems(menuData.data, leftMenu, rightMenu); 1494 } 1495 1496 // Show topbar 1497 const topbar = document.getElementById('polycms-topbar'); 1498 if (topbar) { 1499 topbar.style.display = 'block'; 1500 document.body.classList.add('polycms-topbar-active'); 1501 1502 // Adjust sticky headers 1503 adjustStickyHeaders(); 1504 1505 if (typeof window.loadFrontendCacheStatus === 'function') { 1506 window.loadFrontendCacheStatus(); 1507 } 1508 } 1509 } 1510 }) 1511 .catch(error => { 1512 console.debug('Topbar: Failed to fetch menu items', error); 1513 // Still show topbar even if menu fetch fails 1514 const topbar = document.getElementById('polycms-topbar'); 1515 if (topbar) { 1516 topbar.style.display = 'block'; 1517 document.body.classList.add('polycms-topbar-active'); 1518 1519 if (typeof window.loadFrontendCacheStatus === 'function') { 1520 window.loadFrontendCacheStatus(); 1521 } 1522 } 1523 }); 1524 } 1525 }) 1526 .catch(error => { 1527 // User not authenticated, keep topbar hidden 1528 console.debug('Topbar: User not authenticated'); 1529 // Ensure class is removed when user is not authenticated 1530 document.body.classList.remove('polycms-topbar-active'); 1531 }); 1532 } 1533 1534 // Check after DOM is ready 1535 if (document.readyState === 'loading') { 1536 document.addEventListener('DOMContentLoaded', checkAuthAndShowTopbar); 1537 } else { 1538 checkAuthAndShowTopbar(); 1539 } 1540 1541 function renderMenuItems(items, leftMenu, rightMenu) { 1542 if (!leftMenu || !rightMenu) return; 1543 1544 // Clear existing items 1545 leftMenu.innerHTML = ''; 1546 1547 // PRESERVE Right Menu elements when clearing Right Menu 1548 const themeToggle = document.getElementById('topbar-theme-toggle'); 1549 const langToggle = document.getElementById('topbar-language-dropdown'); 1550 const currToggle = document.getElementById('topbar-currency-dropdown'); 1551 const cacheToggle = document.getElementById('topbar-cache-dropdown'); 1552 1553 rightMenu.innerHTML = ''; 1554 1555 // Group items by left/right 1556 const leftItems = []; 1557 const rightItems = []; 1558
1559 items.forEach(item => { 1560 const group = item.group || 'left'; 1561 if (group === 'right') { 1562 rightItems.push(item); 1563 } else { 1564 leftItems.push(item); 1565 } 1566 }); 1567 1568 // Sort by priority 1569 leftItems.sort((a, b) => (a.priority || 10) - (b.priority || 10)); 1570 rightItems.sort((a, b) => (a.priority || 10) - (b.priority || 10)); 1571 1572 // Render left items 1573 leftItems.forEach(item => { 1574 const element = createMenuItemElement(item); 1575 if (element) leftMenu.appendChild(element); 1576 }); 1577 1578 // Render right items 1579 rightItems.forEach(item => { 1580 const element = createMenuItemElement(item); 1581 if (element) { 1582 rightMenu.appendChild(element); 1583 } 1584 }); 1585 1586 // Re-append preserved items at the end of right menu 1587 if (langToggle) rightMenu.appendChild(langToggle); 1588 if (currToggle) rightMenu.appendChild(currToggle); 1589 if (cacheToggle) rightMenu.appendChild(cacheToggle); 1590 if (themeToggle) rightMenu.appendChild(themeToggle); 1591 } 1592 1593 // Touch & Click handler for mobile / tablet dropdowns 1594 window.handleTopbarDropdownClick = function(event, element) { 1595 const dropdown = element.closest('.topbar-dropdown'); 1596 if (!dropdown) return; 1597 1598 // Check if touch device or mobile/tablet screen width 1599 const isTouchOrMobile = ('ontouchstart' in window) || (window.innerWidth < 1024) || (window.matchMedia && window.matchMedia('(hover: none)').matches); 1600 1601 if (isTouchOrMobile) { 1602 event.preventDefault(); 1603 event.stopPropagation(); 1604 1605 const wasOpen = dropdown.classList.contains('touch-open'); 1606 1607 // Close other top-level dropdowns and switcher panels
1608 document.querySelectorAll('.polycms-topbar .topbar-dropdown.touch-open').forEach(dd => { 1609 if (dd !== dropdown && !dd.contains(dropdown) && !dropdown.contains(dd)) { 1610 dd.classList.remove('touch-open'); 1611 } 1612 }); 1613 1614 document.querySelectorAll('.topbar-switcher-panel').forEach(panel => { 1615 panel.style.display = 'none'; 1616 }); 1617 1618 if (!wasOpen) { 1619 dropdown.classList.add('touch-open'); 1620 if (typeof window.checkTopbarMenuAlignment === 'function') { 1621 window.checkTopbarMenuAlignment(dropdown); 1622 } 1623 } else { 1624 dropdown.classList.remove('touch-open'); 1625 } 1626 } 1627 }; 1628 1629 // Close dropdowns on outside tap/click 1630 document.addEventListener('click', function(e) { 1631 if (!e.target.closest('.topbar-dropdown') && !e.target.closest('.topbar-switcher-dropdown')) {
1632 document.querySelectorAll('.polycms-topbar .topbar-dropdown.touch-open').forEach(dd => { 1633 dd.classList.remove('touch-open'); 1634 }); 1635 } 1636 }); 1637 1638 // Alignment check function for zig-zag (snake) logic 1639 window.checkTopbarMenuAlignment = function(dropdown) { 1640 const dropdownContent = dropdown.querySelector('.topbar-dropdown-content'); 1641 if (!dropdownContent) return; 1642 1643 // Reset alignment classes 1644 dropdown.classList.remove('align-right', 'align-below'); 1645 1646 // Wait for display: flex to apply via CSS :hover to measure 1647 requestAnimationFrame(() => { 1648 const rect = dropdownContent.getBoundingClientRect(); 1649 const winWidth = window.innerWidth; 1650 const winHeight = window.innerHeight; 1651 1652 const initialMomentum = dropdown.getAttribute('data-momentum') || 'right'; 1653 let horizontal = ''; 1654 let vertical = ''; 1655 let currentMomentum = initialMomentum; 1656 1657 // Collision detection 1658 if (initialMomentum === 'right' && rect.right > (winWidth - 20)) { 1659 currentMomentum = 'left'; 1660 horizontal = 'align-right'; 1661 } else if (initialMomentum === 'left' && rect.left < 20) { 1662 currentMomentum = 'right'; 1663 horizontal = ''; 1664 } else if (initialMomentum === 'left') { 1665 horizontal = 'align-right'; 1666 } 1667 1668 // If momentum flipped, align below 1669 if (initialMomentum !== currentMomentum || rect.bottom > winHeight) { 1670 vertical = 'align-below'; 1671 } 1672 1673 if (horizontal) dropdown.classList.add(horizontal); 1674 if (vertical) dropdown.classList.add(vertical); 1675 1676 // Pass momentum to children 1677 dropdownContent.querySelectorAll('.topbar-dropdown').forEach(child => { 1678 child.setAttribute('data-momentum', currentMomentum); 1679 // Also trigger the alignment for children recursively if they are already visible 1680 if (window.getComputedStyle(child).display !== 'none') { 1681 window.checkTopbarMenuAlignment(child); 1682 } 1683 }); 1684 }); 1685 }; 1686 1687 // Function to create menu item element 1688 function createMenuItemElement(item) { 1689 const hasChildren = item.children && item.children.length > 0; 1690 const isHighlight = item.highlight || false; 1691 const icon = item.icon || null; 1692 const label = item.label || ''; 1693 const url = item.url || '#'; 1694 const method = item.method || 'GET'; 1695 1696 if (hasChildren) { 1697 // Create dropdown 1698 const dropdown = document.createElement('div'); 1699 dropdown.id = item.id || ''; 1700 dropdown.className = 'topbar-dropdown' + (item.depth > 0 ? ' submenu' : '') + ' momentum-right'; 1701 dropdown.setAttribute('data-momentum', 'right'); 1702 dropdown.onmouseenter = function() { window.checkTopbarMenuAlignment(this); }; 1703 1704 const link = document.createElement('a'); 1705 link.href = url; 1706 link.className = (isHighlight ? 'topbar-highlight ' : '') + 'has-arrow'; 1707 link.onclick = function(e) { 1708 window.handleTopbarDropdownClick(e, this); 1709 }; 1710 1711 if (icon) { 1712 const iconSpan = document.createElement('span'); 1713 iconSpan.className = 'topbar-icon'; 1714 iconSpan.innerHTML = getIconSvg(icon); 1715 link.appendChild(iconSpan); 1716 } 1717 1718 const labelSpan = document.createElement('span'); 1719 labelSpan.textContent = label; 1720 link.appendChild(labelSpan); 1721 1722 // Add arrow for submenu parents 1723 if (item.depth > 0) { 1724 link.classList.add('topbar-dropdown-item'); 1725 1726 const arrowSvg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); 1727 arrowSvg.setAttribute('class', 'submenu-arrow'); 1728 arrowSvg.setAttribute('fill', 'none'); 1729 arrowSvg.setAttribute('stroke', 'currentColor'); 1730 arrowSvg.setAttribute('viewBox', '0 0 24 24'); 1731 1732 const arrowPath = document.createElementNS('http://www.w3.org/2000/svg', 'path'); 1733 arrowPath.setAttribute('stroke-linecap', 'round'); 1734 arrowPath.setAttribute('stroke-linejoin', 'round'); 1735 arrowPath.setAttribute('stroke-width', '2'); 1736 arrowPath.setAttribute('d', 'M9 5l7 7-7 7'); 1737 1738 arrowSvg.appendChild(arrowPath); 1739 link.appendChild(arrowSvg); 1740 } 1741 1742 const dropdownContent = document.createElement('div'); 1743 dropdownContent.className = 'topbar-dropdown-content'; 1744
1745 item.children.forEach(child => { 1746 // Inject depth for recursion 1747 child.depth = (item.depth || 0) + 1; 1748 const childElement = createMenuItemElement(child); 1749 if (childElement) dropdownContent.appendChild(childElement); 1750 }); 1751 1752 dropdown.appendChild(link); 1753 dropdown.appendChild(dropdownContent); 1754 1755 return dropdown; 1756 } else { 1757 // Create simple link or form 1758 if (method === 'POST') { 1759 const form = document.createElement('form'); 1760 form.className = item.depth > 0 ? 'topbar-dropdown-form' : 'topbar-form'; 1761 form.action = url; 1762 form.method = 'POST'; 1763 1764 const csrfInput = document.createElement('input'); 1765 csrfInput.type = 'hidden'; 1766 csrfInput.name = '_token'; 1767 csrfInput.value = getCsrfToken(); 1768 form.appendChild(csrfInput); 1769 1770 const button = document.createElement('button'); 1771 button.type = 'submit'; 1772 button.id = item.id || ''; 1773 button.className = (item.depth > 0 ? 'topbar-dropdown-item' : 'topbar-button') + (isHighlight ? ' topbar-highlight' : ''); 1774 1775 if (item.id === 'logout') { 1776 button.onclick = handleTopbarLogout; 1777 } 1778 1779 if (icon) { 1780 const iconSpan = document.createElement('span'); 1781 iconSpan.className = 'topbar-icon'; 1782 iconSpan.innerHTML = getIconSvg(icon); 1783 button.appendChild(iconSpan); 1784 } 1785 1786 const labelSpan = document.createElement('span'); 1787 labelSpan.textContent = label; 1788 button.appendChild(labelSpan); 1789 1790 form.appendChild(button); 1791 return form; 1792 } else { 1793 const link = document.createElement('a'); 1794 link.id = item.id || ''; 1795 link.href = url; 1796 link.className = (item.depth > 0 ? 'topbar-dropdown-item' : '') + (isHighlight ? ' topbar-highlight' : ''); 1797 1798 if (icon) { 1799 const iconSpan = document.createElement('span'); 1800 iconSpan.className = 'topbar-icon'; 1801 iconSpan.innerHTML = getIconSvg(icon); 1802 link.appendChild(iconSpan); 1803 } 1804 1805 const labelSpan = document.createElement('span'); 1806 labelSpan.textContent = label; 1807 link.appendChild(labelSpan); 1808 1809 return link; 1810 } 1811 } 1812 } 1813 1814 // Function to get CSRF token from meta tag or cookie 1815 function getCsrfToken() { 1816 const metaTag = document.querySelector('meta[name="csrf-token"]'); 1817 if (metaTag) return metaTag.getAttribute('content'); 1818 1819 // Try to get from cookie 1820 const cookies = document.cookie.split(';'); 1821 for (let cookie of cookies) { 1822 const [name, value] = cookie.trim().split('='); 1823 if (name === 'XSRF-TOKEN') { 1824 return decodeURIComponent(value); 1825 } 1826 } 1827 1828 return ''; 1829 } 1830 1831 // Function to get icon SVG using sprite <use> reference 1832 function getIconSvg(iconName) { 1833 if (!iconName) return ''; 1834 1835 // Handle raw SVG path if name looks like one (M...) 1836 if (iconName.startsWith('M') && iconName.includes(' ')) { 1837 return `<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="${iconName}" /></svg>`; 1838 } 1839 1840 // Resolve alias if exists 1841 let resolved = iconAliases[iconName] || iconName; 1842 1843 // Ensure icon name ends with 'Icon' suffix and starts with Uppercase (for sprite) 1844 if (!resolved.endsWith('Icon')) { 1845 resolved = resolved.charAt(0).toUpperCase() + resolved.slice(1) + 'Icon'; 1846 } else { 1847 // Already ends with Icon, but ensure first letter is capitalized for safety 1848 resolved = resolved.charAt(0).toUpperCase() + resolved.slice(1); 1849 } 1850 1851 return `<svg width="16" height="16"><use href="/icons/heroicons.svg#${resolved}"/></svg>`; 1852 } 1853 1854 // Function to handle logout from topbar (Frontend/Web session only) 1855 window.handleTopbarLogout = function(event) { 1856 event.preventDefault(); 1857 1858 // 1. Clear API token from localStorage (Admin SPA session) 1859 try { 1860 localStorage.removeItem('auth_token'); 1861 } catch (e) { 1862 // Ignore storage errors 1863 } 1864 1865 const form = event.target.closest('form'); 1866 if (form) { 1867 // 2. Refresh the CSRF token in the form from the meta tag 1868 const freshToken = getCsrfToken(); 1869 const tokenInput = form.querySelector('input[name="_token"]'); 1870 if (tokenInput && freshToken) { 1871 tokenInput.value = freshToken; 1872 } 1873 1874 // 3. Submit the form natively (avoids fetch/AJAX 419 issues) 1875 form.submit(); 1876 return; 1877 } 1878 1879 // Fallback: if no form found, redirect to logout URL directly 1880 window.location.href = '/logout'; 1881 }; 1882 1883 // Theme toggle logic 1884 window.handleThemeToggle = function() { 1885 const currentMode = localStorage.getItem('theme_mode') || 'system'; 1886 let newMode = 'light'; 1887 1888 if (currentMode === 'light') { 1889 newMode = 'dark'; 1890 } else if (currentMode === 'dark') { 1891 newMode = 'light'; 1892 } else { 1893 // System mode - check current preference and toggle 1894 const isSystemDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches; 1895 newMode = isSystemDark ? 'light' : 'dark'; 1896 } 1897 1898 localStorage.setItem('theme_mode', newMode); 1899 localStorage.setItem('color-theme', newMode); 1900 updateThemeUI(); 1901 }; 1902 1903 function updateThemeUI() { 1904 const mode = localStorage.getItem('theme_mode'); 1905 let isDark = false;
1906 1907 if (mode) { 1908 if (mode === 'system') { 1909 isDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches; 1910 } else { 1911 isDark = mode === 'dark'; 1912 } 1913 1914 if (isDark) { 1915 document.documentElement.classList.add('dark'); 1916 } else { 1917 document.documentElement.classList.remove('dark'); 1918 } 1919 } else { 1920 // If no theme_mode is set, respect the theme's initial HTML class 1921 isDark = document.documentElement.classList.contains('dark'); 1922 } 1923 1924 const lightIcon = document.getElementById('theme-toggle-light-icon'); 1925 const darkIcon = document.getElementById('theme-toggle-dark-icon'); 1926 1927 if (isDark) { 1928 if (lightIcon) lightIcon.style.display = 'inline-flex'; 1929 if (darkIcon) darkIcon.style.display = 'none'; 1930 } else { 1931 if (lightIcon) lightIcon.style.display = 'none'; 1932 if (darkIcon) darkIcon.style.display = 'inline-flex'; 1933 } 1934 } 1935 1936 // Initialize theme UI 1937 updateThemeUI(); 1938 1939 // Global helper: fixed top offset (wpadminbar + PolyCMS topbar + main header) 1940 window.PolyCMS = window.PolyCMS || {}; 1941 1942 function getFixedElementHeight(element) { 1943 if (!element) return 0; 1944 const style = window.getComputedStyle(element); 1945 if (style.display === 'none' || style.visibility === 'hidden') return 0; 1946 if (style.position !== 'fixed' && style.position !== 'sticky') return 0; 1947 return element.getBoundingClientRect().height || element.offsetHeight || 0; 1948 } 1949 1950 function computeFixedTopOffset(extraOffset = 0) { 1951 const wpAdminBar = document.getElementById('wpadminbar'); 1952 const polycmsTopbar = document.getElementById('polycms-topbar'); 1953 const mainHeader = document.getElementById('main-header'); 1954 const extra = Number(extraOffset) || 0; 1955 1956 return Math.max( 1957 0, 1958 Math.round( 1959 getFixedElementHeight(wpAdminBar) + 1960 getFixedElementHeight(polycmsTopbar) + 1961 getFixedElementHeight(mainHeader) + 1962 extra 1963 ) 1964 ); 1965 } 1966 1967 window.PolyCMS.getFixedTopOffset = function(extraOffset = 0) { 1968 return computeFixedTopOffset(extraOffset); 1969 }; 1970 1971 window.PolyCMS.refreshFixedTopOffset = function(extraOffset = 0) { 1972 const offset = computeFixedTopOffset(extraOffset); 1973 document.documentElement.style.setProperty('--polycms-fixed-top-offset', `${offset}px`); 1974 return offset; 1975 }; 1976 1977 let fixedTopOffsetSyncing = false; 1978 function syncFixedTopOffset() { 1979 if (fixedTopOffsetSyncing) return; 1980 fixedTopOffsetSyncing = true; 1981 window.requestAnimationFrame(() => { 1982 window.PolyCMS.refreshFixedTopOffset(); 1983 fixedTopOffsetSyncing = false; 1984 }); 1985 } 1986 1987 window.addEventListener('resize', syncFixedTopOffset, { passive: true }); 1988 window.addEventListener('scroll', syncFixedTopOffset, { passive: true }); 1989 window.PolyCMS.refreshFixedTopOffset(); 1990 1991 // Function to adjust sticky headers when topbar is active 1992 function adjustStickyHeaders() { 1993 const topbarHeight = 32; // Topbar height in pixels 1994 const headers = document.querySelectorAll('.header, .main-header, header[id="main-header"], header.main-header'); 1995 1996 headers.forEach(header => { 1997 const computedStyle = window.getComputedStyle(header); 1998 if (computedStyle.position === 'sticky' || computedStyle.position === 'fixed') { 1999 // Check if top is currently 0 2000 const currentTop = parseInt(computedStyle.top) || 0; 2001 if (currentTop === 0) { 2002 header.style.top = topbarHeight + 'px'; 2003 } 2004 } 2005 }); 2006 } 2007 2008 // Also adjust when topbar is already visible on page load 2009 // Only add class if topbar is actually visible (not display: none) 2010 const topbarOnLoad = document.getElementById('polycms-topbar'); 2011 if (topbarOnLoad) { 2012 const isVisible = window.getComputedStyle(topbarOnLoad).display !== 'none'; 2013 if (isVisible) { 2014 document.body.classList.add('polycms-topbar-active'); 2015 setTimeout(adjustStickyHeaders, 100); 2016 setTimeout(syncFixedTopOffset, 120); 2017 } else { 2018 // Ensure class is removed if topbar is hidden on page load 2019 document.body.classList.remove('polycms-topbar-active'); 2020 syncFixedTopOffset(); 2021 } 2022 } else { 2023 // Ensure class is removed if topbar doesn't exist 2024 document.body.classList.remove('polycms-topbar-active'); 2025 syncFixedTopOffset(); 2026 } 2027 2028 // Watch for topbar visibility changes 2029 const topbarObserver = new MutationObserver(function(mutations) { 2030 mutations.forEach(function(mutation) { 2031 if (mutation.type === 'attributes' && mutation.attributeName === 'style') { 2032 const topbar = document.getElementById('polycms-topbar'); 2033 if (topbar) { 2034 const isVisible = window.getComputedStyle(topbar).display !== 'none'; 2035 if (isVisible) { 2036 document.body.classList.add('polycms-topbar-active'); 2037 adjustStickyHeaders(); 2038 syncFixedTopOffset(); 2039 } else { 2040 document.body.classList.remove('polycms-topbar-active'); 2041 // Reset headers 2042 const headers = document.querySelectorAll('.header, .main-header, header[id="main-header"], header.main-header');
2043 headers.forEach(header => { 2044 const computedStyle = window.getComputedStyle(header); 2045 if (computedStyle.position === 'sticky' || computedStyle.position === 'fixed') { 2046 if (header.style.top === '32px') { 2047 header.style.top = '0px'; 2048 } 2049 } 2050 }); 2051 syncFixedTopOffset(); 2052 } 2053 } 2054 } 2055 }); 2056 }); 2057 2058 const topbar = document.getElementById('polycms-topbar'); 2059 if (topbar) { 2060 topbarObserver.observe(topbar, { 2061 attributes: true, 2062 attributeFilter: ['style'] 2063 }); 2064 } 2065 2066 // Fix for Inertia SPA navigation losing topbar events 2067 // Re-ensure the topbar has correct interactivity state after navigation 2068 if (typeof document !== 'undefined') { 2069 document.addEventListener('inertia:navigate', function() { 2070 const tb = document.getElementById('polycms-topbar'); 2071 if (tb) { 2072 tb.style.pointerEvents = 'auto'; 2073 tb.style.zIndex = '100000'; 2074 } 2075 2076 // Clear any inline display styles from hover menus to restore CSS :hover 2077 document.querySelectorAll('.topbar-dropdown-content').forEach(d => { 2078 d.style.display = ''; 2079 }); 2080 2081 // Explicitly hide click-based panels upon navigation 2082 document.querySelectorAll('.topbar-switcher-panel').forEach(d => { 2083 d.style.display = 'none'; 2084 }); 2085 2086 syncFixedTopOffset(); 2087 }); 2088 2089 document.addEventListener('inertia:success', function() { 2090 checkAuthAndShowTopbar(); 2091 syncFixedTopOffset(); 2092 if (typeof window.loadFrontendCacheStatus === 'function') { 2093 window.loadFrontendCacheStatus(); 2094 } 2095 }); 2096 } 2097 2098 })(); 2099</script>
2099 2100 2101 <div id="app" style="min-height: 100vh; display: flex; flex-direction: column;"> 2102 2103 <header class="header"> 2104 <div class="container header-inner"> 2105 <!-- Site Branding --> 2106 <div> 2107 <a href="https://headrandom.com" class="logo"> 2108 HeadRandom 2109 </a> 2110 </div> 2111 2112 <!-- Desktop Navigation --> 2113 <nav class="nav-links align-right"> 2114 <div class="nav-item"> 2115 <a href="https://headrandom.com/" class="nav-link" 2116 > 2117 <span class="nav-link-label"> 2118 Home 2119 </span> 2120 </a> 2121 </div> 2122 <div class="nav-item has-dropdown"> 2123 <a href="https://headrandom.com/products" class="nav-link active has-children-link" 2124 > 2125 <span class="nav-link-label"> 2126 Products 2127 </span> 2128 <svg class="submenu-icon" xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m6 9 6 6 6-6"/></svg> 2129 </a> 2130 <ul class="nav-dropdown"> 2131 <div class="nav-item"> 2132 <a href="/product-categories/modules-for-perfex-crm" class="nav-link" 2133 > 2134 <span class="nav-link-label"> 2135 Modules for Perfex CRM 2136 </span> 2137 </a> 2138 </div> 2139 <div class="nav-item"> 2140 <a href="/product-categories/wordpress" class="nav-link" 2141 > 2142 <span class="nav-link-label"> 2143 Plugins for WordPress 2144 </span> 2145 </a> 2146 </div> 2147 <div class="nav-item"> 2148 <a href="/product-categories/desktop-apps" class="nav-link" 2149 > 2150 <span class="nav-link-label"> 2151 Desktop Apps 2152 </span> 2153 </a> 2154 </div> 2155 <div class="nav-item"> 2156 <a href="/product-categories/polycms" class="nav-link" 2157 > 2158 <span class="nav-link-label"> 2159 PolyCMS 2160 </span> 2161 </a> 2162 </div> 2163 </ul> 2164 </div> 2165 <div class="nav-item"> 2166 <a href="/coupons-promotions" class="nav-link" 2167 > 2168 <span class="nav-link-label"> 2169 Special Deals 2170 </span> 2171 </a> 2172 </div> 2173 <div class="nav-item"> 2174 <a href="https://headrandom.com/blog" class="nav-link" 2175 > 2176 <span class="nav-link-label"> 2177 Blog 2178 </span> 2179 </a> 2180 </div> 2181 <div class="nav-item has-dropdown"> 2182 <a href="/documentation" class="nav-link has-children-link" 2183 > 2184 <span class="nav-link-label"> 2185 Documentation 2186 </span> 2187 <svg class="submenu-icon" xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m6 9 6 6 6-6"/></svg> 2188 </a> 2189 <ul class="nav-dropdown"> 2190 <div class="nav-item has-dropdown"> 2191 <a href="/modules-for-perfex-crm" class="nav-link has-children-link" 2192 > 2193 <span class="nav-link-label"> 2194 Modules for Perfex CRM 2195 </span> 2196 <svg class="submenu-icon" xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m9 18 6-6-6-6"/></svg> 2197 </a> 2198 <ul class="nav-dropdown"> 2199 <div class="nav-item"> 2200 <a href="/cms-for-perfex-crm" class="nav-link" 2201 >
2202 <span class="nav-link-label"> 2203 CMS for Perfex CRM 2204 </span> 2205 </a> 2206 </div> 2207 <div class="nav-item"> 2208 <a href="/data-builder-for-perfex-crm" class="nav-link" 2209 > 2210 <span class="nav-link-label"> 2211 Data Builder for Perfex CRM 2212 </span> 2213 </a> 2214 </div> 2215 <div class="nav-item"> 2216 <a href="/polyutilities-for-perfex-crm" class="nav-link" 2217 > 2218 <span class="nav-link-label"> 2219 PolyUtilities for Perfex CRM 2220 </span> 2221 </a> 2222 </div> 2223 <div class="nav-item"> 2224 <a href="/woocommerce-for-perfex-crm" class="nav-link" 2225 > 2226 <span class="nav-link-label"> 2227 WooCommerce for Perfex CRM 2228 </span> 2229 </a> 2230 </div> 2231 <div class="nav-item"> 2232 <a href="/flexinote-for-perfex-crm" class="nav-link" 2233 > 2234 <span class="nav-link-label"> 2235 FlexiNote for Perfex CRM 2236 </span> 2237 </a> 2238 </div> 2239 </ul> 2240 </div> 2241 <div class="nav-item"> 2242 <a href="/ideas-solutions" class="nav-link" 2243 > 2244 <span class="nav-link-label"> 2245 Ideas & Solutions 2246 </span> 2247 </a> 2248 </div> 2249 <div class="nav-item"> 2250 <a href="/stability-strategy" class="nav-link" 2251 > 2252 <span class="nav-link-label"> 2253 Stability & Strategy 2254 </span> 2255 </a> 2256 </div> 2257 <div class="nav-item"> 2258 <a href="/productivity-and-business-workflow" class="nav-link" 2259 > 2260 <span class="nav-link-label"> 2261 Productivity & Business Workflow 2262 </span> 2263 </a> 2264 </div> 2265 <div class="nav-item"> 2266 <a href="/plugins-for-rise-crm" class="nav-link" 2267 > 2268 <span class="nav-link-label"> 2269 Plugins for RISE CRM 2270 </span> 2271 </a> 2272 </div> 2273 <div class="nav-item"> 2274 <a href="/plugins-for-wordpress" class="nav-link" 2275 > 2276 <span class="nav-link-label"> 2277 Plugins for WordPress 2278 </span> 2279 </a> 2280 </div> 2281 </ul> 2282 </div> 2283 <style> 2284 .nav-item-search { display: flex !important; align-items: center !important; } 2285 .nav-item-search .widget { margin: 0 !important; padding: 0 !important; background: transparent !important; border: none !important; box-shadow: none !important; } 2286 .nav-item-search .widget-blog-search { display: flex !important; align-items: center !important; } 2287 .nav-item-search .widget-title { display: none !important; } 2288 </style> 2289 <div class="nav-item nav-item-search"> 2290 <style>#widget-search-0 .widget-search-trigger { border-width: 0px !important; border-style: none !important; } </style><div id="widget-search-0" class="widget widget-blog-search widget-blog-search--icon_modal" data-search-widget data-search-style="icon_modal" data-search-locale="en" data-suggestions-enabled="1" data-suggestions-url="https://headrandom.com/api/v1/search/suggestions" data-suggestion-scope="all" data-suggestion-limit="5"><button type="button" class="widget-search-trigger" data-search-open aria-label="Search"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="11" cy="11" r="8"></circle><path d="m21 21-4.35-4.35"></path></svg></button><div class="widget-search-modal" data-search-modal hidden><div class="widget-search-modal__backdrop" aria-hidden="true"></div><div class="widget-search-modal__panel" role="dialog" aria-modal="true" aria-labelledby="widget-search-0-title"><div class="widget-search-modal__header"><h3 id="widget-search-0-title">Search</h3><button type="button" class="widget-search-modal__close" data-search-close aria-label="Close">Ã</button></div><form action="https://headrandom.com/blog" method="get" class="widget-search-form widget-search-form--modal" data-widget-search-form><label class="sr-only" for="widget-search-0">Search</label><input id="widget-search-0" type="text" inputmode="search" enterkeyhint="search" name="search" autocomplete="off" spellcheck="false" placeholder="Search..." data-search-input /><button type="submit" class="widget-search-icon-submit" aria-label="Search"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="11" cy="11" r="8"></circle><path d="m21 21-4.35-4.35"></path></svg></button><div class="widget-search-suggestions" data-search-suggestions hidden></div></form></div></div></div><style> 2291body.polycms-search-widget-open { overflow: hidden; } 2292 2293.widget-blog-search { 2294 position: relative; 2295} 2296 2297.widget-blog-search--icon_modal, 2298.widget-blog-search--icon_expand, 2299.widget-blog-search--icon_inline, 2300.widget-blog-search--pill, 2301.widget-blog-search--minimal { 2302 display: inline-flex; 2303 align-items: center; 2304} 2305 2306.widget-search-trigger, 2307.widget-search-icon-submit { 2308 display: inline-flex; 2309 align-items: center; 2310 justify-content: center; 2311 width: 2.25rem; 2312 height: 2.25rem; 2313 border-radius: 9999px;
2314 border: 1px solid rgba(148, 163, 184, 0.28); 2315 background: #f8fafc; 2316 color: #475569; 2317 cursor: pointer; 2318 box-shadow: none; 2319 transition: all 0.2s ease; 2320 line-height: 0; 2321} 2322 2323.widget-search-trigger--icon { 2324 width: auto; 2325 height: auto; 2326 padding: 0.35rem; 2327 border: 0; 2328 background: transparent; 2329 color: inherit; 2330 box-shadow: none; 2331} 2332 2333.widget-search-trigger--icon:hover { 2334 background: transparent; 2335 border-color: transparent; 2336 color: #2563eb; 2337} 2338 2339html.dark .widget-search-trigger--icon, 2340.dark .widget-search-trigger--icon { 2341 background: transparent; 2342 border: 0; 2343 color: #cbd5e1; 2344} 2345 2346html.dark .widget-search-trigger--icon:hover, 2347.dark .widget-search-trigger--icon:hover { 2348 background: transparent; 2349 border-color: transparent; 2350 color: #eff6ff; 2351} 2352 2353.widget-search-trigger:not(.widget-search-trigger--icon):hover, 2354.widget-search-icon-submit:hover { 2355 background: #eef2ff; 2356 border-color: rgba(59, 130, 246, 0.35); 2357 color: #2563eb; 2358} 2359 2360html.dark .widget-search-trigger, 2361html.dark .widget-search-icon-submit, 2362.dark .widget-search-trigger, 2363.dark .widget-search-icon-submit { 2364 background: #1e293b; 2365 border-color: rgba(51, 65, 85, 0.9); 2366 color: #cbd5e1; 2367} 2368 2369html.dark .widget-search-trigger:not(.widget-search-trigger--icon):hover, 2370html.dark .widget-search-icon-submit:hover, 2371.dark .widget-search-trigger:not(.widget-search-trigger--icon):hover, 2372.dark .widget-search-icon-submit:hover { 2373 background: #334155; 2374 border-color: rgba(96, 165, 250, 0.45); 2375 color: #eff6ff; 2376} 2377 2378.widget-search-trigger svg, 2379.widget-search-icon-submit svg { 2380 width: 1rem; 2381 height: 1rem; 2382} 2383 2384.widget-search-modal[hidden], 2385.widget-search-expand__panel[hidden], 2386.widget-search-suggestions[hidden] { 2387 display: none !important; 2388} 2389 2390.widget-search-modal { 2391 position: fixed; 2392 inset: 0; 2393 z-index: 120; 2394 display: flex; 2395 align-items: flex-start; 2396 justify-content: center; 2397 padding: 12vh 1rem 1rem; 2398} 2399 2400.widget-search-modal__backdrop { 2401 position: absolute; 2402 inset: 0; 2403 background: rgba(15, 23, 42, 0.45); 2404 backdrop-filter: blur(6px); 2405} 2406 2407.widget-search-modal__panel { 2408 position: relative; 2409 width: min(42rem, 100%); 2410 border: 1px solid rgba(148, 163, 184, 0.22); 2411 border-radius: 1rem; 2412 background: #ffffff; 2413 color: #0f172a; 2414 box-shadow: 0 24px 80px rgba(15, 23, 42, 0.18); 2415 padding: 1.25rem; 2416} 2417 2418html.dark .widget-search-modal__panel, 2419.dark .widget-search-modal__panel { 2420 background: #0f172a; 2421 color: #e2e8f0; 2422 border-color: rgba(51, 65, 85, 0.95); 2423} 2424 2425.widget-search-modal__header { 2426 display: flex; 2427 align-items: center; 2428 justify-content: space-between; 2429 gap: 1rem; 2430 margin-bottom: 1rem; 2431} 2432 2433.widget-search-modal__header h3 { 2434 margin: 0; 2435 font-size: 1.05rem; 2436 font-weight: 700; 2437} 2438 2439.widget-search-modal__close { 2440 display: inline-flex; 2441 align-items: center; 2442 justify-content: center; 2443 width: 2rem; 2444 height: 2rem; 2445 border-radius: 9999px; 2446 border: 1px solid rgba(148, 163, 184, 0.35); 2447 background: #f8fafc; 2448 color: #475569; 2449 cursor: pointer; 2450 line-height: 0; 2451} 2452 2453html.dark .widget-search-modal__close, 2454.dark .widget-search-modal__close { 2455 background: #1e293b; 2456 color: #cbd5e1; 2457 border-color: rgba(51, 65, 85, 0.9); 2458} 2459 2460html.dark .widget-blog-search .widget-search-form--modal .widget-search-icon-submit, 2461.dark .widget-blog-search .widget-search-form--modal .widget-search-icon-submit { 2462 background: #1e293b !important; 2463 color: #cbd5e1 !important; 2464 border-color: rgba(51, 65, 85, 0.9) !important; 2465} 2466 2467.widget-search-form { 2468 position: relative; 2469} 2470 2471.widget-search-form--default { 2472 display: flex; 2473 margin-top: 0.5rem; 2474} 2475 2476.widget-search-form--modal, 2477.widget-search-form--expand, 2478.widget-search-form--icon_inline, 2479.widget-search-form--pill, 2480.widget-search-form--minimal { 2481 display: flex; 2482 align-items: center; 2483 gap: 0.5rem; 2484 margin: 0; 2485} 2486 2487.widget-search-form input[type="search"], 2488.widget-search-form input[type="text"] { 2489 flex: 1; 2490 width: 100%; 2491 border: 0; 2492 outline: 0; 2493 box-shadow: none; 2494 background: transparent; 2495 color: inherit; 2496 font: inherit; 2497 min-width: 0; 2498} 2499 2500.widget-search-form--default input[type="search"], 2501.widget-search-form--default input[type="text"] {
2502 border: 1px solid rgba(148, 163, 184, 0.28); 2503 border-right: none; 2504 border-radius: 0.75rem 0 0 0.75rem; 2505 background: #ffffff; 2506 padding: 0.625rem 1rem; 2507} 2508 2509.widget-search-form--modal { 2510 padding: 0.25rem 0.4rem 0.25rem 0.85rem; 2511 border: 1px solid rgba(148, 163, 184, 0.28); 2512 border-radius: 9999px; 2513 background: #ffffff; 2514} 2515 2516html.dark .widget-search-form--modal, 2517html.dark .widget-search-form--expand, 2518html.dark .widget-search-form--icon_inline, 2519html.dark .widget-search-form--pill, 2520.dark .widget-search-form--modal, 2521.dark .widget-search-form--expand, 2522.dark .widget-search-form--icon_inline, 2523.dark .widget-search-form--pill { 2524 background: #111827; 2525 border-color: rgba(51, 65, 85, 0.9); 2526 color: #e2e8f0; 2527 box-shadow: 0 18px 50px rgba(0, 0, 0, 0.35); 2528} 2529 2530html.dark .widget-search-form input::placeholder, 2531.dark .widget-search-form input::placeholder { 2532 color: #94a3b8; 2533} 2534 2535.widget-blog-search .widget-search-form--modal .widget-search-icon-submit, 2536.widget-blog-search .widget-search-form--expand .widget-search-icon-submit, 2537.widget-blog-search .widget-search-form--icon_inline .widget-search-icon-submit, 2538.widget-blog-search .widget-search-form--pill .widget-search-icon-submit { 2539 flex: 0 0 auto; 2540 margin-left: auto; 2541 padding: 0 !important; 2542 width: 2.25rem !important; 2543 height: 2.25rem !important; 2544 min-width: 2.25rem !important; 2545 min-height: 2.25rem !important; 2546 line-height: 0 !important; 2547 appearance: none !important; 2548 -webkit-appearance: none !important; 2549} 2550 2551.widget-blog-search .widget-search-form--modal .widget-search-icon-submit { 2552 background: #f8fafc !important; 2553 color: #475569 !important; 2554 border: 1px solid rgba(148, 163, 184, 0.35) !important; 2555} 2556 2557.widget-blog-search .widget-search-form--expand .widget-search-icon-submit, 2558.widget-blog-search .widget-search-form--icon_inline .widget-search-icon-submit, 2559.widget-blog-search .widget-search-form--pill .widget-search-icon-submit { 2560 background: transparent !important; 2561 color: inherit !important; 2562 border: 0 !important; 2563 box-shadow: none !important; 2564} 2565 2566.widget-search-form--expand { 2567 position: relative; 2568 padding: 0.25rem 0.4rem 0.25rem 0.85rem; 2569 border: 1px solid rgba(148, 163, 184, 0.28); 2570 border-radius: 9999px; 2571 background: #ffffff; 2572} 2573 2574.widget-search-form--expand input[type="search"], 2575.widget-search-form--expand input[type="text"], 2576.widget-search-form--icon_inline input[type="search"], 2577.widget-search-form--icon_inline input[type="text"], 2578.widget-search-form--pill input[type="search"], 2579.widget-search-form--pill input[type="text"], 2580.widget-search-form--minimal input[type="search"], 2581.widget-search-form--minimal input[type="text"] { 2582 padding: 0.5rem 0.25rem; 2583 min-width: 11rem; 2584} 2585 2586.widget-search-form--icon_inline, 2587.widget-search-form--pill, 2588.widget-search-form--expand { 2589 border: 1px solid rgba(148, 163, 184, 0.28); 2590 border-radius: 9999px; 2591 background: #ffffff; 2592 box-shadow: 0 10px 30px rgba(15, 23, 42, 0.08); 2593 padding: 0.25rem 0.375rem 0.25rem 0.875rem; 2594} 2595 2596.widget-search-form--minimal { 2597 border-bottom: 1px solid rgba(148, 163, 184, 0.28); 2598 padding-bottom: 0.25rem; 2599} 2600 2601.widget-search-suggestions { 2602 position: absolute; 2603 top: calc(100% + 0.5rem); 2604 left: 0; 2605 right: 0; 2606 z-index: 100; 2607 max-height: 22rem; 2608 overflow-y: auto; 2609 border: 1px solid rgba(148, 163, 184, 0.25); 2610 border-radius: 0.9rem; 2611 background: #ffffff; 2612 box-shadow: 0 18px 50px rgba(15, 23, 42, 0.14); 2613 padding: 0.35rem; 2614} 2615 2616html.dark .widget-search-suggestions, 2617.dark .widget-search-suggestions { 2618 background: #0f172a; 2619 border-color: rgba(51, 65, 85, 0.95); 2620 box-shadow: 0 22px 60px rgba(0, 0, 0, 0.42); 2621 color: #e2e8f0; 2622} 2623 2624.widget-search-suggestion { 2625 display: grid; 2626 gap: 0.35rem; 2627 padding: 0.9rem 1rem; 2628 border-radius: 0.75rem; 2629 color: inherit; 2630 text-decoration: none; 2631} 2632 2633.widget-search-suggestion:hover { 2634 background: #f8fafc; 2635} 2636 2637html.dark .widget-search-suggestion:hover, 2638.dark .widget-search-suggestion:hover {
2639 background: rgba(30, 41, 59, 0.85); 2640} 2641 2642.widget-search-suggestion__title { 2643 font-size: 0.95rem; 2644 font-weight: 600; 2645 line-height: 1.35; 2646 color: #0f172a; 2647} 2648 2649html.dark .widget-search-suggestion__title, 2650.dark .widget-search-suggestion__title { 2651 color: #f8fafc; 2652} 2653 2654.widget-search-suggestion__meta, 2655.widget-search-suggestion__excerpt, 2656.widget-search-suggestion-empty { 2657 font-size: 0.8rem; 2658 line-height: 1.45; 2659 color: #64748b; 2660} 2661 2662.widget-search-suggestion__meta { 2663 margin-top: -0.1rem; 2664} 2665 2666html.dark .widget-search-suggestion__meta, 2667html.dark .widget-search-suggestion__excerpt, 2668html.dark .widget-search-suggestion-empty, 2669.dark .widget-search-suggestion__meta, 2670.dark .widget-search-suggestion__excerpt, 2671.dark .widget-search-suggestion-empty { 2672 color: #94a3b8; 2673} 2674</style>
2675<script> 2676(function() { 2677 if (window.PolyCMSSearchWidgetReady) return; 2678 window.PolyCMSSearchWidgetReady = true; 2679 2680 function initSearchWidget(root) { 2681 if (!root || root.__polySearchReady) return; 2682 root.__polySearchReady = true; 2683 2684 var openers = root.querySelectorAll('[data-search-open]'); 2685 var closers = root.querySelectorAll('[data-search-close]'); 2686 var modal = root.querySelector('[data-search-modal]'); 2687 var panel = root.querySelector('[data-search-panel]'); 2688 var forms = root.querySelectorAll('[data-widget-search-form]'); 2689 var suggestionsEnabled = root.dataset.suggestionsEnabled === '1'; 2690 var suggestionsUrl = root.dataset.suggestionsUrl || '/api/v1/search/suggestions'; 2691 var suggestionScope = root.dataset.suggestionScope || 'posts'; 2692 var suggestionLimit = root.dataset.suggestionLimit || '6'; 2693 var searchLocale = root.dataset.searchLocale || document.documentElement.lang || 'en'; 2694 var requestId = 0; 2695 2696 if (modal && modal.parentElement !== document.body) { 2697 document.body.appendChild(modal); 2698 } 2699 2700 function getSearchInput() { 2701 if (modal) { 2702 var modalInput = modal.querySelector('[data-search-input]'); 2703 if (modalInput) return modalInput; 2704 } 2705 return root.querySelector('[data-search-input]'); 2706 } 2707 2708 function open() { 2709 root.classList.add('is-open'); 2710 document.body.classList.add('polycms-search-widget-open'); 2711 if (modal) modal.hidden = false; 2712 if (panel) panel.hidden = false; 2713 var input = getSearchInput(); 2714 if (input) setTimeout(function() { input.focus(); }, 30); 2715 } 2716 2717 function close() { 2718 root.classList.remove('is-open'); 2719 document.body.classList.remove('polycms-search-widget-open'); 2720 if (modal) modal.hidden = true; 2721 if (panel) panel.hidden = true; 2722 hideSuggestions(); 2723 } 2724 2725 function hideSuggestions() { 2726 var suggestionBoxes = modal 2727 ? modal.querySelectorAll('[data-search-suggestions]') 2728 : root.querySelectorAll('[data-search-suggestions]'); 2729 suggestionBoxes.forEach(function(box) { 2730 box.hidden = true; 2731 box.innerHTML = ''; 2732 }); 2733 } 2734
2735 function renderSuggestions(box, results) { 2736 if (!box) return; 2737 if (!results.length) { 2738 box.innerHTML = '<div class="widget-search-suggestion-empty">No results found</div>'; 2739 box.hidden = false; 2740 return; 2741 } 2742 2743 box.innerHTML = results.map(function(item) { 2744 var title = escapeHtml(item.title || ''); 2745 var subtitle = escapeHtml(item.subtitle || item.type || ''); 2746 var excerpt = escapeHtml(item.excerpt || ''); 2747 var url = escapeAttr(item.url || '#'); 2748 return '<a class="widget-search-suggestion" href="' + url + '">' 2749 + '<span class="widget-search-suggestion__title">' + title + '</span>' 2750 + (subtitle ? '<span class="widget-search-suggestion__meta">' + subtitle + '</span>' : '') 2751 + (excerpt ? '<span class="widget-search-suggestion__excerpt">' + excerpt + '</span>' : '') 2752 + '</a>'; 2753 }).join(''); 2754 box.hidden = false; 2755 } 2756 2757 function fetchSuggestions(input, box) { 2758 if (!suggestionsEnabled || !input || !box) return; 2759 var query = input.value.trim(); 2760 if (query.length < 2) { 2761 box.hidden = true; 2762 box.innerHTML = ''; 2763 return; 2764 } 2765 2766 var currentRequest = ++requestId; 2767 var url = new URL(suggestionsUrl, window.location.origin); 2768 url.searchParams.set('q', query); 2769 url.searchParams.set('scope', suggestionScope); 2770 url.searchParams.set('limit', suggestionLimit); 2771 url.searchParams.set('locale', searchLocale); 2772 2773 fetch(url.toString(), { headers: { 'Accept': 'application/json' } }) 2774 .then(function(response) { return response.ok ? response.json() : { results: [] }; }) 2775 .then(function(payload) { 2776 if (currentRequest !== requestId) return; 2777 renderSuggestions(box, Array.isArray(payload.results) ? payload.results : []); 2778 }) 2779 .catch(function() { 2780 if (currentRequest === requestId) hideSuggestions(); 2781 }); 2782 } 2783 2784 function debounce(fn, delay) { 2785 var timer = null; 2786 return function() { 2787 var args = arguments; 2788 clearTimeout(timer); 2789 timer = setTimeout(function() { fn.apply(null, args); }, delay); 2790 }; 2791 } 2792 2793 openers.forEach(function(button) { 2794 button.addEventListener('click', function(event) { 2795 event.preventDefault(); 2796 root.classList.contains('is-open') ? close() : open(); 2797 }); 2798 }); 2799 2800 closers.forEach(function(button) { 2801 button.addEventListener('click', function(event) { 2802 event.preventDefault(); 2803 close(); 2804 }); 2805 }); 2806 2807 forms.forEach(function(form) { 2808 var input = form.querySelector('[data-search-input]'); 2809 var box = form.querySelector('[data-search-suggestions]'); 2810 var debouncedSuggest = debounce(function() { fetchSuggestions(input, box); }, 180); 2811 2812 if (input) { 2813 input.addEventListener('input', debouncedSuggest); 2814 input.addEventListener('focus', function() { 2815 if (input.value.trim().length >= 2) fetchSuggestions(input, box); 2816 }); 2817 } 2818 2819 form.addEventListener('submit', function(event) { 2820 if (!input || input.value.trim().length === 0) { 2821 event.preventDefault(); 2822 if (input) input.focus(); 2823 } 2824 }); 2825 }); 2826 2827 document.addEventListener('click', function(event) { 2828 var insideModal = modal && modal.contains(event.target); 2829 if (!root.contains(event.target) && !insideModal && root.classList.contains('is-open')) { 2830 close(); 2831 } 2832 }); 2833 2834 document.addEventListener('keydown', function(event) { 2835 if (event.key === 'Escape' && root.classList.contains('is-open')) { 2836 close(); 2837 } 2838 }); 2839 } 2840 2841 function escapeHtml(value) { 2842 return String(value).replace(/[&<>
2842"']/g, function(char) { 2843 return ({ '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' })[char]; 2844 }); 2845 } 2846 2847 function escapeAttr(value) { 2848 return escapeHtml(value).replace(/`/g, '`'); 2849 } 2850 2851 function boot() { 2852 document.querySelectorAll('[data-search-widget]').forEach(initSearchWidget); 2853 } 2854 2855 if (document.readyState === 'loading') { 2856 document.addEventListener('DOMContentLoaded', boot); 2857 } else { 2858 boot(); 2859 } 2860})(); 2861</script>
2861 2862 </div> 2863 <div class="nav-item has-dropdown"> 2864 <a href="#" class="nav-link language-switcher has-children-link" 2865 style="display: inline-flex; align-items: center; gap: 4px; vertical-align: middle;" > 2866 <span class="flag-icon-wrapper" style="display: inline-flex; align-items: center; vertical-align: middle;"><svg class="flag-svg flag-en" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36" width="16" height="16" style="vertical-align: middle; display: inline-block; border-radius: 50%; width: 1.1em; height: 1.1em; object-fit: cover;"> 2867 <clipPath id="us-clip-flag_6abedb80012df"><circle cx="18" cy="18" r="18"/></clipPath> 2868 <g clip-path="url(#us-clip-flag_6abedb80012df)"> 2869 <rect width="36" height="36" fill="#B22234"/> 2870 <rect y="2.77" width="36" height="2.77" fill="#FFF"/> 2871 <rect y="8.31" width="36" height="2.77" fill="#FFF"/> 2872 <rect y="13.85" width="36" height="2.77" fill="#FFF"/> 2873 <rect y="19.38" width="36" height="2.77" fill="#FFF"/> 2874 <rect y="24.92" width="36" height="2.77" fill="#FFF"/> 2875 <rect y="30.46" width="36" height="2.77" fill="#FFF"/> 2876 <rect width="18" height="19.38" fill="#3C3B6E"/> 2877 <g fill="#FFF"> 2878 <circle cx="3" cy="3" r="0.6"/><circle cx="6" cy="3" r="0.6"/><circle cx="9" cy="3" r="0.6"/><circle cx="12" cy="3" r="0.6"/><circle cx="15" cy="3" r="0.6"/> 2879 <circle cx="4.5" cy="6.5" r="0.6"/><circle cx="7.5" cy="6.5" r="0.6"/><circle cx="10.5" cy="6.5" r="0.6"/><circle cx="13.5" cy="6.5" r="0.6"/> 2880 <circle cx="3" cy="10" r="0.6"/><circle cx="6" cy="10" r="0.6"/><circle cx="9" cy="10" r="0.6"/><circle cx="12" cy="10" r="0.6"/><circle cx="15" cy="10" r="0.6"/> 2881 <circle cx="4.5" cy="13.5" r="0.6"/><circle cx="7.5" cy="13.5" r="0.6"/><circle cx="10.5" cy="13.5" r="0.6"/><circle cx="13.5" cy="13.5" r="0.6"/> 2882 <circle cx="3" cy="17" r="0.6"/><circle cx="6" cy="17" r="0.6"/><circle cx="9" cy="17" r="0.6"/><circle cx="12" cy="17" r="0.6"/><circle cx="15" cy="17" r="0.6"/> 2883 </g> 2884 </g> 2885 </svg></span> 2886 <svg class="submenu-icon" xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m6 9 6 6 6-6"/></svg> 2887 </a> 2888 <ul class="nav-dropdown"> 2889 <div class="nav-item"> 2890 <a href="https://headrandom.com/products?lang=en" class="nav-link language-item" 2891 > 2892 <span class="flag-icon-wrapper" style="display: inline-flex; align-items: center; margin-right: 8px; vertical-align: middle;"><svg class="flag-svg flag-en" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36" width="16" height="16" style="vertical-align: middle; display: inline-block; border-radius: 50%; width: 1.1em; height: 1.1em; object-fit: cover;"> 2893 <clipPath id="us-clip-flag_6abedb8001c85"><circle cx="18" cy="18" r="18"/></clipPath> 2894 <g clip-path="url(#us-clip-flag_6abedb8001c85)"> 2895 <rect width="36" height="36" fill="#B22234"/> 2896 <rect y="2.77" width="36" height="2.77" fill="#FFF"/> 2897 <rect y="8.31" width="36" height="2.77" fill="#FFF"/> 2898 <rect y="13.85" width="36" height="2.77" fill="#FFF"/> 2899 <rect y="19.38" width="36" height="2.77" fill="#FFF"/> 2900 <rect y="24.92" width="36" height="2.77" fill="#FFF"/> 2901 <rect y="30.46" width="36" height="2.77" fill="#FFF"/> 2902 <rect width="18" height="19.38" fill="#3C3B6E"/> 2903 <g fill="#FFF"> 2904 <circle cx="3" cy="3" r="0.6"/><circle cx="6" cy="3" r="0.6"/><circle cx="9" cy="3" r="0.6"/><circle cx="12" cy="3" r="0.6"/><circle cx="15" cy="3" r="0.6"/> 2905 <circle cx="4.5" cy="6.5" r="0.6"/><circle cx="7.5" cy="6.5" r="0.6"/><circle cx="10.5" cy="6.5" r="0.6"/><circle cx="13.5" cy="6.5" r="0.6"/> 2906 <circle cx="3" cy="10" r="0.6"/><circle cx="6" cy="10" r="0.6"/><circle cx="9" cy="10" r="0.6"/><circle cx="12" cy="10" r="0.6"/><circle cx="15" cy="10" r="0.6"/> 2907 <circle cx="4.5" cy="13.5" r="0.6"/><circle cx="7.5" cy="13.5" r="0.6"/><circle cx="10.5" cy="13.5" r="0.6"/><circle cx="13.5" cy="13.5" r="0.6"/> 2908 <circle cx="3" cy="17" r="0.6"/><circle cx="6" cy="17" r="0.6"/><circle cx="9" cy="17" r="0.6"/><circle cx="12" cy="17" r="0.6"/><circle cx="15" cy="17" r="0.6"/> 2909 </g> 2910 </g> 2911 </svg></span>
2912 <span class="nav-link-label"> 2913 English 2914 </span> 2915 </a> 2916 </div> 2917 <div class="nav-item"> 2918 <a href="https://headrandom.com/products?lang=vi" class="nav-link language-item" 2919 > 2920 <span class="flag-icon-wrapper" style="display: inline-flex; align-items: center; margin-right: 8px; vertical-align: middle;"><svg class="flag-svg flag-vi" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36" width="16" height="16" style="vertical-align: middle; display: inline-block; border-radius: 50%; width: 1.1em; height: 1.1em; object-fit: cover;"> 2921 <clipPath id="vi-clip-flag_6abedb800235c"><circle cx="18" cy="18" r="18"/></clipPath> 2922 <g clip-path="url(#vi-clip-flag_6abedb800235c)"> 2923 <rect width="36" height="36" fill="#DA251D"/> 2924 <polygon fill="#FFFF00" points="18,8 21.1,17.4 31,17.4 23,23.3 26.1,32.7 18,26.8 9.9,32.7 13,23.3 5,17.4 14.9,17.4"/> 2925 </g> 2926 </svg></span> 2927 <span class="nav-link-label"> 2928 Tiếng Viá»t 2929 </span> 2930 </a> 2931 </div> 2932 </ul> 2933 </div> 2934 </nav> 2935 2936 <!-- Header Controls (Right Side on Mobile) --> 2937 <div class="header-controls"> 2938 2939 <!-- Mini Cart Root --> 2940 <div id="mini-cart-root"></div> 2941 2942 <!-- Dark Mode Toggle --> 2943 <style> 2944 .header-controls { 2945 display: flex; 2946 align-items: center; 2947 gap: 0.75rem; 2948 } 2949 .fw-theme-toggle { 2950 display: none; /* Hidden by default to prevent flicker, revealed via JS if guest */ 2951 align-items: center; 2952 justify-content: center; 2953 width: 40px; 2954 height: 40px; 2955 border-radius: 50%; 2956 background-color: #f3f4f6; 2957 border: none; 2958 cursor: pointer; 2959 color: #374151; 2960 transition: all 0.2s; 2961 margin-right: 0; 2962 } 2963 .fw-theme-toggle:hover { 2964 background-color: #e5e7eb; 2965 } 2966 html.dark .fw-theme-toggle { 2967 background-color: #1f2937; 2968 color: #d1d5db; 2969 } 2970 html.dark .fw-theme-toggle:hover { 2971 background-color: #374151; 2972 } 2973 2974 #front-login-btn { 2975 margin-right: 0; 2976 } 2977 #front-login-btn .btn { 2978 display: inline-flex; 2979 align-items: center; 2980 gap: 0.5rem; 2981 } 2982 #front-login-btn .btn-icon { 2983 display: none; 2984 } 2985 2986 @media (max-width: 768px) { 2987 .header-controls { 2988 margin-left: auto; 2989 } 2990 .fw-theme-toggle { 2991 width: 36px; 2992 height: 36px; 2993 margin-right: 0; 2994 } 2995 #front-login-btn .btn { 2996 width: 36px; 2997 height: 36px; 2998 border-radius: 50%; 2999 padding: 0 !important; 3000 display: flex; 3001 align-items: center; 3002 justify-content: center; 3003 background-color: #f3f4f6; 3004 color: #374151; 3005 border: none; 3006 box-shadow: none; 3007 } 3008 #front-login-btn .btn-text { 3009 display: none; 3010 } 3011 #front-login-btn .btn-icon { 3012 display: flex; 3013 align-items: center; 3014 justify-content: center; 3015 } 3016 html.dark #front-login-btn .btn { 3017 background-color: #1f2937; 3018 color: #d1d5db; 3019 } 3020 html.dark #front-login-btn .btn:hover { 3021 background-color: #374151; 3022 } 3023 } 3024 3025 /* Mobile Menu Harmonization */ 3026 .mobile-menu { 3027 background: var(--geist-background) !important; 3028 padding: 1.5rem 0 3rem 0 !important; 3029 } 3030 .mobile-menu .container { 3031 padding: 0 1.25rem; 3032 } 3033 .mobile-menu-item { 3034 border-bottom: 1px solid var(--geist-accents-2); 3035 padding: 0.25rem 0; 3036 } 3037 .mobile-menu-item-search { 3038 border-bottom: none !important; 3039 padding: 0.75rem 0 1rem 0 !important; 3040 margin-bottom: 0.5rem !important; 3041 width: 100% !important; 3042 box-sizing: border-box !important; 3043 background: transparent !important; 3044 } 3045 .mobile-menu-item-search .widget, 3046 .mobile-menu-item-search .widget-blog-search { 3047 margin: 0 !important; 3048 padding: 0 !important; 3049 background: transparent !important; 3050 border: none !important; 3051 border-radius: 0 !important; 3052 box-shadow: none !important; 3053 width: 100% !important; 3054 } 3055 .mobile-menu-item-search .widget-search-form { 3056 margin-top: 0 !important; 3057 display: flex !important; 3058 width: 100% !important; 3059 box-sizing: border-box !important; 3060 background: transparent !important; 3061 border: none !important; 3062 box-shadow: none !important; 3063 padding: 0 !important; 3064 } 3065 .mobile-menu-item-search .widget-search-form input[type="text"], 3066 .mobile-menu-item-search .widget-search-form input[type="search"] { 3067 flex: 1 !important; 3068 border-radius: 8px 0 0 8px !important; 3069 border: 1px solid var(--geist-accents-2, #eaeaea) !important;
3070 border-right: none !important; 3071 background: var(--geist-background, #fff) !important; 3072 color: var(--geist-foreground, #000) !important; 3073 padding: 10px 14px !important; 3074 height: 42px !important; 3075 font-size: 0.95rem !important; 3076 box-sizing: border-box !important; 3077 box-shadow: none !important; 3078 } 3079 .mobile-menu-item-search .widget-search-form button, 3080 .mobile-menu-item-search .widget-search-form button[type="submit"] { 3081 border-radius: 0 8px 8px 0 !important; 3082 border: 1px solid var(--geist-foreground, #000) !important; 3083 background: var(--geist-foreground, #000) !important; 3084 color: var(--geist-background, #fff) !important; 3085 padding: 0 16px !important; 3086 height: 42px !important; 3087 font-weight: 600 !important; 3088 font-size: 0.9rem !important; 3089 cursor: pointer !important; 3090 box-sizing: border-box !important; 3091 display: inline-flex !important; 3092 align-items: center !important; 3093 justify-content: center !important; 3094 appearance: none !important; 3095 -webkit-appearance: none !important; 3096 box-shadow: none !important; 3097 } 3098 html.dark .mobile-menu-item-search .widget-search-form input[type="text"], 3099 html.dark .mobile-menu-item-search .widget-search-form input[type="search"] { 3100 background: rgba(255, 255, 255, 0.05) !important; 3101 border-color: rgba(148, 163, 184, 0.2) !important; 3102 color: #e2e8f0 !important; 3103 } 3104 html.dark .mobile-menu-item-search .widget-search-form button, 3105 html.dark .mobile-menu-item-search .widget-search-form button[type="submit"] { 3106 border-color: #3b82f6 !important; 3107 background: #3b82f6 !important; 3108 color: #fff !important; 3109 } 3110 3111 /* Mobile Language Switcher Flat Grid styles (No card box) */ 3112 .mobile-language-switcher-grid { 3113 margin-top: 12px !important; 3114 margin-bottom: 8px !important; 3115 padding: 0 !important; 3116 border: none !important; 3117 background: transparent !important; 3118 } 3119 .mobile-language-grid-item { 3120 display: inline-flex !important; 3121 flex-direction: row !important; 3122 align-items: center !important; 3123 justify-content: center !important; 3124 gap: 8px !important; 3125 padding: 10px 14px !important; 3126 border-radius: 8px !important; 3127 border: none !important; 3128 background: transparent !important; 3129 box-shadow: none !important; 3130 text-decoration: none !important; 3131 color: var(--geist-foreground, #000) !important; 3132 text-align: center; 3133 font-size: 0.9rem !important; 3134 font-weight: 500 !important; 3135 transition: all 0.2s !important; 3136 } 3137 .mobile-language-grid-item.active { 3138 border: none !important; 3139 background: transparent !important; 3140 color: var(--primary-color, #3b82f6) !important; 3141 font-weight: 700 !important; 3142 } 3143 html.dark .mobile-language-grid-item { 3144 background: transparent !important; 3145 border: none !important; 3146 box-shadow: none !important; 3147 color: #cbd5e1 !important; 3148 } 3149 html.dark .mobile-language-grid-item.active { 3150 background: transparent !important; 3151 border: none !important; 3152 box-shadow: none !important; 3153 color: #60a5fa !important; 3154 font-weight: 700 !important; 3155 } 3156 .mobile-menu .nav-link { 3157 padding: 0.75rem 0.5rem !important; 3158 font-weight: 500; 3159 font-size: 0.9375rem !important; 3160 } 3161 .mobile-submenu { 3162 padding-left: 1.25rem !important; 3163 margin-bottom: 0.5rem !important; 3164 } 3165 .mobile-submenu .mobile-menu-item { 3166 border-bottom: none; 3167 padding: 0.125rem 0; 3168 } 3169 .mobile-submenu .nav-link { 3170 font-size: 0.875rem !important; 3171 color: var(--geist-accents-5) !important; 3172 } 3173 .mobile-submenu .nav-link:hover, 3174 .mobile-submenu .nav-link.active { 3175 color: var(--geist-foreground) !important; 3176 background: transparent !important; 3177 } 3178 .submenu-toggle { 3179 padding: 10px 12px !important; 3180 color: var(--geist-accents-4) !important; 3181 } 3182 .submenu-toggle.active { 3183 color: var(--geist-foreground) !important; 3184 } 3185 </style> 3186 <button id="front-theme-toggle" class="fw-theme-toggle" aria-label="Toggle Dark Mode"> 3187 <svg id="front-icon-moon" style="display: none; width: 1.25rem; height: 1.25rem;" fill="none" stroke="currentColor" viewBox="0 0 24 24">
3187<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z"></path></svg> 3188 <svg id="front-icon-sun" style="display: none; width: 1.25rem; height: 1.25rem;" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z"></path></svg> 3189 </button> 3190
3190<script> 3191 document.addEventListener('DOMContentLoaded', function() { 3192 const toggleBtn = document.getElementById('front-theme-toggle'); 3193 const moonIcon = document.getElementById('front-icon-moon'); 3194 const sunIcon = document.getElementById('front-icon-sun'); 3195 const htmlEl = document.documentElement; 3196 3197 function updateIcons() { 3198 if (htmlEl.classList.contains('dark')) { 3199 moonIcon.style.display = 'none'; 3200 sunIcon.style.display = 'block'; 3201 } else { 3202 sunIcon.style.display = 'none'; 3203 moonIcon.style.display = 'block'; 3204 } 3205 } 3206 3207 toggleBtn.addEventListener('click', function() { 3208 // Toggle class manually (1-click guaranteed based on current state) 3209 htmlEl.classList.toggle('dark'); 3210 3211 // Sync with BOTH potential localStorage keys used by core and theme 3212 const newTheme = htmlEl.classList.contains('dark') ? 'dark' : 'light'; 3213 localStorage.setItem('theme_mode', newTheme); 3214 localStorage.setItem('color-theme', newTheme); 3215 3216 // Re-sync icons immediately and after a short delay 3217 updateIcons(); 3218 setTimeout(updateIcons, 50); 3219 }); 3220 3221 // Sync icons when classes change (e.g. by other scripts) 3222 const observer = new MutationObserver(updateIcons); 3223 observer.observe(htmlEl, { attributes: true, attributeFilter: ['class'] }); 3224 3225 // Check initial state 3226 updateIcons(); 3227 }); 3228 </script>
3228 3229 3230 <!-- CTA / Auth --> 3231 <div class="header-actions" id="front-login-btn" style="display: none;"> 3232 <a href="/login" class="btn btn-primary"> 3233 <span class="btn-text">Log In</span> 3234 <span class="btn-icon"> 3235 <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"> 3236 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z"></path> 3237 </svg> 3238 </span> 3239 </a> 3240 </div> 3241 3242 <!-- Mobile Toggle --> 3243 <button class="mobile-menu-toggle" id="mobile-menu-toggle" aria-label="Toggle navigation"> 3244 <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"> 3245 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" /> 3246 </svg> 3247 </button> 3248 </div> 3249 3250
3250<script> 3251 // Synchronous auth check to prevent UI flickering 3252 (function() { 3253 var isWebAuth = false; 3254 var hasApiToken = localStorage.getItem('auth_token'); 3255 3256 // If neither server-side session nor client-side API token exists, user is a true guest 3257 if (!isWebAuth && !hasApiToken) { 3258 var themeToggle = document.getElementById('front-theme-toggle'); 3259 if (themeToggle) { 3260 themeToggle.style.display = 'flex'; 3261 } 3262 3263 var loginBtn = document.getElementById('front-login-btn'); 3264 if (loginBtn) { 3265 loginBtn.style.display = 'block'; 3266 } 3267 } 3268 3269 // If client-side admin API token exists, tag body immediately and sync cookie 3270 if (hasApiToken) { 3271 document.documentElement.classList.add('has-admin-token'); 3272 if (document.body) { 3273 document.body.classList.add('has-admin-token'); 3274 } 3275 try { 3276 document.cookie = "auth_token=" + encodeURIComponent(hasApiToken) + "; path=/; SameSite=Lax"; 3277 } catch (e) {} 3278 } 3279 })(); 3280 3281 document.addEventListener('DOMContentLoaded', function() { 3282 var token = localStorage.getItem('auth_token'); 3283 if (token) { 3284 document.body.classList.add('has-admin-token'); 3285 try { 3286 document.cookie = "auth_token=" + encodeURIComponent(token) + "; path=/; SameSite=Lax"; 3287 } catch (e) {} 3288 } 3289 }); 3290 </script>
3290 3291 </div> 3292 3293 <!-- Mobile Menu --> 3294 <div class="mobile-menu" id="mobile-menu"> 3295 <div class="container"> 3296 <div class="mobile-menu-item"> 3297 <a href="https://headrandom.com/" class="nav-link" 3298 > 3299 Home 3300 </a> 3301 </div> 3302 <div class="mobile-menu-item"> 3303 <a href="https://headrandom.com/products" class="nav-link active" 3304 > 3305 Products 3306 </a> 3307 <span class="submenu-toggle"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m6 9 6 6 6-6"/></svg></span> 3308 <ul class="mobile-submenu"> 3309 <div class="mobile-menu-item"> 3310 <a href="/product-categories/modules-for-perfex-crm" class="nav-link" 3311 > 3312 Modules for Perfex CRM 3313 </a> 3314 </div> 3315 <div class="mobile-menu-item"> 3316 <a href="/product-categories/wordpress" class="nav-link" 3317 > 3318 Plugins for WordPress 3319 </a> 3320 </div> 3321 <div class="mobile-menu-item"> 3322 <a href="/product-categories/desktop-apps" class="nav-link" 3323 > 3324 Desktop Apps 3325 </a> 3326 </div> 3327 <div class="mobile-menu-item"> 3328 <a href="/product-categories/polycms" class="nav-link" 3329 > 3330 PolyCMS 3331 </a> 3332 </div> 3333 </ul> 3334 </div> 3335 <div class="mobile-menu-item"> 3336 <a href="/coupons-promotions" class="nav-link" 3337 > 3338 Special Deals 3339 </a> 3340 </div> 3341 <div class="mobile-menu-item"> 3342 <a href="https://headrandom.com/blog" class="nav-link" 3343 > 3344 Blog 3345 </a> 3346 </div> 3347 <div class="mobile-menu-item"> 3348 <a href="/documentation" class="nav-link" 3349 > 3350 Documentation 3351 </a> 3352 <span class="submenu-toggle"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m6 9 6 6 6-6"/></svg></span> 3353 <ul class="mobile-submenu"> 3354 <div class="mobile-menu-item"> 3355 <a href="/modules-for-perfex-crm" class="nav-link" 3356 > 3357 Modules for Perfex CRM 3358 </a> 3359 <span class="submenu-toggle"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m6 9 6 6 6-6"/></svg></span> 3360 <ul class="mobile-submenu"> 3361 <div class="mobile-menu-item"> 3362 <a href="/cms-for-perfex-crm" class="nav-link" 3363 > 3364 CMS for Perfex CRM 3365 </a> 3366 </div> 3367 <div class="mobile-menu-item"> 3368 <a href="/data-builder-for-perfex-crm" class="nav-link" 3369 > 3370 Data Builder for Perfex CRM 3371 </a> 3372 </div> 3373 <div class="mobile-menu-item"> 3374 <a href="/polyutilities-for-perfex-crm" class="nav-link" 3375 > 3376 PolyUtilities for Perfex CRM 3377 </a> 3378 </div> 3379 <div class="mobile-menu-item"> 3380 <a href="/woocommerce-for-perfex-crm" class="nav-link" 3381 > 3382 WooCommerce for Perfex CRM 3383 </a> 3384 </div> 3385 <div class="mobile-menu-item"> 3386 <a href="/flexinote-for-perfex-crm" class="nav-link" 3387 > 3388 FlexiNote for Perfex CRM 3389 </a> 3390 </div> 3391 </ul> 3392 </div> 3393 <div class="mobile-menu-item"> 3394 <a href="/ideas-solutions" class="nav-link" 3395 > 3396 Ideas & Solutions 3397 </a> 3398 </div> 3399 <div class="mobile-menu-item"> 3400 <a href="/stability-strategy" class="nav-link" 3401 > 3402 Stability & Strategy 3403 </a> 3404 </div> 3405 <div class="mobile-menu-item"> 3406 <a href="/productivity-and-business-workflow" class="nav-link" 3407 > 3408 Productivity & Business Workflow 3409 </a> 3410 </div> 3411 <div class="mobile-menu-item"> 3412 <a href="/plugins-for-rise-crm" class="nav-link" 3413 > 3414 Plugins for RISE CRM 3415 </a> 3416 </div> 3417 <div class="mobile-menu-item"> 3418 <a href="/plugins-for-wordpress" class="nav-link" 3419 > 3420 Plugins for WordPress 3421 </a> 3422 </div> 3423 </ul> 3424 </div> 3425 <div class="mobile-menu-item mobile-menu-item-search"> 3426 <div id="widget-search-0" class="widget widget-blog-search widget-blog-search--form" data-search-widget data-search-style="form" data-search-locale="en" data-suggestions-enabled="1" data-suggestions-url="https://headrandom.com/api/v1/search/suggestions" data-suggestion-scope="all" data-suggestion-limit="5"><form action="https://headrandom.com/blog" method="get" class="widget-search-form widget-search-form--default" data-widget-search-form><label class="sr-only" for="widget-search-0">Search</label><input id="widget-search-0" type="text" inputmode="search" enterkeyhint="search" name="search" autocomplete="off" spellcheck="false" placeholder="Search..." data-search-input /><button type="submit" class="widget-search-submit-button">Search</button><div class="widget-search-suggestions" data-search-suggestions hidden></div></form></div> 3427 </div> 3428 <div class="mobile-language-switcher-grid" style="display: grid; grid-template-columns: repeat(2, 1fr); gap: 8px; width: 100%; margin-top: 10px; margin-bottom: 10px;"> 3429 <a href="https://headrandom.com/products?lang=en" class="mobile-language-grid-item " >
3430 <span class="flag-icon-wrapper" style="font-size: 1.25rem; display: inline-flex; align-items: center; justify-content: center; height: 20px;"><svg class="flag-svg flag-en" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36" width="16" height="16" style="vertical-align: middle; display: inline-block; border-radius: 50%; width: 1.1em; height: 1.1em; object-fit: cover;"> 3431 <clipPath id="us-clip-flag_6abedb820a828"><circle cx="18" cy="18" r="18"/></clipPath> 3432 <g clip-path="url(#us-clip-flag_6abedb820a828)"> 3433 <rect width="36" height="36" fill="#B22234"/> 3434 <rect y="2.77" width="36" height="2.77" fill="#FFF"/> 3435 <rect y="8.31" width="36" height="2.77" fill="#FFF"/> 3436 <rect y="13.85" width="36" height="2.77" fill="#FFF"/> 3437 <rect y="19.38" width="36" height="2.77" fill="#FFF"/> 3438 <rect y="24.92" width="36" height="2.77" fill="#FFF"/> 3439 <rect y="30.46" width="36" height="2.77" fill="#FFF"/> 3440 <rect width="18" height="19.38" fill="#3C3B6E"/> 3441 <g fill="#FFF"> 3442 <circle cx="3" cy="3" r="0.6"/><circle cx="6" cy="3" r="0.6"/><circle cx="9" cy="3" r="0.6"/><circle cx="12" cy="3" r="0.6"/><circle cx="15" cy="3" r="0.6"/> 3443 <circle cx="4.5" cy="6.5" r="0.6"/><circle cx="7.5" cy="6.5" r="0.6"/><circle cx="10.5" cy="6.5" r="0.6"/><circle cx="13.5" cy="6.5" r="0.6"/> 3444 <circle cx="3" cy="10" r="0.6"/><circle cx="6" cy="10" r="0.6"/><circle cx="9" cy="10" r="0.6"/><circle cx="12" cy="10" r="0.6"/><circle cx="15" cy="10" r="0.6"/> 3445 <circle cx="4.5" cy="13.5" r="0.6"/><circle cx="7.5" cy="13.5" r="0.6"/><circle cx="10.5" cy="13.5" r="0.6"/><circle cx="13.5" cy="13.5" r="0.6"/> 3446 <circle cx="3" cy="17" r="0.6"/><circle cx="6" cy="17" r="0.6"/><circle cx="9" cy="17" r="0.6"/><circle cx="12" cy="17" r="0.6"/><circle cx="15" cy="17" r="0.6"/> 3447 </g> 3448 </g> 3449 </svg></span> 3450 <span>English</span> 3451 </a> 3452 <a href="https://headrandom.com/products?lang=vi" class="mobile-language-grid-item " > 3453 <span class="flag-icon-wrapper" style="font-size: 1.25rem; display: inline-flex; align-items: center; justify-content: center; height: 20px;"><svg class="flag-svg flag-vi" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36" width="16" height="16" style="vertical-align: middle; display: inline-block; border-radius: 50%; width: 1.1em; height: 1.1em; object-fit: cover;"> 3454 <clipPath id="vi-clip-flag_6abedb820a890"><circle cx="18" cy="18" r="18"/></clipPath> 3455 <g clip-path="url(#vi-clip-flag_6abedb820a890)"> 3456 <rect width="36" height="36" fill="#DA251D"/> 3457 <polygon fill="#FFFF00" points="18,8 21.1,17.4 31,17.4 23,23.3 26.1,32.7 18,26.8 9.9,32.7 13,23.3 5,17.4 14.9,17.4"/> 3458 </g> 3459 </svg></span> 3460 <span>Tiếng Viá»t</span> 3461 </a> 3462 </div> 3463 </div> 3464 </div> 3465</header> 3466 3467 3468 <div class="container breadcrumb-bar"> 3469 <nav class="breadcrumb" aria-label="Breadcrumb"> 3470 <ol> 3471 <li> 3472 <a href="https://headrandom.com">Home</a> 3473 </li> 3474 <li> 3475 <span aria-current="page">Products</span> 3476 </li> 3477 </ol> 3478</nav> 3479 </div> 3480 3481 3482 <main style="flex: 1;"> 3483 3484<div class="container section"> 3485 <div class="grid-sidebar no-sidebar" style="grid-template-columns: 1fr;"> 3486 3487 <!-- Main Content Column --> 3488 <div> 3489 <div class="listing-header"> 3490 <div></div> 3491 3492 <div style="display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap; width: 100%;"> 3493 <div id="admin-sidebar-toggle-wrap" style="display: none; align-items: center;" class="admin-sidebar-toggle-wrapper"> 3494 <button type="button" 3495 id="admin-sidebar-toggle-btn" 3496 class="admin-sidebar-toggle-btn " 3497 onclick="toggleSidebarAdminSetting('flexiwhite_products_show_sidebar')" 3498 title="Toggle Sidebar (Admin Option)"> 3499 <svg xmlns="http://www.w3.org/2000/svg" style="width: 14px; height: 14px; flex-shrink: 0;" fill="none" viewBox="0 0 24 24" stroke="currentColor"> 3500 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h8m-8 6h16" /> 3501 </svg>
3502 <span id="admin-sidebar-toggle-label">Sidebar: OFF</span> 3503 <span class="toggle-switch"></span> 3504 </button> 3505</div> 3506 3507<style> 3508 .admin-sidebar-toggle-wrapper { 3509 margin-left: auto; 3510 } 3511 .admin-sidebar-toggle-btn { 3512 display: inline-flex; 3513 align-items: center; 3514 gap: 6px; 3515 padding: 5px 12px; 3516 background: #f8fafc; 3517 border: 1px solid #cbd5e1; 3518 border-radius: 20px; 3519 font-size: 0.78rem; 3520 font-weight: 600; 3521 color: #475569; 3522 cursor: pointer; 3523 transition: all 0.2s ease; 3524 box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); 3525 user-select: none; 3526 } 3527 .admin-sidebar-toggle-btn:hover { 3528 background: #f1f5f9; 3529 border-color: #94a3b8; 3530 color: #0f172a; 3531 } 3532 html.dark .admin-sidebar-toggle-btn, 3533 .dark .admin-sidebar-toggle-btn { 3534 background: #1e293b; 3535 border-color: #334155; 3536 color: #cbd5e1; 3537 } 3538 html.dark .admin-sidebar-toggle-btn:hover, 3539 .dark .admin-sidebar-toggle-btn:hover { 3540 background: #334155; 3541 color: #f8fafc; 3542 } 3543 .admin-sidebar-toggle-btn .toggle-switch { 3544 width: 28px; 3545 height: 16px; 3546 background: #cbd5e1; 3547 border-radius: 10px; 3548 position: relative; 3549 display: inline-block; 3550 transition: background 0.2s ease; 3551 flex-shrink: 0; 3552 } 3553 .admin-sidebar-toggle-btn.is-active .toggle-switch { 3554 background: #10b981; 3555 } 3556 .admin-sidebar-toggle-btn .toggle-switch::after { 3557 content: ''; 3558 position: absolute; 3559 top: 2px; 3560 left: 2px; 3561 width: 12px; 3562 height: 12px; 3563 background: #fff; 3564 border-radius: 50%; 3565 transition: transform 0.2s ease; 3566 box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2); 3567 } 3568 .admin-sidebar-toggle-btn.is-active .toggle-switch::after { 3569 transform: translateX(12px); 3570 } 3571 .admin-toast-notice { 3572 position: fixed; 3573 bottom: 24px; 3574 right: 24px; 3575 background: #0f172a; 3576 color: #fff; 3577 padding: 10px 18px; 3578 border-radius: 10px; 3579 font-size: 0.85rem; 3580 font-weight: 600; 3581 box-shadow: 0 10px 25px rgba(0,0,0,0.2); 3582 z-index: 99999; 3583 opacity: 0; 3584 transform: translateY(10px); 3585 transition: all 0.3s ease; 3586 pointer-events: none; 3587 } 3588 .admin-toast-notice.is-show { 3589 opacity: 1; 3590 transform: translateY(0); 3591 } 3592</style> 3593
3594<script> 3595 function initAdminSidebarToggle() { 3596 const authToken = localStorage.getItem('auth_token'); 3597 if (authToken) { 3598 const wrap = document.getElementById('admin-sidebar-toggle-wrap'); 3599 if (wrap) { 3600 wrap.style.display = 'inline-flex'; 3601 } 3602 } 3603 } 3604 3605 if (document.readyState === 'loading') { 3606 document.addEventListener('DOMContentLoaded', initAdminSidebarToggle); 3607 } else { 3608 initAdminSidebarToggle(); 3609 } 3610 document.addEventListener('inertia:success', initAdminSidebarToggle); 3611 3612 function toggleSidebarAdminSetting(settingKey) { 3613 const authToken = localStorage.getItem('auth_token'); 3614 if (!authToken) { 3615 alert('Administrator session token not found. Please log in to Admin Panel.'); 3616 return; 3617 } 3618 3619 const gridEl = document.querySelector('.grid-sidebar'); 3620 const asideEl = document.querySelector('.grid-sidebar > aside'); 3621 const btnEl = document.getElementById('admin-sidebar-toggle-btn'); 3622 const labelEl = document.getElementById('admin-sidebar-toggle-label'); 3623 3624 if (!gridEl) return; 3625 3626 // Check current state (whether aside is currently visible or hidden) 3627 const isCurrentlyVisible = asideEl 3628 ? (asideEl.style.display !== 'none') 3629 : (!gridEl.classList.contains('no-sidebar')); 3630 3631 const newStatus = isCurrentlyVisible ? 'hide' : 'show'; 3632 const isNowShowing = (newStatus === 'show'); 3633 3634 // 1. Immediate UI Feedback 3635 if (asideEl) { 3636 asideEl.style.display = isNowShowing ? 'block' : 'none'; 3637 } 3638 if (isNowShowing) { 3639 gridEl.classList.remove('no-sidebar'); 3640 gridEl.style.gridTemplateColumns = ''; 3641 } else { 3642 gridEl.classList.add('no-sidebar'); 3643 gridEl.style.gridTemplateColumns = '1fr'; 3644 } 3645 3646 if (btnEl) { 3647 btnEl.classList.toggle('is-active', isNowShowing); 3648 } 3649 if (labelEl) { 3650 labelEl.textContent = isNowShowing ? 'Sidebar: ON' : 'Sidebar: OFF'; 3651 } 3652 3653 showAdminSidebarToast(isNowShowing ? 'Sidebar enabled' : 'Sidebar disabled'); 3654 3655 // 2. Persist to server via Setting API 3656 fetch('/api/v1/settings/group/theme_options', { 3657 method: 'PUT', 3658 headers: { 3659 'Content-Type': 'application/json', 3660 'Accept': 'application/json', 3661 'Authorization': 'Bearer ' + authToken, 3662 'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]')?.getAttribute('content') || '' 3663 }, 3664 body: JSON.stringify({ 3665 key: settingKey, 3666 value: newStatus 3667 }) 3668 }).then(res => res.json()).then(data => { 3669 if (data.success) { 3670 console.log('Sidebar setting updated:', settingKey, newStatus); 3671 } 3672 }).catch(err => { 3673 console.error('Failed to update sidebar setting via API:', err); 3674 }); 3675 } 3676 3677 function showAdminSidebarToast(msg) { 3678 let toast = document.getElementById('admin-sidebar-toast'); 3679 if (!toast) { 3680 toast = document.createElement('div'); 3681 toast.id = 'admin-sidebar-toast'; 3682 toast.className = 'admin-toast-notice'; 3683 document.body.appendChild(toast); 3684 } 3685 toast.textContent = msg; 3686 toast.classList.add('is-show'); 3687 setTimeout(() => { 3688 toast.classList.remove('is-show'); 3689 }, 2500); 3690 } 3691</script>
3691 3692 <div class="listing-toolbar" style="display: flex; align-items: center; justify-content: flex-end; margin-left: auto; gap: 0.75rem; flex-wrap: wrap;"> 3693 3694 <span class="execution-time-badge" data-server-ms="286.63" style="font-size: 0.72rem; font-weight: 500; color: var(--geist-accents-5, #888); white-space: nowrap; display: inline-flex; align-items: center; margin-right: 0.25rem;">286.63 ms</span> 3695 3696 3697 <div class="listing-view-toggle" data-listing-target="products-listing"> 3698 <button type="button" class="view-toggle-btn active" data-view="grid" aria-label="Grid view"> 3699 <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> 3700 <rect x="3" y="3" width="7" height="7"/><rect x="14" y="3" width="7" height="7"/> 3701 <rect x="3" y="14" width="7" height="7"/><rect x="14" y="14" width="7" height="7"/> 3702 </svg> 3703 </button> 3704 <button type="button" class="view-toggle-btn " data-view="list" aria-label="List view"> 3705 <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> 3706 <line x1="8" y1="6" x2="21" y2="6"/><line x1="8" y1="12" x2="21" y2="12"/> 3707 <line x1="8" y1="18" x2="21" y2="18"/><line x1="3" y1="6" x2="3.01" y2="6"/> 3708 <line x1="3" y1="12" x2="3.01" y2="12"/><line x1="3" y1="18" x2="3.01" y2="18"/> 3709 </svg> 3710 </button> 3711 </div> 3712 3713 3714 <div class="fw-sort-tabs"> 3715 3716 <a href="https://headrandom.com/products?sort=best_sellers" 3717 class="fw-sort-tab " 3718 title="Best sellers"> 3719 Best sellers 3720 </a> 3721 3722 3723 <a href="https://headrandom.com/products?sort=newest" 3724 class="fw-sort-tab is-active" 3725 title="Newest"> 3726 Newest 3727 </a> 3728 3729 3730 <a href="https://headrandom.com/products?sort=best_rated" 3731 class="fw-sort-tab " 3732 title="Best rated"> 3733 Best rated 3734 </a> 3735 3736 3737 <a href="https://headrandom.com/products?sort=trending" 3738 class="fw-sort-tab " 3739 title="Trending"> 3740 Trending 3741 </a> 3742 3743 3744 <a href="https://headrandom.com/products?sort=price&order=asc" 3745 class="fw-sort-tab " 3746 title="Price"> 3747 Price <span style="font-size: 0.75rem; margin-left: 2px;">â </span> 3748 </a> 3749 </div> 3750 </div> 3751 </div> 3752 </div> 3753 3754 3755 <style> 3756/* PolyCMS Core Products Slider & Touch Track Styles (Strict Isolation & Prose Immunity) */ 3757.polycms-products-slider-wrap, 3758.fw-featured-slider-wrap { 3759 width: 100%; 3760 margin-bottom: 2rem; 3761 box-sizing: border-box; 3762 position: relative; 3763} 3764.polycms-products-slider-track, 3765.fw-featured-slider-track { 3766 display: flex; 3767 gap: 16px; 3768 overflow-x: auto; 3769 scroll-snap-type: none !important; 3770 scroll-behavior: auto; 3771 -webkit-overflow-scrolling: touch; 3772 padding: 4px 2px 14px 2px; 3773 scrollbar-width: none; 3774 -ms-overflow-style: none; 3775 touch-action: pan-x; 3776} 3777.polycms-products-slider-track::-webkit-scrollbar, 3778.fw-featured-slider-track::-webkit-scrollbar {
3779 display: none; 3780} 3781 3782/* Base Card Container */ 3783.polycms-products-slider-wrap .polycms-products-slide-item, 3784.fw-featured-slider-wrap .fw-featured-slide-item, 3785.polycms-products-slide-item, 3786.fw-featured-slide-item { 3787 flex: 0 0 230px !important; 3788 width: 230px !important; 3789 max-width: 230px !important; 3790 background: var(--geist-background, #ffffff) !important; 3791 border: 1px solid var(--color-border, #e2e8f0) !important; 3792 border-radius: var(--radius, 12px) !important; 3793 overflow: hidden !important; 3794 transition: transform 0.2s ease, box-shadow 0.2s ease, border-color 0.2s ease !important; 3795 display: flex !important; 3796 flex-direction: column !important; 3797 box-sizing: border-box !important; 3798 margin: 0 !important; 3799} 3800.polycms-products-slide-item:hover, 3801.fw-featured-slide-item:hover { 3802 transform: translateY(-3px) !important; 3803 box-shadow: 0 12px 24px -6px rgba(0, 0, 0, 0.08) !important; 3804 border-color: var(--geist-accents-3, #cbd5e1) !important; 3805} 3806 3807/* Card Image Area */ 3808.polycms-products-slider-wrap .polycms-products-item-image, 3809.fw-featured-slider-wrap .fw-featured-item-image, 3810.polycms-products-item-image, 3811.fw-featured-item-image { 3812 position: relative !important; 3813 width: 100% !important; 3814 aspect-ratio: 16 / 10 !important; 3815 overflow: hidden !important; 3816 background: var(--geist-accents-1, #f8fafc) !important; 3817 display: block !important; 3818 margin: 0 !important; 3819 padding: 0 !important; 3820} 3821.polycms-products-item-image img, 3822.fw-featured-item-image img { 3823 width: 100% !important; 3824 height: 100% !important; 3825 object-fit: cover !important; 3826 transition: transform 0.3s ease !important; 3827 pointer-events: none !important; 3828 display: block !important; 3829 margin: 0 !important; 3830} 3831.polycms-products-slide-item:hover .polycms-products-item-image img, 3832.fw-featured-slide-item:hover .fw-featured-item-image img { 3833 transform: scale(1.04) !important; 3834} 3835 3836/* Status Badges */ 3837.polycms-products-slider-wrap .polycms-products-badge, 3838.fw-featured-slider-wrap .fw-featured-badge, 3839.polycms-products-badge, 3840.fw-featured-badge { 3841 position: absolute !important; 3842 top: 8px !important; 3843 left: 8px !important; 3844 padding: 3px 8px !important; 3845 font-size: 0.6875rem !important; /* 11px */ 3846 font-weight: 700 !important; 3847 background: rgba(15, 23, 42, 0.88) !important; 3848 color: #fef08a !important; 3849 border-radius: 6px !important; 3850 backdrop-filter: blur(6px) !important; 3851 -webkit-backdrop-filter: blur(6px) !important; 3852 z-index: 2 !important; 3853 pointer-events: none !important; 3854 line-height: 1 !important; 3855 margin: 0 !important; 3856 display: inline-flex !important; 3857 align-items: center !important; 3858 box-shadow: 0 2px 6px rgba(0, 0, 0, 0.18) !important; 3859 font-family: inherit !important; 3860} 3861.polycms-products-badge .badge-text { 3862 line-height: 1 !important; 3863 white-space: nowrap !important; 3864} 3865.polycms-products-badge-bestseller, 3866.fw-bestseller-badge { 3867 background: rgba(234, 88, 12, 0.92) !important; 3868 color: #fff !important; 3869} 3870.polycms-products-badge-trending { 3871 background: rgba(147, 51, 234, 0.92) !important; 3872 color: #fff !important; 3873} 3874.polycms-products-badge-rated { 3875 background: rgba(202, 138, 4, 0.92) !important; 3876 color: #fff !important; 3877} 3878 3879/* Header Icon Container */ 3880.polycms-slider-header-icon { 3881 display: inline-flex !important; 3882 align-items: center !important; 3883 justify-content: center !important; 3884 width: 28px !important; 3885 height: 28px !important; 3886 border-radius: 50% !important; 3887 background: var(--header-icon-bg, #fef08a) !important; 3888 color: var(--header-icon-color, #a16207) !important; 3889 font-size: 0.85rem !important; 3890 line-height: 1 !important; 3891 flex-shrink: 0 !important; 3892 font-family: 'Apple Color Emoji', 'Segoe UI Emoji', 'Noto Color Emoji', sans-serif !important; 3893 box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05) !important; 3894} 3895.polycms-slider-header-icon svg { 3896 display: block !important; 3897} 3898html.dark .polycms-slider-header-icon, 3899.dark .polycms-slider-header-icon { 3900 background: var(--header-icon-bg-dark, rgba(234, 179, 8, 0.18)) !important; 3901 color: var(--header-icon-color-dark, #facc15) !important; 3902} 3903 3904/* Card Body */ 3905.polycms-products-slider-wrap .polycms-products-item-body, 3906.fw-featured-slider-wrap .fw-featured-item-body, 3907.polycms-products-slide-item .polycms-products-item-body, 3908.fw-featured-slide-item .fw-featured-item-body { 3909 padding: 10px 12px 12px 12px !important; 3910 display: flex !important; 3911 flex-direction: column !important; 3912 flex-grow: 1 !important; 3913 margin: 0 !important; 3914 box-sizing: border-box !important; 3915} 3916 3917/* Category Label */ 3918.polycms-products-slider-wrap .polycms-products-item-cat, 3919.fw-featured-slider-wrap .fw-featured-item-cat, 3920.polycms-products-slide-item .polycms-products-item-cat, 3921.fw-featured-slide-item .fw-featured-item-cat { 3922 font-size: 0.625rem !important; 3923 font-weight: 600 !important; 3924 text-transform: uppercase !important; 3925 letter-spacing: 0.04em !important; 3926 color: var(--geist-accents-5, #64748b) !important; 3927 margin: 0 0 4px 0 !important; 3928 padding: 0 !important; 3929 line-height: 1.2 !important; 3930 white-space: nowrap !important; 3931 overflow: hidden !important; 3932 text-overflow: ellipsis !important; 3933} 3934 3935/* Strict Title Protection against .prose h3 overrides */ 3936.polycms-products-slider-wrap .polycms-products-item-title, 3937.fw-featured-slider-wrap .fw-featured-item-title, 3938.polycms-products-slide-item .polycms-products-item-title, 3939.fw-featured-slide-item .fw-featured-item-title, 3940.polycms-products-slide-item h3, 3941.fw-featured-slide-item h3, 3942.prose .polycms-products-slide-item h3, 3943.prose .fw-featured-slide-item h3 { 3944 font-size: 0.8125rem !important; 3945 font-weight: 600 !important; 3946 line-height: 1.35 !important; 3947 margin: 0 0 6px 0 !important; 3948 padding: 0 !important; 3949 display: -webkit-box !important; 3950 -webkit-line-clamp: 2 !important; 3951 -webkit-box-orient: vertical !important; 3952 overflow: hidden !important; 3953 text-overflow: ellipsis !important; 3954 min-height: 2.2rem !important; 3955 max-height: 2.2rem !important; 3956 height: 2.2rem !important; 3957 letter-spacing: normal !important; 3958 color: var(--geist-foreground, #0f172a) !important; 3959} 3960.polycms-products-slider-wrap .polycms-products-item-title a, 3961.fw-featured-slider-wrap .fw-featured-item-title a, 3962.polycms-products-slide-item h3 a, 3963.fw-featured-slide-item h3 a, 3964.prose .polycms-products-slide-item h3 a, 3965.prose .fw-featured-slide-item h3 a { 3966 font-size: inherit !important; 3967 font-weight: inherit !important; 3968 line-height: inherit !important; 3969 color: var(--geist-foreground, #0f172a) !important; 3970 text-decoration: none !important; 3971 display: inline !important; 3972 transition: color 0.15s ease !important; 3973} 3974.polycms-products-slider-wrap .polycms-products-item-title a:hover, 3975.fw-featured-slider-wrap .fw-featured-item-title a:hover, 3976.polycms-products-slide-item h3 a:hover, 3977.fw-featured-slide-item h3 a:hover, 3978.prose .polycms-products-slide-item h3 a:hover, 3979.prose .fw-featured-slide-item h3 a:hover { 3980 color: var(--primary-color, #3b82f6) !important; 3981} 3982 3983/* Price Row */ 3984.polycms-products-slider-wrap .polycms-products-item-price, 3985.fw-featured-slider-wrap .fw-featured-item-price, 3986.polycms-products-slide-item .polycms-products-item-price, 3987.fw-featured-slide-item .fw-featured-item-price { 3988 margin-top: auto !important; 3989 padding-top: 4px !important; 3990 font-size: 0.875rem !important; 3991 font-weight: 700 !important; 3992 color: var(--geist-foreground, #0f172a) !important; 3993 display: flex !important;
3994 align-items: baseline !important; 3995 gap: 6px !important; 3996 line-height: 1 !important; 3997} 3998.polycms-products-item-price .price-old, 3999.fw-featured-item-price .price-old { 4000 font-size: 0.72rem !important; 4001 color: var(--geist-accents-4, #94a3b8) !important; 4002 text-decoration: line-through !important; 4003 font-weight: 400 !important; 4004} 4005 4006/* Nav Buttons */ 4007.polycms-slider-prev-btn, 4008.polycms-slider-next-btn, 4009.fw-slider-prev-btn, 4010.fw-slider-next-btn { 4011 width: 28px; 4012 height: 28px; 4013 border-radius: 50%; 4014 border: 1px solid var(--color-border, #e2e8f0); 4015 background: var(--geist-background, #fff); 4016 color: var(--geist-foreground, #334155); 4017 font-size: 1.05rem; 4018 line-height: 1; 4019 display: inline-flex; 4020 align-items: center; 4021 justify-content: center; 4022 cursor: pointer; 4023 transition: all 0.15s ease; 4024 user-select: none; 4025} 4026.polycms-slider-prev-btn:hover, 4027.polycms-slider-next-btn:hover, 4028.fw-slider-prev-btn:hover, 4029.fw-slider-next-btn:hover { 4030 background: var(--primary-color, #3b82f6); 4031 color: #ffffff; 4032 border-color: var(--primary-color, #3b82f6); 4033} 4034 4035/* Dark Mode */ 4036html.dark .polycms-products-slide-item, 4037.dark .polycms-products-slide-item, 4038html.dark .fw-featured-slide-item, 4039.dark .fw-featured-slide-item { 4040 background: #0f172a !important; 4041 border-color: rgba(148, 163, 184, 0.2) !important; 4042} 4043html.dark .polycms-slider-prev-btn, 4044html.dark .polycms-slider-next-btn, 4045.dark .polycms-slider-prev-btn, 4046.dark .polycms-slider-next-btn, 4047html.dark .fw-slider-prev-btn, 4048html.dark .fw-slider-next-btn, 4049.dark .fw-slider-prev-btn, 4050.dark .fw-slider-next-btn { 4051 background: #1e293b; 4052 border-color: rgba(148, 163, 184, 0.25); 4053 color: #cbd5e1; 4054} 4055 4056@media (max-width: 640px) { 4057 .polycms-products-slider-wrap .polycms-products-slide-item, 4058 .fw-featured-slider-wrap .fw-featured-slide-item, 4059 .polycms-products-slide-item, 4060 .fw-featured-slide-item { 4061 flex: 0 0 190px !important; 4062 width: 190px !important; 4063 max-width: 190px !important; 4064 } 4065} 4066</style> 4067 4068 <div class="polycms-products-slider-wrap fw-featured-slider-wrap" id="polycms_products_pcs_71fbcc651e" data-instance="pcs_71fbcc651e"> 4069 4070 <div class="polycms-products-slider-header fw-featured-slider-header" style="display: flex; align-items: center; justify-content: space-between; margin-bottom: 1.125rem;"> 4071 <div style="display: flex; align-items: center; gap: 10px;"> 4072 <div> 4073 <h2 class="polycms-products-slider-title fw-featured-slider-title" style="font-size: 1.125rem; font-weight: 700; margin: 0; color: var(--geist-foreground, inherit);"> 4074 Featured Products 4075 </h2> 4076 </div> 4077 </div> 4078 4079 <div style="display: flex; align-items: center; gap: 8px;"> 4080 4081 <div class="polycms-slider-nav-btns fw-slider-nav-btns" style="display: flex; align-items: center; gap: 6px;"> 4082 <button type="button" class="polycms-slider-prev-btn fw-slider-prev-btn" aria-label="Previous" data-nav="prev">â¹</button> 4083 <button type="button" class="polycms-slider-next-btn fw-slider-next-btn" aria-label="Next" data-nav="next">âº</button> 4084 </div> 4085 </div> 4086 </div> 4087 4088 4089 <div id="track_pcs_71fbcc651e" class="polycms-products-slider-track fw-featured-slider-track" data-slider-instance="pcs_71fbcc651e"> 4090 <article class="polycms-products-slide-item fw-featured-slide-item" style="position: relative;"> 4091 <a href="/products/mtxstudio" class="polycms-products-item-image fw-featured-item-image"> 4092 <img src="https://headrandom.com/storage/media/2026/09/thumbs/mtxvoice-screenshot-20260906-202846_featured_565x318.webp" alt="MTxStudio - AI Video Voiceover &
4092 Multi-Track Studio" loading="lazy" decoding="async" class="polycms-lazy-img" onload="this.classList.add('polycms-loaded')"> 4093 4094 <span class="polycms-products-badge polycms-products-badge-featured fw-featured-badge"> 4095 <span class="badge-text">Featured</span> 4096 </span> 4097 </a> 4098 4099 <div class="admin-card-edit-wrap" onclick="event.stopPropagation();"> 4100 4101 <button type="button" 4102 class="admin-card-edit-btn admin-card-visibility-btn is-visible" 4103 data-product-id="96" 4104 data-visibility="visible" 4105 title="Catalog Visibility: Visible (Click to Hide)" 4106 aria-label="Catalog Visibility: Visible (Click to Hide)" 4107 onclick="event.stopPropagation(); event.preventDefault(); toggleAdminCardCatalogVisibility(this, 96);"> 4108 <i class="fas fa-eye"></i> 4109 </button> 4110 4111 <div class="admin-card-edit-dropdown"> 4112 <button type="button" 4113 class="admin-card-edit-btn" 4114 title="Edit Options" 4115 aria-label="Edit Options" 4116 onclick="event.stopPropagation(); event.preventDefault(); const m = this.nextElementSibling; if (m) { m.style.display = (m.style.display === 'none' || !m.style.display) ? 'block' : 'none'; }"> 4117 <i class="fas fa-pencil-alt"></i> 4118 </button> 4119 <div class="admin-card-edit-menu" style="display: none;"> 4120 <a href="https://headrandom.com/admin/products/96/edit" target="_blank" onclick="event.stopPropagation();"> 4121 <i class="fas fa-pencil-alt"></i> 4122 <span>Edit Product</span> 4123 </a> 4124 <a href="https://headrandom.com/admin/project-hub/87/edit" target="_blank" onclick="event.stopPropagation();"> 4125 <i class="fas fa-folder"></i> 4126 <span>Edit Project Hub</span> 4127 </a> 4128 </div> 4129 </div> 4130 </div> 4131
4132<script> 4133window.toggleAdminCardCatalogVisibility = function(btn, productId) { 4134 const authToken = localStorage.getItem('auth_token'); 4135 if (!authToken) { 4136 alert('Administrator session token not found. Please log in to Admin Panel.'); 4137 return; 4138 } 4139 4140 if (btn.classList.contains('is-loading')) return; 4141 4142 const currentVis = btn.getAttribute('data-visibility') || 'visible'; 4143 const isCurrentlyHidden = (currentVis === 'hidden'); 4144 const targetVis = isCurrentlyHidden ? 'visible' : 'hidden'; 4145 4146 // Set loading state on button(s) with this product ID 4147 const matchingBtns = document.querySelectorAll('.admin-card-visibility-btn[data-product-id="' + productId + '"]'); 4148 matchingBtns.forEach(function(b) { 4149 b.classList.add('is-loading'); 4150 const ic = b.querySelector('i'); 4151 if (ic) ic.className = 'fas fa-spinner fa-spin'; 4152 }); 4153 4154 const csrfToken = document.querySelector('meta[name="csrf-token"]')?.getAttribute('content') || ''; 4155 4156 fetch('/api/v1/products/' + productId + '/toggle-catalog-visibility', { 4157 method: 'PATCH', 4158 headers: { 4159 'Content-Type': 'application/json', 4160 'Accept': 'application/json', 4161 'Authorization': 'Bearer ' + authToken, 4162 'X-CSRF-TOKEN': csrfToken 4163 }, 4164 body: JSON.stringify({ 4165 visibility: targetVis 4166 }) 4167 }) 4168 .then(function(res) { 4169 if (!res.ok) { 4170 throw new Error('HTTP ' + res.status); 4171 } 4172 return res.json(); 4173 }) 4174 .then(function(data) { 4175 const newVis = data.data?.catalog_visibility || targetVis; 4176 const isHiddenNow = (newVis === 'hidden'); 4177 4178 matchingBtns.forEach(function(b) { 4179 b.classList.remove('is-loading'); 4180 b.setAttribute('data-visibility', isHiddenNow ? 'hidden' : 'visible'); 4181 const ic = b.querySelector('i'); 4182 if (isHiddenNow) { 4183 b.classList.remove('is-visible'); 4184 b.classList.add('is-hidden'); 4185 if (ic) ic.className = 'fas fa-eye-slash'; 4186 b.setAttribute('title', 'Catalog Visibility: Hidden (Click to Show)'); 4187 b.setAttribute('aria-label', 'Catalog Visibility: Hidden (Click to Show)'); 4188 } else { 4189 b.classList.remove('is-hidden'); 4190 b.classList.add('is-visible'); 4191 if (ic) ic.className = 'fas fa-eye'; 4192 b.setAttribute('title', 'Catalog Visibility: Visible (Click to Hide)'); 4193 b.setAttribute('aria-label', 'Catalog Visibility: Visible (Click to Hide)'); 4194 } 4195 4196 const card = b.closest('.listing-card, .polycms-products-item, article'); 4197 if (card) { 4198 card.classList.toggle('is-catalog-hidden', isHiddenNow); 4199 } 4200 }); 4201 4202 showAdminCardQuickToast(isHiddenNow 4203 ? 'Product is now hidden from catalog' 4204 : 'Product is now visible in catalog'); 4205 }) 4206 .catch(function(err) { 4207 matchingBtns.forEach(function(b) { 4208 b.classList.remove('is-loading'); 4209 const ic = b.querySelector('i'); 4210 if (ic) ic.className = isCurrentlyHidden ? 'fas fa-eye-slash' : 'fas fa-eye'; 4211 }); 4212 console.error('Failed to toggle catalog visibility:', err); 4213 showAdminCardQuickToast('Failed to update visibility', true); 4214 }); 4215}; 4216 4217function showAdminCardQuickToast(msg, isError) { 4218 let toast = document.getElementById('admin-card-quick-toast'); 4219 if (!toast) { 4220 toast = document.createElement('div'); 4221 toast.id = 'admin-card-quick-toast'; 4222 toast.className = 'admin-card-quick-toast'; 4223 document.body.appendChild(toast); 4224 } 4225 toast.textContent = msg; 4226 toast.className = 'admin-card-quick-toast is-show' + (isError ? ' is-error' : ''); 4227 clearTimeout(toast._timer); 4228 toast._timer = setTimeout(function() { 4229 toast.classList.remove('is-show'); 4230 }, 3200); 4231} 4232</script>
4232 4233 4234 <div class="polycms-products-item-body fw-featured-item-body"> 4235 <div class="polycms-products-item-cat fw-featured-item-cat">Desktop Apps</div> 4236 4237 <h3 class="polycms-products-item-title fw-featured-item-title"> 4238 <a href="/products/mtxstudio">MTxStudio - AI Video Voiceover & Multi-Track Studio</a> 4239 </h3> 4240 4241 <div class="polycms-products-item-price fw-featured-item-price"> 4242 <span class="price-current font-bold">Free</span> 4243 </div> 4244 </div> 4245 </article> 4246 <article class="polycms-products-slide-item fw-featured-slide-item" style="position: relative;"> 4247 <a href="/products/fengshui-moving-date-for-wordpress" class="polycms-products-item-image fw-featured-item-image"> 4248 <img src="https://headrandom.com/storage/media/2026/08/thumbs/fengshui-moving-date-for-wordpress_featured_563x375.webp" alt="FengShui Moving Date for WordPress" loading="lazy" decoding="async" class="polycms-lazy-img" onload="this.classList.add('polycms-loaded')"> 4249 4250 <span class="polycms-products-badge polycms-products-badge-featured fw-featured-badge"> 4251 <span class="badge-text">Featured</span> 4252 </span> 4253 </a> 4254 4255 <div class="admin-card-edit-wrap" onclick="event.stopPropagation();"> 4256 4257 <button type="button" 4258 class="admin-card-edit-btn admin-card-visibility-btn is-visible" 4259 data-product-id="50" 4260 data-visibility="visible" 4261 title="Catalog Visibility: Visible (Click to Hide)" 4262 aria-label="Catalog Visibility: Visible (Click to Hide)" 4263 onclick="event.stopPropagation(); event.preventDefault(); toggleAdminCardCatalogVisibility(this, 50);"> 4264 <i class="fas fa-eye"></i> 4265 </button> 4266 4267 <div class="admin-card-edit-dropdown"> 4268 <button type="button" 4269 class="admin-card-edit-btn" 4270 title="Edit Options" 4271 aria-label="Edit Options" 4272 onclick="event.stopPropagation(); event.preventDefault(); const m = this.nextElementSibling; if (m) { m.style.display = (m.style.display === 'none' || !m.style.display) ? 'block' : 'none'; }"> 4273 <i class="fas fa-pencil-alt"></i> 4274 </button> 4275 <div class="admin-card-edit-menu" style="display: none;"> 4276 <a href="https://headrandom.com/admin/products/50/edit" target="_blank" onclick="event.stopPropagation();"> 4277 <i class="fas fa-pencil-alt"></i> 4278 <span>Edit Product</span> 4279 </a> 4280 <a href="https://headrandom.com/admin/project-hub/51/edit" target="_blank" onclick="event.stopPropagation();"> 4281 <i class="fas fa-folder"></i> 4282 <span>Edit Project Hub</span> 4283 </a> 4284 </div> 4285 </div> 4286 </div> 4287 4288 4289 <div class="polycms-products-item-body fw-featured-item-body"> 4290 <div class="pol
4290ycms-products-item-cat fw-featured-item-cat">WordPress</div> 4291 4292 <h3 class="polycms-products-item-title fw-featured-item-title"> 4293 <a href="/products/fengshui-moving-date-for-wordpress">FengShui Moving Date for WordPress</a> 4294 </h3> 4295 4296 <div class="polycms-products-item-price fw-featured-item-price"> 4297 <span class="price-current font-bold">$49.00</span> 4298 </div> 4299 </div> 4300 </article> 4301 <article class="polycms-products-slide-item fw-featured-slide-item" style="position: relative;"> 4302 <a href="/products/mtmedia-web-automation-recorder" class="polycms-products-item-image fw-featured-item-image"> 4303 <img src="https://headrandom.com/storage/media/2026/07/thumbs/mtmedia_featured_565x318.webp" alt="MTMedia - Automated Web Recording & Media Creation Suite for Windows & macOS" loading="lazy" decoding="async" class="polycms-lazy-img" onload="this.classList.add('polycms-loaded')"> 4304 4305 <span class="polycms-products-badge polycms-products-badge-featured fw-featured-badge"> 4306 <span class="badge-text">Featured</span> 4307 </span> 4308 </a> 4309 4310 <div class="admin-card-edit-wrap" onclick="event.stopPropagation();"> 4311 4312 <button type="button" 4313 class="admin-card-edit-btn admin-card-visibility-btn is-visible" 4314 data-product-id="43" 4315 data-visibility="visible" 4316 title="Catalog Visibility: Visible (Click to Hide)" 4317 aria-label="Catalog Visibility: Visible (Click to Hide)" 4318 onclick="event.stopPropagation(); event.preventDefault(); toggleAdminCardCatalogVisibility(this, 43);"> 4319 <i class="fas fa-eye"></i> 4320 </button> 4321 4322 <div class="admin-card-edit-dropdown"> 4323 <button type="button" 4324 class="admin-card-edit-btn" 4325 title="Edit Options" 4326 aria-label="Edit Options" 4327 onclick="event.stopPropagation(); event.preventDefault(); const m = this.nextElementSibling; if (m) { m.style.display = (m.style.display === 'none' || !m.style.display) ? 'block' : 'none'; }"> 4328 <i class="fas fa-pencil-alt"></i> 4329 </button> 4330 <div class="admin-card-edit-menu" style="display: none;"> 4331 <a href="https://headrandom.com/admin/products/43/edit" target="_blank" onclick="event.stopPropagation();"> 4332 <i class="fas fa-pencil-alt"></i> 4333 <span>Edit Product</span> 4334 </a> 4335 <a href="https://headrandom.com/admin/project-hub/45/edit" target="_blank" onclick="event.stopPropagation();"> 4336 <i class="fas fa-folder"></i> 4337 <span>Edit Project Hub</span> 4338 </a> 4339 </div> 4340 </div> 4341 </div> 4342 4343 4344 <div class="polycms-products-item-body fw-featured-item-body"> 4345 <div class="polycms-products-item-cat fw-featured-item-cat">Desktop Apps</div> 4346 4347 <h3 class="pol
4347ycms-products-item-title fw-featured-item-title"> 4348 <a href="/products/mtmedia-web-automation-recorder">MTMedia - Automated Web Recording & Media Creation Suite for Windows & macOS</a> 4349 </h3> 4350 4351 <div class="polycms-products-item-price fw-featured-item-price"> 4352 <span class="price-current font-bold">Free</span> 4353 </div> 4354 </div> 4355 </article> 4356 <article class="polycms-products-slide-item fw-featured-slide-item" style="position: relative;"> 4357 <a href="/products/polycms-cms-website-builder-module-for-perfex-crm" class="polycms-products-item-image fw-featured-item-image"> 4358 <img src="https://headrandom.com/storage/media/2026/05/thumbs/CMS-for-PerfexCRM_featured_565x318.webp" alt="PolyCMS - CMS & Website Builder Module for Perfex CRM" loading="lazy" decoding="async" class="polycms-lazy-img" onload="this.classList.add('polycms-loaded')"> 4359 4360 <span class="polycms-products-badge polycms-products-badge-featured fw-featured-badge"> 4361 <span class="badge-text">Featured</span> 4362 </span> 4363 </a> 4364 4365 <div class="admin-card-edit-wrap" onclick="event.stopPropagation();"> 4366 4367 <button type="button" 4368 class="admin-card-edit-btn admin-card-visibility-btn is-visible" 4369 data-product-id="9" 4370 data-visibility="visible" 4371 title="Catalog Visibility: Visible (Click to Hide)" 4372 aria-label="Catalog Visibility: Visible (Click to Hide)" 4373 onclick="event.stopPropagation(); event.preventDefault(); toggleAdminCardCatalogVisibility(this, 9);"> 4374 <i class="fas fa-eye"></i> 4375 </button> 4376 4377 <div class="admin-card-edit-dropdown"> 4378 <button type="button" 4379 class="admin-card-edit-btn" 4380 title="Edit Options" 4381 aria-label="Edit Options" 4382 onclick="event.stopPropagation(); event.preventDefault(); const m = this.nextElementSibling; if (m) { m.style.display = (m.style.display === 'none' || !m.style.display) ? 'block' : 'none'; }"> 4383 <i class="fas fa-pencil-alt"></i> 4384 </button> 4385 <div class="admin-card-edit-menu" style="display: none;"> 4386 <a href="https://headrandom.com/admin/products/9/edit" target="_blank" onclick="event.stopPropagation();"> 4387 <i class="fas fa-pencil-alt"></i> 4388 <span>Edit Product</span> 4389 </a> 4390 <a href="https://headrandom.com/admin/project-hub/3/edit" target="_blank" onclick="event.stopPropagation();"> 4391 <i class="fas fa-folder"></i> 4392 <span>Edit Project Hub</span> 4393 </a> 4394 </div> 4395 </div> 4396 </div> 4397 4398 4399 <div class="polycms-products-item-body fw-featured-item-body"> 4400 <div class="polycms-products-item-cat fw-featured-item-cat">Modules for Perfex CRM</div> 4401 4402 <h3 class="polycms-products-item-title fw-featured-item-title"> 4403 <a href="/products/polycms-cms-website-builder
4403-module-for-perfex-crm">PolyCMS - CMS & Website Builder Module for Perfex CRM</a> 4404 </h3> 4405 4406 <div class="polycms-products-item-price fw-featured-item-price"> 4407 <span class="price-current font-bold">$19.00</span> 4408 </div> 4409 </div> 4410 </article> 4411 </div> 4412 4413 4414
4414<script> 4415 (function() { 4416 var instanceUid = 'pcs_71fbcc651e'; 4417 var root = document.getElementById('polycms_products_pcs_71fbcc651e'); 4418 var track = document.getElementById('track_pcs_71fbcc651e'); 4419 if (!track || !root) return; 4420 4421 // Ensure browser scroll-snap is disabled on track to prevent sub-pixel locking 4422 track.style.scrollSnapType = 'none'; 4423 track.style.scrollBehavior = 'auto'; 4424 4425 var isAutoplay = true; 4426 var mode = 'continuous'; // 'continuous' or 'stepped' 4427 var direction = 'left'; // 'left' or 'right' 4428 var dirMultiplier = (direction === 'right' || direction === 'backward' || direction === 'reverse') ? -1 : 1; 4429 var continuousSpeed = 35; // px/sec 4430 var steppedSpeed = 4000; // ms 4431 var pauseOnHover = true; 4432 4433 var isInteracting = false; 4434 var resumeTimer = null; 4435 var singleSetWidth = 0; 4436 var rafId = null; 4437 var intervalId = null; 4438 var lastTimestamp = 0; 4439 4440 // Clone initial set to ensure seamless infinite looping without jumping 4441 var originalItems = Array.prototype.slice.call(track.children); 4442 if (originalItems.length >= 2) { 4443 originalItems.forEach(function(item) { 4444 var clone = item.cloneNode(true); 4445 clone.setAttribute('aria-hidden', 'true'); 4446 clone.setAttribute('data-cloned', 'true'); 4447 track.appendChild(clone); 4448 }); 4449 } 4450 4451 function computeSingleSetWidth() { 4452 var total = 0; 4453 originalItems.forEach(function(el) { 4454 total += el.offsetWidth + 16; // width + gap 4455 }); 4456 singleSetWidth = total || (track.scrollWidth / 2); 4457 } 4458 4459 computeSingleSetWidth(); 4460 window.addEventListener('resize', computeSingleSetWidth); 4461 4462 function getScrollStep() { 4463 var firstItem = track.querySelector('.polycms-products-slide-item, .fw-featured-slide-item'); 4464 return firstItem ? (firstItem.offsetWidth + 16) : 246; 4465 } 4466 4467 function scheduleResume(delayMs) { 4468 if (resumeTimer) { 4469 clearTimeout(resumeTimer); 4470 resumeTimer = null; 4471 } 4472 if (!isAutoplay) return; 4473 4474 resumeTimer = setTimeout(function() { 4475 isInteracting = false; 4476 lastTimestamp = performance.now(); 4477 }, delayMs || 3500); 4478 } 4479 4480 function pauseTemporary() { 4481 isInteracting = true; 4482 if (resumeTimer) { 4483 clearTimeout(resumeTimer); 4484 resumeTimer = null; 4485 } 4486 } 4487 4488 // Nav button bindings (Prev / Next scoped strictly to this root instance) 4489 var prevBtn = root.querySelector('[data-nav="prev"]'); 4490 var nextBtn = root.querySelector('[data-nav="next"]'); 4491 4492 if (prevBtn) { 4493 prevBtn.addEventListener('click', function(e) { 4494 e.preventDefault(); 4495 pauseTemporary(); 4496 var step = getScrollStep(); 4497 4498 // Instant wrap jump without smooth animation 4499 track.style.scrollBehavior = 'auto'; 4500 if (track.scrollLeft <= 5) { 4501 track.scrollLeft += singleSetWidth; 4502 } 4503 void track.offsetWidth; // Force reflow 4504 4505 // Perform smooth step backwards 4506 track.style.scrollBehavior = 'smooth'; 4507 track.scrollBy({ left: -step, behavior: 'smooth' }); 4508 scheduleResume(4000); 4509 }); 4510 } 4511 4512 if (nextBtn) { 4513 nextBtn.addEventListener('click', function(e) { 4514 e.preventDefault(); 4515 pauseTemporary(); 4516 var step = getScrollStep(); 4517 4518 track.style.scrollBehavior = 'smooth'; 4519 track.scrollBy({ left: step, behavior: 'smooth' }); 4520 4521 setTimeout(function() { 4522 if (track && track.scrollLeft >= singleSetWidth) { 4523 track.style.scrollBehavior = 'auto'; 4524 track.scrollLeft -= singleSetWidth; 4525 void track.offsetWidth; 4526 } 4527 }, 400); 4528 4529 scheduleResume(4000); 4530 }); 4531 } 4532
4533 // Touch & Mobile Gestures Support (Natural swipe with boundary wrap and auto-resume) 4534 track.addEventListener('touchstart', function() { 4535 pauseTemporary(); 4536 track.style.scrollBehavior = 'auto'; 4537 }, { passive: true }); 4538 4539 track.addEventListener('touchmove', function() { 4540 pauseTemporary(); 4541 if (singleSetWidth > 0) { 4542 if (track.scrollLeft >= singleSetWidth * 1.8) { 4543 track.scrollLeft -= singleSetWidth; 4544 } else if (track.scrollLeft <= 0) { 4545 track.scrollLeft += singleSetWidth; 4546 } 4547 } 4548 }, { passive: true }); 4549 4550 track.addEventListener('touchend', function() { 4551 scheduleResume(3500); 4552 }, { passive: true }); 4553 4554 // Desktop Hover Pausing 4555 if (pauseOnHover) { 4556 track.addEventListener('mouseenter', function() { 4557 pauseTemporary(); 4558 }); 4559 track.addEventListener('mouseleave', function() { 4560 scheduleResume(1500); 4561 }); 4562 } 4563 4564 // Continuous 1-Direction Smooth Marquee Flow 4565 function continuousLoop(timestamp) { 4566 if (!lastTimestamp) lastTimestamp = timestamp; 4567 var delta = (timestamp - lastTimestamp) / 1000; 4568 lastTimestamp = timestamp; 4569 4570 if (!isInteracting && track && singleSetWidth > 0) { 4571 track.style.scrollBehavior = 'auto'; 4572 if (dirMultiplier === 1) { 4573 track.scrollLeft += continuousSpeed * delta; 4574 if (track.scrollLeft >= singleSetWidth) { 4575 track.scrollLeft -= singleSetWidth; 4576 } 4577 } else { 4578 track.scrollLeft -= continuousSpeed * delta; 4579 if (track.scrollLeft <= 0) { 4580 track.scrollLeft += singleSetWidth; 4581 } 4582 } 4583 } 4584 4585 rafId = requestAnimationFrame(continuousLoop); 4586 } 4587 4588 // Stepped 1-Direction Slide 4589 function steppedTick() { 4590 if (isInteracting || !track || singleSetWidth <= 0) return; 4591 var step = getScrollStep() * dirMultiplier; 4592 if (dirMultiplier === -1 && track.scrollLeft <= 5) { 4593 track.style.scrollBehavior = 'auto'; 4594 track.scrollLeft += singleSetWidth; 4595 void track.offsetWidth; 4596 } 4597 track.style.scrollBehavior = 'smooth'; 4598 track.scrollBy({ left: step, behavior: 'smooth' }); 4599 setTimeout(function() { 4600 if (track && track.scrollLeft >= singleSetWidth) { 4601 track.style.scrollBehavior = 'auto'; 4602 track.scrollLeft -= singleSetWidth; 4603 void track.offsetWidth; 4604 } 4605 }, 500); 4606 } 4607 4608 // Start Autoplay Engine 4609 if (isAutoplay) { 4610 if (mode === 'continuous') { 4611 rafId = requestAnimationFrame(continuousLoop); 4612 } else { 4613 intervalId = setInterval(steppedTick, steppedSpeed); 4614 } 4615 } 4616 })(); 4617 </script>
4617 4618 </div> 4619 4620 <div id="products-listing" 4621 class="listing-container" 4622 data-columns="3" 4623 style="--listing-columns: 3"> 4624
4624<script>/*<![CDATA[*/(function(){try{var v=localStorage.getItem('polycms_view_products-listing');if(v==='list'||v==='grid')document.currentScript.parentElement.classList.add('is-'+v);else document.currentScript.parentElement.classList.add('is-grid')}catch(e){document.currentScript.parentElement.classList.add('is-grid')}})();/*]]>*/</script>
4624 4625 4626 <article class="listing-card"> 4627 4628 <a href="/products/omnimention" class="listing-card__image"> 4629 <img src="https://headrandom.com/storage/media/mtxstudio/thumbs/omnimention-for-perfex-cover_featured_565x318.webp" alt="OmniMention for Perfex CRM - Universal Mention & Entity Tagging Ecosystem" loading="lazy" decoding="async" class="polycms-lazy-img" onload="this.classList.add('polycms-loaded')"> 4630 </a> 4631 <div class="admin-card-edit-wrap" onclick="event.stopPropagation();"> 4632 4633 <button type="button" 4634 class="admin-card-edit-btn admin-card-visibility-btn is-visible" 4635 data-product-id="106" 4636 data-visibility="visible" 4637 title="Catalog Visibility: Visible (Click to Hide)" 4638 aria-label="Catalog Visibility: Visible (Click to Hide)" 4639 onclick="event.stopPropagation(); event.preventDefault(); toggleAdminCardCatalogVisibility(this, 106);"> 4640 <i class="fas fa-eye"></i> 4641 </button> 4642 4643 <div class="admin-card-edit-dropdown"> 4644 <button type="button" 4645 class="admin-card-edit-btn" 4646 title="Edit Options" 4647 aria-label="Edit Options" 4648 onclick="event.stopPropagation(); event.preventDefault(); const m = this.nextElementSibling; if (m) { m.style.display = (m.style.display === 'none' || !m.style.display) ? 'block' : 'none'; }"> 4649 <i class="fas fa-pencil-alt"></i> 4650 </button> 4651 <div class="admin-card-edit-menu" style="display: none;"> 4652 <a href="https://headrandom.com/admin/products/106/edit" target="_blank" onclick="event.stopPropagation();"> 4653 <i class="fas fa-pencil-alt"></i> 4654 <span>Edit Product</span> 4655 </a> 4656 <a href="https://headrandom.com/admin/project-hub/97/edit" target="_blank" onclick="event.stopPropagation();"> 4657 <i class="fas fa-folder"></i> 4658 <span>Edit Project Hub</span> 4659 </a> 4660 </div> 4661 </div> 4662 </div> 4663 4664 4665 <div class="listing-card__body"> 4666 <div class="listing-card__meta" style="margin-bottom: 8px;"> 4667 <a href="/product-categories/modules-for-perfex-crm" class="badge">Modules for Perfex CRM</a> 4668 </div> 4669 4670 <h3 class="listing-card__title"> 4671 <a href="/products/omnimention">OmniMention for Perfex CRM - Universal Mention & Entity Tagging Ecosystem</a> 4672 </h3> 4673 4674 4675 <div class="listing-card__meta" style="margin-bottom: 12px;"> 4676 <span class="listing-card__sku">SKU: omnimention</span> 4677 </div> 4678 4679 <div class="listing-card__price-row" style="display: flex; justify-content: space-between; align-items: center; gap: 8px; border-top: 1px solid var(--border-color, #e2e8f0); padding-top: 10px; margin-top: 10px; flex-wrap: wrap;"> 4680 <div class="listing-card__price" style="margin: 0;"> 4681 <span class="price-current">$39</span>
4682 <span class="price-original">$49</span> 4683 <span class="price-badge">SALE</span> 4684 </div> 4685 4686 <div class="listing-card__icons" style="display: flex; align-items: center; gap: 10px; font-size: 0.8rem; color: #64748b;"> 4687 <span class="stats-views" style="display: inline-flex; align-items: center; gap: 3px;" title="Views"> 4688 <i class="far fa-eye" style="font-size: 0.8rem;"></i> 4689 <span>15</span> 4690 </span> 4691 </div> 4692 </div> 4693 </div> 4694 </article> 4695 <article class="listing-card"> 4696 4697 <a href="/products/mtxelevenlabs" class="listing-card__image"> 4698 <img src="https://headrandom.com/storage/media/2026/05/thumbs/HeadRandom-1_featured_565x315.webp" alt="ElevenLabs Voice & SFX Studio - Neural TTS & Cinematic Sound Effects" loading="lazy" decoding="async" class="polycms-lazy-img" onload="this.classList.add('polycms-loaded')"> 4699 </a> 4700 <div class="admin-card-edit-wrap" onclick="event.stopPropagation();"> 4701 4702 <button type="button" 4703 class="admin-card-edit-btn admin-card-visibility-btn is-visible" 4704 data-product-id="104" 4705 data-visibility="visible" 4706 title="Catalog Visibility: Visible (Click to Hide)" 4707 aria-label="Catalog Visibility: Visible (Click to Hide)" 4708 onclick="event.stopPropagation(); event.preventDefault(); toggleAdminCardCatalogVisibility(this, 104);"> 4709 <i class="fas fa-eye"></i> 4710 </button> 4711 4712 <div class="admin-card-edit-dropdown"> 4713 <button type="button" 4714 class="admin-card-edit-btn" 4715 title="Edit Options" 4716 aria-label="Edit Options" 4717 onclick="event.stopPropagation(); event.preventDefault(); const m = this.nextElementSibling; if (m) { m.style.display = (m.style.display === 'none' || !m.style.display) ? 'block' : 'none'; }"> 4718 <i class="fas fa-pencil-alt"></i> 4719 </button> 4720 <div class="admin-card-edit-menu" style="display: none;"> 4721 <a href="https://headrandom.com/admin/products/104/edit" target="_blank" onclick="event.stopPropagation();"> 4722 <i class="fas fa-pencil-alt"></i> 4723 <span>Edit Product</span> 4724 </a> 4725 <a href="https://headrandom.com/admin/project-hub/95/edit" target="_blank" onclick="event.stopPropagation();"> 4726 <i class="fas fa-folder"></i> 4727 <span>Edit Project Hub</span> 4728 </a> 4729 </div> 4730 </div> 4731 </div> 4732 4733 4734 <div class="listing-card__body"> 4735 <div class="listing-card__meta" style="margin-bottom: 8px;"> 4736 <a href="/product-categories/desktop-apps" class="badge">Desktop Apps</a> 4737 </div> 4738 4739 <h3 class="listing-card__title"> 4740 <a href="/products/mtxelevenlabs">ElevenLabs Voice & SFX Studio - Neural TTS & Cinematic Sound Effects</a> 4741 </h3> 4742 4743 4744 <div class="listing-card__meta" style="margin-bottom: 12px;"> 4745 <sp
4745an class="listing-card__sku">SKU: mtxelevenlabs</span> 4746 </div> 4747 4748 <div class="listing-card__price-row" style="display: flex; justify-content: space-between; align-items: center; gap: 8px; border-top: 1px solid var(--border-color, #e2e8f0); padding-top: 10px; margin-top: 10px; flex-wrap: wrap;"> 4749 <div class="listing-card__price" style="margin: 0;"> 4750 <span class="price-current">$0</span> 4751 </div> 4752 4753 <div class="listing-card__icons" style="display: flex; align-items: center; gap: 10px; font-size: 0.8rem; color: #64748b;"> 4754 <span class="stats-views" style="display: inline-flex; align-items: center; gap: 3px;" title="Views"> 4755 <i class="far fa-eye" style="font-size: 0.8rem;"></i> 4756 <span>33</span> 4757 </span> 4758 </div> 4759 </div> 4760 </div> 4761 </article> 4762 <article class="listing-card"> 4763 4764 <a href="/products/mtxchannelmanager" class="listing-card__image"> 4765 <img src="https://headrandom.com/storage/media/2026/05/thumbs/HeadRandom-1_featured_565x315.webp" alt="MTxChannelManager - Multi-Platform Video Distribution Hub" loading="lazy" decoding="async" class="polycms-lazy-img" onload="this.classList.add('polycms-loaded')"> 4766 </a> 4767 <div class="admin-card-edit-wrap" onclick="event.stopPropagation();"> 4768 4769 <button type="button" 4770 class="admin-card-edit-btn admin-card-visibility-btn is-visible" 4771 data-product-id="102" 4772 data-visibility="visible" 4773 title="Catalog Visibility: Visible (Click to Hide)" 4774 aria-label="Catalog Visibility: Visible (Click to Hide)" 4775 onclick="event.stopPropagation(); event.preventDefault(); toggleAdminCardCatalogVisibility(this, 102);"> 4776 <i class="fas fa-eye"></i> 4777 </button> 4778 4779 <div class="admin-card-edit-dropdown"> 4780 <button type="button" 4781 class="admin-card-edit-btn" 4782 title="Edit Options" 4783 aria-label="Edit Options" 4784 onclick="event.stopPropagation(); event.preventDefault(); const m = this.nextElementSibling; if (m) { m.style.display = (m.style.display === 'none' || !m.style.display) ? 'block' : 'none'; }"> 4785 <i class="fas fa-pencil-alt"></i> 4786 </button> 4787 <div class="admin-card-edit-menu" style="display: none;"> 4788 <a href="https://headrandom.com/admin/products/102/edit" target="_blank" onclick="event.stopPropagation();"> 4789 <i class="fas fa-pencil-alt"></i> 4790 <span>Edit Product</span> 4791 </a> 4792 <a href="https://headrandom.com/admin/project-hub/93/edit" target="_blank" onclick="event.stopPropagation();"> 4793 <i class="fas fa-folder"></i> 4794 <span>Edit Project Hub</span> 4795 </a> 4796 </div> 4797 </div> 4798 </div> 4799 4800 4801 <div class="listing-card__body"> 4802 <div class="listing-card__meta" style="margin-bottom: 8px;"> 4803 <a href="/product-categories/desktop-apps" class="badge">Desktop Apps</a> 4804 </div> 4805 4806 <h3 class="listing-card__title"> 4807 <a href="/products/mtxchannelmanager">
4807MTxChannelManager - Multi-Platform Video Distribution Hub</a> 4808 </h3> 4809 4810 4811 <div class="listing-card__meta" style="margin-bottom: 12px;"> 4812 <span class="listing-card__sku">SKU: mtxchannelmanager</span> 4813 </div> 4814 4815 <div class="listing-card__price-row" style="display: flex; justify-content: space-between; align-items: center; gap: 8px; border-top: 1px solid var(--border-color, #e2e8f0); padding-top: 10px; margin-top: 10px; flex-wrap: wrap;"> 4816 <div class="listing-card__price" style="margin: 0;"> 4817 <span class="price-current">$1</span> 4818 </div> 4819 4820 <div class="listing-card__icons" style="display: flex; align-items: center; gap: 10px; font-size: 0.8rem; color: #64748b;"> 4821 <span class="stats-views" style="display: inline-flex; align-items: center; gap: 3px;" title="Views"> 4822 <i class="far fa-eye" style="font-size: 0.8rem;"></i> 4823 <span>40</span> 4824 </span> 4825 </div> 4826 </div> 4827 </div> 4828 </article> 4829 <article class="listing-card"> 4830 4831 <a href="/products/mtxdownloader" class="listing-card__image"> 4832 <img src="https://headrandom.com/storage/media/2026/05/thumbs/HeadRandom-1_featured_565x315.webp" alt="MTxDownloader - Bulk Video Media Vault & Queue Manager" loading="lazy" decoding="async" class="polycms-lazy-img" onload="this.classList.add('polycms-loaded')"> 4833 </a> 4834 <div class="admin-card-edit-wrap" onclick="event.stopPropagation();"> 4835 4836 <button type="button" 4837 class="admin-card-edit-btn admin-card-visibility-btn is-visible" 4838 data-product-id="100" 4839 data-visibility="visible" 4840 title="Catalog Visibility: Visible (Click to Hide)" 4841 aria-label="Catalog Visibility: Visible (Click to Hide)" 4842 onclick="event.stopPropagation(); event.preventDefault(); toggleAdminCardCatalogVisibility(this, 100);"> 4843 <i class="fas fa-eye"></i> 4844 </button> 4845 4846 <div class="admin-card-edit-dropdown"> 4847 <button type="button" 4848 class="admin-card-edit-btn" 4849 title="Edit Options" 4850 aria-label="Edit Options" 4851 onclick="event.stopPropagation(); event.preventDefault(); const m = this.nextElementSibling; if (m) { m.style.display = (m.style.display === 'none' || !m.style.display) ? 'block' : 'none'; }"> 4852 <i class="fas fa-pencil-alt"></i> 4853 </button> 4854 <div class="admin-card-edit-menu" style="display: none;"> 4855 <a href="https://headrandom.com/admin/products/100/edit" target="_blank" onclick="event.stopPropagation();"> 4856 <i class="fas fa-pencil-alt"></i> 4857 <span>Edit Product</span> 4858 </a> 4859 <a href="https://headrandom.com/admin/project-hub/91/edit" target="_blank" onclick="event.stopPropagation();"> 4860 <i class="fas fa-folder"></i>
4861 <span>Edit Project Hub</span> 4862 </a> 4863 </div> 4864 </div> 4865 </div> 4866 4867 4868 <div class="listing-card__body"> 4869 <div class="listing-card__meta" style="margin-bottom: 8px;"> 4870 <a href="/product-categories/desktop-apps" class="badge">Desktop Apps</a> 4871 </div> 4872 4873 <h3 class="listing-card__title"> 4874 <a href="/products/mtxdownloader">MTxDownloader - Bulk Video Media Vault & Queue Manager</a> 4875 </h3> 4876 4877 4878 <div class="listing-card__meta" style="margin-bottom: 12px;"> 4879 <span class="listing-card__sku">SKU: mtxdownloader</span> 4880 </div> 4881 4882 <div class="listing-card__price-row" style="display: flex; justify-content: space-between; align-items: center; gap: 8px; border-top: 1px solid var(--border-color, #e2e8f0); padding-top: 10px; margin-top: 10px; flex-wrap: wrap;"> 4883 <div class="listing-card__price" style="margin: 0;"> 4884 <span class="price-current">$0</span> 4885 </div> 4886 4887 <div class="listing-card__icons" style="display: flex; align-items: center; gap: 10px; font-size: 0.8rem; color: #64748b;"> 4888 <span class="stats-views" style="display: inline-flex; align-items: center; gap: 3px;" title="Views"> 4889 <i class="far fa-eye" style="font-size: 0.8rem;"></i> 4890 <span>39</span> 4891 </span> 4892 </div> 4893 </div> 4894 </div> 4895 </article> 4896 <article class="listing-card"> 4897 4898 <a href="/products/mtxrain" class="listing-card__image"> 4899 <img src="https://headrandom.com/storage/media/mtxstudio/thumbs/mtx-rain-tao-tieng-mua-20260909-173447_featured_565x318.webp" alt="MTxRain - Ambient Rain & Storm Soundscape Studio" loading="lazy" decoding="async" class="polycms-lazy-img" onload="this.classList.add('polycms-loaded')"> 4900 </a> 4901 <div class="admin-card-edit-wrap" onclick="event.stopPropagation();"> 4902 4903 <button type="button" 4904 class="admin-card-edit-btn admin-card-visibility-btn is-visible" 4905 data-product-id="98" 4906 data-visibility="visible" 4907 title="Catalog Visibility: Visible (Click to Hide)" 4908 aria-label="Catalog Visibility: Visible (Click to Hide)" 4909 onclick="event.stopPropagation(); event.preventDefault(); toggleAdminCardCatalogVisibility(this, 98);"> 4910 <i class="fas fa-eye"></i> 4911 </button> 4912 4913 <div class="admin-card-edit-dropdown"> 4914 <button type="button" 4915 class="admin-card-edit-btn" 4916 title="Edit Options" 4917 aria-label="Edit Options" 4918 onclick="event.stopPropagation(); event.preventDefault(); const m = this.nextElementSibling; if (m) { m.style.display = (m.style.display === 'none' || !m.style.display) ? 'block' : 'none'; }"> 4919 <i class="fas fa-pencil-alt"></i> 4920 </button> 4921 <div class="admin-card-edit-menu" style="display: none;"> 4922 <a href="https://headrandom.com/admin/products/98/edit" target="_blank" onclick="event.stopPropagation();"> 4923 <i class="fas fa-pencil-alt"></i>
4924 <span>Edit Product</span> 4925 </a> 4926 <a href="https://headrandom.com/admin/project-hub/89/edit" target="_blank" onclick="event.stopPropagation();"> 4927 <i class="fas fa-folder"></i> 4928 <span>Edit Project Hub</span> 4929 </a> 4930 </div> 4931 </div> 4932 </div> 4933 4934 4935 <div class="listing-card__body"> 4936 <div class="listing-card__meta" style="margin-bottom: 8px;"> 4937 <a href="/product-categories/desktop-apps" class="badge">Desktop Apps</a> 4938 </div> 4939 4940 <h3 class="listing-card__title"> 4941 <a href="/products/mtxrain">MTxRain - Ambient Rain & Storm Soundscape Studio</a> 4942 </h3> 4943 4944 4945 <div class="listing-card__meta" style="margin-bottom: 12px;"> 4946 <span class="listing-card__sku">SKU: mtxrain</span> 4947 </div> 4948 4949 <div class="listing-card__price-row" style="display: flex; justify-content: space-between; align-items: center; gap: 8px; border-top: 1px solid var(--border-color, #e2e8f0); padding-top: 10px; margin-top: 10px; flex-wrap: wrap;"> 4950 <div class="listing-card__price" style="margin: 0;"> 4951 <span class="price-current">$1</span> 4952 </div> 4953 4954 <div class="listing-card__icons" style="display: flex; align-items: center; gap: 10px; font-size: 0.8rem; color: #64748b;"> 4955 <span class="stats-sales" style="display: inline-flex; align-items: center; gap: 2px;" title="Sold"> 4956 <i class="fas fa-shopping-cart" style="font-size: 0.75rem; color: #64748b;"></i> 4957 <span>1</span> 4958 </span> 4959 <span class="stats-views" style="display: inline-flex; align-items: center; gap: 3px;" title="Views"> 4960 <i class="far fa-eye" style="font-size: 0.8rem;"></i> 4961 <span>42</span> 4962 </span> 4963 </div> 4964 </div> 4965 </div> 4966 </article> 4967 <article class="listing-card"> 4968 4969 <a href="/products/mtxstudio" class="listing-card__image"> 4970 <img src="https://headrandom.com/storage/media/2026/09/thumbs/mtxvoice-screenshot-20260906-202846_featured_565x318.webp" alt="MTxStudio - AI Video Voiceover & Multi-Track Studio" loading="lazy" decoding="async" class="polycms-lazy-img" onload="this.classList.add('polycms-loaded')"> 4971 </a> 4972 <div class="admin-card-edit-wrap" onclick="event.stopPropagation();"> 4973 4974 <button type="button" 4975 class="admin-card-edit-btn admin-card-visibility-btn is-visible" 4976 data-product-id="96" 4977 data-visibility="visible" 4978 title="Catalog Visibility: Visible (Click to Hide)" 4979 aria-label="Catalog Visibility: Visible (Click to Hide)" 4980 onclick="event.stopPropagation(); event.preventDefault(); toggleAdminCardCatalogVisibility(this, 96);"> 4981 <i class="fas fa-eye"></i> 4982 </button> 4983 4984 <div class="admin-card-edit-dropdown"> 4985 <button type="button" 4986 class="admin-card-edit-btn" 4987 title="Edit Options" 4988 aria-label="Edit Options" 4989 onclick="event.stopPropagation(); event.preventDefault(); const m = this.nextElementSibling; if (m) { m.style.display = (m.style.display === 'none' || !m.style.display) ? 'block' : 'none'; }"> 4990 <i class="fas fa-pencil-alt"></i> 4991 </button> 4992 <div class="admin-card-edit-menu" style="display: none;"> 4993 <a href="https://headrandom.com/admin/products/96/edit" target="_blank" onclick="event.stopPropagation();"> 4994 <i class="fas fa-pencil-alt"></i>
4995 <span>Edit Product</span> 4996 </a> 4997 <a href="https://headrandom.com/admin/project-hub/87/edit" target="_blank" onclick="event.stopPropagation();"> 4998 <i class="fas fa-folder"></i> 4999 <span>Edit Project Hub</span> 5000 </a> 5001 </div> 5002 </div> 5003 </div> 5004 5005 5006 <div class="listing-card__body"> 5007 <div class="listing-card__meta" style="margin-bottom: 8px;"> 5008 <a href="/product-categories/desktop-apps" class="badge">Desktop Apps</a> 5009 </div> 5010 5011 <h3 class="listing-card__title"> 5012 <a href="/products/mtxstudio">MTxStudio - AI Video Voiceover & Multi-Track Studio</a> 5013 </h3> 5014 5015 5016 <div class="listing-card__meta" style="margin-bottom: 12px;"> 5017 <span class="listing-card__sku">SKU: mtxstudio</span> 5018 </div> 5019 5020 <div class="listing-card__price-row" style="display: flex; justify-content: space-between; align-items: center; gap: 8px; border-top: 1px solid var(--border-color, #e2e8f0); padding-top: 10px; margin-top: 10px; flex-wrap: wrap;"> 5021 <div class="listing-card__price" style="margin: 0;"> 5022 <span class="price-current">$0</span> 5023 </div> 5024 5025 <div class="listing-card__icons" style="display: flex; align-items: center; gap: 10px; font-size: 0.8rem; color: #64748b;"> 5026 <span class="stats-sales" style="display: inline-flex; align-items: center; gap: 2px;" title="Sold"> 5027 <i class="fas fa-shopping-cart" style="font-size: 0.75rem; color: #64748b;"></i> 5028 <span>2</span> 5029 </span> 5030 <span class="stats-views" style="display: inline-flex; align-items: center; gap: 3px;" title="Views"> 5031 <i class="far fa-eye" style="font-size: 0.8rem;"></i> 5032 <span>71</span> 5033 </span> 5034 </div> 5035 </div> 5036 </div> 5037 </article> 5038 <article class="listing-card"> 5039 5040 <a href="/products/polymetrics" class="listing-card__image"> 5041 <img src="https://headrandom.com/storage/media/2026/08/thumbs/polymetricsproductpriceanalysisextensionforenvato_featured_563x375.webp" alt="PolyMetrics Product Price Analysis Extension for Envato" loading="lazy" decoding="async" class="polycms-lazy-img" onload="this.classList.add('polycms-loaded')"> 5042 </a> 5043 <div class="admin-card-edit-wrap" onclick="event.stopPropagation();"> 5044 5045 <button type="button" 5046 class="admin-card-edit-btn admin-card-visibility-btn is-visible" 5047 data-product-id="90" 5048 data-visibility="visible" 5049 title="Catalog Visibility: Visible (Click to Hide)" 5050 aria-label="Catalog Visibility: Visible (Click to Hide)" 5051 onclick="event.stopPropagation(); event.preventDefault(); toggleAdminCardCatalogVisibility(this, 90);"> 5052 <i class="fas fa-eye"></i> 5053 </button> 5054 5055 <div class="admin-card-edit-dropdown"> 5056 <button type="button" 5057 class="admin-card-edit-btn" 5058 title="Edit Options" 5059 aria-label="Edit Options" 5060 onclick="event.stopPropagation(); event.preventDefault(); const m = this.nextElementSibling; if (m) { m.style.display = (m.style.display === 'none' || !m.style.display) ? 'block' : 'none'; }"> 5061 <i class="fas fa-pencil-alt"></i> 5062 </button> 5063 <div class="admin-card-edit-menu" style="display: none;"> 5064 <a href="https://headrandom.com/admin/products/90/edit" target="_blank" onclick="event.stopPropagation();"> 5065 <i class="fas fa-pencil-alt"></i>
5066 <span>Edit Product</span> 5067 </a> 5068 <a href="https://headrandom.com/admin/project-hub/6/edit" target="_blank" onclick="event.stopPropagation();"> 5069 <i class="fas fa-folder"></i> 5070 <span>Edit Project Hub</span> 5071 </a> 5072 </div> 5073 </div> 5074 </div> 5075 5076 5077 <div class="listing-card__body"> 5078 <div class="listing-card__meta" style="margin-bottom: 8px;"> 5079 <a href="/product-categories/chrome-extension" class="badge">Chrome Extension</a> 5080 </div> 5081 5082 <h3 class="listing-card__title"> 5083 <a href="/products/polymetrics">PolyMetrics Product Price Analysis Extension for Envato</a> 5084 </h3> 5085 5086 <p class="listing-card__excerpt" style="margin-bottom: 12px;">Chrome Extension (Manifest V3) for Envato Market Authors and product researchers. Features real-time price & sales metri...</p> 5087 5088 <div class="listing-card__meta" style="margin-bottom: 12px;"> 5089 <span class="listing-card__sku">SKU: polymetrics</span> 5090 </div> 5091 5092 <div class="listing-card__price-row" style="display: flex; justify-content: space-between; align-items: center; gap: 8px; border-top: 1px solid var(--border-color, #e2e8f0); padding-top: 10px; margin-top: 10px; flex-wrap: wrap;"> 5093 <div class="listing-card__price" style="margin: 0;"> 5094 <span class="price-current">$0</span> 5095 </div> 5096 5097 <div class="listing-card__icons" style="display: flex; align-items: center; gap: 10px; font-size: 0.8rem; color: #64748b;"> 5098 <span class="stats-views" style="display: inline-flex; align-items: center; gap: 3px;" title="Views"> 5099 <i class="far fa-eye" style="font-size: 0.8rem;"></i> 5100 <span>87</span> 5101 </span> 5102 </div> 5103 </div> 5104 </div> 5105 </article> 5106 <article class="listing-card"> 5107 5108 <a href="/products/geofesh-for-wordpress" class="listing-card__image"> 5109 <img src="https://headrandom.com/storage/media/2026/08/thumbs/plugin-lap-la-so-tu-tru-la-so-bat-tu-online_featured_540x375.webp" alt="Four Pillars of Destiny (Bazi) & Auspicious Date Selection - GeoFesh for WordPress Plugin" loading="lazy" decoding="async" class="polycms-lazy-img" onload="this.classList.add('polycms-loaded')"> 5110 </a> 5111 <div class="admin-card-edit-wrap" onclick="event.stopPropagation();"> 5112 5113 <button type="button" 5114 class="admin-card-edit-btn admin-card-visibility-btn is-visible" 5115 data-product-id="62" 5116 data-visibility="visible" 5117 title="Catalog Visibility: Visible (Click to Hide)" 5118 aria-label="Catalog Visibility: Visible (Click to Hide)" 5119 onclick="event.stopPropagation(); event.preventDefault(); toggleAdminCardCatalogVisibility(this, 62);"> 5120 <i class="fas fa-eye"></i> 5121 </button> 5122 5123 <div class="admin-card-edit-dropdown"> 5124 <button type="button" 5125 class="admin-card-edit-btn" 5126 title="Edit Options" 5127 aria-label="Edit Options" 5128 onclick="event.stopPropagation(); event.preventDefault(); const m = this.nextElementSibling; if (m) { m.style.display = (m.style.display === 'none' || !m.style.display) ? 'block' : 'none'; }"> 5129 <i class="fas fa-pencil-alt"></i> 5130 </button> 5131 <div class="admin-card-edit-menu" style="display: none;"> 5132 <a href="https://headrandom.com/admin/products/62/edit" target="_blank" onclick="event.stopPropagation();"> 5133 <i class="fas fa-pencil-alt"></i>
5134 <span>Edit Product</span> 5135 </a> 5136 <a href="https://headrandom.com/admin/project-hub/59/edit" target="_blank" onclick="event.stopPropagation();"> 5137 <i class="fas fa-folder"></i> 5138 <span>Edit Project Hub</span> 5139 </a> 5140 </div> 5141 </div> 5142 </div> 5143 5144 5145 <div class="listing-card__body"> 5146 <div class="listing-card__meta" style="margin-bottom: 8px;"> 5147 <a href="/product-categories/wordpress" class="badge">WordPress</a> 5148 </div> 5149 5150 <h3 class="listing-card__title"> 5151 <a href="/products/geofesh-for-wordpress">Four Pillars of Destiny (Bazi) & Auspicious Date Selection - GeoFesh for WordPress Plugin</a> 5152 </h3> 5153 5154 <p class="listing-card__excerpt" style="margin-bottom: 12px;">Professional WordPress plugin for Four Pillars of Destiny (Bazi / Tứ Trụ) calculation, Ten Deities mapping, Shen Sha, 12...</p> 5155 5156 <div class="listing-card__meta" style="margin-bottom: 12px;"> 5157 <span class="listing-card__sku">SKU: wpgeofesh</span> 5158 </div> 5159 5160 <div class="listing-card__price-row" style="display: flex; justify-content: space-between; align-items: center; gap: 8px; border-top: 1px solid var(--border-color, #e2e8f0); padding-top: 10px; margin-top: 10px; flex-wrap: wrap;"> 5161 <div class="listing-card__price" style="margin: 0;"> 5162 <span class="price-current">$0</span> 5163 </div> 5164 5165 <div class="listing-card__icons" style="display: flex; align-items: center; gap: 10px; font-size: 0.8rem; color: #64748b;"> 5166 <span class="stats-views" style="display: inline-flex; align-items: center; gap: 3px;" title="Views"> 5167 <i class="far fa-eye" style="font-size: 0.8rem;"></i> 5168 <span>79</span> 5169 </span> 5170 </div> 5171 </div> 5172 </div> 5173 </article> 5174 <article class="listing-card"> 5175 5176 <a href="/products/sow-hexagram-for-wordpress" class="listing-card__image"> 5177 <img src="https://headrandom.com/storage/media/2026/08/thumbs/ung-dung-gieo-que-luc-hao-mai-hoa_featured_565x289.webp" alt="Gieo Quẻ Kinh Dá»ch - SOW Hexagram for WordPress Plugin" loading="lazy" decoding="async" class="polycms-lazy-img" onload="this.classList.add('polycms-loaded')"> 5178 </a> 5179 <div class="admin-card-edit-wrap" onclick="event.stopPropagation();"> 5180 5181 <button type="button" 5182 class="admin-card-edit-btn admin-card-visibility-btn is-visible" 5183 data-product-id="60" 5184 data-visibility="visible" 5185 title="Catalog Visibility: Visible (Click to Hide)" 5186 aria-label="Catalog Visibility: Visible (Click to Hide)" 5187 onclick="event.stopPropagation(); event.preventDefault(); toggleAdminCardCatalogVisibility(this, 60);"> 5188 <i class="fas fa-eye"></i> 5189 </button> 5190 5191 <div class="admin-card-edit-dropdown"> 5192 <button type="button" 5193 class="admin-card-edit-btn" 5194 title="Edit Options" 5195 aria-label="Edit Options" 5196 onclick="event.stopPropagation(); event.preventDefault(); const m = this.nextElementSibling; if (m) { m.style.display = (m.style.display === 'none' || !m.style.display) ? 'block' : 'none'; }"> 5197 <i class="fas fa-pencil-alt"></i> 5198 </button> 5199 <div class="admin-card-edit-menu" style="display: none;"> 5200 <a href="https://headrandom.com/admin/products/60/edit" target="_blank" onclick="event.stopPropagation();"> 5201 <i class="fas fa-pencil-alt"></i>
5202 <span>Edit Product</span> 5203 </a> 5204 <a href="https://headrandom.com/admin/project-hub/57/edit" target="_blank" onclick="event.stopPropagation();"> 5205 <i class="fas fa-folder"></i> 5206 <span>Edit Project Hub</span> 5207 </a> 5208 </div> 5209 </div> 5210 </div> 5211 5212 5213 <div class="listing-card__body"> 5214 <div class="listing-card__meta" style="margin-bottom: 8px;"> 5215 <a href="/product-categories/wordpress" class="badge">WordPress</a> 5216 </div> 5217 5218 <h3 class="listing-card__title"> 5219 <a href="/products/sow-hexagram-for-wordpress">Gieo Quẻ Kinh Dá»ch - SOW Hexagram for WordPress Plugin</a> 5220 </h3> 5221 5222 <p class="listing-card__excerpt" style="margin-bottom: 12px;">Enterprise-grade WordPress I-Ching Divination plugin powering Six-Line (Lục Hà o) and Plum Blossom Numerology (Mai Hoa Dá»...</p> 5223 5224 <div class="listing-card__meta" style="margin-bottom: 12px;"> 5225 <span class="listing-card__sku">SKU: wpsowhexagram</span> 5226 </div> 5227 5228 <div class="listing-card__price-row" style="display: flex; justify-content: space-between; align-items: center; gap: 8px; border-top: 1px solid var(--border-color, #e2e8f0); padding-top: 10px; margin-top: 10px; flex-wrap: wrap;"> 5229 <div class="listing-card__price" style="margin: 0;"> 5230 <span class="price-current">$0</span> 5231 </div> 5232 5233 <div class="listing-card__icons" style="display: flex; align-items: center; gap: 10px; font-size: 0.8rem; color: #64748b;"> 5234 <span class="stats-views" style="display: inline-flex; align-items: center; gap: 3px;" title="Views"> 5235 <i class="far fa-eye" style="font-size: 0.8rem;"></i> 5236 <span>80</span> 5237 </span> 5238 </div> 5239 </div> 5240 </div> 5241 </article> 5242 <article class="listing-card"> 5243 5244 <a href="/products/demo-builder-for-perfex-crm" class="listing-card__image"> 5245 <img src="https://headrandom.com/storage/media/2026/08/thumbs/demo-builder-for-perfex-crm_featured_563x375.webp" alt="Demo Builder for Perfex CRM - Automated Demo Sandbox, Visitor Tracking & Reset Engine" loading="lazy" decoding="async" class="polycms-lazy-img" onload="this.classList.add('polycms-loaded')"> 5246 </a> 5247 <div class="admin-card-edit-wrap" onclick="event.stopPropagation();"> 5248 5249 <button type="button" 5250 class="admin-card-edit-btn admin-card-visibility-btn is-visible" 5251 data-product-id="57" 5252 data-visibility="visible" 5253 title="Catalog Visibility: Visible (Click to Hide)" 5254 aria-label="Catalog Visibility: Visible (Click to Hide)" 5255 onclick="event.stopPropagation(); event.preventDefault(); toggleAdminCardCatalogVisibility(this, 57);"> 5256 <i class="fas fa-eye"></i> 5257 </button> 5258 5259 <div class="admin-card-edit-dropdown"> 5260 <button type="button" 5261 class="admin-card-edit-btn" 5262 title="Edit Options" 5263 aria-label="Edit Options" 5264 onclick="event.stopPropagation(); event.preventDefault(); const m = this.nextElementSibling; if (m) { m.style.display = (m.style.display === 'none' || !m.style.display) ? 'block' : 'none'; }"> 5265 <i class="fas fa-pencil-alt"></i> 5266 </button> 5267 <div class="admin-card-edit-menu" style="display: none;"> 5268 <a href="https://headrandom.com/admin/products/57/edit" target="_blank" onclick="event.stopPropagation();"> 5269 <i class="fas fa-pencil-alt"></i>
5270 <span>Edit Product</span> 5271 </a> 5272 <a href="https://headrandom.com/admin/project-hub/13/edit" target="_blank" onclick="event.stopPropagation();"> 5273 <i class="fas fa-folder"></i> 5274 <span>Edit Project Hub</span> 5275 </a> 5276 </div> 5277 </div> 5278 </div> 5279 5280 5281 <div class="listing-card__body"> 5282 <div class="listing-card__meta" style="margin-bottom: 8px;"> 5283 <a href="/product-categories/modules-for-perfex-crm" class="badge">Modules for Perfex CRM</a> 5284 </div> 5285 5286 <h3 class="listing-card__title"> 5287 <a href="/products/demo-builder-for-perfex-crm">Demo Builder for Perfex CRM - Automated Demo Sandbox, Visitor Tracking & Reset Engine</a> 5288 </h3> 5289 5290 5291 <div class="listing-card__meta" style="margin-bottom: 12px;"> 5292 <span class="listing-card__sku">SKU: demo-builder-perfex</span> 5293 </div> 5294 5295 <div class="listing-card__price-row" style="display: flex; justify-content: space-between; align-items: center; gap: 8px; border-top: 1px solid var(--border-color, #e2e8f0); padding-top: 10px; margin-top: 10px; flex-wrap: wrap;"> 5296 <div class="listing-card__price" style="margin: 0;"> 5297 <span class="price-current">$59</span> 5298 </div> 5299 5300 <div class="listing-card__icons" style="display: flex; align-items: center; gap: 10px; font-size: 0.8rem; color: #64748b;"> 5301 <span class="stats-sales" style="display: inline-flex; align-items: center; gap: 2px;" title="Sold"> 5302 <i class="fas fa-shopping-cart" style="font-size: 0.75rem; color: #64748b;"></i> 5303 <span>15</span> 5304 </span> 5305 <span class="stats-views" style="display: inline-flex; align-items: center; gap: 3px;" title="Views"> 5306 <i class="far fa-eye" style="font-size: 0.8rem;"></i> 5307 <span>109</span> 5308 </span> 5309 </div> 5310 </div> 5311 </div> 5312 </article> 5313 <article class="listing-card"> 5314 5315 <a href="/products/fengshui-moving-date-for-wordpress" class="listing-card__image"> 5316 <img src="https://headrandom.com/storage/media/2026/08/thumbs/fengshui-moving-date-for-wordpress_featured_563x375.webp" alt="FengShui Moving Date for WordPress" loading="lazy" decoding="async" class="polycms-lazy-img" onload="this.classList.add('polycms-loaded')"> 5317 </a> 5318 <div class="admin-card-edit-wrap" onclick="event.stopPropagation();"> 5319 5320 <button type="button" 5321 class="admin-card-edit-btn admin-card-visibility-btn is-visible" 5322 data-product-id="50" 5323 data-visibility="visible" 5324 title="Catalog Visibility: Visible (Click to Hide)" 5325 aria-label="Catalog Visibility: Visible (Click to Hide)" 5326 onclick="event.stopPropagation(); event.preventDefault(); toggleAdminCardCatalogVisibility(this, 50);"> 5327 <i class="fas fa-eye"></i> 5328 </button> 5329 5330 <div class="admin-card-edit-dropdown"> 5331 <button type="button" 5332 class="admin-card-edit-btn" 5333 title="Edit Options" 5334 aria-label="Edit Options" 5335 onclick="event.stopPropagation(); event.preventDefault(); const m = this.nextElementSibling; if (m) { m.style.display = (m.style.display === 'none' || !m.style.display) ? 'block' : 'none'; }"> 5336 <i class="fas fa-pencil-alt"></i> 5337 </button> 5338 <div class="admin-card-edit-menu" style="display: none;"> 5339 <a href="https://headrandom.com/admin/products/50/edit" target="_blank" onclick="event.stopPropagation();"> 5340 <i class="fas fa-pencil-alt"></i>
5341 <span>Edit Product</span> 5342 </a> 5343 <a href="https://headrandom.com/admin/project-hub/51/edit" target="_blank" onclick="event.stopPropagation();"> 5344 <i class="fas fa-folder"></i> 5345 <span>Edit Project Hub</span> 5346 </a> 5347 </div> 5348 </div> 5349 </div> 5350 5351 5352 <div class="listing-card__body"> 5353 <div class="listing-card__meta" style="margin-bottom: 8px;"> 5354 <a href="/product-categories/wordpress" class="badge">WordPress</a> 5355 </div> 5356 5357 <h3 class="listing-card__title"> 5358 <a href="/products/fengshui-moving-date-for-wordpress">FengShui Moving Date for WordPress</a> 5359 </h3> 5360 5361 5362 <div class="listing-card__meta" style="margin-bottom: 12px;"> 5363 <span class="listing-card__sku">SKU: wpfengshui-moving-date</span> 5364 </div> 5365 5366 <div class="listing-card__price-row" style="display: flex; justify-content: space-between; align-items: center; gap: 8px; border-top: 1px solid var(--border-color, #e2e8f0); padding-top: 10px; margin-top: 10px; flex-wrap: wrap;"> 5367 <div class="listing-card__price" style="margin: 0;"> 5368 <span class="price-current">$18.47</span> 5369 <span class="price-original">$29</span> 5370 <span class="price-badge">SALE</span> 5371 </div> 5372 5373 <div class="listing-card__icons" style="display: flex; align-items: center; gap: 10px; font-size: 0.8rem; color: #64748b;"> 5374 <span class="stats-sales" style="display: inline-flex; align-items: center; gap: 2px;" title="Sold"> 5375 <i class="fas fa-shopping-cart" style="font-size: 0.75rem; color: #64748b;"></i> 5376 <span>6</span> 5377 </span> 5378 <span class="stats-views" style="display: inline-flex; align-items: center; gap: 3px;" title="Views"> 5379 <i class="far fa-eye" style="font-size: 0.8rem;"></i> 5380 <span>140</span> 5381 </span> 5382 </div> 5383 </div> 5384 </div> 5385 </article> 5386 <article class="listing-card"> 5387 5388 <a href="/products/fengshui-api-for-wordpress" class="listing-card__image"> 5389 <img src="https://headrandom.com/storage/media/2026/08/thumbs/fengshui-api-for-wordpress_featured_565x318.webp" alt="FengShui API for WordPress" loading="lazy" decoding="async" class="polycms-lazy-img" onload="this.classList.add('polycms-loaded')"> 5390 </a> 5391 <div class="admin-card-edit-wrap" onclick="event.stopPropagation();"> 5392 5393 <button type="button" 5394 class="admin-card-edit-btn admin-card-visibility-btn is-visible" 5395 data-product-id="52" 5396 data-visibility="visible" 5397 title="Catalog Visibility: Visible (Click to Hide)" 5398 aria-label="Catalog Visibility: Visible (Click to Hide)" 5399 onclick="event.stopPropagation(); event.preventDefault(); toggleAdminCardCatalogVisibility(this, 52);"> 5400 <i class="fas fa-eye"></i> 5401 </button> 5402 5403 <div class="admin-card-edit-dropdown"> 5404 <button type="button" 5405 class="admin-card-edit-btn" 5406 title="Edit Options" 5407 aria-label="Edit Options" 5408 onclick="event.stopPropagation(); event.preventDefault(); const m = this.nextElementSibling; if (m) { m.style.display = (m.style.display === 'none' || !m.style.display) ? 'block' : 'none'; }"> 5409 <i class="fas fa-pencil-alt"></i> 5410 </button> 5411 <div class="admin-card-edit-menu" style="display: none;"> 5412 <a href="https://headrandom.com/admin/products/52/edit" target="_blank" onclick="event.stopPropagation();"> 5413 <i class="fas fa-pencil-alt"></i>
5414 <span>Edit Product</span> 5415 </a> 5416 <a href="https://headrandom.com/admin/project-hub/52/edit" target="_blank" onclick="event.stopPropagation();"> 5417 <i class="fas fa-folder"></i> 5418 <span>Edit Project Hub</span> 5419 </a> 5420 </div> 5421 </div> 5422 </div> 5423 5424 5425 <div class="listing-card__body"> 5426 <div class="listing-card__meta" style="margin-bottom: 8px;"> 5427 <a href="/product-categories/wordpress" class="badge">WordPress</a> 5428 </div> 5429 5430 <h3 class="listing-card__title"> 5431 <a href="/products/fengshui-api-for-wordpress">FengShui API for WordPress</a> 5432 </h3> 5433 5434 5435 <div class="listing-card__meta" style="margin-bottom: 12px;"> 5436 <span class="listing-card__sku">SKU: wpfengshui</span> 5437 </div> 5438 5439 <div class="listing-card__price-row" style="display: flex; justify-content: space-between; align-items: center; gap: 8px; border-top: 1px solid var(--border-color, #e2e8f0); padding-top: 10px; margin-top: 10px; flex-wrap: wrap;"> 5440 <div class="listing-card__price" style="margin: 0;"> 5441 <span class="price-current">$38.99</span> 5442 <span class="price-original">$39</span> 5443 <span class="price-badge">SALE</span> 5444 </div> 5445 5446 <div class="listing-card__icons" style="display: flex; align-items: center; gap: 10px; font-size: 0.8rem; color: #64748b;"> 5447 <span class="stats-sales" style="display: inline-flex; align-items: center; gap: 2px;" title="Sold"> 5448 <i class="fas fa-shopping-cart" style="font-size: 0.75rem; color: #64748b;"></i> 5449 <span>2</span> 5450 </span> 5451 <span class="stats-views" style="display: inline-flex; align-items: center; gap: 3px;" title="Views"> 5452 <i class="far fa-eye" style="font-size: 0.8rem;"></i> 5453 <span>134</span> 5454 </span> 5455 </div> 5456 </div> 5457 </div> 5458 </article> 5459 </div> 5460 5461 <div class="listing-pagination" style="margin-top: 4rem;"> 5462 <nav role="navigation" aria-label="Pagination Navigation" class="flex items-center justify-between"> 5463 <div class="flex justify-between flex-1 sm:hidden"> 5464 <span class="relative inline-flex items-center px-4 py-2 text-sm font-medium text-gray-500 bg-white border border-gray-300 cursor-default leading-5 rounded-md dark:text-gray-600 dark:bg-gray-800 dark:border-gray-600"> 5465 « Previous 5466 </span> 5467 5468 <a href="https://headrandom.com/products?page=2" class="relative inline-flex items-center px-4 py-2 ml-3 text-sm font-medium text-gray-700 bg-white border border-gray-300 leading-5 rounded-md hover:text-gray-500 focus:outline-none focus:ring ring-gray-300 focus:border-blue-300 active:bg-gray-100 active:text-gray-700 transition ease-in-out duration-150 dark:bg-gray-800 dark:border-gray-600 dark:text-gray-300 dark:focus:border-blue-700 dark:active:bg-gray-700 dark:active:text-gray-300"> 5469 Next » 5470 </a> 5471 </div> 5472 5473 <div class="hidden sm:flex-1 sm:flex sm:items-center sm:justify-between"> 5474 <div> 5475 <p class="text-sm text-gray-700 leading-5 dark:text-gray-400"> 5476 Showing
5477 <span class="font-medium">1</span> 5478 to 5479 <span class="font-medium">12</span> 5480 of 5481 <span class="font-medium">22</span> 5482 results 5483 </p> 5484 </div> 5485 5486 <div> 5487 <span class="relative z-0 inline-flex rtl:flex-row-reverse shadow-sm rounded-md"> 5488 5489 <span aria-disabled="true" aria-label="&laquo; Previous"> 5490 <span class="relative inline-flex items-center px-2 py-2 text-sm font-medium text-gray-500 bg-white border border-gray-300 cursor-default rounded-l-md leading-5 dark:bg-gray-800 dark:border-gray-600" aria-hidden="true"> 5491 <svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20"> 5492 <path fill-rule="evenodd" d="M12.707 5.293a1 1 0 010 1.414L9.414 10l3.293 3.293a1 1 0 01-1.414 1.414l-4-4a1 1 0 010-1.414l4-4a1 1 0 011.414 0z" clip-rule="evenodd" /> 5493 </svg> 5494 </span> 5495 </span> 5496 5497 5498 5499 5500 5501 <span aria-current="page"> 5502 <span class="relative inline-flex items-center px-4 py-2 -ml-px text-sm font-medium text-gray-500 bg-white border border-gray-300 cursor-default leading-5 dark:bg-gray-800 dark:border-gray-600">1</span> 5503 </span> 5504 <a href="https://headrandom.com/products?page=2" class="relative inline-flex items-center px-4 py-2 -ml-px text-sm font-medium text-gray-700 bg-white border border-gray-300 leading-5 hover:text-gray-500 focus:z-10 focus:outline-none focus:ring ring-gray-300 focus:border-blue-300 active:bg-gray-100 active:text-gray-700 transition ease-in-out duration-150 dark:bg-gray-800 dark:border-gray-600 dark:text-gray-400 dark:hover:text-gray-300 dark:active:bg-gray-700 dark:focus:border-blue-800" aria-label="Go to page 2"> 5505 2 5506 </a> 5507 5508 5509 <a href="https://headrandom.com/products?page=2" rel="next" class="relative inline-flex items-center px-2 py-2 -ml-px text-sm font-medium text-gray-500 bg-white border border-gray-300 rounded-r-md leading-5 hover:text-gray-400 focus:z-10 focus:outline-none focus:ring ring-gray-300 focus:border-blue-300 active:bg-gray-100 active:text-gray-500 transition ease-in-out duration-150 dark:bg-gray-800 dark:border-gray-600 dark:active:bg-gray-700 dark:focus:border-blue-800" aria-label="Next &raquo;"> 5510 <svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20"> 5511 <path fill-rule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clip-rule="evenodd" /> 5512 </svg> 5513 </a> 5514 </span> 5515 </div> 5516 </div> 5517 </nav> 5518 5519 </div> 5520 </div> 5521 5522 <aside style="display: none;"> 5523 <div class="widget-area sidebar-widget-stack" data-widget-area="sidebar_shop"> 5524 <style> 5525 .polycms-widget-align-right { text-align: right; } 5526 .polycms-widget-align-right .footer-social-icons, 5527 .polycms-widget-align-right .footer-menu-icons, 5528 .polycms-widget-align-right .footer-menu-horizontal { justify-content: flex-end; } 5529 .polycms-widget-align-right .widget-menu-items ul { display: flex; flex-direction: column; align-items: flex-end; } 5530 @media (max-width: 767px) { 5531 .footer-social-icons { justify-content: center !important; } 5532 } 5533 </style>
5533<div class="polycms-widget-align-left"><div class="widget widget-product-categories"><h3 class="widget-title">Product Categories</h3><ul class="widget-list"><li><a href="https://headrandom.com/product-categories/chrome-extension">Chrome Extension</a></li><li><a href="https://headrandom.com/product-categories/cyberpanel">CyberPanel</a></li><li><a href="https://headrandom.com/product-categories/desktop-apps">Desktop Apps</a></li><li><a href="https://headrandom.com/product-categories/modules-for-perfex-crm">Modules for Perfex CRM</a></li><li><a href="https://headrandom.com/product-categories/polycms">PolyCMS</a></li><li><a href="https://headrandom.com/product-categories/wordpress">WordPress</a></li></ul></div><div class="widget widget-products"> 5534 <h3 class="widget-title">Latest Products</h3> 5535 <ul class="widget-list" style="list-style: none; padding: 0; margin: 0;"> 5536 <li class="widget-product-item" style="display: flex; gap: 12px; margin-bottom: 12px; align-items: center;"> 5537 <a href="https://headrandom.com/products/omnimention" class="widget-product-image" style="width: 50px; height: 50px; flex-shrink: 0; display: block; border-radius: 6px; overflow: hidden; background: #f1f5f9; border: 1px solid #e2e8f0;"> 5538 <img src="https://headrandom.com/storage/media/mtxstudio/thumbs/omnimention-for-perfex-cover_thumb_350x197.webp" alt="OmniMention for Perfex CRM - Universal Mention & Entity Tagging Ecosystem" style="width: 100%; height: 100%; object-fit: cover;" loading="lazy" decoding="async" class="polycms-lazy-img" onload="this.classList.add('polycms-loaded')"> 5539 </a> 5540 <div class="widget-product-info" style="flex-grow: 1; min-width: 0;"> 5541 <a href="https://headrandom.com/products/omnimention" class="widget-product-name" style="font-size: 0.9rem; font-weight: 600; color: var(--geist-foreground, #1e293b); text-decoration: none; display: block; margin-bottom: 4px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;"> 5542 OmniMention for Perfex CRM - Universal Mention & Entity Tagging Ecosystem 5543 </a> 5544 <div class="widget-product-price" style="font-size: 0.85rem;"> 5545 <span class="price-old" style="text-decoration: line-through; color: #94a3b8; margin-right: 6px;">$49</span> 5546 <span class="price-new" style="color: #ef4444; font-weight: 700;">$39</span> 5547 </div> 5548 </div> 5549 </li> 5550 <li class="widget-product-item" style="display: flex; gap: 12px; margin-bottom: 12px; align-items: center;"> 5551 <a href="https://headrandom.com/products/mtxelevenlabs" class="widget-product-image" style="width: 50px; height: 50px; flex-shrink: 0; display: block; border-radius: 6px; overflow: hidden; background: #f1f5f9; border: 1px solid #e2e8f0;"> 5552 <img src="https://headrandom.com/storage/media/2026/05/thumbs/HeadRandom-1_thumb_350x195.webp" alt="ElevenLabs Voice & SFX Studio - Neural TTS & Cinematic Sound Effects" style="width: 100%; height: 100%; object-fit: cover;" loading="lazy" decoding="async" class="polycms-lazy-img" onload="this.classList.add('polycms-loaded')"> 5553 </a> 5554 <div class="widget-product-info" style="flex-grow: 1; min-width: 0;"> 5555 <a href="https://headrandom.com/products/mtxelevenlabs" class="widget-product-name" style="font-size: 0.9rem; font-weight: 600; color: var(--geist-foreground, #1e293b); text-decoration: none; display: block; margin-bottom: 4px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;"> 5556 ElevenLabs Voice & SFX Studio - Neural TTS & Cinematic Sound Effects 5557 </a> 5558 <div class="widget-product-price" style="font-size: 0.85rem;">
5559 <span class="price-normal" style="color: var(--geist-accents-6, #475569); font-weight: 600;">$0</span> 5560 </div> 5561 </div> 5562 </li> 5563 <li class="widget-product-item" style="display: flex; gap: 12px; margin-bottom: 12px; align-items: center;"> 5564 <a href="https://headrandom.com/products/mtxchannelmanager" class="widget-product-image" style="width: 50px; height: 50px; flex-shrink: 0; display: block; border-radius: 6px; overflow: hidden; background: #f1f5f9; border: 1px solid #e2e8f0;"> 5565 <img src="https://headrandom.com/storage/media/2026/05/thumbs/HeadRandom-1_thumb_350x195.webp" alt="MTxChannelManager - Multi-Platform Video Distribution Hub" style="width: 100%; height: 100%; object-fit: cover;" loading="lazy" decoding="async" class="polycms-lazy-img" onload="this.classList.add('polycms-loaded')"> 5566 </a> 5567 <div class="widget-product-info" style="flex-grow: 1; min-width: 0;"> 5568 <a href="https://headrandom.com/products/mtxchannelmanager" class="widget-product-name" style="font-size: 0.9rem; font-weight: 600; color: var(--geist-foreground, #1e293b); text-decoration: none; display: block; margin-bottom: 4px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;"> 5569 MTxChannelManager - Multi-Platform Video Distribution Hub 5570 </a> 5571 <div class="widget-product-price" style="font-size: 0.85rem;"> 5572 <span class="price-normal" style="color: var(--geist-accents-6, #475569); font-weight: 600;">$1</span> 5573 </div> 5574 </div> 5575 </li> 5576 <li class="widget-product-item" style="display: flex; gap: 12px; margin-bottom: 12px; align-items: center;"> 5577 <a href="https://headrandom.com/products/mtxdownloader" class="widget-product-image" style="width: 50px; height: 50px; flex-shrink: 0; display: block; border-radius: 6px; overflow: hidden; background: #f1f5f9; border: 1px solid #e2e8f0;"> 5578 <img src="https://headrandom.com/storage/media/2026/05/thumbs/HeadRandom-1_thumb_350x195.webp" alt="MTxDownloader - Bulk Video Media Vault & Queue Manager" style="width: 100%; height: 100%; object-fit: cover;" loading="lazy" decoding="async" class="polycms-lazy-img" onload="this.classList.add('polycms-loaded')"> 5579 </a> 5580 <div class="widget-product-info" style="flex-grow: 1; min-width: 0;"> 5581 <a href="https://headrandom.com/products/mtxdownloader" class="widget-product-name" style="font-size: 0.9rem; font-weight: 600; color: var(--geist-foreground, #1e293b); text-decoration: none; display: block; margin-bottom: 4px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;"> 5582 MTxDownloader - Bulk Video Media Vault & Queue Manager 5583 </a> 5584 <div class="widget-product-price" style="font-size: 0.85rem;"> 5585 <span class="price-normal" style="color: var(--geist-accents-6, #475569); font-weight: 600;">$0</span> 5586 </div> 5587 </div> 5588 </li> 5589 </ul> 5590</div> 5591</div> 5592 </div> 5593 </aside> 5594 5595 </div> 5596</div> 5597 </main> 5598 5599 5600 <footer class="footer" style="border-top: 1px solid var(--geist-accents-2); padding: 4rem 0 3rem 0; font-size: 0.875rem; background: var(--geist-background);"> 5601 <style> 5602 .footer-widgets { 5603 display: grid; 5604 grid-template-columns: 1fr; 5605 gap: 2rem; 5606 margin-bottom: 3rem; 5607 } 5608 @media (min-width: 768px) { 5609 .footer-widgets { 5610 grid-template-columns: 1fr 1fr 1fr 1fr 1.5fr; 5611 } 5612 .footer-widget-col-5 { 5613 display: flex; 5614 flex-direction: column; 5615 align-items: flex-start; 5616 text-align: left; 5617 } 5618 } 5619 .footer-widgets .widget { 5620 padding: 0 !important; 5621 border: none !important; 5622 background: transparent !important; 5623 margin-bottom: 0 !important; 5624 } 5625 .footer-widgets .widget-title { 5626 font-size: 0.8125rem !important; 5627 font-weight: 700 !important; 5628 text-transform: uppercase !important; 5629 letter-spacing: 0.08em !important; 5630 color: var(--geist-foreground) !important; 5631 margin-bottom: 1.25rem !important; 5632 } 5633 .footer-widgets .widget-content { 5634 color: var(--geist-accents-5); 5635 line-height: 1.6; 5636 } 5637 .footer-widgets .widget-content a { 5638 transition: color 0.2s; 5639 text-decoration: none; 5640 color: var(--geist-accents-5); 5641 } 5642 .footer-widgets .widget-content a:hover { 5643 color: var(--geist-foreground) !important; 5644 text-decoration: underline; 5645 } 5646 .admin-quick-edit-btn { 5647 position: absolute; 5648 top: -10px; 5649 right: -10px; 5650 z-index: 100; 5651 display: none; 5652 align-items: center; 5653 justify-content: center; 5654 width: 24px; 5655 height: 24px; 5656 background: #4f46e5; 5657 color: #ffffff !important; 5658 border-radius: 50%; 5659 box-shadow: 0 4px 6px -1px rgba(79, 70, 229, 0.4), 0 2px 4px -1px rgba(79, 70, 229, 0.2); 5660 opacity: 0; 5661 transition: all 0.2s ease-in-out; 5662 cursor: pointer; 5663 } 5664 body.polycms-topbar-active .admin-quick-edit-btn { 5665 display: flex; 5666 } 5667 .footer-widgets-container:hover .admin-quick-edit-btn, 5668 .footer-bottom-left:hover .admin-quick-edit-btn, 5669 .footer-social-wrapper:hover .admin-quick-edit-btn, 5670 .footer-bottom-widgets-container:hover .admin-quick-edit-btn { 5671 opacity: 1; 5672 transform: scale(1.1); 5673 } 5674 .admin-quick-edit-btn:hover { 5675 background: #4338ca; 5676 transform: scale(1.2) !important; 5677 } 5678 .footer-bottom-widgets { 5679 display: flex; 5680 justify-content: space-between; 5681 align-items: flex-end; 5682 flex-wrap: wrap; 5683 gap: 2rem; 5684 border-top: 1px solid var(--geist-accents-2); 5685 padding-top: 2rem; 5686 margin-top: 3rem; 5687 } 5688 .footer-bottom-widgets .widget { 5689 background: transparent !important; 5690 border: none !important; 5691 box-shadow: none !important; 5692 padding: 0 !important; 5693 margin: 0 !important; 5694 } 5695 .footer-bottom-widgets .widget-footer-menu ul { 5696 display: flex; 5697 gap: 1.25rem; 5698 flex-wrap: wrap; 5699 margin-bottom: 0.5rem; 5700 } 5701 .footer-bottom-widgets .widget-footer-menu ul li { 5702 line-height: 1 !important; 5703 } 5704 .footer-bottom-widgets .widget-footer-menu ul li a { 5705 font-weight: 600; 5706 color: var(--geist-foreground) !important; 5707 } 5708 .footer-bottom-widgets .widget-footer-menu ul li a:hover { 5709 color: var(--geist-link) !important; 5710 } 5711 .footer-bottom-widgets .widget-html-block { 5712 flex: 1 1 650px; 5713 } 5714 .footer-bottom-widgets .widget-social-links { 5715 margin-left: auto; 5716 } 5717 .footer-disclaimer a, 5718 .widget-html-editor a, 5719 .widget-html-block a, 5720 .footer-bottom-widgets .widget-html-editor a { 5721 color: var(--theme-link-color, var(--geist-link, #2563eb)) !important; 5722 text-decoration: none; 5723 transition: color 0.2s ease; 5724 } 5725 .footer-disclaimer a:hover, 5726 .widget-html-editor a:hover, 5727 .widget-html-block a:hover, 5728 .footer-bottom-widgets .widget-html-editor a:hover { 5729 color: var(--theme-link-hover-color, #1e40af) !important; 5730 text-decoration: underline; 5731 } 5732 html.dark .footer-disclaimer a, 5733 html.dark .widget-html-editor a, 5734 html.dark .widget-html-block a, 5735 html.dark .footer-bottom-widgets .widget-html-editor a { 5736 color: var(--theme-link-color, #4299e1) !important; 5737 } 5738 html.dark .footer-disclaimer a:hover, 5739 html.dark .widget-html-editor a:hover, 5740 html.dark .widget-html-block a:hover, 5741 html.dark .footer-bottom-widgets .widget-html-editor a:hover { 5742 color: var(--theme-link-hover-color, #63b3ed) !important; 5743 } 5744 </style> 5745 5746 <div class="container"> 5747 5748 5749 <div class="footer-widgets-container" style="position: relative;"> 5750 <a href="/admin/widgets" target="_blank" class="admin-quick-edit-btn" title="Edit Widgets"> 5751 <svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
5751<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z"/></svg> 5752 </a> 5753 <div class="footer-widgets" > 5754 <div class="footer-widget-col footer-widget-col-1"> 5755 <div class="widget-area " data-widget-area="footer_col_1"> 5756 <style> 5757 .polycms-widget-align-right { text-align: right; } 5758 .polycms-widget-align-right .footer-social-icons, 5759 .polycms-widget-align-right .footer-menu-icons, 5760 .polycms-widget-align-right .footer-menu-horizontal { justify-content: flex-end; } 5761 .polycms-widget-align-right .widget-menu-items ul { display: flex; flex-direction: column; align-items: flex-end; } 5762 @media (max-width: 767px) { 5763 .footer-social-icons { justify-content: center !important; } 5764 } 5765 </style><div class="polycms-widget-align-left"><h4 class="widget-heading font-bold">POLYCMS</h4><div class="widget-menu-items"><ul style="list-style: none; padding: 0; margin: 0; line-height: 2.2;"><li><a href="https://polycms.org" target="_self" style="color: var(--geist-accents-5); text-decoration: none; font-size: 0.9rem; transition: color 0.2s; display: inline-flex; align-items: center; gap: 0.5rem;" onmouseover="this.style.color='var(--geist-foreground)'" onmouseout="this.style.color='var(--geist-accents-5)'">Core Features</a></li><li><a href="https://headrandom.com/products" target="_self" style="color: var(--geist-accents-5); text-decoration: none; font-size: 0.9rem; transition: color 0.2s; display: inline-flex; align-items: center; gap: 0.5rem;" onmouseover="this.style.color='var(--geist-foreground)'" onmouseout="this.style.color='var(--geist-accents-5)'">Themes & Plugins</a></li><li><a href="https://polycms.org/docs/polycms-rest-api-developer-guide" target="_self" rel="nofollow" style="color: var(--geist-accents-5); text-decoration: none; font-size: 0.9rem; transition: color 0.2s; display: inline-flex; align-items: center; gap: 0.5rem;" onmouseover="this.style.color='var(--geist-foreground)'" onmouseout="this.style.color='var(--geist-accents-5)'">Developer API</a></li></ul></div></div> 5766 </div> 5767 </div> 5768 <div class="footer-widget-col footer-widget-col-2"> 5769 <div class="widget-area " data-widget-area="footer_col_2"> 5770 <style> 5771 .polycms-widget-align-right { text-align: right; } 5772 .polycms-widget-align-right .footer-social-icons, 5773 .polycms-widget-align-right .footer-menu-icons, 5774 .polycms-widget-align-right .footer-menu-horizontal { justify-content: flex-end; } 5775 .polycms-widget-align-right .widget-menu-items ul { display: flex; flex-direction: column; align-items: flex-end; } 5776 @media (max-width: 767px) { 5777 .footer-social-icons { justify-content: center !important; } 5778 } 5779 </style><div class="polycms-widget-align-left"><h4 class="widget-heading font-bold">HELP</h4><div class="widget-menu-items"><ul style="list-style: none; padding: 0; margin: 0; line-height: 2.2;"><li><a href="https://headrandom.com/y34yNm5v" target="_self" style="color: var(--geist-accents-5); text-decoration: none; font-size: 0.9rem; transition: color 0.2s; display: inline-flex; align-items: center; gap: 0.5rem;" onmouseover="this.style.color='var(--geist-foreground)'" onmouseout="this.style.color='var(--geist-accents-5)'">Help Center</a></li><li><a href="https://headrandom.com/documentation" target="_self" style="color: var(--geist-accents-5); text-decoration: none; font-size: 0.9rem; transition: color 0.2s; display: inline-flex; align-items: center; gap: 0.5rem;" onmouseover="this.style.color='var(--geist-foreground)'" onmouseout="this.style.color='var(--geist-accents-5)'">Documentation</a></li><li><a href="https://headrandom.com/contact" target="_self" style="color: var(--geist-accents-5); text-decoration: none; font-size: 0.9rem; transition: color 0.2s; display: inline-flex; align-items: center; gap: 0.5rem;" onmouseover="this.style.color='var(--geist-foreground)'" onmouseout="this.style.color='var(--geist-accents-5)'">Contact</a></li></ul></div></div> 5780 </div> 5781 </div> 5782 <div class="footer-widget-col footer-widget-col-3"> 5783 <div class="widget-area " data-widget-area="footer_col_3"> 5784 <style> 5785 .polycms-widget-align-right { text-align: right; } 5786 .polycms-widget-align-right .footer-social-icons, 5787 .polycms-widget-align-right .footer-menu-icons, 5788 .polycms-widget-align-right .footer-menu-horizontal { justify-content: flex-end; } 5789 .polycms-widget-align-right .widget-menu-items ul { display: flex; flex-direction: column; align-items: flex-end; } 5790 @media (max-width: 767px) { 5791 .footer-social-icons { justify-content: center !important; } 5792 } 5793 </style>
5793<div class="polycms-widget-align-left"></div> 5794 </div> 5795 </div> 5796 <div class="footer-widget-col footer-widget-col-4"> 5797 <div class="widget-area " data-widget-area="footer_col_4"> 5798 <style> 5799 .polycms-widget-align-right { text-align: right; } 5800 .polycms-widget-align-right .footer-social-icons, 5801 .polycms-widget-align-right .footer-menu-icons, 5802 .polycms-widget-align-right .footer-menu-horizontal { justify-content: flex-end; } 5803 .polycms-widget-align-right .widget-menu-items ul { display: flex; flex-direction: column; align-items: flex-end; } 5804 @media (max-width: 767px) { 5805 .footer-social-icons { justify-content: center !important; } 5806 } 5807 </style><div class="polycms-widget-align-left"></div> 5808 </div> 5809 </div> 5810 <div class="footer-widget-col footer-widget-col-5"> 5811 <style> 5812 .polycms-widget-align-right { text-align: right; } 5813 .polycms-widget-align-right .footer-social-icons, 5814 .polycms-widget-align-right .footer-menu-icons, 5815 .polycms-widget-align-right .footer-menu-horizontal { justify-content: flex-end; } 5816 .polycms-widget-align-right .widget-menu-items ul { display: flex; flex-direction: column; align-items: flex-end; } 5817 @media (max-width: 767px) { 5818 .footer-social-icons { justify-content: center !important; } 5819 } 5820 </style><div class="polycms-widget-align-left"><h4 class="widget-heading font-bold">SUBSCRIBE</h4><div class="widget widget-contact-form" style="width: 100%; position: relative;"><form id="contact-form-1-6abedb820d641" class="contact-form-widget-el" style="display: flex; align-items: flex-end; gap: 0.5rem; width: 100%;"><input type="hidden" name="form_id" value="1"><div class="form-group" style="display: flex; flex-direction: column; gap: 0.25rem; flex: 1; min-width: 0; position: relative;"><label style="font-size: 0.8rem; font-weight: 500; color: var(--geist-accents-5); white-space: nowrap; text-overflow: ellipsis; overflow: hidden; display: block;">Email Address <span style="color: var(--geist-error); font-size: 0.7rem;">*</span></label><input type="email" name="email" required placeholder="Your email address..." style="width: 100%; height: 42px; padding: 0.6rem 0.8rem; border-radius: 8px; border: 1px solid var(--geist-accents-2); background: var(--geist-background); color: var(--geist-foreground); font-size: 0.85rem; outline: none; transition: border-color 0.2s; box-sizing: border-box;" onfocus="this.style.borderColor='var(--geist-foreground)'" onblur="this.style.borderColor='var(--geist-accents-2)'"><span class="invalid-feedback" style="display: none; color: #ef4444; font-size: 0.75rem; position: absolute; top: 100%; left: 0; right: 0; z-index: 99; margin-top: 0.25rem; white-space: nowrap; text-overflow: ellipsis; overflow: hidden;"></span></div><button type="submit" class="submit-btn" style="padding: 0 1.25rem; border-radius: 8px; border: none; background: var(--geist-foreground); color: var(--geist-background); font-size: 0.85rem; font-weight: 600; cursor: pointer; transition: opacity 0.2s; display: flex; align-items: center; justify-content: center; height: 42px; white-space: nowrap; box-sizing: border-box;" onmouseover="this.style.opacity='0.9'" onmouseout="this.style.opacity='1'"><span>Submit</span></button><div class="form-feedback" style="display: none; font-size: 0.85rem; position: absolute; top: 100%; left: 0; right: 0; z-index: 99; margin-top: 0.5rem; padding: 0.5rem 0.75rem; border-radius: 6px; box-shadow: 0 4px 12px rgba(0,0,0,0.1);"></div></form>
5820<script> 5821 (function() { 5822 var form = document.getElementById("contact-form-1-6abedb820d641"); 5823 if (!form) return; 5824 5825 // Register input clear handlers 5826 form.querySelectorAll(".form-group input, .form-group textarea").forEach(function(el) { 5827 el.addEventListener("input", function() { 5828 el.style.borderColor = "var(--geist-accents-2)"; 5829 var errSpan = el.parentNode.querySelector(".invalid-feedback"); 5830 if (errSpan) { 5831 errSpan.style.display = "none"; 5832 } 5833 }); 5834 }); 5835 5836 form.addEventListener("submit", function(e) { 5837 e.preventDefault(); 5838 var btn = form.querySelector(".submit-btn"); 5839 var feedback = form.querySelector(".form-feedback"); 5840 var btnText = btn.querySelector("span"); 5841 5842 btn.disabled = true; 5843 btn.style.opacity = "0.7"; 5844 btnText.textContent = "Sending..."; 5845 feedback.style.display = "none"; 5846 5847 // Clear validation errors 5848 form.querySelectorAll(".form-group input, .form-group textarea").forEach(function(el) { 5849 el.style.borderColor = "var(--geist-accents-2)"; 5850 var errSpan = el.parentNode.querySelector(".invalid-feedback"); 5851 if (errSpan) { 5852 errSpan.style.display = "none"; 5853 errSpan.textContent = ""; 5854 } 5855 }); 5856 var recaptchaErr = form.querySelector(".recaptcha-container .invalid-feedback"); 5857 if (recaptchaErr) { 5858 recaptchaErr.style.display = "none"; 5859 recaptchaErr.textContent = ""; 5860 } 5861 5862 var formData = new FormData(form); 5863 var data = {}; 5864 formData.forEach(function(value, key) { 5865 data[key] = value; 5866 }); 5867 5868 fetch("/api/v1/public/contacts/submit", { 5869 method: "POST", 5870 headers: { 5871 "Content-Type": "application/json", 5872 "Accept": "application/json", 5873 "X-Requested-With": "XMLHttpRequest" 5874 }, 5875 body: JSON.stringify(data) 5876 }) 5877 .then(function(response) { 5878 return response.json().then(function(json) { 5879 return { status: response.status, ok: response.ok, data: json }; 5880 }); 5881 }) 5882 .then(function(res) { 5883 btn.disabled = false; 5884 btn.style.opacity = "1"; 5885 btnText.textContent = "Submit"; 5886 5887 if (res.ok) { 5888 feedback.style.display = "block"; 5889 feedback.style.background = "rgba(16, 185, 129, 0.1)"; 5890 feedback.style.color = "#10b981"; 5891 feedback.style.border = "1px solid rgba(16, 185, 129, 0.2)"; 5892 feedback.textContent = res.data.message || "Thank you! Your submission has been received."; 5893 form.reset(); 5894 if (typeof grecaptcha !== "undefined") { 5895 grecaptcha.reset(); 5896 } 5897 5898 setTimeout(function() { 5899 feedback.style.display = "none"; 5900 }, 5000); 5901 } else { 5902 if (res.data.errors) { 5903 for (var key in res.data.errors) { 5904 if (key === "g-recaptcha-response") { 5905 var container = form.querySelector(".recaptcha-container"); 5906 if (container) { 5907 var errSpan = container.querySelector(".invali
5907d-feedback"); 5908 if (errSpan) { 5909 errSpan.style.display = "block"; 5910 errSpan.textContent = res.data.errors[key].join(" "); 5911 } 5912 } 5913 continue; 5914 } 5915 var inputEl = form.querySelector("[name='" + key + "']"); 5916 if (inputEl) { 5917 inputEl.style.borderColor = "#ef4444"; 5918 var errSpan = inputEl.parentNode.querySelector(".invalid-feedback"); 5919 if (errSpan) { 5920 errSpan.style.display = "block"; 5921 errSpan.textContent = res.data.errors[key].join(" "); 5922 } 5923 } 5924 } 5925 5926 setTimeout(function() { 5927 form.querySelectorAll(".form-group input, .form-group textarea").forEach(function(el) { 5928 el.style.borderColor = "var(--geist-accents-2)"; 5929 var errSpan = el.parentNode.querySelector(".invalid-feedback"); 5930 if (errSpan) { 5931 errSpan.style.display = "none"; 5932 } 5933 }); 5934 var recaptchaErr = form.querySelector(".recaptcha-container .invalid-feedback"); 5935 if (recaptchaErr) { 5936 recaptchaErr.style.display = "none"; 5937 } 5938 }, 5000); 5939 } else { 5940 feedback.style.display = "block"; 5941 feedback.style.background = "rgba(239, 68, 68, 0.1)"; 5942 feedback.style.color = "#ef4444"; 5943 feedback.style.border = "1px solid rgba(239, 68, 68, 0.2)"; 5944 feedback.textContent = res.data.message || "An error occurred. Please try again."; 5945 5946 setTimeout(function() { 5947 feedback.style.display = "none"; 5948 }, 5000); 5949 } 5950 } 5951 }) 5952 .catch(function(err) { 5953 btn.disabled = false; 5954 btn.style.opacity = "1"; 5955 btnText.textContent = "Submit"; 5956 feedback.style.display = "block"; 5957 feedback.style.background = "rgba(239, 68, 68, 0.1)"; 5958 feedback.style.color = "#ef4444"; 5959 feedback.style.border = "1px solid rgba(239, 68, 68, 0.2)"; 5960 feedback.textContent = "Connection error. Please try again."; 5961 }); 5962 }); 5963 })(); 5964 </script>
5964</div></div> 5965 </div> 5966 </div> 5967 </div> 5968 5969 <div class="footer-bottom-widgets-container" style="position: relative; width: 100%;"> 5970 <a href="/admin/widgets" target="_blank" class="admin-quick-edit-btn" title="Edit Footer Bottom" style="top: 10px; right: 10px;"> 5971 <svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z"/></svg> 5972 </a> 5973 <div class="footer-bottom-widgets"> 5974 <style> 5975 .polycms-widget-grid { display: grid; gap: 2rem; width: 100%; } 5976 .polycms-widget-grid .widget { flex: none !important; margin: 0 !important; width: 100% !important; } 5977 .polycms-widget-grid .widget-social-links { margin-left: 0 !important; } 5978 .footer-bottom-widgets:has(.polycms-widget-grid) { display: block !important; } 5979 .polycms-widget-align-right { text-align: right; } 5980 .polycms-widget-align-right .footer-social-icons, 5981 .polycms-widget-align-right .footer-menu-icons, 5982 .polycms-widget-align-right .footer-menu-horizontal { justify-content: flex-end; } 5983 .polycms-widget-align-right .widget-menu-items ul { display: flex; flex-direction: column; align-items: flex-end; } 5984 @media (max-width: 767px) { 5985 .polycms-widget-grid { grid-template-columns: 1fr !important; } 5986 .footer-social-icons { justify-content: center !important; } 5987 } 5988 </style><div class="polycms-widget-grid polycms-widget-grid-split-left" style="grid-template-columns: 2fr 1fr;"><div class="polycms-widget-col polycms-widget-col-0 polycms-widget-align-left" style=""><div class="widget-menu-items widget-menu-items-horizontal"><div class="footer-menu-horizontal" style="display: flex; gap: 1.5rem; align-items: center; flex-wrap: wrap;"><a href="https://codecanyon.net/user/polyxgo/portfolio" target="_blank" style="color: var(--geist-foreground); font-weight: 600; text-decoration: none; font-size: 0.9rem; transition: color 0.2s; display: inline-flex; align-items: center; gap: 0.5rem;" onmouseover="this.style.color='var(--geist-link)'" onmouseout="this.style.color='var(--geist-foreground)'">Envato Portfolio</a><a href="https://headrandom.com/y34yNm5v" target="_blank" style="color: var(--geist-foreground); font-weight: 600; text-decoration: none; font-size: 0.9rem; transition: color 0.2s; display: inline-flex; align-items: center; gap: 0.5rem;" onmouseover="this.style.color='var(--geist-link)'" onmouseout="this.style.color='var(--geist-foreground)'">Support Center</a><a href="https://www.facebook.com/polyxgoltd" target="_blank" style="color: var(--geist-foreground); font-weight: 600; text-decoration: none; font-size: 0.9rem; transition: color 0.2s; display: inline-flex; align-items: center; gap: 0.5rem;" onmouseover="this.style.color='var(--geist-link)'" onmouseout="this.style.color='var(--geist-foreground)'">Facebook Page</a><a href="https://headrandom.com/GlU63s5D" target="_blank" style="color: var(--geist-foreground); font-weight: 600; text-decoration: none; font-size: 0.9rem; transition: color 0.2s; display: inline-flex; align-items: center; gap: 0.5rem;" onmouseover="this.style.color='var(--geist-link)'" onmouseout="this.style.color='var(--geist-foreground)'">YouTube Channel</a></div></div><div class="widget widget-html-editor"><div class="widget-content">Powered by <a target="_blank" rel="nofollow" class="text-admin-theme-primary dark:text-admin-theme-primary hover:underline" href="https://polycms.org">PolyCMS</a> - Modern Open-Source CMS built with Laravel.<br>© 2026 PolyXGO. All rights reserved.</div></div></div><div class="polycms-widget-col polycms-widget-col-1 polycms-widget-align-right" style="text-align: right; display: flex; flex-direction: column; align-items: flex-end;"><div class="widget-social-links"><div class="widget-content"><div class="footer-social-icons" style="display: flex; gap: 0.5rem; align-items: center;"><a href="https://www.facebook.com/polyxgoltd" target="_blank" title="Facebook" style="width: 32px; height: 32px; border-radius: 50%; border: 1px solid var(--geist-accents-2); display: flex; align-items: center; justify-content: center; color: var(--geist-accents-5); text-decoration: none; transition: all 0.2s; overflow: hidden;" onmouseover="this.style.borderColor='var(--geist-foreground)'; this.style.color='var(--geist-foreground)'; this.style.background='var(--geist-accents-1)';" onmouseout="this.style.borderColor='var(--geist-accents-2)'; this.style.color='var(--geist-accents-5)'; this.style.background='transparent';"><span class="social-icon-svg-wrapper" style="width: 16px; height: 16px; display: flex; align-items: center; justify-content: center; overflow: hidden; fill: currentColor;"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 16 16" style="width: 100%; height: 100%; display: block; overflow: hidden;"><path d="M16 8.049c0-4.446-3.582-8.05-8-8.05C3.58 0-.002 3.603-.002 8.05c0 4.017 2.926 7.347 6.75 7.951v-5.625
5988h-2.03V8.05H6.75V6.275c0-2.017 1.195-3.131 3.022-3.131.876 0 1.791.157 1.791.157v1.98h-1.009c-.993 0-1.303.621-1.303 1.258v1.51h2.218l-.354 2.326H9.25V16c3.824-.604 6.75-3.934 6.75-7.951"/></svg></span></a><a href="https://headrandom.com/GlU63s5D" target="_blank" title="YouTube" style="width: 32px; height: 32px; border-radius: 50%; border: 1px solid var(--geist-accents-2); display: flex; align-items: center; justify-content: center; color: var(--geist-accents-5); text-decoration: none; transition: all 0.2s; overflow: hidden;" onmouseover="this.style.borderColor='var(--geist-foreground)'; this.style.color='var(--geist-foreground)'; this.style.background='var(--geist-accents-1)';" onmouseout="this.style.borderColor='var(--geist-accents-2)'; this.style.color='var(--geist-accents-5)'; this.style.background='transparent';"><span class="social-icon-svg-wrapper" style="width: 16px; height: 16px; display: flex; align-items: center; justify-content: center; overflow: hidden; fill: currentColor;"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 16 16" style="width: 100%; height: 100%; display: block; overflow: hidden;"><path d="M8.051 1.999h-.089c-1.603-.02-6.72-.08-8.382.458-1.22.4-1.218 1.583-1.218 2.295a63 63 0 0 0-.012 8.154c-.012.711-.012 1.892 1.218 2.295 1.662.539 6.779.479 8.382.458.026 0 .053.004.079.004.026 0 .053-.004.079-.004 1.602-.021 6.721-.08 8.382-.458 1.22-.4 1.217-1.583 1.217-2.295.012-1.785.012-6.374 0-8.154-.013-.711-.013-1.892-1.217-2.295-1.66-.539-6.779-.479-8.382-.458h-.089zm-.584 9.098V5.086L12.5 8.092z"/></svg></span></a><a href="https://github.com/polyxgo" target="_blank" title="GitHub" style="width: 32px; height: 32px; border-radius: 50%; border: 1px solid var(--geist-accents-2); display: flex; align-items: center; justify-content: center; color: var(--geist-accents-5); text-decoration: none; transition: all 0.2s; overflow: hidden;" onmouseover="this.style.borderColor='var(--geist-foreground)'; this.style.color='var(--geist-foreground)'; this.style.background='var(--geist-accents-1)';" onmouseout="this.style.borderColor='var(--geist-accents-2)'; this.style.color='var(--geist-accents-5)'; this.style.background='transparent';"><span class="social-icon-svg-wrapper" style="width: 16px; height: 16px; display: flex; align-items: center; justify-content: center; overflow: hidden; fill: currentColor;"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 16 16" style="width: 100%; height: 100%; display: block; overflow: hidden;"><path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27s1.36.09 2 .27c1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.01 8.01 0 0 0 16 8c0-4.42-3.58-8-8-8"/></svg></span></a><a href="https://codecanyon.net/user/polyxgo/portfolio" target="_blank" title="Envato" style="width: 32px; height: 32px; border-radius: 50%; border: 1px solid var(--geist-accents-2); display: flex; align-items: center; justify-content: center; color: var(--geist-accents-5); text-decoration: none; transition: all 0.2s; overflow: hidden;" onmouseover="this.style.borderColor='var(--geist-foreground)'; this.style.color='var(--geist-foreground)'; this.style.background='var(--geist-accents-1)';" onmouseout="this.style.borderColor='var(--geist-accents-2)'; this.style.color='var(--geist-accents-5)'; this.style.background='transparent';"><span class="social-icon-svg-wrapper" style="width: 16px; height: 16px; display: flex; align-items: center; justify-content: center; overflow: hidden; fill: currentColor;"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 16 16" style="width: 100%; height: 100%; display: block; overflow: hidden;"><path d="M11.644 1.206c.712.44 1.347.962 1.9 1.55-1.137.953-2.484 1.825-4.015 2.593-.207-.585-.395-1.19-.562-1.813 1.037-.9 1.93-1.68 2.677-2.33M7.625 4.148c.244.887.585 1.737-1.71 1.737C4.5 6.5 3.665 6.643 3.624 6.65a7 7 0 0 1 2.001-2.502M5.58 7.647c.03-.007 1.047-.16 2.873-.787.21.46.438.92.684 1.37-1.92.632-3.447 1.97-3.528 2.046a7 7 0 0 1-.03-2.63m.967 3.398c.09-.08 1.637-1.39 3.585-2.003.224.417.464.823.722 1.217-2.155 1.045-3.321 2.809-3.364 2.877a7 7 0 0 1-.943-2.09m3.606 2.766q.081-.137.954-1.39c.27-.37.558-.75.864-1.13 1.32.748 2.41 1.764 3.197 2.977a7 7 0 0 1-5.015-.457m5.918-1.579c-.742-1.127-1.748-2.062-2.96-2.73.238-.344.492-.68.762-1.006 1.36.425 2.793.593 4.135.534-.08 1.26-.786 2.336-1.937 3.202"/></svg></span></a></div></div></div></div></div> 5989 </div> 5990 </div> 5991 </div> 5992 </div> 5993</footer> 5994 </div> 5995 5996 5997 <div class="post-scroll-tools"> 5998 <div class="post-scroll-tools-inner"> 5999 <button class="scroll-btn" id="scroll-to-top" aria-label="Scroll to top" title="Scroll to top"> 6000 <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"> 6001 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 10l7-7m0 0l7 7m-7-7v18" /> 6002 </svg> 6003 </button> 6004 <button class="scroll-btn" id="scroll-to-bottom" aria-label="Scroll to bottom" title="Scroll to bottom"> 6005 <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"> 6006 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 14l-7 7m0 0l-7-7m7 7V3" /> 6007 </svg> 6008 </button> 6009 </div> 6010 </div> 6011 6012 <!-- MTxFlow Core Library --> 6013
6013<script src="https://headrandom.com/vendor/mtx-flow/mtx-flow.bundle.min.js"></script>
6013 6014 6015 <!-- Theme Scripts --> 6016
6016<script src="https://headrandom.com/themes/flexiwhite/js/main.js?v=1790892930"></script>
6016 6017 6018
6018<script> 6019 (function() { 6020 document.addEventListener("mouseover", function(e) { 6021 var link = e.target.closest("a"); 6022 if (!link || !link.href) return; 6023 if (!link.href.startsWith(location.origin)) return; 6024 6025 // Exclude prefetching the current active page 6026 var cleanLinkHref = link.href.split("#")[0].split("?")[0]; 6027 var cleanCurrentHref = location.href.split("#")[0].split("?")[0]; 6028 if (cleanLinkHref === cleanCurrentHref) return; 6029 6030 var href = link.getAttribute("href") || ""; 6031 6032 // 1. Explicit no-prefetch flags 6033 if (link.hasAttribute("data-prefetched") || link.hasAttribute("data-no-prefetch") || link.classList.contains("no-prefetch")) return; 6034 6035 // 2. Interactive modal / popup triggers 6036 if (link.hasAttribute("data-bs-toggle") || link.hasAttribute("data-toggle") || link.hasAttribute("data-modal") || link.hasAttribute("data-lightbox") || link.hasAttribute("data-fancybox")) return; 6037 6038 // 3. Target / rel attributes 6039 var target = link.getAttribute("target") || ""; 6040 var rel = link.getAttribute("rel") || ""; 6041 if (target === "_blank" || rel.includes("nofollow") || rel.includes("sponsored")) return; 6042 6043 // 4. Exclude javascript links, anchors, and query strings 6044 if (href.startsWith("#") || href.startsWith("javascript:") || href.includes("?")) return; 6045 6046 // 5. Path pattern exclusions 6047 var lowercaseHref = href.toLowerCase(); 6048 var excludePaths = ["/admin", "/logout", "/login", "/register", "/auth", "/account", "/cart", "/checkout", "/add-to-cart", "/remove-cart", "/wishlist", "/compare", "/download", "/file/", "/lang/", "/locale/", "/currency/", "/switch-"]; 6049 for (var i = 0; i < excludePaths.length; i++) { 6050 if (lowercaseHref.includes(excludePaths[i])) return; 6051 } 6052 6053 // 6. Downloadable file extension exclusions 6054 var fileExts = [".pdf", ".zip", ".rar", ".7z", ".tar", ".gz", ".mp4", ".mp3", ".doc", ".docx", ".xls", ".xlsx", ".exe", ".apk"]; 6055 for (var j = 0; j < fileExts.length; j++) { 6056 if (lowercaseHref.endsWith(fileExts[j])) return; 6057 } 6058 6059 var prefetchLink = document.createElement("link"); 6060 prefetchLink.rel = "prefetch"; 6061 prefetchLink.href = link.href; 6062 document.head.appendChild(prefetchLink); 6063 link.setAttribute("data-prefetched", "true"); 6064 }); 6065 })(); 6066 </script>
6066 6067<style> 6068 .execution-time-badge { 6069 font-size: 0.8125rem; 6070 font-weight: 500; 6071 color: var(--geist-accents-5, #888); 6072 white-space: nowrap; 6073 display: inline-flex; 6074 align-items: center; 6075 } 6076 @media (max-width: 640px) { 6077 .execution-time-badge { 6078 font-size: 0.54rem !important; 6079 letter-spacing: -0.02em !important; 6080 max-width: calc(100vw - 110px); 6081 overflow: hidden; 6082 text-overflow: ellipsis; 6083 } 6084 .execution-time-badge svg { 6085 width: 0.52rem !important; 6086 height: 0.52rem !important; 6087 } 6088 } 6089 </style>
6090<script> 6091 document.addEventListener("DOMContentLoaded", function() { 6092 setTimeout(function() { 6093 var perf = performance.getEntriesByType("navigation")[0]; 6094 if (perf) { 6095 var rawMs = 0; 6096 var start = perf.activationStart || perf.requestStart || perf.startTime || 0; 6097 if (perf.responseEnd && perf.responseEnd > 0 && perf.responseEnd > start) { 6098 rawMs = perf.responseEnd - start; 6099 } else if (perf.domInteractive && perf.domInteractive > 0 && perf.domInteractive > start) { 6100 rawMs = perf.domInteractive - start; 6101 } else { 6102 rawMs = perf.duration || 0; 6103 } 6104 var pageMs = isNaN(rawMs) || rawMs <= 0 ? "0.00" : parseFloat(rawMs).toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 }); 6105 document.querySelectorAll(".execution-time-badge").forEach(function(badge) { 6106 var serverMs = badge.getAttribute("data-server-ms") || ""; 6107 var boltSvg = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" style="width: 0.68rem; height: 0.68rem; display: inline-block; vertical-align: -1px; margin-right: 2px; color: var(--geist-accents-5, #888);"><path fill-rule="evenodd" d="M14.615 1.595a.75.75 0 0 1 .359.852L12.982 9.75h7.268a.75.75 0 0 1 .548 1.262l-10.5 11.25a.75.75 0 0 1-1.265-.723l1.992-7.289H3.75a.75.75 0 0 1-.548-1.262l10.5-11.25a.75.75 0 0 1 .913-.143Z" clip-rule="evenodd" /></svg>'; 6108 var rocketSvg = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" style="width: 0.68rem; height: 0.68rem; display: inline-block; vertical-align: -1px; margin-right: 2px; color: var(--geist-accents-5, #888);"><path d="M10.5 1.5a.75.75 0 0 0-.75.75v1.5h-1.5a.75.75 0 0 0 0 1.5h1.5v1.5a.75.75 0 0 0 1.5 0V5.25h1.5a.75.75 0 0 0 0-1.5h-1.5V2.25a.75.75 0 0 0-.75-.75ZM6 6a.75.75 0 0 0-.75.75v3h-3a.75.75 0 0 0 0 1.5h3v3a.75.75 0 0 0 1.5 0v-3h3a.75.75 0 0 0 0-1.5h-3v-3A.75.75 0 0 0 6 6Zm12 1.5a.75.75 0 0 0-.75.75v3h-3a.75.75 0 0 0 0 1.5h3v3a.75.75 0 0 0 1.5 0v-3h3a.75.75 0 0 0 0-1.5h-3v-3A.75.75 0 0 0 18 7.5Z"/></svg>'; 6109 badge.innerHTML = boltSvg + serverMs + " ms (Server) <span style=\"opacity: 0.4; margin: 0 3px;\">|</span> " + rocketSvg + pageMs + " ms (Page)"; 6110 }); 6111 } 6112 }, 10); 6113 }); 6114 </script>
6114 6115 6116<!-- PolyCMS Cookie Consent Banner --> 6117<style> 6118 #polycms-cookie-consent { 6119 display: none; 6120 position: fixed; 6121 bottom: 0; 6122 left: 0; 6123 right: 0; 6124 z-index: 99999; 6125 background-color: #111; 6126 color: #fff; 6127 padding: 16px 20px; 6128 align-items: center; 6129 justify-content: center; 6130 gap: 18px; 6131 font-family: -apple-system, system-ui, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif; 6132 font-size: 14px; 6133 box-shadow: 0 -2px 10px rgba(0,0,0,0.5); 6134 } 6135 #polycms-cookie-consent .polycms-cookie-inner { 6136 width: min(100%, 1120px); 6137 display: flex; 6138 align-items: center; 6139 justify-content: space-between; 6140 gap: 18px; 6141 } 6142 #polycms-cookie-consent .polycms-cookie-message { 6143 display: flex; 6144 align-items: center; 6145 gap: 14px; 6146 flex: 1; 6147 min-width: 240px; 6148 } 6149 #polycms-cookie-consent .polycms-cookie-icon { 6150 background-color: #ef4444; 6151 border-radius: 50%; 6152 width: 36px; 6153 height: 36px; 6154 display: flex; 6155 align-items: center; 6156 justify-content: center; 6157 flex-shrink: 0; 6158 } 6159 #polycms-cookie-consent .polycms-cookie-message p { 6160 margin: 0; 6161 line-height: 1.45; 6162 font-weight: 600; 6163 } 6164 #polycms-cookie-consent .polycms-cookie-actions { 6165 display: flex; 6166 align-items: center; 6167 justify-content: flex-end; 6168 gap: 10px; 6169 flex-wrap: wrap; 6170 } 6171 #polycms-cookie-consent button { 6172 min-height: 36px; 6173 border-radius: 5px; 6174 cursor: pointer; 6175 font-weight: 600; 6176 font-size: 13px; 6177 transition: all 0.2s; 6178 white-space: nowrap; 6179 } 6180 #cookie-reject, 6181 #cookie-customize { 6182 background: #fff; 6183 color: #333; 6184 border: 1px solid #ccc; 6185 padding: 8px 16px; 6186 } 6187 #cookie-accept { 6188 background: #3b82f6; 6189 color: #fff; 6190 border: 1px solid #2563eb; 6191 padding: 8px 16px; 6192 } 6193 @media (max-width: 640px) { 6194 #polycms-cookie-consent { 6195 padding: 14px 18px; 6196 } 6197 #polycms-cookie-consent .polycms-cookie-inner { 6198 flex-direction: column; 6199 align-items: stretch; 6200 gap: 12px; 6201 } 6202 #polycms-cookie-consent .polycms-cookie-message { 6203 align-items: flex-start; 6204 gap: 12px; 6205 min-width: 0; 6206 } 6207 #polycms-cookie-consent .polycms-cookie-icon { 6208 width: 34px; 6209 height: 34px;
6210 margin-top: 1px; 6211 } 6212 #polycms-cookie-consent .polycms-cookie-message p { 6213 font-size: 12.5px; 6214 line-height: 1.45; 6215 } 6216 #polycms-cookie-consent .polycms-cookie-actions { 6217 display: grid; 6218 grid-template-columns: minmax(0, 0.72fr) minmax(0, 1.68fr); 6219 gap: 8px; 6220 } 6221 #polycms-cookie-consent button { 6222 width: 100%; 6223 min-height: 34px; 6224 padding: 7px 10px; 6225 font-size: 12px; 6226 } 6227 #cookie-accept { 6228 grid-column: 1 / -1; 6229 } 6230 } 6231</style> 6232<div id="polycms-cookie-consent" style="display: none;"> 6233 <div class="polycms-cookie-inner"> 6234 <div class="polycms-cookie-message"> 6235 <div class="polycms-cookie-icon"> 6236 <svg style="width: 20px; height: 20px; fill: #fff;" viewBox="0 0 24 24"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z"/></svg> 6237 </div> 6238 <p>Your experience on this site will be improved by allowing cookies.</p> 6239 </div> 6240 <div class="polycms-cookie-actions"> 6241 <button id="cookie-reject">Reject</button> 6242 <button id="cookie-customize">Customize preferences</button> 6243 <button id="cookie-accept">Accept cookies</button> 6244 </div> 6245 </div> 6246</div> 6247
6248<script> 6249(function() { 6250 var banner = document.getElementById("polycms-cookie-consent"); 6251 if (!banner) return; 6252 6253 var consentCookie = document.cookie.match(/(?:^|;\s*)polycms_consent=([^;]*)/); 6254 // If user has NOT given consent yet, show the banner 6255 if (!consentCookie) { 6256 banner.style.display = "flex"; 6257 } 6258 6259 function setCookie(value) { 6260 var d = new Date(); 6261 d.setTime(d.getTime() + (365*24*60*60*1000)); 6262 document.cookie = "polycms_consent=" + value + ";expires=" + d.toUTCString() + ";path=/;SameSite=Lax"; 6263 banner.style.display = "none"; 6264 } 6265 6266 var btnAccept = document.getElementById("cookie-accept"); 6267 var btnReject = document.getElementById("cookie-reject"); 6268 var btnCustomize = document.getElementById("cookie-customize"); 6269 6270 if (btnAccept) btnAccept.addEventListener("click", function() { setCookie("accepted"); }); 6271 if (btnReject) btnReject.addEventListener("click", function() { setCookie("rejected"); }); 6272 if (btnCustomize) btnCustomize.addEventListener("click", function() { 6273 window.location.href = "/privacy-policy"; 6274 }); 6275})(); 6276</script>
6276 6277<!-- End PolyCMS Cookie Consent --></body> 6278</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.