Principles / Guardrails
Rules to follow when building new screens or modifying existing ones. docs/design.md §4 Usage Rules is the single source of truth; this page summarizes it all as cards.
Tokens & Components
Color, type, spacing, radius, and elevation must be expressed through tokens only. Reach for catalog components before rolling your own patterns.
Use only defined tokens
Color, font, background, spacing, radius, and elevation must use variables declared in tokens.css only. Arbitrary HEX values and arbitrary px values are not allowed. If a value is missing, add a token first.
Reuse defined components
Do not invent new patterns ad hoc. Compose from the §3 component catalog first — Card, Button, Badge, FAQ, Table, and so on.
Typography & Color
Rules for heading color, default button style, fonts, and gradients. Emphasis and interaction each have a clearly defined role.
Heading color = ink-deep by default
All headings (h2–h5) use --c-ink-deep. --c-primary (blue) is reserved for links, interactive elements, and emphasis text — never for heading color. Eyebrow labels use normal (400) weight — bold is not allowed.
Default button = outline
.btn defaults to outline style, filling with primary on hover. Do not use a solid (filled) button as the default variant. New buttons must extend this class as the base and add only layout overrides.
Fonts: Pretendard / Satoshi only
Korean and general text use --ff (Pretendard Variable); Latin and numerals use --ff-en (Satoshi). No other external web fonts are allowed.
No italic
Emphasis must be expressed through weight or color only. em and i elements are forced to font-style: normal.
No emoji
UI icons must use inline SVG only (plus/close pseudo-elements, chevrons, etc.). Emoji rendering varies across operating systems, breaking visual consistency.
Gradients: LIGHT × LIGHT only
Wash gradients are only permitted between light colors. Gradients between primary, dark-blue, and ink-deep are not allowed. Depth on dark backgrounds must be expressed with a flat color + shadow.
List bullets: one global token
Every list bullet — pseudo-element • and native ::marker alike — uses the single alias --bullet-color (light: primary, dark: sky). Per-page bullet colors are forbidden, and disc markers must not be mixed with • on the same page — use the shared li::before pattern so the glyph stays uniform too.
No middle-dot abuse in text
Do not use • / · as a stand-in for words in running text. Write dates and ranges out — e.g. 2026년 6월 ~ 12월, never 2026 · 6–12월. Middle dots are allowed only for compact same-kind enumeration inside chips and labels.
Layout
Rules for content width, horizontal padding, navigation style, and optical corrections for Korean type. Header, body, and footer share the same alignment baseline.
Global max-width: 1640px
The body max-width for all app pages (edu, data, etc.) is --content-max: 1640px — identical to the header and footer. Per-page widths are not allowed.
Consistent edge padding
On desktop, --chrome-pad (clamp(24px, 3vw, 48px)) gives header, body, and footer the same horizontal inset. On mobile (640px and below), all three are fixed at 36px.
Rounded boxes: bottom padding +4–6px
Korean glyphs have no descenders, so symmetric padding reads as more space at the top than the bottom. Add 4–6px of extra bottom padding to rounded cards and boxes (left/right remain symmetric).
Nav menu: weight 600 / chevron 2.5
All menu items in the header and floating capsule use font-weight 600. Chevron arrow SVGs must have a strokeWidth of 2.5.
Dividers: full-bleed only — never stop mid-screen
A divider that ends in the middle of the screen reads as broken UI. Never put a horizontal hairline on a max-width container — put the border on a full-width wrapper with the constrained content inside, or use patterns/full-bleed-divider. Vertical sidebar-to-body dividers are forbidden entirely(a sticky sidebar's border ends where its content ends and dangles) — separate with whitespace, and no sidebar-internal title underlines either. Allowed short lines: indent guides, in-content reading-column rules, lines fully enclosed in a card.
Numbering/icons: center on the container
A number badge or icon that labels a list row or step card is vertically centered against the row container (div) — never against the first text line. Use top: 50% + translateY(-50%) for absolute badges, or flex align-items: center on the row. Keep at least 20px of gap between the badge and the text block.
Symmetric spacing around dividers
The whitespace above and below every horizontal divider must be equal — section hairlines use symmetric padding: 80px 0, accordion item lines use equal padding on both sides. An asymmetric gap around a line reads as a layout bug.
Dark Mode
Dark mode is handled through global token overrides. Do not create separate dark designs per component.
Dark mode = global token override
Dark mode support is implemented via [data-theme="dark"] token overrides. Scoped rules using :global(html[data-theme="dark"]) .x are added only for surfaces where a token override is not sufficient.
Dos and Don'ts
A quick-reference checklist for the judgment calls that come up most often when applying these principles on screen. Focused on color contrast, typography, and selection indicators.
- CTAs must contrast clearly with their background. Use primary on light backgrounds; sky on ink-deep or primary backgrounds.
- Limit section backgrounds to the 5 defined surfaces: canvas, light-grey, primary, dark-blue, and ink-deep.
- Default heading color is ink-deep — use primary on light, white/sky on dark.
- Emphasis via weight 600 or color only. Do not fork body text sizes for emphasis.
- Korean letter-spacing: −1% (--tracking) across the board — the Pretendard readability sweet spot.
- Selection indicators use circle shape for both single and multiple selections.
- Image placeholders should use one of the 4 defined flat-color boxes that suits the section.
- Same-color background + same-color CTA. Primary on primary and ink-deep on ink-deep both disappear.
- A lone primary CTA on an ink-deep background — contrast is too weak (use sky instead).
- Italic — Korean faux-italics hurt readability; use weight or color instead.
- Rounded-rectangle selection indicators — use circle consistently.
- sky-blue as a wide section background — it is for emphasis text only.
- Korean weight 900 — 800 is the ceiling. Avoid odd in-between sizes (13px, 15px, 17px).
- Gradients between deep colors (primary, dark-blue, ink-deep) — LIGHT × LIGHT wash only.
- A one-sided border on a rounded box. A single-side accent (border-top / -left / etc.) on a box with a radius cuts across the rounded corner and reads as broken — use a full 1px hairline + soft shadow, or a tag/pill that carries the color.