Free
Hero
Tenace Hero
A hero block extracted from the Tenace template, available in Tailwind CSS and Bootstrap.
0
2
A hero block extracted from the Tenace template, available in Tailwind CSS and Bootstrap.
<!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>Tenace Hero | Tailwind CSS UI Block</title>
<meta name="description" content="A hero block extracted from the Tenace template, available in Tailwind CSS and Bootstrap.">
<meta name="keywords" content="Tenace, Tailwind CSS template, HTML website template, education template, online course template, bridge school, card game lessons, e-learning platform, online academy">
<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="Tenace | Tailwind CSS Education Template">
<meta property="og:description" content="A bold, geometric Tailwind CSS education template for online bridge schools, with an interactive bidding quiz, a course spotlight and a weekly lesson calendar.">
<meta property="og:image" content="">
<meta property="og:image:alt" content="Tenace template preview">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:url" content="">
<meta name="twitter:title" content="Tenace | Tailwind CSS Education Template">
<meta name="twitter:description" content="A bold, geometric Tailwind CSS education template for online bridge schools, with an interactive bidding quiz, a course spotlight and a weekly lesson calendar.">
<meta name="twitter:image" content="">
<meta name="twitter:image:alt" content="Tenace 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=Inter:wght@300;400;500;600&family=Unbounded:wght@600;800&display=swap" rel="stylesheet">
<script>
tailwind.config = {
theme: {
extend: {
colors: { indigo: { DEFAULT: '#2f2fa2', deep: '#23238a', soft: '#6b5bd2' }, sun: '#fbbf3c', petal: '#f9b4c0', blush: '#f6e9e8', ink: '#141414', heart: '#d6324f' },
fontFamily: { sans: ['Inter', 'sans-serif'], display: ['Unbounded', '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; }
.marquee { display: flex; overflow: hidden; gap: 3rem; }
.marquee-track { display: flex; flex-shrink: 0; align-items: center; gap: 3rem; animation: marquee 30s linear infinite; }
.marquee:hover .marquee-track { animation-play-state: paused; }
@keyframes marquee { to { transform: translateX(calc(-100% - 3rem)); } }
.ring-progress { transition: stroke-dashoffset 1.2s cubic-bezier(.2,.8,.2,1); }
.reveal-ready [data-ring] .ring-progress { stroke-dashoffset: 100; }
.reveal-ready [data-ring].is-visible .ring-progress { stroke-dashoffset: var(--ring-offset); }
.reveal-ready [data-reveal], .reveal-ready [data-tile] { opacity: 0; transform: translateY(24px); transition: opacity .6s ease, transform .6s ease; transition-delay: var(--reveal-delay, 0ms); }
.reveal-ready [data-tile] { transform: scale(.85); }
.reveal-ready [data-reveal].is-visible, .reveal-ready [data-tile].is-visible { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
html { scroll-behavior: auto; }
.marquee-track { animation: none; }
.marquee { overflow-x: auto; }
::view-transition-old(root), ::view-transition-new(root) { animation: none; }
}
</style>
</head>
<body class="bg-blush font-sans text-ink antialiased">
<% active_page = "index" %>
<% { "contacts" => "Contacts", "pricing" => "Choose a plan", "about" => "About us", "courses" => "Courses" }.each do |slug, label| %>
<% active = active_page == slug %>
<% end %>
<% { "index" => "Home", "courses" => "Courses", "pricing" => "Choose a plan", "about" => "About us", "contacts" => "Contacts", "login" => "Log in" }.each do |slug, label| %>
<% active = active_page == slug %>
<% end %>
<% tiles = [
[:photo, "bg-sun", "rounded-full", "1438761681033-6461ffad8d80", "Young woman with auburn hair by a lake"],
[:shape, "bg-indigo-soft", "rounded-tl-full rounded-br-full"],
[:suit, "bg-indigo", "♥", "text-sun"],
[:photo, "bg-petal", "rounded-t-full", "1507003211169-0a1dd7228f2d", "Smiling man with a beard"],
[:shape, "bg-indigo-soft", "rounded-br-full"],
[:shape, "bg-sun", "rounded-tr-full rounded-bl-full"],
[:shape, "bg-indigo-soft", "rounded-full"],
[:shape, "bg-indigo-soft", "rounded-tl-full"],
[:shape, "bg-[#4b3fc4]", "rounded-b-full"],
[:brand, "bg-petal", "rounded-t-full"],
[:shape, "bg-indigo-soft", "rounded-tr-full"],
[:suit, "bg-indigo", "♦", "text-petal"],
[:photo, "bg-petal", "rounded-full", "1500648767791-00dcc994a43e", "Man in a grey sweater smiling"],
[:shape, "bg-indigo-soft", "rounded-bl-full"],
[:photo, "bg-sun", "rounded-t-full", "1573496359142-b8d87734a5a2", "Woman in a grey blazer smiling"],
[:shape, "bg-petal", "rounded-tl-full"],
[:shape, "bg-indigo-soft", "rounded-t-full"],
[:suit, "bg-indigo", "♣", "text-indigo-soft"],
[:shape, "bg-indigo-soft", "rounded-t-full"],
[:shape, "bg-petal", "rounded-t-full"]
] %>
<!-- block:start hero -->
<section class="relative overflow-hidden lg:-mt-[7rem] lg:min-h-[52rem]">
<div class="relative mx-auto grid max-w-[1600px] lg:min-h-[52rem] lg:grid-cols-[1.1fr_1fr]">
<div class="flex flex-col justify-center px-5 pb-12 pt-6 md:px-12 lg:pb-24 lg:pt-40">
<h1 class="font-display text-[1.9rem] font-extrabold uppercase leading-[1.08] tracking-tight sm:text-4xl md:text-5xl xl:text-[3.4rem]">
Learn <span class="text-indigo">bridge</span> by<br>playing real hands
</h1>
<p class="mt-6 text-xl font-light md:text-2xl">Sharpen every bid, lead and play</p>
<a href="courses.html" class="mt-9 inline-flex w-fit items-center rounded-md bg-indigo px-10 py-4 text-sm font-semibold uppercase tracking-wide text-white transition hover:bg-indigo-deep">Start learning</a>
<ul class="mt-16 flex gap-4 lg:mt-auto lg:pt-24">
<% [["fa-whatsapp", "WhatsApp", "https://www.whatsapp.com"], ["fa-facebook-f", "Facebook", "https://www.facebook.com"], ["fa-twitter", "Twitter", "https://twitter.com"]].each do |icon, label, url| %>
<li><a href="<%= url %>" aria-label="<%= label %>" class="grid h-10 w-10 place-items-center rounded-full bg-white text-indigo shadow-sm transition hover:bg-indigo hover:text-white"><i class="fa-brands <%= icon %>" aria-hidden="true"></i></a></li>
<% end %>
</ul>
</div>
<div class="relative bg-indigo px-5 pb-8 pt-8 md:px-12 lg:pb-0 lg:pt-36">
<div class="mx-auto grid max-w-xl grid-cols-4 lg:-ml-24 lg:max-w-none">
<% tiles.each_with_index do |(kind, bg, *rest), index| %>
<div data-tile style="--reveal-delay: <%= (index % 7) * 60 %>ms" class="relative aspect-square">
<% case kind %>
<% when :photo %>
<div class="h-full w-full overflow-hidden <%= bg %> <%= rest[0] %>"><img src="https://images.unsplash.com/photo-<%= rest[1] %>?auto=format&fit=crop&w=600&q=80" alt="<%= rest[2] %>" class="h-full w-full object-cover" loading="lazy"></div>
<% when :suit %>
<div class="grid h-full w-full place-items-center <%= bg %> font-display text-6xl md:text-7xl <%= rest[1] %>" aria-hidden="true"><%= rest[0] %></div>
<% when :brand %>
<div class="flex h-full w-full flex-col items-center justify-end pb-[12%] <%= bg %> <%= rest[0] %>">
<span class="text-5xl leading-none text-indigo md:text-6xl" aria-hidden="true">♠</span>
<span class="mt-2 font-display text-[0.6rem] font-extrabold text-indigo sm:text-xs">TENACE</span>
</div>
<% else %>
<div class="h-full w-full <%= bg %> <%= rest[0] %>" aria-hidden="true"></div>
<% end %>
</div>
<% end %>
</div>
</div>
</div>
</section>
<!-- block:end hero -->
<script>
document.querySelectorAll('[data-menu-toggle]').forEach((button) => {
const menu = document.getElementById(button.getAttribute('aria-controls'));
if (!menu) return;
button.addEventListener('click', () => {
const open = button.getAttribute('aria-expanded') === 'true';
button.setAttribute('aria-expanded', String(!open));
menu.classList.toggle('hidden', open);
});
});
document.querySelectorAll('[data-quiz]').forEach((quiz) => {
const hands = [...quiz.querySelectorAll('[data-quiz-hand]')];
let current = 0;
let score = 0;
hands.forEach((hand) => {
const feedback = hand.querySelector('[data-quiz-feedback]');
const verdict = hand.querySelector('[data-quiz-verdict]');
const answer = verdict.textContent;
feedback.hidden = true;
hand.querySelectorAll('[data-quiz-option]').forEach((option) => {
option.addEventListener('click', () => {
if (!feedback.hidden) return;
const right = option.dataset.correct === 'true';
option.setAttribute('aria-pressed', 'true');
if (right) score += 1;
verdict.textContent = right ? `Spot on: ${option.textContent.trim()} is right.` : `Not quite. ${answer}`;
feedback.hidden = false;
quiz.querySelector('[data-quiz-score]').textContent = score;
});
});
hand.querySelector('[data-quiz-next]')?.addEventListener('click', () => {
hand.hidden = true;
current = (current + 1) % hands.length;
if (current === 0) { score = 0; quiz.querySelector('[data-quiz-score]').textContent = 0; }
const next = hands[current];
next.hidden = false;
next.querySelector('[data-quiz-feedback]').hidden = true;
next.querySelectorAll('[data-quiz-option]').forEach((option) => option.removeAttribute('aria-pressed'));
quiz.querySelector('[data-quiz-index]').textContent = current + 1;
next.querySelector('[data-quiz-option]')?.focus();
});
});
});
document.querySelectorAll('[data-tabs]').forEach((tablist) => {
const tabs = [...tablist.querySelectorAll('[role="tab"]')];
const select = (tab) => tabs.forEach((other) => {
const active = other === tab;
other.setAttribute('aria-selected', String(active));
other.tabIndex = active ? 0 : -1;
document.getElementById(other.getAttribute('aria-controls')).hidden = !active;
});
tabs.forEach((tab, index) => {
tab.addEventListener('click', () => select(tab));
tab.addEventListener('keydown', (event) => {
const step = { ArrowRight: 1, ArrowDown: 1, ArrowLeft: -1, ArrowUp: -1 }[event.key];
if (!step) return;
event.preventDefault();
const next = tabs[(index + step + tabs.length) % tabs.length];
next.focus();
select(next);
});
});
});
document.querySelectorAll('[data-switcher]').forEach((root) => {
root.addEventListener('click', (event) => {
const button = event.target.closest('[data-switch]');
if (!button) return;
root.querySelectorAll('[data-switch]').forEach((other) => other.setAttribute('aria-selected', String(other === button)));
root.querySelectorAll('[data-switch-panel]').forEach((panel) => { panel.hidden = panel.dataset.switchPanel !== button.dataset.switch; });
});
});
document.querySelectorAll('[data-search-target]').forEach((input) => {
const list = document.querySelector(input.dataset.searchTarget);
const empty = list?.parentElement.querySelector('[data-search-empty]');
input.addEventListener('input', () => {
const query = input.value.trim().toLowerCase();
let shown = 0;
list.querySelectorAll('[data-search-item]').forEach((item) => {
const match = !query || item.textContent.toLowerCase().includes(query);
item.hidden = !match;
if (match) shown += 1;
});
if (empty) empty.hidden = shown > 0;
});
});
document.querySelectorAll('[data-course-tools]').forEach((tools) => {
const grid = document.querySelector(tools.dataset.courseTools);
const search = tools.querySelector('[data-course-search]');
const sort = tools.querySelector('[data-course-sort]');
const count = tools.querySelector('[data-course-count]');
const apply = () => {
const query = search.value.trim().toLowerCase();
const items = [...grid.querySelectorAll('[data-course]')];
items.sort((a, b) => Number(a.dataset[sort.value]) - Number(b.dataset[sort.value])).forEach((item) => grid.append(item));
let shown = 0;
items.forEach((item) => {
const match = !query || item.textContent.toLowerCase().includes(query);
item.hidden = !match;
if (match) shown += 1;
});
count.textContent = shown;
};
search.addEventListener('input', apply);
sort.addEventListener('change', apply);
});
document.querySelectorAll('[data-booking]').forEach((form) => {
const summary = form.querySelector('[data-booking-summary]');
const update = () => {
const day = [...form.querySelectorAll('[name="day"]')].find((input) => input.checked);
const time = [...form.querySelectorAll('[name="time"]')].find((input) => input.checked);
summary.textContent = day && time ? `${day.value} at ${time.value}` : 'Pick a day and a time';
};
form.addEventListener('change', update);
update();
});
document.querySelectorAll('[data-contact-form], [data-booking]').forEach((form) => {
form.addEventListener('submit', (event) => {
event.preventDefault();
const status = form.querySelector('[data-form-status]');
const groups = [...form.querySelectorAll('[data-required-group]')].every((group) => [...group.querySelectorAll('[name]')].some((choice) => choice.checked));
if (!groups || !form.checkValidity()) {
status.textContent = form.dataset.error;
return;
}
status.textContent = form.dataset.success;
form.reset();
form.dispatchEvent(new Event('change'));
});
});
document.querySelectorAll('[data-current-year]').forEach((el) => { el.textContent = new Date().getFullYear(); });
(() => {
const items = document.querySelectorAll('[data-reveal], [data-tile]');
const skip = navigator.webdriver || !('IntersectionObserver' in window) || matchMedia('(prefers-reduced-motion: reduce)').matches;
if (!items.length || skip) return;
document.documentElement.classList.add('reveal-ready');
const observer = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (!entry.isIntersecting) return;
entry.target.classList.add('is-visible');
observer.unobserve(entry.target);
});
}, { rootMargin: '0px 0px -10% 0px' });
items.forEach((item) => observer.observe(item));
})();
</script>
</body>
</html>
Education
Unlock the entire library of premium templates and blocks. Renews automatically, cancel anytime.
Tailwind CSS · HTML download