Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

524 řádky
27KB

  1. <%
  2. Response.Charset = "utf-8"
  3. Response.CodePage = 65001
  4. %>
  5. <!doctype html>
  6. <html lang="en">
  7. <head>
  8. <meta charset="utf-8">
  9. <meta name="viewport" content="width=device-width, initial-scale=1">
  10. <title>PostcardMojo | Big Local Reach on One 9×12 Postcard</title>
  11. <meta name="description" content="Put your business on an oversized 9×12 postcard shared by a curated group of local businesses and delivered directly to nearby mailboxes.">
  12. <meta name="theme-color" content="#062f4f">
  13. <link rel="canonical" href="https://postcardmojo.com/">
  14. <meta property="og:type" content="website">
  15. <meta property="og:site_name" content="PostcardMojo">
  16. <meta property="og:title" content="PostcardMojo | Big Local Reach on One 9×12 Postcard">
  17. <meta property="og:description" content="Put your business on an oversized 9×12 postcard shared by a curated group of local businesses and delivered directly to nearby mailboxes.">
  18. <meta property="og:url" content="https://postcardmojo.com/">
  19. <meta property="og:image" content="https://postcardmojo.com/images/og-image.jpg">
  20. <meta property="og:image:width" content="1200">
  21. <meta property="og:image:height" content="630">
  22. <meta property="og:image:alt" content="PostcardMojo shared 9×12 postcard featuring local business ads">
  23. <meta name="twitter:card" content="summary_large_image">
  24. <meta name="twitter:title" content="PostcardMojo | Big Local Reach on One 9×12 Postcard">
  25. <meta name="twitter:description" content="Put your business on an oversized 9×12 postcard shared by a curated group of local businesses and delivered directly to nearby mailboxes.">
  26. <meta name="twitter:image" content="https://postcardmojo.com/images/og-image.jpg">
  27. <script type="application/ld+json">
  28. {
  29. "@context": "https://schema.org",
  30. "@graph": [
  31. {
  32. "@type": "Organization",
  33. "@id": "https://postcardmojo.com/#organization",
  34. "name": "PostcardMojo",
  35. "url": "https://postcardmojo.com/",
  36. "logo": "https://postcardmojo.com/images/logos/png/logo_full_large.png"
  37. },
  38. {
  39. "@type": "WebSite",
  40. "@id": "https://postcardmojo.com/#website",
  41. "url": "https://postcardmojo.com/",
  42. "name": "PostcardMojo",
  43. "publisher": {
  44. "@id": "https://postcardmojo.com/#organization"
  45. }
  46. },
  47. {
  48. "@type": "FAQPage",
  49. "mainEntity": [
  50. {
  51. "@type": "Question",
  52. "name": "What is a shared 9×12 postcard?",
  53. "acceptedAnswer": {
  54. "@type": "Answer",
  55. "text": "It is one oversized mail piece featuring a curated collection of local business ads. The format gives recipients multiple useful offers while advertisers share print and mailing costs."
  56. }
  57. },
  58. {
  59. "@type": "Question",
  60. "name": "Will a direct competitor appear beside me?",
  61. "acceptedAnswer": {
  62. "@type": "Answer",
  63. "text": "Category availability is managed by campaign. Ask about category placement and any available exclusivity when reserving your space."
  64. }
  65. },
  66. {
  67. "@type": "Question",
  68. "name": "Do I need a finished ad?",
  69. "acceptedAnswer": {
  70. "@type": "Answer",
  71. "text": "No. You can send us your own finished design, or we can create one for you. Either way, start with your logo, offer, contact details, and any brand assets you already have. Creative requirements are confirmed for your campaign."
  72. }
  73. },
  74. {
  75. "@type": "Question",
  76. "name": "Where will the postcard be mailed?",
  77. "acceptedAnswer": {
  78. "@type": "Answer",
  79. "text": "Campaigns are planned around selected local areas. Exact geography, timing, and mailing details are confirmed before you reserve a spot."
  80. }
  81. },
  82. {
  83. "@type": "Question",
  84. "name": "What does a campaign cost?",
  85. "acceptedAnswer": {
  86. "@type": "Answer",
  87. "text": "Pricing depends on the campaign, placement, and mailing plan. Request current details for the area you want to reach."
  88. }
  89. }
  90. ]
  91. }
  92. ]
  93. }
  94. </script>
  95. <link rel="icon" type="image/jpeg" href="/images/logos/sharp/jpg/icon_64.jpg">
  96. <link rel="preload" as="image" type="image/webp" href="/images/hero-postcard-1200.webp" imagesrcset="/images/hero-postcard-600.webp 600w, /images/hero-postcard-1200.webp 1200w" imagesizes="(max-width: 700px) 92vw, 640px">
  97. <link rel="preconnect" href="https://fonts.googleapis.com">
  98. <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
  99. <link href="https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;600;700&family=Manrope:wght@600;700;800&display=swap" rel="stylesheet">
  100. <link rel="stylesheet" href="/css/home.css">
  101. </head>
  102. <body id="top">
  103. <svg width="0" height="0" style="position:absolute" aria-hidden="true" focusable="false">
  104. <defs>
  105. <symbol id="i-layout" viewBox="0 0 24 24"><path d="M3 3h18v18H3zM3 9h18M9 21V9"/></symbol>
  106. <symbol id="i-pen" viewBox="0 0 24 24"><path d="M16.5 3.5l4 4L8 20l-5 1 1-5zM14 6l4 4"/></symbol>
  107. <symbol id="i-mail" viewBox="0 0 24 24"><path d="M3 5h18v14H3zM3 5l9 8 9-8"/></symbol>
  108. <symbol id="i-home" viewBox="0 0 24 24"><path d="M3 11l9-8 9 8M5 9.5V21h14V9.5M10 21v-6h4v6"/></symbol>
  109. <symbol id="i-heart" viewBox="0 0 24 24"><path d="M12 21s-8-5-8-11a4.5 4.5 0 0 1 8-2.5A4.5 4.5 0 0 1 20 10c0 6-8 11-8 11z"/></symbol>
  110. <symbol id="i-dining" viewBox="0 0 24 24"><path d="M5 3v6a3 3 0 0 0 6 0V3M8 3v18M17 21V3c-2.5 1.5-4 4.5-4 8h4"/></symbol>
  111. <symbol id="i-briefcase" viewBox="0 0 24 24"><path d="M3 7h18v13H3zM9 7V4h6v3M3 13h18"/></symbol>
  112. <symbol id="i-check" viewBox="0 0 24 24"><path d="M4 12.5l5 5L20 6.5"/></symbol>
  113. <symbol id="i-arrow-up-right" viewBox="0 0 24 24"><path d="M7 17L17 7M8 7h9v9"/></symbol>
  114. </defs>
  115. </svg>
  116. <a class="skip-link" href="#main-content">Skip to main content</a>
  117. <header class="site-header">
  118. <div class="shell nav-shell">
  119. <a class="brand" href="/" aria-label="PostcardMojo home">
  120. <img src="/images/logos/sharp/jpg/logo_full_small_b.jpg" width="217" height="73" alt="PostcardMojo">
  121. </a>
  122. <nav class="site-nav" id="site-nav" aria-label="Primary navigation">
  123. <a href="#how-it-works">How it works</a>
  124. <a href="#ad-sizes">Ad sizes</a>
  125. <a href="#why-postcards">Why it works</a>
  126. <a href="#good-fit">Who it is for</a>
  127. <a href="#faq">FAQ</a>
  128. </nav>
  129. <a class="button button-small button-primary" href="#contact">Find your spot</a>
  130. <button class="nav-toggle" type="button" aria-expanded="false" aria-controls="site-nav" aria-label="Menu">
  131. <span class="nav-toggle-bars" aria-hidden="true"></span>
  132. </button>
  133. </div>
  134. </header>
  135. <main id="main-content">
  136. <section class="hero">
  137. <div class="hero-glow hero-glow-one" aria-hidden="true"></div>
  138. <div class="hero-glow hero-glow-two" aria-hidden="true"></div>
  139. <div class="shell hero-grid">
  140. <div class="hero-copy">
  141. <p class="eyebrow"><span></span> Shared direct mail for local businesses</p>
  142. <h1>Make your business <em>impossible to miss</em> in the mailbox.</h1>
  143. <p class="hero-lede">PostcardMojo puts a curated lineup of local businesses on one oversized 9×12 postcard and is delivered to 5,000 mailboxes. Your offer gets a bold, tangible place in nearby homes while participating businesses share the cost of printing and postage.</p>
  144. <div class="hero-actions">
  145. <a class="button button-primary" href="#contact">Explore a campaign</a>
  146. <a class="button button-quiet" href="#how-it-works">See how it works <span aria-hidden="true">→</span></a>
  147. </div>
  148. <ul class="hero-points" aria-label="Campaign highlights">
  149. <li><span><svg class="icon" aria-hidden="true" focusable="false"><use href="#i-check"/></svg></span> Oversized 9×12 format</li>
  150. <li><span><svg class="icon" aria-hidden="true" focusable="false"><use href="#i-check"/></svg></span> Built for neighborhood reach</li>
  151. <li><span><svg class="icon" aria-hidden="true" focusable="false"><use href="#i-check"/></svg></span> Shared production costs</li>
  152. </ul>
  153. </div>
  154. <div class="postcard-stage">
  155. <div class="postcard-shadow" aria-hidden="true"></div>
  156. <div class="postcard">
  157. <picture>
  158. <source type="image/webp" srcset="/images/hero-postcard-600.webp 600w, /images/hero-postcard-1200.webp 1200w" sizes="(max-width: 700px) 92vw, 640px">
  159. <img class="postcard-image" src="/images/hero-postcard-1200.jpg" srcset="/images/hero-postcard-600.jpg 600w, /images/hero-postcard-1200.jpg 1200w" sizes="(max-width: 700px) 92vw, 640px" width="1200" height="900" fetchpriority="high" decoding="async" alt="Sample shared postcard featuring advertisements for local home-service businesses">
  160. </picture>
  161. </div>
  162. <div class="stage-note"><span><svg class="icon" aria-hidden="true" focusable="false"><use href="#i-arrow-up-right"/></svg></span> One card. Multiple businesses. A whole neighborhood of opportunity.</div>
  163. </div>
  164. </div>
  165. </section>
  166. <section class="signal-strip" aria-label="What makes PostcardMojo different">
  167. <div class="shell signal-grid">
  168. <div><strong>5,000</strong><span>Mailboxes reached</span></div>
  169. <div><strong>9 × 12 in</strong><span>Oversized postcard</span></div>
  170. <div><strong>2 ad sizes</strong><span>3×4 or 6×4</span></div>
  171. <div><strong>Design help</strong><span>Send yours or we create it</span></div>
  172. </div>
  173. </section>
  174. <section class="section section-light" id="how-it-works">
  175. <div class="shell">
  176. <div class="section-heading heading-centered">
  177. <p class="eyebrow eyebrow-centered"><span></span> Simple by design</p>
  178. <h2>Three steps to the mailbox.</h2>
  179. <p>Pick your size, give us your ad, and we handle the printing and mailing.</p>
  180. </div>
  181. <ol class="steps">
  182. <li>
  183. <span class="step-number">01</span>
  184. <div class="step-icon"><svg class="icon" aria-hidden="true" focusable="false"><use href="#i-layout"/></svg></div>
  185. <h3>Choose your ad size</h3>
  186. <p>Pick a 3×4 or a 6×4 space on the shared 9×12 postcard.</p>
  187. </li>
  188. <li>
  189. <span class="step-number">02</span>
  190. <div class="step-icon"><svg class="icon" aria-hidden="true" focusable="false"><use href="#i-pen"/></svg></div>
  191. <h3>Send your layout or let us design it</h3>
  192. <p>Already have an ad? Send it over. Need one? We will design it for you.</p>
  193. </li>
  194. <li>
  195. <span class="step-number">03</span>
  196. <div class="step-icon"><svg class="icon" aria-hidden="true" focusable="false"><use href="#i-mail"/></svg></div>
  197. <h3>We mail it out</h3>
  198. <p>We print the postcard and deliver it to mailboxes in your area.</p>
  199. </li>
  200. </ol>
  201. </div>
  202. </section>
  203. <section class="section section-warm" id="ad-sizes">
  204. <div class="shell">
  205. <div class="section-heading heading-centered">
  206. <p class="eyebrow eyebrow-centered"><span></span> Pick your space</p>
  207. <h2>Two sizes. One clear offer.</h2>
  208. <p>Every ad shares the 9×12 postcard with other local businesses. Choose the size that fits your message.</p>
  209. </div>
  210. <figure class="size-scale">
  211. <div class="size-scale-row" role="img" aria-label="Scale drawing of the 9 by 12 inch postcard beside the 6 by 4 inch and 3 by 4 inch ad sizes">
  212. <div class="scale-item"><span class="scale-shape scale-card"></span><figcaption>9×12 postcard</figcaption></div>
  213. <div class="scale-item"><span class="scale-shape scale-large"></span><figcaption>6×4 ad</figcaption></div>
  214. <div class="scale-item"><span class="scale-shape scale-small"></span><figcaption>3×4 ad</figcaption></div>
  215. </div>
  216. <p class="scale-caption">Shown to scale</p>
  217. </figure>
  218. <div class="size-grid">
  219. <article class="size-card">
  220. <h3>3×4 spot</h3>
  221. <p>A focused space for one strong offer, your logo, and a clear next step.</p>
  222. <ul>
  223. <li>Headline and one offer</li>
  224. <li>Phone number, URL, or QR code</li>
  225. </ul>
  226. </article>
  227. <article class="size-card size-card-featured">
  228. <h3>6×4 spot</h3>
  229. <p>Twice the width of a 3×4, with more room for a photo, a bigger offer, and a message that stands out on the card.</p>
  230. <ul>
  231. <li>Headline, photo, and offer</li>
  232. <li>Phone number, URL, and QR code</li>
  233. </ul>
  234. </article>
  235. </div>
  236. <div class="pricing-note">
  237. <div>
  238. <h3>Pricing and mail dates are set per campaign</h3>
  239. <p>We are building the next campaign now. Tell us your business and service area and we will confirm pricing, availability, and the mail date for your spot.</p>
  240. </div>
  241. <a class="button button-primary" href="#contact">Get pricing for my area</a>
  242. </div>
  243. </div>
  244. </section>
  245. <section class="section section-navy" id="why-postcards">
  246. <div class="shell value-grid">
  247. <div class="value-copy">
  248. <p class="eyebrow eyebrow-on-dark"><span></span> A physical advantage</p>
  249. <h2>Digital ads disappear with a swipe. A great postcard gets held.</h2>
  250. <p>PostcardMojo gives your business a physical moment with a local customer. The oversized format creates room for a useful offer, recognizable branding, and a direct next step.</p>
  251. <a class="text-link" href="#contact">Put your offer on the next card <span aria-hidden="true">→</span></a>
  252. </div>
  253. <div class="benefit-list">
  254. <article>
  255. <span class="benefit-mark">01</span>
  256. <div><h3>Big enough to notice</h3><p>A 9×12 card has the visual presence to stand apart from ordinary envelopes and smaller mail pieces.</p></div>
  257. </article>
  258. <article>
  259. <span class="benefit-mark">02</span>
  260. <div><h3>Local enough to matter</h3><p>Campaigns can be centered on the communities where participating businesses want to be known.</p></div>
  261. </article>
  262. <article>
  263. <span class="benefit-mark">03</span>
  264. <div><h3>Shared without feeling small</h3><p>Businesses share the mail piece while each ad keeps its own message, offer, and brand identity.</p></div>
  265. </article>
  266. <article>
  267. <span class="benefit-mark">04</span>
  268. <div><h3>Easy to act on</h3><p>A phone number, URL, QR code, or offer gives recipients a simple way to take the next step.</p></div>
  269. </article>
  270. </div>
  271. </div>
  272. </section>
  273. <section class="section section-warm" id="good-fit">
  274. <div class="shell">
  275. <div class="section-heading heading-split">
  276. <div>
  277. <p class="eyebrow"><span></span> Made for the neighborhood</p>
  278. <h2>Local businesses belong in local mailboxes.</h2>
  279. </div>
  280. <p>If nearby households can become customers, a PostcardMojo campaign can help introduce your business and give them a reason to respond.</p>
  281. </div>
  282. <div class="fit-grid">
  283. <article class="fit-card">
  284. <span class="fit-icon"><svg class="icon" aria-hidden="true" focusable="false"><use href="#i-home"/></svg></span>
  285. <h3>Home services</h3>
  286. <p>Landscaping, cleaning, roofing, HVAC, plumbing, remodeling, and other trusted pros.</p>
  287. </article>
  288. <article class="fit-card">
  289. <span class="fit-icon"><svg class="icon" aria-hidden="true" focusable="false"><use href="#i-heart"/></svg></span>
  290. <h3>Health &amp; wellness</h3>
  291. <p>Dentists, chiropractors, fitness studios, salons, spas, and wellness providers.</p>
  292. </article>
  293. <article class="fit-card">
  294. <span class="fit-icon"><svg class="icon" aria-hidden="true" focusable="false"><use href="#i-dining"/></svg></span>
  295. <h3>Food &amp; experiences</h3>
  296. <p>Restaurants, cafés, entertainment, family activities, and places worth discovering.</p>
  297. </article>
  298. <article class="fit-card">
  299. <span class="fit-icon"><svg class="icon" aria-hidden="true" focusable="false"><use href="#i-briefcase"/></svg></span>
  300. <h3>Professional services</h3>
  301. <p>Real estate, insurance, financial, legal, pet care, automotive, and local experts.</p>
  302. </article>
  303. </div>
  304. </div>
  305. </section>
  306. <section class="section offer-section">
  307. <div class="shell offer-grid">
  308. <div class="offer-card" aria-hidden="true">
  309. <div class="offer-stamp">YOUR<br>OFFER</div>
  310. <p class="offer-kicker">LOCAL FAVORITE</p>
  311. <p class="offer-headline">Give neighbors a reason to try you.</p>
  312. <div class="offer-coupon"><strong>20% OFF</strong><span>your first visit</span></div>
  313. <div class="offer-url">YOURBUSINESS.COM</div>
  314. </div>
  315. <div class="offer-copy">
  316. <p class="eyebrow"><span></span> Make the space count</p>
  317. <h2>A clear offer turns attention into action.</h2>
  318. <p>Your ad does not need to tell your whole story. It needs to make one strong promise and give a nearby customer one easy next step.</p>
  319. <ul class="check-list">
  320. <li><span><svg class="icon" aria-hidden="true" focusable="false"><use href="#i-check"/></svg></span><div><strong>A direct headline</strong><small>Say what you do and why it matters.</small></div></li>
  321. <li><span><svg class="icon" aria-hidden="true" focusable="false"><use href="#i-check"/></svg></span><div><strong>A compelling reason to respond</strong><small>Feature an offer, service, or timely benefit.</small></div></li>
  322. <li><span><svg class="icon" aria-hidden="true" focusable="false"><use href="#i-check"/></svg></span><div><strong>A simple call to action</strong><small>Use a memorable URL, phone number, or QR code.</small></div></li>
  323. </ul>
  324. </div>
  325. </div>
  326. </section>
  327. <section class="section section-light" id="faq">
  328. <div class="shell faq-grid">
  329. <div class="faq-intro">
  330. <p class="eyebrow"><span></span> The short version</p>
  331. <h2>Questions before you join the card?</h2>
  332. <p>Every campaign is shaped around its participating businesses and selected local area. These answers cover the basics.</p>
  333. </div>
  334. <div class="faq-list">
  335. <details open>
  336. <summary>What is a shared 9×12 postcard?<span aria-hidden="true">+</span></summary>
  337. <p>It is one oversized mail piece featuring a curated collection of local business ads. The format gives recipients multiple useful offers while advertisers share print and mailing costs.</p>
  338. </details>
  339. <details>
  340. <summary>Will a direct competitor appear beside me?<span aria-hidden="true">+</span></summary>
  341. <p>Category availability is managed by campaign. Ask about category placement and any available exclusivity when reserving your space.</p>
  342. </details>
  343. <details>
  344. <summary>Do I need a finished ad?<span aria-hidden="true">+</span></summary>
  345. <p>No. You can send us your own finished design, or we can create one for you. Either way, start with your logo, offer, contact details, and any brand assets you already have. Creative requirements are confirmed for your campaign.</p>
  346. </details>
  347. <details>
  348. <summary>Where will the postcard be mailed?<span aria-hidden="true">+</span></summary>
  349. <p>Campaigns are planned around selected local areas. Exact geography, timing, and mailing details are confirmed before you reserve a spot.</p>
  350. </details>
  351. <details>
  352. <summary>What does a campaign cost?<span aria-hidden="true">+</span></summary>
  353. <p>Pricing depends on the campaign, placement, and mailing plan. Request current details for the area you want to reach.</p>
  354. <a class="button button-small button-primary" href="#contact">Request Details</a>
  355. </details>
  356. </div>
  357. </div>
  358. </section>
  359. <section class="contact-section" id="contact" aria-labelledby="contact-title">
  360. <div class="shell contact-card">
  361. <div class="cta-rings" aria-hidden="true"></div>
  362. <div class="contact-intro">
  363. <p class="eyebrow eyebrow-on-dark"><span></span> Your neighborhood is waiting</p>
  364. <h2 id="contact-title">Interested in a spot on the next card?</h2>
  365. <p>Tell us what you do and where you want to be seen. We will help you explore the right PostcardMojo campaign and confirm sizes, pricing, and mail dates.</p>
  366. <p class="contact-note">Campaign availability varies by area. We reply within one business day.</p>
  367. </div>
  368. <div class="contact-panel">
  369. <% If contactSent Then %>
  370. <p class="contact-success" role="status" tabindex="-1">Thank you! Your message was sent and we will be in touch soon.</p>
  371. <% Else %>
  372. <form class="contact-form" method="post" action="/contact#contact" novalidate aria-labelledby="contact-title">
  373. <% If UBound(contactErrors) >= 0 Then %>
  374. <div class="contact-errors" role="alert" tabindex="-1">
  375. <ul>
  376. <% Dim contactErrorIndex : For contactErrorIndex = 0 To UBound(contactErrors) %>
  377. <li><%= Server.HTMLEncode(contactErrors(contactErrorIndex)) %></li>
  378. <% Next %>
  379. </ul>
  380. </div>
  381. <% End If %>
  382. <input type="hidden" name="csrf_token" value="<%= Server.HTMLEncode(ContactCsrfToken()) %>">
  383. <div class="contact-trap" aria-hidden="true"><label>Leave this empty <input type="text" name="zq_trap_field" tabindex="-1" autocomplete="off"></label></div>
  384. <label><span>Name <span aria-hidden="true">*</span></span>
  385. <input type="text" name="name" maxlength="100" required autocomplete="name" value="<%= Server.HTMLEncode(contactName & "") %>">
  386. </label>
  387. <label><span>Email <span aria-hidden="true">*</span></span>
  388. <input type="email" name="email" maxlength="150" required autocomplete="email" value="<%= Server.HTMLEncode(contactEmail & "") %>">
  389. </label>
  390. <label>Phone
  391. <input type="tel" name="phone" maxlength="40" autocomplete="tel" value="<%= Server.HTMLEncode(contactPhone & "") %>">
  392. </label>
  393. <label>Business
  394. <input type="text" name="business" maxlength="150" autocomplete="organization" value="<%= Server.HTMLEncode(contactBusiness & "") %>">
  395. </label>
  396. <label class="contact-wide">How can we help?
  397. <textarea name="message" rows="3" maxlength="2000"><%= Server.HTMLEncode(contactMessage & "") %></textarea>
  398. </label>
  399. <button class="button button-gold" type="submit">Send my interest</button>
  400. <p class="contact-privacy">We use your details only to contact you about our services. We never sell or share them. <a href="/privacy">Privacy policy</a></p>
  401. </form>
  402. <% End If %>
  403. </div>
  404. </div>
  405. </section>
  406. </main>
  407. <footer class="site-footer">
  408. <div class="shell footer-grid">
  409. <a class="footer-brand" href="#top" aria-label="Back to top">
  410. <img src="/images/logos/sharp/jpg/logo_full_small_a.jpg" width="187" height="63" alt="PostcardMojo">
  411. </a>
  412. <p>Big local visibility, delivered.</p>
  413. <nav aria-label="Footer navigation">
  414. <a href="#how-it-works">How it works</a>
  415. <a href="#faq">FAQ</a>
  416. <a href="#contact">Contact</a>
  417. <a href="/privacy">Privacy</a>
  418. </nav>
  419. <small>&copy; <%= Year(Date()) %> PostcardMojo. All rights reserved.</small>
  420. </div>
  421. </footer>
  422. <div class="sticky-cta" id="sticky-cta">
  423. <a class="button button-gold" href="#contact">Get pricing for my area</a>
  424. </div>
  425. <script src="/js/nav.js"></script>
  426. <script>
  427. (function () {
  428. var bar = document.getElementById('sticky-cta');
  429. var hero = document.querySelector('.hero');
  430. var contact = document.getElementById('contact');
  431. if (bar && hero && contact && 'IntersectionObserver' in window) {
  432. var heroVisible = true;
  433. var contactVisible = false;
  434. function updateBar() {
  435. bar.classList.toggle('is-visible', !heroVisible && !contactVisible);
  436. }
  437. new IntersectionObserver(function (entries) {
  438. heroVisible = entries[0].isIntersecting;
  439. updateBar();
  440. }).observe(hero);
  441. new IntersectionObserver(function (entries) {
  442. contactVisible = entries[0].isIntersecting;
  443. updateBar();
  444. }).observe(contact);
  445. }
  446. })();
  447. </script>
  448. <script>
  449. (function () {
  450. var form = document.querySelector('.contact-form');
  451. var notice = document.querySelector('.contact-errors, .contact-success');
  452. if (notice) notice.focus();
  453. if (!form) return;
  454. var rules = [
  455. { name: 'name', message: 'Please enter your name.' },
  456. { name: 'email', message: 'Please enter a valid email address.', pattern: /^[^\s@<>,;"]+@[^\s@<>,;"]+\.[A-Za-z]{2,}$/ }
  457. ];
  458. function clearError(field) {
  459. var old = document.getElementById('error-' + field.name);
  460. if (old) old.remove();
  461. field.removeAttribute('aria-invalid');
  462. field.removeAttribute('aria-describedby');
  463. }
  464. function showError(field, message) {
  465. clearError(field);
  466. var note = document.createElement('p');
  467. note.className = 'field-error';
  468. note.id = 'error-' + field.name;
  469. note.textContent = message;
  470. field.insertAdjacentElement('afterend', note);
  471. field.setAttribute('aria-invalid', 'true');
  472. field.setAttribute('aria-describedby', note.id);
  473. }
  474. form.addEventListener('submit', function (event) {
  475. var firstInvalid = null;
  476. rules.forEach(function (rule) {
  477. var field = form.elements[rule.name];
  478. var value = field.value.trim();
  479. var invalid = value.length === 0 || (rule.pattern && !rule.pattern.test(value));
  480. if (invalid) {
  481. showError(field, rule.message);
  482. if (!firstInvalid) firstInvalid = field;
  483. } else {
  484. clearError(field);
  485. }
  486. });
  487. if (firstInvalid) {
  488. event.preventDefault();
  489. firstInvalid.focus();
  490. }
  491. });
  492. form.addEventListener('input', function (event) {
  493. if (event.target.getAttribute('aria-invalid') === 'true') clearError(event.target);
  494. });
  495. })();
  496. </script>
  497. </body>
  498. </html>

Powered by TurnKey Linux.