What an element does when you point at it. Four opt-in classes, composable, and available to anything — a card, a button, a link, an icon. A component should never re-derive a hover; it wears one.
.mk-lift-sm · .mk-lift · .mk-lift-lg
Motion only — the element rises. Three stops, and that is the whole scale.
Transforms need a block-ish box, so pair with d-inline-block
on something inline.
Rises 2px
mk-lift-sm — hover or tab to it
Rises 4px
mk-lift — hover or tab to it
Rises 8px
mk-lift-lg — hover or tab to it
.mk-shadow-sm · .mk-shadow · .mk-shadow-lg
The shadow half — three stops, doubling like the lift scale beside it.
Drawn in ink, so it flips with the mode on its own. Every
stop is rgba(var(--bs-body-color-rgb), …), which is near-black
on a light page and near-white on a dark one — from one declaration each,
with no -light/-dark twin and no per-mode override
to keep in step. It follows the surface, not the page: inside a
dark band on a light page the ink is already re-bound, so the shadow is
already white.
A literal black shadow cannot work on a dark ground — there is nothing left to darken, and it disappears. What reads as elevation on dark is light. Opacity rises with size because a larger shadow spreads the same ink over more pixels.
Small
mk-shadow-sm — hover or tab to it
Base
mk-shadow — hover or tab to it
Large
mk-shadow-lg — hover or tab to it
.mk-highlight
The border answers in the accent — the “this one” cue, and the only one of the four that communicates rather than moves.
It needs a border it is allowed to repaint. Two ways to
lose it, both silent: an element with border: none has no
width or style for the colour to land on, and — the one that actually
catches people — Bootstrap's .border utility is a
shorthand carrying !important, so it sets
border-color too and nothing without !important
can repaint it. Give the element a real border rule. Every card in this
system does, which is why all three could drop their hand-written version.
Border answers
mk-highlight — hover or tab to it
All three — the card hover
mk-lift mk-shadow mk-highlight — hover or tab to it
.mk-nudge · .mk-nudge--back
For an inline “go” link: the trailing icon slides in the reading direction
instead of the whole element moving. Icon-library agnostic — it targets a
direct <i> or <svg> child.
--back inverts both halves, so a back-link's arrow leads the
label and still moves away from it.
class="mk-lift mk-shadow mk-highlight"
The three halves are separate because they are separately useful — a button raises without lifting, an icon nudges without either. Together they are the card hover this system had been writing out by hand in three stylesheets:
<a class="mk-feature-card mk-lift-sm mk-shadow-sm mk-highlight">…</a>
<a class="page-card mk-lift mk-shadow mk-highlight">…</a>
<article class="article-card mk-lift mk-shadow mk-highlight">…</article> @media (prefers-reduced-motion: reduce)
mk-lift and mk-nudge stand down entirely — they are
movement. mk-shadow and mk-highlight do not,
deliberately: a shadow appearing and a border changing colour are not motion,
and suppressing them would leave someone with reduced motion — and every
keyboard user, since all four fire on :focus-visible — with no
hover feedback at all.
The focus ring (--ring) is documented under
Tokens. It looks like an effect and
is not one: it is an accessibility contract, and it should never be retuned
alongside hover taste.