Files
albertandClaude Sonnet 5 661a7e060c Add k3s deployment scaffolding for dist/ on Vultr
Ships the static landing page to the existing k3s cluster at
65.20.110.165, served at www.apexturf.es (apexturf.es redirects to
it), using a self-hosted Gitea instance as the container registry.

- deploy/Dockerfile + nginx.conf: nginx:alpine image serving dist/
  (SPA-safe fallback, gzip, cache headers). Build-tested locally
  against the real dist/ output.
- deploy/k8s/apex-turf/: Namespace, Deployment, Service, and two
  Ingresses (www.apexturf.es + a Traefik Middleware redirect from
  the bare domain).
- deploy/k8s/cert-manager/: Let's Encrypt ClusterIssuers (prod +
  staging) for HTTP-01 via the cluster's bundled Traefik.
- deploy/k8s/gitea/: Helm values for a lightweight, SQLite-backed
  Gitea at git.apexturf.es with its container registry enabled.
- docs/DEPLOYMENT.md: full phased runbook with exact commands,
  troubleshooting, and a redeploy cheat sheet.
- docs/README.md: point at the new deploy/ tree and runbook.

Nothing here touches the remote cluster — these are local manifests
and docs for the user to apply themselves.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-24 20:38:03 +02:00

7.2 KiB
Raw Permalink Blame History

Apex Turf — Landing Page

A single-page marketing landing page for Apex Turf, a premium artificial-turf design & installation company (residential landscaping, pádel courts, football/multisport pitches, and golf putting greens), built with plain HTML, CSS and vanilla JavaScript — no build step, no frameworks, no dependencies.

Where things live

dist/
├── index.html              # the landing page
├── css/styles.css          # all styling (CSS variables, layout, components)
├── js/main.js               # all interactivity (vanilla JS, no dependencies)
└── assets/images/
    ├── animals/             # lion, shark, panther, eagle — hero/section imagery
    │   (compressed to ~250420KB JPEGs; originals lived in ../animals)
    └── logos/                # apexturf-logo.png (full lockup), apexturf-icon.png (mark only)
        (resized from ../logos, background-transparent variants)
docs/
├── README.md                 # this file
├── Changelog.md
├── CONTENT-SPECS.md          # all 7 pdfs/ specs archived as markdown (4 used, 2 not-yet-built, 1 duplicate)
└── DEPLOYMENT.md              # runbook: ship dist/ to the k3s cluster on Vultr
deploy/
├── Dockerfile                 # nginx:alpine serving dist/ (build context = repo root)
├── nginx.conf
└── k8s/
    ├── apex-turf/              # Namespace, Deployment, Service, Ingress (+www redirect) for the site
    ├── cert-manager/            # Let's Encrypt ClusterIssuers
    └── gitea/                   # Helm values for the self-hosted Gitea registry

To preview locally: open dist/index.html directly in a browser, or serve the folder (python3 -m http.server from inside dist/) so the favicon/font preconnects behave exactly as in production.

Design source

The three reference mockups in ../website-ideas/ (Websiteidea1.png Websiteidea3.png) all share one layout: a full-bleed, diagonally-split hero — Residential Turf (lion) fixed on the left, and a rotating Sport Turf category (Pádel/shark, Football/panther, Golf/eagle) on the right. Rather than picking one mockup, the landing page combines all three: the hero's right pane auto-rotates through Pádel → Football → Golf every 6 seconds (with manual P/F/G tabs, pause-on-hover/focus), so every specialty shown across the three reference images is represented on one page.

Copy, section structure, and messaging (headlines, value pillars, "Installers First, Not Salesmen", the Apex Guarantee, etc.) are drawn from the four sport-specific and About Us page specifications in ../pdfs/, condensed from full dedicated pages into single-page sections since this build is one landing page rather than a multi-page site. The full content of all 7 PDFs (../pdfs/ has 8 files, but two golf specs are identical duplicates) is archived as markdown in CONTENT-SPECS.md — including the two specs that describe pages not built here: a gated "Maintenance Handbook" lead-magnet page, and a 3-step turf project/sample-request questionnaire meant to replace the current one-screen quote form. Both are noted as follow-up work in that file.

Page structure

  1. Header — logo, nav (Home / Landscaping / Pádel / Football / Golf / About Us), sticky on scroll, hamburger menu on mobile.
  2. Hero — split diagonal layout as above.
  3. Value pillars — Child & Family Safe, Pet-Friendly, Built for Spanish Weather, Low Maintenance (not no maintenance).
  4. Specialties grid — 4 quick-nav cards (Landscaping / Pádel / Football / Golf) linking to detail sections below.
  5. Detail sections ×4 — one per specialty, alternating image/text layout, each with its own feature list and CTA, matching the messaging of the corresponding PDF spec.
  6. About — "Master Installers. Absolute Precision." trust section with the two Apex Guarantee cards.
  7. Showcase/Gallery — a 4-image visual recap of the specialties (not client project photos — there were none supplied; swap in real installation photography here when available).
  8. Contact / quote form — front-end-only form (name, email, phone, project type, message) with client-side validation and a success message. There is no backend — see "What still needs wiring up" below.
  9. Footer — logo, quick links, contact info, social icons.

Notable implementation details

  • No build tooling. Plain CSS with custom properties for the palette/spacing scale; plain ES5-ish vanilla JS (one IIFE, no bundler needed).
  • Self-contained interactivity: sticky header, mobile nav, hero tab rotation, scroll-spy nav highlighting, scroll-reveal animations, smooth-scroll with header offset, back-to-top button, and the quote form — all in js/main.js, no external libraries.
  • Grid-blowout defense: every grid-template-columns track uses minmax(0, …fr) rather than a bare fr. A bare fr track's implicit auto minimum can exceed the container's padded content box and force horizontal overflow — this was caught during testing (see Changelog) and fixed everywhere as a standing defensive pattern, not just on the section where it first showed up.
  • Scroll-reveal never gets stuck hidden: the fade-in-on-scroll effect (.reveal.is-visible) is wrapped in try/catch with a 2.5s safety-net timeout that force-reveals everything, and a <noscript> rule shows everything immediately if JavaScript is unavailable.
  • prefers-reduced-motion is respected throughout (reveal animations, hero auto-rotation, and smooth scrolling all fall back to instant/static behavior).
  • Accessibility basics: semantic landmarks, aria-label/aria-expanded on the nav toggle, role=tab / aria-selected on the hero sport tabs, alt text on every image, visible focus states inherited from default UA styles (not suppressed).
  • Images were re-compressed (JPEG quality ~72, resized logo PNGs) from the originals in ../animals and ../logos to keep total page weight reasonable (~1.5MB of images total).

What still needs wiring up before going live

This is a front-end-only deliverable. Before launch:

  • Contact form has no backend. It currently just shows a client-side "thanks" message and does not send an email or hit an API. Wire #quoteForm's submit handler in js/main.js to a real form endpoint (e.g. Formspree, a serverless function, or your own backend).
  • Placeholder contact details: phone +34 900 123 456, email hello@apexturf.com, and "Madrid, Spain" are placeholders (no real contact info was supplied) — replace with the real ones in index.html (they appear in both the Contact section and the footer). Social links (#) are also placeholders — point them at real profiles.
  • Gallery images are stand-ins. The showcase/gallery section reuses the four mascot photos for lack of real installation photography — swap in real project photos when available.
  • Two specced pages/flows aren't built at all yet (full details in CONTENT-SPECS.md):
    1. A gated "Maintenance Handbook" PDF lead-magnet page (email-capture → PDF download).
    2. A 3-step turf project/sample-request questionnaire meant to eventually replace the current single-screen #quoteForm, with supplier-webhook and CRM routing.