Update team visibility and refresh premium UI styling
This commit is contained in:
@@ -91,13 +91,13 @@
|
|||||||
Oops! The page you're looking for doesn't exist or has been moved.
|
Oops! The page you're looking for doesn't exist or has been moved.
|
||||||
Let's get you back on track.
|
Let's get you back on track.
|
||||||
</p>
|
</p>
|
||||||
<a href="index.html" class="btn">
|
<a href="/index.html" class="btn">
|
||||||
<i class="fas fa-home"></i> Back to Homepage
|
<i class="fas fa-home"></i> Back to Homepage
|
||||||
</a>
|
</a>
|
||||||
<div class="links">
|
<div class="links">
|
||||||
<a href="services.html">Services</a>
|
<a href="/services.html">Services</a>
|
||||||
<a href="about.html">About Us</a>
|
<a href="/about.html">About Us</a>
|
||||||
<a href="contact.html">Contact</a>
|
<a href="/contact.html">Contact</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
+2
-63
@@ -218,7 +218,7 @@
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- Team Section -->
|
<!-- Team Section -->
|
||||||
<section class="team-section section" id="team">
|
<section class="team-section section" id="team" hidden>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="section-header">
|
<div class="section-header">
|
||||||
<span class="section-label">Our People</span>
|
<span class="section-label">Our People</span>
|
||||||
@@ -226,68 +226,7 @@
|
|||||||
<p class="section-description">Experts dedicated to building resilient, future-ready systems</p>
|
<p class="section-description">Experts dedicated to building resilient, future-ready systems</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="team-grid" id="team-grid" data-team-grid="true">
|
<div class="team-grid" id="team-grid" data-team-grid="true"></div>
|
||||||
<div class="team-card">
|
|
||||||
<div class="team-image">
|
|
||||||
<!-- Replace with real photo -->
|
|
||||||
<img src="images/team/member-1.svg" alt="Founder & CEO" width="400" height="400">
|
|
||||||
<div class="team-social">
|
|
||||||
<a href="https://www.linkedin.com/company/mspe-pro" aria-label="LinkedIn" target="_blank" rel="noopener noreferrer"><i class="fab fa-linkedin-in"></i></a>
|
|
||||||
<a href="mailto:info@mspe.pro" aria-label="Email"><i class="fas fa-envelope"></i></a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="team-info">
|
|
||||||
<h4>Kareem Mansour</h4>
|
|
||||||
<p>Founder & CEO</p>
|
|
||||||
<small style="font-size: 0.78rem; color: #64748b; line-height: 1.5; margin-top: 0.4rem; display: block;">Network & infrastructure specialist · 12+ yrs across enterprise and SMB environments.</small>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="team-card">
|
|
||||||
<div class="team-image">
|
|
||||||
<!-- Replace with real photo -->
|
|
||||||
<img src="images/team/member-2.svg" alt="CTO" width="400" height="400">
|
|
||||||
<div class="team-social">
|
|
||||||
<a href="https://www.linkedin.com/company/mspe-pro" aria-label="LinkedIn" target="_blank" rel="noopener noreferrer"><i class="fab fa-linkedin-in"></i></a>
|
|
||||||
<a href="mailto:info@mspe.pro" aria-label="Email"><i class="fas fa-envelope"></i></a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="team-info">
|
|
||||||
<h4>Nour Haddad</h4>
|
|
||||||
<p>Chief Technology Officer</p>
|
|
||||||
<small style="font-size: 0.78rem; color: #64748b; line-height: 1.5; margin-top: 0.4rem; display: block;">Systems architect with deep expertise in cloud platforms and enterprise IT design.</small>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="team-card">
|
|
||||||
<div class="team-image">
|
|
||||||
<!-- Replace with real photo -->
|
|
||||||
<img src="images/team/member-3.svg" alt="Security Lead" width="400" height="400">
|
|
||||||
<div class="team-social">
|
|
||||||
<a href="https://www.linkedin.com/company/mspe-pro" aria-label="LinkedIn" target="_blank" rel="noopener noreferrer"><i class="fab fa-linkedin-in"></i></a>
|
|
||||||
<a href="mailto:info@mspe.pro" aria-label="Email"><i class="fas fa-envelope"></i></a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="team-info">
|
|
||||||
<h4>Ranya Aziz</h4>
|
|
||||||
<p>Head of Cybersecurity</p>
|
|
||||||
<small style="font-size: 0.78rem; color: #64748b; line-height: 1.5; margin-top: 0.4rem; display: block;">Penetration tester and SIEM specialist · CEH certified and ISO 27001 lead auditor.</small>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="team-card">
|
|
||||||
<div class="team-image">
|
|
||||||
<!-- Replace with real photo -->
|
|
||||||
<img src="images/team/member-4.svg" alt="Cloud Architect" width="400" height="400">
|
|
||||||
<div class="team-social">
|
|
||||||
<a href="https://www.linkedin.com/company/mspe-pro" aria-label="LinkedIn" target="_blank" rel="noopener noreferrer"><i class="fab fa-linkedin-in"></i></a>
|
|
||||||
<a href="mailto:info@mspe.pro" aria-label="Email"><i class="fas fa-envelope"></i></a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="team-info">
|
|
||||||
<h4>Elie Khoury</h4>
|
|
||||||
<p>Cloud Solutions Architect</p>
|
|
||||||
<small style="font-size: 0.78rem; color: #64748b; line-height: 1.5; margin-top: 0.4rem; display: block;">Azure & AWS certified · specializes in cloud migration, hybrid infrastructure, and DevOps.</small>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,11 @@ require_once 'config.php';
|
|||||||
$method = $_SERVER['REQUEST_METHOD'];
|
$method = $_SERVER['REQUEST_METHOD'];
|
||||||
$id = $_GET['id'] ?? null;
|
$id = $_GET['id'] ?? null;
|
||||||
|
|
||||||
|
// CSRF protection for write operations
|
||||||
|
if ($method !== 'GET') {
|
||||||
|
requireSameOriginRequest();
|
||||||
|
}
|
||||||
|
|
||||||
switch ($method) {
|
switch ($method) {
|
||||||
case 'GET':
|
case 'GET':
|
||||||
if ($id) {
|
if ($id) {
|
||||||
|
|||||||
@@ -11,6 +11,11 @@ $method = $_SERVER['REQUEST_METHOD'];
|
|||||||
$id = $_GET['id'] ?? null;
|
$id = $_GET['id'] ?? null;
|
||||||
$type = $_GET['type'] ?? null; // 'global' for global sections
|
$type = $_GET['type'] ?? null; // 'global' for global sections
|
||||||
|
|
||||||
|
// CSRF protection for write operations
|
||||||
|
if ($method !== 'GET') {
|
||||||
|
requireSameOriginRequest();
|
||||||
|
}
|
||||||
|
|
||||||
switch ($method) {
|
switch ($method) {
|
||||||
case 'GET':
|
case 'GET':
|
||||||
if ($type === 'global') {
|
if ($type === 'global') {
|
||||||
|
|||||||
@@ -8,6 +8,11 @@ require_once 'config.php';
|
|||||||
$method = $_SERVER['REQUEST_METHOD'];
|
$method = $_SERVER['REQUEST_METHOD'];
|
||||||
$id = $_GET['id'] ?? null;
|
$id = $_GET['id'] ?? null;
|
||||||
|
|
||||||
|
// CSRF protection for write operations
|
||||||
|
if ($method !== 'GET') {
|
||||||
|
requireSameOriginRequest();
|
||||||
|
}
|
||||||
|
|
||||||
switch ($method) {
|
switch ($method) {
|
||||||
case 'GET':
|
case 'GET':
|
||||||
if ($id) {
|
if ($id) {
|
||||||
|
|||||||
@@ -8,6 +8,11 @@ require_once 'config.php';
|
|||||||
$method = $_SERVER['REQUEST_METHOD'];
|
$method = $_SERVER['REQUEST_METHOD'];
|
||||||
$id = $_GET['id'] ?? null;
|
$id = $_GET['id'] ?? null;
|
||||||
|
|
||||||
|
// CSRF protection for write operations
|
||||||
|
if ($method !== 'GET') {
|
||||||
|
requireSameOriginRequest();
|
||||||
|
}
|
||||||
|
|
||||||
switch ($method) {
|
switch ($method) {
|
||||||
case 'GET':
|
case 'GET':
|
||||||
if ($id) {
|
if ($id) {
|
||||||
|
|||||||
@@ -8,6 +8,11 @@ require_once 'config.php';
|
|||||||
$method = $_SERVER['REQUEST_METHOD'];
|
$method = $_SERVER['REQUEST_METHOD'];
|
||||||
$id = $_GET['id'] ?? null;
|
$id = $_GET['id'] ?? null;
|
||||||
|
|
||||||
|
// CSRF protection for write operations
|
||||||
|
if ($method !== 'GET') {
|
||||||
|
requireSameOriginRequest();
|
||||||
|
}
|
||||||
|
|
||||||
switch ($method) {
|
switch ($method) {
|
||||||
case 'GET':
|
case 'GET':
|
||||||
if ($id) {
|
if ($id) {
|
||||||
|
|||||||
@@ -8,6 +8,11 @@ require_once 'config.php';
|
|||||||
$method = $_SERVER['REQUEST_METHOD'];
|
$method = $_SERVER['REQUEST_METHOD'];
|
||||||
$id = $_GET['id'] ?? null;
|
$id = $_GET['id'] ?? null;
|
||||||
|
|
||||||
|
// CSRF protection for write operations
|
||||||
|
if ($method !== 'GET') {
|
||||||
|
requireSameOriginRequest();
|
||||||
|
}
|
||||||
|
|
||||||
switch ($method) {
|
switch ($method) {
|
||||||
case 'GET':
|
case 'GET':
|
||||||
if ($id) {
|
if ($id) {
|
||||||
|
|||||||
+1
-1
@@ -19,7 +19,7 @@ body.premium-ui .header {
|
|||||||
}
|
}
|
||||||
|
|
||||||
body.premium-ui .header.scrolled {
|
body.premium-ui .header.scrolled {
|
||||||
background: rgba(3, 7, 16, 0.97) !important;
|
background: rgba(14, 30, 52, 0.94) !important;
|
||||||
border-bottom: 1px solid rgba(148, 163, 184, 0.1) !important;
|
border-bottom: 1px solid rgba(148, 163, 184, 0.1) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+16
-2
@@ -53,6 +53,8 @@
|
|||||||
position: relative;
|
position: relative;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
max-width: 900px;
|
||||||
|
margin: 0 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.breadcrumb {
|
.breadcrumb {
|
||||||
@@ -89,6 +91,7 @@
|
|||||||
color: var(--text-white);
|
color: var(--text-white);
|
||||||
margin-bottom: 1rem;
|
margin-bottom: 1rem;
|
||||||
line-height: 1.2;
|
line-height: 1.2;
|
||||||
|
text-wrap: balance;
|
||||||
}
|
}
|
||||||
|
|
||||||
.page-subtitle {
|
.page-subtitle {
|
||||||
@@ -97,6 +100,7 @@
|
|||||||
max-width: 600px;
|
max-width: 600px;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
line-height: 1.7;
|
line-height: 1.7;
|
||||||
|
text-wrap: pretty;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ========================
|
/* ========================
|
||||||
@@ -747,7 +751,7 @@
|
|||||||
margin-bottom: 2rem;
|
margin-bottom: 2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.service-features {
|
.service-content .service-features {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 1fr 1fr;
|
grid-template-columns: 1fr 1fr;
|
||||||
gap: 1rem;
|
gap: 1rem;
|
||||||
@@ -1660,6 +1664,16 @@
|
|||||||
gap: 1.5rem;
|
gap: 1.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (min-width: 1201px) {
|
||||||
|
.contact-cards > :nth-child(5) {
|
||||||
|
grid-column: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-cards > :nth-child(6) {
|
||||||
|
grid-column: 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.contact-card {
|
.contact-card {
|
||||||
background: var(--text-white);
|
background: var(--text-white);
|
||||||
padding: 2rem;
|
padding: 2rem;
|
||||||
@@ -2197,7 +2211,7 @@
|
|||||||
grid-template-columns: repeat(2, 1fr);
|
grid-template-columns: repeat(2, 1fr);
|
||||||
}
|
}
|
||||||
|
|
||||||
.service-features,
|
.service-content .service-features,
|
||||||
.service-features-grid {
|
.service-features-grid {
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
}
|
}
|
||||||
|
|||||||
+42
-4
@@ -6,9 +6,9 @@
|
|||||||
/* ==================== CSS Variables ==================== */
|
/* ==================== CSS Variables ==================== */
|
||||||
:root {
|
:root {
|
||||||
/* Primary Colors */
|
/* Primary Colors */
|
||||||
--primary: #0a1628;
|
--primary: #10223b;
|
||||||
--primary-light: #1a365d;
|
--primary-light: #1f3f69;
|
||||||
--primary-dark: #050d17;
|
--primary-dark: #0b1930;
|
||||||
|
|
||||||
/* Accent Colors */
|
/* Accent Colors */
|
||||||
--accent: #0ea5e9;
|
--accent: #0ea5e9;
|
||||||
@@ -55,7 +55,7 @@
|
|||||||
--text-muted: #94a3b8;
|
--text-muted: #94a3b8;
|
||||||
|
|
||||||
/* Background Colors */
|
/* Background Colors */
|
||||||
--bg-dark: #0a1628;
|
--bg-dark: #122a47;
|
||||||
--bg-light: #f8fafc;
|
--bg-light: #f8fafc;
|
||||||
|
|
||||||
/* Border Color */
|
/* Border Color */
|
||||||
@@ -235,6 +235,7 @@ select {
|
|||||||
color: var(--gray-900);
|
color: var(--gray-900);
|
||||||
margin-bottom: var(--spacing-md);
|
margin-bottom: var(--spacing-md);
|
||||||
line-height: 1.2;
|
line-height: 1.2;
|
||||||
|
text-wrap: balance;
|
||||||
}
|
}
|
||||||
|
|
||||||
.section-description {
|
.section-description {
|
||||||
@@ -256,10 +257,13 @@ select {
|
|||||||
padding: 0.75rem 1.5rem;
|
padding: 0.75rem 1.5rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
font-size: 0.9375rem;
|
font-size: 0.9375rem;
|
||||||
|
line-height: 1.2;
|
||||||
|
min-height: 44px;
|
||||||
border-radius: var(--radius-md);
|
border-radius: var(--radius-md);
|
||||||
transition: var(--transition-base);
|
transition: var(--transition-base);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
border: 2px solid transparent;
|
border: 2px solid transparent;
|
||||||
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-primary {
|
.btn-primary {
|
||||||
@@ -532,6 +536,10 @@ select {
|
|||||||
gap: var(--spacing-md);
|
gap: var(--spacing-md);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.nav-actions .btn {
|
||||||
|
min-width: 168px;
|
||||||
|
}
|
||||||
|
|
||||||
.nav-toggle {
|
.nav-toggle {
|
||||||
display: none;
|
display: none;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@@ -641,6 +649,7 @@ select {
|
|||||||
word-break: normal;
|
word-break: normal;
|
||||||
overflow-wrap: normal;
|
overflow-wrap: normal;
|
||||||
hyphens: none;
|
hyphens: none;
|
||||||
|
text-wrap: balance;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hero-title .highlight {
|
.hero-title .highlight {
|
||||||
@@ -1049,6 +1058,23 @@ select {
|
|||||||
font-size: 0.75rem;
|
font-size: 0.75rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.frameworks-grid .service-title {
|
||||||
|
min-height: 2.8em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.frameworks-grid .service-description {
|
||||||
|
min-height: 5.6em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.frameworks-grid .service-features li {
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.frameworks-grid .service-features li i {
|
||||||
|
margin-top: 0.35em;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.service-link {
|
.service-link {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -1073,6 +1099,13 @@ select {
|
|||||||
color: var(--accent-light);
|
color: var(--accent-light);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (max-width: 1200px) {
|
||||||
|
.frameworks-grid .service-title,
|
||||||
|
.frameworks-grid .service-description {
|
||||||
|
min-height: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* ==================== Why Us Section ==================== */
|
/* ==================== Why Us Section ==================== */
|
||||||
.why-us {
|
.why-us {
|
||||||
background: #050810;
|
background: #050810;
|
||||||
@@ -1712,10 +1745,14 @@ select {
|
|||||||
.footer-logo {
|
.footer-logo {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
gap: 0.625rem;
|
gap: 0.625rem;
|
||||||
margin-bottom: var(--spacing-md);
|
margin-bottom: var(--spacing-md);
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.footer-logo img {
|
.footer-logo img {
|
||||||
@@ -1723,6 +1760,7 @@ select {
|
|||||||
height: 60px;
|
height: 60px;
|
||||||
width: auto;
|
width: auto;
|
||||||
max-width: 220px;
|
max-width: 220px;
|
||||||
|
margin: 0 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.footer-logo .logo-text {
|
.footer-logo .logo-text {
|
||||||
|
|||||||
+4
-3
@@ -107,10 +107,11 @@
|
|||||||
|
|
||||||
/* Enhanced Body Background */
|
/* Enhanced Body Background */
|
||||||
body {
|
body {
|
||||||
background: #050810;
|
background: #0d2038;
|
||||||
background-image:
|
background-image:
|
||||||
radial-gradient(ellipse at 0% 0%, rgba(0, 245, 255, 0.06) 0%, transparent 40%),
|
radial-gradient(ellipse at 0% 0%, rgba(0, 245, 255, 0.1) 0%, transparent 42%),
|
||||||
radial-gradient(ellipse at 100% 0%, rgba(181, 55, 242, 0.06) 0%, transparent 40%);
|
radial-gradient(ellipse at 100% 0%, rgba(181, 55, 242, 0.09) 0%, transparent 42%),
|
||||||
|
linear-gradient(180deg, #17335a 0%, #10223d 45%, #0d1d34 100%);
|
||||||
/* background-attachment: fixed removed — causes full repaint on every scroll */
|
/* background-attachment: fixed removed — causes full repaint on every scroll */
|
||||||
position: relative;
|
position: relative;
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
|
|||||||
+88
-2
@@ -6,6 +6,22 @@
|
|||||||
// API Base URL - adjust based on your hosting setup
|
// API Base URL - adjust based on your hosting setup
|
||||||
const API_BASE_URL = '/api';
|
const API_BASE_URL = '/api';
|
||||||
|
|
||||||
|
// Central icon map: change values here to swap icons site-wide where data-icon-key is used.
|
||||||
|
const ICON_CLASS_MAP = {
|
||||||
|
service_it_support: 'fas fa-headset',
|
||||||
|
service_cybersecurity: 'fas fa-shield-alt',
|
||||||
|
service_cloud: 'fas fa-cloud',
|
||||||
|
service_consulting: 'fas fa-chess-king',
|
||||||
|
framework_iso27001: 'fas fa-certificate',
|
||||||
|
framework_nist_csf: 'fas fa-sitemap',
|
||||||
|
framework_soc2: 'fas fa-user-shield',
|
||||||
|
framework_pci_dss: 'fas fa-credit-card',
|
||||||
|
framework_hipaa: 'fas fa-heartbeat',
|
||||||
|
framework_gdpr_ccpa: 'fas fa-scale-balanced',
|
||||||
|
framework_nist_800: 'fas fa-building-shield',
|
||||||
|
framework_cobit_telco: 'fas fa-network-wired'
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Escape HTML special characters to prevent XSS when inserting into innerHTML.
|
* Escape HTML special characters to prevent XSS when inserting into innerHTML.
|
||||||
* Use for ALL user/API data interpolated into template literals.
|
* Use for ALL user/API data interpolated into template literals.
|
||||||
@@ -40,6 +56,7 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
// Initialize all modules
|
// Initialize all modules
|
||||||
initPremiumExperience();
|
initPremiumExperience();
|
||||||
initSiteLinkEnhancements();
|
initSiteLinkEnhancements();
|
||||||
|
initReplaceableIcons();
|
||||||
optimizeImagesForCLS();
|
optimizeImagesForCLS();
|
||||||
loadPublicSiteSettings();
|
loadPublicSiteSettings();
|
||||||
initPreloader();
|
initPreloader();
|
||||||
@@ -62,6 +79,50 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
loadTeam();
|
loadTeam();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function sanitizeIconClasses(iconClasses, fallback = 'fas fa-circle') {
|
||||||
|
const tokens = String(iconClasses || '')
|
||||||
|
.trim()
|
||||||
|
.split(/\s+/)
|
||||||
|
.filter(Boolean)
|
||||||
|
.filter(token => /^fa[a-z0-9-]+$/i.test(token));
|
||||||
|
|
||||||
|
if (!tokens.length) {
|
||||||
|
return fallback.split(/\s+/);
|
||||||
|
}
|
||||||
|
|
||||||
|
const hasStyleToken = tokens.some(token => /^(fas|far|fab|fal|fat|fa-solid|fa-regular|fa-brands)$/i.test(token));
|
||||||
|
if (!hasStyleToken) {
|
||||||
|
tokens.unshift('fas');
|
||||||
|
}
|
||||||
|
|
||||||
|
return tokens;
|
||||||
|
}
|
||||||
|
|
||||||
|
function initReplaceableIcons(scope = document) {
|
||||||
|
const iconNodes = scope.querySelectorAll('[data-icon-key], [data-icon]');
|
||||||
|
if (!iconNodes.length) return;
|
||||||
|
|
||||||
|
iconNodes.forEach(node => {
|
||||||
|
const targetIcon = node.matches('i') ? node : node.querySelector('i');
|
||||||
|
if (!targetIcon) return;
|
||||||
|
|
||||||
|
const explicitIcon = node.getAttribute('data-icon') || targetIcon.getAttribute('data-icon');
|
||||||
|
const iconKey = node.getAttribute('data-icon-key') || targetIcon.getAttribute('data-icon-key');
|
||||||
|
const mappedIcon = iconKey ? ICON_CLASS_MAP[iconKey] : '';
|
||||||
|
const selected = explicitIcon || mappedIcon;
|
||||||
|
if (!selected) return;
|
||||||
|
|
||||||
|
Array.from(targetIcon.classList).forEach(cls => {
|
||||||
|
if (/^fa/i.test(cls)) {
|
||||||
|
targetIcon.classList.remove(cls);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
sanitizeIconClasses(selected).forEach(cls => targetIcon.classList.add(cls));
|
||||||
|
targetIcon.setAttribute('aria-hidden', 'true');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function initSiteLinkEnhancements() {
|
function initSiteLinkEnhancements() {
|
||||||
// Fallback social URLs: only used for placeholder links (href="#" or "javascript:void(0)").
|
// Fallback social URLs: only used for placeholder links (href="#" or "javascript:void(0)").
|
||||||
// Preferred approach: set correct URLs directly in HTML. These are a safety net.
|
// Preferred approach: set correct URLs directly in HTML. These are a safety net.
|
||||||
@@ -536,6 +597,7 @@ function animateCounter(element, target) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* ==================== Testimonials Slider ==================== */
|
/* ==================== Testimonials Slider ==================== */
|
||||||
|
let _testimonialInterval = null;
|
||||||
function initTestimonials() {
|
function initTestimonials() {
|
||||||
const testimonials = document.querySelectorAll('.testimonial-card');
|
const testimonials = document.querySelectorAll('.testimonial-card');
|
||||||
const prevBtn = document.querySelector('.testimonial-prev');
|
const prevBtn = document.querySelector('.testimonial-prev');
|
||||||
@@ -544,8 +606,17 @@ function initTestimonials() {
|
|||||||
|
|
||||||
if (!testimonials.length) return;
|
if (!testimonials.length) return;
|
||||||
|
|
||||||
|
// Clear any previous interval to prevent stacking
|
||||||
|
if (_testimonialInterval) {
|
||||||
|
clearInterval(_testimonialInterval);
|
||||||
|
_testimonialInterval = null;
|
||||||
|
}
|
||||||
|
|
||||||
let currentIndex = 0;
|
let currentIndex = 0;
|
||||||
|
|
||||||
|
// Clear previous dots before recreating
|
||||||
|
if (dotsContainer) dotsContainer.innerHTML = '';
|
||||||
|
|
||||||
// Create dots
|
// Create dots
|
||||||
testimonials.forEach((_, index) => {
|
testimonials.forEach((_, index) => {
|
||||||
const dot = document.createElement('span');
|
const dot = document.createElement('span');
|
||||||
@@ -587,7 +658,7 @@ function initTestimonials() {
|
|||||||
testimonialContainer.addEventListener('focusin', () => { testimonialPaused = true; });
|
testimonialContainer.addEventListener('focusin', () => { testimonialPaused = true; });
|
||||||
testimonialContainer.addEventListener('focusout', () => { testimonialPaused = false; });
|
testimonialContainer.addEventListener('focusout', () => { testimonialPaused = false; });
|
||||||
}
|
}
|
||||||
setInterval(() => {
|
_testimonialInterval = setInterval(() => {
|
||||||
if (!testimonialPaused) goToTestimonial(currentIndex + 1);
|
if (!testimonialPaused) goToTestimonial(currentIndex + 1);
|
||||||
}, 8000);
|
}, 8000);
|
||||||
}
|
}
|
||||||
@@ -951,7 +1022,7 @@ async function loadServices() {
|
|||||||
|
|
||||||
return `
|
return `
|
||||||
<div class="service-card" id="${escapeAttr(slug)}" data-aos="fade-up" data-aos-delay="${index * 100}">
|
<div class="service-card" id="${escapeAttr(slug)}" data-aos="fade-up" data-aos-delay="${index * 100}">
|
||||||
<div class="service-icon">
|
<div class="service-icon" data-icon="${escapeAttr(icon)}">
|
||||||
<i class="fas ${escapeAttr(icon)}"></i>
|
<i class="fas ${escapeAttr(icon)}"></i>
|
||||||
</div>
|
</div>
|
||||||
<h3 class="service-title">${escapeHTML(service.name || 'Service')}</h3>
|
<h3 class="service-title">${escapeHTML(service.name || 'Service')}</h3>
|
||||||
@@ -969,6 +1040,8 @@ async function loadServices() {
|
|||||||
servicesGrids.forEach(grid => {
|
servicesGrids.forEach(grid => {
|
||||||
grid.innerHTML = servicesMarkup;
|
grid.innerHTML = servicesMarkup;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
initReplaceableIcons();
|
||||||
} else {
|
} else {
|
||||||
// No API data returned — static fallback cards already rendered in HTML
|
// No API data returned — static fallback cards already rendered in HTML
|
||||||
}
|
}
|
||||||
@@ -981,9 +1054,15 @@ async function loadServices() {
|
|||||||
/* ==================== Load Team from API ==================== */
|
/* ==================== Load Team from API ==================== */
|
||||||
async function loadTeam() {
|
async function loadTeam() {
|
||||||
const teamGrid = document.querySelector('[data-team-grid]');
|
const teamGrid = document.querySelector('[data-team-grid]');
|
||||||
|
const teamSection = teamGrid ? teamGrid.closest('.team-section') : null;
|
||||||
|
|
||||||
if (!teamGrid) return;
|
if (!teamGrid) return;
|
||||||
|
|
||||||
|
// Keep hidden until admin-managed content exists
|
||||||
|
if (teamSection) {
|
||||||
|
teamSection.hidden = true;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`${API_BASE_URL}/team.php`);
|
const response = await fetch(`${API_BASE_URL}/team.php`);
|
||||||
const result = await response.json();
|
const result = await response.json();
|
||||||
@@ -1018,8 +1097,15 @@ async function loadTeam() {
|
|||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
}).join('');
|
}).join('');
|
||||||
|
|
||||||
|
if (teamSection) {
|
||||||
|
teamSection.hidden = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
teamGrid.innerHTML = '';
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
teamGrid.innerHTML = '';
|
||||||
console.log('Using static team content or API unavailable');
|
console.log('Using static team content or API unavailable');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+112
-4
@@ -158,7 +158,7 @@
|
|||||||
|
|
||||||
<div class="services-grid" data-services-grid="true">
|
<div class="services-grid" data-services-grid="true">
|
||||||
<div class="service-card" id="it-support">
|
<div class="service-card" id="it-support">
|
||||||
<div class="service-icon"><i class="fas fa-headset"></i></div>
|
<div class="service-icon" data-icon-key="service_it_support"><i class="fas fa-headset"></i></div>
|
||||||
<h3 class="service-title">IT Support & Maintenance</h3>
|
<h3 class="service-title">IT Support & Maintenance</h3>
|
||||||
<p class="service-description">Proactive managed IT support that keeps your systems running at peak performance. From helpdesk to infrastructure management, we handle it all.</p>
|
<p class="service-description">Proactive managed IT support that keeps your systems running at peak performance. From helpdesk to infrastructure management, we handle it all.</p>
|
||||||
<ul class="service-features">
|
<ul class="service-features">
|
||||||
@@ -169,7 +169,7 @@
|
|||||||
<a href="contact.html?service=it-support" class="service-link">Request Scope <i class="fas fa-arrow-right"></i></a>
|
<a href="contact.html?service=it-support" class="service-link">Request Scope <i class="fas fa-arrow-right"></i></a>
|
||||||
</div>
|
</div>
|
||||||
<div class="service-card" id="cybersecurity">
|
<div class="service-card" id="cybersecurity">
|
||||||
<div class="service-icon"><i class="fas fa-shield-alt"></i></div>
|
<div class="service-icon" data-icon-key="service_cybersecurity"><i class="fas fa-shield-alt"></i></div>
|
||||||
<h3 class="service-title">Cybersecurity Solutions</h3>
|
<h3 class="service-title">Cybersecurity Solutions</h3>
|
||||||
<p class="service-description">End-to-end security services to protect your business from evolving threats. Risk assessment, vulnerability management, and incident response.</p>
|
<p class="service-description">End-to-end security services to protect your business from evolving threats. Risk assessment, vulnerability management, and incident response.</p>
|
||||||
<ul class="service-features">
|
<ul class="service-features">
|
||||||
@@ -180,7 +180,7 @@
|
|||||||
<a href="contact.html?service=cybersecurity" class="service-link">Request Scope <i class="fas fa-arrow-right"></i></a>
|
<a href="contact.html?service=cybersecurity" class="service-link">Request Scope <i class="fas fa-arrow-right"></i></a>
|
||||||
</div>
|
</div>
|
||||||
<div class="service-card" id="cloud">
|
<div class="service-card" id="cloud">
|
||||||
<div class="service-icon"><i class="fas fa-cloud"></i></div>
|
<div class="service-icon" data-icon-key="service_cloud"><i class="fas fa-cloud"></i></div>
|
||||||
<h3 class="service-title">Cloud Services</h3>
|
<h3 class="service-title">Cloud Services</h3>
|
||||||
<p class="service-description">Cloud architecture, migration, and optimization. We design scalable, secure cloud environments tailored to your business needs.</p>
|
<p class="service-description">Cloud architecture, migration, and optimization. We design scalable, secure cloud environments tailored to your business needs.</p>
|
||||||
<ul class="service-features">
|
<ul class="service-features">
|
||||||
@@ -191,7 +191,7 @@
|
|||||||
<a href="contact.html?service=cloud" class="service-link">Request Scope <i class="fas fa-arrow-right"></i></a>
|
<a href="contact.html?service=cloud" class="service-link">Request Scope <i class="fas fa-arrow-right"></i></a>
|
||||||
</div>
|
</div>
|
||||||
<div class="service-card" id="consulting">
|
<div class="service-card" id="consulting">
|
||||||
<div class="service-icon"><i class="fas fa-chess-king"></i></div>
|
<div class="service-icon" data-icon-key="service_consulting"><i class="fas fa-chess-king"></i></div>
|
||||||
<h3 class="service-title">Strategic IT Consulting</h3>
|
<h3 class="service-title">Strategic IT Consulting</h3>
|
||||||
<p class="service-description">Expert guidance to align technology with your business goals. We deliver roadmaps, vendor selection, and digital transformation strategies.</p>
|
<p class="service-description">Expert guidance to align technology with your business goals. We deliver roadmaps, vendor selection, and digital transformation strategies.</p>
|
||||||
<ul class="service-features">
|
<ul class="service-features">
|
||||||
@@ -205,6 +205,114 @@
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<!-- Compliance & Frameworks Guide -->
|
||||||
|
<section class="services section" id="frameworks">
|
||||||
|
<div class="container">
|
||||||
|
<div class="section-header">
|
||||||
|
<span class="section-label">Compliance Guidance</span>
|
||||||
|
<h2 class="section-title">Which Security Framework Fits Your Industry?</h2>
|
||||||
|
<p class="section-description">Frameworks are not just checklists. They help you reduce risk, pass audits, and win client trust. We translate each framework into a practical roadmap your team can execute.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="services-grid frameworks-grid" aria-label="Cybersecurity frameworks explained">
|
||||||
|
<article class="service-card">
|
||||||
|
<div class="service-icon" data-icon-key="framework_iso27001"><i class="fas fa-certificate"></i></div>
|
||||||
|
<h3 class="service-title">ISO 27001</h3>
|
||||||
|
<p class="service-description"><strong>Best for:</strong> Organizations in regulated sectors or those selling B2B internationally.</p>
|
||||||
|
<ul class="service-features">
|
||||||
|
<li><i class="fas fa-check"></i> Information Security Management System (ISMS)</li>
|
||||||
|
<li><i class="fas fa-check"></i> Strong governance and audit readiness</li>
|
||||||
|
<li><i class="fas fa-check"></i> Often required in enterprise procurement</li>
|
||||||
|
</ul>
|
||||||
|
</article>
|
||||||
|
|
||||||
|
<article class="service-card">
|
||||||
|
<div class="service-icon" data-icon-key="framework_nist_csf"><i class="fas fa-sitemap"></i></div>
|
||||||
|
<h3 class="service-title">NIST Cybersecurity Framework</h3>
|
||||||
|
<p class="service-description"><strong>Best for:</strong> Critical infrastructure, large organizations, and mature risk programs.</p>
|
||||||
|
<ul class="service-features">
|
||||||
|
<li><i class="fas fa-check"></i> Identify, Protect, Detect, Respond, Recover</li>
|
||||||
|
<li><i class="fas fa-check"></i> Practical risk-based architecture</li>
|
||||||
|
<li><i class="fas fa-check"></i> Excellent baseline for long-term maturity</li>
|
||||||
|
</ul>
|
||||||
|
</article>
|
||||||
|
|
||||||
|
<article class="service-card">
|
||||||
|
<div class="service-icon" data-icon-key="framework_soc2"><i class="fas fa-user-shield"></i></div>
|
||||||
|
<h3 class="service-title">SOC 2</h3>
|
||||||
|
<p class="service-description"><strong>Best for:</strong> SaaS, MSPs, cloud service providers, and data-processing companies.</p>
|
||||||
|
<ul class="service-features">
|
||||||
|
<li><i class="fas fa-check"></i> Trust criteria: Security, Availability, Confidentiality</li>
|
||||||
|
<li><i class="fas fa-check"></i> Frequently requested by enterprise customers</li>
|
||||||
|
<li><i class="fas fa-check"></i> Strong commercial trust signal</li>
|
||||||
|
</ul>
|
||||||
|
</article>
|
||||||
|
|
||||||
|
<article class="service-card">
|
||||||
|
<div class="service-icon" data-icon-key="framework_pci_dss"><i class="fas fa-credit-card"></i></div>
|
||||||
|
<h3 class="service-title">PCI DSS</h3>
|
||||||
|
<p class="service-description"><strong>Best for:</strong> Merchants and businesses that store, process, or transmit card data.</p>
|
||||||
|
<ul class="service-features">
|
||||||
|
<li><i class="fas fa-check"></i> Payment card data protection controls</li>
|
||||||
|
<li><i class="fas fa-check"></i> Network segmentation and monitoring</li>
|
||||||
|
<li><i class="fas fa-check"></i> Mandatory for card-handling environments</li>
|
||||||
|
</ul>
|
||||||
|
</article>
|
||||||
|
|
||||||
|
<article class="service-card">
|
||||||
|
<div class="service-icon" data-icon-key="framework_hipaa"><i class="fas fa-heartbeat"></i></div>
|
||||||
|
<h3 class="service-title">HIPAA</h3>
|
||||||
|
<p class="service-description"><strong>Best for:</strong> Healthcare entities and vendors handling protected health information.</p>
|
||||||
|
<ul class="service-features">
|
||||||
|
<li><i class="fas fa-check"></i> Administrative, technical, and physical safeguards</li>
|
||||||
|
<li><i class="fas fa-check"></i> Data privacy and breach response expectations</li>
|
||||||
|
<li><i class="fas fa-check"></i> Essential for U.S. healthcare-related operations</li>
|
||||||
|
</ul>
|
||||||
|
</article>
|
||||||
|
|
||||||
|
<article class="service-card">
|
||||||
|
<div class="service-icon" data-icon-key="framework_gdpr_ccpa"><i class="fas fa-scale-balanced"></i></div>
|
||||||
|
<h3 class="service-title">GDPR & CCPA/CPRA</h3>
|
||||||
|
<p class="service-description"><strong>Best for:</strong> Organizations collecting personal data from EU or California residents.</p>
|
||||||
|
<ul class="service-features">
|
||||||
|
<li><i class="fas fa-check"></i> Privacy-by-design and data subject rights</li>
|
||||||
|
<li><i class="fas fa-check"></i> Consent, retention, and transparency controls</li>
|
||||||
|
<li><i class="fas fa-check"></i> Reduces legal and reputational exposure</li>
|
||||||
|
</ul>
|
||||||
|
</article>
|
||||||
|
|
||||||
|
<article class="service-card">
|
||||||
|
<div class="service-icon" data-icon-key="framework_nist_800"><i class="fas fa-building-shield"></i></div>
|
||||||
|
<h3 class="service-title">NIST SP 800-53 / 800-171</h3>
|
||||||
|
<p class="service-description"><strong>Best for:</strong> Government suppliers and organizations handling controlled data.</p>
|
||||||
|
<ul class="service-features">
|
||||||
|
<li><i class="fas fa-check"></i> Structured control catalog for federal ecosystems</li>
|
||||||
|
<li><i class="fas fa-check"></i> Required in many public-sector contracts</li>
|
||||||
|
<li><i class="fas fa-check"></i> Strong alignment with secure architecture practices</li>
|
||||||
|
</ul>
|
||||||
|
</article>
|
||||||
|
|
||||||
|
<article class="service-card">
|
||||||
|
<div class="service-icon" data-icon-key="framework_cobit_telco"><i class="fas fa-network-wired"></i></div>
|
||||||
|
<h3 class="service-title">COBIT / Telecom Frameworks</h3>
|
||||||
|
<p class="service-description"><strong>Best for:</strong> Telecom, utilities, and governance-heavy environments.</p>
|
||||||
|
<ul class="service-features">
|
||||||
|
<li><i class="fas fa-check"></i> Governance, control objectives, and accountability</li>
|
||||||
|
<li><i class="fas fa-check"></i> Useful for board-level reporting and assurance</li>
|
||||||
|
<li><i class="fas fa-check"></i> Helps connect cyber risk with business outcomes</li>
|
||||||
|
</ul>
|
||||||
|
</article>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="section-cta" style="margin-top: 2rem; text-align: center;">
|
||||||
|
<p style="margin-bottom: 1rem; color: var(--gray-500);">Not sure which framework applies to your business? We can map your obligations and priorities in one session.</p>
|
||||||
|
<a href="contact.html?service=cybersecurity" class="btn btn-primary">Get My Compliance Roadmap <i class="fas fa-arrow-right"></i></a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p style="margin-top: 1rem; text-align: center; font-size: 0.9rem; color: var(--gray-500);">Educational guidance only. Regulatory and legal requirements vary by jurisdiction and contract terms.</p>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
<!-- Pricing -->
|
<!-- Pricing -->
|
||||||
<section class="pricing section">
|
<section class="pricing section">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
|
|||||||
Reference in New Issue
Block a user