Appearance
Website Rebuild Log
Document type: Website Rebuild — change log Last updated: 2026-06-03 Live at:
- Production: kayasync.com — v1.1.1, shipped 2026-06-03 (tag-triggered deploys via
git tag v*) - Staging: test.kayasync.com (noindexed, auto-deploys on push to
main)
A running log of what has been built and shipped on the public website (kayasync.com / test.kayasync.com), in chronological order. The Copy Deck defines what the site says; this page records what the site looks like and how it's structured.
All copy on the public site stays at Level 1 disclosure per NKA's brief — no architecture detail, no internal mechanism names, no banned terms.
2026-05-23 — Wave A: Bricolage Modernist design refresh
After the first NKA remediation pass, the site read as "any 2025 dark fintech site" — generic Inter / Space Grotesk typography, glowing radial orbs as the only background, repeated card grids, off-the-shelf icons. Wave A replaced the foundation with a distinctive, operational visual system.
Aesthetic direction locked: Bricolage Modernist. Swiss-influenced grid with brand warmth — think Stripe / Linear / Vercel rigor, but with route-handoff visuals and warmer accent colours that ground the site in Kaya Sync's domain. Chosen over Editorial / Warm Paper and Documentary Field after a side-by-side comparison.
What changed
| Layer | From | To |
|---|---|---|
| Display type | Space Grotesk | Bricolage Grotesque (variable, 500–800) |
| Mono accent | none | JetBrains Mono for timestamps, IDs, operational labels |
| Body type | Inter | Inter (kept — workhorse) |
| Dark surface | #05070d (cool blue-ink) | #0b0d12 (deeper, warmer) |
| Background atmosphere | Two animated radial-blur orbs (orange + teal) | Swiss dot-grid plate + brand-gradient scroll-triggered route line under nav |
| Brand accents | flat orange + teal | + data accents (#4ec38a green, #d99a3a amber) used sparingly in artefact cards only |
| Hero | Single centred column | Asymmetric 7/12 + 5/12 layout with a custom RouteBand artefact on the right |
| Section eyebrows | Plain text-brand-orange | Mono micro-caps with rule line |
New components shipped
RouteBand.astro— the hero's right-column artefact. Five labelled handoff stops on a brand-gradient route, mono timestamps, "Live" pulse indicator,CAPACITY · HANDOFFS · EVIDENCEfooter. Tells the visitor what the product is before they read a word.EvidenceCard.astro— small mock receipt-style block showingHANDOFF · 12:34, anonymised route, signed-off mark. Lives in the Field Reality section.CoordinationCard.astro—Request → Match → Confirmstack with mono timestamps and color-coded status pills. Lives in the How It Works snippet.StatBand.astro— full-width band between Problem and How It Works with three high-level figures (16 ECOWAS countries · 1 controlled pilot in preparation · 8 founding team members). Numbers count up on scroll into view.motion.ts— tiny IntersectionObserver helper, no deps, respectsprefers-reduced-motion.
Rebuilt sections
/how-it-works— 5 steps now render as a vertical journey rail. A continuous orange→teal route line connects 5 station dots, each step has a mono header (01 ── REQUEST · 08:14 [OPEN]) and a colour-coded status pill (OPEN / CAPTURED / ACTIVE / RESOLVED / VERIFIED)./technology— first tried a heavy "ops dashboard" treatment (sparklines, mock metrics, terminal-style header). Pulled back at NKA review to a clean 2-column list: brand icon + title + paragraph. Reads quiet and breathes./team— first tried a "personnel manifest" treatment (mono IDs, function classifiers, signature footer). Pulled back at NKA review to a clean grid: brand-tinted initials block + name + role + bio. No card chrome.
Footer + nav
- Footer split into 4 columns: brand block · Company (How It Works, Business Model, Technology, Team) · Partners (Pilot, Settlement, Government, Operators, Investors) · Reach us. Headings in mono micro-caps.
- Nav uses the real
/img/logo.jpgimage at top-left (matches footer treatment), and the scroll-triggered underline now carries the brand-orange → brand-teal gradient.
Behaviour preserved
- ClientRouter view transitions
- Light/dark theme persistence across navigation (
astro:before-swap) PUBLIC_IS_TESTnoindex on staging- Form pipeline via Resend (
/api/lead) - All Level-1 banned terms still return zero matches in deployed HTML
Fixes shipped alongside
- OG previews were 404-ing because
public/og/*.pngwas never generated — pointedBaseLayoutdefault at/img/logo.jpgso every social share resolves FieldRealitysection (withEvidenceCard) was orphaned — slotted into the homepage between AudienceGrid and CloudUseCase
Commits
| SHA | Message |
|---|---|
4d75dfe | Remediate site per NKA brief for Google Cloud reapplication |
2ae52bc | Wave A design rethink: Bricolage Modernist foundation |
fb836d6 | Fix OG image 404s and slot FieldReality into homepage |
2026-05-27 — v1.0.1: production cutover to kayasync.com
NKA signed off on the deployed test build. Production deploy infrastructure added and kayasync.com flipped from the legacy "Coming Soon" placeholder to the new Wave A site.
What changed
- Tag-triggered prod workflow (
.github/workflows/deploy-prod.yml): pushes tomaincontinue to auto-deploytest.kayasync.com; onlygit push origin v*triggers a production deploy. Gives every shipped version a named git tag (rollback = re-tag at an older SHA and push). - Separate prod Worker (
kayasync-website-prod) bound to bothkayasync.comandwww.kayasync.comvia Cloudflare Workers Custom Domains. The test Worker (kayasync-website-test) is untouched ontest.kayasync.com. - Build patch step in prod workflow: after
npm run build, the workflow usesjqto overwritenameandroutesin the Astro-generateddist/server/wrangler.json(Cloudflare's wrangler env blocks don't survive the @astrojs/cloudflare adapter's config-redirect, so an in-place patch is the cleanest fix). - PUBLIC_IS_TEST not set for the prod build → no
<meta name="robots" content="noindex,nofollow">, so Google can crawl. - OG images still falling back to
/img/logo.jpg(per-page OG cards still pending in Wave B).
Two false starts before the actual ship
- v1.0.0 attempt #1 failed because the workflow used
wrangler deploy --config wrangler.prod.jsonc, which disabled the Astro adapter's virtual-entry resolution (@astrojs/cloudflare/entrypoints/server). - v1.0.0 attempt #2 (after switching to
--env prod) deployed successfully but silently bound totest.kayasync.comagain — @astrojs/cloudflare doesn't materialise env-specific overrides into the generatedwrangler.json(it only lists them indefinedEnvironments), so--env prodhad nothing to apply. - v1.0.0 attempt #3 (with the jq-patch approach) failed at the custom-domain binding step:
Hostname 'kayasync.com' already has externally managed DNS records (A, CNAME, etc). Delete them first or try a different hostname.Existing DNS records from the old "Coming Soon" placeholder were intercepting the apex. - v1.0.1 — DNS cleared manually in the Cloudflare dashboard, re-tagged at the same fix commit, deployed cleanly.
Smoke checks (post-deploy, 2026-05-27)
kayasync.comandwww.kayasync.com→ 200- All 12 routes (
/,/how-it-works/,/business-model/,/team/,/technology/,/pilot-partners/,/government/,/settlement-partners/,/operators/,/investors/,/privacy/,/terms/) → 200 - Title:
Kaya Sync | From Anywhere, to Everywhere(not the legacy "Coming Soon") - Canonical:
https://kayasync.com/ - Robots meta: absent (production-correct)
- Fonts loaded: Bricolage Grotesque + Inter + JetBrains Mono
- Wave A content markers present:
route-band__frame,stat-band__num,cd-card__head,/img/logo.jpg - Banned-term grep on the deployed home HTML: zero matches
Commits
| SHA | Tag | Message |
|---|---|---|
c4461ec | v1.0.1 | Fix prod deploy: patch generated wrangler.json in workflow |
f474ee0 | — | Switch prod deploy to wrangler environments (didn't work, kept commit for history) |
76fdffc | — | Add tag-triggered production deploy to kayasync.com |
How to ship the next version
bash
# normal work on main keeps auto-deploying to test
git push origin main
# when test is approved, promote to prod
git tag v1.0.2 # bump patch / minor / major as appropriate
git push origin v1.0.2 # triggers .github/workflows/deploy-prod.yml2026-06-03 — v1.1.0: NKA round-2 form remediation
NKA flagged ahead of the Google Cloud reapplication that all partnership forms were failing on prod and that several field-level issues needed fixing. Resolved in two passes.
Priority 1 (resolved out-of-band before code)
All partnership forms on prod returned 500 "Server is not configured (no API key found)". Root cause: the v1.0.1 prod deploy created a fresh kayasync-website-prod Worker that had no RESEND_API_KEY secret — Cloudflare Worker secrets are per-worker and the test worker's secret didn't carry over. Fix: npx wrangler secret put RESEND_API_KEY --name kayasync-website-prod with the existing Resend key, run with a temporary CLOUDFLARE_API_TOKEN. Live the moment it was set, no redeploy needed.
Smoke-tested all 5 forms on prod, all 200, all 5 lead emails confirmed received.
Priority 2 (shipped as v1.1.0)
| Item | Where |
|---|---|
| Full global country list on partnership forms | Investor, Enterprise, Government, Settlement |
| African-only country dropdown on Operator (new field) | Operator |
| Phone field accepts country code (dial-code dropdown + phone input, combined to one value on submit) | All non-Operator forms |
| Operator phone unchanged (explicit NKA exception) | Operator |
| "PAYG devices" added to Partnership interest | Settlement |
| Volume label adds "(Kg)" | Enterprise |
| "Main Route" relabelled "Corridor", converted from free text to a select with the 10 Techiman corridors + "Other" | Operator |
"Other → free text" reveal pattern (paired input revealed when select = Other; merged back into parent field as "Other: <text>" on submit) | Universal — Enterprise (sector + interest_area), Settlement (institution_type), Operator (vehicle + corridor) |
Fallback support contact (cto@kayasync.com) retained in FormShell error path | All forms |
New / changed files
- New:
src/lib/countries.ts— generated from restcountries.com, exportscountries(250+),africa(54),dialCodes(name → E.164 code map) - Changed:
FormField.astro(new propsphoneWithCountryCode,revealOtherAs),FormShell.astro(JS combines code+phone and folds Other-reveal on submit),api/lead.ts(server-side no-JS fallback for both combining patterns),InvestorForm.astro,EnterpriseForm.astro,GovernmentForm.astro,SettlementForm.astro,OperatorForm.astro
Decisions taken under the brief
- Other-reveal pattern applied universally — NKA's note listed "Sector → Other reveals free text" under the Operator form, but Operator has no Sector field. Interpreted intent as the pattern, applied wherever a select has "Other" rather than adding a literal Sector field to Operator.
- Volume (Kg) applied to Enterprise only — NKA listed it under Operator but only Enterprise has the volume field. Operator users are drivers, not shippers.
- Phone country code via separate dial-code dropdown + tel input — chosen over single tel-with-pattern (too easy to skip) and country-driven auto-fill (more JS surface, edge-case prone). Combined to one
phone_or_whatsappvalue on submit so the API and email format stay unchanged.
Verification
End-to-end smoke tests on both test.kayasync.com and kayasync.com exercising every NKA item (Operator corridor reveal, Investor phone-code split, Enterprise Other-sector + Volume(Kg), Settlement PAYG, Government global country). All 10 returned 200 and landed in cto@kayasync.com inbox.
Commits
| SHA | Tag | Message |
|---|---|---|
85afa3f | v1.1.0 | Forms: NKA round-2 remediation (countries, phone codes, corridors, PAYG) |
2026-06-03 — v1.1.1: make /privacy/ and /terms/ indexable (Google-readiness audit close-out)
After v1.1.0 shipped, NKA's earlier Google-readiness memo (five technical gates that must be closed before the Google for Startups Cloud reapplication) was re-read and audited gate-by-gate. Four of the five gates were already closed by work shipped through v1.1.0; one real code issue was found and fixed in this release; the rest is on Evanson (Google Search Console + email deliverability tests).
Gate audit summary
| Gate | Status going in | Action |
|---|---|---|
| Google indexing freshness | ✅ Production serves clean content | None on our side. Evanson: set up GSC, submit sitemap, request indexing for the 8 priority URLs |
| Sitemap / canonical / staging treatment | ✅ All clean (sitemap-0.xml has only prod URLs, every priority URL canonical-tagged at apex, test still noindexed) | None |
| Form routing tested end-to-end | ✅ Done in v1.1.0 (10 smoke emails delivered to cto@ + kobby.andah@) | None |
Published email deliverability (hello@, privacy@, legal@) | ✅ MX + SPF configured (Google Workspace); ⚠️ functional test needs Evanson to send actual messages | None on code side |
| Production metadata + social previews | ✅ All 8 priority URLs have correct title / description / OG image / Twitter card | None (Wave B can later swap in per-page OG cards) |
The one real fix in this release
/privacy/ and /terms/ had noindex={true} hardcoded on their BaseLayout call — leftover from the early-draft phase when the policies weren't finalised. NKA explicitly listed both as priority diligence URLs that need to be indexed. Removed the prop from both pages; the test environment still applies noindex automatically via PUBLIC_IS_TEST=true (the shouldNoIndex = noindex || isTestEnv logic in BaseLayout.astro), so test-env behaviour is unchanged.
Versioning note
This was tagged v1.0.3 initially, then re-tagged as v1.1.1 (same commit, cleaner semver — v1.0.3 would have been a step backwards after v1.1.0). The v1.0.3 tag was deleted both locally and on origin to keep the audit trail clean.
Commits
| SHA | Tag | Message |
|---|---|---|
4447777 | v1.1.1 | Make /privacy/ and /terms/ indexable |
Verification (post-deploy)
bash
curl -sL https://kayasync.com/privacy/ | grep -E '<meta name="robots"' # expect EMPTY
curl -sL https://kayasync.com/terms/ | grep -E '<meta name="robots"' # expect EMPTY
curl -sL https://test.kayasync.com/privacy/ | grep -E '<meta name="robots"' # expect noindex,nofollowAll three confirmed in this state on 2026-06-03.
Still on Evanson (no code, blocks Google reapplication)
- Google Search Console: add property → verify (DNS TXT or Workspace) → submit
https://kayasync.com/sitemap-index.xml→ URL Inspection → Request Indexing for each of the 8 priority URLs. - Email deliverability: send self-tests to
hello@kayasync.com,privacy@kayasync.com,legal@kayasync.com. Set up as Workspace aliases oncto@if any bounce. - (Optional) add a DMARC TXT record for outbound deliverability hygiene. Not blocking for Google.
Once GSC has crawled and emails are confirmed deliverable, Google for Startups Cloud reapplication can be submitted.
What's next (not yet shipped)
- Wave B — custom illustrations. 5–6 spot illustrations to replace generic icons in the key narrative slots (hero, problem, how-it-works steps, field reality, settlement, team). Drafted as Gemini prompts, integrated as inline SVG.
- Per-page OG images. Replace the logo-as-fallback with proper per-page OG cards that match the new visual system. Drop them into
public/og/and restore the per-pageogImageprops. - Brand mark refresh. Out of scope for Wave A; revisit if Wave B alone doesn't lift the visual signal enough.
Cross-references
- Copy Deck (Sign-Off Draft) — the source of truth for what each page says
- Privacy Policy (Draft) · Terms of Service (Draft)
- Hosting & Data Plan — covers the platform stack; the public site sits inside the "Edge / public surface" layer