diff --git a/4-vitals-monitor.html b/4-vitals-monitor.html index d3bb85b..2820ce1 100644 --- a/4-vitals-monitor.html +++ b/4-vitals-monitor.html @@ -239,6 +239,7 @@ font-weight: 700; color: var(--heading); margin-bottom: 32px; + text-align: center; } /* ========================================= @@ -339,6 +340,81 @@ margin-top: 4px; } + /* ========================================= + SKILLS SECTION + ========================================= */ + + .skills-category { + margin-bottom: 40px; + } + + .skills-category:last-child { + margin-bottom: 0; + } + + .skills-cat-label { + font-family: var(--font-secondary); + font-size: 12px; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.08em; + color: var(--muted); + margin-bottom: 20px; + padding-left: 4px; + } + + .skills-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); + gap: 24px; + } + + .skill-item { + display: flex; + flex-direction: column; + align-items: center; + padding: 16px; + border-radius: var(--radius); + transition: background 0.3s ease; + } + + .skill-item:hover { + background: var(--teal-light); + } + + .skill-item[data-color="coral"]:hover { + background: var(--coral-light); + } + + .skill-gauge { + display: block; + } + + .skill-progress { + stroke-dasharray: 213.628; + stroke-dashoffset: 213.628; + transition: stroke-dashoffset 1.2s ease-out; + } + + .skill-name { + font-family: var(--font-primary); + font-size: 12px; + font-weight: 600; + color: var(--heading); + margin-top: 8px; + text-align: center; + line-height: 1.3; + } + + .skill-cat { + font-family: var(--font-secondary); + font-size: 10px; + color: var(--muted); + text-transform: uppercase; + letter-spacing: 0.04em; + margin-top: 2px; + } + /* ========================================= RESPONSIVE: 768px ========================================= */ @@ -365,6 +441,10 @@ display: grid; grid-template-columns: repeat(2, 1fr); } + + .skills-grid { + grid-template-columns: repeat(3, 1fr); + } } /* ========================================= @@ -393,6 +473,20 @@ display: grid; grid-template-columns: 1fr; } + + .skills-grid { + grid-template-columns: repeat(2, 1fr); + gap: 16px; + } + + .skill-gauge { + width: 64px; + height: 64px; + } + + .skill-item { + padding: 12px; + } } @@ -449,7 +543,187 @@ - + Skills & Expertise + + + Technical + + + + + + 90% + + Python + Technical + + + + + + 88% + + SQL + Technical + + + + + + 92% + + Power BI + Technical + + + + + + 70% + + JS / TS + Technical + + + + + + 95% + + Data Analysis + Technical + + + + + + 88% + + Dashboard Dev + Technical + + + + + + 82% + + Algorithm Design + Technical + + + + + + 80% + + Data Pipelines + Technical + + + + + + Clinical + + + + + + 95% + + Medicines Optimisation + Clinical + + + + + + 90% + + Pop. Health Analytics + Clinical + + + + + + 85% + + NICE TA + Clinical + + + + + + 80% + + Health Economics + Clinical + + + + + + 82% + + Clinical Pathways + Clinical + + + + + + 88% + + CD Assurance + Clinical + + + + + + Strategic + + + + + + 90% + + Budget Mgmt + Strategic + + + + + + 88% + + Stakeholder Engagement + Strategic + + + + + + 85% + + Pharma Negotiation + Strategic + + + + + + 82% + + Team Development + Strategic + + + @@ -869,8 +1143,9 @@ var cvContent = document.getElementById('cv-content'); cvContent.classList.add('revealed'); - // Initialize nav tracking and smooth scroll after reveal + // Initialize nav tracking, smooth scroll, and skill gauges after reveal initNavTracking(); + initSkillGauges(); }, 500); } @@ -920,6 +1195,45 @@ }); } + /* ========================================= + SKILL GAUGES: Scroll-triggered animation + ========================================= */ + + function initSkillGauges() { + var skillsSection = document.getElementById('skills'); + if (!skillsSection) return; + + var skillItems = skillsSection.querySelectorAll('.skill-item'); + var circumference = 2 * Math.PI * 34; // ~213.628 + var animated = false; + + var gaugeObserver = new IntersectionObserver(function(entries) { + entries.forEach(function(entry) { + if (entry.isIntersecting && !animated) { + animated = true; + gaugeObserver.unobserve(entry.target); + + skillItems.forEach(function(item, index) { + var level = parseInt(item.getAttribute('data-level'), 10); + var progressCircle = item.querySelector('.skill-progress'); + if (!progressCircle) return; + + var targetOffset = circumference * (1 - level / 100); + + // Stagger each gauge by 100ms + setTimeout(function() { + progressCircle.style.strokeDashoffset = targetOffset; + }, index * 100); + }); + } + }); + }, { + threshold: 0.15 + }); + + gaugeObserver.observe(skillsSection); + } + })();