# SimpleNote Web - Style Guide
## 1. Design Tokens
Design tokens are CSS custom properties that define the visual language. They enable theming (dark/light modes) and ensure consistency.
### 1.1 Color Palette
```css
:root {
/* === Dark Theme (Default) === */
/* Backgrounds */
--color-bg: #0f1117;
--color-surface: #1a1d26;
--color-surface-raised: #22262f;
--color-hover: rgba(255, 255, 255, 0.05);
--color-active: rgba(255, 255, 255, 0.08);
/* Text */
--color-text: #e4e6eb;
--color-text-secondary: #b0b3b8;
--color-text-muted: #65676b;
/* Borders */
--color-border: #303338;
--color-border-light: #404249;
/* Accent (Primary brand color - cyan/teal) */
--color-accent: #00d4aa;
--color-accent-hover: #00e8bb;
--color-accent-alpha: rgba(0, 212, 170, 0.15);
/* Semantic Colors */
--color-success: #31a065;
--color-success-bg: rgba(49, 160, 101, 0.15);
--color-warning: #cf9d2c;
--color-warning-bg: rgba(207, 157, 44, 0.15);
--color-danger: #cf4a4a;
--color-danger-hover: #e05555;
--color-info: #4a90cf;
--color-info-bg: rgba(74, 144, 207, 0.15);
/* Type-specific colors */
--color-requirement: #00d4aa; /* Matches accent */
--color-note: #4a90cf;
--color-spec: #9b59b6;
--color-general: #65676b;
/* Priority */
--color-priority-high: #cf4a4a;
--color-priority-medium: #cf9d2c;
--color-priority-low: #31a065;
/* Shadows */
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.3);
--shadow-md: 0 4px 12px rgba(0, 0, 0, 0.25);
--shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.3);
--shadow-xl: 0 20px 60px rgba(0, 0, 0, 0.4);
/* Focus ring */
--focus-ring: 0 0 0 3px rgba(0, 212, 170, 0.4);
}
/* === Light Theme === */
[data-theme="light"] {
--color-bg: #f5f6f8;
--color-surface: #ffffff;
--color-surface-raised: #f0f1f3;
--color-hover: rgba(0, 0, 0, 0.04);
--color-active: rgba(0, 0, 0, 0.06);
--color-text: #1a1d26;
--color-text-secondary: #4a4f5c;
--color-text-muted: #8b919d;
--color-border: #e1e3e8;
--color-border-light: #ebedf2;
--color-accent: #00a884;
--color-accent-hover: #00c49a;
--color-accent-alpha: rgba(0, 168, 132, 0.12);
--color-success: #22863a;
--color-success-bg: rgba(34, 134, 58, 0.1);
--color-warning: #b08800;
--color-warning-bg: rgba(176, 136, 0, 0.1);
--color-danger: #cb2431;
--color-danger-hover: #d93542;
--color-info: #0366d6;
--color-info-bg: rgba(3, 102, 214, 0.1);
--color-requirement: #00a884;
--color-note: #0366d6;
--color-spec: #6f42c1;
--color-general: #6a737d;
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.06);
--shadow-md: 0 4px 12px rgba(0, 0, 0, 0.08);
--shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.1);
--shadow-xl: 0 20px 60px rgba(0, 0, 0, 0.15);
--focus-ring: 0 0 0 3px rgba(0, 168, 132, 0.35);
}
```
### 1.2 Typography
```css
:root {
/* Font Families */
--font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
--font-mono: 'JetBrains Mono', 'Fira Code', 'Monaco', 'Consolas', monospace;
/* Font Sizes (1.25 scale) */
--text-xs: 0.64rem; /* 10.24px */
--text-sm: 0.8rem; /* 12.8px */
--text-base: 1rem; /* 16px */
--text-lg: 1.25rem; /* 20px */
--text-xl: 1.563rem; /* 25px */
--text-2xl: 1.953rem; /* 31.25px */
--text-3xl: 2.441rem; /* 39px */
/* Line Heights */
--leading-tight: 1.25;
--leading-normal: 1.5;
--leading-relaxed: 1.75;
/* Font Weights */
--font-normal: 400;
--font-medium: 500;
--font-semibold: 600;
--font-bold: 700;
/* Letter Spacing */
--tracking-tight: -0.025em;
--tracking-normal: 0;
--tracking-wide: 0.025em;
--tracking-wider: 0.05em;
}
/* Google Fonts Import */
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap');
```
#### Typography Scale
| Element | Size | Weight | Line Height |
|---------|------|--------|-------------|
| H1 | 2rem (32px) | 700 | 1.2 |
| H2 | 1.5rem (24px) | 600 | 1.25 |
| H3 | 1.25rem (20px) | 600 | 1.3 |
| H4 | 1rem (16px) | 600 | 1.4 |
| Body | 1rem (16px) | 400 | 1.5 |
| Small | 0.875rem (14px) | 400 | 1.5 |
| Caption | 0.75rem (12px) | 400 | 1.4 |
| Code | 0.9375rem (15px) | 400 | 1.6 |
### 1.3 Spacing
```css
:root {
/* Spacing scale (4px base) */
--space-0: 0;
--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 */
/* Border Radius */
--radius-sm: 4px;
--radius-md: 6px;
--radius-lg: 8px;
--radius-xl: 12px;
--radius-2xl: 16px;
--radius-full: 9999px;
/* Transitions */
--transition-fast: 0.1s ease;
--transition-normal: 0.15s ease;
--transition-slow: 0.25s ease;
--transition-spring: 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
}
```
### 1.4 Z-Index Scale
```css
:root {
--z-base: 0;
--z-dropdown: 100;
--z-sticky: 200;
--z-modal-backdrop: 500;
--z-modal: 600;
--z-toast: 700;
--z-tooltip: 800;
--z-max: 9999;
}
```
---
## 2. Global Styles
### 2.1 CSS Reset
```css
*, *::before, *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
html {
font-size: 16px;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-rendering: optimizeLegibility;
}
body {
font-family: var(--font-sans);
font-size: var(--text-base);
line-height: var(--leading-normal);
color: var(--color-text);
background: var(--color-bg);
min-height: 100vh;
}
img, svg {
display: block;
max-width: 100%;
}
button {
font: inherit;
cursor: pointer;
}
input, textarea, select {
font: inherit;
}
a {
color: var(--color-accent);
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
ul, ol {
list-style: none;
}
/* Scrollbar styling */
::-webkit-scrollbar {
width: 8px;
height: 8px;
}
::-webkit-scrollbar-track {
background: var(--color-surface);
}
::-webkit-scrollbar-thumb {
background: var(--color-border);
border-radius: var(--radius-full);
}
::-webkit-scrollbar-thumb:hover {
background: var(--color-text-muted);
}
/* Selection */
::selection {
background: var(--color-accent-alpha);
color: var(--color-text);
}
```
### 2.2 Focus Styles
```css
:focus {
outline: none;
}
:focus-visible {
outline: none;
box-shadow: var(--focus-ring);
border-radius: var(--radius-sm);
}
```
### 2.3 Smooth Scrolling
```css
html {
scroll-behavior: smooth;
}
@media (prefers-reduced-motion: reduce) {
html {
scroll-behavior: auto;
}
*, *::before, *::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}
```
---
## 3. Typography Components
### 3.1 Headings
```css
h1, .h1 {
font-size: var(--text-2xl);
font-weight: var(--font-bold);
line-height: var(--leading-tight);
letter-spacing: var(--tracking-tight);
color: var(--color-text);
}
h2, .h2 {
font-size: var(--text-xl);
font-weight: var(--font-semibold);
line-height: 1.25;
letter-spacing: var(--tracking-tight);
}
h3, .h3 {
font-size: var(--text-lg);
font-weight: var(--font-semibold);
line-height: 1.3;
}
h4, .h4 {
font-size: var(--text-base);
font-weight: var(--font-semibold);
line-height: 1.4;
}
```
### 3.2 Body Text
```css
p {
margin-bottom: var(--space-4);
}
p:last-child {
margin-bottom: 0;
}
.text-sm {
font-size: var(--text-sm);
}
.text-xs {
font-size: var(--text-xs);
}
.text-muted {
color: var(--color-text-muted);
}
.text-secondary {
color: var(--color-text-secondary);
}
.font-mono {
font-family: var(--font-mono);
}
```
### 3.3 Prose (Markdown Content)
```css
.prose {
max-width: 70ch;
color: var(--color-text);
}
.prose h1 { /* ... */ }
.prose h2 { /* ... */ }
.prose h3 { /* ... */ }
.prose h4 { /* ... */ }
.prose p {
margin-bottom: 1em;
line-height: 1.7;
}
.prose ul,
.prose ol {
margin-bottom: 1em;
padding-left: 1.5em;
}
.prose ul { list-style-type: disc; }
.prose ol { list-style-type: decimal; }
.prose li {
margin-bottom: 0.25em;
line-height: 1.6;
}
.prose code {
font-family: var(--font-mono);
font-size: 0.875em;
background: var(--color-surface);
padding: 0.125em 0.375em;
border-radius: var(--radius-sm);
color: var(--color-accent);
}
.prose pre {
background: var(--color-surface);
border: 1px solid var(--color-border);
border-radius: var(--radius-lg);
padding: 1rem;
overflow-x: auto;
margin-bottom: 1em;
}
.prose pre code {
background: transparent;
padding: 0;
color: var(--color-text);
font-size: 0.875rem;
line-height: 1.6;
}
.prose blockquote {
border-left: 4px solid var(--color-accent);
padding-left: 1rem;
margin: 1em 0;
color: var(--color-text-secondary);
font-style: italic;
}
.prose table {
width: 100%;
border-collapse: collapse;
margin-bottom: 1em;
}
.prose th,
.prose td {
padding: 0.5rem 0.75rem;
border: 1px solid var(--color-border);
text-align: left;
}
.prose th {
background: var(--color-surface);
font-weight: var(--font-semibold);
}
.prose tr:hover td {
background: var(--color-hover);
}
/* Task list checkboxes */
.prose input[type="checkbox"] {
margin-right: 0.5em;
accent-color: var(--color-accent);
}
.prose a {
color: var(--color-accent);
text-decoration: underline;
}
.prose img {
max-width: 100%;
border-radius: var(--radius-lg);
margin: 1em 0;
}
.prose hr {
border: none;
border-top: 1px solid var(--color-border);
margin: 2em 0;
}
```
---
## 4. Animation Guidelines
### 4.1 Motion Principles
1. **Purposeful**: Animation should communicate state changes, not decorate
2. **Quick**: Most transitions should be 150-250ms
3. **Responsive**: Motion should feel immediate to user input
4. **Respectful**: Don't animate if user prefers reduced motion
### 4.2 Standard Animations
```css
/* Fade in */
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
/* Slide in from bottom */
@keyframes slideInUp {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* Slide in from right (toasts) */
@keyframes slideInRight {
from {
opacity: 0;
transform: translateX(100%);
}
to {
opacity: 1;
transform: translateX(0);
}
}
/* Scale in (modals) */
@keyframes scaleIn {
from {
opacity: 0;
transform: scale(0.95);
}
to {
opacity: 1;
transform: scale(1);
}
}
/* Pulse (saving indicator) */
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.5; }
}
/* Spin (loading) */
@keyframes spin {
to { transform: rotate(360deg); }
}
/* Shimmer (skeleton) */
@keyframes shimmer {
0% { background-position: 200% 0; }
100% { background-position: -200% 0; }
}
```
### 4.3 Reduced Motion
```css
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}
```
---
## 5. Responsive Breakpoints
```css
/* Mobile first breakpoints */
/* sm: 640px - Large phones */
/* md: 768px - Tablets */
/* lg: 1024px - Laptops */
/* xl: 1280px - Desktops */
/* 2xl: 1536px - Large screens */
@media (min-width: 640px) {
/* sm */
}
@media (min-width: 768px) {
/* md */
}
@media (min-width: 1024px) {
/* lg */
}
@media (min-width: 1280px) {
/* xl */
}
@media (min-width: 1536px) {
/* 2xl */
}
/* Mobile-only (no breakpoint, mobile first) */
/* styles apply to all, tablet+ override below */
/* Tablet and up */
@media (min-width: 768px) {
.hide-tablet { display: none; }
}
/* Desktop only */
@media (min-width: 1024px) {
.hide-desktop { display: none; }
}
```
---
## 6. Icon Guidelines
### 6.1 Icon System
Using Lucide Icons (SVG-based, MIT licensed).
```html
```
### 6.2 Icon Usage
```css
.icon {
display: inline-block;
vertical-align: middle;
flex-shrink: 0;
}
.icon-sm { width: 1rem; height: 1rem; }
.icon-md { width: 1.25rem; height: 1.25rem; }
.icon-lg { width: 1.5rem; height: 1.5rem; }
/* Buttons with icons */
.btn-icon {
display: inline-flex;
align-items: center;
gap: var(--space-2);
}
/* Icon-only buttons need proper sizing */
.btn-icon-only {
width: 2.5rem;
height: 2.5rem;
padding: 0;
display: inline-flex;
align-items: center;
justify-content: center;
}
```
### 6.3 Common Icons
| Icon | Use Case |
|------|----------|
| `search` | Search input |
| `plus` | Create new items |
| `folder-plus` | Create library |
| `file-plus` | Create document |
| `edit` / `pencil` | Edit |
| `trash-2` | Delete |
| `download` | Export |
| `chevron-down` | Dropdown toggle |
| `chevron-right` | Tree expand |
| `x` | Close, dismiss |
| `check` | Confirm, saved |
| `alert-circle` | Error |
| `info` | Info toast |
| `settings` | Settings |
| `moon` | Dark mode |
| `sun` | Light mode |
| `home` | Dashboard |
| `folder` | Library |
| `file-text` | Document |
| `tag` | Tag |
| `link` | Internal link |
| `external-link` | External link |
| `copy` | Copy to clipboard |
| `eye` | Preview |
| `eye-off` | Hide |
| `keyboard` | Shortcuts |
---
## 7. Form Styling
### 7.1 Form Layouts
```css
/* Vertical form (default) */
.form-vertical {
display: flex;
flex-direction: column;
gap: var(--space-4);
}
.form-horizontal {
display: flex;
flex-wrap: wrap;
gap: var(--space-4);
align-items: flex-start;
}
.form-horizontal .form-group {
flex: 1;
min-width: 200px;
}
/* Inline form */
.form-inline {
display: flex;
gap: var(--space-2);
align-items: center;
}
```
### 7.2 Fieldset & Legend
```css
fieldset {
border: 1px solid var(--color-border);
border-radius: var(--radius-lg);
padding: var(--space-4);
margin-bottom: var(--space-4);
}
legend {
font-size: var(--text-sm);
font-weight: var(--font-semibold);
color: var(--color-text-muted);
text-transform: uppercase;
letter-spacing: var(--tracking-wider);
padding: 0 var(--space-2);
}
```
### 7.3 Help Text & Errors
```css
.help-text {
font-size: var(--text-sm);
color: var(--color-text-muted);
margin-top: var(--space-1);
}
.error-message {
font-size: var(--text-sm);
color: var(--color-danger);
margin-top: var(--space-1);
display: flex;
align-items: center;
gap: var(--space-1);
}
.input:invalid,
.input.error {
border-color: var(--color-danger);
}
.input:invalid:focus,
.input.error:focus {
box-shadow: 0 0 0 3px rgba(207, 74, 74, 0.25);
}
```
---
## 8. Status & State Colors
### 8.1 Status Badge Colors
| Status | Background | Text | Border |
|--------|------------|------|--------|
| draft | `var(--color-warning-bg)` | `var(--color-warning)` | none |
| approved | `var(--color-info-bg)` | `var(--color-info)` | none |
| implemented | `var(--color-success-bg)` | `var(--color-success)` | none |
### 8.2 Priority Colors
| Priority | Color | Emoji |
|----------|-------|-------|
| high | `var(--color-priority-high)` | 🔴 |
| medium | `var(--color-priority-medium)` | 🟡 |
| low | `var(--color-priority-low)` | 🟢 |
### 8.3 Type Badge Colors
| Type | Border | Text |
|------|--------|------|
| requirement | `var(--color-requirement)` | `var(--color-requirement)` |
| note | `var(--color-note)` | `var(--color-note)` |
| spec | `var(--color-spec)` | `var(--color-spec)` |
| general | `var(--color-border)` | `var(--color-text-muted)` |
---
## 9. Loading & Skeleton States
### 9.1 Skeleton Colors
```css
.skeleton {
background: linear-gradient(
90deg,
var(--color-border) 25%,
var(--color-hover) 50%,
var(--color-border) 75%
);
background-size: 200% 100%;
animation: shimmer 1.5s infinite;
}
@keyframes shimmer {
0% { background-position: 200% 0; }
100% { background-position: -200% 0; }
}
/* Dark mode adjustment */
[data-theme="dark"] .skeleton {
background: linear-gradient(
90deg,
var(--color-surface) 25%,
var(--color-surface-raised) 50%,
var(--color-surface) 75%
);
background-size: 200% 100%;
}
```
### 9.2 Loading Overlay
```css
.loading-overlay {
position: absolute;
inset: 0;
background: rgba(var(--color-bg), 0.8);
display: flex;
align-items: center;
justify-content: center;
z-index: var(--z-sticky);
}
[data-theme="dark"] .loading-overlay {
background: rgba(15, 17, 23, 0.8);
}
```
---
## 10. Dark Mode Implementation
### 10.1 Theme Toggle
```javascript
// Theme toggle component
function ThemeToggle() {
const toggle = () => {
const current = document.documentElement.getAttribute('data-theme');
const next = current === 'light' ? 'dark' : 'light';
document.documentElement.setAttribute('data-theme', next);
localStorage.setItem('theme', next);
};
return `
`;
}
// Initialize theme on load
function initTheme() {
const saved = localStorage.getItem('theme');
const preferred = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
const theme = saved || preferred;
document.documentElement.setAttribute('data-theme', theme);
}
```
### 10.2 CSS Variables at :root vs [data-theme]
```css
/* Default (dark) - no selector needed */
:root {
--color-bg: #0f1117;
/* ... */
}
/* Light theme - explicit selector */
[data-theme="light"] {
--color-bg: #f5f6f8;
/* ... */
}
```
---
## 11. Code Syntax Highlighting
Using highlight.js or Prism for code blocks within markdown.
```css
/* Code highlighting tokens - dark theme */
.hljs {
background: var(--color-surface);
color: var(--color-text);
}
.hljs-keyword { color: #c678dd; }
.hljs-string { color: #98c379; }
.hljs-number { color: #d19a66; }
.hljs-function { color: #61afef; }
.hljs-comment { color: #5c6370; font-style: italic; }
.hljs-variable { color: #e06c75; }
.hljs-attr { color: #d19a66; }
.hljs-tag { color: #e06c75; }
.hljs-attribute { color: #d19a66; }
/* Code highlighting - light theme adjustments */
[data-theme="light"] .hljs-keyword { color: #a626a4; }
[data-theme="light"] .hljs-string { color: #50a14f; }
[data-theme="light"] .hljs-number { color: #986801; }
[data-theme="light"] .hljs-function { color: #4078f2; }
[data-theme="light"] .hljs-comment { color: #a0a1a7; }
[data-theme="light"] .hljs-variable { color: #e45649; }
[data-theme="light"] .hljs-attr { color: #986801; }
[data-theme="light"] .hljs-tag { color: #e45649; }
[data-theme="light"] .hljs-attribute { color: #986801; }
```
---
## 12. Print Styles
```css
@media print {
/* Hide navigation, sidebars, buttons */
.sidebar,
.app-header,
.toolbar,
.bottom-nav,
.btn,
.btn-ghost {
display: none !important;
}
/* Expand content */
.main-content {
width: 100% !important;
padding: 0 !important;
}
/* Adjust colors for print */
body {
background: white;
color: black;
}
/* Ensure links show URLs */
a[href^="http"]::after {
content: " (" attr(href) ")";
font-size: 0.8em;
}
/* Avoid page breaks inside elements */
.doc-card,
.prose h1,
.prose h2,
.prose h3,
.prose table {
break-inside: avoid;
}
}
```
---
## 13. Accessibility Checklist
- [ ] All interactive elements have visible focus indicators
- [ ] Color contrast ratio ≥ 4.5:1 for text
- [ ] All images have alt text (or aria-hidden="true")
- [ ] Form inputs have associated labels
- [ ] Buttons have accessible names
- [ ] Icons have aria-label or visible text
- [ ] Modals trap focus and can be closed with Escape
- [ ] Toast notifications use role="alert" or role="status"
- [ ] Loading states announce to screen readers
- [ ] Reduced motion is respected
- [ ] Skip-to-content link is provided
- [ ] Semantic HTML is used (nav, main, aside, article, etc.)