Strivo UI Template - Let's templates
Strivo preview 1
Free
0 1

Strivo

By Jonah Hale

Strivo is a bold, electric-blue health and fitness template for training studios, with a motion-blur hero, rotating program card, giant marquee, numbered services, training cycle diagram, heart rate zone calculator, reviews, FAQ tabs and services, programs, wellness plans and contact pages.

Live Demo
strivo-tailwind.html
<%# letstemplates: access=premium category=health-fitness %>
<!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>Strivo | Tailwind CSS Health &amp; Fitness Template</title>
  <meta name="description" content="Strivo is a bold, electric-blue Tailwind CSS health and fitness template for training studios, with a motion-blur hero, rotating program card, giant marquee, numbered services, training cycle diagram, heart rate zone calculator, reviews, FAQ tabs and services, programs, wellness plans and contact pages.">
  <meta name="keywords" content="Strivo, Tailwind CSS template, HTML website template, fitness template, training studio, HIIT, heart rate zones, personal training, wellness plans, gym landing page">
  <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="Strivo | Tailwind CSS Health &amp; Fitness Template">
  <meta property="og:description" content="A bold electric-blue Tailwind CSS training template with a heart rate zone calculator, training cycle diagram and wellness plans by audience.">
  <meta property="og:image" content="">
  <meta property="og:image:alt" content="Strivo template preview">

  <meta name="twitter:card" content="summary_large_image">
  <meta name="twitter:url" content="">
  <meta name="twitter:title" content="Strivo | Tailwind CSS Health &amp; Fitness Template">
  <meta name="twitter:description" content="A bold electric-blue Tailwind CSS training template with a heart rate zone calculator, training cycle diagram and wellness plans by audience.">
  <meta name="twitter:image" content="">
  <meta name="twitter:image:alt" content="Strivo 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=Archivo:wght@400;500;600;800;900&display=swap" rel="stylesheet">
  <script>
    tailwind.config = {
      theme: {
        extend: {
          colors: { volt: { DEFAULT: '#1aa3e8', deep: '#0b5fa6', pale: '#d9f0fc' }, ink: { DEFAULT: '#0b0d10', soft: '#1a1e24' }, cream: '#fbf6ef', flare: '#ff7a3d' },
          fontFamily: { sans: ['Archivo', '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; } }
    @keyframes marquee { to { transform: translateX(-50%); } }
    html { scroll-behavior: smooth; }
    [hidden] { display: none !important; }
    .marquee { animation: marquee 30s linear infinite; }
    .blur-photo { filter: blur(6px) saturate(1.2); transform: scale(1.08); }
    .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; }
      .marquee { animation: none; }
      ::view-transition-old(root), ::view-transition-new(root) { animation: none; }
    }
  </style>
</head>
<body class="bg-ink font-sans text-white antialiased">
  <% active_page = "index" %>
  <% nav = { "services" => "Services", "programs" => "Programs", "wellness-plans" => "Wellness plans" } %>
  <!-- block:start navbar -->
  <header class="<%= active_page == 'index' ? 'absolute inset-x-0 top-0' : 'relative bg-volt-deep' %> z-40">
    <nav class="mx-auto flex max-w-7xl items-center justify-between gap-6 px-5 py-6 md:px-12 md:py-8" aria-label="Main">
      <a href="index.html" class="flex items-center gap-2 text-2xl font-extrabold uppercase tracking-tight"><svg viewBox="0 0 32 20" class="h-5 w-8" aria-hidden="true"><path d="M2 6v8M6 3v14M26 3v14M30 6v8M6 10h20" fill="none" stroke="currentColor" stroke-width="3.2" stroke-linecap="square"/></svg>Strivo</a>
      <ul class="hidden items-center gap-12 text-sm font-semibold uppercase tracking-wide lg:flex">
        <% nav.each do |slug, label| %>
          <% active = active_page == slug %>
          <li><a href="<%= slug %>.html" <%= 'aria-current="page"'.html_safe if active %> class="border-b-2 pb-1 transition <%= active ? 'border-white' : 'border-transparent opacity-85 hover:border-white/60' %>"><%= label %></a></li>
        <% end %>
      </ul>
      <div class="flex items-center gap-3">
        <a href="contact.html" class="hidden border border-white px-6 py-3.5 text-sm font-semibold uppercase tracking-wide transition hover:bg-white hover:text-ink sm:inline-block">Get started</a>
        <button type="button" data-menu-toggle aria-controls="mobile-menu" aria-expanded="false" class="grid h-12 w-12 place-items-center border border-white/60 lg:hidden" aria-label="Open menu"><i class="fa-solid fa-bars" aria-hidden="true"></i></button>
      </div>
    </nav>
    <div id="mobile-menu" class="mx-5 hidden bg-white p-2 text-ink lg:hidden">
      <ul class="grid">
        <% { "index" => "Home" }.merge(nav).merge("contact" => "Contact").each do |slug, label| %>
          <% active = active_page == slug %>
          <li><a href="<%= slug %>.html" <%= 'aria-current="page"'.html_safe if active %> class="flex items-center justify-between border-b border-ink/10 px-4 py-4 text-lg font-extrabold uppercase last:border-0 <%= active ? 'bg-volt text-white' : 'hover:bg-volt-pale' %>"><%= label %><i class="fa-solid fa-arrow-right text-sm" aria-hidden="true"></i></a></li>
        <% end %>
      </ul>
    </div>
  </header>
  <!-- block:end navbar -->

  <% cards = [["HIIT Training", "Short, sharp intervals that build engine and grit in 30 minutes.", "1599058917212-d750089bc07e", "Woman training with battle ropes"], ["Strength Lab", "Coached lifting that grows muscle and power safely.", "1541534741688-6078c6bfb5c5", "Woman lifting a barbell in a squat rack"], ["Mobility Reset", "Joint-friendly flows that keep you moving freely.", "1599901860904-17e6ed7083a0", "Person stretching in a downward dog pose"]] %>
  <!-- block:start hero -->
  <section class="relative isolate overflow-hidden bg-volt">
    <img src="https://images.unsplash.com/photo-1594882645126-14020914d58d?auto=format&fit=crop&w=1800&q=70" alt="" class="blur-photo absolute inset-0 -z-20 h-full w-full object-cover">
    <div class="absolute inset-0 -z-10 bg-gradient-to-b from-volt/80 via-volt/40 via-55% to-ink"></div>
    <div class="mx-auto max-w-7xl px-5 pb-10 pt-36 md:px-12 md:pt-44">
      <h1 class="text-[3.4rem] font-extrabold uppercase leading-[.86] tracking-tight sm:text-7xl md:text-8xl lg:text-[8.5rem]" data-reveal><span class="block">Built for</span><span class="block sm:pl-[22%]">Every</span><span class="block">Stride</span></h1>
      <div class="mt-8 grid gap-8 lg:-mt-24 lg:grid-cols-[1fr_minmax(0,34rem)]">
        <span class="hidden lg:block"></span>
        <div>
          <p class="text-lg leading-relaxed md:text-2xl" data-reveal style="--reveal-delay: 80ms">Train with intent: tailored sessions, coaches who notice the details and an energy that makes every goal feel within reach.</p>
          <a href="programs.html" class="mt-10 flex items-center justify-between gap-6 border border-white/40 bg-white/75 px-8 py-7 text-lg font-extrabold uppercase text-ink backdrop-blur-xl transition hover:bg-white md:ml-auto md:w-[26rem]">Find your program<i class="fa-solid fa-arrow-right" aria-hidden="true"></i></a>
        </div>
      </div>
      <div class="mt-16 grid gap-6 md:grid-cols-2 lg:grid-cols-[1fr_1.6fr_1.1fr_1fr] lg:items-start">
        <div data-reveal><p class="text-5xl font-extrabold" data-count="420">420</p><p class="mt-1 text-lg text-white/85">Body transformations</p></div>
        <div class="relative min-h-[13rem] overflow-hidden bg-cream text-ink" data-hero-card data-reveal style="--reveal-delay: 80ms">
          <% cards.each_with_index do |(title, text, photo, alt), index| %>
            <article class="absolute inset-0 grid grid-cols-[1.1fr_1fr] transition-opacity duration-500" data-hero-slide <%= 'hidden' unless index.zero? %>>
              <div class="flex flex-col p-6"><h2 class="text-2xl font-extrabold uppercase leading-none md:text-3xl"><%= title %></h2><p class="mt-auto text-sm"><%= text %></p></div>
              <img src="https://images.unsplash.com/photo-<%= photo %>?auto=format&fit=crop&w=500&h=500&q=75" alt="<%= alt %>" class="h-full w-full object-cover">
            </article>
          <% end %>
          <div class="absolute bottom-3 right-3 z-10 flex gap-1.5" role="group" aria-label="Featured programs">
            <% cards.each_with_index do |(title), index| %>
              <button type="button" data-hero-dot="<%= index %>" aria-pressed="<%= index.zero? %>" class="h-2 w-6 bg-ink/25 transition aria-pressed:w-10 aria-pressed:bg-ink" aria-label="Show <%= title %>"></button>
            <% end %>
          </div>
        </div>
        <div class="border-t border-white/70 pt-5" data-reveal style="--reveal-delay: 160ms"><p class="text-5xl font-extrabold"><span data-count="6000">6000</span>+</p><p class="mt-1 text-lg text-white/85">Coached sessions a year</p></div>
        <p class="text-white/85 lg:pt-1" data-reveal style="--reveal-delay: 240ms">Gain muscle, sharpen power and build strength that carries into everything you do.</p>
      </div>
    </div>
  </section>
  <!-- block:end hero -->

  <!-- block:start marquee -->
  <section class="overflow-hidden border-y border-white/10 bg-ink py-10" aria-label="Strivo promise">
    <div class="marquee flex w-max items-center gap-10 whitespace-nowrap text-6xl font-black uppercase tracking-tight md:text-8xl">
      <% 2.times do |copy| %>
        <% ["Train smart", "Move fast", "Lift heavy", "Recover well"].each_with_index do |word, index| %>
          <span class="<%= index.odd? ? 'text-transparent [-webkit-text-stroke:2px_#1aa3e8]' : '' %>" <%= 'aria-hidden="true"'.html_safe if copy == 1 %>><%= word %></span><span class="text-volt" aria-hidden="true">✦</span>
        <% end %>
      <% end %>
    </div>
    <div class="mx-auto mt-8 flex max-w-7xl justify-end px-5 md:px-12"><a href="contact.html" class="flex items-center gap-4 bg-volt px-7 py-4 font-extrabold uppercase transition hover:bg-volt-deep">Book a free session<i class="fa-solid fa-arrow-right" aria-hidden="true"></i></a></div>
  </section>
  <!-- block:end marquee -->

  <% services = [["Personal training", "One coach, one plan and a weekly review of every lift, run and rest day. Sessions move with your calendar and your energy.", "1517838277536-f5f99be501cd", "Hands gripping a loaded barbell"], ["HIIT & conditioning", "Thirty-minute intervals with heart rate screens on the wall, so you always know when to push and when to hold back.", "1554284126-aa88f22d8b74", "Group lifting dumbbells in a class"], ["Strength & power", "Small-group barbell work focused on technique first, then load. Perfect for first-timers and returning lifters.", "1532029837206-abbe2b7620e3", "Man pressing a barbell in a rack"], ["Mobility & recovery", "Guided mobility, breathwork and a recovery suite so the hard sessions actually pay off.", "1600881333168-2ef49b341f30", "Woman in a downward dog yoga pose"]] %>
  <!-- block:start features -->
  <section id="services" class="bg-cream text-ink">
    <div class="mx-auto max-w-7xl px-5 py-20 md:px-12 md:py-28">
      <div class="flex flex-wrap items-end justify-between gap-6">
        <h2 class="max-w-2xl text-5xl font-extrabold uppercase leading-[.9] tracking-tight md:text-7xl">What we do best</h2>
        <a href="services.html" class="border-b-2 border-ink pb-1 font-semibold uppercase">All services</a>
      </div>
      <ol class="mt-14 border-t border-ink" data-services>
        <% services.each_with_index do |(title, text, photo, alt), index| %>
          <li class="border-b border-ink">
            <h3>
              <button type="button" data-service-toggle aria-expanded="<%= index.zero? %>" aria-controls="service-<%= index %>" class="group grid w-full grid-cols-[3.5rem_1fr_auto] items-center gap-4 py-7 text-left md:grid-cols-[7rem_1fr_auto]">
                <span class="text-3xl font-extrabold text-volt md:text-5xl">0<%= index + 1 %></span>
                <span class="text-2xl font-extrabold uppercase md:text-5xl"><%= title %></span>
                <span class="grid h-12 w-12 place-items-center border border-ink transition group-hover:bg-ink group-hover:text-white group-aria-expanded:rotate-45 group-aria-expanded:bg-volt group-aria-expanded:border-volt group-aria-expanded:text-white"><i class="fa-solid fa-plus" aria-hidden="true"></i></span>
              </button>
            </h3>
            <div id="service-<%= index %>" class="grid gap-6 pb-8 md:grid-cols-[7rem_1fr_20rem]" <%= 'hidden' unless index.zero? %>>
              <span class="hidden md:block"></span>
              <p class="max-w-xl text-lg text-ink/75"><%= text %><a href="services.html" class="mt-5 block w-fit font-semibold uppercase text-volt-deep underline underline-offset-4">Learn more</a></p>
              <img src="https://images.unsplash.com/photo-<%= photo %>?auto=format&fit=crop&w=640&h=420&q=75" alt="<%= alt %>" class="aspect-[3/2] w-full object-cover">
            </div>
          </li>
        <% end %>
      </ol>
    </div>
  </section>
  <!-- block:end features -->

  <% phases = [["Assess", "Weeks 1–2", "Movement screen, strength tests and a resting heart rate baseline. We find your starting line, not someone else's.", "fa-clipboard-check"], ["Build", "Weeks 3–6", "Volume climbs gradually. Technique stays sharp and every session has a clear purpose.", "fa-layer-group"], ["Peak", "Weeks 7–10", "Intensity rises, volume drops. You test new personal bests in strength and conditioning.", "fa-bolt"], ["Recover", "Weeks 11–12", "A planned deload with mobility and sleep focus, then we reassess and start the next cycle stronger.", "fa-moon"]] %>
  <!-- block:start process -->
  <section class="relative overflow-hidden bg-volt-deep" data-cycle>
    <div class="mx-auto grid max-w-7xl items-center gap-14 px-5 py-20 md:px-12 md:py-28 lg:grid-cols-2">
      <div>
        <h2 class="text-5xl font-extrabold uppercase leading-[.9] tracking-tight md:text-7xl">The 12-week cycle</h2>
        <p class="mt-6 max-w-md text-lg text-white/80">Every Strivo program follows the same proven rhythm. Tap a phase to see what happens inside it.</p>
        <div class="mt-10 border-l-4 border-white pl-6" aria-live="polite">
          <p class="text-sm font-semibold uppercase tracking-widest text-white/70" data-cycle-weeks><%= phases[0][1] %></p>
          <p class="mt-2 text-4xl font-extrabold uppercase" data-cycle-title><%= phases[0][0] %></p>
          <p class="mt-3 max-w-md text-white/85" data-cycle-text><%= phases[0][2] %></p>
        </div>
      </div>
      <div class="relative mx-auto aspect-square w-full max-w-md">
        <div class="absolute inset-[12%] rounded-full border-2 border-dashed border-white/40"></div>
        <div class="absolute inset-[30%] grid place-items-center rounded-full bg-white text-center text-ink"><span><span class="block text-5xl font-black leading-none">12</span><span class="text-xs font-semibold uppercase tracking-widest">weeks</span></span></div>
        <% positions = ["left-1/2 top-[12%]", "left-[88%] top-1/2", "left-1/2 top-[88%]", "left-[12%] top-1/2"] %>
        <% phases.each_with_index do |(title, _weeks, _text, icon), index| %>
          <button type="button" data-phase="<%= index %>" aria-pressed="<%= index.zero? %>" class="absolute <%= positions[index] %> flex h-24 w-24 -translate-x-1/2 -translate-y-1/2 flex-col items-center justify-center gap-1 bg-ink text-xs font-bold uppercase tracking-wide transition hover:scale-105 aria-pressed:bg-white aria-pressed:text-ink md:h-28 md:w-28"><i class="fa-solid <%= icon %> text-xl" aria-hidden="true"></i><%= title %></button>
        <% end %>
      </div>
    </div>
    <script type="application/json" data-cycle-data><%= raw phases.map { |(title, weeks, text)| { title: title, weeks: weeks, text: text } }.to_json %></script>
  </section>
  <!-- block:end process -->

  <% age = 32 %>
  <% rest = 60 %>
  <% zones = [["Zone 1", "Recovery", 0.5, 0.6, "Easy walk or Mobility Reset"], ["Zone 2", "Endurance", 0.6, 0.7, "Long steady ride or easy run"], ["Zone 3", "Tempo", 0.7, 0.8, "Strength Lab circuits"], ["Zone 4", "Threshold", 0.8, 0.9, "HIIT Training intervals"], ["Zone 5", "Max effort", 0.9, 1.0, "Sprint finishers, 20 seconds max"]] %>
  <% reserve = 220 - age - rest %>
  <!-- block:start demo -->
  <section id="zones" class="bg-ink" data-zones>
    <div class="mx-auto grid max-w-7xl gap-12 px-5 py-20 md:px-12 md:py-28 lg:grid-cols-[1fr_1.3fr]">
      <div>
        <p class="text-sm font-semibold uppercase tracking-widest text-volt">Zone finder</p>
        <h2 class="mt-4 text-5xl font-extrabold uppercase leading-[.9] tracking-tight md:text-7xl">Know your numbers</h2>
        <p class="mt-6 max-w-md text-white/75">Our coaches program every session by heart rate zone. Enter two numbers to see yours.</p>
        <div class="mt-10 grid gap-8">
          <label class="grid gap-3"><span class="flex justify-between text-sm font-semibold uppercase tracking-wide">Age <output class="text-2xl text-volt" data-zone-age-out><%= age %></output></span><input type="range" min="18" max="75" value="<%= age %>" class="accent-[#1aa3e8]" data-zone-age></label>
          <label class="grid gap-3"><span class="flex justify-between text-sm font-semibold uppercase tracking-wide">Resting heart rate <output class="text-2xl text-volt" data-zone-rest-out><%= rest %> bpm</output></span><input type="range" min="40" max="90" value="<%= rest %>" class="accent-[#1aa3e8]" data-zone-rest></label>
        </div>
        <p class="mt-10 border-t border-white/15 pt-6 text-white/70">Max heart rate <span class="ml-2 text-3xl font-extrabold text-white" data-zone-max><%= 220 - age %></span> bpm</p>
      </div>
      <div>
        <ul class="grid gap-2" role="list">
          <% zones.each_with_index do |(name, label, low, high), index| %>
            <li>
              <button type="button" data-zone="<%= index %>" aria-pressed="<%= index == 3 %>" class="group relative grid w-full grid-cols-[6rem_1fr_auto] items-center gap-4 overflow-hidden bg-ink-soft px-5 py-5 text-left transition hover:bg-white/10 aria-pressed:bg-volt">
                <span class="absolute inset-y-0 left-0 bg-white/5 group-aria-pressed:bg-white/15" style="width: <%= (high * 100).round %>%"></span>
                <span class="relative text-sm font-semibold uppercase tracking-wide"><%= name %></span>
                <span class="relative text-xl font-extrabold uppercase"><%= label %></span>
                <span class="relative text-lg font-semibold tabular-nums" data-zone-range><%= (rest + reserve * low).round %>–<%= (rest + reserve * high).round %></span>
              </button>
            </li>
          <% end %>
        </ul>
        <p class="mt-6 flex items-center gap-3 border border-white/15 px-5 py-4" aria-live="polite"><i class="fa-solid fa-dumbbell text-volt" aria-hidden="true"></i><span>Try this: <strong data-zone-session><%= zones[3][4] %></strong></span></p>
      </div>
    </div>
    <script type="application/json" data-zone-data><%= raw zones.map { |(name, label, low, high, session)| { low: low, high: high, session: session } }.to_json %></script>
  </section>
  <!-- block:end demo -->

  <% reviews = [["I've tried every gym in town. Strivo is the first place where the plan changed when my life did.", "Nadia Brooks", "Down 11 kg in 6 months", "avatar-2"], ["The heart rate screens in HIIT are addictive. I finally understand what easy and hard really mean.", "Owen Price", "First sub-50 10K", "avatar-4"], ["Coming back after a knee injury, the coaches built my confidence before they built my squat.", "Leila Haddad", "Back to 80 kg squat", "avatar-5"], ["Twelve-week cycles keep me honest. Every deload week I'm amazed how much stronger I feel.", "Chris Moreno", "+30% on every lift", "avatar-3"]] %>
  <!-- block:start reviews -->
  <section class="bg-cream text-ink" data-carousel>
    <div class="mx-auto max-w-7xl px-5 py-20 md:px-12 md:py-28">
      <div class="flex flex-wrap items-end justify-between gap-6">
        <h2 class="text-5xl font-extrabold uppercase leading-[.9] tracking-tight md:text-7xl">Member stories</h2>
        <div class="flex gap-2">
          <button type="button" data-prev class="grid h-14 w-14 place-items-center border border-ink transition hover:bg-ink hover:text-white" aria-label="Previous story"><i class="fa-solid fa-arrow-left" aria-hidden="true"></i></button>
          <button type="button" data-next class="grid h-14 w-14 place-items-center bg-volt text-white transition hover:bg-volt-deep" aria-label="Next story"><i class="fa-solid fa-arrow-right" aria-hidden="true"></i></button>
        </div>
      </div>
      <div class="mt-12 overflow-hidden">
        <ul class="flex transition-transform duration-500 motion-reduce:transition-none" data-track>
          <% reviews.each_with_index do |(quote, name, result, avatar), index| %>
            <li class="w-full shrink-0 md:w-1/2 md:pr-6" aria-roledescription="slide" aria-label="<%= index + 1 %> of <%= reviews.size %>">
              <figure class="flex h-full flex-col border-t-4 border-ink bg-white p-8">
                <blockquote class="text-2xl font-medium leading-snug">“<%= quote %>”</blockquote>
                <figcaption class="mt-auto flex items-center gap-4 pt-8"><img src="https://storage.googleapis.com/uxpilot-auth.appspot.com/avatars/<%= avatar %>.jpg" alt="" class="h-12 w-12 object-cover"><span><span class="block font-extrabold uppercase"><%= name %></span><span class="text-sm text-volt-deep"><%= result %></span></span></figcaption>
              </figure>
            </li>
          <% end %>
        </ul>
      </div>
      <div class="mt-8 flex gap-2" role="group" aria-label="Choose a story">
        <% reviews.each_with_index do |_, index| %>
          <button type="button" data-dot="<%= index %>" aria-pressed="<%= index.zero? %>" class="h-1.5 w-10 bg-ink/20 transition aria-pressed:bg-ink" aria-label="Story <%= index + 1 %>"></button>
        <% end %>
      </div>
    </div>
  </section>
  <!-- block:end reviews -->

  <% faqs = { "membership" => ["Membership", [["Can I pause my plan?", "Yes, up to six weeks a year with no fee."], ["Is there a contract?", "Monthly plans roll monthly. Annual plans save 15% and can be transferred."], ["Do you offer corporate plans?", "Yes. Teams of five or more get pooled sessions and a shared dashboard."]]], "training" => ["Training", [["I'm a complete beginner. Is that okay?", "Absolutely. Your first two weeks are an assessment phase built for exactly that."], ["How long are sessions?", "HIIT runs 30 minutes, strength and personal training 50 to 60."], ["Do I need a heart rate monitor?", "We lend chest straps for every class, or you can pair your own."]]], "recovery" => ["Recovery", [["What's in the recovery suite?", "Sauna, cold plunge, compression boots and a stretching zone."], ["Do you help with nutrition?", "Wellness plans include a monthly nutrition check-in with our dietitian."], ["Can I train with an injury?", "Often, yes. Tell us first and we'll build sessions around it with our physio."]]] } %>
  <!-- block:start faq -->
  <section class="bg-ink" data-faq-tabs>
    <div class="mx-auto grid max-w-7xl gap-12 px-5 py-20 md:px-12 md:py-28 lg:grid-cols-[1fr_1.5fr]">
      <div>
        <h2 class="text-5xl font-extrabold uppercase leading-[.9] tracking-tight md:text-7xl">Questions</h2>
        <div class="mt-10 flex flex-wrap gap-2 lg:flex-col lg:items-start" role="tablist" aria-label="Question topics">
          <% faqs.each_with_index do |(key, (label)), index| %>
            <button type="button" role="tab" id="faq-tab-<%= key %>" aria-controls="faq-<%= key %>" aria-selected="<%= index.zero? %>" tabindex="<%= index.zero? ? 0 : -1 %>" class="border border-white/30 px-5 py-3 text-sm font-semibold uppercase tracking-wide transition hover:border-white aria-selected:border-volt aria-selected:bg-volt"><%= label %></button>
          <% end %>
        </div>
      </div>
      <div>
        <% faqs.each_with_index do |(key, (_label, items)), index| %>
          <dl id="faq-<%= key %>" role="tabpanel" aria-labelledby="faq-tab-<%= key %>" class="border-t border-white/20" <%= 'hidden' unless index.zero? %>>
            <% items.each do |(question, answer)| %>
              <div class="border-b border-white/20 py-7"><dt class="text-xl font-extrabold uppercase"><%= question %></dt><dd class="mt-2 text-white/75"><%= answer %></dd></div>
            <% end %>
          </dl>
        <% end %>
      </div>
    </div>
  </section>
  <!-- block:end faq -->

  <!-- block:start footer -->
  <footer class="bg-volt">
    <div class="mx-auto max-w-7xl px-5 py-16 md:px-12">
      <div class="grid gap-10 border-b border-white/30 pb-14 lg:grid-cols-[1.4fr_1fr]">
        <p class="text-4xl font-extrabold uppercase leading-[.95] tracking-tight md:text-6xl">Your first session is on us</p>
        <form class="self-end" data-newsletter novalidate>
          <label for="footer-email" class="text-sm font-semibold uppercase tracking-wide">Email for a free pass</label>
          <div class="mt-3 flex">
            <input id="footer-email" name="email" type="email" required autocomplete="email" placeholder="you@example.com" class="min-w-0 flex-1 bg-white px-5 py-4 text-ink placeholder:text-ink/40 focus:outline-none focus:ring-2 focus:ring-ink">
            <button type="submit" class="bg-ink px-6 font-extrabold uppercase transition hover:bg-ink-soft">Claim</button>
          </div>
          <p class="mt-3 min-h-[1.5rem] text-sm font-medium" data-form-status role="status"></p>
        </form>
      </div>
      <div class="grid gap-10 py-12 sm:grid-cols-2 lg:grid-cols-4">
        <div>
          <a href="index.html" class="flex items-center gap-2 text-2xl font-extrabold uppercase"><svg viewBox="0 0 32 20" class="h-5 w-8" aria-hidden="true"><path d="M2 6v8M6 3v14M26 3v14M30 6v8M6 10h20" fill="none" stroke="currentColor" stroke-width="3.2" stroke-linecap="square"/></svg>Strivo</a>
          <p class="mt-4 max-w-xs text-white/85">Modern training for people who want results without the guesswork.</p>
        </div>
        <% [["Train", [["Services", "services.html"], ["Programs", "programs.html"], ["Zone finder", "index.html#zones"]]], ["Join", [["Wellness plans", "wellness-plans.html"], ["Free session", "contact.html"], ["Corporate", "wellness-plans.html"]]], ["Visit", [["210 Canal Street, Manchester", nil], ["hello@strivo.fit", "mailto:hello@strivo.fit"], ["+44 161 555 0192", "tel:+441615550192"]]]].each do |(title, links)| %>
          <div>
            <h2 class="text-sm font-semibold uppercase tracking-widest text-white/70"><%= title %></h2>
            <ul class="mt-4 grid gap-2">
              <% links.each do |(label, href)| %><li><% if href %><a href="<%= href %>" class="hover:underline"><%= label %></a><% else %><%= label %><% end %></li><% end %>
            </ul>
          </div>
        <% end %>
      </div>
      <p class="flex flex-wrap justify-between gap-4 border-t border-white/30 pt-6 text-sm text-white/80"><span>&copy; 2026 Strivo Training Ltd.</span><span class="flex gap-5"><a href="contact.html" aria-label="Instagram" class="hover:text-ink"><i class="fa-brands fa-instagram" aria-hidden="true"></i></a><a href="contact.html" aria-label="TikTok" class="hover:text-ink"><i class="fa-brands fa-tiktok" aria-hidden="true"></i></a><a href="contact.html" aria-label="YouTube" class="hover:text-ink"><i class="fa-brands fa-youtube" aria-hidden="true"></i></a></span></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-hero-card]').forEach((root) => {
      const slides = [...root.querySelectorAll('[data-hero-slide]')];
      const dots = [...root.querySelectorAll('[data-hero-dot]')];
      let current = 0;
      const show = (index) => {
        current = index;
        slides.forEach((slide, i) => { slide.hidden = i !== index; });
        dots.forEach((dot, i) => dot.setAttribute('aria-pressed', String(i === index)));
      };
      dots.forEach((dot, i) => dot.addEventListener('click', () => show(i)));
      if (!reducedMotion && !navigator.webdriver) setInterval(() => { if (!root.matches(':hover')) show((current + 1) % slides.length); }, 5000);
    });

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

    document.querySelectorAll('[data-cycle]').forEach((root) => {
      const data = JSON.parse(root.querySelector('[data-cycle-data]').textContent);
      const buttons = [...root.querySelectorAll('[data-phase]')];
      buttons.forEach((button) => button.addEventListener('click', () => {
        buttons.forEach((other) => other.setAttribute('aria-pressed', String(other === button)));
        const phase = data[Number(button.dataset.phase)];
        root.querySelector('[data-cycle-title]').textContent = phase.title;
        root.querySelector('[data-cycle-weeks]').textContent = phase.weeks;
        root.querySelector('[data-cycle-text]').textContent = phase.text;
      }));
    });

    document.querySelectorAll('[data-zones]').forEach((root) => {
      const data = JSON.parse(root.querySelector('[data-zone-data]').textContent);
      const age = root.querySelector('[data-zone-age]');
      const rest = root.querySelector('[data-zone-rest]');
      const buttons = [...root.querySelectorAll('[data-zone]')];
      const update = () => {
        const max = 220 - Number(age.value);
        const reserve = max - Number(rest.value);
        root.querySelector('[data-zone-age-out]').textContent = age.value;
        root.querySelector('[data-zone-rest-out]').textContent = `${rest.value} bpm`;
        root.querySelector('[data-zone-max]').textContent = max;
        buttons.forEach((button, i) => { button.querySelector('[data-zone-range]').textContent = `${Math.round(Number(rest.value) + reserve * data[i].low)}–${Math.round(Number(rest.value) + reserve * data[i].high)}`; });
      };
      age.addEventListener('input', update);
      rest.addEventListener('input', update);
      buttons.forEach((button) => button.addEventListener('click', () => {
        buttons.forEach((other) => other.setAttribute('aria-pressed', String(other === button)));
        root.querySelector('[data-zone-session]').textContent = data[Number(button.dataset.zone)].session;
      }));
    });

    document.querySelectorAll('[data-carousel]').forEach((root) => {
      const track = root.querySelector('[data-track]');
      const dots = [...root.querySelectorAll('[data-dot]')];
      const count = track.children.length;
      let index = 0;
      const go = (next) => {
        index = (next + count) % count;
        track.style.transform = `translateX(-${track.children[index].offsetLeft}px)`;
        dots.forEach((dot, i) => dot.setAttribute('aria-pressed', String(i === index)));
      };
      root.querySelector('[data-prev]').addEventListener('click', () => go(index - 1));
      root.querySelector('[data-next]').addEventListener('click', () => go(index + 1));
      dots.forEach((dot, i) => dot.addEventListener('click', () => go(i)));
    });

    document.querySelectorAll('[data-faq-tabs]').forEach((root) => {
      const tabs = [...root.querySelectorAll('[role="tab"]')];
      const select = (tab, focus) => {
        tabs.forEach((other) => { const on = other === tab; other.setAttribute('aria-selected', String(on)); other.tabIndex = on ? 0 : -1; document.getElementById(other.getAttribute('aria-controls')).hidden = !on; });
        if (focus) tab.focus();
      };
      tabs.forEach((tab, i) => {
        tab.addEventListener('click', () => select(tab));
        tab.addEventListener('keydown', (event) => {
          if (event.key === 'ArrowRight' || event.key === 'ArrowDown') select(tabs[(i + 1) % tabs.length], true);
          if (event.key === 'ArrowLeft' || event.key === 'ArrowUp') select(tabs[(i - 1 + tabs.length) % tabs.length], true);
        });
      });
    });

    document.querySelectorAll('[data-newsletter]').forEach((form) => {
      const status = form.querySelector('[data-form-status]');
      form.addEventListener('submit', (event) => {
        event.preventDefault();
        const email = form.querySelector('[name="email"]');
        if (!email.value.trim() || !email.checkValidity()) { status.textContent = 'Please enter a valid email address.'; email.focus(); return; }
        status.textContent = 'Pass on its way. Check your inbox to book your first session.';
        form.reset();
      });
    });

    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));
      const counter = new IntersectionObserver((entries) => entries.forEach((entry) => {
        if (!entry.isIntersecting) return;
        const el = entry.target; const end = Number(el.dataset.count); const start = performance.now();
        const tick = (now) => { const p = Math.min((now - start) / 900, 1); el.textContent = Math.round(end * p); if (p < 1) requestAnimationFrame(tick); };
        requestAnimationFrame(tick); counter.unobserve(el);
      }), { threshold: 0.5 });
      document.querySelectorAll('[data-count]').forEach((el) => counter.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 Health & Fitness Templates