Dimitrios Mousouroulis

Dimitrios Mousouroulis


Simplified Reporting.Decisions.

(function () { /* ========================================================= ANIMATED HERO TEXT — SCRIPT Place in: Hero section → Inline Embed → HTML PURPOSE - Measures rotating words safely - Rotates through the words once - Stops on the final chosen word - Restarts when users leave and re-enter #home / #hero EDIT MAINLY: 1) Stop word index 2) Minimum transitions before stopping 3) Section restart trigger thresholds ========================================================= */ function initDMPremiumHero() { var root = document.getElementById('dm-hero-premium'); if (!root) return; if (root.__dmHeroController) { root.__dmHeroController.refreshLater([0, 80, 220]); return; } var stage = root.querySelector('.dm-rotating-stage'); var words = Array.from(root.querySelectorAll('.dm-rotating-word')); if (!stage || !words.length) return; var activeIndex = words.findIndex(function (word) { return word.classList.contains('is-active'); }); var startIndex = activeIndex > -1 ? activeIndex : 0; var current = startIndex; var intervalId = null; var resizeTimer = null; var rotateDelay = 2200; var fadeSpeed = 220; var lastGoodWidth = 0; var lastGoodHeight = 0; var stopIndex = 2; /* 0 = Smarter, 1 = Faster, 2 = Clearer */ var minTransitionsBeforeStop = 3; var transitionCount = 0; var hasStopped = false; var allowLoop = true; var runToken = 0; /* ========================================================= BLOCK 1 — READ CSS VARIABLES ========================================================= */ function readVars() { var styles = getComputedStyle(document.documentElement); rotateDelay = parseFloat(styles.getPropertyValue('--dm-rotate-delay')) || 2200; fadeSpeed = parseFloat(styles.getPropertyValue('--dm-fade-speed')) || 220; } /* ========================================================= BLOCK 2 — MEASUREMENT HELPERS ========================================================= */ function isRenderable(el) { if (!el || !el.isConnected) return false; var style = getComputedStyle(el); if (style.display === 'none' || style.visibility === 'hidden') return false; var rect = el.getBoundingClientRect(); return rect.width > 20 && rect.height > 0; } function applyDimensions(width, height) { if (!width || !height) return false; lastGoodWidth = width; lastGoodHeight = height; stage.style.width = width + 'px'; stage.style.height = height + 'px'; words.forEach(function (word) { word.style.minWidth = width + 'px'; }); return true; } function syncVisibleWord() { words.forEach(function (word, i) { word.classList.remove('is-active', 'is-exit'); if (i === current) word.classList.add('is-active'); }); } function measure() { if (!isRenderable(root)) { if (lastGoodWidth && lastGoodHeight) { applyDimensions(lastGoodWidth, lastGoodHeight); return true; } return false; } var maxWidth = 0; var maxHeight = 0; words.forEach(function (word) { var hadActive = word.classList.contains('is-active'); var hadExit = word.classList.contains('is-exit'); word.classList.remove('is-active', 'is-exit'); word.classList.add('is-active'); word.style.position = 'relative'; word.style.width = 'auto'; word.style.minWidth = '0'; word.style.visibility = 'visible'; word.style.opacity = '1'; maxWidth = Math.max(maxWidth, Math.ceil(word.getBoundingClientRect().width)); maxHeight = Math.max(maxHeight, Math.ceil(word.getBoundingClientRect().height)); word.style.position = ''; word.style.width = ''; word.style.minWidth = ''; word.style.visibility = ''; word.style.opacity = ''; word.classList.remove('is-active', 'is-exit'); if (hadActive) word.classList.add('is-active'); if (hadExit) word.classList.add('is-exit'); }); if (maxWidth > 8 && maxHeight > 8) { return applyDimensions(maxWidth + 2, maxHeight + 2); } if (lastGoodWidth && lastGoodHeight) { applyDimensions(lastGoodWidth, lastGoodHeight); return true; } return false; } /* ========================================================= BLOCK 3 — ROTATION LOGIC ========================================================= */ function pauseLoop() { runToken += 1; clearInterval(intervalId); intervalId = null; } function stopNow() { pauseLoop(); hasStopped = true; current = stopIndex; syncVisibleWord(); } function nextWord() { if (hasStopped || !allowLoop) return; var token = runToken; var prev = current; current = (current + 1) % words.length; transitionCount += 1; words[prev].classList.remove('is-active'); words[prev].classList.add('is-exit'); requestAnimationFrame(function () { if (token !== runToken) return; words[current].classList.remove('is-exit'); words[current].classList.add('is-active'); if (current === stopIndex && transitionCount >= minTransitionsBeforeStop) { setTimeout(function () { if (token !== runToken) return; stopNow(); }, fadeSpeed); } }); setTimeout(function () { if (token !== runToken) return; words[prev].classList.remove('is-exit'); }, fadeSpeed); } function startLoop() { clearInterval(intervalId); intervalId = null; if (!hasStopped && allowLoop && words.length > 1) { intervalId = setInterval(nextWord, rotateDelay); } } function resetAndPlay() { runToken += 1; clearInterval(intervalId); intervalId = null; allowLoop = true; hasStopped = false; transitionCount = 0; current = startIndex; readVars(); measure(); syncVisibleWord(); startLoop(); } function setLoopAllowed(isAllowed) { allowLoop = !!isAllowed; if (!allowLoop) { pauseLoop(); return; } startLoop(); } /* ========================================================= BLOCK 4 — REFRESH LOGIC ========================================================= */ function refreshNow() { readVars(); measure(); syncVisibleWord(); startLoop(); } function refreshLater(delays) { (delays || [0]).forEach(function (delay) { setTimeout(function () { requestAnimationFrame(function () { requestAnimationFrame(function () { refreshNow(); }); }); }, delay); }); } /* ========================================================= BLOCK 5 — SECTION RESTART TRIGGER ========================================================= */ function findFirstById(ids) { for (var i = 0; i < ids.length; i++) { var el = document.getElementById(ids[i]); if (el) return el; } return null; } function resolveMeaningfulBox(el) { if (!el) return null; var currentEl = el; while (currentEl && currentEl !== document.body) { var rect = currentEl.getBoundingClientRect(); if (rect.height >= 140 && rect.width >= 40) { return currentEl; } currentEl = currentEl.parentElement; } return el; } function getHeroTarget() { var anchor = findFirstById(['home', 'hero']); if (anchor) return resolveMeaningfulBox(anchor); return resolveMeaningfulBox(root); } function isHeroTargetActive(target) { if (!target) return false; var rect = target.getBoundingClientRect(); var vh = window.innerHeight || document.documentElement.clientHeight; /* ======================================================= EDIT HERE IF NEEDED More eager restart: - Increase 0.72 to 0.80 - Decrease 0.12 to 0.05 More conservative restart: - Decrease 0.72 to 0.60 - Increase 0.12 to 0.20 ======================================================= */ return rect.top <= vh * 0.72 && rect.bottom >= vh * 0.12; } function bindHeroRestartWatcher() { if (root.dataset.heroRestartBound === '1') return; root.dataset.heroRestartBound = '1'; var active = null; var ticking = false; function check() { ticking = false; var target = getHeroTarget(); var nowActive = isHeroTargetActive(target); if (nowActive && active !== true) { active = true; resetAndPlay(); } else if (!nowActive && active !== false) { active = false; setLoopAllowed(false); } } function requestCheck() { if (ticking) return; ticking = true; window.requestAnimationFrame(check); } window.addEventListener('scroll', requestCheck, { passive: true }); window.addEventListener('resize', requestCheck); window.addEventListener('orientationchange', requestCheck); window.addEventListener('hashchange', function () { setTimeout(requestCheck, 80); setTimeout(requestCheck, 260); setTimeout(requestCheck, 700); }); window.addEventListener('pageshow', function () { setTimeout(requestCheck, 80); setTimeout(requestCheck, 260); }); document.addEventListener('visibilitychange', function () { if (document.visibilityState === 'visible') { setTimeout(requestCheck, 120); } }); /* Carrd can settle late */ setTimeout(requestCheck, 120); setTimeout(requestCheck, 500); setTimeout(requestCheck, 1100); setTimeout(requestCheck, 1800); } /* ========================================================= BLOCK 6 — PUBLIC CONTROLLER ========================================================= */ root.__dmHeroController = { refreshNow: refreshNow, refreshLater: refreshLater, resetAndPlay: resetAndPlay, setLoopAllowed: setLoopAllowed }; /* ========================================================= BLOCK 7 — INITIALIZATION ========================================================= */ refreshLater([0, 80, 220]); bindHeroRestartWatcher(); if (document.fonts && document.fonts.ready) { document.fonts.ready.then(function () { refreshLater([0, 80, 220]); }); } else { setTimeout(function () { refreshLater([120, 260]); }, 120); } window.addEventListener('load', function () { refreshLater([80, 220]); }); window.addEventListener('resize', function () { clearTimeout(resizeTimer); resizeTimer = setTimeout(function () { refreshLater([0, 120]); }, 120); }); window.addEventListener('pageshow', function () { refreshLater([0, 120, 280]); }); window.addEventListener('hashchange', function () { refreshLater([60, 180, 320]); }); window.addEventListener('popstate', function () { refreshLater([60, 180, 320]); }); document.addEventListener('visibilitychange', function () { if (document.visibilityState === 'visible') { refreshLater([80, 220]); } }); if ('ResizeObserver' in window) { var ro = new ResizeObserver(function () { refreshLater([0, 80]); }); ro.observe(root); } } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', initDMPremiumHero); } else { initDMPremiumHero(); } })();

I turn data, reporting and delivery complexity into clean dashboards and updates that help leaders see what matters and move with confidence.




Experience across sectors


Roles across consulting, life sciences, SaaS, centered on reporting, analytics, and delivery.


Workable
Dayforce
Deloitte
Gilead
UC Irvine
Workable
Dayforce
Deloitte
Gilead
UC Irvine
(function () { /* =================================================== */ /* SECTION 8 — DESKTOP MEASURED LOOP */ /* =================================================== */ function initDesktopLogoMarquee(marquee) { if (!marquee || marquee.dataset.boundDesktop === '1') return; marquee.dataset.boundDesktop = '1'; var firstSet = marquee.querySelector('.dm-logo-set-desktop'); if (!firstSet) return; var resizeTimer; function updateDesktopLogoMarquee() { if (window.matchMedia('(max-width: 768px)').matches) return; var styles = getComputedStyle(marquee); var pxPerSecond = parseFloat(styles.getPropertyValue('--dm-px-per-second')) || 35; var setWidth = firstSet.getBoundingClientRect().width; if (!setWidth) return; marquee.style.setProperty('--dm-set-width', setWidth.toFixed(3) + 'px'); marquee.style.setProperty('--dm-duration', (setWidth / pxPerSecond).toFixed(3) + 's'); } var imgs = marquee.querySelectorAll('img'); imgs.forEach(function (img) { if (!img.complete) { img.addEventListener('load', updateDesktopLogoMarquee, { once: true }); } }); window.addEventListener('load', updateDesktopLogoMarquee); window.addEventListener('resize', function () { clearTimeout(resizeTimer); resizeTimer = setTimeout(updateDesktopLogoMarquee, 120); }); updateDesktopLogoMarquee(); } /* =================================================== */ /* SECTION 9 — MOBILE MEASURED LOOP */ /* =================================================== */ function initMobileLogoMarquee(marquee) { if (!marquee || marquee.dataset.boundMobile === '1') return; marquee.dataset.boundMobile = '1'; var firstSet = marquee.querySelector('.dm-logo-set-mobile'); if (!firstSet) return; var resizeTimer; function updateMobileLogoMarquee() { if (!window.matchMedia('(max-width: 768px)').matches) return; var setWidth = firstSet.getBoundingClientRect().width; if (!setWidth) return; marquee.style.setProperty('--dm-mobile-set-width', setWidth.toFixed(3) + 'px'); } var imgs = marquee.querySelectorAll('img'); imgs.forEach(function (img) { if (!img.complete) { img.addEventListener('load', updateMobileLogoMarquee, { once: true }); } }); window.addEventListener('load', updateMobileLogoMarquee); window.addEventListener('resize', function () { clearTimeout(resizeTimer); resizeTimer = setTimeout(updateMobileLogoMarquee, 120); }); updateMobileLogoMarquee(); } /* =================================================== */ /* SECTION 10 — INIT */ /* =================================================== */ document.querySelectorAll('.dm-logo-marquee-desktop').forEach(initDesktopLogoMarquee); document.querySelectorAll('.dm-logo-marquee-mobile').forEach(initMobileLogoMarquee); })();


Selected business impact


Selected results across executive reporting, analytics, and program coordination.


$35M

Opportunity uncovered

200+

Stakeholders aligned

6+

Years of experience



How I approach the work


I like the kind of work that turns complexity into meaningful output that people can actually use.


Professional Summary


I have worked across consulting, business intelligence, and more recently IT project coordination, often in environments that are complex, fast-moving, and highly cross-functional. That experience has shaped the way I work: bringing structure to ambiguity, making information easier to act on, and turning raw data into output that supports clearer decisions.My background spans sectors including dry bulk shipping, SaaS, and life sciences, with work ranging from sales growth and executive reporting to large-scale IT delivery coordination. What ties it all together is a consistent approach: reducing noise, sharpening the story, and delivering work that is useful, clear, and decision-oriented.

Dimitrios Mousouroulis headshot

Dimitrios Mousouroulis

PMO Analytics Business Intelligence

Raleigh, North Carolina (Eastern Time)

Core strengths

  • Analytical storytelling
  • Clearer decision support
  • PMO and program reporting
  • Executive-ready communication
  • Business intelligence and dashboards

Industries
Life SciencesSaaSConsultingShipping
Top Skills
Power BIDAXExcelPower QueryMPP


Selected project work


A selection of reporting, analysis, and design work built to make business information clearer and more useful.


Dashboard Wireframes

Dashboard wireframes designed to help teams structure reports before development. Built around hierarchy, executive readability, and clearer decision-making.


Pricing Analysis & Forecast

A structured pricing and performance project built to surface trends, support planning, and turn analysis into decision-ready outputs for business stakeholders.


Chart Makeovers

A visual redesign series that turns weaker charts into clearer, more readable alternatives, with a focus on comparison, hierarchy, and communication.


Superstore Sales Analysis

A SQL analytics project using BigQuery to explore sales, profit, margin, and product performance patterns across regions, states, cities, and categories.


European Soccer Analysis

A SQL analytics project using BigQuery to analyze European soccer seasons, leagues, teams, match activity, and player attributes into clear performance insights.


View all



Writing and visual thinking


Short posts on dashboards, chart design, and practical ways to make data easier to understand.


/* ========================================================= BLOCK 9 — CAROUSEL LOGIC + ORIGINAL LOOK LAZY LOADING Only functional change from original: - Posts 3–6 load only when their slide becomes visible. - Posts 1–2 load immediately. ========================================================= */ (function () { var root = document.getElementById('li-carousel-01'); if (!root) return; var slides = Array.prototype.slice.call(root.querySelectorAll('.li-slide')); var prev = root.querySelector('.li-prev'); var next = root.querySelector('.li-next'); var dotsWrap = root.querySelector('.li-dots'); if (!slides.length || !prev || !next || !dotsWrap) return; var page = 0; var perView = 2; var totalPages = 1; var resizeTimer = null; function getPerView() { return window.innerWidth <= 1100 ? 1 : 2; } function getFixedIframeHeight() { var styles = window.getComputedStyle(root); var raw = window.innerWidth <= 1100 ? styles.getPropertyValue('--li-fixed-height-mobile') : styles.getPropertyValue('--li-fixed-height-desktop'); var n = parseFloat(raw); return Number.isFinite(n) ? n : (window.innerWidth <= 1100 ? 515 : 665); } function applyIframeHeights() { var target = getFixedIframeHeight(); var iframes = root.querySelectorAll('iframe'); for (var i = 0; i < iframes.length; i++) { var iframe = iframes[i]; iframe.style.setProperty('height', target + 'px', 'important'); iframe.style.setProperty('min-height', target + 'px', 'important'); iframe.style.setProperty('width', '100%', 'important'); iframe.style.setProperty('min-width', '100%', 'important'); iframe.style.setProperty('max-width', '100%', 'important'); iframe.style.setProperty('display', 'block', 'important'); iframe.style.setProperty('border', '0', 'important'); } } function loadVisibleIframes() { var visibleSlides = root.querySelectorAll('.li-slide:not(.is-hidden)'); for (var i = 0; i < visibleSlides.length; i++) { var iframe = visibleSlides[i].querySelector('iframe'); if (!iframe) continue; if (iframe.getAttribute('data-li-loaded') === 'true') continue; var target = iframe.getAttribute('data-li-src'); if (!target) continue; iframe.setAttribute('src', target); iframe.setAttribute('data-li-loaded', 'true'); } setTimeout(applyIframeHeights, 60); setTimeout(applyIframeHeights, 240); setTimeout(applyIframeHeights, 900); } function trackCarousel(controlType, destinationPage) { if (!window.dmTrack) return; window.dmTrack('insight_carousel_nav', { link_group: 'insights_carousel', control_type: controlType, destination_page: String(destinationPage), total_pages: String(totalPages) }); } function buildDots() { dotsWrap.innerHTML = ''; for (var i = 0; i < totalPages; i++) { var btn = document.createElement('button'); btn.className = 'li-dot' + (i === page ? ' is-active' : ''); btn.type = 'button'; btn.setAttribute('aria-label', 'Go to page ' + (i + 1)); btn.setAttribute('data-index', String(i)); dotsWrap.appendChild(btn); } } function update() { var start = page * perView; var end = Math.min(start + perView, slides.length); for (var i = 0; i < slides.length; i++) { if (i >= start && i < end) { slides[i].classList.remove('is-hidden'); } else { slides[i].classList.add('is-hidden'); } } prev.disabled = page === 0; next.disabled = page >= totalPages - 1; var dots = dotsWrap.children; for (var d = 0; d < dots.length; d++) { if (d === page) { dots[d].classList.add('is-active'); } else { dots[d].classList.remove('is-active'); } } loadVisibleIframes(); setTimeout(applyIframeHeights, 30); setTimeout(applyIframeHeights, 120); } function recalc() { perView = getPerView(); totalPages = Math.max(1, Math.ceil(slides.length / perView)); if (page > totalPages - 1) { page = totalPages - 1; } applyIframeHeights(); buildDots(); update(); } prev.addEventListener('click', function (e) { e.preventDefault(); e.stopPropagation(); if (page > 0) { page -= 1; update(); trackCarousel('prev', page + 1); } }); next.addEventListener('click', function (e) { e.preventDefault(); e.stopPropagation(); if (page < totalPages - 1) { page += 1; update(); trackCarousel('next', page + 1); } }); dotsWrap.addEventListener('click', function (e) { var btn = e.target.closest ? e.target.closest('.li-dot') : null; if (!btn) return; e.preventDefault(); e.stopPropagation(); page = Number(btn.getAttribute('data-index') || 0); update(); trackCarousel('dot', page + 1); }); window.addEventListener('resize', function () { clearTimeout(resizeTimer); resizeTimer = setTimeout(recalc, 120); }); window.addEventListener('load', function () { recalc(); setTimeout(applyIframeHeights, 300); setTimeout(applyIframeHeights, 900); setTimeout(applyIframeHeights, 1600); }); recalc(); })();


Ways to get in touch


Reach out by email, LinkedIn, or Calendly to connect, collaborate, or continue the conversation.




Background at a glance


A concise overview of my experience, education, and tools, with the background behind the work I do.



Font Load – PP Neue

Global Width / Shell

Global Animated BG

Cookies Button Styling

GA4 Portfolio Tracking

Mobile Burger — CSS

Mobile Burger — JS

Back to Top Button

Status Dot Animations

Impact Animation

Nav Sticky Glass

Nav Visibility Guard

Nav Link Centering

Nav Link Effects

Nav + Hero – CTA

Botpress Loader

Projects – View All

Projects – CTA Styling

Projects – Meta

Mobile Viewport Fix