Diff -- /var/www/vhosts/3dshawn.com/affiliate.3dshawn.com/TEMPLATES/affsoft_marketing.html

O Operator
Diff

/var/www/vhosts/3dshawn.com/affiliate.3dshawn.com/TEMPLATES/affsoft_marketing.html

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

Added
+125
lines
Removed
-0
lines
Context
0
unchanged
Blobs
from
to 2a449ec2b83c
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<meta http-equiv="Cache-Control" content="no-store, no-cache, must-revalidate, max-age=0">
7<meta http-equiv="Pragma" content="no-cache">
8<meta http-equiv="Expires" content="0">
9 <title>$title &middot; $website_title</title>
10$meta_tags
11 <link rel="icon" type="image/svg+xml" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'><rect x='0.75' y='0.75' width='30.5' height='30.5' rx='7.5' fill='%232a1547' stroke='white' stroke-width='1.5'/><text x='16' y='22' font-family='Arial,Helvetica,sans-serif' font-size='14' font-weight='700' fill='white' text-anchor='middle'>AS</text></svg>">
12 <link rel="preconnect" href="https://fonts.googleapis.com">
13 <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
14 <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">
15 <link rel="stylesheet" href="$assets_css/site.css?v=20260608p">
16 $extra_css
17</head>
18<body>
19 <!-- Shared logged-out marketing nav. Single source of truth for the
20 header on every page that uses affsoft_marketing.html as its
21 shell (login, signup, forgot/reset password, verify email, and
22 the public marketing pages: features, tour, why, pricing, faq,
23 about, contact, terms, privacy). Do NOT duplicate inline in
24 per-page bodies -- this is the one place to edit it. -->
25 <header class="landing-nav">
26 <div class="landing-nav-inner">
27 <a href="index.cgi" class="flex items-center gap-3" style="text-decoration:none">
28 <div class="brand-mark"><span>AS</span></div>
29 <div class="brand-text"><span class="brand-name">AffSoft</span><span class="brand-sub">Affiliate platform</span></div>
30 </a>
31 <nav class="links">
32 <a href="features.cgi">Features</a>
33 <a href="tour.cgi">Tour</a>
34 <a href="why.cgi">Why AffSoft</a>
35 <a href="pricing.cgi">Pricing</a>
36 <a href="faq.cgi">FAQ</a>
37 <a href="about.cgi">About</a>
38 </nav>
39 <div class="auth-actions">
40 <a href="login.cgi" class="btn btn-ghost btn-sm">Sign in</a>
41 <a href="signup.cgi" class="btn btn-primary btn-sm">Start free trial</a>
42 </div>
43 </div>
44 </header>
45
46 $body
47 <script src="$assets_js/site.js"></script>
48 <!-- In-app popup helper (confirm/alert/prompt/toast). Same script the
49 dashboard uses, loaded on marketing/storefront pages too so
50 buyer-side flows (cart, checkout) get consistent overlays
51 instead of native alert(). -->
52 <script src="$assets_js/confirm.js?v=1"></script>
53 <!-- Visitor tracking + customer chat widget.
54 Loaded on every page that uses the marketing wrapper -- which is
55 all logged-out marketing pages, every public storefront, plus the
56 buyer-facing cart / checkout / my_orders pages. NOT loaded on the
57 seller dashboard (affsoft_wrapper.html) -- admins control and read
58 the chat from /admin_chat.cgi and /admin_visitors.cgi instead.
59 Also suppressed when an admin is previewing this page inside the
60 /admin_heatmap.cgi iframe (heatmap_view=1) so their preview
61 clicks don't get recorded as real visitor activity. -->
62 [if:!$heatmap_view]<script src="$assets_js/track.js?v=5"></script>[/if]
63 $extra_js
64
65<!-- Anonymous path tracker. Only included from the marketing wrapper, so
66 logged-in app pages never call /t.cgi. -->
67<script>
68(function(){
69 try {
70 var u = new URLSearchParams(location.search);
71 var qs = '?p=' + encodeURIComponent(location.pathname + location.search)
72 + '&r=' + encodeURIComponent(document.referrer || '')
73 + '&us=' + encodeURIComponent(u.get('utm_source') || '')
74 + '&um=' + encodeURIComponent(u.get('utm_medium') || '')
75 + '&uc=' + encodeURIComponent(u.get('utm_campaign') || '');
76 var img = new Image();
77 img.referrerPolicy = 'no-referrer-when-downgrade';
78 img.src = '/t.cgi' + qs;
79 } catch (e) { /* silent */ }
80})();
81</script><!-- Viewer-local timestamp renderer (portfolio-canonical).
82 Server emits `<span class="ts" data-ts="EPOCH" data-fmt="…">FALLBACK</span>`.
83 Formats: datetime | date | date-short | time | relative
84 Original text is the no-JS fallback. Re-run via window.tzLocalize() after AJAX. -->
85<script>
86(function(){
87 function fmt(el){
88 var e = parseInt(el.getAttribute('data-ts'), 10);
89 if (!e) return;
90 var d = new Date(e * 1000);
91 var kind = el.getAttribute('data-fmt') || 'datetime';
92 var out;
93 switch (kind) {
94 case 'date': out = d.toLocaleDateString(undefined, {year:'numeric',month:'short',day:'numeric'}); break;
95 case 'date-short': out = d.toLocaleDateString(undefined, {month:'short',day:'numeric'}); break;
96 case 'time': out = d.toLocaleTimeString(undefined, {hour:'2-digit',minute:'2-digit'}); break;
97 case 'relative': out = rel(e); break;
98 default: out = d.toLocaleDateString(undefined, {year:'numeric',month:'short',day:'numeric'})
99 + ' ' + d.toLocaleTimeString(undefined, {hour:'2-digit',minute:'2-digit'});
100 }
101 el.textContent = out;
102 if (!el.title) el.title = d.toString();
103 }
104 function rel(e){
105 var s = Math.floor(Date.now()/1000) - e, future = s < 0; s = Math.abs(s);
106 var n, u;
107 if (s < 60) { n = s; u = 'second'; }
108 else if (s < 3600) { n = Math.floor(s/60); u = 'minute'; }
109 else if (s < 86400) { n = Math.floor(s/3600); u = 'hour'; }
110 else if (s < 2592000){ n = Math.floor(s/86400); u = 'day'; }
111 else if (s < 31536000){n = Math.floor(s/2592000); u = 'month'; }
112 else { n = Math.floor(s/31536000);u = 'year'; }
113 var p = n === 1 ? '' : 's';
114 return future ? ('in ' + n + ' ' + u + p) : (n + ' ' + u + p + ' ago');
115 }
116 function localize(root){ (root||document).querySelectorAll('span.ts[data-ts], time[data-ts]').forEach(fmt); }
117 window.tzLocalize = localize;
118 if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', function(){ localize(); });
119 else localize();
120 window.addEventListener('ts-refresh', function(){ localize(); });
121})();
122</script>
123
124</body>
125</html>