journeybook 0.1.6.pre.alpha

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 (134) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +9 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.md +354 -0
  5. data/Rakefile +6 -0
  6. data/app/assets/images/journeybook/.keep +0 -0
  7. data/app/assets/images/journeybook/logo.svg +5 -0
  8. data/app/assets/javascripts/journeybook/sortable.js +96 -0
  9. data/app/assets/stylesheets/journeybook/application.css +1556 -0
  10. data/app/controllers/concerns/.keep +0 -0
  11. data/app/controllers/concerns/journeybook/public_pages.rb +31 -0
  12. data/app/controllers/journeybook/admin/ai_pages_controller.rb +65 -0
  13. data/app/controllers/journeybook/admin/ai_style_prompts_controller.rb +51 -0
  14. data/app/controllers/journeybook/admin/components_controller.rb +57 -0
  15. data/app/controllers/journeybook/admin/dashboard_controller.rb +13 -0
  16. data/app/controllers/journeybook/admin/media_assets_controller.rb +59 -0
  17. data/app/controllers/journeybook/admin/navigation_items_controller.rb +91 -0
  18. data/app/controllers/journeybook/admin/navigation_menus_controller.rb +59 -0
  19. data/app/controllers/journeybook/admin/pages_controller.rb +304 -0
  20. data/app/controllers/journeybook/admin/redirects_controller.rb +51 -0
  21. data/app/controllers/journeybook/admin/sites_controller.rb +51 -0
  22. data/app/controllers/journeybook/application_controller.rb +52 -0
  23. data/app/controllers/journeybook/form_submissions_controller.rb +55 -0
  24. data/app/helpers/journeybook/application_helper.rb +4 -0
  25. data/app/helpers/journeybook/navigation_helper.rb +11 -0
  26. data/app/javascript/journeybook/application.js +5 -0
  27. data/app/javascript/journeybook/component_search_controller.js +13 -0
  28. data/app/jobs/journeybook/application_job.rb +4 -0
  29. data/app/models/concerns/.keep +0 -0
  30. data/app/models/journeybook/ai_style_prompt.rb +6 -0
  31. data/app/models/journeybook/application_record.rb +5 -0
  32. data/app/models/journeybook/media_asset.rb +26 -0
  33. data/app/models/journeybook/navigation_item.rb +45 -0
  34. data/app/models/journeybook/navigation_menu.rb +23 -0
  35. data/app/models/journeybook/page.rb +96 -0
  36. data/app/models/journeybook/redirect.rb +31 -0
  37. data/app/models/journeybook/site.rb +62 -0
  38. data/app/services/journeybook/ai/markdown_generator.rb +15 -0
  39. data/app/services/journeybook/ai/openai_client.rb +54 -0
  40. data/app/services/journeybook/ai/prompt_builder.rb +154 -0
  41. data/app/services/journeybook/ai/template_validator.rb +17 -0
  42. data/app/services/journeybook/component_parser.rb +53 -0
  43. data/app/services/journeybook/component_renderer.rb +108 -0
  44. data/app/services/journeybook/component_tag_updater.rb +132 -0
  45. data/app/services/journeybook/component_validator.rb +111 -0
  46. data/app/services/journeybook/form_mailer.rb +69 -0
  47. data/app/services/journeybook/html_sanitizer.rb +46 -0
  48. data/app/services/journeybook/letter_opener_client.rb +14 -0
  49. data/app/services/journeybook/markdown_renderer.rb +29 -0
  50. data/app/services/journeybook/page_renderer.rb +58 -0
  51. data/app/services/journeybook/page_resolver.rb +55 -0
  52. data/app/services/journeybook/postmark_client.rb +48 -0
  53. data/app/services/journeybook/storage/s3_client.rb +96 -0
  54. data/app/views/journeybook/admin/ai_pages/_draft_form.html.erb +73 -0
  55. data/app/views/journeybook/admin/ai_pages/new.html.erb +43 -0
  56. data/app/views/journeybook/admin/ai_style_prompts/_form.html.erb +16 -0
  57. data/app/views/journeybook/admin/ai_style_prompts/edit.html.erb +2 -0
  58. data/app/views/journeybook/admin/ai_style_prompts/index.html.erb +26 -0
  59. data/app/views/journeybook/admin/ai_style_prompts/new.html.erb +2 -0
  60. data/app/views/journeybook/admin/components/_component.html.erb +17 -0
  61. data/app/views/journeybook/admin/components/_reference.html.erb +9 -0
  62. data/app/views/journeybook/admin/components/index.html.erb +46 -0
  63. data/app/views/journeybook/admin/components/preview.html.erb +13 -0
  64. data/app/views/journeybook/admin/dashboard/show.html.erb +34 -0
  65. data/app/views/journeybook/admin/media_assets/_reference.html.erb +16 -0
  66. data/app/views/journeybook/admin/media_assets/index.html.erb +43 -0
  67. data/app/views/journeybook/admin/media_assets/new.html.erb +41 -0
  68. data/app/views/journeybook/admin/navigation_items/_form.html.erb +46 -0
  69. data/app/views/journeybook/admin/navigation_items/edit.html.erb +2 -0
  70. data/app/views/journeybook/admin/navigation_items/new.html.erb +2 -0
  71. data/app/views/journeybook/admin/navigation_menus/_form.html.erb +10 -0
  72. data/app/views/journeybook/admin/navigation_menus/edit.html.erb +38 -0
  73. data/app/views/journeybook/admin/navigation_menus/index.html.erb +28 -0
  74. data/app/views/journeybook/admin/navigation_menus/new.html.erb +2 -0
  75. data/app/views/journeybook/admin/pages/_collection_field.html.erb +58 -0
  76. data/app/views/journeybook/admin/pages/_form.html.erb +77 -0
  77. data/app/views/journeybook/admin/pages/_image_picker_modal.html.erb +23 -0
  78. data/app/views/journeybook/admin/pages/_table.html.erb +37 -0
  79. data/app/views/journeybook/admin/pages/_url_field.html.erb +25 -0
  80. data/app/views/journeybook/admin/pages/edit.html.erb +547 -0
  81. data/app/views/journeybook/admin/pages/errors.html.erb +25 -0
  82. data/app/views/journeybook/admin/pages/index.html.erb +52 -0
  83. data/app/views/journeybook/admin/pages/new.html.erb +27 -0
  84. data/app/views/journeybook/admin/pages/new_component.html.erb +70 -0
  85. data/app/views/journeybook/admin/pages/public_preview.html.erb +27 -0
  86. data/app/views/journeybook/admin/pages/source.html.erb +23 -0
  87. data/app/views/journeybook/admin/redirects/_form.html.erb +9 -0
  88. data/app/views/journeybook/admin/redirects/edit.html.erb +2 -0
  89. data/app/views/journeybook/admin/redirects/index.html.erb +15 -0
  90. data/app/views/journeybook/admin/redirects/new.html.erb +2 -0
  91. data/app/views/journeybook/admin/shared/_drag_handle.html.erb +3 -0
  92. data/app/views/journeybook/admin/shared/_errors.html.erb +10 -0
  93. data/app/views/journeybook/admin/sites/_form.html.erb +12 -0
  94. data/app/views/journeybook/admin/sites/edit.html.erb +2 -0
  95. data/app/views/journeybook/admin/sites/index.html.erb +26 -0
  96. data/app/views/journeybook/admin/sites/new.html.erb +2 -0
  97. data/app/views/layouts/journeybook/application.html.erb +57 -0
  98. data/config/importmap.rb +3 -0
  99. data/config/routes.rb +39 -0
  100. data/db/migrate/20260627000001_create_journeybook_sites.rb +13 -0
  101. data/db/migrate/20260627000002_create_journeybook_pages.rb +23 -0
  102. data/db/migrate/20260627000003_create_journeybook_redirects.rb +13 -0
  103. data/db/migrate/20260628000004_add_context_fields_to_journeybook_sites.rb +38 -0
  104. data/db/migrate/20260628000005_create_journeybook_media_assets.rb +24 -0
  105. data/db/migrate/20260629000006_create_journeybook_navigation.rb +28 -0
  106. data/db/migrate/20260731000007_add_open_in_new_window_to_journeybook_navigation_items.rb +5 -0
  107. data/db/migrate/20260731000008_create_journeybook_ai_style_prompts.rb +12 -0
  108. data/db/migrate/20260801000009_add_blog_fields_to_journeybook_pages.rb +9 -0
  109. data/db/migrate/20260801000010_add_knowledge_base_fields_to_journeybook_pages.rb +8 -0
  110. data/db/migrate/20260801000011_add_position_to_journeybook_pages.rb +6 -0
  111. data/lib/generators/journeybook/install/install_generator.rb +72 -0
  112. data/lib/generators/journeybook/install/templates/add_blog_fields_to_journeybook_pages.rb +9 -0
  113. data/lib/generators/journeybook/install/templates/add_context_fields_to_journeybook_sites.rb +38 -0
  114. data/lib/generators/journeybook/install/templates/add_knowledge_base_fields_to_journeybook_pages.rb +8 -0
  115. data/lib/generators/journeybook/install/templates/add_open_in_new_window_to_journeybook_navigation_items.rb +5 -0
  116. data/lib/generators/journeybook/install/templates/add_position_to_journeybook_pages.rb +6 -0
  117. data/lib/generators/journeybook/install/templates/create_journeybook_ai_style_prompts.rb +12 -0
  118. data/lib/generators/journeybook/install/templates/create_journeybook_media_assets.rb +24 -0
  119. data/lib/generators/journeybook/install/templates/create_journeybook_navigation.rb +28 -0
  120. data/lib/generators/journeybook/install/templates/create_journeybook_pages.rb +33 -0
  121. data/lib/generators/journeybook/install/templates/create_journeybook_redirects.rb +13 -0
  122. data/lib/generators/journeybook/install/templates/create_journeybook_sites.rb +13 -0
  123. data/lib/generators/journeybook/install/templates/journeybook.rb +42 -0
  124. data/lib/generators/journeybook/install/templates/pages_controller.rb +3 -0
  125. data/lib/generators/journeybook/install/templates/show.html.erb +10 -0
  126. data/lib/journeybook/component_registry.rb +136 -0
  127. data/lib/journeybook/configuration.rb +55 -0
  128. data/lib/journeybook/engine.rb +19 -0
  129. data/lib/journeybook/page_template_registry.rb +67 -0
  130. data/lib/journeybook/public_page_constraint.rb +23 -0
  131. data/lib/journeybook/version.rb +3 -0
  132. data/lib/journeybook.rb +62 -0
  133. data/lib/tasks/journeybook_tasks.rake +8 -0
  134. metadata +266 -0
@@ -0,0 +1,1556 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the bottom of the
9
+ * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
10
+ * files in this directory. Styles in this file should be added after the last require_* statement.
11
+ * It is generally better to create a new file per style scope.
12
+ *
13
+ *= require_tree .
14
+ *= require_self
15
+ */
16
+
17
+ /* ===================================================================
18
+ JOURNEYBOOK ADMIN — DESIGN SYSTEM
19
+ Light, professional, extendable.
20
+ Override any --jb-* custom property in your host app to customise.
21
+ =================================================================== */
22
+
23
+ /* ---- 1. TOKENS ---------------------------------------------------- */
24
+
25
+ :root {
26
+ color-scheme: light;
27
+
28
+ /* Surfaces */
29
+ --jb-bg: #f8fafc; /* page chrome */
30
+ --jb-surface: #ffffff; /* card / panel */
31
+ --jb-surface-2: #f1f5f9; /* subtle alternate surface, hover fill */
32
+
33
+ /* Borders */
34
+ --jb-border: #e2e8f0; /* default border */
35
+ --jb-border-2: #cbd5e1; /* stronger border, focus ring */
36
+
37
+ /* Text */
38
+ --jb-text: #0f172a; /* primary */
39
+ --jb-text-2: #475569; /* secondary / labels */
40
+ --jb-text-3: #94a3b8; /* muted / placeholders */
41
+
42
+ /* Accent — primary action colour */
43
+ --jb-accent: #0f172a;
44
+ --jb-accent-hover: #1e293b;
45
+
46
+ /* Semantic */
47
+ --jb-danger: #dc2626;
48
+ --jb-danger-bg: #fef2f2;
49
+ --jb-danger-border: #fca5a5;
50
+ --jb-success: #16a34a;
51
+ --jb-success-bg: #f0fdf4;
52
+ --jb-success-border: #86efac;
53
+ --jb-warning: #b45309;
54
+ --jb-warning-bg: #fffbeb;
55
+ --jb-warning-border: #fde68a;
56
+
57
+ /* Elevation */
58
+ --jb-shadow-xs: 0 1px 2px rgba(0, 0, 0, .05);
59
+ --jb-shadow-sm: 0 1px 3px rgba(0, 0, 0, .08), 0 1px 2px -1px rgba(0, 0, 0, .06);
60
+
61
+ /* Shape */
62
+ --jb-radius: 0.5rem;
63
+ --jb-radius-sm: 0.375rem;
64
+ --jb-radius-lg: 0.75rem;
65
+
66
+ /* Layout */
67
+ --jb-sidebar-w: 15rem;
68
+ --jb-main-max: 1200px;
69
+ --jb-editor-topbar-h: 3.25rem;
70
+ }
71
+
72
+ /* ---- 2. RESET & BASE ---------------------------------------------- */
73
+
74
+ *, *::before, *::after { box-sizing: border-box; }
75
+
76
+ body {
77
+ margin: 0;
78
+ background: var(--jb-bg);
79
+ color: var(--jb-text);
80
+ font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
81
+ font-size: 14px;
82
+ line-height: 1.5;
83
+ -webkit-font-smoothing: antialiased;
84
+ }
85
+
86
+ a { color: inherit; }
87
+
88
+ code {
89
+ background: var(--jb-surface-2);
90
+ border: 1px solid var(--jb-border);
91
+ border-radius: 0.25rem;
92
+ color: var(--jb-text-2);
93
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
94
+ font-size: 0.8125rem;
95
+ padding: 0.1em 0.35em;
96
+ }
97
+
98
+ /* ---- 3. SHELL ----------------------------------------------------- */
99
+
100
+ .jb-shell {
101
+ display: grid;
102
+ grid-template-columns: var(--jb-sidebar-w) 1fr;
103
+ min-height: 100vh;
104
+ }
105
+
106
+ /* ---- 4. SIDEBAR --------------------------------------------------- */
107
+
108
+ .jb-sidebar {
109
+ background: var(--jb-surface);
110
+ border-right: 1px solid var(--jb-border);
111
+ display: flex;
112
+ flex-direction: column;
113
+ height: 100vh;
114
+ overflow-y: auto;
115
+ padding: 1.25rem 0.875rem;
116
+ position: sticky;
117
+ top: 0;
118
+ }
119
+
120
+ .jb-brand {
121
+ align-items: center;
122
+ color: var(--jb-text);
123
+ display: flex;
124
+ font-size: 0.875rem;
125
+ font-weight: 600;
126
+ gap: 0.5rem;
127
+ letter-spacing: -0.01em;
128
+ margin-bottom: 1.25rem;
129
+ padding: 0 0.25rem;
130
+ text-decoration: none;
131
+ }
132
+
133
+ .jb-brand-logo {
134
+ border-radius: 0.45rem;
135
+ box-shadow: 0 10px 24px rgba(15, 23, 42, .16);
136
+ flex-shrink: 0;
137
+ height: 2rem;
138
+ width: 2rem;
139
+ }
140
+
141
+ /* ---- 5. NAVIGATION ------------------------------------------------ */
142
+
143
+ .jb-nav {
144
+ display: flex;
145
+ flex: 1;
146
+ flex-direction: column;
147
+ gap: 0.125rem;
148
+ }
149
+
150
+ .jb-nav a {
151
+ border-radius: var(--jb-radius-sm);
152
+ color: var(--jb-text-2);
153
+ font-size: 0.875rem;
154
+ font-weight: 500;
155
+ padding: 0.45rem 0.625rem;
156
+ text-decoration: none;
157
+ transition: background 0.1s, color 0.1s;
158
+ }
159
+
160
+ .jb-nav a:hover {
161
+ background: var(--jb-surface-2);
162
+ color: var(--jb-text);
163
+ }
164
+
165
+ .jb-nav a.is-active {
166
+ background: var(--jb-surface-2);
167
+ color: var(--jb-text);
168
+ font-weight: 600;
169
+ }
170
+
171
+ /* ---- 6. SITE SWITCHER --------------------------------------------- */
172
+
173
+ .jb-context {
174
+ border-top: 1px solid var(--jb-border);
175
+ display: grid;
176
+ gap: 0.375rem;
177
+ margin-top: auto;
178
+ padding-top: 1rem;
179
+ }
180
+
181
+ .jb-context label {
182
+ color: var(--jb-text-3);
183
+ font-size: 0.6875rem;
184
+ font-weight: 600;
185
+ letter-spacing: 0.08em;
186
+ text-transform: uppercase;
187
+ }
188
+
189
+ .jb-context select {
190
+ appearance: none;
191
+ background: var(--jb-surface-2) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%2394a3b8' stroke-width='2'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E") no-repeat right 0.5rem center;
192
+ border: 1px solid var(--jb-border);
193
+ border-radius: var(--jb-radius-sm);
194
+ color: var(--jb-text);
195
+ font: inherit;
196
+ padding: 0.45rem 2rem 0.45rem 0.5rem;
197
+ width: 100%;
198
+ }
199
+
200
+ .jb-context select:focus {
201
+ border-color: var(--jb-border-2);
202
+ outline: 2px solid rgba(15, 23, 42, .1);
203
+ outline-offset: -1px;
204
+ }
205
+
206
+ /* ---- 7. MAIN CONTENT ---------------------------------------------- */
207
+
208
+ .jb-main {
209
+ margin: 0 auto;
210
+ max-width: var(--jb-main-max);
211
+ padding: 2rem;
212
+ width: 100%;
213
+ }
214
+
215
+ .jb-main-wide { max-width: none; }
216
+
217
+ /* ---- 8. PAGE HEADER ----------------------------------------------- */
218
+
219
+ .jb-header {
220
+ align-items: flex-start;
221
+ border-bottom: 1px solid var(--jb-border);
222
+ display: flex;
223
+ gap: 1rem;
224
+ justify-content: space-between;
225
+ margin-bottom: 1.5rem;
226
+ padding-bottom: 1.25rem;
227
+ }
228
+
229
+ .jb-eyebrow {
230
+ color: var(--jb-text-3);
231
+ font-size: 0.6875rem;
232
+ font-weight: 600;
233
+ letter-spacing: 0.1em;
234
+ margin: 0 0 0.3rem;
235
+ text-transform: uppercase;
236
+ }
237
+
238
+ .jb-title {
239
+ font-size: clamp(1.35rem, 2vw, 1.875rem);
240
+ font-weight: 700;
241
+ letter-spacing: -0.03em;
242
+ line-height: 1.1;
243
+ margin: 0;
244
+ }
245
+
246
+ .jb-subtitle {
247
+ color: var(--jb-text-2);
248
+ font-size: 0.875rem;
249
+ line-height: 1.6;
250
+ margin: 0.4rem 0 0;
251
+ max-width: 48rem;
252
+ }
253
+
254
+ /* ---- 9. SPACING UTILITIES ----------------------------------------- */
255
+
256
+ .jb-section { margin-top: 1.25rem; }
257
+ .jb-section-lg { margin-top: 2rem; }
258
+
259
+ /* ---- 10. GRIDS ---------------------------------------------------- */
260
+
261
+ .jb-grid { display: grid; gap: 0.875rem; }
262
+ .jb-grid-2 { grid-template-columns: minmax(0, 1fr) minmax(18rem, 22rem); }
263
+ .jb-grid-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
264
+
265
+ .jb-ai-layout {
266
+ align-items: start;
267
+ gap: 1.25rem;
268
+ }
269
+
270
+ /* ---- 11. CARDS ---------------------------------------------------- */
271
+
272
+ .jb-card {
273
+ background: var(--jb-surface);
274
+ border: 1px solid var(--jb-border);
275
+ border-radius: var(--jb-radius-lg);
276
+ box-shadow: var(--jb-shadow-xs);
277
+ padding: 1.25rem;
278
+ }
279
+
280
+ /* Flush card — no padding; use for edge-to-edge tables */
281
+ .jb-card-flush {
282
+ overflow: hidden;
283
+ padding: 0;
284
+ }
285
+
286
+ /* Card-level header is tighter than the page-level header */
287
+ .jb-card .jb-header {
288
+ margin-bottom: 1rem;
289
+ padding-bottom: 1rem;
290
+ }
291
+
292
+ .jb-card-title {
293
+ font-size: 0.9375rem;
294
+ font-weight: 600;
295
+ letter-spacing: -0.01em;
296
+ margin: 0;
297
+ }
298
+
299
+ .jb-ai-card { gap: 1.125rem; }
300
+ .jb-ai-fields { gap: 0.75rem 0.875rem; }
301
+
302
+ .jb-reference {
303
+ align-self: start;
304
+ padding: 1rem;
305
+ }
306
+
307
+ .jb-reference .jb-subtitle { margin-top: 0.25rem; }
308
+
309
+ .jb-reference-list {
310
+ gap: 0.625rem;
311
+ margin-top: 0.875rem;
312
+ }
313
+
314
+ .jb-reference .jb-component {
315
+ gap: 0.5rem;
316
+ padding: 0.875rem;
317
+ }
318
+
319
+ .jb-reference-stack {
320
+ align-self: start;
321
+ display: grid;
322
+ gap: 0.875rem;
323
+ }
324
+
325
+ .jb-page-editor-layout {
326
+ align-items: start;
327
+ display: grid;
328
+ gap: 1.25rem;
329
+ grid-template-columns: minmax(0, 1fr) minmax(18rem, 24rem);
330
+ }
331
+
332
+ .jb-page-editor-card {
333
+ gap: 1.25rem;
334
+ }
335
+
336
+ .jb-page-editor-layout .jb-reference-stack {
337
+ position: sticky;
338
+ top: 2rem;
339
+ }
340
+
341
+ /* ---- 12. STAT CARDS ----------------------------------------------- */
342
+
343
+ .jb-stat {
344
+ align-items: flex-start;
345
+ display: flex;
346
+ flex-direction: column;
347
+ gap: 0.25rem;
348
+ }
349
+
350
+ .jb-stat strong {
351
+ color: var(--jb-text);
352
+ display: block;
353
+ font-size: 1.875rem;
354
+ font-weight: 700;
355
+ letter-spacing: -0.04em;
356
+ line-height: 1;
357
+ }
358
+
359
+ .jb-stat-label {
360
+ color: var(--jb-text-2);
361
+ font-size: 0.8125rem;
362
+ font-weight: 500;
363
+ }
364
+
365
+ /* ---- 13. DATA TABLE ----------------------------------------------- */
366
+
367
+ .jb-table {
368
+ border-collapse: collapse;
369
+ width: 100%;
370
+ }
371
+
372
+ .jb-table th,
373
+ .jb-table td {
374
+ border-bottom: 1px solid var(--jb-border);
375
+ padding: 0.75rem 1.25rem;
376
+ text-align: left;
377
+ vertical-align: middle;
378
+ }
379
+
380
+ .jb-table th {
381
+ color: var(--jb-text-3);
382
+ font-size: 0.6875rem;
383
+ font-weight: 600;
384
+ letter-spacing: 0.07em;
385
+ text-transform: uppercase;
386
+ white-space: nowrap;
387
+ }
388
+
389
+ .jb-table td { color: var(--jb-text); font-size: 0.875rem; }
390
+ .jb-table tbody tr:last-child td { border-bottom: none; }
391
+ .jb-table tbody tr:hover td { background: var(--jb-surface-2); }
392
+
393
+ /* ---- 14. FORMS ---------------------------------------------------- */
394
+
395
+ .jb-form { display: grid; gap: 1rem; }
396
+ .jb-fields { display: grid; gap: 0.875rem; grid-template-columns: repeat(2, minmax(0, 1fr)); }
397
+ .jb-field { display: grid; gap: 0.375rem; }
398
+
399
+ .jb-field label {
400
+ color: var(--jb-text-2);
401
+ font-size: 0.75rem;
402
+ font-weight: 600;
403
+ letter-spacing: 0.04em;
404
+ text-transform: uppercase;
405
+ }
406
+
407
+ .jb-field input,
408
+ .jb-field select,
409
+ .jb-field textarea {
410
+ appearance: none;
411
+ background: var(--jb-surface);
412
+ border: 1px solid var(--jb-border);
413
+ border-radius: var(--jb-radius-sm);
414
+ color: var(--jb-text);
415
+ font: inherit;
416
+ font-size: 0.875rem;
417
+ padding: 0.5625rem 0.75rem;
418
+ transition: border-color 0.15s, box-shadow 0.15s;
419
+ width: 100%;
420
+ }
421
+
422
+ .jb-field input::placeholder,
423
+ .jb-field textarea::placeholder { color: var(--jb-text-3); }
424
+
425
+ .jb-field input:focus,
426
+ .jb-field select:focus,
427
+ .jb-field textarea:focus {
428
+ border-color: var(--jb-border-2);
429
+ box-shadow: 0 0 0 3px rgba(15, 23, 42, .08);
430
+ outline: none;
431
+ }
432
+
433
+ .jb-field select {
434
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%2394a3b8' stroke-width='2'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
435
+ background-position: right 0.625rem center;
436
+ background-repeat: no-repeat;
437
+ padding-right: 2rem;
438
+ }
439
+
440
+ .jb-field textarea { min-height: 10rem; resize: vertical; }
441
+ .jb-field-short textarea { min-height: 7rem; } /* meta description */
442
+ .jb-prompt textarea { min-height: 10rem; } /* AI prompt */
443
+
444
+ .jb-checkbox-field {
445
+ align-items: center;
446
+ color: var(--jb-text-2);
447
+ display: inline-flex;
448
+ font-size: 0.8125rem;
449
+ font-weight: 600;
450
+ gap: 0.5rem;
451
+ }
452
+
453
+ .jb-checkbox-field input { accent-color: var(--jb-accent); height: 1rem; width: 1rem; }
454
+
455
+ .jb-markdown textarea {
456
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
457
+ font-size: 0.8125rem;
458
+ line-height: 1.6;
459
+ }
460
+
461
+ .jb-source-editor textarea {
462
+ min-height: calc(100vh - 16rem);
463
+ resize: vertical;
464
+ }
465
+
466
+ .jb-help {
467
+ color: var(--jb-text-3);
468
+ font-size: 0.75rem;
469
+ line-height: 1.5;
470
+ }
471
+
472
+ /* ---- 15. ACTIONS & BUTTONS ---------------------------------------- */
473
+
474
+ .jb-actions {
475
+ align-items: center;
476
+ display: flex;
477
+ flex-wrap: wrap;
478
+ gap: 0.5rem;
479
+ }
480
+
481
+ .jb-button,
482
+ .jb-link-button,
483
+ input[type="submit"].jb-button,
484
+ button.jb-button {
485
+ align-items: center;
486
+ appearance: none;
487
+ background: var(--jb-accent);
488
+ border: 1px solid var(--jb-accent);
489
+ border-radius: var(--jb-radius-sm);
490
+ color: #ffffff;
491
+ cursor: pointer;
492
+ display: inline-flex;
493
+ font: inherit;
494
+ font-size: 0.8125rem;
495
+ font-weight: 600;
496
+ gap: 0.375rem;
497
+ line-height: 1;
498
+ padding: 0.5625rem 0.875rem;
499
+ text-decoration: none;
500
+ transition: background 0.1s, border-color 0.1s;
501
+ white-space: nowrap;
502
+ }
503
+
504
+ .jb-button:hover,
505
+ .jb-link-button:hover,
506
+ input[type="submit"].jb-button:hover,
507
+ button.jb-button:hover {
508
+ background: var(--jb-accent-hover);
509
+ border-color: var(--jb-accent-hover);
510
+ }
511
+
512
+ .jb-button-secondary {
513
+ background: var(--jb-surface);
514
+ border-color: var(--jb-border);
515
+ color: var(--jb-text);
516
+ }
517
+
518
+ .jb-button-secondary:hover {
519
+ background: var(--jb-surface-2);
520
+ border-color: var(--jb-border-2);
521
+ color: var(--jb-text);
522
+ }
523
+
524
+ .jb-button-danger {
525
+ background: var(--jb-surface);
526
+ border-color: var(--jb-danger-border);
527
+ color: var(--jb-danger);
528
+ }
529
+
530
+ .jb-button-danger:hover {
531
+ background: var(--jb-danger-bg);
532
+ border-color: var(--jb-danger);
533
+ }
534
+
535
+ /* ---- 16. BADGES --------------------------------------------------- */
536
+
537
+ .jb-badge {
538
+ background: var(--jb-surface-2);
539
+ border: 1px solid var(--jb-border);
540
+ border-radius: 0.3rem;
541
+ color: var(--jb-text-2);
542
+ display: inline-flex;
543
+ font-size: 0.6875rem;
544
+ font-weight: 500;
545
+ line-height: 1;
546
+ padding: 0.25rem 0.5rem;
547
+ white-space: nowrap;
548
+ }
549
+
550
+ .jb-badge-published {
551
+ background: var(--jb-success-bg);
552
+ border-color: var(--jb-success-border);
553
+ color: var(--jb-success);
554
+ }
555
+
556
+ .jb-badge-draft {
557
+ background: var(--jb-warning-bg);
558
+ border-color: var(--jb-warning-border);
559
+ color: var(--jb-warning);
560
+ }
561
+
562
+ /* ---- 17. FLASH MESSAGES ------------------------------------------- */
563
+
564
+ .jb-notice,
565
+ .jb-alert {
566
+ backdrop-filter: blur(12px);
567
+ border-radius: var(--jb-radius);
568
+ box-shadow: var(--jb-shadow-sm);
569
+ font-size: 0.875rem;
570
+ margin: 0;
571
+ padding: 0.625rem 0.875rem;
572
+ }
573
+
574
+ .jb-flashes {
575
+ display: grid;
576
+ gap: 0.5rem;
577
+ max-width: min(22rem, calc(100vw - 2rem));
578
+ pointer-events: none;
579
+ position: fixed;
580
+ right: 1.25rem;
581
+ top: 1.25rem;
582
+ z-index: 100;
583
+ }
584
+
585
+ .jb-flashes > * { pointer-events: auto; }
586
+
587
+ .jb-notice {
588
+ background: color-mix(in srgb, var(--jb-success-bg) 88%, transparent);
589
+ border: 1px solid color-mix(in srgb, var(--jb-success-border) 72%, transparent);
590
+ color: var(--jb-success);
591
+ }
592
+
593
+ .jb-alert {
594
+ background: color-mix(in srgb, var(--jb-danger-bg) 88%, transparent);
595
+ border: 1px solid color-mix(in srgb, var(--jb-danger-border) 72%, transparent);
596
+ color: var(--jb-danger);
597
+ }
598
+
599
+ /* ---- 18. FORM ERRORS ---------------------------------------------- */
600
+
601
+ .jb-errors {
602
+ background: var(--jb-danger-bg);
603
+ border: 1px solid var(--jb-danger-border);
604
+ border-radius: var(--jb-radius);
605
+ color: var(--jb-danger);
606
+ font-size: 0.875rem;
607
+ padding: 0.875rem 1rem;
608
+ }
609
+
610
+ .jb-errors ul { margin: 0.375rem 0 0; padding-left: 1.25rem; }
611
+ .jb-errors li { margin: 0.125rem 0; }
612
+
613
+ /* ---- 19. COMPONENT LIBRARY ---------------------------------------- */
614
+
615
+ .jb-component { display: grid; gap: 0.625rem; }
616
+
617
+ .jb-component-library {
618
+ align-items: start;
619
+ display: grid;
620
+ gap: 1.5rem;
621
+ grid-template-columns: 18rem minmax(0, 1fr);
622
+ }
623
+
624
+ .jb-component-picker {
625
+ align-self: start;
626
+ position: sticky;
627
+ top: 2rem;
628
+ }
629
+
630
+ .jb-component-nav {
631
+ display: grid;
632
+ gap: 0.375rem;
633
+ margin-top: 0.875rem;
634
+ }
635
+
636
+ .jb-component-search {
637
+ color: var(--jb-text-2);
638
+ display: grid;
639
+ font-size: 0.75rem;
640
+ font-weight: 600;
641
+ gap: 0.25rem;
642
+ margin-top: 0.875rem;
643
+ }
644
+
645
+ .jb-component-search input {
646
+ background: var(--jb-surface);
647
+ border: 1px solid var(--jb-border);
648
+ border-radius: var(--jb-radius-sm);
649
+ color: var(--jb-text);
650
+ font: inherit;
651
+ padding: 0.5rem 0.625rem;
652
+ }
653
+
654
+ .jb-component-nav-item {
655
+ align-items: stretch;
656
+ display: flex;
657
+ gap: 0.375rem;
658
+ }
659
+
660
+ .jb-component-nav-item > a {
661
+ flex: 1;
662
+ }
663
+
664
+ .jb-component-nav-item form {
665
+ display: flex;
666
+ }
667
+
668
+ .jb-component-nav a {
669
+ border: 1px solid transparent;
670
+ border-radius: var(--jb-radius-sm);
671
+ color: var(--jb-text-2);
672
+ display: grid;
673
+ gap: 0.125rem;
674
+ padding: 0.625rem;
675
+ text-decoration: none;
676
+ }
677
+
678
+ .jb-component-nav a[hidden] {
679
+ display: none;
680
+ }
681
+
682
+ .jb-component-nav-item[hidden] {
683
+ display: none;
684
+ }
685
+
686
+ .jb-component-add-button {
687
+ align-items: center;
688
+ background: var(--jb-surface);
689
+ border: 1px solid var(--jb-border);
690
+ border-radius: var(--jb-radius-sm);
691
+ color: var(--jb-text-2);
692
+ cursor: pointer;
693
+ display: inline-flex;
694
+ font-size: 1.25rem;
695
+ height: 100%;
696
+ justify-content: center;
697
+ line-height: 1;
698
+ padding: 0;
699
+ width: 2.25rem;
700
+ }
701
+
702
+ .jb-component-add-button:hover {
703
+ background: var(--jb-accent);
704
+ border-color: var(--jb-accent);
705
+ color: #ffffff;
706
+ }
707
+
708
+ .jb-component-nav a:hover,
709
+ .jb-component-nav a.is-active {
710
+ background: var(--jb-surface-2);
711
+ border-color: var(--jb-border);
712
+ color: var(--jb-text);
713
+ }
714
+
715
+ .jb-component-nav strong {
716
+ color: inherit;
717
+ font-size: 0.875rem;
718
+ font-weight: 600;
719
+ }
720
+
721
+ .jb-component-nav span {
722
+ color: var(--jb-text-2);
723
+ display: -webkit-box;
724
+ font-size: 0.75rem;
725
+ line-clamp: 2;
726
+ overflow: hidden;
727
+ -webkit-box-orient: vertical;
728
+ -webkit-line-clamp: 2;
729
+ }
730
+
731
+ .jb-component-preview-card .jb-header { align-items: center; }
732
+
733
+ .jb-component-preview {
734
+ border: 0;
735
+ min-height: clamp(34rem, 72vh, 56rem);
736
+ width: 100%;
737
+ }
738
+
739
+ .jb-component-add-page {
740
+ align-items: start;
741
+ display: grid;
742
+ gap: 1.5rem;
743
+ grid-template-columns: 20rem minmax(0, 1fr);
744
+ }
745
+
746
+ .jb-component-add-sidebar-footer,
747
+ .jb-component-add-footer {
748
+ border-top: 1px solid var(--jb-border);
749
+ margin-top: 1rem;
750
+ padding-top: 1rem;
751
+ }
752
+
753
+ .jb-component-add-preview {
754
+ display: grid;
755
+ gap: 1rem;
756
+ }
757
+
758
+ .jb-component-add-preview-frame {
759
+ border: 0;
760
+ min-height: clamp(34rem, 70vh, 54rem);
761
+ width: 100%;
762
+ }
763
+
764
+ /* ---- PAGE EDITOR --------------------------------------------------- */
765
+
766
+ .jb-editor-main {
767
+ margin: 0;
768
+ max-width: none;
769
+ padding: 0;
770
+ }
771
+
772
+ .jb-page-editor {
773
+ display: grid;
774
+ grid-template-columns: 22rem minmax(0, 1fr);
775
+ height: 100vh;
776
+ overflow: hidden;
777
+ }
778
+
779
+ .jb-editor-sidebar {
780
+ background: var(--jb-surface);
781
+ border-right: 1px solid var(--jb-border);
782
+ display: flex;
783
+ flex-direction: column;
784
+ min-height: 0;
785
+ min-width: 0;
786
+ overflow-y: auto;
787
+ }
788
+
789
+ .jb-editor-pagebar,
790
+ .jb-editor-preview-topbar {
791
+ align-items: center;
792
+ background: var(--jb-surface);
793
+ border-bottom: 1px solid var(--jb-border);
794
+ display: flex;
795
+ flex-shrink: 0;
796
+ height: var(--jb-editor-topbar-h);
797
+ padding: 0 0.75rem;
798
+ }
799
+
800
+ .jb-page-switcher {
801
+ position: relative;
802
+ width: 100%;
803
+ }
804
+
805
+ .jb-page-switcher summary {
806
+ align-items: center;
807
+ border-radius: var(--jb-radius-sm);
808
+ cursor: pointer;
809
+ display: flex;
810
+ font-size: 0.875rem;
811
+ font-weight: 700;
812
+ justify-content: space-between;
813
+ list-style: none;
814
+ min-width: 0;
815
+ padding: 0.5rem 0.625rem;
816
+ }
817
+
818
+ .jb-page-switcher summary::-webkit-details-marker { display: none; }
819
+
820
+ .jb-page-switcher summary::after {
821
+ color: var(--jb-text-3);
822
+ content: "▼";
823
+ flex-shrink: 0;
824
+ font-size: 0.75rem;
825
+ margin-left: 0.5rem;
826
+ }
827
+
828
+ .jb-page-switcher summary:hover {
829
+ background: var(--jb-surface-2);
830
+ }
831
+
832
+ .jb-page-switcher summary span {
833
+ overflow: hidden;
834
+ text-overflow: ellipsis;
835
+ white-space: nowrap;
836
+ }
837
+
838
+ .jb-page-switcher-menu {
839
+ background: var(--jb-surface);
840
+ border: 1px solid var(--jb-border);
841
+ border-radius: var(--jb-radius);
842
+ box-shadow: var(--jb-shadow-sm);
843
+ display: grid;
844
+ gap: 0.25rem;
845
+ left: 0;
846
+ max-height: min(26rem, calc(100vh - 5rem));
847
+ overflow-y: auto;
848
+ padding: 0.375rem;
849
+ position: absolute;
850
+ right: 0;
851
+ top: calc(100% + 0.375rem);
852
+ z-index: 10;
853
+ }
854
+
855
+ .jb-page-switcher-menu a {
856
+ border-radius: var(--jb-radius-sm);
857
+ color: var(--jb-text);
858
+ display: grid;
859
+ gap: 0.125rem;
860
+ padding: 0.5rem 0.625rem;
861
+ text-decoration: none;
862
+ }
863
+
864
+ .jb-page-switcher-menu a:hover,
865
+ .jb-page-switcher-menu a.is-active {
866
+ background: var(--jb-surface-2);
867
+ }
868
+
869
+ .jb-page-switcher-menu strong {
870
+ font-size: 0.8125rem;
871
+ font-weight: 700;
872
+ overflow: hidden;
873
+ text-overflow: ellipsis;
874
+ white-space: nowrap;
875
+ }
876
+
877
+ .jb-page-switcher-menu span {
878
+ color: var(--jb-text-2);
879
+ font-size: 0.75rem;
880
+ overflow: hidden;
881
+ text-overflow: ellipsis;
882
+ white-space: nowrap;
883
+ }
884
+
885
+ .jb-editor-tabs {
886
+ background: var(--jb-surface);
887
+ border-bottom: 1px solid var(--jb-border);
888
+ display: grid;
889
+ gap: 0.375rem;
890
+ grid-template-columns: 1fr 1fr;
891
+ padding: 0.75rem;
892
+ position: sticky;
893
+ top: 0;
894
+ z-index: 1;
895
+ }
896
+
897
+ .jb-editor-tabs a {
898
+ border-radius: var(--jb-radius-sm);
899
+ color: var(--jb-text-2);
900
+ font-size: 0.8125rem;
901
+ font-weight: 600;
902
+ padding: 0.5rem 0.625rem;
903
+ text-align: center;
904
+ text-decoration: none;
905
+ }
906
+
907
+ .jb-editor-tabs a:hover,
908
+ .jb-editor-tabs a.is-active {
909
+ background: var(--jb-surface-2);
910
+ color: var(--jb-text);
911
+ }
912
+
913
+ .jb-editor-panel {
914
+ display: grid;
915
+ gap: 1rem;
916
+ padding: 1rem;
917
+ }
918
+
919
+ .jb-editor-panel-footer {
920
+ border-top: 1px solid var(--jb-border);
921
+ padding-top: 1rem;
922
+ }
923
+
924
+ .jb-editor-title,
925
+ .jb-editor-subtitle {
926
+ font-size: 1rem;
927
+ font-weight: 700;
928
+ letter-spacing: -0.02em;
929
+ line-height: 1.2;
930
+ margin: 0;
931
+ }
932
+
933
+ .jb-editor-subtitle {
934
+ font-size: 0.9375rem;
935
+ }
936
+
937
+ .jb-component-instance-list {
938
+ display: grid;
939
+ gap: 0.5rem;
940
+ }
941
+
942
+ .jb-component-instance {
943
+ align-items: start;
944
+ border: 1px solid var(--jb-border);
945
+ border-radius: var(--jb-radius-sm);
946
+ display: grid;
947
+ gap: 0.625rem;
948
+ grid-template-columns: auto 1fr;
949
+ padding: 0.625rem;
950
+ }
951
+
952
+ .jb-component-instance:hover {
953
+ background: var(--jb-surface-2);
954
+ border-color: var(--jb-border-2);
955
+ }
956
+
957
+ .jb-component-instance.is-hidden {
958
+ background: var(--jb-surface-2);
959
+ opacity: 0.65;
960
+ }
961
+
962
+ .jb-component-instance-main {
963
+ display: grid;
964
+ gap: 0.625rem;
965
+ min-width: 0;
966
+ }
967
+
968
+ .jb-component-instance-summary {
969
+ color: var(--jb-text);
970
+ display: grid;
971
+ gap: 0.125rem;
972
+ }
973
+
974
+ .jb-component-instance-list strong {
975
+ font-size: 0.8125rem;
976
+ font-weight: 700;
977
+ }
978
+
979
+ .jb-component-instance-list span {
980
+ color: var(--jb-text-2);
981
+ display: -webkit-box;
982
+ font-size: 0.75rem;
983
+ line-clamp: 2;
984
+ overflow: hidden;
985
+ -webkit-box-orient: vertical;
986
+ -webkit-line-clamp: 2;
987
+ }
988
+
989
+ .jb-component-instance-actions {
990
+ display: flex;
991
+ flex-wrap: wrap;
992
+ gap: 0.375rem;
993
+ }
994
+
995
+ .jb-collection {
996
+ display: grid;
997
+ gap: 0.75rem;
998
+ }
999
+
1000
+ .jb-collection-items {
1001
+ display: grid;
1002
+ gap: 0.625rem;
1003
+ }
1004
+
1005
+ .jb-collection-item {
1006
+ align-items: start;
1007
+ background: var(--jb-surface-2);
1008
+ border: 1px solid var(--jb-border);
1009
+ border-radius: var(--jb-radius-sm);
1010
+ display: grid;
1011
+ gap: 0.625rem;
1012
+ grid-template-columns: auto 1fr auto;
1013
+ margin: 0;
1014
+ padding: 0.75rem;
1015
+ }
1016
+
1017
+ .jb-collection-item legend {
1018
+ color: var(--jb-text-2);
1019
+ font-size: 0.75rem;
1020
+ font-weight: 700;
1021
+ grid-column: 1 / 3;
1022
+ grid-row: 1;
1023
+ padding: 0;
1024
+ }
1025
+
1026
+ .jb-collection-remove {
1027
+ align-items: center;
1028
+ background: var(--jb-danger-bg);
1029
+ border: 1px solid var(--jb-danger-border);
1030
+ border-radius: 999px;
1031
+ color: var(--jb-danger);
1032
+ cursor: pointer;
1033
+ display: inline-flex;
1034
+ font-size: 1.125rem;
1035
+ grid-column: 3;
1036
+ grid-row: 1;
1037
+ height: 1.5rem;
1038
+ justify-content: center;
1039
+ line-height: 1;
1040
+ padding: 0;
1041
+ width: 1.5rem;
1042
+ }
1043
+
1044
+ .jb-collection-remove:hover {
1045
+ background: var(--jb-danger);
1046
+ border-color: var(--jb-danger);
1047
+ color: var(--jb-surface);
1048
+ }
1049
+
1050
+ .jb-collection-remove:disabled {
1051
+ cursor: not-allowed;
1052
+ opacity: 0.45;
1053
+ }
1054
+
1055
+ .jb-collection-fields {
1056
+ display: grid;
1057
+ gap: 0.625rem;
1058
+ grid-column: 2 / -1;
1059
+ grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
1060
+ }
1061
+
1062
+ .jb-collection-fields label {
1063
+ color: var(--jb-text-2);
1064
+ display: grid;
1065
+ font-size: 0.75rem;
1066
+ font-weight: 600;
1067
+ gap: 0.25rem;
1068
+ }
1069
+
1070
+ .jb-collection-fields input,
1071
+ .jb-collection-fields textarea {
1072
+ background: var(--jb-surface);
1073
+ border: 1px solid var(--jb-border);
1074
+ border-radius: var(--jb-radius-sm);
1075
+ color: var(--jb-text);
1076
+ font: inherit;
1077
+ padding: 0.5rem 0.625rem;
1078
+ width: 100%;
1079
+ }
1080
+
1081
+ .jb-drag-cell { width: 1%; }
1082
+
1083
+ .jb-sortable-list {
1084
+ display: grid;
1085
+ gap: 0.5rem;
1086
+ padding: 0.75rem;
1087
+ }
1088
+
1089
+ .jb-sortable-item {
1090
+ align-items: center;
1091
+ background: var(--jb-surface);
1092
+ border: 1px solid var(--jb-border);
1093
+ border-radius: var(--jb-radius-sm);
1094
+ display: grid;
1095
+ gap: 0.75rem;
1096
+ grid-template-columns: auto 1fr auto;
1097
+ padding: 0.75rem;
1098
+ }
1099
+
1100
+ .jb-sortable-item:hover {
1101
+ background: var(--jb-surface-2);
1102
+ border-color: var(--jb-border-2);
1103
+ }
1104
+
1105
+ .jb-sortable-item-body {
1106
+ display: grid;
1107
+ gap: 0.15rem;
1108
+ min-width: 0;
1109
+ }
1110
+
1111
+ .jb-sortable-item-body strong {
1112
+ font-size: 0.875rem;
1113
+ }
1114
+
1115
+ .jb-sortable-item-body small {
1116
+ color: var(--jb-text-3);
1117
+ font-size: 0.75rem;
1118
+ }
1119
+
1120
+ .jb-drag-handle {
1121
+ align-items: center;
1122
+ color: var(--jb-text-3);
1123
+ cursor: grab;
1124
+ display: inline-flex;
1125
+ flex-shrink: 0;
1126
+ height: 1.75rem;
1127
+ justify-content: center;
1128
+ touch-action: none;
1129
+ user-select: none;
1130
+ width: 1.25rem;
1131
+ }
1132
+
1133
+ .jb-drag-handle:active { cursor: grabbing; }
1134
+ .jb-drag-handle svg { fill: currentColor; height: 1rem; width: 0.75rem; pointer-events: none; }
1135
+ [data-sortable-item].is-dragging {
1136
+ opacity: 0.45;
1137
+ outline: 1px dashed var(--jb-border-2);
1138
+ }
1139
+
1140
+ .jb-component-instance-actions form {
1141
+ display: inline-flex;
1142
+ }
1143
+
1144
+ .jb-component-instance-actions .jb-link-button {
1145
+ background: var(--jb-surface);
1146
+ border-color: var(--jb-border);
1147
+ color: var(--jb-text);
1148
+ }
1149
+
1150
+ .jb-component-instance-actions .jb-link-button:hover {
1151
+ background: var(--jb-surface-2);
1152
+ border-color: var(--jb-border-2);
1153
+ }
1154
+
1155
+ .jb-link-button-small {
1156
+ font-size: 0.75rem;
1157
+ padding: 0.375rem 0.5rem;
1158
+ }
1159
+
1160
+ .jb-link-button-danger {
1161
+ border-color: var(--jb-danger-border) !important;
1162
+ color: var(--jb-danger) !important;
1163
+ background: transparent !important;
1164
+ }
1165
+
1166
+ .jb-link-button-danger:hover {
1167
+ border-color: var(--jb-danger) !important;
1168
+ }
1169
+
1170
+ .jb-link-button:disabled,
1171
+ .jb-link-button[disabled] {
1172
+ cursor: not-allowed;
1173
+ opacity: 0.45;
1174
+ }
1175
+
1176
+ .jb-component-editor {
1177
+ gap: 1rem;
1178
+ }
1179
+
1180
+ .jb-component-editor-actions {
1181
+ background: var(--jb-surface);
1182
+ border-top: 1px solid var(--jb-border);
1183
+ bottom: 0;
1184
+ margin: 0 -1rem -1rem;
1185
+ padding: 1rem;
1186
+ position: sticky;
1187
+ z-index: 1;
1188
+ }
1189
+
1190
+ .jb-component-editor-actions .jb-button {
1191
+ flex: 1 1 0;
1192
+ justify-content: center;
1193
+ }
1194
+
1195
+ .jb-editor-back {
1196
+ align-items: center;
1197
+ color: var(--jb-text-2);
1198
+ display: inline-flex;
1199
+ font-size: 0.8125rem;
1200
+ font-weight: 600;
1201
+ text-decoration: none;
1202
+ }
1203
+
1204
+ .jb-editor-back:hover {
1205
+ color: var(--jb-text);
1206
+ }
1207
+
1208
+ .jb-editor-textarea-short {
1209
+ min-height: 6rem;
1210
+ }
1211
+
1212
+ .jb-url-editor {
1213
+ display: grid;
1214
+ gap: 0.5rem;
1215
+ }
1216
+
1217
+ .jb-url-editor label {
1218
+ color: var(--jb-text-2);
1219
+ display: grid;
1220
+ font-size: 0.75rem;
1221
+ font-weight: 600;
1222
+ gap: 0.25rem;
1223
+ }
1224
+
1225
+ .jb-icon-editor {
1226
+ display: grid;
1227
+ gap: 0.375rem;
1228
+ grid-template-columns: repeat(2, minmax(0, 1fr));
1229
+ margin-top: 0.375rem;
1230
+ }
1231
+
1232
+ .jb-icon-editor input,
1233
+ .jb-icon-editor select {
1234
+ min-width: 0;
1235
+ }
1236
+
1237
+ .jb-image-picker-trigger {
1238
+ align-items: center;
1239
+ background: var(--jb-surface);
1240
+ border: 1px dashed var(--jb-border-2);
1241
+ border-radius: var(--jb-radius-sm);
1242
+ color: var(--jb-text);
1243
+ cursor: pointer;
1244
+ display: flex;
1245
+ font: inherit;
1246
+ font-size: 0.8125rem;
1247
+ font-weight: 600;
1248
+ gap: 0.625rem;
1249
+ min-height: 3rem;
1250
+ padding: 0.375rem 0.625rem;
1251
+ text-align: left;
1252
+ width: 100%;
1253
+ }
1254
+
1255
+ .jb-image-picker-trigger:hover {
1256
+ background: var(--jb-surface-2);
1257
+ border-color: var(--jb-accent);
1258
+ }
1259
+
1260
+ .jb-image-picker-preview {
1261
+ border-radius: calc(var(--jb-radius-sm) - 0.125rem);
1262
+ height: 2.25rem;
1263
+ object-fit: cover;
1264
+ width: 3.5rem;
1265
+ }
1266
+
1267
+ .jb-image-picker-modal {
1268
+ background: var(--jb-surface);
1269
+ border: 1px solid var(--jb-border);
1270
+ border-radius: var(--jb-radius);
1271
+ box-shadow: var(--jb-shadow-lg);
1272
+ color: var(--jb-text);
1273
+ margin: auto;
1274
+ max-height: min(42rem, calc(100vh - 2rem));
1275
+ max-width: 54rem;
1276
+ padding: 0;
1277
+ width: calc(100% - 2rem);
1278
+ }
1279
+
1280
+ .jb-image-picker-modal::backdrop {
1281
+ background: rgb(0 0 0 / 45%);
1282
+ }
1283
+
1284
+ .jb-image-picker-modal-header,
1285
+ .jb-image-picker-modal-footer {
1286
+ align-items: center;
1287
+ display: flex;
1288
+ justify-content: space-between;
1289
+ padding: 1rem 1.25rem;
1290
+ }
1291
+
1292
+ .jb-image-picker-modal-header {
1293
+ border-bottom: 1px solid var(--jb-border);
1294
+ }
1295
+
1296
+ .jb-image-picker-modal-header h2 {
1297
+ font-size: 1rem;
1298
+ margin: 0.125rem 0 0;
1299
+ }
1300
+
1301
+ .jb-image-picker-close {
1302
+ align-items: center;
1303
+ background: transparent;
1304
+ border: 0;
1305
+ border-radius: 999px;
1306
+ color: var(--jb-text-2);
1307
+ cursor: pointer;
1308
+ display: inline-flex;
1309
+ font-size: 1.5rem;
1310
+ height: 2rem;
1311
+ justify-content: center;
1312
+ padding: 0;
1313
+ width: 2rem;
1314
+ }
1315
+
1316
+ .jb-image-picker-close:hover {
1317
+ background: var(--jb-surface-2);
1318
+ color: var(--jb-text);
1319
+ }
1320
+
1321
+ .jb-image-picker-grid {
1322
+ display: grid;
1323
+ gap: 0.75rem;
1324
+ grid-template-columns: repeat(auto-fill, minmax(10rem, 1fr));
1325
+ max-height: 30rem;
1326
+ overflow-y: auto;
1327
+ padding: 1.25rem;
1328
+ }
1329
+
1330
+ .jb-image-picker-asset {
1331
+ background: var(--jb-surface);
1332
+ border: 1px solid var(--jb-border);
1333
+ border-radius: var(--jb-radius-sm);
1334
+ color: var(--jb-text);
1335
+ cursor: pointer;
1336
+ display: grid;
1337
+ font: inherit;
1338
+ gap: 0.5rem;
1339
+ overflow: hidden;
1340
+ padding: 0.5rem;
1341
+ text-align: left;
1342
+ }
1343
+
1344
+ .jb-image-picker-asset:hover {
1345
+ background: var(--jb-surface-2);
1346
+ border-color: var(--jb-accent);
1347
+ }
1348
+
1349
+ .jb-image-picker-asset img {
1350
+ aspect-ratio: 4 / 3;
1351
+ border-radius: calc(var(--jb-radius-sm) - 0.125rem);
1352
+ object-fit: cover;
1353
+ width: 100%;
1354
+ }
1355
+
1356
+ .jb-image-picker-asset span,
1357
+ .jb-image-picker-asset small {
1358
+ display: block;
1359
+ min-width: 0;
1360
+ overflow: hidden;
1361
+ text-overflow: ellipsis;
1362
+ white-space: nowrap;
1363
+ }
1364
+
1365
+ .jb-image-picker-asset small {
1366
+ color: var(--jb-text-2);
1367
+ font-size: 0.6875rem;
1368
+ margin-top: 0.125rem;
1369
+ }
1370
+
1371
+ .jb-editor-preview {
1372
+ background: var(--jb-bg);
1373
+ display: grid;
1374
+ grid-template-rows: var(--jb-editor-topbar-h) minmax(0, 1fr);
1375
+ min-height: 0;
1376
+ min-width: 0;
1377
+ }
1378
+
1379
+ .jb-editor-preview-topbar {
1380
+ position: relative;
1381
+ justify-content: center;
1382
+ }
1383
+
1384
+ .jb-edit-page-shortcut {
1385
+ left: 0.75rem;
1386
+ position: absolute;
1387
+ }
1388
+
1389
+ .jb-edit-page-shortcut[hidden] {
1390
+ display: none;
1391
+ }
1392
+
1393
+ .jb-editor-preview-actions {
1394
+ display: flex;
1395
+ gap: 0.5rem;
1396
+ position: absolute;
1397
+ right: 0.75rem;
1398
+ }
1399
+
1400
+ .jb-editor-preview-actions form {
1401
+ margin: 0;
1402
+ }
1403
+
1404
+ .jb-preview-tabs {
1405
+ background: var(--jb-surface-2);
1406
+ border: 1px solid var(--jb-border);
1407
+ border-radius: var(--jb-radius-sm);
1408
+ display: inline-grid;
1409
+ gap: 0.125rem;
1410
+ grid-template-columns: 1fr 1fr;
1411
+ padding: 0.1875rem;
1412
+ }
1413
+
1414
+ .jb-preview-tabs button {
1415
+ appearance: none;
1416
+ background: transparent;
1417
+ border: 0;
1418
+ border-radius: calc(var(--jb-radius-sm) - 0.125rem);
1419
+ color: var(--jb-text-2);
1420
+ cursor: pointer;
1421
+ font: inherit;
1422
+ font-size: 0.8125rem;
1423
+ font-weight: 600;
1424
+ padding: 0.375rem 0.75rem;
1425
+ }
1426
+
1427
+ .jb-preview-tabs button.is-active {
1428
+ background: var(--jb-surface);
1429
+ box-shadow: var(--jb-shadow-xs);
1430
+ color: var(--jb-text);
1431
+ }
1432
+
1433
+ .jb-editor-preview-stage {
1434
+ display: flex;
1435
+ min-height: 0;
1436
+ overflow: auto;
1437
+ }
1438
+
1439
+ .jb-editor-preview iframe {
1440
+ border: 0;
1441
+ display: block;
1442
+ flex: 1;
1443
+ height: 100%;
1444
+ min-width: 0;
1445
+ width: 100%;
1446
+ }
1447
+
1448
+ .jb-page-editor.is-mobile-preview .jb-editor-preview-stage {
1449
+ align-items: flex-start;
1450
+ justify-content: center;
1451
+ padding: 1.25rem;
1452
+ }
1453
+
1454
+ .jb-page-editor.is-mobile-preview .jb-editor-preview iframe {
1455
+ border: 1px solid var(--jb-border);
1456
+ border-radius: 1.25rem;
1457
+ box-shadow: 0 18px 44px rgba(15, 23, 42, .16);
1458
+ flex: 0 0 auto;
1459
+ max-width: 100%;
1460
+ width: 390px;
1461
+ }
1462
+
1463
+ .jb-code {
1464
+ background: var(--jb-surface-2);
1465
+ border: 1px solid var(--jb-border);
1466
+ border-radius: var(--jb-radius-sm);
1467
+ color: var(--jb-text-2);
1468
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
1469
+ font-size: 0.75rem;
1470
+ overflow-x: auto;
1471
+ padding: 0.625rem 0.875rem;
1472
+ white-space: pre-wrap;
1473
+ }
1474
+
1475
+ /* ---- 20. PAGE PREVIEW --------------------------------------------- */
1476
+
1477
+ .jb-preview {
1478
+ background: #ffffff;
1479
+ border: 1px solid var(--jb-border);
1480
+ border-radius: var(--jb-radius-lg);
1481
+ color: #111827;
1482
+ overflow: hidden;
1483
+ padding: 1.5rem;
1484
+ }
1485
+
1486
+ /* ---- 21. MEDIA LIBRARY -------------------------------------------- */
1487
+
1488
+ .jb-media-grid {
1489
+ display: grid;
1490
+ gap: 1rem;
1491
+ grid-template-columns: repeat(auto-fill, minmax(18rem, 1fr));
1492
+ }
1493
+
1494
+ .jb-media-card {
1495
+ display: grid;
1496
+ gap: 1rem;
1497
+ overflow: hidden;
1498
+ padding: 0;
1499
+ }
1500
+
1501
+ .jb-media-thumb {
1502
+ aspect-ratio: 16 / 10;
1503
+ background: var(--jb-surface-2);
1504
+ border-bottom: 1px solid var(--jb-border);
1505
+ display: block;
1506
+ object-fit: cover;
1507
+ width: 100%;
1508
+ }
1509
+
1510
+ .jb-media-body {
1511
+ display: grid;
1512
+ gap: 0.625rem;
1513
+ padding: 0 1rem 1rem;
1514
+ }
1515
+
1516
+ .jb-media-body p { margin: 0; }
1517
+
1518
+ .jb-media-snippets {
1519
+ display: grid;
1520
+ gap: 0.375rem;
1521
+ }
1522
+
1523
+ .jb-media-snippets code,
1524
+ .jb-media-reference-item code {
1525
+ overflow-wrap: anywhere;
1526
+ }
1527
+
1528
+ .jb-media-reference-item {
1529
+ border: 1px solid var(--jb-border);
1530
+ border-radius: var(--jb-radius-sm);
1531
+ display: grid;
1532
+ gap: 0.375rem;
1533
+ padding: 0.625rem;
1534
+ }
1535
+
1536
+ .jb-media-reference-thumb {
1537
+ aspect-ratio: 16 / 9;
1538
+ background: var(--jb-surface-2);
1539
+ border-radius: var(--jb-radius-sm);
1540
+ display: block;
1541
+ object-fit: cover;
1542
+ width: 100%;
1543
+ }
1544
+
1545
+ /* ---- 22. RESPONSIVE ----------------------------------------------- */
1546
+
1547
+ @media (max-width: 960px) {
1548
+ .jb-shell { grid-template-columns: 1fr; }
1549
+ .jb-sidebar { height: auto; overflow-y: visible; position: static; }
1550
+ .jb-grid-2, .jb-grid-3, .jb-fields, .jb-component-library, .jb-component-add-page, .jb-page-editor-layout, .jb-page-editor { grid-template-columns: 1fr; }
1551
+ .jb-component-picker, .jb-page-editor-layout .jb-reference-stack { position: static; }
1552
+ .jb-header { flex-direction: column; }
1553
+ .jb-main { padding: 1.25rem; }
1554
+ .jb-editor-main { padding: 0; }
1555
+ .jb-editor-preview iframe { height: 70vh; }
1556
+ }