Pure TailwindMIT licensed

Tailwind Stratified Bento Grid Layout

Twelve tiles on a carmine canvas, each split by a hard-stop duotone gradient, and each carrying its inverse as a before: layer that wipes down on hover via clip-path: inset(). Every one of the CSS version's twelve placement rules moves onto its tile, so the bento's weighting is finally readable in the markup.

Live Demo
Plain CSSTailwind v4
Try it

Untitled UI Pro: 5,000+ React + Tailwind CSS v4 components · from $349 one-time

Untitled UI React · Affiliate link

Get Untitled UI Pro

The code

<section class="tcg-07 w-full min-h-svh flex items-center justify-center bg-tcg07-bg font-tcg07-sans text-tcg07-ink p-9" aria-label="Stratified duotone bento grid demo">
  <div class="w-full max-w-[1100px] grid grid-cols-6 max-[640px]:grid-cols-3 [grid-auto-rows:110px] gap-3.5">

    <a href="#users" style="--top:#f4a572;--bot:#d97f4f" class="group relative isolate col-span-2 max-[640px]:col-span-1 flex flex-col justify-end gap-1 px-4.5 py-4 rounded-[14px] overflow-hidden no-underline text-inherit bg-linear-[to_bottom,var(--top)_0_50%,var(--bot)_50%_100%] before:absolute before:inset-0 before:z-0 before:bg-linear-[to_bottom,var(--bot)_0_50%,var(--top)_50%_100%] before:[clip-path:inset(0_0_100%_0)] before:transition-[clip-path] before:duration-[380ms] before:ease-tcg07 hover:before:[clip-path:inset(0)] focus-visible:outline-2 focus-visible:outline-white focus-visible:outline-offset-2 motion-reduce:before:hidden">
      <span class="relative z-1 text-[.68rem] font-semibold tracking-[0.12em] uppercase text-tcg07-shade">Active users</span>
      <span class="relative z-1 text-[1.8rem] font-extrabold tracking-[-0.02em] leading-none text-white [text-shadow:0_1px_2px_oklch(0_0_0/0.22)] tabular-nums">247,318</span>
      <span class="relative z-1 text-[.72rem] font-semibold text-white/92">&#9650; 12.4% this week</span>
    </a>

    <a href="#uptime" style="--top:#1f8c6e;--bot:#0f5b48" class="group relative isolate col-span-1 flex flex-col items-center justify-center text-center gap-1 px-4.5 py-4 rounded-[14px] overflow-hidden no-underline text-inherit bg-linear-[to_bottom,var(--top)_0_50%,var(--bot)_50%_100%] before:absolute before:inset-0 before:z-0 before:bg-linear-[to_bottom,var(--bot)_0_50%,var(--top)_50%_100%] before:[clip-path:inset(0_0_100%_0)] before:transition-[clip-path] before:duration-[380ms] before:ease-tcg07 hover:before:[clip-path:inset(0)] focus-visible:outline-2 focus-visible:outline-white focus-visible:outline-offset-2 motion-reduce:before:hidden">
      <span class="relative z-1 text-[1.8rem] leading-none text-white [text-shadow:0_1px_2px_oklch(0_0_0/0.18)]" aria-hidden="true">&#10003;</span>
      <span class="relative z-1 text-[.95rem] font-bold leading-[1.25] text-white [text-shadow:0_1px_2px_oklch(0_0_0/0.22)]">99.98% uptime</span>
    </a>

    <a href="#plan" style="--top:#c4b5fd;--bot:#9b87e5" class="group relative isolate col-span-1 row-span-2 flex flex-col justify-end gap-1 px-4.5 py-4 rounded-[14px] overflow-hidden no-underline text-inherit bg-linear-[to_bottom,var(--top)_0_50%,var(--bot)_50%_100%] before:absolute before:inset-0 before:z-0 before:bg-linear-[to_bottom,var(--bot)_0_50%,var(--top)_50%_100%] before:[clip-path:inset(0_0_100%_0)] before:transition-[clip-path] before:duration-[380ms] before:ease-tcg07 hover:before:[clip-path:inset(0)] focus-visible:outline-2 focus-visible:outline-white focus-visible:outline-offset-2 motion-reduce:before:hidden">
      <span class="relative z-1 text-[.68rem] font-semibold tracking-[0.12em] uppercase text-tcg07-shade">Plan</span>
      <span class="relative z-1 text-[.95rem] font-bold leading-[1.25] text-white [text-shadow:0_1px_2px_oklch(0_0_0/0.22)]">Pro</span>
      <span class="relative z-1 text-[1.5rem] font-extrabold leading-none text-white [text-shadow:0_1px_2px_oklch(0_0_0/0.22)]">$24<small class="ml-0.5 text-[.7rem] font-semibold opacity-85">/mo</small></span>
      <span class="relative z-1 self-start mt-1 px-2.25 py-1.25 rounded-md bg-black/22 text-[.74rem] font-bold text-white transition-[background] duration-250 group-hover:bg-black/38 motion-reduce:transition-none">Upgrade &rarr;</span>
    </a>

    <a href="#cache" style="--top:#34d399;--bot:#0f7a52" class="group relative isolate col-span-1 flex flex-col items-center justify-center text-center gap-1 px-4.5 py-4 rounded-[14px] overflow-hidden no-underline text-inherit bg-linear-[to_bottom,var(--top)_0_50%,var(--bot)_50%_100%] before:absolute before:inset-0 before:z-0 before:bg-linear-[to_bottom,var(--bot)_0_50%,var(--top)_50%_100%] before:[clip-path:inset(0_0_100%_0)] before:transition-[clip-path] before:duration-[380ms] before:ease-tcg07 hover:before:[clip-path:inset(0)] focus-visible:outline-2 focus-visible:outline-white focus-visible:outline-offset-2 motion-reduce:before:hidden">
      <span class="relative z-1 text-[1.8rem] leading-none text-white [text-shadow:0_1px_2px_oklch(0_0_0/0.18)]" aria-hidden="true">&#9889;</span>
      <span class="relative z-1 text-[.95rem] font-bold leading-[1.25] text-white [text-shadow:0_1px_2px_oklch(0_0_0/0.22)]">Edge cache</span>
    </a>

    <a href="#search" style="--top:#f0bb91;--bot:#cc8a5e" class="group relative isolate col-span-1 flex flex-col items-center justify-center text-center gap-1 px-4.5 py-4 rounded-[14px] overflow-hidden no-underline text-inherit bg-linear-[to_bottom,var(--top)_0_50%,var(--bot)_50%_100%] before:absolute before:inset-0 before:z-0 before:bg-linear-[to_bottom,var(--bot)_0_50%,var(--top)_50%_100%] before:[clip-path:inset(0_0_100%_0)] before:transition-[clip-path] before:duration-[380ms] before:ease-tcg07 hover:before:[clip-path:inset(0)] focus-visible:outline-2 focus-visible:outline-white focus-visible:outline-offset-2 motion-reduce:before:hidden">
      <span class="relative z-1 text-[1.8rem] leading-none text-white [text-shadow:0_1px_2px_oklch(0_0_0/0.18)]" aria-hidden="true">&#8984;</span>
      <span class="relative z-1 text-[.95rem] font-bold leading-[1.25] text-white [text-shadow:0_1px_2px_oklch(0_0_0/0.22)]">Command search</span>
    </a>

    <a href="#story" style="--top:#f9c1cf;--bot:#e187a0" class="group relative isolate col-span-3 max-[640px]:col-span-2 flex flex-col justify-end gap-1 px-4.5 py-4 rounded-[14px] overflow-hidden no-underline text-inherit bg-linear-[to_bottom,var(--top)_0_50%,var(--bot)_50%_100%] before:absolute before:inset-0 before:z-0 before:bg-linear-[to_bottom,var(--bot)_0_50%,var(--top)_50%_100%] before:[clip-path:inset(0_0_100%_0)] before:transition-[clip-path] before:duration-[380ms] before:ease-tcg07 hover:before:[clip-path:inset(0)] focus-visible:outline-2 focus-visible:outline-white focus-visible:outline-offset-2 motion-reduce:before:hidden">
      <span class="relative z-1 text-[.68rem] font-semibold tracking-[0.12em] uppercase text-tcg07-shade">Customer story</span>
      <span class="relative z-1 text-[.95rem] font-bold leading-[1.25] text-white [text-shadow:0_1px_2px_oklch(0_0_0/0.22)]">It paid back in 6 weeks.</span>
      <span class="relative z-1 text-[.68rem] font-semibold text-tcg07-shade">Maya Chen &middot; Linear</span>
    </a>

    <a href="#rating" style="--top:#c5da9c;--bot:#94b864" class="group relative isolate col-span-1 flex flex-col items-center justify-center text-center gap-1 px-4.5 py-4 rounded-[14px] overflow-hidden no-underline text-inherit bg-linear-[to_bottom,var(--top)_0_50%,var(--bot)_50%_100%] before:absolute before:inset-0 before:z-0 before:bg-linear-[to_bottom,var(--bot)_0_50%,var(--top)_50%_100%] before:[clip-path:inset(0_0_100%_0)] before:transition-[clip-path] before:duration-[380ms] before:ease-tcg07 hover:before:[clip-path:inset(0)] focus-visible:outline-2 focus-visible:outline-white focus-visible:outline-offset-2 motion-reduce:before:hidden">
      <span class="relative z-1 text-[1.8rem] leading-none text-white [text-shadow:0_1px_2px_oklch(0_0_0/0.18)]" aria-hidden="true">&#9733;</span>
      <span class="relative z-1 text-[.95rem] font-bold leading-[1.25] text-white [text-shadow:0_1px_2px_oklch(0_0_0/0.22)] tabular-nums">4.9 / 5</span>
    </a>

    <a href="#revenue" style="--top:#fff4a3;--bot:#e8d558" class="group relative isolate col-span-2 max-[640px]:col-span-1 flex flex-col justify-end gap-1 px-4.5 py-4 rounded-[14px] overflow-hidden no-underline text-inherit bg-linear-[to_bottom,var(--top)_0_50%,var(--bot)_50%_100%] before:absolute before:inset-0 before:z-0 before:bg-linear-[to_bottom,var(--bot)_0_50%,var(--top)_50%_100%] before:[clip-path:inset(0_0_100%_0)] before:transition-[clip-path] before:duration-[380ms] before:ease-tcg07 hover:before:[clip-path:inset(0)] focus-visible:outline-2 focus-visible:outline-tcg07-ink focus-visible:outline-offset-2 motion-reduce:before:hidden">
      <span class="relative z-1 text-[.68rem] font-semibold tracking-[0.12em] uppercase text-tcg07-shade">Monthly revenue</span>
      <span class="relative z-1 text-[1.8rem] font-extrabold tracking-[-0.02em] leading-none text-tcg07-ink tabular-nums">$2.4M</span>
      <span class="relative z-1 text-[.72rem] font-semibold text-tcg07-shade">&#9650; 38% YoY</span>
    </a>

    <a href="#api" style="--top:#1f8c6e;--bot:#0f5b48" class="group relative isolate col-span-1 flex flex-col items-center justify-center text-center gap-1 px-4.5 py-4 rounded-[14px] overflow-hidden no-underline text-inherit bg-linear-[to_bottom,var(--top)_0_50%,var(--bot)_50%_100%] before:absolute before:inset-0 before:z-0 before:bg-linear-[to_bottom,var(--bot)_0_50%,var(--top)_50%_100%] before:[clip-path:inset(0_0_100%_0)] before:transition-[clip-path] before:duration-[380ms] before:ease-tcg07 hover:before:[clip-path:inset(0)] focus-visible:outline-2 focus-visible:outline-white focus-visible:outline-offset-2 motion-reduce:before:hidden">
      <span class="relative z-1 text-[1.8rem] leading-none text-white [text-shadow:0_1px_2px_oklch(0_0_0/0.18)]" aria-hidden="true">&#9881;</span>
      <span class="relative z-1 text-[.95rem] font-bold leading-[1.25] text-white [text-shadow:0_1px_2px_oklch(0_0_0/0.22)]">API v3</span>
    </a>

    <a href="#dark" style="--top:#f4a572;--bot:#d97f4f" class="group relative isolate col-span-1 flex flex-col items-center justify-center text-center gap-1 px-4.5 py-4 rounded-[14px] overflow-hidden no-underline text-inherit bg-linear-[to_bottom,var(--top)_0_50%,var(--bot)_50%_100%] before:absolute before:inset-0 before:z-0 before:bg-linear-[to_bottom,var(--bot)_0_50%,var(--top)_50%_100%] before:[clip-path:inset(0_0_100%_0)] before:transition-[clip-path] before:duration-[380ms] before:ease-tcg07 hover:before:[clip-path:inset(0)] focus-visible:outline-2 focus-visible:outline-white focus-visible:outline-offset-2 motion-reduce:before:hidden">
      <span class="relative z-1 text-[1.8rem] leading-none text-white [text-shadow:0_1px_2px_oklch(0_0_0/0.18)]" aria-hidden="true">&#9790;</span>
      <span class="relative z-1 text-[.95rem] font-bold leading-[1.25] text-white [text-shadow:0_1px_2px_oklch(0_0_0/0.22)]">Dark mode</span>
    </a>

    <a href="#sync" style="--top:#c4b5fd;--bot:#9b87e5" class="group relative isolate col-span-1 flex flex-col items-center justify-center text-center gap-1 px-4.5 py-4 rounded-[14px] overflow-hidden no-underline text-inherit bg-linear-[to_bottom,var(--top)_0_50%,var(--bot)_50%_100%] before:absolute before:inset-0 before:z-0 before:bg-linear-[to_bottom,var(--bot)_0_50%,var(--top)_50%_100%] before:[clip-path:inset(0_0_100%_0)] before:transition-[clip-path] before:duration-[380ms] before:ease-tcg07 hover:before:[clip-path:inset(0)] focus-visible:outline-2 focus-visible:outline-white focus-visible:outline-offset-2 motion-reduce:before:hidden">
      <span class="relative z-1 text-[1.8rem] leading-none text-white [text-shadow:0_1px_2px_oklch(0_0_0/0.18)]" aria-hidden="true">&#10227;</span>
      <span class="relative z-1 text-[.95rem] font-bold leading-[1.25] text-white [text-shadow:0_1px_2px_oklch(0_0_0/0.22)]">Auto sync</span>
    </a>

    <a href="#trial" style="--top:#f9c1cf;--bot:#e187a0" class="group relative isolate col-span-3 max-[640px]:col-span-2 flex flex-col justify-end gap-1 px-4.5 py-4 rounded-[14px] overflow-hidden no-underline text-inherit bg-linear-[to_bottom,var(--top)_0_50%,var(--bot)_50%_100%] before:absolute before:inset-0 before:z-0 before:bg-linear-[to_bottom,var(--bot)_0_50%,var(--top)_50%_100%] before:[clip-path:inset(0_0_100%_0)] before:transition-[clip-path] before:duration-[380ms] before:ease-tcg07 hover:before:[clip-path:inset(0)] focus-visible:outline-2 focus-visible:outline-white focus-visible:outline-offset-2 motion-reduce:before:hidden">
      <span class="relative z-1 text-[.68rem] font-semibold tracking-[0.12em] uppercase text-tcg07-shade">Get started</span>
      <span class="relative z-1 text-[.95rem] font-bold leading-[1.25] text-white [text-shadow:0_1px_2px_oklch(0_0_0/0.22)]">Start your 14-day free trial</span>
      <span class="relative z-1 self-start mt-1 px-2.25 py-1.25 rounded-md bg-black/22 text-[.74rem] font-bold text-white transition-[background] duration-250 group-hover:bg-black/38 motion-reduce:transition-none">Create account &rarr;</span>
    </a>

  </div>
</section>
@import "tailwindcss";

@theme {
  --color-tcg07-bg: #c93a4a;
  --color-tcg07-bg: oklch(0.55 0.19 20);
  --color-tcg07-ink: #1a1414;
  --color-tcg07-ink: oklch(0.2 0.02 30);
  --color-tcg07-shade: #3a2a2a;
  --color-tcg07-shade: oklch(0.3 0.02 30);
  --font-tcg07-sans: 'Space Grotesk', system-ui, sans-serif;
  --ease-tcg07: cubic-bezier(0.65, 0.05, 0.35, 1);
}
/* Root rule: the full-bleed contract. */

.tcg-07 {
  width: 100%;
  min-height: 100svh;
}

.tcg-07 ::selection {
  background: #fff;
  color: #c93a4a;
}

Setup — do this once per project

Skip this if your project already runs Tailwind v4.

1Load Tailwind
<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.

2Add the stylesheetRequiredthe @theme block is what makes the custom utilities exist
@import "tailwindcss";

@theme {
  --color-tcg07-bg: #c93a4a;
  --color-tcg07-bg: oklch(0.55 0.19 20);
  --color-tcg07-ink: #1a1414;
  --color-tcg07-ink: oklch(0.2 0.02 30);
  --color-tcg07-shade: #3a2a2a;
  --color-tcg07-shade: oklch(0.3 0.02 30);
  --font-tcg07-sans: 'Space Grotesk', system-ui, sans-serif;
  --ease-tcg07: cubic-bezier(0.65, 0.05, 0.35, 1);
}
/* Root rule: the full-bleed contract. */

.tcg-07 {
  width: 100%;
  min-height: 100svh;
}

.tcg-07 ::selection {
  background: #fff;
  color: #c93a4a;
}
3Fonts used by this demooptional — skip if you have your own type stack
<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=Space+Grotesk:wght@400;500;600;700;800&display=swap">

What changed in the port

Which parts became utilities, which stayed CSS, and why.

  • Twelve placement rules become twelve pairs of span utilities on the tiles, and the stylesheet's whole placement block disappears. On a bento this is the single biggest structural win of the port.
  • Both clip-path states sit on the same element, so the closed and open geometry cannot drift apart — the same argument the clip-path hamburger makes, applied to a wipe.
  • The CSS version's rgba(0,0,0,.55) kickers became a solid --color-tcg07-shade token: alpha-black on a mid-tone duotone is a contrast gamble at small sizes.
  • The easing curve is an @theme entry, which mints a real ease-tcg07 utility — a curve reused by twelve tiles is exactly what a token is for.
  • motion-reduce:before:hidden removes the wipe rather than slowing it, which is the correct reduced-motion answer for a full-tile colour sweep.
  • Tiles keep group so the CTA pill can darken with the tile's own hover (group-hover:bg-black/38) instead of needing a descendant rule.
Paste this into ChatGPT, Claude, Cursor, or any coding assistant. The block below is pre-framed with everything the AI needs to integrate this demo into your project — markup, styles, scoping notes, and the source URL. Hit Copy and paste straight into your chat.
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 Stratified Bento Grid Layout
Source: https://codefronts.com/layouts/tailwind-card-grid-layout/tailwind-stratified-bento-grid-layout/

Twelve tiles on a carmine canvas, each split by a hard-stop duotone gradient, and each carrying its inverse as a before: layer that wipes down on hover via clip-path: inset(). Every one of the CSS version's twelve placement rules moves onto its tile, so the bento's weighting is finally readable in the markup.
## HTML
```html
<section class="tcg-07 w-full min-h-svh flex items-center justify-center bg-tcg07-bg font-tcg07-sans text-tcg07-ink p-9" aria-label="Stratified duotone bento grid demo">
  <div class="w-full max-w-[1100px] grid grid-cols-6 max-[640px]:grid-cols-3 [grid-auto-rows:110px] gap-3.5">

    <a href="#users" style="--top:#f4a572;--bot:#d97f4f" class="group relative isolate col-span-2 max-[640px]:col-span-1 flex flex-col justify-end gap-1 px-4.5 py-4 rounded-[14px] overflow-hidden no-underline text-inherit bg-linear-[to_bottom,var(--top)_0_50%,var(--bot)_50%_100%] before:absolute before:inset-0 before:z-0 before:bg-linear-[to_bottom,var(--bot)_0_50%,var(--top)_50%_100%] before:[clip-path:inset(0_0_100%_0)] before:transition-[clip-path] before:duration-[380ms] before:ease-tcg07 hover:before:[clip-path:inset(0)] focus-visible:outline-2 focus-visible:outline-white focus-visible:outline-offset-2 motion-reduce:before:hidden">
      <span class="relative z-1 text-[.68rem] font-semibold tracking-[0.12em] uppercase text-tcg07-shade">Active users</span>
      <span class="relative z-1 text-[1.8rem] font-extrabold tracking-[-0.02em] leading-none text-white [text-shadow:0_1px_2px_oklch(0_0_0/0.22)] tabular-nums">247,318</span>
      <span class="relative z-1 text-[.72rem] font-semibold text-white/92">&#9650; 12.4% this week</span>
    </a>

    <a href="#uptime" style="--top:#1f8c6e;--bot:#0f5b48" class="group relative isolate col-span-1 flex flex-col items-center justify-center text-center gap-1 px-4.5 py-4 rounded-[14px] overflow-hidden no-underline text-inherit bg-linear-[to_bottom,var(--top)_0_50%,var(--bot)_50%_100%] before:absolute before:inset-0 before:z-0 before:bg-linear-[to_bottom,var(--bot)_0_50%,var(--top)_50%_100%] before:[clip-path:inset(0_0_100%_0)] before:transition-[clip-path] before:duration-[380ms] before:ease-tcg07 hover:before:[clip-path:inset(0)] focus-visible:outline-2 focus-visible:outline-white focus-visible:outline-offset-2 motion-reduce:before:hidden">
      <span class="relative z-1 text-[1.8rem] leading-none text-white [text-shadow:0_1px_2px_oklch(0_0_0/0.18)]" aria-hidden="true">&#10003;</span>
      <span class="relative z-1 text-[.95rem] font-bold leading-[1.25] text-white [text-shadow:0_1px_2px_oklch(0_0_0/0.22)]">99.98% uptime</span>
    </a>

    <a href="#plan" style="--top:#c4b5fd;--bot:#9b87e5" class="group relative isolate col-span-1 row-span-2 flex flex-col justify-end gap-1 px-4.5 py-4 rounded-[14px] overflow-hidden no-underline text-inherit bg-linear-[to_bottom,var(--top)_0_50%,var(--bot)_50%_100%] before:absolute before:inset-0 before:z-0 before:bg-linear-[to_bottom,var(--bot)_0_50%,var(--top)_50%_100%] before:[clip-path:inset(0_0_100%_0)] before:transition-[clip-path] before:duration-[380ms] before:ease-tcg07 hover:before:[clip-path:inset(0)] focus-visible:outline-2 focus-visible:outline-white focus-visible:outline-offset-2 motion-reduce:before:hidden">
      <span class="relative z-1 text-[.68rem] font-semibold tracking-[0.12em] uppercase text-tcg07-shade">Plan</span>
      <span class="relative z-1 text-[.95rem] font-bold leading-[1.25] text-white [text-shadow:0_1px_2px_oklch(0_0_0/0.22)]">Pro</span>
      <span class="relative z-1 text-[1.5rem] font-extrabold leading-none text-white [text-shadow:0_1px_2px_oklch(0_0_0/0.22)]">$24<small class="ml-0.5 text-[.7rem] font-semibold opacity-85">/mo</small></span>
      <span class="relative z-1 self-start mt-1 px-2.25 py-1.25 rounded-md bg-black/22 text-[.74rem] font-bold text-white transition-[background] duration-250 group-hover:bg-black/38 motion-reduce:transition-none">Upgrade &rarr;</span>
    </a>

    <a href="#cache" style="--top:#34d399;--bot:#0f7a52" class="group relative isolate col-span-1 flex flex-col items-center justify-center text-center gap-1 px-4.5 py-4 rounded-[14px] overflow-hidden no-underline text-inherit bg-linear-[to_bottom,var(--top)_0_50%,var(--bot)_50%_100%] before:absolute before:inset-0 before:z-0 before:bg-linear-[to_bottom,var(--bot)_0_50%,var(--top)_50%_100%] before:[clip-path:inset(0_0_100%_0)] before:transition-[clip-path] before:duration-[380ms] before:ease-tcg07 hover:before:[clip-path:inset(0)] focus-visible:outline-2 focus-visible:outline-white focus-visible:outline-offset-2 motion-reduce:before:hidden">
      <span class="relative z-1 text-[1.8rem] leading-none text-white [text-shadow:0_1px_2px_oklch(0_0_0/0.18)]" aria-hidden="true">&#9889;</span>
      <span class="relative z-1 text-[.95rem] font-bold leading-[1.25] text-white [text-shadow:0_1px_2px_oklch(0_0_0/0.22)]">Edge cache</span>
    </a>

    <a href="#search" style="--top:#f0bb91;--bot:#cc8a5e" class="group relative isolate col-span-1 flex flex-col items-center justify-center text-center gap-1 px-4.5 py-4 rounded-[14px] overflow-hidden no-underline text-inherit bg-linear-[to_bottom,var(--top)_0_50%,var(--bot)_50%_100%] before:absolute before:inset-0 before:z-0 before:bg-linear-[to_bottom,var(--bot)_0_50%,var(--top)_50%_100%] before:[clip-path:inset(0_0_100%_0)] before:transition-[clip-path] before:duration-[380ms] before:ease-tcg07 hover:before:[clip-path:inset(0)] focus-visible:outline-2 focus-visible:outline-white focus-visible:outline-offset-2 motion-reduce:before:hidden">
      <span class="relative z-1 text-[1.8rem] leading-none text-white [text-shadow:0_1px_2px_oklch(0_0_0/0.18)]" aria-hidden="true">&#8984;</span>
      <span class="relative z-1 text-[.95rem] font-bold leading-[1.25] text-white [text-shadow:0_1px_2px_oklch(0_0_0/0.22)]">Command search</span>
    </a>

    <a href="#story" style="--top:#f9c1cf;--bot:#e187a0" class="group relative isolate col-span-3 max-[640px]:col-span-2 flex flex-col justify-end gap-1 px-4.5 py-4 rounded-[14px] overflow-hidden no-underline text-inherit bg-linear-[to_bottom,var(--top)_0_50%,var(--bot)_50%_100%] before:absolute before:inset-0 before:z-0 before:bg-linear-[to_bottom,var(--bot)_0_50%,var(--top)_50%_100%] before:[clip-path:inset(0_0_100%_0)] before:transition-[clip-path] before:duration-[380ms] before:ease-tcg07 hover:before:[clip-path:inset(0)] focus-visible:outline-2 focus-visible:outline-white focus-visible:outline-offset-2 motion-reduce:before:hidden">
      <span class="relative z-1 text-[.68rem] font-semibold tracking-[0.12em] uppercase text-tcg07-shade">Customer story</span>
      <span class="relative z-1 text-[.95rem] font-bold leading-[1.25] text-white [text-shadow:0_1px_2px_oklch(0_0_0/0.22)]">It paid back in 6 weeks.</span>
      <span class="relative z-1 text-[.68rem] font-semibold text-tcg07-shade">Maya Chen &middot; Linear</span>
    </a>

    <a href="#rating" style="--top:#c5da9c;--bot:#94b864" class="group relative isolate col-span-1 flex flex-col items-center justify-center text-center gap-1 px-4.5 py-4 rounded-[14px] overflow-hidden no-underline text-inherit bg-linear-[to_bottom,var(--top)_0_50%,var(--bot)_50%_100%] before:absolute before:inset-0 before:z-0 before:bg-linear-[to_bottom,var(--bot)_0_50%,var(--top)_50%_100%] before:[clip-path:inset(0_0_100%_0)] before:transition-[clip-path] before:duration-[380ms] before:ease-tcg07 hover:before:[clip-path:inset(0)] focus-visible:outline-2 focus-visible:outline-white focus-visible:outline-offset-2 motion-reduce:before:hidden">
      <span class="relative z-1 text-[1.8rem] leading-none text-white [text-shadow:0_1px_2px_oklch(0_0_0/0.18)]" aria-hidden="true">&#9733;</span>
      <span class="relative z-1 text-[.95rem] font-bold leading-[1.25] text-white [text-shadow:0_1px_2px_oklch(0_0_0/0.22)] tabular-nums">4.9 / 5</span>
    </a>

    <a href="#revenue" style="--top:#fff4a3;--bot:#e8d558" class="group relative isolate col-span-2 max-[640px]:col-span-1 flex flex-col justify-end gap-1 px-4.5 py-4 rounded-[14px] overflow-hidden no-underline text-inherit bg-linear-[to_bottom,var(--top)_0_50%,var(--bot)_50%_100%] before:absolute before:inset-0 before:z-0 before:bg-linear-[to_bottom,var(--bot)_0_50%,var(--top)_50%_100%] before:[clip-path:inset(0_0_100%_0)] before:transition-[clip-path] before:duration-[380ms] before:ease-tcg07 hover:before:[clip-path:inset(0)] focus-visible:outline-2 focus-visible:outline-tcg07-ink focus-visible:outline-offset-2 motion-reduce:before:hidden">
      <span class="relative z-1 text-[.68rem] font-semibold tracking-[0.12em] uppercase text-tcg07-shade">Monthly revenue</span>
      <span class="relative z-1 text-[1.8rem] font-extrabold tracking-[-0.02em] leading-none text-tcg07-ink tabular-nums">$2.4M</span>
      <span class="relative z-1 text-[.72rem] font-semibold text-tcg07-shade">&#9650; 38% YoY</span>
    </a>

    <a href="#api" style="--top:#1f8c6e;--bot:#0f5b48" class="group relative isolate col-span-1 flex flex-col items-center justify-center text-center gap-1 px-4.5 py-4 rounded-[14px] overflow-hidden no-underline text-inherit bg-linear-[to_bottom,var(--top)_0_50%,var(--bot)_50%_100%] before:absolute before:inset-0 before:z-0 before:bg-linear-[to_bottom,var(--bot)_0_50%,var(--top)_50%_100%] before:[clip-path:inset(0_0_100%_0)] before:transition-[clip-path] before:duration-[380ms] before:ease-tcg07 hover:before:[clip-path:inset(0)] focus-visible:outline-2 focus-visible:outline-white focus-visible:outline-offset-2 motion-reduce:before:hidden">
      <span class="relative z-1 text-[1.8rem] leading-none text-white [text-shadow:0_1px_2px_oklch(0_0_0/0.18)]" aria-hidden="true">&#9881;</span>
      <span class="relative z-1 text-[.95rem] font-bold leading-[1.25] text-white [text-shadow:0_1px_2px_oklch(0_0_0/0.22)]">API v3</span>
    </a>

    <a href="#dark" style="--top:#f4a572;--bot:#d97f4f" class="group relative isolate col-span-1 flex flex-col items-center justify-center text-center gap-1 px-4.5 py-4 rounded-[14px] overflow-hidden no-underline text-inherit bg-linear-[to_bottom,var(--top)_0_50%,var(--bot)_50%_100%] before:absolute before:inset-0 before:z-0 before:bg-linear-[to_bottom,var(--bot)_0_50%,var(--top)_50%_100%] before:[clip-path:inset(0_0_100%_0)] before:transition-[clip-path] before:duration-[380ms] before:ease-tcg07 hover:before:[clip-path:inset(0)] focus-visible:outline-2 focus-visible:outline-white focus-visible:outline-offset-2 motion-reduce:before:hidden">
      <span class="relative z-1 text-[1.8rem] leading-none text-white [text-shadow:0_1px_2px_oklch(0_0_0/0.18)]" aria-hidden="true">&#9790;</span>
      <span class="relative z-1 text-[.95rem] font-bold leading-[1.25] text-white [text-shadow:0_1px_2px_oklch(0_0_0/0.22)]">Dark mode</span>
    </a>

    <a href="#sync" style="--top:#c4b5fd;--bot:#9b87e5" class="group relative isolate col-span-1 flex flex-col items-center justify-center text-center gap-1 px-4.5 py-4 rounded-[14px] overflow-hidden no-underline text-inherit bg-linear-[to_bottom,var(--top)_0_50%,var(--bot)_50%_100%] before:absolute before:inset-0 before:z-0 before:bg-linear-[to_bottom,var(--bot)_0_50%,var(--top)_50%_100%] before:[clip-path:inset(0_0_100%_0)] before:transition-[clip-path] before:duration-[380ms] before:ease-tcg07 hover:before:[clip-path:inset(0)] focus-visible:outline-2 focus-visible:outline-white focus-visible:outline-offset-2 motion-reduce:before:hidden">
      <span class="relative z-1 text-[1.8rem] leading-none text-white [text-shadow:0_1px_2px_oklch(0_0_0/0.18)]" aria-hidden="true">&#10227;</span>
      <span class="relative z-1 text-[.95rem] font-bold leading-[1.25] text-white [text-shadow:0_1px_2px_oklch(0_0_0/0.22)]">Auto sync</span>
    </a>

    <a href="#trial" style="--top:#f9c1cf;--bot:#e187a0" class="group relative isolate col-span-3 max-[640px]:col-span-2 flex flex-col justify-end gap-1 px-4.5 py-4 rounded-[14px] overflow-hidden no-underline text-inherit bg-linear-[to_bottom,var(--top)_0_50%,var(--bot)_50%_100%] before:absolute before:inset-0 before:z-0 before:bg-linear-[to_bottom,var(--bot)_0_50%,var(--top)_50%_100%] before:[clip-path:inset(0_0_100%_0)] before:transition-[clip-path] before:duration-[380ms] before:ease-tcg07 hover:before:[clip-path:inset(0)] focus-visible:outline-2 focus-visible:outline-white focus-visible:outline-offset-2 motion-reduce:before:hidden">
      <span class="relative z-1 text-[.68rem] font-semibold tracking-[0.12em] uppercase text-tcg07-shade">Get started</span>
      <span class="relative z-1 text-[.95rem] font-bold leading-[1.25] text-white [text-shadow:0_1px_2px_oklch(0_0_0/0.22)]">Start your 14-day free trial</span>
      <span class="relative z-1 self-start mt-1 px-2.25 py-1.25 rounded-md bg-black/22 text-[.74rem] font-bold text-white transition-[background] duration-250 group-hover:bg-black/38 motion-reduce:transition-none">Create account &rarr;</span>
    </a>

  </div>
</section>
```
## CSS
```css
@import "tailwindcss";

@theme {
  --color-tcg07-bg: #c93a4a;
  --color-tcg07-bg: oklch(0.55 0.19 20);
  --color-tcg07-ink: #1a1414;
  --color-tcg07-ink: oklch(0.2 0.02 30);
  --color-tcg07-shade: #3a2a2a;
  --color-tcg07-shade: oklch(0.3 0.02 30);
  --font-tcg07-sans: 'Space Grotesk', system-ui, sans-serif;
  --ease-tcg07: cubic-bezier(0.65, 0.05, 0.35, 1);
}
/* Root rule: the full-bleed contract. */

.tcg-07 {
  width: 100%;
  min-height: 100svh;
}

.tcg-07 ::selection {
  background: #fff;
  color: #c93a4a;
}
```

How this works

Two gradients, one inverted. The tile paints --top over --bot with a 50% hard stop; the before: layer paints the same pair swapped and starts fully clipped away:

class="bg-linear-[to_bottom,var(--top)_0_50%,var(--bot)_50%_100%]
  before:bg-linear-[to_bottom,var(--bot)_0_50%,var(--top)_50%_100%]
  before:[clip-path:inset(0_0_100%_0)]
  hover:before:[clip-path:inset(0)]"

Both states live on the element, which is the same argument the hamburger collection makes about clip-path reveals: a mismatched pair is this pattern's most common bug, and it cannot happen when the pair is one class list apart.

The content never moves. isolate on the tile and relative z-1 on the spans keep the text above the wipe for the whole 380ms, so a metric stays readable while its background inverts.

Placement is markup now. .tile--f { grid-column: span 3 } becomes col-span-3 on the tile itself. Twelve rules, twelve pairs of utilities, and the stylesheet loses its entire placement section — the clearest demonstration in this collection of what utilities buy on a bento.

Per-tile colour stays inline. Twelve tiles, twelve --top/--bot pairs, each read four times (base gradient, inverse gradient, and both through the wipe). Instance data, so style, not @theme.

Make it yours

  • Reweight the bento by editing col-span-* / row-span-* on any tile; nothing else needs to know.
  • Recolour a tile through its inline --top and --bot — base gradient and hover inverse follow together.
  • Move the strata line by editing both gradients' stops to 0_60% / 60%_100% for an asymmetric split.
  • Reverse the wipe direction: before:[clip-path:inset(100%_0_0_0)] travels upward instead.
  • Retheme the canvas with --color-tcg07-bg; try a near-black for a dark-magazine variant.

Gotchas — read before shipping

  • Arbitrary clip-paths take no spaces: inset(0_0_100%_0), and the gradient stop pairs use the same escape.
  • Transition clip-path, never the layer's size. The clip runs on the compositor; animating width or height repaints layout every frame.
  • The hard-stop gradient can show a 1px hairline at some sub-pixel zoom levels; nudge the stops to 49.9% / 50.1% if you see it.
  • CSS variables set in an inline style cannot be transitioned. Tweening the duotone itself needs @property registration, not a longer duration.
  • Without isolate the before: layer's z-index escapes into the page's stacking context and can cover a neighbouring tile's content.

Browser support

ChromeSafariFirefoxEdge
111+16.4+128+111+

Animatable clip-path: inset() is Baseline since 2021 and GPU-composited in Chrome and Safari; Firefox before 119 repaints on the CPU. The floor quoted is Tailwind v4's own generated sheet.

Techniques used in this demo

Theme tokensset in @theme, used by a utility

Arbitraryneeds bracket syntax

HTML & JSno Tailwind involved

Search CodeFronts

Loading…