diff --git a/DEPLOYMENT.md b/DEPLOYMENT.md
index 0907d6a..876dc8f 100644
--- a/DEPLOYMENT.md
+++ b/DEPLOYMENT.md
@@ -156,11 +156,10 @@ nginx/goodwalk.co.nz.svelte.conf.example
```
Important:
-- The normal `deploy.ps1` flow does not deploy or reload the shared nginx stack.
-- Copy the updated nginx config to `/docker/nginx/conf.d/goodwalk.co.nz.conf` and reload nginx once.
-- The repo example now uses Docker's internal resolver so future app/mail container rebuilds will not leave nginx pinned to stale upstream IPs.
+- `deploy.ps1` now copies the repo nginx config to `/docker/nginx/conf.d/goodwalk.co.nz.conf` and reloads the shared nginx container as part of deployment.
+- The repo nginx config uses Docker's internal resolver so future app/mail container rebuilds will not leave nginx pinned to stale upstream IPs.
-Then reload nginx:
+Manual nginx commands, if you ever need them:
```bash
docker compose -p nginx -f /docker/nginx/docker-compose.yml exec nginx nginx -t
diff --git a/deploy.ps1 b/deploy.ps1
index c3a13b8..c36cb22 100644
--- a/deploy.ps1
+++ b/deploy.ps1
@@ -20,6 +20,10 @@ $SshConfigPath = Join-Path $LocalProjectPath 'ssh-config'
$RemoteDeploymentPath = '/docker/goodwalk-svelte'
$ComposeFileName = 'docker-compose.prod.yml'
$DockerProjectName = 'goodwalk-svelte'
+$NginxConfigSource = 'nginx/goodwalk.co.nz.svelte.conf.example'
+$NginxConfigTarget = '/docker/nginx/conf.d/goodwalk.co.nz.conf'
+$NginxComposeFile = '/docker/nginx/docker-compose.yml'
+$NginxProjectName = 'nginx'
# Optional deployment settings.
$VerifyUrl = 'https://www.goodwalk.co.nz/api/health'
@@ -161,6 +165,10 @@ Assert-NotBlank -Name 'LocalProjectPath' -Value $LocalProjectPath
Assert-NotBlank -Name 'RemoteDeploymentPath' -Value $RemoteDeploymentPath
Assert-NotBlank -Name 'ComposeFileName' -Value $ComposeFileName
Assert-NotBlank -Name 'DockerProjectName' -Value $DockerProjectName
+Assert-NotBlank -Name 'NginxConfigSource' -Value $NginxConfigSource
+Assert-NotBlank -Name 'NginxConfigTarget' -Value $NginxConfigTarget
+Assert-NotBlank -Name 'NginxComposeFile' -Value $NginxComposeFile
+Assert-NotBlank -Name 'NginxProjectName' -Value $NginxProjectName
if (-not [string]::IsNullOrWhiteSpace($Service)) {
$Service = $Service.Trim()
@@ -196,6 +204,8 @@ Write-Host "[deploy] Local project path: $LocalProjectPath"
Write-Host "[deploy] Remote deployment path: $RemoteDeploymentPath"
Write-Host "[deploy] Remote compose file: $ComposeFileName"
Write-Host "[deploy] Docker project name: $DockerProjectName"
+Write-Host "[deploy] Shared nginx config: $NginxConfigTarget"
+Write-Host "[deploy] Shared nginx compose file: $NginxComposeFile"
Write-Host "[deploy] SSH target: $sshTarget"
Write-Host "[deploy] SSH config: $SshConfigPath"
if (-not [string]::IsNullOrWhiteSpace($Service)) {
@@ -212,6 +222,7 @@ Write-Host ' - Only the top-level Goodwalk compose project will be updated.'
Write-Host ' - Legacy WordPress/onboarding compose files are not used.'
Write-Host ' - Remote .env files are preserved because they are not uploaded.'
Write-Host ' - No global Docker prune/stop/delete commands are used.'
+Write-Host ' - Shared nginx will be updated and reloaded with the Docker-DNS-based config.'
if (-not $Force) {
$confirmation = Read-Host "Type DEPLOY to continue with the remote path '$RemoteDeploymentPath'"
@@ -253,7 +264,15 @@ try {
'--compose-file',
$ComposeFileName,
'--project-name',
- $DockerProjectName
+ $DockerProjectName,
+ '--nginx-source',
+ $NginxConfigSource,
+ '--nginx-target',
+ $NginxConfigTarget,
+ '--nginx-compose-file',
+ $NginxComposeFile,
+ '--nginx-project-name',
+ $NginxProjectName
) + $(if (-not [string]::IsNullOrWhiteSpace($Service)) { @('--service', $Service) } else { @() }))
Write-Host ''
diff --git a/mail-api/main.py b/mail-api/main.py
index d9289cc..369c193 100644
--- a/mail-api/main.py
+++ b/mail-api/main.py
@@ -380,7 +380,7 @@ def client_email(data: BookingSubmission) -> str:
style="max-width:600px;width:100%;border-radius:16px;overflow:hidden;
box-shadow:0 4px 24px rgba(0,0,0,0.08);">
- {_logo_header(subtitle="Auckland’s favourite dog walking service")}
+ {_logo_header(subtitle="Professional dog walking services")}
diff --git a/package-lock.json b/package-lock.json
index e31d669..208bcfa 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -13,7 +13,7 @@
},
"devDependencies": {
"@sveltejs/adapter-node": "^5.2.11",
- "@sveltejs/kit": "^2.17.1",
+ "@sveltejs/kit": "^2.59.0",
"@sveltejs/vite-plugin-svelte": "^5.0.3",
"@testing-library/jest-dom": "^6.9.1",
"@testing-library/svelte": "^5.3.1",
@@ -1271,9 +1271,9 @@
}
},
"node_modules/@sveltejs/kit": {
- "version": "2.58.0",
- "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.58.0.tgz",
- "integrity": "sha512-kT9GCN8yJTkCK1W+Gi/bvGooWAM7y7WXP+yd+rf6QOIjyoK1ERPrMwSufXJUNu2pMWIqruhFvmz+LbOqsEmKmA==",
+ "version": "2.59.0",
+ "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.59.0.tgz",
+ "integrity": "sha512-WeJaGKvDf3uVQB4bnDHhM+BXCY34LC1v0HiPqnSpvNkjB54r8DAUP1rpk73s+5zprIirEKtUcVfgh6+fPODjzQ==",
"dev": true,
"license": "MIT",
"dependencies": {
diff --git a/package.json b/package.json
index d2867b3..2116bf5 100644
--- a/package.json
+++ b/package.json
@@ -17,7 +17,7 @@
},
"devDependencies": {
"@sveltejs/adapter-node": "^5.2.11",
- "@sveltejs/kit": "^2.17.1",
+ "@sveltejs/kit": "^2.59.0",
"@sveltejs/vite-plugin-svelte": "^5.0.3",
"@testing-library/jest-dom": "^6.9.1",
"@testing-library/svelte": "^5.3.1",
diff --git a/scripts/deploy-remote.sh b/scripts/deploy-remote.sh
index d19dd1d..858e584 100644
--- a/scripts/deploy-remote.sh
+++ b/scripts/deploy-remote.sh
@@ -6,12 +6,19 @@ DEPLOY_PATH=""
COMPOSE_FILE=""
PROJECT_NAME=""
SERVICE_NAME=""
+NGINX_SOURCE=""
+NGINX_TARGET=""
+NGINX_COMPOSE_FILE=""
+NGINX_PROJECT_NAME=""
usage() {
cat <<'EOF'
Usage:
deploy-remote.sh --archive --deploy-path --compose-file --project-name
deploy-remote.sh --archive --deploy-path --compose-file --project-name [--service ]
+ deploy-remote.sh --archive --deploy-path --compose-file --project-name \
+ [--service ] [--nginx-source ] [--nginx-target ] \
+ [--nginx-compose-file ] [--nginx-project-name ]
This script only updates the main Goodwalk compose project at the specified
deployment path. It does not touch unrelated Docker projects or global Docker
@@ -46,6 +53,22 @@ while [[ $# -gt 0 ]]; do
SERVICE_NAME="${2:-}"
shift 2
;;
+ --nginx-source)
+ NGINX_SOURCE="${2:-}"
+ shift 2
+ ;;
+ --nginx-target)
+ NGINX_TARGET="${2:-}"
+ shift 2
+ ;;
+ --nginx-compose-file)
+ NGINX_COMPOSE_FILE="${2:-}"
+ shift 2
+ ;;
+ --nginx-project-name)
+ NGINX_PROJECT_NAME="${2:-}"
+ shift 2
+ ;;
-h|--help)
usage
exit 0
@@ -66,6 +89,22 @@ fi
[[ "$DEPLOY_PATH" != "/" ]] || fail "Refusing to deploy to /"
[[ -f "$ARCHIVE_PATH" ]] || fail "Archive not found: $ARCHIVE_PATH"
+nginx_args=("$NGINX_SOURCE" "$NGINX_TARGET" "$NGINX_COMPOSE_FILE" "$NGINX_PROJECT_NAME")
+nginx_args_present=0
+for value in "${nginx_args[@]}"; do
+ if [[ -n "$value" ]]; then
+ nginx_args_present=1
+ break
+ fi
+done
+
+if (( nginx_args_present )); then
+ [[ -n "$NGINX_SOURCE" ]] || fail "--nginx-source is required when nginx deployment is enabled"
+ [[ -n "$NGINX_TARGET" ]] || fail "--nginx-target is required when nginx deployment is enabled"
+ [[ -n "$NGINX_COMPOSE_FILE" ]] || fail "--nginx-compose-file is required when nginx deployment is enabled"
+ [[ -n "$NGINX_PROJECT_NAME" ]] || fail "--nginx-project-name is required when nginx deployment is enabled"
+fi
+
if docker compose version >/dev/null 2>&1; then
COMPOSE_CMD=(docker compose)
elif command -v docker-compose >/dev/null 2>&1; then
@@ -89,6 +128,12 @@ echo "[deploy-remote] Docker project: $PROJECT_NAME"
if [[ -n "$SERVICE_NAME" ]]; then
echo "[deploy-remote] Target service: $SERVICE_NAME"
fi
+if (( nginx_args_present )); then
+ echo "[deploy-remote] Nginx config source: $NGINX_SOURCE"
+ echo "[deploy-remote] Nginx config target: $NGINX_TARGET"
+ echo "[deploy-remote] Nginx compose file: $NGINX_COMPOSE_FILE"
+ echo "[deploy-remote] Nginx project: $NGINX_PROJECT_NAME"
+fi
echo "[deploy-remote] Staging archive in: $STAGING_DIR"
mkdir -p "$DEPLOY_PATH"
@@ -171,4 +216,19 @@ if [[ -z "$SERVICE_NAME" || "$SERVICE_NAME" == "app" || "$SERVICE_NAME" == "db"
"${COMPOSE_CMD[@]}" -p "$PROJECT_NAME" -f "$COMPOSE_FILE" exec -T app node scripts/sync-homepage-content.mjs
fi
+if (( nginx_args_present )); then
+ [[ -f "$DEPLOY_PATH/$NGINX_SOURCE" ]] || fail "Nginx config missing from deployment payload: $DEPLOY_PATH/$NGINX_SOURCE"
+ [[ -f "$NGINX_COMPOSE_FILE" ]] || fail "Nginx compose file was not found on the server: $NGINX_COMPOSE_FILE"
+
+ echo "[deploy-remote] Updating shared nginx config to avoid stale container IPs"
+ mkdir -p "$(dirname "$NGINX_TARGET")"
+ cp "$DEPLOY_PATH/$NGINX_SOURCE" "$NGINX_TARGET"
+
+ echo "[deploy-remote] Validating nginx configuration"
+ "${COMPOSE_CMD[@]}" -p "$NGINX_PROJECT_NAME" -f "$NGINX_COMPOSE_FILE" exec -T nginx nginx -t
+
+ echo "[deploy-remote] Reloading shared nginx"
+ "${COMPOSE_CMD[@]}" -p "$NGINX_PROJECT_NAME" -f "$NGINX_COMPOSE_FILE" exec -T nginx nginx -s reload
+fi
+
echo "[deploy-remote] Remote deployment finished"
diff --git a/src/lib/components/IntroStrip.svelte b/src/lib/components/IntroStrip.svelte
index 8547d56..64432a8 100644
--- a/src/lib/components/IntroStrip.svelte
+++ b/src/lib/components/IntroStrip.svelte
@@ -10,9 +10,21 @@
diff --git a/src/lib/components/SuccessModal.svelte b/src/lib/components/SuccessModal.svelte
index f1c975f..4ee8c82 100644
--- a/src/lib/components/SuccessModal.svelte
+++ b/src/lib/components/SuccessModal.svelte
@@ -67,7 +67,7 @@
- In the meantime, feel free to follow along on Instagram for daily walks and happy dogs.
+ In the meantime, feel free to follow along on Instagram for daily walks and happy dogs!
diff --git a/src/lib/components/TestimonialsSection.svelte b/src/lib/components/TestimonialsSection.svelte
index 08dce18..7b5a4d4 100644
--- a/src/lib/components/TestimonialsSection.svelte
+++ b/src/lib/components/TestimonialsSection.svelte
@@ -8,9 +8,9 @@
export let testimonials: TestimonialContent[];
export let heading = 'Why people choose us!';
export let blurb =
- 'Real dogs, real routines, trusted by happy owners. Follow along on Instagram to see the Tiny Gang out on their daily adventures.';
+ "Happy owners, even happier dogs. Our Auckland dog walking clients love what the Tiny Gang brings to their dog's routine — and you can see why. Follow along on Instagram for daily adventures, wagging tails and the odd zoomie";
export let instagramHref = 'https://www.instagram.com/goodwalk.nz/';
- export let instagramLabel = '@goodwalk.nz';
+ export let instagramLabel = 'goodwalk.nz';
type TestimonialSlide = TestimonialContent & { imageUrl: string };
diff --git a/src/lib/content/homepage.ts b/src/lib/content/homepage.ts
index b827089..3c2bb69 100644
--- a/src/lib/content/homepage.ts
+++ b/src/lib/content/homepage.ts
@@ -50,8 +50,8 @@ export const homepageContent: HomePageContent = {
title: 'Happy pets,',
subtitle: 'happy humans',
body:
- 'Offering tailored pack walks for small and medium dogs, and one-on-one walks for large breeds. Our walkers give personalised attention to each dog, easing stress, anxiety and ensuring a quality experience. Our expertise in small-medium breeds ensures tailored care for their unique needs. Join our',
- emphasis: 'TINY GANG!',
+ 'Professional dog walking services in Auckland for small, medium and large breeds. Our experienced walkers provide tailored pack walks for smaller dogs and one-on-one walks for larger breeds - giving every dog the personalised attention they deserve. We specialise in understanding the unique needs of small-to-medium breeds, helping to ease stress and anxiety while keeping tails wagging. Ready to join our',
+ emphasis: 'TINY GANG?',
cta: { label: 'Book now', href: '#newlead', variant: 'green' },
imageUrl: '/images/auckland-dog-walking-happy-dogs-happy-humans.webp',
imageAlt: 'Woman cuddling a dog for Goodwalk Auckland dog walking services'
diff --git a/src/lib/styles/responsive.css b/src/lib/styles/responsive.css
index 39f193c..cc81f0d 100644
--- a/src/lib/styles/responsive.css
+++ b/src/lib/styles/responsive.css
@@ -299,6 +299,10 @@
font-size: 21px;
}
+ .intro-google-logo {
+ width: 24px;
+ }
+
#intro p {
font-size: 17px;
line-height: 1.45;
@@ -312,7 +316,7 @@
gap: 10px;
}
- #intro a {
+ .intro-trust-cta {
gap: 8px;
padding: 8px 14px;
font-size: 15px;
diff --git a/src/lib/styles/sections.css b/src/lib/styles/sections.css
index dbc56fe..cf475ba 100644
--- a/src/lib/styles/sections.css
+++ b/src/lib/styles/sections.css
@@ -67,6 +67,7 @@ section {
.intro-trust-mark {
display: inline-flex;
+ position: relative;
align-items: center;
justify-content: center;
width: 56px;
@@ -75,9 +76,50 @@ section {
background: #fff;
color: #e00706;
font-size: 24px;
+ overflow: hidden;
box-shadow: inset 0 0 0 1px rgba(14, 27, 41, 0.08);
}
+.intro-trust-mark-link {
+ text-decoration: none;
+ isolation: isolate;
+ transition:
+ transform 0.22s cubic-bezier(0.22, 1, 0.36, 1),
+ box-shadow 0.22s ease;
+}
+
+.intro-trust-mark-link::after {
+ content: '';
+ position: absolute;
+ inset: -30% 35%;
+ background: linear-gradient(120deg, transparent 0%, rgba(255, 255, 255, 0.2) 30%, rgba(255, 255, 255, 0.92) 50%, rgba(255, 255, 255, 0.2) 70%, transparent 100%);
+ transform: translateX(-220%) rotate(18deg);
+ opacity: 0;
+ pointer-events: none;
+ animation: introGoogleShine 4.8s ease-in-out infinite;
+}
+
+.intro-trust-mark-link:hover,
+.intro-trust-mark-link:focus-visible {
+ transform: translateY(-1px) scale(1.04);
+ box-shadow:
+ inset 0 0 0 1px rgba(14, 27, 41, 0.08),
+ 0 10px 24px rgba(17, 20, 24, 0.12);
+}
+
+.intro-trust-mark-link:focus-visible {
+ outline: 2px solid rgba(10, 48, 78, 0.28);
+ outline-offset: 3px;
+}
+
+.intro-google-logo {
+ display: block;
+ position: relative;
+ z-index: 1;
+ width: 28px;
+ height: auto;
+}
+
.intro-trust-copy {
min-width: 0;
}
@@ -107,7 +149,7 @@ section {
font-size: 14px;
}
-#intro a {
+.intro-trust-cta {
display: inline-flex;
align-items: center;
gap: 8px;
@@ -121,11 +163,37 @@ section {
box-shadow: inset 0 0 0 1px rgba(14, 27, 41, 0.08);
}
-#intro a .icon {
+.intro-trust-cta .icon {
color: #e00706;
font-size: 20px;
}
+@keyframes introGoogleShine {
+ 0%,
+ 64%,
+ 100% {
+ transform: translateX(-220%) rotate(18deg);
+ opacity: 0;
+ }
+
+ 72% {
+ opacity: 1;
+ }
+
+ 84% {
+ transform: translateX(220%) rotate(18deg);
+ opacity: 0;
+ }
+}
+
+@media (prefers-reduced-motion: reduce) {
+ .intro-trust-mark-link,
+ .intro-trust-mark-link::after {
+ animation: none;
+ transition: none;
+ }
+}
+
#promise,
#testimonials,
#info {
diff --git a/static/images/google-g-logo.svg b/static/images/google-g-logo.svg
new file mode 100644
index 0000000..a54eeab
--- /dev/null
+++ b/static/images/google-g-logo.svg
@@ -0,0 +1,6 @@
+
+
+
+
+
+