# Neo-Brutalist

굵은 검정 테두리와 번지지 않는 하드 오프셋 그림자, 쨍한 원색으로 무장한 시끄럽고 장난스러운 네오브루탈리즘 — 버튼은 눌리고 튀어 오른다.

- taxonomy: neo-brutalist · neubrutalism, hard-shadow, bold-borders, high-contrast, playful, saturated-primaries, chunky · complexity=medium
- page types: landing, marketing, portfolio
- best for: 대담한 마케팅 랜딩 페이지, 크리에이티브 에이전시·스튜디오 사이트, 개성을 뽐내는 포트폴리오, 젊은 SaaS 제품의 히어로 섹션
- avoid for: 데이터 밀도가 높은 엔터프라이즈 대시보드, 차분함이 필요한 금융·의료 서비스, 장문 독서 중심의 콘텐츠 사이트, 미니멀·절제된 럭셔리 브랜드
- provenance: authored (Neubrutalism web movement (편집 큐레이션)) — confidence: colors=manual, typography=manual, spacing=manual, shadows=manual, motion=manual, layout=manual

## Design rules

# Neo-Brutalist

## Overview
Loud, playful neubrutalism. The entire language is built from three moves: a thick solid black border, a hard offset drop shadow with **zero blur**, and saturated primary color filling big blocks. Nothing is soft — no gradients, no glass, no blur. Depth is faked purely by a single crisp shadow that looks like the object was cut out and pasted on. Interactions are physical: things pop up when you hover and press down when you click. If a screen feels timid, the fix is more contrast and a bolder color block — not restraint.

## Colors & Roles
High-saturation primaries on warm paper. `background` is a warm off-white, `foreground` a near-black. The chromatic trio does the shouting: `primary` electric blue (oklch ~0.55/0.24/255), `secondary` yellow (~0.90/0.19/100), `accent` hot pink (~0.70/0.22/350). These fill whole surfaces — buttons, cards, badges — rather than being used as thin accents. `border` and `input` are the same near-black as `foreground`; the border color **is** the shadow color. In dark mode the surfaces go deep blue-black and `border`/`input`/shadow flip to near-**white**, so the "outline + hard shadow = form" grammar survives the theme switch. `muted` stays low-chroma for supporting text only.

## Typography Rules
Big weight contrast. Display and headings use a heavy face (Archivo Black → Space Grotesk fallback) at weight 700–800, oversized and tracking-tight (`display` = `clamp(3rem, 9vw, 7rem)`, line-height 0.92, −0.03em). Body is Space Grotesk 400 at 1.0625rem / 1.55 for comfortable reading. Labels and badges are uppercase with wide tracking (0.04em) and heavy weight — treat them like stickers slapped on the page. Modular scale ratio ≈ 1.25; the drama comes from weight and size jumps, not a delicate ratio.

## Layout Principles
Max content width 1200px on a 12-column / 24px-gutter grid. Compose like a collage of chunky color blocks, each fenced by a thick border and sitting on its hard shadow. Whitespace is medium — elements crowd together confidently rather than floating in air. Give each section its own rhythm with a contrasting primary-color block and an uppercase label badge to announce it.

## Depth & Elevation
One elevation trick, used everywhere: a single hard offset shadow — `box-shadow: 4px 4px 0 var(--foreground)` — full opacity, blur 0, spread 0, always cast to the bottom-right. Emphasis cards or hover states push it to 6px 6px. Never stack multiple soft shadows, never blur one. The shadow always shares its color with the border. `effects.depth` is high (0.9) but achieved entirely without gradients or glow.

## Shapes
Chunky corners: `box`/`selector` radius ~12px, `field` (inputs/buttons) ~8px. Corners are soft enough to feel friendly but the borders are hard and thick (2–3px). Square (0px) is an acceptable variant, but never mix hairline borders with these shapes.

## Component Stylings
- **Button**: 3px solid `border`, radius ~8px, filled with a saturated primary, heavy uppercase-ish label, `box-shadow: 4px 4px 0 var(--foreground)`. **Hover** lifts it: `translate(-2px,-2px)` and shadow grows to 6px 6px. **Active/press** pushes it into the shadow: `translate(4px,4px)` and shadow collapses to 0 — it looks physically pressed. **Focus** = 3px offset ring. **Disabled** = opacity 0.5, shadow removed, no motion.
- **Card**: 3px border, ~12px radius, 4px 4px hard shadow bottom-right, background `card` or a primary block; padding 24–32px.
- **Input**: 3px border, ~8px radius, `card` background, no inset shadow. Focus adds a 3px ring plus a slightly pressed 2px 2px shadow.
- **Nav**: thick 3px bottom border or a solid primary bar; logo in heavy display type, links as uppercase labels, the CTA keeps its hard shadow.
- **Badge**: uppercase label, 2px border, primary background, may be rotated a couple degrees like a sticker.

## Motion
Physical and snappy, not floaty. Durations are short (100–150ms). Hover uses the `pop` keyframe (lift toward top-left, shadow grows); click uses `press` (drop into the shadow, shadow → 0). Standard easing is crisp; emphasis easing has a slight overshoot (`cubic-bezier(0.34, 1.56, 0.64, 1)`) for a springy bounce. Prefer translate/scale over opacity fades. No parallax.

## Do's and Don'ts
**Do:** border every card and button with 2–3px solid black (white in dark); cast one crisp zero-blur shadow bottom-right; fill big blocks with saturated blue/yellow/pink; make buttons pop on hover and press on click; set headings in a heavy face.
**Don't:** use blurred or multi-layer soft shadows; use gradients, glassmorphism, or pastel low-contrast palettes; draw thin 1px gray dividers; dull the palette into calm neutrals.

## Responsive Behavior
The 12-column grid collapses to a single stacked column on mobile; color blocks become full-width bands. Display type scales via `clamp()`. Shadows and border widths stay constant across breakpoints — the chunkiness is the brand and should not thin out on small screens.

## Agent Prompt Guide
> Build this in the 'Neo-Brutalist' style: thick 2-3px solid black borders on every card and button, hard offset drop shadows with zero blur (4px 4px 0, full-opacity black), saturated electric-blue/yellow/pink primaries filling big blocks, chunky ~12px radius, heavy Archivo-Black display type with uppercase sticker labels, and buttons that pop up on hover and press down (shadow collapses to 0) on click — loud, playful, high-contrast, no gradients.

## Known Gaps / Confidence
Authored seed style (not extracted from a live URL), so all tokens are `manual` confidence. The heavy display face assumes Archivo Black; Space Grotesk is the practical Google-Fonts fallback for both display and body. Dark-mode border/shadow inversion (near-white) is a deliberate call to keep the outline-and-shadow grammar legible on dark surfaces.


## Tokens (theme.css — use these values verbatim, do not re-derive)

```css
/* Neo-Brutalist — theme.css (generated, do not edit) */
:root {
  --radius: 12px;
  --radius-selector: 12px;
  --radius-field: 8px;
  --font-sans: 'Space Grotesk', 'Archivo', system-ui, -apple-system, sans-serif;
  --font-serif: 'DM Serif Display', Georgia, serif;
  --font-mono: 'JetBrains Mono', 'IBM Plex Mono', monospace;
  --font-display: 'Archivo Black', 'Space Grotesk', system-ui, sans-serif;
  --spacing: 8px;
  --shadow: 4px 4px 0px 0px color-mix(in oklab, oklch(0.16 0.02 270) 100%, transparent);
  --ks-display-weight: 800;
  --ks-display-tracking: -0.03em;
  --background: oklch(0.97 0.02 95);
  --foreground: oklch(0.16 0.02 270);
  --card: oklch(1 0 0);
  --card-foreground: oklch(0.16 0.02 270);
  --popover: oklch(1 0 0);
  --popover-foreground: oklch(0.16 0.02 270);
  --primary: oklch(0.55 0.24 255);
  --primary-foreground: oklch(0.99 0 0);
  --secondary: oklch(0.90 0.19 100);
  --secondary-foreground: oklch(0.16 0.02 270);
  --muted: oklch(0.94 0.01 95);
  --muted-foreground: oklch(0.44 0.02 270);
  --accent: oklch(0.70 0.22 350);
  --accent-foreground: oklch(0.16 0.02 270);
  --destructive: oklch(0.58 0.24 27);
  --destructive-foreground: oklch(0.99 0 0);
  --border: oklch(0.16 0.02 270);
  --input: oklch(0.16 0.02 270);
  --ring: oklch(0.55 0.24 255);
  --chart-1: oklch(0.55 0.24 255);
  --chart-2: oklch(0.90 0.19 100);
  --chart-3: oklch(0.70 0.22 350);
  --chart-4: oklch(0.75 0.20 145);
  --chart-5: oklch(0.16 0.02 270);
}

.dark {
  --background: oklch(0.19 0.02 270);
  --foreground: oklch(0.96 0.01 95);
  --card: oklch(0.23 0.02 270);
  --card-foreground: oklch(0.96 0.01 95);
  --popover: oklch(0.23 0.02 270);
  --popover-foreground: oklch(0.96 0.01 95);
  --primary: oklch(0.63 0.22 255);
  --primary-foreground: oklch(0.15 0.02 270);
  --secondary: oklch(0.88 0.19 100);
  --secondary-foreground: oklch(0.15 0.02 270);
  --muted: oklch(0.27 0.02 270);
  --muted-foreground: oklch(0.72 0.02 95);
  --accent: oklch(0.72 0.22 350);
  --accent-foreground: oklch(0.15 0.02 270);
  --destructive: oklch(0.63 0.24 27);
  --destructive-foreground: oklch(0.99 0 0);
  --border: oklch(0.96 0.01 95);
  --input: oklch(0.96 0.01 95);
  --ring: oklch(0.63 0.22 255);
  --chart-1: oklch(0.63 0.22 255);
  --chart-2: oklch(0.88 0.19 100);
  --chart-3: oklch(0.72 0.22 350);
  --chart-4: oklch(0.78 0.20 145);
  --chart-5: oklch(0.96 0.01 95);
}
```

## Golden example (exemplar.html — match this structure and token usage)

```html
<!-- Golden snippet for "Neo-Brutalist". Fragment — assumes the style's CSS variables
     (--background, --foreground, --primary, --secondary, --accent, --card, --border,
      --radius, --font-sans, --font-display, ...) are in scope.
     Tokens only; no literal colors. Depth = one hard zero-blur shadow cast bottom-right. -->
<section style="background:var(--background); color:var(--foreground); font-family:var(--font-sans); padding:clamp(2rem,6vw,5rem); max-width:1200px; margin:0 auto;">

  <span style="display:inline-block; transform:rotate(-2deg); background:var(--secondary); color:var(--secondary-foreground); border:2px solid var(--border); border-radius:var(--radius); box-shadow:4px 4px 0 var(--foreground); padding:8px 16px; font-size:.8125rem; font-weight:700; letter-spacing:.04em; text-transform:uppercase;">
    New — v2.0 is here
  </span>

  <div style="display:grid; grid-template-columns:repeat(12,1fr); gap:24px; align-items:start; margin-top:clamp(1.5rem,4vw,2.5rem);">
    <h1 style="grid-column:1 / span 8; margin:0; font-family:var(--font-display); font-weight:800; font-size:clamp(3rem,9vw,7rem); line-height:.92; letter-spacing:-.03em;">
      Ship it<br>LOUD.
    </h1>
    <p style="grid-column:9 / span 4; margin:0; align-self:end; font-size:1.0625rem; line-height:1.55;">
      Thick borders, hard shadows, zero blur. A design system that refuses to whisper.
    </p>
  </div>

  <div style="display:flex; flex-wrap:wrap; gap:1.25rem; margin-top:clamp(2rem,5vw,3rem);">
    <a href="#" style="background:var(--primary); color:var(--primary-foreground); border:3px solid var(--border); border-radius:var(--radius); box-shadow:4px 4px 0 var(--foreground); padding:14px 32px; font-size:.9375rem; font-weight:700; letter-spacing:.02em; text-transform:uppercase; text-decoration:none;">
      Start building
    </a>
    <a href="#" style="background:var(--card); color:var(--card-foreground); border:3px solid var(--border); border-radius:var(--radius); box-shadow:4px 4px 0 var(--foreground); padding:14px 32px; font-size:.9375rem; font-weight:700; letter-spacing:.02em; text-transform:uppercase; text-decoration:none;">
      See the docs
    </a>
  </div>

  <div style="display:grid; grid-template-columns:repeat(3,1fr); gap:24px; margin-top:clamp(2.5rem,6vw,4rem);">
    <article style="background:var(--accent); color:var(--accent-foreground); border:3px solid var(--border); border-radius:var(--radius); box-shadow:4px 4px 0 var(--foreground); padding:28px;">
      <p style="margin:0 0 .75rem; font-size:.8125rem; font-weight:700; letter-spacing:.04em; text-transform:uppercase;">01 — Borders</p>
      <h3 style="margin:0 0 .5rem; font-family:var(--font-display); font-weight:700; font-size:1.375rem; line-height:1.15;">3px, solid, no apologies</h3>
      <p style="margin:0; font-size:1rem; line-height:1.5;">Every block is fenced in. The outline is the object.</p>
    </article>
    <article style="background:var(--secondary); color:var(--secondary-foreground); border:3px solid var(--border); border-radius:var(--radius); box-shadow:4px 4px 0 var(--foreground); padding:28px;">
      <p style="margin:0 0 .75rem; font-size:.8125rem; font-weight:700; letter-spacing:.04em; text-transform:uppercase;">02 — Shadows</p>
      <h3 style="margin:0 0 .5rem; font-family:var(--font-display); font-weight:700; font-size:1.375rem; line-height:1.15;">Zero blur, one direction</h3>
      <p style="margin:0; font-size:1rem; line-height:1.5;">A single 4px offset shadow, cut out and pasted on.</p>
    </article>
    <article style="background:var(--card); color:var(--card-foreground); border:3px solid var(--border); border-radius:var(--radius); box-shadow:4px 4px 0 var(--foreground); padding:28px;">
      <p style="margin:0 0 .75rem; font-size:.8125rem; font-weight:700; letter-spacing:.04em; text-transform:uppercase; color:var(--primary);">03 — Motion</p>
      <h3 style="margin:0 0 .5rem; font-family:var(--font-display); font-weight:700; font-size:1.375rem; line-height:1.15;">Pop up, press down</h3>
      <p style="margin:0; font-size:1rem; line-height:1.5;">Hover lifts it; a click collapses the shadow to nothing.</p>
    </article>
  </div>
</section>
```

## Apply

- shadcn project: `npx shadcn@latest add https://web.ggum.uk/styles/r/neo-brutalist.json` — installs the tokens above into globals.css, then use semantic classes (bg-background, text-primary, …) only.
- other stack: paste the theme.css block above into your global stylesheet and style everything via `var(--…)` references.
- single HTML/artifact: embed the theme.css block in a `<style>` tag and follow the exemplar's markup pattern.
- dark mode: toggle the `.dark` class (both variants are in the tokens above).
- before finishing: re-check every Don't in the Design rules section above against your output.
