# 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.)