-
Website Design
-
- Custom web design & user experience (UX) services
- Discovery, planning, & wireframing
- Website redesign & optimization
-
+
+
+
+
+
+ Custom web design & user experience (UX) services
+ Discovery, planning, & wireframing
+ Website redesign & optimization
+
+
-
-
-
Website Development
-
- Full-stack web development (Front-End & Back-End)
- Custom solutions (e.g., CMS, eCommerce, booking systems)
- Ongoing maintenance & support
-
+
+
+
+
+ Full-stack web development (Front-End & Back-End)
+ Custom solutions (e.g., CMS, eCommerce, booking systems)
+ Ongoing maintenance & support
+
+
-
-
-
Other Related Services
-
- Basic SEO setup & Google Analytics integration
- Hosting services
- Deployment
- E-commerce
-
+
+
+
+
+ Basic SEO setup & Google Analytics integration
+ Hosting services
+ Deployment
+ E-commerce
+
+
-
-
-
❯
-
+
+
+
+
diff --git a/src/scripts/carousel.js b/src/scripts/carousel.js
deleted file mode 100644
index e69de29..0000000
diff --git a/src/scripts/contact-form.js b/src/scripts/contact-form.js
index 05379d8..8c53ba9 100644
--- a/src/scripts/contact-form.js
+++ b/src/scripts/contact-form.js
@@ -23,6 +23,28 @@ form.addEventListener("submit", function(event) {
clearErrors(); // Clear previous errors
+ const honeypotField = document.getElementById("url").value.trim();
+ // Add the honeypot check at the top
+ if (honeypotField.length > 0) {
+ console.warn("Honeypot field was filled. Blocking submission.");
+ // You might want to display a message to the user,
+ // but it's often better to fail silently to not alert the bot.
+ // For debugging, you can add an alert:
+ // alert("Submission failed due to security check.");
+ return; // This is the most important part: stop the function here.
+ }
+
+ // Get the hCaptcha response token
+ const hCaptchaResponse = document.querySelector('[name="h-captcha-response"]').value;
+
+ // Check if the hCaptcha token is missing
+ if (!hCaptchaResponse) {
+ // You might want to display a user-facing error here
+ console.warn("hCaptcha token is missing. Submission blocked.");
+ alert("Please complete the hCaptcha verification.");
+ hasErrors = true;
+ }
+
// Get values
const firstName = document.getElementById("first-name").value.trim();
const lastName = document.getElementById("last-name").value.trim();
@@ -79,9 +101,45 @@ form.addEventListener("submit", function(event) {
}
if (!hasErrors) {
- alert("Form submitted successfully!");
- // form.submit(); // Uncomment when ready to send to server
- }
+ // Package the form data into an object
+ const formData = {
+ firstName: firstName,
+ lastName: lastName,
+ organization: organization,
+ email: email,
+ phone: phone,
+ contactMethod: contactMethod,
+ message: message,
+ url: honeypotField,
+ hCaptchaResponse: hCaptchaResponse
+ };
+
+ // Send the data to the backend using fetch()
+ fetch('/api/submit-form', {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify(formData), // Convert the data object to a JSON string
+ })
+ .then(response => {
+ if (response.ok) {
+ return response.json(); // Parse the JSON response
+ }
+ throw new Error('Network response was not ok.');
+ })
+ .then(data => {
+ // Success: handle the server's response
+ console.log('Success:', data);
+ alert('Form submitted successfully!');
+ form.reset(); // Optionally, reset the form after successful submission
+ })
+ .catch((error) => {
+ // Error: handle any network or server errors
+ console.error('Error:', error);
+ alert('An error occurred during submission. Please try again.');
+ });
+}
});
form.addEventListener("reset", function (event) {
diff --git a/src/scripts/services.js b/src/scripts/services.js
new file mode 100644
index 0000000..abbf761
--- /dev/null
+++ b/src/scripts/services.js
@@ -0,0 +1,17 @@
+document.addEventListener('DOMContentLoaded', function() {
+ const accordionHeaders = document.querySelectorAll('.accordion-header');
+
+ accordionHeaders.forEach(header => {
+ header.addEventListener('click', function() {
+ const content = this.nextElementSibling;
+
+ // Check if maxHeight has a value. If it does, the accordion is open.
+ if (content.style.maxHeight) {
+ content.style.maxHeight = null; // Close the accordion
+ } else {
+ // The accordion is closed, open it by setting max-height to its scroll height
+ content.style.maxHeight = content.scrollHeight + 'px';
+ }
+ });
+ });
+});
\ No newline at end of file
diff --git a/src/styles/about.css b/src/styles/about.css
index 3d3f6b9..0e21bc1 100644
--- a/src/styles/about.css
+++ b/src/styles/about.css
@@ -20,7 +20,7 @@ body {
}
.i-am {
- color: #ea7e0b;
+ color: #ca6e0b;
font-weight: bold;
}
@@ -42,7 +42,7 @@ body {
.click {
font-weight: bold;
- color:#ea7e0b;
+ color:#ca6e0b;
margin-top: 20px;
text-align: center;
}
@@ -81,7 +81,7 @@ body {
}
.w3-acag21 {
- color: #ea7e0b;
+ color: #ca6e0b;
}
/*? ↓ Contact Section Styles ↓ */
@@ -208,7 +208,7 @@ textarea:focus {
button[type="submit"], button[type="reset"] {
margin:20px 0px 20px 0px;
padding: 8px 25px;
- background-color: #ea7e0b;
+ background-color: #ca6e0b;
color: white;
border: none;
border-radius: 50px;
@@ -221,6 +221,10 @@ button[type="submit"]:hover, button[type="reset"]:hover {
background-color: #2e97be;
}
+.honeypot-field {
+ display: none;
+}
+
/* Responsive tweaks */
@media (max-width: 768px) {
.form-sections {
diff --git a/src/styles/index.css b/src/styles/index.css
index 27cbae5..91126d0 100644
--- a/src/styles/index.css
+++ b/src/styles/index.css
@@ -3,7 +3,7 @@ body {
background-image: url("/images/pattern-randomized.svg");
background-attachment: fixed;
background-size: cover;
-font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+ font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
}
.intro.module {
@@ -25,10 +25,11 @@ font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
.intro h1 {
color: #495057;
margin-bottom: 20px;
+ line-height: 1.2em;
}
.intro h1 .accent-name {
- color: #ea7e0b;
+ color: var(--primary-color);
}
.intro p {
@@ -54,8 +55,12 @@ font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
margin-bottom: 20px;
}
+.benefits-container h2, .accordion-container h2, .project-steps h2 {
+ font-color: #2e97be;
+}
+
.benefits-container p, .transition p {
- font-size: 1.2em;
+ font-size: 1.1em;
font-weight: 600;
}
@@ -68,6 +73,13 @@ font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
min-height: 150px;
}
+/* Correct media query to force a single column layout below 950px */
+@media (max-width: 950px) {
+ .benefits-visual {
+ grid-template-columns: 1fr;
+ }
+}
+
.benefits-card {
display: flex;
flex-direction: column;
@@ -78,7 +90,7 @@ font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
border-radius: 10px;
padding: 15px 10px 15px 10px;
text-align: center;
- box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.2);
transition: all 0.3s ease-in-out;
overflow: hidden;
}
@@ -86,7 +98,7 @@ font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
.benefits-card:hover {
transform: translateY(-5px);
background: linear-gradient(to right, #DDF0FF 0%, #fff 40%, #fff 60%, #DDF0FF 100%);
- box-shadow: 0 6px 12px rgba(0, 0, 0, 0.1);
+ box-shadow: 0 6px 12px rgba(0, 0, 0, 0.4);
}
.benefits-card h3 {
@@ -130,92 +142,114 @@ font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 1.4rem;
}
-
-
/*? ↓ Start Services Container ↓ */
-.carousel-container {
+.services-section.module {
+ max-width: 850px;
+}
+
+.accordion-container {
position: relative;
width: 100%;
max-width: 800px;
margin: 10px auto;
overflow: hidden;
- min-height: 400px;
+ min-height: 150px;
+ background-color: transparent; /* Ensure no background color is affecting the text */
}
-.carousel {
+.accordion-container h2, .accordion-container p {
+ margin-bottom: 20px;
+}
+
+.accordion-container p {
+ font-weight: 600;
+ color: #333333;
+}
+
+.accordion {
display: flex;
transition: transform 0.5s ease-in-out;
height: 100%;
}
-.service-cards {
- display: flex;
- flex-wrap: wrap;
- justify-content: center;
- gap: 20px;
+.accordion-item {
+ position: relative;
width: 100%;
- max-width: 1200px;
- margin: 50px auto;
-}
-
-.service-card {
- width: 300px;
- background-color: #ffffff;
- border: 1px solid #dee2e6;
+ background-color: #ffffff; /* Ensure a solid white background */
border-radius: 10px;
padding: 20px;
text-align: center;
box-sizing: border-box;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
+ opacity: 0.8;
+ transition: opacity 0.3s ease, transform 0.3s ease;
}
-.service-card h3 {
- font-size: 1.3em;
- color: #495057;
- background-color: #f8f9fa;
+.accordion-item.active {
+ opacity: 1; /* Fully opaque for the focused card */
+ transform: scale(1.1);
+ z-index: 1;
+ min-height: 318px; /* Ensure the focused card is above others */
+}
+
+/* Styles for an active (open) accordion item */
+.accordion-item.active .accordion-content {
+ max-height: 500px; /* This value should be large enough to contain all content */
+ padding: 15px; /* Adds padding back when open */
+ border-top: 1px solid #dee2e6; /* Adds a border to separate header and content */
+}
+
+.accordion-header {
+ width: 100%;
+ background-color: #ddf0ff;
border: 1px solid #dee2e6;
border-radius: 8px;
padding: 10px;
box-shadow: none;
margin-bottom: 15px;
-}
-
-.service-card li {
- padding: 10px;
- color: #495057;
-}
-
-.service-card ul {
- list-style: none;
- padding: 0;
-}
-
-.carousel-button {
- position: absolute;
- top: 50%;
- transform: translateY(-50%);
- background-color: rgba(46, 151, 190, 0.8);
- color: #fff;
- border: none;
- padding: 10px 15px;
- border-radius: 5px;
+ font-size: 1.3em;
+ color: #333333;
cursor: pointer;
- font-size: 20px;
- z-index: 1;
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.2);
transition: background-color 0.3s ease;
}
-.carousel-button:hover {
- background-color: #ea7e0b;
+.accordion-header:hover {
+ background-color: #ca6e0b;
+ color: #fff;
}
-.prev-button {
- left: 10px;
+.accordion-content {
+ max-height: 0;
+ overflow: hidden;
+ transition: max-height 0.3s ease;
+ background-color: #ffffff; /* Ensure a solid white background */
+ padding: 0 15px;
+ color: #333333; /* Explicitly set text color to dark gray */
}
-.next-button {
- right: 10px;
+.accordion-content ul {
+ list-style: none;
+ padding: 0;
+ min-height: 192px;
+}
+
+.accordion-content li {
+ padding: 10px;
+ color: #333333; /* Explicitly set text color to dark gray */
+}
+
+.hover-list {
+ transition: max-height 0.4s ease-in-out, opacity 0.4s ease-in-out;
+ max-height: 0;
+ opacity: 0;
+ overflow: hidden;
+}
+
+.hover-list.active {
+ max-height: 300px; /* Adjust this value if your lists get longer */
+ opacity: 1;
}
/*? ↓ Start CTA Section ↓ */
@@ -241,7 +275,7 @@ font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
display: inline-block;
padding: 8px 25px;
margin: 20px 0px 20px 0px;
- background-color: #ea7e0b;
+ background-color: #ca6e0b;
color: #fff;
text-decoration: none;
font-weight: 600;
@@ -256,7 +290,7 @@ font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
}
.demos-link:active, .cta-button:active {
- background-color: #ea7e0b;
+ background-color: #ca6e0b;
box-shadow: 0 4px 8px rgba(46, 151, 190, 0.2);
}
diff --git a/src/styles/variables.css b/src/styles/variables.css
index 1ad81ab..1a3363f 100644
--- a/src/styles/variables.css
+++ b/src/styles/variables.css
@@ -1,7 +1,7 @@
:root {
/* Color Palette */
--primary-color: #2e97be;
- --secondary-color: #ea7e0b;
+ --secondary-color: #ca6e0b;
--text-color: #495057;
--light-bg-color: #ffffff;
--light-gray-color: #f8f9fa;