22 / 30
All 30 in 30 Tailwind CSS Text Hover Effects
- 01Tailwind CSS Animated Underline Hover Effect
- 02Tailwind Liquid Text Fill Hover Animation
- 03Tailwind Gradient Text Hover Effect with bg-clip-text
- 04Tailwind Animated Strikethrough Text Hover Effect
- 05Tailwind Text Swap and Flip Up Hover Effect
- 06Tailwind CSS Glitch Text Hover Effect
- 07Tailwind Neon Glow Text with Flicker Animation
- 08Tailwind Metallic Gold Shimmer Text Effect
- 09Tailwind 3D Text Pop and Lift Hover Effect
- 10Tailwind Staggered Letter Wave Hover Animation
- 11Tailwind Spotlight Text Reveal on Mouse Hover
- 12Tailwind Hover to Reveal Hidden Spoiler Text
- 13Tailwind Blur to Focus Text Hover Effect
- 14Tailwind Magnetic Hover Effect for Buttons and Text
- 15Tailwind Letter Spacing Expand on Hover (Tracking Animation)
- 16Tailwind Outline Text Stroke to Fill Hover Effect
- 17Tailwind Text Scramble and Matrix Decrypt Hover Effect
- 18Tailwind Animated Border Button Hover Effect
- 19Tailwind Elastic Rubber Band Text Hover Animation
- 20Tailwind Variable Font Weight Hover Animation
- 21Tailwind Animated Rainbow Gradient Text on Hover
- 22Tailwind 3D Perspective Tilt Text Hover Effect
- 23Tailwind Smoke Dissolve Text Hover Effect
- 24Tailwind Fire Text Effect with Heat Wave Glow
- 25Tailwind Dynamic Text Shadow that Follows the Cursor
- 26Tailwind Infinite Text Marquee that Speeds Up on Hover
- 27Tailwind Duotone Split Color Text Hover Effect
- 28Tailwind CSS Tooltip on Hover (No JavaScript)
- 29Tailwind SVG Water Ripple Distortion Text Effect
- 30Tailwind Clip-Path Text Reveal Hover Animation
Tailwind 3D Perspective Tilt Text Hover Effect
A conference wordmark that leans toward the cursor from any corner — without JavaScript. Four invisible quadrant zones are named peers (peer/tl…peer/br); the word reads peer-hover/tl:rotate-x-[11deg] peer-hover/tl:-rotate-y-[13deg] and a matching shadow that always falls away from the tilt. Keyboard focus plays a gentle sway.
Untitled UI Pro: 5,000+ React + Tailwind CSS v4 components · from $349 one-time
Untitled UI React · Affiliate link
The code
<section class="tth-22 w-full min-h-svh grid place-items-center bg-tth22-bg bg-[radial-gradient(80%_65%_at_50%_30%,var(--color-tth22-glow),var(--color-tth22-bg)_75%)] px-5 py-14 font-tth22-sans text-tth22-ink" aria-label="Perspective tilt text demo">
<div class="flex flex-col items-center gap-[clamp(18px,3.4vw,28px)] text-center">
<p class="text-[12.5px] font-extrabold uppercase tracking-[0.24em] text-tth22-mut">Pivot — the design systems summit</p>
<a id="tth22-top" href="#tth22-top" aria-label="PIVOT '26 — get tickets" class="group/tilt relative block rounded-2xl px-[clamp(20px,4vw,44px)] py-[clamp(16px,3vw,30px)] no-underline perspective-[850px] focus-visible:outline-[2.5px] focus-visible:outline-offset-4 focus-visible:outline-tth22-acc">
<i aria-hidden="true" class="peer/tl absolute left-0 top-0 z-10 size-1/2"></i><i aria-hidden="true" class="peer/tr absolute right-0 top-0 z-10 size-1/2"></i><i aria-hidden="true" class="peer/bl absolute bottom-0 left-0 z-10 size-1/2"></i><i aria-hidden="true" class="peer/br absolute bottom-0 right-0 z-10 size-1/2"></i>
<span aria-hidden="true" class="block text-[clamp(58px,13.5vw,140px)] font-black leading-none tracking-[-0.04em] [text-shadow:0_.06em_.09em_oklch(0.2_0.02_270/0.22)] transition-[transform,text-shadow] duration-500 ease-[cubic-bezier(.2,.8,.25,1)] peer-hover/tl:rotate-x-[11deg] peer-hover/tl:-rotate-y-[13deg] peer-hover/tl:[text-shadow:.07em_.11em_.13em_oklch(0.2_0.02_270/0.42)] peer-hover/tr:rotate-x-[11deg] peer-hover/tr:rotate-y-[13deg] peer-hover/tr:[text-shadow:-.07em_.11em_.13em_oklch(0.2_0.02_270/0.42)] peer-hover/bl:-rotate-x-[11deg] peer-hover/bl:-rotate-y-[13deg] peer-hover/bl:[text-shadow:.07em_-.07em_.13em_oklch(0.2_0.02_270/0.4)] peer-hover/br:-rotate-x-[11deg] peer-hover/br:rotate-y-[13deg] peer-hover/br:[text-shadow:-.07em_-.07em_.13em_oklch(0.2_0.02_270/0.4)] group-focus-visible/tilt:animate-tth22-sway motion-reduce:transition-none motion-reduce:animate-none!">PIVOT<span class="text-tth22-acc">’26</span></span>
</a>
<p class="max-w-[52ch] text-[15px] leading-[1.7] text-tth22-mut">Approach the wordmark from any corner — it leans toward you. Four invisible hover quadrants, four poses, one transition blending them. No script.</p>
<p class="text-[12.5px] text-tth22-mut">The shadow always slides opposite the tilt — fixed lamp, turning object. <kbd class="rounded-[5px] border border-b-2 border-tth22-line bg-white px-1.5 py-0.5 font-tth22-mono text-[11px]">Tab</kbd> to it for the keyboard sway.</p>
</div>
</section><section class="tth-22 w-full min-h-svh grid place-items-center bg-tth22-bg bg-[radial-gradient(80%_65%_at_50%_30%,var(--color-tth22-glow),var(--color-tth22-bg)_75%)] px-5 py-14 font-tth22-sans text-tth22-ink" aria-label="Perspective tilt text demo">
<div class="flex flex-col items-center gap-[clamp(18px,3.4vw,28px)] text-center">
<p class="text-[12.5px] font-extrabold uppercase tracking-[0.24em] text-tth22-mut">Pivot — the design systems summit</p>
<a id="tth22-top" href="#tth22-top" aria-label="PIVOT '26 — get tickets" class="group/tilt relative block rounded-2xl px-[clamp(20px,4vw,44px)] py-[clamp(16px,3vw,30px)] no-underline perspective-[850px] focus-visible:outline-[2.5px] focus-visible:outline-offset-4 focus-visible:outline-tth22-acc">
<i aria-hidden="true" class="peer/tl absolute left-0 top-0 z-10 size-1/2"></i><i aria-hidden="true" class="peer/tr absolute right-0 top-0 z-10 size-1/2"></i><i aria-hidden="true" class="peer/bl absolute bottom-0 left-0 z-10 size-1/2"></i><i aria-hidden="true" class="peer/br absolute bottom-0 right-0 z-10 size-1/2"></i>
<span aria-hidden="true" class="block text-[clamp(58px,13.5vw,140px)] font-black leading-none tracking-[-0.04em] [text-shadow:0_.06em_.09em_oklch(0.2_0.02_270/0.22)] transition-[transform,text-shadow] duration-500 ease-[cubic-bezier(.2,.8,.25,1)] peer-hover/tl:rotate-x-[11deg] peer-hover/tl:-rotate-y-[13deg] peer-hover/tl:[text-shadow:.07em_.11em_.13em_oklch(0.2_0.02_270/0.42)] peer-hover/tr:rotate-x-[11deg] peer-hover/tr:rotate-y-[13deg] peer-hover/tr:[text-shadow:-.07em_.11em_.13em_oklch(0.2_0.02_270/0.42)] peer-hover/bl:-rotate-x-[11deg] peer-hover/bl:-rotate-y-[13deg] peer-hover/bl:[text-shadow:.07em_-.07em_.13em_oklch(0.2_0.02_270/0.4)] peer-hover/br:-rotate-x-[11deg] peer-hover/br:rotate-y-[13deg] peer-hover/br:[text-shadow:-.07em_-.07em_.13em_oklch(0.2_0.02_270/0.4)] group-focus-visible/tilt:animate-tth22-sway motion-reduce:transition-none motion-reduce:animate-none!">PIVOT<span class="text-tth22-acc">’26</span></span>
</a>
<p class="max-w-[52ch] text-[15px] leading-[1.7] text-tth22-mut">Approach the wordmark from any corner — it leans toward you. Four invisible hover quadrants, four poses, one transition blending them. No script.</p>
<p class="text-[12.5px] text-tth22-mut">The shadow always slides opposite the tilt — fixed lamp, turning object. <kbd class="rounded-[5px] border border-b-2 border-tth22-line bg-white px-1.5 py-0.5 font-tth22-mono text-[11px]">Tab</kbd> to it for the keyboard sway.</p>
</div>
</section>@import "tailwindcss";
@theme {
--color-tth22-bg: #eceef3;
--color-tth22-bg: oklch(0.94 0.006 260);
--color-tth22-glow: #f6f7fa;
--color-tth22-glow: oklch(0.975 0.004 260);
--color-tth22-ink: #1a1c2b;
--color-tth22-ink: oklch(0.22 0.02 270);
--color-tth22-mut: #5a5d6c;
--color-tth22-mut: oklch(0.47 0.015 265);
--color-tth22-acc: #3c55d8;
--color-tth22-acc: oklch(0.52 0.2 265);
--color-tth22-line: #d4d6de;
--color-tth22-line: oklch(0.86 0.008 260);
--font-tth22-sans: 'Schibsted Grotesk', system-ui, sans-serif;
--font-tth22-mono: 'JetBrains Mono', ui-monospace, monospace;
--animate-tth22-sway: tth22-sway 3.2s ease-in-out infinite;
@keyframes tth22-sway {
0%,
100% {
transform: rotateX(9deg) rotateY(-11deg);
}
50% {
transform: rotateX(-9deg) rotateY(11deg);
}
}
}
.tth-22 {
width: 100%;
min-height: 100svh;
}@import "tailwindcss";
@theme {
--color-tth22-bg: #eceef3;
--color-tth22-bg: oklch(0.94 0.006 260);
--color-tth22-glow: #f6f7fa;
--color-tth22-glow: oklch(0.975 0.004 260);
--color-tth22-ink: #1a1c2b;
--color-tth22-ink: oklch(0.22 0.02 270);
--color-tth22-mut: #5a5d6c;
--color-tth22-mut: oklch(0.47 0.015 265);
--color-tth22-acc: #3c55d8;
--color-tth22-acc: oklch(0.52 0.2 265);
--color-tth22-line: #d4d6de;
--color-tth22-line: oklch(0.86 0.008 260);
--font-tth22-sans: 'Schibsted Grotesk', system-ui, sans-serif;
--font-tth22-mono: 'JetBrains Mono', ui-monospace, monospace;
--animate-tth22-sway: tth22-sway 3.2s ease-in-out infinite;
@keyframes tth22-sway {
0%,
100% {
transform: rotateX(9deg) rotateY(-11deg);
}
50% {
transform: rotateX(-9deg) rotateY(11deg);
}
}
}
.tth-22 {
width: 100%;
min-height: 100svh;
}Setup — do this once per project
Skip this if your project already runs Tailwind v4.
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>Compiles in the browser — perfect for a CodePen or a quick test, not for production.
npm install tailwindcss @tailwindcss/vite
npm install tailwindcss @tailwindcss/vite// vite.config.js ("type": "module" in package.json)
import { defineConfig } from 'vite'
import tailwindcss from '@tailwindcss/vite'
export default defineConfig({
plugins: [tailwindcss()],
})// vite.config.js ("type": "module" in package.json)
import { defineConfig } from 'vite'
import tailwindcss from '@tailwindcss/vite'
export default defineConfig({
plugins: [tailwindcss()],
})Any v4 setup works — Vite, PostCSS or the CLI. Nothing in this demo is bundler-specific.
@import "tailwindcss";
@theme {
--color-tth22-bg: #eceef3;
--color-tth22-bg: oklch(0.94 0.006 260);
--color-tth22-glow: #f6f7fa;
--color-tth22-glow: oklch(0.975 0.004 260);
--color-tth22-ink: #1a1c2b;
--color-tth22-ink: oklch(0.22 0.02 270);
--color-tth22-mut: #5a5d6c;
--color-tth22-mut: oklch(0.47 0.015 265);
--color-tth22-acc: #3c55d8;
--color-tth22-acc: oklch(0.52 0.2 265);
--color-tth22-line: #d4d6de;
--color-tth22-line: oklch(0.86 0.008 260);
--font-tth22-sans: 'Schibsted Grotesk', system-ui, sans-serif;
--font-tth22-mono: 'JetBrains Mono', ui-monospace, monospace;
--animate-tth22-sway: tth22-sway 3.2s ease-in-out infinite;
@keyframes tth22-sway {
0%,
100% {
transform: rotateX(9deg) rotateY(-11deg);
}
50% {
transform: rotateX(-9deg) rotateY(11deg);
}
}
}
.tth-22 {
width: 100%;
min-height: 100svh;
}@import "tailwindcss";
@theme {
--color-tth22-bg: #eceef3;
--color-tth22-bg: oklch(0.94 0.006 260);
--color-tth22-glow: #f6f7fa;
--color-tth22-glow: oklch(0.975 0.004 260);
--color-tth22-ink: #1a1c2b;
--color-tth22-ink: oklch(0.22 0.02 270);
--color-tth22-mut: #5a5d6c;
--color-tth22-mut: oklch(0.47 0.015 265);
--color-tth22-acc: #3c55d8;
--color-tth22-acc: oklch(0.52 0.2 265);
--color-tth22-line: #d4d6de;
--color-tth22-line: oklch(0.86 0.008 260);
--font-tth22-sans: 'Schibsted Grotesk', system-ui, sans-serif;
--font-tth22-mono: 'JetBrains Mono', ui-monospace, monospace;
--animate-tth22-sway: tth22-sway 3.2s ease-in-out infinite;
@keyframes tth22-sway {
0%,
100% {
transform: rotateX(9deg) rotateY(-11deg);
}
50% {
transform: rotateX(-9deg) rotateY(11deg);
}
}
}
.tth-22 {
width: 100%;
min-height: 100svh;
}<link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Schibsted+Grotesk:wght@400..900&family=JetBrains+Mono:wght@400;600&display=swap">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Schibsted+Grotesk:wght@400..900&family=JetBrains+Mono:wght@400;600&display=swap">What changed in the port
Which parts became utilities, which stayed CSS, and why.
- Four
.z--tl:hover ~ .wordsibling rules became named-peer variants (peer-hover/tl:…peer-hover/br:) on the word; v4'srotate-x-*/rotate-y-*replaced the hand-writtentransformchains. - UI upgrade from the CSS original: the wordmark was a
tabindex="0"div — focusable but inert. It's now a real link (“PIVOT ’26 — get tickets”), so keyboard focus leads somewhere. - UI upgrade: the ’26 is set in the accent, Schibsted Grotesk Black gives tighter, sturdier letterforms, and muted copy rose to 6:1.
Here's a working CSS demo from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Tailwind 3D Perspective Tilt Text Hover Effect
Source: https://codefronts.com/motion/tailwind-css-text-hover-effects/tailwind-3d-perspective-tilt-text-hover-effect/
A conference wordmark that leans toward the cursor from any corner — without JavaScript. Four invisible quadrant zones are named peers (peer/tl…peer/br); the word reads peer-hover/tl:rotate-x-[11deg] peer-hover/tl:-rotate-y-[13deg] and a matching shadow that always falls away from the tilt. Keyboard focus plays a gentle sway.
## HTML
```html
<section class="tth-22 w-full min-h-svh grid place-items-center bg-tth22-bg bg-[radial-gradient(80%_65%_at_50%_30%,var(--color-tth22-glow),var(--color-tth22-bg)_75%)] px-5 py-14 font-tth22-sans text-tth22-ink" aria-label="Perspective tilt text demo">
<div class="flex flex-col items-center gap-[clamp(18px,3.4vw,28px)] text-center">
<p class="text-[12.5px] font-extrabold uppercase tracking-[0.24em] text-tth22-mut">Pivot — the design systems summit</p>
<a id="tth22-top" href="#tth22-top" aria-label="PIVOT '26 — get tickets" class="group/tilt relative block rounded-2xl px-[clamp(20px,4vw,44px)] py-[clamp(16px,3vw,30px)] no-underline perspective-[850px] focus-visible:outline-[2.5px] focus-visible:outline-offset-4 focus-visible:outline-tth22-acc">
<i aria-hidden="true" class="peer/tl absolute left-0 top-0 z-10 size-1/2"></i><i aria-hidden="true" class="peer/tr absolute right-0 top-0 z-10 size-1/2"></i><i aria-hidden="true" class="peer/bl absolute bottom-0 left-0 z-10 size-1/2"></i><i aria-hidden="true" class="peer/br absolute bottom-0 right-0 z-10 size-1/2"></i>
<span aria-hidden="true" class="block text-[clamp(58px,13.5vw,140px)] font-black leading-none tracking-[-0.04em] [text-shadow:0_.06em_.09em_oklch(0.2_0.02_270/0.22)] transition-[transform,text-shadow] duration-500 ease-[cubic-bezier(.2,.8,.25,1)] peer-hover/tl:rotate-x-[11deg] peer-hover/tl:-rotate-y-[13deg] peer-hover/tl:[text-shadow:.07em_.11em_.13em_oklch(0.2_0.02_270/0.42)] peer-hover/tr:rotate-x-[11deg] peer-hover/tr:rotate-y-[13deg] peer-hover/tr:[text-shadow:-.07em_.11em_.13em_oklch(0.2_0.02_270/0.42)] peer-hover/bl:-rotate-x-[11deg] peer-hover/bl:-rotate-y-[13deg] peer-hover/bl:[text-shadow:.07em_-.07em_.13em_oklch(0.2_0.02_270/0.4)] peer-hover/br:-rotate-x-[11deg] peer-hover/br:rotate-y-[13deg] peer-hover/br:[text-shadow:-.07em_-.07em_.13em_oklch(0.2_0.02_270/0.4)] group-focus-visible/tilt:animate-tth22-sway motion-reduce:transition-none motion-reduce:animate-none!">PIVOT<span class="text-tth22-acc">’26</span></span>
</a>
<p class="max-w-[52ch] text-[15px] leading-[1.7] text-tth22-mut">Approach the wordmark from any corner — it leans toward you. Four invisible hover quadrants, four poses, one transition blending them. No script.</p>
<p class="text-[12.5px] text-tth22-mut">The shadow always slides opposite the tilt — fixed lamp, turning object. <kbd class="rounded-[5px] border border-b-2 border-tth22-line bg-white px-1.5 py-0.5 font-tth22-mono text-[11px]">Tab</kbd> to it for the keyboard sway.</p>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tth22-bg: #eceef3;
--color-tth22-bg: oklch(0.94 0.006 260);
--color-tth22-glow: #f6f7fa;
--color-tth22-glow: oklch(0.975 0.004 260);
--color-tth22-ink: #1a1c2b;
--color-tth22-ink: oklch(0.22 0.02 270);
--color-tth22-mut: #5a5d6c;
--color-tth22-mut: oklch(0.47 0.015 265);
--color-tth22-acc: #3c55d8;
--color-tth22-acc: oklch(0.52 0.2 265);
--color-tth22-line: #d4d6de;
--color-tth22-line: oklch(0.86 0.008 260);
--font-tth22-sans: 'Schibsted Grotesk', system-ui, sans-serif;
--font-tth22-mono: 'JetBrains Mono', ui-monospace, monospace;
--animate-tth22-sway: tth22-sway 3.2s ease-in-out infinite;
@keyframes tth22-sway {
0%,
100% {
transform: rotateX(9deg) rotateY(-11deg);
}
50% {
transform: rotateX(-9deg) rotateY(11deg);
}
}
}
.tth-22 {
width: 100%;
min-height: 100svh;
}
```Here's a working CSS demo from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Tailwind 3D Perspective Tilt Text Hover Effect
Source: https://codefronts.com/motion/tailwind-css-text-hover-effects/tailwind-3d-perspective-tilt-text-hover-effect/
A conference wordmark that leans toward the cursor from any corner — without JavaScript. Four invisible quadrant zones are named peers (peer/tl…peer/br); the word reads peer-hover/tl:rotate-x-[11deg] peer-hover/tl:-rotate-y-[13deg] and a matching shadow that always falls away from the tilt. Keyboard focus plays a gentle sway.
## HTML
```html
<section class="tth-22 w-full min-h-svh grid place-items-center bg-tth22-bg bg-[radial-gradient(80%_65%_at_50%_30%,var(--color-tth22-glow),var(--color-tth22-bg)_75%)] px-5 py-14 font-tth22-sans text-tth22-ink" aria-label="Perspective tilt text demo">
<div class="flex flex-col items-center gap-[clamp(18px,3.4vw,28px)] text-center">
<p class="text-[12.5px] font-extrabold uppercase tracking-[0.24em] text-tth22-mut">Pivot — the design systems summit</p>
<a id="tth22-top" href="#tth22-top" aria-label="PIVOT '26 — get tickets" class="group/tilt relative block rounded-2xl px-[clamp(20px,4vw,44px)] py-[clamp(16px,3vw,30px)] no-underline perspective-[850px] focus-visible:outline-[2.5px] focus-visible:outline-offset-4 focus-visible:outline-tth22-acc">
<i aria-hidden="true" class="peer/tl absolute left-0 top-0 z-10 size-1/2"></i><i aria-hidden="true" class="peer/tr absolute right-0 top-0 z-10 size-1/2"></i><i aria-hidden="true" class="peer/bl absolute bottom-0 left-0 z-10 size-1/2"></i><i aria-hidden="true" class="peer/br absolute bottom-0 right-0 z-10 size-1/2"></i>
<span aria-hidden="true" class="block text-[clamp(58px,13.5vw,140px)] font-black leading-none tracking-[-0.04em] [text-shadow:0_.06em_.09em_oklch(0.2_0.02_270/0.22)] transition-[transform,text-shadow] duration-500 ease-[cubic-bezier(.2,.8,.25,1)] peer-hover/tl:rotate-x-[11deg] peer-hover/tl:-rotate-y-[13deg] peer-hover/tl:[text-shadow:.07em_.11em_.13em_oklch(0.2_0.02_270/0.42)] peer-hover/tr:rotate-x-[11deg] peer-hover/tr:rotate-y-[13deg] peer-hover/tr:[text-shadow:-.07em_.11em_.13em_oklch(0.2_0.02_270/0.42)] peer-hover/bl:-rotate-x-[11deg] peer-hover/bl:-rotate-y-[13deg] peer-hover/bl:[text-shadow:.07em_-.07em_.13em_oklch(0.2_0.02_270/0.4)] peer-hover/br:-rotate-x-[11deg] peer-hover/br:rotate-y-[13deg] peer-hover/br:[text-shadow:-.07em_-.07em_.13em_oklch(0.2_0.02_270/0.4)] group-focus-visible/tilt:animate-tth22-sway motion-reduce:transition-none motion-reduce:animate-none!">PIVOT<span class="text-tth22-acc">’26</span></span>
</a>
<p class="max-w-[52ch] text-[15px] leading-[1.7] text-tth22-mut">Approach the wordmark from any corner — it leans toward you. Four invisible hover quadrants, four poses, one transition blending them. No script.</p>
<p class="text-[12.5px] text-tth22-mut">The shadow always slides opposite the tilt — fixed lamp, turning object. <kbd class="rounded-[5px] border border-b-2 border-tth22-line bg-white px-1.5 py-0.5 font-tth22-mono text-[11px]">Tab</kbd> to it for the keyboard sway.</p>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tth22-bg: #eceef3;
--color-tth22-bg: oklch(0.94 0.006 260);
--color-tth22-glow: #f6f7fa;
--color-tth22-glow: oklch(0.975 0.004 260);
--color-tth22-ink: #1a1c2b;
--color-tth22-ink: oklch(0.22 0.02 270);
--color-tth22-mut: #5a5d6c;
--color-tth22-mut: oklch(0.47 0.015 265);
--color-tth22-acc: #3c55d8;
--color-tth22-acc: oklch(0.52 0.2 265);
--color-tth22-line: #d4d6de;
--color-tth22-line: oklch(0.86 0.008 260);
--font-tth22-sans: 'Schibsted Grotesk', system-ui, sans-serif;
--font-tth22-mono: 'JetBrains Mono', ui-monospace, monospace;
--animate-tth22-sway: tth22-sway 3.2s ease-in-out infinite;
@keyframes tth22-sway {
0%,
100% {
transform: rotateX(9deg) rotateY(-11deg);
}
50% {
transform: rotateX(-9deg) rotateY(11deg);
}
}
}
.tth-22 {
width: 100%;
min-height: 100svh;
}
```How this works
Hover zones. Four absolutely positioned <i> elements cover the quadrants of the wordmark, above it in z-order. Each is a named peer, and because they come before the word in the DOM, the word can read their hover state:
<i class="peer/tl absolute left-0 top-0 z-10 size-1/2"></i>…
<span class="transition-[transform,text-shadow] duration-500
peer-hover/tl:rotate-x-[11deg] peer-hover/tl:-rotate-y-[13deg]
peer-hover/tr:rotate-x-[11deg] peer-hover/tr:rotate-y-[13deg] …">Blending. Moving from one quadrant to the next swaps targets mid-transition, so the word glides between poses rather than snapping — a cheap approximation of continuous tracking.
Shadow logic. Each pose's shadow offset is the opposite of its tilt, as if a lamp were fixed above the viewer.
Make it yours
- Stronger tilt: raise 11/13deg to 16/18deg and lower perspective to 650px.
- Nine zones: a 3×3 grid of peers adds pure X and Y poses.
- Use on cards: put the same zones over any card and tilt the card body.
Gotchas — read before shipping
- The zones must be siblings that precede the target —
peer-*only looks backwards. - Zones sit on top, so they'd swallow clicks on inner links; here the whole wrapper is one link, so clicks still land.
- Text in 3D can blur during the transition on low-DPI screens; it re-sharpens at rest.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 111+ | 16.4+ | 128+ | 111+ |
3D transforms are universal; the floor is Tailwind v4's sheet.