diff --git a/app/controllers/HomeController.asp b/app/controllers/HomeController.asp index e36cfd2..c61b7d3 100644 --- a/app/controllers/HomeController.asp +++ b/app/controllers/HomeController.asp @@ -26,6 +26,13 @@ Class HomeController_Class <% End Sub + ' GET /privacy - the privacy policy page. + Public Sub Privacy() +%> + +<% + End Sub + ' GetAntiCSRFToken returns an empty value the first time it creates a token, so read it again. Private Function ContactCsrfToken() ContactCsrfToken = HTMLSecurity().GetAntiCSRFToken("home.contact") diff --git a/app/views/Home/landing.asp b/app/views/Home/landing.asp index 83e48c5..3a40ccf 100644 --- a/app/views/Home/landing.asp +++ b/app/views/Home/landing.asp @@ -10,13 +10,110 @@ Response.CodePage = 65001 PostcardMojo | Big Local Reach on One 9×12 Postcard + + + + + + + + + + + + + + + + + + @@ -48,66 +149,31 @@ Response.CodePage = 65001 See how it works
- Sample shared postcard featuring advertisements for local home-service businesses + + + Sample shared postcard featuring advertisements for local home-service businesses +
-
One card. Multiple businesses. A whole neighborhood of opportunity.
+
One card. Multiple businesses. A whole neighborhood of opportunity.
- -
-
9 × 12Oversized presence
-
One cardA curated local lineup
-
SharedPrint and postage costs
-
LocalCampaign-focused reach
+
5,000Mailboxes reached
+
9 × 12 inOversized postcard
+
2 ad sizes3×4 or 6×4
+
Design helpSend yours or we create it
@@ -121,19 +187,19 @@ Response.CodePage = 65001
  1. 01 - +

    Choose your ad size

    -

    Pick a 3×4 or a 6×8 space on the shared 9×12 postcard.

    +

    Pick a 3×4 or a 6×4 space on the shared 9×12 postcard.

  2. 02 - +

    Send your layout or let us design it

    Already have an ad? Send it over. Need one? We will design it for you.

  3. 03 - +

    We mail it out

    We print the postcard and deliver it to mailboxes in your area.

  4. @@ -141,13 +207,59 @@ Response.CodePage = 65001 +
    +
    +
    +

    Pick your space

    +

    Two sizes. One clear offer.

    +

    Every ad shares the 9×12 postcard with other local businesses. Choose the size that fits your message.

    +
    + +
    + +

    Shown to scale

    +
    + +
    +
    +

    3×4 spot

    +

    A focused space for one strong offer, your logo, and a clear next step.

    +
      +
    • Headline and one offer
    • +
    • Phone number, URL, or QR code
    • +
    +
    + +
    + +
    +
    +

    Pricing and mail dates are set per campaign

    +

    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.

    +
    + Get pricing for my area +
    +
    +
    +

    A physical advantage

    Digital ads disappear with a swipe. A great postcard gets held.

    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.

    - Put your offer on the next card + Put your offer on the next card
    @@ -181,22 +293,22 @@ Response.CodePage = 65001
    - +

    Home services

    Landscaping, cleaning, roofing, HVAC, plumbing, remodeling, and other trusted pros.

    - +

    Health & wellness

    Dentists, chiropractors, fitness studios, salons, spas, and wellness providers.

    - +

    Food & experiences

    Restaurants, cafés, entertainment, family activities, and places worth discovering.

    - +

    Professional services

    Real estate, insurance, financial, legal, pet care, automotive, and local experts.

    @@ -218,9 +330,9 @@ Response.CodePage = 65001

    A clear offer turns attention into action.

    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.

      -
    • ✓
      A direct headlineSay what you do and why it matters.
    • -
    • ✓
      A compelling reason to respondFeature an offer, service, or timely benefit.
    • -
    • ✓
      A simple call to actionUse a memorable URL, phone number, or QR code.
    • +
    • A direct headlineSay what you do and why it matters.
    • +
    • A compelling reason to respondFeature an offer, service, or timely benefit.
    • +
    • A simple call to actionUse a memorable URL, phone number, or QR code.
    @@ -244,7 +356,7 @@ Response.CodePage = 65001
    Do I need a finished ad? -

    Start with your logo, offer, contact details, and any brand assets you already have. Creative requirements and available assistance can be confirmed for your campaign.

    +

    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.

    Where will the postcard be mailed? @@ -253,22 +365,56 @@ Response.CodePage = 65001
    What does a campaign cost?

    Pricing depends on the campaign, placement, and mailing plan. Request current details for the area you want to reach.

    + Request Details
    -
    -
    +
    +
    -
    +

    Your neighborhood is waiting

    -

    Put your business in the next mailbox moment.

    -

    Tell us what you do and where you want to be seen. We will help you explore the right PostcardMojo campaign.

    +

    Interested in a spot on the next card?

    +

    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.

    +

    Campaign availability varies by area. We reply within one business day.

    -
    - Request campaign details - Campaign availability varies by area. +
    +<% If contactSent Then %> +

    Thank you! Your message was sent and we will be in touch soon.

    +<% Else %> +
    +<% If UBound(contactErrors) >= 0 Then %> + +<% End If %> + + + + + + + + +

    We use your details only to contact you about our services. We never sell or share them. Privacy policy

    +
    +<% End If %>
    @@ -284,9 +430,94 @@ Response.CodePage = 65001 How it works FAQ Contact + Privacy © <%= Year(Date()) %> PostcardMojo. All rights reserved.
    + + + + + + + + diff --git a/app/views/Home/privacy.asp b/app/views/Home/privacy.asp new file mode 100644 index 0000000..0d9bbbe --- /dev/null +++ b/app/views/Home/privacy.asp @@ -0,0 +1,114 @@ +<% +Response.Charset = "utf-8" +Response.CodePage = 65001 +%> + + + + + + Privacy Policy | PostcardMojo + + + + + + + + + + + + + + +
    + +
    + + + + + + diff --git a/public/Default.asp b/public/Default.asp index 509accc..13da6c0 100644 --- a/public/Default.asp +++ b/public/Default.asp @@ -6,6 +6,7 @@ router.AddRoute "GET", "", "HomeController", "Index" router.AddRoute "GET", "/home", "HomeController", "Index" router.AddRoute "POST", "/contact", "HomeController", "Contact" + router.AddRoute "GET", "/privacy", "HomeController", "Privacy" ' Dispatch the request (resolves route and executes controller action) MVC.DispatchRequest Request.ServerVariables("REQUEST_METHOD"), _ diff --git a/public/css/home.css b/public/css/home.css index 35a95cb..596fc32 100644 --- a/public/css/home.css +++ b/public/css/home.css @@ -58,10 +58,16 @@ summary { } :focus-visible { - outline: 3px solid var(--gold); + outline: 3px solid var(--navy); outline-offset: 4px; } +.section-navy :focus-visible, +.contact-card :focus-visible, +.pricing-note :focus-visible { + outline-color: var(--gold); +} + .skip-link { position: fixed; z-index: 1000; @@ -90,8 +96,7 @@ summary { z-index: 50; top: 0; border-bottom: 1px solid rgba(5, 47, 79, 0.1); - background: rgba(255, 253, 248, 0.94); - backdrop-filter: blur(14px); + background: var(--white); } .nav-shell { @@ -235,7 +240,7 @@ summary { .hero-grid { min-height: 710px; display: grid; - grid-template-columns: minmax(0, 0.93fr) minmax(500px, 1.07fr); + grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr); align-items: center; gap: clamp(38px, 6vw, 78px); padding-block: 74px 80px; @@ -268,8 +273,7 @@ summary { .section-heading h2, .value-copy h2, .offer-copy h2, -.faq-intro h2, -.cta-card h2 { +.faq-intro h2 { margin: 0; color: var(--navy); font-family: var(--font-display); @@ -353,15 +357,22 @@ summary { .postcard { position: relative; - width: min(100%, 610px); + width: 100%; + max-width: 640px; aspect-ratio: 12 / 9; overflow: hidden; border: 1px solid rgba(5, 47, 79, 0.12); - border-radius: 18px; + border-radius: 0; background: #fffef9; box-shadow: 0 34px 80px rgba(5, 47, 79, 0.22), 0 5px 15px rgba(5, 47, 79, 0.12); } +.postcard picture { + display: block; + width: 100%; + height: 100%; +} + .postcard-image { width: 100%; height: 100%; @@ -538,8 +549,7 @@ summary { .section-heading h2, .value-copy h2, .offer-copy h2, -.faq-intro h2, -.cta-card h2 { +.faq-intro h2 { font-size: clamp(2.25rem, 4.3vw, 4rem); } @@ -607,7 +617,7 @@ summary { position: absolute; top: 20px; right: 22px; - color: #a1acb3; + color: var(--muted); font-family: var(--font-display); font-size: 0.76rem; font-weight: 800; @@ -677,8 +687,7 @@ summary { .eyebrow-on-dark { color: #f9d86e; } -.value-copy h2, -.cta-card h2 { +.value-copy h2 { color: var(--white); } @@ -1007,53 +1016,8 @@ summary { color: var(--muted); } -.cta-section { - padding: 30px 0 110px; - background: var(--white); -} - -.cta-card { - position: relative; - isolation: isolate; - min-height: 365px; - display: grid; - grid-template-columns: minmax(0, 1fr) auto; - align-items: center; - gap: 55px; - overflow: hidden; - padding: clamp(45px, 7vw, 85px); - border-radius: var(--radius-lg); - background: var(--navy); - box-shadow: 0 30px 70px rgba(5, 47, 79, 0.24); - color: var(--white); -} - -.cta-card > div:not(.cta-rings) { - position: relative; - z-index: 1; -} - -.cta-card h2 { - max-width: 750px; -} - -.cta-card p:not(.eyebrow) { - max-width: 650px; - margin: 20px 0 0; - color: #c9d6dd; - font-size: 1.03rem; -} - -.cta-actions { - min-width: 245px; - display: grid; - justify-items: center; - gap: 13px; -} - -.cta-actions span { - color: #b7c8d1; - font-size: 0.75rem; +.faq-list details .button { + margin: 0 0 25px; } .cta-rings { @@ -1071,7 +1035,7 @@ summary { .site-footer { padding-block: 42px; border-top: 1px solid var(--line); - background: var(--paper); + background: var(--white); } .footer-grid { @@ -1100,7 +1064,7 @@ summary { grid-column: 1 / -1; padding-top: 22px; border-top: 1px solid var(--line); - color: #77838b; + color: var(--muted); font-size: 0.73rem; } @@ -1130,21 +1094,9 @@ summary { .steps::before { display: none; } - - .cta-card { - grid-template-columns: 1fr; - } - - .cta-actions { - justify-items: start; - } } @media (max-width: 840px) { - .site-header { - position: relative; - } - .nav-shell { min-height: auto; grid-template-columns: 1fr auto; @@ -1269,7 +1221,6 @@ summary { .postcard { width: 100%; - border-radius: 12px; } .postcard-feature { @@ -1327,8 +1278,7 @@ summary { .section-heading h2, .value-copy h2, .offer-copy h2, - .faq-intro h2, - .cta-card h2 { + .faq-intro h2 { font-size: clamp(2.05rem, 10vw, 3rem); } @@ -1386,22 +1336,6 @@ summary { margin-right: 0; } - .cta-section { - padding-bottom: 70px; - } - - .cta-card { - min-height: auto; - gap: 35px; - padding: 42px 27px; - border-radius: 24px; - } - - .cta-actions, - .cta-actions .button { - width: 100%; - } - .footer-grid { grid-template-columns: 1fr; } @@ -1428,22 +1362,59 @@ summary { } } -/* Contact card */ +/* Contact section */ +.contact-section { + padding: 30px 0 110px; + background: var(--white); +} + .contact-card { position: relative; - z-index: 2; - padding: clamp(22px, 3vw, 34px); - border-radius: 18px; + isolation: isolate; + display: grid; + grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr); + align-items: center; + gap: clamp(36px, 6vw, 80px); + overflow: hidden; + padding: clamp(36px, 6vw, 80px); + border-radius: var(--radius-lg); background: var(--navy); + box-shadow: 0 30px 70px rgba(5, 47, 79, 0.24); color: var(--white); - box-shadow: 0 24px 60px rgba(5, 47, 79, 0.28); } -.contact-card h2 { - margin: 0 0 18px; +.contact-intro, +.contact-panel { + position: relative; + z-index: 1; +} + +.contact-intro h2 { + margin: 0; + color: var(--white); font-family: var(--font-display); - font-size: clamp(1.5rem, 2.4vw, 2rem); - line-height: 1.15; + font-size: clamp(2rem, 3.6vw, 3.25rem); + font-weight: 800; + letter-spacing: -0.045em; + line-height: 1.06; +} + +.contact-intro p:not(.eyebrow) { + margin: 20px 0 0; + color: #c9d6dd; + font-size: 1.03rem; +} + +.contact-intro .contact-note { + color: #b7c8d1; + font-size: 0.82rem; +} + +.contact-panel { + padding: clamp(22px, 3vw, 34px); + border: 1px solid rgba(255, 255, 255, 0.12); + border-radius: 18px; + background: rgba(255, 255, 255, 0.06); } .contact-form { @@ -1496,6 +1467,7 @@ summary { .contact-success { margin: 0; color: var(--gold); + font-size: 1.1rem; font-weight: 700; } @@ -1504,43 +1476,462 @@ summary { left: -9999px; } -.hero .hero-grid { - width: min(1640px, calc(100% - 32px)); - grid-template-columns: minmax(0, 0.75fr) minmax(0, 1.6fr) minmax(280px, 0.75fr); - grid-template-areas: "copy card contact"; - align-items: center; - gap: clamp(20px, 2.5vw, 40px); +.hero-copy .hero-actions + .hero-points { + margin-top: 29px; } -.hero-grid .hero-copy { grid-area: copy; } -.hero-grid .contact-card { grid-area: contact; } -.hero-grid .postcard-stage { grid-area: card; min-height: 0; } -.hero-grid .postcard { width: 100%; } +@media (max-width: 1080px) { + .contact-card { + grid-template-columns: 1fr; + } +} -.hero-grid h1 { font-size: clamp(2rem, 3vw, 3.1rem); } -.hero-grid .contact-form { grid-template-columns: 1fr; gap: 12px; } -.hero-grid .stage-note { position: static; margin-top: 16px; max-width: none; } +@media (max-width: 600px) { + .contact-section { + padding-bottom: 70px; + } -@media (max-width: 1100px) { - .hero .hero-grid { - grid-template-columns: minmax(0, 1fr) minmax(300px, 0.9fr); - grid-template-areas: "copy contact" "card card"; - align-items: start; + .contact-card { + padding: 36px 20px; + border-radius: 24px; } - .hero-grid .postcard { width: min(100%, 610px); } - .hero-grid .postcard-stage { min-height: 520px; } + .contact-form { + grid-template-columns: 1fr; + } + + .contact-form .button { + width: 100%; + } +} + +/* Ad sizes */ +.size-scale { + margin: 0 0 48px; + text-align: center; +} + +.size-scale-row { + --u: clamp(11px, 2.4vw, 20px); + display: flex; + align-items: flex-end; + justify-content: center; + gap: clamp(22px, 5vw, 56px); +} + +.scale-item { + display: grid; + justify-items: center; + gap: 10px; +} + +.scale-item figcaption { + color: var(--navy); + font-family: var(--font-display); + font-size: 0.82rem; + font-weight: 800; +} + +.scale-shape { + display: block; + box-shadow: 0 10px 24px rgba(5, 47, 79, 0.14); +} + +.scale-card { + width: calc(var(--u) * 12); + height: calc(var(--u) * 9); + border: 2px solid var(--navy); + background: var(--white); +} + +.scale-large { + width: calc(var(--u) * 6); + height: calc(var(--u) * 4); + background: var(--navy); +} + +.scale-small { + width: calc(var(--u) * 3); + height: calc(var(--u) * 4); + background: var(--gold); +} + +.scale-caption { + margin: 16px 0 0; + color: var(--muted); + font-size: 0.82rem; +} + +.size-grid { + max-width: 820px; + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 18px; + margin: 0 auto; +} + +.size-card { + padding: 30px; + border: 1px solid rgba(5, 47, 79, 0.1); + background: var(--white); +} + +.size-card-featured { + border-color: var(--navy); + box-shadow: 0 20px 50px rgba(5, 47, 79, 0.12); +} + +.size-card h3 { + margin: 0; + color: var(--navy); + font-family: var(--font-display); + font-size: 1.4rem; + font-weight: 800; +} + +.size-card p { + margin: 10px 0 0; + color: var(--muted); + font-size: 0.95rem; +} + +.size-card ul { + margin: 18px 0 0; + padding: 0; + color: var(--ink); + font-size: 0.9rem; + font-weight: 600; + list-style: none; +} + +.size-card li { + padding-block: 8px; + border-top: 1px solid var(--line); +} + +.pricing-note { + max-width: 820px; + display: flex; + align-items: center; + justify-content: space-between; + gap: 28px; + margin: 18px auto 0; + padding: 28px 30px; + background: var(--navy); + color: var(--white); +} + +.pricing-note h3 { + margin: 0; + font-family: var(--font-display); + font-size: 1.15rem; + font-weight: 800; +} + +.pricing-note p { + margin: 8px 0 0; + color: #c9d6dd; + font-size: 0.92rem; +} + +.pricing-note .button { + flex: 0 0 auto; + background: var(--gold); + color: var(--navy-deep); +} + +.pricing-note .button:hover { + background: #ffd44a; } @media (max-width: 700px) { - .hero .hero-grid { + .size-grid { grid-template-columns: 1fr; - grid-template-areas: "copy" "contact" "card"; + } + + .pricing-note { + flex-direction: column; + align-items: stretch; + text-align: left; + } +} + +/* Icons */ +.icon { + width: 1em; + height: 1em; + flex: 0 0 auto; + fill: none; + stroke: currentColor; + stroke-width: 2; + stroke-linecap: square; + stroke-linejoin: miter; +} + +.step-icon .icon { width: 28px; height: 28px; } +.fit-icon .icon { width: 32px; height: 32px; } +.hero-points .icon { width: 12px; height: 12px; stroke-width: 3; } +.stage-note .icon { width: 16px; height: 16px; } +.check-list .icon { width: 18px; height: 18px; stroke-width: 3; } + +/* Form feedback and focus */ +.contact-form input:focus-visible, +.contact-form textarea:focus-visible { + outline-offset: 2px; +} + +.contact-errors:focus, +.contact-success:focus { + outline: 3px solid var(--gold); + outline-offset: 4px; +} + +.contact-form input[aria-invalid="true"], +.contact-form textarea[aria-invalid="true"] { + border: 2px solid #e5533d; +} + +.field-error { + margin: 0; + color: #ffd2c9; + font-size: 0.82rem; + font-weight: 600; +} + +.contact-form { + align-items: start; +} + +.contact-form label { + align-content: start; +} + +/* Mobile navigation and sticky call to action */ +.nav-toggle, +.sticky-cta { + display: none; +} + +[id] { + scroll-margin-top: 90px; +} + +@media (max-width: 840px) { + .has-js .nav-shell { + min-height: 72px; + grid-template-columns: 1fr auto auto; + padding-block: 8px; + } + + .has-js .nav-toggle { + width: 48px; + height: 48px; + display: inline-grid; + place-items: center; + padding: 0; + border: 1px solid rgba(5, 47, 79, 0.18); + background: var(--white); + cursor: pointer; + } + + .nav-toggle-bars, + .nav-toggle-bars::before, + .nav-toggle-bars::after { + width: 22px; + height: 2px; + display: block; + background: var(--navy); + content: ""; + transition: transform 180ms ease, background-color 180ms ease; + } + + .nav-toggle-bars { + position: relative; + } + + .nav-toggle-bars::before, + .nav-toggle-bars::after { + position: absolute; + left: 0; + } + + .nav-toggle-bars::before { top: -7px; } + .nav-toggle-bars::after { top: 7px; } + + .nav-toggle[aria-expanded="true"] .nav-toggle-bars { + background: transparent; + } + + .nav-toggle[aria-expanded="true"] .nav-toggle-bars::before { + transform: translateY(7px) rotate(45deg); + } + + .nav-toggle[aria-expanded="true"] .nav-toggle-bars::after { + transform: translateY(-7px) rotate(-45deg); + } + + .has-js .site-nav { + position: absolute; + top: 100%; + right: 0; + left: 0; + display: none; + flex-direction: column; + justify-content: flex-start; + gap: 0; + overflow: visible; + padding: 4px 20px 14px; + border-bottom: 1px solid rgba(5, 47, 79, 0.1); + background: var(--white); + box-shadow: 0 18px 30px rgba(5, 47, 79, 0.12); + } + + .has-js .site-nav.is-open { + display: flex; + } + + .has-js .site-nav a { + padding: 15px 0; + border-bottom: 1px solid var(--line); + font-size: 1rem; + } + + .has-js .site-nav a:last-child { + border-bottom: 0; + } + + .has-js .site-nav a::after { + display: none; } } @media (max-width: 700px) { - .contact-form { - grid-template-columns: 1fr; + .has-js .nav-shell > .button { + display: none; + } + + .has-js .nav-shell { + grid-template-columns: 1fr auto; + } + + body { + padding-bottom: 84px; + } + + .has-js .sticky-cta { + position: fixed; + z-index: 40; + right: 0; + bottom: 0; + left: 0; + display: block; + padding: 12px 14px calc(12px + env(safe-area-inset-bottom, 0px)); + border-top: 1px solid rgba(5, 47, 79, 0.12); + background: var(--white); + box-shadow: 0 -10px 30px rgba(5, 47, 79, 0.14); + transform: translateY(110%); + transition: transform 220ms ease; } + + .has-js .sticky-cta.is-visible { + transform: translateY(0); + } + + .sticky-cta .button { + width: 100%; + } +} + +/* Privacy note and legal pages */ +.contact-privacy { + grid-column: 1 / -1; + margin: 0; + color: #c9d6dd; + font-size: 0.82rem; +} + +.contact-privacy a { + color: #f9d86e; +} + +.legal-page { + background: var(--white); +} + +.legal-shell { + max-width: 760px; +} + +.legal-shell h1 { + margin: 0; + color: var(--navy); + font-family: var(--font-display); + font-size: clamp(2.2rem, 5vw, 3.4rem); + font-weight: 800; + letter-spacing: -0.045em; + line-height: 1.08; +} + +.legal-updated { + margin: 12px 0 0; + color: var(--muted); + font-size: 0.9rem; +} + +.legal-lead { + margin: 28px 0 0; + padding: 20px 24px; + border-left: 4px solid var(--gold); + background: var(--cream); + color: var(--navy); + font-size: 1.1rem; + font-weight: 600; +} + +.legal-shell h2 { + margin: 40px 0 0; + color: var(--navy); + font-family: var(--font-display); + font-size: 1.35rem; + font-weight: 800; +} + +.legal-shell p, +.legal-shell li { + color: #334b5c; +} + +.legal-shell p { + margin: 12px 0 0; +} + +.legal-shell ul { + margin: 12px 0 0; + padding-left: 22px; +} + +.legal-shell li + li { + margin-top: 6px; +} + +.legal-shell a:not(.text-link) { + color: var(--blue); + font-weight: 600; +} + +.legal-back { + margin-top: 48px; +} + +.legal-back .text-link { + color: var(--blue); +} + +.legal-shell .legal-lead { + margin-top: 28px; + color: var(--navy); +} + +.legal-shell .legal-updated { + color: var(--muted); } diff --git a/public/images/hero-postcard-1200.jpg b/public/images/hero-postcard-1200.jpg new file mode 100644 index 0000000..317b82d Binary files /dev/null and b/public/images/hero-postcard-1200.jpg differ diff --git a/public/images/hero-postcard-1200.webp b/public/images/hero-postcard-1200.webp new file mode 100644 index 0000000..c21cf32 Binary files /dev/null and b/public/images/hero-postcard-1200.webp differ diff --git a/public/images/hero-postcard-600.jpg b/public/images/hero-postcard-600.jpg new file mode 100644 index 0000000..4640f96 Binary files /dev/null and b/public/images/hero-postcard-600.jpg differ diff --git a/public/images/hero-postcard-600.webp b/public/images/hero-postcard-600.webp new file mode 100644 index 0000000..2b5dfb6 Binary files /dev/null and b/public/images/hero-postcard-600.webp differ diff --git a/public/images/og-image.jpg b/public/images/og-image.jpg new file mode 100644 index 0000000..07d9dfc Binary files /dev/null and b/public/images/og-image.jpg differ diff --git a/public/js/nav.js b/public/js/nav.js new file mode 100644 index 0000000..cbe2def --- /dev/null +++ b/public/js/nav.js @@ -0,0 +1,27 @@ +(function () { + document.documentElement.classList.add('has-js'); + + var toggle = document.querySelector('.nav-toggle'); + var nav = document.getElementById('site-nav'); + if (!toggle || !nav) return; + + function setMenu(open) { + nav.classList.toggle('is-open', open); + toggle.setAttribute('aria-expanded', String(open)); + } + + toggle.addEventListener('click', function () { + setMenu(toggle.getAttribute('aria-expanded') !== 'true'); + }); + + nav.addEventListener('click', function (event) { + if (event.target.closest('a')) setMenu(false); + }); + + document.addEventListener('keydown', function (event) { + if (event.key === 'Escape' && nav.classList.contains('is-open')) { + setMenu(false); + toggle.focus(); + } + }); +})(); diff --git a/public/robots.txt b/public/robots.txt new file mode 100644 index 0000000..ecb25fa --- /dev/null +++ b/public/robots.txt @@ -0,0 +1,4 @@ +User-agent: * +Allow: / + +Sitemap: https://postcardmojo.com/sitemap.xml diff --git a/public/sitemap.xml b/public/sitemap.xml new file mode 100644 index 0000000..3fadd5a --- /dev/null +++ b/public/sitemap.xml @@ -0,0 +1,9 @@ + + + + https://postcardmojo.com/ + + + https://postcardmojo.com/privacy + + diff --git a/public/web.config b/public/web.config index a899764..c4d5908 100644 --- a/public/web.config +++ b/public/web.config @@ -56,6 +56,12 @@ + + + + + +