# Mono — LLM Reference > Mono is a minimal, classname-based CSS framework. One file: `mono.css`. No build step, no JS dependencies, no utility class explosion. Interactive components (accordion, dropdown, modal) use native HTML elements — `
`, ``, `` — and require no JavaScript. Everything else is semantic HTML styled with a small set of BEM-ish class names. Dark mode is built in. Everything is driven by CSS custom properties. Source: https://github.com/injoon5/mono --- ## Setup ```html ``` No npm. No bundler. Pretendard font is loaded automatically via @import inside the CSS. --- ## Design tokens All tokens are CSS custom properties on `:root`. Override them in your own stylesheet after importing Mono. ### Color — semantic (use these in your own styles) | Token | Light value | Dark value | |---|---|---| | `--color-bg` | neutral-50 (near white) | neutral-950 (near black) | | `--color-surface` | #ffffff | neutral-900 | | `--color-surface-2` | neutral-100 | neutral-800 | | `--color-border` | neutral-200 | neutral-800 | | `--color-border-strong` | neutral-300 | neutral-700 | | `--color-text` | neutral-900 | neutral-50 | | `--color-text-2` | neutral-600 (secondary text) | neutral-400 | | `--color-text-3` | neutral-400 (muted/placeholder) | neutral-600 | | `--color-accent` | neutral-900 | neutral-50 | | `--color-accent-text` | neutral-50 | neutral-950 | | `--color-focus` | neutral-900 | neutral-200 | ### Color — raw palette (11 achromatic neutral steps, oklch) ``` --neutral-50 oklch(0.985 0 0) near white --neutral-100 oklch(0.97 0 0) --neutral-200 oklch(0.922 0 0) --neutral-300 oklch(0.87 0 0) --neutral-400 oklch(0.715 0 0) --neutral-500 oklch(0.556 0 0) --neutral-600 oklch(0.439 0 0) --neutral-700 oklch(0.371 0 0) --neutral-800 oklch(0.269 0 0) --neutral-900 oklch(0.205 0 0) #171717 --neutral-950 oklch(0.145 0 0) near black ``` ### Type scale ``` --text-xs 0.75rem (12px) --text-sm 0.875rem (14px) --text-base 1rem (16px) <- body default --text-md 1.0625rem (17px) --text-lg 1.1875rem (19px) --text-xl 1.4375rem (23px) --text-2xl 1.8125rem (29px) --text-3xl 2.375rem (38px) --text-4xl 3.125rem (50px) ``` ### Line height ``` --leading-tight 1.2 (headings) --leading-snug 1.4 --leading-normal 1.6 (body default) --leading-loose 1.8 ``` ### Letter spacing ``` --tracking-tight -0.03em --tracking-snug -0.02em --tracking-normal -0.01em (body default) --tracking-wide 0.04em --tracking-wider 0.08em (labels/caps) ``` ### Spacing scale ``` --space-1 0.25rem (4px) --space-2 0.5rem (8px) --space-3 0.75rem (12px) --space-4 1rem (16px) --space-5 1.25rem (20px) --space-6 1.5rem (24px) --space-8 2rem (32px) --space-10 2.5rem (40px) --space-12 3rem (48px) --space-16 4rem (64px) --space-20 5rem (80px) --space-24 6rem (96px) ``` ### Border radius ``` --radius-sm 4px --radius-md 7px --radius-lg 11px --radius-xl 16px --radius-full 9999px ``` ### Shadows ``` --shadow-xs subtle, 1px --shadow-sm light, 3px --shadow-md medium, 12px --shadow-lg large, 32px --shadow-xl dramatic, 48px ``` ### Transitions ``` --ease cubic-bezier(0.16, 1, 0.3, 1) spring-out --ease-in cubic-bezier(0.4, 0, 1, 1) --ease-out cubic-bezier(0, 0, 0.2, 1) --transition 150ms var(--ease) --transition-slow 280ms var(--ease) ``` --- ## Dark mode Dark mode activates automatically via `prefers-color-scheme: dark`. To override manually, set `data-theme` on ``: ```html ``` Toggle with JS: ```js const root = document.documentElement const isDark = root.getAttribute('data-theme') === 'dark' || (!root.getAttribute('data-theme') && window.matchMedia('(prefers-color-scheme: dark)').matches) root.setAttribute('data-theme', isDark ? 'light' : 'dark') ``` --- ## Typography Headings are styled by tag. No class needed. ```html

Display — 50px, weight 700, tracking -0.04em

Heading — 38px, weight 600, tracking -0.03em

Subheading — 29px, weight 600, tracking -0.025em

Title — 23px, weight 600, tracking -0.02em

Subtitle — 19px, weight 600, tracking -0.015em
Label — 16px, weight 600

Body — color-text-2, max-width 68ch, line-height 1.6

Bold text — color-text, weight 600 Italic Inline code — monospace, surface-2 bg, border Cmd K
Quote — left border, italic, color-text-2
Block code
``` ### Text utility classes ``` .text-xs font-size: --text-xs .text-sm font-size: --text-sm .text-lg font-size: --text-lg .text-xl font-size: --text-xl .text-muted color: --color-text-2 .text-faint color: --color-text-3 .text-strong color: --color-text ``` ### Section label (small all-caps eyebrow text) ```html ``` Renders as: 12px, 500 weight, tracking 0.08em, uppercase, color-text-3. --- ## Layout ### Container Centers content with max-width and horizontal padding. ```html
``` ### Section ```html
``` Section header pattern: ```html

What we do

Supporting description text.

``` ### Grid ```html
``` Default gap is `--space-6` (1.5rem). ### Stack (vertical flex) ```html
``` ### Cluster (horizontal flex, wrapping) ```html
``` --- ## Nav Sticky frosted-glass navbar. No dividers between links. On screens ≤768px the links hide and a hamburger button appears. On screens ≤640px the `.nav-actions` also hide — only brand + hamburger remain. ```html ``` Drawer JS (required — only JS needed for nav): ```js function toggleDrawer() { const drawer = document.getElementById('nav-drawer'); const btn = document.getElementById('nav-hamburger'); const icon = document.getElementById('hamburger-icon'); const isOpen = drawer.classList.contains('open'); drawer.classList.toggle('open', !isOpen); btn.setAttribute('aria-expanded', String(!isOpen)); icon.innerHTML = isOpen ? '' : ''; } function closeDrawer() { const drawer = document.getElementById('nav-drawer'); const btn = document.getElementById('nav-hamburger'); const icon = document.getElementById('hamburger-icon'); drawer.classList.remove('open'); btn.setAttribute('aria-expanded', 'false'); icon.innerHTML = ''; } window.addEventListener('resize', () => { if (window.innerWidth > 768) closeDrawer(); }); ``` Nav links: hover darkens color and shows a slim underline sliding in from center. Active link has a persistent underline. No background color change on hover. --- ## Buttons ```html Go ``` Default padding: `9px 20px`. Default font size: 16px. --- ## Form controls All controls share the same visual style: 1px border, `--color-border`, `--radius-md`, transitions on focus/hover. ### Input ```html
``` ### Textarea ```html ``` Resizable vertically, min-height 100px. ### Select ```html ``` Custom chevron arrow via background-image. ### Field wrapper ```html
We'll never share your email.
Only letters and numbers allowed.
``` ### Checkbox ```html ``` ### Radio ```html ``` ### Switch ```html ``` ### Range ```html ``` ### Input group (joined controls) ```html
``` --- ## Card ```html

Title

Supporting text.

Card title Tag
Content goes here.
...

Featured

Description.

``` --- ## Badge ```html Default Solid Live ``` --- ## Accordion Uses native `
`/``. No JavaScript needed. The browser owns open/close state. Add `open` attribute to start expanded. ```html
Question text
Answer text.
Another question
Another answer.
``` When `[open]`: the chevron `.accordion-icon` rotates 180deg via CSS. The body fades and slides in via `@keyframes accordionIn`. Keyboard and screen-reader accessible natively. --- ## Dropdown Uses native `
`/``. No JavaScript needed. The `` takes `.btn` classes directly as the trigger. Closes on Escape natively. ```html ``` Icon-only trigger: ```html ``` Menu animates in with opacity + `scale(0.98)` from top-left when `[open]`. Min-width 200px. Note: clicking a menu item won't auto-close the `
` — add `onclick="this.closest('details').removeAttribute('open')"` to items if you need that behaviour. --- ## Modal Uses native ``. Open with `.showModal()`. Close buttons use `
` — no JS. Escape key, focus trapping, and backdrop are all handled by the browser. ```html
``` To close on backdrop click, add one JS listener (the only JS needed for modals): ```js document.querySelectorAll('dialog.modal').forEach(dialog => { dialog.addEventListener('click', e => { if (e.target === dialog) dialog.close() }) }) ``` Size variants: `dialog.modal` (default, 500px), `dialog.modal-sm` (360px), `dialog.modal-lg` (720px). Backdrop: `dialog::backdrop` with blur. Enter animation uses `@starting-style` (Chrome 117+, Firefox 129+). --- ## Loading states ### Spinner ```html ``` ### Animated dots ```html ``` ### Skeleton shimmer ```html
``` --- ## Table ```html
Name Status Date
Project alpha Active 2 hours ago
Project beta Paused 3 days ago
``` `.table-wrap` handles horizontal scroll and the rounded border. Rows highlight on hover. --- ## Alert ```html
Informational message. Learn more.
Deployment successful.
Build failed.
``` --- ## Avatar ```html AB AB AB AB Name
AB CD +4
``` --- ## Divider ```html
OR
``` --- ## Utility classes ### Display / flex ``` .flex display: flex .inline-flex display: inline-flex .items-center align-items: center .items-start align-items: flex-start .justify-center justify-content: center .justify-between justify-content: space-between .flex-1 flex: 1 .flex-wrap flex-wrap: wrap .w-full width: 100% ``` ### Gap ``` .gap-1 .gap-2 .gap-3 .gap-4 .gap-6 .gap-8 ``` ### Margin top / bottom ``` .mt-1 .mt-2 .mt-3 .mt-4 .mt-6 .mt-8 .mt-12 .mb-1 .mb-2 .mb-3 .mb-4 .mb-6 .mb-8 ``` ### Border radius ``` .rounded-sm 4px .rounded-md 7px .rounded-lg 11px .rounded-full 9999px ``` ### Shadows / backgrounds / border ``` .shadow-sm .shadow-md .shadow-lg .bg-surface background: --color-surface .bg-surface-2 background: --color-surface-2 .border border: 1px solid --color-border ``` ### Misc ``` .opacity-50 opacity: 0.5 .cursor-not-allowed cursor: not-allowed .sr-only visually hidden, accessible to screen readers ``` --- ## Customization ### Swap the accent color ```css :root { --color-accent: oklch(0.5 0.2 250); --color-accent-text: #ffffff; } ``` ### Write new components using tokens Always use semantic tokens so dark mode works for free: ```css .my-component { background: var(--color-surface); border: 1px solid var(--color-border); border-radius: var(--radius-md); padding: var(--space-4); color: var(--color-text-2); transition: border-color var(--transition); } ``` ### Change the font ```css :root { --font-sans: "Your Font", system-ui, sans-serif; } ``` --- ## Common patterns ### Page shell ```html

2025 Brand

``` ### Settings / form page ```html

Account settings

Manage your profile and preferences.

Profile
Notifications

Email updates

Receive product news

Security alerts

Account activity notifications

``` ### Feature grid ```html

Everything included

No tiers, no add-ons.

Feature name

Short description of what this does.

``` --- ## Responsive breakpoints Mono is desktop-first with two responsive breakpoints. | Breakpoint | Width | What changes | |---|---|---| | Tablet | ≤768px | Nav links hidden → hamburger shown. Heading scale reduced. Section padding reduced. | | Mobile | ≤640px | Nav actions hidden. Grids collapse to 1 column. Headings further reduced. Modals become bottom sheets. Section padding reduced further. | ### Typography scale at each breakpoint | Element | Desktop | Tablet (≤768px) | Mobile (≤640px) | |---|---|---|---| | h1 | 50px | 38px | 29px | | h2 | 38px | 29px | 23px | | h3 | 29px | 23px | 19px | ### Grid collapse ``` grid-2 → 2 col → 1 col at 640px grid-3 → 3 col → 2 col at 1024px → 1 col at 640px grid-4 → 4 col → 2 col at 1024px → 1 col at 640px ``` ### Modal on mobile On screens ≤640px, `dialog.modal` becomes a bottom sheet: full-width, pinned to the bottom, slides up from below. No class change needed — the CSS handles it automatically. ### Mobile utility classes ``` .sm\:stack stack children vertically on mobile (flex-direction: column) .sm\:w-full full width on mobile ``` ### Always mobile-safe patterns Use `.cluster` with `flex-wrap: wrap` for button groups — they reflow naturally. Use `.stack` for vertical layouts. Use `max-width: none` on `

` when full-width text is needed inside flex containers. --- ## Notes for code generation - Always use semantic HTML elements: `