Diff -- /var/www/vhosts/3dshawn.com/abforge.3dshawn.com/TEMPLATES/abforge_marketing.html

O Operator
Diff

/var/www/vhosts/3dshawn.com/abforge.3dshawn.com/TEMPLATES/abforge_marketing.html

added on local at 2026-07-11 08:17:30

Added
+110
lines
Removed
-0
lines
Context
0
unchanged
Blobs
from
to 9b661f73333e
Restore this content →
Unified diff
Naive LCS-based line diff. Additions in emerald, deletions in rose. Both sides decompressed live from BLOB_STORE.
1<!DOCTYPE html>
2<html lang="en">
3<head>
4 <meta charset="UTF-8">
5 <meta name="viewport" content="width=device-width, initial-scale=1.0">
6 <title>$title &middot; $website_title</title>
7$meta_tags
8 <link rel="icon" type="image/svg+xml" href="$assets/images/favicon.svg?v=20260608">
9 <link rel="alternate icon" href="$assets/images/favicon.svg?v=20260608">
10 <link rel="apple-touch-icon" href="$assets/images/favicon.svg?v=20260608">
11 <link rel="preconnect" href="https://fonts.googleapis.com">
12 <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
13 <link href="https://fonts.googleapis.com/css2?family=Inter:wght\@400;500;600;700&family=Space+Grotesk:wght\@500;600;700&family=JetBrains+Mono:wght\@400;600&display=swap" rel="stylesheet">
14 <link rel="stylesheet" href="$assets_css/site.css?v=2026-06-12-fixbrand">
15 $extra_css
16</head>
17<body>
18 $body
19 <script src="$assets_js/site.js"></script>
20 <!-- In-app popup helper (confirm/alert/prompt/toast). Same script the
21 dashboard uses, loaded on marketing pages too so public flows
22 get consistent overlays instead of native alert(). -->
23 <script src="$assets_js/confirm.js?v=1"></script>
24 <!-- Visitor tracking + customer chat widget.
25 Loaded on every page that uses the marketing wrapper -- which is
26 every logged-out marketing page. NOT loaded on the logged-in
27 dashboard (abforge_wrapper.html) -- admins control and read the
28 chat from /admin_chat.cgi and /admin_visitors.cgi instead.
29 Also suppressed when an admin is previewing this page inside the
30 /admin_heatmap.cgi iframe (heatmap_view=1) so their preview
31 clicks don't get recorded as real visitor activity. -->
32 [if:!$heatmap_view]<script src="$assets_js/track.js?v=5"></script>[/if]
33 $extra_js
34
35<!-- Anonymous path tracker. Only included from the marketing wrapper, so
36 logged-in app pages never call /t.cgi. -->
37<script>
38(function(){
39 try {
40 var u = new URLSearchParams(location.search);
41 var qs = '?p=' + encodeURIComponent(location.pathname + location.search)
42 + '&r=' + encodeURIComponent(document.referrer || '')
43 + '&us=' + encodeURIComponent(u.get('utm_source') || '')
44 + '&um=' + encodeURIComponent(u.get('utm_medium') || '')
45 + '&uc=' + encodeURIComponent(u.get('utm_campaign') || '');
46 var img = new Image();
47 img.referrerPolicy = 'no-referrer-when-downgrade';
48 img.src = '/t.cgi' + qs;
49 } catch (e) { /* silent */ }
50})();
51</script>
52<script>
53/* sidebar-scroll-preserve: keeps .sidebar scrollTop across page loads */
54(function(){
55 var sb = document.querySelector('.sidebar');
56 if (!sb) return;
57 var KEY = 'abforge.3dshawn.com-sidebar-scroll';
58 try { var s = parseInt(localStorage.getItem(KEY), 10) || 0; if (s > 0) sb.scrollTop = s; } catch(e){}
59 var t = null;
60 sb.addEventListener('scroll', function(){
61 if (t) clearTimeout(t);
62 t = setTimeout(function(){ try { localStorage.setItem(KEY, sb.scrollTop); } catch(e){} }, 80);
63 }, { passive: true });
64})();
65</script>
66<!-- Viewer-local timestamp renderer (portfolio-canonical).
67 Server emits `<span class="ts" data-ts="EPOCH" data-fmt="…">FALLBACK</span>`.
68 Formats: datetime | date | date-short | time | relative
69 Original text is the no-JS fallback. Re-run via window.tzLocalize() after AJAX. -->
70<script>
71(function(){
72 function fmt(el){
73 var e = parseInt(el.getAttribute('data-ts'), 10);
74 if (!e) return;
75 var d = new Date(e * 1000);
76 var kind = el.getAttribute('data-fmt') || 'datetime';
77 var out;
78 switch (kind) {
79 case 'date': out = d.toLocaleDateString(undefined, {year:'numeric',month:'short',day:'numeric'}); break;
80 case 'date-short': out = d.toLocaleDateString(undefined, {month:'short',day:'numeric'}); break;
81 case 'time': out = d.toLocaleTimeString(undefined, {hour:'2-digit',minute:'2-digit'}); break;
82 case 'relative': out = rel(e); break;
83 default: out = d.toLocaleDateString(undefined, {year:'numeric',month:'short',day:'numeric'})
84 + ' ' + d.toLocaleTimeString(undefined, {hour:'2-digit',minute:'2-digit'});
85 }
86 el.textContent = out;
87 if (!el.title) el.title = d.toString();
88 }
89 function rel(e){
90 var s = Math.floor(Date.now()/1000) - e, future = s < 0; s = Math.abs(s);
91 var n, u;
92 if (s < 60) { n = s; u = 'second'; }
93 else if (s < 3600) { n = Math.floor(s/60); u = 'minute'; }
94 else if (s < 86400) { n = Math.floor(s/3600); u = 'hour'; }
95 else if (s < 2592000){ n = Math.floor(s/86400); u = 'day'; }
96 else if (s < 31536000){n = Math.floor(s/2592000); u = 'month'; }
97 else { n = Math.floor(s/31536000);u = 'year'; }
98 var p = n === 1 ? '' : 's';
99 return future ? ('in ' + n + ' ' + u + p) : (n + ' ' + u + p + ' ago');
100 }
101 function localize(root){ (root||document).querySelectorAll('span.ts[data-ts], time[data-ts]').forEach(fmt); }
102 window.tzLocalize = localize;
103 if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', function(){ localize(); });
104 else localize();
105 window.addEventListener('ts-refresh', function(){ localize(); });
106})();
107</script>
108
109</body>
110</html>