From e347292cacfae4330ceff07b3a614b11f61500b0 Mon Sep 17 00:00:00 2001 From: thijs Date: Fri, 8 May 2026 11:59:43 +0200 Subject: [PATCH] 2.0 --- assets/css/custom/modern.css | 1071 ++++++++++++++++++++++++++++++++++ assets/js/custom/modern.js | 409 +++++++++++++ index.html | 806 +++++++++++++------------ 3 files changed, 1906 insertions(+), 380 deletions(-) create mode 100644 assets/css/custom/modern.css create mode 100644 assets/js/custom/modern.js diff --git a/assets/css/custom/modern.css b/assets/css/custom/modern.css new file mode 100644 index 0000000..f23038e --- /dev/null +++ b/assets/css/custom/modern.css @@ -0,0 +1,1071 @@ +/* ============================================================ + OPZEKER IT — MODERN / FUTURISTIC REDESIGN + Design system, glassmorphism, gradients, scroll animations + ============================================================ */ + +/* ---------- Design Tokens ---------- */ +:root { + /* Brand */ + --c-bg: #05060d; + --c-bg-2: #0a0b18; + --c-surface: rgba(255, 255, 255, 0.04); + --c-surface-2: rgba(255, 255, 255, 0.07); + --c-border: rgba(255, 255, 255, 0.10); + --c-border-2: rgba(255, 255, 255, 0.18); + + --c-text: #e8ebff; + --c-text-dim: #a5acc9; + --c-text-mute: #6d7497; + + --c-primary: #9600f4; + --c-primary-2: #7100b7; + --c-accent: #00f2ff; + --c-accent-2: #00bbff; + --c-pink: #d42bff; + + --grad-brand: linear-gradient(135deg, #00f2ff 0%, #9600f4 60%, #d42bff 100%); + --grad-brand-soft: linear-gradient(135deg, rgba(0,242,255,.18), rgba(150,0,244,.18)); + --grad-cta: linear-gradient(90deg, #00f2ff 0%, #00bbff 100%); + --grad-text: linear-gradient(90deg, #00f2ff 0%, #d42bff 100%); + + /* Type */ + --f-sans: 'Inter', 'Space Grotesk', 'Source Sans Pro', system-ui, -apple-system, sans-serif; + --f-display: 'Space Grotesk', 'Inter', sans-serif; + --f-mono: 'JetBrains Mono', ui-monospace, 'SFMono-Regular', Menlo, monospace; + + /* Radii & shadows */ + --r-sm: 8px; + --r-md: 14px; + --r-lg: 20px; + --r-xl: 28px; + --r-pill: 999px; + + --shadow-glow: 0 0 40px rgba(150, 0, 244, .35); + --shadow-glow2: 0 0 60px rgba(0, 242, 255, .25); + --shadow-card: 0 10px 40px rgba(0, 0, 0, .35), inset 0 1px 0 rgba(255,255,255,.06); + + /* Motion */ + --ease-out: cubic-bezier(.22, 1, .36, 1); + --ease-in-out: cubic-bezier(.65, 0, .35, 1); +} + +/* ---------- Reset & base ---------- */ +*, +*::before, +*::after { box-sizing: border-box; } + +html { scroll-behavior: smooth; } + +body { + margin: 0; + font-family: var(--f-sans); + font-size: 16px; + line-height: 1.65; + color: var(--c-text); + background: var(--c-bg); + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + overflow-x: hidden; +} + +/* Animated aurora background behind everything */ +body::before { + content: ""; + position: fixed; + inset: 0; + z-index: -3; + background: + radial-gradient(1200px 600px at 15% 10%, rgba(150, 0, 244, .22), transparent 60%), + radial-gradient(900px 500px at 85% 20%, rgba(0, 187, 255, .18), transparent 60%), + radial-gradient(900px 700px at 50% 110%, rgba(212, 43, 255, .18), transparent 60%), + linear-gradient(180deg, #05060d 0%, #080a18 50%, #05060d 100%); + pointer-events: none; +} + +/* Subtle grid overlay */ +body::after { + content: ""; + position: fixed; + inset: 0; + z-index: -2; + background-image: + linear-gradient(to right, rgba(255,255,255,.035) 1px, transparent 1px), + linear-gradient(to bottom, rgba(255,255,255,.035) 1px, transparent 1px); + background-size: 64px 64px; + mask-image: radial-gradient(ellipse 80% 60% at 50% 40%, #000 40%, transparent 100%); + -webkit-mask-image: radial-gradient(ellipse 80% 60% at 50% 40%, #000 40%, transparent 100%); + pointer-events: none; +} + +img { max-width: 100%; height: auto; display: block; } +a { color: inherit; text-decoration: none; transition: color .25s var(--ease-out); } +a:hover { color: var(--c-accent); } + +h1, h2, h3, h4, h5 { + font-family: var(--f-display); + font-weight: 700; + letter-spacing: -0.02em; + line-height: 1.1; + margin: 0 0 .5em; + color: #fff; +} + +p { margin: 0 0 1em; color: var(--c-text-dim); } + +/* ---------- Layout helpers ---------- */ +.mx-container { + width: 100%; + max-width: 1240px; + margin: 0 auto; + padding: 0 clamp(20px, 4vw, 40px); +} + +.mx-section { + position: relative; + padding: clamp(80px, 12vw, 160px) 0; +} + +.mx-eyebrow { + display: inline-flex; + align-items: center; + gap: 10px; + font-family: var(--f-mono); + font-size: 12px; + letter-spacing: 0.2em; + text-transform: uppercase; + color: var(--c-accent); + padding: 8px 14px; + border-radius: var(--r-pill); + background: rgba(0, 242, 255, .06); + border: 1px solid rgba(0, 242, 255, .25); + backdrop-filter: blur(8px); + -webkit-backdrop-filter: blur(8px); + margin-bottom: 20px; +} +.mx-eyebrow::before { + content: ""; + width: 6px; + height: 6px; + border-radius: 50%; + background: var(--c-accent); + box-shadow: 0 0 10px var(--c-accent); + animation: pulse 2s infinite; +} + +@keyframes pulse { + 0%, 100% { opacity: 1; transform: scale(1); } + 50% { opacity: .5; transform: scale(1.3); } +} + +.mx-section-title { + font-size: clamp(32px, 5vw, 56px); + font-weight: 700; + margin-bottom: 16px; +} +.mx-section-title .grad { + background: var(--grad-text); + -webkit-background-clip: text; + background-clip: text; + -webkit-text-fill-color: transparent; + color: transparent; +} +.mx-section-subtitle { + font-size: clamp(15px, 1.4vw, 18px); + color: var(--c-text-dim); + max-width: 640px; + margin-bottom: 60px; +} + +/* ---------- Navigation ---------- */ +.mx-header { + position: fixed; + top: 0; + left: 0; + right: 0; + z-index: 100; + padding: 18px 0; + transition: all .35s var(--ease-out); +} +.mx-header.scrolled { + padding: 10px 0; + background: rgba(5, 6, 13, .75); + backdrop-filter: blur(16px) saturate(180%); + -webkit-backdrop-filter: blur(16px) saturate(180%); + border-bottom: 1px solid var(--c-border); +} +.mx-nav-inner { + display: flex; + align-items: center; + justify-content: space-between; + gap: 24px; +} +.mx-logo { + display: flex; + align-items: center; + gap: 12px; + font-family: var(--f-display); + font-weight: 700; + font-size: 20px; + color: #fff; + letter-spacing: -0.02em; +} +.mx-logo img { + height: 40px; + width: auto; + filter: drop-shadow(0 0 12px rgba(150, 0, 244, .4)); + transition: filter .3s; +} +.mx-logo:hover img { filter: drop-shadow(0 0 20px rgba(0, 242, 255, .6)); } + +.mx-nav-links { + display: flex; + align-items: center; + gap: 4px; + list-style: none; + margin: 0; + padding: 6px; + background: rgba(255, 255, 255, .03); + border: 1px solid var(--c-border); + border-radius: var(--r-pill); + backdrop-filter: blur(12px); + -webkit-backdrop-filter: blur(12px); +} +.mx-nav-links a { + display: inline-block; + padding: 8px 16px; + border-radius: var(--r-pill); + font-size: 14px; + font-weight: 500; + color: var(--c-text-dim); + transition: all .25s var(--ease-out); + position: relative; +} +.mx-nav-links a:hover, +.mx-nav-links a.active { + color: #fff; + background: rgba(255, 255, 255, .07); +} + +.mx-nav-cta { + display: inline-flex; + align-items: center; + gap: 8px; + padding: 10px 20px; + font-size: 14px; + font-weight: 600; + color: #05060d; + background: var(--grad-cta); + border-radius: var(--r-pill); + transition: all .3s var(--ease-out); + border: none; + cursor: pointer; +} +.mx-nav-cta:hover { + transform: translateY(-2px); + box-shadow: 0 10px 30px rgba(0, 242, 255, .35); + color: #05060d; +} + +.mx-burger { + display: none; + width: 40px; height: 40px; + border: 1px solid var(--c-border); + background: rgba(255,255,255,.04); + border-radius: 10px; + cursor: pointer; + padding: 0; + position: relative; +} +.mx-burger span, +.mx-burger::before, +.mx-burger::after { + content: ""; + position: absolute; + left: 10px; right: 10px; + height: 2px; + background: #fff; + border-radius: 2px; + transition: all .3s var(--ease-out); +} +.mx-burger::before { top: 13px; } +.mx-burger span { top: 19px; } +.mx-burger::after { top: 25px; } +.mx-burger.open::before { top: 19px; transform: rotate(45deg); } +.mx-burger.open span { opacity: 0; } +.mx-burger.open::after { top: 19px; transform: rotate(-45deg); } + +@media (max-width: 900px) { + .mx-nav-links, .mx-nav-cta { display: none; } + .mx-burger { display: inline-block; } + .mx-nav-links.mobile-open { + display: flex; + flex-direction: column; + align-items: stretch; + position: absolute; + top: 70px; left: 20px; right: 20px; + border-radius: var(--r-lg); + padding: 12px; + background: rgba(10, 11, 24, .95); + backdrop-filter: blur(20px); + -webkit-backdrop-filter: blur(20px); + } + .mx-nav-links.mobile-open a { padding: 14px 16px; text-align: left; } +} + +/* ---------- Buttons ---------- */ +.mx-btn { + display: inline-flex; + align-items: center; + justify-content: center; + gap: 10px; + padding: 14px 28px; + font-family: var(--f-sans); + font-size: 15px; + font-weight: 600; + letter-spacing: 0.01em; + border-radius: var(--r-pill); + cursor: pointer; + transition: all .3s var(--ease-out); + border: 1px solid transparent; + position: relative; + overflow: hidden; + white-space: nowrap; +} +.mx-btn .arrow { + transition: transform .3s var(--ease-out); +} +.mx-btn:hover .arrow { transform: translateX(4px); } + +.mx-btn-primary { + color: #05060d; + background: var(--grad-cta); + box-shadow: 0 8px 28px rgba(0, 242, 255, .25); +} +.mx-btn-primary:hover { + transform: translateY(-2px); + box-shadow: 0 14px 42px rgba(0, 242, 255, .45); + color: #05060d; +} + +.mx-btn-ghost { + color: #fff; + background: rgba(255, 255, 255, .04); + border-color: var(--c-border-2); + backdrop-filter: blur(8px); + -webkit-backdrop-filter: blur(8px); +} +.mx-btn-ghost:hover { + transform: translateY(-2px); + background: rgba(255, 255, 255, .08); + border-color: rgba(0, 242, 255, .5); + color: #fff; +} + +/* ---------- HERO ---------- */ +.mx-hero { + position: relative; + min-height: 100vh; + display: flex; + align-items: center; + justify-content: center; + overflow: hidden; + padding: 120px 0 80px; +} +#mx-webgl { + position: absolute; + inset: 0; + z-index: 0; + pointer-events: none; +} +.mx-hero::after { + content: ""; + position: absolute; + inset: 0; + background: radial-gradient(ellipse 60% 50% at 50% 50%, transparent 0%, rgba(5,6,13,.4) 70%, var(--c-bg) 100%); + pointer-events: none; + z-index: 1; +} +.mx-hero-content { + position: relative; + z-index: 2; + text-align: center; + max-width: 960px; + margin: 0 auto; +} +.mx-hero-badge { + display: inline-flex; + align-items: center; + gap: 10px; + padding: 8px 16px; + border: 1px solid var(--c-border-2); + background: rgba(255, 255, 255, .04); + backdrop-filter: blur(12px); + -webkit-backdrop-filter: blur(12px); + border-radius: var(--r-pill); + font-family: var(--f-mono); + font-size: 12px; + letter-spacing: 0.15em; + text-transform: uppercase; + color: var(--c-text-dim); + margin-bottom: 28px; +} +.mx-hero-badge .dot { + width: 8px; height: 8px; + border-radius: 50%; + background: #00ff9c; + box-shadow: 0 0 12px #00ff9c; + animation: pulse 2s infinite; +} +.mx-hero h1 { + font-size: clamp(42px, 7vw, 88px); + line-height: 1.02; + font-weight: 700; + letter-spacing: -0.03em; + margin-bottom: 24px; +} +.mx-hero h1 .grad { + background: var(--grad-text); + -webkit-background-clip: text; + background-clip: text; + -webkit-text-fill-color: transparent; + color: transparent; + display: inline-block; +} +.mx-hero .typed-line { + font-family: var(--f-mono); + font-size: clamp(16px, 2vw, 22px); + color: var(--c-accent); + margin-bottom: 20px; + min-height: 1.5em; +} +.mx-hero .typed-cursor { + display: inline-block; + margin-left: 2px; + font-weight: 400; + animation: blink 1s step-end infinite; +} +@keyframes blink { 50% { opacity: 0; } } + +.mx-hero p { + font-size: clamp(16px, 1.6vw, 20px); + color: var(--c-text-dim); + max-width: 680px; + margin: 0 auto 40px; +} +.mx-hero-ctas { + display: flex; + gap: 14px; + justify-content: center; + flex-wrap: wrap; +} + +/* Scroll indicator */ +.mx-scroll-indicator { + position: absolute; + bottom: 30px; + left: 50%; + transform: translateX(-50%); + z-index: 2; + color: var(--c-text-mute); + font-family: var(--f-mono); + font-size: 11px; + letter-spacing: 0.2em; + text-transform: uppercase; + display: flex; + flex-direction: column; + align-items: center; + gap: 10px; + opacity: .7; +} +.mx-scroll-indicator .line { + width: 1px; height: 40px; + background: linear-gradient(to bottom, transparent, var(--c-accent)); + animation: scroll-line 2s var(--ease-in-out) infinite; +} +@keyframes scroll-line { + 0% { transform: scaleY(0); transform-origin: top; } + 50% { transform: scaleY(1); transform-origin: top; } + 50.001% { transform-origin: bottom; } + 100% { transform: scaleY(0); transform-origin: bottom; } +} + +/* ---------- Trusted / Marquee ---------- */ +.mx-marquee { + padding: 30px 0; + border-top: 1px solid var(--c-border); + border-bottom: 1px solid var(--c-border); + overflow: hidden; + background: rgba(255,255,255,.015); +} +.mx-marquee-track { + display: flex; + gap: 80px; + animation: marquee 35s linear infinite; + width: max-content; +} +.mx-marquee-item { + font-family: var(--f-display); + font-weight: 600; + font-size: clamp(18px, 2vw, 26px); + color: var(--c-text-mute); + letter-spacing: 0.02em; + white-space: nowrap; + display: inline-flex; + align-items: center; + gap: 14px; +} +.mx-marquee-item::after { + content: "●"; + color: var(--c-accent); + font-size: 10px; + opacity: .5; +} +@keyframes marquee { to { transform: translateX(-50%); } } + +/* ---------- About / Split ---------- */ +.mx-about-grid { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 80px; + align-items: center; +} +@media (max-width: 900px) { .mx-about-grid { grid-template-columns: 1fr; gap: 50px; } } + +.mx-about-visual { + position: relative; + aspect-ratio: 1 / 1; + border-radius: var(--r-xl); + background: + radial-gradient(circle at 30% 30%, rgba(0,242,255,.3), transparent 50%), + radial-gradient(circle at 70% 70%, rgba(150,0,244,.35), transparent 50%), + linear-gradient(135deg, rgba(255,255,255,.05), rgba(255,255,255,.01)); + border: 1px solid var(--c-border); + overflow: hidden; + box-shadow: var(--shadow-card); +} +.mx-about-visual::before { + content: ""; + position: absolute; + inset: 0; + background-image: + linear-gradient(to right, rgba(255,255,255,.06) 1px, transparent 1px), + linear-gradient(to bottom, rgba(255,255,255,.06) 1px, transparent 1px); + background-size: 32px 32px; +} +.mx-about-visual .orb { + position: absolute; + top: 50%; left: 50%; + transform: translate(-50%, -50%); + width: 60%; + aspect-ratio: 1; + border-radius: 50%; + background: conic-gradient(from 0deg, #00f2ff, #9600f4, #d42bff, #00f2ff); + filter: blur(30px); + opacity: .6; + animation: spin 20s linear infinite; +} +.mx-about-visual .orb-core { + position: absolute; + top: 50%; left: 50%; + transform: translate(-50%, -50%); + width: 35%; + aspect-ratio: 1; + border-radius: 50%; + background: radial-gradient(circle, rgba(255,255,255,.9), rgba(255,255,255,.1) 40%, transparent 70%); + box-shadow: 0 0 80px rgba(0, 242, 255, .5); +} +.mx-about-visual .ring { + position: absolute; + top: 50%; left: 50%; + border: 1px solid rgba(255,255,255,.15); + border-radius: 50%; + transform: translate(-50%, -50%); + animation: spin 40s linear infinite; +} +.mx-about-visual .ring.r1 { width: 70%; aspect-ratio: 1; } +.mx-about-visual .ring.r2 { width: 90%; aspect-ratio: 1; animation-duration: 60s; animation-direction: reverse; } +.mx-about-visual .ring::after { + content: ""; + position: absolute; + top: -4px; left: 50%; + width: 8px; height: 8px; + background: var(--c-accent); + border-radius: 50%; + box-shadow: 0 0 20px var(--c-accent); +} +@keyframes spin { to { transform: translate(-50%, -50%) rotate(360deg); } } + +.mx-about-text h2 { font-size: clamp(32px, 4.5vw, 52px); margin-bottom: 20px; } +.mx-about-text h2 .grad { + background: var(--grad-text); + -webkit-background-clip: text; background-clip: text; + -webkit-text-fill-color: transparent; +} +.mx-about-text p { font-size: 17px; color: var(--c-text-dim); } +.mx-about-pills { + display: flex; + flex-wrap: wrap; + gap: 10px; + margin-top: 24px; +} +.mx-about-pills span { + font-family: var(--f-mono); + font-size: 12px; + padding: 7px 14px; + border-radius: var(--r-pill); + background: rgba(255,255,255,.04); + border: 1px solid var(--c-border); + color: var(--c-text); +} + +/* ---------- Stats ---------- */ +.mx-stats { + display: grid; + grid-template-columns: repeat(4, 1fr); + gap: 20px; +} +@media (max-width: 900px) { .mx-stats { grid-template-columns: repeat(2, 1fr); } } + +.mx-stat { + text-align: center; + padding: 32px 20px; + background: var(--c-surface); + border: 1px solid var(--c-border); + border-radius: var(--r-lg); + backdrop-filter: blur(8px); + -webkit-backdrop-filter: blur(8px); + position: relative; + overflow: hidden; + transition: all .4s var(--ease-out); +} +.mx-stat::before { + content: ""; + position: absolute; + top: 0; left: -100%; + width: 100%; height: 100%; + background: var(--grad-brand-soft); + transition: left .6s var(--ease-out); +} +.mx-stat:hover { + border-color: rgba(0, 242, 255, .4); + transform: translateY(-4px); +} +.mx-stat:hover::before { left: 0; } +.mx-stat > * { position: relative; z-index: 1; } +.mx-stat-num { + font-family: var(--f-display); + font-size: clamp(40px, 5vw, 60px); + font-weight: 700; + background: var(--grad-text); + -webkit-background-clip: text; background-clip: text; + -webkit-text-fill-color: transparent; + line-height: 1; + margin-bottom: 8px; +} +.mx-stat-label { + font-family: var(--f-mono); + font-size: 12px; + letter-spacing: 0.15em; + text-transform: uppercase; + color: var(--c-text-dim); +} + +/* ---------- Services ---------- */ +.mx-services-grid { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 22px; +} +@media (max-width: 1000px) { .mx-services-grid { grid-template-columns: repeat(2, 1fr); } } +@media (max-width: 640px) { .mx-services-grid { grid-template-columns: 1fr; } } + +.mx-service-card { + position: relative; + padding: 36px 30px; + background: var(--c-surface); + border: 1px solid var(--c-border); + border-radius: var(--r-xl); + backdrop-filter: blur(10px); + -webkit-backdrop-filter: blur(10px); + overflow: hidden; + transition: transform .5s var(--ease-out), border-color .3s, box-shadow .3s; + isolation: isolate; +} +.mx-service-card::before { + content: ""; + position: absolute; + inset: 0; + background: radial-gradient(600px circle at var(--mx, 50%) var(--my, 50%), rgba(0, 242, 255, .15), transparent 40%); + opacity: 0; + transition: opacity .3s; + pointer-events: none; + z-index: 0; +} +.mx-service-card::after { + content: ""; + position: absolute; + inset: -1px; + border-radius: inherit; + padding: 1px; + background: linear-gradient(135deg, rgba(0, 242, 255, .5), transparent 40%, transparent 60%, rgba(212, 43, 255, .5)); + -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0); + mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0); + -webkit-mask-composite: xor; + mask-composite: exclude; + opacity: 0; + transition: opacity .3s; + pointer-events: none; + z-index: 1; +} +.mx-service-card:hover { transform: translateY(-6px); } +.mx-service-card:hover::before { opacity: 1; } +.mx-service-card:hover::after { opacity: 1; } +.mx-service-card > * { position: relative; z-index: 2; } + +.mx-service-icon { + width: 56px; height: 56px; + display: inline-flex; + align-items: center; + justify-content: center; + border-radius: var(--r-md); + background: var(--grad-brand-soft); + border: 1px solid var(--c-border-2); + color: var(--c-accent); + font-size: 24px; + margin-bottom: 22px; + box-shadow: inset 0 1px 0 rgba(255,255,255,.08); +} +.mx-service-card h3 { + font-size: 22px; + margin-bottom: 12px; +} +.mx-service-card p { font-size: 15px; color: var(--c-text-dim); margin: 0 0 20px; } +.mx-service-card .arrow-link { + display: inline-flex; + align-items: center; + gap: 8px; + font-family: var(--f-mono); + font-size: 12px; + letter-spacing: 0.15em; + text-transform: uppercase; + color: var(--c-accent); + transition: gap .3s; +} +.mx-service-card .arrow-link:hover { gap: 14px; } + +/* ---------- Tech stack ---------- */ +.mx-tech-grid { + display: grid; + grid-template-columns: repeat(6, 1fr); + gap: 14px; +} +@media (max-width: 900px) { .mx-tech-grid { grid-template-columns: repeat(3, 1fr); } } +@media (max-width: 480px) { .mx-tech-grid { grid-template-columns: repeat(2, 1fr); } } + +.mx-tech { + aspect-ratio: 1 / 1; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 10px; + padding: 16px; + background: var(--c-surface); + border: 1px solid var(--c-border); + border-radius: var(--r-md); + backdrop-filter: blur(8px); + -webkit-backdrop-filter: blur(8px); + transition: all .3s var(--ease-out); + text-align: center; + color: var(--c-text-dim); +} +.mx-tech i { font-size: 34px; transition: color .3s, transform .3s; } +.mx-tech span { + font-family: var(--f-mono); + font-size: 11px; + letter-spacing: 0.1em; + text-transform: uppercase; +} +.mx-tech:hover { + background: rgba(0, 242, 255, .06); + border-color: rgba(0, 242, 255, .4); + color: #fff; + transform: translateY(-4px); +} +.mx-tech:hover i { color: var(--c-accent); transform: scale(1.15); } + +/* ---------- Process ---------- */ +.mx-process { + display: grid; + grid-template-columns: repeat(4, 1fr); + gap: 20px; + position: relative; +} +@media (max-width: 900px) { .mx-process { grid-template-columns: 1fr 1fr; } } +@media (max-width: 520px) { .mx-process { grid-template-columns: 1fr; } } + +.mx-process-step { + position: relative; + padding: 30px 24px; + background: var(--c-surface); + border: 1px solid var(--c-border); + border-radius: var(--r-lg); + backdrop-filter: blur(8px); + -webkit-backdrop-filter: blur(8px); + transition: all .4s var(--ease-out); +} +.mx-process-step:hover { + border-color: var(--c-border-2); + transform: translateY(-4px); + box-shadow: 0 20px 50px rgba(0,0,0,.4); +} +.mx-process-num { + font-family: var(--f-mono); + font-size: 12px; + letter-spacing: 0.2em; + color: var(--c-accent); + margin-bottom: 16px; +} +.mx-process-step h4 { font-size: 19px; margin-bottom: 10px; } +.mx-process-step p { font-size: 14px; color: var(--c-text-dim); margin: 0; } + +/* ---------- Skills (progress bars redesigned) ---------- */ +.mx-skills-wrap { + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 22px 60px; +} +@media (max-width: 700px) { .mx-skills-wrap { grid-template-columns: 1fr; } } + +.mx-skill { + display: grid; + grid-template-columns: 1fr auto; + align-items: baseline; + gap: 0 12px; + padding-bottom: 14px; + border-bottom: 1px solid var(--c-border); +} +.mx-skill-name { + font-family: var(--f-mono); + font-size: 13px; + color: var(--c-text); + letter-spacing: 0.06em; +} +.mx-skill-val { + font-family: var(--f-mono); + font-size: 13px; + color: var(--c-accent); +} +.mx-skill-track { + grid-column: 1 / -1; + margin-top: 10px; + height: 4px; + background: rgba(255,255,255,.06); + border-radius: 2px; + overflow: hidden; + position: relative; +} +.mx-skill-bar { + position: absolute; + top: 0; left: 0; + height: 100%; + width: 0; + background: var(--grad-cta); + border-radius: 2px; + box-shadow: 0 0 12px rgba(0, 242, 255, .6); + transition: width 1.4s var(--ease-out); +} + +/* ---------- CTA banner ---------- */ +.mx-cta-banner { + position: relative; + padding: clamp(50px, 8vw, 90px) clamp(30px, 6vw, 80px); + border-radius: var(--r-xl); + background: + radial-gradient(800px 300px at 10% 0%, rgba(0, 242, 255, .25), transparent 60%), + radial-gradient(800px 400px at 100% 100%, rgba(150, 0, 244, .35), transparent 60%), + linear-gradient(180deg, rgba(255,255,255,.03), rgba(255,255,255,.01)); + border: 1px solid var(--c-border-2); + overflow: hidden; + text-align: center; + box-shadow: var(--shadow-card); +} +.mx-cta-banner::before { + content: ""; + position: absolute; + inset: 0; + background-image: + linear-gradient(to right, rgba(255,255,255,.04) 1px, transparent 1px), + linear-gradient(to bottom, rgba(255,255,255,.04) 1px, transparent 1px); + background-size: 48px 48px; + mask-image: radial-gradient(ellipse 80% 100% at 50% 50%, #000, transparent 80%); + -webkit-mask-image: radial-gradient(ellipse 80% 100% at 50% 50%, #000, transparent 80%); + pointer-events: none; +} +.mx-cta-banner > * { position: relative; } +.mx-cta-banner h2 { + font-size: clamp(30px, 5vw, 52px); + margin-bottom: 16px; +} +.mx-cta-banner h2 .grad { + background: var(--grad-text); + -webkit-background-clip: text; background-clip: text; + -webkit-text-fill-color: transparent; +} +.mx-cta-banner p { + font-size: 17px; + color: var(--c-text-dim); + max-width: 560px; + margin: 0 auto 32px; +} + +/* ---------- Contact ---------- */ +.mx-contact-grid { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 50px; + align-items: start; +} +@media (max-width: 900px) { .mx-contact-grid { grid-template-columns: 1fr; } } + +.mx-contact-info h2 { font-size: clamp(32px, 4.5vw, 52px); margin-bottom: 16px; } +.mx-contact-info h2 .grad { + background: var(--grad-text); + -webkit-background-clip: text; background-clip: text; + -webkit-text-fill-color: transparent; +} +.mx-contact-info p { font-size: 17px; color: var(--c-text-dim); margin-bottom: 32px; } + +.mx-contact-card { + padding: 36px; + background: var(--c-surface); + border: 1px solid var(--c-border-2); + border-radius: var(--r-xl); + backdrop-filter: blur(12px); + -webkit-backdrop-filter: blur(12px); + box-shadow: var(--shadow-card); +} +.mx-contact-list { + list-style: none; + padding: 0; + margin: 0; + display: flex; + flex-direction: column; + gap: 16px; +} +.mx-contact-list li { + display: flex; + align-items: center; + gap: 16px; + padding: 18px; + background: rgba(255,255,255,.03); + border: 1px solid var(--c-border); + border-radius: var(--r-md); + transition: all .3s var(--ease-out); +} +.mx-contact-list li:hover { + background: rgba(0, 242, 255, .06); + border-color: rgba(0, 242, 255, .35); + transform: translateX(4px); +} +.mx-contact-icon { + width: 42px; height: 42px; + display: inline-flex; + align-items: center; + justify-content: center; + border-radius: var(--r-sm); + background: var(--grad-brand-soft); + color: var(--c-accent); + font-size: 16px; + flex-shrink: 0; +} +.mx-contact-meta { + font-family: var(--f-mono); + font-size: 11px; + letter-spacing: 0.15em; + text-transform: uppercase; + color: var(--c-text-mute); + margin: 0; +} +.mx-contact-val { + color: #fff; + font-size: 16px; + margin: 0; + font-weight: 500; +} + +.mx-socials { + display: flex; + gap: 10px; + margin-top: 28px; +} +.mx-socials a { + width: 44px; height: 44px; + display: inline-flex; + align-items: center; + justify-content: center; + border-radius: 50%; + background: rgba(255,255,255,.04); + border: 1px solid var(--c-border); + color: var(--c-text); + font-size: 18px; + transition: all .3s var(--ease-out); +} +.mx-socials a:hover { + background: var(--grad-cta); + color: #05060d; + border-color: transparent; + transform: translateY(-3px); + box-shadow: 0 10px 24px rgba(0, 242, 255, .35); +} + +/* ---------- Footer ---------- */ +.mx-footer { + padding: 40px 0; + border-top: 1px solid var(--c-border); + text-align: center; + color: var(--c-text-mute); + font-size: 14px; + background: rgba(0,0,0,.2); +} +.mx-footer a { color: var(--c-text); } +.mx-footer a:hover { color: var(--c-accent); } + +/* ---------- Reveal on scroll ---------- */ +.reveal { + opacity: 0; + transform: translateY(30px); + transition: opacity .9s var(--ease-out), transform .9s var(--ease-out); + will-change: transform, opacity; +} +.reveal.is-visible { + opacity: 1; + transform: translateY(0); +} +.reveal.delay-1 { transition-delay: .1s; } +.reveal.delay-2 { transition-delay: .2s; } +.reveal.delay-3 { transition-delay: .3s; } +.reveal.delay-4 { transition-delay: .4s; } + +/* ---------- Reduced motion ---------- */ +@media (prefers-reduced-motion: reduce) { + *, *::before, *::after { + animation-duration: .01ms !important; + transition-duration: .01ms !important; + } + .reveal { opacity: 1; transform: none; } +} + +/* ---------- Hide old theme artefacts if still loaded ---------- */ +.mx-hide-legacy #st-logo, +.mx-hide-legacy #st-nav, +.mx-hide-legacy header:not(.mx-header), +.mx-hide-legacy .hero-section-2, +.mx-hide-legacy .about-section, +.mx-hide-legacy .services-section, +.mx-hide-legacy .quote-section, +.mx-hide-legacy .call-to-section, +.mx-hide-legacy .skills-section, +.mx-hide-legacy .image-section, +.mx-hide-legacy .contact-section, +.mx-hide-legacy > footer:not(.mx-footer) { display: none !important; } diff --git a/assets/js/custom/modern.js b/assets/js/custom/modern.js new file mode 100644 index 0000000..8c718dd --- /dev/null +++ b/assets/js/custom/modern.js @@ -0,0 +1,409 @@ +/* ============================================================ + OPZEKER IT — MODERN JS + - Three.js animated WebGL hero (particle network / torus knot) + - Typed text rotator + - Scroll reveal (IntersectionObserver) + - Spotlight hover on service cards + - Magnetic nav, sticky header, scrollspy, smooth scroll + - Counter up, skill bars animation + ============================================================ */ +(function () { + 'use strict'; + + /* ---------- Helpers ---------- */ + const $ = (s, r = document) => r.querySelector(s); + const $$ = (s, r = document) => Array.from(r.querySelectorAll(s)); + const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches; + + /* ============================================================ + 1. THREE.JS WEBGL HERO BACKGROUND + Dynamic particle network + glowing torus knot + ============================================================ */ + function initWebGLHero() { + const container = document.getElementById('mx-webgl'); + if (!container || typeof THREE === 'undefined') return; + + const scene = new THREE.Scene(); + const camera = new THREE.PerspectiveCamera( + 55, + container.clientWidth / container.clientHeight, + 0.1, + 1000 + ); + camera.position.z = 18; + + const renderer = new THREE.WebGLRenderer({ + antialias: true, + alpha: true, + powerPreference: 'high-performance' + }); + renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)); + renderer.setSize(container.clientWidth, container.clientHeight); + renderer.setClearColor(0x000000, 0); + container.appendChild(renderer.domElement); + + /* ----- Glowing torus knot (center hero object) ----- */ + const knotGeo = new THREE.TorusKnotGeometry(3.2, 0.55, 220, 28, 2, 3); + const knotMat = new THREE.MeshBasicMaterial({ + color: 0x9600f4, + wireframe: true, + transparent: true, + opacity: 0.28 + }); + const knot = new THREE.Mesh(knotGeo, knotMat); + scene.add(knot); + + // Second ghostly knot for parallax + const knot2Mat = new THREE.MeshBasicMaterial({ + color: 0x00f2ff, + wireframe: true, + transparent: true, + opacity: 0.18 + }); + const knot2 = new THREE.Mesh(knotGeo, knot2Mat); + knot2.scale.setScalar(1.15); + scene.add(knot2); + + /* ----- Particle starfield ----- */ + const particleCount = prefersReducedMotion ? 400 : 1400; + const positions = new Float32Array(particleCount * 3); + const colors = new Float32Array(particleCount * 3); + const colorA = new THREE.Color(0x00f2ff); + const colorB = new THREE.Color(0xd42bff); + + for (let i = 0; i < particleCount; i++) { + const i3 = i * 3; + // distribute in a large sphere shell + const r = 10 + Math.random() * 30; + const theta = Math.random() * Math.PI * 2; + const phi = Math.acos(2 * Math.random() - 1); + positions[i3] = r * Math.sin(phi) * Math.cos(theta); + positions[i3 + 1] = r * Math.sin(phi) * Math.sin(theta); + positions[i3 + 2] = r * Math.cos(phi); + + const c = colorA.clone().lerp(colorB, Math.random()); + colors[i3] = c.r; + colors[i3 + 1] = c.g; + colors[i3 + 2] = c.b; + } + + const pGeo = new THREE.BufferGeometry(); + pGeo.setAttribute('position', new THREE.BufferAttribute(positions, 3)); + pGeo.setAttribute('color', new THREE.BufferAttribute(colors, 3)); + + const pMat = new THREE.PointsMaterial({ + size: 0.08, + vertexColors: true, + transparent: true, + opacity: 0.9, + sizeAttenuation: true, + blending: THREE.AdditiveBlending, + depthWrite: false + }); + const points = new THREE.Points(pGeo, pMat); + scene.add(points); + + /* ----- Interaction: mouse parallax ----- */ + const target = { x: 0, y: 0 }; + const current = { x: 0, y: 0 }; + + container.parentElement.addEventListener('mousemove', (e) => { + const rect = container.getBoundingClientRect(); + target.x = ((e.clientX - rect.left) / rect.width - 0.5) * 2; + target.y = ((e.clientY - rect.top) / rect.height - 0.5) * 2; + }); + + /* ----- Resize ----- */ + function onResize() { + const w = container.clientWidth; + const h = container.clientHeight; + camera.aspect = w / h; + camera.updateProjectionMatrix(); + renderer.setSize(w, h); + } + window.addEventListener('resize', onResize); + + /* ----- Animate ----- */ + let rafId; + const clock = new THREE.Clock(); + function animate() { + const t = clock.getElapsedTime(); + + // Smooth mouse lerp + current.x += (target.x - current.x) * 0.05; + current.y += (target.y - current.y) * 0.05; + + // Rotate knots + knot.rotation.x = t * 0.15 + current.y * 0.4; + knot.rotation.y = t * 0.22 + current.x * 0.4; + knot2.rotation.x = -t * 0.10 + current.y * 0.25; + knot2.rotation.y = -t * 0.17 + current.x * 0.25; + + // Rotate particle field slowly + points.rotation.y = t * 0.03 + current.x * 0.15; + points.rotation.x = current.y * 0.15; + + // Subtle camera breathing + camera.position.z = 18 + Math.sin(t * 0.3) * 0.4; + camera.lookAt(0, 0, 0); + + renderer.render(scene, camera); + rafId = requestAnimationFrame(animate); + } + animate(); + + // Pause when tab hidden + document.addEventListener('visibilitychange', () => { + if (document.hidden) cancelAnimationFrame(rafId); + else animate(); + }); + } + + /* ============================================================ + 2. TYPED ROTATOR + ============================================================ */ + function initTyped() { + const el = $('#mx-typed'); + if (!el) return; + + const words = JSON.parse(el.dataset.words || '[]'); + if (!words.length) return; + + const cursor = document.createElement('span'); + cursor.className = 'typed-cursor'; + cursor.textContent = '|'; + + const textSpan = document.createElement('span'); + el.appendChild(textSpan); + el.appendChild(cursor); + + let i = 0, j = 0, deleting = false; + + function tick() { + const word = words[i]; + if (!deleting) { + textSpan.textContent = word.slice(0, ++j); + if (j === word.length) { + deleting = true; + return setTimeout(tick, 1600); + } + } else { + textSpan.textContent = word.slice(0, --j); + if (j === 0) { + deleting = false; + i = (i + 1) % words.length; + } + } + setTimeout(tick, deleting ? 40 : 70); + } + tick(); + } + + /* ============================================================ + 3. HEADER SHRINK + SCROLLSPY + SMOOTH SCROLL + BURGER + ============================================================ */ + function initHeader() { + const header = $('.mx-header'); + const navLinks = $$('.mx-nav-links a[href^="#"]'); + const sections = navLinks + .map(a => document.getElementById(a.getAttribute('href').slice(1))) + .filter(Boolean); + + function onScroll() { + if (window.scrollY > 30) header.classList.add('scrolled'); + else header.classList.remove('scrolled'); + + // scrollspy + const scroll = window.scrollY + 120; + let activeId = null; + sections.forEach(sec => { + if (sec.offsetTop <= scroll) activeId = sec.id; + }); + navLinks.forEach(a => { + a.classList.toggle('active', a.getAttribute('href') === '#' + activeId); + }); + } + window.addEventListener('scroll', onScroll, { passive: true }); + onScroll(); + + // Smooth scroll for internal links + $$('a[href^="#"]').forEach(a => { + a.addEventListener('click', (e) => { + const id = a.getAttribute('href'); + if (id === '#' || id.length < 2) return; + const target = document.querySelector(id); + if (!target) return; + e.preventDefault(); + const y = target.getBoundingClientRect().top + window.scrollY - 70; + window.scrollTo({ top: y, behavior: 'smooth' }); + + // close mobile nav + const nav = $('.mx-nav-links'); + const burger = $('.mx-burger'); + if (nav && nav.classList.contains('mobile-open')) { + nav.classList.remove('mobile-open'); + burger && burger.classList.remove('open'); + } + }); + }); + + // Burger + const burger = $('.mx-burger'); + const nav = $('.mx-nav-links'); + if (burger && nav) { + burger.addEventListener('click', () => { + burger.classList.toggle('open'); + nav.classList.toggle('mobile-open'); + }); + } + } + + /* ============================================================ + 4. SCROLL REVEAL + ============================================================ */ + function initReveal() { + const els = $$('.reveal'); + if (!('IntersectionObserver' in window)) { + els.forEach(el => el.classList.add('is-visible')); + return; + } + const io = new IntersectionObserver((entries) => { + entries.forEach(entry => { + if (entry.isIntersecting) { + entry.target.classList.add('is-visible'); + io.unobserve(entry.target); + } + }); + }, { threshold: 0.12, rootMargin: '0px 0px -50px 0px' }); + els.forEach(el => io.observe(el)); + } + + /* ============================================================ + 5. SPOTLIGHT HOVER (service cards) + ============================================================ */ + function initSpotlight() { + $$('.mx-service-card').forEach(card => { + card.addEventListener('mousemove', (e) => { + const r = card.getBoundingClientRect(); + card.style.setProperty('--mx', ((e.clientX - r.left) / r.width * 100) + '%'); + card.style.setProperty('--my', ((e.clientY - r.top) / r.height * 100) + '%'); + }); + }); + } + + /* ============================================================ + 6. TILT on cards (subtle 3D) + ============================================================ */ + function initTilt() { + if (prefersReducedMotion) return; + $$('[data-tilt]').forEach(el => { + const maxTilt = parseFloat(el.dataset.tilt) || 6; + el.style.transformStyle = 'preserve-3d'; + el.addEventListener('mousemove', (e) => { + const r = el.getBoundingClientRect(); + const px = (e.clientX - r.left) / r.width - 0.5; + const py = (e.clientY - r.top) / r.height - 0.5; + el.style.transform = `perspective(900px) rotateY(${px * maxTilt}deg) rotateX(${-py * maxTilt}deg) translateY(-6px)`; + }); + el.addEventListener('mouseleave', () => { + el.style.transform = ''; + }); + }); + } + + /* ============================================================ + 7. MAGNETIC buttons + ============================================================ */ + function initMagnetic() { + if (prefersReducedMotion) return; + $$('[data-magnetic]').forEach(el => { + const strength = parseFloat(el.dataset.magnetic) || 0.3; + el.addEventListener('mousemove', (e) => { + const r = el.getBoundingClientRect(); + const mx = e.clientX - (r.left + r.width / 2); + const my = e.clientY - (r.top + r.height / 2); + el.style.transform = `translate(${mx * strength}px, ${my * strength}px)`; + }); + el.addEventListener('mouseleave', () => { + el.style.transform = ''; + }); + }); + } + + /* ============================================================ + 8. COUNTER UP + SKILL BARS (on reveal) + ============================================================ */ + function initCounters() { + if (!('IntersectionObserver' in window)) return; + + // Numbers + $$('[data-count]').forEach(el => { + const target = parseFloat(el.dataset.count); + const duration = parseInt(el.dataset.duration || '1800', 10); + const suffix = el.dataset.suffix || ''; + const prefix = el.dataset.prefix || ''; + let started = false; + + const io = new IntersectionObserver((entries) => { + entries.forEach(entry => { + if (entry.isIntersecting && !started) { + started = true; + const start = performance.now(); + function step(now) { + const t = Math.min(1, (now - start) / duration); + const eased = 1 - Math.pow(1 - t, 3); + const val = target * eased; + const display = Number.isInteger(target) + ? Math.round(val) + : val.toFixed(1); + el.textContent = prefix + display + suffix; + if (t < 1) requestAnimationFrame(step); + } + requestAnimationFrame(step); + io.unobserve(el); + } + }); + }, { threshold: 0.5 }); + io.observe(el); + }); + + // Skill bars + $$('.mx-skill-bar').forEach(bar => { + const pct = parseFloat(bar.dataset.value || '0'); + const io = new IntersectionObserver((entries) => { + entries.forEach(entry => { + if (entry.isIntersecting) { + bar.style.width = pct + '%'; + io.unobserve(bar); + } + }); + }, { threshold: 0.3 }); + io.observe(bar); + }); + } + + /* ============================================================ + 9. MARQUEE DUPLICATION (seamless loop) + ============================================================ */ + function initMarquee() { + $$('.mx-marquee-track').forEach(track => { + const clone = track.innerHTML; + track.innerHTML = clone + clone; + }); + } + + /* ============================================================ + BOOT + ============================================================ */ + document.addEventListener('DOMContentLoaded', () => { + initHeader(); + initReveal(); + initSpotlight(); + initTilt(); + initMagnetic(); + initCounters(); + initMarquee(); + initTyped(); + initWebGLHero(); + }); +})(); diff --git a/index.html b/index.html index 9f812db..2257e7a 100644 --- a/index.html +++ b/index.html @@ -1,436 +1,482 @@ - + - - - - - + + + + + - Opzeker IT + + + + + + + Opzeker IT — Cloud · DevOps · Automation - - + + + + + - - - - - - - - - - - - - + + - - + - -
-