Skip to main content
Fervor Grade™  /  The CRO Index  /  National Site Inspection
National Site Inspection — Roofing — Canada & United States

Signature Installs PEI

A Site Inspection of the highest-traffic organic pages across signatureinstalls.com — measuring whether the website earns trust independent of brand equity.

Domain signatureinstalls.com
Inspection Date March 19, 2026
Pages Inspected 2
48 /100 Weighted Score: Grade F (Condemned)
Executive Summary

The Signature Installs Site Inspection

Phone numbers are visible in the header but render as plain text on both desktop and mobile, so visitors on a phone cannot tap to dial — confirmed by zero tel: links across every captured viewport. The Fervor Grade™ National Site Inspection scored www.signatureinstalls.com at 48/100 — Grade F, Condemned.

Capture Context

This Site Inspection reflects what automated visitors see. The inspection's captured screenshots show the brand's response to bot-class traffic — Googlebot, SEO crawlers, uptime monitors, accessibility tools, and headless browsers all hit the same surface. A site that blocks these visitors has a real discoverability + conversion problem regardless of what a human on a consumer browser sees. The score below is the correct read of that bot-class view.

  • Brand metadata reconciled to the canonical manifest: slug=signature-installs, brandName='Signature Installs', domain='www.signatureinstalls.com', trade='roofing'. Prior score carried a different brandName and domain that do not appear in fresh structural captures; this re-score uses the manifest values as canonical.
Overall Weighted Brand Score 48
Fervor Grade™ Interpretation

48/100 · Grade F — Condemned. The website is broken. Critical infrastructure is missing — no clear primary CTA, no usable conversion path, or the site fails basic accessibility.

Homepage 51 Service Page (/roofing.html) 49
Homepage 51 ×0.15 · wt. 25.5
Service Page (/roofing.html) 49 ×0.20 · wt. 24.5

Methodology note. This Site Inspection applies the Fervor Grade™ 2.5 National Site Inspection framework to five key conversion pages on www.signatureinstalls.com. Scoring categories: First Impression (/20), Trust & Credibility (/22), Lead Capture (/20), Mobile Experience (/15), Content & SEO (/15), Accessibility (/8). Pages are weighted by conversion funnel role: Homepage ×0.15, Location Finder ×0.20, Location Page ×0.30, Service Page ×0.20, Lead Capture ×0.15. Fervor Grade™ scores conversion infrastructure independent of brand equity.

Page 1 of 5 — Homepage

Homepage

Homepage
https://www.signatureinstalls.com
51 /100 F — Red Band
First Impression
12/20
Trust & Credibility
12/22
Lead Capture
13/20
Mobile Experience
5/15
Content & SEO
7/15
Accessibility
1/8
Page Total
51/100
⚠ Warn — First Impression

First Impression scored 12/20 on the Homepage Site Inspection. See the rubric components in the Scoring Summary section for category-level breakdowns.

⚠ Warn — Trust & Credibility

Trust & Credibility scored 12/22 on the Homepage Site Inspection. See the rubric components in the Scoring Summary section for category-level breakdowns.

⚠ Warn — Lead Capture

Lead Capture scored 13/20 on the Homepage Site Inspection. See the rubric components in the Scoring Summary section for category-level breakdowns.

✗ Issue — Mobile Experience

Mobile Experience scored 5/15 on the Homepage Site Inspection. See the rubric components in the Scoring Summary section for category-level breakdowns.

✗ Issue — Content & SEO

Content & SEO scored 7/15 on the Homepage Site Inspection. See the rubric components in the Scoring Summary section for category-level breakdowns.

✗ Issue — Accessibility

Accessibility scored 1/8 on the Homepage Site Inspection. See the rubric components in the Scoring Summary section for category-level breakdowns.

Page 2 of 5 — Location Finder

Service Page (/roofing.html)

Service Page (/roofing.html)
https://www.signatureinstalls.com/services/
49 /100 F — Red Band
First Impression
12/20
Trust & Credibility
12/22
Lead Capture
12/20
Mobile Experience
5/15
Content & SEO
7/15
Accessibility
1/8
Page Total
49/100
⚠ Warn — First Impression

First Impression scored 12/20 on the Service Page (/roofing.html) Site Inspection. See the rubric components in the Scoring Summary section for category-level breakdowns.

⚠ Warn — Trust & Credibility

Trust & Credibility scored 12/22 on the Service Page (/roofing.html) Site Inspection. See the rubric components in the Scoring Summary section for category-level breakdowns.

⚠ Warn — Lead Capture

Lead Capture scored 13/20 on the Service Page (/roofing.html) Site Inspection. See the rubric components in the Scoring Summary section for category-level breakdowns.

✗ Issue — Mobile Experience

Mobile Experience scored 5/15 on the Service Page (/roofing.html) Site Inspection. See the rubric components in the Scoring Summary section for category-level breakdowns.

✗ Issue — Content & SEO

Content & SEO scored 7/15 on the Service Page (/roofing.html) Site Inspection. See the rubric components in the Scoring Summary section for category-level breakdowns.

✗ Issue — Accessibility

Accessibility scored 1/8 on the Service Page (/roofing.html) Site Inspection. See the rubric components in the Scoring Summary section for category-level breakdowns.

Strengths Identified

What's Done Well

Fervor Grade™ — Top Strengths

Phone numbers are visible in the header but render as plain text on both desktop and mobile, so...

  • Phone numbers are visible in the header but render as plain text on both desktop and mobile, so visitors on a phone cannot tap to dial — confirmed by zero tel: links across every captured viewport.
  • Neither captured page carries any structured data (no LocalBusiness, no Organization, no Service schema), and the tag duplicates the brand name twice on both pages, limiting how search engines and AI summaries describe the business.</li> <li>Three different phone numbers appear across the header and body copy (902.370.2740, 902.267.3308, 902.367.3308), creating an ambiguous primary number for prospects choosing which line to dial.</li> </ul> </div> </section> <section class="section"> <span class="section-eyebrow">Critical Conversion Failures</span> <h2 class="section-title" id="conversion-killers">Conversion Killers</h2> <div class="killer-box"> <span class="section-eyebrow">Fervor Grade™ — Most Damaging Findings</span> <h2 class="killer-title">Conversion Machinery Below Industry Bar</h2> <ul class="killer-list"> <li class="killer-item"><span class="killer-item-label">✗ Accessibility</span><p>Replace the generic 'Picture' alt text on hero and footer photos with descriptive captions so screen-reader visitors and image search both gain context.</p></li> </ul> <div class="killer-stat">22% of users abandon forms because the process is too long or complicated (Baymard Institute, 2024). 62.45% of users browse on mobile (Statcounter, 2025).</div> </div> </section> <section class="section"> <span class="section-eyebrow">Revenue Projection</span> <h2 class="section-title" id="revenue-impact">Revenue Impact</h2> <h3>Conversion Gap Calculation</h3> <p><strong>Step 1 — Traffic Baseline (estimated):</strong> Signature Installs draws an estimated 5,000–15,000 monthly organic visitors from search and direct traffic. Estimate from third-party tools; actual variance ±30–50%.</p> <p><strong>Step 2 — Conversion Benchmarks (published):</strong> The average paid search conversion rate for roofing services is 8.0–12.0% (LocaliQ 2025, 3,200+ campaigns). The average CPC is $8–$18. Average project value for this brand: $6,000–$18,000 (mid: $9,500) (trade-segment benchmark fallback (no brand-specific data)).</p> <p><strong>Step 3 — Conversion Gap Argument (observed):</strong> The Site Inspection did not surface any single conversion-blocker. Improvements are distributed across rubric categories scoring below 80%.</p> <p><strong>Step 4 — Financial Range:</strong></p> <div class="revenue-panel"> <h3>Assumptions</h3> <table class="Site Inspection-table"> <thead> <tr><th>Variable</th><th>Value</th><th>Source / Rationale</th></tr> </thead> <tbody> <tr><td>Monthly organic visitors (estimated)</td><td><strong>5,000 – 15,000</strong></td><td>Third-party traffic estimates ±30–50%</td></tr> <tr><td>Industry CVR for roofing services</td><td><strong>8.0% – 12.0%</strong></td><td>LocaliQ 2025 (3,200+ campaigns)</td></tr> <tr><td>Estimated current site CVR</td><td><strong>3.8% – 5.8%</strong></td><td>Scaled by current Fervor Grade weighted score</td></tr> <tr><td>Estimated CVR after fixes</td><td><strong>8.0% – 12.0%</strong></td><td>Industry benchmark for category</td></tr> <tr><td>Avg project value</td><td><strong>$6,000 – $18,000 (mid: $9,500)</strong></td><td>[BRAND] from per-brand pricing research, confidence: low</td></tr> <tr><td>Close rate (industry)</td><td><strong>30% – 40%</strong></td><td>Standard residential-services close rate</td></tr> </tbody> </table> <div class="revenue-row"> <div class="revenue-cell"> <span class="revenue-cell-label">Monthly revenue left on the table</span> <span class="revenue-cell-val" style="color:var(--green)">$647K – $7.1M/month</span> </div> <div class="revenue-cell"> <span class="revenue-cell-label">Annual cost of inaction</span> <span class="revenue-cell-val" style="color:var(--accent)">$7.8M – $84.8M/year</span> </div> </div> </div> <p><strong>Step 5 — Paid Traffic Argument:</strong> At the industry CPC of $8–$18 for roofing services and a brand avg-project-value of $9,500, every paid click hits the site's current conversion infrastructure. Improving the lowest-scoring rubric category lifts ROI on every advertising dollar already being spent.</p> <p class="revenue-note">Revenue projections are estimates based on published industry benchmarks and third-party traffic estimates. They should not be interpreted as guarantees.</p> </section> <section class="section"> <span class="section-eyebrow">Immediate Opportunities</span> <h2 class="section-title" id="quick-wins">Quick Wins</h2> <p class="section-intro">Four high-impact, low-effort improvements ranked by expected conversion lift.</p> <div class="quickwin-list"> <div class="quickwin"><span class="quickwin-num">1</span><div><p class="quickwin-title">Wrap the header phone number in a tel: link on every page so mobile visitors can tap...</p><p class="quickwin-detail">Wrap the header phone number in a tel: link on every page so mobile visitors can tap to call instead of copying digits manually.</p><span class="quickwin-impact">Implementation: 1–2 weeks · Expected lift: 5–15% on the affected page</span></div></div> <div class="quickwin"><span class="quickwin-num">2</span><div><p class="quickwin-title">Add LocalBusiness structured data to the homepage and the roofing page, including the...</p><p class="quickwin-detail">Add LocalBusiness structured data to the homepage and the roofing page, including the Prince Edward Island street address, service area, and warranty terms.</p><span class="quickwin-impact">Implementation: 1–2 weeks · Expected lift: 5–15% on the affected page</span></div></div> <div class="quickwin"><span class="quickwin-num">3</span><div><p class="quickwin-title">Replace the generic 'Picture' alt text on hero and footer photos with descriptive...</p><p class="quickwin-detail">Replace the generic 'Picture' alt text on hero and footer photos with descriptive captions so screen-reader visitors and image search both gain context.</p><span class="quickwin-impact">Implementation: 1–2 weeks · Expected lift: 5–15% on the affected page</span></div></div> <div class="quickwin"><span class="quickwin-num">4</span><div><p class="quickwin-title">Reconcile the three phone numbers in the header and body copy down to one primary...</p><p class="quickwin-detail">Reconcile the three phone numbers in the header and body copy down to one primary number so visitors are never unsure which line connects to the business.</p><span class="quickwin-impact">Implementation: 1–2 weeks · Expected lift: 5–15% on the affected page</span></div></div> </div> </section> <section class="section"> <span class="section-eyebrow">Competitive Context</span> <h2 class="section-title" id="competitive-position">Strengths, Vulnerabilities, and Competitive Position</h2> <h3>National Brand vs. Local Competitors</h3> <p><strong>Strengths:</strong></p> <ul><li>Phone numbers are visible in the header but render as plain text on both desktop and mobile, so visitors on a phone cannot tap to dial — confirmed by zero tel: links across every captured viewport.</li> <li>Neither captured page carries any structured data (no LocalBusiness, no Organization, no Service schema), and the <title> tag duplicates the brand name twice on both pages, limiting how search engines and AI summaries describe the business.</li> <li>Three different phone numbers appear across the header and body copy (902.370.2740, 902.267.3308, 902.367.3308), creating an ambiguous primary number for prospects choosing which line to dial.</li></ul> <p><strong>Vulnerabilities:</strong></p> <ul><li>No critical vulnerabilities surfaced in the Site Inspection; tier-level gaps are tracked in the Quick Wins section.</li></ul> </section> <section class="section"> <span class="section-eyebrow">Verdict</span> <h2 class="section-title" id="the-summary">The Summary</h2> <div class="verdict-box"> <span class="section-eyebrow">Inspection Verdict — Signature Installs</span> <p class="verdict-p1">Signature Installs scores 48/100 on the Fervor Grade™ National Framework — Grade F, Condemned. The website is broken. Critical infrastructure is missing — no clear primary CTA, no usable conversion path, or the site fails basic accessibility. Phone numbers are visible in the header but render as plain text on both desktop and mobile, so visitors on a phone cannot tap to dial — confirmed by zero tel: links across every captured viewport.</p> <p class="verdict-p2">The Site Inspection observed Signature Installs's framework pages and applied the standard Fervor Grade™ rubric. The lowest-scoring category was Accessibility at 1/8; category-level breakdowns and per-page observations follow.</p> <div class="verdict-primary"> PRIMARY ISSUE <strong>Accessibility scores below the 70% bar across the Site Inspected pages. The category-level rubric components and supporting evidence are detailed in the per-page Site Inspections above.</strong> </div> <div class="verdict-primary" style="margin-top:1rem;"> RECOMMENDED FIRST ACTION <strong>Wrap the header phone number in a tel: link on every page so mobile visitors can tap to call instead of copying digits manually.</strong> </div> </div> </section> <section class="section"> <span class="section-eyebrow">Scoring Summary</span> <h2 class="section-title" id="weighted-brand-score-calculation">Weighted Brand Score Calculation</h2> <table class="Site Inspection-table"> <thead> <tr><th>Page</th><th>Raw Score</th><th>Weight</th><th>Weighted</th></tr> </thead> <tbody> <tr> <td><strong>Homepage</strong></td> <td><strong style="color:var(--Site Inspection-accent)">51</strong>/100</td> <td>×0.15</td> <td><strong>25.5</strong></td> </tr> <tr> <td><strong>Service Page (/roofing.html)</strong></td> <td><strong style="color:var(--Site Inspection-accent)">49</strong>/100</td> <td>×0.20</td> <td><strong>24.5</strong></td> </tr> <tr style="background:var(--paper-2);"> <td colspan="3"><strong>Overall Weighted Brand Score</strong></td> <td><strong style="font-size:1.1rem;">48 / 100</strong></td> </tr> </tbody> </table> </section> <section class="section"> <span class="section-eyebrow">Scoring Detail</span> <h2 class="section-title" id="scoring-detail">Why This Brand Scored What It Did</h2> <p class="section-intro">Every category total above resolves to a set of named line-items the inspection scored against. Each line shows what we looked for, what we found, and how it scored. Use this to see exactly where the score came from — and where the wins are if you want to move the number.</p> <div class="rubric-detail-card"><div class="rubric-detail-card-head"><h3 class="rubric-detail-card-title">First Impression</h3><span class="rubric-detail-card-score"><strong>12</strong>/20</span></div><div class="score-bar-track rubric-detail-bar-track"><div class="score-bar-fill fill-amber" style="width:60%"></div></div><div class="rubric-detail-rows"><div class="rubric-detail-row rubric-detail-row--zero"><p class="rubric-detail-evidence rubric-detail-evidence--empty">No per-subscore evidence recorded. Category total reflects aggregate observation rather than line-item scoring.</p></div></div></div> <div class="rubric-detail-card"><div class="rubric-detail-card-head"><h3 class="rubric-detail-card-title">Trust & Credibility</h3><span class="rubric-detail-card-score"><strong>12</strong>/22</span></div><div class="score-bar-track rubric-detail-bar-track"><div class="score-bar-fill fill-red" style="width:55%"></div></div><div class="rubric-detail-rows"><div class="rubric-detail-row rubric-detail-row--zero"><p class="rubric-detail-evidence rubric-detail-evidence--empty">No per-subscore evidence recorded. Category total reflects aggregate observation rather than line-item scoring.</p></div></div></div> <div class="rubric-detail-card"><div class="rubric-detail-card-head"><h3 class="rubric-detail-card-title">Lead Capture</h3><span class="rubric-detail-card-score"><strong>13</strong>/20</span></div><div class="score-bar-track rubric-detail-bar-track"><div class="score-bar-fill fill-amber" style="width:65%"></div></div><div class="rubric-detail-rows"><div class="rubric-detail-row rubric-detail-row--zero"><p class="rubric-detail-evidence rubric-detail-evidence--empty">No per-subscore evidence recorded. Category total reflects aggregate observation rather than line-item scoring.</p></div></div></div> <div class="rubric-detail-card"><div class="rubric-detail-card-head"><h3 class="rubric-detail-card-title">Mobile Experience</h3><span class="rubric-detail-card-score"><strong>5</strong>/15</span></div><div class="score-bar-track rubric-detail-bar-track"><div class="score-bar-fill fill-red" style="width:33%"></div></div><div class="rubric-detail-rows"><div class="rubric-detail-row rubric-detail-row--zero"><p class="rubric-detail-evidence rubric-detail-evidence--empty">No per-subscore evidence recorded. Category total reflects aggregate observation rather than line-item scoring.</p></div></div></div> <div class="rubric-detail-card"><div class="rubric-detail-card-head"><h3 class="rubric-detail-card-title">Content & SEO</h3><span class="rubric-detail-card-score"><strong>7</strong>/15</span></div><div class="score-bar-track rubric-detail-bar-track"><div class="score-bar-fill fill-red" style="width:47%"></div></div><div class="rubric-detail-rows"><div class="rubric-detail-row rubric-detail-row--zero"><p class="rubric-detail-evidence rubric-detail-evidence--empty">No per-subscore evidence recorded. Category total reflects aggregate observation rather than line-item scoring.</p></div></div></div> <div class="rubric-detail-card"><div class="rubric-detail-card-head"><h3 class="rubric-detail-card-title">Accessibility</h3><span class="rubric-detail-card-score"><strong>1</strong>/8</span></div><div class="score-bar-track rubric-detail-bar-track"><div class="score-bar-fill fill-red" style="width:12%"></div></div><div class="rubric-detail-rows"><div class="rubric-detail-row rubric-detail-row--zero"><p class="rubric-detail-evidence rubric-detail-evidence--empty">No per-subscore evidence recorded. Category total reflects aggregate observation rather than line-item scoring.</p></div></div></div> <div class="pricing-transparency-block"><h3 class="rubric-detail-card-title">Pricing Transparency</h3><p class="pricing-transparency-intro">Four signals from the homepage and service-page capture. Prospects who can't find a price band or financing option often bounce before filling out a form.</p><table class="Site Inspection-table Site Inspection-table--compact"><tbody><tr><td>Transparent pricing visible on page</td><td><span class="pricing-yn pricing-yn--unknown">Unknown</span></td></tr><tr><td>Starting price listed</td><td><span class="pricing-yn pricing-yn--no">Not listed</span></td></tr><tr><td>Packages or tiers listed</td><td><span class="pricing-yn pricing-yn--unknown">Unknown</span></td></tr><tr><td>Financing options surfaced</td><td><span class="pricing-yn pricing-yn--unknown">Unknown</span></td></tr></tbody></table><p class="pricing-methodology"><strong>How this was checked:</strong> Brand publishes no pricing, no 'starting at' copy, no financing examples, and no quote calculator across the captured pages. Trade-segment benchmark for Prince Edward Island residential asphalt-shingle roof replacement used as a fallback: avg_project_value=9500 with a 6000-to-18000 range reflecting the bulk of the brand's multi-trade portfolio (roofing dominates, with siding / windows / framing as secondary). Tagged [BENCHMARK-FALLBACK] given the absence of brand-specific pricing in fresh captures.</p></div> </section> <section class="section"> <span class="section-eyebrow">Site Inspection Framework</span> <h2 class="section-title" id="modifiers-applied">Modifiers Applied</h2> <div class="method-box"> <table class="Site Inspection-table"> <thead> <tr><th>Modifier</th><th>Trigger</th><th>Score Impact</th></tr> </thead> <tbody> <tr><td colspan="3">No score-adjusting modifiers triggered.</td></tr> </tbody> </table> </div> </section> <section class="section"> <span class="section-eyebrow">Data Integrity</span> <h2 class="section-title" id="data-confidence">Data Confidence Statement</h2> <div class="method-box"> <p><strong>Observed with certainty:</strong> First Impression: Hero 'Signature Installs' wordmark plus service-list body ('Specializing in: Roofing (Commercial and Residential) ~ 5" Seamless Gutters ~ Patio Decks ~ Renovations ~ Siding ~ Windows & Doors ~ Framing ~ Free Estimates ~ Warrenties' with typo) plus orange 'Free Estimates' CTA plus dual-phone header (T 902.370.2740 / F 902.367.3308) plus dated template aesthetic plus 5-Year Labor Warranty lozenge badge. Brand name duplicated in <title> tag.. Trust Credibility: 'PROFESSIONALS YOU CAN TRUST' framing plus 'LOCALLY OWNED AND OPERATED' Prince Edward Island plus 5 Year Labor Warranty badge plus 'with over 85 years of collective experience' plus multi-bullet team-quality copy (We know our work / Your job is done right / We STAY SAFE / Your property is left cleaner than when we found it / We have REPEAT CUSTOMERS) plus Member: PEI Business Federation Ltd. footer badge. Zero aggregated review count or rating on either captured page (dom_facts review_widgets=[], ratings=[]).. Lead Capture: Inline 'CONTACT US: We welcome your inquiries' form on the homepage with 5 visible fields (First, Last, Phone, Email, Comment) plus Submit. dom_facts forms[0] action=/ajax/apps/formSubmitAjax.php (legacy template handler), 9 total fields (4 hidden anti-spam). cta_clickthrough.json captures 22 of 22 successful 'Contact Us' clicks routing to /contact-us.html across both viewports.. Mobile Experience: Mobile screenshot shows the desktop layout shrunk into a narrow viewport (no responsive breakpoint, sidebar stacking awkward, horizontal overflow). dom_facts mobile.tel_links=[] on both pages — phone numbers are plain text only, mobile visitors cannot tap to dial. lighthouse mobile performance=0.58, LCP=5.8s (POOR), FCP=4.7s (POOR), TBT=390ms.. Content Seo: dom_facts schema_jsonld=[] on both captured pages — zero structured data. <title> brand-name duplicated (73 to 80 characters, over the 60 cap). meta.description identical on both pages. /roofing.html service page is thin (html_size=41598) with the 6-bullet feature list duplicated twice. lighthouse SEO=0.83 on desktop and mobile (held up by basic on-page tags).. Accessibility: axe-core 4.10.2 (WCAG 2.1 AA plus best-practice) brand-level dedupe across 4 runs (home and roofing-html, desktop and mobile): critical=1 (image-alt, 8 nodes), serious=6 (color-contrast 40 nodes / html-has-lang 4 / link-in-text-block 4 / link-name 8 / list 2 / marquee 2), moderate=3 (landmark-one-main 4 / page-has-heading-one 4 / region 40), minor=0. Deduction formula applied: 8 - 1.5(1) - 0.75(6) - 0.25(3) - 0.10(0) = 1.25, rounded to 1.. Full Evidence Stack: architecture.json detector confirms single_page_brochure (high confidence) with total_urls=25 and page_role_coverage=0.40 and section_markers=['phone_visible_in_html','email_visible_in_html'] — routes the rubric path to the thin-sitemap brochure variant where homepage and the captured service page share the page-weight pool 50 / 50.. Html: Raw HTML captures confirm the structural reads cited above — used as the canonical reference for tel_links absence, schema_jsonld absence, form action attribution, and the duplicated feature-list block on the roofing page..</p> <p><strong>Estimated with published benchmarks:</strong> Monthly organic traffic estimated via third-party tools (±30–50%). Industry CPC, CVR, and CPL drawn from LocaliQ 2025 (3,200+ campaigns). Average project values from roofing industry sources. Actual conversion rate, ad spend, lead volume, and close rate are unknown in non-client Site Inspections.</p> </div> </section> <section class="section"> <span class="section-eyebrow">Sources</span> <h2 class="section-title" id="citations">Citations</h2> <div class="citation">[1] BrightLocal (2025). "97% of consumers read reviews before hiring a local business." <a href="https://www.brightlocal.com/research/local-consumer-review-survey/">brightlocal.com</a></div> <div class="citation">[2] Baymard Institute (2024). "22% of users abandon forms because the process is too long or complicated." <a href="https://baymard.com/lists/cart-abandonment-rate">baymard.com</a></div> <div class="citation">[3] Statcounter (2025). "62.45% of users browse the web on mobile." <a href="https://gs.statcounter.com/platform-market-share/desktop-mobile-tablet">gs.statcounter.com</a></div> <div class="citation">[4] LocaliQ (2025). "Industry CPC + CVR benchmarks across 3,200+ campaigns." <a href="https://localiq.com/blog/search-advertising-benchmarks/">localiq.com</a></div> <div class="citation">[5] Nielsen Norman Group (2024). "Trust signals (reviews, credentials, named team) are the strongest predictors of B2C service-page conversion." <a href="https://www.nngroup.com/articles/trust-signals/">nngroup.com</a></div> </section><nav style="margin-top: 3rem; padding-top: 2rem; border-top: 1px solid var(--audit-rule);"> <a href="/contractor/cro-index/" style="font-family: var(--font-mono); font-size: 0.75rem; letter-spacing: 0.1em; text-transform: uppercase; color: var(--text-muted); text-decoration: none;"> ← Back to Contractor CRO Index </a> </nav> </article> <div class="td-sidebar-rail" data-astro-cid-xzg2zzut> <!-- Desktop sidebar --><aside class="guides-sidebar" aria-label="Related Inspections" data-astro-cid-7o3n3qur> <p class="guides-sidebar__title" data-astro-cid-7o3n3qur>Related Inspections</p> <nav class="guides-sidebar__list" data-astro-cid-7o3n3qur> <div class="guides-sidebar__group" data-astro-cid-7o3n3qur> <div class="guides-sidebar__header" data-astro-cid-7o3n3qur> <span class="guides-sidebar__heading" data-astro-cid-7o3n3qur>More Roofing Inspections</span> <button class="guides-sidebar__toggle" aria-expanded="false" aria-label="Toggle More Roofing Inspections" data-guides-toggle data-astro-cid-7o3n3qur> <svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg" data-astro-cid-7o3n3qur> <path d="M3 4.5L6 7.5L9 4.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" data-astro-cid-7o3n3qur></path> </svg> </button> </div> <ul class="guides-sidebar__links" data-guides-links hidden data-astro-cid-7o3n3qur> <li data-astro-cid-7o3n3qur> <a href="/contractor/cro-index/crown-roofing/" class="guides-sidebar__link" data-astro-cid-7o3n3qur>Crown Industrial Roofing (90/100)</a> </li><li data-astro-cid-7o3n3qur> <a href="/contractor/cro-index/great-canadian-roofing-siding/" class="guides-sidebar__link" data-astro-cid-7o3n3qur>Great Canadian Roofing, Siding, Exteriors (89/100)</a> </li><li data-astro-cid-7o3n3qur> <a href="/contractor/cro-index/wegner-roofing/" class="guides-sidebar__link" data-astro-cid-7o3n3qur>Wegner Roofing & Solar (88/100)</a> </li><li data-astro-cid-7o3n3qur> <a href="/contractor/cro-index/pinnacle-roofing-skylights/" class="guides-sidebar__link" data-astro-cid-7o3n3qur>Pinnacle Roofing & Skylights (86/100)</a> </li><li data-astro-cid-7o3n3qur> <a href="/contractor/cro-index/schroeder-roofing/" class="guides-sidebar__link" data-astro-cid-7o3n3qur>Schroeder Roofing (85/100)</a> </li><li data-astro-cid-7o3n3qur> <a href="/contractor/cro-index/sentry-roofing/" class="guides-sidebar__link" data-astro-cid-7o3n3qur>Sentry Roofing (85/100)</a> </li><li data-astro-cid-7o3n3qur> <a href="/contractor/cro-index/power-home-remodeling/" class="guides-sidebar__link" data-astro-cid-7o3n3qur>Power Home Remodeling (84/100)</a> </li><li data-astro-cid-7o3n3qur> <a href="/contractor/cro-index/dr-roof-atlanta-roofing-specialists/" class="guides-sidebar__link" data-astro-cid-7o3n3qur>Dr. Roof / Atlanta Roofing Specialists (84/100)</a> </li> </ul> </div><div class="guides-sidebar__group" data-astro-cid-7o3n3qur> <div class="guides-sidebar__header" data-astro-cid-7o3n3qur> <span class="guides-sidebar__heading" data-astro-cid-7o3n3qur>Trade Guide</span> <button class="guides-sidebar__toggle" aria-expanded="false" aria-label="Toggle Trade Guide" data-guides-toggle data-astro-cid-7o3n3qur> <svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg" data-astro-cid-7o3n3qur> <path d="M3 4.5L6 7.5L9 4.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" data-astro-cid-7o3n3qur></path> </svg> </button> </div> <ul class="guides-sidebar__links" data-guides-links hidden data-astro-cid-7o3n3qur> <li data-astro-cid-7o3n3qur> <a href="/contractor/exterior/roofing/" class="guides-sidebar__link" data-astro-cid-7o3n3qur>Roofing Contractor Guide</a> </li> </ul> </div> </nav> </aside> <!-- Mobile: inline section --> <div class="guides-sidebar-mobile" aria-label="Related Inspections" data-astro-cid-7o3n3qur> <h2 class="guides-sidebar-mobile__title" data-astro-cid-7o3n3qur>Related Inspections</h2> <div class="guides-sidebar-mobile__grid" data-astro-cid-7o3n3qur> <div class="guides-sidebar-mobile__card" data-astro-cid-7o3n3qur> <h3 data-astro-cid-7o3n3qur> <span data-astro-cid-7o3n3qur>More Roofing Inspections</span> </h3> <ul data-astro-cid-7o3n3qur> <li data-astro-cid-7o3n3qur><a href="/contractor/cro-index/crown-roofing/" data-astro-cid-7o3n3qur>Crown Industrial Roofing (90/100)</a></li><li data-astro-cid-7o3n3qur><a href="/contractor/cro-index/great-canadian-roofing-siding/" data-astro-cid-7o3n3qur>Great Canadian Roofing, Siding, Exteriors (89/100)</a></li><li data-astro-cid-7o3n3qur><a href="/contractor/cro-index/wegner-roofing/" data-astro-cid-7o3n3qur>Wegner Roofing & Solar (88/100)</a></li><li data-astro-cid-7o3n3qur><a href="/contractor/cro-index/pinnacle-roofing-skylights/" data-astro-cid-7o3n3qur>Pinnacle Roofing & Skylights (86/100)</a></li><li data-astro-cid-7o3n3qur><a href="/contractor/cro-index/schroeder-roofing/" data-astro-cid-7o3n3qur>Schroeder Roofing (85/100)</a></li><li data-astro-cid-7o3n3qur><a href="/contractor/cro-index/sentry-roofing/" data-astro-cid-7o3n3qur>Sentry Roofing (85/100)</a></li><li data-astro-cid-7o3n3qur><a href="/contractor/cro-index/power-home-remodeling/" data-astro-cid-7o3n3qur>Power Home Remodeling (84/100)</a></li><li data-astro-cid-7o3n3qur><a href="/contractor/cro-index/dr-roof-atlanta-roofing-specialists/" data-astro-cid-7o3n3qur>Dr. Roof / Atlanta Roofing Specialists (84/100)</a></li> </ul> </div><div class="guides-sidebar-mobile__card" data-astro-cid-7o3n3qur> <h3 data-astro-cid-7o3n3qur> <span data-astro-cid-7o3n3qur>Trade Guide</span> </h3> <ul data-astro-cid-7o3n3qur> <li data-astro-cid-7o3n3qur><a href="/contractor/exterior/roofing/" data-astro-cid-7o3n3qur>Roofing Contractor Guide</a></li> </ul> </div> </div> </div> <script type="module">document.querySelectorAll("[data-guides-toggle]").forEach(e=>{e.addEventListener("click",()=>{const d=e.getAttribute("aria-expanded")==="true",t=e.closest(".guides-sidebar__group")?.querySelector("[data-guides-links]");t&&(d?(t.setAttribute("hidden",""),e.setAttribute("aria-expanded","false")):(t.removeAttribute("hidden"),e.setAttribute("aria-expanded","true")))})});</script> </div> </div> </main> <footer class="ft" role="contentinfo" data-astro-cid-sz7xmlte> <div class="ft__inner" data-astro-cid-sz7xmlte> <!-- ═══ TOP: 4-column grid ═══ --> <div class="ft__grid" data-astro-cid-sz7xmlte> <!-- Column 1: Brand + Newsletter --> <div class="ft__brand" data-astro-cid-sz7xmlte> <a href="/" class="ft__logo" aria-label="Fervor Studio, Home" data-astro-cid-sz7xmlte>FERVOR</a> <p class="ft__tagline" data-astro-cid-sz7xmlte> Conversion first websites and local SEO for home service contractors doing $500K to $5M. </p> <div class="ft__newsletter" data-astro-cid-sz7xmlte> <p class="ft__col-label" data-astro-cid-sz7xmlte>Join Booked Solid</p> <p class="ft__newsletter-desc" data-astro-cid-sz7xmlte> Clear emails about what's actually working for contractors. CRO plays, site fixes, the occasional teardown. </p> <form class="ft__form footer-newsletter-js" data-endpoint="/api/contact" novalidate data-astro-cid-sz7xmlte> <input type="text" name="firstName" placeholder="Your first name" class="ft__input ft__input--name" autocomplete="given-name" required aria-label="Your first name" data-astro-cid-sz7xmlte> <div class="ft__form-row" data-astro-cid-sz7xmlte> <input type="email" name="email" placeholder="your@email.com" class="ft__input" autocomplete="email" required aria-label="Email address" data-astro-cid-sz7xmlte> <button type="submit" class="ft__submit" data-astro-cid-sz7xmlte> <span class="nl-btn-text" data-astro-cid-sz7xmlte>Subscribe</span> <span class="nl-btn-loading" style="display:none;" data-astro-cid-sz7xmlte>...</span> </button> </div> <div style="position:absolute;left:-9999px;" aria-hidden="true" data-astro-cid-sz7xmlte> <input type="text" name="website_url" tabindex="-1" autocomplete="off" data-astro-cid-sz7xmlte> </div> <label class="ft__consent" data-astro-cid-sz7xmlte> <input type="checkbox" name="consent" required data-astro-cid-sz7xmlte> <span data-astro-cid-sz7xmlte>Yes, send me The Crew newsletter. I can unsubscribe at any time.</span> </label> <span class="nl-error" data-astro-cid-sz7xmlte></span> <span class="nl-success" style="display:none;" data-astro-cid-sz7xmlte>You're in. Welcome to The Crew.</span> <p class="ft__legal-note" data-astro-cid-sz7xmlte>Sent by Fervor Group Inc., Cochrane, AB. <a href="/privacy/" data-astro-cid-sz7xmlte>Privacy Policy</a></p> </form> </div> </div> <!-- Column 2: Services --> <nav class="ft__col" aria-label="Services" data-astro-cid-sz7xmlte> <p class="ft__col-label" data-astro-cid-sz7xmlte>Services</p> <ul class="ft__links" data-astro-cid-sz7xmlte> <li data-astro-cid-sz7xmlte> <a href="/services/booked-by-design/" class data-astro-cid-sz7xmlte> Booked by Design™ </a> </li><li data-astro-cid-sz7xmlte> <a href="/services/leak-plug-sprint/" class data-astro-cid-sz7xmlte> Leak Plug Sprint </a> </li><li data-astro-cid-sz7xmlte> <a href="/services/local-dominance-setup/" class data-astro-cid-sz7xmlte> Local Dominance Setup </a> </li><li data-astro-cid-sz7xmlte> <a href="/services/performance-partner/" class data-astro-cid-sz7xmlte> Performance Partner™ </a> </li><li data-astro-cid-sz7xmlte> <a href="/services/contractor-growth-engine/" class data-astro-cid-sz7xmlte> Growth Engine </a> </li><li data-astro-cid-sz7xmlte> <a href="/services/content-starter-pack/" class data-astro-cid-sz7xmlte> Content Starter Pack </a> </li><li data-astro-cid-sz7xmlte> <a href="/services/review-velocity-boost/" class data-astro-cid-sz7xmlte> Review Velocity Boost </a> </li><li data-astro-cid-sz7xmlte> <a href="/services/priority-build/" class data-astro-cid-sz7xmlte> Priority Build </a> </li><li data-astro-cid-sz7xmlte> <a href="/site-inspection/" class="ft__link--highlight" data-astro-cid-sz7xmlte> The Site Inspection </a> </li> </ul> </nav> <!-- Column 3: Contractor Guides --> <nav class="ft__col" aria-label="Contractor Guides" data-astro-cid-sz7xmlte> <p class="ft__col-label" data-astro-cid-sz7xmlte>Contractor Guides</p> <ul class="ft__links" data-astro-cid-sz7xmlte> <li data-astro-cid-sz7xmlte> <a href="/contractor/building-envelope/roofing/" class data-astro-cid-sz7xmlte> Roofing </a> </li><li data-astro-cid-sz7xmlte> <a href="/contractor/building-systems/hvac/" class data-astro-cid-sz7xmlte> HVAC </a> </li><li data-astro-cid-sz7xmlte> <a href="/contractor/building-systems/plumbing/" class data-astro-cid-sz7xmlte> Plumbing </a> </li><li data-astro-cid-sz7xmlte> <a href="/contractor/building-systems/electrician/" class data-astro-cid-sz7xmlte> Electrician </a> </li><li data-astro-cid-sz7xmlte> <a href="/contractor/residential-construction/remodeling/" class data-astro-cid-sz7xmlte> Remodeling </a> </li><li data-astro-cid-sz7xmlte> <a href="/contractor/residential-construction/kitchen-bath/" class data-astro-cid-sz7xmlte> Kitchen & Bath </a> </li><li data-astro-cid-sz7xmlte> <a href="/contractor/building-systems/solar/" class data-astro-cid-sz7xmlte> Solar </a> </li><li data-astro-cid-sz7xmlte> <a href="/contractor/" class="ft__link--highlight" data-astro-cid-sz7xmlte> All Trades </a> </li> </ul> </nav> <!-- Column 4: Company --> <nav class="ft__col" aria-label="Company" data-astro-cid-sz7xmlte> <p class="ft__col-label" data-astro-cid-sz7xmlte>Company</p> <ul class="ft__links" data-astro-cid-sz7xmlte> <li data-astro-cid-sz7xmlte><a href="/about/" data-astro-cid-sz7xmlte>About</a></li><li data-astro-cid-sz7xmlte><a href="/contractor/cro-index/" data-astro-cid-sz7xmlte>The CRO Index</a></li><li data-astro-cid-sz7xmlte><a href="/contractor/cro-index/page-breakdowns/" data-astro-cid-sz7xmlte>Page Breakdowns</a></li><li data-astro-cid-sz7xmlte><a href="/compare/" data-astro-cid-sz7xmlte>Agency Comparison</a></li> </ul> </nav> <!-- Column 5: Tools --> <nav class="ft__col" aria-label="Tools" data-astro-cid-sz7xmlte> <p class="ft__col-label" data-astro-cid-sz7xmlte>Tools</p> <ul class="ft__links" data-astro-cid-sz7xmlte> <li data-astro-cid-sz7xmlte><a href="/revenue-loss-calculator/" data-astro-cid-sz7xmlte>Lead Leak Calculator</a></li> </ul> </nav> </div> <!-- ═══ BOTTOM BAR ═══ --> <div class="ft__bottom" data-astro-cid-sz7xmlte> <div class="ft__bottom-left" data-astro-cid-sz7xmlte> <span class="ft__copyright" data-astro-cid-sz7xmlte>© 2026 Fervor Studio</span> <span class="ft__dot" aria-hidden="true" data-astro-cid-sz7xmlte>·</span> <a href="/privacy/" class="ft__bottom-link" data-astro-cid-sz7xmlte>Privacy Policy</a> <span class="ft__dot" aria-hidden="true" data-astro-cid-sz7xmlte>·</span> <a href="/terms/" class="ft__bottom-link" data-astro-cid-sz7xmlte>Terms of Service</a> <span class="ft__dot" aria-hidden="true" data-astro-cid-sz7xmlte>·</span> <a href="/cookies/" class="ft__bottom-link" data-astro-cid-sz7xmlte>Cookie Policy</a> <span class="ft__dot" aria-hidden="true" data-astro-cid-sz7xmlte>·</span> <a href="/accessibility/" class="ft__bottom-link" data-astro-cid-sz7xmlte>Accessibility</a> <span class="ft__dot" aria-hidden="true" data-astro-cid-sz7xmlte>·</span> <a href="/affiliate-disclosure/" class="ft__bottom-link" data-astro-cid-sz7xmlte>Affiliate Disclosure</a> </div> <a href="https://fervorstudio.ca" class="ft__sig" target="_blank" rel="noopener noreferrer" data-astro-cid-sz7xmlte>Designed with Fervor</a> </div> </div> </footer> <script> document.addEventListener('DOMContentLoaded', () => { document.querySelectorAll('.footer-newsletter-js').forEach(form => { form.addEventListener('submit', async (e) => { e.preventDefault(); const f = e.target; const endpoint = f.dataset.endpoint; const errorEl = f.querySelector('.nl-error'); const successEl = f.querySelector('.nl-success'); const btnText = f.querySelector('.nl-btn-text'); const btnLoading = f.querySelector('.nl-btn-loading'); const submitBtn = f.querySelector('button[type="submit"]'); if (errorEl) errorEl.textContent = ''; const fd = new FormData(f); const data = { email: fd.get('email')?.toString().trim() || '', firstName: fd.get('firstName')?.toString().trim() || '', service: 'newsletter', sourcePage: window.location.pathname, website_url: fd.get('website_url')?.toString() || '', }; if (!data.firstName) { if (errorEl) errorEl.textContent = 'Please enter your name.'; return; } if (!data.email) { if (errorEl) errorEl.textContent = 'Please enter your email.'; return; } if (!/^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/.test(data.email)) { if (errorEl) errorEl.textContent = 'Please enter a valid email address.'; return; } var consentBox = f.querySelector('input[name="consent"]'); if (consentBox && !consentBox.checked) { if (errorEl) errorEl.textContent = 'Please confirm you want to receive our newsletter.'; return; } submitBtn.disabled = true; if (btnText) btnText.style.display = 'none'; if (btnLoading) btnLoading.style.display = 'inline'; try { const res = await fetch(endpoint, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data), }); const result = await res.json(); if (res.ok && result.success) { window.dataLayer = window.dataLayer || []; window.dataLayer.push({ event: 'newsletter_signup', newsletter_name: 'the_crew', signup_location: 'footer', page_path: window.location.pathname }); Array.from(f.querySelectorAll('input, button, label')).forEach(el => el.style.display = 'none'); const legal = f.querySelector('.ft__legal-note'); if (legal) legal.style.display = 'none'; if (successEl) successEl.style.display = 'block'; } else { if (errorEl) errorEl.textContent = result.errors?.email || result.message || 'Something went wrong.'; } } catch { if (errorEl) errorEl.textContent = 'Network error. Please try again.'; } finally { submitBtn.disabled = false; if (btnText) btnText.style.display = 'inline'; if (btnLoading) btnLoading.style.display = 'none'; } }); }); }); </script> <!-- ── Sticky Mobile CTA ── --> <a href="/site-inspection/" class="sticky-mobile-cta" aria-label="Get My Site Inspection"> Get My Site Inspection </a> <!-- Consent Banner, fixed bottom, PIPEDA compliant --> <div id="fervor-consent-banner" class="consent-banner" role="dialog" aria-label="Cookie consent" aria-modal="false" style="display:none" data-astro-cid-2effgw6e> <div class="consent-inner" data-astro-cid-2effgw6e> <p class="consent-message" data-astro-cid-2effgw6e> We use cookies to understand how you interact with our site and improve your experience. You can accept or reject non-essential cookies. <a href="/cookies/" class="consent-link" data-astro-cid-2effgw6e>Cookie Policy</a> </p> <div class="consent-actions" data-astro-cid-2effgw6e> <button type="button" class="consent-btn consent-btn--reject" id="consent-reject" data-astro-cid-2effgw6e> Reject </button> <button type="button" class="consent-btn consent-btn--accept" id="consent-accept" data-astro-cid-2effgw6e> Accept </button> </div> </div> </div> <script> // ── Consent Banner Logic ── // Runs inline to avoid Astro bundling. Must execute before GTM. (function() { var COOKIE_NAME = 'fervor_consent'; var COOKIE_MAX_AGE = 31536000; // 12 months function getCookie(name) { var match = document.cookie.match(new RegExp('(^| )' + name + '=([^;]+)')); return match ? decodeURIComponent(match[2]) : null; } function setCookie(name, value, maxAge) { document.cookie = name + '=' + encodeURIComponent(value) + '; path=/; max-age=' + maxAge + '; SameSite=Lax; Secure'; } function updateConsent(analytics, marketing) { if (typeof gtag === 'function') { gtag('consent', 'update', { 'analytics_storage': analytics ? 'granted' : 'denied', 'ad_storage': marketing ? 'granted' : 'denied', 'ad_user_data': marketing ? 'granted' : 'denied', 'ad_personalization': marketing ? 'granted' : 'denied' }); } // Store in cookie with timestamp and version for PIPEDA audit trail var consent = JSON.stringify({ analytics: analytics, marketing: marketing, timestamp: new Date().toISOString(), version: '1' }); setCookie(COOKIE_NAME, consent, COOKIE_MAX_AGE); // Push consent event for GTM window.dataLayer = window.dataLayer || []; window.dataLayer.push({ 'event': 'consent_update', 'consent_analytics': analytics, 'consent_marketing': marketing }); // Notify other scripts (e.g. Clarity gating) of consent change window.dispatchEvent(new CustomEvent('fervor:consent-updated', { detail: { analytics: analytics, marketing: marketing } })); } // Check for existing consent var existing = getCookie(COOKIE_NAME); if (existing) { try { var parsed = JSON.parse(existing); // Restore consent state from cookie if (typeof gtag === 'function') { gtag('consent', 'update', { 'analytics_storage': parsed.analytics ? 'granted' : 'denied', 'ad_storage': parsed.marketing ? 'granted' : 'denied', 'ad_user_data': parsed.marketing ? 'granted' : 'denied', 'ad_personalization': parsed.marketing ? 'granted' : 'denied' }); } } catch(e) {} // Don't show banner, user already chose return; } // Show banner (no existing consent) var banner = document.getElementById('fervor-consent-banner'); if (banner) { banner.style.display = ''; requestAnimationFrame(function() { requestAnimationFrame(function() { banner.setAttribute('data-visible', ''); }); }); } // Accept: grant analytics, deny marketing (no ads yet) var acceptBtn = document.getElementById('consent-accept'); if (acceptBtn) { acceptBtn.addEventListener('click', function() { updateConsent(true, false); if (banner) { banner.removeAttribute('data-visible'); setTimeout(function() { banner.style.display = 'none'; }, 350); } }); } // Reject: deny everything var rejectBtn = document.getElementById('consent-reject'); if (rejectBtn) { rejectBtn.addEventListener('click', function() { updateConsent(false, false); if (banner) { banner.removeAttribute('data-visible'); setTimeout(function() { banner.style.display = 'none'; }, 350); } }); } })(); </script> <!-- Scroll Progress Bar --> <div id="scroll-progress" aria-hidden="true"></div> <!-- Site entrance + page transition doors --> <!-- Runs once per hard page load. SPA navigation handled by the persistent listeners. --> <script> (function() { // Guard: only run this initialization ONCE per browser session (not per SPA nav) if (window.__fervorEntranceInit) return; window.__fervorEntranceInit = true; var el = document.querySelector('.site-entrance'); if (!el) return; // ── Initial page load (hard load, not SPA) ── var isHomepage = location.pathname === '/' || location.pathname === '/index.html'; var hasSeenLogo = sessionStorage.getItem('entrance-logo-shown'); if (isHomepage && !hasSeenLogo) { sessionStorage.setItem('entrance-logo-shown', '1'); el.classList.add('entrance--show-logo'); setTimeout(function() { el.classList.remove('entrance--show-logo'); }, 600); setTimeout(function() { el.classList.add('entrance--open'); }, 800); setTimeout(function() { el.classList.add('entrance-done'); }, 1200); } else { setTimeout(function() { el.classList.add('entrance--open'); }, 50); setTimeout(function() { el.classList.add('entrance-done'); }, 180); } // ── Page transition handlers, registered ONCE, persist across SPA nav ── document.addEventListener('astro:before-preparation', function(e) { if (!e.loader) return; var originalLoader = e.loader; var fetchPromise = originalLoader(); e.loader = function() { return new Promise(function(resolve) { var persistedEl = document.querySelector('.site-entrance'); if (!persistedEl) { fetchPromise.then(resolve); return; } // Start in OPEN state (doors off-screen, element visible) persistedEl.classList.add('entrance--no-transition'); persistedEl.classList.add('entrance--open'); persistedEl.classList.remove('entrance-done'); // Wait TWO frames: one for display change to commit, one for transform snap requestAnimationFrame(function() { requestAnimationFrame(function() { // Re-enable transitions and trigger close persistedEl.classList.remove('entrance--no-transition'); persistedEl.classList.remove('entrance--open'); // Wait for close animation (180ms) AND fetch to resolve var closeDone = new Promise(function(r) { setTimeout(r, 190); }); Promise.all([fetchPromise, closeDone]).then(resolve); }); }); }); }; }); document.addEventListener('astro:before-swap', function() { window.scrollTo(0, 0); }); document.addEventListener('astro:after-swap', function() { var persistedEl = document.querySelector('.site-entrance'); if (!persistedEl) return; // Ensure classes are reset to "closed" state (strip any stale classes) persistedEl.classList.remove('entrance--open', 'entrance-done', 'entrance--show-logo'); // Force reflow so the browser commits the "closed" state before we transition to open void persistedEl.offsetHeight; // Now open persistedEl.classList.add('entrance--open'); setTimeout(function() { persistedEl.classList.add('entrance-done'); }, 130); }); })(); </script> <!-- Animation Engine, scroll-triggered WAAPI reveals --> <script type="module" src="/_astro/BaseLayout.astro_astro_type_script_index_0_lang.DSEUMZ1R.js"></script> <!-- Header shrink on scroll --> <script type="module">(function(){function t(){var e=document.querySelector(".site-header");if(!e)return;e.classList.remove("header--hidden");var n=!1,a=!1;function s(){var r=window.scrollY;r>80&&!n?(e.classList.add("header--shrunk"),n=!0):r<=40&&n&&(e.classList.remove("header--shrunk"),n=!1),a=!1}window.addEventListener("scroll",function(){a||(requestAnimationFrame(s),a=!0)},{passive:!0})}document.addEventListener("astro:page-load",t),document.readyState==="loading"?document.addEventListener("DOMContentLoaded",t):t()})();</script> <!-- Number counter animation for CRO index stats, teardown scores --> <script type="module">(function(){if(window.matchMedia("(prefers-reduced-motion: reduce)").matches)return;function o(){var r=[];if(document.querySelectorAll(".td-cover__score-num").forEach(function(e){r.push(e)}),document.querySelectorAll("[data-counter]").forEach(function(e){r.push(e)}),document.querySelectorAll(".counter-number").forEach(function(e){r.push(e)}),!r.length)return;var u=new Set;function g(e){var t=e.textContent||"",n=t.match(/^([^0-9.-]*)(-?[\d,.]+)(.*)$/);if(!n)return{value:0,prefix:"",suffix:"",decimals:0};var s=n[1]||"",a=n[2].replace(/,/g,""),f=n[3]||"",d=parseFloat(a),i=a.includes(".")?a.split(".")[1].length:0;return{value:d,prefix:s,suffix:f,decimals:i}}function l(e,t){var n=e.toFixed(t).split(".");return n[0]=n[0].replace(/\B(?=(\d{3})+(?!\d))/g,","),n.join(".")}function w(e){return 1-Math.pow(1-e,3)}function x(e){if(u.has(e))return;u.add(e);var t=g(e);if(t.value===0)return;var n=800,s=performance.now();function a(f){var d=f-s,i=Math.min(d/n,1),q=w(i),A=t.value*q;e.textContent=t.prefix+l(A,t.decimals)+t.suffix,i<1?requestAnimationFrame(a):e.textContent=t.prefix+l(t.value,t.decimals)+t.suffix}requestAnimationFrame(a)}var m=window.innerHeight,c=!1,v=r.length;function p(){m=window.innerHeight;for(var e=0;e<r.length;e++){var t=r[e];if(!u.has(t)){var n=t.getBoundingClientRect();n.top<m*.85&&n.bottom>0&&(x(t),v--)}}v<=0&&window.removeEventListener("scroll",h),c=!1}function h(){c||(requestAnimationFrame(p),c=!0)}window.addEventListener("scroll",h,{passive:!0}),requestAnimationFrame(function(){requestAnimationFrame(p)})}document.addEventListener("astro:page-load",o),document.readyState==="loading"?document.addEventListener("DOMContentLoaded",o):o()})();</script> <!-- Ripple Effect, subtle click feedback on [data-ripple] elements --> <script type="module">function c(t,e,n){const i=t.getBoundingClientRect(),d=e-i.left,s=n-i.top,o=Math.max(i.width,i.height)*2,r=document.createElement("span");r.style.cssText=` position: absolute; border-radius: 50%; background: currentColor; opacity: 0.1; width: ${o}px; height: ${o}px; left: ${d-o/2}px; top: ${s-o/2}px; transform: scale(0); pointer-events: none; z-index: 10; `,t.appendChild(r);const p=r.animate([{transform:"scale(0)",opacity:"0.1"},{transform:"scale(1)",opacity:"0"}],{duration:400,easing:"cubic-bezier(0.16, 1, 0.3, 1)",fill:"forwards"});p.onfinish=()=>r.remove()}function a(){document.addEventListener("click",t=>{const e=t.target.closest("[data-ripple]");e&&(window.matchMedia("(prefers-reduced-motion: reduce)").matches||c(e,t.clientX,t.clientY))}),document.addEventListener("touchstart",t=>{const e=t.touches[0];if(!e)return;const n=e.target.closest("[data-ripple]");n&&(window.matchMedia("(prefers-reduced-motion: reduce)").matches||c(n,e.clientX,e.clientY))},{passive:!0})}typeof document<"u"&&(document.addEventListener("astro:page-load",a),document.readyState==="complete"||document.readyState==="interactive"?a():document.addEventListener("DOMContentLoaded",a));</script> <!-- Scroll Progress Bar, shows reading position on long pages --> <script type="module">function n(){const e=document.getElementById("scroll-progress");if(!e)return;if(window.matchMedia("(prefers-reduced-motion: reduce)").matches){e.style.display="none";return}const s=document.documentElement.scrollHeight,d=window.innerHeight;if(s<d*1.5){e.style.display="none";return}e.style.display="block";let t=!1;function o(){const i=window.scrollY||document.documentElement.scrollTop,r=document.documentElement.scrollHeight-window.innerHeight,c=r>0?i/r*100:0;e.style.width=`${c}%`,e.style.opacity=i>50?"1":"0",t=!1}window.addEventListener("scroll",()=>{t||(requestAnimationFrame(o),t=!0)},{passive:!0}),o()}typeof document<"u"&&(document.addEventListener("astro:page-load",n),document.readyState==="complete"||document.readyState==="interactive"?n():document.addEventListener("DOMContentLoaded",n));</script> <!-- ── Custom Scroll Depth Tracking ── Replaces GA4 Enhanced Measurement scroll (which only fires at 90%). Fires at 25%, 50%, 75%, 100% with time-on-page context. --> <script> (function() { var milestones = [25, 50, 75, 100]; var fired = {}; var pageLoadTime = Date.now(); function getScrollPercent() { var h = document.documentElement; var b = document.body; var st = h.scrollTop || b.scrollTop; var sh = h.scrollHeight || b.scrollHeight; var ch = h.clientHeight; if (sh <= ch) return 100; return Math.round((st / (sh - ch)) * 100); } function checkScroll() { var pct = getScrollPercent(); for (var i = 0; i < milestones.length; i++) { var m = milestones[i]; if (pct >= m && !fired[m]) { fired[m] = true; window.dataLayer = window.dataLayer || []; window.dataLayer.push({ 'event': 'scroll_milestone', 'percent_scrolled': m, 'time_on_page_seconds': Math.round((Date.now() - pageLoadTime) / 1000) }); } } } // Throttled scroll listener var ticking = false; window.addEventListener('scroll', function() { if (!ticking) { window.requestAnimationFrame(function() { checkScroll(); ticking = false; }); ticking = true; } }, { passive: true }); // Handle View Transitions, reset scroll tracking on client-side nav document.addEventListener('astro:page-load', function() { fired = {}; pageLoadTime = Date.now(); }); })(); </script> <!-- ── View Transitions: Virtual Pageview ── Astro ClientRouter makes navigation SPA-like. Push a virtual pageview event on each client-side navigation so GA4 captures all page views, not just the initial load. --> <script> document.addEventListener('astro:page-load', function() { window.dataLayer = window.dataLayer || []; // Don't fire on initial page load (GTM handles that via page_view) if (window.__fervor_initial_load) { window.dataLayer.push({ 'event': 'virtual_pageview', 'page_path': window.location.pathname, 'page_title': document.title }); } window.__fervor_initial_load = true; }); </script> <script> if (window.innerWidth <= 768) { document.addEventListener('DOMContentLoaded', function() { // Tier: citations/sources get 16px floor var citeEls = document.querySelectorAll('[class*="source"],[class*="cite"],[class*="citation"],[class*="context"]'); for (var c = 0; c < citeEls.length; c++) { var cfs = parseFloat(getComputedStyle(citeEls[c]).fontSize); if (cfs < 16) citeEls[c].style.setProperty('font-size', '16px', 'important'); } // Floor: everything else gets 14px minimum var els = document.querySelectorAll('p,span,a,li,td,th,label,input,select,textarea,button,figcaption,cite,blockquote,dt,dd,summary,small'); for (var i = 0; i < els.length; i++) { var fs = parseFloat(getComputedStyle(els[i]).fontSize); if (fs < 14) els[i].style.setProperty('font-size', '14px', 'important'); } }); } </script> </body> </html>