swadhinbiswas

[email protected]
2026-03-20 16:32:18 +0600 committed NaN years ago
2b362eb
commit 2b362eb
3 files changed
+3683 -0
β–Όdocs-site/index.html
+1769-0
1
+<!DOCTYPE html>
2
+<html lang="en">
3
+<head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>OpenGrammar Documentation</title>
7
+ <meta name="description" content="Complete documentation for OpenGrammar - Your privacy-first, open-source writing assistant">
8
+ <link rel="preconnect" href="https://fonts.googleapis.com">
9
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
10
+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
11
+ <link rel="stylesheet" href="styles.css">
12
+</head>
13
+<body>
14
+ <div class="paper-texture"></div>
15
+
16
+ <!-- Sidebar Navigation -->
17
+ <aside class="sidebar">
18
+ <div class="sidebar-header">
19
+ <div class="logo">
20
+ <svg class="logo-icon" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
21
+ <rect width="40" height="40" rx="8" fill="url(#logo-gradient)"/>
22
+ <path d="M12 20L18 26L28 14" stroke="white" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
23
+ <defs>
24
+ <linearGradient id="logo-gradient" x1="0" y1="0" x2="40" y2="40" gradientUnits="userSpaceOnUse">
25
+ <stop stop-color="#3B82F6"/>
26
+ <stop offset="1" stop-color="#8B5CF6"/>
27
+ </linearGradient>
28
+ </defs>
29
+ </svg>
30
+ <span class="logo-text">OpenGrammar</span>
31
+ </div>
32
+ <span class="version-badge">v2.1.0</span>
33
+ </div>
34
+
35
+ <nav class="sidebar-nav">
36
+ <div class="nav-section">
37
+ <div class="nav-section-title">Getting Started</div>
38
+ <a href="#quick-start" class="nav-link active" data-page="quick-start">
39
+ <svg class="nav-icon" viewBox="0 0 20 20" fill="currentColor">
40
+ <path d="M10.894 2.553a1 1 0 00-1.788 0l-7 14a1 1 0 001.169 1.409l5-1.429A1 1 0 009 15.571V11a1 1 0 112 0v4.571a1 1 0 00.725.962l5 1.428a1 1 0 001.17-1.408l-7-14z"/>
41
+ </svg>
42
+ Quick Start
43
+ </a>
44
+ <a href="#what-is-opengrammar" class="nav-link" data-page="what-is-opengrammar">
45
+ <svg class="nav-icon" viewBox="0 0 20 20" fill="currentColor">
46
+ <path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z" clip-rule="evenodd"/>
47
+ </svg>
48
+ What is OpenGrammar?
49
+ </a>
50
+ </div>
51
+
52
+ <div class="nav-section">
53
+ <div class="nav-section-title">Installation</div>
54
+ <a href="#browser-setup" class="nav-link" data-page="browser-setup">
55
+ <svg class="nav-icon" viewBox="0 0 20 20" fill="currentColor">
56
+ <path fill-rule="evenodd" d="M3 5a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM3 10a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM3 15a1 1 0 011-1h6a1 1 0 110 2H4a1 1 0 01-1-1z" clip-rule="evenodd"/>
57
+ </svg>
58
+ Browser Extension
59
+ </a>
60
+ <a href="#backend-deployment" class="nav-link" data-page="backend-deployment">
61
+ <svg class="nav-icon" viewBox="0 0 20 20" fill="currentColor">
62
+ <path fill-rule="evenodd" d="M2 5a2 2 0 012-2h12a2 2 0 012 2v10a2 2 0 01-2 2H4a2 2 0 01-2-2V5zm3.293 1.293a1 1 0 011.414 0l3 3a1 1 0 010 1.414l-3 3a1 1 0 01-1.414-1.414L7.586 10 5.293 7.707a1 1 0 010-1.414z" clip-rule="evenodd"/>
63
+ </svg>
64
+ Backend Deployment
65
+ </a>
66
+ <a href="#docker-self-hosting" class="nav-link" data-page="docker-self-hosting">
67
+ <svg class="nav-icon" viewBox="0 0 20 20" fill="currentColor">
68
+ <path d="M5 4a2 2 0 012-2h6a2 2 0 012 2v14l-5-2.5L5 18V4z"/>
69
+ </svg>
70
+ Docker Self-Hosting
71
+ </a>
72
+ </div>
73
+
74
+ <div class="nav-section">
75
+ <div class="nav-section-title">Configuration</div>
76
+ <a href="#ai-providers" class="nav-link" data-page="ai-providers">
77
+ <svg class="nav-icon" viewBox="0 0 20 20" fill="currentColor">
78
+ <path d="M13 6a3 3 0 11-6 0 3 3 0 016 0zM18 8a2 2 0 11-4 0 2 2 0 014 0zM14 15a4 4 0 00-8 0v3h8v-3zM6 8a2 2 0 11-4 0 2 2 0 014 0zM16 18v-3a5.972 5.972 0 00-.75-2.906A3.005 3.005 0 0119 15v3h-3zM4.75 12.094A5.973 5.973 0 004 15v3H1v-3a3 3 0 013.75-2.906z"/>
79
+ </svg>
80
+ AI Providers
81
+ </a>
82
+ <a href="#extension-settings" class="nav-link" data-page="extension-settings">
83
+ <svg class="nav-icon" viewBox="0 0 20 20" fill="currentColor">
84
+ <path fill-rule="evenodd" d="M11.49 3.17c-.38-1.56-2.6-1.56-2.98 0a1.532 1.532 0 01-2.286.948c-1.372-.836-2.942.734-2.106 2.106.54.886.061 2.042-.947 2.287-1.561.379-1.561 2.6 0 2.978a1.532 1.532 0 01.947 2.287c-.836 1.372.734 2.942 2.106 2.106a1.532 1.532 0 012.287.947c.379 1.561 2.6 1.561 2.978 0a1.533 1.533 0 012.287-.947c1.372.836 2.942-.734 2.106-2.106a1.533 1.533 0 01.947-2.287c1.561-.379 1.561-2.6 0-2.978a1.532 1.532 0 01-.947-2.287c.836-1.372-.734-2.942-2.106-2.106a1.532 1.532 0 01-2.287-.947zM10 13a3 3 0 100-6 3 3 0 000 6z" clip-rule="evenodd"/>
85
+ </svg>
86
+ Extension Settings
87
+ </a>
88
+ </div>
89
+
90
+ <div class="nav-section">
91
+ <div class="nav-section-title">User Guide</div>
92
+ <a href="#using-opengrammar" class="nav-link" data-page="using-opengrammar">
93
+ <svg class="nav-icon" viewBox="0 0 20 20" fill="currentColor">
94
+ <path d="M9 4.804A7.968 7.968 0 005.5 4c-1.255 0-2.443.29-3.5.804v10A7.969 7.969 0 015.5 14c1.669 0 3.218.51 4.5 1.385A7.962 7.962 0 0114.5 14c1.255 0 2.443.29 3.5.804v-10A7.968 7.968 0 0014.5 4c-1.255 0-2.443.29-3.5.804V12a1 1 0 11-2 0V4.804z"/>
95
+ </svg>
96
+ Using OpenGrammar
97
+ </a>
98
+ <a href="#tone-rewriting" class="nav-link" data-page="tone-rewriting">
99
+ <svg class="nav-icon" viewBox="0 0 20 20" fill="currentColor">
100
+ <path fill-rule="evenodd" d="M4 2a2 2 0 00-2 2v11a3 3 0 106 0V4a2 2 0 00-2-2H4zm1 14a1 1 0 100-2 1 1 0 000 2zm5-1.757l4.9-4.9a2 2 0 000-2.828L13.485 5.1a2 2 0 00-2.828 0L10 5.757v8.486zM16 18H9.071l6-6H16a2 2 0 012 2v2a2 2 0 01-2 2z" clip-rule="evenodd"/>
101
+ </svg>
102
+ Tone Rewriting
103
+ </a>
104
+ <a href="#writing-statistics" class="nav-link" data-page="writing-statistics">
105
+ <svg class="nav-icon" viewBox="0 0 20 20" fill="currentColor">
106
+ <path d="M2 11a1 1 0 011-1h2a1 1 0 011 1v5a1 1 0 01-1 1H3a1 1 0 01-1-1v-5zM8 7a1 1 0 011-1h2a1 1 0 011 1v9a1 1 0 01-1 1H9a1 1 0 01-1-1V7zM14 4a1 1 0 011-1h2a1 1 0 011 1v12a1 1 0 01-1 1h-2a1 1 0 01-1-1V4z"/>
107
+ </svg>
108
+ Writing Statistics
109
+ </a>
110
+ <a href="#keyboard-shortcuts" class="nav-link" data-page="keyboard-shortcuts">
111
+ <svg class="nav-icon" viewBox="0 0 20 20" fill="currentColor">
112
+ <path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z" clip-rule="evenodd"/>
113
+ </svg>
114
+ Keyboard Shortcuts
115
+ </a>
116
+ </div>
117
+
118
+ <div class="nav-section">
119
+ <div class="nav-section-title">Support</div>
120
+ <a href="#troubleshooting" class="nav-link" data-page="troubleshooting">
121
+ <svg class="nav-icon" viewBox="0 0 20 20" fill="currentColor">
122
+ <path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-8-3a1 1 0 00-.867.5 1 1 0 11-1.731-1A3 3 0 0113 8a3.001 3.001 0 01-2 2.83V11a1 1 0 11-2 0v-1a1 1 0 011-1 1 1 0 100-2zm0 8a1 1 0 100-2 1 1 0 000 2z" clip-rule="evenodd"/>
123
+ </svg>
124
+ Troubleshooting
125
+ </a>
126
+ <a href="#faq" class="nav-link" data-page="faq">
127
+ <svg class="nav-icon" viewBox="0 0 20 20" fill="currentColor">
128
+ <path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-8-3a1 1 0 00-.867.5 1 1 0 11-1.731-1A3 3 0 0113 8a3.001 3.001 0 01-2 2.83V11a1 1 0 11-2 0v-1a1 1 0 011-1 1 1 0 100-2zm0 8a1 1 0 100-2 1 1 0 000 2z" clip-rule="evenodd"/>
129
+ </svg>
130
+ FAQ
131
+ </a>
132
+ <a href="#api-reference" class="nav-link" data-page="api-reference">
133
+ <svg class="nav-icon" viewBox="0 0 20 20" fill="currentColor">
134
+ <path fill-rule="evenodd" d="M12.316 3.051a1 1 0 01.633 1.265l-4 12a1 1 0 11-1.898-.632l4-12a1 1 0 011.265-.633zM5.707 6.293a1 1 0 010 1.414L3.414 10l2.293 2.293a1 1 0 11-1.414 1.414l-3-3a1 1 0 010-1.414l3-3a1 1 0 011.414 0zm8.586 0a1 1 0 011.414 0l3 3a1 1 0 010 1.414l-3 3a1 1 0 11-1.414-1.414L16.586 10l-2.293-2.293a1 1 0 010-1.414z" clip-rule="evenodd"/>
135
+ </svg>
136
+ API Reference
137
+ </a>
138
+ </div>
139
+ </nav>
140
+
141
+ <div class="sidebar-footer">
142
+ <a href="https://github.com/swadhinbiswas/opengrammar" target="_blank" class="github-link">
143
+ <svg class="github-icon" viewBox="0 0 24 24" fill="currentColor">
144
+ <path fill-rule="evenodd" d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z" clip-rule="evenodd"/>
145
+ </svg>
146
+ GitHub
147
+ </a>
148
+ </div>
149
+ </aside>
150
+
151
+ <!-- Main Content -->
152
+ <main class="main-content">
153
+ <header class="content-header">
154
+ <button class="menu-toggle" id="menuToggle">
155
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
156
+ <path d="M3 12h18M3 6h18M3 18h18"/>
157
+ </svg>
158
+ </button>
159
+ <div class="search-box">
160
+ <svg class="search-icon" viewBox="0 0 20 20" fill="currentColor">
161
+ <path fill-rule="evenodd" d="M8 4a4 4 0 100 8 4 4 0 000-8zM2 8a6 6 0 1110.89 3.476l4.817 4.817a1 1 0 01-1.414 1.414l-4.816-4.816A6 6 0 012 8z" clip-rule="evenodd"/>
162
+ </svg>
163
+ <input type="text" placeholder="Search documentation..." id="searchInput">
164
+ <kbd>⌘K</kbd>
165
+ </div>
166
+ <div class="header-actions">
167
+ <button class="theme-toggle" id="themeToggle" title="Toggle theme">
168
+ <svg class="sun-icon" viewBox="0 0 20 20" fill="currentColor">
169
+ <path fill-rule="evenodd" d="M10 2a1 1 0 011 1v1a1 1 0 11-2 0V3a1 1 0 011-1zm4 8a4 4 0 11-8 0 4 4 0 018 0zm-.464 4.95l.707.707a1 1 0 001.414-1.414l-.707-.707a1 1 0 00-1.414 1.414zm2.12-10.607a1 1 0 010 1.414l-.706.707a1 1 0 11-1.414-1.414l.707-.707a1 1 0 011.414 0zM17 11a1 1 0 100-2h-1a1 1 0 100 2h1zm-7 4a1 1 0 011 1v1a1 1 0 11-2 0v-1a1 1 0 011-1zM5.05 6.464A1 1 0 106.465 5.05l-.708-.707a1 1 0 00-1.414 1.414l.707.707zm1.414 8.486l-.707.707a1 1 0 01-1.414-1.414l.707-.707a1 1 0 011.414 1.414zM4 11a1 1 0 100-2H3a1 1 0 000 2h1z" clip-rule="evenodd"/>
170
+ </svg>
171
+ <svg class="moon-icon" viewBox="0 0 20 20" fill="currentColor">
172
+ <path d="M17.293 13.293A8 8 0 016.707 2.707a8.001 8.001 0 1010.586 10.586z"/>
173
+ </svg>
174
+ </button>
175
+ <a href="https://github.com/swadhinbiswas/opengrammar" target="_blank" class="github-btn">
176
+ <svg viewBox="0 0 24 24" fill="currentColor">
177
+ <path fill-rule="evenodd" d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z"/>
178
+ </svg>
179
+ Star on GitHub
180
+ </a>
181
+ </div>
182
+ </header>
183
+
184
+ <div class="content-wrapper">
185
+ <!-- Quick Start Section -->
186
+ <article id="quick-start" class="content-section active">
187
+ <div class="section-header">
188
+ <nav class="breadcrumb">
189
+ <a href="#">Docs</a>
190
+ <span class="breadcrumb-sep">/</span>
191
+ <span>Getting Started</span>
192
+ <span class="breadcrumb-sep">/</span>
193
+ <span class="current">Quick Start</span>
194
+ </nav>
195
+ <h1>πŸš€ Quick Start</h1>
196
+ <p class="section-description">Get OpenGrammar up and running in 5 minutes!</p>
197
+ </div>
198
+
199
+ <div class="content-body">
200
+ <div class="callout callout-primary">
201
+ <div class="callout-icon">⚑</div>
202
+ <div class="callout-content">
203
+ <strong>5-Minute Setup</strong>
204
+ <p>Follow these steps to get OpenGrammar running quickly. You'll need an API key for the best experience.</p>
205
+ </div>
206
+ </div>
207
+
208
+ <h2 id="step-1-get-api-key">Step 1: Get Your API Key (Optional but Recommended)</h2>
209
+ <p>For the best grammar checking experience, you'll need an API key. We recommend <strong>Groq</strong> for its free tier:</p>
210
+
211
+ <ol class="step-list">
212
+ <li>Visit <a href="https://console.groq.com" target="_blank">Groq Console</a></li>
213
+ <li>Sign up / Log in</li>
214
+ <li>Go to <strong>API Keys</strong> β†’ <strong>Create API Key</strong></li>
215
+ <li>Copy your key (starts with <code>gsk_</code>)</li>
216
+ </ol>
217
+
218
+ <div class="callout callout-success">
219
+ <div class="callout-icon">βœ…</div>
220
+ <div class="callout-content">
221
+ <strong>Free Tier:</strong> 100 requests/day - enough for most users!
222
+ </div>
223
+ </div>
224
+
225
+ <h2 id="step-2-build-extension">Step 2: Build the Extension</h2>
226
+
227
+ <div class="code-block">
228
+ <div class="code-header">
229
+ <span class="code-lang">bash</span>
230
+ <button class="copy-btn" onclick="copyCode(this)">
231
+ <svg viewBox="0 0 20 20" fill="currentColor">
232
+ <path d="M8 3a1 1 0 011-1h2a1 1 0 110 2H9a1 1 0 01-1-1z"/>
233
+ <path d="M6 3a2 2 0 00-2 2v11a2 2 0 002 2h8a2 2 0 002-2V5a2 2 0 00-2-2 3 3 0 01-3 3H9a3 3 0 01-3-3z"/>
234
+ </svg>
235
+ Copy
236
+ </button>
237
+ </div>
238
+ <pre><code class="language-bash"># Clone the repository
239
+git clone https://github.com/swadhinbiswas/opengrammar.git
240
+cd opengrammar/opengrammar/extension
241
+
242
+# Install dependencies
243
+bun install
244
+
245
+# Build the extension
246
+bun run build</code></pre>
247
+ </div>
248
+
249
+ <p>This creates a <code>dist/</code> folder with the built extension.</p>
250
+
251
+ <h2 id="step-3-load-browser">Step 3: Load in Your Browser</h2>
252
+
253
+ <div class="tabs">
254
+ <div class="tab-buttons">
255
+ <button class="tab-btn active" data-tab="chrome">Chrome</button>
256
+ <button class="tab-btn" data-tab="brave">Brave</button>
257
+ <button class="tab-btn" data-tab="edge">Edge</button>
258
+ <button class="tab-btn" data-tab="firefox">Firefox</button>
259
+ </div>
260
+ <div class="tab-content">
261
+ <div class="tab-pane active" id="chrome">
262
+ <h4>Chrome / Brave / Edge</h4>
263
+ <ol>
264
+ <li>Open <code>chrome://extensions/</code> (or <code>brave://extensions/</code> / <code>edge://extensions/</code>)</li>
265
+ <li>Enable <strong>Developer mode</strong> (toggle in top-right)</li>
266
+ <li>Click <strong>Load unpacked</strong></li>
267
+ <li>Select the <code>opengrammar/extension/dist</code> folder</li>
268
+ <li>βœ… Extension loaded! You'll see the OpenGrammar icon</li>
269
+ </ol>
270
+ </div>
271
+ <div class="tab-pane" id="brave">
272
+ <h4>Brave Browser</h4>
273
+ <ol>
274
+ <li>Open <code>brave://extensions/</code></li>
275
+ <li>Enable <strong>Developer mode</strong> (top-right)</li>
276
+ <li>Click <strong>Load unpacked</strong></li>
277
+ <li>Select <code>opengrammar/extension/dist</code> folder</li>
278
+ <li>βœ… Extension loaded!</li>
279
+ </ol>
280
+ </div>
281
+ <div class="tab-pane" id="edge">
282
+ <h4>Microsoft Edge</h4>
283
+ <ol>
284
+ <li>Open <code>edge://extensions/</code></li>
285
+ <li>Enable <strong>Developer mode</strong> (left sidebar)</li>
286
+ <li>Click <strong>Load unpacked</strong></li>
287
+ <li>Select <code>opengrammar/extension/dist</code> folder</li>
288
+ <li>βœ… Extension loaded!</li>
289
+ </ol>
290
+ </div>
291
+ <div class="tab-pane" id="firefox">
292
+ <h4>Mozilla Firefox</h4>
293
+ <div class="callout callout-warning">
294
+ <div class="callout-icon">⚠️</div>
295
+ <div class="callout-content">
296
+ <strong>Note:</strong> Firefox support is temporary. The extension must be reloaded each time you restart Firefox.
297
+ </div>
298
+ </div>
299
+ <ol>
300
+ <li>Open <code>about:debugging#/runtime/this-firefox</code></li>
301
+ <li>Click <strong>Load Temporary Add-on</strong></li>
302
+ <li>Navigate to <code>opengrammar/extension/dist</code></li>
303
+ <li>Select <code>manifest.json</code></li>
304
+ <li>βœ… Extension loaded!</li>
305
+ </ol>
306
+ </div>
307
+ </div>
308
+ </div>
309
+
310
+ <h2 id="step-4-configure">Step 4: Configure</h2>
311
+ <ol class="step-list">
312
+ <li>Click the OpenGrammar icon in your toolbar</li>
313
+ <li>Click <strong>Settings</strong> (gear icon)</li>
314
+ <li>Enter your API key (from Step 1)</li>
315
+ <li>Select Provider: <strong>Groq</strong></li>
316
+ <li>Select Model: <strong>llama-3.1-70b-versatile</strong></li>
317
+ <li>Backend URL: <code>http://localhost:8787</code> (for local testing)</li>
318
+ </ol>
319
+
320
+ <h2 id="step-5-start-writing">Step 5: Start Writing!</h2>
321
+ <ol class="step-list">
322
+ <li>Open any text box (Gmail, Google Docs, Notion, etc.)</li>
323
+ <li>Type something with a grammar error: <code>me and him went to store</code></li>
324
+ <li>You'll see a <span class="highlight-red">red underline</span> under the error</li>
325
+ <li>Click it to see the suggestion: <code>he and I went to store</code></li>
326
+ <li>Click <strong>Apply</strong> to fix it!</li>
327
+ </ol>
328
+
329
+ <div class="feature-grid">
330
+ <div class="feature-card">
331
+ <div class="feature-icon">πŸ“š</div>
332
+ <h4>Read Next</h4>
333
+ <ul class="link-list">
334
+ <li><a href="#backend-deployment">Backend Deployment</a></li>
335
+ <li><a href="#ai-providers">AI Provider Setup</a></li>
336
+ <li><a href="#using-opengrammar">Using OpenGrammar</a></li>
337
+ </ul>
338
+ </div>
339
+ <div class="feature-card">
340
+ <div class="feature-icon">⌨️</div>
341
+ <h4>Quick Commands</h4>
342
+ <div class="code-block small">
343
+ <pre><code># Start local backend
344
+cd opengrammar/opengrammar/backend
345
+bun run dev
346
+
347
+# Test backend
348
+curl http://localhost:8787/health</code></pre>
349
+ </div>
350
+ </div>
351
+ </div>
352
+
353
+ <div class="section-nav">
354
+ <a href="#" class="prev-link">
355
+ <svg viewBox="0 0 20 20" fill="currentColor">
356
+ <path fill-rule="evenodd" d="M12.707 5.293a1 1 0 010 1.414L9.414 10l3.293 3.293a1 1 0 01-1.414 1.414l-4-4a1 1 0 010-1.414l4-4a1 1 0 011.414 0z" clip-rule="evenodd"/>
357
+ </svg>
358
+ <span>Previous</span>
359
+ </a>
360
+ <a href="#browser-setup" class="next-link">
361
+ <span>Next</span>
362
+ <svg viewBox="0 0 20 20" fill="currentColor">
363
+ <path fill-rule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clip-rule="evenodd"/>
364
+ </svg>
365
+ </a>
366
+ </div>
367
+ </div>
368
+ </article>
369
+
370
+ <!-- Browser Extension Setup -->
371
+ <article id="browser-setup" class="content-section">
372
+ <div class="section-header">
373
+ <nav class="breadcrumb">
374
+ <a href="#">Docs</a>
375
+ <span class="breadcrumb-sep">/</span>
376
+ <span>Installation</span>
377
+ <span class="breadcrumb-sep">/</span>
378
+ <span class="current">Browser Extension</span>
379
+ </nav>
380
+ <h1>🌐 Browser Extension Setup</h1>
381
+ <p class="section-description">Install and configure OpenGrammar on Chrome, Brave, Edge, and Firefox.</p>
382
+ </div>
383
+
384
+ <div class="content-body">
385
+ <h2>πŸ“‹ Supported Browsers</h2>
386
+
387
+ <div class="table-wrapper">
388
+ <table class="data-table">
389
+ <thead>
390
+ <tr>
391
+ <th>Browser</th>
392
+ <th>Version</th>
393
+ <th>Status</th>
394
+ </tr>
395
+ </thead>
396
+ <tbody>
397
+ <tr>
398
+ <td><strong>Google Chrome</strong></td>
399
+ <td>88+</td>
400
+ <td><span class="status-badge success">βœ… Fully Supported</span></td>
401
+ </tr>
402
+ <tr>
403
+ <td><strong>Brave</strong></td>
404
+ <td>1.20+</td>
405
+ <td><span class="status-badge success">βœ… Fully Supported</span></td>
406
+ </tr>
407
+ <tr>
408
+ <td><strong>Microsoft Edge</strong></td>
409
+ <td>88+</td>
410
+ <td><span class="status-badge success">βœ… Fully Supported</span></td>
411
+ </tr>
412
+ <tr>
413
+ <td><strong>Mozilla Firefox</strong></td>
414
+ <td>90+</td>
415
+ <td><span class="status-badge warning">βœ… Supported (Temporary)</span></td>
416
+ </tr>
417
+ <tr>
418
+ <td><strong>Opera</strong></td>
419
+ <td>74+</td>
420
+ <td><span class="status-badge success">βœ… Supported</span></td>
421
+ </tr>
422
+ <tr>
423
+ <td><strong>Vivaldi</strong></td>
424
+ <td>3.6+</td>
425
+ <td><span class="status-badge success">βœ… Supported</span></td>
426
+ </tr>
427
+ </tbody>
428
+ </table>
429
+ </div>
430
+
431
+ <h2>πŸ”§ Installation - Chrome</h2>
432
+
433
+ <h3>Step 1: Build the Extension</h3>
434
+ <div class="code-block">
435
+ <div class="code-header">
436
+ <span class="code-lang">bash</span>
437
+ <button class="copy-btn" onclick="copyCode(this)">
438
+ <svg viewBox="0 0 20 20" fill="currentColor">
439
+ <path d="M8 3a1 1 0 011-1h2a1 1 0 110 2H9a1 1 0 01-1-1z"/>
440
+ <path d="M6 3a2 2 0 00-2 2v11a2 2 0 002 2h8a2 2 0 002-2V5a2 2 0 00-2-2 3 3 0 01-3 3H9a3 3 0 01-3-3z"/>
441
+ </svg>
442
+ Copy
443
+ </button>
444
+ </div>
445
+ <pre><code class="language-bash"># Navigate to extension folder
446
+cd opengrammar/opengrammar/extension
447
+
448
+# Install dependencies
449
+bun install
450
+
451
+# Build for production
452
+bun run build</code></pre>
453
+ </div>
454
+
455
+ <h3>Step 2: Load in Chrome</h3>
456
+ <ol class="step-list">
457
+ <li>Open Chrome</li>
458
+ <li>Navigate to <code>chrome://extensions/</code></li>
459
+ <li>Enable <strong>Developer mode</strong> (toggle in top-right corner)</li>
460
+ <li>Click <strong>Load unpacked</strong></li>
461
+ <li>Select the <code>opengrammar/extension/dist</code> folder</li>
462
+ <li>Click <strong>Select</strong></li>
463
+ </ol>
464
+ <div class="callout callout-success">
465
+ <div class="callout-icon">βœ…</div>
466
+ <div class="callout-content">
467
+ <strong>Extension loaded!</strong> You'll see the OpenGrammar icon in your toolbar.
468
+ </div>
469
+ </div>
470
+
471
+ <h2>βš™οΈ Initial Configuration</h2>
472
+
473
+ <h3>Step 1: Open Settings</h3>
474
+ <ol>
475
+ <li>Click the OpenGrammar icon in your toolbar</li>
476
+ <li>Click the <strong>Settings</strong> (gear) icon</li>
477
+ </ol>
478
+
479
+ <h3>Step 2: Configure Backend URL</h3>
480
+ <p>Enter your backend URL based on your deployment:</p>
481
+ <ul>
482
+ <li>Local: <code>http://localhost:8787</code></li>
483
+ <li>Cloudflare: <code>https://opengrammar.yourname.workers.dev</code></li>
484
+ <li>Vercel: <code>https://opengrammar-backend.vercel.app</code></li>
485
+ <li>Railway: <code>https://your-app.railway.app</code></li>
486
+ <li>Render: <code>https://opengrammar-backend.onrender.com</code></li>
487
+ <li>Docker: <code>http://localhost:8787</code></li>
488
+ </ul>
489
+
490
+ <h3>Step 3: Configure AI Provider</h3>
491
+ <div class="provider-cards">
492
+ <div class="provider-card">
493
+ <div class="provider-icon">⚑</div>
494
+ <h4>Groq (Free)</h4>
495
+ <p>100 requests/day free</p>
496
+ <code>llama-3.1-70b-versatile</code>
497
+ </div>
498
+ <div class="provider-card">
499
+ <div class="provider-icon">🟒</div>
500
+ <h4>OpenAI</h4>
501
+ <p>Best quality</p>
502
+ <code>gpt-4o-mini</code>
503
+ </div>
504
+ <div class="provider-card">
505
+ <div class="provider-icon">πŸ¦™</div>
506
+ <h4>Ollama</h4>
507
+ <p>Local & offline</p>
508
+ <code>qwen2.5:1.5b</code>
509
+ </div>
510
+ </div>
511
+
512
+ <h2>🎨 User Interface</h2>
513
+
514
+ <h3>Color-Coded Underlines</h3>
515
+ <div class="color-guide">
516
+ <div class="color-item">
517
+ <div class="color-swatch red"></div>
518
+ <div class="color-info">
519
+ <strong>Red</strong>
520
+ <span>Grammar/Spelling errors</span>
521
+ </div>
522
+ </div>
523
+ <div class="color-item">
524
+ <div class="color-swatch amber"></div>
525
+ <div class="color-info">
526
+ <strong>Amber</strong>
527
+ <span>Clarity issues</span>
528
+ </div>
529
+ </div>
530
+ <div class="color-item">
531
+ <div class="color-swatch blue"></div>
532
+ <div class="color-info">
533
+ <strong>Blue</strong>
534
+ <span>Style suggestions</span>
535
+ </div>
536
+ </div>
537
+ </div>
538
+
539
+ <div class="section-nav">
540
+ <a href="#quick-start" class="prev-link">
541
+ <svg viewBox="0 0 20 20" fill="currentColor">
542
+ <path fill-rule="evenodd" d="M12.707 5.293a1 1 0 010 1.414L9.414 10l3.293 3.293a1 1 0 01-1.414 1.414l-4-4a1 1 0 010-1.414l4-4a1 1 0 011.414 0z" clip-rule="evenodd"/>
543
+ </svg>
544
+ <span>Previous</span>
545
+ </a>
546
+ <a href="#backend-deployment" class="next-link">
547
+ <span>Next</span>
548
+ <svg viewBox="0 0 20 20" fill="currentColor">
549
+ <path fill-rule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clip-rule="evenodd"/>
550
+ </svg>
551
+ </a>
552
+ </div>
553
+ </div>
554
+ </article>
555
+
556
+ <!-- More sections will be loaded dynamically -->
557
+ <article id="what-is-opengrammar" class="content-section">
558
+ <div class="section-header">
559
+ <nav class="breadcrumb">
560
+ <a href="#">Docs</a>
561
+ <span class="breadcrumb-sep">/</span>
562
+ <span>Getting Started</span>
563
+ <span class="breadcrumb-sep">/</span>
564
+ <span class="current">What is OpenGrammar?</span>
565
+ </nav>
566
+ <h1>πŸ“– What is OpenGrammar?</h1>
567
+ <p class="section-description">Your privacy-first, open-source writing assistant</p>
568
+ </div>
569
+
570
+ <div class="content-body">
571
+ <div class="hero-card">
572
+ <div class="hero-card-content">
573
+ <h2>Why OpenGrammar?</h2>
574
+ <p>Most popular grammar assistants require you to send every keystroke to their servers and charge a hefty monthly fee for advanced features. OpenGrammar changes that.</p>
575
+ </div>
576
+ </div>
577
+
578
+ <h2>🌟 Key Features</h2>
579
+
580
+ <div class="feature-grid-2">
581
+ <div class="feature-box">
582
+ <div class="feature-box-icon">πŸ”’</div>
583
+ <h3>Zero Cost Option</h3>
584
+ <p>The core engine runs locally in your browser, checking for passive voice, repetition, and readability without needing a server or an internet connection.</p>
585
+ </div>
586
+ <div class="feature-box">
587
+ <div class="feature-box-icon">πŸ”‘</div>
588
+ <h3>Bring Your Own AI</h3>
589
+ <p>Just paste in your own API key (like OpenAI, Groq, or OpenRouter). You pay only fractions of a cent for what you actually use, directly to the AI provider.</p>
590
+ </div>
591
+ <div class="feature-box">
592
+ <div class="feature-box-icon">πŸ›‘οΈ</div>
593
+ <h3>Absolute Privacy</h3>
594
+ <p>We don't have a database. We don't have user accounts. Your API key never leaves your browser. If you use the AI features, your text is sent securely to a stateless edge function, processed, and immediately forgotten.</p>
595
+ </div>
596
+ <div class="feature-box">
597
+ <div class="feature-box-icon">πŸ“¦</div>
598
+ <h3>Open Source & Self-Hosted</h3>
599
+ <p>You can deploy the backend to Cloudflare Workers or Vercel Edge for free in one command. You own the infrastructure.</p>
600
+ </div>
601
+ </div>
602
+
603
+ <h2>✨ Features</h2>
604
+
605
+ <ul class="feature-list">
606
+ <li>
607
+ <svg viewBox="0 0 20 20" fill="currentColor">
608
+ <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd"/>
609
+ </svg>
610
+ <strong>Works Everywhere:</strong> Seamlessly integrates into text inputs, textareas, and rich text editors (like Gmail, Google Docs, Notion, and Reddit).
611
+ </li>
612
+ <li>
613
+ <svg viewBox="0 0 20 20" fill="currentColor">
614
+ <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd"/>
615
+ </svg>
616
+ <strong>Blazing Fast:</strong> Built with modern web technologies (React, Vite, Manifest V3) for minimal performance impact.
617
+ </li>
618
+ <li>
619
+ <svg viewBox="0 0 20 20" fill="currentColor">
620
+ <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd"/>
621
+ </svg>
622
+ <strong>Dual-Engine Architecture:</strong>
623
+ <ul>
624
+ <li><em>Rule-Based (Free & Offline):</em> Catches passive voice, repeated words, and overly long sentences.</li>
625
+ <li><em>AI-Powered (Requires API Key):</em> Advanced grammar, spelling, clarity, and stylistic suggestions.</li>
626
+ </ul>
627
+ </li>
628
+ <li>
629
+ <svg viewBox="0 0 20 20" fill="currentColor">
630
+ <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd"/>
631
+ </svg>
632
+ <strong>Tone & Style Rewriting:</strong> Right-click context menus or shortcuts to quickly rewrite text in 8 different tones.
633
+ </li>
634
+ <li>
635
+ <svg viewBox="0 0 20 20" fill="currentColor">
636
+ <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd"/>
637
+ </svg>
638
+ <strong>Writing Statistics:</strong> Built-in dashboard for readability scores, reading time, and vocabulary diversity.
639
+ </li>
640
+ <li>
641
+ <svg viewBox="0 0 20 20" fill="currentColor">
642
+ <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd"/>
643
+ </svg>
644
+ <strong>Intuitive UI:</strong> Familiar red, yellow, and blue underlines with click-to-apply suggestions.
645
+ </li>
646
+ </ul>
647
+
648
+ <div class="section-nav">
649
+ <a href="#quick-start" class="prev-link">
650
+ <svg viewBox="0 0 20 20" fill="currentColor">
651
+ <path fill-rule="evenodd" d="M12.707 5.293a1 1 0 010 1.414L9.414 10l3.293 3.293a1 1 0 01-1.414 1.414l-4-4a1 1 0 010-1.414l4-4a1 1 0 011.414 0z" clip-rule="evenodd"/>
652
+ </svg>
653
+ <span>Previous</span>
654
+ </a>
655
+ <a href="#browser-setup" class="next-link">
656
+ <span>Next</span>
657
+ <svg viewBox="0 0 20 20" fill="currentColor">
658
+ <path fill-rule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clip-rule="evenodd"/>
659
+ </svg>
660
+ </a>
661
+ </div>
662
+ </div>
663
+ </article>
664
+
665
+ <!-- Placeholder sections for other docs -->
666
+ <article id="backend-deployment" class="content-section">
667
+ <div class="section-header">
668
+ <nav class="breadcrumb">
669
+ <a href="#">Docs</a>
670
+ <span class="breadcrumb-sep">/</span>
671
+ <span>Installation</span>
672
+ <span class="breadcrumb-sep">/</span>
673
+ <span class="current">Backend Deployment</span>
674
+ </nav>
675
+ <h1>🌐 Backend Deployment</h1>
676
+ <p class="section-description">Deploy OpenGrammar backend to production with any of these platforms.</p>
677
+ </div>
678
+ <div class="content-body">
679
+ <div class="callout callout-info">
680
+ <div class="callout-icon">πŸ“‹</div>
681
+ <div class="callout-content">
682
+ <strong>Deployment Options Comparison</strong>
683
+ <p>Choose the platform that best fits your needs.</p>
684
+ </div>
685
+ </div>
686
+
687
+ <div class="table-wrapper">
688
+ <table class="data-table">
689
+ <thead>
690
+ <tr>
691
+ <th>Platform</th>
692
+ <th>Free Tier</th>
693
+ <th>Setup Time</th>
694
+ <th>Best For</th>
695
+ </tr>
696
+ </thead>
697
+ <tbody>
698
+ <tr>
699
+ <td><strong>Cloudflare Workers</strong></td>
700
+ <td>100K req/day</td>
701
+ <td>5 min</td>
702
+ <td>Production, global CDN</td>
703
+ </tr>
704
+ <tr>
705
+ <td><strong>Vercel</strong></td>
706
+ <td>100GB-hours/mo</td>
707
+ <td>5 min</td>
708
+ <td>Easy deployment</td>
709
+ </tr>
710
+ <tr>
711
+ <td><strong>Railway</strong></td>
712
+ <td>$5 credit</td>
713
+ <td>10 min</td>
714
+ <td>Always-on, no sleep</td>
715
+ </tr>
716
+ <tr>
717
+ <td><strong>Render</strong></td>
718
+ <td>750 hours/mo</td>
719
+ <td>10 min</td>
720
+ <td>Simple web service</td>
721
+ </tr>
722
+ <tr>
723
+ <td><strong>Docker</strong></td>
724
+ <td>Free</td>
725
+ <td>15 min</td>
726
+ <td>Self-hosting, full control</td>
727
+ </tr>
728
+ </tbody>
729
+ </table>
730
+ </div>
731
+
732
+ <h2>☁️ Cloudflare Workers (Recommended)</h2>
733
+
734
+ <h3>Prerequisites</h3>
735
+ <ul>
736
+ <li>Cloudflare account (free)</li>
737
+ <li>Node.js 18+</li>
738
+ </ul>
739
+
740
+ <h3>Step 1: Install Wrangler CLI</h3>
741
+ <div class="code-block">
742
+ <div class="code-header">
743
+ <span class="code-lang">bash</span>
744
+ <button class="copy-btn" onclick="copyCode(this)">
745
+ <svg viewBox="0 0 20 20" fill="currentColor">
746
+ <path d="M8 3a1 1 0 011-1h2a1 1 0 110 2H9a1 1 0 01-1-1z"/>
747
+ <path d="M6 3a2 2 0 00-2 2v11a2 2 0 002 2h8a2 2 0 002-2V5a2 2 0 00-2-2 3 3 0 01-3 3H9a3 3 0 01-3-3z"/>
748
+ </svg>
749
+ Copy
750
+ </button>
751
+ </div>
752
+ <pre><code class="language-bash">npm install -g wrangler</code></pre>
753
+ </div>
754
+
755
+ <h3>Step 2: Login to Cloudflare</h3>
756
+ <div class="code-block">
757
+ <pre><code class="language-bash">wrangler login</code></pre>
758
+ </div>
759
+
760
+ <h3>Step 3: Configure Environment</h3>
761
+ <div class="code-block">
762
+ <pre><code class="language-bash">cd opengrammar/opengrammar/backend
763
+
764
+# Create .dev.vars for local development
765
+cat > .dev.vars << EOF
766
+DEBUG=true
767
+GROQ_API_KEY=your_groq_key
768
+OPENAI_API_KEY=your_openai_key
769
+EOF</code></pre>
770
+ </div>
771
+
772
+ <h3>Step 4: Deploy</h3>
773
+ <div class="code-block">
774
+ <pre><code class="language-bash"># Deploy to production
775
+wrangler deploy --env production</code></pre>
776
+ </div>
777
+
778
+ <h3>Step 5: Get Your URL</h3>
779
+ <p>After deployment, you'll see:</p>
780
+ <div class="code-block">
781
+ <pre><code>Deployed https://opengrammar.yourname.workers.dev</code></pre>
782
+ </div>
783
+
784
+ <h2>β–² Vercel</h2>
785
+
786
+ <h3>Step 1: Install Vercel CLI</h3>
787
+ <div class="code-block">
788
+ <pre><code class="language-bash">npm install -g vercel</code></pre>
789
+ </div>
790
+
791
+ <h3>Step 2: Deploy</h3>
792
+ <div class="code-block">
793
+ <pre><code class="language-bash">cd opengrammar/opengrammar/backend
794
+vercel --prod</code></pre>
795
+ </div>
796
+
797
+ <h2>🐳 Docker Self-Hosting</h2>
798
+
799
+ <h3>Option 1: Docker Compose</h3>
800
+ <div class="code-block">
801
+ <pre><code class="language-bash">cd opengrammar/opengrammar
802
+
803
+# Start backend only
804
+docker-compose up -d opengrammar-backend
805
+
806
+# Start with Ollama (local LLM)
807
+docker-compose --profile local-llm up -d</code></pre>
808
+ </div>
809
+
810
+ <div class="section-nav">
811
+ <a href="#browser-setup" class="prev-link">
812
+ <svg viewBox="0 0 20 20" fill="currentColor">
813
+ <path fill-rule="evenodd" d="M12.707 5.293a1 1 0 010 1.414L9.414 10l3.293 3.293a1 1 0 01-1.414 1.414l-4-4a1 1 0 010-1.414l4-4a1 1 0 011.414 0z" clip-rule="evenodd"/>
814
+ </svg>
815
+ <span>Previous</span>
816
+ </a>
817
+ <a href="#docker-self-hosting" class="next-link">
818
+ <span>Next</span>
819
+ <svg viewBox="0 0 20 20" fill="currentColor">
820
+ <path fill-rule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clip-rule="evenodd"/>
821
+ </svg>
822
+ </a>
823
+ </div>
824
+ </div>
825
+ </article>
826
+
827
+ <article id="docker-self-hosting" class="content-section">
828
+ <div class="section-header">
829
+ <nav class="breadcrumb">
830
+ <a href="#">Docs</a>
831
+ <span class="breadcrumb-sep">/</span>
832
+ <span>Installation</span>
833
+ <span class="breadcrumb-sep">/</span>
834
+ <span class="current">Docker Self-Hosting</span>
835
+ </nav>
836
+ <h1>🐳 Docker Self-Hosting</h1>
837
+ <p class="section-description">Run OpenGrammar locally with Docker and optional local LLM support (Ollama).</p>
838
+ </div>
839
+ <div class="content-body">
840
+ <div class="callout callout-primary">
841
+ <div class="callout-icon">🎯</div>
842
+ <div class="callout-content">
843
+ <strong>Why Self-Host with Docker?</strong>
844
+ <ul>
845
+ <li><strong>Complete Privacy:</strong> All data stays on your machine</li>
846
+ <li><strong>Free:</strong> No API costs (with local LLM)</li>
847
+ <li><strong>Offline:</strong> Works without internet</li>
848
+ <li><strong>Full Control:</strong> Customize everything</li>
849
+ <li><strong>No Rate Limits:</strong> Use as much as you want</li>
850
+ </ul>
851
+ </div>
852
+ </div>
853
+
854
+ <h2>πŸš€ Quick Start</h2>
855
+
856
+ <h3>Option 1: Backend Only (Use Cloud APIs)</h3>
857
+ <div class="code-block">
858
+ <pre><code class="language-bash">cd opengrammar/opengrammar
859
+
860
+# Create environment file
861
+cat > .env << EOF
862
+PORT=8787
863
+NODE_ENV=production
864
+GROQ_API_KEY=your_groq_key
865
+OPENAI_API_KEY=your_openai_key
866
+EOF
867
+
868
+# Start backend
869
+docker-compose up -d opengrammar-backend
870
+
871
+# Check status
872
+docker-compose ps
873
+
874
+# View logs
875
+docker-compose logs -f opengrammar-backend</code></pre>
876
+ </div>
877
+
878
+ <h3>Option 2: Backend + Ollama (Local LLM)</h3>
879
+ <div class="code-block">
880
+ <pre><code class="language-bash">cd opengrammar/opengrammar
881
+
882
+# Start everything (requires NVIDIA GPU)
883
+docker-compose --profile local-llm up -d</code></pre>
884
+ </div>
885
+
886
+ <h2>πŸ€– Local LLM Setup with Ollama</h2>
887
+
888
+ <h3>Step 1: Start Ollama Container</h3>
889
+ <div class="code-block">
890
+ <pre><code class="language-bash">docker-compose --profile local-llm up -d ollama</code></pre>
891
+ </div>
892
+
893
+ <h3>Step 2: Pull Grammar-Focused Models</h3>
894
+ <div class="code-block">
895
+ <pre><code class="language-bash"># Enter Ollama container
896
+docker exec -it opengrammar-ollama bash
897
+
898
+# Pull models (inside container)
899
+ollama pull qwen2.5:0.5b # Ultra fast, 400MB
900
+ollama pull qwen2.5:1.5b # Balanced, 1GB
901
+ollama pull phi4-mini:3.8b # Great quality, 2.5GB
902
+ollama pull llama3.2:3b # Good all-rounder, 2GB
903
+
904
+# Exit container
905
+exit</code></pre>
906
+ </div>
907
+
908
+ <h2>🎯 Model Recommendations</h2>
909
+
910
+ <div class="table-wrapper">
911
+ <table class="data-table">
912
+ <thead>
913
+ <tr>
914
+ <th>Model</th>
915
+ <th>Size</th>
916
+ <th>RAM</th>
917
+ <th>Speed</th>
918
+ <th>Quality</th>
919
+ <th>Best For</th>
920
+ </tr>
921
+ </thead>
922
+ <tbody>
923
+ <tr>
924
+ <td><strong>qwen2.5:0.5b</strong></td>
925
+ <td>400MB</td>
926
+ <td>1GB</td>
927
+ <td>⚑⚑⚑⚑⚑</td>
928
+ <td>⭐⭐⭐</td>
929
+ <td>Fast basic checks</td>
930
+ </tr>
931
+ <tr>
932
+ <td><strong>qwen2.5:1.5b</strong></td>
933
+ <td>1GB</td>
934
+ <td>2GB</td>
935
+ <td>⚑⚑⚑⚑</td>
936
+ <td>⭐⭐⭐⭐</td>
937
+ <td>Balanced</td>
938
+ </tr>
939
+ <tr>
940
+ <td><strong>phi4-mini:3.8b</strong></td>
941
+ <td>2.5GB</td>
942
+ <td>4GB</td>
943
+ <td>⚑⚑⚑</td>
944
+ <td>⭐⭐⭐⭐⭐</td>
945
+ <td>Best quality</td>
946
+ </tr>
947
+ <tr>
948
+ <td><strong>llama3.2:3b</strong></td>
949
+ <td>2GB</td>
950
+ <td>3GB</td>
951
+ <td>⚑⚑⚑⚑</td>
952
+ <td>⭐⭐⭐⭐</td>
953
+ <td>Good balance</td>
954
+ </tr>
955
+ </tbody>
956
+ </table>
957
+ </div>
958
+
959
+ <div class="section-nav">
960
+ <a href="#backend-deployment" class="prev-link">
961
+ <svg viewBox="0 0 20 20" fill="currentColor">
962
+ <path fill-rule="evenodd" d="M12.707 5.293a1 1 0 010 1.414L9.414 10l3.293 3.293a1 1 0 01-1.414 1.414l-4-4a1 1 0 010-1.414l4-4a1 1 0 011.414 0z" clip-rule="evenodd"/>
963
+ </svg>
964
+ <span>Previous</span>
965
+ </a>
966
+ <a href="#ai-providers" class="next-link">
967
+ <span>Next</span>
968
+ <svg viewBox="0 0 20 20" fill="currentColor">
969
+ <path fill-rule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clip-rule="evenodd"/>
970
+ </svg>
971
+ </a>
972
+ </div>
973
+ </div>
974
+ </article>
975
+
976
+ <article id="ai-providers" class="content-section">
977
+ <div class="section-header">
978
+ <nav class="breadcrumb">
979
+ <a href="#">Docs</a>
980
+ <span class="breadcrumb-sep">/</span>
981
+ <span>Configuration</span>
982
+ <span class="breadcrumb-sep">/</span>
983
+ <span class="current">AI Providers</span>
984
+ </nav>
985
+ <h1>πŸ€– AI Provider Setup</h1>
986
+ <p class="section-description">Configure AI providers for advanced grammar checking and tone rewriting.</p>
987
+ </div>
988
+ <div class="content-body">
989
+ <h2>πŸ“‹ Overview</h2>
990
+ <p>OpenGrammar supports <strong>6 AI providers</strong>, giving you flexibility in cost, quality, and privacy.</p>
991
+
992
+ <div class="provider-comparison">
993
+ <div class="provider-card-large">
994
+ <div class="provider-header">
995
+ <span class="provider-icon">⚑</span>
996
+ <h3>Groq</h3>
997
+ </div>
998
+ <div class="provider-stats">
999
+ <div class="stat"><span>Speed:</span> ⚑⚑⚑</div>
1000
+ <div class="stat"><span>Quality:</span> ⭐⭐⭐⭐</div>
1001
+ <div class="stat"><span>Cost:</span> Free tier</div>
1002
+ </div>
1003
+ <p class="provider-desc">Fast & free - 100 requests/day</p>
1004
+ </div>
1005
+ <div class="provider-card-large">
1006
+ <div class="provider-header">
1007
+ <span class="provider-icon">🟒</span>
1008
+ <h3>OpenAI</h3>
1009
+ </div>
1010
+ <div class="provider-stats">
1011
+ <div class="stat"><span>Speed:</span> ⚑⚑</div>
1012
+ <div class="stat"><span>Quality:</span> ⭐⭐⭐⭐⭐</div>
1013
+ <div class="stat"><span>Cost:</span> $$</div>
1014
+ </div>
1015
+ <p class="provider-desc">Best quality - GPT-4o-mini</p>
1016
+ </div>
1017
+ <div class="provider-card-large">
1018
+ <div class="provider-header">
1019
+ <span class="provider-icon">πŸ¦™</span>
1020
+ <h3>Ollama</h3>
1021
+ </div>
1022
+ <div class="provider-stats">
1023
+ <div class="stat"><span>Speed:</span> ⚑⚑⚑</div>
1024
+ <div class="stat"><span>Quality:</span> ⭐⭐⭐</div>
1025
+ <div class="stat"><span>Cost:</span> Free</div>
1026
+ </div>
1027
+ <p class="provider-desc">Privacy, offline - Local LLM</p>
1028
+ </div>
1029
+ </div>
1030
+
1031
+ <h2>⚑ Groq (Recommended - Free)</h2>
1032
+
1033
+ <h3>Step 1: Create Account</h3>
1034
+ <ol>
1035
+ <li>Visit <a href="https://console.groq.com" target="_blank">Groq Console</a></li>
1036
+ <li>Click <strong>Sign Up</strong></li>
1037
+ <li>Complete registration</li>
1038
+ </ol>
1039
+
1040
+ <h3>Step 2: Get API Key</h3>
1041
+ <ol>
1042
+ <li>Go to <strong>API Keys</strong> in left sidebar</li>
1043
+ <li>Click <strong>Create API Key</strong></li>
1044
+ <li>Give it a name (e.g., "OpenGrammar")</li>
1045
+ <li>Copy the key (starts with <code>gsk_</code>)</li>
1046
+ </ol>
1047
+
1048
+ <h3>Step 3: Configure in Extension</h3>
1049
+ <ol>
1050
+ <li>Click OpenGrammar icon β†’ Settings</li>
1051
+ <li>Provider: <strong>Groq</strong></li>
1052
+ <li>API Key: <code>gsk_xxx</code> (paste your key)</li>
1053
+ <li>Model: <strong>llama-3.1-70b-versatile</strong></li>
1054
+ <li>Click <strong>Save</strong></li>
1055
+ </ol>
1056
+
1057
+ <div class="section-nav">
1058
+ <a href="#docker-self-hosting" class="prev-link">
1059
+ <svg viewBox="0 0 20 20" fill="currentColor">
1060
+ <path fill-rule="evenodd" d="M12.707 5.293a1 1 0 010 1.414L9.414 10l3.293 3.293a1 1 0 01-1.414 1.414l-4-4a1 1 0 010-1.414l4-4a1 1 0 011.414 0z" clip-rule="evenodd"/>
1061
+ </svg>
1062
+ <span>Previous</span>
1063
+ </a>
1064
+ <a href="#using-opengrammar" class="next-link">
1065
+ <span>Next</span>
1066
+ <svg viewBox="0 0 20 20" fill="currentColor">
1067
+ <path fill-rule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clip-rule="evenodd"/>
1068
+ </svg>
1069
+ </a>
1070
+ </div>
1071
+ </div>
1072
+ </article>
1073
+
1074
+ <article id="using-opengrammar" class="content-section">
1075
+ <div class="section-header">
1076
+ <nav class="breadcrumb">
1077
+ <a href="#">Docs</a>
1078
+ <span class="breadcrumb-sep">/</span>
1079
+ <span>User Guide</span>
1080
+ <span class="breadcrumb-sep">/</span>
1081
+ <span class="current">Using OpenGrammar</span>
1082
+ </nav>
1083
+ <h1>πŸ“– Using OpenGrammar</h1>
1084
+ <p class="section-description">Complete user guide to all features and functionality.</p>
1085
+ </div>
1086
+ <div class="content-body">
1087
+ <h2>✍️ Grammar Checking</h2>
1088
+
1089
+ <h3>Color-Coded Underlines</h3>
1090
+ <div class="color-guide">
1091
+ <div class="color-item">
1092
+ <div class="color-swatch red"></div>
1093
+ <div class="color-info">
1094
+ <strong>Red</strong>
1095
+ <span>Spelling/Grammar errors</span>
1096
+ </div>
1097
+ </div>
1098
+ <div class="color-item">
1099
+ <div class="color-swatch amber"></div>
1100
+ <div class="color-info">
1101
+ <strong>Amber</strong>
1102
+ <span>Clarity issues</span>
1103
+ </div>
1104
+ </div>
1105
+ <div class="color-item">
1106
+ <div class="color-swatch blue"></div>
1107
+ <div class="color-info">
1108
+ <strong>Blue</strong>
1109
+ <span>Style suggestions</span>
1110
+ </div>
1111
+ </div>
1112
+ </div>
1113
+
1114
+ <h3>Using Grammar Checking</h3>
1115
+ <ol class="step-list">
1116
+ <li><strong>Start Typing</strong> - Open any text input (Gmail, Google Docs, Notion, etc.)</li>
1117
+ <li><strong>Watch for Underlines</strong> - As you type, OpenGrammar automatically checks</li>
1118
+ <li><strong>Review Suggestions</strong> - Click any underlined text to see suggestions</li>
1119
+ <li><strong>Apply Changes</strong> - Click Apply, Ignore, or Add to Dictionary</li>
1120
+ </ol>
1121
+
1122
+ <h2>🎨 Tone Rewriting</h2>
1123
+
1124
+ <h3>Available Tones</h3>
1125
+ <div class="tone-grid">
1126
+ <div class="tone-card">
1127
+ <span class="tone-emoji">🎩</span>
1128
+ <h4>Formal</h4>
1129
+ <p>Business, academic</p>
1130
+ </div>
1131
+ <div class="tone-card">
1132
+ <span class="tone-emoji">😊</span>
1133
+ <h4>Casual</h4>
1134
+ <p>Friends, chat</p>
1135
+ </div>
1136
+ <div class="tone-card">
1137
+ <span class="tone-emoji">πŸ’Ό</span>
1138
+ <h4>Professional</h4>
1139
+ <p>Work emails</p>
1140
+ </div>
1141
+ <div class="tone-card">
1142
+ <span class="tone-emoji">πŸ€—</span>
1143
+ <h4>Friendly</h4>
1144
+ <p>Social media</p>
1145
+ </div>
1146
+ <div class="tone-card">
1147
+ <span class="tone-emoji">⚑</span>
1148
+ <h4>Concise</h4>
1149
+ <p>Quick messages</p>
1150
+ </div>
1151
+ <div class="tone-card">
1152
+ <span class="tone-emoji">πŸ“š</span>
1153
+ <h4>Detailed</h4>
1154
+ <p>Explanations</p>
1155
+ </div>
1156
+ <div class="tone-card">
1157
+ <span class="tone-emoji">πŸ’ͺ</span>
1158
+ <h4>Persuasive</h4>
1159
+ <p>Sales, pitches</p>
1160
+ </div>
1161
+ <div class="tone-card">
1162
+ <span class="tone-emoji">😐</span>
1163
+ <h4>Neutral</h4>
1164
+ <p>General use</p>
1165
+ </div>
1166
+ </div>
1167
+
1168
+ <div class="section-nav">
1169
+ <a href="#ai-providers" class="prev-link">
1170
+ <svg viewBox="0 0 20 20" fill="currentColor">
1171
+ <path fill-rule="evenodd" d="M12.707 5.293a1 1 0 010 1.414L9.414 10l3.293 3.293a1 1 0 01-1.414 1.414l-4-4a1 1 0 010-1.414l4-4a1 1 0 011.414 0z" clip-rule="evenodd"/>
1172
+ </svg>
1173
+ <span>Previous</span>
1174
+ </a>
1175
+ <a href="#tone-rewriting" class="next-link">
1176
+ <span>Next</span>
1177
+ <svg viewBox="0 0 20 20" fill="currentColor">
1178
+ <path fill-rule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clip-rule="evenodd"/>
1179
+ </svg>
1180
+ </a>
1181
+ </div>
1182
+ </div>
1183
+ </article>
1184
+
1185
+ <!-- Additional placeholder sections -->
1186
+ <article id="tone-rewriting" class="content-section">
1187
+ <div class="section-header">
1188
+ <nav class="breadcrumb">
1189
+ <a href="#">Docs</a>
1190
+ <span class="breadcrumb-sep">/</span>
1191
+ <span>User Guide</span>
1192
+ <span class="breadcrumb-sep">/</span>
1193
+ <span class="current">Tone Rewriting</span>
1194
+ </nav>
1195
+ <h1>🎨 Tone Rewriting</h1>
1196
+ <p class="section-description">Master the art of rewriting text in different tones.</p>
1197
+ </div>
1198
+ <div class="content-body">
1199
+ <h2>🎭 Available Tones</h2>
1200
+
1201
+ <div class="tone-detail-grid">
1202
+ <div class="tone-detail-card">
1203
+ <div class="tone-detail-header">
1204
+ <span class="tone-detail-icon">🎩</span>
1205
+ <h3>Formal</h3>
1206
+ </div>
1207
+ <p class="tone-detail-use">Use for: Academic writing, business proposals, official communications</p>
1208
+ <div class="tone-detail-example">
1209
+ <div class="example-input">
1210
+ <span class="label">Input:</span>
1211
+ <code>hey whats up</code>
1212
+ </div>
1213
+ <div class="example-output">
1214
+ <span class="label">Output:</span>
1215
+ <code>Greetings, how are you?</code>
1216
+ </div>
1217
+ </div>
1218
+ </div>
1219
+
1220
+ <div class="tone-detail-card">
1221
+ <div class="tone-detail-header">
1222
+ <span class="tone-detail-icon">😊</span>
1223
+ <h3>Casual</h3>
1224
+ </div>
1225
+ <p class="tone-detail-use">Use for: Social media, text messages, informal emails</p>
1226
+ <div class="tone-detail-example">
1227
+ <div class="example-input">
1228
+ <span class="label">Input:</span>
1229
+ <code>Greetings, how are you?</code>
1230
+ </div>
1231
+ <div class="example-output">
1232
+ <span class="label">Output:</span>
1233
+ <code>Hey, what's up?</code>
1234
+ </div>
1235
+ </div>
1236
+ </div>
1237
+
1238
+ <div class="tone-detail-card">
1239
+ <div class="tone-detail-header">
1240
+ <span class="tone-detail-icon">πŸ’Ό</span>
1241
+ <h3>Professional</h3>
1242
+ </div>
1243
+ <p class="tone-detail-use">Use for: Work emails, business communication, reports</p>
1244
+ <div class="tone-detail-example">
1245
+ <div class="example-input">
1246
+ <span class="label">Input:</span>
1247
+ <code>hey can we meet tmrw</code>
1248
+ </div>
1249
+ <div class="example-output">
1250
+ <span class="label">Output:</span>
1251
+ <code>Hello, could we schedule a meeting for tomorrow?</code>
1252
+ </div>
1253
+ </div>
1254
+ </div>
1255
+ </div>
1256
+
1257
+ <h2>πŸš€ How to Use</h2>
1258
+
1259
+ <h3>Method 1: Right-Click Menu</h3>
1260
+ <ol>
1261
+ <li>Select text you want to rewrite</li>
1262
+ <li>Right-click</li>
1263
+ <li>Choose "Rewrite with OpenGrammar"</li>
1264
+ <li>Choose tone and see preview</li>
1265
+ <li>Apply or Copy result</li>
1266
+ </ol>
1267
+
1268
+ <h3>Method 2: Keyboard Shortcut</h3>
1269
+ <ol>
1270
+ <li>Select text</li>
1271
+ <li>Press <kbd>Ctrl+Shift+R</kbd> (Windows/Linux) or <kbd>Cmd+Shift+R</kbd> (Mac)</li>
1272
+ <li>Choose tone</li>
1273
+ <li>Apply changes</li>
1274
+ </ol>
1275
+
1276
+ <div class="section-nav">
1277
+ <a href="#using-opengrammar" class="prev-link">
1278
+ <svg viewBox="0 0 20 20" fill="currentColor">
1279
+ <path fill-rule="evenodd" d="M12.707 5.293a1 1 0 010 1.414L9.414 10l3.293 3.293a1 1 0 01-1.414 1.414l-4-4a1 1 0 010-1.414l4-4a1 1 0 011.414 0z" clip-rule="evenodd"/>
1280
+ </svg>
1281
+ <span>Previous</span>
1282
+ </a>
1283
+ <a href="#writing-statistics" class="next-link">
1284
+ <span>Next</span>
1285
+ <svg viewBox="0 0 20 20" fill="currentColor">
1286
+ <path fill-rule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clip-rule="evenodd"/>
1287
+ </svg>
1288
+ </a>
1289
+ </div>
1290
+ </div>
1291
+ </article>
1292
+
1293
+ <article id="writing-statistics" class="content-section">
1294
+ <div class="section-header">
1295
+ <nav class="breadcrumb">
1296
+ <a href="#">Docs</a>
1297
+ <span class="breadcrumb-sep">/</span>
1298
+ <span>User Guide</span>
1299
+ <span class="breadcrumb-sep">/</span>
1300
+ <span class="current">Writing Statistics</span>
1301
+ </nav>
1302
+ <h1>πŸ“Š Writing Statistics</h1>
1303
+ <p class="section-description">Analyze and improve your writing with detailed statistics.</p>
1304
+ </div>
1305
+ <div class="content-body">
1306
+ <h2>πŸ“ˆ Available Metrics</h2>
1307
+
1308
+ <h3>Readability Scores</h3>
1309
+
1310
+ <div class="metric-card">
1311
+ <div class="metric-header">
1312
+ <h4>Flesch Reading Ease Score</h4>
1313
+ <span class="metric-badge">0-100</span>
1314
+ </div>
1315
+ <div class="metric-scale">
1316
+ <div class="scale-item"><span class="range">90-100</span> <span class="label">Very Easy (5th grade)</span></div>
1317
+ <div class="scale-item"><span class="range">80-89</span> <span class="label">Easy (6th grade)</span></div>
1318
+ <div class="scale-item"><span class="range">70-79</span> <span class="label">Fairly Easy (7th grade)</span></div>
1319
+ <div class="scale-item"><span class="range">60-69</span> <span class="label">Standard (8th-9th grade)</span></div>
1320
+ <div class="scale-item"><span class="range">50-59</span> <span class="label">Fairly Difficult (10th-12th)</span></div>
1321
+ <div class="scale-item"><span class="range">30-49</span> <span class="label">Difficult (College)</span></div>
1322
+ <div class="scale-item"><span class="range">0-29</span> <span class="label">Very Difficult (Graduate+)</span></div>
1323
+ </div>
1324
+ </div>
1325
+
1326
+ <div class="metric-card">
1327
+ <div class="metric-header">
1328
+ <h4>Flesch-Kincaid Grade Level</h4>
1329
+ <span class="metric-badge">US Grades</span>
1330
+ </div>
1331
+ <div class="metric-scale">
1332
+ <div class="scale-item"><span class="range">1-6</span> <span class="label">Elementary School</span></div>
1333
+ <div class="scale-item"><span class="range">7-9</span> <span class="label">Middle School</span></div>
1334
+ <div class="scale-item"><span class="range">10-12</span> <span class="label">High School</span></div>
1335
+ <div class="scale-item"><span class="range">13-16</span> <span class="label">College</span></div>
1336
+ <div class="scale-item"><span class="range">17+</span> <span class="label">Graduate School</span></div>
1337
+ </div>
1338
+ </div>
1339
+
1340
+ <h3>Time Estimates</h3>
1341
+ <ul>
1342
+ <li><strong>Reading Time:</strong> Words Γ· 200 words per minute</li>
1343
+ <li><strong>Speaking Time:</strong> Words Γ· 150 words per minute</li>
1344
+ </ul>
1345
+
1346
+ <div class="section-nav">
1347
+ <a href="#tone-rewriting" class="prev-link">
1348
+ <svg viewBox="0 0 20 20" fill="currentColor">
1349
+ <path fill-rule="evenodd" d="M12.707 5.293a1 1 0 010 1.414L9.414 10l3.293 3.293a1 1 0 01-1.414 1.414l-4-4a1 1 0 010-1.414l4-4a1 1 0 011.414 0z" clip-rule="evenodd"/>
1350
+ </svg>
1351
+ <span>Previous</span>
1352
+ </a>
1353
+ <a href="#keyboard-shortcuts" class="next-link">
1354
+ <span>Next</span>
1355
+ <svg viewBox="0 0 20 20" fill="currentColor">
1356
+ <path fill-rule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clip-rule="evenodd"/>
1357
+ </svg>
1358
+ </a>
1359
+ </div>
1360
+ </div>
1361
+ </article>
1362
+
1363
+ <article id="keyboard-shortcuts" class="content-section">
1364
+ <div class="section-header">
1365
+ <nav class="breadcrumb">
1366
+ <a href="#">Docs</a>
1367
+ <span class="breadcrumb-sep">/</span>
1368
+ <span>User Guide</span>
1369
+ <span class="breadcrumb-sep">/</span>
1370
+ <span class="current">Keyboard Shortcuts</span>
1371
+ </nav>
1372
+ <h1>⌨️ Keyboard Shortcuts</h1>
1373
+ <p class="section-description">All keyboard shortcuts for quick access to OpenGrammar features.</p>
1374
+ </div>
1375
+ <div class="content-body">
1376
+ <h2>Default Shortcuts</h2>
1377
+
1378
+ <div class="table-wrapper">
1379
+ <table class="data-table">
1380
+ <thead>
1381
+ <tr>
1382
+ <th>Action</th>
1383
+ <th>Windows/Linux</th>
1384
+ <th>Mac</th>
1385
+ </tr>
1386
+ </thead>
1387
+ <tbody>
1388
+ <tr>
1389
+ <td><strong>Rewrite Selected Text</strong></td>
1390
+ <td><kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>R</kbd></td>
1391
+ <td><kbd>Cmd</kbd> + <kbd>Shift</kbd> + <kbd>R</kbd></td>
1392
+ </tr>
1393
+ <tr>
1394
+ <td><strong>Toggle Extension</strong></td>
1395
+ <td><kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>E</kbd></td>
1396
+ <td><kbd>Cmd</kbd> + <kbd>Shift</kbd> + <kbd>E</kbd></td>
1397
+ </tr>
1398
+ <tr>
1399
+ <td><strong>Open Statistics</strong></td>
1400
+ <td><kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>S</kbd></td>
1401
+ <td><kbd>Cmd</kbd> + <kbd>Shift</kbd> + <kbd>S</kbd></td>
1402
+ </tr>
1403
+ <tr>
1404
+ <td><strong>Open Settings</strong></td>
1405
+ <td><kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>,</kbd></td>
1406
+ <td><kbd>Cmd</kbd> + <kbd>Shift</kbd> + <kbd>,</kbd></td>
1407
+ </tr>
1408
+ </tbody>
1409
+ </table>
1410
+ </div>
1411
+
1412
+ <div class="section-nav">
1413
+ <a href="#writing-statistics" class="prev-link">
1414
+ <svg viewBox="0 0 20 20" fill="currentColor">
1415
+ <path fill-rule="evenodd" d="M12.707 5.293a1 1 0 010 1.414L9.414 10l3.293 3.293a1 1 0 01-1.414 1.414l-4-4a1 1 0 010-1.414l4-4a1 1 0 011.414 0z" clip-rule="evenodd"/>
1416
+ </svg>
1417
+ <span>Previous</span>
1418
+ </a>
1419
+ <a href="#troubleshooting" class="next-link">
1420
+ <span>Next</span>
1421
+ <svg viewBox="0 0 20 20" fill="currentColor">
1422
+ <path fill-rule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clip-rule="evenodd"/>
1423
+ </svg>
1424
+ </a>
1425
+ </div>
1426
+ </div>
1427
+ </article>
1428
+
1429
+ <article id="troubleshooting" class="content-section">
1430
+ <div class="section-header">
1431
+ <nav class="breadcrumb">
1432
+ <a href="#">Docs</a>
1433
+ <span class="breadcrumb-sep">/</span>
1434
+ <span>Support</span>
1435
+ <span class="breadcrumb-sep">/</span>
1436
+ <span class="current">Troubleshooting</span>
1437
+ </nav>
1438
+ <h1>πŸ”§ Troubleshooting</h1>
1439
+ <p class="section-description">Solve common OpenGrammar issues with this comprehensive guide.</p>
1440
+ </div>
1441
+ <div class="content-body">
1442
+ <h2>πŸ” Common Issues</h2>
1443
+
1444
+ <h3>No Grammar Highlights</h3>
1445
+ <div class="troubleshoot-card">
1446
+ <h4>Symptoms</h4>
1447
+ <ul>
1448
+ <li>Typing text with errors</li>
1449
+ <li>No red/amber/blue underlines appear</li>
1450
+ <li>Extension icon shows no error count</li>
1451
+ </ul>
1452
+ <h4>Solutions</h4>
1453
+ <ol>
1454
+ <li>Check extension is enabled</li>
1455
+ <li>Verify site is not in disabled domains</li>
1456
+ <li>Test backend: <code>curl http://localhost:8787/health</code></li>
1457
+ <li>Reload the page</li>
1458
+ <li>Check browser console (F12) for errors</li>
1459
+ </ol>
1460
+ </div>
1461
+
1462
+ <h3>Backend Connection Failed</h3>
1463
+ <div class="troubleshoot-card">
1464
+ <h4>Symptoms</h4>
1465
+ <ul>
1466
+ <li>Red status indicator in extension</li>
1467
+ <li>"Cannot connect to backend" error</li>
1468
+ <li>No AI suggestions</li>
1469
+ </ul>
1470
+ <h4>Solutions</h4>
1471
+ <ol>
1472
+ <li>Verify Backend URL in settings</li>
1473
+ <li>Test backend: <code>curl your-backend-url/health</code></li>
1474
+ <li>Check CORS configuration</li>
1475
+ <li>Restart backend service</li>
1476
+ <li>Check firewall settings</li>
1477
+ </ol>
1478
+ </div>
1479
+
1480
+ <h3>AI Not Working</h3>
1481
+ <div class="troubleshoot-card">
1482
+ <h4>Symptoms</h4>
1483
+ <ul>
1484
+ <li>Rule-based checks work</li>
1485
+ <li>AI suggestions don't appear</li>
1486
+ <li>"API key invalid" error</li>
1487
+ </ul>
1488
+ <h4>Solutions</h4>
1489
+ <ol>
1490
+ <li>Verify API key is entered correctly</li>
1491
+ <li>Check for typos (no spaces)</li>
1492
+ <li>Ensure correct provider is selected</li>
1493
+ <li>Test API key with provider directly</li>
1494
+ <li>Check rate limits (Groq: 100/day free)</li>
1495
+ </ol>
1496
+ </div>
1497
+
1498
+ <div class="section-nav">
1499
+ <a href="#keyboard-shortcuts" class="prev-link">
1500
+ <svg viewBox="0 0 20 20" fill="currentColor">
1501
+ <path fill-rule="evenodd" d="M12.707 5.293a1 1 0 010 1.414L9.414 10l3.293 3.293a1 1 0 01-1.414 1.414l-4-4a1 1 0 010-1.414l4-4a1 1 0 011.414 0z" clip-rule="evenodd"/>
1502
+ </svg>
1503
+ <span>Previous</span>
1504
+ </a>
1505
+ <a href="#faq" class="next-link">
1506
+ <span>Next</span>
1507
+ <svg viewBox="0 0 20 20" fill="currentColor">
1508
+ <path fill-rule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clip-rule="evenodd"/>
1509
+ </svg>
1510
+ </a>
1511
+ </div>
1512
+ </div>
1513
+ </article>
1514
+
1515
+ <article id="faq" class="content-section">
1516
+ <div class="section-header">
1517
+ <nav class="breadcrumb">
1518
+ <a href="#">Docs</a>
1519
+ <span class="breadcrumb-sep">/</span>
1520
+ <span>Support</span>
1521
+ <span class="breadcrumb-sep">/</span>
1522
+ <span class="current">FAQ</span>
1523
+ </nav>
1524
+ <h1>❓ Frequently Asked Questions</h1>
1525
+ <p class="section-description">Common questions about OpenGrammar.</p>
1526
+ </div>
1527
+ <div class="content-body">
1528
+ <div class="faq-list">
1529
+ <div class="faq-item">
1530
+ <div class="faq-question">
1531
+ <h3>Is OpenGrammar really free?</h3>
1532
+ <svg viewBox="0 0 20 20" fill="currentColor">
1533
+ <path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd"/>
1534
+ </svg>
1535
+ </div>
1536
+ <div class="faq-answer">
1537
+ <p>Yes! The core rule-based engine is completely free and works offline. For AI-powered features, you bring your own API key and pay only for what you use directly to the provider (often fractions of a cent).</p>
1538
+ </div>
1539
+ </div>
1540
+
1541
+ <div class="faq-item">
1542
+ <div class="faq-question">
1543
+ <h3>How does OpenGrammar protect my privacy?</h3>
1544
+ <svg viewBox="0 0 20 20" fill="currentColor">
1545
+ <path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd"/>
1546
+ </svg>
1547
+ </div>
1548
+ <div class="faq-answer">
1549
+ <p>OpenGrammar has no databases, no user accounts, and no tracking. Your API key never leaves your browser. When using AI features, text is sent to a stateless edge function, processed, and immediately forgotten.</p>
1550
+ </div>
1551
+ </div>
1552
+
1553
+ <div class="faq-item">
1554
+ <div class="faq-question">
1555
+ <h3>Which AI provider should I use?</h3>
1556
+ <svg viewBox="0 0 20 20" fill="currentColor">
1557
+ <path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd"/>
1558
+ </svg>
1559
+ </div>
1560
+ <div class="faq-answer">
1561
+ <p>For free usage, we recommend <strong>Groq</strong> (100 requests/day free). For best quality, use <strong>OpenAI GPT-4o-mini</strong>. For complete privacy, use <strong>Ollama</strong> to run models locally offline.</p>
1562
+ </div>
1563
+ </div>
1564
+
1565
+ <div class="faq-item">
1566
+ <div class="faq-question">
1567
+ <h3>Can I use OpenGrammar without internet?</h3>
1568
+ <svg viewBox="0 0 20 20" fill="currentColor">
1569
+ <path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd"/>
1570
+ </svg>
1571
+ </div>
1572
+ <div class="faq-answer">
1573
+ <p>Yes! The rule-based engine works completely offline. For AI features, you can use Ollama to run models locally on your machine, giving you full offline capability.</p>
1574
+ </div>
1575
+ </div>
1576
+
1577
+ <div class="faq-item">
1578
+ <div class="faq-question">
1579
+ <h3>Does OpenGrammar work on Google Docs?</h3>
1580
+ <svg viewBox="0 0 20 20" fill="currentColor">
1581
+ <path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd"/>
1582
+ </svg>
1583
+ </div>
1584
+ <div class="faq-answer">
1585
+ <p>Yes, OpenGrammar works on Google Docs and most rich text editors. Google Docs support is actively being improved for better compatibility.</p>
1586
+ </div>
1587
+ </div>
1588
+ </div>
1589
+
1590
+ <div class="section-nav">
1591
+ <a href="#troubleshooting" class="prev-link">
1592
+ <svg viewBox="0 0 20 20" fill="currentColor">
1593
+ <path fill-rule="evenodd" d="M12.707 5.293a1 1 0 010 1.414L9.414 10l3.293 3.293a1 1 0 01-1.414 1.414l-4-4a1 1 0 010-1.414l4-4a1 1 0 011.414 0z" clip-rule="evenodd"/>
1594
+ </svg>
1595
+ <span>Previous</span>
1596
+ </a>
1597
+ <a href="#api-reference" class="next-link">
1598
+ <span>Next</span>
1599
+ <svg viewBox="0 0 20 20" fill="currentColor">
1600
+ <path fill-rule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clip-rule="evenodd"/>
1601
+ </svg>
1602
+ </a>
1603
+ </div>
1604
+ </div>
1605
+ </article>
1606
+
1607
+ <article id="api-reference" class="content-section">
1608
+ <div class="section-header">
1609
+ <nav class="breadcrumb">
1610
+ <a href="#">Docs</a>
1611
+ <span class="breadcrumb-sep">/</span>
1612
+ <span>Support</span>
1613
+ <span class="breadcrumb-sep">/</span>
1614
+ <span class="current">API Reference</span>
1615
+ </nav>
1616
+ <h1>πŸ“š API Reference</h1>
1617
+ <p class="section-description">Backend API documentation for developers.</p>
1618
+ </div>
1619
+ <div class="content-body">
1620
+ <h2>Endpoints</h2>
1621
+
1622
+ <h3>Health Check</h3>
1623
+ <div class="api-endpoint">
1624
+ <div class="api-method get">GET</div>
1625
+ <code class="api-path">/health</code>
1626
+ </div>
1627
+ <p>Returns the health status of the backend service.</p>
1628
+
1629
+ <div class="code-block">
1630
+ <div class="code-header">
1631
+ <span class="code-lang">bash</span>
1632
+ <button class="copy-btn" onclick="copyCode(this)">
1633
+ <svg viewBox="0 0 20 20" fill="currentColor">
1634
+ <path d="M8 3a1 1 0 011-1h2a1 1 0 110 2H9a1 1 0 01-1-1z"/>
1635
+ <path d="M6 3a2 2 0 00-2 2v11a2 2 0 002 2h8a2 2 0 002-2V5a2 2 0 00-2-2 3 3 0 01-3 3H9a3 3 0 01-3-3z"/>
1636
+ </svg>
1637
+ Copy
1638
+ </button>
1639
+ </div>
1640
+ <pre><code class="language-bash">curl http://localhost:8787/health</code></pre>
1641
+ </div>
1642
+
1643
+ <h4>Response</h4>
1644
+ <div class="code-block">
1645
+ <pre><code class="language-json">{
1646
+ "status": "healthy",
1647
+ "timestamp": "2026-03-20T12:00:00.000Z",
1648
+ "environment": "production",
1649
+ "version": "2.0.0"
1650
+}</code></pre>
1651
+ </div>
1652
+
1653
+ <h3>Analyze Text</h3>
1654
+ <div class="api-endpoint">
1655
+ <div class="api-method post">POST</div>
1656
+ <code class="api-path">/analyze</code>
1657
+ </div>
1658
+ <p>Analyze text for grammar, spelling, clarity, and style issues.</p>
1659
+
1660
+ <div class="code-block">
1661
+ <div class="code-header">
1662
+ <span class="code-lang">bash</span>
1663
+ <button class="copy-btn" onclick="copyCode(this)">
1664
+ <svg viewBox="0 0 20 20" fill="currentColor">
1665
+ <path d="M8 3a1 1 0 011-1h2a1 1 0 110 2H9a1 1 0 01-1-1z"/>
1666
+ <path d="M6 3a2 2 0 00-2 2v11a2 2 0 002 2h8a2 2 0 002-2V5a2 2 0 00-2-2 3 3 0 01-3 3H9a3 3 0 01-3-3z"/>
1667
+ </svg>
1668
+ Copy
1669
+ </button>
1670
+ </div>
1671
+ <pre><code class="language-bash">curl -X POST http://localhost:8787/analyze \
1672
+ -H "Content-Type: application/json" \
1673
+ -d '{
1674
+ "text": "me and him went to store",
1675
+ "apiKey": "your-api-key",
1676
+ "provider": "groq",
1677
+ "model": "llama-3.1-70b-versatile"
1678
+ }'</code></pre>
1679
+ </div>
1680
+
1681
+ <h4>Request Body</h4>
1682
+ <div class="table-wrapper">
1683
+ <table class="data-table">
1684
+ <thead>
1685
+ <tr>
1686
+ <th>Field</th>
1687
+ <th>Type</th>
1688
+ <th>Required</th>
1689
+ <th>Description</th>
1690
+ </tr>
1691
+ </thead>
1692
+ <tbody>
1693
+ <tr>
1694
+ <td><code>text</code></td>
1695
+ <td>string</td>
1696
+ <td>Yes</td>
1697
+ <td>Text to analyze (max 50,000 chars)</td>
1698
+ </tr>
1699
+ <tr>
1700
+ <td><code>apiKey</code></td>
1701
+ <td>string</td>
1702
+ <td>No</td>
1703
+ <td>AI provider API key</td>
1704
+ </tr>
1705
+ <tr>
1706
+ <td><code>provider</code></td>
1707
+ <td>string</td>
1708
+ <td>No</td>
1709
+ <td>AI provider (groq, openai, ollama, etc.)</td>
1710
+ </tr>
1711
+ <tr>
1712
+ <td><code>model</code></td>
1713
+ <td>string</td>
1714
+ <td>No</td>
1715
+ <td>Model to use for AI analysis</td>
1716
+ </tr>
1717
+ </tbody>
1718
+ </table>
1719
+ </div>
1720
+
1721
+ <h3>Rewrite Text</h3>
1722
+ <div class="api-endpoint">
1723
+ <div class="api-method post">POST</div>
1724
+ <code class="api-path">/rewrite</code>
1725
+ </div>
1726
+ <p>Rewrite text in different tones.</p>
1727
+
1728
+ <div class="code-block">
1729
+ <pre><code class="language-bash">curl -X POST http://localhost:8787/rewrite \
1730
+ -H "Content-Type: application/json" \
1731
+ -d '{
1732
+ "text": "hey whats up",
1733
+ "tone": "formal",
1734
+ "apiKey": "your-api-key"
1735
+ }'</code></pre>
1736
+ </div>
1737
+
1738
+ <h4>Response</h4>
1739
+ <div class="code-block">
1740
+ <pre><code class="language-json">{
1741
+ "original": "hey whats up",
1742
+ "rewritten": "Greetings, how are you?",
1743
+ "tone": "formal"
1744
+}</code></pre>
1745
+ </div>
1746
+
1747
+ <div class="section-nav">
1748
+ <a href="#faq" class="prev-link">
1749
+ <svg viewBox="0 0 20 20" fill="currentColor">
1750
+ <path fill-rule="evenodd" d="M12.707 5.293a1 1 0 010 1.414L9.414 10l3.293 3.293a1 1 0 01-1.414 1.414l-4-4a1 1 0 010-1.414l4-4a1 1 0 011.414 0z" clip-rule="evenodd"/>
1751
+ </svg>
1752
+ <span>Previous</span>
1753
+ </a>
1754
+ </div>
1755
+ </div>
1756
+ </article>
1757
+ </div>
1758
+
1759
+ <footer class="content-footer">
1760
+ <div class="footer-content">
1761
+ <p>Built with ❀️ by <a href="https://github.com/swadhinbiswas" target="_blank">Swadhin Biswas</a></p>
1762
+ <p>OpenGrammar is licensed under <a href="https://opensource.org/licenses/Apache-2.0" target="_blank">Apache 2.0</a></p>
1763
+ </div>
1764
+ </footer>
1765
+ </main>
1766
+
1767
+ <script src="script.js"></script>
1768
+</body>
1769
+</html>
0
1770
β–Όdocs-site/script.js
+365-0
1
+// ===================================
2
+// OpenGrammar Documentation Scripts
3
+// ===================================
4
+
5
+document.addEventListener('DOMContentLoaded', () => {
6
+ // Initialize theme
7
+ initTheme();
8
+
9
+ // Initialize navigation
10
+ initNavigation();
11
+
12
+ // Initialize tabs
13
+ initTabs();
14
+
15
+ // Initialize FAQ
16
+ initFAQ();
17
+
18
+ // Initialize search
19
+ initSearch();
20
+
21
+ // Initialize mobile menu
22
+ initMobileMenu();
23
+
24
+ // Initialize code copy
25
+ initCodeCopy();
26
+
27
+ // Initialize smooth scroll
28
+ initSmoothScroll();
29
+});
30
+
31
+// Theme Toggle
32
+function initTheme() {
33
+ const themeToggle = document.getElementById('themeToggle');
34
+ const mobileThemeToggle = document.getElementById('mobile-theme-toggle');
35
+
36
+ // Check for saved theme preference or default to light mode
37
+ const savedTheme = localStorage.getItem('theme');
38
+ if (savedTheme === 'dark') {
39
+ document.body.classList.add('dark');
40
+ }
41
+
42
+ // Desktop theme toggle
43
+ if (themeToggle) {
44
+ themeToggle.addEventListener('click', () => {
45
+ document.body.classList.toggle('dark');
46
+ const isDark = document.body.classList.contains('dark');
47
+ localStorage.setItem('theme', isDark ? 'dark' : 'light');
48
+ });
49
+ }
50
+
51
+ // Mobile theme toggle
52
+ if (mobileThemeToggle) {
53
+ mobileThemeToggle.addEventListener('click', () => {
54
+ document.body.classList.toggle('dark');
55
+ const isDark = document.body.classList.contains('dark');
56
+ localStorage.setItem('theme', isDark ? 'dark' : 'light');
57
+ });
58
+ }
59
+}
60
+
61
+// Navigation
62
+function initNavigation() {
63
+ const navLinks = document.querySelectorAll('.nav-link');
64
+ const sections = document.querySelectorAll('.content-section');
65
+
66
+ // Handle nav link clicks
67
+ navLinks.forEach(link => {
68
+ link.addEventListener('click', (e) => {
69
+ e.preventDefault();
70
+ const targetId = link.getAttribute('data-page');
71
+
72
+ // Update active nav link
73
+ navLinks.forEach(l => l.classList.remove('active'));
74
+ link.classList.add('active');
75
+
76
+ // Show target section
77
+ showSection(targetId);
78
+
79
+ // Update URL hash
80
+ window.location.hash = targetId;
81
+
82
+ // Close mobile menu if open
83
+ closeMobileMenu();
84
+
85
+ // Scroll to top
86
+ window.scrollTo({ top: 0, behavior: 'smooth' });
87
+ });
88
+ });
89
+
90
+ // Handle initial hash
91
+ const hash = window.location.hash.slice(1);
92
+ if (hash) {
93
+ showSection(hash);
94
+ navLinks.forEach(link => {
95
+ if (link.getAttribute('data-page') === hash) {
96
+ link.classList.add('active');
97
+ }
98
+ });
99
+ } else {
100
+ // Default to quick-start
101
+ showSection('quick-start');
102
+ const firstLink = document.querySelector('.nav-link[data-page="quick-start"]');
103
+ if (firstLink) firstLink.classList.add('active');
104
+ }
105
+
106
+ // Handle browser back/forward
107
+ window.addEventListener('hashchange', () => {
108
+ const hash = window.location.hash.slice(1);
109
+ if (hash) {
110
+ showSection(hash);
111
+ navLinks.forEach(link => {
112
+ link.classList.toggle('active', link.getAttribute('data-page') === hash);
113
+ });
114
+ }
115
+ });
116
+}
117
+
118
+function showSection(sectionId) {
119
+ const sections = document.querySelectorAll('.content-section');
120
+ sections.forEach(section => {
121
+ section.classList.toggle('active', section.id === sectionId);
122
+ });
123
+
124
+ // Update breadcrumb
125
+ updateBreadcrumb(sectionId);
126
+}
127
+
128
+function updateBreadcrumb(sectionId) {
129
+ const section = document.getElementById(sectionId);
130
+ if (!section) return;
131
+
132
+ const navLink = document.querySelector(`.nav-link[data-page="${sectionId}"]`);
133
+ if (!navLink) return;
134
+
135
+ const sectionTitle = navLink.textContent.trim();
136
+ const sectionGroup = navLink.closest('.nav-section');
137
+ const groupName = sectionGroup?.querySelector('.nav-section-title')?.textContent.trim() || 'Docs';
138
+
139
+ const breadcrumbs = document.querySelectorAll('.breadcrumb');
140
+ breadcrumbs.forEach(breadcrumb => {
141
+ const parentSection = breadcrumb.closest('.content-section');
142
+ if (parentSection && parentSection.id === sectionId) {
143
+ breadcrumb.innerHTML = `
144
+ <a href="#">Docs</a>
145
+ <span class="breadcrumb-sep">/</span>
146
+ <span>${groupName}</span>
147
+ <span class="breadcrumb-sep">/</span>
148
+ <span class="current">${sectionTitle}</span>
149
+ `;
150
+ }
151
+ });
152
+}
153
+
154
+// Tabs
155
+function initTabs() {
156
+ const tabContainers = document.querySelectorAll('.tabs');
157
+
158
+ tabContainers.forEach(container => {
159
+ const buttons = container.querySelectorAll('.tab-btn');
160
+ const panes = container.querySelectorAll('.tab-pane');
161
+
162
+ buttons.forEach(button => {
163
+ button.addEventListener('click', () => {
164
+ const targetTab = button.getAttribute('data-tab');
165
+
166
+ // Update active button
167
+ buttons.forEach(b => b.classList.remove('active'));
168
+ button.classList.add('active');
169
+
170
+ // Update active pane
171
+ panes.forEach(pane => {
172
+ pane.classList.toggle('active', pane.id === targetTab);
173
+ });
174
+ });
175
+ });
176
+ });
177
+}
178
+
179
+// FAQ
180
+function initFAQ() {
181
+ const faqItems = document.querySelectorAll('.faq-item');
182
+
183
+ faqItems.forEach(item => {
184
+ const question = item.querySelector('.faq-question');
185
+ question?.addEventListener('click', () => {
186
+ const isActive = item.classList.contains('active');
187
+
188
+ // Close all other items
189
+ faqItems.forEach(otherItem => {
190
+ if (otherItem !== item) {
191
+ otherItem.classList.remove('active');
192
+ }
193
+ });
194
+
195
+ // Toggle current item
196
+ item.classList.toggle('active', !isActive);
197
+ });
198
+ });
199
+}
200
+
201
+// Search
202
+function initSearch() {
203
+ const searchInput = document.getElementById('searchInput');
204
+ if (!searchInput) return;
205
+
206
+ searchInput.addEventListener('input', (e) => {
207
+ const query = e.target.value.toLowerCase().trim();
208
+
209
+ if (query.length < 2) {
210
+ return;
211
+ }
212
+
213
+ // Search in section titles
214
+ const sections = document.querySelectorAll('.content-section');
215
+ let foundMatch = false;
216
+
217
+ sections.forEach(section => {
218
+ const title = section.querySelector('h1')?.textContent.toLowerCase() || '';
219
+ const description = section.querySelector('.section-description')?.textContent.toLowerCase() || '';
220
+
221
+ if (title.includes(query) || description.includes(query)) {
222
+ if (!foundMatch) {
223
+ showSection(section.id);
224
+ foundMatch = true;
225
+
226
+ // Update nav
227
+ document.querySelectorAll('.nav-link').forEach(link => {
228
+ link.classList.toggle('active', link.getAttribute('data-page') === section.id);
229
+ });
230
+ }
231
+ }
232
+ });
233
+
234
+ if (foundMatch) {
235
+ window.scrollTo({ top: 0, behavior: 'smooth' });
236
+ }
237
+ });
238
+
239
+ // Keyboard shortcut for search
240
+ document.addEventListener('keydown', (e) => {
241
+ if ((e.metaKey || e.ctrlKey) && e.key === 'k') {
242
+ e.preventDefault();
243
+ searchInput?.focus();
244
+ }
245
+ });
246
+}
247
+
248
+// Mobile Menu
249
+function initMobileMenu() {
250
+ const menuToggle = document.getElementById('menuToggle');
251
+ const sidebar = document.querySelector('.sidebar');
252
+
253
+ menuToggle?.addEventListener('click', () => {
254
+ sidebar?.classList.toggle('open');
255
+ });
256
+
257
+ // Close menu on outside click
258
+ document.addEventListener('click', (e) => {
259
+ if (sidebar && !sidebar.contains(e.target) && !menuToggle?.contains(e.target)) {
260
+ closeMobileMenu();
261
+ }
262
+ });
263
+}
264
+
265
+function closeMobileMenu() {
266
+ const sidebar = document.querySelector('.sidebar');
267
+ sidebar?.classList.remove('open');
268
+}
269
+
270
+// Code Copy
271
+function initCodeCopy() {
272
+ document.addEventListener('click', (e) => {
273
+ const copyBtn = e.target.closest('.copy-btn');
274
+ if (!copyBtn) return;
275
+
276
+ const codeBlock = copyBtn.closest('.code-block');
277
+ const code = codeBlock?.querySelector('code')?.textContent;
278
+
279
+ if (code) {
280
+ navigator.clipboard.writeText(code).then(() => {
281
+ // Show success feedback
282
+ const originalText = copyBtn.innerHTML;
283
+ copyBtn.innerHTML = `
284
+ <svg viewBox="0 0 20 20" fill="currentColor">
285
+ <path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd"/>
286
+ </svg>
287
+ Copied!
288
+ `;
289
+
290
+ setTimeout(() => {
291
+ copyBtn.innerHTML = originalText;
292
+ }, 2000);
293
+ });
294
+ }
295
+ });
296
+}
297
+
298
+// Copy code function (global)
299
+window.copyCode = function(btn) {
300
+ const codeBlock = btn.closest('.code-block');
301
+ const code = codeBlock?.querySelector('code')?.textContent;
302
+
303
+ if (code) {
304
+ navigator.clipboard.writeText(code).then(() => {
305
+ const originalText = btn.innerHTML;
306
+ btn.innerHTML = `
307
+ <svg viewBox="0 0 20 20" fill="currentColor">
308
+ <path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd"/>
309
+ </svg>
310
+ Copied!
311
+ `;
312
+
313
+ setTimeout(() => {
314
+ btn.innerHTML = originalText;
315
+ }, 2000);
316
+ });
317
+ }
318
+};
319
+
320
+// Smooth Scroll
321
+function initSmoothScroll() {
322
+ document.querySelectorAll('a[href^="#"]').forEach(anchor => {
323
+ anchor.addEventListener('click', function(e) {
324
+ const href = this.getAttribute('href');
325
+ if (href !== '#') {
326
+ e.preventDefault();
327
+ const target = document.querySelector(href);
328
+ if (target) {
329
+ target.scrollIntoView({
330
+ behavior: 'smooth',
331
+ block: 'start'
332
+ });
333
+ }
334
+ }
335
+ });
336
+ });
337
+}
338
+
339
+// Highlight active section on scroll
340
+window.addEventListener('scroll', () => {
341
+ const sections = document.querySelectorAll('.content-section.active');
342
+ const navLinks = document.querySelectorAll('.nav-link');
343
+
344
+ // This could be enhanced to update nav based on scroll position
345
+ // for long pages with multiple subsections
346
+});
347
+
348
+// Add animation on section change
349
+document.addEventListener('DOMContentLoaded', () => {
350
+ const observer = new MutationObserver((mutations) => {
351
+ mutations.forEach((mutation) => {
352
+ if (mutation.attributeName === 'class' && mutation.target.classList.contains('content-section')) {
353
+ if (mutation.target.classList.contains('active')) {
354
+ mutation.target.style.animation = 'none';
355
+ mutation.target.offsetHeight; // Trigger reflow
356
+ mutation.target.style.animation = 'fadeIn 0.3s ease';
357
+ }
358
+ }
359
+ });
360
+ });
361
+
362
+ document.querySelectorAll('.content-section').forEach(section => {
363
+ observer.observe(section, { attributes: true });
364
+ });
365
+});
0
366
β–Όdocs-site/styles.css
+1549-0
1
+/* ===================================
2
+ OpenGrammar Documentation Styles
3
+ Paper Texture & 256-bit Color Theme
4
+ =================================== */
5
+
6
+:root {
7
+ /* Paper Theme Colors */
8
+ --paper-bg: #FDFBF7;
9
+ --paper-bg-secondary: #F8F6F0;
10
+ --paper-border: #E8E4D9;
11
+ --paper-text: #2D2A26;
12
+ --paper-text-muted: #6B665C;
13
+
14
+ /* 256-bit Rich Colors */
15
+ --primary-50: #EEF4FF;
16
+ --primary-100: #DCE6FF;
17
+ --primary-200: #BACEFF;
18
+ --primary-300: #96A9FF;
19
+ --primary-400: #6B85FF;
20
+ --primary-500: #4F66F0;
21
+ --primary-600: #3D4FDE;
22
+ --primary-700: #303EC4;
23
+ --primary-800: #2834A3;
24
+ --primary-900: #242F85;
25
+
26
+ /* Accent Colors */
27
+ --amber-50: #FFFBEB;
28
+ --amber-100: #FEF3C7;
29
+ --amber-200: #FDE68A;
30
+ --amber-300: #FCD34D;
31
+ --amber-400: #FBBF24;
32
+ --amber-500: #F59E0B;
33
+ --amber-600: #D97706;
34
+
35
+ --red-50: #FEF2F2;
36
+ --red-100: #FEE2E2;
37
+ --red-200: #FECACA;
38
+ --red-300: #FCA5A5;
39
+ --red-400: #F87171;
40
+ --red-500: #EF4444;
41
+ --red-600: #DC2626;
42
+
43
+ --green-50: #F0FDF4;
44
+ --green-100: #DCFCE7;
45
+ --green-200: #BBF7D0;
46
+ --green-300: #86EFAC;
47
+ --green-400: #4ADE80;
48
+ --green-500: #22C55E;
49
+ --green-600: #16A34A;
50
+
51
+ --blue-50: #EFF6FF;
52
+ --blue-100: #DBEAFE;
53
+ --blue-200: #BFDBFE;
54
+ --blue-300: #93C5FD;
55
+ --blue-400: #60A5FA;
56
+ --blue-500: #3B82F6;
57
+ --blue-600: #2563EB;
58
+
59
+ --purple-50: #F5F3FF;
60
+ --purple-100: #EDE9FE;
61
+ --purple-200: #DDD6FE;
62
+ --purple-300: #C4B5FD;
63
+ --purple-400: #A78BFA;
64
+ --purple-500: #8B5CF6;
65
+ --purple-600: #7C3AED;
66
+
67
+ /* Dark Mode Colors */
68
+ --dark-bg: #0F1115;
69
+ --dark-bg-secondary: #16181D;
70
+ --dark-border: #2A2D35;
71
+ --dark-text: #E8E6E3;
72
+ --dark-text-muted: #9CA3AF;
73
+
74
+ /* Typography */
75
+ --font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
76
+ --font-mono: 'JetBrains Mono', 'Fira Code', monospace;
77
+
78
+ /* Spacing */
79
+ --sidebar-width: 280px;
80
+ --header-height: 64px;
81
+
82
+ /* Shadows */
83
+ --shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
84
+ --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
85
+ --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
86
+ --shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
87
+}
88
+
89
+/* Dark Mode */
90
+.dark {
91
+ --paper-bg: #0F1115;
92
+ --paper-bg-secondary: #16181D;
93
+ --paper-border: #2A2D35;
94
+ --paper-text: #E8E6E3;
95
+ --paper-text-muted: #9CA3AF;
96
+}
97
+
98
+/* Reset & Base */
99
+*, *::before, *::after {
100
+ box-sizing: border-box;
101
+ margin: 0;
102
+ padding: 0;
103
+}
104
+
105
+html {
106
+ scroll-behavior: smooth;
107
+ -webkit-font-smoothing: antialiased;
108
+ -moz-osx-font-smoothing: grayscale;
109
+}
110
+
111
+body {
112
+ font-family: var(--font-sans);
113
+ font-size: 16px;
114
+ line-height: 1.7;
115
+ color: var(--paper-text);
116
+ background-color: var(--paper-bg);
117
+ overflow-x: hidden;
118
+}
119
+
120
+/* Paper Texture Overlay */
121
+.paper-texture {
122
+ position: fixed;
123
+ top: 0;
124
+ left: 0;
125
+ width: 100%;
126
+ height: 100%;
127
+ pointer-events: none;
128
+ z-index: -1;
129
+ opacity: 0.4;
130
+ background-image:
131
+ url("data:image/svg+xml,%3Csvg width='200' height='200' viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='200' height='200' filter='url(%23noise)' opacity='0.08'/%3E%3C/svg%3E");
132
+}
133
+
134
+/* Sidebar */
135
+.sidebar {
136
+ position: fixed;
137
+ top: 0;
138
+ left: 0;
139
+ width: var(--sidebar-width);
140
+ height: 100vh;
141
+ background: linear-gradient(180deg, var(--paper-bg) 0%, var(--paper-bg-secondary) 100%);
142
+ border-right: 1px solid var(--paper-border);
143
+ display: flex;
144
+ flex-direction: column;
145
+ z-index: 100;
146
+ overflow: hidden;
147
+}
148
+
149
+.sidebar-header {
150
+ padding: 24px 20px;
151
+ border-bottom: 1px solid var(--paper-border);
152
+ display: flex;
153
+ flex-direction: column;
154
+ gap: 12px;
155
+}
156
+
157
+.logo {
158
+ display: flex;
159
+ align-items: center;
160
+ gap: 12px;
161
+}
162
+
163
+.logo-icon {
164
+ width: 40px;
165
+ height: 40px;
166
+ border-radius: 10px;
167
+ box-shadow: var(--shadow-md);
168
+}
169
+
170
+.logo-text {
171
+ font-size: 20px;
172
+ font-weight: 700;
173
+ background: linear-gradient(135deg, var(--primary-600) 0%, var(--purple-600) 100%);
174
+ -webkit-background-clip: text;
175
+ -webkit-text-fill-color: transparent;
176
+ background-clip: text;
177
+}
178
+
179
+.version-badge {
180
+ display: inline-block;
181
+ padding: 4px 10px;
182
+ background: linear-gradient(135deg, var(--primary-100) 0%, var(--purple-100) 100%);
183
+ color: var(--primary-700);
184
+ font-size: 12px;
185
+ font-weight: 600;
186
+ border-radius: 20px;
187
+ text-align: center;
188
+}
189
+
190
+/* Sidebar Navigation */
191
+.sidebar-nav {
192
+ flex: 1;
193
+ overflow-y: auto;
194
+ padding: 16px 12px;
195
+}
196
+
197
+.nav-section {
198
+ margin-bottom: 24px;
199
+}
200
+
201
+.nav-section-title {
202
+ font-size: 11px;
203
+ font-weight: 600;
204
+ text-transform: uppercase;
205
+ letter-spacing: 0.05em;
206
+ color: var(--paper-text-muted);
207
+ padding: 8px 12px;
208
+ margin-bottom: 4px;
209
+}
210
+
211
+.nav-link {
212
+ display: flex;
213
+ align-items: center;
214
+ gap: 10px;
215
+ padding: 10px 12px;
216
+ color: var(--paper-text-muted);
217
+ text-decoration: none;
218
+ border-radius: 8px;
219
+ font-size: 14px;
220
+ font-weight: 500;
221
+ transition: all 0.2s ease;
222
+ margin-bottom: 2px;
223
+}
224
+
225
+.nav-link:hover {
226
+ background: var(--paper-bg-secondary);
227
+ color: var(--paper-text);
228
+}
229
+
230
+.nav-link.active {
231
+ background: linear-gradient(135deg, var(--primary-50) 0%, var(--purple-50) 100%);
232
+ color: var(--primary-700);
233
+}
234
+
235
+.nav-icon {
236
+ width: 18px;
237
+ height: 18px;
238
+ flex-shrink: 0;
239
+}
240
+
241
+/* Sidebar Footer */
242
+.sidebar-footer {
243
+ padding: 16px;
244
+ border-top: 1px solid var(--paper-border);
245
+}
246
+
247
+.github-link {
248
+ display: flex;
249
+ align-items: center;
250
+ justify-content: center;
251
+ gap: 8px;
252
+ padding: 10px;
253
+ background: var(--paper-bg-secondary);
254
+ border: 1px solid var(--paper-border);
255
+ border-radius: 8px;
256
+ color: var(--paper-text);
257
+ text-decoration: none;
258
+ font-size: 14px;
259
+ font-weight: 500;
260
+ transition: all 0.2s ease;
261
+}
262
+
263
+.github-link:hover {
264
+ background: var(--paper-bg);
265
+ border-color: var(--primary-300);
266
+}
267
+
268
+.github-icon {
269
+ width: 20px;
270
+ height: 20px;
271
+}
272
+
273
+/* Main Content */
274
+.main-content {
275
+ margin-left: var(--sidebar-width);
276
+ min-height: 100vh;
277
+}
278
+
279
+/* Content Header */
280
+.content-header {
281
+ position: sticky;
282
+ top: 0;
283
+ z-index: 50;
284
+ height: var(--header-height);
285
+ background: rgba(253, 251, 247, 0.9);
286
+ backdrop-filter: blur(12px);
287
+ border-bottom: 1px solid var(--paper-border);
288
+ display: flex;
289
+ align-items: center;
290
+ padding: 0 32px;
291
+ gap: 24px;
292
+}
293
+
294
+.dark .content-header {
295
+ background: rgba(15, 17, 21, 0.9);
296
+}
297
+
298
+.menu-toggle {
299
+ display: none;
300
+ background: none;
301
+ border: none;
302
+ cursor: pointer;
303
+ padding: 8px;
304
+ border-radius: 8px;
305
+ color: var(--paper-text);
306
+}
307
+
308
+.menu-toggle:hover {
309
+ background: var(--paper-bg-secondary);
310
+}
311
+
312
+.menu-toggle svg {
313
+ width: 24px;
314
+ height: 24px;
315
+}
316
+
317
+/* Search Box */
318
+.search-box {
319
+ flex: 1;
320
+ max-width: 480px;
321
+ position: relative;
322
+ display: flex;
323
+ align-items: center;
324
+}
325
+
326
+.search-icon {
327
+ position: absolute;
328
+ left: 14px;
329
+ width: 18px;
330
+ height: 18px;
331
+ color: var(--paper-text-muted);
332
+ pointer-events: none;
333
+}
334
+
335
+.search-box input {
336
+ width: 100%;
337
+ padding: 10px 16px 10px 42px;
338
+ background: var(--paper-bg-secondary);
339
+ border: 1px solid var(--paper-border);
340
+ border-radius: 10px;
341
+ font-size: 14px;
342
+ color: var(--paper-text);
343
+ outline: none;
344
+ transition: all 0.2s ease;
345
+}
346
+
347
+.search-box input:focus {
348
+ border-color: var(--primary-400);
349
+ box-shadow: 0 0 0 3px var(--primary-100);
350
+}
351
+
352
+.search-box kbd {
353
+ position: absolute;
354
+ right: 12px;
355
+ padding: 4px 8px;
356
+ background: var(--paper-bg);
357
+ border: 1px solid var(--paper-border);
358
+ border-radius: 6px;
359
+ font-size: 12px;
360
+ font-family: var(--font-mono);
361
+ color: var(--paper-text-muted);
362
+}
363
+
364
+/* Header Actions */
365
+.header-actions {
366
+ display: flex;
367
+ align-items: center;
368
+ gap: 12px;
369
+ margin-left: auto;
370
+}
371
+
372
+.theme-toggle {
373
+ background: var(--paper-bg-secondary);
374
+ border: 1px solid var(--paper-border);
375
+ padding: 8px;
376
+ border-radius: 8px;
377
+ cursor: pointer;
378
+ color: var(--paper-text);
379
+ transition: all 0.2s ease;
380
+}
381
+
382
+.theme-toggle:hover {
383
+ background: var(--paper-bg);
384
+}
385
+
386
+.theme-toggle svg {
387
+ width: 20px;
388
+ height: 20px;
389
+}
390
+
391
+.theme-toggle .moon-icon {
392
+ display: none;
393
+}
394
+
395
+.dark .theme-toggle .sun-icon {
396
+ display: none;
397
+}
398
+
399
+.dark .theme-toggle .moon-icon {
400
+ display: block;
401
+}
402
+
403
+.github-btn {
404
+ display: flex;
405
+ align-items: center;
406
+ gap: 8px;
407
+ padding: 8px 16px;
408
+ background: var(--paper-text);
409
+ color: var(--paper-bg);
410
+ border: none;
411
+ border-radius: 8px;
412
+ font-size: 14px;
413
+ font-weight: 500;
414
+ text-decoration: none;
415
+ transition: all 0.2s ease;
416
+}
417
+
418
+.github-btn:hover {
419
+ opacity: 0.9;
420
+ transform: translateY(-1px);
421
+}
422
+
423
+.github-btn svg {
424
+ width: 20px;
425
+ height: 20px;
426
+}
427
+
428
+/* Content Wrapper */
429
+.content-wrapper {
430
+ padding: 48px 64px;
431
+ max-width: 1200px;
432
+}
433
+
434
+/* Content Section */
435
+.content-section {
436
+ display: none;
437
+}
438
+
439
+.content-section.active {
440
+ display: block;
441
+ animation: fadeIn 0.3s ease;
442
+}
443
+
444
+@keyframes fadeIn {
445
+ from {
446
+ opacity: 0;
447
+ transform: translateY(10px);
448
+ }
449
+ to {
450
+ opacity: 1;
451
+ transform: translateY(0);
452
+ }
453
+}
454
+
455
+/* Section Header */
456
+.section-header {
457
+ margin-bottom: 40px;
458
+ padding-bottom: 32px;
459
+ border-bottom: 1px solid var(--paper-border);
460
+}
461
+
462
+.breadcrumb {
463
+ display: flex;
464
+ align-items: center;
465
+ gap: 8px;
466
+ font-size: 14px;
467
+ color: var(--paper-text-muted);
468
+ margin-bottom: 16px;
469
+}
470
+
471
+.breadcrumb a {
472
+ color: var(--primary-600);
473
+ text-decoration: none;
474
+}
475
+
476
+.breadcrumb a:hover {
477
+ text-decoration: underline;
478
+}
479
+
480
+.breadcrumb-sep {
481
+ color: var(--paper-text-muted);
482
+}
483
+
484
+.breadcrumb .current {
485
+ color: var(--paper-text);
486
+}
487
+
488
+.section-header h1 {
489
+ font-size: 42px;
490
+ font-weight: 800;
491
+ line-height: 1.2;
492
+ margin-bottom: 12px;
493
+ background: linear-gradient(135deg, var(--paper-text) 0%, var(--paper-text-muted) 100%);
494
+ -webkit-background-clip: text;
495
+ -webkit-text-fill-color: transparent;
496
+ background-clip: text;
497
+}
498
+
499
+.section-description {
500
+ font-size: 18px;
501
+ color: var(--paper-text-muted);
502
+ max-width: 700px;
503
+}
504
+
505
+/* Content Body */
506
+.content-body {
507
+ font-size: 17px;
508
+ line-height: 1.8;
509
+}
510
+
511
+.content-body h2 {
512
+ font-size: 28px;
513
+ font-weight: 700;
514
+ margin: 48px 0 20px;
515
+ color: var(--paper-text);
516
+}
517
+
518
+.content-body h3 {
519
+ font-size: 22px;
520
+ font-weight: 600;
521
+ margin: 36px 0 16px;
522
+ color: var(--paper-text);
523
+}
524
+
525
+.content-body h4 {
526
+ font-size: 18px;
527
+ font-weight: 600;
528
+ margin: 28px 0 12px;
529
+ color: var(--paper-text);
530
+}
531
+
532
+.content-body p {
533
+ margin-bottom: 20px;
534
+ color: var(--paper-text);
535
+}
536
+
537
+.content-body ul,
538
+.content-body ol {
539
+ margin: 20px 0 20px 28px;
540
+}
541
+
542
+.content-body li {
543
+ margin-bottom: 10px;
544
+}
545
+
546
+.content-body a {
547
+ color: var(--primary-600);
548
+ text-decoration: none;
549
+ border-bottom: 1px solid transparent;
550
+ transition: border-color 0.2s ease;
551
+}
552
+
553
+.content-body a:hover {
554
+ border-bottom-color: var(--primary-600);
555
+}
556
+
557
+.content-body code {
558
+ font-family: var(--font-mono);
559
+ font-size: 14px;
560
+ padding: 3px 8px;
561
+ background: var(--paper-bg-secondary);
562
+ border: 1px solid var(--paper-border);
563
+ border-radius: 6px;
564
+ color: var(--paper-text);
565
+}
566
+
567
+.content-body pre {
568
+ margin: 20px 0;
569
+ overflow-x: auto;
570
+}
571
+
572
+/* Callouts */
573
+.callout {
574
+ display: flex;
575
+ gap: 16px;
576
+ padding: 20px;
577
+ border-radius: 12px;
578
+ margin: 24px 0;
579
+ border-left: 4px solid;
580
+}
581
+
582
+.callout-icon {
583
+ font-size: 24px;
584
+ flex-shrink: 0;
585
+}
586
+
587
+.callout-content strong {
588
+ display: block;
589
+ margin-bottom: 4px;
590
+}
591
+
592
+.callout-primary {
593
+ background: var(--primary-50);
594
+ border-color: var(--primary-500);
595
+}
596
+
597
+.callout-success {
598
+ background: var(--green-50);
599
+ border-color: var(--green-500);
600
+}
601
+
602
+.callout-warning {
603
+ background: var(--amber-50);
604
+ border-color: var(--amber-500);
605
+}
606
+
607
+.callout-info {
608
+ background: var(--blue-50);
609
+ border-color: var(--blue-500);
610
+}
611
+
612
+/* Code Block */
613
+.code-block {
614
+ margin: 24px 0;
615
+ border-radius: 12px;
616
+ overflow: hidden;
617
+ border: 1px solid var(--paper-border);
618
+}
619
+
620
+.code-header {
621
+ display: flex;
622
+ justify-content: space-between;
623
+ align-items: center;
624
+ padding: 12px 16px;
625
+ background: var(--paper-bg-secondary);
626
+ border-bottom: 1px solid var(--paper-border);
627
+}
628
+
629
+.code-lang {
630
+ font-size: 12px;
631
+ font-weight: 600;
632
+ color: var(--paper-text-muted);
633
+ text-transform: uppercase;
634
+}
635
+
636
+.copy-btn {
637
+ display: flex;
638
+ align-items: center;
639
+ gap: 6px;
640
+ padding: 6px 12px;
641
+ background: transparent;
642
+ border: 1px solid var(--paper-border);
643
+ border-radius: 6px;
644
+ font-size: 13px;
645
+ color: var(--paper-text-muted);
646
+ cursor: pointer;
647
+ transition: all 0.2s ease;
648
+}
649
+
650
+.copy-btn:hover {
651
+ background: var(--paper-bg);
652
+ color: var(--paper-text);
653
+}
654
+
655
+.copy-btn svg {
656
+ width: 16px;
657
+ height: 16px;
658
+}
659
+
660
+.code-block pre {
661
+ margin: 0;
662
+ padding: 20px;
663
+ background: var(--paper-bg-secondary);
664
+ overflow-x: auto;
665
+}
666
+
667
+.code-block small pre {
668
+ padding: 12px;
669
+}
670
+
671
+.code-block code {
672
+ font-family: var(--font-mono);
673
+ font-size: 14px;
674
+ line-height: 1.6;
675
+ color: var(--paper-text);
676
+}
677
+
678
+/* Step List */
679
+.step-list {
680
+ counter-reset: step;
681
+ list-style: none;
682
+ margin: 24px 0;
683
+ padding: 0;
684
+}
685
+
686
+.step-list li {
687
+ position: relative;
688
+ padding-left: 48px;
689
+ margin-bottom: 16px;
690
+}
691
+
692
+.step-list li::before {
693
+ counter-increment: step;
694
+ content: counter(step);
695
+ position: absolute;
696
+ left: 0;
697
+ top: 0;
698
+ width: 32px;
699
+ height: 32px;
700
+ background: linear-gradient(135deg, var(--primary-500) 0%, var(--purple-500) 100%);
701
+ color: white;
702
+ border-radius: 50%;
703
+ display: flex;
704
+ align-items: center;
705
+ justify-content: center;
706
+ font-weight: 600;
707
+ font-size: 14px;
708
+}
709
+
710
+/* Tabs */
711
+.tabs {
712
+ margin: 24px 0;
713
+}
714
+
715
+.tab-buttons {
716
+ display: flex;
717
+ gap: 4px;
718
+ padding: 4px;
719
+ background: var(--paper-bg-secondary);
720
+ border: 1px solid var(--paper-border);
721
+ border-radius: 10px;
722
+ margin-bottom: 16px;
723
+}
724
+
725
+.tab-btn {
726
+ flex: 1;
727
+ padding: 10px 16px;
728
+ background: transparent;
729
+ border: none;
730
+ border-radius: 8px;
731
+ font-size: 14px;
732
+ font-weight: 500;
733
+ color: var(--paper-text-muted);
734
+ cursor: pointer;
735
+ transition: all 0.2s ease;
736
+}
737
+
738
+.tab-btn:hover {
739
+ color: var(--paper-text);
740
+}
741
+
742
+.tab-btn.active {
743
+ background: var(--paper-bg);
744
+ color: var(--primary-600);
745
+ box-shadow: var(--shadow-sm);
746
+}
747
+
748
+.tab-content {
749
+ background: var(--paper-bg);
750
+ border: 1px solid var(--paper-border);
751
+ border-radius: 10px;
752
+ padding: 24px;
753
+}
754
+
755
+.tab-pane {
756
+ display: none;
757
+}
758
+
759
+.tab-pane.active {
760
+ display: block;
761
+}
762
+
763
+/* Tables */
764
+.table-wrapper {
765
+ overflow-x: auto;
766
+ margin: 24px 0;
767
+ border-radius: 12px;
768
+ border: 1px solid var(--paper-border);
769
+}
770
+
771
+.data-table {
772
+ width: 100%;
773
+ border-collapse: collapse;
774
+ font-size: 15px;
775
+}
776
+
777
+.data-table th,
778
+.data-table td {
779
+ padding: 14px 16px;
780
+ text-align: left;
781
+ border-bottom: 1px solid var(--paper-border);
782
+}
783
+
784
+.data-table th {
785
+ background: var(--paper-bg-secondary);
786
+ font-weight: 600;
787
+ font-size: 13px;
788
+ text-transform: uppercase;
789
+ letter-spacing: 0.05em;
790
+ color: var(--paper-text-muted);
791
+}
792
+
793
+.data-table tr:last-child td {
794
+ border-bottom: none;
795
+}
796
+
797
+.data-table tr:hover {
798
+ background: var(--paper-bg-secondary);
799
+}
800
+
801
+/* Status Badge */
802
+.status-badge {
803
+ display: inline-block;
804
+ padding: 4px 10px;
805
+ border-radius: 20px;
806
+ font-size: 12px;
807
+ font-weight: 600;
808
+}
809
+
810
+.status-badge.success {
811
+ background: var(--green-100);
812
+ color: var(--green-700);
813
+}
814
+
815
+.status-badge.warning {
816
+ background: var(--amber-100);
817
+ color: var(--amber-700);
818
+}
819
+
820
+/* Feature Grid */
821
+.feature-grid {
822
+ display: grid;
823
+ grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
824
+ gap: 20px;
825
+ margin: 32px 0;
826
+}
827
+
828
+.feature-card {
829
+ padding: 24px;
830
+ background: var(--paper-bg-secondary);
831
+ border: 1px solid var(--paper-border);
832
+ border-radius: 12px;
833
+}
834
+
835
+.feature-card .feature-icon {
836
+ font-size: 32px;
837
+ margin-bottom: 12px;
838
+}
839
+
840
+.feature-card h4 {
841
+ font-size: 18px;
842
+ font-weight: 600;
843
+ margin-bottom: 12px;
844
+}
845
+
846
+.link-list {
847
+ list-style: none;
848
+ margin: 0;
849
+ padding: 0;
850
+}
851
+
852
+.link-list li {
853
+ margin-bottom: 8px;
854
+}
855
+
856
+.link-list a {
857
+ color: var(--primary-600);
858
+ text-decoration: none;
859
+}
860
+
861
+.link-list a:hover {
862
+ text-decoration: underline;
863
+}
864
+
865
+/* Provider Cards */
866
+.provider-cards {
867
+ display: grid;
868
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
869
+ gap: 16px;
870
+ margin: 24px 0;
871
+}
872
+
873
+.provider-card {
874
+ padding: 20px;
875
+ background: var(--paper-bg-secondary);
876
+ border: 1px solid var(--paper-border);
877
+ border-radius: 12px;
878
+ text-align: center;
879
+}
880
+
881
+.provider-card .provider-icon {
882
+ font-size: 32px;
883
+ margin-bottom: 12px;
884
+}
885
+
886
+.provider-card h4 {
887
+ font-size: 16px;
888
+ font-weight: 600;
889
+ margin-bottom: 8px;
890
+}
891
+
892
+.provider-card p {
893
+ font-size: 14px;
894
+ color: var(--paper-text-muted);
895
+ margin-bottom: 8px;
896
+}
897
+
898
+.provider-card code {
899
+ font-size: 12px;
900
+}
901
+
902
+/* Color Guide */
903
+.color-guide {
904
+ display: flex;
905
+ flex-direction: column;
906
+ gap: 12px;
907
+ margin: 24px 0;
908
+}
909
+
910
+.color-item {
911
+ display: flex;
912
+ align-items: center;
913
+ gap: 16px;
914
+}
915
+
916
+.color-swatch {
917
+ width: 40px;
918
+ height: 40px;
919
+ border-radius: 8px;
920
+ border: 2px solid var(--paper-border);
921
+ box-shadow: var(--shadow-sm);
922
+}
923
+
924
+.color-swatch.red {
925
+ background: linear-gradient(135deg, var(--red-400) 0%, var(--red-500) 100%);
926
+}
927
+
928
+.color-swatch.amber {
929
+ background: linear-gradient(135deg, var(--amber-400) 0%, var(--amber-500) 100%);
930
+}
931
+
932
+.color-swatch.blue {
933
+ background: linear-gradient(135deg, var(--blue-400) 0%, var(--blue-500) 100%);
934
+}
935
+
936
+.color-info {
937
+ display: flex;
938
+ flex-direction: column;
939
+}
940
+
941
+.color-info strong {
942
+ font-size: 16px;
943
+ margin-bottom: 2px;
944
+}
945
+
946
+.color-info span {
947
+ font-size: 14px;
948
+ color: var(--paper-text-muted);
949
+}
950
+
951
+/* Tone Grid */
952
+.tone-grid {
953
+ display: grid;
954
+ grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
955
+ gap: 16px;
956
+ margin: 24px 0;
957
+}
958
+
959
+.tone-card {
960
+ padding: 20px;
961
+ background: var(--paper-bg-secondary);
962
+ border: 1px solid var(--paper-border);
963
+ border-radius: 12px;
964
+ text-align: center;
965
+ transition: all 0.2s ease;
966
+}
967
+
968
+.tone-card:hover {
969
+ transform: translateY(-2px);
970
+ box-shadow: var(--shadow-md);
971
+}
972
+
973
+.tone-emoji {
974
+ font-size: 32px;
975
+ display: block;
976
+ margin-bottom: 8px;
977
+}
978
+
979
+.tone-card h4 {
980
+ font-size: 15px;
981
+ font-weight: 600;
982
+ margin-bottom: 4px;
983
+}
984
+
985
+.tone-card p {
986
+ font-size: 13px;
987
+ color: var(--paper-text-muted);
988
+ margin: 0;
989
+}
990
+
991
+/* Tone Detail Grid */
992
+.tone-detail-grid {
993
+ display: grid;
994
+ grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
995
+ gap: 20px;
996
+ margin: 24px 0;
997
+}
998
+
999
+.tone-detail-card {
1000
+ padding: 24px;
1001
+ background: var(--paper-bg-secondary);
1002
+ border: 1px solid var(--paper-border);
1003
+ border-radius: 12px;
1004
+}
1005
+
1006
+.tone-detail-header {
1007
+ display: flex;
1008
+ align-items: center;
1009
+ gap: 12px;
1010
+ margin-bottom: 12px;
1011
+}
1012
+
1013
+.tone-detail-icon {
1014
+ font-size: 28px;
1015
+}
1016
+
1017
+.tone-detail-header h3 {
1018
+ font-size: 18px;
1019
+ font-weight: 600;
1020
+ margin: 0;
1021
+}
1022
+
1023
+.tone-detail-use {
1024
+ font-size: 14px;
1025
+ color: var(--paper-text-muted);
1026
+ margin-bottom: 16px;
1027
+}
1028
+
1029
+.tone-detail-example {
1030
+ background: var(--paper-bg);
1031
+ border-radius: 8px;
1032
+ padding: 16px;
1033
+}
1034
+
1035
+.example-input,
1036
+.example-output {
1037
+ margin-bottom: 12px;
1038
+}
1039
+
1040
+.example-input:last-child,
1041
+.example-output:last-child {
1042
+ margin-bottom: 0;
1043
+}
1044
+
1045
+.example-input .label,
1046
+.example-output .label {
1047
+ font-size: 12px;
1048
+ font-weight: 600;
1049
+ color: var(--paper-text-muted);
1050
+ text-transform: uppercase;
1051
+ margin-bottom: 4px;
1052
+ display: block;
1053
+}
1054
+
1055
+.example-output code {
1056
+ background: var(--green-50);
1057
+ border-color: var(--green-200);
1058
+ color: var(--green-700);
1059
+}
1060
+
1061
+/* Metric Card */
1062
+.metric-card {
1063
+ background: var(--paper-bg-secondary);
1064
+ border: 1px solid var(--paper-border);
1065
+ border-radius: 12px;
1066
+ padding: 24px;
1067
+ margin: 24px 0;
1068
+}
1069
+
1070
+.metric-header {
1071
+ display: flex;
1072
+ justify-content: space-between;
1073
+ align-items: center;
1074
+ margin-bottom: 16px;
1075
+}
1076
+
1077
+.metric-header h4 {
1078
+ font-size: 18px;
1079
+ font-weight: 600;
1080
+ margin: 0;
1081
+}
1082
+
1083
+.metric-badge {
1084
+ padding: 4px 10px;
1085
+ background: var(--primary-100);
1086
+ color: var(--primary-700);
1087
+ border-radius: 20px;
1088
+ font-size: 12px;
1089
+ font-weight: 600;
1090
+}
1091
+
1092
+.metric-scale {
1093
+ display: flex;
1094
+ flex-direction: column;
1095
+ gap: 8px;
1096
+}
1097
+
1098
+.scale-item {
1099
+ display: flex;
1100
+ gap: 12px;
1101
+ font-size: 14px;
1102
+}
1103
+
1104
+.scale-item .range {
1105
+ font-family: var(--font-mono);
1106
+ font-weight: 600;
1107
+ color: var(--primary-600);
1108
+ min-width: 80px;
1109
+}
1110
+
1111
+.scale-item .label {
1112
+ color: var(--paper-text-muted);
1113
+}
1114
+
1115
+/* FAQ List */
1116
+.faq-list {
1117
+ display: flex;
1118
+ flex-direction: column;
1119
+ gap: 16px;
1120
+}
1121
+
1122
+.faq-item {
1123
+ background: var(--paper-bg-secondary);
1124
+ border: 1px solid var(--paper-border);
1125
+ border-radius: 12px;
1126
+ overflow: hidden;
1127
+}
1128
+
1129
+.faq-question {
1130
+ display: flex;
1131
+ justify-content: space-between;
1132
+ align-items: center;
1133
+ padding: 20px 24px;
1134
+ cursor: pointer;
1135
+ transition: all 0.2s ease;
1136
+}
1137
+
1138
+.faq-question:hover {
1139
+ background: var(--paper-bg);
1140
+}
1141
+
1142
+.faq-question h3 {
1143
+ font-size: 17px;
1144
+ font-weight: 600;
1145
+ margin: 0;
1146
+}
1147
+
1148
+.faq-question svg {
1149
+ width: 20px;
1150
+ height: 20px;
1151
+ color: var(--paper-text-muted);
1152
+ transition: transform 0.2s ease;
1153
+}
1154
+
1155
+.faq-item.active .faq-question svg {
1156
+ transform: rotate(180deg);
1157
+}
1158
+
1159
+.faq-answer {
1160
+ padding: 0 24px;
1161
+ max-height: 0;
1162
+ overflow: hidden;
1163
+ transition: all 0.3s ease;
1164
+}
1165
+
1166
+.faq-item.active .faq-answer {
1167
+ padding: 0 24px 20px;
1168
+ max-height: 500px;
1169
+}
1170
+
1171
+/* Troubleshoot Card */
1172
+.troubleshoot-card {
1173
+ background: var(--paper-bg-secondary);
1174
+ border: 1px solid var(--paper-border);
1175
+ border-radius: 12px;
1176
+ padding: 24px;
1177
+ margin: 24px 0;
1178
+}
1179
+
1180
+.troubleshoot-card h4 {
1181
+ font-size: 16px;
1182
+ font-weight: 600;
1183
+ margin: 20px 0 12px;
1184
+}
1185
+
1186
+.troubleshoot-card h4:first-child {
1187
+ margin-top: 0;
1188
+}
1189
+
1190
+.troubleshoot-card ul,
1191
+.troubleshoot-card ol {
1192
+ margin: 12px 0 12px 24px;
1193
+}
1194
+
1195
+/* Provider Comparison */
1196
+.provider-comparison {
1197
+ display: grid;
1198
+ grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
1199
+ gap: 20px;
1200
+ margin: 24px 0;
1201
+}
1202
+
1203
+.provider-card-large {
1204
+ background: var(--paper-bg-secondary);
1205
+ border: 1px solid var(--paper-border);
1206
+ border-radius: 12px;
1207
+ padding: 24px;
1208
+ transition: all 0.2s ease;
1209
+}
1210
+
1211
+.provider-card-large:hover {
1212
+ transform: translateY(-2px);
1213
+ box-shadow: var(--shadow-lg);
1214
+}
1215
+
1216
+.provider-header {
1217
+ display: flex;
1218
+ align-items: center;
1219
+ gap: 12px;
1220
+ margin-bottom: 16px;
1221
+}
1222
+
1223
+.provider-icon {
1224
+ font-size: 32px;
1225
+}
1226
+
1227
+.provider-header h3 {
1228
+ font-size: 20px;
1229
+ font-weight: 700;
1230
+ margin: 0;
1231
+}
1232
+
1233
+.provider-stats {
1234
+ display: flex;
1235
+ flex-direction: column;
1236
+ gap: 8px;
1237
+ margin-bottom: 16px;
1238
+}
1239
+
1240
+.provider-stats .stat {
1241
+ font-size: 14px;
1242
+ color: var(--paper-text-muted);
1243
+}
1244
+
1245
+.provider-desc {
1246
+ font-size: 14px;
1247
+ color: var(--paper-text);
1248
+ margin: 0;
1249
+}
1250
+
1251
+/* Feature Grid 2 */
1252
+.feature-grid-2 {
1253
+ display: grid;
1254
+ grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
1255
+ gap: 20px;
1256
+ margin: 24px 0;
1257
+}
1258
+
1259
+.feature-box {
1260
+ padding: 24px;
1261
+ background: var(--paper-bg-secondary);
1262
+ border: 1px solid var(--paper-border);
1263
+ border-radius: 12px;
1264
+}
1265
+
1266
+.feature-box-icon {
1267
+ font-size: 32px;
1268
+ margin-bottom: 12px;
1269
+}
1270
+
1271
+.feature-box h3 {
1272
+ font-size: 18px;
1273
+ font-weight: 600;
1274
+ margin-bottom: 8px;
1275
+}
1276
+
1277
+.feature-box p {
1278
+ font-size: 15px;
1279
+ color: var(--paper-text-muted);
1280
+ margin: 0;
1281
+}
1282
+
1283
+/* Feature List */
1284
+.feature-list {
1285
+ list-style: none;
1286
+ margin: 24px 0;
1287
+ padding: 0;
1288
+}
1289
+
1290
+.feature-list li {
1291
+ display: flex;
1292
+ gap: 12px;
1293
+ margin-bottom: 16px;
1294
+ padding-left: 0;
1295
+}
1296
+
1297
+.feature-list li::before {
1298
+ content: none;
1299
+}
1300
+
1301
+.feature-list li svg {
1302
+ width: 20px;
1303
+ height: 20px;
1304
+ color: var(--green-500);
1305
+ flex-shrink: 0;
1306
+ margin-top: 2px;
1307
+}
1308
+
1309
+.feature-list li ul {
1310
+ margin: 8px 0 0 32px;
1311
+}
1312
+
1313
+/* Hero Card */
1314
+.hero-card {
1315
+ background: linear-gradient(135deg, var(--primary-50) 0%, var(--purple-50) 100%);
1316
+ border: 1px solid var(--primary-200);
1317
+ border-radius: 16px;
1318
+ padding: 32px;
1319
+ margin: 24px 0;
1320
+}
1321
+
1322
+.hero-card-content h2 {
1323
+ font-size: 24px;
1324
+ font-weight: 700;
1325
+ margin: 0 0 12px;
1326
+}
1327
+
1328
+.hero-card-content p {
1329
+ font-size: 16px;
1330
+ color: var(--paper-text-muted);
1331
+ margin: 0;
1332
+}
1333
+
1334
+/* Section Nav */
1335
+.section-nav {
1336
+ display: flex;
1337
+ justify-content: space-between;
1338
+ margin-top: 64px;
1339
+ padding-top: 32px;
1340
+ border-top: 1px solid var(--paper-border);
1341
+}
1342
+
1343
+.prev-link,
1344
+.next-link {
1345
+ display: flex;
1346
+ align-items: center;
1347
+ gap: 8px;
1348
+ padding: 12px 20px;
1349
+ background: var(--paper-bg-secondary);
1350
+ border: 1px solid var(--paper-border);
1351
+ border-radius: 10px;
1352
+ color: var(--paper-text);
1353
+ text-decoration: none;
1354
+ font-size: 14px;
1355
+ font-weight: 500;
1356
+ transition: all 0.2s ease;
1357
+}
1358
+
1359
+.prev-link:hover,
1360
+.next-link:hover {
1361
+ background: var(--paper-bg);
1362
+ border-color: var(--primary-300);
1363
+}
1364
+
1365
+.prev-link svg,
1366
+.next-link svg {
1367
+ width: 18px;
1368
+ height: 18px;
1369
+}
1370
+
1371
+/* API Endpoint */
1372
+.api-endpoint {
1373
+ display: flex;
1374
+ align-items: center;
1375
+ gap: 12px;
1376
+ margin: 16px 0;
1377
+}
1378
+
1379
+.api-method {
1380
+ padding: 6px 12px;
1381
+ border-radius: 6px;
1382
+ font-size: 13px;
1383
+ font-weight: 700;
1384
+ font-family: var(--font-mono);
1385
+}
1386
+
1387
+.api-method.get {
1388
+ background: var(--blue-100);
1389
+ color: var(--blue-700);
1390
+}
1391
+
1392
+.api-method.post {
1393
+ background: var(--green-100);
1394
+ color: var(--green-700);
1395
+}
1396
+
1397
+.api-path {
1398
+ font-family: var(--font-mono);
1399
+ font-size: 15px;
1400
+ font-weight: 600;
1401
+}
1402
+
1403
+/* Highlight */
1404
+.highlight-red {
1405
+ color: var(--red-600);
1406
+ font-weight: 600;
1407
+}
1408
+
1409
+/* Kbd */
1410
+kbd {
1411
+ display: inline-block;
1412
+ padding: 4px 8px;
1413
+ background: var(--paper-bg-secondary);
1414
+ border: 1px solid var(--paper-border);
1415
+ border-radius: 6px;
1416
+ font-family: var(--font-mono);
1417
+ font-size: 13px;
1418
+ color: var(--paper-text);
1419
+}
1420
+
1421
+/* Footer */
1422
+.content-footer {
1423
+ padding: 48px 64px;
1424
+ border-top: 1px solid var(--paper-border);
1425
+ margin-top: 64px;
1426
+}
1427
+
1428
+.footer-content {
1429
+ max-width: 1200px;
1430
+ text-align: center;
1431
+ color: var(--paper-text-muted);
1432
+ font-size: 14px;
1433
+}
1434
+
1435
+.footer-content p {
1436
+ margin-bottom: 8px;
1437
+}
1438
+
1439
+.footer-content a {
1440
+ color: var(--primary-600);
1441
+ text-decoration: none;
1442
+}
1443
+
1444
+.footer-content a:hover {
1445
+ text-decoration: underline;
1446
+}
1447
+
1448
+/* Responsive */
1449
+@media (max-width: 1024px) {
1450
+ .main-content {
1451
+ margin-left: 0;
1452
+ }
1453
+
1454
+ .sidebar {
1455
+ transform: translateX(-100%);
1456
+ transition: transform 0.3s ease;
1457
+ }
1458
+
1459
+ .sidebar.open {
1460
+ transform: translateX(0);
1461
+ }
1462
+
1463
+ .menu-toggle {
1464
+ display: block;
1465
+ }
1466
+
1467
+ .content-wrapper {
1468
+ padding: 32px 24px;
1469
+ }
1470
+
1471
+ .content-header {
1472
+ padding: 0 24px;
1473
+ }
1474
+
1475
+ .search-box {
1476
+ max-width: 100%;
1477
+ }
1478
+
1479
+ .section-header h1 {
1480
+ font-size: 32px;
1481
+ }
1482
+}
1483
+
1484
+@media (max-width: 768px) {
1485
+ .header-actions {
1486
+ gap: 8px;
1487
+ }
1488
+
1489
+ .github-btn span {
1490
+ display: none;
1491
+ }
1492
+
1493
+ .content-wrapper {
1494
+ padding: 24px 16px;
1495
+ }
1496
+
1497
+ .content-footer {
1498
+ padding: 32px 16px;
1499
+ }
1500
+
1501
+ .provider-cards,
1502
+ .provider-comparison,
1503
+ .feature-grid,
1504
+ .feature-grid-2,
1505
+ .tone-grid,
1506
+ .tone-detail-grid {
1507
+ grid-template-columns: 1fr;
1508
+ }
1509
+
1510
+ .tab-buttons {
1511
+ flex-wrap: wrap;
1512
+ }
1513
+
1514
+ .section-nav {
1515
+ flex-direction: column;
1516
+ gap: 12px;
1517
+ }
1518
+
1519
+ .prev-link,
1520
+ .next-link {
1521
+ width: 100%;
1522
+ justify-content: center;
1523
+ }
1524
+}
1525
+
1526
+/* Scrollbar */
1527
+::-webkit-scrollbar {
1528
+ width: 10px;
1529
+ height: 10px;
1530
+}
1531
+
1532
+::-webkit-scrollbar-track {
1533
+ background: var(--paper-bg-secondary);
1534
+}
1535
+
1536
+::-webkit-scrollbar-thumb {
1537
+ background: var(--paper-border);
1538
+ border-radius: 5px;
1539
+}
1540
+
1541
+::-webkit-scrollbar-thumb:hover {
1542
+ background: var(--paper-text-muted);
1543
+}
1544
+
1545
+/* Selection */
1546
+::selection {
1547
+ background: var(--primary-200);
1548
+ color: var(--primary-900);
1549
+}
0
1550