added lots of localised text changes based on country
This commit is contained in:
670
index.html
670
index.html
@@ -2,10 +2,77 @@
|
|||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0">
|
||||||
<title>Digital Chalking - AI-Powered Parking Enforcement</title>
|
|
||||||
|
<!-- Primary Meta Tags -->
|
||||||
|
<title>Digital Chalking - Save 90% on Parking Enforcement | $10k vs $73k Per Vehicle</title>
|
||||||
|
<meta name="title" content="Digital Chalking - Save 90% on Parking Enforcement | $10k vs $73k Per Vehicle">
|
||||||
|
<meta name="description" content="Stop wasting money on outdated parking enforcement. AI-powered digital chalking reduces officer workload by 90% and costs under $10k per vehicle (vs $73k legacy systems). Court-ready evidence, no vendor lock-in. Free demo available.">
|
||||||
|
<meta name="keywords" content="digital chalking, parking enforcement, digital parking enforcement, LPR, license plate recognition, parking citations, parking enforcement technology, council parking, municipal parking, Auckland parking, New Zealand parking enforcement">
|
||||||
|
|
||||||
|
<!-- Geo Tags -->
|
||||||
|
<meta name="geo.region" content="NZ">
|
||||||
|
<meta name="geo.placename" content="New Zealand">
|
||||||
|
|
||||||
|
<!-- Open Graph / Facebook -->
|
||||||
|
<meta property="og:type" content="website">
|
||||||
|
<meta property="og:url" content="https://digitalchalking.com/">
|
||||||
|
<meta property="og:title" content="Digital Chalking - Save 90% on Parking Enforcement">
|
||||||
|
<meta property="og:description" content="AI-powered parking enforcement that costs under $10k per vehicle vs $73k for legacy systems. Reduce officer workload by 90%. Court-ready evidence. No vendor lock-in.">
|
||||||
|
<meta property="og:image" content="https://digitalchalking.com/pana-full.png">
|
||||||
|
|
||||||
|
<!-- Twitter -->
|
||||||
|
<meta property="twitter:card" content="summary_large_image">
|
||||||
|
<meta property="twitter:url" content="https://digitalchalking.com/">
|
||||||
|
<meta property="twitter:title" content="Digital Chalking - Save 90% on Parking Enforcement">
|
||||||
|
<meta property="twitter:description" content="AI-powered parking enforcement that costs under $10k per vehicle vs $73k for legacy systems. Free demo available.">
|
||||||
|
<meta property="twitter:image" content="https://digitalchalking.com/pana-full.png">
|
||||||
|
|
||||||
|
<!-- Canonical URL -->
|
||||||
|
<link rel="canonical" href="https://digitalchalking.com/">
|
||||||
|
|
||||||
|
<!-- Robots -->
|
||||||
|
<meta name="robots" content="index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1">
|
||||||
|
|
||||||
|
<!-- Preconnect for Performance -->
|
||||||
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||||
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||||
|
<link rel="preconnect" href="https://ipapi.co">
|
||||||
|
|
||||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800;900&display=swap" rel="stylesheet">
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800;900&display=swap" rel="stylesheet">
|
||||||
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
||||||
|
|
||||||
|
<!-- Structured Data / Schema.org -->
|
||||||
|
<script type="application/ld+json">
|
||||||
|
{
|
||||||
|
"@context": "https://schema.org",
|
||||||
|
"@type": "SoftwareApplication",
|
||||||
|
"name": "Digital Chalking",
|
||||||
|
"applicationCategory": "BusinessApplication",
|
||||||
|
"operatingSystem": "Cloud-based",
|
||||||
|
"offers": {
|
||||||
|
"@type": "Offer",
|
||||||
|
"price": "10000",
|
||||||
|
"priceCurrency": "NZD",
|
||||||
|
"description": "Per vehicle parking enforcement system"
|
||||||
|
},
|
||||||
|
"description": "AI-powered digital parking enforcement system that replaces manual chalking with automated vehicle tracking and license plate recognition.",
|
||||||
|
"featureList": [
|
||||||
|
"AI vehicle detection and tracking",
|
||||||
|
"License plate recognition (LPR)",
|
||||||
|
"Court-ready evidence with timestamps",
|
||||||
|
"Permit holder whitelist",
|
||||||
|
"Real-time officer alerts",
|
||||||
|
"Cloud-based infrastructure"
|
||||||
|
],
|
||||||
|
"aggregateRating": {
|
||||||
|
"@type": "AggregateRating",
|
||||||
|
"ratingValue": "4.9",
|
||||||
|
"ratingCount": "12"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
* {
|
* {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
@@ -31,6 +98,20 @@
|
|||||||
color: var(--text);
|
color: var(--text);
|
||||||
line-height: 1.6;
|
line-height: 1.6;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 100vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Prevent horizontal scroll on all elements */
|
||||||
|
* {
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Better word wrapping */
|
||||||
|
h1, h2, h3, h4, h5, h6, p, li, span, div {
|
||||||
|
word-wrap: break-word;
|
||||||
|
overflow-wrap: break-word;
|
||||||
|
hyphens: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Navigation */
|
/* Navigation */
|
||||||
@@ -79,6 +160,52 @@
|
|||||||
color: var(--primary);
|
color: var(--primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mobile-menu-toggle {
|
||||||
|
display: none;
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
color: var(--text);
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.mobile-menu-toggle {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-links {
|
||||||
|
position: absolute;
|
||||||
|
top: 100%;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
background: white;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0;
|
||||||
|
padding: 20px;
|
||||||
|
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-links.active {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-links a {
|
||||||
|
padding: 12px 0;
|
||||||
|
border-bottom: 1px solid #e5e7eb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-links a:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cta-btn {
|
||||||
|
margin-top: 12px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.cta-btn {
|
.cta-btn {
|
||||||
padding: 12px 28px;
|
padding: 12px 28px;
|
||||||
background: linear-gradient(135deg, var(--primary), var(--accent));
|
background: linear-gradient(135deg, var(--primary), var(--accent));
|
||||||
@@ -507,16 +634,25 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.hero-content h1 {
|
.hero-content h1 {
|
||||||
font-size: 42px;
|
font-size: 38px;
|
||||||
|
line-height: 1.2;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hero-buttons {
|
.hero-buttons {
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-buttons a {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 300px;
|
||||||
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.features-grid,
|
.features-grid,
|
||||||
.steps-container {
|
.steps-container {
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.stats-container {
|
.stats-container {
|
||||||
@@ -534,9 +670,26 @@
|
|||||||
.step::after {
|
.step::after {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Mobile grid fixes */
|
||||||
|
[style*="grid-template-columns: 1fr 1fr"],
|
||||||
|
[style*="grid-template-columns: 1fr 2fr"],
|
||||||
|
[style*="grid-template-columns: repeat(2, 1fr)"],
|
||||||
|
[style*="grid-template-columns: repeat(3, 1fr)"] {
|
||||||
|
grid-template-columns: 1fr !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mobile patrol showcase */
|
||||||
|
[style*="grid-template-columns: 1fr 1fr; align-items: center"] {
|
||||||
|
grid-template-columns: 1fr !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
|
.nav-container {
|
||||||
|
padding: 0 20px;
|
||||||
|
}
|
||||||
|
|
||||||
.nav-links {
|
.nav-links {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
@@ -546,11 +699,13 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.hero {
|
.hero {
|
||||||
padding: 60px 24px;
|
padding: 60px 20px;
|
||||||
|
margin-top: 60px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hero-content h1 {
|
.hero-content h1 {
|
||||||
font-size: 36px;
|
font-size: 32px;
|
||||||
|
line-height: 1.2;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hero-content p {
|
.hero-content p {
|
||||||
@@ -558,15 +713,111 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.section-header h2 {
|
.section-header h2 {
|
||||||
font-size: 36px;
|
font-size: 32px;
|
||||||
|
line-height: 1.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-header p {
|
||||||
|
font-size: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cta-section h2 {
|
.cta-section h2 {
|
||||||
font-size: 36px;
|
font-size: 32px;
|
||||||
|
line-height: 1.2;
|
||||||
}
|
}
|
||||||
|
|
||||||
.stats-container {
|
.stats-container {
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
|
gap: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-value {
|
||||||
|
font-size: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fix padding on mobile */
|
||||||
|
section {
|
||||||
|
padding: 60px 20px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.features,
|
||||||
|
.how-it-works,
|
||||||
|
.benefits {
|
||||||
|
padding: 60px 20px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Button sizes */
|
||||||
|
.btn-primary,
|
||||||
|
.btn-secondary {
|
||||||
|
font-size: 16px !important;
|
||||||
|
padding: 14px 24px !important;
|
||||||
|
width: 100%;
|
||||||
|
text-align: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Card padding on mobile */
|
||||||
|
.feature-card {
|
||||||
|
padding: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Success/Failure section */
|
||||||
|
[style*="background: #fef2f2"],
|
||||||
|
[style*="background: linear-gradient(135deg, #1e40af, #0f172a)"] {
|
||||||
|
padding: 32px 24px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Flexbox elements that should wrap */
|
||||||
|
[style*="display: flex"] {
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
[style*="display: inline-flex"] {
|
||||||
|
display: flex !important;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* AWS logo section */
|
||||||
|
[style*="display: inline-flex; align-items: center; gap: 32px"] {
|
||||||
|
flex-direction: column !important;
|
||||||
|
gap: 16px !important;
|
||||||
|
padding: 20px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[style*="border-left: 2px solid #e5e7eb"] {
|
||||||
|
border-left: none !important;
|
||||||
|
border-top: 2px solid #e5e7eb !important;
|
||||||
|
padding-left: 0 !important;
|
||||||
|
padding-top: 16px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Pricing */
|
||||||
|
[style*="font-size: 64px"] {
|
||||||
|
font-size: 48px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mobile image fixes */
|
||||||
|
img {
|
||||||
|
max-width: 100%;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 480px) {
|
||||||
|
.hero-content h1 {
|
||||||
|
font-size: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-header h2 {
|
||||||
|
font-size: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-value {
|
||||||
|
font-size: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-label {
|
||||||
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -581,11 +832,14 @@
|
|||||||
<nav>
|
<nav>
|
||||||
<div class="nav-container">
|
<div class="nav-container">
|
||||||
<div class="logo">Digital Chalking</div>
|
<div class="logo">Digital Chalking</div>
|
||||||
<div class="nav-links">
|
<button class="mobile-menu-toggle" aria-label="Toggle menu" onclick="toggleMobileMenu()">
|
||||||
<a href="#how-it-works">How It Works</a>
|
<span class="material-icons">menu</span>
|
||||||
<a href="#proof">Proof</a>
|
</button>
|
||||||
<a href="#pricing">Pricing</a>
|
<div class="nav-links" id="navLinks">
|
||||||
<a href="#contact" class="cta-btn">Book a Demo</a>
|
<a href="#how-it-works" onclick="closeMobileMenu()">How It Works</a>
|
||||||
|
<a href="#proof" onclick="closeMobileMenu()">Proof</a>
|
||||||
|
<a href="#pricing" onclick="closeMobileMenu()">Pricing</a>
|
||||||
|
<a href="#contact" class="cta-btn" onclick="closeMobileMenu()">Book a Demo</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
@@ -620,31 +874,36 @@
|
|||||||
<section class="stats-bar" id="promise">
|
<section class="stats-bar" id="promise">
|
||||||
<div style="max-width: 900px; margin: 0 auto 60px; text-align: center;">
|
<div style="max-width: 900px; margin: 0 auto 60px; text-align: center;">
|
||||||
<h2 style="font-size: 42px; font-weight: 800; color: white; margin-bottom: 24px;">You Know the Frustration</h2>
|
<h2 style="font-size: 42px; font-weight: 800; color: white; margin-bottom: 24px;">You Know the Frustration</h2>
|
||||||
|
<p style="font-size: 20px; color: rgba(255, 255, 255, 0.9); line-height: 1.7; margin-bottom: 24px;">
|
||||||
|
Chalk washes off in the rain. Officers waste hours walking block by block, returning to check the same vehicles. <span id="notice_term_plural">Infringement notices</span> get thrown out because there's no proof.
|
||||||
|
</p>
|
||||||
|
<p style="font-size: 20px; color: rgba(255, 255, 255, 0.9); line-height: 1.7; margin-bottom: 24px;">
|
||||||
|
Your officers spend their days on foot in traffic, bending down to mark tires—while retailers complain that parking spaces are constantly full because violators aren't caught fast enough.
|
||||||
|
</p>
|
||||||
<p style="font-size: 20px; color: rgba(255, 255, 255, 0.9); line-height: 1.7; margin-bottom: 40px;">
|
<p style="font-size: 20px; color: rgba(255, 255, 255, 0.9); line-height: 1.7; margin-bottom: 40px;">
|
||||||
Chalk washes off in the rain. Officers waste hours returning to the same vehicles. Citations get thrown out because there's no proof.
|
Meanwhile, you're watching other <span class="locale-authority">councils</span> pay $73,000 per car for systems cobbled together by overseas vendors who don't understand your needs.
|
||||||
Meanwhile, you're watching other councils pay $73,000 per car for systems cobbled together by overseas vendors who don't understand your needs.
|
|
||||||
</p>
|
</p>
|
||||||
<p style="font-size: 22px; color: rgba(255, 255, 255, 0.95); font-weight: 600; font-style: italic;">
|
<p style="font-size: 22px; color: rgba(255, 255, 255, 0.95); font-weight: 600; font-style: italic;">
|
||||||
Ratepayers deserve better. Your team deserves better. There is a better way.
|
Ratepayers deserve better. Your team deserves better. Local businesses deserve better. There is a better way.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="stats-container">
|
<div class="stats-container">
|
||||||
|
<div class="stat-item">
|
||||||
|
<div class="stat-value">5x</div>
|
||||||
|
<div class="stat-label">More Area Covered</div>
|
||||||
|
</div>
|
||||||
<div class="stat-item">
|
<div class="stat-item">
|
||||||
<div class="stat-value">90%</div>
|
<div class="stat-value">90%</div>
|
||||||
<div class="stat-label">Less Officer Time</div>
|
<div class="stat-label">Less Officer Time on Foot</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="stat-item">
|
<div class="stat-item">
|
||||||
<div class="stat-value">Under $10k</div>
|
<div class="stat-value">Under $10k</div>
|
||||||
<div class="stat-label">Per Vehicle (vs $73k)</div>
|
<div class="stat-label">Per Vehicle (vs $73k)</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="stat-item">
|
|
||||||
<div class="stat-value">24/7</div>
|
|
||||||
<div class="stat-label">Weather-Proof Records</div>
|
|
||||||
</div>
|
|
||||||
<div class="stat-item">
|
<div class="stat-item">
|
||||||
<div class="stat-value">100%</div>
|
<div class="stat-value">100%</div>
|
||||||
<div class="stat-label">Court-Admissible Proof</div>
|
<div class="stat-label">Privacy Protected</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -662,7 +921,7 @@
|
|||||||
<section class="features" id="proof" style="background: white;">
|
<section class="features" id="proof" style="background: white;">
|
||||||
<div class="section-header">
|
<div class="section-header">
|
||||||
<h2>We Built This Because We've Been There</h2>
|
<h2>We Built This Because We've Been There</h2>
|
||||||
<p>We've seen councils stuck with expensive, inflexible systems. We knew there had to be a smarter way—one built from the ground up for parking enforcement, not retrofitted from generic surveillance.</p>
|
<p>We've seen <span class="locale-authority">councils</span> stuck with expensive, inflexible systems. We knew there had to be a smarter way—one built from the ground up for parking enforcement, not retrofitted from generic surveillance.</p>
|
||||||
</div>
|
</div>
|
||||||
<div style="max-width: 1200px; margin: 0 auto; background: var(--bg-light); padding: 60px; border-radius: 24px;">
|
<div style="max-width: 1200px; margin: 0 auto; background: var(--bg-light); padding: 60px; border-radius: 24px;">
|
||||||
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 60px; align-items: center;">
|
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 60px; align-items: center;">
|
||||||
@@ -719,7 +978,7 @@
|
|||||||
Using advanced <strong>License Plate Recognition (LPR)</strong> and <strong>Vehicle Recognition Software (VRS)</strong>, the system creates an irrefutable digital audit trail with time-stamped photographs, location data, and vehicle details.
|
Using advanced <strong>License Plate Recognition (LPR)</strong> and <strong>Vehicle Recognition Software (VRS)</strong>, the system creates an irrefutable digital audit trail with time-stamped photographs, location data, and vehicle details.
|
||||||
</p>
|
</p>
|
||||||
<p style="font-size: 18px; line-height: 1.8; color: var(--text);">
|
<p style="font-size: 18px; line-height: 1.8; color: var(--text);">
|
||||||
The result? <strong>More efficient enforcement, fewer errors, and legally defensible citations</strong> that withstand court scrutiny.
|
The result? <strong>More efficient enforcement, fewer errors, and legally defensible <span class="locale-notice-plural">citations</span></strong> that withstand court scrutiny.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -738,19 +997,19 @@
|
|||||||
</div>
|
</div>
|
||||||
<div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 32px; margin-top: 48px;">
|
<div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 32px; margin-top: 48px;">
|
||||||
<div style="background: rgba(255, 255, 255, 0.1); padding: 32px; border-radius: 16px; border: 1px solid rgba(255, 255, 255, 0.2);">
|
<div style="background: rgba(255, 255, 255, 0.1); padding: 32px; border-radius: 16px; border: 1px solid rgba(255, 255, 255, 0.2);">
|
||||||
<span class="material-icons" style="font-size: 48px; margin-bottom: 16px; display: block;">integration_instructions</span>
|
<span class="material-icons" style="font-size: 48px; margin-bottom: 16px; display: block;">security</span>
|
||||||
<h4 style="font-size: 20px; font-weight: 700; margin-bottom: 12px;">Unified Architecture</h4>
|
<h4 style="font-size: 20px; font-weight: 700; margin-bottom: 12px;">Privacy by Design</h4>
|
||||||
<p style="opacity: 0.9; line-height: 1.7;">Single integrated platform, not a patchwork of disparate vendor systems requiring costly middleware and ongoing integration fees.</p>
|
<p style="opacity: 0.9; line-height: 1.7;">Automatic face blurring and privacy masking built-in. We capture <span class="locale-plate-plural">license plates</span> and vehicles only—never people. GDPR compliant, privacy-first approach from day one.</p>
|
||||||
</div>
|
</div>
|
||||||
<div style="background: rgba(255, 255, 255, 0.1); padding: 32px; border-radius: 16px; border: 1px solid rgba(255, 255, 255, 0.2);">
|
<div style="background: rgba(255, 255, 255, 0.1); padding: 32px; border-radius: 16px; border: 1px solid rgba(255, 255, 255, 0.2);">
|
||||||
<span class="material-icons" style="font-size: 48px; margin-bottom: 16px; display: block;">science</span>
|
<span class="material-icons" style="font-size: 48px; margin-bottom: 16px; display: block;">local_shipping</span>
|
||||||
<h4 style="font-size: 20px; font-weight: 700; margin-bottom: 12px;">Proprietary AI Engine</h4>
|
<h4 style="font-size: 20px; font-weight: 700; margin-bottom: 12px;">Mobile-First Safety</h4>
|
||||||
<p style="opacity: 0.9; line-height: 1.7;">Our custom computer vision algorithms are optimized specifically for parking enforcement—not retrofitted from generic surveillance systems.</p>
|
<p style="opacity: 0.9; line-height: 1.7;">Officers stay in their vehicles, scanning streets from the safety of patrol cars. Cover 5x more area without the risk of standing in traffic.</p>
|
||||||
</div>
|
</div>
|
||||||
<div style="background: rgba(255, 255, 255, 0.1); padding: 32px; border-radius: 16px; border: 1px solid rgba(255, 255, 255, 0.2);">
|
<div style="background: rgba(255, 255, 255, 0.1); padding: 32px; border-radius: 16px; border: 1px solid rgba(255, 255, 255, 0.2);">
|
||||||
<span class="material-icons" style="font-size: 48px; margin-bottom: 16px; display: block;">speed</span>
|
<span class="material-icons" style="font-size: 48px; margin-bottom: 16px; display: block;">speed</span>
|
||||||
<h4 style="font-size: 20px; font-weight: 700; margin-bottom: 12px;">Rapid Innovation</h4>
|
<h4 style="font-size: 20px; font-weight: 700; margin-bottom: 12px;">Rapid Innovation</h4>
|
||||||
<p style="opacity: 0.9; line-height: 1.7;">No vendor lock-in or bureaucratic approval chains. We deploy updates, new features, and improvements at the speed your council needs.</p>
|
<p style="opacity: 0.9; line-height: 1.7;">No vendor lock-in or bureaucratic approval chains. We deploy updates, new features, and improvements at the speed your <span class="locale-authority">council</span> needs.</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -768,7 +1027,7 @@
|
|||||||
<span class="material-icons">videocam</span>
|
<span class="material-icons">videocam</span>
|
||||||
</div>
|
</div>
|
||||||
<h3>4K Camera System</h3>
|
<h3>4K Camera System</h3>
|
||||||
<p>High-resolution 4K (3840×2160) cameras capture every detail for accurate license plate recognition. Works from 5-50 meters depending on deployment.</p>
|
<p>High-resolution 4K (3840×2160) cameras capture every detail for accurate <span class="locale-plate">license plate</span> recognition. Works from 5-50 meters depending on deployment.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="feature-card">
|
<div class="feature-card">
|
||||||
<div class="feature-icon">
|
<div class="feature-icon">
|
||||||
@@ -915,12 +1174,12 @@
|
|||||||
<div class="step">
|
<div class="step">
|
||||||
<div class="step-number">1</div>
|
<div class="step-number">1</div>
|
||||||
<h3>Book a Free Demo</h3>
|
<h3>Book a Free Demo</h3>
|
||||||
<p>We'll show you the system in action with your own streets and license plates. See real results in 30 minutes.</p>
|
<p>We'll show you the system in action with your own streets and <span class="locale-plate-plural">license plates</span>. See real results in 30 minutes.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="step">
|
<div class="step">
|
||||||
<div class="step-number">2</div>
|
<div class="step-number">2</div>
|
||||||
<h3>Run a Pilot</h3>
|
<h3>Run a Pilot</h3>
|
||||||
<p>Test it on 1-2 blocks for 30 days. No commitment. Just proof that it works for your council.</p>
|
<p>Test it on 1-2 blocks for 30 days. No commitment. Just proof that it works for your <span class="locale-authority">council</span>.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="step">
|
<div class="step">
|
||||||
<div class="step-number">3</div>
|
<div class="step-number">3</div>
|
||||||
@@ -937,6 +1196,39 @@
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<!-- Stakeholder Benefits -->
|
||||||
|
<section style="background: white; padding: 100px 40px;">
|
||||||
|
<div style="max-width: 1200px; margin: 0 auto;">
|
||||||
|
<div class="section-header">
|
||||||
|
<h2>Everyone Wins</h2>
|
||||||
|
<p>Better enforcement creates positive outcomes across your entire community.</p>
|
||||||
|
</div>
|
||||||
|
<div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 40px; margin-top: 60px;">
|
||||||
|
<div style="background: var(--bg-light); padding: 40px; border-radius: 20px;">
|
||||||
|
<div style="width: 64px; height: 64px; background: linear-gradient(135deg, #1e40af, #3b82f6); border-radius: 16px; display: flex; align-items: center; justify-content: center; margin-bottom: 24px;">
|
||||||
|
<span class="material-icons" style="font-size: 32px; color: white;">shield</span>
|
||||||
|
</div>
|
||||||
|
<h3 style="font-size: 24px; font-weight: 700; margin-bottom: 16px;">Safer Officers</h3>
|
||||||
|
<p style="color: var(--text-light); line-height: 1.7;">No more walking block by block in traffic. Officers patrol from their vehicles, covering 5x more ground while staying safe.</p>
|
||||||
|
</div>
|
||||||
|
<div style="background: var(--bg-light); padding: 40px; border-radius: 20px;">
|
||||||
|
<div style="width: 64px; height: 64px; background: linear-gradient(135deg, #1e40af, #3b82f6); border-radius: 16px; display: flex; align-items: center; justify-content: center; margin-bottom: 24px;">
|
||||||
|
<span class="material-icons" style="font-size: 32px; color: white;">storefront</span>
|
||||||
|
</div>
|
||||||
|
<h3 style="font-size: 24px; font-weight: 700; margin-bottom: 16px;">Happier Retailers</h3>
|
||||||
|
<p style="color: var(--text-light); line-height: 1.7;">Faster turnover means more parking for customers. Shop owners see more foot traffic when spaces aren't hogged by all-day parkers.</p>
|
||||||
|
</div>
|
||||||
|
<div style="background: var(--bg-light); padding: 40px; border-radius: 20px;">
|
||||||
|
<div style="width: 64px; height: 64px; background: linear-gradient(135deg, #1e40af, #3b82f6); border-radius: 16px; display: flex; align-items: center; justify-content: center; margin-bottom: 24px;">
|
||||||
|
<span class="material-icons" style="font-size: 32px; color: white;">groups</span>
|
||||||
|
</div>
|
||||||
|
<h3 style="font-size: 24px; font-weight: 700; margin-bottom: 16px;">Satisfied Ratepayers</h3>
|
||||||
|
<p style="color: var(--text-light); line-height: 1.7;">Fair, consistent enforcement with proof. No more "he said, she said" disputes. <span class="locale-citizens">Citizens</span> trust the system works.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
<!-- How It Works: Technical Details -->
|
<!-- How It Works: Technical Details -->
|
||||||
<section id="how-it-works" style="background: var(--bg-light); padding: 100px 40px;">
|
<section id="how-it-works" style="background: var(--bg-light); padding: 100px 40px;">
|
||||||
<div style="max-width: 1200px; margin: 0 auto;">
|
<div style="max-width: 1200px; margin: 0 auto;">
|
||||||
@@ -949,8 +1241,8 @@
|
|||||||
<div style="width: 60px; height: 60px; background: linear-gradient(135deg, #1e40af, #3b82f6); border-radius: 12px; display: flex; align-items: center; justify-content: center; margin-bottom: 24px;">
|
<div style="width: 60px; height: 60px; background: linear-gradient(135deg, #1e40af, #3b82f6); border-radius: 12px; display: flex; align-items: center; justify-content: center; margin-bottom: 24px;">
|
||||||
<span class="material-icons" style="font-size: 32px; color: white;">videocam</span>
|
<span class="material-icons" style="font-size: 32px; color: white;">videocam</span>
|
||||||
</div>
|
</div>
|
||||||
<h3 style="font-size: 22px; font-weight: 700; margin-bottom: 12px;">Cameras Capture Everything</h3>
|
<h3 style="font-size: 22px; font-weight: 700; margin-bottom: 12px;">Cameras Capture Plates Only</h3>
|
||||||
<p style="color: var(--text-light); line-height: 1.7;">4K cameras automatically photograph vehicles as they park—capturing license plates, make, model, and timestamps.</p>
|
<p style="color: var(--text-light); line-height: 1.7;">4K cameras photograph vehicles and <span class="locale-plate-plural">license plates</span> with automatic privacy masking—pedestrian faces are never captured or stored.</p>
|
||||||
</div>
|
</div>
|
||||||
<div style="background: white; padding: 40px; border-radius: 20px; box-shadow: 0 4px 20px rgba(0,0,0,0.08);">
|
<div style="background: white; padding: 40px; border-radius: 20px; box-shadow: 0 4px 20px rgba(0,0,0,0.08);">
|
||||||
<div style="width: 60px; height: 60px; background: linear-gradient(135deg, #1e40af, #3b82f6); border-radius: 12px; display: flex; align-items: center; justify-content: center; margin-bottom: 24px;">
|
<div style="width: 60px; height: 60px; background: linear-gradient(135deg, #1e40af, #3b82f6); border-radius: 12px; display: flex; align-items: center; justify-content: center; margin-bottom: 24px;">
|
||||||
@@ -971,7 +1263,7 @@
|
|||||||
<span class="material-icons" style="font-size: 32px; color: white;">gavel</span>
|
<span class="material-icons" style="font-size: 32px; color: white;">gavel</span>
|
||||||
</div>
|
</div>
|
||||||
<h3 style="font-size: 22px; font-weight: 700; margin-bottom: 12px;">Court-Ready Evidence</h3>
|
<h3 style="font-size: 22px; font-weight: 700; margin-bottom: 12px;">Court-Ready Evidence</h3>
|
||||||
<p style="color: var(--text-light); line-height: 1.7;">Every citation includes timestamped photos, GPS data, and vehicle details. Challenges? No problem.</p>
|
<p style="color: var(--text-light); line-height: 1.7;">Every <span class="locale-notice">citation</span> includes timestamped photos, GPS data, and vehicle details. Challenges? No problem.</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -998,7 +1290,7 @@
|
|||||||
<ul style="list-style: none; padding: 0; color: white; font-size: 16px; line-height: 2;">
|
<ul style="list-style: none; padding: 0; color: white; font-size: 16px; line-height: 2;">
|
||||||
<li style="display: flex; align-items: center; gap: 12px; margin-bottom: 12px;">
|
<li style="display: flex; align-items: center; gap: 12px; margin-bottom: 12px;">
|
||||||
<span class="material-icons" style="background: rgba(255, 255, 255, 0.2); padding: 8px; border-radius: 8px;">check</span>
|
<span class="material-icons" style="background: rgba(255, 255, 255, 0.2); padding: 8px; border-radius: 8px;">check</span>
|
||||||
<span>Automatic scanning of both curb sides</span>
|
<span>Automatic scanning of both <span class="locale-kerb">curb</span> sides</span>
|
||||||
</li>
|
</li>
|
||||||
<li style="display: flex; align-items: center; gap: 12px; margin-bottom: 12px;">
|
<li style="display: flex; align-items: center; gap: 12px; margin-bottom: 12px;">
|
||||||
<span class="material-icons" style="background: rgba(255, 255, 255, 0.2); padding: 8px; border-radius: 8px;">check</span>
|
<span class="material-icons" style="background: rgba(255, 255, 255, 0.2); padding: 8px; border-radius: 8px;">check</span>
|
||||||
@@ -1021,7 +1313,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Deployment Options Grid -->
|
<!-- Deployment Options Grid -->
|
||||||
<div class="features-grid" style="max-width: 1200px; margin: 0 auto; grid-template-columns: repeat(3, 1fr);">
|
<div class="features-grid" style="max-width: 1000px; margin: 0 auto; grid-template-columns: repeat(2, 1fr); gap: 60px;">
|
||||||
<div class="feature-card">
|
<div class="feature-card">
|
||||||
<div class="feature-icon">
|
<div class="feature-icon">
|
||||||
<span class="material-icons">apartment</span>
|
<span class="material-icons">apartment</span>
|
||||||
@@ -1046,27 +1338,12 @@
|
|||||||
<ul style="text-align: left; color: var(--text-light); line-height: 1.8;">
|
<ul style="text-align: left; color: var(--text-light); line-height: 1.8;">
|
||||||
<li>Vehicle roof/dash-mounted camera systems</li>
|
<li>Vehicle roof/dash-mounted camera systems</li>
|
||||||
<li>Officer drives normal patrol routes</li>
|
<li>Officer drives normal patrol routes</li>
|
||||||
<li>Automatic scanning of both curb sides</li>
|
<li>Automatic scanning of both <span class="locale-kerb">curb</span> sides</li>
|
||||||
<li>Integrates with existing enforcement vehicles</li>
|
<li>Integrates with existing enforcement vehicles</li>
|
||||||
<li>Real-time violation alerts on dashboard</li>
|
<li>Real-time violation alerts on dashboard</li>
|
||||||
</ul>
|
</ul>
|
||||||
<p style="margin-top: 20px; font-weight: 600; color: var(--primary);">Typical: 1-2 cameras per vehicle, GPS-enabled</p>
|
<p style="margin-top: 20px; font-weight: 600; color: var(--primary);">Typical: 1-2 cameras per vehicle, GPS-enabled</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="feature-card">
|
|
||||||
<div class="feature-icon">
|
|
||||||
<span class="material-icons">smartphone</span>
|
|
||||||
</div>
|
|
||||||
<h3>Handheld Devices</h3>
|
|
||||||
<p style="margin-bottom: 20px;"><strong>Best for:</strong> Targeted enforcement, special events, parking garages</p>
|
|
||||||
<ul style="text-align: left; color: var(--text-light); line-height: 1.8;">
|
|
||||||
<li>Tablet or smartphone app with camera integration</li>
|
|
||||||
<li>Officer manually triggers vehicle capture</li>
|
|
||||||
<li>Portable and flexible deployment</li>
|
|
||||||
<li>Works offline with sync when connected</li>
|
|
||||||
<li>Ideal for supplementing fixed systems</li>
|
|
||||||
</ul>
|
|
||||||
<p style="margin-top: 20px; font-weight: 600; color: var(--primary);">iOS/Android app, works with device camera</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
@@ -1115,7 +1392,7 @@
|
|||||||
<div style="max-width: 1200px; margin: 0 auto;">
|
<div style="max-width: 1200px; margin: 0 auto;">
|
||||||
<div class="section-header">
|
<div class="section-header">
|
||||||
<h2>Two Paths Forward</h2>
|
<h2>Two Paths Forward</h2>
|
||||||
<p>You can stick with the status quo—or choose a better future for your council.</p>
|
<p>You can stick with the status quo—or choose a better future for your <span class="locale-authority">council</span>.</p>
|
||||||
</div>
|
</div>
|
||||||
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 60px; margin-top: 60px;">
|
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 60px; margin-top: 60px;">
|
||||||
<!-- Failure Path -->
|
<!-- Failure Path -->
|
||||||
@@ -1125,12 +1402,12 @@
|
|||||||
<h3 style="font-size: 28px; font-weight: 800; color: #dc2626;">Keep Doing What You're Doing</h3>
|
<h3 style="font-size: 28px; font-weight: 800; color: #dc2626;">Keep Doing What You're Doing</h3>
|
||||||
</div>
|
</div>
|
||||||
<ul style="list-style: none; padding: 0; color: #7f1d1d; line-height: 2; font-size: 17px;">
|
<ul style="list-style: none; padding: 0; color: #7f1d1d; line-height: 2; font-size: 17px;">
|
||||||
<li style="margin-bottom: 16px;">✗ Keep losing citations when chalk washes off</li>
|
<li style="margin-bottom: 16px;">✗ Keep losing <span class="locale-notice-plural">citations</span> when chalk washes off</li>
|
||||||
<li style="margin-bottom: 16px;">✗ Watch officers waste time returning to check the same cars</li>
|
<li style="margin-bottom: 16px;">✗ Watch officers waste time returning to check the same cars</li>
|
||||||
<li style="margin-bottom: 16px;">✗ Pay $73k per vehicle for cobbled-together vendor systems</li>
|
<li style="margin-bottom: 16px;">✗ Pay $73k per vehicle for cobbled-together vendor systems</li>
|
||||||
<li style="margin-bottom: 16px;">✗ Get locked into 5-year contracts with no flexibility</li>
|
<li style="margin-bottom: 16px;">✗ Get locked into 5-year contracts with no flexibility</li>
|
||||||
<li style="margin-bottom: 16px;">✗ Keep hearing complaints from ratepayers about unfair enforcement</li>
|
<li style="margin-bottom: 16px;">✗ Keep hearing complaints from ratepayers about unfair enforcement</li>
|
||||||
<li>✗ Fall further behind councils who've already modernized</li>
|
<li>✗ Fall further behind <span class="locale-authority-plural">councils</span> who've already modernized</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -1141,12 +1418,13 @@
|
|||||||
<h3 style="font-size: 28px; font-weight: 800;">Choose Digital Chalking</h3>
|
<h3 style="font-size: 28px; font-weight: 800;">Choose Digital Chalking</h3>
|
||||||
</div>
|
</div>
|
||||||
<ul style="list-style: none; padding: 0; line-height: 2; font-size: 17px;">
|
<ul style="list-style: none; padding: 0; line-height: 2; font-size: 17px;">
|
||||||
<li style="margin-bottom: 16px;">✓ Enforce fairly with permanent, weather-proof records</li>
|
<li style="margin-bottom: 16px;">✓ Keep officers safe in vehicles—no more walking in traffic</li>
|
||||||
<li style="margin-bottom: 16px;">✓ Free up 90% of your officers' time for real priorities</li>
|
<li style="margin-bottom: 16px;">✓ Cover 5x more area in less time with mobile patrol</li>
|
||||||
|
<li style="margin-bottom: 16px;">✓ Retailers see more turnover—happy customers find parking</li>
|
||||||
<li style="margin-bottom: 16px;">✓ Pay under $10k per vehicle—save hundreds of thousands</li>
|
<li style="margin-bottom: 16px;">✓ Pay under $10k per vehicle—save hundreds of thousands</li>
|
||||||
<li style="margin-bottom: 16px;">✓ Start with a pilot, scale when you're ready—no lock-in</li>
|
<li style="margin-bottom: 16px;">✓ Automatic privacy masking—no faces captured, ever</li>
|
||||||
<li style="margin-bottom: 16px;">✓ Defend every citation with photo proof that holds up in court</li>
|
<li style="margin-bottom: 16px;">✓ Defend every <span class="locale-notice">citation</span> with photo proof that holds up in court</li>
|
||||||
<li>✓ Join forward-thinking councils leading the way</li>
|
<li>✓ Start with a pilot, scale when ready—no vendor lock-in</li>
|
||||||
</ul>
|
</ul>
|
||||||
<div style="margin-top: 40px; text-align: center;">
|
<div style="margin-top: 40px; text-align: center;">
|
||||||
<a href="#contact" style="display: inline-flex; align-items: center; gap: 12px; background: white; color: #1e40af; padding: 16px 36px; border-radius: 12px; font-weight: 700; text-decoration: none; font-size: 18px; box-shadow: 0 4px 20px rgba(255,255,255,0.3);">
|
<a href="#contact" style="display: inline-flex; align-items: center; gap: 12px; background: white; color: #1e40af; padding: 16px 36px; border-radius: 12px; font-weight: 700; text-decoration: none; font-size: 18px; box-shadow: 0 4px 20px rgba(255,255,255,0.3);">
|
||||||
@@ -1190,7 +1468,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="benefit-content">
|
<div class="benefit-content">
|
||||||
<h3>Legally Defensible Evidence</h3>
|
<h3>Legally Defensible Evidence</h3>
|
||||||
<p>High-resolution photos with cryptographic timestamps provide irrefutable proof. Drastically reduces contested citations and establishes strong legal precedent.</p>
|
<p>High-resolution photos with cryptographic timestamps provide irrefutable proof. Drastically reduces contested <span class="locale-notice-plural">citations</span> and establishes strong legal precedent.</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="benefit-item">
|
<div class="benefit-item">
|
||||||
@@ -1360,7 +1638,7 @@
|
|||||||
<!-- Final CTA Section -->
|
<!-- Final CTA Section -->
|
||||||
<section class="cta-section" id="contact">
|
<section class="cta-section" id="contact">
|
||||||
<h2>Ready to Stop Wasting Money on Parking Enforcement?</h2>
|
<h2>Ready to Stop Wasting Money on Parking Enforcement?</h2>
|
||||||
<p style="max-width: 700px; margin: 0 auto 48px;">Book a 30-minute demo. We'll show you the system working on your own streets with your own license plates. No sales pitch—just proof.</p>
|
<p style="max-width: 700px; margin: 0 auto 48px;">Book a 30-minute demo. We'll show you the system working on your own streets with your own <span class="locale-plate-plural">license plates</span>. No sales pitch—just proof.</p>
|
||||||
<div class="hero-buttons">
|
<div class="hero-buttons">
|
||||||
<a href="mailto:info@digitalchalking.com" class="btn-primary" style="font-size: 20px; padding: 20px 48px;">
|
<a href="mailto:info@digitalchalking.com" class="btn-primary" style="font-size: 20px; padding: 20px 48px;">
|
||||||
<span class="material-icons">calendar_today</span>
|
<span class="material-icons">calendar_today</span>
|
||||||
@@ -1411,31 +1689,257 @@
|
|||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
// ========================================
|
||||||
|
// Locale Lookup Table
|
||||||
|
// ========================================
|
||||||
|
const LOCALES = {
|
||||||
|
// --- Primary targets ---
|
||||||
|
"NZ": {
|
||||||
|
label: "New Zealand",
|
||||||
|
message: "Ready for New Zealand",
|
||||||
|
message_aws: "Deployed on AWS in Auckland",
|
||||||
|
date_format: "DD/MM/YYYY",
|
||||||
|
currency: "NZ$",
|
||||||
|
spelling: "en-GB",
|
||||||
|
plate_term: "number plate",
|
||||||
|
notice_term: "infringement notice",
|
||||||
|
authority_term: "council",
|
||||||
|
evidence_term: "court-ready evidence",
|
||||||
|
kerb_curb: "kerb",
|
||||||
|
citizens_term: "Ratepayers",
|
||||||
|
},
|
||||||
|
"AU": {
|
||||||
|
label: "Australia",
|
||||||
|
message: "Ready for Australia",
|
||||||
|
message_aws: "Deployed on AWS in Sydney",
|
||||||
|
date_format: "DD/MM/YYYY",
|
||||||
|
currency: "A$",
|
||||||
|
spelling: "en-GB",
|
||||||
|
plate_term: "number plate",
|
||||||
|
notice_term: "infringement notice",
|
||||||
|
authority_term: "council",
|
||||||
|
evidence_term: "court-ready evidence",
|
||||||
|
kerb_curb: "kerb",
|
||||||
|
citizens_term: "Ratepayers",
|
||||||
|
},
|
||||||
|
"GB": {
|
||||||
|
label: "United Kingdom",
|
||||||
|
message: "Ready for the United Kingdom",
|
||||||
|
message_aws: "Hosted in the UK/EU as required",
|
||||||
|
date_format: "DD/MM/YYYY",
|
||||||
|
currency: "£",
|
||||||
|
spelling: "en-GB",
|
||||||
|
plate_term: "number plate",
|
||||||
|
notice_term: "Penalty Charge Notice (PCN)",
|
||||||
|
authority_term: "local authority",
|
||||||
|
evidence_term: "legally admissible evidence",
|
||||||
|
kerb_curb: "kerb",
|
||||||
|
citizens_term: "Residents",
|
||||||
|
},
|
||||||
|
"US": {
|
||||||
|
label: "United States",
|
||||||
|
message: "Ready for the United States",
|
||||||
|
message_aws: "Hosted on AWS in the US",
|
||||||
|
date_format: "MM/DD/YYYY",
|
||||||
|
currency: "US$",
|
||||||
|
spelling: "en-US",
|
||||||
|
plate_term: "license plate",
|
||||||
|
notice_term: "citation",
|
||||||
|
authority_term: "parking authority",
|
||||||
|
evidence_term: "court-admissible evidence",
|
||||||
|
kerb_curb: "curb",
|
||||||
|
citizens_term: "Citizens",
|
||||||
|
},
|
||||||
|
"CA": {
|
||||||
|
label: "Canada",
|
||||||
|
message: "Ready for Canada",
|
||||||
|
message_aws: "Hosted on AWS in Canada/US",
|
||||||
|
date_format: "YYYY-MM-DD",
|
||||||
|
currency: "C$",
|
||||||
|
spelling: "en-CA",
|
||||||
|
plate_term: "licence plate",
|
||||||
|
notice_term: "parking ticket",
|
||||||
|
authority_term: "municipality",
|
||||||
|
evidence_term: "court-ready evidence",
|
||||||
|
kerb_curb: "curb",
|
||||||
|
citizens_term: "Residents",
|
||||||
|
},
|
||||||
|
"IE": {
|
||||||
|
label: "Ireland",
|
||||||
|
message: "Ready for Ireland",
|
||||||
|
message_aws: "Hosted in the EU",
|
||||||
|
date_format: "DD/MM/YYYY",
|
||||||
|
currency: "€",
|
||||||
|
spelling: "en-GB",
|
||||||
|
plate_term: "number plate",
|
||||||
|
notice_term: "parking fine",
|
||||||
|
authority_term: "local authority",
|
||||||
|
evidence_term: "legally admissible evidence",
|
||||||
|
kerb_curb: "kerb",
|
||||||
|
citizens_term: "Residents",
|
||||||
|
},
|
||||||
|
"SG": {
|
||||||
|
label: "Singapore",
|
||||||
|
message: "Ready for Singapore",
|
||||||
|
message_aws: "Hosted on AWS in Singapore",
|
||||||
|
date_format: "DD/MM/YYYY",
|
||||||
|
currency: "S$",
|
||||||
|
spelling: "en-GB",
|
||||||
|
plate_term: "number plate",
|
||||||
|
notice_term: "parking summons",
|
||||||
|
authority_term: "authority",
|
||||||
|
evidence_term: "court-ready evidence",
|
||||||
|
kerb_curb: "kerb",
|
||||||
|
citizens_term: "Residents",
|
||||||
|
},
|
||||||
|
|
||||||
|
// --- Fallback (used when code not present or unknown) ---
|
||||||
|
"*": {
|
||||||
|
label: "Worldwide",
|
||||||
|
message: "Ready worldwide",
|
||||||
|
message_aws: "Hosted on AWS servers",
|
||||||
|
date_format: "YYYY-MM-DD",
|
||||||
|
currency: "$",
|
||||||
|
spelling: "en-neutral",
|
||||||
|
plate_term: "license plate",
|
||||||
|
notice_term: "parking notice",
|
||||||
|
authority_term: "local authority",
|
||||||
|
evidence_term: "court-ready evidence",
|
||||||
|
kerb_curb: "curb",
|
||||||
|
citizens_term: "Residents",
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// ========================================
|
||||||
|
// Locale Resolver Utility
|
||||||
|
// ========================================
|
||||||
|
function resolveLocale(countryCode) {
|
||||||
|
const code = (countryCode || "").toUpperCase();
|
||||||
|
const base = LOCALES["*"];
|
||||||
|
const specific = LOCALES[code] || {};
|
||||||
|
return { ...base, ...specific, country_code: code };
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========================================
|
||||||
|
// Update Locale-Specific Terms
|
||||||
|
// ========================================
|
||||||
|
function updateLocaleTerms(cfg) {
|
||||||
|
// Helper to capitalize first letter
|
||||||
|
const capitalize = (str) => str.charAt(0).toUpperCase() + str.slice(1);
|
||||||
|
|
||||||
|
// Update plate terms
|
||||||
|
document.querySelectorAll('.locale-plate').forEach(el => {
|
||||||
|
el.textContent = cfg.plate_term;
|
||||||
|
});
|
||||||
|
|
||||||
|
document.querySelectorAll('.locale-plate-plural').forEach(el => {
|
||||||
|
el.textContent = cfg.plate_term + 's';
|
||||||
|
});
|
||||||
|
|
||||||
|
// Update notice/citation terms
|
||||||
|
document.querySelectorAll('.locale-notice').forEach(el => {
|
||||||
|
el.textContent = cfg.notice_term;
|
||||||
|
});
|
||||||
|
|
||||||
|
document.querySelectorAll('.locale-notice-plural').forEach(el => {
|
||||||
|
el.textContent = capitalize(cfg.notice_term) + 's';
|
||||||
|
});
|
||||||
|
|
||||||
|
// Update authority terms (council/municipality/etc)
|
||||||
|
document.querySelectorAll('.locale-authority').forEach(el => {
|
||||||
|
el.textContent = cfg.authority_term;
|
||||||
|
});
|
||||||
|
|
||||||
|
document.querySelectorAll('.locale-authority-plural').forEach(el => {
|
||||||
|
el.textContent = cfg.authority_term + 's';
|
||||||
|
});
|
||||||
|
|
||||||
|
// Update kerb/curb terms
|
||||||
|
document.querySelectorAll('.locale-kerb').forEach(el => {
|
||||||
|
el.textContent = cfg.kerb_curb;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Update citizens/ratepayers/residents terms
|
||||||
|
document.querySelectorAll('.locale-citizens').forEach(el => {
|
||||||
|
el.textContent = cfg.citizens_term;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Update the original notice_term_plural id for backward compatibility
|
||||||
|
const elNoticeTerm = document.getElementById("notice_term_plural");
|
||||||
|
if (elNoticeTerm) {
|
||||||
|
elNoticeTerm.textContent = capitalize(cfg.notice_term) + 's';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========================================
|
||||||
|
// Mobile Menu Toggle
|
||||||
|
// ========================================
|
||||||
|
function toggleMobileMenu() {
|
||||||
|
const navLinks = document.getElementById('navLinks');
|
||||||
|
navLinks.classList.toggle('active');
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeMobileMenu() {
|
||||||
|
const navLinks = document.getElementById('navLinks');
|
||||||
|
navLinks.classList.remove('active');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close mobile menu when clicking outside
|
||||||
|
document.addEventListener('click', function(event) {
|
||||||
|
const nav = document.querySelector('nav');
|
||||||
|
const navLinks = document.getElementById('navLinks');
|
||||||
|
|
||||||
|
if (!nav.contains(event.target)) {
|
||||||
|
navLinks.classList.remove('active');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// ========================================
|
||||||
|
// Geo-Location Detection & Locale Setup
|
||||||
|
// ========================================
|
||||||
(async () => {
|
(async () => {
|
||||||
try {
|
try {
|
||||||
const res = await fetch("https://ipapi.co/json/");
|
const res = await fetch("https://ipapi.co/json/");
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
|
const cfg = resolveLocale(data.country_code);
|
||||||
|
|
||||||
let message = "Welcome!";
|
// Update UI with localized strings
|
||||||
let message_aws = "Hosted on AWS servers";
|
const message = cfg.message;
|
||||||
|
const message_aws = cfg.message_aws;
|
||||||
|
|
||||||
if (data.country_code === "NZ") {
|
const elMessage = document.getElementById("message");
|
||||||
message = "Ready for New Zealand";
|
const elMessageAws = document.getElementById("message_aws");
|
||||||
message_aws = "Deployed on AWS in Auckland.";
|
const elNoticeTerm = document.getElementById("notice_term_plural");
|
||||||
} else if (data.country_code === "AU") {
|
|
||||||
message = "Ready for Australia";
|
|
||||||
message_aws = "Deployed on AWS in Sydney";
|
|
||||||
} else {
|
|
||||||
message = "Ready worldwide";
|
|
||||||
message_aws = "Hosted on AWS servers";
|
|
||||||
}
|
|
||||||
|
|
||||||
document.getElementById("message").textContent = message;
|
if (elMessage) elMessage.textContent = message;
|
||||||
document.getElementById("message_aws").textContent = message_aws;
|
if (elMessageAws) elMessageAws.textContent = message_aws;
|
||||||
} catch (e) {
|
|
||||||
console.error("Geo lookup failed", e);
|
// Update all locale-specific terms
|
||||||
document.getElementById("message").textContent = "Ready worldwide";
|
updateLocaleTerms(cfg);
|
||||||
document.getElementById("message_aws").textContent = "Hosted on AWS servers";
|
|
||||||
|
// Expose locale configuration globally for other components
|
||||||
|
window.__LOCALE__ = cfg;
|
||||||
|
|
||||||
|
// Optional: Log for debugging
|
||||||
|
console.log('Locale detected:', cfg.label, `(${cfg.country_code})`);
|
||||||
|
|
||||||
|
} catch (err) {
|
||||||
|
// On failure, use fallback
|
||||||
|
console.error("Geo lookup failed, using fallback locale:", err);
|
||||||
|
const cfg = resolveLocale();
|
||||||
|
|
||||||
|
const elMessage = document.getElementById("message");
|
||||||
|
const elMessageAws = document.getElementById("message_aws");
|
||||||
|
const elNoticeTerm = document.getElementById("notice_term_plural");
|
||||||
|
|
||||||
|
if (elMessage) elMessage.textContent = cfg.message;
|
||||||
|
if (elMessageAws) elMessageAws.textContent = cfg.message_aws;
|
||||||
|
|
||||||
|
// Update all locale-specific terms
|
||||||
|
updateLocaleTerms(cfg);
|
||||||
|
|
||||||
|
// Expose fallback locale
|
||||||
|
window.__LOCALE__ = cfg;
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
Reference in New Issue
Block a user