04 / 22
All 22 in 22 CSS Brutalism
- 01Neubrutalist SaaS Pricing Cards
- 02Pastel Dashboard with Hard Shadows
- 03Neubrutalist Signup Form
- 04Sticker Style Feature Cards
- 05Neubrutalist Navbar with Offset Shadow
- 06Playful Button Set
- 07Neubrutalist Modal Dialog
- 08Bold Testimonial Wall
- 09Neubrutalist Blog Card Grid
- 10Chunky Toggle and Checkbox Set
- 11Neubrutalist Hero Section
- 12Offset Shadow Image Gallery
- 13Neubrutalist Stats Panel
- 14Rounded Block Footer
- 15Brutalist Product Card Grid
- 16Brutalist Form Controls
- 17Brutalist Data Dashboard
- 18Brutalist Portfolio Grid
- 19Brutalist Indie SaaS Pricing
- 20Windows 95 Desktop UI
- 21Brutalist Editorial Long Read
- 22Brutalist Streetwear Catalog
Sticker Style Feature Cards
Six feature cards pasted onto the page at slightly different angles, each one straightening under the pointer as its shadow deepens. Every card's tilt is a single --rot value set inline, so the composition is data, not a pile of :nth-child overrides — and because rotate is its own property now, the hover transition can't fight a transform shorthand.
Untitled UI Pro: a 10,000+ component Figma UI kit · from $129 one-time
Untitled UI · Affiliate link
The code
<div class="brt-04">
<input class="brt-04__sr" type="checkbox" id="brt-04-dark">
<label class="brt-04__theme" for="brt-04-dark">
<svg class="brt-04__moon" viewBox="0 0 24 24" fill="none" aria-hidden="true" focusable="false"><path d="M20 14.2A8.2 8.2 0 0 1 9.8 4 8.4 8.4 0 1 0 20 14.2" stroke="currentColor" stroke-width="2.2" stroke-linejoin="round"/></svg>
<svg class="brt-04__sun" viewBox="0 0 24 24" fill="none" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="4.2" stroke="currentColor" stroke-width="2.2"/><path d="M12 3v2.2M12 18.8V21M3 12h2.2M18.8 12H21M5.6 5.6l1.6 1.6M16.8 16.8l1.6 1.6M18.4 5.6l-1.6 1.6M7.2 16.8l-1.6 1.6" stroke="currentColor" stroke-width="2.2" stroke-linecap="round"/></svg>
<span class="brt-04__vh">Dark theme</span>
</label>
<div class="brt-04__stage">
<section class="brt-04__wrap" aria-labelledby="brt-04-h">
<header class="brt-04__head">
<p class="brt-04__eyebrow">Why teams switch</p>
<h2 class="brt-04__h" id="brt-04-h">Everything sticks together</h2>
</header>
<ul class="brt-04__grid">
<li class="brt-04__card" style="--rot:-2deg">
<span class="brt-04__icon"><svg viewBox="0 0 24 24" fill="none" aria-hidden="true" focusable="false"><path d="M13 2 4 14h6l-1 8 9-12h-6z" stroke="currentColor" stroke-width="2.2" stroke-linejoin="round"/></svg></span>
<h3 class="brt-04__t"><a href="#brt-04-h">Deploys in 40 seconds</a></h3>
<p class="brt-04__p">Push to main and the build is live before your coffee lands. Rollbacks are one keystroke.</p>
</li>
<li class="brt-04__card" style="--rot:1.5deg">
<span class="brt-04__icon"><svg viewBox="0 0 24 24" fill="none" aria-hidden="true" focusable="false"><path d="M12 3l7.5 3.4v5.1c0 4.3-3 8-7.5 9.5-4.5-1.5-7.5-5.2-7.5-9.5V6.4z" stroke="currentColor" stroke-width="2.2" stroke-linejoin="round"/><path d="M8.6 12.2l2.4 2.3 4.4-4.6" stroke="currentColor" stroke-width="2.4" stroke-linecap="square"/></svg></span>
<h3 class="brt-04__t"><a href="#brt-04-h">SOC 2 without the binder</a></h3>
<p class="brt-04__p">Audit trails, SSO and device checks ship on by default. Evidence exports as CSV.</p>
</li>
<li class="brt-04__card" style="--rot:-1deg">
<span class="brt-04__icon"><svg viewBox="0 0 24 24" fill="none" aria-hidden="true" focusable="false"><path d="M4 18V8m5 10V4m5 14v-6m5 6V9" stroke="currentColor" stroke-width="2.6" stroke-linecap="square"/></svg></span>
<h3 class="brt-04__t"><a href="#brt-04-h">Numbers you can trust</a></h3>
<p class="brt-04__p">Every metric links back to the raw event. No pipeline mystery, no nightly reconciliation.</p>
</li>
<li class="brt-04__card" style="--rot:2.5deg">
<span class="brt-04__icon"><svg viewBox="0 0 24 24" fill="none" aria-hidden="true" focusable="false"><circle cx="9" cy="8.5" r="3.2" stroke="currentColor" stroke-width="2.2"/><path d="M3 20c1.2-3 3.4-4.5 6-4.5S13.8 17 15 20" stroke="currentColor" stroke-width="2.2" stroke-linecap="square"/><path d="M16 5.5a3.2 3.2 0 0 1 0 6M18 20c-.5-2-1.2-3.4-2.2-4.4" stroke="currentColor" stroke-width="2.2" stroke-linecap="square"/></svg></span>
<h3 class="brt-04__t"><a href="#brt-04-h">Guests, not seats</a></h3>
<p class="brt-04__p">Invite a client to one project for free. They see what you share and nothing else.</p>
</li>
<li class="brt-04__card" style="--rot:-2.5deg">
<span class="brt-04__icon"><svg viewBox="0 0 24 24" fill="none" aria-hidden="true" focusable="false"><rect x="3.5" y="5" width="17" height="14" rx="2" stroke="currentColor" stroke-width="2.2"/><path d="M3.5 9.5h17M8 3.5V6m8-2.5V6" stroke="currentColor" stroke-width="2.2" stroke-linecap="square"/></svg></span>
<h3 class="brt-04__t"><a href="#brt-04-h">Schedules that hold</a></h3>
<p class="brt-04__p">Timezones, freezes and on-call windows are one calendar the whole team can read.</p>
</li>
<li class="brt-04__card" style="--rot:1deg">
<span class="brt-04__icon"><svg viewBox="0 0 24 24" fill="none" aria-hidden="true" focusable="false"><path d="M4 7h16M4 12h11M4 17h7" stroke="currentColor" stroke-width="2.6" stroke-linecap="square"/><circle cx="19" cy="16.5" r="3" stroke="currentColor" stroke-width="2.2"/></svg></span>
<h3 class="brt-04__t"><a href="#brt-04-h">Search that finds it</a></h3>
<p class="brt-04__p">Full-text across docs, tickets and commits, ranked by what your team opened last.</p>
</li>
</ul>
</section>
</div>
</div><div class="brt-04">
<input class="brt-04__sr" type="checkbox" id="brt-04-dark">
<label class="brt-04__theme" for="brt-04-dark">
<svg class="brt-04__moon" viewBox="0 0 24 24" fill="none" aria-hidden="true" focusable="false"><path d="M20 14.2A8.2 8.2 0 0 1 9.8 4 8.4 8.4 0 1 0 20 14.2" stroke="currentColor" stroke-width="2.2" stroke-linejoin="round"/></svg>
<svg class="brt-04__sun" viewBox="0 0 24 24" fill="none" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="4.2" stroke="currentColor" stroke-width="2.2"/><path d="M12 3v2.2M12 18.8V21M3 12h2.2M18.8 12H21M5.6 5.6l1.6 1.6M16.8 16.8l1.6 1.6M18.4 5.6l-1.6 1.6M7.2 16.8l-1.6 1.6" stroke="currentColor" stroke-width="2.2" stroke-linecap="round"/></svg>
<span class="brt-04__vh">Dark theme</span>
</label>
<div class="brt-04__stage">
<section class="brt-04__wrap" aria-labelledby="brt-04-h">
<header class="brt-04__head">
<p class="brt-04__eyebrow">Why teams switch</p>
<h2 class="brt-04__h" id="brt-04-h">Everything sticks together</h2>
</header>
<ul class="brt-04__grid">
<li class="brt-04__card" style="--rot:-2deg">
<span class="brt-04__icon"><svg viewBox="0 0 24 24" fill="none" aria-hidden="true" focusable="false"><path d="M13 2 4 14h6l-1 8 9-12h-6z" stroke="currentColor" stroke-width="2.2" stroke-linejoin="round"/></svg></span>
<h3 class="brt-04__t"><a href="#brt-04-h">Deploys in 40 seconds</a></h3>
<p class="brt-04__p">Push to main and the build is live before your coffee lands. Rollbacks are one keystroke.</p>
</li>
<li class="brt-04__card" style="--rot:1.5deg">
<span class="brt-04__icon"><svg viewBox="0 0 24 24" fill="none" aria-hidden="true" focusable="false"><path d="M12 3l7.5 3.4v5.1c0 4.3-3 8-7.5 9.5-4.5-1.5-7.5-5.2-7.5-9.5V6.4z" stroke="currentColor" stroke-width="2.2" stroke-linejoin="round"/><path d="M8.6 12.2l2.4 2.3 4.4-4.6" stroke="currentColor" stroke-width="2.4" stroke-linecap="square"/></svg></span>
<h3 class="brt-04__t"><a href="#brt-04-h">SOC 2 without the binder</a></h3>
<p class="brt-04__p">Audit trails, SSO and device checks ship on by default. Evidence exports as CSV.</p>
</li>
<li class="brt-04__card" style="--rot:-1deg">
<span class="brt-04__icon"><svg viewBox="0 0 24 24" fill="none" aria-hidden="true" focusable="false"><path d="M4 18V8m5 10V4m5 14v-6m5 6V9" stroke="currentColor" stroke-width="2.6" stroke-linecap="square"/></svg></span>
<h3 class="brt-04__t"><a href="#brt-04-h">Numbers you can trust</a></h3>
<p class="brt-04__p">Every metric links back to the raw event. No pipeline mystery, no nightly reconciliation.</p>
</li>
<li class="brt-04__card" style="--rot:2.5deg">
<span class="brt-04__icon"><svg viewBox="0 0 24 24" fill="none" aria-hidden="true" focusable="false"><circle cx="9" cy="8.5" r="3.2" stroke="currentColor" stroke-width="2.2"/><path d="M3 20c1.2-3 3.4-4.5 6-4.5S13.8 17 15 20" stroke="currentColor" stroke-width="2.2" stroke-linecap="square"/><path d="M16 5.5a3.2 3.2 0 0 1 0 6M18 20c-.5-2-1.2-3.4-2.2-4.4" stroke="currentColor" stroke-width="2.2" stroke-linecap="square"/></svg></span>
<h3 class="brt-04__t"><a href="#brt-04-h">Guests, not seats</a></h3>
<p class="brt-04__p">Invite a client to one project for free. They see what you share and nothing else.</p>
</li>
<li class="brt-04__card" style="--rot:-2.5deg">
<span class="brt-04__icon"><svg viewBox="0 0 24 24" fill="none" aria-hidden="true" focusable="false"><rect x="3.5" y="5" width="17" height="14" rx="2" stroke="currentColor" stroke-width="2.2"/><path d="M3.5 9.5h17M8 3.5V6m8-2.5V6" stroke="currentColor" stroke-width="2.2" stroke-linecap="square"/></svg></span>
<h3 class="brt-04__t"><a href="#brt-04-h">Schedules that hold</a></h3>
<p class="brt-04__p">Timezones, freezes and on-call windows are one calendar the whole team can read.</p>
</li>
<li class="brt-04__card" style="--rot:1deg">
<span class="brt-04__icon"><svg viewBox="0 0 24 24" fill="none" aria-hidden="true" focusable="false"><path d="M4 7h16M4 12h11M4 17h7" stroke="currentColor" stroke-width="2.6" stroke-linecap="square"/><circle cx="19" cy="16.5" r="3" stroke="currentColor" stroke-width="2.2"/></svg></span>
<h3 class="brt-04__t"><a href="#brt-04-h">Search that finds it</a></h3>
<p class="brt-04__p">Full-text across docs, tickets and commits, ranked by what your team opened last.</p>
</li>
</ul>
</section>
</div>
</div>@import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@500;600;700&display=swap');
.brt-04 {
--page: #fbf7f0;
--panel: #ffffff;
--ink: #0b0b0f;
--on: #0b0b0f;
--muted: #4a4a52;
--lilac: #c4b5fd;
--mint: #86efac;
--coral: #fda4af;
--butter: #fde68a;
--sky: #93c5fd;
--edge: #000000;
--sh: #000000;
--bw: 3px;
--r: 16px;
--icon-r: 50%;
width: 100%;
min-height: 100vh;
min-height: 100svh;
display: block;
position: relative;
box-sizing: border-box;
background: var(--page);
color: var(--ink);
font-family: 'Space Grotesk','Sora',ui-sans-serif,system-ui,sans-serif;
}
.brt-04 *,
.brt-04 *::before,
.brt-04 *::after {
box-sizing: border-box;
}
@supports (color: oklch(0.7 0.1 300)) {
.brt-04 {
--page: oklch(0.975 0.014 84);
--panel: oklch(1 0 0);
--ink: oklch(0.16 0.01 285);
--lilac: oklch(0.82 0.11 296);
--mint: oklch(0.89 0.13 155);
--coral: oklch(0.83 0.10 15);
--butter: oklch(0.92 0.11 95);
--sky: oklch(0.83 0.09 250);
}
}
.brt-04__vh {
position: absolute;
width: 1px;
height: 1px;
margin: -1px;
overflow: hidden;
clip-path: inset(50%);
white-space: nowrap;
}
.brt-04__sr {
position: absolute;
width: 1px;
height: 1px;
opacity: 0;
pointer-events: none;
}
.brt-04__theme {
position: absolute;
inset-block-start: 1rem;
inset-inline-end: 1rem;
z-index: 5;
inline-size: 2.5rem;
block-size: 2.5rem;
display: grid;
place-items: center;
background: var(--panel);
color: var(--ink);
border: var(--bw) solid var(--edge);
border-radius: 10px;
box-shadow: 4px 4px 0 var(--sh);
cursor: pointer;
transition: translate .14s ease, box-shadow .14s ease;
}
.brt-04__theme::after {
content: '';
position: absolute;
inset: -2px;
}
.brt-04__theme svg {
inline-size: 1.25rem;
block-size: 1.25rem;
}
.brt-04__theme:active {
translate: 2px 2px;
box-shadow: 2px 2px 0 var(--sh);
}
.brt-04__sr:focus-visible + .brt-04__theme {
outline: 3px solid var(--edge);
outline-offset: 3px;
}
.brt-04__sun {
display: none;
}
.brt-04__stage {
min-height: 100vh;
min-height: 100svh;
display: grid;
place-items: center;
padding: clamp(1.5rem,5vw,3.5rem);
}
.brt-04__wrap {
inline-size: min(70rem,100%);
}
.brt-04__head {
margin-block-end: clamp(1.75rem,4vw,2.5rem);
text-align: center;
}
.brt-04__eyebrow {
display: inline-block;
margin: 0 0 .7rem;
padding: .3rem .65rem;
rotate: -2deg;
background: var(--sky);
color: var(--on);
border: 2px solid var(--edge);
border-radius: 7px;
box-shadow: 3px 3px 0 var(--sh);
font-size: .74rem;
font-weight: 700;
letter-spacing: .14em;
text-transform: uppercase;
}
.brt-04__h {
margin: 0;
font-size: clamp(2rem,5.2vw,3.1rem);
font-weight: 700;
letter-spacing: -.025em;
line-height: 1.02;
text-wrap: balance;
}
.brt-04__grid {
list-style: none;
margin: 0;
padding: .5rem;
display: grid;
gap: clamp(1.25rem,2.8vw,2rem);
grid-template-columns: repeat(auto-fit,minmax(min(16rem,100%),1fr));
}
.brt-04__card {
position: relative;
display: flex;
flex-direction: column;
gap: .65rem;
padding: clamp(1.1rem,2vw,1.5rem);
border: var(--bw) solid var(--edge);
border-radius: var(--r);
box-shadow: 6px 6px 0 var(--sh);
color: var(--on);
rotate: var(--rot,0deg);
transition: rotate .16s ease, translate .16s ease, box-shadow .16s ease;
}
.brt-04__card:nth-child(4n+1) {
background: var(--butter);
}
.brt-04__card:nth-child(4n+2) {
background: var(--mint);
}
.brt-04__card:nth-child(4n+3) {
background: var(--lilac);
}
.brt-04__card:nth-child(4n+4) {
background: var(--coral);
}
@media (hover: hover) {
.brt-04__card:hover {
rotate: 0deg;
translate: -2px -3px;
box-shadow: 10px 10px 0 var(--sh);
z-index: 2;
}
}
.brt-04__card:has(a:focus-visible) {
rotate: 0deg;
translate: -2px -3px;
box-shadow: 10px 10px 0 var(--sh);
z-index: 2;
}
.brt-04__icon {
display: grid;
place-items: center;
inline-size: 3rem;
block-size: 3rem;
background: var(--panel);
color: var(--ink);
border: var(--bw) solid var(--edge);
border-radius: var(--icon-r);
box-shadow: 3px 3px 0 var(--sh);
}
.brt-04__icon svg {
inline-size: 1.5rem;
block-size: 1.5rem;
}
.brt-04__t {
margin: .35rem 0 0;
font-size: 1.2rem;
font-weight: 700;
letter-spacing: -.015em;
line-height: 1.15;
}
.brt-04__t a {
color: inherit;
text-decoration: none;
}
.brt-04__t a::after {
content: '';
position: absolute;
inset: 0;
border-radius: var(--r);
}
.brt-04__t a:focus-visible {
outline: none;
}
.brt-04__card:has(a:focus-visible) .brt-04__t a::after {
outline: 3px solid var(--edge);
outline-offset: 4px;
}
.brt-04__p {
margin: 0;
font-size: .95rem;
line-height: 1.5;
opacity: .8;
text-wrap: pretty;
}
.brt-04:has(#brt-04-dark:checked) {
--page: #14131a;
--panel: #221f2b;
--ink: #f7f5ef;
--muted: #b5b1c2;
--edge: #f7f5ef;
--sh: #f7f5ef;
}
.brt-04:has(#brt-04-dark:checked) .brt-04__moon {
display: none;
}
.brt-04:has(#brt-04-dark:checked) .brt-04__sun {
display: block;
}
@media (prefers-color-scheme: dark) {
.brt-04:not(:has(#brt-04-dark:checked)) {
--page: #14131a;
--panel: #221f2b;
--ink: #f7f5ef;
--muted: #b5b1c2;
--edge: #f7f5ef;
--sh: #f7f5ef;
}
.brt-04:not(:has(#brt-04-dark:checked)) .brt-04__moon {
display: none;
}
.brt-04:not(:has(#brt-04-dark:checked)) .brt-04__sun {
display: block;
}
}
@media (prefers-reduced-motion: reduce) {
.brt-04 *,
.brt-04 *::before,
.brt-04 *::after {
transition: none !important;
animation: none !important;
}
}
@media (forced-colors: active) {
.brt-04__card,
.brt-04__icon,
.brt-04__theme {
border-color: CanvasText;
box-shadow: none;
}
}
/* stage children default to min-width:auto, so a wide heading or grid
track forces the panel past the stage; 0 lets it shrink instead */
.brt-04__stage > * {
min-inline-size: 0;
max-inline-size: 100%;
}@import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@500;600;700&display=swap');
.brt-04 {
--page: #fbf7f0;
--panel: #ffffff;
--ink: #0b0b0f;
--on: #0b0b0f;
--muted: #4a4a52;
--lilac: #c4b5fd;
--mint: #86efac;
--coral: #fda4af;
--butter: #fde68a;
--sky: #93c5fd;
--edge: #000000;
--sh: #000000;
--bw: 3px;
--r: 16px;
--icon-r: 50%;
width: 100%;
min-height: 100vh;
min-height: 100svh;
display: block;
position: relative;
box-sizing: border-box;
background: var(--page);
color: var(--ink);
font-family: 'Space Grotesk','Sora',ui-sans-serif,system-ui,sans-serif;
}
.brt-04 *,
.brt-04 *::before,
.brt-04 *::after {
box-sizing: border-box;
}
@supports (color: oklch(0.7 0.1 300)) {
.brt-04 {
--page: oklch(0.975 0.014 84);
--panel: oklch(1 0 0);
--ink: oklch(0.16 0.01 285);
--lilac: oklch(0.82 0.11 296);
--mint: oklch(0.89 0.13 155);
--coral: oklch(0.83 0.10 15);
--butter: oklch(0.92 0.11 95);
--sky: oklch(0.83 0.09 250);
}
}
.brt-04__vh {
position: absolute;
width: 1px;
height: 1px;
margin: -1px;
overflow: hidden;
clip-path: inset(50%);
white-space: nowrap;
}
.brt-04__sr {
position: absolute;
width: 1px;
height: 1px;
opacity: 0;
pointer-events: none;
}
.brt-04__theme {
position: absolute;
inset-block-start: 1rem;
inset-inline-end: 1rem;
z-index: 5;
inline-size: 2.5rem;
block-size: 2.5rem;
display: grid;
place-items: center;
background: var(--panel);
color: var(--ink);
border: var(--bw) solid var(--edge);
border-radius: 10px;
box-shadow: 4px 4px 0 var(--sh);
cursor: pointer;
transition: translate .14s ease, box-shadow .14s ease;
}
.brt-04__theme::after {
content: '';
position: absolute;
inset: -2px;
}
.brt-04__theme svg {
inline-size: 1.25rem;
block-size: 1.25rem;
}
.brt-04__theme:active {
translate: 2px 2px;
box-shadow: 2px 2px 0 var(--sh);
}
.brt-04__sr:focus-visible + .brt-04__theme {
outline: 3px solid var(--edge);
outline-offset: 3px;
}
.brt-04__sun {
display: none;
}
.brt-04__stage {
min-height: 100vh;
min-height: 100svh;
display: grid;
place-items: center;
padding: clamp(1.5rem,5vw,3.5rem);
}
.brt-04__wrap {
inline-size: min(70rem,100%);
}
.brt-04__head {
margin-block-end: clamp(1.75rem,4vw,2.5rem);
text-align: center;
}
.brt-04__eyebrow {
display: inline-block;
margin: 0 0 .7rem;
padding: .3rem .65rem;
rotate: -2deg;
background: var(--sky);
color: var(--on);
border: 2px solid var(--edge);
border-radius: 7px;
box-shadow: 3px 3px 0 var(--sh);
font-size: .74rem;
font-weight: 700;
letter-spacing: .14em;
text-transform: uppercase;
}
.brt-04__h {
margin: 0;
font-size: clamp(2rem,5.2vw,3.1rem);
font-weight: 700;
letter-spacing: -.025em;
line-height: 1.02;
text-wrap: balance;
}
.brt-04__grid {
list-style: none;
margin: 0;
padding: .5rem;
display: grid;
gap: clamp(1.25rem,2.8vw,2rem);
grid-template-columns: repeat(auto-fit,minmax(min(16rem,100%),1fr));
}
.brt-04__card {
position: relative;
display: flex;
flex-direction: column;
gap: .65rem;
padding: clamp(1.1rem,2vw,1.5rem);
border: var(--bw) solid var(--edge);
border-radius: var(--r);
box-shadow: 6px 6px 0 var(--sh);
color: var(--on);
rotate: var(--rot,0deg);
transition: rotate .16s ease, translate .16s ease, box-shadow .16s ease;
}
.brt-04__card:nth-child(4n+1) {
background: var(--butter);
}
.brt-04__card:nth-child(4n+2) {
background: var(--mint);
}
.brt-04__card:nth-child(4n+3) {
background: var(--lilac);
}
.brt-04__card:nth-child(4n+4) {
background: var(--coral);
}
@media (hover: hover) {
.brt-04__card:hover {
rotate: 0deg;
translate: -2px -3px;
box-shadow: 10px 10px 0 var(--sh);
z-index: 2;
}
}
.brt-04__card:has(a:focus-visible) {
rotate: 0deg;
translate: -2px -3px;
box-shadow: 10px 10px 0 var(--sh);
z-index: 2;
}
.brt-04__icon {
display: grid;
place-items: center;
inline-size: 3rem;
block-size: 3rem;
background: var(--panel);
color: var(--ink);
border: var(--bw) solid var(--edge);
border-radius: var(--icon-r);
box-shadow: 3px 3px 0 var(--sh);
}
.brt-04__icon svg {
inline-size: 1.5rem;
block-size: 1.5rem;
}
.brt-04__t {
margin: .35rem 0 0;
font-size: 1.2rem;
font-weight: 700;
letter-spacing: -.015em;
line-height: 1.15;
}
.brt-04__t a {
color: inherit;
text-decoration: none;
}
.brt-04__t a::after {
content: '';
position: absolute;
inset: 0;
border-radius: var(--r);
}
.brt-04__t a:focus-visible {
outline: none;
}
.brt-04__card:has(a:focus-visible) .brt-04__t a::after {
outline: 3px solid var(--edge);
outline-offset: 4px;
}
.brt-04__p {
margin: 0;
font-size: .95rem;
line-height: 1.5;
opacity: .8;
text-wrap: pretty;
}
.brt-04:has(#brt-04-dark:checked) {
--page: #14131a;
--panel: #221f2b;
--ink: #f7f5ef;
--muted: #b5b1c2;
--edge: #f7f5ef;
--sh: #f7f5ef;
}
.brt-04:has(#brt-04-dark:checked) .brt-04__moon {
display: none;
}
.brt-04:has(#brt-04-dark:checked) .brt-04__sun {
display: block;
}
@media (prefers-color-scheme: dark) {
.brt-04:not(:has(#brt-04-dark:checked)) {
--page: #14131a;
--panel: #221f2b;
--ink: #f7f5ef;
--muted: #b5b1c2;
--edge: #f7f5ef;
--sh: #f7f5ef;
}
.brt-04:not(:has(#brt-04-dark:checked)) .brt-04__moon {
display: none;
}
.brt-04:not(:has(#brt-04-dark:checked)) .brt-04__sun {
display: block;
}
}
@media (prefers-reduced-motion: reduce) {
.brt-04 *,
.brt-04 *::before,
.brt-04 *::after {
transition: none !important;
animation: none !important;
}
}
@media (forced-colors: active) {
.brt-04__card,
.brt-04__icon,
.brt-04__theme {
border-color: CanvasText;
box-shadow: none;
}
}
/* stage children default to min-width:auto, so a wide heading or grid
track forces the panel past the stage; 0 lets it shrink instead */
.brt-04__stage > * {
min-inline-size: 0;
max-inline-size: 100%;
}Here's a working CSS Brutalism 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: Sticker Style Feature Cards
Source: https://codefronts.com/design-styles/css-brutalist/sticker-style-feature-cards/
Six feature cards pasted onto the page at slightly different angles, each one straightening under the pointer as its shadow deepens. Every card's tilt is a single --rot value set inline, so the composition is data, not a pile of :nth-child overrides — and because rotate is its own property now, the hover transition can't fight a transform shorthand.
## HTML
```html
<div class="brt-04">
<input class="brt-04__sr" type="checkbox" id="brt-04-dark">
<label class="brt-04__theme" for="brt-04-dark">
<svg class="brt-04__moon" viewBox="0 0 24 24" fill="none" aria-hidden="true" focusable="false"><path d="M20 14.2A8.2 8.2 0 0 1 9.8 4 8.4 8.4 0 1 0 20 14.2" stroke="currentColor" stroke-width="2.2" stroke-linejoin="round"/></svg>
<svg class="brt-04__sun" viewBox="0 0 24 24" fill="none" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="4.2" stroke="currentColor" stroke-width="2.2"/><path d="M12 3v2.2M12 18.8V21M3 12h2.2M18.8 12H21M5.6 5.6l1.6 1.6M16.8 16.8l1.6 1.6M18.4 5.6l-1.6 1.6M7.2 16.8l-1.6 1.6" stroke="currentColor" stroke-width="2.2" stroke-linecap="round"/></svg>
<span class="brt-04__vh">Dark theme</span>
</label>
<div class="brt-04__stage">
<section class="brt-04__wrap" aria-labelledby="brt-04-h">
<header class="brt-04__head">
<p class="brt-04__eyebrow">Why teams switch</p>
<h2 class="brt-04__h" id="brt-04-h">Everything sticks together</h2>
</header>
<ul class="brt-04__grid">
<li class="brt-04__card" style="--rot:-2deg">
<span class="brt-04__icon"><svg viewBox="0 0 24 24" fill="none" aria-hidden="true" focusable="false"><path d="M13 2 4 14h6l-1 8 9-12h-6z" stroke="currentColor" stroke-width="2.2" stroke-linejoin="round"/></svg></span>
<h3 class="brt-04__t"><a href="#brt-04-h">Deploys in 40 seconds</a></h3>
<p class="brt-04__p">Push to main and the build is live before your coffee lands. Rollbacks are one keystroke.</p>
</li>
<li class="brt-04__card" style="--rot:1.5deg">
<span class="brt-04__icon"><svg viewBox="0 0 24 24" fill="none" aria-hidden="true" focusable="false"><path d="M12 3l7.5 3.4v5.1c0 4.3-3 8-7.5 9.5-4.5-1.5-7.5-5.2-7.5-9.5V6.4z" stroke="currentColor" stroke-width="2.2" stroke-linejoin="round"/><path d="M8.6 12.2l2.4 2.3 4.4-4.6" stroke="currentColor" stroke-width="2.4" stroke-linecap="square"/></svg></span>
<h3 class="brt-04__t"><a href="#brt-04-h">SOC 2 without the binder</a></h3>
<p class="brt-04__p">Audit trails, SSO and device checks ship on by default. Evidence exports as CSV.</p>
</li>
<li class="brt-04__card" style="--rot:-1deg">
<span class="brt-04__icon"><svg viewBox="0 0 24 24" fill="none" aria-hidden="true" focusable="false"><path d="M4 18V8m5 10V4m5 14v-6m5 6V9" stroke="currentColor" stroke-width="2.6" stroke-linecap="square"/></svg></span>
<h3 class="brt-04__t"><a href="#brt-04-h">Numbers you can trust</a></h3>
<p class="brt-04__p">Every metric links back to the raw event. No pipeline mystery, no nightly reconciliation.</p>
</li>
<li class="brt-04__card" style="--rot:2.5deg">
<span class="brt-04__icon"><svg viewBox="0 0 24 24" fill="none" aria-hidden="true" focusable="false"><circle cx="9" cy="8.5" r="3.2" stroke="currentColor" stroke-width="2.2"/><path d="M3 20c1.2-3 3.4-4.5 6-4.5S13.8 17 15 20" stroke="currentColor" stroke-width="2.2" stroke-linecap="square"/><path d="M16 5.5a3.2 3.2 0 0 1 0 6M18 20c-.5-2-1.2-3.4-2.2-4.4" stroke="currentColor" stroke-width="2.2" stroke-linecap="square"/></svg></span>
<h3 class="brt-04__t"><a href="#brt-04-h">Guests, not seats</a></h3>
<p class="brt-04__p">Invite a client to one project for free. They see what you share and nothing else.</p>
</li>
<li class="brt-04__card" style="--rot:-2.5deg">
<span class="brt-04__icon"><svg viewBox="0 0 24 24" fill="none" aria-hidden="true" focusable="false"><rect x="3.5" y="5" width="17" height="14" rx="2" stroke="currentColor" stroke-width="2.2"/><path d="M3.5 9.5h17M8 3.5V6m8-2.5V6" stroke="currentColor" stroke-width="2.2" stroke-linecap="square"/></svg></span>
<h3 class="brt-04__t"><a href="#brt-04-h">Schedules that hold</a></h3>
<p class="brt-04__p">Timezones, freezes and on-call windows are one calendar the whole team can read.</p>
</li>
<li class="brt-04__card" style="--rot:1deg">
<span class="brt-04__icon"><svg viewBox="0 0 24 24" fill="none" aria-hidden="true" focusable="false"><path d="M4 7h16M4 12h11M4 17h7" stroke="currentColor" stroke-width="2.6" stroke-linecap="square"/><circle cx="19" cy="16.5" r="3" stroke="currentColor" stroke-width="2.2"/></svg></span>
<h3 class="brt-04__t"><a href="#brt-04-h">Search that finds it</a></h3>
<p class="brt-04__p">Full-text across docs, tickets and commits, ranked by what your team opened last.</p>
</li>
</ul>
</section>
</div>
</div>
```
## CSS
```css
@import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@500;600;700&display=swap');
.brt-04 {
--page: #fbf7f0;
--panel: #ffffff;
--ink: #0b0b0f;
--on: #0b0b0f;
--muted: #4a4a52;
--lilac: #c4b5fd;
--mint: #86efac;
--coral: #fda4af;
--butter: #fde68a;
--sky: #93c5fd;
--edge: #000000;
--sh: #000000;
--bw: 3px;
--r: 16px;
--icon-r: 50%;
width: 100%;
min-height: 100vh;
min-height: 100svh;
display: block;
position: relative;
box-sizing: border-box;
background: var(--page);
color: var(--ink);
font-family: 'Space Grotesk','Sora',ui-sans-serif,system-ui,sans-serif;
}
.brt-04 *,
.brt-04 *::before,
.brt-04 *::after {
box-sizing: border-box;
}
@supports (color: oklch(0.7 0.1 300)) {
.brt-04 {
--page: oklch(0.975 0.014 84);
--panel: oklch(1 0 0);
--ink: oklch(0.16 0.01 285);
--lilac: oklch(0.82 0.11 296);
--mint: oklch(0.89 0.13 155);
--coral: oklch(0.83 0.10 15);
--butter: oklch(0.92 0.11 95);
--sky: oklch(0.83 0.09 250);
}
}
.brt-04__vh {
position: absolute;
width: 1px;
height: 1px;
margin: -1px;
overflow: hidden;
clip-path: inset(50%);
white-space: nowrap;
}
.brt-04__sr {
position: absolute;
width: 1px;
height: 1px;
opacity: 0;
pointer-events: none;
}
.brt-04__theme {
position: absolute;
inset-block-start: 1rem;
inset-inline-end: 1rem;
z-index: 5;
inline-size: 2.5rem;
block-size: 2.5rem;
display: grid;
place-items: center;
background: var(--panel);
color: var(--ink);
border: var(--bw) solid var(--edge);
border-radius: 10px;
box-shadow: 4px 4px 0 var(--sh);
cursor: pointer;
transition: translate .14s ease, box-shadow .14s ease;
}
.brt-04__theme::after {
content: '';
position: absolute;
inset: -2px;
}
.brt-04__theme svg {
inline-size: 1.25rem;
block-size: 1.25rem;
}
.brt-04__theme:active {
translate: 2px 2px;
box-shadow: 2px 2px 0 var(--sh);
}
.brt-04__sr:focus-visible + .brt-04__theme {
outline: 3px solid var(--edge);
outline-offset: 3px;
}
.brt-04__sun {
display: none;
}
.brt-04__stage {
min-height: 100vh;
min-height: 100svh;
display: grid;
place-items: center;
padding: clamp(1.5rem,5vw,3.5rem);
}
.brt-04__wrap {
inline-size: min(70rem,100%);
}
.brt-04__head {
margin-block-end: clamp(1.75rem,4vw,2.5rem);
text-align: center;
}
.brt-04__eyebrow {
display: inline-block;
margin: 0 0 .7rem;
padding: .3rem .65rem;
rotate: -2deg;
background: var(--sky);
color: var(--on);
border: 2px solid var(--edge);
border-radius: 7px;
box-shadow: 3px 3px 0 var(--sh);
font-size: .74rem;
font-weight: 700;
letter-spacing: .14em;
text-transform: uppercase;
}
.brt-04__h {
margin: 0;
font-size: clamp(2rem,5.2vw,3.1rem);
font-weight: 700;
letter-spacing: -.025em;
line-height: 1.02;
text-wrap: balance;
}
.brt-04__grid {
list-style: none;
margin: 0;
padding: .5rem;
display: grid;
gap: clamp(1.25rem,2.8vw,2rem);
grid-template-columns: repeat(auto-fit,minmax(min(16rem,100%),1fr));
}
.brt-04__card {
position: relative;
display: flex;
flex-direction: column;
gap: .65rem;
padding: clamp(1.1rem,2vw,1.5rem);
border: var(--bw) solid var(--edge);
border-radius: var(--r);
box-shadow: 6px 6px 0 var(--sh);
color: var(--on);
rotate: var(--rot,0deg);
transition: rotate .16s ease, translate .16s ease, box-shadow .16s ease;
}
.brt-04__card:nth-child(4n+1) {
background: var(--butter);
}
.brt-04__card:nth-child(4n+2) {
background: var(--mint);
}
.brt-04__card:nth-child(4n+3) {
background: var(--lilac);
}
.brt-04__card:nth-child(4n+4) {
background: var(--coral);
}
@media (hover: hover) {
.brt-04__card:hover {
rotate: 0deg;
translate: -2px -3px;
box-shadow: 10px 10px 0 var(--sh);
z-index: 2;
}
}
.brt-04__card:has(a:focus-visible) {
rotate: 0deg;
translate: -2px -3px;
box-shadow: 10px 10px 0 var(--sh);
z-index: 2;
}
.brt-04__icon {
display: grid;
place-items: center;
inline-size: 3rem;
block-size: 3rem;
background: var(--panel);
color: var(--ink);
border: var(--bw) solid var(--edge);
border-radius: var(--icon-r);
box-shadow: 3px 3px 0 var(--sh);
}
.brt-04__icon svg {
inline-size: 1.5rem;
block-size: 1.5rem;
}
.brt-04__t {
margin: .35rem 0 0;
font-size: 1.2rem;
font-weight: 700;
letter-spacing: -.015em;
line-height: 1.15;
}
.brt-04__t a {
color: inherit;
text-decoration: none;
}
.brt-04__t a::after {
content: '';
position: absolute;
inset: 0;
border-radius: var(--r);
}
.brt-04__t a:focus-visible {
outline: none;
}
.brt-04__card:has(a:focus-visible) .brt-04__t a::after {
outline: 3px solid var(--edge);
outline-offset: 4px;
}
.brt-04__p {
margin: 0;
font-size: .95rem;
line-height: 1.5;
opacity: .8;
text-wrap: pretty;
}
.brt-04:has(#brt-04-dark:checked) {
--page: #14131a;
--panel: #221f2b;
--ink: #f7f5ef;
--muted: #b5b1c2;
--edge: #f7f5ef;
--sh: #f7f5ef;
}
.brt-04:has(#brt-04-dark:checked) .brt-04__moon {
display: none;
}
.brt-04:has(#brt-04-dark:checked) .brt-04__sun {
display: block;
}
@media (prefers-color-scheme: dark) {
.brt-04:not(:has(#brt-04-dark:checked)) {
--page: #14131a;
--panel: #221f2b;
--ink: #f7f5ef;
--muted: #b5b1c2;
--edge: #f7f5ef;
--sh: #f7f5ef;
}
.brt-04:not(:has(#brt-04-dark:checked)) .brt-04__moon {
display: none;
}
.brt-04:not(:has(#brt-04-dark:checked)) .brt-04__sun {
display: block;
}
}
@media (prefers-reduced-motion: reduce) {
.brt-04 *,
.brt-04 *::before,
.brt-04 *::after {
transition: none !important;
animation: none !important;
}
}
@media (forced-colors: active) {
.brt-04__card,
.brt-04__icon,
.brt-04__theme {
border-color: CanvasText;
box-shadow: none;
}
}
/* stage children default to min-width:auto, so a wide heading or grid
track forces the panel past the stage; 0 lets it shrink instead */
.brt-04__stage > * {
min-inline-size: 0;
max-inline-size: 100%;
}
```Here's a working CSS Brutalism 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: Sticker Style Feature Cards
Source: https://codefronts.com/design-styles/css-brutalist/sticker-style-feature-cards/
Six feature cards pasted onto the page at slightly different angles, each one straightening under the pointer as its shadow deepens. Every card's tilt is a single --rot value set inline, so the composition is data, not a pile of :nth-child overrides — and because rotate is its own property now, the hover transition can't fight a transform shorthand.
## HTML
```html
<div class="brt-04">
<input class="brt-04__sr" type="checkbox" id="brt-04-dark">
<label class="brt-04__theme" for="brt-04-dark">
<svg class="brt-04__moon" viewBox="0 0 24 24" fill="none" aria-hidden="true" focusable="false"><path d="M20 14.2A8.2 8.2 0 0 1 9.8 4 8.4 8.4 0 1 0 20 14.2" stroke="currentColor" stroke-width="2.2" stroke-linejoin="round"/></svg>
<svg class="brt-04__sun" viewBox="0 0 24 24" fill="none" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="4.2" stroke="currentColor" stroke-width="2.2"/><path d="M12 3v2.2M12 18.8V21M3 12h2.2M18.8 12H21M5.6 5.6l1.6 1.6M16.8 16.8l1.6 1.6M18.4 5.6l-1.6 1.6M7.2 16.8l-1.6 1.6" stroke="currentColor" stroke-width="2.2" stroke-linecap="round"/></svg>
<span class="brt-04__vh">Dark theme</span>
</label>
<div class="brt-04__stage">
<section class="brt-04__wrap" aria-labelledby="brt-04-h">
<header class="brt-04__head">
<p class="brt-04__eyebrow">Why teams switch</p>
<h2 class="brt-04__h" id="brt-04-h">Everything sticks together</h2>
</header>
<ul class="brt-04__grid">
<li class="brt-04__card" style="--rot:-2deg">
<span class="brt-04__icon"><svg viewBox="0 0 24 24" fill="none" aria-hidden="true" focusable="false"><path d="M13 2 4 14h6l-1 8 9-12h-6z" stroke="currentColor" stroke-width="2.2" stroke-linejoin="round"/></svg></span>
<h3 class="brt-04__t"><a href="#brt-04-h">Deploys in 40 seconds</a></h3>
<p class="brt-04__p">Push to main and the build is live before your coffee lands. Rollbacks are one keystroke.</p>
</li>
<li class="brt-04__card" style="--rot:1.5deg">
<span class="brt-04__icon"><svg viewBox="0 0 24 24" fill="none" aria-hidden="true" focusable="false"><path d="M12 3l7.5 3.4v5.1c0 4.3-3 8-7.5 9.5-4.5-1.5-7.5-5.2-7.5-9.5V6.4z" stroke="currentColor" stroke-width="2.2" stroke-linejoin="round"/><path d="M8.6 12.2l2.4 2.3 4.4-4.6" stroke="currentColor" stroke-width="2.4" stroke-linecap="square"/></svg></span>
<h3 class="brt-04__t"><a href="#brt-04-h">SOC 2 without the binder</a></h3>
<p class="brt-04__p">Audit trails, SSO and device checks ship on by default. Evidence exports as CSV.</p>
</li>
<li class="brt-04__card" style="--rot:-1deg">
<span class="brt-04__icon"><svg viewBox="0 0 24 24" fill="none" aria-hidden="true" focusable="false"><path d="M4 18V8m5 10V4m5 14v-6m5 6V9" stroke="currentColor" stroke-width="2.6" stroke-linecap="square"/></svg></span>
<h3 class="brt-04__t"><a href="#brt-04-h">Numbers you can trust</a></h3>
<p class="brt-04__p">Every metric links back to the raw event. No pipeline mystery, no nightly reconciliation.</p>
</li>
<li class="brt-04__card" style="--rot:2.5deg">
<span class="brt-04__icon"><svg viewBox="0 0 24 24" fill="none" aria-hidden="true" focusable="false"><circle cx="9" cy="8.5" r="3.2" stroke="currentColor" stroke-width="2.2"/><path d="M3 20c1.2-3 3.4-4.5 6-4.5S13.8 17 15 20" stroke="currentColor" stroke-width="2.2" stroke-linecap="square"/><path d="M16 5.5a3.2 3.2 0 0 1 0 6M18 20c-.5-2-1.2-3.4-2.2-4.4" stroke="currentColor" stroke-width="2.2" stroke-linecap="square"/></svg></span>
<h3 class="brt-04__t"><a href="#brt-04-h">Guests, not seats</a></h3>
<p class="brt-04__p">Invite a client to one project for free. They see what you share and nothing else.</p>
</li>
<li class="brt-04__card" style="--rot:-2.5deg">
<span class="brt-04__icon"><svg viewBox="0 0 24 24" fill="none" aria-hidden="true" focusable="false"><rect x="3.5" y="5" width="17" height="14" rx="2" stroke="currentColor" stroke-width="2.2"/><path d="M3.5 9.5h17M8 3.5V6m8-2.5V6" stroke="currentColor" stroke-width="2.2" stroke-linecap="square"/></svg></span>
<h3 class="brt-04__t"><a href="#brt-04-h">Schedules that hold</a></h3>
<p class="brt-04__p">Timezones, freezes and on-call windows are one calendar the whole team can read.</p>
</li>
<li class="brt-04__card" style="--rot:1deg">
<span class="brt-04__icon"><svg viewBox="0 0 24 24" fill="none" aria-hidden="true" focusable="false"><path d="M4 7h16M4 12h11M4 17h7" stroke="currentColor" stroke-width="2.6" stroke-linecap="square"/><circle cx="19" cy="16.5" r="3" stroke="currentColor" stroke-width="2.2"/></svg></span>
<h3 class="brt-04__t"><a href="#brt-04-h">Search that finds it</a></h3>
<p class="brt-04__p">Full-text across docs, tickets and commits, ranked by what your team opened last.</p>
</li>
</ul>
</section>
</div>
</div>
```
## CSS
```css
@import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@500;600;700&display=swap');
.brt-04 {
--page: #fbf7f0;
--panel: #ffffff;
--ink: #0b0b0f;
--on: #0b0b0f;
--muted: #4a4a52;
--lilac: #c4b5fd;
--mint: #86efac;
--coral: #fda4af;
--butter: #fde68a;
--sky: #93c5fd;
--edge: #000000;
--sh: #000000;
--bw: 3px;
--r: 16px;
--icon-r: 50%;
width: 100%;
min-height: 100vh;
min-height: 100svh;
display: block;
position: relative;
box-sizing: border-box;
background: var(--page);
color: var(--ink);
font-family: 'Space Grotesk','Sora',ui-sans-serif,system-ui,sans-serif;
}
.brt-04 *,
.brt-04 *::before,
.brt-04 *::after {
box-sizing: border-box;
}
@supports (color: oklch(0.7 0.1 300)) {
.brt-04 {
--page: oklch(0.975 0.014 84);
--panel: oklch(1 0 0);
--ink: oklch(0.16 0.01 285);
--lilac: oklch(0.82 0.11 296);
--mint: oklch(0.89 0.13 155);
--coral: oklch(0.83 0.10 15);
--butter: oklch(0.92 0.11 95);
--sky: oklch(0.83 0.09 250);
}
}
.brt-04__vh {
position: absolute;
width: 1px;
height: 1px;
margin: -1px;
overflow: hidden;
clip-path: inset(50%);
white-space: nowrap;
}
.brt-04__sr {
position: absolute;
width: 1px;
height: 1px;
opacity: 0;
pointer-events: none;
}
.brt-04__theme {
position: absolute;
inset-block-start: 1rem;
inset-inline-end: 1rem;
z-index: 5;
inline-size: 2.5rem;
block-size: 2.5rem;
display: grid;
place-items: center;
background: var(--panel);
color: var(--ink);
border: var(--bw) solid var(--edge);
border-radius: 10px;
box-shadow: 4px 4px 0 var(--sh);
cursor: pointer;
transition: translate .14s ease, box-shadow .14s ease;
}
.brt-04__theme::after {
content: '';
position: absolute;
inset: -2px;
}
.brt-04__theme svg {
inline-size: 1.25rem;
block-size: 1.25rem;
}
.brt-04__theme:active {
translate: 2px 2px;
box-shadow: 2px 2px 0 var(--sh);
}
.brt-04__sr:focus-visible + .brt-04__theme {
outline: 3px solid var(--edge);
outline-offset: 3px;
}
.brt-04__sun {
display: none;
}
.brt-04__stage {
min-height: 100vh;
min-height: 100svh;
display: grid;
place-items: center;
padding: clamp(1.5rem,5vw,3.5rem);
}
.brt-04__wrap {
inline-size: min(70rem,100%);
}
.brt-04__head {
margin-block-end: clamp(1.75rem,4vw,2.5rem);
text-align: center;
}
.brt-04__eyebrow {
display: inline-block;
margin: 0 0 .7rem;
padding: .3rem .65rem;
rotate: -2deg;
background: var(--sky);
color: var(--on);
border: 2px solid var(--edge);
border-radius: 7px;
box-shadow: 3px 3px 0 var(--sh);
font-size: .74rem;
font-weight: 700;
letter-spacing: .14em;
text-transform: uppercase;
}
.brt-04__h {
margin: 0;
font-size: clamp(2rem,5.2vw,3.1rem);
font-weight: 700;
letter-spacing: -.025em;
line-height: 1.02;
text-wrap: balance;
}
.brt-04__grid {
list-style: none;
margin: 0;
padding: .5rem;
display: grid;
gap: clamp(1.25rem,2.8vw,2rem);
grid-template-columns: repeat(auto-fit,minmax(min(16rem,100%),1fr));
}
.brt-04__card {
position: relative;
display: flex;
flex-direction: column;
gap: .65rem;
padding: clamp(1.1rem,2vw,1.5rem);
border: var(--bw) solid var(--edge);
border-radius: var(--r);
box-shadow: 6px 6px 0 var(--sh);
color: var(--on);
rotate: var(--rot,0deg);
transition: rotate .16s ease, translate .16s ease, box-shadow .16s ease;
}
.brt-04__card:nth-child(4n+1) {
background: var(--butter);
}
.brt-04__card:nth-child(4n+2) {
background: var(--mint);
}
.brt-04__card:nth-child(4n+3) {
background: var(--lilac);
}
.brt-04__card:nth-child(4n+4) {
background: var(--coral);
}
@media (hover: hover) {
.brt-04__card:hover {
rotate: 0deg;
translate: -2px -3px;
box-shadow: 10px 10px 0 var(--sh);
z-index: 2;
}
}
.brt-04__card:has(a:focus-visible) {
rotate: 0deg;
translate: -2px -3px;
box-shadow: 10px 10px 0 var(--sh);
z-index: 2;
}
.brt-04__icon {
display: grid;
place-items: center;
inline-size: 3rem;
block-size: 3rem;
background: var(--panel);
color: var(--ink);
border: var(--bw) solid var(--edge);
border-radius: var(--icon-r);
box-shadow: 3px 3px 0 var(--sh);
}
.brt-04__icon svg {
inline-size: 1.5rem;
block-size: 1.5rem;
}
.brt-04__t {
margin: .35rem 0 0;
font-size: 1.2rem;
font-weight: 700;
letter-spacing: -.015em;
line-height: 1.15;
}
.brt-04__t a {
color: inherit;
text-decoration: none;
}
.brt-04__t a::after {
content: '';
position: absolute;
inset: 0;
border-radius: var(--r);
}
.brt-04__t a:focus-visible {
outline: none;
}
.brt-04__card:has(a:focus-visible) .brt-04__t a::after {
outline: 3px solid var(--edge);
outline-offset: 4px;
}
.brt-04__p {
margin: 0;
font-size: .95rem;
line-height: 1.5;
opacity: .8;
text-wrap: pretty;
}
.brt-04:has(#brt-04-dark:checked) {
--page: #14131a;
--panel: #221f2b;
--ink: #f7f5ef;
--muted: #b5b1c2;
--edge: #f7f5ef;
--sh: #f7f5ef;
}
.brt-04:has(#brt-04-dark:checked) .brt-04__moon {
display: none;
}
.brt-04:has(#brt-04-dark:checked) .brt-04__sun {
display: block;
}
@media (prefers-color-scheme: dark) {
.brt-04:not(:has(#brt-04-dark:checked)) {
--page: #14131a;
--panel: #221f2b;
--ink: #f7f5ef;
--muted: #b5b1c2;
--edge: #f7f5ef;
--sh: #f7f5ef;
}
.brt-04:not(:has(#brt-04-dark:checked)) .brt-04__moon {
display: none;
}
.brt-04:not(:has(#brt-04-dark:checked)) .brt-04__sun {
display: block;
}
}
@media (prefers-reduced-motion: reduce) {
.brt-04 *,
.brt-04 *::before,
.brt-04 *::after {
transition: none !important;
animation: none !important;
}
}
@media (forced-colors: active) {
.brt-04__card,
.brt-04__icon,
.brt-04__theme {
border-color: CanvasText;
box-shadow: none;
}
}
/* stage children default to min-width:auto, so a wide heading or grid
track forces the panel past the stage; 0 lets it shrink instead */
.brt-04__stage > * {
min-inline-size: 0;
max-inline-size: 100%;
}
```How this works
Tilt as data. Each card reads its own angle from an inline property, which means the visual rhythm lives in the HTML where you can see it:
<li class="brt-04__card" style="--rot:-2deg">…
.brt-04__card{ rotate:var(--rot,0deg); transition:rotate .16s ease, box-shadow .16s ease, translate .16s ease; }
.brt-04__card:hover{ rotate:0deg; translate:-2px -3px; box-shadow:10px 10px 0 var(--sh); }Using the standalone rotate property (not transform: rotate()) matters here: hover also nudges translate, and with the shorthand the two rules would overwrite each other. Independent transform properties compose and interpolate separately.
Keyboard parity. A hover-only effect is a broken effect. The card's link is the focus target, so the card straightens from :has():
.brt-04__card:has(a:focus-visible){ rotate:0deg; box-shadow:10px 10px 0 var(--sh); }Sticker physics. Real stickers have a hard edge and a hard shadow. Keep the border 3px, the radius 12-16px, and the shadow offset larger than the border — at 4px border with a 4px shadow the two read as one line and the sticker illusion collapses.
Make it yours
- Change the mood by editing the inline
--rotvalues: ±1deg reads accidental and expensive, ±4deg reads playful, ±8deg reads chaotic. - Cycle the pastel fills by editing the four
:nth-childrules, or set a per-card--fillinline for full control. - Swap the icon circles for squares by setting
--icon-r: 10px; the border and shadow tokens stay. - For a two-up layout on wide screens, raise the
minmax()floor to22rem. No media queries to touch. - Add a
--rotof 0 to one card and give it a bigger shadow to mark a featured item without changing its colour.
Gotchas — read before shipping
- Rotated boxes overflow their grid cell. Give the grid a little extra
gapand the section some padding, or the outer cards clip against the viewport edge. - Don't rotate text-heavy cards more than about 4deg — glyph rasterisation gets soft and long headings start to look like a mistake.
- Animate
rotate/translate/box-shadow, nevermarginorinset— the first pair is compositor-friendly, the second forces layout on every frame. - Rotation creates a containing block for absolutely-positioned children, so a badge pinned inside a tilted card rotates with it. That is usually what you want; if not, pin the badge outside the card.
- On touch,
:hoversticks after a tap in some browsers. The@media (hover: hover)guard keeps mobile showing the intended tilt. - Keep the whole card clickable via a stretched pseudo-element on the link rather than wrapping a heading and paragraph in an anchor — the link text stays meaningful to screen readers.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 114+ | 17.5+ | 121+ | 114+ |
Floor set by :has(), oklch(), text-wrap as this demo is written. The core technique itself goes back further — Chrome 105+.
Independent rotate/translate/scale properties are Chrome 104 / Safari 14.1 / Firefox 72. :has() (Chrome 105 / Safari 15.4 / Firefox 121) gives keyboard parity and drives the CSS-only theme toggle; without it hover still works. oklch() sits behind @supports with hex first.