Kinetiq UI Template - Let's templates
Kinetiq preview 1
Free
0 9

Kinetiq

By Mina Ortiz

Kinetiq is a bold consulting template for startup accelerators and innovation studios, with chrome-tube hero art that draws itself on scroll, count-up stats, neon photography, values, a founder letter, a filterable team grid and a lime newsletter card.

Live Demo
kinetiq-tailwind.html
<%# letstemplates: access=premium category=consulting %>
<!DOCTYPE html>
<html lang="en">
<head>
  <script>
    window.FontAwesomeConfig = { autoReplaceSvg: 'nest' };
  </script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/js/all.min.js" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Kinetiq | Tailwind CSS Consulting Template</title>
  <meta name="description" content="Kinetiq is a bold Tailwind CSS consulting template for startup accelerators and innovation studios, with chrome-tube hero art that draws itself on scroll, count-up stats, neon photography, values, a founder letter, a filterable team grid and a lime newsletter card.">
  <meta name="keywords" content="Kinetiq, Tailwind CSS template, HTML website template, consulting template, startup accelerator website, innovation consultancy, venture studio, corporate innovation, team page, newsletter signup">
  <meta name="author" content="Let's templates">
  <link rel="canonical" href="">

  <meta property="og:type" content="product">
  <meta property="og:site_name" content="Let's templates">
  <meta property="og:locale" content="en_US">
  <meta property="og:url" content="">
  <meta property="og:title" content="Kinetiq | Tailwind CSS Consulting Template">
  <meta property="og:description" content="A bold Tailwind CSS template for startup accelerators and innovation consultancies, with chrome-tube hero art, count-up stats and a filterable team grid.">
  <meta property="og:image" content="">
  <meta property="og:image:alt" content="Kinetiq template preview">

  <meta name="twitter:card" content="summary_large_image">
  <meta name="twitter:url" content="">
  <meta name="twitter:title" content="Kinetiq | Tailwind CSS Consulting Template">
  <meta name="twitter:description" content="A bold Tailwind CSS template for startup accelerators and innovation consultancies, with chrome-tube hero art, count-up stats and a filterable team grid.">
  <meta name="twitter:image" content="">
  <meta name="twitter:image:alt" content="Kinetiq template preview">
  <script src="https://cdn.tailwindcss.com/3.4.17"></script>
  <link rel="preconnect" href="https://fonts.googleapis.com">
  <link href="https://fonts.googleapis.com/css2?family=Big+Shoulders+Display:wght@600;800;900&family=Inter:wght@400;500;600&display=swap" rel="stylesheet">
  <script>
    tailwind.config = {
      theme: {
        extend: {
          colors: { lime: { DEFAULT: '#e2f43a', soft: '#f3fbb8' }, coal: { DEFAULT: '#222528', soft: '#2c3035', line: '#3a3f45' } },
          fontFamily: { sans: ['Inter', 'sans-serif'], display: ['"Big Shoulders Display"', 'sans-serif'] }
        }
      }
    }
  </script>
  <style>
    @view-transition { navigation: auto; }
    ::view-transition-old(root) { animation: 180ms ease-out both page-fade-out; }
    ::view-transition-new(root) { animation: 220ms ease-in both page-fade-in; }
    @keyframes page-fade-out { to { opacity: 0; } }
    @keyframes page-fade-in { from { opacity: 0; } }
    html { scroll-behavior: smooth; }
    [hidden] { display: none !important; }
    .tube { filter: drop-shadow(0 18px 18px rgba(0, 0, 0, .18)); }
    .neon { filter: saturate(1.4) hue-rotate(-12deg); }
    .glow { text-shadow: 0 0 28px rgba(226, 244, 58, .45); }
    .reveal-ready [data-reveal] { opacity: 0; transform: translateY(24px); transition: opacity .6s ease, transform .6s ease; transition-delay: var(--reveal-delay, 0ms); }
    .reveal-ready [data-reveal].is-visible { opacity: 1; transform: none; }
    @media (prefers-reduced-motion: reduce) {
      html { scroll-behavior: auto; }
      ::view-transition-old(root), ::view-transition-new(root) { animation: none; }
    }
  </style>
</head>
<body class="bg-coal font-sans text-white antialiased">
  <% active_page = "index" %>
  <% nav = { "work" => "Our work", "about" => "About", "contact" => "Contact" } %>
  <% audiences = { "startups" => "For startups", "corporates" => "For corporates" } %>
  <!-- block:start navbar -->
  <header class="sticky top-0 z-40 bg-coal">
    <nav class="mx-auto grid max-w-7xl grid-cols-[1fr_auto_1fr] items-center gap-4 px-5 py-4 md:px-10" aria-label="Main">
      <ul class="hidden items-center gap-8 text-xs font-semibold uppercase tracking-wider lg:flex">
        <% nav.each do |slug, label| %>
          <% active = active_page == slug %>
          <li><a href="<%= slug %>.html" <%= 'aria-current="page"'.html_safe if active %> class="transition <%= active ? 'text-lime' : 'hover:text-lime' %>"><%= label %></a></li>
        <% end %>
      </ul>
      <a href="index.html" class="col-start-1 font-display text-3xl font-black uppercase tracking-tight lg:col-start-2">Kinet<span class="italic text-lime">i</span>q</a>
      <ul class="hidden items-center justify-end gap-8 text-xs font-semibold uppercase tracking-wider text-lime lg:flex">
        <% audiences.each do |slug, label| %>
          <% active = active_page == slug %>
          <li><a href="<%= slug %>.html" <%= 'aria-current="page"'.html_safe if active %> class="inline-flex items-center gap-1.5 transition hover:text-white <%= 'underline underline-offset-4' if active %>"><%= label %><i class="fa-solid fa-arrow-up rotate-45 text-[10px]" aria-hidden="true"></i></a></li>
        <% end %>
      </ul>
      <button type="button" data-menu-toggle aria-controls="mobile-menu" aria-expanded="false" class="col-start-3 grid h-10 w-10 place-items-center justify-self-end border-2 border-white/80 lg:hidden" aria-label="Open menu"><i class="fa-solid fa-bars" aria-hidden="true"></i></button>
    </nav>
    <div id="mobile-menu" class="hidden border-t border-coal-line px-5 pb-8 pt-4 lg:hidden">
      <ul class="grid gap-1 font-display text-4xl font-extrabold uppercase">
        <% { "index" => "Home" }.merge(nav).merge(audiences).each do |slug, label| %>
          <% active = active_page == slug %>
          <li><a href="<%= slug %>.html" <%= 'aria-current="page"'.html_safe if active %> class="block py-1 <%= active ? 'text-lime' : 'hover:text-lime' %>"><%= label %></a></li>
        <% end %>
      </ul>
    </div>
  </header>
  <!-- block:end navbar -->

  <!-- block:start hero -->
  <section class="relative overflow-hidden bg-white text-coal" data-draw>
    <svg class="tube pointer-events-none absolute -left-24 top-12 w-64 md:-left-10 md:top-20 md:w-80 lg:w-[22rem]" viewBox="0 0 320 240" fill="none" aria-hidden="true">
      <defs><linearGradient id="chrome-a" x1="0" y1="0" x2="1" y2="1"><stop offset="0" stop-color="#fafafa"/><stop offset=".35" stop-color="#c9ccd1"/><stop offset=".55" stop-color="#f5f5f5"/><stop offset=".8" stop-color="#9ea3aa"/><stop offset="1" stop-color="#e6e7ea"/></linearGradient></defs>
      <path d="M-10 70C60 40 170 30 200 70c30 40-60 90-110 60S80 40 160 40s150 70 120 140c-20 45-100 50-150 20" stroke="url(#chrome-a)" stroke-width="30" stroke-linecap="round" data-draw-path/>
    </svg>
    <svg class="tube pointer-events-none absolute -right-28 bottom-10 w-64 md:-right-6 md:top-24 md:w-80 lg:w-[22rem]" viewBox="0 0 300 300" fill="none" aria-hidden="true">
      <defs><linearGradient id="chrome-b" x1="1" y1="0" x2="0" y2="1"><stop offset="0" stop-color="#f4f4f5"/><stop offset=".4" stop-color="#b9bdc4"/><stop offset=".6" stop-color="#fbfbfb"/><stop offset=".85" stop-color="#a3a8ae"/><stop offset="1" stop-color="#e4e5e8"/></linearGradient></defs>
      <path d="M150 20c80-20 120 40 80 80s-140 40-150 110c-8 60 80 90 140 50 50-34 30-100-20-110" stroke="url(#chrome-b)" stroke-width="30" stroke-linecap="round" data-draw-path/>
    </svg>
    <div class="relative mx-auto flex max-w-3xl flex-col items-center px-5 py-24 text-center md:py-32">
      <h1 class="font-display text-6xl font-extrabold uppercase leading-[0.92] tracking-tight md:text-8xl" data-reveal>We spark the companies of what comes next</h1>
      <p class="mt-8 max-w-md text-coal/60" data-reveal style="--reveal-delay: 100ms">We help bold founders build and scale, and we help established teams get ready for whatever the market throws at them.</p>
      <a href="startups.html" class="mt-10 bg-lime px-8 py-4 text-xs font-bold uppercase tracking-wider text-coal transition hover:bg-coal hover:text-lime" data-reveal style="--reveal-delay: 200ms">Let's build it</a>
    </div>
  </section>
  <!-- block:end hero -->

  <% stats = [["1400", "", "Founders backed through our programmes"], ["0.9", "BN", "Euros raised by startups we've coached"], ["45", "+", "Corporate partners across Europe"]] %>
  <!-- block:start stats -->
  <section class="mx-auto max-w-7xl px-5 pb-16 pt-20 md:px-10 md:pt-24">
    <h2 class="font-display text-3xl font-semibold md:text-4xl">The numbers <span class="glow text-lime">say it</span> for us:</h2>
    <dl class="mt-10 grid gap-8 md:grid-cols-3">
      <% stats.each_with_index do |(value, unit, label), index| %>
        <div class="flex items-center gap-5" data-reveal style="--reveal-delay: <%= index * 100 %>ms">
          <dt class="sr-only"><%= label %></dt>
          <dd class="glow font-display text-6xl font-semibold text-white/40 transition md:text-7xl" data-stat><span data-count="<%= value %>"><%= value.include?('.') ? value : value.to_i.to_s.reverse.scan(/\d{1,3}/).join(',').reverse %></span><%= unit %></dd>
          <p class="max-w-[10rem] text-xs text-white/70" aria-hidden="true"><%= label %></p>
        </div>
      <% end %>
    </dl>
  </section>
  <!-- block:end stats -->

  <!-- block:start about -->
  <section class="relative mx-auto grid max-w-7xl items-center gap-12 py-16 md:grid-cols-2 md:py-24">
    <div class="relative">
      <img src="https://images.unsplash.com/photo-1492684223066-81342ee5ff30?auto=format&fit=crop&w=1000&h=700&q=80" alt="Crowd under purple lights and falling confetti at a launch night" class="neon aspect-[10/7] w-full object-cover">
      <svg class="pointer-events-none absolute -bottom-16 -left-4 w-32 md:-left-10 md:w-40" viewBox="0 0 120 120" fill="none" aria-hidden="true"><path d="M86 72c-6 14-26 18-36 8s-6-30 10-34 24 6 20 18-14 14-18 6m28-14c4 20 10 26 18 20 12-10 6-44-24-54-32-10-66 14-64 48 2 36 44 48 72 32" stroke="#e2f43a" stroke-width="10" stroke-linecap="round"/></svg>
    </div>
    <div class="px-5 md:pr-10" data-reveal>
      <h2 class="font-display text-4xl font-extrabold uppercase md:text-5xl">Words about our <span class="italic">company</span></h2>
      <p class="mt-8 text-sm leading-relaxed text-white/80">We are a crew of hands-on operators spread across six countries. Whether you're a two-person startup or a corporate giant that has lost its speed, we help you get moving again. Our playbook comes from years of work with ambitious founders, research labs, global firms and public bodies.</p>
      <p class="mt-5 text-sm leading-relaxed text-white/80">More than 1,400 founders have gone through our programmes. We've helped companies design innovation tracks that actually ship, scout new technology, train their people and launch products customers pay for.</p>
    </div>
  </section>
  <!-- block:end about -->

  <% values = [["Curiosity first", "We question the obvious, try the untested and enjoy the ride while we're at it."], ["Honest impact", "We take on work that changes something. If we can't help, we'll say so straight away."]] %>
  <!-- block:start features -->
  <section class="mx-auto grid max-w-7xl gap-10 px-5 py-16 md:grid-cols-3 md:px-10 md:py-24">
    <div data-reveal>
      <h2 class="font-display text-3xl font-extrabold uppercase"><span class="text-lime">Values</span> <span class="italic">we live by</span></h2>
      <p class="mt-4 max-w-xs text-sm text-white/70">We exist to get things moving. Everything we do — for founders and for corporates alike — follows these two rules.</p>
    </div>
    <% values.each_with_index do |(title, text), index| %>
      <div class="flex gap-5" data-reveal style="--reveal-delay: <%= (index + 1) * 100 %>ms">
        <i class="fa-solid fa-asterisk text-5xl text-lime" aria-hidden="true"></i>
        <div>
          <h3 class="font-display text-2xl font-semibold"><%= title %></h3>
          <p class="mt-3 text-sm text-white/70"><%= text %></p>
        </div>
      </div>
    <% end %>
  </section>
  <!-- block:end features -->

  <section class="mx-auto grid max-w-7xl items-center gap-12 px-5 py-16 md:grid-cols-2 md:px-10 md:py-24">
    <div class="order-2 md:order-1" data-reveal>
      <h2 class="font-display text-4xl font-extrabold uppercase md:text-5xl">A note from our <span class="italic">founder</span></h2>
      <p class="mt-8 text-sm leading-relaxed text-white/80">Most markets reward playing it safe. We started Kinetiq to reward the opposite: new companies that try something hard, and old ones willing to reinvent themselves. We've sat on both sides of the table, raised money, missed targets and shipped products people loved.</p>
      <p class="mt-5 text-sm leading-relaxed text-white/80">That's why we can help. We know what it takes to find customers, earn their trust and build something they keep using. And honestly — we just like hard problems.</p>
      <p class="mt-8 font-display text-2xl font-semibold text-lime">— Lena Marković, founder</p>
    </div>
    <div class="order-1 md:order-2">
      <img src="https://images.unsplash.com/photo-1505373877841-8d25f7d46678?auto=format&fit=crop&w=900&h=900&q=80" alt="Speaker presenting on a big screen to a dark hall" class="neon aspect-square w-full object-cover">
    </div>
  </section>

  <% partners = [["Lena Marković", "Founder & managing partner", "Belgrade", 1], ["Jonas Weber", "Partner, venture programmes", "Berlin", 2], ["Aino Virtanen", "Partner, corporate innovation", "Helsinki", 3], ["Tomás Ruiz", "Partner, investor relations", "Madrid", 4], ["Mira Novak", "Partner, deep tech", "Ljubljana", 5], ["Pieter de Groot", "Partner, product", "Rotterdam", 6]] %>
  <% team = [["Clara Jensen", "Programme lead", "programmes", 7], ["Omar Haddad", "Startup coach", "programmes", 8], ["Sofia Rossi", "Venture analyst", "ventures", 9], ["Niko Petrov", "Product designer", "programmes", 1], ["Hana Kim", "Innovation consultant", "corporate", 2], ["Lucas Moreau", "Data lead", "ventures", 3], ["Ella Svensson", "Community manager", "programmes", 4], ["Ravi Patel", "Corporate trainer", "corporate", 5], ["Zoe Adams", "Operations", "ventures", 6], ["Ivan Horvat", "Innovation consultant", "corporate", 7]] %>
  <!-- block:start team -->
  <div>
    <section class="mx-auto max-w-7xl px-5 py-16 md:px-10 md:py-24">
      <h2 class="text-center font-display text-3xl font-extrabold uppercase"><span class="text-lime">Core</span> partners</h2>
      <ul class="mt-12 grid grid-cols-2 gap-x-6 gap-y-10 md:grid-cols-3">
        <% partners.each_with_index do |(name, role, city, avatar), index| %>
          <li class="text-center" data-reveal style="--reveal-delay: <%= (index % 3) * 80 %>ms">
            <img src="https://storage.googleapis.com/uxpilot-auth.appspot.com/avatars/avatar-<%= avatar %>.jpg" alt="Portrait of <%= name %>" class="mx-auto h-20 w-20 rounded-full object-cover">
            <h3 class="mt-4 font-display text-xl font-semibold"><%= name %></h3>
            <p class="mt-1 text-xs text-white/60"><%= role %> · <%= city %></p>
            <a href="contact.html" class="mt-3 inline-grid h-6 w-6 place-items-center bg-lime text-xs text-coal" aria-label="<%= name %> on LinkedIn"><i class="fa-brands fa-linkedin-in" aria-hidden="true"></i></a>
          </li>
        <% end %>
      </ul>
    </section>
    <section class="relative overflow-hidden bg-white py-16 text-coal md:py-24" data-team>
      <svg class="pointer-events-none absolute -left-10 top-0 w-48 md:w-64" viewBox="0 0 260 120" fill="none" aria-hidden="true"><path d="M-10 60c40-50 90-50 100-10s-50 40-40 10 70-40 110 0 60 30 100 10" stroke="#e2f43a" stroke-width="12" stroke-linecap="round"/></svg>
      <div class="relative mx-auto max-w-7xl px-5 md:px-10">
        <h2 class="text-center font-display text-4xl font-semibold md:text-5xl">Meet the crew</h2>
        <div class="mt-8 flex flex-wrap justify-center gap-2" role="group" aria-label="Filter the team">
          <% { "all" => "Everyone", "programmes" => "Programmes", "ventures" => "Ventures", "corporate" => "Corporate" }.each do |key, label| %>
            <button type="button" data-filter="<%= key %>" aria-pressed="<%= key == 'all' %>" class="border-2 border-coal px-4 py-2 text-xs font-bold uppercase tracking-wider transition hover:bg-lime aria-pressed:bg-coal aria-pressed:text-lime"><%= label %></button>
          <% end %>
        </div>
        <ul class="mt-12 grid grid-cols-2 gap-x-4 gap-y-10 sm:grid-cols-3 lg:grid-cols-5">
          <% team.each do |(name, role, group, avatar)| %>
            <li class="text-center" data-category="<%= group %>">
              <img src="https://storage.googleapis.com/uxpilot-auth.appspot.com/avatars/avatar-<%= avatar %>.jpg" alt="Portrait of <%= name %>" class="mx-auto h-16 w-16 rounded-full object-cover">
              <h3 class="mt-3 font-display text-lg font-semibold"><%= name %></h3>
              <p class="text-xs text-coal/60"><%= role %></p>
            </li>
          <% end %>
        </ul>
      </div>
    </section>
  </div>
  <!-- block:end team -->

  <!-- block:start newsletter -->
  <section class="bg-white px-5 pb-20 text-coal md:px-10">
    <div class="mx-auto max-w-4xl bg-lime px-6 py-12 text-center shadow-[0_30px_60px_-20px_rgba(34,37,40,.35)] md:px-16">
      <h2 class="font-display text-4xl font-semibold leading-tight md:text-5xl">Hear about the next <span class="italic">opportunity</span> first</h2>
      <p class="mx-auto mt-4 max-w-md text-sm text-coal/70">One email a month with open calls, events and the stories behind our latest programmes.</p>
      <form class="mx-auto mt-8 flex max-w-md flex-col gap-2 sm:flex-row" data-newsletter novalidate>
        <label for="newsletter-email" class="sr-only">Email</label>
        <input id="newsletter-email" name="email" type="email" required autocomplete="email" placeholder="Your email address" class="min-w-0 flex-1 border-2 border-coal bg-white px-4 py-3 text-sm focus:outline-none focus:ring-2 focus:ring-coal">
        <button type="submit" class="bg-coal px-6 py-3 text-xs font-bold uppercase tracking-wider text-white transition hover:bg-white hover:text-coal">Subscribe</button>
      </form>
      <p class="mt-3 text-xs" data-form-status role="status"></p>
    </div>
  </section>
  <!-- block:end newsletter -->

  <!-- block:start footer -->
  <footer class="bg-coal">
    <div class="mx-auto grid max-w-7xl gap-10 px-5 py-16 sm:grid-cols-2 md:px-10 lg:grid-cols-[1.4fr_1fr_1fr_1fr]">
      <div>
        <a href="index.html" class="font-display text-3xl font-black uppercase">Kinet<span class="italic text-lime">i</span>q</a>
        <div class="mt-6 flex gap-2">
          <a href="contact.html" class="grid h-8 w-8 place-items-center bg-lime text-sm text-coal" aria-label="LinkedIn"><i class="fa-brands fa-linkedin-in" aria-hidden="true"></i></a>
          <a href="contact.html" class="grid h-8 w-8 place-items-center bg-lime text-sm text-coal" aria-label="Instagram"><i class="fa-brands fa-instagram" aria-hidden="true"></i></a>
        </div>
      </div>
      <div>
        <h2 class="text-xs font-bold uppercase tracking-wider text-lime">Links</h2>
        <ul class="mt-4 grid gap-2 text-sm text-white/70">
          <% { "index" => "Home" }.merge(nav).each do |slug, label| %>
            <li><a href="<%= slug %>.html" class="hover:text-lime"><%= label %></a></li>
          <% end %>
        </ul>
      </div>
      <div>
        <h2 class="text-xs font-bold uppercase tracking-wider text-lime">Programmes</h2>
        <ul class="mt-4 grid gap-2 text-sm text-white/70">
          <li><a href="startups.html" class="hover:text-lime">Founder sprint</a></li>
          <li><a href="startups.html" class="hover:text-lime">Scale track</a></li>
          <li><a href="corporates.html" class="hover:text-lime">Corporate labs</a></li>
        </ul>
      </div>
      <div>
        <h2 class="text-xs font-bold uppercase tracking-wider text-lime">Contact</h2>
        <ul class="mt-4 grid gap-2 text-sm text-white/70">
          <li><a href="mailto:hello@kinetiq.studio" class="hover:text-lime">hello@kinetiq.studio</a></li>
          <li>Karl-Marx-Allee 90, Berlin</li>
          <li>+49 30 5550 1840</li>
        </ul>
      </div>
    </div>
    <div class="mx-auto flex max-w-7xl flex-wrap justify-between gap-4 border-t border-coal-line px-5 py-6 text-xs text-white/50 md:px-10">
      <p>&copy; 2026 Kinetiq. All rights reserved.</p>
      <p><a href="contact.html" class="hover:text-lime">Privacy</a> · <a href="contact.html" class="hover:text-lime">Imprint</a></p>
    </div>
  </footer>
  <!-- block:end footer -->

  <script>
    const reducedMotion = matchMedia('(prefers-reduced-motion: reduce)').matches;
    const watchMotion = !reducedMotion && !navigator.webdriver && 'IntersectionObserver' in window;

    document.querySelectorAll('[data-menu-toggle]').forEach((button) => {
      const menu = document.getElementById(button.getAttribute('aria-controls'));
      button.addEventListener('click', () => {
        const open = button.getAttribute('aria-expanded') === 'true';
        button.setAttribute('aria-expanded', String(!open));
        menu.classList.toggle('hidden', open);
      });
    });

    document.querySelectorAll('[data-draw]').forEach((root) => {
      if (!watchMotion) return;
      root.querySelectorAll('[data-draw-path]').forEach((path, index) => {
        const length = path.getTotalLength();
        path.style.strokeDasharray = length;
        path.style.strokeDashoffset = length;
        requestAnimationFrame(() => requestAnimationFrame(() => {
          path.style.transition = `stroke-dashoffset .7s ease-out ${index * 150}ms`;
          path.style.strokeDashoffset = 0;
        }));
      });
    });

    document.querySelectorAll('[data-team]').forEach((root) => {
      const chips = [...root.querySelectorAll('[data-filter]')];
      chips.forEach((chip) => chip.addEventListener('click', () => {
        chips.forEach((other) => other.setAttribute('aria-pressed', String(other === chip)));
        root.querySelectorAll('[data-category]').forEach((item) => { item.hidden = chip.dataset.filter !== 'all' && item.dataset.category !== chip.dataset.filter; });
      }));
    });

    document.querySelectorAll('[data-newsletter]').forEach((form) => {
      const status = form.parentElement.querySelector('[data-form-status]');
      form.addEventListener('submit', (event) => {
        event.preventDefault();
        const email = form.elements.email;
        if (!email.checkValidity()) { status.textContent = 'Please enter a valid email address.'; email.focus(); return; }
        status.textContent = "You're on the list — see you next month.";
        form.reset();
      });
    });

    document.querySelectorAll('[data-count]').forEach((el) => {
      const stat = el.closest('[data-stat]');
      const target = Number(el.dataset.count);
      const decimals = el.dataset.count.includes('.') ? 1 : 0;
      const format = (value) => (decimals ? value.toFixed(1) : Math.round(value).toLocaleString('en-US'));
      if (!watchMotion) { stat.classList.replace('text-white/40', 'text-lime'); return; }
      const observer = new IntersectionObserver(([entry]) => {
        if (!entry.isIntersecting) return;
        observer.disconnect();
        const start = performance.now();
        const tick = (now) => { const t = Math.min(1, (now - start) / 700); el.textContent = format(target * t); if (t < 1) requestAnimationFrame(tick); else stat.classList.replace('text-white/40', 'text-lime'); };
        requestAnimationFrame(tick);
      });
      observer.observe(el);
    });

    if (watchMotion) {
      document.documentElement.classList.add('reveal-ready');
      const observer = new IntersectionObserver((entries) => entries.forEach((entry) => {
        if (entry.isIntersecting) { entry.target.classList.add('is-visible'); observer.unobserve(entry.target); }
      }), { threshold: 0.15 });
      document.querySelectorAll('[data-reveal]').forEach((el) => observer.observe(el));
    }
  </script>
</body>
</html>

Unlimited access to all templates

Unlock our entire library of premium UI kits, dashboards, and landing pages. Renews automatically, cancel anytime.

$20 / 3 months or $60 / year
Get Unlimited Access

More Professional Services Templates