Mooshie commited on
Commit
ec87762
·
verified ·
1 Parent(s): 76c6e64

increase professionalism and interactivity

Browse files
components/back-to-top.js ADDED
@@ -0,0 +1,75 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ class CustomBackToTop extends HTMLElement {
2
+ connectedCallback() {
3
+ this.attachShadow({ mode: 'open' });
4
+ this.shadowRoot.innerHTML = `
5
+ <style>
6
+ :host {
7
+ position: fixed;
8
+ bottom: 2rem;
9
+ right: 2rem;
10
+ z-index: 100;
11
+ opacity: 0;
12
+ visibility: hidden;
13
+ transition: all 0.3s ease;
14
+ }
15
+
16
+ :host.visible {
17
+ opacity: 1;
18
+ visibility: visible;
19
+ }
20
+
21
+ .back-to-top-btn {
22
+ width: 50px;
23
+ height: 50px;
24
+ background: #EAB308;
25
+ border: none;
26
+ border-radius: 50%;
27
+ cursor: pointer;
28
+ display: flex;
29
+ align-items: center;
30
+ justify-content: center;
31
+ box-shadow: 0 4px 15px rgba(234, 179, 8, 0.3);
32
+ transition: all 0.3s ease;
33
+ }
34
+
35
+ .back-to-top-btn:hover {
36
+ transform: translateY(-5px);
37
+ box-shadow: 0 8px 25px rgba(234, 179, 8, 0.4);
38
+ }
39
+
40
+ .back-to-top-btn svg {
41
+ color: black;
42
+ transition: transform 0.3s ease;
43
+ }
44
+
45
+ .back-to-top-btn:hover svg {
46
+ transform: translateY(-3px);
47
+ }
48
+ </style>
49
+
50
+ <button class="back-to-top-btn" id="back-to-top" aria-label="Back to top">
51
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="12" y1="19" x2="12" y2="5"></line><polyline points="5 12 12 5 19 12"></polyline></svg>
52
+ </button>
53
+ `;
54
+
55
+ const btn = this.shadowRoot.getElementById('back-to-top');
56
+
57
+ // Show/hide button based on scroll position
58
+ window.addEventListener('scroll', () => {
59
+ if (window.scrollY > 500) {
60
+ this.classList.add('visible');
61
+ } else {
62
+ this.classList.remove('visible');
63
+ }
64
+ });
65
+
66
+ // Scroll to top on click
67
+ btn.addEventListener('click', () => {
68
+ window.scrollTo({
69
+ top: 0,
70
+ behavior: 'smooth'
71
+ });
72
+ });
73
+ }
74
+ }
75
+ customElements.define('custom-back-to-top', CustomBackToTop);
components/contact.js CHANGED
@@ -41,13 +41,32 @@ class CustomContact extends HTMLElement {
41
  transition: all 0.3s ease;
42
  margin-bottom: 3rem;
43
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44
 
45
  .email-btn:hover {
46
  background: rgba(234, 179, 8, 0.1);
47
  transform: translateY(-3px);
 
48
  }
49
-
50
- .social-links {
51
  display: flex;
52
  justify-content: center;
53
  gap: 2rem;
@@ -57,13 +76,31 @@ class CustomContact extends HTMLElement {
57
  color: #52525b;
58
  transition: all 0.3s ease;
59
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
60
 
61
  .social-link:hover {
62
  color: #EAB308;
63
  transform: translateY(-3px);
64
  }
65
-
66
- .footer-note {
67
  margin-top: 4rem;
68
  color: #52525b;
69
  font-size: 0.875rem;
 
41
  transition: all 0.3s ease;
42
  margin-bottom: 3rem;
43
  }
44
+ .email-btn {
45
+ position: relative;
46
+ overflow: hidden;
47
+ }
48
+
49
+ .email-btn::before {
50
+ content: '';
51
+ position: absolute;
52
+ top: 0;
53
+ left: -100%;
54
+ width: 100%;
55
+ height: 100%;
56
+ background: linear-gradient(90deg, transparent, rgba(255,255,255,0.2), transparent);
57
+ transition: left 0.5s ease;
58
+ }
59
+
60
+ .email-btn:hover::before {
61
+ left: 100%;
62
+ }
63
 
64
  .email-btn:hover {
65
  background: rgba(234, 179, 8, 0.1);
66
  transform: translateY(-3px);
67
+ box-shadow: 0 10px 20px rgba(234, 179, 8, 0.2);
68
  }
69
+ .social-links {
 
70
  display: flex;
71
  justify-content: center;
72
  gap: 2rem;
 
76
  color: #52525b;
77
  transition: all 0.3s ease;
78
  }
79
+ .social-link {
80
+ position: relative;
81
+ }
82
+
83
+ .social-link::after {
84
+ content: '';
85
+ position: absolute;
86
+ bottom: -5px;
87
+ left: 50%;
88
+ width: 0;
89
+ height: 2px;
90
+ background: #EAB308;
91
+ transition: all 0.3s ease;
92
+ transform: translateX(-50%);
93
+ }
94
+
95
+ .social-link:hover::after {
96
+ width: 100%;
97
+ }
98
 
99
  .social-link:hover {
100
  color: #EAB308;
101
  transform: translateY(-3px);
102
  }
103
+ .footer-note {
 
104
  margin-top: 4rem;
105
  color: #52525b;
106
  font-size: 0.875rem;
components/footer.js ADDED
@@ -0,0 +1,118 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ class CustomFooter extends HTMLElement {
2
+ connectedCallback() {
3
+ this.attachShadow({ mode: 'open' });
4
+ this.shadowRoot.innerHTML = `
5
+ <style>
6
+ :host {
7
+ display: block;
8
+ background: #0a0a0a;
9
+ border-top: 1px solid #262626;
10
+ padding: 4rem 1rem 2rem 1rem;
11
+ }
12
+
13
+ .footer-content {
14
+ max-width: 1200px;
15
+ margin: 0 auto;
16
+ text-align: center;
17
+ }
18
+
19
+ .footer-logo {
20
+ font-family: 'Fira Code', monospace;
21
+ font-size: 1.5rem;
22
+ font-weight: 700;
23
+ color: #EAB308;
24
+ margin-bottom: 1.5rem;
25
+ display: inline-block;
26
+ }
27
+
28
+ .footer-links {
29
+ display: flex;
30
+ justify-content: center;
31
+ gap: 2rem;
32
+ margin-bottom: 2rem;
33
+ flex-wrap: wrap;
34
+ }
35
+
36
+ .footer-link {
37
+ color: #9ca3af;
38
+ text-decoration: none;
39
+ font-size: 0.9rem;
40
+ transition: color 0.3s ease;
41
+ }
42
+
43
+ .footer-link:hover {
44
+ color: #EAB308;
45
+ }
46
+
47
+ .social-icons {
48
+ display: flex;
49
+ justify-content: center;
50
+ gap: 1.5rem;
51
+ margin-bottom: 2rem;
52
+ }
53
+
54
+ .social-icon {
55
+ color: #52525b;
56
+ transition: all 0.3s ease;
57
+ }
58
+
59
+ .social-icon:hover {
60
+ color: #EAB308;
61
+ transform: translateY(-3px);
62
+ }
63
+
64
+ .copyright {
65
+ color: #52525b;
66
+ font-size: 0.875rem;
67
+ font-family: 'Fira Code', monospace;
68
+ padding-top: 2rem;
69
+ border-top: 1px solid #1f1f1f;
70
+ }
71
+
72
+ .heart {
73
+ color: #EAB308;
74
+ animation: pulse 1s ease infinite;
75
+ }
76
+
77
+ @keyframes pulse {
78
+ 0%, 100% { transform: scale(1); }
79
+ 50% { transform: scale(1.2); }
80
+ }
81
+ </style>
82
+
83
+ <footer>
84
+ <div class="footer-content">
85
+ <div class="footer-logo">&lt;KV/&gt;</div>
86
+
87
+ <nav class="footer-links">
88
+ <a href="#hero" class="footer-link">Home</a>
89
+ <a href="#about" class="footer-link">About</a>
90
+ <a href="#skills" class="footer-link">Skills</a>
91
+ <a href="#projects" class="footer-link">Projects</a>
92
+ <a href="#contact" class="footer-link">Contact</a>
93
+ </nav>
94
+
95
+ <div class="social-icons">
96
+ <a href="#" class="social-icon" aria-label="GitHub">
97
+ <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"></path></svg>
98
+ </a>
99
+ <a href="#" class="social-icon" aria-label="LinkedIn">
100
+ <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M16 8a6 6 0 0 1 6 6v7h-4v-7a2 2 0 0 0-2-2 2 2 0 0 0-2 2v7h-4v-7a6 6 0 0 1 6-6z"></path><rect x="2" y="9" width="4" height="12"></rect><circle cx="4" cy="4" r="2"></circle></svg>
101
+ </a>
102
+ <a href="#" class="social-icon" aria-label="Twitter">
103
+ <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M23 3a10.9 10.9 0 0 1-3.14 1.53 4.48 4.48 0 0 0-7.86 3v1A10.66 10.66 0 0 1 3 4s-4 9 5 13a11.64 11.64 0 0 1-7 2c9 5 20 0 20-11.5a4.5 4.5 0 0 0-.08-.83A7.72 7.72 0 0 0 23 3z"></path></svg>
104
+ </a>
105
+ <a href="mailto:hello@kentvuong.com" class="social-icon" aria-label="Email">
106
+ <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"></path><polyline points="22,6 12,13 2,6"></polyline></svg>
107
+ </a>
108
+ </div>
109
+
110
+ <div class="copyright">
111
+ <p>Built with <span class="heart">♥</span> by Kent Vuong &copy; 2024</p>
112
+ </div>
113
+ </div>
114
+ </footer>
115
+ `;
116
+ }
117
+ }
118
+ customElements.define('custom-footer', CustomFooter);
components/hero.js CHANGED
@@ -123,7 +123,6 @@ class CustomHero extends HTMLElement {
123
  z-index: 1;
124
  pointer-events: none;
125
  }
126
-
127
  .grid-bg {
128
  position: absolute;
129
  top: 0;
@@ -132,27 +131,103 @@ class CustomHero extends HTMLElement {
132
  height: 100%;
133
  background-image: linear-gradient(rgba(255,255,255,0.03) 1px, transparent 1px),
134
  linear-gradient(90deg, rgba(255,255,255,0.03) 1px, transparent 1px);
135
- background-size: 30px 30px;
136
  z-index: 0;
137
- mask-image: radial-gradient(circle at center, black 40%, transparent 100%);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
138
  }
139
- </style>
140
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
141
  <div class="grid-bg"></div>
 
 
 
 
 
142
  <div class="glow-bg"></div>
143
-
144
- <div class="container animate-fade-in">
145
  <div class="status-badge">
146
  <div class="status-dot"></div>
147
  <span>Open to Work</span>
148
  </div>
149
-
150
  <h1>
151
- Hi, I'm Kent Vuong
152
  <span class="highlight">Full-Stack & DevOps Engineer</span>
153
  </h1>
154
-
155
- <p>
156
  I build scalable web applications and robust cloud infrastructure.
157
  Passionate about clean code, automation, and delivering exceptional user experiences.
158
  </p>
 
123
  z-index: 1;
124
  pointer-events: none;
125
  }
 
126
  .grid-bg {
127
  position: absolute;
128
  top: 0;
 
131
  height: 100%;
132
  background-image: linear-gradient(rgba(255,255,255,0.03) 1px, transparent 1px),
133
  linear-gradient(90deg, rgba(255,255,255,0.03) 1px, transparent 1px);
134
+ background-size: 50px 50px;
135
  z-index: 0;
136
+ mask-image: radial-gradient(circle at center, black 30%, transparent 100%);
137
+ animation: gridMove 20s linear infinite;
138
+ }
139
+
140
+ @keyframes gridMove {
141
+ 0% { transform: perspective(500px) rotateX(60deg) translateY(0); }
142
+ 100% { transform: perspective(500px) rotateX(60deg) translateY(50px); }
143
+ }
144
+
145
+ .floating-shapes {
146
+ position: absolute;
147
+ top: 0;
148
+ left: 0;
149
+ width: 100%;
150
+ height: 100%;
151
+ overflow: hidden;
152
+ z-index: 1;
153
+ }
154
+
155
+ .shape {
156
+ position: absolute;
157
+ border-radius: 50%;
158
+ opacity: 0.1;
159
+ animation: float 15s ease-in-out infinite;
160
+ }
161
+
162
+ .shape-1 {
163
+ width: 300px;
164
+ height: 300px;
165
+ background: #EAB308;
166
+ top: 10%;
167
+ right: 10%;
168
+ animation-delay: 0s;
169
+ }
170
+
171
+ .shape-2 {
172
+ width: 200px;
173
+ height: 200px;
174
+ background: #EAB308;
175
+ bottom: 20%;
176
+ left: 10%;
177
+ animation-delay: 5s;
178
  }
179
+
180
+ .shape-3 {
181
+ width: 150px;
182
+ height: 150px;
183
+ background: #EAB308;
184
+ top: 50%;
185
+ left: 5%;
186
+ animation-delay: 10s;
187
+ }
188
+
189
+ @keyframes float {
190
+ 0%, 100% { transform: translateY(0) rotate(0deg); }
191
+ 25% { transform: translateY(-20px) rotate(5deg); }
192
+ 50% { transform: translateY(0) rotate(0deg); }
193
+ 75% { transform: translateY(20px) rotate(-5deg); }
194
+ }
195
+
196
+ .typing-text {
197
+ display: inline-block;
198
+ overflow: hidden;
199
+ border-right: 3px solid #EAB308;
200
+ white-space: nowrap;
201
+ animation: typing 3s steps(40, end), blink-caret 0.75s step-end infinite;
202
+ }
203
+
204
+ @keyframes typing {
205
+ from { width: 0 }
206
+ to { width: 100% }
207
+ }
208
+
209
+ @keyframes blink-caret {
210
+ from, to { border-color: transparent }
211
+ 50% { border-color: #EAB308 }
212
+ }
213
+ </style>
214
  <div class="grid-bg"></div>
215
+ <div class="floating-shapes">
216
+ <div class="shape shape-1"></div>
217
+ <div class="shape shape-2"></div>
218
+ <div class="shape shape-3"></div>
219
+ </div>
220
  <div class="glow-bg"></div>
221
+ <div class="container animate-fade-in">
 
222
  <div class="status-badge">
223
  <div class="status-dot"></div>
224
  <span>Open to Work</span>
225
  </div>
 
226
  <h1>
227
+ Hi, I'm <span style="background: linear-gradient(135deg, #EAB308, #CA8A04); -webkit-background-clip: text; -webkit-text-fill-color: transparent;">Kent Vuong</span>
228
  <span class="highlight">Full-Stack & DevOps Engineer</span>
229
  </h1>
230
+ <p>
 
231
  I build scalable web applications and robust cloud infrastructure.
232
  Passionate about clean code, automation, and delivering exceptional user experiences.
233
  </p>
components/preloader.js ADDED
@@ -0,0 +1,96 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ class CustomPreloader extends HTMLElement {
2
+ connectedCallback() {
3
+ this.attachShadow({ mode: 'open' });
4
+ this.shadowRoot.innerHTML = `
5
+ <style>
6
+ :host {
7
+ position: fixed;
8
+ top: 0;
9
+ left: 0;
10
+ width: 100%;
11
+ height: 100%;
12
+ background: #0a0a0a;
13
+ display: flex;
14
+ align-items: center;
15
+ justify-content: center;
16
+ z-index: 9999;
17
+ transition: opacity 0.5s ease, visibility 0.5s ease;
18
+ }
19
+
20
+ :host.hidden {
21
+ opacity: 0;
22
+ visibility: hidden;
23
+ }
24
+
25
+ .preloader-content {
26
+ text-align: center;
27
+ }
28
+
29
+ .loader {
30
+ width: 60px;
31
+ height: 60px;
32
+ border: 3px solid #262626;
33
+ border-top-color: #EAB308;
34
+ border-radius: 50%;
35
+ animation: spin 0.8s linear infinite;
36
+ margin: 0 auto 1.5rem auto;
37
+ }
38
+
39
+ @keyframes spin {
40
+ to { transform: rotate(360deg); }
41
+ }
42
+
43
+ .loading-text {
44
+ font-family: 'Fira Code', monospace;
45
+ color: #EAB308;
46
+ font-size: 0.9rem;
47
+ letter-spacing: 2px;
48
+ }
49
+
50
+ .progress-bar {
51
+ width: 200px;
52
+ height: 2px;
53
+ background: #262626;
54
+ margin: 1rem auto 0;
55
+ border-radius: 2px;
56
+ overflow: hidden;
57
+ }
58
+
59
+ .progress-fill {
60
+ height: 100%;
61
+ background: #EAB308;
62
+ width: 0;
63
+ transition: width 0.3s ease;
64
+ }
65
+ </style>
66
+
67
+ <div class="preloader-content">
68
+ <div class="loader"></div>
69
+ <div class="loading-text">LOADING</div>
70
+ <div class="progress-bar">
71
+ <div class="progress-fill" id="progress-fill"></div>
72
+ </div>
73
+ </div>
74
+ `;
75
+
76
+ // Simulate loading progress
77
+ const progressFill = this.shadowRoot.getElementById('progress-fill');
78
+ let progress = 0;
79
+ const interval = setInterval(() => {
80
+ progress += Math.random() * 30;
81
+ if (progress >= 100) {
82
+ progress = 100;
83
+ clearInterval(interval);
84
+ setTimeout(() => {
85
+ this.classList.add('hidden');
86
+ document.body.style.overflow = 'auto';
87
+ }, 300);
88
+ }
89
+ progressFill.style.width = `${progress}%`;
90
+ }, 200);
91
+
92
+ // Prevent scroll while loading
93
+ document.body.style.overflow = 'hidden';
94
+ }
95
+ }
96
+ customElements.define('custom-preloader', CustomPreloader);
components/projects.js CHANGED
@@ -64,12 +64,16 @@ class CustomProjects extends HTMLElement {
64
  min-width: calc(50% - 1rem);
65
  }
66
  }
 
 
 
 
67
 
68
  .project-container:hover {
69
  border-color: #EAB308;
 
70
  }
71
-
72
- .project-image {
73
  width: 100%;
74
  height: 300px;
75
  object-fit: cover;
@@ -140,13 +144,31 @@ class CustomProjects extends HTMLElement {
140
  .link-item:hover {
141
  color: #EAB308;
142
  }
143
-
144
  .link-item svg {
145
  width: 18px;
146
  height: 18px;
 
 
 
 
 
147
  }
148
 
149
- .nav-btn {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
150
  position: absolute;
151
  top: 50%;
152
  transform: translateY(-50%);
@@ -246,23 +268,24 @@ class CustomProjects extends HTMLElement {
246
  <img src="http://static.photos/technology/640x360/42" alt="Mooshieblob.com Project" class="project-image">
247
 
248
  <div class="project-content">
 
 
 
249
  <div class="folder-icon">
250
- <svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"></path></svg>
251
  </div>
252
-
253
  <h3>mooshieblob.com</h3>
254
 
255
  <p>
256
- My fun alias profile showcasing my AI projects and online persona, featuring interactive demos and creative experiments.
257
  </p>
258
-
259
  <div class="tech-stack">
260
  <span class="tech-item">Nuxt.js</span>
261
- <span class="tech-item">Tailwind</span>
262
  <span class="tech-item">Cloudflare AI</span>
 
263
  </div>
264
-
265
- <div class="project-links">
266
  <a href="https://github.com/Mooshieblob1/mooshieblob1.github.io" target="_blank" class="link-item">
267
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"></path></svg>
268
  Code
@@ -283,21 +306,27 @@ class CustomProjects extends HTMLElement {
283
  <div class="folder-icon">
284
  <svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"></path></svg>
285
  </div>
 
 
 
 
 
 
286
 
287
  <h3>Cloud Dashboard</h3>
288
 
289
  <p>
290
- A comprehensive cloud infrastructure monitoring dashboard with real-time metrics, alerts, and automated scaling controls.
291
  </p>
292
-
293
  <div class="tech-stack">
294
  <span class="tech-item">React</span>
 
295
  <span class="tech-item">AWS</span>
296
  <span class="tech-item">Terraform</span>
297
  <span class="tech-item">Grafana</span>
 
298
  </div>
299
-
300
- <div class="project-links">
301
  <a href="#" target="_blank" class="link-item">
302
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"></path></svg>
303
  Code
@@ -318,21 +347,27 @@ class CustomProjects extends HTMLElement {
318
  <div class="folder-icon">
319
  <svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"></path></svg>
320
  </div>
 
 
 
 
 
 
321
 
322
  <h3>E-Commerce Platform</h3>
323
 
324
  <p>
325
- A full-stack e-commerce solution with headless CMS, payment integration, inventory management, and multi-region deployment.
326
  </p>
327
-
328
  <div class="tech-stack">
329
  <span class="tech-item">Next.js</span>
330
  <span class="tech-item">Stripe</span>
331
  <span class="tech-item">PostgreSQL</span>
 
332
  <span class="tech-item">Docker</span>
 
333
  </div>
334
-
335
- <div class="project-links">
336
  <a href="#" target="_blank" class="link-item">
337
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"></path></svg>
338
  Code
@@ -353,21 +388,26 @@ class CustomProjects extends HTMLElement {
353
  <div class="folder-icon">
354
  <svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"></path></svg>
355
  </div>
 
 
 
 
 
 
356
 
357
  <h3>DevOps Pipeline</h3>
358
 
359
  <p>
360
- Automated CI/CD pipeline solution with self-hosted runners, security scanning, and multi-environment deployments.
361
  </p>
362
-
363
  <div class="tech-stack">
364
  <span class="tech-item">GitHub Actions</span>
365
  <span class="tech-item">Kubernetes</span>
366
  <span class="tech-item">Helm</span>
367
  <span class="tech-item">ArgoCD</span>
 
368
  </div>
369
-
370
- <div class="project-links">
371
  <a href="#" target="_blank" class="link-item">
372
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"></path></svg>
373
  Code
 
64
  min-width: calc(50% - 1rem);
65
  }
66
  }
67
+ .project-container {
68
+ transform-style: preserve-3d;
69
+ transition: all 0.5s ease;
70
+ }
71
 
72
  .project-container:hover {
73
  border-color: #EAB308;
74
+ transform: translateY(-10px) rotateX(5deg);
75
  }
76
+ .project-image {
 
77
  width: 100%;
78
  height: 300px;
79
  object-fit: cover;
 
144
  .link-item:hover {
145
  color: #EAB308;
146
  }
 
147
  .link-item svg {
148
  width: 18px;
149
  height: 18px;
150
+ transition: transform 0.3s ease;
151
+ }
152
+
153
+ .link-item:hover svg {
154
+ transform: translateX(5px);
155
  }
156
 
157
+ .project-tags {
158
+ display: flex;
159
+ gap: 0.5rem;
160
+ margin-bottom: 1rem;
161
+ }
162
+
163
+ .tag {
164
+ background: rgba(234, 179, 8, 0.1);
165
+ color: #EAB308;
166
+ padding: 0.25rem 0.75rem;
167
+ border-radius: 9999px;
168
+ font-size: 0.75rem;
169
+ font-family: 'Fira Code', monospace;
170
+ }
171
+ .nav-btn {
172
  position: absolute;
173
  top: 50%;
174
  transform: translateY(-50%);
 
268
  <img src="http://static.photos/technology/640x360/42" alt="Mooshieblob.com Project" class="project-image">
269
 
270
  <div class="project-content">
271
+ <div class="project-tags">
272
+ <span class="tag">Featured</span>
273
+ </div>
274
  <div class="folder-icon">
275
+ <svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"></path></svg>
276
  </div>
 
277
  <h3>mooshieblob.com</h3>
278
 
279
  <p>
280
+ My fun alias profile showcasing my AI projects and online persona, featuring interactive demos, creative experiments, and real-time AI integrations.
281
  </p>
 
282
  <div class="tech-stack">
283
  <span class="tech-item">Nuxt.js</span>
284
+ <span class="tech-item">Tailwind CSS</span>
285
  <span class="tech-item">Cloudflare AI</span>
286
+ <span class="tech-item">Vercel</span>
287
  </div>
288
+ <div class="project-links">
 
289
  <a href="https://github.com/Mooshieblob1/mooshieblob1.github.io" target="_blank" class="link-item">
290
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"></path></svg>
291
  Code
 
306
  <div class="folder-icon">
307
  <svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"></path></svg>
308
  </div>
309
+ <div class="project-tags">
310
+ <span class="tag">Enterprise</span>
311
+ </div>
312
+ <div class="folder-icon">
313
+ <svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"></path></svg>
314
+ </div>
315
 
316
  <h3>Cloud Dashboard</h3>
317
 
318
  <p>
319
+ A comprehensive cloud infrastructure monitoring dashboard with real-time metrics, intelligent alerts, automated scaling controls, and predictive analytics.
320
  </p>
 
321
  <div class="tech-stack">
322
  <span class="tech-item">React</span>
323
+ <span class="tech-item">TypeScript</span>
324
  <span class="tech-item">AWS</span>
325
  <span class="tech-item">Terraform</span>
326
  <span class="tech-item">Grafana</span>
327
+ <span class="tech-item">Prometheus</span>
328
  </div>
329
+ <div class="project-links">
 
330
  <a href="#" target="_blank" class="link-item">
331
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"></path></svg>
332
  Code
 
347
  <div class="folder-icon">
348
  <svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"></path></svg>
349
  </div>
350
+ <div class="project-tags">
351
+ <span class="tag">SaaS</span>
352
+ </div>
353
+ <div class="folder-icon">
354
+ <svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"></path></svg>
355
+ </div>
356
 
357
  <h3>E-Commerce Platform</h3>
358
 
359
  <p>
360
+ A full-stack e-commerce solution with headless CMS, seamless payment integration, real-time inventory management, and global multi-region deployment.
361
  </p>
 
362
  <div class="tech-stack">
363
  <span class="tech-item">Next.js</span>
364
  <span class="tech-item">Stripe</span>
365
  <span class="tech-item">PostgreSQL</span>
366
+ <span class="tech-item">Redis</span>
367
  <span class="tech-item">Docker</span>
368
+ <span class="tech-item">GraphQL</span>
369
  </div>
370
+ <div class="project-links">
 
371
  <a href="#" target="_blank" class="link-item">
372
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"></path></svg>
373
  Code
 
388
  <div class="folder-icon">
389
  <svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"></path></svg>
390
  </div>
391
+ <div class="project-tags">
392
+ <span class="tag">Infrastructure</span>
393
+ </div>
394
+ <div class="folder-icon">
395
+ <svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"></path></svg>
396
+ </div>
397
 
398
  <h3>DevOps Pipeline</h3>
399
 
400
  <p>
401
+ Automated CI/CD pipeline solution with self-hosted runners, comprehensive security scanning, automated testing, and multi-environment deployments.
402
  </p>
 
403
  <div class="tech-stack">
404
  <span class="tech-item">GitHub Actions</span>
405
  <span class="tech-item">Kubernetes</span>
406
  <span class="tech-item">Helm</span>
407
  <span class="tech-item">ArgoCD</span>
408
+ <span class="tech-item">SonarQube</span>
409
  </div>
410
+ <div class="project-links">
 
411
  <a href="#" target="_blank" class="link-item">
412
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"></path></svg>
413
  Code
components/scroll-progress.js ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ class CustomScrollProgress extends HTMLElement {
2
+ connectedCallback() {
3
+ this.attachShadow({ mode: 'open' });
4
+ this.shadowRoot.innerHTML = `
5
+ <style>
6
+ :host {
7
+ position: fixed;
8
+ top: 0;
9
+ left: 0;
10
+ width: 100%;
11
+ height: 3px;
12
+ z-index: 9999;
13
+ pointer-events: none;
14
+ }
15
+
16
+ .progress-bar {
17
+ height: 100%;
18
+ background: linear-gradient(90deg, #EAB308, #CA8A04);
19
+ width: 0%;
20
+ transition: width 0.1s ease-out;
21
+ box-shadow: 0 0 10px rgba(234, 179, 8, 0.5);
22
+ }
23
+ </style>
24
+ <div class="progress-bar" id="progress-bar"></div>
25
+ `;
26
+
27
+ const progressBar = this.shadowRoot.getElementById('progress-bar');
28
+
29
+ window.addEventListener('scroll', () => {
30
+ const scrollTop = window.scrollY;
31
+ const docHeight = document.documentElement.scrollHeight - window.innerHeight;
32
+ const progress = (scrollTop / docHeight) * 100;
33
+ progressBar.style.width = `${progress}%`;
34
+ });
35
+ }
36
+ }
37
+ customElements.define('custom-scroll-progress', CustomScrollProgress);
components/skills.js CHANGED
@@ -99,11 +99,41 @@ class CustomSkills extends HTMLElement {
99
  color: #d4d4d8;
100
  transition: all 0.2s;
101
  }
102
-
103
  .tech-item:hover {
104
  background: #EAB308;
105
  color: black;
106
  font-weight: 500;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
107
  }
108
  </style>
109
 
@@ -113,10 +143,17 @@ class CustomSkills extends HTMLElement {
113
  <p class="subtitle">Technologies I work with</p>
114
  </div>
115
 
 
 
 
 
 
 
 
116
  <div class="skills-grid">
117
  <!-- Frontend -->
118
- <div class="skill-card">
119
- <div class="card-icon">
120
  <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="3" width="20" height="14" rx="2" ry="2"></rect><line x1="8" y1="21" x2="16" y2="21"></line><line x1="12" y1="17" x2="12" y2="21"></line></svg>
121
  </div>
122
  <h3>Frontend</h3>
@@ -131,10 +168,9 @@ class CustomSkills extends HTMLElement {
131
  <li class="tech-item">SCSS</li>
132
  </ul>
133
  </div>
134
-
135
  <!-- Backend -->
136
- <div class="skill-card">
137
- <div class="card-icon">
138
  <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="16 18 22 12 16 6"></polyline><polyline points="8 6 2 12 8 18"></polyline></svg>
139
  </div>
140
  <h3>Backend</h3>
@@ -149,10 +185,9 @@ class CustomSkills extends HTMLElement {
149
  <li class="tech-item">GraphQL</li>
150
  </ul>
151
  </div>
152
-
153
  <!-- DevOps -->
154
- <div class="skill-card">
155
- <div class="card-icon">
156
  <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 10h-1.26A8 8 0 1 0 9 20h9a5 5 0 0 0 0-10z"></path></svg>
157
  </div>
158
  <h3>DevOps & Cloud</h3>
@@ -171,5 +206,30 @@ class CustomSkills extends HTMLElement {
171
  </section>
172
  `;
173
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
174
  }
175
- customElements.define('custom-skills', CustomSkills);
 
99
  color: #d4d4d8;
100
  transition: all 0.2s;
101
  }
 
102
  .tech-item:hover {
103
  background: #EAB308;
104
  color: black;
105
  font-weight: 500;
106
+ transform: translateY(-2px);
107
+ }
108
+
109
+ .filter-buttons {
110
+ display: flex;
111
+ justify-content: center;
112
+ gap: 1rem;
113
+ margin-bottom: 3rem;
114
+ flex-wrap: wrap;
115
+ }
116
+
117
+ .filter-btn {
118
+ padding: 0.5rem 1.5rem;
119
+ background: transparent;
120
+ border: 1px solid #262626;
121
+ color: #9ca3af;
122
+ border-radius: 9999px;
123
+ cursor: pointer;
124
+ font-size: 0.9rem;
125
+ font-family: 'Fira Code', monospace;
126
+ transition: all 0.3s ease;
127
+ }
128
+
129
+ .filter-btn:hover, .filter-btn.active {
130
+ border-color: #EAB308;
131
+ color: #EAB308;
132
+ background: rgba(234, 179, 8, 0.1);
133
+ }
134
+
135
+ .skill-card.hidden {
136
+ display: none;
137
  }
138
  </style>
139
 
 
143
  <p class="subtitle">Technologies I work with</p>
144
  </div>
145
 
146
+ <div class="filter-buttons">
147
+ <button class="filter-btn active" data-filter="all">All</button>
148
+ <button class="filter-btn" data-filter="frontend">Frontend</button>
149
+ <button class="filter-btn" data-filter="backend">Backend</button>
150
+ <button class="filter-btn" data-filter="devops">DevOps</button>
151
+ </div>
152
+
153
  <div class="skills-grid">
154
  <!-- Frontend -->
155
+ <div class="skill-card" data-category="frontend">
156
+ <div class="card-icon">
157
  <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="3" width="20" height="14" rx="2" ry="2"></rect><line x1="8" y1="21" x2="16" y2="21"></line><line x1="12" y1="17" x2="12" y2="21"></line></svg>
158
  </div>
159
  <h3>Frontend</h3>
 
168
  <li class="tech-item">SCSS</li>
169
  </ul>
170
  </div>
 
171
  <!-- Backend -->
172
+ <div class="skill-card" data-category="backend">
173
+ <div class="card-icon">
174
  <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="16 18 22 12 16 6"></polyline><polyline points="8 6 2 12 8 18"></polyline></svg>
175
  </div>
176
  <h3>Backend</h3>
 
185
  <li class="tech-item">GraphQL</li>
186
  </ul>
187
  </div>
 
188
  <!-- DevOps -->
189
+ <div class="skill-card" data-category="devops">
190
+ <div class="card-icon">
191
  <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 10h-1.26A8 8 0 1 0 9 20h9a5 5 0 0 0 0-10z"></path></svg>
192
  </div>
193
  <h3>DevOps & Cloud</h3>
 
206
  </section>
207
  `;
208
  }
209
+
210
+ initFilter() {
211
+ const filterBtns = this.shadowRoot.querySelectorAll('.filter-btn');
212
+ const skillCards = this.shadowRoot.querySelectorAll('.skill-card');
213
+
214
+ filterBtns.forEach(btn => {
215
+ btn.addEventListener('click', () => {
216
+ const filter = btn.dataset.filter;
217
+
218
+ // Update active button
219
+ filterBtns.forEach(b => b.classList.remove('active'));
220
+ btn.classList.add('active');
221
+
222
+ // Filter cards
223
+ skillCards.forEach(card => {
224
+ if (filter === 'all' || card.dataset.category === filter) {
225
+ card.classList.remove('hidden');
226
+ card.style.animation = 'fadeIn 0.5s ease forwards';
227
+ } else {
228
+ card.classList.add('hidden');
229
+ }
230
+ });
231
+ });
232
+ });
233
+ }
234
  }
235
+ customElements.define('custom-skills', CustomSkills);
components/terminal.js CHANGED
@@ -109,11 +109,39 @@ class CustomTerminal extends HTMLElement {
109
  width: 0;
110
  animation: typing 2s steps(40, end) forwards;
111
  }
112
-
113
  @keyframes typing {
114
  from { width: 0 }
115
  to { width: 100% }
116
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
117
  </style>
118
 
119
  <section id="about">
@@ -135,40 +163,135 @@ class CustomTerminal extends HTMLElement {
135
 
136
  <div class="output" id="output-1" style="opacity: 0; animation: fadeIn 0.5s forwards 2.5s;">
137
  <strong>> Kent Vuong</strong><br>
138
- > Full-Stack Dev
 
139
  </div>
140
 
141
  <div class="command-line" style="opacity: 0; animation: fadeIn 0.5s forwards 3s;">
142
  <span class="prompt">$</span>
143
- <span class="command typing-effect" style="width: 0; animation: typing 1.5s steps(30, end) forwards 3.5s;">cat skills.txt</span>
144
  </div>
145
 
146
  <div class="output" id="output-2" style="opacity: 0; animation: fadeIn 0.5s forwards 5.5s;">
147
- <strong>> Cloud | Containers | CI/CD</strong><br>
148
- > Full-Stack | DevOps
 
 
 
 
 
 
 
 
 
 
149
  </div>
150
 
151
  <div class="command-line" style="opacity: 0; animation: fadeIn 0.5s forwards 6s;">
152
  <span class="prompt">$</span>
153
- <span class="command typing-effect" style="width: 0; animation: typing 1.5s steps(30, end) forwards 6.5s;">connect --social</span>
154
  </div>
155
 
156
  <div class="output" style="opacity: 0; animation: fadeIn 0.5s forwards 8.5s;">
157
- <a href="#contact" style="color: #EAB308; text-decoration: underline; cursor: pointer;">Initializing handshake...</a>
 
 
 
 
 
 
 
158
  </div>
159
 
160
  <div class="command-line">
161
  <span class="prompt">$</span>
 
162
  <span class="cursor"></span>
163
  </div>
164
  </div>
165
  </div>
166
  </section>
167
-
168
  <style>
169
  @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
170
  </style>
171
  `;
172
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
173
  }
174
- customElements.define('custom-terminal', CustomTerminal);
 
109
  width: 0;
110
  animation: typing 2s steps(40, end) forwards;
111
  }
 
112
  @keyframes typing {
113
  from { width: 0 }
114
  to { width: 100% }
115
  }
116
+
117
+ .interactive-command {
118
+ color: #22c55e;
119
+ cursor: pointer;
120
+ transition: all 0.2s;
121
+ }
122
+
123
+ .interactive-command:hover {
124
+ color: #4ade80;
125
+ text-decoration: underline;
126
+ }
127
+
128
+ .file-tree {
129
+ font-family: 'Fira Code', monospace;
130
+ color: #a1a1aa;
131
+ line-height: 1.6;
132
+ }
133
+
134
+ .tree-item {
135
+ padding: 0.25rem 0;
136
+ }
137
+
138
+ .tree-folder {
139
+ color: #EAB308;
140
+ }
141
+
142
+ .tree-file {
143
+ color: #9ca3af;
144
+ }
145
  </style>
146
 
147
  <section id="about">
 
163
 
164
  <div class="output" id="output-1" style="opacity: 0; animation: fadeIn 0.5s forwards 2.5s;">
165
  <strong>> Kent Vuong</strong><br>
166
+ > Full-Stack Developer & DevOps Engineer<br>
167
+ > Building scalable solutions since 2019
168
  </div>
169
 
170
  <div class="command-line" style="opacity: 0; animation: fadeIn 0.5s forwards 3s;">
171
  <span class="prompt">$</span>
172
+ <span class="command typing-effect" style="width: 0; animation: typing 1.5s steps(30, end) forwards 3.5s;">ls -la experience/</span>
173
  </div>
174
 
175
  <div class="output" id="output-2" style="opacity: 0; animation: fadeIn 0.5s forwards 5.5s;">
176
+ <div class="file-tree">
177
+ <div class="tree-item tree-folder">📁 .senior-engineer/</div>
178
+ <div class="tree-item tree-file"> └── microservices-architecture.yaml</div>
179
+ <div class="tree-item tree-folder">📁 .cloud-infrastructure/</div>
180
+ <div class="tree-item tree-file"> ├── aws-deployments/</div>
181
+ <div class="tree-item tree-file"> ├── kubernetes-clusters/</div>
182
+ <div class="tree-item tree-file"> └── ci-cd-pipelines/</div>
183
+ <div class="tree-item tree-folder">📁 .web-development/</div>
184
+ <div class="tree-item tree-file"> ├── react-applications/</div>
185
+ <div class="tree-item tree-file"> ├── nextjs-ssr/</div>
186
+ <div class="tree-item tree-file"> └── nodejs-apis/</div>
187
+ </div>
188
  </div>
189
 
190
  <div class="command-line" style="opacity: 0; animation: fadeIn 0.5s forwards 6s;">
191
  <span class="prompt">$</span>
192
+ <span class="command typing-effect" style="width: 0; animation: typing 1.5s steps(30, end) forwards 6.5s;">cat motivation.txt</span>
193
  </div>
194
 
195
  <div class="output" style="opacity: 0; animation: fadeIn 0.5s forwards 8.5s;">
196
+ <strong>> "Code is poetry, infrastructure is the canvas."</strong><br>
197
+ > Passionate about creating elegant solutions<br>
198
+ > to complex problems. Always learning, always evolving.
199
+ </div>
200
+
201
+ <div class="command-line" style="opacity: 0; animation: fadeIn 0.5s forwards 9s;">
202
+ <span class="prompt">$</span>
203
+ <span class="interactive-command" id="try-cmd">Try typing a command...</span>
204
  </div>
205
 
206
  <div class="command-line">
207
  <span class="prompt">$</span>
208
+ <input type="text" id="terminal-input" style="background: transparent; border: none; color: #fff; font-family: inherit; font-size: inherit; outline: none; width: calc(100% - 40px);" autocomplete="off">
209
  <span class="cursor"></span>
210
  </div>
211
  </div>
212
  </div>
213
  </section>
 
214
  <style>
215
  @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
216
  </style>
217
  `;
218
  }
219
+
220
+ initTerminal() {
221
+ const input = this.shadowRoot.getElementById('terminal-input');
222
+
223
+ input.addEventListener('keypress', (e) => {
224
+ if (e.key === 'Enter') {
225
+ const command = input.value.trim().toLowerCase();
226
+ this.handleCommand(command);
227
+ input.value = '';
228
+ }
229
+ });
230
+ }
231
+
232
+ handleCommand(command) {
233
+ const terminalBody = this.shadowRoot.getElementById('terminal-content');
234
+
235
+ // Create new command line
236
+ const newCommandLine = document.createElement('div');
237
+ newCommandLine.className = 'command-line';
238
+ newCommandLine.innerHTML = `<span class="prompt">$</span><span class="command">${command}</span>`;
239
+
240
+ // Insert before the input line
241
+ const inputLine = terminalBody.lastElementChild;
242
+ terminalBody.insertBefore(newCommandLine, inputLine);
243
+
244
+ // Create output
245
+ const output = document.createElement('div');
246
+ output.className = 'output';
247
+
248
+ switch(command) {
249
+ case 'help':
250
+ output.innerHTML = `<strong>Available commands:</strong><br>
251
+ > about - Learn more about me<br>
252
+ > skills - View my technical skills<br>
253
+ > projects - See my work<br>
254
+ > contact - Get in touch<br>
255
+ > clear - Clear terminal`;
256
+ break;
257
+ case 'about':
258
+ output.innerHTML = `<strong>Kent Vuong</strong><br>
259
+ > Full-Stack & DevOps Engineer<br>
260
+ > 5+ years of experience<br>
261
+ > Based in San Francisco, CA`;
262
+ break;
263
+ case 'skills':
264
+ output.innerHTML = `<strong>Core Skills:</strong><br>
265
+ > Frontend: React, Vue, Next.js<br>
266
+ > Backend: Node.js, Python, Go<br>
267
+ > DevOps: AWS, Docker, K8s, Terraform<br>
268
+ > Databases: PostgreSQL, MongoDB, Redis`;
269
+ break;
270
+ case 'projects':
271
+ output.innerHTML = `<strong>Featured Projects:</strong><br>
272
+ > mooshieblob.com - AI Showcase<br>
273
+ > Cloud Dashboard - Infrastructure Monitor<br>
274
+ > E-Commerce Platform - Full-Stack Solution<br>
275
+ > DevOps Pipeline - CI/CD Automation`;
276
+ break;
277
+ case 'contact':
278
+ output.innerHTML = `<strong>Let's Connect!</strong><br>
279
+ > Email: hello@kentvuong.com<br>
280
+ > GitHub: @Mooshieblob1<br>
281
+ > LinkedIn: /in/kentvuong<br>
282
+ > <a href="#contact" style="color: #EAB308;">Jump to Contact Section →</a>`;
283
+ break;
284
+ case 'clear':
285
+ // Remove all command lines except the last one (input)
286
+ while (terminalBody.children.length > 1) {
287
+ terminalBody.removeChild(terminalBody.firstChild);
288
+ }
289
+ return;
290
+ default:
291
+ output.innerHTML = `<span style="color: #ef4444;">Command not found: ${command}</span><br>Type 'help' for available commands.`;
292
+ }
293
+
294
+ terminalBody.insertBefore(output, inputLine);
295
+ }
296
  }
297
+ customElements.define('custom-terminal', CustomTerminal);
index.html CHANGED
@@ -39,11 +39,22 @@
39
  </head>
40
  <body class="bg-brand-black text-gray-200 font-sans antialiased overflow-x-hidden selection:bg-brand-yellow selection:text-brand-black">
41
 
 
 
 
 
 
 
 
 
 
 
 
 
42
  <!-- Components -->
43
  <script src="components/navbar.js"></script>
44
  <custom-navbar></custom-navbar>
45
-
46
- <main class="relative z-10">
47
 
48
  <!-- Hero Section -->
49
  <script src="components/hero.js"></script>
@@ -64,11 +75,14 @@
64
  <!-- Contact Section -->
65
  <script src="components/contact.js"></script>
66
  <custom-contact></custom-contact>
67
-
68
  </main>
69
 
 
 
 
 
70
  <script src="script.js"></script>
71
- <script>
72
  feather.replace();
73
  </script>
74
  <script src="https://huggingface.co/deepsite/deepsite-badge.js"></script>
 
39
  </head>
40
  <body class="bg-brand-black text-gray-200 font-sans antialiased overflow-x-hidden selection:bg-brand-yellow selection:text-brand-black">
41
 
42
+ <!-- Preloader -->
43
+ <custom-preloader></custom-preloader>
44
+ <script src="components/preloader.js"></script>
45
+
46
+ <!-- Scroll Progress -->
47
+ <custom-scroll-progress></custom-scroll-progress>
48
+ <script src="components/scroll-progress.js"></script>
49
+
50
+ <!-- Back to Top -->
51
+ <custom-back-to-top></custom-back-to-top>
52
+ <script src="components/back-to-top.js"></script>
53
+
54
  <!-- Components -->
55
  <script src="components/navbar.js"></script>
56
  <custom-navbar></custom-navbar>
57
+ <main class="relative z-10">
 
58
 
59
  <!-- Hero Section -->
60
  <script src="components/hero.js"></script>
 
75
  <!-- Contact Section -->
76
  <script src="components/contact.js"></script>
77
  <custom-contact></custom-contact>
 
78
  </main>
79
 
80
+ <!-- Footer -->
81
+ <script src="components/footer.js"></script>
82
+ <custom-footer></custom-footer>
83
+
84
  <script src="script.js"></script>
85
+ <script>
86
  feather.replace();
87
  </script>
88
  <script src="https://huggingface.co/deepsite/deepsite-badge.js"></script>
script.js CHANGED
@@ -1,3 +1,4 @@
 
1
  // Logic to handle navigation active state based on scroll position
2
  document.addEventListener('DOMContentLoaded', () => {
3
  const sections = document.querySelectorAll('section[id]');
@@ -14,11 +15,9 @@ document.addEventListener('DOMContentLoaded', () => {
14
  if (entry.isIntersecting) {
15
  const id = entry.target.getAttribute('id');
16
  navLinks.forEach(link => {
17
- link.classList.remove('text-brand-yellow', 'border-brand-yellow');
18
- link.classList.add('text-gray-400', 'border-transparent');
19
  if (link.getAttribute('href') === `#${id}`) {
20
- link.classList.remove('text-gray-400', 'border-transparent');
21
- link.classList.add('text-brand-yellow', 'border-brand-yellow');
22
  }
23
  });
24
  }
@@ -27,6 +26,114 @@ document.addEventListener('DOMContentLoaded', () => {
27
 
28
  sections.forEach(section => observer.observe(section));
29
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
  // Dispatch event to notify components that the DOM is ready
31
  window.dispatchEvent(new Event('app-ready'));
32
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
  // Logic to handle navigation active state based on scroll position
3
  document.addEventListener('DOMContentLoaded', () => {
4
  const sections = document.querySelectorAll('section[id]');
 
15
  if (entry.isIntersecting) {
16
  const id = entry.target.getAttribute('id');
17
  navLinks.forEach(link => {
18
+ link.classList.remove('active');
 
19
  if (link.getAttribute('href') === `#${id}`) {
20
+ link.classList.add('active');
 
21
  }
22
  });
23
  }
 
26
 
27
  sections.forEach(section => observer.observe(section));
28
 
29
+ // Scroll reveal animation
30
+ const revealElements = document.querySelectorAll('.reveal, .reveal-left, .reveal-right');
31
+
32
+ const revealObserver = new IntersectionObserver((entries) => {
33
+ entries.forEach(entry => {
34
+ if (entry.isIntersecting) {
35
+ entry.target.classList.add('active');
36
+ }
37
+ });
38
+ }, { threshold: 0.1 });
39
+
40
+ revealElements.forEach(el => revealObserver.observe(el));
41
+
42
+ // Initialize components when DOM is ready
43
+ const initComponents = () => {
44
+ // Initialize Terminal
45
+ const terminal = document.querySelector('custom-terminal');
46
+ if (terminal && terminal.initTerminal) {
47
+ setTimeout(() => terminal.initTerminal(), 3000);
48
+ }
49
+
50
+ // Initialize Projects scroll
51
+ const projects = document.querySelector('custom-projects');
52
+ if (projects && projects.initScrollNavigation) {
53
+ projects.initScrollNavigation();
54
+ }
55
+
56
+ // Initialize Skills filter
57
+ const skills = document.querySelector('custom-skills');
58
+ if (skills && skills.initFilter) {
59
+ skills.initFilter();
60
+ }
61
+ };
62
+
63
  // Dispatch event to notify components that the DOM is ready
64
  window.dispatchEvent(new Event('app-ready'));
65
+
66
+ // Initialize components
67
+ initComponents();
68
+
69
+ // Parallax effect for hero section
70
+ window.addEventListener('scroll', () => {
71
+ const scrolled = window.pageYOffset;
72
+ const hero = document.querySelector('custom-hero');
73
+ if (hero) {
74
+ const shapes = hero.shadowRoot?.querySelector('.floating-shapes');
75
+ if (shapes) {
76
+ shapes.style.transform = `translateY(${scrolled * 0.3}px)`;
77
+ }
78
+ }
79
+ });
80
+
81
+ // Magnetic button effect
82
+ const magneticBtns = document.querySelectorAll('.magnetic-btn');
83
+ magneticBtns.forEach(btn => {
84
+ btn.addEventListener('mousemove', (e) => {
85
+ const rect = btn.getBoundingClientRect();
86
+ const x = e.clientX - rect.left - rect.width / 2;
87
+ const y = e.clientY - rect.top - rect.height / 2;
88
+ btn.style.transform = `translate(${x * 0.3}px, ${y * 0.3}px)`;
89
+ });
90
+
91
+ btn.addEventListener('mouseleave', () => {
92
+ btn.style.transform = 'translate(0, 0)';
93
+ });
94
+ });
95
+
96
+ // Smooth scroll for anchor links
97
+ document.querySelectorAll('a[href^="#"]').forEach(anchor => {
98
+ anchor.addEventListener('click', function(e) {
99
+ e.preventDefault();
100
+ const target = document.querySelector(this.getAttribute('href'));
101
+ if (target) {
102
+ target.scrollIntoView({
103
+ behavior: 'smooth',
104
+ block: 'start'
105
+ });
106
+ }
107
+ });
108
+ });
109
+
110
+ // Add reveal classes to skill cards
111
+ const skillCards = document.querySelectorAll('.skill-card');
112
+ skillCards.forEach((card, index) => {
113
+ card.classList.add('reveal');
114
+ card.style.transitionDelay = `${index * 0.1}s`;
115
+ });
116
+
117
+ // Add reveal classes to project containers
118
+ const projectContainers = document.querySelectorAll('.project-container');
119
+ projectContainers.forEach((card, index) => {
120
+ card.classList.add('reveal');
121
+ card.style.transitionDelay = `${index * 0.15}s`;
122
+ });
123
+ });
124
+
125
+ // Typing effect for hero
126
+ function typeWriter(element, text, speed = 50) {
127
+ let i = 0;
128
+ element.innerHTML = '';
129
+
130
+ function type() {
131
+ if (i < text.length) {
132
+ element.innerHTML += text.charAt(i);
133
+ i++;
134
+ setTimeout(type, speed);
135
+ }
136
+ }
137
+
138
+ type();
139
+ }
style.css CHANGED
@@ -31,17 +31,77 @@ body {
31
  -webkit-background-clip: text;
32
  -webkit-text-fill-color: transparent;
33
  }
34
-
35
  /* Animations */
36
  @keyframes fadeIn {
37
  from { opacity: 0; transform: translateY(20px); }
38
  to { opacity: 1; transform: translateY(0); }
39
  }
40
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
41
  .animate-fade-in {
42
  animation: fadeIn 0.8s ease-out forwards;
43
  }
44
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
  /* Blinking Cursor Animation */
46
  @keyframes blink {
47
  0%, 100% { opacity: 1; }
@@ -58,7 +118,6 @@ body {
58
  linear-gradient(90deg, rgba(234, 179, 8, 0.05) 1px, transparent 1px);
59
  background-size: 40px 40px;
60
  }
61
-
62
  /* Glitch Effect on Hover */
63
  .glitch-hover:hover {
64
  animation: glitch 0.3s cubic-bezier(.25, .46, .45, .94) both infinite;
@@ -72,4 +131,63 @@ body {
72
  60% { transform: translate(2px, 2px) }
73
  80% { transform: translate(2px, -2px) }
74
  100% { transform: translate(0) }
75
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
  -webkit-background-clip: text;
32
  -webkit-text-fill-color: transparent;
33
  }
 
34
  /* Animations */
35
  @keyframes fadeIn {
36
  from { opacity: 0; transform: translateY(20px); }
37
  to { opacity: 1; transform: translateY(0); }
38
  }
39
 
40
+ @keyframes slideUp {
41
+ from { opacity: 0; transform: translateY(40px); }
42
+ to { opacity: 1; transform: translateY(0); }
43
+ }
44
+
45
+ @keyframes slideInLeft {
46
+ from { opacity: 0; transform: translateX(-30px); }
47
+ to { opacity: 1; transform: translateX(0); }
48
+ }
49
+
50
+ @keyframes slideInRight {
51
+ from { opacity: 0; transform: translateX(30px); }
52
+ to { opacity: 1; transform: translateX(0); }
53
+ }
54
+
55
+ @keyframes scaleIn {
56
+ from { opacity: 0; transform: scale(0.9); }
57
+ to { opacity: 1; transform: scale(1); }
58
+ }
59
+
60
  .animate-fade-in {
61
  animation: fadeIn 0.8s ease-out forwards;
62
  }
63
 
64
+ .animate-slide-up {
65
+ animation: slideUp 0.8s ease-out forwards;
66
+ }
67
+
68
+ .animate-scale-in {
69
+ animation: scaleIn 0.6s ease-out forwards;
70
+ }
71
+
72
+ /* Scroll Reveal Classes */
73
+ .reveal {
74
+ opacity: 0;
75
+ transform: translateY(30px);
76
+ transition: all 0.8s ease;
77
+ }
78
+
79
+ .reveal.active {
80
+ opacity: 1;
81
+ transform: translateY(0);
82
+ }
83
+
84
+ .reveal-left {
85
+ opacity: 0;
86
+ transform: translateX(-50px);
87
+ transition: all 0.8s ease;
88
+ }
89
+
90
+ .reveal-left.active {
91
+ opacity: 1;
92
+ transform: translateX(0);
93
+ }
94
+
95
+ .reveal-right {
96
+ opacity: 0;
97
+ transform: translateX(50px);
98
+ transition: all 0.8s ease;
99
+ }
100
+
101
+ .reveal-right.active {
102
+ opacity: 1;
103
+ transform: translateX(0);
104
+ }
105
  /* Blinking Cursor Animation */
106
  @keyframes blink {
107
  0%, 100% { opacity: 1; }
 
118
  linear-gradient(90deg, rgba(234, 179, 8, 0.05) 1px, transparent 1px);
119
  background-size: 40px 40px;
120
  }
 
121
  /* Glitch Effect on Hover */
122
  .glitch-hover:hover {
123
  animation: glitch 0.3s cubic-bezier(.25, .46, .45, .94) both infinite;
 
131
  60% { transform: translate(2px, 2px) }
132
  80% { transform: translate(2px, -2px) }
133
  100% { transform: translate(0) }
134
+ }
135
+
136
+ /* Smooth Scroll Behavior */
137
+ html {
138
+ scroll-behavior: smooth;
139
+ }
140
+
141
+ /* Selection Styling */
142
+ ::selection {
143
+ background: #EAB308;
144
+ color: #0a0a0a;
145
+ }
146
+
147
+ /* Focus Styles */
148
+ a:focus, button:focus, input:focus {
149
+ outline: 2px solid #EAB308;
150
+ outline-offset: 2px;
151
+ }
152
+
153
+ /* Improved Button Hover Effects */
154
+ .btn-primary {
155
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
156
+ }
157
+
158
+ .btn-primary:active {
159
+ transform: scale(0.95);
160
+ }
161
+
162
+ /* Card Hover 3D Effect */
163
+ .card-3d {
164
+ perspective: 1000px;
165
+ }
166
+
167
+ .card-3d-inner {
168
+ transition: transform 0.6s;
169
+ transform-style: preserve-3d;
170
+ }
171
+
172
+ .card-3d:hover .card-3d-inner {
173
+ transform: rotateY(5deg) rotateX(5deg);
174
+ }
175
+
176
+ /* Gradient Text Animation */
177
+ .gradient-text-animate {
178
+ background: linear-gradient(90deg, #EAB308, #CA8A04, #EAB308);
179
+ background-size: 200% auto;
180
+ -webkit-background-clip: text;
181
+ -webkit-text-fill-color: transparent;
182
+ animation: gradientMove 3s linear infinite;
183
+ }
184
+
185
+ @keyframes gradientMove {
186
+ 0% { background-position: 0% center; }
187
+ 100% { background-position: 200% center; }
188
+ }
189
+
190
+ /* Magnetic Button Effect */
191
+ .magnetic-btn {
192
+ transition: transform 0.3s ease;
193
+ }