diff --git a/src/glenntyson/images/headshot.png b/src/glenntyson/images/headshot.png new file mode 100644 index 0000000..d8a6f80 Binary files /dev/null and b/src/glenntyson/images/headshot.png differ diff --git a/src/glenntyson/index.html b/src/glenntyson/index.html new file mode 100644 index 0000000..af07271 --- /dev/null +++ b/src/glenntyson/index.html @@ -0,0 +1,207 @@ + + + + + + Glenn Tyson | Student Portfolio + + + + + + + + + +
+
+
+ Professional headshot of Glenn Tyson +
+ +
+ +

I'm Glenn Tyson

+

+ I am an entry-level software developer who is focused on learning, building strong projects, + and growing into a dependable member of a professional development team. +

+

+ I enjoy working with Java, web development, backend systems, and problem solving. + I like taking what I learn and applying it through real hands-on projects that help me grow. +

+ + +
+
+ +
+ +

Who I Am

+

+ I am an aspiring software developer building a foundation in programming, + frontend development, backend development, and software problem solving. +

+

+ My goal is to continue improving through hands-on experience, strengthen my technical skills, + and contribute to projects that solve real problems and support real users. +

+
+ +
+ +

My Learning Journey

+ +
+

Software Development Studies

+

Current Student / Developer in Training

+

+ I am developing a strong foundation in software development through project-based learning + and consistent hands-on coding practice. +

+

+ My work includes Java, HTML, CSS, JavaScript, SQL, backend logic, debugging, + and building applications that strengthen both my technical skills and confidence as a developer. +

+

+ I am continuing to improve in coding, problem solving, and software design while preparing + for professional opportunities in technology. +

+
+
+ +
+ +

Certifications

+ +
+
HTML — Pursuing
+
Google AI — Pursuing
+
CompTIA — Pursuing
+
Scrum — Earned
+
Java — Earned
+
+
+ +
+ +

What I'm Working With

+ +
+
Java
+
HTML
+
CSS
+
JavaScript
+
SQL
+
GitHub
+
Spring Boot
+
Teamwork
+
Communication
+
+
+ +
+ +

What I’m Building Toward

+ +
+
+

Keep Learning

+

+ Continue improving my programming, debugging, and development skills through practice, + coursework, and project work. +

+
+ +
+

Build Strong Projects

+

+ Create projects that show my growth, technical ability, and understanding of + real software development concepts. +

+
+ +
+

Start My Career

+

+ Grow into a professional developer role where I can contribute to a team, + continue learning, and keep improving over time. +

+
+
+
+ +
+ +

Get In Touch

+

+ I would be glad to connect about opportunities, projects, or networking. +

+ +
+
+

Email

+

gatyson261@gmail.com

+
+ +
+

GitHub

+

github.com/GTyson261

+
+
+
+
+ + + + + + \ No newline at end of file diff --git a/src/glenntyson/projects.html b/src/glenntyson/projects.html new file mode 100644 index 0000000..ceb32cf --- /dev/null +++ b/src/glenntyson/projects.html @@ -0,0 +1,132 @@ + + + + + + Glenn Tyson | Projects + + + + + + + + + +
+
+ +

My Work

+

+ These projects show my growth in Java, backend development, problem solving, + and building applications through hands-on practice. +

+
+ +
+
+
+

Java Chess Game

+ Java / JavaFX +
+

+ A chess application built with Java and JavaFX that includes game logic, + board movement, and a graphical interface for playing chess. +

+

+ This project helped me strengthen object-oriented programming, class design, + and working with interactive user interfaces. +

+ + + View on GitHub + +
+ +
+
+

Forum Web App

+ Java / SQLite +
+

+ A forum-style web application built with Java, SQLite, and a custom HTTP server. + It supports user login, post creation, editing, and deleting posts. +

+

+ This project helped me practice backend logic, database integration, + routing, debugging, and test coverage. +

+
+ +
+
+

Portfolio Website

+ HTML / CSS / JavaScript +
+

+ A personal portfolio site designed to introduce who I am, show my skills, + and highlight my projects in a clean, professional layout. +

+

+ This project helped me improve responsive design, page structure, + styling, and interactive front-end effects. +

+
+
+
+ + + + + + \ No newline at end of file diff --git a/src/glenntyson/script.js b/src/glenntyson/script.js new file mode 100644 index 0000000..75ddbab --- /dev/null +++ b/src/glenntyson/script.js @@ -0,0 +1,472 @@ +const canvas = document.getElementById("cursorEffectCanvas"); +const ctx = canvas.getContext("2d"); + +const stars = []; +const maxStars = 70; +let lastStarTime = 0; + +function resizeCanvas() { + canvas.width = window.innerWidth; + canvas.height = window.innerHeight; +} + +function createStar(x, y) { + const angle = Math.random() * Math.PI * 2; + const speed = Math.random() * 0.8 + 0.2; + + stars.push({ + x, + y, + size: Math.random() * 2.5 + 1.5, + alpha: 1, + vx: Math.cos(angle) * speed, + vy: Math.sin(angle) * speed, + life: Math.random() * 20 + 40, + maxLife: 60 + }); + + if (stars.length > maxStars) { + stars.shift(); + } +} + +function drawStar(x, y, size, alpha) { + ctx.save(); + ctx.translate(x, y); + ctx.globalAlpha = alpha; + ctx.fillStyle = "#7cc4ff"; + ctx.shadowBlur = 12; + ctx.shadowColor = "#7cc4ff"; + + ctx.beginPath(); + + for (let i = 0; i < 5; i++) { + const outerAngle = (Math.PI / 180) * (i * 72 - 90); + const innerAngle = (Math.PI / 180) * (i * 72 + 36 - 90); + + const outerX = Math.cos(outerAngle) * size; + const outerY = Math.sin(outerAngle) * size; + const innerX = Math.cos(innerAngle) * (size * 0.45); + const innerY = Math.sin(innerAngle) * (size * 0.45); + + if (i === 0) { + ctx.moveTo(outerX, outerY); + } else { + ctx.lineTo(outerX, outerY); + } + + ctx.lineTo(innerX, innerY); + } + + ctx.closePath(); + ctx.fill(); + ctx.restore(); +} + +function drawLines() { + for (let i = 0; i < stars.length; i++) { + for (let j = i + 1; j < stars.length; j++) { + const dx = stars[i].x - stars[j].x; + const dy = stars[i].y - stars[j].y; + const distance = Math.sqrt(dx * dx + dy * dy); + + if (distance < 100) { + const opacity = ((100 - distance) / 100) * 0.35 * Math.min(stars[i].alpha, stars[j].alpha); + + ctx.save(); + ctx.strokeStyle = `rgba(124, 196, 255, ${opacity})`; + ctx.lineWidth = 1; + ctx.beginPath(); + ctx.moveTo(stars[i].x, stars[i].y); + ctx.lineTo(stars[j].x, stars[j].y); + ctx.stroke(); + ctx.restore(); + } + } + } +} + +function updateStars() { + for (let i = stars.length - 1; i >= 0; i--) { + const star = stars[i]; + star.x += star.vx; + star.y += star.vy; + star.life -= 1; + star.alpha = star.life / star.maxLife; + + if (star.life <= 0) { + stars.splice(i, 1); + } + } +} + +function animate() { + ctx.clearRect(0, 0, canvas.width, canvas.height); + updateStars(); + drawLines(); + + for (const star of stars) { + drawStar(star.x, star.y, star.size, Math.max(star.alpha, 0)); + } + + requestAnimationFrame(animate); +} + +document.addEventListener("mousemove", (event) => { + const now = performance.now(); + + if (now - lastStarTime > 16) { + createStar(event.clientX, event.clientY); + lastStarTime = now; + } +}); + +const nav = document.getElementById("siteNav"); +const navIndicator = document.getElementById("navIndicator"); +const navLinks = nav ? Array.from(nav.querySelectorAll("a")) : []; + +function setActiveNavLink(link) { + if (!nav || !navIndicator || !link) return; + + navLinks.forEach((navLink) => navLink.classList.remove("active-link")); + link.classList.add("active-link"); + + navIndicator.style.width = `${link.offsetWidth - 20}px`; + navIndicator.style.left = `${link.offsetLeft + 10}px`; + navIndicator.style.opacity = "1"; +} + +function updateScrollingNav() { + if (!navLinks.length) return; + + const currentPage = window.location.pathname.split("/").pop() || "index.html"; + + if (currentPage.includes("projects")) { + const projectsLink = navLinks.find((link) => link.getAttribute("href") === "projects.html"); + if (projectsLink) setActiveNavLink(projectsLink); + return; + } + + const sections = [ + { id: "about", href: "#about" }, + { id: "education", href: "#education" }, + { id: "certifications", href: "#certifications" }, + { id: "skills", href: "#skills" }, + { id: "contact", href: "#contact" } + ]; + + const scrollPosition = window.scrollY + 140; + let activeSection = sections[0]; + + for (const section of sections) { + const element = document.getElementById(section.id); + if (element && scrollPosition >= element.offsetTop) { + activeSection = section; + } + } + + const activeLink = navLinks.find((link) => link.getAttribute("href") === activeSection.href); + if (activeLink) setActiveNavLink(activeLink); +} + +function setInitialNavState() { + if (!navLinks.length) return; + + const currentPage = window.location.pathname.split("/").pop() || "index.html"; + + if (currentPage.includes("projects")) { + const projectsLink = navLinks.find((link) => link.getAttribute("href") === "projects.html"); + if (projectsLink) { + setActiveNavLink(projectsLink); + } + } else { + updateScrollingNav(); + } +} + +window.addEventListener("scroll", updateScrollingNav); + +window.addEventListener("resize", () => { + resizeCanvas(); + setInitialNavState(); +}); + +navLinks.forEach((link) => { + link.addEventListener("mouseenter", () => { + setActiveNavLink(link); + }); + + link.addEventListener("mouseleave", () => { + setInitialNavState(); + }); +}); + +/* Dark mode */ +const THEME_KEY = "portfolioTheme"; +const themeToggle = document.getElementById("themeToggle"); + +function applyTheme(theme) { + if (!themeToggle) return; + + if (theme === "dark") { + document.body.classList.add("dark-mode"); + themeToggle.textContent = "ā˜€ļø"; + themeToggle.setAttribute("aria-label", "Switch to light mode"); + } else { + document.body.classList.remove("dark-mode"); + themeToggle.textContent = "šŸŒ™"; + themeToggle.setAttribute("aria-label", "Switch to dark mode"); + } +} + +function loadTheme() { + const savedTheme = localStorage.getItem(THEME_KEY) || "light"; + applyTheme(savedTheme); +} + +if (themeToggle) { + themeToggle.addEventListener("click", () => { + const isDark = document.body.classList.contains("dark-mode"); + const nextTheme = isDark ? "light" : "dark"; + localStorage.setItem(THEME_KEY, nextTheme); + applyTheme(nextTheme); + }); +} + +/* YouTube music setup */ +const YOUTUBE_URL = "https://www.youtube.com/watch?v=yW51MHHHL7Y"; +const MUSIC_ENABLED_KEY = "portfolioMusicEnabled"; +const MUSIC_TIME_KEY = "portfolioMusicTime"; +const MUSIC_VIDEO_KEY = "portfolioMusicVideoId"; +const MUSIC_VOLUME_KEY = "portfolioMusicVolume"; + +const musicToggle = document.getElementById("musicToggle"); +const volumeSlider = document.getElementById("volumeSlider"); + +let player = null; +let playerReady = false; +let saveTimeInterval = null; + +function extractYouTubeVideoId(url) { + try { + const parsedUrl = new URL(url); + + if (parsedUrl.hostname.includes("youtu.be")) { + return parsedUrl.pathname.replace("/", "").trim(); + } + + if (parsedUrl.searchParams.get("v")) { + return parsedUrl.searchParams.get("v"); + } + + if (parsedUrl.pathname.includes("/embed/")) { + return parsedUrl.pathname.split("/embed/")[1].split("/")[0]; + } + + if (parsedUrl.pathname.includes("/shorts/")) { + return parsedUrl.pathname.split("/shorts/")[1].split("/")[0]; + } + + return ""; + } catch (error) { + return ""; + } +} + +const videoId = extractYouTubeVideoId(YOUTUBE_URL); + +if (!videoId) { + console.warn("Invalid YouTube URL. Add a valid YouTube link in YOUTUBE_URL."); +} else { + localStorage.setItem(MUSIC_VIDEO_KEY, videoId); +} + +function updateMusicButton(isPlaying) { + if (!musicToggle) return; + musicToggle.textContent = isPlaying ? "Music On" : "Music Off"; +} + +function getSavedMusicEnabled() { + return localStorage.getItem(MUSIC_ENABLED_KEY) === "true"; +} + +function getSavedMusicTime() { + const saved = Number(localStorage.getItem(MUSIC_TIME_KEY)); + return Number.isFinite(saved) ? saved : 0; +} + +function getSavedMusicVolume() { + const saved = Number(localStorage.getItem(MUSIC_VOLUME_KEY)); + if (Number.isFinite(saved) && saved >= 0 && saved <= 100) { + return saved; + } + return 35; +} + +function setSavedMusicVolume(volume) { + localStorage.setItem(MUSIC_VOLUME_KEY, String(volume)); +} + +function saveMusicTime() { + if (player && playerReady && typeof player.getCurrentTime === "function") { + const currentTime = player.getCurrentTime(); + if (Number.isFinite(currentTime)) { + localStorage.setItem(MUSIC_TIME_KEY, String(currentTime)); + } + } +} + +function startSavingMusicTime() { + if (saveTimeInterval) clearInterval(saveTimeInterval); + saveTimeInterval = setInterval(saveMusicTime, 1000); +} + +function stopSavingMusicTime() { + if (saveTimeInterval) { + clearInterval(saveTimeInterval); + saveTimeInterval = null; + } +} + +function loadYouTubeApi() { + if (!videoId) return; + + if (window.YT && window.YT.Player) { + onYouTubeIframeAPIReady(); + return; + } + + const tag = document.createElement("script"); + tag.src = "https://www.youtube.com/iframe_api"; + document.head.appendChild(tag); +} + +window.onYouTubeIframeAPIReady = function () { + if (!videoId) return; + + player = new YT.Player("youtubePlayer", { + height: "200", + width: "200", + videoId, + playerVars: { + autoplay: 0, + controls: 0, + disablekb: 1, + fs: 0, + modestbranding: 1, + playsinline: 1, + rel: 0, + origin: window.location.origin + }, + events: { + onReady: onPlayerReady, + onStateChange: onPlayerStateChange + } + }); +}; + +function onPlayerReady() { + playerReady = true; + + const savedTime = getSavedMusicTime(); + const shouldPlay = getSavedMusicEnabled(); + const savedVolume = getSavedMusicVolume(); + + if (volumeSlider) { + volumeSlider.value = savedVolume; + } + + player.setVolume(savedVolume); + + if (savedTime > 0) { + player.seekTo(savedTime, true); + } + + if (shouldPlay && savedVolume > 0) { + player.unMute(); + player.playVideo(); + updateMusicButton(true); + startSavingMusicTime(); + } else { + player.mute(); + updateMusicButton(false); + } +} + +function onPlayerStateChange(event) { + if (!window.YT || !window.YT.PlayerState) return; + + if (event.data === YT.PlayerState.PLAYING) { + startSavingMusicTime(); + } + + if (event.data === YT.PlayerState.PAUSED || event.data === YT.PlayerState.ENDED) { + saveMusicTime(); + } + + if (event.data === YT.PlayerState.ENDED) { + player.seekTo(0, true); + if (getSavedMusicEnabled() && getSavedMusicVolume() > 0) { + player.playVideo(); + } + } +} + +if (musicToggle) { + musicToggle.addEventListener("click", () => { + if (!player || !playerReady) return; + + const isEnabled = getSavedMusicEnabled(); + const currentVolume = getSavedMusicVolume(); + + if (isEnabled) { + player.pauseVideo(); + player.mute(); + localStorage.setItem(MUSIC_ENABLED_KEY, "false"); + saveMusicTime(); + updateMusicButton(false); + stopSavingMusicTime(); + } else { + localStorage.setItem(MUSIC_ENABLED_KEY, "true"); + + if (currentVolume > 0) { + player.setVolume(currentVolume); + player.unMute(); + player.playVideo(); + startSavingMusicTime(); + updateMusicButton(true); + } else { + updateMusicButton(false); + } + } + }); +} + +if (volumeSlider) { + volumeSlider.addEventListener("input", (event) => { + const volume = Number(event.target.value); + setSavedMusicVolume(volume); + + if (player && playerReady) { + player.setVolume(volume); + + if (volume === 0) { + player.mute(); + updateMusicButton(false); + } else if (getSavedMusicEnabled()) { + player.unMute(); + updateMusicButton(true); + } + } + }); +} + +window.addEventListener("beforeunload", () => { + saveMusicTime(); +}); + +loadTheme(); +resizeCanvas(); +setInitialNavState(); +animate(); +loadYouTubeApi(); \ No newline at end of file diff --git a/src/glenntyson/styles.css b/src/glenntyson/styles.css new file mode 100644 index 0000000..4b621a3 --- /dev/null +++ b/src/glenntyson/styles.css @@ -0,0 +1,691 @@ +:root { + --bg-main: #eef3f8; + --bg-gradient-1: rgba(47, 111, 178, 0.15); + --bg-gradient-2: rgba(124, 196, 255, 0.2); + --bg-gradient-3: rgba(47, 111, 178, 0.12); + --bg-overlay-1: rgba(124, 196, 255, 0.15); + --bg-overlay-2: rgba(47, 111, 178, 0.1); + + --bg-card: rgba(255, 255, 255, 0.85); + --bg-card-solid: #ffffff; + --bg-soft: #f8fbff; + --bg-tag: #f3f7fb; + --bg-pill: #eef4fb; + + --text-main: #1f2a36; + --text-heading: #183153; + --text-muted: #58708b; + --text-link: #2f6fb2; + --text-link-hover: #183153; + + --border-main: #d8e0ea; + --border-soft: #b9c9dc; + --accent: #2f6fb2; + --accent-hover: #255f9a; + --accent-light: #7cc4ff; + + --header-bg: rgba(255, 255, 255, 0.9); + --header-shadow: rgba(0, 0, 0, 0.05); + + --control-bg: #ffffff; + --control-text: #26476b; + --nav-hover: #e8f0f9; + + --project-cta-bg: #24292e; + --project-cta-hover: #1b1f23; +} + +body.dark-mode { + --bg-main: #0f1720; + --bg-gradient-1: rgba(35, 79, 132, 0.28); + --bg-gradient-2: rgba(124, 196, 255, 0.12); + --bg-gradient-3: rgba(52, 110, 176, 0.18); + --bg-overlay-1: rgba(124, 196, 255, 0.1); + --bg-overlay-2: rgba(47, 111, 178, 0.12); + + --bg-card: rgba(20, 30, 45, 0.9); + --bg-card-solid: #162232; + --bg-soft: #19283a; + --bg-tag: #1a2a3d; + --bg-pill: #1c2d42; + + --text-main: #e6edf5; + --text-heading: #f4f8fc; + --text-muted: #9fb3c8; + --text-link: #7cc4ff; + --text-link-hover: #b8ddff; + + --border-main: #2a3b52; + --border-soft: #39506c; + --accent: #7cc4ff; + --accent-hover: #5eb0f5; + --accent-light: #9ad2ff; + + --header-bg: rgba(15, 23, 32, 0.9); + --header-shadow: rgba(0, 0, 0, 0.25); + + --control-bg: #1c2a3a; + --control-text: #e6edf5; + --nav-hover: #1a2a3d; + + --project-cta-bg: #0f141a; + --project-cta-hover: #06090d; +} + +html { + scroll-behavior: smooth; + scroll-padding-top: 90px; +} + +* { + box-sizing: border-box; +} + +body { + margin: 0; + font-family: Arial, sans-serif; + color: var(--text-main); + line-height: 1.6; + position: relative; + overflow-x: hidden; + background: + radial-gradient(circle at 20% 20%, var(--bg-gradient-1), transparent 40%), + radial-gradient(circle at 80% 30%, var(--bg-gradient-2), transparent 45%), + radial-gradient(circle at 50% 80%, var(--bg-gradient-3), transparent 40%), + linear-gradient(135deg, var(--bg-main), var(--bg-main)); + background-size: 200% 200%; + animation: gradientShift 25s ease infinite; + transition: background-color 0.4s ease, color 0.4s ease; +} + +body::before { + content: ""; + position: fixed; + inset: 0; + pointer-events: none; + z-index: -1; + background: + radial-gradient(circle at 30% 40%, var(--bg-overlay-1), transparent 50%), + radial-gradient(circle at 70% 60%, var(--bg-overlay-2), transparent 50%); + animation: glowDrift 30s ease-in-out infinite; +} + +.page-width { + width: min(1000px, calc(100% - 32px)); + margin: 0 auto; +} + +.cursor-effect-canvas { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + pointer-events: none; + z-index: 9999; +} + +.site-header { + background: var(--header-bg); + border-bottom: 1px solid var(--border-main); + position: sticky; + top: 0; + z-index: 10; + backdrop-filter: blur(8px); + box-shadow: 0 4px 12px var(--header-shadow); + transition: background 0.4s ease, border-color 0.4s ease, box-shadow 0.4s ease; +} + +.header-layout { + display: flex; + justify-content: space-between; + align-items: center; + gap: 20px; + padding: 14px 0; +} + +.header-actions { + display: flex; + align-items: center; + gap: 14px; + flex-wrap: wrap; + justify-content: flex-end; +} + +.ui-controls { + display: flex; + align-items: center; + gap: 12px; + flex-wrap: wrap; +} + +.music-controls { + display: flex; + align-items: center; + gap: 12px; + flex-wrap: wrap; +} + +.theme-toggle, +.music-toggle { + border: 1px solid var(--border-soft); + background: var(--control-bg); + color: var(--control-text); + border-radius: 10px; + padding: 10px 14px; + font-weight: 700; + cursor: pointer; + transition: transform 0.2s ease, background-color 0.2s ease, box-shadow 0.2s ease, color 0.2s ease, border-color 0.2s ease; +} + +.theme-toggle { + min-width: 48px; + font-size: 18px; + padding: 10px; +} + +.theme-toggle:hover, +.music-toggle:hover { + background: var(--nav-hover); + transform: translateY(-1px); + box-shadow: 0 6px 14px rgba(31, 42, 54, 0.08); +} + +.volume-control { + display: flex; + align-items: center; + gap: 10px; + background: var(--control-bg); + border: 1px solid var(--border-soft); + border-radius: 10px; + padding: 8px 12px; + color: var(--control-text); + font-weight: 700; + transition: background-color 0.2s ease, color 0.2s ease, border-color 0.2s ease; +} + +.volume-control span { + font-size: 0.95rem; + white-space: nowrap; +} + +.volume-control input[type="range"] { + width: 110px; + accent-color: var(--accent); + cursor: pointer; +} + +.identity-block h1 { + margin: 0; + color: var(--text-heading); + font-size: 2.2rem; + letter-spacing: 0.3px; + transition: color 0.4s ease; +} + +.site-subtitle { + margin: 4px 0 0; + color: var(--text-muted); + font-size: 0.95rem; + transition: color 0.4s ease; +} + +.site-nav { + display: flex; + flex-wrap: wrap; + gap: 10px; + position: relative; +} + +.site-nav a { + text-decoration: none; + color: var(--text-main); + font-weight: 600; + padding: 8px 10px 14px; + border-radius: 8px; + transition: background-color 0.25s ease, color 0.25s ease, transform 0.2s ease; + position: relative; +} + +.site-nav a:hover { + background: var(--nav-hover); + color: var(--text-heading); + transform: translateY(-1px); +} + +.site-nav a.active-link { + color: var(--text-heading); +} + +.nav-indicator { + position: absolute; + bottom: 4px; + left: 0; + width: 0; + height: 3px; + border-radius: 999px; + background: linear-gradient(to right, var(--accent-light), var(--accent)); + transition: left 0.3s ease, width 0.3s ease, opacity 0.3s ease; + opacity: 0; +} + +.youtube-player-wrap { + position: fixed; + width: 1px; + height: 1px; + overflow: hidden; + left: -9999px; + top: -9999px; +} + +main { + padding: 32px 0 48px; +} + +.intro-layout { + display: grid; + grid-template-columns: 280px 1fr; + gap: 24px; + margin-bottom: 24px; +} + +.profile-photo-panel, +.profile-summary-panel, +.resume-section, +.project-entry, +.info-card, +.contact-card { + background: var(--bg-card); + border: 1px solid var(--border-main); + border-radius: 16px; + box-shadow: 0 12px 30px rgba(31, 42, 54, 0.12); + backdrop-filter: blur(6px); + transition: background 0.4s ease, border-color 0.4s ease, box-shadow 0.25s ease, transform 0.25s ease; +} + +.profile-photo-panel, +.profile-summary-panel, +.resume-section, +.project-entry, +.info-card, +.contact-card { + animation: fadeUp 0.7s ease both; +} + +.profile-summary-panel { + animation-delay: 0.08s; +} + +.resume-section:nth-of-type(1) { + animation-delay: 0.12s; +} + +.resume-section:nth-of-type(2) { + animation-delay: 0.18s; +} + +.resume-section:nth-of-type(3) { + animation-delay: 0.24s; +} + +.profile-photo-panel { + padding: 20px; + display: flex; + align-items: center; + justify-content: center; + position: relative; + overflow: hidden; +} + +.profile-photo-panel::before { + content: ""; + position: absolute; + width: 220px; + height: 220px; + background: radial-gradient(circle, rgba(124, 196, 255, 0.28), rgba(124, 196, 255, 0.08), transparent 70%); + border-radius: 50%; + z-index: 0; + animation: portraitGlow 8s ease-in-out infinite; +} + +.profile-photo-panel img { + width: 100%; + max-width: 220px; + border-radius: 14px; + display: block; + border: 3px solid white; + box-shadow: 0 10px 30px rgba(47, 111, 178, 0.25); + position: relative; + z-index: 1; +} + +.profile-summary-panel { + padding: 28px; +} + +.section-label { + margin: 0 0 8px; + font-size: 0.8rem; + font-weight: 800; + letter-spacing: 1.8px; + text-transform: uppercase; + color: var(--text-muted); + transition: color 0.4s ease; +} + +.profile-summary-panel h2, +.resume-section h2, +.project-entry h3, +.info-card h3, +.contact-card h3, +.education-entry h3 { + margin-top: 0; + color: var(--text-heading); + transition: color 0.4s ease; +} + +.profile-summary-panel h2, +.resume-section h2 { + margin-bottom: 14px; + font-size: 2rem; + line-height: 1.15; +} + +.intro-lead { + font-size: 1.05rem; + color: var(--text-main); +} + +.button-row { + display: flex; + flex-wrap: wrap; + gap: 12px; + margin-top: 20px; +} + +.button-main, +.button-alt { + display: inline-block; + text-decoration: none; + padding: 11px 16px; + border-radius: 10px; + font-weight: 700; + transition: transform 0.2s ease, background-color 0.2s ease, border-color 0.2s ease, box-shadow 0.2s ease, color 0.2s ease; +} + +.button-main { + background: var(--accent); + color: #ffffff; +} + +.button-main:hover { + background: var(--accent-hover); + transform: translateY(-1px); + box-shadow: 0 6px 16px rgba(47, 111, 178, 0.18); +} + +.button-alt { + background: var(--bg-card-solid); + color: var(--accent); + border: 1px solid var(--border-soft); +} + +.button-alt:hover { + background: var(--bg-tag); + transform: translateY(-1px); +} + +.resume-section { + padding: 26px; + margin-bottom: 24px; + scroll-margin-top: 100px; +} + +.resume-section:hover, +.project-entry:hover, +.info-card:hover, +.contact-card:hover { + transform: translateY(-4px); + box-shadow: 0 18px 40px rgba(31, 42, 54, 0.18); +} + +.education-entry { + margin-top: 16px; + padding: 20px; + background: var(--bg-soft); + border: 1px solid var(--border-main); + border-left: 5px solid var(--accent); + border-radius: 12px; + transition: background 0.4s ease, border-color 0.4s ease; +} + +.education-meta { + margin-top: 0; + margin-bottom: 12px; + font-weight: 700; + color: var(--text-muted); +} + +.skills-list { + display: flex; + flex-wrap: wrap; + gap: 12px; + margin-top: 18px; +} + +.skill-item { + padding: 10px 14px; + background: var(--bg-tag); + border: 1px solid var(--border-main); + border-radius: 999px; + font-weight: 600; + color: var(--control-text); + transition: background 0.4s ease, border-color 0.4s ease, color 0.4s ease; +} + +.goal-list { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 18px; + margin-top: 20px; +} + +.info-card { + padding: 20px; +} + +.info-card p { + margin-bottom: 0; +} + +.contact-grid { + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 18px; + margin-top: 18px; +} + +.contact-card { + padding: 20px; +} + +.contact-card a, +.project-entry a { + color: var(--text-link); +} + +.contact-card a:hover, +.project-entry a:hover { + color: var(--text-link-hover); +} + +.page-intro-section { + margin-bottom: 20px; +} + +.project-stack { + display: grid; + gap: 20px; +} + +.project-entry { + padding: 24px; + display: flex; + flex-direction: column; +} + +.project-entry-top { + display: flex; + justify-content: space-between; + align-items: center; + gap: 12px; + margin-bottom: 12px; +} + +.project-type { + background: var(--bg-pill); + color: var(--control-text); + border: 1px solid var(--border-main); + border-radius: 999px; + padding: 6px 12px; + font-size: 0.85rem; + font-weight: 700; + transition: background 0.4s ease, border-color 0.4s ease, color 0.4s ease; +} + +.project-cta { + display: inline-flex; + align-items: center; + gap: 10px; + margin-top: 14px; + width: fit-content; + background: var(--project-cta-bg); + color: #ffffff; +} + +.project-cta:hover { + background: var(--project-cta-hover); + color: #ffffff; +} + +.github-icon { + width: 18px; + height: 18px; + display: inline-block; + background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='white' viewBox='0 0 24 24'%3E%3Cpath d='M12 0C5.37 0 0 5.37 0 12c0 5.3 3.44 9.8 8.21 11.39.6.11.82-.26.82-.58 0-.29-.01-1.06-.02-2.08-3.34.73-4.04-1.61-4.04-1.61-.55-1.39-1.34-1.76-1.34-1.76-1.1-.76.08-.75.08-.75 1.22.09 1.86 1.25 1.86 1.25 1.08 1.85 2.83 1.32 3.52 1.01.11-.78.42-1.32.76-1.62-2.66-.3-5.46-1.33-5.46-5.93 0-1.31.47-2.38 1.24-3.22-.12-.3-.54-1.52.12-3.17 0 0 1.01-.32 3.3 1.23a11.5 11.5 0 013-.4c1.02 0 2.05.14 3 .4 2.29-1.55 3.3-1.23 3.3-1.23.66 1.65.24 2.87.12 3.17.77.84 1.24 1.91 1.24 3.22 0 4.61-2.8 5.63-5.47 5.93.43.37.82 1.1.82 2.22 0 1.6-.01 2.89-.01 3.28 0 .32.21.69.83.57C20.56 21.79 24 17.3 24 12c0-6.63-5.37-12-12-12z'/%3E%3C/svg%3E") no-repeat center; + background-size: contain; +} + +.site-footer { + text-align: center; + padding: 20px 16px 30px; + color: var(--text-muted); + transition: color 0.4s ease; +} + +@keyframes gradientShift { + 0% { background-position: 0% 50%; } + 25% { background-position: 50% 60%; } + 50% { background-position: 100% 50%; } + 75% { background-position: 60% 40%; } + 100% { background-position: 0% 50%; } +} + +@keyframes glowDrift { + 0% { transform: translate(0px, 0px); } + 50% { transform: translate(20px, -20px); } + 100% { transform: translate(0px, 0px); } +} + +@keyframes portraitGlow { + 0% { + transform: scale(1) translateY(0); + opacity: 0.75; + } + 50% { + transform: scale(1.08) translateY(-6px); + opacity: 1; + } + 100% { + transform: scale(1) translateY(0); + opacity: 0.75; + } +} + +@keyframes fadeUp { + from { + opacity: 0; + transform: translateY(18px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +@media (max-width: 1100px) { + .header-layout { + flex-direction: column; + align-items: flex-start; + } + + .header-actions { + width: 100%; + justify-content: flex-start; + } + + .ui-controls, + .music-controls { + width: 100%; + justify-content: flex-start; + } +} + +@media (max-width: 820px) { + .intro-layout, + .goal-list, + .contact-grid { + grid-template-columns: 1fr; + } + + .profile-photo-panel img { + max-width: 200px; + } + + .project-entry-top { + flex-direction: column; + align-items: flex-start; + } +} + +@media (max-width: 560px) { + .page-width { + width: min(100% - 20px, 1000px); + } + + .profile-summary-panel, + .resume-section, + .project-entry, + .info-card, + .contact-card { + padding: 20px; + } + + .profile-summary-panel h2, + .resume-section h2 { + font-size: 1.6rem; + } + + .site-nav { + gap: 6px; + } + + .site-nav a { + padding: 8px 8px 14px; + font-size: 0.95rem; + } + + .volume-control input[type="range"] { + width: 90px; + } +} \ No newline at end of file