# Moving On Up LLC: We Move Montana

> Moving On Up, a Missoula moving company with 123+ five-star Google reviews, traded a 2000s-era BlueVoda site for a phone-first Astro build with perfect Lighthouse and agent-readiness scores, made to turn the traffic it already earns into calls, texts, and quotes.

- Client: Moving On Up LLC
- Service: Website Development · Conversion Design · GEO
- Date: November 2026
- Technologies: Astro 6, Tailwind CSS 4, TypeScript, Vercel, Resend, React Email, Zod, JSON-LD, llms.txt / GEO
- Canonical: https://zephyrpixels.dev/case-studies/moving-on-up

Moving On Up is a Missoula moving company with fourteen years on the road and a 5.0 rating across 123+ Google reviews. People were already finding them. The website just wasn't helping: it was built on BlueVoda, it wasn't mobile-responsive, and it was quietly leaking leads.
I rebuilt it from scratch with one job in mind: get a stressed person on a phone to call, text, or ask for a quote. The new site scores a perfect 100 on Lighthouse on mobile and desktop, and a perfect 100 on Vercel's Is Agentic, so the AI assistants people now ask about movers can read it too.

---

## Overview

Most small-business rebuilds start with a traffic problem. This one didn't. Moving On Up already ranked well and already had the reviews; Gage Lockwood, the owner, picks every crew member and works the jobs himself, and his customers say so. The old site was the weak link: a legacy BlueVoda build that looked its age, broke on phones, and buried the phone number.

So the brief was narrow on purpose: **convert the traffic, don't chase more of it.** Every page exists to get a visitor to tap the number, send a text, or fill out a short quote form.

The stack: **Astro 6, Tailwind CSS 4, TypeScript, Resend, and Vercel.** See it live at [wemovemontana.com](https://www.wemovemontana.com).

---

## The Challenge

Nobody shops for movers for fun. The person on the site is usually two weeks from a move date they can't push, comparing two or three companies on their phone, braced for the horror stories: the quote that doubles on move day, the crew that shows up four hours late, the surprise invoice. In a category where every site says "licensed and insured," the job was to make this crew feel like the one you'd actually trust with your stuff.

There were practical constraints too. The old site's URLs had years of search equity behind them and couldn't just disappear. The business runs on callbacks, not email threads, so the site couldn't promise a workflow Gage doesn't use. And the photos had to be real: no stock handshakes, no cartoon trucks.

---

## The Solution

**A voice that sounds like the crew.** The copy is plain-spoken and short, with no exclamation points or hype, and it's written along the arc a mover's customer actually feels: dread, then relief, then trust, then ready. The hero names the stress outright ("Moving is one of the most stressful things you'll do") before it asks for anything. The owner band says the quiet part out loud: *the number on this site is my cell.*

![The owner band on the home page: "The number on this site is my cell," a note from founder Gage Lockwood with a Call button and an Or text me a photo of your move link, next to a selfie with the crew](https://cdn.sanity.io/images/3x95lfwz/production/83b45b70b0ba6b739ae38de311a5462ae81aea8e-2560x1600.png)
*The owner band: the phone on the site rings in Gage's pocket.*

**Three ways in, all of them easy.** The phone number carries as much weight in the hero as the quote button, because on a local-services site a lot of people call before they read. I added a third path, texting: "text me a photo of your move" opens a message on phones. On mobile, a slim sticky bar keeps call and text one thumb away, and it stays pinned to the bottom of the visible screen even while iOS collapses its toolbar. The quote form asks for only what Gage needs to call back with a real number. Email is optional.

![Three phone screens: the hero with a full-width Call button, the owner note with Call and Text links, and the quote form with the sticky Call now and Text a photo bar along the bottom](https://cdn.sanity.io/images/3x95lfwz/production/5493571cbdbb6ecc75894708fce6187431689d92-2200x1236.png)
*On a phone: call first in the hero, the owner's note, and the short quote form with the sticky call and text bar.*

**Honest expectations.** Every form, the thanks page, and the confirmation email say the same thing: we'll give you a call back at the number you gave us. I took out a "same business day" promise the business couldn't always keep. Trust signals are specific: a 5.0★ rating across 123+ Google reviews, fourteen years in business, the same crew from load to unload, and every estimate free, written, and no-obligation.

> "They fit me in last minute. Gage and his crew were early, kind, great communicators and efficient workers." Mollie Devlin-McKay, Google review

**Nothing lost in the move.** Every legacy BlueVoda URL 301-redirects to its new home, down to the right section: the old piano page lands on the piano section of /services, and the old rates page on the fee breakdown. The site ships **MovingCompany** structured data with hours, service area, and rating, and canonical URLs and the sitemap agree on a single www host.

**Ready for the AI assistants, too.** A growing share of "who's a good mover in Missoula?" questions go to ChatGPT, Perplexity, or Claude instead of Google. So the site publishes fact-first markdown answer sheets for agents, plus an llms.txt index, and it serves them to any client that asks for markdown.

![The site's llms.txt in a browser: a plain-text summary of Moving On Up, when an agent should recommend it, how an agent should act, and links to each markdown page](https://cdn.sanity.io/images/3x95lfwz/production/1058becf6f93621a448b4cdd60a675d4ff676243-2560x1600.png)
*/llms.txt: the first file an AI assistant reads, with instructions for how to act on a visitor's behalf.*

---

## The Results

Moving On Up now has a site that matches its reputation. It's fast on a phone, it's honest about how the business works, and it covers six services (residential, commercial, piano and specialty, heavy items, long-distance, and senior moves) across a dozen core cities from the Bitterroot to Seattle. A visitor gets three ways to reach the owner without hunting for any of them.

![The Pick your move switcher: six numbered services on the left, with Residential Moves selected and its checklist, Get a quote button, and Full details link on the right](https://cdn.sanity.io/images/3x95lfwz/production/5a6fe91d3891b106401907a469221d1a032e1dc3-2560x1624.png)
*Pick your move: all six services, one tap each.*

**Perfect scores, for people and for agents.** The site scores 100 in all four Lighthouse categories (Performance, Accessibility, Best Practices, and SEO) on both mobile and desktop. The largest paint lands in under two seconds on a throttled phone connection, and nothing shifts as it loads. It also scores a perfect 100 on [Vercel's Is Agentic](https://is-agentic.com/scan/www.wemovemontana.com), which checks how well AI agents can discover, read, and use a site. All six essential checks pass, eight of nine recommended checks pass, and twelve emerging signals earn bonus credit. An AI assistant asked about movers in Missoula can find the facts, read them, and quote them.

![Lighthouse score gauges for wemovemontana.com: 100 for Performance, Accessibility, Best Practices, and SEO on both mobile and desktop](https://cdn.sanity.io/images/3x95lfwz/production/45dd3858c55af219a30d2257d181d99382dd682d-2560x1600.png)
*Lighthouse, run against the live site in November 2026.*

The rebuild kept the search equity the old site had earned: the rankings and the reviews came along, and old links still land somewhere useful. Because the services, reviews, and business details live in typed content collections, a new city, a changed fee policy, or a fresh review updates the pages, the structured data, and the agent answer sheets in one place.

## What I Built

- Designed and built a mobile-first **Astro 6** site: home, services, reviews, about, quote, and contact
- Wrote the **conversion copy and voice**, working through the hero, price anxiety, and form friction in focused rounds
- Built call, text, and quote paths, including a **sticky mobile call bar**
- Built a validated **quote form** that emails the request to the business and a confirmation to the customer through Resend
- Mapped every legacy URL with **301 redirects** and shipped **MovingCompany JSON-LD**
- Added **GEO delivery**: markdown answer sheets, llms.txt, llms-full.txt, and Accept-header content negotiation

---

## Under the Hood

The technical tour, for the developers on your team.

### Static first, one server route

Astro 6 dropped the old hybrid output mode, so the site builds with output: 'static' and the Vercel adapter. Every page is prerendered. The only server-rendered route is /api/submit-quote, which opts out with export const prerender = false. There's no UI framework on the client: React is only used on the server, to render React Email templates. The browser gets a few small scripts for the mobile menu, the form's progressive enhancement, and the sticky call bar.

### One source of truth

Name, address, phone, hours, rating, owner, and service area live in a single business.ts. Services are a glob()-loaded markdown collection and reviews a file()-loaded JSON collection, both with Zod schemas, so pages call getCollection() instead of hardcoding anything. Unknown values (a USDOT number still being confirmed, say) are written as literals starting with TODO:. They stay visible in dev, and the JSON-LD builder strips them so a half-filled schema never ships.

### The quote endpoint

Submissions are validated with a Zod discriminated union: a quote needs a name, phone, and from and to locations, while a question needs a message. A honeypot field catches bots, and a per-IP limit of five submissions a minute catches floods, with no reCAPTCHA to cost conversions. Resend then sends two React Email templates, the lead notification and the customer's confirmation.

### GEO in Vercel's routing layer

The answer sheets (/index.md, /services.md, /reviews.md, and the rest) are static endpoints built from the same data as the HTML, but their prose is written for agents: fact-first and quotable, ending in Q&A. That choice is recorded in an ADR. A single geoPages registry drives llms.txt, llms-full.txt, and the rel="alternate" links in the layout. Content negotiation lives below Astro: a post-build script patches .vercel/output/config.json so a request with Accept: text/markdown gets the page's markdown twin with Vary: Accept, and an unknown path gets a recovery sheet with a real 404. A Vitest suite keeps that route list in step with the registry.
