Services Grid
A three-column grid of services, each an icon, a title and a line of copy.
6 frameworksBeginner
Service cards that lift and reveal a call to action on hover and on focus.
<!--
The whole card is one link, not a card containing a link: that keeps it a
single tab stop and gives the hover target and the click target the same
bounds. Which is also why the reveal is driven by :hover AND :focus-visible on
that link - a card whose call to action only exists under a cursor is a card a
keyboard user never learns is clickable.
The CTA row is aria-hidden and the link carries the real accessible name, so
the affordance stays decorative rather than announcing "Learn more" with no
hint of what about.
-->
<ul class="svc-hover">
<li>
<a class="svc-hover__card" href="/services/discovery">
<span class="svc-hover__icon" aria-hidden="true">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" focusable="false">
<circle cx="11" cy="11" r="7" /><path d="m20 20-3.5-3.5" />
</svg>
</span>
<h3 class="svc-hover__title">Discovery sprint</h3>
<p class="svc-hover__copy">Two weeks to turn a wish list into a scoped, costed plan.</p>
<span class="svc-hover__cta" aria-hidden="true">
Learn more
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" focusable="false">
<path d="M5 12h14" /><path d="m12 5 7 7-7 7" />
</svg>
</span>
</a>
</li>
</ul>| Prop | Type | Default | Description |
|---|---|---|---|
kicker | string | - | Small label shown above the title. |
titlerequired | string | - | Heading text for the card. |
servicesrequired | HoverService[] | - | The services to list, each with an icon, name and summary. |
ctaLabel | string | 'Learn more' | Call-to-action button text. |
className | string | - | Additional classes merged onto the root element. |
Every `hover:` utility here has a `focus-visible:` twin, and that pairing is the whole point: a card whose call to action only exists under a cursor is a card a keyboard user never learns is clickable. The card *is* the link rather than a card containing one, which keeps it a single tab stop and gives the hover target and the click target the same bounds - and lets `group` hang off the anchor so the reveal answers `group-focus-visible` too. The reveal is `opacity`, not `display`, so the CTA row holds its space at rest and the card does not grow and shove the grid the moment a cursor touches it. Reduced motion drops the travel and keeps the fade, since the fade is the part that carries information.