The living proposal. Built page by page from an honest read of the whole suite — what exists, what's dead weight, what to build next. Grows every pass.
v7 · 2026-08-06 · full-suite census: 49 pages walked · per-page detail: blueprint-annex.html · companion: wiring-map.html (flows, holes, APIs, perf)Alan's steer, morning 2026-08-06: the graveyard and orphan items are QUESTIONS, not decisions. Rule adopted: a "zero inbound links" finding from the automated walk is a HYPOTHESIS — before ANY page is archived, retired, promoted, or rewired, it gets a human click-through: walk it like a user and confirm nothing still presents itself as wired (a redirect, a switcher entry, a hardcoded ref, a path the graph missed can all still point at it). Everything in §7 stays drafted-only until Alan eyeballs and click-confirms. And one canonical question is now formally OPEN: which VERSION of the plant library is final — the walk observed at least three candidates (the plant_master table behind /api/plant-library; a separate plant_library table that home.html's count strip reads; the old external Netlify plant DB) and that choice determines what gets wired into everything else. It goes to whoever built the library and the report pages — not decided here. SITREP on the spine; the front is the active lane, the graveyard is parked.
The four 404 front-page tiles fixed (today / new-lead / properties / procurement were branch-only) · sun-sweep's dead nav link off the retired hub · rentals rates date-stamped with a confirm-by-phone note · the status board bannered as a dated hand-authored snapshot. Plus the walk itself: this blueprint, the 51-page annex, and the wiring map — every page of the suite read cold, receipted on the spine.
P5-1 public-site hero fix (§3 — a two-minute commit) · review.html retire-vs-fill (§4 — recommend retire-from-nav now) · library pagination (§5) · map ?mid= parameterization (§6) · files.html seed merge + lost-adds recovery sweep (§6) · the §7 items — plan.html / workspace.html / proposal.html / the 10-page graveyard — are HELD as questions per the morning ruling (row 259), pending Alan's click-through. Each non-held item is one small reversible commit with the exact path written out.
The Google review link for rev.html's GOOGLE_REVIEW_URL — the single highest-value review fix in the suite (completes an already-working flow) · the three review-platform profile URLs if you choose fill over retire (§4) · the launcher call — index.html (the hub every device opens) still doesn't link home.html, so the new front door stays invisible until the one-line swap or a tile · the standing gates: URT-DATA-01 (unlocks persistence + the staged P1 migration), the E2E sweep roll, and the doc-wall share · NEW: the plant-library version check-in — which library is canonical, answered with its builders (§0 ruling card).
| Page | State | The one thing |
|---|---|---|
| urth-report | SOLID | THE live client report — the standard the rest measure against |
| brain (registry/est/jobs) | SOLID | Engine half real; estimate persists nowhere; 3 disagreeing schedules |
| site-marks | SOLID | Great field tool whose data nothing reads; saves photos on every tap |
| library · designer · sun-sweep · sun3d · 3d · massing · client-map · client-file | SOLID | Live tools; library unpaginated (plan in §5); sun-sweep's hub link fixed 2026-08-06; massing reachable only via report (held question, §7) |
| suppliers · rentals · files · reviews-inbox · rev · doc + 4 reference guides | SOLID | rev is the real review capture; rentals rates date-stamped 2026-08-06; files seed-loss = the key-bump ritual (corrected read + plan in §6) |
| home · today · new-lead · properties · procurement · wiring-map | SOLID | New front layer — 404s fixed this pass (were branch-only) |
| status | HALF | Hand-drawn "live/planned" claims that drift silently — banner + date added 2026-08-06; still not generated |
| action-plan | HALF | Device-local (localStorage), June-era seed, no sync, no consumers |
| proposal | HALF | Client deliverable running on the RETIRED P01–P13 demo data — held question, §7 (row 259) |
| workspace | ORPHAN | Fully built all-in-one — held question, §7 (row 259) |
| plan | ORPHAN | The richest plan surface (flags + standing requests) — held question, §7 (row 259) |
| ingest | STUB | One hardcoded address, base64 photos in localStorage, reaches nothing |
| card · tree-sources | STUB | card bypassed by .vcf redirects; tree-sources = useful diagnostic, invisible |
| report · property-report | LEGACY | Report v1/v2 lineage — walker's read: superseded by urth-report (held, §7) |
| reports (supplier sourcing) | LEGACY | 37KB, "updated automatically" is false — walker's read: superseded by suppliers (held, §7) |
| hub · brochure_v2 · review | LEGACY | hub redirected; brochure on demo data; review still in switcher with 4 PLACEHOLDER links live — decision in §4 |
| exec-summary · orlando ×3 · steward | LEGACY | Hand-authored June snapshots presenting stale claims as current (held, §7) |
Full per-page blocks — role, links, data, state, top issue for all 51 surfaces — live in the annex.
Graph health: no missing-file links after this run's 404 fix · functional broken buttons: review.html's four placeholder URLs (LawnStarter / Angi / Yelp / the Zelle tip link — all four confirmed live on main, see §4) + rev.html's empty GOOGLE_REVIEW_URL · sun-sweep's hub link fixed 2026-08-06 · index.html (the PWA home) does not link home.html yet.
site_marks → planting engine (existing-plants + verified per-pin sun) → estimate. The walk is the business's unfair advantage and today it reaches nothing.
Retire buildBudget()'s hardcoded mix; the engine's schedule (with its why/relaxations finally rendered) becomes the only plant list; scope table consumes it. plan.html already renders exactly this — see §7.
Estimates, leads, designer looks, action plan — everything now dying in DOM/localStorage lands in the staged P1 tables the moment the boundary call is made.
canopy_missing, light-ladder degradation, geocode-failed, overlay-failed — every silent fallback becomes a visible badge. The Q-ladder's geometry_source/missing_info fields are the destination.
Suppliers table → price book (sheet import, source+date per rate) → engine + estimate. Kills the $10-default and the 1.9 hardcoded markup.
designer/site-marks/brain via /api/c; sunat into precompute; stop shipping every photo on every tap; paginate library (exact plan in §5). One pattern, five wins.
HELD as questions per the morning ruling (row 259) — the full card with per-page walker's-read lines stays drafted in §7; nothing moves until Alan's click-through review.
review.html placeholders — decision drafted in §4 · GOOGLE_REVIEW_URL · sun-sweep's hub link fixed 2026-08-06 · My Maps hardcoded mid — plan in §6 · date-stamp rentals rates done 2026-08-06 + status board done 2026-08-06 · files.html seed data loss — corrected read + plan in §6.
On urthlandscaping.com at 390px wide, the page's only <h1> sits >1,100px down — a visitor sees a photo and no words until they scroll past a full screen and a half.
Two rules stack: .hero{height:100vh;height:100dvh} makes screen one the photo alone — zero text — and .intro{min-height:100vh; justify-content:center} then vertically centers the H1 in screen two. Net: the H1's top lands ≈1.4 viewports down (~1,150–1,250px at 390×844). The measurement matches the geometry exactly.
Append at the end of the existing <style>:
@media (max-width:760px){
.hero{ height:42vh; height:42dvh; min-height:280px; }
.intro{ min-height:0; justify-content:flex-start; padding:40px 6vw 64px; }
}
Result at 390×844: the photo ends ≈354px, the eyebrow lands ≈395px, and the H1's top sits ≈430px — brand, tagline, and the Request-a-Quote button all on screen one, even with Safari's collapsed 664px viewport. Desktop is untouched (a full-bleed hero is a defensible desktop choice — shortening it there too is Alan's call). Spec only this pass — the walk is read-only; landing it is a two-minute copy-level commit on the urth-website repo when Alan nods.
A genuinely good copy-once, post-everywhere flow: the client writes their review once, taps a platform button, the page copies their words to the clipboard and opens that platform — paste & post. Fully built, nice UX. But every destination is a placeholder on main: YOUR_LAWNSTARTER_PROFILE, YOUR_ANGI_ID, YOUR_YELP_ID, and the gold Tip-the-team button's YOUR_ZELLE_OR_CHASE_LINK (the earlier tip-link removal landed on the branch, not main — all four are live broken buttons today). A fifth button, Google, is honestly disabled as "coming soon". And the app switcher on every page carries this as "Reviews" — one tap from anywhere to four buttons that go nowhere.
One line in apps.js: swap the switcher entry {n:'Reviews', u:'review.html'} → {n:'Reviews inbox', u:'reviews-inbox.html'}. Nav then reaches the review surface that actually works — the internal inbox reading urth_reviews, with capture staying rev.html via the NFC tap redirect. review.html is NOT deleted: still reachable by URL, ready to return.
What's lost while retired: the only surface that pushes happy clients to public platforms (LawnStarter/Angi/Yelp). Honestly: that flow has never worked — the buttons are placeholders — so nothing working is lost, and four broken buttons leave the daily nav. Rollback = revert the one line.
The page works the moment these are real: (1) LawnStarter profile URL → the go('https://www.lawnstarter.com/…') button · (2) Angi company ID → angi.com/companyprofile/… · (3) Yelp business ID → yelp.com/writeareview/biz/… · plus either a real payment link for the tip button or deleting the tip block.
The precondition no edit can route around: those profiles have to exist. If URTH has no LawnStarter/Angi/Yelp business profile yet, there is nothing to fill — creating them is the actual task, and it's a business task, not a code one.
Retire the tile today (nav shows only working things; the inbox becomes the visible surface), keep review.html in the wings, and restore it filled when the platform profiles are real. Separately and regardless of A/B: filling rev.html's empty GOOGLE_REVIEW_URL is the single highest-value review fix in the suite — it completes an already-working capture flow (tap → stars → 5★ → straight to Google) and needs only the Google review link. Nothing was changed this pass — no placeholder filled, no file deleted, no switcher edit; both options are one small reversible commit on your word.
render() rebuilds the ENTIRE grid on every change: grid.innerHTML = rows.map(card).join('') — all ~454 cards at once on load, and again on every keystroke in the search box (q.oninput = render). Images are lazy but the DOM build/layout of 454 cards is the cost. Everything else — spot logic, ten filters, modal — is sound.
(1) Keep the filtered result in a module var; render only FILTERED.slice(0, shown) — first page 24 cards (even rows at 2/3/4 columns; identical mechanism to procurement's 20). (2) A "Load more" button after the grid appends the next slice via insertAdjacentHTML — no full rebuild. (3) ANY filter/segment/search change resets to page one (procurement's applyFilter rule). (4) The count line becomes "showing 24 of 213 matches · 454 in library"; the survive/thrive read-line keeps computing over the FULL dataset — its truth doesn't change. (5) 150ms debounce on the search input — kills the per-keystroke rebuild. Untouched: card markup, modal (_i indexing unaffected — it indexes DATA, not the rendered slice), spot logic, filters, API call, offline fallback. First-paint DOM drops ~95% (454 → 24 cards). Rollback = revert one commit.
Status: STAGED — no code shipped. It's a surgical edit inside the live library page (not an additive new file like the shell pages), so it ships on Alan's nod, not on an overnight pass.
Defect (from source): the Google My Maps document id mid=1bQu0vtv0AXkjdjZ3hKDlTyOyk7FJJTY is hardcoded in THREE places — the map-list link, the embed-header "Open in Google" link, and the iframe src. Only that one My Map can ever show; any other document Alan builds is unreachable from the suite.
The plan: give the three elements ids (mymapsLink, mymapsOpen, mymapsFrame) and add a six-line script before </body>: var MID = new URLSearchParams(location.search).get('mid') || '1bQu0vtv0AXkjdjZ3hKDlTyOyk7FJJTY'; then set both hrefs to /maps/d/viewer?mid=+MID and the iframe to /maps/d/embed?mid=+MID. Zero behavior change with no param; any other My Map becomes reachable as map.html?mid=<id>. End-state when there's more than one document: a small named list of maps rendered as rows (and DB-driven under R3). Rollback = revert. STAGED — no code shipped (surgical edit in a live page).
Correction to the census: the current code is better than the walk's one-liner claimed. A migrate() already runs on every load and appends missing seed items non-destructively — user adds survive seed edits as long as the storage key never changes. The REAL loss mechanism is the key-bump ritual itself: the key is urth_files_v29 — twenty-nine bumps of history — and every bump orphans everything under the old key, user adds included. Second defect: migrate() matches seed items by URL, so a seed item whose URL changes needs a hand-written remap (the nursery-capture pdf→xlsx→Sheet special-case in the code is the scar tissue).
The plan: (1) Freeze the key — urth_files_v29 is permanent, commented "never bump; migrate() owns seed changes". (2) Stable id (slug) on every SEED item; migrate() upserts by id — new ids appended, changed seed fields (url/kind/name) updated in place, user-added items (no id) never touched; the URL-matching hack dies. (3) Optional RETIRED=[ids] list so removed seed items can actually leave the list. (4) One-time recovery sweep: scan localStorage for older urth_files_v* keys and merge in any user-added items not already present — the adds lost to past bumps are likely STILL SITTING in localStorage under old keys on Alan's devices, recoverable for free. (5) End-state under R3: the list belongs in a table once URT-DATA-01 opens persistence — localStorage stays per-device forever otherwise. No deletes anywhere; rollback = revert. STAGED — no code shipped.
Morning ruling (spine 259): everything in this section is a HYPOTHESIS from the automated link-graph walk, held pending a human click-through — nothing moves, nothing archives, nothing rewires until Alan walks each page like a user and confirms nothing still points at it (redirects, switcher entries, hardcoded refs, paths the graph missed). The recommendations below stand as the walker's read, not verdicts.
What it uniquely does (read cold): the only surface in the suite that renders the planting engine's REASONING — the full schedule with a per-plant "why" and evidence badges (native / wildlife / UF-IFAS / researched), the engine's logged relaxations ("design budget relaxed to avoid a bare spot — which rung, where"), the hardiness-data caveat, the standing requests from the Designer session, a how-it's-built spec, and a raw-JSON link. brain.html and urth-report embed the plan image; none of this reasoning is visible anywhere else. It is the live prototype of proposal R2 ("the engine's schedule with its why/relaxations finally rendered").
Promote path (one small commit): a switcher entry ("Planting Plan") or a "Full plan + reasoning →" link from brain's planting section and urth-report's plan block, passing ?id= (which also retires its hardcoded default UUID in practice). Retire path: lose the only window into why the engine chose what it chose — not recommended. HELD — nothing shipped; awaits click-through.
What it is (read cold): a fully built four-section all-in-one — Site Analysis (sun/height/slope/scorch images + live numbers), Design (designer/library links + inline plan), Deliverables (report, 3D, CAD), Client (a client_record editor with proposal log). Three of the four are weaker duplicates: Site Analysis ⊂ urth-report; Design duplicates designer + plan.html (without the reasoning); Client duplicates client-file.html — and dangerously, it is a second write path to urth_properties.client_record (both upsert with merge-duplicates), so edits made here and there can silently overwrite each other.
The two organs to harvest before any archive: the Deliverables section is the ONLY UI door to the CAD exports — the combined blueprint SVG (/api/blueprint?sun=1) and the layered /api/dxf download appear nowhere else in the suite. HELD — nothing shipped; awaits click-through.
Live Three.js massing tool; the link-graph walk found only urth-report’s link inbound — a hypothesis pending click-through. Candidate one-liner if confirmed: add it to the apps.js switcher or link it from sun3d (the sibling 3D view).
The defect: a client-facing proposal page still linked from brain.html, but running on the RETIRED data.js P01–P13 demo system with a hardcoded app.urthlandscaping.com API base — registry UUIDs won't resolve, so opening it from a real property serves demo-or-broken content to exactly the audience that must never see it.
Retire path (one line): remove the brain.html link; urth-report.html IS the client deliverable today. Rebuild path: port to registry UUIDs + live pricing — duplicates the Proposal object already staged in the P1 record model (the Q1/Q2/Q3 ladder). HELD — nothing shipped; awaits click-through.
report.html — graph: zero inbound; superseded twice over (→ property-report → urth-report) · property-report.html — graph: zero inbound; superseded by urth-report · reports.html — graph: zero inbound; "updated automatically" claim is false; suppliers.html absorbed its notes · brochure_v2.html — graph: zero inbound; retired P01–P13 demo data · exec-summary.html — graph: zero inbound; stale snapshot · orlando ×3 — graph: zero inbound; stale June snapshots · steward.html — graph: zero inbound; overlaps action-plan · hub.html — redirected by vercel.json; last inbound fixed this run.
Per the ruling: every "zero inbound" line above is a HYPOTHESIS. Before any page moves, it gets a click-through — walked like a user, checked for anything (redirect, switcher entry, hardcoded ref, missed path) that still presents it as wired. The mechanic if confirmed remains: one reversible commit moving confirmed pages into /archive/; git history preserves everything either way. HELD — nothing moved.
Decide, don't archive (also held): ingest.html — fold its pins/zones/photos idea into site-marks, then delete the prototype · card.html — wire the .vcf subdomains here or delete · tree-sources.html — keep; promote as a dev diagnostic via the wiring map.
The same planting-engine explainer lives in TWO places: planting-report.html (a page, linked from home + index + hub) and docs-data.js's "planting-how-it-works" entry (served via doc.html?f=, linked from files.html). Two copies drift. Walker's read: the page is canonical — it has three hub inbound links; the docs-data.js entry becomes a one-line pointer to the page. One small commit when nodded; note only.
The deep plumbing read lives at wiring-map.html: per-surface wiring + 8 dead-ends (#wiring) · 11 client-trust decision holes, worst three = treetop-sun fallback, all-full-sun ladder collapse, whole-parcel canopy-off (#holes) · external-API audit incl. Perenual-isn't-real (#apis) · slow-load top 5 (#perf). This blueprint supersedes nothing there; it adds the page census + the ranked build order.