Overview / home
The default landing view. App shell (light mist sidebar, light main), top bar with page title + search + account chip + the one sunset CTA, a four-up KPI row, and the day's lead feed. The active nav item is the only sunset moment in the chrome; the "Request reviews" CTA is the one glowing element in the body.
Full shell: Overview
Components: .wv-shell · .wv-stat (+ sparkline) · .wv-listrow · .wv-badge · .wv-btn--primary. Data props: businessName, kpis[], leads[], plan.
call Leads
34
arrow_upward 22% vs last monthsupport_agent Calls answered
100%
arrow_upward Monty caught 9star Reviews
4.9
arrow_upward 6 new this monthtrending_up Avg rank
#3.2
arrow_upward Up 2 spots (lower = better)bolt Today's leads
Sample dataverified Your site

Front desk handled 3 calls
while you were on a job
Tap Leads to read what they asked and what got booked.
KPI stat card: anatomy
Single card. Data props: label, icon, value, delta (up=sage / down=coral / flat=muted), spark[]. Sparkline is inline SVG in the locked palette.
call Leads
34
arrow_upward 22%cancel_presentation Bounce
31%
arrow_downward 5% (down is good)schedule Avg reply
12s
remove Steadypaid Booked value
$5.4k
arrow_upward 18%Charts
Hand-drawn inline SVG, no chart library, no script. Locked chart style: sunset is the primary series, sage the secondary comparison, navy #222F3E for axis + labels, soft --light gridlines, rounded bar ends. One loud series per chart; everything else stays quiet. Every chart carries a "Sample data" tag.
show_chart Leads over time
Sample databar_chart Calls per day
Sample datadonut_large Lead source split
Sample dataformat_list_numbered Keyword rank
Sample dataLeads table
The full leads view. Reuses .wv-table (rounded outer frame, flat inner rows, hover highlight) with sortable-look headers, status pills, and a per-row action. Clicking a row opens the lead detail drawer (next section).
Components: .wv-table · .wv-badge (status) · .wv-btn--tertiary. Data props: columns[], rows[], sortKey.
Lead detail drawer
The slide-over that opens from a lead row. Contact block (tap-to-call / tap-to-email), an activity timeline (newest first, hot events flagged sunset), a call-recording affordance, and a notes field. Shown statically here over a dimmed scrim so the catalog renders it without script.
Components: drawer scaffold + .wv-badge · .wv-input · .wv-btn--primary. Data props: lead{}, timeline[], recordingUrl, notes.
Reviews widget
Aggregate score, star rating, recent reviews (labeled sample data), and the one-tap "Request a review" action that fires the review-request sequence. The sunset CTA is the single loud moment.
Components: .dx-stars · .wv-card · .wv-btn--primary. Data props: avg, count, reviews[].
star Your reviews
Sample dataforum Recent
Sample data"Booked in two minutes from their site. Place looks brand new. Booking again."
"Called after hours, got a text right back and a slot the next morning. Easy."
"Great clean. Would have liked a reminder text the day before, otherwise perfect."
Keyword / rank widget Tier 2
The keyword dashboard, Tier 2 only. Each tracked keyword shows its current rank, a trend arrow (up = climbing, green; down = slipping, coral), and a sunset progress bar where a longer bar means a better position. Plain-language framing: the client reads "where you show up," not SEO jargon.
Components: .dx-kw rows + trend arrows. Data props: keywords[] (term, rank, trend, volume).
trending_up Where you show up on Google
Sample dataAI Front Desk panel Tier 2
The Tier 2 value-add, translated to plain benefit. Not "AI" as a feature. It is "answered while you worked." The panel shows a real transcript preview (a missed call Monty caught and booked), the on/off toggle, and a running count. Light mist surface, sunset for the AI's own replies. The client reads outcomes, not a chatbot.
Components: .dx-ai · .dx-toggle (CSS-only) · .dx-bubble · Monty. Data props: enabled, transcript[], caughtCount.

Monty answered while you worked
Missed call · 7:48 PM · booked
toggle_on Front desk
support_agent Caught this month
23 calls & chats
arrow_upward 9 booked into jobs · sample dataBookings / calendar widget
Upcoming jobs and a mini month strip. Days with a job carry a quiet sage dot; today is the one sunset moment. The list reads as a plain schedule, not a calendar app.
Components: .dx-monthstrip · .dx-booking · .wv-badge. Data props: month, daysWithJobs[], upcoming[].
calendar_month June
Sample dataevent_upcoming Today's jobs
Sample dataBilling / invoice card
Plan, next charge, and the invoice history, Stripe-style and read-only. Month-to-month, no contracts (the offer). The plan badge reflects Tier 1 or Tier 2; the price traces to the locked pricing.
Components: .wv-card · .wv-badge--sunset · .dx-inv rows · .wv-btn--secondary. Data props: plan, price, nextCharge, invoices[].
States
The states that separate a 6/10 product from an 8/10 one. Empty (Monty, never a cold "no data"), loading skeleton (token-driven shimmer, CSS-only), error (Monty, "we're on it"), and the offline / install affordances.
Empty state
Component: .wv-empty + Monty. One warm line, one action. Never "0 results."

No leads yet. Here's what happens next.
Your site is live and getting found. The first lead lands right here. Want to kick things off with a review request?
Loading skeleton
Component: .dx-skel, token-driven shimmer, CSS-only (wv-shimmer keyframe), respects reduced-motion. Mirrors the real layout's shape.
Error state
Component: .wv-empty + Monty + .wv-btn--secondary. Reassuring, not alarming. We own the problem.

Something broke. We're on it.
Your dashboard hit a snag loading this. Nothing's lost, and our team's already been pinged. Give it a moment and try again.
Offline & install (PWA)
Components: .dx-offline (mist pill, amber icon) · .dx-pwa (dashed sunset border). Connection + add-to-home affordances.
Mobile dashboard
The client checks this on a phone between jobs. The shell collapses to stacked cards with a fixed bottom nav; the same KPIs, the same lead feed, the same sunset CTA. This is where most clients actually live.
Components: phone frame + .dx-mini-stat · .wv-listrow · .dx-phone__nav. Same tokens, responsive collapse.

Monty caught 3 calls
while you were out