Convention: Frontend CSS
Rule
All frontend CSS follows the playground philosophy: real CSS, not utility classes. Mobile-first. Human-verified.
Canonical Reference
The CSS fundamentals guide lives in the playground repo:
~/pal-e-playground/guide/index.html (live at the playground Tailscale funnel). That guide defines the 3 layout systems (Box Model, Flexbox, Grid), the 5 core properties, the 10 rules, and the debugging playbook. Agents must read it before writing frontend CSS.Design Tokens
All colors, spacing, and typography are defined as CSS custom properties in
app.css. Components reference variables (var(--color-bg)), never hardcoded hex values.Palette
| Token | Value | Purpose |
|---|---|---|
| <code>--color-bg</code> | #fafafa | Page background (light) |
| <code>--color-text</code> | #1a1a1a | Primary text |
| <code>--color-link</code> | #0366d6 | Links (blue, not pink) |
| <code>--color-nav-bg</code> | #1a1a1a | Nav bar (dark) |
| <code>--color-border</code> | #e0e0e0 | Subtle borders |
| <code>--color-tag-bg</code> | #e8e8e8 | Tag backgrounds |
Typography
- Font: Atkinson Hyperlegible (Google Fonts). Fallback: system sans-serif.
- Line height: 1.6 minimum for body text
- Content width:
max-width: 48rem, centered withmargin: 0 auto
The 3 Layout Systems
| System | Job | When to Use |
|---|---|---|
| <strong>Box Model</strong> | Sizing & spacing | Every element — <code>box-sizing</code>, <code>padding</code>, <code>margin</code>, <code>border</code> |
| <strong>Flexbox</strong> | 1D layout (row OR column) | Navbars, button rows, card rows, toolbars, side-by-side panels |
| <strong>Grid</strong> | 2D layout (rows AND columns) | Full page layouts, dashboards, image galleries |
Decision tree: Need rows AND columns? Grid. Need a row OR column? Flexbox. Need sizing or spacing? Box Model.
The 5 Core Properties
| Property | Controls | Key Values |
|---|---|---|
| <code>display</code> | What layout system | <code>block</code>, <code>flex</code>, <code>grid</code>, <code>inline</code>, <code>none</code> |
| <code>position</code> | Flow vs anchored | <code>static</code>, <code>relative</code>, <code>absolute</code>, <code>fixed</code>, <code>sticky</code> |
| <code>width/height</code> | Size constraints | Prefer <code>max-width</code> over fixed <code>width</code> for responsive |
| <code>margin/padding</code> | Spacing | Margin = outside, padding = inside. Use <code>gap</code> in flex/grid instead of margin hacks |
| <code>overflow</code> | Clipping/scrolling | <code>visible</code>, <code>hidden</code>, <code>auto</code>, <code>scroll</code> |
Layout Rules
*, *::before, *::after { box-sizing: border-box; }— alwaysbody { margin: 0; }— always- Flexbox for rows/columns, Grid for page layout
gapfor spacing, not margin hacksmax-width + margin: 0 autofor readable content- Mobile breakpoint at 600px
img { max-width: 100%; }— images scale to containermin-height: 100vhfor full-page sections
Debugging Playbook
When a layout breaks, run this checklist in order. Most issues resolve before step 5.
- Inspect the element — Right-click → Inspect. Hover to see the box model (content/padding/border/margin) live.
- Check the parent's display — Layout bugs almost always come from the parent, not the child. Is the parent
flex,grid, orblock? Checkflex-direction,justify-content,align-items,gap. - Check size constraints — Look for
width,max-width,height,min-height. Gotcha:height: 100%only works if the parent has a defined height. - Check position — Is
position: absoluteremoving the element from flow? Is arelativeancestor missing? - Check overflow — Content disappearing? Look for
overflow: hidden. Panels needoverflow: auto. - Toggle styles live — DevTools lets you turn properties on/off and edit values live. Do this constantly.
Quick debug trick:
* { outline: 1px solid red; } — makes every box visible. Use DevTools "Computed" tab for final authority on actual applied values.Common gotchas:
- "Won't center" — parent isn't
flex/grid, or missingjustify-content/align-items - "Overflowing" — fixed width + padding with
content-box, or flex child not shrinking (fix:min-width: 0) - "Unexpected space" — default browser margins on headings/paragraphs, or margin collapse
What NOT to Do
- No hardcoded hex in components — use CSS custom properties
- No Tailwind arbitrary values (
bg-[#0e0e18]) — use real CSS or token-based Tailwind classes - No AI slop palette: no cyan-on-dark, no pink neon accents, no gradient text
- No skipping mobile check — if it scrolls horizontally on phone, it's broken
- No shipping without Lucas seeing it on device
- No
float,clearfix,tablelayouts, or manual margin spacing — useflex/grid/gap
Process
- Design in
pal-e-playgroundwith vanilla HTML+CSS (seesop-frontend-experiment) - Verify on phone via Tailscale funnel
- The HTML/CSS IS the spec — no screenshots as intermediary
- Agent ports CSS to SvelteKit production repo (copy-paste, not rewrite)
- Lucas verifies production on phone before merge
Related
project-frontend-playground— where design happenssop-frontend-experiment— how to create experiments and onboard new projectsfeedback_frontend_iteration— the lesson that created this conventionfeedback_svelte_is_html— .svelte files ARE HTML- Playground guide:
pal-e-playground/guide/index.html