This our services section HTML CSS JS tutorial shows you how to build a dark-themed services list with a hover and click accordion. Each service item expands to reveal a description on hover for desktop users and on tap for touch devices. The section also includes a stats block, a label row with a stretching rule line, and a large heading that scales with the screen size.
Final output:
Services
Naming, visual systems, brand voice, the connective tissue that makes companies recognizable across every touchpoint, from pitch deck to packaging.
Zero-to-one product thinking through to flow refinement. Interfaces that convert because they actually make sense to the people using them.
Production-grade frontend and full-stack. We write code that ships, scales, and won’t embarrass you six months into production.
Animation that earns its frame time — micro-interactions, campaign films, and product demos that communicate without a single word.
Editorial strategy, CMS design, and content operations for teams publishing at scale without losing coherence or momentum.
Steps for Services section with accordion HTML CSS JS:
1. Let’s start with a section element with the class section-services. Inside it, add a .services-wrapper div with a .services-header and a .services-content-wrapper div inside it.
<section class="section-services">
<div class="services-wrapper">
<div class="services-header"></div>
<div class="services-content-wrapper"></div>
</div>
</section>
I’ll be using Unbounded and DM Mono fonts from Google Fonts; link your fonts in the head.
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=DM+Mono:ital,wght@0,300;0,400;0,500;1,300;1,400;1,500&family=Unbounded:wght@200..900&display=swap" rel="stylesheet">
Reset margins, set Unbounded as the font family, and give the section a near-black background with some padding. Define the lime green color as a CSS variable on the section so it can be reused throughout. Center the .services-wrapper with the inline margin set to auto and a max-width.
* {
margin: 0;
box-sizing: border-box;
}
:root{
--lime: #C4F000;
}
body {
font-family: "Unbounded", sans-serif;
}
.section-services {
padding: 5rem 5%;
background-color: #080808;
color: hsl(0, 0%, 50%);
}
.section-services .services-wrapper {
max-width: 67rem;
margin-inline: auto;
}
2. Fill in .services-header with a top row div containing the label, a rule, and a discipline count. Then add the heading and a .services-stats-wrapper with three stat blocks below it.
<div class="services-header">
<div>
<span class="services-label">What We Do</span>
<span class="rule"></span>
<span>06 disciplines</span>
</div>
<h2>Services</h2>
<div class="services-stats-wrapper">
<div class="services-stats-block">
<span class="stats">12 <span>yrs</span></span>
<span class="stats-label">In practice</span>
</div>
<div class="services-stats-block">
<span class="stats">200<span>+</span></span>
<span class="stats-label">Projects shipped</span>
</div>
<div class="services-stats-block">
<span class="stats">60<span>+</span></span>
<span class="stats-label">Clients served</span>
</div>
</div>
</div>
Use flexbox with the flex direction set to column and a gap to stack the header elements. For the top row, use flexbox with the items centered and the justify content set to space-between to push the label and discipline count to opposite ends. The .rule is an empty span that acts as a horizontal line; give it a flex value of 1 so it stretches to fill the remaining space between the two text elements.
.section-services .services-header {
display: flex;
flex-direction: column;
gap: 2.5rem;
}
.section-services .services-header > div:first-child {
display: flex;
gap: 1rem;
align-items: center;
justify-content: space-between;
}
.section-services .services-header > div:first-child span {
font-family: "DM Mono", monospace;
font-size: .75rem;
line-height: 1.2;
letter-spacing: 2.42px;
color: hsl(0, 0%, 50%);
}
.section-services .services-label {
color: var(--lime);
text-transform: uppercase;
}
.section-services .rule {
flex: 1;
height: 1px;
background-color: hsl(0, 0%, 40%);
}
Output:
Services
3. Style the heading with a heavy font weight and a large font size using clamp() so it scales smoothly between screen sizes. Use a tight line height and a large negative letter spacing to make the big text feel more compact.
.section-services .services-header h2 {
font-weight: 900;
font-size: clamp(3rem, calc(10vw + 1rem), 7rem);
line-height: 1;
letter-spacing: -2.8px;
color: #FFFFFF;
}
Style .services-stats-wrapper with a border around it. On screens wider than 576px, switch to a three-column grid layout. On mobile, the blocks stack vertically and use a bottom border instead of a right border to divide them. The stat number gets white and bold with the suffix colored lime, and the label uses DM Mono in uppercase.
.section-services .services-stats-wrapper {
border: 1px solid hsl(0, 0%, 20%);
}
@media screen and (min-width: 577px) {
.section-services .services-stats-wrapper {
display: grid;
grid-template-columns: repeat(3, 1fr);
}
}
.section-services .services-stats-block {
padding: 1.25rem;
display: flex;
flex-direction: column;
gap: .5rem;
}
.section-services .services-stats-block:not(:last-child) {
border-right: 1px solid hsl(0, 0%, 20%);
}
@media screen and (max-width: 576px) {
.section-services .services-stats-block:not(:last-child) {
border-right: none;
border-bottom: 1px solid hsl(0, 0%, 20%);
}
}
.section-services .stats {
font-weight: 900;
font-size: 1.875rem;
line-height: 1;
color: #FFFFFF;
}
.section-services .stats span {
color: var(--lime);
}
.section-services .stats-label {
font-family: "DM Mono", monospace;
font-size: .75rem;
line-height: 1.2;
letter-spacing: 1.1px;
text-transform: uppercase;
}
Output:
Services
4. Now add the service items inside .services-content-wrapper. Each .services-item has a .services-item-header with the number, title, tags, meta info, and an arrow icon. Below the header, add a .services-item-description with a description paragraph inside a wrapper div. The extra wrapper div is needed for the smooth open/close animation later.
<div class="services-content-wrapper">
<div class="services-item">
<div class="services-item-header">
<span class="num">01</span>
<span class="title">Brand Strategy & Identity</span>
<div class="services-tags">
<span class="services-tag">IDENTITY</span>
<span class="services-tag">POSITIONING</span>
<span class="services-tag">GUIDELINES</span>
</div>
<div class="services-meta">
<div class="category">BRANDING</div>
<div class="stat">47 brands</div>
</div>
<span class="arrow">
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M5.25 5.25H12.75V12.75" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
<path d="M5.25 12.75L12.75 5.25" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
</svg>
</span>
</div>
<div class="services-item-description">
<div>
<p>Naming, visual systems, brand voice, the connective tissue that makes companies recognizable across every touchpoint.</p>
</div>
</div>
</div>
<!-- add more items -->
</div>
Style .services-content-wrapper with a top border. Give each .services-item a bottom border, some padding, and set the position to relative so the lime green indicator line can be placed inside it using absolute positioning. The ::before pseudo-element creates that line on the left edge. It starts scaled to zero on the vertical axis and transitions to full height when the item gets the active class.
.section-services .services-content-wrapper {
margin-top: 3.75rem;
border-top: 1px solid hsl(0, 0%, 20%);
}
.section-services .services-item {
border-bottom: 1px solid hsl(0, 0%, 20%);
padding: 2rem 2rem 2rem 1.5rem;
position: relative;
}
.section-services .services-item::before {
content: "";
position: absolute;
left: 0;
top: 0;
bottom: 0;
width: 2px;
background: var(--lime);
transform: scaleY(0);
transform-origin: top center;
transition: transform 0.38s cubic-bezier(0.22, 1, 0.36, 1);
}
.section-services .services-item.active::before {
transform: scaleY(1);
}
Output:
Services
Naming, visual systems, brand voice, the connective tissue that makes companies recognizable across every touchpoint, from pitch deck to packaging.
Zero-to-one product thinking through to flow refinement. Interfaces that convert because they actually make sense to the people using them.
Production-grade frontend and full-stack. We write code that ships, scales, and won’t embarrass you six months into production.
Animation that earns its frame time — micro-interactions, campaign films, and product demos that communicate without a single word.
Editorial strategy, CMS design, and content operations for teams publishing at scale without losing coherence or momentum.
5. Style the header row. Use flexbox with the items centered and a gap to lay out the number, title, tags, meta, and arrow in a row. Use clamp() on the title font size so it scales with the screen. Hide the tags and meta on mobile since they’d make the row too crowded on smaller screens. Push the meta to the right by setting the left margin to auto on it. On mobile, also set the left margin on the arrow to auto so it pushes to the right edge instead.
.section-services .services-item-header {
display: flex;
align-items: center;
gap: 1rem;
}
.section-services .num {
color: hsl(0, 0%, 30%);
font-size: 0.85rem;
width: 30px;
}
.section-services .title {
font-weight: 700;
font-size: clamp(1rem, 1vw, 1.375rem);
line-height: 1.27;
color: #fff;
}
.section-services .services-tags {
display: flex;
gap: .5rem;
flex-wrap: wrap;
}
@media screen and (max-width: 768px) {
.section-services .services-tags {
display: none;
}
}
.section-services .services-tag {
font-size: 0.7rem;
color: hsl(0, 0%, 50%);
border: 1px solid hsl(0, 0%, 20%);
padding: 0.125rem 0.625rem;
border-radius: .25rem;
font-family: "DM Mono", monospace;
line-height: 1.3;
letter-spacing: 0.25px;
text-transform: uppercase;
}
.section-services .services-meta {
margin-left: auto;
text-align: right;
flex-shrink: 0;
}
@media screen and (max-width: 768px) {
.section-services .services-meta {
display: none;
}
}
.section-services .category {
font-size: 0.75rem;
color: hsl(0, 0%, 50%);
letter-spacing: 1px;
text-transform: uppercase;
}
.section-services .stat {
font-size: 0.8rem;
color: var(--lime);
margin-top: .25rem;
}
Output:
Services
Naming, visual systems, brand voice, the connective tissue that makes companies recognizable across every touchpoint, from pitch deck to packaging.
Zero-to-one product thinking through to flow refinement. Interfaces that convert because they actually make sense to the people using them.
Production-grade frontend and full-stack. We write code that ships, scales, and won’t embarrass you six months into production.
Animation that earns its frame time — micro-interactions, campaign films, and product demos that communicate without a single word.
Editorial strategy, CMS design, and content operations for teams publishing at scale without losing coherence or momentum.
6. Style the arrow icon and add a transform on the active state to move it diagonally, hinting that the item is now open. On mobile, set the left margin on the arrow to auto so it pushes to the right edge of the row. Then style .services-item-description using the same grid-template-rows trick from the FAQ Section post to animate the height smoothly from zero to its natural size.
.section-services .arrow {
color: hsl(0, 0%, 50%);
margin-left: 2.5rem;
transition: transform .3s ease;
}
@media screen and (max-width: 768px) {
.section-services .arrow {
margin-left: auto;
}
}
.section-services .services-item.active .arrow {
transform: translate(.5rem, -.5rem);
}
.section-services .services-item-description {
display: grid;
grid-template-rows: 0fr;
transition: grid-template-rows 0.3s ease;
margin-left: 3rem;
}
.section-services .services-item.active .services-item-description {
grid-template-rows: 1fr;
}
.section-services .services-item-description > div {
overflow: hidden;
}
.section-services .services-item-description p {
margin-top: .75rem;
color: #F5F0E873;
font-size: 0.875rem;
font-family: "DM Mono", monospace;
line-height: 1.5;
max-width: 600px;
font-weight: 300;
}
Output:
Services
Naming, visual systems, brand voice, the connective tissue that makes companies recognizable across every touchpoint, from pitch deck to packaging.
Zero-to-one product thinking through to flow refinement. Interfaces that convert because they actually make sense to the people using them.
Production-grade frontend and full-stack. We write code that ships, scales, and won’t embarrass you six months into production.
Animation that earns its frame time — micro-interactions, campaign films, and product demos that communicate without a single word.
Editorial strategy, CMS design, and content operations for teams publishing at scale without losing coherence or momentum.
7. Now for the JavaScript. Add a script.js file and link it before the closing body tag. Wait for the page to load using DOMContentLoaded. Then check if the user’s device supports hover using matchMedia. This is important because on touch devices there’s no real hover state, so we only want the mouseenter and mouseleave events to fire on devices that actually have a mouse or trackpad.t.
document.addEventListener("DOMContentLoaded", () => {
const canHover = matchMedia('(hover: hover) and (pointer: fine)').matches;
});
Loop through all .services-item elements. If the device supports hover, add mouseenter and mouseleave listeners to add and remove the active class as the user moves their mouse in and out. Then add a click listener on every device that toggles the active class, so touch users can still tap to open and close each item.
document.querySelectorAll('.services-item').forEach(item => {
if (canHover) {
item.addEventListener('mouseenter', () => item.classList.add('active'));
item.addEventListener('mouseleave', () => item.classList.remove('active'));
}
item.addEventListener('click', () => item.classList.toggle('active'));
});
Output:
Services
Naming, visual systems, brand voice, the connective tissue that makes companies recognizable across every touchpoint, from pitch deck to packaging.
Zero-to-one product thinking through to flow refinement. Interfaces that convert because they actually make sense to the people using them.
Production-grade frontend and full-stack. We write code that ships, scales, and won’t embarrass you six months into production.
Animation that earns its frame time — micro-interactions, campaign films, and product demos that communicate without a single word.
Editorial strategy, CMS design, and content operations for teams publishing at scale without losing coherence or momentum.
Final Output Code for Our Services Section HTML CSS JavaScript:
Head
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=DM+Mono:ital,wght@0,300;0,400;0,500;1,300;1,400;1,500&family=Unbounded:wght@200..900&display=swap" rel="stylesheet">
HTML
<section class="section-services">
<div class="services-wrapper">
<div class="services-header">
<div>
<span class="services-label">What We Do</span>
<span class="rule"></span>
<span>06 disciplines</span>
</div>
<h2>Services</h2>
<div class="services-stats-wrapper">
<div class="services-stats-block">
<span class="stats">12 <span>yrs</span></span>
<span class="stats-label">In practice</span>
</div>
<div class="services-stats-block">
<span class="stats">200<span>+</span></span>
<span class="stats-label">Projects shipped</span>
</div>
<div class="services-stats-block">
<span class="stats">60<span>+</span></span>
<span class="stats-label">Clients served</span>
</div>
</div>
</div>
<div class="services-content-wrapper">
<div class="services-item">
<div class="services-item-header">
<span class="num">01</span>
<span class="title">Brand Strategy & Identity</span>
<div class="services-tags">
<span class="services-tag">IDENTITY</span>
<span class="services-tag">POSITIONING</span>
<span class="services-tag">GUIDELINES</span>
</div>
<div class="services-meta">
<div class="category">BRANDING</div>
<div class="stat">47 brands</div>
</div>
<span class="arrow">
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M5.25 5.25H12.75V12.75" stroke="currentColor" stroke-width="1.5"
stroke-linecap="round" stroke-linejoin="round" />
<path d="M5.25 12.75L12.75 5.25" stroke="currentColor" stroke-width="1.5"
stroke-linecap="round" stroke-linejoin="round" />
</svg>
</span>
</div>
<div class="services-item-description">
<div>
<p>Naming, visual systems, brand voice, the connective tissue that makes companies
recognizable
across every touchpoint, from pitch deck to packaging.</p>
</div>
</div>
</div>
<div class="services-item">
<div class="services-item-header">
<span class="num">02</span>
<span class="title">Digital Product Design</span>
<div class="services-tags">
<span class="services-tag">UX Research</span>
<span class="services-tag">Prototyping</span>
<span class="services-tag">Design Systems</span>
</div>
<div class="services-meta">
<div class="category">UX / UI</div>
<div class="stat">12 products</div>
</div>
<span class="arrow">
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M5.25 5.25H12.75V12.75" stroke="currentColor" stroke-width="1.5"
stroke-linecap="round" stroke-linejoin="round" />
<path d="M5.25 12.75L12.75 5.25" stroke="currentColor" stroke-width="1.5"
stroke-linecap="round" stroke-linejoin="round" />
</svg>
</span>
</div>
<div class="services-item-description">
<div>
<p>Zero-to-one product thinking through to flow refinement. Interfaces that convert because
they actually make sense to the people using them.</p>
</div>
</div>
</div>
<div class="services-item">
<div class="services-item-header">
<span class="num">03</span>
<span class="title">Web Engineering</span>
<div class="services-tags">
<span class="services-tag">React</span>
<span class="services-tag">Next.js</span>
<span class="services-tag">Performance</span>
</div>
<div class="services-meta">
<div class="category">Dev</div>
<div class="stat">200+ sites</div>
</div>
<span class="arrow">
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M5.25 5.25H12.75V12.75" stroke="currentColor" stroke-width="1.5"
stroke-linecap="round" stroke-linejoin="round" />
<path d="M5.25 12.75L12.75 5.25" stroke="currentColor" stroke-width="1.5"
stroke-linecap="round" stroke-linejoin="round" />
</svg>
</span>
</div>
<div class="services-item-description">
<div>
<p>Production-grade frontend and full-stack. We write code that ships, scales, and won't
embarrass you six months into production.
</p>
</div>
</div>
</div>
<div class="services-item">
<div class="services-item-header">
<span class="num">04</span>
<span class="title">Motion & Creative Direction</span>
<div class="services-tags">
<span class="services-tag">After Effects</span>
<span class="services-tag">3D</span>
<span class="services-tag">Interaction</span>
</div>
<div class="services-meta">
<div class="category">Motion</div>
<div class="stat">88 films</div>
</div>
<span class="arrow">
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M5.25 5.25H12.75V12.75" stroke="currentColor" stroke-width="1.5"
stroke-linecap="round" stroke-linejoin="round" />
<path d="M5.25 12.75L12.75 5.25" stroke="currentColor" stroke-width="1.5"
stroke-linecap="round" stroke-linejoin="round" />
</svg>
</span>
</div>
<div class="services-item-description">
<div>
<p>Animation that earns its frame time — micro-interactions, campaign films, and product
demos that communicate without a single word.
</p>
</div>
</div>
</div>
<div class="services-item">
<div class="services-item-header">
<span class="num">05</span>
<span class="title">Content Architecture</span>
<div class="services-tags">
<span class="services-tag">Editorial</span>
<span class="services-tag">CMS Strategy</span>
<span class="services-tag">OPS</span>
</div>
<div class="services-meta">
<div class="category">Content</div>
<div class="stat">60 publishers</div>
</div>
<span class="arrow">
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M5.25 5.25H12.75V12.75" stroke="currentColor" stroke-width="1.5"
stroke-linecap="round" stroke-linejoin="round" />
<path d="M5.25 12.75L12.75 5.25" stroke="currentColor" stroke-width="1.5"
stroke-linecap="round" stroke-linejoin="round" />
</svg>
</span>
</div>
<div class="services-item-description">
<div>
<p>Editorial strategy, CMS design, and content operations for teams publishing at scale
without losing coherence or momentum.
</p>
</div>
</div>
</div>
</div>
</div>
</section>
CSS
* {
margin: 0;
box-sizing: border-box;
}
body {
font-family: "Unbounded", sans-serif;
}
:root{
--lime: #C4F000;
}
.section-services {
padding: 5rem 5%;
background-color: #080808;
color: hsl(0, 0%, 50%);
}
.section-services .services-wrapper {
max-width: 67rem;
margin-inline: auto;
}
.section-services .services-header {
display: flex;
flex-direction: column;
gap: 2.5rem;
}
.section-services .services-header > div:first-child {
display: flex;
gap: 1rem;
align-items: center;
justify-content: space-between;
}
.section-services .services-header > div:first-child span {
font-family: "DM Mono", monospace;
font-size: .75rem;
line-height: 1.2;
letter-spacing: 2.42px;
color: hsl(0, 0%, 50%);
}
.section-services .services-label {
color: var(--lime);
text-transform: uppercase;
}
.section-services .rule {
flex: 1;
height: 1px;
background-color: hsl(0, 0%, 40%);
}
.section-services .services-header h2 {
font-weight: 900;
font-size: clamp(3rem, calc(10vw + 1rem), 7rem);
line-height: 1;
letter-spacing: -2.8px;
color: #FFFFFF;
}
.section-services .services-stats-wrapper {
border: 1px solid hsl(0, 0%, 20%);
}
@media screen and (min-width: 577px) {
.section-services .services-stats-wrapper {
display: grid;
grid-template-columns: repeat(3, 1fr);
}
}
.section-services .services-stats-block {
padding: 1.25rem;
display: flex;
flex-direction: column;
gap: .5rem;
}
.section-services .services-stats-block:not(:last-child) {
border-right: 1px solid hsl(0, 0%, 20%);
}
@media screen and (max-width: 576px) {
.section-services .services-stats-block:not(:last-child) {
border-right: none;
border-bottom: 1px solid hsl(0, 0%, 20%);
}
}
.section-services .stats {
font-weight: 900;
font-size: 1.875rem;
line-height: 1;
color: #FFFFFF;
}
.section-services .stats span {
color: var(--lime);
}
.section-services .stats-label {
font-family: "DM Mono", monospace;
font-size: .75rem;
line-height: 1.2;
letter-spacing: 1.1px;
text-transform: uppercase;
}
.section-services .services-content-wrapper {
margin-top: 3.75rem;
border-top: 1px solid hsl(0, 0%, 20%);
}
.section-services .services-item {
border-bottom: 1px solid hsl(0, 0%, 20%);
padding: 2rem 2rem 2rem 1.5rem;
position: relative;
}
.section-services .services-item::before {
content: "";
position: absolute;
left: 0;
top: 0;
bottom: 0;
width: 2px;
background: var(--lime);
transform: scaleY(0);
transform-origin: top center;
transition: transform 0.38s cubic-bezier(0.22, 1, 0.36, 1);
}
.section-services .services-item.active::before {
transform: scaleY(1);
}
.section-services .services-item-header {
display: flex;
align-items: center;
gap: 1rem;
}
.section-services .num {
color: hsl(0, 0%, 30%);
font-size: 0.85rem;
width: 30px;
}
.section-services .title {
font-weight: 700;
font-size: clamp(1rem, 1vw, 1.375rem);
line-height: 1.27;
color: #fff;
}
.section-services .services-tags {
display: flex;
gap: .5rem;
flex-wrap: wrap;
}
@media screen and (max-width: 768px) {
.section-services .services-tags {
display: none;
}
}
.section-services .services-tag {
font-size: 0.7rem;
color: hsl(0, 0%, 50%);
border: 1px solid hsl(0, 0%, 20%);
padding: 0.125rem 0.625rem;
border-radius: .25rem;
font-family: "DM Mono", monospace;
line-height: 1.3;
letter-spacing: 0.25px;
text-transform: uppercase;
}
.section-services .services-meta {
margin-left: auto;
text-align: right;
flex-shrink: 0;
}
@media screen and (max-width: 768px) {
.section-services .services-meta {
display: none;
}
}
.section-services .category {
font-size: 0.75rem;
color: hsl(0, 0%, 50%);
letter-spacing: 1px;
text-transform: uppercase;
}
.section-services .stat {
font-size: 0.8rem;
color: var(--lime);
margin-top: .25rem;
}
.section-services .arrow {
color: hsl(0, 0%, 50%);
margin-left: 2.5rem;
transition: transform .3s ease;
}
@media screen and (max-width: 768px) {
.section-services .arrow {
margin-left: auto;
}
}
.section-services .services-item.active .arrow {
transform: translate(.5rem, -.5rem);
}
.section-services .services-item-description {
display: grid;
grid-template-rows: 0fr;
transition: grid-template-rows 0.3s ease;
margin-left: 3rem;
}
.section-services .services-item.active .services-item-description {
grid-template-rows: 1fr;
}
.section-services .services-item-description > div {
overflow: hidden;
}
.section-services .services-item-description p {
margin-top: .75rem;
color: #F5F0E873;
font-size: 0.875rem;
font-family: "DM Mono", monospace;
line-height: 1.5;
max-width: 600px;
font-weight: 300;
}
JS:
document.addEventListener("DOMContentLoaded", () => {
const canHover = matchMedia('(hover: hover) and (pointer: fine)').matches;
document.querySelectorAll('.services-item').forEach(item => {
if (canHover) {
item.addEventListener('mouseenter', () => item.classList.add('active'));
item.addEventListener('mouseleave', () => item.classList.remove('active'));
}
item.addEventListener('click', () => item.classList.toggle('active'));
});
});
If you have any doubts or stuck somewhere, you can reach out through Coding Yaar's Discord server.