Compare commits

...

2 Commits

Author SHA1 Message Date
Michael Victory 5872f22470 Perf: self-host fonts (drop render-blocking Google Fonts) + defer Cal + viewport-aware lighter mobile hero
Self-hosted woff2 (8 latin faces, subset, font-display swap), preload H1/body; removed Google Fonts link. Cal embed loads on first interaction. New 0.31MB mobile hero served at <=760px (was one 0.8MB file to all viewports). A11y: eyebrow up to 0.72rem.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-25 19:18:37 -07:00
Michael Victory 27d4abf061 Add private SEO/performance dashboard page (noindex) for mobile viewing
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-25 18:12:38 -07:00
12 changed files with 140 additions and 8 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+22 -7
View File
@@ -5,9 +5,10 @@
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<title>Shop Wisdom | Keep What Your Best People Know — for Canadian Manufacturers</title> <title>Shop Wisdom | Keep What Your Best People Know — for Canadian Manufacturers</title>
<meta name="description" content="Your best people are retiring. I help Canadian manufacturers capture the know-how that lives in a few heads, build it into systems the whole shop can run on, and stay on to keep it that way. You own everything — and it stays in Canada."> <meta name="description" content="Your best people are retiring. I help Canadian manufacturers capture the know-how that lives in a few heads, build it into systems the whole shop can run on, and stay on to keep it that way. You own everything — and it stays in Canada.">
<link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preload" href="assets/fonts/playfair-400.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link rel="preload" href="assets/fonts/playfair-400i.woff2" as="font" type="font/woff2" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;700&family=Lora:ital,wght@0,400;0,500;1,400&family=Playfair+Display:ital,wght@0,400;0,700;1,400&display=swap"> <link rel="preload" href="assets/fonts/dmsans-400.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="assets/fonts/lora-400.woff2" as="font" type="font/woff2" crossorigin>
<link rel="stylesheet" href="style.css"> <link rel="stylesheet" href="style.css">
<meta name="robots" content="index,follow"> <meta name="robots" content="index,follow">
<meta name="theme-color" content="#f7f4ef"> <meta name="theme-color" content="#f7f4ef">
@@ -139,9 +140,7 @@
<main id="top"> <main id="top">
<section class="hero band light" data-bg="light"> <section class="hero band light" data-bg="light">
<video class="hero-video" autoplay muted loop playsinline poster="assets/hero/hero-poster.jpg" aria-hidden="true"> <video class="hero-video" autoplay muted loop playsinline preload="none" poster="assets/hero/hero-poster.jpg" aria-hidden="true" data-src-desktop="assets/hero/hero.mp4" data-src-mobile="assets/hero/hero-mobile.mp4"></video>
<source src="assets/hero/hero.mp4" type="video/mp4" />
</video>
<div class="wrap hero-wrap"><div class="hero-col"> <div class="wrap hero-wrap"><div class="hero-col">
<p class="eyebrow">Knowledge continuity · for Canadian manufacturers</p> <p class="eyebrow">Knowledge continuity · for Canadian manufacturers</p>
<h1>Your best people are retiring. Their know&#8209;how doesn't <em>have to.</em></h1> <h1>Your best people are retiring. Their know&#8209;how doesn't <em>have to.</em></h1>
@@ -515,10 +514,26 @@
})(); })();
</script> </script>
<!-- Hero ambient loop: viewport-aware source (light mobile encode), poster-first; skipped on Save-Data / reduced-motion -->
<script>
(function () {
var hv = document.querySelector('.hero-video');
if (!hv) return;
var conn = navigator.connection || {};
if (conn.saveData === true) return;
if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) return;
var isMobile = window.matchMedia('(max-width: 760px)').matches;
var src = hv.getAttribute(isMobile ? 'data-src-mobile' : 'data-src-desktop');
if (!src) return;
var s = document.createElement('source'); s.src = src; s.type = 'video/mp4'; hv.appendChild(s);
hv.load();
})();
</script>
<!-- Cal.com booking embed (opens the booking popup on-brand; href is the no-JS fallback) --> <!-- Cal.com booking embed (opens the booking popup on-brand; href is the no-JS fallback) -->
<script> <script>
(function (C, A, L) { let p = function (a, ar) { a.q.push(ar); }; let d = C.document; C.Cal = C.Cal || function () { let cal = C.Cal; let ar = arguments; if (!cal.loaded) { cal.ns = {}; cal.q = cal.q || []; d.head.appendChild(d.createElement("script")).src = A; cal.loaded = true; } if (ar[0] === L) { const api = function () { p(api, arguments); }; const namespace = ar[1]; api.q = api.q || []; if (typeof namespace === "string") { cal.ns[namespace] = cal.ns[namespace] || api; p(cal.ns[namespace], ar); p(cal, ["initNamespace", namespace]); } else p(cal, ar); return; } p(cal, ar); }; })(window, "https://cal.shopwisdom.ca/embed/embed.js", "init"); (function (C, A, L) { let p = function (a, ar) { a.q.push(ar); }; let d = C.document; C.Cal = C.Cal || function () { let cal = C.Cal; let ar = arguments; if (!cal.loaded) { cal.ns = {}; cal.q = cal.q || []; d.head.appendChild(d.createElement("script")).src = A; cal.loaded = true; } if (ar[0] === L) { const api = function () { p(api, arguments); }; const namespace = ar[1]; api.q = api.q || []; if (typeof namespace === "string") { cal.ns[namespace] = cal.ns[namespace] || api; p(cal.ns[namespace], ar); p(cal, ["initNamespace", namespace]); } else p(cal, ar); return; } p(cal, ar); }; })(window, "https://cal.shopwisdom.ca/embed/embed.js", "init");
Cal("init", { origin: "https://cal.shopwisdom.ca" }); (function(){var d=false;function go(){if(d)return;d=true;Cal("init",{origin:"https://cal.shopwisdom.ca"});}var ev=["pointerdown","mousemove","touchstart","scroll","keydown"];function on(){go();ev.forEach(function(e){window.removeEventListener(e,on);});}ev.forEach(function(e){window.addEventListener(e,on,{passive:true});});})();
</script> </script>
<!-- Motion: reveal-on-scroll + stagger + open-o divider + persistent CTA. Gated on html.has-motion. --> <!-- Motion: reveal-on-scroll + stagger + open-o divider + persistent CTA. Gated on html.has-motion. -->
+108
View File
@@ -0,0 +1,108 @@
<!DOCTYPE html>
<html lang="en-CA">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>SEO &amp; Performance — ShopWisdom + Open Communications</title>
<meta name="robots" content="noindex,nofollow">
<meta name="theme-color" content="#0f1729">
<style>
:root{
--bg:#f7f4ef; --surface:#ffffff; --surface2:#efebe3; --ink:#0f1729; --muted:#5f6675;
--line:rgba(15,23,41,.12); --ok-bg:#e1f5ee; --ok:#0f6e56; --warn-bg:#faeeda; --warn:#854f0b; --accent:#1660c4;
}
@media (prefers-color-scheme:dark){
:root{ --bg:#0f1422; --surface:#171d2e; --surface2:#1e2740; --ink:#eef1f6; --muted:#9aa3b4;
--line:rgba(247,244,239,.14); --ok-bg:#0e3a30; --ok:#7fe0c2; --warn-bg:#3d2f12; --warn:#f0c97a; --accent:#7fb0ef; }
}
*{box-sizing:border-box}
body{margin:0;background:var(--bg);color:var(--ink);font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;line-height:1.6;-webkit-text-size-adjust:100%}
.wrap{max-width:760px;margin:0 auto;padding:28px 18px 56px}
h1{font-size:1.5rem;font-weight:600;margin:0 0 4px}
.sub{color:var(--muted);font-size:.85rem;margin:0 0 22px}
.card{background:var(--surface);border:1px solid var(--line);border-radius:14px;padding:18px 20px;margin:0 0 14px}
.ch{font-weight:600;font-size:1rem;margin:0 0 2px}
.csub{color:var(--muted);font-size:.8rem;margin:0 0 14px}
.head{display:flex;align-items:center;gap:9px;margin-bottom:14px;flex-wrap:wrap}
.dot{width:9px;height:9px;border-radius:50%;background:#1d9e75;flex:none}
.nm{font-weight:600}.nm a{color:inherit;text-decoration:none;border-bottom:1px solid var(--line)}
.tag{color:var(--muted);font-size:.78rem}
.metrics{display:grid;grid-template-columns:1fr 1fr;gap:12px}
.mc{background:var(--surface2);border-radius:10px;padding:12px 14px}
.mc .l{font-size:.78rem;color:var(--muted)}
.mc .v{font-size:1.5rem;font-weight:600;margin-top:2px}
.mc .u{font-size:.8rem;color:var(--muted);font-weight:400}
.meta{font-size:.78rem;color:var(--muted);margin-top:12px;display:flex;flex-wrap:wrap;gap:6px 14px}
.meta .pass{color:var(--ok);font-weight:600}
.pills{display:flex;flex-wrap:wrap;gap:7px;margin-bottom:6px}
.pill{font-size:.78rem;padding:5px 10px;border-radius:8px;background:var(--ok-bg);color:var(--ok);font-weight:500}
.wrow{display:flex;gap:10px;padding:11px 0;border-top:1px solid var(--line);font-size:.86rem}
.wrow .ic{color:var(--warn);font-weight:700;flex:none}
.wrow b{font-weight:600}
ul.fixes{margin:6px 0 0;padding-left:18px}
ul.fixes li{margin:7px 0;font-size:.9rem}
.btns{display:flex;flex-wrap:wrap;gap:10px;margin-top:8px}
.btn{display:inline-block;font-size:.82rem;padding:9px 14px;border-radius:9px;border:1px solid var(--line);color:var(--accent);text-decoration:none;background:var(--surface2)}
.foot{color:var(--muted);font-size:.76rem;margin-top:20px;text-align:center;line-height:1.7}
</style>
</head>
<body>
<div class="wrap">
<h1>SEO &amp; performance</h1>
<p class="sub">shopwisdom.ca · opencommunications.consulting — live snapshot, 25 Jun 2026</p>
<div class="card">
<div class="head"><span class="dot"></span><span class="nm"><a href="https://shopwisdom.ca/">Shop Wisdom</a></span><span class="tag">shopwisdom.ca · live</span></div>
<div class="metrics">
<div class="mc"><div class="l">Response</div><div class="v">514 <span class="u">ms</span></div></div>
<div class="mc"><div class="l">Page weight</div><div class="v">37 <span class="u">KB</span></div></div>
</div>
<div class="meta"><span>1 H1</span><span>11 images</span><span>6 JS · 2 CSS</span><span class="pass">11 pass · 4 to improve</span></div>
</div>
<div class="card">
<div class="head"><span class="dot"></span><span class="nm"><a href="https://www.opencommunications.consulting/">Open Communications</a></span><span class="tag">opencommunications.consulting · live</span></div>
<div class="metrics">
<div class="mc"><div class="l">Response</div><div class="v">675 <span class="u">ms</span></div></div>
<div class="mc"><div class="l">Page weight</div><div class="v">31 <span class="u">KB</span></div></div>
</div>
<div class="meta"><span>1 H1</span><span>4 images</span><span>7 JS · 2 CSS</span><span class="pass">11 pass · 4 to improve</span></div>
</div>
<div class="card">
<div class="ch">SEO &amp; GEO signals</div>
<div class="csub">Read live from each site's HTML — same template, so these hold for both.</div>
<div class="pills">
<span class="pill">✓ HTTPS</span><span class="pill">✓ canonical</span><span class="pill">✓ index,follow</span>
<span class="pill">✓ lang en-CA</span><span class="pill">✓ single H1</span><span class="pill">✓ Open Graph</span>
<span class="pill">✓ Twitter card</span><span class="pill">✓ JSON-LD @graph</span><span class="pill">✓ sitemap.xml</span>
<span class="pill">✓ robots.txt</span><span class="pill">✓ llms.txt</span>
</div>
<div class="wrow"><span class="ic">!</span><div><b>Title runs long</b> — SW 76 / OC 77 chars. Google trims ~60, so the tail is cut in results.</div></div>
<div class="wrow"><span class="ic">!</span><div><b>Meta description runs long</b> — SW 237 chars (OC similar). Trims ~155 in search snippets.</div></div>
<div class="wrow"><span class="ic">!</span><div><b>No FAQ / FAQPage schema</b> — the top remaining win for rich results + AI answer citations.</div></div>
<div class="wrow"><span class="ic">!</span><div><b>Fonts render-blocking</b> — loaded from Google's CDN; self-hosting helps speed and sovereignty.</div></div>
</div>
<div class="card">
<div class="ch">Performance</div>
<div class="csub" style="margin-bottom:10px">Both are static HTML on the OVH box — fast first byte (SW 514 ms · OC 675 ms) and light pages (≤37 KB). The one real lever is the render-blocking Google-Fonts request. Full Core Web Vitals weren't captured here (PageSpeed rate-limited) — run them live:</div>
<div class="btns">
<a class="btn" href="https://pagespeed.web.dev/report?url=https%3A%2F%2Fshopwisdom.ca%2F">PageSpeed: Shop Wisdom →</a>
<a class="btn" href="https://pagespeed.web.dev/report?url=https%3A%2F%2Fwww.opencommunications.consulting%2F">PageSpeed: OC →</a>
</div>
</div>
<div class="card">
<div class="ch">Top fixes (both sites)</div>
<ul class="fixes">
<li><b>Add FAQ + FAQPage schema</b> — biggest remaining lever for rich results and AI citations.</li>
<li><b>Self-host the fonts</b> — removes the render-blocking Google request (speed + sovereignty).</li>
<li><b>Trim titles &amp; meta descriptions</b> — title under 60 chars, description under 155.</li>
</ul>
</div>
<p class="foot">Live data read from each site's served HTML + server response time.<br>Ask Claude to "refresh the SEO dashboard" to regenerate. Private page — not indexed.</p>
</div>
</body>
</html>
+10 -1
View File
@@ -1,3 +1,12 @@
@font-face{font-family:'DM Sans';font-style:normal;font-weight:400;font-display:swap;src:url('assets/fonts/dmsans-400.woff2') format('woff2')}
@font-face{font-family:'DM Sans';font-style:normal;font-weight:500;font-display:swap;src:url('assets/fonts/dmsans-500.woff2') format('woff2')}
@font-face{font-family:'Lora';font-style:normal;font-weight:400;font-display:swap;src:url('assets/fonts/lora-400.woff2') format('woff2')}
@font-face{font-family:'Lora';font-style:normal;font-weight:500;font-display:swap;src:url('assets/fonts/lora-500.woff2') format('woff2')}
@font-face{font-family:'Lora';font-style:italic;font-weight:400;font-display:swap;src:url('assets/fonts/lora-400i.woff2') format('woff2')}
@font-face{font-family:'Playfair Display';font-style:normal;font-weight:400;font-display:swap;src:url('assets/fonts/playfair-400.woff2') format('woff2')}
@font-face{font-family:'Playfair Display';font-style:normal;font-weight:700;font-display:swap;src:url('assets/fonts/playfair-700.woff2') format('woff2')}
@font-face{font-family:'Playfair Display';font-style:italic;font-weight:400;font-display:swap;src:url('assets/fonts/playfair-400i.woff2') format('woff2')}
:root { :root {
--paper: #f7f4ef; --paper: #f7f4ef;
--paper-2: #efebe3; --paper-2: #efebe3;
@@ -49,7 +58,7 @@ strong { font-weight: 500; color: var(--ink); }
/* Eyebrow with steel dash */ /* Eyebrow with steel dash */
.eyebrow { .eyebrow {
font-family: 'DM Sans', sans-serif; font-size: 0.66rem; font-weight: 400; font-family: 'DM Sans', sans-serif; font-size: 0.72rem; font-weight: 400;
text-transform: uppercase; letter-spacing: 0.18em; color: var(--accent); text-transform: uppercase; letter-spacing: 0.18em; color: var(--accent);
margin: 0 0 24px; display: flex; align-items: center; margin: 0 0 24px; display: flex; align-items: center;
} }