Free
0
1
Northline
Northline is a bold, neon-accented agency template for creative studios, product designers, and branding teams with 3D hero tiles, stat cards, case studies, pricing, and testimonials.
Download Codebase
Commercial License<%# letstemplates: access=free category=agency %>
<!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>Northline | Tailwind CSS Creative Agency Template</title>
<meta name="description" content="Northline is a bold, neon-accented Tailwind CSS agency template for creative studios, product designers, and branding teams with 3D hero tiles, stat cards, case studies, pricing, and testimonials.">
<meta name="keywords" content="Northline, Tailwind CSS template, HTML website template, agency template, creative studio, branding agency, UI UX design studio, case studies, responsive agency design">
<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="Northline | Tailwind CSS Creative Agency Template">
<meta property="og:description" content="A bold, neon-accented Tailwind CSS agency template for creative studios, product designers, and branding teams with 3D hero tiles, stat cards, case studies, pricing, and testimonials.">
<meta property="og:image" content="">
<meta property="og:image:alt" content="Northline template preview">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:url" content="">
<meta name="twitter:title" content="Northline | Tailwind CSS Creative Agency Template">
<meta name="twitter:description" content="A bold, neon-accented Tailwind CSS agency template for creative studios, product designers, and branding teams with 3D hero tiles, stat cards, case studies, pricing, and testimonials.">
<meta name="twitter:image" content="">
<meta name="twitter:image:alt" content="Northline template preview">
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=Bebas+Neue&family=Inter:wght@300;400;500;600&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
<script>
tailwind.config = {
theme: {
extend: {
colors: {
night: '#07051a',
indigo: '#110766',
royal: '#4b3fd6',
violet: '#a259ff',
lilac: '#dcd6ff',
lime: '#c8ff4a',
coral: '#ff5a5f',
cream: '#fdebd8'
},
fontFamily: {
sans: ['Inter', 'ui-sans-serif', 'system-ui', 'sans-serif'],
display: ['"Bebas Neue"', 'Impact', 'sans-serif'],
mono: ['"JetBrains Mono"', 'ui-monospace', 'monospace']
}
}
}
};
</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; }
.no-scrollbar { scrollbar-width: none; }
.no-scrollbar::-webkit-scrollbar { display: none; }
.hero-glow { background: radial-gradient(60% 45% at 50% 78%, rgba(120, 180, 255, .35), transparent 70%), radial-gradient(80% 60% at 50% 40%, rgba(162, 89, 255, .18), transparent 70%), #0b0822; }
.platform { background: radial-gradient(closest-side, #f3dcff, #d9b3ff 70%, #b98bff); box-shadow: 0 0 80px 20px rgba(200, 150, 255, .45), inset 0 0 0 10px rgba(255,255,255,.35); }
.tile { position: absolute; display: flex; align-items: center; justify-content: center; border-radius: 1.4rem; box-shadow: 0 30px 60px -20px rgba(0,0,0,.6), inset 0 -10px 20px rgba(0,0,0,.25), inset 0 6px 12px rgba(255,255,255,.2); animation: float 7s ease-in-out infinite; animation-delay: var(--delay, 0s); }
@keyframes float { 50% { translate: 0 -14px; } }
.stripes { background: repeating-linear-gradient(0deg, #ffffff 0 18px, #e4e0ff 18px 24px); }
.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; }
.tile { animation: none; }
::view-transition-old(root), ::view-transition-new(root) { animation: none; }
}
</style>
</head>
<body class="bg-night font-sans text-white antialiased overflow-x-hidden">
<%
nav_links = [["Home", "index.html"], ["Our work", "our-work.html"], ["Service", "services.html"], ["Reviews", "reviews.html"], ["Contact", "contact.html"]]
tiles = [
{ style: "left:4%; top:14%; width:9rem; height:6rem; background:linear-gradient(135deg,#2a3aa8,#101a5c); transform:rotate(18deg) skewX(-12deg); --delay:.2s", label: "WEB", size: "md:flex" },
{ style: "left:1%; top:32%; width:10rem; height:10rem; background:linear-gradient(135deg,#231b2e,#0e0b14); transform:rotate(28deg) skewX(-10deg); filter:blur(2px); --delay:1s", label: "", size: "lg:flex" },
{ style: "left:12%; top:48%; width:9.5rem; height:10.5rem; background:linear-gradient(160deg,#3a2bb5,#a879ff 60%,#e6ccff); transform:rotate(-16deg) skewY(6deg); --delay:.6s", icon: "fa-chess-board", size: "md:flex" },
{ style: "left:5%; top:58%; width:13rem; height:9rem; background:linear-gradient(160deg,#6d5ce6,#a18cff); transform:rotate(22deg) skewX(-18deg); --delay:1.4s", icon: "fa-sun", size: "lg:flex" },
{ style: "right:18%; top:9%; width:6.5rem; height:6.5rem; background:linear-gradient(135deg,#221c52,#141033); transform:rotate(40deg); --delay:.4s", label: "", size: "md:flex" },
{ style: "right:4%; top:22%; width:10rem; height:6.5rem; background:linear-gradient(135deg,#1f4b48,#10242a); transform:rotate(-24deg) skewX(20deg); --delay:1.2s", label: "UI", size: "md:flex" },
{ style: "right:9%; top:34%; width:5rem; height:5.5rem; background:linear-gradient(135deg,#231d55,#16123a); transform:rotate(12deg); --delay:2s", label: "", size: "lg:flex" },
{ style: "right:12%; top:46%; width:11rem; height:11rem; background:linear-gradient(150deg,#b6a4ff,#56e3a7 60%,#9ef2d2); transform:rotate(18deg) skewX(-14deg); --delay:.8s", icon: "fa-star", size: "md:flex" },
{ style: "right:3%; top:56%; width:13rem; height:10rem; background:linear-gradient(150deg,#6f5ce0,#59d8b6); transform:rotate(22deg) skewX(-20deg); --delay:1.6s", icon: "fa-q", size: "lg:flex" }
]
stats = [
{ label: "Projects shipped this year", value: "120", suffix: "++", icon: "fa-trophy", bg: "bg-lime text-night", wide: true },
{ label: "Client challenges cracked", value: "98", suffix: "%", icon: "fa-award", bg: "bg-violet text-white" },
{ label: "Brands backing us across the globe", value: "45", suffix: "++", icon: "fa-face-smile", bg: "bg-coral text-white" }
]
cases = [
{ slug: "kinmo-matcha", name: "Kinmo Matcha", tag: "Food & beverage", text: "A ceremonial-grade matcha brand with packaging as calm and bright as the first sip.", image: "https://images.unsplash.com/photo-1767721887917-ad186b3f5f2d?auto=format&fit=crop&w=900&q=80", alt: "Two green matcha latte canisters on a pale green background" },
{ slug: "fernwell", name: "Fernwell", tag: "Skincare & body", text: "Clean body oils in apothecary bottles, launched with a lush greenhouse campaign.", image: "https://images.unsplash.com/photo-1699373383905-d0eafdffe5c1?auto=format&fit=crop&w=900&q=80", alt: "White bottle of body oil in front of lush green fiddle-leaf leaves" },
{ slug: "clearmist", name: "Clearmist", tag: "Wellness", text: "A face mist rebrand that turned a pharmacy staple into a daily ritual people post about.", image: "https://images.unsplash.com/photo-1770795469594-768039ef6650?auto=format&fit=crop&w=900&q=80", alt: "Hand holding a white spray bottle of skincare mist" },
{ slug: "emberlight", name: "Emberlight", tag: "Home & living", text: "Hand-poured candles with an identity built around warm amber glass and quiet type.", image: "https://images.unsplash.com/photo-1602607203588-d6d0eda790e3?auto=format&fit=crop&w=900&q=80", alt: "Amber glass candle jars and a kraft box arranged on stone blocks" }
]
plans = [
{ name: "Starter", note: "Great for solo founders", price: "$300", unit: "/project", features: ["Core design support", "1–2 rounds of revisions", "One landing page or UI screen", "Standard turnaround"], cta: "Get Started", featured: false },
{ name: "Growth", note: "Built for scaling brands", price: "$800", unit: "/project", features: ["Full web or app design", "Up to 5 revisions", "UI/UX strategy session", "Starter design system", "Priority turnaround"], cta: "Get Started", featured: true },
{ name: "Custom", note: "For larger teams", price: "Let's talk", unit: "", features: ["Everything in Starter & Growth", "End-to-end product design", "In-depth UX research", "Dedicated design lead", "Ongoing partnership"], cta: "Contact Us", featured: false }
]
reviews = [
{ name: "Rafael Okoro", role: "Senior Product Designer, Driftbox", quote: "Partnering with them lifted our whole product experience, and our users noticed straight away.", avatar: "https://images.unsplash.com/photo-1758335068076-7564a9ada09f?auto=format&fit=crop&w=300&q=80" },
{ name: "Mina Castell", role: "Head of Brand, Kinmo Matcha", quote: "They found the calm in our brand we couldn't put into words, then made it sell.", avatar: "https://storage.googleapis.com/uxpilot-auth.appspot.com/avatars/avatar-2.jpg" },
{ name: "Jonah Weiss", role: "Founder, Fernwell", quote: "Launch week sold out twice. The campaign did exactly what we hoped, then some.", avatar: "https://storage.googleapis.com/uxpilot-auth.appspot.com/avatars/avatar-4.jpg" }
]
pixels = [[0,0,1],[1,1,2],[2,1,2],[3,0,0],[4,0,1],[5,0,1],[6,0,1],[1,2,1],[3,1,2],[4,2,2],[5,1,2],[6,2,1],[7,2,1],[4,3,1],[5,3,0],[6,3,1],[7,3,1],[8,3,1],[3,4,1],[5,4,1],[7,4,2],[4,5,0],[6,5,1],[7,5,1],[6,6,2],[8,2,1]]
%>
<!-- block:start navbar -->
<header id="top" class="absolute inset-x-0 top-0 z-40">
<nav class="mx-auto flex max-w-[1440px] items-center justify-between px-5 py-6 md:px-20 md:py-10" aria-label="Main">
<a href="index.html" class="flex items-center gap-2 text-2xl font-medium tracking-tight">
<span class="relative inline-flex h-10 w-10 items-center justify-center rounded-full bg-[conic-gradient(#c8ff4a_0_75%,#3d4a2b_75%)]"><span class="h-4 w-4 rounded-full bg-night ring-4 ring-lime"></span></span>
Northline
</a>
<ul class="hidden items-center gap-8 font-mono text-sm uppercase lg:flex" data-nav>
<% nav_links.each_with_index do |(label, href), index| %>
<li><a href="<%= href %>" aria-current="<%= index.zero? ? 'page' : 'false' %>" class="<%= index.zero? ? 'text-white' : 'text-white/60 hover:text-white' %> transition"><%= label %></a></li>
<% end %>
</ul>
<div class="flex items-center gap-3">
<a href="contact.html" class="hidden rounded-full bg-lime px-6 py-3 font-mono text-sm uppercase text-night transition hover:bg-white sm:inline-flex">Work with us</a>
<button type="button" data-menu-toggle aria-controls="mobile-menu" aria-expanded="false" class="inline-flex h-11 w-11 items-center justify-center rounded-full bg-white/10 lg:hidden" aria-label="Open menu"><i class="fa-solid fa-bars"></i></button>
</div>
</nav>
<div id="mobile-menu" class="hidden mx-5 rounded-3xl bg-indigo p-6 lg:hidden">
<ul class="space-y-1 font-display text-4xl">
<% nav_links.each_with_index do |(label, href), index| %>
<li><a href="<%= href %>" aria-current="<%= index.zero? ? 'page' : 'false' %>" class="<%= index.zero? ? 'text-lime' : 'hover:text-lime' %>"><%= label %></a></li>
<% end %>
</ul>
<a href="contact.html" class="mt-6 inline-flex rounded-full bg-lime px-6 py-3 font-mono text-sm uppercase text-night">Work with us</a>
</div>
</header>
<!-- block:end navbar -->
<main>
<!-- block:start hero -->
<section id="hero" class="hero-glow relative overflow-hidden">
<div class="pointer-events-none absolute inset-0 mx-auto max-w-[1440px]" aria-hidden="true">
<% tiles.each do |tile| %>
<div class="tile hidden <%= tile[:size] %>" style="<%= tile[:style] %>">
<% if tile[:label].present? %><span class="font-sans text-4xl font-black italic text-white/40"><%= tile[:label] %></span><% end %>
<% if tile[:icon] %><i class="fa-solid <%= tile[:icon] %> text-5xl text-indigo/70"></i><% end %>
</div>
<% end %>
</div>
<div class="relative mx-auto flex min-h-[760px] max-w-[1440px] flex-col items-center px-5 pt-40 text-center md:min-h-[1080px] md:pt-52">
<h1 class="font-display text-[19vw] leading-[0.86] text-[#f3e8ff] md:text-[150px] lg:text-[164px]">Ideas meet<br>purpose with<br>impact</h1>
<p class="mt-8 max-w-[26rem] text-base font-light text-white/75">We turn considered ideas into meaningful work that moves real numbers.</p>
<div class="mt-8 flex flex-wrap justify-center gap-4 font-mono text-base uppercase">
<a href="our-work.html" class="rounded-full bg-white px-7 py-3 text-night shadow-[inset_0_-4px_0_rgba(0,0,0,.15)] transition hover:bg-lime">See our work</a>
<a href="contact.html" class="rounded-full bg-night px-7 py-3 text-white ring-1 ring-white/20 transition hover:ring-lime">Get a quote</a>
</div>
<div class="platform pointer-events-none absolute bottom-[12%] left-1/2 h-[90px] w-[88%] max-w-[1000px] -translate-x-1/2 rounded-[50%] md:h-[130px]" aria-hidden="true"></div>
<div class="pointer-events-none absolute inset-x-0 bottom-0 h-[16%] rounded-t-[50%] bg-gradient-to-b from-[#1a1535] to-night" aria-hidden="true"></div>
</div>
</section>
<!-- block:end hero -->
<!-- block:start stats -->
<section id="impact" class="relative overflow-hidden bg-lilac text-night">
<div class="stripes absolute inset-x-0 top-0 h-[80%]" aria-hidden="true"></div>
<div class="relative mx-auto grid max-w-[1440px] gap-10 px-5 py-20 md:px-20 lg:grid-cols-2 lg:py-28">
<div>
<h2 class="font-display text-[17vw] leading-[0.9] md:text-[124px] lg:text-[136px]">Bold ideas<br>built <img src="https://images.unsplash.com/photo-1684158100445-8e6926faf964?auto=format&fit=crop&w=500&q=80" alt="" class="inline-block h-[0.82em] w-[1.2em] object-cover align-[-0.08em]"> to<br>make a mark</h2>
<p class="mt-8 max-w-[20rem] font-mono text-sm uppercase leading-snug">We treat every brief with care. If something is worth making, it is worth making properly.</p>
</div>
<div data-stat-slider>
<div data-stat-track class="no-scrollbar grid snap-x snap-mandatory auto-cols-[85%] grid-flow-col gap-5 overflow-x-auto sm:auto-cols-auto sm:grid-flow-row sm:grid-cols-2">
<% stats.each_with_index do |stat, index| %>
<article class="<%= stat[:bg] %> flex min-h-[300px] snap-start flex-col justify-between p-5 md:min-h-[330px] <%= stat[:wide] ? 'sm:col-start-2' : '' %>" data-reveal style="--reveal-delay: <%= index * 120 %>ms">
<div class="flex items-start justify-between gap-4">
<h3 class="max-w-[12ch] font-mono text-xl uppercase leading-tight md:text-2xl"><%= stat[:label] %></h3>
<span class="inline-flex h-12 w-12 shrink-0 items-center justify-center rounded-full bg-night text-white"><i class="fa-solid <%= stat[:icon] %>"></i></span>
</div>
<p class="font-display text-8xl leading-none md:text-[120px]"><span data-count-to="<%= stat[:value] %>"><%= stat[:value] %></span><span class="text-6xl"><%= stat[:suffix] %></span></p>
</article>
<% end %>
</div>
<div class="mt-8 flex justify-end gap-2" data-stat-dots>
<% stats.each_with_index do |_, index| %>
<button type="button" data-stat-dot="<%= index %>" aria-label="Show stat <%= index + 1 %>" aria-current="<%= index.zero? %>" class="h-1.5 w-7 rounded-full bg-night/15 transition-all aria-[current=true]:w-14 aria-[current=true]:bg-night"></button>
<% end %>
</div>
</div>
</div>
</section>
<!-- block:end stats -->
<!-- block:start gallery -->
<section id="work" class="bg-night py-20 md:py-28" data-case-slider>
<div class="mx-auto max-w-[1440px] px-5 text-center md:px-20">
<h2 class="mx-auto max-w-[16ch] font-display text-6xl leading-[0.9] md:text-8xl lg:text-[104px]">Shaping the next wave of consumer brands</h2>
<p class="mx-auto mt-6 max-w-2xl font-light text-white/60">We help brands grow faster with sharp strategy and digital experiences people remember.</p>
</div>
<div class="mx-auto mt-14 flex max-w-[1440px] justify-end gap-3 px-5 md:px-20">
<button type="button" data-case-prev class="inline-flex h-12 w-12 items-center justify-center rounded-full border border-white/20 transition hover:bg-white hover:text-night" aria-label="Previous case study"><i class="fa-solid fa-arrow-left"></i></button>
<button type="button" data-case-next class="inline-flex h-12 w-12 items-center justify-center rounded-full bg-lime text-night transition hover:bg-white" aria-label="Next case study"><i class="fa-solid fa-arrow-right"></i></button>
</div>
<div data-case-track class="no-scrollbar mt-6 flex snap-x snap-mandatory gap-6 overflow-x-auto scroll-smooth px-5 md:gap-10 md:px-6">
<% cases.each do |item| %>
<article class="group grid w-[88%] shrink-0 snap-start gap-5 sm:w-[600px] sm:grid-cols-2">
<a href="<%= item[:slug] %>.html" class="block aspect-[289/366] overflow-hidden bg-white/5">
<img src="<%= item[:image] %>" alt="<%= item[:alt] %>" loading="lazy" class="h-full w-full object-cover transition duration-700 group-hover:scale-105">
</a>
<div class="flex flex-col justify-between gap-6">
<span class="w-fit rounded-full bg-white/10 px-3 py-1.5 font-mono text-xs uppercase text-white/80"><%= item[:tag] %></span>
<div>
<h3 class="font-display text-4xl"><a href="<%= item[:slug] %>.html" class="hover:text-lime"><%= item[:name] %></a></h3>
<p class="mt-3 text-sm font-light leading-relaxed text-white/80"><%= item[:text] %></p>
<a href="<%= item[:slug] %>.html" class="mt-4 inline-flex items-center gap-2 font-mono text-xs uppercase text-lime">View case <i class="fa-solid fa-arrow-right"></i></a>
</div>
</div>
</article>
<% end %>
</div>
</section>
<!-- block:end gallery -->
<!-- block:start pricing -->
<section id="pricing" class="bg-gradient-to-b from-night via-[#231a7a] to-royal px-5 pb-24 pt-10 md:px-20 md:pb-32">
<div class="mx-auto max-w-[1440px]">
<div class="text-center">
<h2 class="mx-auto max-w-[14ch] font-display text-6xl leading-[0.9] md:text-8xl lg:text-[104px]">Flexible pricing for bold ideas</h2>
<p class="mx-auto mt-6 max-w-md font-light text-white/70">Pick the plan that fits your stage, with room to scale as your brand grows.</p>
</div>
<div class="mx-auto mt-16 grid max-w-[1160px] gap-6 md:grid-cols-3">
<% plans.each_with_index do |plan, index| %>
<article class="relative flex flex-col p-8 text-night <%= plan[:featured] ? 'bg-[#b8b0ff]' : 'bg-white' %>" data-reveal style="--reveal-delay: <%= index * 100 %>ms">
<% if plan[:featured] %><span class="absolute -top-3 right-6 rotate-6 rounded-full bg-lime px-3 py-1 text-xs font-medium shadow"><i class="fa-solid fa-fire text-coral"></i> Most popular</span><% end %>
<h3 class="text-lg font-medium"><%= plan[:name] %></h3>
<p class="mt-1 text-night/60"><%= plan[:note] %></p>
<p class="mt-5 border-b border-night/10 pb-6 text-4xl font-semibold tracking-tight"><%= plan[:price] %><span class="text-lg font-normal text-night/60"><%= plan[:unit] %></span></p>
<ul class="mt-6 flex-1 space-y-3 text-night/70">
<% plan[:features].each do |feature| %>
<li class="flex items-center gap-3"><i class="fa-solid fa-check text-xs"></i> <%= feature %></li>
<% end %>
</ul>
<a href="contact.html" class="mt-12 rounded-full py-3.5 text-center font-medium transition <%= plan[:featured] ? 'bg-lime hover:bg-night hover:text-lime' : 'border border-night/15 hover:bg-night hover:text-white' %>"><%= plan[:cta] %></a>
</article>
<% end %>
</div>
</div>
</section>
<!-- block:end pricing -->
<!-- block:start reviews -->
<section id="reviews" data-review-slider aria-roledescription="carousel" aria-label="Client reviews">
<div class="relative overflow-hidden bg-indigo">
<div class="pointer-events-none absolute right-0 top-0 hidden h-full w-[576px] lg:block" aria-hidden="true">
<% pixels.each do |x, y, tone| %>
<span class="absolute h-16 w-16 <%= tone == 0 ? 'rounded-full bg-cream' : tone == 1 ? 'bg-cream' : 'bg-cream/40' %>" style="left: <%= x * 64 %>px; top: <%= y * 64 %>px"></span>
<% end %>
</div>
<div class="relative mx-auto max-w-[1440px] px-5 py-20 md:px-20 md:py-28 lg:px-[320px]">
<% reviews.each_with_index do |review, index| %>
<div data-review-person <%= 'hidden' unless index.zero? %>>
<img src="<%= review[:avatar] %>" alt="Portrait of <%= review[:name] %>" class="h-40 w-40 rounded-full object-cover ring-[10px] ring-royal/60">
<p class="mt-8 text-5xl font-light uppercase tracking-tight text-cream md:text-6xl"><%= review[:name] %></p>
<p class="mt-3 font-mono text-lg text-cream/90"><%= review[:role] %></p>
</div>
<% end %>
</div>
</div>
<div class="bg-cream text-royal">
<div class="mx-auto grid max-w-[1440px] gap-6 px-5 py-16 md:grid-cols-[160px_1fr] md:px-20 md:py-20 lg:px-[160px]">
<i class="fa-solid fa-quote-left text-7xl" aria-hidden="true"></i>
<div aria-live="polite">
<% reviews.each_with_index do |review, index| %>
<blockquote data-review-quote class="max-w-[24ch] text-3xl leading-tight md:text-5xl" <%= 'hidden' unless index.zero? %>><%= review[:quote] %>”</blockquote>
<% end %>
<div class="mt-12 flex gap-4">
<button type="button" data-review-prev class="inline-flex h-12 w-12 items-center justify-center rounded-full bg-indigo text-white transition hover:bg-royal" aria-label="Previous review"><i class="fa-solid fa-arrow-left"></i></button>
<button type="button" data-review-next class="inline-flex h-12 w-12 items-center justify-center rounded-full bg-indigo text-white transition hover:bg-royal" aria-label="Next review"><i class="fa-solid fa-arrow-right"></i></button>
</div>
</div>
</div>
</div>
</section>
<!-- block:end reviews -->
</main>
<!-- block:start footer -->
<footer id="footer" class="bg-[#04021a]">
<div class="mx-auto max-w-[1440px] px-5 md:px-20">
<div class="flex flex-col gap-8 border-b border-white/10 py-16 md:flex-row md:items-end md:justify-between">
<p class="max-w-[22ch] font-display text-5xl leading-[1.02] md:text-6xl">Sharp strategy and bold design <span class="text-white/30">made to bring your brand vision to life</span></p>
<ul class="space-y-2 font-mono text-sm uppercase md:text-right">
<li><a href="mailto:hello@northline.studio" class="hover:text-lime">hello@northline.studio</a></li>
<li><a href="tel:+13125550188" class="hover:text-lime">(+1) 312 555 0188</a></li>
<li>Chicago 220, United States</li>
</ul>
</div>
<div class="grid gap-12 py-16 md:grid-cols-2 lg:grid-cols-12">
<div class="font-mono text-sm uppercase lg:col-span-3">
<h2 class="text-white/40">Services</h2>
<ul class="mt-5 space-y-3">
<li><a href="services.html#branding" class="hover:text-lime">Brand strategy</a></li>
<li><a href="services.html#product" class="hover:text-lime">UI/UX design</a></li>
<li><a href="services.html#web" class="hover:text-lime">Web development</a></li>
<li><a href="services.html#growth" class="hover:text-lime">Digital marketing</a></li>
</ul>
</div>
<div class="font-mono text-sm uppercase lg:col-span-3">
<h2 class="text-white/40">Support</h2>
<ul class="mt-5 space-y-3">
<li><a href="contact.html" class="hover:text-lime">Contact us</a></li>
<li><a href="contact.html#faq" class="hover:text-lime">FAQs</a></li>
<li><a href="index.html#pricing" class="hover:text-lime">Pricing & packages</a></li>
<li><a href="reviews.html" class="hover:text-lime">Client reviews</a></li>
</ul>
</div>
<div class="font-mono text-sm uppercase lg:col-span-2">
<h2 class="text-white/40">Social</h2>
<ul class="mt-5 flex gap-2">
<% [["facebook-f", "Facebook", "https://www.facebook.com/"], ["instagram", "Instagram", "https://www.instagram.com/"], ["twitter", "Twitter", "https://twitter.com/"], ["linkedin-in", "LinkedIn", "https://www.linkedin.com/"]].each do |icon, label, href| %>
<li><a href="<%= href %>" class="inline-flex h-10 w-10 items-center justify-center rounded-lg bg-white/5 transition hover:bg-lime hover:text-night" aria-label="<%= label %>"><i class="fa-brands fa-<%= icon %>"></i></a></li>
<% end %>
</ul>
</div>
<div class="md:col-span-2 lg:col-span-4">
<h2 class="font-display text-6xl leading-none">Join the list</h2>
<p class="mt-3 font-mono text-sm uppercase leading-relaxed">Fresh insights and studio news, once a month.</p>
<form data-newsletter class="mt-6 space-y-4">
<label for="footer-email" class="sr-only">Your email</label>
<input id="footer-email" type="email" required placeholder="YOUR EMAIL" class="w-full rounded-md bg-white/15 px-4 py-3 font-mono text-sm uppercase outline-none placeholder:text-white/50 focus:ring-2 focus:ring-lime">
<button type="submit" class="inline-flex items-center gap-2 rounded-full bg-white px-6 py-3 font-mono text-sm uppercase text-night transition hover:bg-lime">Subscribe <i class="fa-solid fa-arrow-right"></i></button>
<p data-newsletter-note hidden class="font-mono text-sm uppercase text-lime" role="status">You're on the list.</p>
</form>
</div>
</div>
<div class="flex flex-col gap-4 border-t border-white/10 py-8 font-mono text-sm uppercase sm:flex-row sm:justify-between">
<p>© 2026 Northline. All rights reserved</p>
<p class="flex gap-6"><a href="contact.html" class="hover:text-lime">Terms & conditions</a><span aria-hidden="true">|</span><a href="contact.html" class="hover:text-lime">Privacy policy</a></p>
</div>
</div>
</footer>
<!-- block:end footer -->
<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-stat-slider]").forEach((slider) => {
const track = slider.querySelector("[data-stat-track]");
const dots = [...slider.querySelectorAll("[data-stat-dot]")];
const cards = [...track.children];
const mark = (active) => dots.forEach((dot, i) => dot.setAttribute("aria-current", String(i === active)));
dots.forEach((dot, i) => dot.addEventListener("click", () => {
mark(i);
cards[i].animate([{ transform: "scale(1)" }, { transform: "scale(1.03)" }, { transform: "scale(1)" }], { duration: 400 });
if (track.scrollWidth > track.clientWidth) track.scrollTo({ left: cards[i].offsetLeft - track.offsetLeft, behavior: "smooth" });
}));
track.addEventListener("scroll", () => {
const index = Math.round(track.scrollLeft / (cards[0].offsetWidth || 1));
mark(Math.min(index, cards.length - 1));
}, { passive: true });
});
document.querySelectorAll("[data-case-slider]").forEach((slider) => {
const track = slider.querySelector("[data-case-track]");
const step = () => (track.firstElementChild?.offsetWidth || 400) + 40;
const move = (direction) => {
const max = track.scrollWidth - track.clientWidth - 4;
if (direction > 0 && track.scrollLeft >= max) return track.scrollTo({ left: 0 });
if (direction < 0 && track.scrollLeft <= 4) return track.scrollTo({ left: track.scrollWidth });
track.scrollBy({ left: direction * step() });
};
slider.querySelector("[data-case-prev]")?.addEventListener("click", () => move(-1));
slider.querySelector("[data-case-next]")?.addEventListener("click", () => move(1));
});
document.querySelectorAll("[data-review-slider]").forEach((slider) => {
const people = [...slider.querySelectorAll("[data-review-person]")];
const quotes = [...slider.querySelectorAll("[data-review-quote]")];
let index = 0;
const show = (next) => {
index = (next + quotes.length) % quotes.length;
people.forEach((item, i) => { item.hidden = i !== index; });
quotes.forEach((item, i) => { item.hidden = i !== index; });
};
slider.querySelector("[data-review-prev]")?.addEventListener("click", () => show(index - 1));
slider.querySelector("[data-review-next]")?.addEventListener("click", () => show(index + 1));
});
document.querySelectorAll("[data-newsletter]").forEach((form) => {
form.addEventListener("submit", (event) => {
event.preventDefault();
const note = form.querySelector("[data-newsletter-note]");
if (note) note.hidden = false;
form.reset();
});
});
(() => {
const counters = document.querySelectorAll("[data-count-to]");
if (!counters.length || navigator.webdriver || matchMedia("(prefers-reduced-motion: reduce)").matches || !("IntersectionObserver" in window)) return;
const observer = new IntersectionObserver((entries) => {
entries.forEach(({ isIntersecting, target }) => {
if (!isIntersecting) return;
observer.unobserve(target);
const end = Number(target.dataset.countTo);
const start = performance.now();
const tick = (now) => {
const progress = Math.min((now - start) / 1200, 1);
target.textContent = Math.round(end * progress).toLocaleString();
if (progress < 1) requestAnimationFrame(tick);
};
requestAnimationFrame(tick);
});
});
counters.forEach((counter) => observer.observe(counter));
})();
(() => {
const items = document.querySelectorAll("[data-reveal]");
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>
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