@o-a/cms-agent 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (201) hide show
  1. package/LICENSE +105 -0
  2. package/README.md +132 -0
  3. package/dist/boot.d.ts +15 -0
  4. package/dist/boot.js +33 -0
  5. package/dist/config.d.ts +19 -0
  6. package/dist/config.js +45 -0
  7. package/dist/create-site/cli.d.ts +2 -0
  8. package/dist/create-site/cli.js +31 -0
  9. package/dist/create-site/generate-site.d.ts +9 -0
  10. package/dist/create-site/generate-site.js +109 -0
  11. package/dist/create-site/mint-token-cli.d.ts +2 -0
  12. package/dist/create-site/mint-token-cli.js +26 -0
  13. package/dist/create-site/mint-token.d.ts +7 -0
  14. package/dist/create-site/mint-token.js +49 -0
  15. package/dist/create-site/template/content/menus/footerCompany.json +9 -0
  16. package/dist/create-site/template/content/menus/footerProduct.json +9 -0
  17. package/dist/create-site/template/content/menus/footerResources.json +9 -0
  18. package/dist/create-site/template/content/menus/main.json +9 -0
  19. package/dist/create-site/template/content/pages/404.json +22 -0
  20. package/dist/create-site/template/content/pages/about/careers.json +21 -0
  21. package/dist/create-site/template/content/pages/about/team.json +21 -0
  22. package/dist/create-site/template/content/pages/about.json +21 -0
  23. package/dist/create-site/template/content/pages/docs/deployment.json +21 -0
  24. package/dist/create-site/template/content/pages/docs/getting-started/quickstart.json +21 -0
  25. package/dist/create-site/template/content/pages/docs/getting-started.json +23 -0
  26. package/dist/create-site/template/content/pages/docs.json +21 -0
  27. package/dist/create-site/template/content/pages/index.json +181 -0
  28. package/dist/create-site/template/content/redirects.json +4 -0
  29. package/dist/create-site/template/dockerignore +6 -0
  30. package/dist/create-site/template/gitignore +11 -0
  31. package/dist/create-site/template/theme/assets/site.js +49 -0
  32. package/dist/create-site/template/theme/assets/style.css +1153 -0
  33. package/dist/create-site/template/theme/blocks/button.liquid +21 -0
  34. package/dist/create-site/template/theme/blocks/comparison-row.liquid +19 -0
  35. package/dist/create-site/template/theme/blocks/faq-item.liquid +22 -0
  36. package/dist/create-site/template/theme/blocks/feature-card.liquid +23 -0
  37. package/dist/create-site/template/theme/blocks/logo-mark.liquid +13 -0
  38. package/dist/create-site/template/theme/blocks/pricing-tier.liquid +42 -0
  39. package/dist/create-site/template/theme/blocks/step-card.liquid +19 -0
  40. package/dist/create-site/template/theme/blocks/testimonial-card.liquid +25 -0
  41. package/dist/create-site/template/theme/layouts/theme.liquid +99 -0
  42. package/dist/create-site/template/theme/sections/comparison.liquid +41 -0
  43. package/dist/create-site/template/theme/sections/cta-banner.liquid +27 -0
  44. package/dist/create-site/template/theme/sections/faq.liquid +27 -0
  45. package/dist/create-site/template/theme/sections/feature-grid.liquid +27 -0
  46. package/dist/create-site/template/theme/sections/hero.liquid +36 -0
  47. package/dist/create-site/template/theme/sections/how-it-works.liquid +27 -0
  48. package/dist/create-site/template/theme/sections/pricing.liquid +27 -0
  49. package/dist/create-site/template/theme/sections/social-proof.liquid +21 -0
  50. package/dist/create-site/template/theme/sections/testimonials.liquid +27 -0
  51. package/dist/create-site/template/theme/snippets/icon.liquid +24 -0
  52. package/dist/create-site/template/theme/snippets/logo.liquid +7 -0
  53. package/dist/create-site/template/theme/snippets/site-name.liquid +1 -0
  54. package/dist/create-site/template/vhost/Dockerfile +33 -0
  55. package/dist/create-site/template/vhost/docker-entrypoint.sh +30 -0
  56. package/dist/index.d.ts +2 -0
  57. package/dist/index.js +4 -0
  58. package/dist/media/drivers/driver.d.ts +11 -0
  59. package/dist/media/drivers/driver.js +1 -0
  60. package/dist/media/drivers/local-fs-driver.d.ts +3 -0
  61. package/dist/media/drivers/local-fs-driver.js +81 -0
  62. package/dist/media/filename.d.ts +1 -0
  63. package/dist/media/filename.js +31 -0
  64. package/dist/media/manage-media.d.ts +19 -0
  65. package/dist/media/manage-media.js +45 -0
  66. package/dist/migrations/index.d.ts +3 -0
  67. package/dist/migrations/index.js +49 -0
  68. package/dist/renderer/engine.d.ts +2 -0
  69. package/dist/renderer/engine.js +48 -0
  70. package/dist/renderer/render-page.d.ts +28 -0
  71. package/dist/renderer/render-page.js +143 -0
  72. package/dist/renderer/theme-templates.d.ts +7 -0
  73. package/dist/renderer/theme-templates.js +82 -0
  74. package/dist/routes/assets.d.ts +6 -0
  75. package/dist/routes/assets.js +30 -0
  76. package/dist/routes/batch.d.ts +10 -0
  77. package/dist/routes/batch.js +148 -0
  78. package/dist/routes/capabilities.d.ts +5 -0
  79. package/dist/routes/capabilities.js +27 -0
  80. package/dist/routes/content.d.ts +8 -0
  81. package/dist/routes/content.js +166 -0
  82. package/dist/routes/drafts.d.ts +10 -0
  83. package/dist/routes/drafts.js +73 -0
  84. package/dist/routes/git.d.ts +8 -0
  85. package/dist/routes/git.js +158 -0
  86. package/dist/routes/index.d.ts +19 -0
  87. package/dist/routes/index.js +84 -0
  88. package/dist/routes/media-public.d.ts +5 -0
  89. package/dist/routes/media-public.js +48 -0
  90. package/dist/routes/media.d.ts +9 -0
  91. package/dist/routes/media.js +84 -0
  92. package/dist/routes/menus.d.ts +8 -0
  93. package/dist/routes/menus.js +77 -0
  94. package/dist/routes/preview-revision.d.ts +13 -0
  95. package/dist/routes/preview-revision.js +109 -0
  96. package/dist/routes/preview.d.ts +13 -0
  97. package/dist/routes/preview.js +52 -0
  98. package/dist/routes/public.d.ts +11 -0
  99. package/dist/routes/public.js +117 -0
  100. package/dist/routes/publish.d.ts +10 -0
  101. package/dist/routes/publish.js +105 -0
  102. package/dist/routes/redirects.d.ts +8 -0
  103. package/dist/routes/redirects.js +132 -0
  104. package/dist/routes/search.d.ts +8 -0
  105. package/dist/routes/search.js +11 -0
  106. package/dist/routes/sitemap.d.ts +6 -0
  107. package/dist/routes/sitemap.js +79 -0
  108. package/dist/routes/theme.d.ts +10 -0
  109. package/dist/routes/theme.js +17 -0
  110. package/dist/schemas/instance.schema.json +17 -0
  111. package/dist/schemas/menu.schema.json +23 -0
  112. package/dist/schemas/page.schema.json +20 -0
  113. package/dist/schemas/post.schema.json +25 -0
  114. package/dist/schemas/redirects.schema.json +24 -0
  115. package/dist/search/drivers/driver.d.ts +9 -0
  116. package/dist/search/drivers/driver.js +1 -0
  117. package/dist/search/drivers/node-sqlite-driver.d.ts +3 -0
  118. package/dist/search/drivers/node-sqlite-driver.js +19 -0
  119. package/dist/search/query-index.d.ts +5 -0
  120. package/dist/search/query-index.js +21 -0
  121. package/dist/search/rebuild-index.d.ts +2 -0
  122. package/dist/search/rebuild-index.js +111 -0
  123. package/dist/server-config.d.ts +22 -0
  124. package/dist/server-config.js +196 -0
  125. package/dist/server.d.ts +13 -0
  126. package/dist/server.js +163 -0
  127. package/dist/services/batch.d.ts +35 -0
  128. package/dist/services/batch.js +136 -0
  129. package/dist/services/checkpoint.d.ts +4 -0
  130. package/dist/services/checkpoint.js +45 -0
  131. package/dist/services/content-read.d.ts +27 -0
  132. package/dist/services/content-read.js +156 -0
  133. package/dist/services/delete-content.d.ts +12 -0
  134. package/dist/services/delete-content.js +174 -0
  135. package/dist/services/dev-tunnel.d.ts +5 -0
  136. package/dist/services/dev-tunnel.js +5 -0
  137. package/dist/services/drafts.d.ts +15 -0
  138. package/dist/services/drafts.js +155 -0
  139. package/dist/services/etag.d.ts +2 -0
  140. package/dist/services/etag.js +30 -0
  141. package/dist/services/fs-walk.d.ts +1 -0
  142. package/dist/services/fs-walk.js +26 -0
  143. package/dist/services/git-commit.d.ts +3 -0
  144. package/dist/services/git-commit.js +12 -0
  145. package/dist/services/git-history.d.ts +28 -0
  146. package/dist/services/git-history.js +131 -0
  147. package/dist/services/git-revert.d.ts +12 -0
  148. package/dist/services/git-revert.js +140 -0
  149. package/dist/services/git.d.ts +16 -0
  150. package/dist/services/git.js +127 -0
  151. package/dist/services/interval-job.d.ts +4 -0
  152. package/dist/services/interval-job.js +9 -0
  153. package/dist/services/ip-allowlist.d.ts +7 -0
  154. package/dist/services/ip-allowlist.js +31 -0
  155. package/dist/services/manage-menus.d.ts +10 -0
  156. package/dist/services/manage-menus.js +84 -0
  157. package/dist/services/manage-redirects.d.ts +25 -0
  158. package/dist/services/manage-redirects.js +166 -0
  159. package/dist/services/menus.d.ts +8 -0
  160. package/dist/services/menus.js +42 -0
  161. package/dist/services/migration-runner.d.ts +13 -0
  162. package/dist/services/migration-runner.js +123 -0
  163. package/dist/services/mime-types.d.ts +3 -0
  164. package/dist/services/mime-types.js +36 -0
  165. package/dist/services/move.d.ts +16 -0
  166. package/dist/services/move.js +175 -0
  167. package/dist/services/path-safety.d.ts +6 -0
  168. package/dist/services/path-safety.js +112 -0
  169. package/dist/services/post-urls.d.ts +3 -0
  170. package/dist/services/post-urls.js +27 -0
  171. package/dist/services/prepared-operation.d.ts +4 -0
  172. package/dist/services/prepared-operation.js +1 -0
  173. package/dist/services/publish.d.ts +14 -0
  174. package/dist/services/publish.js +254 -0
  175. package/dist/services/rate-limit-config.d.ts +9 -0
  176. package/dist/services/rate-limit-config.js +20 -0
  177. package/dist/services/redirects.d.ts +27 -0
  178. package/dist/services/redirects.js +175 -0
  179. package/dist/services/resolve-blog-url.d.ts +11 -0
  180. package/dist/services/resolve-blog-url.js +31 -0
  181. package/dist/services/resolve-url.d.ts +11 -0
  182. package/dist/services/resolve-url.js +20 -0
  183. package/dist/services/startup-checks.d.ts +10 -0
  184. package/dist/services/startup-checks.js +81 -0
  185. package/dist/services/static-file.d.ts +7 -0
  186. package/dist/services/static-file.js +37 -0
  187. package/dist/services/theme-component-file.d.ts +5 -0
  188. package/dist/services/theme-component-file.js +32 -0
  189. package/dist/services/theme-page-templates.d.ts +7 -0
  190. package/dist/services/theme-page-templates.js +53 -0
  191. package/dist/services/theme-schemas.d.ts +2 -0
  192. package/dist/services/theme-schemas.js +63 -0
  193. package/dist/services/token-auth.d.ts +10 -0
  194. package/dist/services/token-auth.js +64 -0
  195. package/dist/services/urls.d.ts +2 -0
  196. package/dist/services/urls.js +20 -0
  197. package/dist/services/validation.d.ts +24 -0
  198. package/dist/services/validation.js +158 -0
  199. package/dist/services/write-queue.d.ts +1 -0
  200. package/dist/services/write-queue.js +14 -0
  201. package/package.json +53 -0
@@ -0,0 +1,1153 @@
1
+ /* ============================================================
2
+ Granite CMS — marketing theme
3
+ Charcoal / stone palette, one accent, system font stack.
4
+ ============================================================ */
5
+
6
+ :root {
7
+ --color-bg: #f7f5f1;
8
+ --color-bg-alt: #efebe4;
9
+ --color-surface: #ffffff;
10
+
11
+ --color-ink: #1c1a17;
12
+ --color-stone-900: #262420;
13
+ --color-stone-700: #524d45;
14
+ --color-stone-600: #6b6459;
15
+ --color-stone-500: #8a8276;
16
+ --color-stone-300: #cec5b6;
17
+ --color-stone-200: #e2dbcd;
18
+ --color-stone-100: #ece6db;
19
+ --color-border: #ddd4c4;
20
+
21
+ --color-dark: #171512;
22
+ --color-dark-surface: #221f1a;
23
+ --color-dark-border: #38332b;
24
+ --color-dark-ink: #f3efe7;
25
+ --color-dark-muted: #b4ab9b;
26
+
27
+ --accent: #c2410c;
28
+ --accent-dark: #9a340a;
29
+ --accent-light: #e8c4ac;
30
+ --accent-tint: rgba(194, 65, 12, 0.09);
31
+ --accent-tint-strong: rgba(194, 65, 12, 0.16);
32
+
33
+ --font-sans: -apple-system, BlinkMacSystemFont, "Inter", "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
34
+ --font-mono: ui-monospace, "SF Mono", "Cascadia Code", "Roboto Mono", Menlo, Consolas, monospace;
35
+
36
+ --radius-sm: 6px;
37
+ --radius-md: 10px;
38
+ --radius-lg: 16px;
39
+
40
+ --shadow-sm: 0 1px 2px rgba(28, 26, 23, 0.06);
41
+ --shadow-md: 0 8px 24px -8px rgba(28, 26, 23, 0.16);
42
+ --shadow-lg: 0 24px 48px -16px rgba(28, 26, 23, 0.22);
43
+
44
+ --container: 1180px;
45
+ --header-h: 72px;
46
+ }
47
+
48
+ /* ----- reset ----- */
49
+ *,
50
+ *::before,
51
+ *::after {
52
+ box-sizing: border-box;
53
+ }
54
+
55
+ html {
56
+ scroll-behavior: smooth;
57
+ }
58
+
59
+ body {
60
+ margin: 0;
61
+ background: var(--color-bg);
62
+ color: var(--color-ink);
63
+ font-family: var(--font-sans);
64
+ font-size: 16px;
65
+ line-height: 1.55;
66
+ -webkit-font-smoothing: antialiased;
67
+ position: relative;
68
+ }
69
+
70
+ /* subtle granite-speckle texture, nod to the name without being literal */
71
+ body::before {
72
+ content: "";
73
+ position: fixed;
74
+ inset: 0;
75
+ pointer-events: none;
76
+ z-index: 0;
77
+ opacity: 0.55;
78
+ background-image:
79
+ radial-gradient(circle at 20% 30%, rgba(38, 36, 32, 0.05) 0, rgba(38, 36, 32, 0.05) 1px, transparent 1.6px),
80
+ radial-gradient(circle at 62% 68%, rgba(38, 36, 32, 0.045) 0, rgba(38, 36, 32, 0.045) 1px, transparent 1.6px),
81
+ radial-gradient(circle at 82% 18%, rgba(38, 36, 32, 0.04) 0, rgba(38, 36, 32, 0.04) 1px, transparent 1.6px),
82
+ radial-gradient(circle at 38% 82%, rgba(38, 36, 32, 0.045) 0, rgba(38, 36, 32, 0.045) 1px, transparent 1.6px),
83
+ radial-gradient(circle at 5% 90%, rgba(38, 36, 32, 0.035) 0, rgba(38, 36, 32, 0.035) 1px, transparent 1.6px);
84
+ background-size: 220px 220px, 260px 260px, 190px 190px, 240px 240px, 300px 300px;
85
+ background-position: 0 0, 40px 60px, 120px 10px, 170px 140px, 20px 200px;
86
+ }
87
+
88
+ img,
89
+ svg {
90
+ display: block;
91
+ max-width: 100%;
92
+ }
93
+
94
+ a {
95
+ color: inherit;
96
+ text-decoration: none;
97
+ }
98
+
99
+ ul {
100
+ list-style: none;
101
+ margin: 0;
102
+ padding: 0;
103
+ }
104
+
105
+ h1, h2, h3, h4, p {
106
+ margin: 0;
107
+ }
108
+
109
+ button {
110
+ font: inherit;
111
+ color: inherit;
112
+ background: none;
113
+ border: none;
114
+ cursor: pointer;
115
+ }
116
+
117
+ .container {
118
+ width: 100%;
119
+ max-width: var(--container);
120
+ margin: 0 auto;
121
+ padding: 0 24px;
122
+ }
123
+
124
+ .skip-link {
125
+ position: absolute;
126
+ left: -9999px;
127
+ top: 0;
128
+ background: var(--color-ink);
129
+ color: #fff;
130
+ padding: 10px 16px;
131
+ z-index: 200;
132
+ border-radius: 0 0 var(--radius-sm) 0;
133
+ }
134
+
135
+ .skip-link:focus {
136
+ left: 0;
137
+ }
138
+
139
+ /* ----- typography ----- */
140
+ h1, h2, h3, h4 {
141
+ font-family: var(--font-sans);
142
+ font-weight: 700;
143
+ letter-spacing: -0.02em;
144
+ color: var(--color-stone-900);
145
+ }
146
+
147
+ .eyebrow {
148
+ display: inline-flex;
149
+ align-items: center;
150
+ gap: 8px;
151
+ font-size: 13px;
152
+ font-weight: 600;
153
+ letter-spacing: 0.06em;
154
+ text-transform: uppercase;
155
+ color: var(--accent-dark);
156
+ }
157
+
158
+ .eyebrow::before {
159
+ content: "";
160
+ width: 6px;
161
+ height: 6px;
162
+ border-radius: 50%;
163
+ background: var(--accent);
164
+ }
165
+
166
+ .section-head {
167
+ max-width: 640px;
168
+ margin: 0 0 48px;
169
+ }
170
+
171
+ .section-head h2 {
172
+ font-size: clamp(28px, 3.4vw, 38px);
173
+ margin-top: 14px;
174
+ }
175
+
176
+ .section-head p {
177
+ margin-top: 14px;
178
+ font-size: 17px;
179
+ color: var(--color-stone-600);
180
+ }
181
+
182
+ .section-head.center {
183
+ margin-left: auto;
184
+ margin-right: auto;
185
+ text-align: center;
186
+ }
187
+
188
+ section {
189
+ position: relative;
190
+ z-index: 1;
191
+ padding: 96px 0;
192
+ }
193
+
194
+ @media (max-width: 760px) {
195
+ section {
196
+ padding: 64px 0;
197
+ }
198
+ }
199
+
200
+ .section-alt {
201
+ background: var(--color-bg-alt);
202
+ border-top: 1px solid var(--color-border);
203
+ border-bottom: 1px solid var(--color-border);
204
+ }
205
+
206
+ /* ----- buttons ----- */
207
+ .btn {
208
+ display: inline-flex;
209
+ align-items: center;
210
+ justify-content: center;
211
+ gap: 8px;
212
+ padding: 13px 24px;
213
+ border-radius: var(--radius-sm);
214
+ font-weight: 600;
215
+ font-size: 15px;
216
+ border: 1px solid transparent;
217
+ transition: transform 0.15s ease, box-shadow 0.15s ease, background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease;
218
+ white-space: nowrap;
219
+ }
220
+
221
+ .btn:hover {
222
+ transform: translateY(-1px);
223
+ }
224
+
225
+ .btn:active {
226
+ transform: translateY(0);
227
+ }
228
+
229
+ .btn--primary {
230
+ background: var(--accent);
231
+ color: #fff;
232
+ box-shadow: 0 1px 0 rgba(0, 0, 0, 0.05);
233
+ }
234
+
235
+ .btn--primary:hover {
236
+ background: var(--accent-dark);
237
+ box-shadow: var(--shadow-md);
238
+ }
239
+
240
+ .btn--secondary {
241
+ background: transparent;
242
+ color: var(--color-stone-900);
243
+ border-color: var(--color-border);
244
+ }
245
+
246
+ .btn--secondary:hover {
247
+ border-color: var(--color-stone-900);
248
+ background: var(--color-surface);
249
+ }
250
+
251
+ .btn--on-dark {
252
+ background: transparent;
253
+ color: var(--color-dark-ink);
254
+ border-color: var(--color-dark-border);
255
+ }
256
+
257
+ .btn--on-dark:hover {
258
+ border-color: var(--color-dark-ink);
259
+ background: rgba(255, 255, 255, 0.06);
260
+ }
261
+
262
+ .btn--sm {
263
+ padding: 9px 16px;
264
+ font-size: 14px;
265
+ }
266
+
267
+ .btn--block {
268
+ width: 100%;
269
+ }
270
+
271
+ /* ----- header / nav ----- */
272
+ .site-header {
273
+ position: sticky;
274
+ top: 0;
275
+ z-index: 100;
276
+ background: rgba(247, 245, 241, 0.86);
277
+ backdrop-filter: blur(10px);
278
+ -webkit-backdrop-filter: blur(10px);
279
+ border-bottom: 1px solid transparent;
280
+ transition: border-color 0.2s ease, box-shadow 0.2s ease;
281
+ }
282
+
283
+ .site-header.is-scrolled {
284
+ border-bottom-color: var(--color-border);
285
+ box-shadow: var(--shadow-sm);
286
+ }
287
+
288
+ .site-header__inner {
289
+ height: var(--header-h);
290
+ display: flex;
291
+ align-items: center;
292
+ justify-content: space-between;
293
+ gap: 24px;
294
+ }
295
+
296
+ .logo {
297
+ display: flex;
298
+ align-items: center;
299
+ gap: 9px;
300
+ font-weight: 700;
301
+ font-size: 18px;
302
+ letter-spacing: -0.01em;
303
+ color: var(--color-stone-900);
304
+ }
305
+
306
+ .logo__mark {
307
+ width: 26px;
308
+ height: 26px;
309
+ flex-shrink: 0;
310
+ }
311
+
312
+ .site-nav {
313
+ display: none;
314
+ }
315
+
316
+ .site-nav ul {
317
+ display: flex;
318
+ align-items: center;
319
+ gap: 32px;
320
+ }
321
+
322
+ .site-nav a {
323
+ font-size: 15px;
324
+ font-weight: 500;
325
+ color: var(--color-stone-700);
326
+ transition: color 0.15s ease;
327
+ position: relative;
328
+ }
329
+
330
+ .site-nav a:hover {
331
+ color: var(--color-stone-900);
332
+ }
333
+
334
+ .site-header__actions {
335
+ display: flex;
336
+ align-items: center;
337
+ gap: 14px;
338
+ }
339
+
340
+ .site-header__actions .btn--primary {
341
+ display: none;
342
+ }
343
+
344
+ .nav-toggle {
345
+ display: flex;
346
+ flex-direction: column;
347
+ justify-content: center;
348
+ gap: 5px;
349
+ width: 36px;
350
+ height: 36px;
351
+ padding: 8px;
352
+ }
353
+
354
+ .nav-toggle span {
355
+ display: block;
356
+ height: 2px;
357
+ width: 100%;
358
+ background: var(--color-stone-900);
359
+ border-radius: 2px;
360
+ transition: transform 0.2s ease, opacity 0.2s ease;
361
+ }
362
+
363
+ .nav-toggle[aria-expanded="true"] span:nth-child(1) {
364
+ transform: translateY(7px) rotate(45deg);
365
+ }
366
+
367
+ .nav-toggle[aria-expanded="true"] span:nth-child(2) {
368
+ opacity: 0;
369
+ }
370
+
371
+ .nav-toggle[aria-expanded="true"] span:nth-child(3) {
372
+ transform: translateY(-7px) rotate(-45deg);
373
+ }
374
+
375
+ .mobile-nav {
376
+ display: none;
377
+ flex-direction: column;
378
+ gap: 20px;
379
+ padding: 20px 24px 28px;
380
+ border-top: 1px solid var(--color-border);
381
+ background: var(--color-bg);
382
+ }
383
+
384
+ .mobile-nav.is-open {
385
+ display: flex;
386
+ }
387
+
388
+ .mobile-nav ul {
389
+ display: flex;
390
+ flex-direction: column;
391
+ gap: 4px;
392
+ }
393
+
394
+ .mobile-nav a {
395
+ display: block;
396
+ padding: 10px 2px;
397
+ font-size: 16px;
398
+ font-weight: 500;
399
+ color: var(--color-stone-800, var(--color-stone-900));
400
+ }
401
+
402
+ @media (min-width: 900px) {
403
+ .site-nav {
404
+ display: block;
405
+ }
406
+
407
+ .site-header__actions .btn--primary {
408
+ display: inline-flex;
409
+ }
410
+
411
+ .nav-toggle {
412
+ display: none;
413
+ }
414
+
415
+ .mobile-nav {
416
+ display: none !important;
417
+ }
418
+ }
419
+
420
+ /* ----- reveal-on-scroll ----- */
421
+ .reveal {
422
+ opacity: 0;
423
+ transform: translateY(18px);
424
+ transition: opacity 0.6s ease, transform 0.6s ease;
425
+ }
426
+
427
+ .reveal.is-visible {
428
+ opacity: 1;
429
+ transform: translateY(0);
430
+ }
431
+
432
+ @media (prefers-reduced-motion: reduce) {
433
+ .reveal {
434
+ opacity: 1;
435
+ transform: none;
436
+ transition: none;
437
+ }
438
+
439
+ html {
440
+ scroll-behavior: auto;
441
+ }
442
+ }
443
+
444
+ /* ----- hero ----- */
445
+ .hero {
446
+ padding-top: 72px;
447
+ overflow: hidden;
448
+ }
449
+
450
+ .hero__inner {
451
+ display: grid;
452
+ grid-template-columns: minmax(0, 1fr);
453
+ gap: 56px;
454
+ align-items: center;
455
+ }
456
+
457
+ .hero__content h1 {
458
+ font-size: clamp(36px, 5.4vw, 58px);
459
+ line-height: 1.08;
460
+ margin-top: 18px;
461
+ }
462
+
463
+ .hero__content h1 .accent {
464
+ color: var(--accent);
465
+ }
466
+
467
+ .hero__content p {
468
+ margin-top: 22px;
469
+ font-size: 19px;
470
+ color: var(--color-stone-600);
471
+ max-width: 46ch;
472
+ }
473
+
474
+ .hero__actions {
475
+ display: flex;
476
+ flex-wrap: wrap;
477
+ gap: 14px;
478
+ margin-top: 34px;
479
+ }
480
+
481
+ .hero__actions .btn {
482
+ padding: 14px 26px;
483
+ font-size: 16px;
484
+ }
485
+
486
+ .code-panel {
487
+ background: var(--color-dark);
488
+ border-radius: var(--radius-lg);
489
+ box-shadow: var(--shadow-lg);
490
+ border: 1px solid var(--color-dark-border);
491
+ overflow: hidden;
492
+ }
493
+
494
+ .code-panel__bar {
495
+ display: flex;
496
+ align-items: center;
497
+ gap: 8px;
498
+ padding: 13px 16px;
499
+ border-bottom: 1px solid var(--color-dark-border);
500
+ }
501
+
502
+ .code-panel__bar span {
503
+ width: 10px;
504
+ height: 10px;
505
+ border-radius: 50%;
506
+ background: var(--color-dark-border);
507
+ }
508
+
509
+ .code-panel__bar span:nth-child(1) {
510
+ background: #e0605a;
511
+ }
512
+
513
+ .code-panel__bar span:nth-child(2) {
514
+ background: #e0b355;
515
+ }
516
+
517
+ .code-panel__bar span:nth-child(3) {
518
+ background: #6fb583;
519
+ }
520
+
521
+ .code-panel__title {
522
+ margin-left: 8px;
523
+ font-family: var(--font-mono);
524
+ font-size: 12px;
525
+ color: var(--color-dark-muted);
526
+ }
527
+
528
+ .code-panel pre {
529
+ margin: 0;
530
+ padding: 22px 20px 26px;
531
+ overflow-x: auto;
532
+ }
533
+
534
+ .code-panel code {
535
+ font-family: var(--font-mono);
536
+ font-size: 13.5px;
537
+ line-height: 1.7;
538
+ color: #e8e2d6;
539
+ white-space: pre;
540
+ }
541
+
542
+ @media (min-width: 960px) {
543
+ .hero__inner {
544
+ grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr);
545
+ }
546
+ }
547
+
548
+ /* ----- social proof ----- */
549
+ .social-proof {
550
+ padding: 56px 0;
551
+ }
552
+
553
+ .social-proof__label {
554
+ text-align: center;
555
+ font-size: 13px;
556
+ font-weight: 600;
557
+ letter-spacing: 0.08em;
558
+ text-transform: uppercase;
559
+ color: var(--color-stone-500);
560
+ margin-bottom: 36px;
561
+ }
562
+
563
+ .social-proof__row {
564
+ display: grid;
565
+ grid-template-columns: repeat(2, 1fr);
566
+ gap: 28px;
567
+ align-items: center;
568
+ justify-items: center;
569
+ }
570
+
571
+ .logo-mark {
572
+ font-family: var(--font-mono);
573
+ font-weight: 600;
574
+ font-size: 17px;
575
+ letter-spacing: -0.01em;
576
+ color: var(--color-stone-400, var(--color-stone-500));
577
+ filter: grayscale(1);
578
+ opacity: 0.7;
579
+ transition: opacity 0.2s ease;
580
+ }
581
+
582
+ .logo-mark:hover {
583
+ opacity: 1;
584
+ }
585
+
586
+ @media (min-width: 700px) {
587
+ .social-proof__row {
588
+ grid-template-columns: repeat(5, 1fr);
589
+ }
590
+ }
591
+
592
+ /* ----- feature grid ----- */
593
+ .feature-grid {
594
+ display: grid;
595
+ gap: 22px;
596
+ grid-template-columns: 1fr;
597
+ }
598
+
599
+ .feature-card {
600
+ background: var(--color-surface);
601
+ border: 1px solid var(--color-border);
602
+ border-radius: var(--radius-md);
603
+ padding: 30px;
604
+ transition: transform 0.2s ease, box-shadow 0.2s ease, border-color 0.2s ease;
605
+ }
606
+
607
+ .feature-card:hover {
608
+ transform: translateY(-3px);
609
+ box-shadow: var(--shadow-md);
610
+ border-color: var(--color-stone-300);
611
+ }
612
+
613
+ .feature-card__icon {
614
+ width: 42px;
615
+ height: 42px;
616
+ border-radius: var(--radius-sm);
617
+ background: var(--accent-tint);
618
+ color: var(--accent);
619
+ display: flex;
620
+ align-items: center;
621
+ justify-content: center;
622
+ margin-bottom: 20px;
623
+ }
624
+
625
+ .feature-card__icon svg {
626
+ width: 22px;
627
+ height: 22px;
628
+ }
629
+
630
+ .feature-card h3 {
631
+ font-size: 18px;
632
+ }
633
+
634
+ .feature-card p {
635
+ margin-top: 10px;
636
+ font-size: 15px;
637
+ color: var(--color-stone-600);
638
+ }
639
+
640
+ @media (min-width: 700px) {
641
+ .feature-grid {
642
+ grid-template-columns: repeat(2, 1fr);
643
+ }
644
+ }
645
+
646
+ @media (min-width: 1000px) {
647
+ .feature-grid {
648
+ grid-template-columns: repeat(3, 1fr);
649
+ }
650
+ }
651
+
652
+ /* ----- how it works ----- */
653
+ .steps {
654
+ display: grid;
655
+ gap: 32px;
656
+ grid-template-columns: 1fr;
657
+ counter-reset: step;
658
+ }
659
+
660
+ .step-card {
661
+ position: relative;
662
+ padding-left: 0;
663
+ }
664
+
665
+ .step-card__number {
666
+ font-family: var(--font-mono);
667
+ font-size: 14px;
668
+ font-weight: 600;
669
+ color: var(--accent);
670
+ display: inline-flex;
671
+ align-items: center;
672
+ gap: 10px;
673
+ }
674
+
675
+ .step-card__number::before {
676
+ content: "";
677
+ width: 34px;
678
+ height: 1px;
679
+ background: var(--color-border);
680
+ }
681
+
682
+ .step-card__number::after {
683
+ content: "";
684
+ flex: 1;
685
+ height: 1px;
686
+ background: var(--color-border);
687
+ }
688
+
689
+ .step-card h3 {
690
+ font-size: 20px;
691
+ margin-top: 16px;
692
+ }
693
+
694
+ .step-card p {
695
+ margin-top: 10px;
696
+ color: var(--color-stone-600);
697
+ font-size: 15px;
698
+ }
699
+
700
+ @media (min-width: 800px) {
701
+ .steps {
702
+ grid-template-columns: repeat(3, 1fr);
703
+ }
704
+ }
705
+
706
+ /* ----- comparison table ----- */
707
+ .comparison-table {
708
+ width: 100%;
709
+ border-collapse: separate;
710
+ border-spacing: 0;
711
+ background: var(--color-surface);
712
+ border: 1px solid var(--color-border);
713
+ border-radius: var(--radius-md);
714
+ overflow: hidden;
715
+ }
716
+
717
+ .comparison-table th,
718
+ .comparison-table td {
719
+ padding: 16px 20px;
720
+ text-align: left;
721
+ font-size: 14.5px;
722
+ border-bottom: 1px solid var(--color-border);
723
+ }
724
+
725
+ .comparison-table tr:last-child td {
726
+ border-bottom: none;
727
+ }
728
+
729
+ .comparison-table thead th {
730
+ background: var(--color-bg-alt);
731
+ font-size: 13px;
732
+ text-transform: uppercase;
733
+ letter-spacing: 0.05em;
734
+ color: var(--color-stone-600);
735
+ font-weight: 600;
736
+ }
737
+
738
+ .comparison-table th:first-child,
739
+ .comparison-table td:first-child {
740
+ color: var(--color-stone-700);
741
+ font-weight: 500;
742
+ }
743
+
744
+ .comparison-table .col-granite {
745
+ background: var(--accent-tint);
746
+ color: var(--color-stone-900);
747
+ font-weight: 600;
748
+ }
749
+
750
+ .comparison-table thead .col-granite {
751
+ background: var(--accent);
752
+ color: #fff;
753
+ }
754
+
755
+ .comparison-wrap {
756
+ overflow-x: auto;
757
+ -webkit-overflow-scrolling: touch;
758
+ }
759
+
760
+ /* ----- testimonials ----- */
761
+ .testimonial-grid {
762
+ display: grid;
763
+ gap: 22px;
764
+ grid-template-columns: 1fr;
765
+ }
766
+
767
+ .testimonial-card {
768
+ background: var(--color-surface);
769
+ border: 1px solid var(--color-border);
770
+ border-radius: var(--radius-md);
771
+ padding: 32px;
772
+ }
773
+
774
+ .testimonial-card blockquote {
775
+ margin: 0;
776
+ font-size: 18px;
777
+ line-height: 1.55;
778
+ color: var(--color-stone-900);
779
+ }
780
+
781
+ .testimonial-card blockquote::before {
782
+ content: "\201C";
783
+ color: var(--accent);
784
+ }
785
+
786
+ .testimonial-card__author {
787
+ display: flex;
788
+ align-items: center;
789
+ gap: 12px;
790
+ margin-top: 24px;
791
+ }
792
+
793
+ .avatar {
794
+ width: 42px;
795
+ height: 42px;
796
+ border-radius: 50%;
797
+ background: var(--color-stone-900);
798
+ color: #fff;
799
+ display: flex;
800
+ align-items: center;
801
+ justify-content: center;
802
+ font-weight: 600;
803
+ font-size: 14px;
804
+ flex-shrink: 0;
805
+ }
806
+
807
+ .testimonial-card__author strong {
808
+ display: block;
809
+ font-size: 15px;
810
+ color: var(--color-stone-900);
811
+ }
812
+
813
+ .testimonial-card__author span {
814
+ display: block;
815
+ font-size: 13.5px;
816
+ color: var(--color-stone-500);
817
+ margin-top: 2px;
818
+ }
819
+
820
+ @media (min-width: 780px) {
821
+ .testimonial-grid {
822
+ grid-template-columns: repeat(2, 1fr);
823
+ }
824
+ }
825
+
826
+ /* ----- pricing ----- */
827
+ .pricing-grid {
828
+ display: grid;
829
+ gap: 22px;
830
+ grid-template-columns: 1fr;
831
+ align-items: start;
832
+ }
833
+
834
+ .pricing-tier {
835
+ background: var(--color-surface);
836
+ border: 1px solid var(--color-border);
837
+ border-radius: var(--radius-lg);
838
+ padding: 32px;
839
+ transition: transform 0.2s ease, box-shadow 0.2s ease;
840
+ }
841
+
842
+ .pricing-tier:hover {
843
+ transform: translateY(-3px);
844
+ box-shadow: var(--shadow-md);
845
+ }
846
+
847
+ .pricing-tier--highlight {
848
+ background: var(--color-stone-900);
849
+ border-color: var(--color-stone-900);
850
+ color: #fff;
851
+ position: relative;
852
+ }
853
+
854
+ .pricing-tier--highlight::before {
855
+ content: "Most popular";
856
+ position: absolute;
857
+ top: -13px;
858
+ left: 32px;
859
+ background: var(--accent);
860
+ color: #fff;
861
+ font-size: 12px;
862
+ font-weight: 600;
863
+ letter-spacing: 0.03em;
864
+ padding: 5px 12px;
865
+ border-radius: 999px;
866
+ }
867
+
868
+ .pricing-tier__name {
869
+ font-size: 15px;
870
+ font-weight: 600;
871
+ color: var(--color-stone-600);
872
+ }
873
+
874
+ .pricing-tier--highlight .pricing-tier__name {
875
+ color: var(--color-stone-300);
876
+ }
877
+
878
+ .pricing-tier__price {
879
+ display: flex;
880
+ align-items: baseline;
881
+ gap: 6px;
882
+ margin-top: 14px;
883
+ }
884
+
885
+ .pricing-tier__price strong {
886
+ font-size: 40px;
887
+ font-weight: 700;
888
+ letter-spacing: -0.02em;
889
+ color: inherit;
890
+ }
891
+
892
+ .pricing-tier__price span {
893
+ font-size: 14px;
894
+ color: var(--color-stone-500);
895
+ }
896
+
897
+ .pricing-tier--highlight .pricing-tier__price span {
898
+ color: var(--color-stone-300);
899
+ }
900
+
901
+ .pricing-tier__desc {
902
+ margin-top: 12px;
903
+ font-size: 14.5px;
904
+ color: var(--color-stone-600);
905
+ }
906
+
907
+ .pricing-tier--highlight .pricing-tier__desc {
908
+ color: var(--color-stone-300);
909
+ }
910
+
911
+ .pricing-tier__features {
912
+ margin-top: 24px;
913
+ display: flex;
914
+ flex-direction: column;
915
+ gap: 11px;
916
+ }
917
+
918
+ .pricing-tier__features li {
919
+ display: flex;
920
+ align-items: flex-start;
921
+ gap: 10px;
922
+ font-size: 14.5px;
923
+ }
924
+
925
+ .pricing-tier__features svg {
926
+ width: 16px;
927
+ height: 16px;
928
+ color: var(--accent);
929
+ flex-shrink: 0;
930
+ margin-top: 3px;
931
+ }
932
+
933
+ .pricing-tier .btn {
934
+ margin-top: 28px;
935
+ width: 100%;
936
+ }
937
+
938
+ @media (min-width: 900px) {
939
+ .pricing-grid {
940
+ grid-template-columns: repeat(3, 1fr);
941
+ }
942
+
943
+ .pricing-tier--highlight {
944
+ transform: scale(1.04);
945
+ }
946
+
947
+ .pricing-tier--highlight:hover {
948
+ transform: scale(1.04) translateY(-3px);
949
+ }
950
+ }
951
+
952
+ /* ----- FAQ ----- */
953
+ .faq-list {
954
+ display: flex;
955
+ flex-direction: column;
956
+ gap: 12px;
957
+ max-width: 760px;
958
+ }
959
+
960
+ .faq-item {
961
+ background: var(--color-surface);
962
+ border: 1px solid var(--color-border);
963
+ border-radius: var(--radius-md);
964
+ overflow: hidden;
965
+ }
966
+
967
+ .faq-item summary {
968
+ cursor: pointer;
969
+ list-style: none;
970
+ padding: 20px 24px;
971
+ display: flex;
972
+ align-items: center;
973
+ justify-content: space-between;
974
+ gap: 16px;
975
+ font-weight: 600;
976
+ font-size: 16px;
977
+ color: var(--color-stone-900);
978
+ }
979
+
980
+ .faq-item summary::-webkit-details-marker {
981
+ display: none;
982
+ }
983
+
984
+ .faq-item__icon {
985
+ flex-shrink: 0;
986
+ width: 20px;
987
+ height: 20px;
988
+ color: var(--accent);
989
+ transition: transform 0.2s ease;
990
+ }
991
+
992
+ .faq-item[open] .faq-item__icon {
993
+ transform: rotate(45deg);
994
+ }
995
+
996
+ .faq-item__body {
997
+ padding: 0 24px 22px;
998
+ font-size: 15px;
999
+ color: var(--color-stone-600);
1000
+ }
1001
+
1002
+ /* ----- CTA banner ----- */
1003
+ .cta-banner {
1004
+ background: var(--color-dark);
1005
+ color: var(--color-dark-ink);
1006
+ border-radius: var(--radius-lg);
1007
+ padding: 64px 40px;
1008
+ text-align: center;
1009
+ position: relative;
1010
+ overflow: hidden;
1011
+ }
1012
+
1013
+ .cta-banner::after {
1014
+ content: "";
1015
+ position: absolute;
1016
+ inset: 0;
1017
+ background-image: radial-gradient(circle at 50% 0%, rgba(194, 65, 12, 0.22), transparent 60%);
1018
+ pointer-events: none;
1019
+ }
1020
+
1021
+ .cta-banner__inner {
1022
+ position: relative;
1023
+ z-index: 1;
1024
+ max-width: 560px;
1025
+ margin: 0 auto;
1026
+ }
1027
+
1028
+ .cta-banner h2 {
1029
+ color: #fff;
1030
+ font-size: clamp(26px, 3.6vw, 36px);
1031
+ }
1032
+
1033
+ .cta-banner p {
1034
+ margin-top: 16px;
1035
+ color: var(--color-dark-muted);
1036
+ font-size: 16.5px;
1037
+ }
1038
+
1039
+ .cta-banner__actions {
1040
+ margin-top: 30px;
1041
+ display: flex;
1042
+ flex-wrap: wrap;
1043
+ gap: 14px;
1044
+ justify-content: center;
1045
+ }
1046
+
1047
+ /* ----- footer ----- */
1048
+ .site-footer {
1049
+ background: var(--color-stone-900);
1050
+ color: var(--color-stone-300);
1051
+ padding: 72px 0 32px;
1052
+ position: relative;
1053
+ z-index: 1;
1054
+ }
1055
+
1056
+ .footer__grid {
1057
+ display: grid;
1058
+ gap: 48px;
1059
+ grid-template-columns: 1fr;
1060
+ }
1061
+
1062
+ .footer__brand p {
1063
+ margin-top: 14px;
1064
+ font-size: 14.5px;
1065
+ color: var(--color-stone-500);
1066
+ max-width: 28ch;
1067
+ }
1068
+
1069
+ .footer__brand .logo {
1070
+ color: #fff;
1071
+ }
1072
+
1073
+ .footer__social {
1074
+ display: flex;
1075
+ gap: 14px;
1076
+ margin-top: 22px;
1077
+ }
1078
+
1079
+ .footer__social a {
1080
+ width: 34px;
1081
+ height: 34px;
1082
+ border-radius: 50%;
1083
+ border: 1px solid var(--color-stone-700);
1084
+ display: flex;
1085
+ align-items: center;
1086
+ justify-content: center;
1087
+ color: var(--color-stone-300);
1088
+ transition: border-color 0.15s ease, color 0.15s ease, background-color 0.15s ease;
1089
+ }
1090
+
1091
+ .footer__social svg {
1092
+ width: 16px;
1093
+ height: 16px;
1094
+ }
1095
+
1096
+ .footer__social a:hover {
1097
+ border-color: var(--accent);
1098
+ color: #fff;
1099
+ background: var(--accent);
1100
+ }
1101
+
1102
+ .footer__cols {
1103
+ display: grid;
1104
+ gap: 32px;
1105
+ grid-template-columns: repeat(2, 1fr);
1106
+ }
1107
+
1108
+ .footer__col h3 {
1109
+ font-size: 13px;
1110
+ font-weight: 600;
1111
+ letter-spacing: 0.05em;
1112
+ text-transform: uppercase;
1113
+ color: var(--color-stone-500);
1114
+ }
1115
+
1116
+ .footer__col ul {
1117
+ margin-top: 18px;
1118
+ display: flex;
1119
+ flex-direction: column;
1120
+ gap: 12px;
1121
+ }
1122
+
1123
+ .footer__col a {
1124
+ font-size: 14.5px;
1125
+ color: var(--color-stone-300);
1126
+ transition: color 0.15s ease;
1127
+ }
1128
+
1129
+ .footer__col a:hover {
1130
+ color: #fff;
1131
+ }
1132
+
1133
+ .footer__bottom {
1134
+ margin-top: 56px;
1135
+ padding-top: 28px;
1136
+ border-top: 1px solid var(--color-stone-700);
1137
+ font-size: 13.5px;
1138
+ color: var(--color-stone-500);
1139
+ display: flex;
1140
+ flex-wrap: wrap;
1141
+ gap: 12px;
1142
+ justify-content: space-between;
1143
+ }
1144
+
1145
+ @media (min-width: 720px) {
1146
+ .footer__grid {
1147
+ grid-template-columns: 1.2fr 2fr;
1148
+ }
1149
+
1150
+ .footer__cols {
1151
+ grid-template-columns: repeat(3, 1fr);
1152
+ }
1153
+ }