# CSS recipes — 3D tilt, depth-of-field, glass, dot-grid, shadow

Reusable, battle-tested snippets for turning a flat UI mockup into a hero. Build the interface flat first,
then wrap it in these. All verified in Chromium via the Playwright render path.

## 3D tilt (the hero angle)
Put the whole app in a perspective stage and rotate it. Tune the three angles to match your reference —
stronger `rotateZ` = more diagonal (a common marketing look).

```css
.stage { position:absolute; inset:0; perspective: 1050px; }      /* smaller = stronger perspective */
.app {
  transform: translate(var(--tx), var(--ty)) scale(var(--scale))
             rotateX(46deg) rotateY(18deg) rotateZ(-27deg);        /* lean back / turn / diagonal */
  transform-origin: left top;
  transform-style: preserve-3d;
}
```
Starting point that reads like a premium CRM hero: `perspective 1050px, rotateX 44–46, rotateY 18–20,
rotateZ -21 to -27, scale ~1.4–1.5`. Reposition with `--tx/--ty` so the app crops to fill the frame (bleed
off the far/bottom edges rather than floating with empty margins). Iterate against the reference.

## Depth of field (far corner softens)
A 2D blurred overlay masked by a gradient, placed ON TOP of the 3D scene (not inside the transform, where
`backdrop-filter` misbehaves). Blur strongest at the far corner, sharp where the focal element is.

```css
.dof {
  position:absolute; inset:0; z-index:2; pointer-events:none;
  backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px);
  -webkit-mask-image: linear-gradient(108deg, rgba(0,0,0,0) 42%, rgba(0,0,0,.35) 60%, rgba(0,0,0,.85) 78%, #000 100%);
          mask-image: linear-gradient(108deg, rgba(0,0,0,0) 42%, rgba(0,0,0,.35) 60%, rgba(0,0,0,.85) 78%, #000 100%);
}
```
(Adjust the gradient angle to point at your far corner. This is a *good-enough* DoF; the GPT Image 2 finish
does true lens depth better if you're taking it that far.)

## Glassmorphism card
```css
.card {
  background: rgba(255,255,255,0.82);
  backdrop-filter: blur(40px) saturate(185%); -webkit-backdrop-filter: blur(40px) saturate(185%);
  border: 1px solid rgba(255,255,255,0.75);
  border-radius: 22px;
  box-shadow: 0 2px 4px rgba(28,28,38,.04), 0 20px 50px -18px rgba(30,30,40,.22),
              inset 0 1px 0 rgba(255,255,255,.9);
}
```

## Bottom blur-fade (content dissolves at the edge)
```css
.card {
  -webkit-mask-image: linear-gradient(to bottom, #000 0%, #000 80%, transparent 99%);
          mask-image: linear-gradient(to bottom, #000 0%, #000 80%, transparent 99%);
}
/* plus a progressive frost band for real "blur toward the edge": */
.blurband { position:absolute; left:0; right:0; bottom:0; height:132px; pointer-events:none;
  backdrop-filter: blur(3px);
  -webkit-mask-image: linear-gradient(to top,#000 0%,#000 22%,transparent 100%);
          mask-image: linear-gradient(to top,#000 0%,#000 22%,transparent 100%); }
```

## Dot-grid background (Attio/Linear style)
```css
.scene { background: radial-gradient(135% 115% at 50% 4%, #f7f7f9 0%, #eeeef1 52%, #e5e5ea 100%); }
.scene::before {
  content:''; position:absolute; inset:-10%;
  background-image: radial-gradient(#d6d4d0 1.15px, transparent 1.15px);
  background-size: 23px 23px; opacity:.55;
  -webkit-mask-image: radial-gradient(130% 120% at 40% 42%, #000 55%, transparent 92%);
          mask-image: radial-gradient(130% 120% at 40% 42%, #000 55%, transparent 92%);
}
```

## Soft floating shadow
```css
.app {
  box-shadow: 0 2px 6px rgba(28,28,38,.05),
              70px 90px 120px -40px rgba(60,55,48,.32),
              30px 40px 70px -30px rgba(60,55,48,.22);
}
```

## Film grain / vignette / grade (subtle premium finish, if not going to GPT)
```css
.grain { position:absolute; inset:-20%; opacity:.05; mix-blend-mode:overlay;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E"); }
.vig { position:absolute; inset:0; background:radial-gradient(120% 110% at 45% 42%, transparent 52%, rgba(40,36,30,.16) 100%); }
```
Note: a pure-CSS grade like this is very subtle — if the goal is a real premium jump, the GPT Image 2 finish
is the bigger lever. Use CSS grade only when you must keep it 100% deterministic.

## Crispness
`html, body { width:<design-w>; height:<design-h> } body { zoom: 2 }` and render at a 2× viewport. `zoom`
re-lays out at higher density (crisp text) — better than `transform: scale`, which rasterizes blurry.
