mirror of
https://github.com/myronblair/parkerslingshotrentals
synced 2026-06-30 09:40:14 -05:00
072272104e
- db.php: SITE_URL -> https://www.parkerslingshotrentals.com - db.php: add ADMIN_PHONE (817) 266-2022 - index.html, contact.php, admin/index.php: fix placeholder phone 555-0199 -> 266-2022 - admin/view-doc.php: new secure doc viewer (URL-token auth, bookings table) - upload-docs.php, view-doc.php: added from subdomain (already used db.php/bookings)
1217 lines
56 KiB
HTML
1217 lines
56 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||
<title>Parker County Slingshot Rentals | Polaris Slingshot | Weatherford, TX</title>
|
||
<meta name="description" content="Rent a Polaris Slingshot in Parker County, TX. Experience the thrill of open-air three-wheel driving through Weatherford and the DFW area. Book online today — daily and weekend rentals available." />
|
||
<meta name="keywords" content="Polaris Slingshot rental, Parker County slingshot rental, Weatherford TX slingshot, DFW slingshot rental, three wheel rental Texas, slingshot car rental, open air vehicle rental, adventure rental Weatherford" />
|
||
<meta name="robots" content="index, follow" />
|
||
<link rel="canonical" href="https://parkerslingshotrentals.com/" />
|
||
|
||
<!-- Open Graph -->
|
||
<meta property="og:type" content="website" />
|
||
<meta property="og:site_name" content="Parker County Slingshot Rentals" />
|
||
<meta property="og:title" content="Parker County Slingshot Rentals | Polaris Slingshot | Weatherford, TX" />
|
||
<meta property="og:description" content="Rent a Polaris Slingshot in Parker County, TX. Daily and weekend rentals. Experience open-air three-wheel driving through the beautiful Texas Hill Country near DFW." />
|
||
<meta property="og:url" content="https://parkerslingshotrentals.com/" />
|
||
<meta property="og:image" content="https://parkerslingshotrentals.com/assets/og-image.jpg" />
|
||
<meta property="og:locale" content="en_US" />
|
||
|
||
<!-- Twitter Card -->
|
||
<meta name="twitter:card" content="summary_large_image" />
|
||
<meta name="twitter:title" content="Parker County Slingshot Rentals | Polaris Slingshot | Weatherford, TX" />
|
||
<meta name="twitter:description" content="Rent a Polaris Slingshot in Parker County, TX. Daily and weekend rentals available. Book today!" />
|
||
<meta name="twitter:image" content="https://parkerslingshotrentals.com/assets/og-image.jpg" />
|
||
|
||
<!-- JSON-LD Structured Data -->
|
||
<script type="application/ld+json">
|
||
{
|
||
"@context": "https://schema.org",
|
||
"@graph": [
|
||
{
|
||
"@type": "LocalBusiness",
|
||
"@id": "https://parkerslingshotrentals.com/#business",
|
||
"name": "Parker County Slingshot Rentals",
|
||
"description": "Polaris Slingshot rentals in Parker County, Texas. Daily and weekend rentals available for thrill-seekers near Weatherford and the DFW metroplex.",
|
||
"url": "https://parkerslingshotrentals.com",
|
||
"telephone": "+1-817-555-0199",
|
||
"email": "info@parkerslingshotrentals.com",
|
||
"priceRange": "$$",
|
||
"currenciesAccepted": "USD",
|
||
"paymentAccepted": "Cash, Credit Card",
|
||
"address": {
|
||
"@type": "PostalAddress",
|
||
"addressLocality": "Weatherford",
|
||
"addressRegion": "TX",
|
||
"postalCode": "76086",
|
||
"addressCountry": "US"
|
||
},
|
||
"geo": {
|
||
"@type": "GeoCoordinates",
|
||
"latitude": 32.7554,
|
||
"longitude": -97.7981
|
||
},
|
||
"openingHoursSpecification": [
|
||
{
|
||
"@type": "OpeningHoursSpecification",
|
||
"dayOfWeek": ["Monday","Tuesday","Wednesday","Thursday","Friday"],
|
||
"opens": "09:00",
|
||
"closes": "18:00"
|
||
},
|
||
{
|
||
"@type": "OpeningHoursSpecification",
|
||
"dayOfWeek": ["Saturday","Sunday"],
|
||
"opens": "08:00",
|
||
"closes": "20:00"
|
||
}
|
||
],
|
||
"sameAs": [],
|
||
"hasOfferCatalog": {
|
||
"@type": "OfferCatalog",
|
||
"name": "Slingshot Rental Packages",
|
||
"itemListElement": [
|
||
{
|
||
"@type": "Offer",
|
||
"itemOffered": {
|
||
"@type": "Product",
|
||
"name": "Half-Day Slingshot Rental",
|
||
"description": "4-hour Polaris Slingshot rental — perfect for a quick thrill around Parker County."
|
||
},
|
||
"priceCurrency": "USD",
|
||
"price": "99.00"
|
||
},
|
||
{
|
||
"@type": "Offer",
|
||
"itemOffered": {
|
||
"@type": "Product",
|
||
"name": "Full-Day Slingshot Rental",
|
||
"description": "8-hour Polaris Slingshot rental — explore Weatherford, Mineral Wells, and beyond."
|
||
},
|
||
"priceCurrency": "USD",
|
||
"price": "169.00"
|
||
},
|
||
{
|
||
"@type": "Offer",
|
||
"itemOffered": {
|
||
"@type": "Product",
|
||
"name": "Weekend Slingshot Rental",
|
||
"description": "48-hour weekend Polaris Slingshot rental — the ultimate Texas road trip experience."
|
||
},
|
||
"priceCurrency": "USD",
|
||
"price": "299.00"
|
||
}
|
||
]
|
||
}
|
||
},
|
||
{
|
||
"@type": "WebSite",
|
||
"@id": "https://parkerslingshotrentals.com/#website",
|
||
"url": "https://parkerslingshotrentals.com",
|
||
"name": "Parker County Slingshot Rentals",
|
||
"publisher": {"@id": "https://parkerslingshotrentals.com/#business"},
|
||
"potentialAction": {
|
||
"@type": "SearchAction",
|
||
"target": "https://parkerslingshotrentals.com/?s={search_term_string}",
|
||
"query-input": "required name=search_term_string"
|
||
}
|
||
},
|
||
{
|
||
"@type": "FAQPage",
|
||
"mainEntity": [
|
||
{
|
||
"@type": "Question",
|
||
"name": "Do I need a motorcycle license to rent a Polaris Slingshot in Texas?",
|
||
"acceptedAnswer": {
|
||
"@type": "Answer",
|
||
"text": "In Texas, a standard Class C driver's license is sufficient to operate a Polaris Slingshot. No motorcycle endorsement is required. You must be 25 or older to rent."
|
||
}
|
||
},
|
||
{
|
||
"@type": "Question",
|
||
"name": "What is included in the rental?",
|
||
"acceptedAnswer": {
|
||
"@type": "Answer",
|
||
"text": "Every rental includes the Polaris Slingshot, DOT-approved helmets for driver and passenger, a safety orientation, a suggested scenic route map, and roadside assistance. Renters must provide proof of valid personal auto insurance. We carry a comprehensive fleet policy covering the vehicle."
|
||
}
|
||
},
|
||
{
|
||
"@type": "Question",
|
||
"name": "How many people can ride in a Polaris Slingshot?",
|
||
"acceptedAnswer": {
|
||
"@type": "Answer",
|
||
"text": "The Polaris Slingshot seats two people — a driver and one passenger. Both will enjoy an open-air, sports-car-style driving experience."
|
||
}
|
||
},
|
||
{
|
||
"@type": "Question",
|
||
"name": "Where can I drive the Slingshot?",
|
||
"acceptedAnswer": {
|
||
"@type": "Answer",
|
||
"text": "You can drive throughout Parker County and the surrounding DFW area including Weatherford, Mineral Wells, Granbury, and Azle. We provide a recommended scenic route guide with every rental."
|
||
}
|
||
}
|
||
]
|
||
}
|
||
]
|
||
}
|
||
</script>
|
||
|
||
<!-- Fonts & Icons -->
|
||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Barlow+Condensed:wght@600;700;800&display=swap" rel="stylesheet" />
|
||
|
||
<style>
|
||
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
||
|
||
:root {
|
||
--orange: #f97316;
|
||
--orange-dark: #ea580c;
|
||
--black: #0d0d0d;
|
||
--dark: #1a1a2e;
|
||
--gray: #6b7280;
|
||
--light: #f9fafb;
|
||
--white: #ffffff;
|
||
--radius: 12px;
|
||
}
|
||
|
||
html { scroll-behavior: smooth; }
|
||
body { font-family: 'Inter', sans-serif; background: var(--black); color: var(--white); line-height: 1.6; }
|
||
|
||
/* NAV */
|
||
nav {
|
||
position: fixed; top: 0; left: 0; right: 0; z-index: 100;
|
||
display: flex; align-items: center; justify-content: space-between;
|
||
padding: 1rem 2rem;
|
||
background: rgba(13,13,13,0.92);
|
||
backdrop-filter: blur(8px);
|
||
border-bottom: 1px solid rgba(255,255,255,0.06);
|
||
}
|
||
.nav-logo { font-family: 'Barlow Condensed', sans-serif; font-size: 1.4rem; font-weight: 800; color: var(--orange); letter-spacing: 0.5px; text-decoration: none; }
|
||
.nav-links { display: flex; gap: 2rem; list-style: none; }
|
||
.nav-links a { color: rgba(255,255,255,0.8); text-decoration: none; font-weight: 500; font-size: 0.9rem; transition: color 0.2s; }
|
||
.nav-links a:hover { color: var(--orange); }
|
||
.nav-cta { background: var(--orange); color: white; padding: 0.6rem 1.4rem; border-radius: 6px; text-decoration: none; font-weight: 600; font-size: 0.9rem; transition: background 0.2s; }
|
||
.nav-cta:hover { background: var(--orange-dark); }
|
||
|
||
/* HERO */
|
||
.hero {
|
||
min-height: 100vh;
|
||
display: flex; align-items: center; justify-content: center;
|
||
text-align: center;
|
||
padding: 6rem 2rem 4rem;
|
||
background: linear-gradient(135deg, #0d0d0d 0%, #1a0a00 50%, #0d0d0d 100%);
|
||
position: relative; overflow: hidden;
|
||
}
|
||
.hero::before {
|
||
content: '';
|
||
position: absolute; inset: 0;
|
||
background: radial-gradient(ellipse at center, rgba(249,115,22,0.12) 0%, transparent 70%);
|
||
}
|
||
.hero-badge {
|
||
display: inline-block;
|
||
background: rgba(249,115,22,0.15);
|
||
border: 1px solid rgba(249,115,22,0.4);
|
||
color: var(--orange);
|
||
padding: 0.35rem 1rem;
|
||
border-radius: 999px;
|
||
font-size: 0.8rem;
|
||
font-weight: 600;
|
||
letter-spacing: 1px;
|
||
text-transform: uppercase;
|
||
margin-bottom: 1.5rem;
|
||
}
|
||
.hero h1 {
|
||
font-family: 'Barlow Condensed', sans-serif;
|
||
font-size: clamp(3rem, 8vw, 6rem);
|
||
font-weight: 800;
|
||
line-height: 1;
|
||
letter-spacing: -1px;
|
||
margin-bottom: 1.5rem;
|
||
}
|
||
.hero h1 span { color: var(--orange); }
|
||
.hero p {
|
||
font-size: 1.2rem;
|
||
color: rgba(255,255,255,0.7);
|
||
max-width: 600px;
|
||
margin: 0 auto 2.5rem;
|
||
}
|
||
.hero-btns { display: flex; gap: 1rem; justify-content: center; flex-wrap: wrap; }
|
||
.btn-primary {
|
||
background: var(--orange); color: white;
|
||
padding: 0.85rem 2rem; border-radius: 8px;
|
||
text-decoration: none; font-weight: 700; font-size: 1rem;
|
||
transition: background 0.2s, transform 0.15s;
|
||
display: inline-block;
|
||
}
|
||
.btn-primary:hover { background: var(--orange-dark); transform: translateY(-2px); }
|
||
.btn-secondary {
|
||
background: rgba(255,255,255,0.08); color: white;
|
||
border: 1px solid rgba(255,255,255,0.2);
|
||
padding: 0.85rem 2rem; border-radius: 8px;
|
||
text-decoration: none; font-weight: 600; font-size: 1rem;
|
||
transition: background 0.2s;
|
||
display: inline-block;
|
||
}
|
||
.btn-secondary:hover { background: rgba(255,255,255,0.14); }
|
||
.hero-scroll { margin-top: 4rem; opacity: 0.4; font-size: 0.8rem; letter-spacing: 1px; text-transform: uppercase; }
|
||
|
||
/* SECTIONS */
|
||
section { padding: 5rem 2rem; }
|
||
.container { max-width: 1100px; margin: 0 auto; }
|
||
.section-label { font-size: 0.75rem; font-weight: 700; letter-spacing: 2px; text-transform: uppercase; color: var(--orange); margin-bottom: 0.75rem; }
|
||
.section-title { font-family: 'Barlow Condensed', sans-serif; font-size: clamp(2rem, 4vw, 3rem); font-weight: 800; margin-bottom: 1rem; }
|
||
.section-sub { color: rgba(255,255,255,0.6); font-size: 1rem; max-width: 560px; margin-bottom: 3rem; }
|
||
|
||
/* WHY */
|
||
.why { background: #111111; }
|
||
.features-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 1.5rem; }
|
||
.feature-card {
|
||
background: rgba(255,255,255,0.04);
|
||
border: 1px solid rgba(255,255,255,0.07);
|
||
border-radius: var(--radius);
|
||
padding: 2rem;
|
||
transition: border-color 0.2s;
|
||
}
|
||
.feature-card:hover { border-color: rgba(249,115,22,0.4); }
|
||
.feature-icon { font-size: 2rem; margin-bottom: 1rem; }
|
||
.feature-card h3 { font-size: 1.1rem; font-weight: 700; margin-bottom: 0.5rem; }
|
||
.feature-card p { color: rgba(255,255,255,0.55); font-size: 0.9rem; }
|
||
|
||
/* PRICING */
|
||
.pricing { background: var(--black); }
|
||
.pricing-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 1.5rem; }
|
||
.price-card {
|
||
background: rgba(255,255,255,0.04);
|
||
border: 1px solid rgba(255,255,255,0.08);
|
||
border-radius: var(--radius);
|
||
padding: 2.5rem 2rem;
|
||
text-align: center;
|
||
position: relative;
|
||
transition: transform 0.2s, border-color 0.2s;
|
||
}
|
||
.price-card:hover { transform: translateY(-4px); border-color: rgba(249,115,22,0.3); }
|
||
.price-card.featured {
|
||
border-color: var(--orange);
|
||
background: rgba(249,115,22,0.07);
|
||
}
|
||
.price-badge {
|
||
position: absolute; top: -13px; left: 50%; transform: translateX(-50%);
|
||
background: var(--orange); color: white;
|
||
padding: 0.25rem 1rem; border-radius: 999px;
|
||
font-size: 0.75rem; font-weight: 700; text-transform: uppercase; letter-spacing: 1px;
|
||
}
|
||
.price-name { font-size: 0.85rem; font-weight: 600; color: var(--orange); text-transform: uppercase; letter-spacing: 1px; margin-bottom: 0.5rem; }
|
||
.price-amount { font-family: 'Barlow Condensed', sans-serif; font-size: 3.5rem; font-weight: 800; line-height: 1; margin-bottom: 0.25rem; }
|
||
.price-amount sup { font-size: 1.5rem; vertical-align: top; margin-top: 0.5rem; }
|
||
.price-duration { color: rgba(255,255,255,0.5); font-size: 0.85rem; margin-bottom: 1.5rem; }
|
||
.price-features { list-style: none; text-align: left; margin-bottom: 2rem; }
|
||
.price-features li { padding: 0.4rem 0; color: rgba(255,255,255,0.7); font-size: 0.9rem; display: flex; align-items: center; gap: 0.5rem; }
|
||
.price-features li::before { content: '✓'; color: var(--orange); font-weight: 700; flex-shrink: 0; }
|
||
|
||
/* HOW IT WORKS */
|
||
.how { background: #111111; }
|
||
.steps { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 2rem; counter-reset: steps; }
|
||
.step { text-align: center; counter-increment: steps; }
|
||
.step-num {
|
||
width: 56px; height: 56px; border-radius: 50%;
|
||
background: rgba(249,115,22,0.15); border: 2px solid var(--orange);
|
||
display: flex; align-items: center; justify-content: center;
|
||
font-family: 'Barlow Condensed', sans-serif; font-size: 1.4rem; font-weight: 800; color: var(--orange);
|
||
margin: 0 auto 1rem;
|
||
}
|
||
.step h3 { font-size: 1rem; font-weight: 700; margin-bottom: 0.5rem; }
|
||
.step p { color: rgba(255,255,255,0.55); font-size: 0.875rem; }
|
||
|
||
/* ROUTES */
|
||
.routes { background: var(--black); }
|
||
.routes-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 1.5rem; }
|
||
.route-card {
|
||
background: rgba(255,255,255,0.03);
|
||
border: 1px solid rgba(255,255,255,0.07);
|
||
border-radius: var(--radius); padding: 1.75rem;
|
||
}
|
||
.route-card h3 { font-size: 1rem; font-weight: 700; margin-bottom: 0.4rem; }
|
||
.route-card .miles { font-size: 0.8rem; color: var(--orange); font-weight: 600; margin-bottom: 0.5rem; }
|
||
.route-card p { color: rgba(255,255,255,0.5); font-size: 0.875rem; }
|
||
|
||
/* FAQ */
|
||
.faq { background: #111111; }
|
||
.faq-list { display: flex; flex-direction: column; gap: 0; max-width: 760px; }
|
||
details {
|
||
border-bottom: 1px solid rgba(255,255,255,0.08);
|
||
padding: 1.25rem 0;
|
||
}
|
||
details:first-child { border-top: 1px solid rgba(255,255,255,0.08); }
|
||
summary {
|
||
font-weight: 600; font-size: 1rem; cursor: pointer;
|
||
list-style: none; display: flex; justify-content: space-between; align-items: center;
|
||
}
|
||
summary::-webkit-details-marker { display: none; }
|
||
summary::after { content: '+'; font-size: 1.4rem; color: var(--orange); flex-shrink: 0; transition: transform 0.2s; }
|
||
details[open] summary::after { transform: rotate(45deg); }
|
||
details p { color: rgba(255,255,255,0.6); margin-top: 0.75rem; font-size: 0.95rem; }
|
||
|
||
/* CONTACT */
|
||
.contact { background: var(--black); }
|
||
.contact-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 4rem; align-items: start; }
|
||
@media (max-width: 700px) { .contact-grid { grid-template-columns: 1fr; gap: 2rem; } }
|
||
.contact-info h2 { font-family: 'Barlow Condensed', sans-serif; font-size: 2.5rem; font-weight: 800; margin-bottom: 1rem; }
|
||
.contact-info p { color: rgba(255,255,255,0.6); margin-bottom: 2rem; }
|
||
.contact-detail { display: flex; align-items: center; gap: 0.75rem; margin-bottom: 1rem; color: rgba(255,255,255,0.7); font-size: 0.95rem; }
|
||
.contact-detail span:first-child { font-size: 1.2rem; }
|
||
.contact-form { display: flex; flex-direction: column; gap: 1rem; }
|
||
.form-row { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; }
|
||
@media (max-width: 500px) { .form-row { grid-template-columns: 1fr; } }
|
||
.contact-form input, .contact-form select, .contact-form textarea {
|
||
background: rgba(255,255,255,0.05);
|
||
border: 1px solid rgba(255,255,255,0.1);
|
||
border-radius: 8px; padding: 0.85rem 1rem;
|
||
color: white; font-family: inherit; font-size: 0.95rem;
|
||
outline: none; transition: border-color 0.2s; width: 100%;
|
||
}
|
||
.contact-form input:focus, .contact-form select:focus, .contact-form textarea:focus { border-color: var(--orange); }
|
||
.contact-form select option { background: #1a1a1a; }
|
||
.contact-form textarea { resize: vertical; min-height: 120px; }
|
||
.contact-form button {
|
||
background: var(--orange); color: white;
|
||
border: none; border-radius: 8px;
|
||
padding: 0.9rem; font-size: 1rem; font-weight: 700;
|
||
cursor: pointer; transition: background 0.2s;
|
||
}
|
||
.contact-form button:hover { background: var(--orange-dark); }
|
||
.form-msg { padding: 0.75rem 1rem; border-radius: 8px; font-size: 0.9rem; display: none; }
|
||
.form-msg.success { background: rgba(34,197,94,0.15); border: 1px solid rgba(34,197,94,0.3); color: #4ade80; display: block; }
|
||
.form-msg.error { background: rgba(239,68,68,0.15); border: 1px solid rgba(239,68,68,0.3); color: #f87171; display: block; }
|
||
|
||
/* AVAILABILITY CALENDAR */
|
||
.cal-wrap { background: rgba(255,255,255,0.04); border: 1px solid rgba(255,255,255,0.08); border-radius: 12px; padding: 1.25rem; margin-bottom: 1.25rem; }
|
||
.cal-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 1rem; }
|
||
.cal-header h3 { font-family: 'Barlow Condensed', sans-serif; font-size: 1.2rem; font-weight: 700; letter-spacing: 0.5px; }
|
||
.cal-nav { background: rgba(255,255,255,0.07); border: none; color: white; border-radius: 6px; width: 32px; height: 32px; cursor: pointer; font-size: 1rem; display: flex; align-items: center; justify-content: center; transition: background 0.2s; }
|
||
.cal-nav:hover { background: var(--orange); }
|
||
.cal-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 3px; }
|
||
.cal-day-label { text-align: center; font-size: 0.65rem; font-weight: 600; letter-spacing: 1px; color: rgba(255,255,255,0.35); padding: 0.25rem 0; text-transform: uppercase; }
|
||
.cal-day { text-align: center; border-radius: 6px; padding: 0.4rem 0.25rem; font-size: 0.8rem; font-weight: 500; min-height: 32px; display: flex; align-items: center; justify-content: center; transition: background 0.15s, color 0.15s; }
|
||
.cal-day.empty { background: transparent; }
|
||
.cal-day.past { color: rgba(255,255,255,0.2); cursor: default; }
|
||
.cal-day.booked { background: rgba(239,68,68,0.18); color: rgba(239,68,68,0.6); cursor: not-allowed; position: relative; }
|
||
.cal-day.booked::after { content: ''; position: absolute; bottom: 3px; left: 50%; transform: translateX(-50%); width: 4px; height: 4px; border-radius: 50%; background: rgba(239,68,68,0.5); }
|
||
.cal-day.available { background: rgba(255,255,255,0.05); color: rgba(255,255,255,0.85); cursor: pointer; }
|
||
.cal-day.available:hover { background: rgba(249,115,22,0.25); color: var(--orange); }
|
||
.cal-day.today { border: 1px solid rgba(249,115,22,0.5); }
|
||
.cal-day.selected { background: var(--orange) !important; color: white !important; font-weight: 700; }
|
||
.cal-legend { display: flex; gap: 1rem; margin-top: 0.75rem; flex-wrap: wrap; }
|
||
.cal-legend-item { display: flex; align-items: center; gap: 0.4rem; font-size: 0.72rem; color: rgba(255,255,255,0.45); }
|
||
.cal-legend-dot { width: 10px; height: 10px; border-radius: 3px; flex-shrink: 0; }
|
||
.cal-loading { text-align: center; padding: 1.5rem; color: rgba(255,255,255,0.3); font-size: 0.85rem; }
|
||
|
||
/* FOOTER */
|
||
footer {
|
||
background: #080808;
|
||
border-top: 1px solid rgba(255,255,255,0.06);
|
||
padding: 2.5rem 2rem;
|
||
text-align: center;
|
||
}
|
||
.footer-logo { font-family: 'Barlow Condensed', sans-serif; font-size: 1.4rem; font-weight: 800; color: var(--orange); margin-bottom: 0.5rem; }
|
||
footer p { color: rgba(255,255,255,0.35); font-size: 0.85rem; }
|
||
.footer-links { display: flex; gap: 1.5rem; justify-content: center; margin: 1rem 0; flex-wrap: wrap; }
|
||
.footer-links a { color: rgba(255,255,255,0.4); text-decoration: none; font-size: 0.85rem; transition: color 0.2s; }
|
||
.footer-links a:hover { color: var(--orange); }
|
||
|
||
/* HAMBURGER / MOBILE NAV */
|
||
.nav-hamburger {
|
||
display: none;
|
||
flex-direction: column;
|
||
gap: 5px;
|
||
background: none;
|
||
border: none;
|
||
cursor: pointer;
|
||
padding: 6px;
|
||
border-radius: 6px;
|
||
transition: background 0.2s;
|
||
z-index: 101;
|
||
}
|
||
.nav-hamburger:hover { background: rgba(255,255,255,0.07); }
|
||
.nav-hamburger span {
|
||
display: block;
|
||
width: 24px;
|
||
height: 2px;
|
||
background: white;
|
||
border-radius: 2px;
|
||
transition: transform 0.25s, opacity 0.25s;
|
||
transform-origin: center;
|
||
}
|
||
.nav-hamburger.open span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
|
||
.nav-hamburger.open span:nth-child(2) { opacity: 0; transform: scaleX(0); }
|
||
.nav-hamburger.open span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }
|
||
|
||
.nav-drawer {
|
||
display: none;
|
||
position: fixed;
|
||
top: 0; left: 0; right: 0; bottom: 0;
|
||
z-index: 99;
|
||
flex-direction: column;
|
||
padding-top: 72px;
|
||
background: rgba(13,13,13,0.97);
|
||
backdrop-filter: blur(12px);
|
||
animation: drawerIn 0.22s ease;
|
||
}
|
||
@keyframes drawerIn {
|
||
from { opacity: 0; transform: translateY(-8px); }
|
||
to { opacity: 1; transform: translateY(0); }
|
||
}
|
||
.nav-drawer.open { display: flex; }
|
||
.nav-drawer ul {
|
||
list-style: none;
|
||
display: flex;
|
||
flex-direction: column;
|
||
padding: 1.5rem 2rem;
|
||
gap: 0;
|
||
flex: 1;
|
||
}
|
||
.nav-drawer ul li a {
|
||
display: block;
|
||
padding: 1rem 0;
|
||
color: rgba(255,255,255,0.85);
|
||
text-decoration: none;
|
||
font-size: 1.25rem;
|
||
font-weight: 600;
|
||
border-bottom: 1px solid rgba(255,255,255,0.07);
|
||
transition: color 0.2s;
|
||
}
|
||
.nav-drawer ul li:last-child a { border-bottom: none; }
|
||
.nav-drawer ul li a:hover { color: var(--orange); }
|
||
.nav-drawer .drawer-cta {
|
||
margin: 1rem 2rem 2.5rem;
|
||
}
|
||
.nav-drawer .drawer-cta a {
|
||
display: block;
|
||
text-align: center;
|
||
background: var(--orange);
|
||
color: white;
|
||
padding: 1rem;
|
||
border-radius: 8px;
|
||
font-weight: 700;
|
||
font-size: 1.1rem;
|
||
text-decoration: none;
|
||
transition: background 0.2s;
|
||
}
|
||
.nav-drawer .drawer-cta a:hover { background: var(--orange-dark); }
|
||
|
||
@media (max-width: 768px) {
|
||
.nav-links { display: none; }
|
||
.nav-cta { display: none; }
|
||
.nav-hamburger { display: flex; }
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
|
||
<!-- Navigation -->
|
||
<nav aria-label="Main navigation">
|
||
<a href="/" class="nav-logo">Parker County Slingshot</a>
|
||
<ul class="nav-links">
|
||
<li><a href="#why">Why Us</a></li>
|
||
<li><a href="#pricing">Pricing</a></li>
|
||
<li><a href="#how">How It Works</a></li>
|
||
<li><a href="#routes">Routes</a></li>
|
||
<li><a href="#faq">FAQ</a></li>
|
||
</ul>
|
||
<a href="#contact" class="nav-cta">Book Now</a>
|
||
<button class="nav-hamburger" id="navToggle" aria-label="Toggle menu" aria-expanded="false" aria-controls="navDrawer">
|
||
<span></span><span></span><span></span>
|
||
</button>
|
||
</nav>
|
||
|
||
<!-- Mobile Drawer -->
|
||
<div class="nav-drawer" id="navDrawer" role="dialog" aria-label="Mobile navigation">
|
||
<ul>
|
||
<li><a href="#why">Why Us</a></li>
|
||
<li><a href="#pricing">Pricing</a></li>
|
||
<li><a href="#how">How It Works</a></li>
|
||
<li><a href="#routes">Routes</a></li>
|
||
<li><a href="#faq">FAQ</a></li>
|
||
<li><a href="#contact">Contact</a></li>
|
||
</ul>
|
||
<div class="drawer-cta"><a href="#contact">Book Now</a></div>
|
||
</div>
|
||
|
||
<!-- Hero -->
|
||
<header class="hero" role="banner">
|
||
<div style="position:relative;z-index:1;">
|
||
<div class="hero-badge">Weatherford, Texas</div>
|
||
<h1>Feel the Road.<br /><span>Rent a Slingshot.</span></h1>
|
||
<p>Parker County's premier Polaris Slingshot rental experience. Open-air freedom, three-wheel thrills, Texas roads built for adventure.</p>
|
||
<div class="hero-btns">
|
||
<a href="#pricing" class="btn-primary">View Rental Packages</a>
|
||
<a href="#how" class="btn-secondary">How It Works</a>
|
||
</div>
|
||
<p class="hero-scroll">Scroll to explore ↓</p>
|
||
</div>
|
||
</header>
|
||
|
||
<!-- Why Choose Us -->
|
||
<section class="why" id="why" aria-label="Why choose Parker County Slingshot Rentals">
|
||
<div class="container">
|
||
<p class="section-label">Why Us</p>
|
||
<h2 class="section-title">Built for the Thrill-Seeker</h2>
|
||
<p class="section-sub">Everything you need for an unforgettable open-road experience — no hassle, just pure adrenaline.</p>
|
||
<div class="features-grid">
|
||
<div class="feature-card">
|
||
<div class="feature-icon">🏎️</div>
|
||
<h3>Polaris Slingshot SL</h3>
|
||
<p>Our fleet features the latest Polaris Slingshot models — powerful, fast, and impossible to ignore on Texas roads.</p>
|
||
</div>
|
||
<div class="feature-card">
|
||
<div class="feature-icon">🛡️</div>
|
||
<h3>Full Coverage Insurance</h3>
|
||
<p>Every rental includes comprehensive coverage. Drive with confidence knowing you're fully protected.</p>
|
||
</div>
|
||
<div class="feature-card">
|
||
<div class="feature-icon">🗺️</div>
|
||
<h3>Scenic Route Guides</h3>
|
||
<p>We hand you a curated Texas route map — the best backroads, vistas, and stops around Parker County.</p>
|
||
</div>
|
||
<div class="feature-card">
|
||
<div class="feature-icon">⛑️</div>
|
||
<h3>Safety First</h3>
|
||
<p>DOT-approved helmets included with every rental. Safety orientation for all drivers before you hit the road.</p>
|
||
</div>
|
||
<div class="feature-card">
|
||
<div class="feature-icon">📞</div>
|
||
<h3>Roadside Assistance</h3>
|
||
<p>24/7 roadside support so you're never stranded. We've got your back from pickup to return.</p>
|
||
</div>
|
||
<div class="feature-card">
|
||
<div class="feature-icon">✅</div>
|
||
<h3>Easy Booking</h3>
|
||
<p>Simple online reservation, flexible pickup times, and transparent pricing. No hidden fees — ever.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- Pricing -->
|
||
<section class="pricing" id="pricing" aria-label="Slingshot rental pricing">
|
||
<div class="container">
|
||
<p class="section-label">Rental Packages</p>
|
||
<h2 class="section-title">Pick Your Adventure</h2>
|
||
<p class="section-sub">Transparent pricing. No surprise fees. Just you, the open road, and a machine that turns heads.</p>
|
||
<div class="pricing-grid">
|
||
<div class="price-card">
|
||
<p class="price-name">Half Day</p>
|
||
<p class="price-amount"><sup>$</sup>99</p>
|
||
<p class="price-duration">4 hours of freedom</p>
|
||
<ul class="price-features">
|
||
<li>Polaris Slingshot SL</li>
|
||
<li>DOT helmets included</li>
|
||
<li>Safety orientation</li>
|
||
<li>Route map & guide</li>
|
||
<li>Proof of insurance required</li>
|
||
<li>Roadside assistance</li>
|
||
</ul>
|
||
<a href="#contact" class="btn-primary" style="display:block;width:100%;text-align:center;">Book Half Day</a>
|
||
</div>
|
||
<div class="price-card featured">
|
||
<div class="price-badge">Most Popular</div>
|
||
<p class="price-name">Full Day</p>
|
||
<p class="price-amount"><sup>$</sup>169</p>
|
||
<p class="price-duration">8 hours of adventure</p>
|
||
<ul class="price-features">
|
||
<li>Polaris Slingshot SL</li>
|
||
<li>DOT helmets included</li>
|
||
<li>Safety orientation</li>
|
||
<li>Route map & guide</li>
|
||
<li>Proof of insurance required</li>
|
||
<li>Roadside assistance</li>
|
||
</ul>
|
||
<a href="#contact" class="btn-primary" style="display:block;width:100%;text-align:center;">Book Full Day</a>
|
||
</div>
|
||
<div class="price-card">
|
||
<p class="price-name">Weekend</p>
|
||
<p class="price-amount"><sup>$</sup>299</p>
|
||
<p class="price-duration">48-hour getaway</p>
|
||
<ul class="price-features">
|
||
<li>Polaris Slingshot SL</li>
|
||
<li>DOT helmets included</li>
|
||
<li>Safety orientation</li>
|
||
<li>Route map & guide</li>
|
||
<li>Proof of insurance required</li>
|
||
<li>24/7 roadside assistance</li>
|
||
</ul>
|
||
<a href="#contact" class="btn-primary" style="display:block;width:100%;text-align:center;">Book Weekend</a>
|
||
</div>
|
||
</div>
|
||
<p style="text-align:center;color:rgba(255,255,255,0.4);font-size:0.85rem;margin-top:2rem;">Must be 25+ with valid driver's license. Security deposit required. Prices include tax.</p>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- How It Works -->
|
||
<section class="how" id="how" aria-label="How the rental process works">
|
||
<div class="container">
|
||
<p class="section-label">The Process</p>
|
||
<h2 class="section-title">Ready in 5 Simple Steps</h2>
|
||
<p class="section-sub">From booking to keys in hand — we make it effortless so you can focus on the fun.</p>
|
||
<div class="steps">
|
||
<div class="step">
|
||
<div class="step-num">1</div>
|
||
<h3>Choose Your Package</h3>
|
||
<p>Half day, full day, or weekend — pick the adventure that fits your schedule and budget.</p>
|
||
</div>
|
||
<div class="step">
|
||
<div class="step-num">2</div>
|
||
<h3>Book & Submit</h3>
|
||
<p>Fill out our simple booking form online or give us a call. We'll review your request right away.</p>
|
||
</div>
|
||
<div class="step">
|
||
<div class="step-num">3</div>
|
||
<h3>Get Approved</h3>
|
||
<p>We'll confirm availability and reach out within a few hours. Once approved, you're officially on the calendar.</p>
|
||
</div>
|
||
<div class="step">
|
||
<div class="step-num">4</div>
|
||
<h3>Sign Your Waiver</h3>
|
||
<p>You'll receive a link to our digital rental agreement. Sign it online in minutes — no printer needed.</p>
|
||
</div>
|
||
<div class="step">
|
||
<div class="step-num">5</div>
|
||
<h3>Hit the Road</h3>
|
||
<p>Arrive at pickup with your license and proof of insurance. Complete your safety briefing, grab your helmets, and go.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- Scenic Routes -->
|
||
<section class="routes" id="routes" aria-label="Recommended scenic driving routes">
|
||
<div class="container">
|
||
<p class="section-label">Scenic Routes</p>
|
||
<h2 class="section-title">Texas Roads Worth Driving</h2>
|
||
<p class="section-sub">We know the best roads. Every rental comes with a recommended route guide — here's a taste.</p>
|
||
<div class="routes-grid">
|
||
<div class="route-card">
|
||
<h3>The Parker County Loop</h3>
|
||
<p class="miles">~45 miles • 1.5 hrs</p>
|
||
<p>Roll through Weatherford's historic downtown, Millsap, and back through the rolling Texas plains. The perfect intro ride.</p>
|
||
</div>
|
||
<div class="route-card">
|
||
<h3>Possum Kingdom Run</h3>
|
||
<p class="miles">~80 miles • 2.5 hrs</p>
|
||
<p>Head northwest toward Mineral Wells and Possum Kingdom Lake. Hill Country scenery, lake views, and open highway.</p>
|
||
</div>
|
||
<div class="route-card">
|
||
<h3>Granbury & Glen Rose</h3>
|
||
<p class="miles">~70 miles • 2 hrs</p>
|
||
<p>Cruise south to the charming Granbury square and dinosaur country in Glen Rose. Great for couples and history lovers.</p>
|
||
</div>
|
||
<div class="route-card">
|
||
<h3>DFW Sunset Cruise</h3>
|
||
<p class="miles">~60 miles • 2 hrs</p>
|
||
<p>Head east toward the Fort Worth skyline at golden hour, loop through Azle and back. City lights in an open cockpit.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- FAQ -->
|
||
<section class="faq" id="faq" aria-label="Frequently asked questions">
|
||
<div class="container">
|
||
<p class="section-label">FAQ</p>
|
||
<h2 class="section-title">Questions & Answers</h2>
|
||
<p class="section-sub">Everything you need to know before you book.</p>
|
||
<div class="faq-list">
|
||
<details>
|
||
<summary>Do I need a motorcycle license to rent a Polaris Slingshot in Texas?</summary>
|
||
<p>In Texas, a standard Class C driver's license is all you need. No motorcycle endorsement required. You must be 25 or older with a clean driving record to rent.</p>
|
||
</details>
|
||
<details>
|
||
<summary>What's included in every rental?</summary>
|
||
<p>Every rental includes the Polaris Slingshot, DOT-approved helmets for driver and passenger, a safety orientation, a suggested scenic route map, and roadside assistance. Renters must provide proof of valid personal auto insurance. We carry a comprehensive fleet policy covering the vehicle.</p>
|
||
</details>
|
||
<details>
|
||
<summary>How many people can ride in a Polaris Slingshot?</summary>
|
||
<p>The Polaris Slingshot is a two-seater — one driver and one passenger. Both experience the open-air thrill side by side in sports-car-style seats.</p>
|
||
</details>
|
||
<details>
|
||
<summary>Is there a security deposit?</summary>
|
||
<p>Yes, a refundable security deposit is required at the time of pickup. The deposit is returned in full upon safe return of the vehicle with no damage.</p>
|
||
</details>
|
||
<details>
|
||
<summary>Can I drive outside of Parker County?</summary>
|
||
<p>Yes — you can drive throughout the DFW area including Weatherford, Mineral Wells, Granbury, Azle, and Fort Worth. We'll note any restrictions in your rental agreement.</p>
|
||
</details>
|
||
<details>
|
||
<summary>What if it rains?</summary>
|
||
<p>The Polaris Slingshot can be driven in light rain, but we recommend rescheduling in severe weather for your safety and comfort. We offer flexible rescheduling with 24-hour notice.</p>
|
||
</details>
|
||
<details>
|
||
<summary>How do I cancel or reschedule?</summary>
|
||
<p>Cancel or reschedule free of charge up to 24 hours before your rental start time. Cancellations within 24 hours are subject to a 50% fee.</p>
|
||
</details>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- Contact / Booking -->
|
||
<section class="contact" id="contact" aria-label="Contact and booking">
|
||
<div class="container">
|
||
<div class="contact-grid">
|
||
<div class="contact-info">
|
||
<p class="section-label">Book Your Rental</p>
|
||
<h2>Ready to Ride?</h2>
|
||
<p>Send us your preferred date and package and we'll confirm availability within a few hours. Can't wait? Give us a call.</p>
|
||
<div class="contact-detail">
|
||
<span>📍</span>
|
||
<span>Weatherford, TX 76086<br />(Exact pickup address provided at booking)</span>
|
||
</div>
|
||
<div class="contact-detail">
|
||
<span>📞</span>
|
||
<a href="tel:+18172662022" style="color:inherit;text-decoration:none;">(817) 266-2022</a>
|
||
</div>
|
||
<div class="contact-detail">
|
||
<span>✉️</span>
|
||
<a href="mailto:info@parkerslingshotrentals.com" style="color:inherit;text-decoration:none;">info@parkerslingshotrentals.com</a>
|
||
</div>
|
||
<div class="contact-detail">
|
||
<span>🕐</span>
|
||
<span>Mon–Fri: 9am–6pm • Sat–Sun: 8am–8pm</span>
|
||
</div>
|
||
</div>
|
||
<div>
|
||
<!-- Availability Calendar -->
|
||
<div class="cal-wrap" id="calWrap">
|
||
<div class="cal-header">
|
||
<button class="cal-nav" id="calPrev" aria-label="Previous month">‹</button>
|
||
<h3 id="calTitle">Loading…</h3>
|
||
<button class="cal-nav" id="calNext" aria-label="Next month">›</button>
|
||
</div>
|
||
<div class="cal-grid" id="calGrid">
|
||
<div class="cal-loading" style="grid-column:1/-1">Checking availability…</div>
|
||
</div>
|
||
<div class="cal-legend">
|
||
<div class="cal-legend-item"><div class="cal-legend-dot" style="background:rgba(255,255,255,0.12)"></div> Available</div>
|
||
<div class="cal-legend-item"><div class="cal-legend-dot" style="background:var(--orange)"></div> Selected</div>
|
||
<div class="cal-legend-item" id="legend-range" style="display:none"><div class="cal-legend-dot" style="background:rgba(249,115,22,0.35)"></div> In Range</div>
|
||
<div class="cal-legend-item"><div class="cal-legend-dot" style="background:rgba(239,68,68,0.35)"></div> Unavailable</div>
|
||
</div>
|
||
<p id="calHint" style="font-size:0.72rem;color:rgba(255,255,255,0.35);margin-top:0.5rem">Click a date to select it — click again to deselect. Weekend package shows both days automatically.</p>
|
||
</div>
|
||
|
||
<form class="contact-form" id="bookingForm" novalidate>
|
||
<div class="form-row">
|
||
<input type="text" name="name" placeholder="Your Name" required />
|
||
<input type="email" name="email" placeholder="Email Address" required />
|
||
</div>
|
||
<input type="tel" name="phone" placeholder="Phone Number" />
|
||
<select name="package" required>
|
||
<option value="">Select Rental Package</option>
|
||
<option value="half-day">Half Day — $99</option>
|
||
<option value="full-day">Full Day — $169</option>
|
||
<option value="weekend">Weekend — $299</option>
|
||
</select>
|
||
<input type="date" name="date" required />
|
||
<div id="date-unavail-msg" style="display:none;color:#f87171;font-size:.82rem;margin-top:.25rem">That date is already booked or unavailable. Please choose another.</div>
|
||
<textarea name="message" placeholder="Anything else we should know? (optional)"></textarea>
|
||
|
||
<!-- Square deposit card -->
|
||
<div style="background:rgba(255,255,255,0.04);border:1px solid rgba(255,255,255,0.1);border-radius:8px;padding:1rem;margin-top:0.25rem">
|
||
<div style="display:flex;justify-content:space-between;align-items:baseline;margin-bottom:0.5rem">
|
||
<p style="font-size:0.78rem;font-weight:700;text-transform:uppercase;letter-spacing:1px;color:rgba(249,115,22,0.8);margin:0">Deposit — $45 today</p>
|
||
<p id="balance-due-label" style="font-size:0.78rem;color:rgba(255,255,255,0.45);margin:0;display:none">Balance at pickup: <strong id="balance-due-amount" style="color:rgba(255,255,255,0.75)"></strong></p>
|
||
</div>
|
||
<p style="font-size:0.8rem;color:rgba(255,255,255,0.5);margin-bottom:0.85rem;line-height:1.5">A $45 hold is placed on your card to secure your date — <strong style="color:rgba(255,255,255,0.75)">not charged</strong> until confirmed. Remaining balance is due at pickup.</p>
|
||
<div id="card-container" style="min-height:44px"></div>
|
||
<p id="card-errors" style="color:#f87171;font-size:0.78rem;margin-top:0.4rem;display:none"></p>
|
||
<div id="deposit-status" style="display:none;margin-top:0.6rem;font-size:0.82rem;border-radius:6px;padding:0.5rem 0.75rem;line-height:1.5"></div>
|
||
</div>
|
||
|
||
<button type="submit" id="submitBtn">Submit Booking Request</button>
|
||
<div class="form-msg" id="formMsg"></div>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- Footer -->
|
||
<footer>
|
||
<p class="footer-logo">Parker County Slingshot Rentals</p>
|
||
<div class="footer-links">
|
||
<a href="#why">Why Us</a>
|
||
<a href="#pricing">Pricing</a>
|
||
<a href="#how">How It Works</a>
|
||
<a href="#routes">Routes</a>
|
||
<a href="#faq">FAQ</a>
|
||
<a href="#contact">Contact</a>
|
||
</div>
|
||
<p>© 2026 Parker County Slingshot Rentals — Weatherford, Texas. All rights reserved.</p>
|
||
<p style="margin-top:0.5rem;">Polaris Slingshot® is a registered trademark of Polaris Inc. We are an independent rental operator.</p>
|
||
</footer>
|
||
|
||
<script src="https://web.squarecdn.com/v1/square.js"></script>
|
||
<script>
|
||
// ── Mobile nav ───────────────────────────────────────────────────────────────
|
||
const navToggle = document.getElementById('navToggle');
|
||
const navDrawer = document.getElementById('navDrawer');
|
||
function closeDrawer() {
|
||
navToggle.classList.remove('open');
|
||
navDrawer.classList.remove('open');
|
||
navToggle.setAttribute('aria-expanded', 'false');
|
||
document.body.style.overflow = '';
|
||
}
|
||
navToggle.addEventListener('click', () => {
|
||
const isOpen = navDrawer.classList.toggle('open');
|
||
navToggle.classList.toggle('open', isOpen);
|
||
navToggle.setAttribute('aria-expanded', String(isOpen));
|
||
document.body.style.overflow = isOpen ? 'hidden' : '';
|
||
});
|
||
// Close on any link click inside drawer
|
||
navDrawer.querySelectorAll('a').forEach(a => a.addEventListener('click', closeDrawer));
|
||
// Close on Escape key
|
||
document.addEventListener('keydown', e => { if (e.key === 'Escape') closeDrawer(); });
|
||
|
||
// ── Availability Calendar ────────────────────────────────────────────────────
|
||
const dateInput = document.querySelector('input[type="date"]');
|
||
const calGrid = document.getElementById('calGrid');
|
||
const calTitle = document.getElementById('calTitle');
|
||
const DAY_NAMES = ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'];
|
||
const MONTH_NAMES = ['January','February','March','April','May','June','July','August','September','October','November','December'];
|
||
|
||
const todayStr = new Date().toISOString().split('T')[0];
|
||
if (dateInput) dateInput.min = todayStr;
|
||
|
||
let calYear = new Date().getFullYear();
|
||
let calMonth = new Date().getMonth() + 1; // 1-based
|
||
let bookedSet = new Set();
|
||
let selectedDates = new Set(); // all pinned start dates
|
||
let lastSelectedDate = null; // what goes in the booking form
|
||
let selectedPackage = 'half-day';
|
||
const availCache = {};
|
||
|
||
function getEndDateStr(startDate, pkg) {
|
||
if (!startDate || pkg !== 'weekend') return startDate;
|
||
const d = new Date(startDate + 'T12:00:00');
|
||
d.setDate(d.getDate() + 1);
|
||
return d.toISOString().split('T')[0];
|
||
}
|
||
|
||
async function fetchAvail(month, year) {
|
||
const key = year + '-' + String(month).padStart(2, '0');
|
||
if (!availCache[key]) {
|
||
const res = await fetch('/availability.php?month=' + month + '&year=' + year);
|
||
const data = await res.json();
|
||
availCache[key] = new Set(data.booked_dates || []);
|
||
}
|
||
return availCache[key];
|
||
}
|
||
|
||
async function hasRangeConflict(startDate, pkg) {
|
||
const endDate = getEndDateStr(startDate, pkg);
|
||
const dates = (endDate && endDate !== startDate) ? [startDate, endDate] : [startDate];
|
||
for (const date of dates) {
|
||
const [y, m] = date.split('-').map(Number);
|
||
const set = await fetchAvail(m, y);
|
||
if (set.has(date)) return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
function showDateUnavail() {
|
||
const msg = document.getElementById('date-unavail-msg');
|
||
if (msg) { msg.style.display = 'block'; setTimeout(() => msg.style.display = 'none', 5000); }
|
||
}
|
||
|
||
function updateLegend() {
|
||
const rangeItem = document.getElementById('legend-range');
|
||
const hint = document.getElementById('calHint');
|
||
const isWknd = selectedPackage === 'weekend';
|
||
if (rangeItem) rangeItem.style.display = isWknd ? 'flex' : 'none';
|
||
if (hint) hint.textContent = isWknd
|
||
? 'Click your start date — both weekend days highlight automatically.'
|
||
: 'Click any available date to select it.';
|
||
}
|
||
|
||
async function loadCalendar(month, year) {
|
||
calTitle.textContent = MONTH_NAMES[month - 1] + ' ' + year;
|
||
calGrid.innerHTML = '<div class="cal-loading" style="grid-column:1/-1">Checking availability…</div>';
|
||
try {
|
||
bookedSet = await fetchAvail(month, year);
|
||
renderCalendar(month, year);
|
||
} catch {
|
||
calGrid.innerHTML = '<div class="cal-loading" style="grid-column:1/-1;color:rgba(239,68,68,0.6)">Could not load availability.</div>';
|
||
}
|
||
}
|
||
|
||
function renderCalendar(month, year) {
|
||
const fragment = document.createDocumentFragment();
|
||
|
||
// Day-name headers
|
||
DAY_NAMES.forEach(d => {
|
||
const el = document.createElement('div');
|
||
el.className = 'cal-day-label';
|
||
el.textContent = d;
|
||
fragment.appendChild(el);
|
||
});
|
||
|
||
const firstDay = new Date(year, month - 1, 1).getDay(); // 0=Sun
|
||
const daysInMo = new Date(year, month, 0).getDate();
|
||
|
||
// Blank cells before first day
|
||
for (let i = 0; i < firstDay; i++) {
|
||
const el = document.createElement('div');
|
||
el.className = 'cal-day empty';
|
||
fragment.appendChild(el);
|
||
}
|
||
|
||
// Pre-compute all in-range dates across every selected start date
|
||
const inRangeDates = new Set();
|
||
for (const start of selectedDates) {
|
||
const endD = getEndDateStr(start, selectedPackage);
|
||
if (endD && endD !== start) {
|
||
const dd = new Date(start + 'T12:00:00'); dd.setDate(dd.getDate() + 1);
|
||
while (dd.toISOString().split('T')[0] <= endD) {
|
||
inRangeDates.add(dd.toISOString().split('T')[0]); dd.setDate(dd.getDate() + 1);
|
||
}
|
||
}
|
||
}
|
||
|
||
for (let d = 1; d <= daysInMo; d++) {
|
||
const dateStr = year + '-' + String(month).padStart(2,'0') + '-' + String(d).padStart(2,'0');
|
||
const el = document.createElement('div');
|
||
el.textContent = d;
|
||
|
||
const isPast = dateStr < todayStr;
|
||
const isBooked = bookedSet.has(dateStr);
|
||
const isToday = dateStr === todayStr;
|
||
const isSel = selectedDates.has(dateStr);
|
||
const isInRange = !isSel && inRangeDates.has(dateStr);
|
||
|
||
if (isSel) {
|
||
el.className = 'cal-day selected';
|
||
el.addEventListener('click', () => selectDate(dateStr)); // click again to deselect
|
||
} else if (isInRange) {
|
||
el.className = 'cal-day in-range' + (isBooked ? ' booked' : '');
|
||
el.title = isBooked ? 'Conflict — this day is unavailable' : 'In your booking range';
|
||
} else if (isPast) {
|
||
el.className = 'cal-day past';
|
||
} else if (isBooked) {
|
||
el.className = 'cal-day booked';
|
||
el.title = 'Unavailable';
|
||
} else {
|
||
el.className = 'cal-day available' + (isToday ? ' today' : '');
|
||
el.addEventListener('click', () => selectDate(dateStr));
|
||
}
|
||
|
||
fragment.appendChild(el);
|
||
}
|
||
|
||
calGrid.innerHTML = '';
|
||
calGrid.appendChild(fragment);
|
||
}
|
||
|
||
async function selectDate(dateStr) {
|
||
if (selectedDates.has(dateStr)) {
|
||
// Toggle off — deselect this date
|
||
selectedDates.delete(dateStr);
|
||
lastSelectedDate = selectedDates.size > 0
|
||
? [...selectedDates].sort().reverse()[0] : null;
|
||
} else {
|
||
if (await hasRangeConflict(dateStr, selectedPackage)) {
|
||
showDateUnavail(); return;
|
||
}
|
||
selectedDates.add(dateStr);
|
||
lastSelectedDate = dateStr;
|
||
document.getElementById('bookingForm').scrollIntoView({ behavior: 'smooth', block: 'start' });
|
||
}
|
||
if (dateInput) dateInput.value = lastSelectedDate || '';
|
||
renderCalendar(calMonth, calYear);
|
||
}
|
||
|
||
document.getElementById('calPrev').addEventListener('click', () => {
|
||
calMonth--;
|
||
if (calMonth < 1) { calMonth = 12; calYear--; }
|
||
loadCalendar(calMonth, calYear);
|
||
});
|
||
document.getElementById('calNext').addEventListener('click', () => {
|
||
calMonth++;
|
||
if (calMonth > 12) { calMonth = 1; calYear++; }
|
||
loadCalendar(calMonth, calYear);
|
||
});
|
||
|
||
// Initial load
|
||
loadCalendar(calMonth, calYear);
|
||
|
||
// Keep calendar in sync when user types a date manually; validate against availability
|
||
if (dateInput) {
|
||
dateInput.addEventListener('change', async () => {
|
||
const val = dateInput.value;
|
||
if (!val) return;
|
||
const [y, m] = val.split('-').map(Number);
|
||
if (m !== calMonth || y !== calYear) {
|
||
calMonth = m; calYear = y;
|
||
await loadCalendar(calMonth, calYear);
|
||
}
|
||
if (await hasRangeConflict(val, selectedPackage)) {
|
||
dateInput.value = lastSelectedDate || '';
|
||
showDateUnavail();
|
||
} else {
|
||
selectedDates.add(val);
|
||
lastSelectedDate = val;
|
||
const msg = document.getElementById('date-unavail-msg');
|
||
if (msg) msg.style.display = 'none';
|
||
}
|
||
renderCalendar(calMonth, calYear);
|
||
});
|
||
}
|
||
|
||
// ── Balance-due display ───────────────────────────────────────────────────────
|
||
const PACKAGE_PRICES = { 'half-day': 99, 'full-day': 169, 'weekend': 299 };
|
||
const DEPOSIT = 45;
|
||
const pkgSelect = document.querySelector('select[name="package"]');
|
||
const balLabel = document.getElementById('balance-due-label');
|
||
const balAmt = document.getElementById('balance-due-amount');
|
||
if (pkgSelect) { selectedPackage = pkgSelect.value || 'half-day'; }
|
||
if (pkgSelect) {
|
||
pkgSelect.addEventListener('change', function() {
|
||
selectedPackage = this.value;
|
||
updateLegend();
|
||
if (selectedDates.size > 0) {
|
||
Promise.all([...selectedDates].map(d => hasRangeConflict(d, selectedPackage).then(c => c ? d : null)))
|
||
.then(conflicts => {
|
||
conflicts.filter(Boolean).forEach(d => selectedDates.delete(d));
|
||
if (!selectedDates.has(lastSelectedDate)) lastSelectedDate = [...selectedDates].sort().reverse()[0] || null;
|
||
if (dateInput) dateInput.value = lastSelectedDate || '';
|
||
if (conflicts.some(Boolean)) showDateUnavail();
|
||
renderCalendar(calMonth, calYear);
|
||
});
|
||
} else { renderCalendar(calMonth, calYear); }
|
||
const price = PACKAGE_PRICES[this.value];
|
||
if (price && balLabel && balAmt) {
|
||
balAmt.textContent = '$' + (price - DEPOSIT).toFixed(2).replace(/\.00$/, '');
|
||
balLabel.style.display = '';
|
||
} else if (balLabel) {
|
||
balLabel.style.display = 'none';
|
||
}
|
||
});
|
||
}
|
||
|
||
// ── Square Web Payments ───────────────────────────────────────────────────────
|
||
let squareCard = null;
|
||
async function initSquare() {
|
||
if (!window.Square) return;
|
||
const cardEl = document.getElementById('card-container');
|
||
if (cardEl) cardEl.style.display = '';
|
||
try {
|
||
const payments = Square.payments('sq0idp-YSM7BU9IVyOWSzpeP-0nzQ', 'L8GZYHYKE95CE');
|
||
squareCard = await payments.card({
|
||
style: {
|
||
'.input-container': { borderColor: 'rgba(255,255,255,0.12)', borderRadius: '6px' },
|
||
'.input-container.is-focus': { borderColor: '#f97316' },
|
||
'.input-container.is-error': { borderColor: '#ef4444' },
|
||
'input': { color: '#ffffff', fontSize: '15px' },
|
||
'.message-text': { color: '#f87171' },
|
||
}
|
||
});
|
||
await squareCard.attach('#card-container');
|
||
} catch (e) {
|
||
console.warn('Square init error:', e);
|
||
}
|
||
}
|
||
initSquare();
|
||
|
||
// ── Booking Form ─────────────────────────────────────────────────────────────
|
||
document.getElementById('bookingForm').addEventListener('submit', async function(e) {
|
||
e.preventDefault();
|
||
const form = this;
|
||
const msg = document.getElementById('formMsg');
|
||
const btn = document.getElementById('submitBtn');
|
||
const cardErrors = document.getElementById('card-errors');
|
||
const depositStatus = document.getElementById('deposit-status');
|
||
|
||
btn.textContent = 'Processing…';
|
||
btn.disabled = true;
|
||
msg.className = 'form-msg';
|
||
msg.style.display = 'none';
|
||
if (cardErrors) { cardErrors.style.display = 'none'; cardErrors.textContent = ''; }
|
||
|
||
function setDepStatus(text, type) {
|
||
if (!depositStatus) return;
|
||
if (!text) { depositStatus.style.display = 'none'; depositStatus.textContent = ''; return; }
|
||
depositStatus.textContent = text;
|
||
depositStatus.style.display = 'block';
|
||
const map = {
|
||
processing: { background: 'rgba(249,115,22,0.1)', color: 'rgba(249,115,22,0.95)', border: '1px solid rgba(249,115,22,0.25)' },
|
||
success: { background: 'rgba(22,163,74,0.15)', color: '#86efac', border: '1px solid rgba(22,163,74,0.35)' },
|
||
error: { background: 'rgba(239,68,68,0.1)', color: '#fca5a5', border: '1px solid rgba(239,68,68,0.25)' },
|
||
};
|
||
Object.assign(depositStatus.style, map[type] || {});
|
||
}
|
||
|
||
try {
|
||
let squareToken = null;
|
||
if (squareCard) {
|
||
setDepStatus('Verifying card…', 'processing');
|
||
const result = await squareCard.tokenize();
|
||
if (result.status !== 'OK') {
|
||
const errMsg = result.errors ? result.errors.map(x => x.message).join(', ') : 'Card error — please check your details.';
|
||
if (cardErrors) { cardErrors.textContent = errMsg; cardErrors.style.display = 'block'; }
|
||
setDepStatus('', '');
|
||
btn.textContent = 'Submit Booking Request';
|
||
btn.disabled = false;
|
||
return;
|
||
}
|
||
squareToken = result.token;
|
||
setDepStatus('Card verified — authorizing $45 deposit hold…', 'processing');
|
||
}
|
||
|
||
const data = {
|
||
name: form.querySelector('[name="name"]').value,
|
||
email: form.querySelector('[name="email"]').value,
|
||
phone: form.querySelector('[name="phone"]').value,
|
||
package: form.querySelector('[name="package"]').value,
|
||
date: form.querySelector('[name="date"]').value,
|
||
message: form.querySelector('[name="message"]').value,
|
||
square_token: squareToken,
|
||
};
|
||
|
||
const res = await fetch('/contact.php', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data) });
|
||
const json = await res.json();
|
||
|
||
if (json.success) {
|
||
if (json.deposit_held) {
|
||
const holdSuffix = json.square_payment_id ? ' · Confirmation: …' + json.square_payment_id.slice(-10).toUpperCase() : '';
|
||
setDepStatus('✓ $45 deposit hold authorized' + holdSuffix, 'success');
|
||
const cardEl = document.getElementById('card-container');
|
||
if (cardEl) cardEl.style.display = 'none';
|
||
} else {
|
||
setDepStatus('', '');
|
||
}
|
||
|
||
msg.className = 'form-msg success';
|
||
msg.innerHTML = 'Booking request received! Your reference is <strong>' + json.ref + '</strong>. We\'ll be in touch shortly.';
|
||
msg.style.display = 'block';
|
||
form.reset();
|
||
if (squareCard) { squareCard.destroy(); squareCard = null; }
|
||
selectedDates.clear(); lastSelectedDate = null;
|
||
if (dateInput) dateInput.min = new Date().toISOString().split('T')[0];
|
||
btn.textContent = 'Request Sent!';
|
||
btn.style.background = '#16a34a';
|
||
loadCalendar(calMonth, calYear);
|
||
} else {
|
||
throw new Error(json.error || 'Something went wrong.');
|
||
}
|
||
} catch (err) {
|
||
setDepStatus('', '');
|
||
msg.className = 'form-msg error';
|
||
msg.textContent = err.message || 'Something went wrong. Please try again or call us directly.';
|
||
msg.style.display = 'block';
|
||
btn.textContent = 'Submit Booking Request';
|
||
btn.disabled = false;
|
||
}
|
||
});
|
||
</script>
|
||
</body>
|
||
</html>
|