name styling description 样式规范与设计系统 / Styling Standards & Design System Enforcement. 定义项目样式全流程标准:所有样式必须基于 @pawhaven/design-system 设计 Token、必须使用 Tailwind 语义 utility class(禁止 CSS 变量绕过 bg-[var(--color-*)])、禁止硬编码颜色值(hex/rgb/rgba/hsl)、禁止魔法数字(backdrop-blur-[12px]/w-[137px])、禁止内联 style={}、响应式断点规范、cn() 工具类合并、深色模式兼容。 触发场景 / Trigger: 样式 styling CSS SCSS SASS CSS Modules Tailwind utility-first utility class atomic CSS, Tailwind className utility class postcss JIT just-in-time compiler config, 设计系统 design system design token primitives foundation brand identity consistency, design tokens colors spacing typography font shadow radius border elevation z-index, 颜色 color palette primary secondary accent neutral background surface text border, 间距 spacing padding margin gap layout grid flex box alignment, 响应式 responsive breakpoint sm md lg xl 2xl mobile tablet desktop adaptive, 深色模式 dark mode light mode theme toggle color-scheme prefers-color-scheme, 硬编码颜色 hardcoded color hex #fff #000 rgb( rgba( hsl( hsla( named color, 魔法数字 magic numbers arbitrary values arbitrary px backdrop-blur-[ w-[ h-[ p-[ m-[, CSS 变量绕过 CSS variable bypass var() var(--color- bg-[var( text-[var( border-[var(, 内联样式 inline style={} style attribute direct styling forbidden must use className, className cn() classnames clsx twMerge tailwind-merge utility function merge combine, 主题 theme theming CSS custom properties design token variable light dark, 排版 typography font font-family font-size font-weight line-height letter-spacing, 断点 breakpoint responsive utility sm: md: lg: xl: 2xl: mobile-first desktop-first, @pawhaven/design-system shared design token package npm workspace monorepo, backdrop-blur filter blur effect glassmorphism glass effect frosted, grid flexbox layout container max-width mx-auto alignment justify align, hover focus active disabled state pseudo-class variant variant-*:, transition animation animate motion duration timing easing keyframe.
version 2
Purpose
This skill defines the project's styling standards.
All UI must be built using @pawhaven/design-system (packages/design-system/) as the single source of truth for design tokens, theme mappings, utility classes, and component patterns.
Visual reference spec: packages/design-system/design-system.html
Design System Foundation
Package: @pawhaven/design-system
The design system lives at packages/design-system/ and provides everything needed for styling:
Import in your app root
import '@pawhaven/design-system/styles.css' ;
import {
color,
spacing,
radius,
shadow,
duration,
easing,
typography,
tokenVar,
colorPrimitives,
} from '@pawhaven/design-system' ;
import { MUITheme } from '@pawhaven/design-system/theme' ;
Package structure
packages/design-system/
├── design-system.html # Visual reference spec (all tokens, typography, layouts)
├── index.css # CSS entry (tailwindcss + tokens + theme + utilities + base)
├── theme.css # Semantic token mappings (bg-primary, text-muted, etc.)
├── utilities.css # Custom @utility classes (btn-primary, card, input-field, etc.)
├── tokens/ # Primitive CSS @theme blocks
│ ├── color.css # 7 color scales: gray, orange, green, red, yellow, blue, brown
│ ├── typography.css # Fonts: Inter/Nunito (sans), Poppins (heading), Merriweather (serif)
│ ├── spacing.css # Spacing scale + container widths
│ ├── radius.css # xs → 3xl + full
│ ├── shadow.css # xs → xl + shadow colors
│ ├── motion.css # Duration (75ms → 1000ms) + easing curves
│ ├── breakpoint.css # xs → 2xl
│ ├── border.css # 0 → 8px
│ ├── opacity.css # 0 → 100
│ ├── sizing.css # Width/height primitives
│ └── z-index.css # 0 → 50 + auto
└── src/
├── index.ts # JS/TS barrel export
├── tokens.ts # Typed TS token references
└── MUI-theme.ts # MUI v7 theme (derives from CSS variables)
Core Principles
1. Design System First — Always use tokens from @pawhaven/design-system
Every visual value must come from the design system. Never introduce ad-hoc colors, spacing, or styles.
2. Semantic Colors
Use semantic tokens, never raw color values.
Key rule : every CSS variable defined in theme.css (e.g. --color-surface-dark) already has a corresponding Tailwind utility class (e.g. bg-surface-dark). Never write var(--color-*) directly — it is the equivalent of hardcoding, just wrapped in a CSS variable that bypasses the utility system.
❌ Bad — all of these are wrong for the same reason: they bypass the semantic utility layer:
text - red - 500 ;
bg - blue - 600 ;
border - gray - 300 ;
bg - [var ( --color-surface - dark )];
text - [var ( --color - text - inverse )];
style = {{ fontFamily : 'var(--font-heading)' }};
✅ Good — use the semantic tokens defined in theme.css:
bg - primary;
text - text;
text - text - secondary;
text - text - muted;
text - text - inverse;
bg - background;
bg - surface;
bg - muted;
border - border;
border - border - focus;
text - error;
text - success;
text - warning;
text - info;
Available semantic color tokens (from theme.css):
Category Tokens Brand / Primary primary, primary-hover, primary-active, primary-light, primary-subtleSecondary secondary, secondary-hover, secondary-active, secondary-lightSurfaces surface, surface-elevated, surface-hover, surface-active, surface-dark, background, background-subtle, muted, muted-strongText text, text-secondary, text-tertiary, text-muted, text-placeholder, text-inverse, text-linkBorders border, border-hover, border-strong, border-focus, border-errorStatus error, error-light, success, success-light, warning, warning-light, info, info-lightRescue status rescue-status-pending, rescue-status-inProgress, rescue-status-treated, rescue-status-recovering, rescue-status-awaitingAdoption, rescue-status-adopted, rescue-status-failed
How to Pick the Right Utility Class
When you need any visual property (color, spacing, font, radius, shadow, etc.), follow this decision flow in order. This single rule replaces all individual "don't do this" lists — if you follow it, you will never hardcode, never use magic numbers, and never bypass the design system.
Need a visual value?
│
├─ 1. Is there a custom utility class in utilities.css?
│ YES → Use it (btn-primary, card, input-field, flex-center, link, etc.)
│
├─ 2. Is there a semantic token in theme.css?
│ YES → Use the Tailwind utility class directly (bg-primary, text-muted,
│ font-heading, shadow-card, duration-200, ease-standard, etc.)
│
├─ 3. Is there a primitive token in tokens/*.css?
│ YES → Use the standard Tailwind class (p-4, rounded-lg, text-xl, etc.)
│
└─ 4. None of the above exist
→ Add a new token to @pawhaven/design-system first, then use it
Why this matters : bg-[var(--color-primary)] fails at step 2 — the semantic token exists but you're bypassing it. style={{ fontFamily: '...' }} fails at step 2 — font-heading exists. w-[317px] fails at step 3 — it's not a valid spacing token. Every common mistake is a violation of this flow at some step.
3. Custom Utility Classes
Use the custom utility classes from utilities.css whenever applicable. Do not re-create these patterns manually.
Layout utilities
flex - center;
flex - between;
flex - col - center;
Button utilities
btn - base;
btn - primary;
btn - secondary;
btn - outline;
button - reset;
button - rounded;
Example:
<button className="btn-base btn-primary rounded-xl px-4 py-2" >Save </button>
<button className ="btn-base btn-outline rounded-xl px-4 py-2" > Cancel</button >
Surface utilities
card;
Form utilities
input - field;
form - error;
Link utilities
link;
link - reset;
Accessibility utilities
focus - ring;
4. Typography — Use the defined font families
The design system defines four font families:
Token Tailwind Family Usage font-headingfont-headingPoppins, Nunito, sans-serif Page headings, section titles font-sansfont-sansInter, Nunito, system-ui, sans-serif Body text, UI font-seriffont-serifMerriweather, serif Editorial / long-form font-handwritingfont-handwritingPatrick Hand, cursive Handwritten accents
Available font sizes: text-xs (0.75rem) → text-6xl (3.75rem)
Available font weights: font-normal (400), font-medium (500), font-semibold (600), font-bold (700), font-extrabold (800)
Available line heights: leading-none (1), leading-tight (1.25), leading-snug (1.375), leading-normal (1.5), leading-relaxed (1.625), leading-loose (2)
❌ Avoid:
text-[15px]
leading-[21px]
font-[550 ]
5. Spacing — Use the spacing scale
Primitive spacing scale from tokens/spacing.css:
Token Value px1px 00 10.25rem (4px) 20.5rem (8px) 30.75rem (12px) 41rem (16px) 51.5rem (24px) 62rem (32px) 83rem (48px) 104rem (64px) 125rem (80px)
Semantic spacing aliases (from theme.css):
gutter (spacing-5): horizontal container padding
section (spacing-10): section vertical padding
card (spacing-5): card internal padding
input (spacing-3): input field padding
Container widths: sm (640px), md (768px), lg (1024px), xl (1280px), 2xl (1536px)
Max content width: max-w-6xl (72rem / 1152px)
❌ Avoid:
mt-[17px]
w-[287px]
left-[43px]
h-[91px]
6. Border Radius — Use the radius scale
Token Tailwind Value Usage radius-xsrounded-xs2px Subtle rounding radius-smrounded-sm4px Small elements radius-mdrounded-md8px Buttons, inputs, trait tags, nav items radius-lgrounded-lg12px Cards, logo icon radius-xlrounded-xl16px Buttons (cta) radius-2xlrounded-2xl24px Cards (large) radius-3xlrounded-3xl32px Containers radius-fullrounded-full9999px Badges, pills, avatars
Semantic radius aliases: radius-input (sm), radius-button (md), radius-card (lg), radius-dialog (xl)
❌ Avoid:
rounded-[11px]
rounded-[13px]
7. Shadows — Use the shadow tokens
Token Value Usage shadow-xs0 1px 2px Very subtle shadow-sm0 1px 3px Cards default shadow-md0 3px 6px Dropdowns shadow-lg0 8px 20px Cards hover, modals shadow-xl0 12px 28px Toasts, elevated shadow-innerinset shadow Inner depth shadow-nonenone Reset
Semantic shadow aliases: shadow-card (sm), shadow-dropdown (md), shadow-modal (lg), shadow-toast (xl)
❌ Avoid custom box-shadow values.
8. Motion — Use duration + easing tokens
Available durations: duration-75, duration-100, duration-150, duration-200, duration-300, duration-500, duration-700, duration-1000
Available easings: ease-standard, ease-in, ease-out, ease-in-out, ease-decelerate, ease-accelerate, ease-bounce
✅ Good:
transition-colors duration-150 ease-standard
transition-opacity duration-200 ease-out
❌ Avoid:
duration-[375ms]
9. Z-Index — Use the z-index scale
Primitive scale: z-0, z-10, z-20, z-30, z-40, z-50, z-auto
Semantic aliases:
Token Value Usage z-base1 Default content z-dropdown100 Dropdowns, popovers z-sticky200 Sticky headers z-overlay300 Overlays, drawers z-modal400 Modals, dialogs z-notification500 Notifications z-toast600 Toasts (highest)
❌ Avoid:
z - [99 ];
z - [9999 ];
10. Breakpoints — Use defined breakpoint tokens
Token Width xs360px sm640px md768px lg1024px xl1280px 2xl1536px
11. No Hardcoded Design Values
Never hardcode design values inside components.
❌ Avoid:
className='w-[237px]'
className='text-[#3498db]'
className='rounded-[13px]'
style={{ marginTop : 37 }}
style={{ color : "#4285F4" }}
✅ Use design tokens instead:
className = 'rounded-lg' ;
className = 'bg-primary' ;
className = 'text-muted' ;
className = 'p-4' ;
12. No Magic Numbers
❌ Avoid:
mt-[17px]
w-[287px]
left-[43px]
h-[91px]
✅ Prefer the spacing scale:
mt - 4 ;
w - full;
max - w - md;
h - 24 ;
If a value is reused across the application, promote it into the design system instead of hardcoding it.
13. Hover Effects — Use the defined patterns
Element Effect Tailwind Cards 2px lift + larger shadow -translate-y-1 shadow-lgCard images 5% zoom over 500ms scale-105 transition-transform duration-500Nav items (inactive) bg → muted, text → foreground hover:bg-muted hover:text-textButtons 10% opacity reduction or underline hover:opacity-90 / hover:underlineLogo 5% scale on parent hover group-hover:scale-105 transition-transform
14. Icons — Use Lucide with consistent sizing
All icons come from the Lucide library. Render as inline SVGs with:
fill="none", stroke="currentColor", stroke-width="2"
stroke-linecap="round", stroke-linejoin="round"
viewBox="0 0 24 24"
Icon sizes by context:
Context Tailwind Nav icons w-4 h-4Card meta icons (location, time) w-3.5 h-3.5Badge icons (urgent) w-3 h-3Mobile menu / Hero button w-5 h-5
Icons should use currentColor and inherit text color. Avoid manually styling every icon.
15. Utility First
Prefer Tailwind utilities over custom CSS.
✅ Good:
<div className="flex items-center gap-4 rounded-lg border bg-surface p-6" >
❌ Bad — avoid creating CSS classes for simple layouts:
.card {
display : flex;
padding : 24px ;
}
16. Responsive by Default
Every layout should work across supported screen sizes. Use responsive utilities:
grid grid-cols-1 md :grid-cols-2 xl :grid-cols-3
Avoid fixed widths whenever possible.
17. Build Flexible Layouts
Prefer Flexbox, Grid, gap, max-width, min-width, auto sizing.
Avoid pixel-perfect positioning:
left-[183px]
top-[42px]
Prefer natural document flow.
18. Dark Mode — Use semantic tokens
Never hardcode light mode colors. Always rely on semantic tokens that support both themes:
bg - background;
text - text;
border - border;
19. State Styles
Interactive states should always exist. Include appropriate styles for:
Hover, Focus, Active, Disabled, Loading, Selected
Use consistent design tokens.
20. Animations
Prefer design system animations.
✅ Good:
transition-colors duration-200 ease-standard
transition-opacity duration-150
21. Class Composition — Use cn()
Use a class composition utility (for example cn()):
✅ Good:
className={cn (
"rounded-lg bg-surface" ,
isActive && "border-primary" ,
className
)}
Avoid manual string concatenation.
22. Custom CSS
Only write custom CSS when Tailwind cannot express the desired behavior.
Before creating CSS ask:
Can this be solved with Tailwind?
Can this become a reusable component?
Can this become a design token in @pawhaven/design-system?
23. Inline Styles
❌ Avoid — all static visual values belong in utility classes (see decision flow above):
style={{ width : 320 }}
style={{ fontFamily : 'var(--font-heading)' }}
style={{ color : '#4285F4' }}
✅ Good — inline only for truly dynamic values computed at runtime:
style={{ '--progress' : `${progress} %` } as React .CSSProperties }
24. TypeScript Token Access
For JS-driven styling (inline styles, MUI overrides, canvas, charts), use the typed TS tokens:
import {
color,
spacing,
radius,
shadow,
duration,
easing,
typography,
tokenVar,
colorPrimitives,
} from '@pawhaven/design-system' ;
const style = { color : color.primary , padding : spacing.card };
const primaryVar = tokenVar ('color.primary' );
const primaryColor = colorPrimitives.orange [6 ];
const bgColor = color.background ;
const textColor = color.text ;
const cardRadius = radius.card ;
const cardShadow = shadow.card ;
const fastEase = easing.standard ;
const baseDuration = duration.base ;
const headingFont = typography.fontHeading ;
25. MUI Components
When using MUI, apply the shared MUI theme:
import { ThemeProvider } from '@mui/material/styles' ;
import { MUITheme } from '@pawhaven/design-system/theme' ;
function App ( ) {
return (
<ThemeProvider theme ={MUITheme} >
{/* MUI components now share the same tokens as Tailwind */}
</ThemeProvider >
);
}
The MUI theme reads CSS variables at runtime. Changing a token in tokens/color.css updates both Tailwind and MUI automatically.
26. Adding New Tokens
If a new visual value is truly needed and is not already in the design system:
Add it to the appropriate tokens/*.css file
If it's a semantic mapping, add it to theme.css
Add the corresponding TS reference in src/tokens.ts
Re-export from src/index.ts if needed
Update design-system.html as the visual reference
Never add ad-hoc values directly in components.
Code Review Checklist
Before completing a feature verify:
@pawhaven/design-system is imported (styles.css in root)
Follows the "How to Pick the Right Utility Class" decision flow
No hardcoded colors — semantic tokens used (bg-primary, text-text, etc.)
No var(--color-*) bypass — every CSS variable reference uses its utility class
No hardcoded spacing — spacing scale used (p-4, gap-2, etc.)
No hardcoded typography — font tokens used as classes (font-heading, text-xl)
No magic numbers — no w-[317px], mt-[13px], etc.
No arbitrary Tailwind values — no text-[#xxx], rounded-[Npx]
No arbitrary z-index values — use semantic z-scale
Custom utilities used where applicable (btn-primary, card, input-field, flex-center, etc.)
No inline styling (unless truly dynamic)
Icon-only links/buttons have an aria-label for accessibility
Responsive layout is supported
Design tokens are used
Semantic colors are used
Uses cn() for class composition
Interactive states are implemented (hover, focus, active, disabled)
Dark mode is supported via semantic tokens
Tailwind utilities are preferred over custom CSS
MUI components use MUITheme from @pawhaven/design-system/theme
Icons use Lucide with consistent sizing and currentColor
Common Mistakes
Avoid:
text-[#123456] — hardcoded hex
bg-[var(--color-*)] / text-[var(--color-*)] — CSS variable bypass, use the semantic utility class
style={{ fontFamily }} / style={{ color }} / style={{ width }} — static values in inline styles
w-[317px] — magic number
mt-[13px] — magic number
rounded-[9px] — magic number
style={{ ... }} — inline styles for static values
Pixel-perfect positioning
Random spacing values
Random z-index values
Component-specific colors
Duplicate visual styles
Creating new design patterns without updating @pawhaven/design-system
Re-creating utility classes that already exist in utilities.css
Using raw Tailwind color names (text-orange-500) instead of semantic tokens (text-primary)
If unsure, follow the decision flow in "How to Pick the Right Utility Class" above.
Definition of Done
A component satisfies this skill only if:
It imports and uses @pawhaven/design-system as its design foundation
All styles are implemented with Tailwind utilities where possible
Custom utilities from utilities.css are reused where applicable
No hardcoded visual values exist
No magic numbers are introduced
Semantic design tokens are used for all colors, spacing, typography, radius, shadows
The layout is responsive across defined breakpoints
Dark mode is supported via semantic tokens
Interactive states are handled consistently
The component remains visually consistent with the rest of the application