@orion-studios/payload-studio 0.5.0-beta.7 → 0.5.0-beta.70

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 (67) hide show
  1. package/README.md +20 -0
  2. package/dist/admin/client.d.mts +2 -0
  3. package/dist/admin/client.d.ts +2 -0
  4. package/dist/admin/client.js +779 -137
  5. package/dist/admin/client.mjs +769 -129
  6. package/dist/admin/index.d.mts +1 -1
  7. package/dist/admin/index.d.ts +1 -1
  8. package/dist/admin/index.js +100 -8
  9. package/dist/admin/index.mjs +3 -1
  10. package/dist/admin-app/client.d.mts +7 -0
  11. package/dist/admin-app/client.d.ts +7 -0
  12. package/dist/admin-app/client.js +1262 -3
  13. package/dist/admin-app/client.mjs +1164 -2
  14. package/dist/admin-app/index.d.mts +1 -1
  15. package/dist/admin-app/index.d.ts +1 -1
  16. package/dist/admin-app/index.js +167 -0
  17. package/dist/admin-app/index.mjs +13 -1
  18. package/dist/admin-app/styles.css +229 -0
  19. package/dist/blocks/index.js +633 -8
  20. package/dist/blocks/index.mjs +2 -2
  21. package/dist/{chunk-ZLLNO5FM.mjs → chunk-CKX5Y2HU.mjs} +44 -13
  22. package/dist/{chunk-J7W5EE3B.mjs → chunk-HCEPGEAI.mjs} +100 -8
  23. package/dist/chunk-HXGAG6I7.mjs +325 -0
  24. package/dist/chunk-ROTPP5CU.mjs +99 -0
  25. package/dist/{chunk-ETRRXURT.mjs → chunk-SIL2J5MF.mjs} +14 -0
  26. package/dist/chunk-VDGSMD6H.mjs +1072 -0
  27. package/dist/{chunk-PC5622T7.mjs → chunk-XK3K5GRP.mjs} +620 -9
  28. package/dist/chunk-XVH5SCBD.mjs +234 -0
  29. package/dist/{index-CmR6NInu.d.ts → index-BIwu3qIH.d.mts} +29 -3
  30. package/dist/{index-CmR6NInu.d.mts → index-BIwu3qIH.d.ts} +29 -3
  31. package/dist/index-CdnUNrvX.d.mts +134 -0
  32. package/dist/{index-DbH0Ljwp.d.ts → index-CpG3UHcS.d.mts} +1 -0
  33. package/dist/{index-DbH0Ljwp.d.mts → index-CpG3UHcS.d.ts} +1 -0
  34. package/dist/index-DyHbWliW.d.ts +134 -0
  35. package/dist/index-ZbOx4OCF.d.mts +128 -0
  36. package/dist/index-ZbOx4OCF.d.ts +128 -0
  37. package/dist/{index-DJFhANvJ.d.mts → index-cDYkEj29.d.mts} +20 -2
  38. package/dist/{index-DJFhANvJ.d.ts → index-cDYkEj29.d.ts} +20 -2
  39. package/dist/index.d.mts +5 -5
  40. package/dist/index.d.ts +5 -5
  41. package/dist/index.js +2145 -305
  42. package/dist/index.mjs +9 -9
  43. package/dist/nextjs/index.d.mts +1 -1
  44. package/dist/nextjs/index.d.ts +1 -1
  45. package/dist/nextjs/index.js +996 -13
  46. package/dist/nextjs/index.mjs +4 -1
  47. package/dist/studio/index.d.mts +2 -1
  48. package/dist/studio/index.d.ts +2 -1
  49. package/dist/studio/index.js +171 -2
  50. package/dist/studio/index.mjs +7 -3
  51. package/dist/studio-pages/builder.css +358 -8
  52. package/dist/studio-pages/client.d.mts +17 -0
  53. package/dist/studio-pages/client.d.ts +17 -0
  54. package/dist/studio-pages/client.js +5657 -1478
  55. package/dist/studio-pages/client.mjs +5549 -1461
  56. package/dist/studio-pages/index.d.mts +3 -2
  57. package/dist/studio-pages/index.d.ts +3 -2
  58. package/dist/studio-pages/index.js +799 -29
  59. package/dist/studio-pages/index.mjs +6 -2
  60. package/package.json +26 -12
  61. package/dist/chunk-AAOHJDNS.mjs +0 -67
  62. package/dist/chunk-N67KVM2S.mjs +0 -156
  63. package/dist/chunk-UJFU323N.mjs +0 -301
  64. package/dist/index-B9N5MyjF.d.mts +0 -39
  65. package/dist/index-BallJs-K.d.mts +0 -43
  66. package/dist/index-BallJs-K.d.ts +0 -43
  67. package/dist/index-g8tBHLKD.d.ts +0 -39
@@ -4,7 +4,10 @@ import {
4
4
  createPayloadClient,
5
5
  createSiteQueries,
6
6
  resolveMedia
7
- } from "../chunk-ZLLNO5FM.mjs";
7
+ } from "../chunk-CKX5Y2HU.mjs";
8
+ import "../chunk-HXGAG6I7.mjs";
9
+ import "../chunk-VDGSMD6H.mjs";
10
+ import "../chunk-SIL2J5MF.mjs";
8
11
  import "../chunk-6BWS3CLP.mjs";
9
12
  export {
10
13
  WEBSITE_CONTENT_TAG,
@@ -1 +1,2 @@
1
- export { c as StudioCompileResult, S as StudioDocumentV1, d as StudioInspectorField, e as StudioInspectorPanel, f as StudioMigration, b as StudioModuleManifest, g as StudioNode, h as StudioNodeData, a as StudioNodeTypeDefinition, j as StudioPageService, k as StudioPaletteGroup, l as StudioPaletteItem, m as StudioPermission, n as StudioRegistry, o as StudioValidationIssue, p as assertStudioDocumentV1, q as compileStudioDocument, r as createEmptyStudioDocument, s as createStudioRegistry, t as migrateStudioDocument, v as validateStudioDocument } from '../index-CmR6NInu.mjs';
1
+ export { I as ImageUploadOptimizationOptions, c as StudioCompileResult, S as StudioDocumentV1, d as StudioInspectorField, e as StudioInspectorPanel, f as StudioMigration, b as StudioModuleManifest, g as StudioNode, h as StudioNodeData, a as StudioNodeTypeDefinition, j as StudioPageService, k as StudioPaletteGroup, l as StudioPaletteItem, m as StudioPermission, n as StudioRegistry, o as StudioValidationIssue, p as SupportedImageMimeType, q as assertStudioDocumentV1, r as compileStudioDocument, s as createEmptyStudioDocument, t as createImageUploadOptimizationHook, u as createStudioRegistry, v as migrateStudioDocument, w as validateStudioDocument, x as withImageUploadOptimization } from '../index-BIwu3qIH.mjs';
2
+ import 'payload';
@@ -1 +1,2 @@
1
- export { c as StudioCompileResult, S as StudioDocumentV1, d as StudioInspectorField, e as StudioInspectorPanel, f as StudioMigration, b as StudioModuleManifest, g as StudioNode, h as StudioNodeData, a as StudioNodeTypeDefinition, j as StudioPageService, k as StudioPaletteGroup, l as StudioPaletteItem, m as StudioPermission, n as StudioRegistry, o as StudioValidationIssue, p as assertStudioDocumentV1, q as compileStudioDocument, r as createEmptyStudioDocument, s as createStudioRegistry, t as migrateStudioDocument, v as validateStudioDocument } from '../index-CmR6NInu.js';
1
+ export { I as ImageUploadOptimizationOptions, c as StudioCompileResult, S as StudioDocumentV1, d as StudioInspectorField, e as StudioInspectorPanel, f as StudioMigration, b as StudioModuleManifest, g as StudioNode, h as StudioNodeData, a as StudioNodeTypeDefinition, j as StudioPageService, k as StudioPaletteGroup, l as StudioPaletteItem, m as StudioPermission, n as StudioRegistry, o as StudioValidationIssue, p as SupportedImageMimeType, q as assertStudioDocumentV1, r as compileStudioDocument, s as createEmptyStudioDocument, t as createImageUploadOptimizationHook, u as createStudioRegistry, v as migrateStudioDocument, w as validateStudioDocument, x as withImageUploadOptimization } from '../index-BIwu3qIH.js';
2
+ import 'payload';
@@ -23,11 +23,178 @@ __export(studio_exports, {
23
23
  assertStudioDocumentV1: () => assertStudioDocumentV1,
24
24
  compileStudioDocument: () => compileStudioDocument,
25
25
  createEmptyStudioDocument: () => createEmptyStudioDocument,
26
+ createImageUploadOptimizationHook: () => createImageUploadOptimizationHook,
26
27
  createStudioRegistry: () => createStudioRegistry,
27
28
  migrateStudioDocument: () => migrateStudioDocument,
28
- validateStudioDocument: () => validateStudioDocument
29
+ validateStudioDocument: () => validateStudioDocument,
30
+ withImageUploadOptimization: () => withImageUploadOptimization
29
31
  });
30
32
  module.exports = __toCommonJS(studio_exports);
33
+
34
+ // src/studio/imageUploadOptimization.ts
35
+ var import_promises = require("fs/promises");
36
+ var DEFAULT_SUPPORTED_MIME_TYPES = [
37
+ "image/jpeg",
38
+ "image/jpg",
39
+ "image/png",
40
+ "image/webp",
41
+ "image/avif",
42
+ "image/tiff"
43
+ ];
44
+ var DEFAULT_OPTIONS = {
45
+ avifQuality: 50,
46
+ enforceSmallerForLossy: true,
47
+ jpegQuality: 78,
48
+ minBytes: 48 * 1024,
49
+ minQualityFloor: 42,
50
+ onlyIfSmaller: true,
51
+ pngCompressionLevel: 9,
52
+ skipAnimated: true,
53
+ tiffQuality: 75,
54
+ webpQuality: 78
55
+ };
56
+ var clamp = (value, min, max) => Math.max(min, Math.min(max, Math.round(value)));
57
+ var isUploadMutationOperation = (operation) => operation === "create" || operation === "update" || operation === "updateByID";
58
+ var isLossyMimeType = (mimetype) => mimetype === "image/jpeg" || mimetype === "image/jpg" || mimetype === "image/webp" || mimetype === "image/avif" || mimetype === "image/tiff";
59
+ var readIncomingBuffer = async (file) => {
60
+ if (file.tempFilePath) {
61
+ return (0, import_promises.readFile)(file.tempFilePath);
62
+ }
63
+ return file.data;
64
+ };
65
+ var writeOptimizedBuffer = async (file, buffer) => {
66
+ if (file.tempFilePath) {
67
+ await (0, import_promises.unlink)(file.tempFilePath).catch(() => void 0);
68
+ }
69
+ return {
70
+ ...file,
71
+ data: buffer,
72
+ size: buffer.length,
73
+ tempFilePath: void 0
74
+ };
75
+ };
76
+ var createImageUploadOptimizationHook = (options = {}) => {
77
+ const supportedMimeTypes = new Set(options.supportedMimeTypes || DEFAULT_SUPPORTED_MIME_TYPES);
78
+ const settings = { ...DEFAULT_OPTIONS, ...options };
79
+ return async ({ operation, req }) => {
80
+ if (!isUploadMutationOperation(operation)) {
81
+ return;
82
+ }
83
+ const file = req.file;
84
+ if (!file) {
85
+ return;
86
+ }
87
+ if (!supportedMimeTypes.has(file.mimetype)) {
88
+ return;
89
+ }
90
+ if (typeof file.size === "number" && file.size < settings.minBytes) {
91
+ return;
92
+ }
93
+ const sharpFactory = req.payload?.config?.sharp;
94
+ if (typeof sharpFactory !== "function") {
95
+ return;
96
+ }
97
+ const originalBuffer = await readIncomingBuffer(file);
98
+ if (!Buffer.isBuffer(originalBuffer) || originalBuffer.length === 0) {
99
+ return;
100
+ }
101
+ const animatedInput = file.mimetype === "image/avif" || file.mimetype === "image/webp";
102
+ const metadataProbe = await sharpFactory(
103
+ originalBuffer,
104
+ animatedInput ? {
105
+ animated: true
106
+ } : void 0
107
+ ).metadata();
108
+ if (settings.skipAnimated && typeof metadataProbe.pages === "number" && metadataProbe.pages > 1) {
109
+ return;
110
+ }
111
+ const buildPipeline = (qualityOverride) => {
112
+ let pipeline = sharpFactory(
113
+ originalBuffer,
114
+ animatedInput ? {
115
+ animated: true
116
+ } : void 0
117
+ );
118
+ switch (file.mimetype) {
119
+ case "image/jpeg":
120
+ case "image/jpg":
121
+ pipeline = pipeline.jpeg({
122
+ mozjpeg: true,
123
+ progressive: true,
124
+ quality: clamp(qualityOverride ?? settings.jpegQuality, 20, 100)
125
+ });
126
+ break;
127
+ case "image/png":
128
+ pipeline = pipeline.png({
129
+ compressionLevel: clamp(settings.pngCompressionLevel, 0, 9),
130
+ palette: false
131
+ });
132
+ break;
133
+ case "image/webp":
134
+ pipeline = pipeline.webp({
135
+ quality: clamp(qualityOverride ?? settings.webpQuality, 20, 100)
136
+ });
137
+ break;
138
+ case "image/avif":
139
+ pipeline = pipeline.avif({
140
+ quality: clamp(qualityOverride ?? settings.avifQuality, 20, 100)
141
+ });
142
+ break;
143
+ case "image/tiff":
144
+ pipeline = pipeline.tiff({
145
+ quality: clamp(qualityOverride ?? settings.tiffQuality, 20, 100)
146
+ });
147
+ break;
148
+ default:
149
+ return null;
150
+ }
151
+ return pipeline;
152
+ };
153
+ const initialPipeline = buildPipeline();
154
+ if (!initialPipeline) {
155
+ return;
156
+ }
157
+ let optimizedBuffer = await initialPipeline.toBuffer();
158
+ const shouldSweepQuality = settings.enforceSmallerForLossy && isLossyMimeType(file.mimetype);
159
+ if (shouldSweepQuality) {
160
+ const initialQuality = file.mimetype === "image/jpeg" || file.mimetype === "image/jpg" ? settings.jpegQuality : file.mimetype === "image/webp" ? settings.webpQuality : file.mimetype === "image/avif" ? settings.avifQuality : settings.tiffQuality;
161
+ let bestBuffer = optimizedBuffer;
162
+ let quality = clamp(initialQuality - 5, settings.minQualityFloor, 100);
163
+ while (quality >= settings.minQualityFloor) {
164
+ const retryPipeline = buildPipeline(quality);
165
+ if (!retryPipeline) {
166
+ break;
167
+ }
168
+ const retryBuffer = await retryPipeline.toBuffer();
169
+ if (retryBuffer.length < bestBuffer.length) {
170
+ bestBuffer = retryBuffer;
171
+ }
172
+ quality -= 5;
173
+ }
174
+ optimizedBuffer = bestBuffer;
175
+ }
176
+ if (settings.onlyIfSmaller && optimizedBuffer.length >= originalBuffer.length) {
177
+ return;
178
+ }
179
+ req.file = await writeOptimizedBuffer(file, optimizedBuffer);
180
+ };
181
+ };
182
+ var withImageUploadOptimization = (collection, options = {}) => {
183
+ if (!collection.upload) {
184
+ return collection;
185
+ }
186
+ const existingHooks = collection.hooks || {};
187
+ const beforeOperation = existingHooks.beforeOperation || [];
188
+ return {
189
+ ...collection,
190
+ hooks: {
191
+ ...existingHooks,
192
+ beforeOperation: [createImageUploadOptimizationHook(options), ...beforeOperation]
193
+ }
194
+ };
195
+ };
196
+
197
+ // src/studio/index.ts
31
198
  var isRecord = (value) => Boolean(value) && typeof value === "object" && !Array.isArray(value);
32
199
  var makeIssue = (message, path, code = "studio.invalid") => ({
33
200
  code,
@@ -165,7 +332,9 @@ function migrateStudioDocument(value, migrations) {
165
332
  assertStudioDocumentV1,
166
333
  compileStudioDocument,
167
334
  createEmptyStudioDocument,
335
+ createImageUploadOptimizationHook,
168
336
  createStudioRegistry,
169
337
  migrateStudioDocument,
170
- validateStudioDocument
338
+ validateStudioDocument,
339
+ withImageUploadOptimization
171
340
  });
@@ -2,16 +2,20 @@ import {
2
2
  assertStudioDocumentV1,
3
3
  compileStudioDocument,
4
4
  createEmptyStudioDocument,
5
+ createImageUploadOptimizationHook,
5
6
  createStudioRegistry,
6
7
  migrateStudioDocument,
7
- validateStudioDocument
8
- } from "../chunk-N67KVM2S.mjs";
8
+ validateStudioDocument,
9
+ withImageUploadOptimization
10
+ } from "../chunk-HXGAG6I7.mjs";
9
11
  import "../chunk-6BWS3CLP.mjs";
10
12
  export {
11
13
  assertStudioDocumentV1,
12
14
  compileStudioDocument,
13
15
  createEmptyStudioDocument,
16
+ createImageUploadOptimizationHook,
14
17
  createStudioRegistry,
15
18
  migrateStudioDocument,
16
- validateStudioDocument
19
+ validateStudioDocument,
20
+ withImageUploadOptimization
17
21
  };
@@ -38,6 +38,22 @@ h4 {
38
38
  padding-inline: var(--orion-shell-inline);
39
39
  }
40
40
 
41
+ .orion-builder-shell.padx-none {
42
+ --orion-shell-inline: 0px;
43
+ }
44
+
45
+ .orion-builder-shell.padx-sm {
46
+ --orion-shell-inline: 0.6rem;
47
+ }
48
+
49
+ .orion-builder-shell.padx-md {
50
+ --orion-shell-inline: 1.2rem;
51
+ }
52
+
53
+ .orion-builder-shell.padx-lg {
54
+ --orion-shell-inline: 2rem;
55
+ }
56
+
41
57
  .orion-builder-shell.pad-sm {
42
58
  --orion-shell-padding-y: 1.4rem;
43
59
  }
@@ -88,12 +104,12 @@ h4 {
88
104
  padding: 0;
89
105
  }
90
106
 
91
- .orion-builder-shell.hero {
107
+ .orion-builder-shell .hero {
92
108
  margin: 0;
93
109
  background: transparent;
94
110
  }
95
111
 
96
- .orion-builder-shell.hero .hero-media {
112
+ .orion-builder-shell .hero-media {
97
113
  background: transparent;
98
114
  }
99
115
 
@@ -154,11 +170,51 @@ h4 {
154
170
 
155
171
  .hero-grid {
156
172
  display: grid;
173
+ border-radius: inherit;
174
+ overflow: hidden;
157
175
  }
158
176
 
159
177
  .hero-media {
160
178
  min-height: 360px;
161
179
  background: transparent;
180
+ border-radius: inherit;
181
+ }
182
+
183
+ .orion-builder-upload-slot {
184
+ position: relative;
185
+ }
186
+
187
+ .orion-builder-upload-overlay {
188
+ align-items: center;
189
+ background: rgba(9, 28, 21, 0.58);
190
+ border-radius: inherit;
191
+ color: #ffffff;
192
+ display: inline-flex;
193
+ font-size: 0.8rem;
194
+ font-weight: 700;
195
+ gap: 0.5rem;
196
+ inset: 0;
197
+ justify-content: center;
198
+ letter-spacing: 0.01em;
199
+ pointer-events: none;
200
+ position: absolute;
201
+ z-index: 4;
202
+ }
203
+
204
+ .orion-builder-upload-spinner {
205
+ animation: orion-builder-upload-spin 0.9s linear infinite;
206
+ border: 2px solid rgba(255, 255, 255, 0.35);
207
+ border-radius: 999px;
208
+ border-top-color: #ffffff;
209
+ display: inline-block;
210
+ height: 18px;
211
+ width: 18px;
212
+ }
213
+
214
+ @keyframes orion-builder-upload-spin {
215
+ to {
216
+ transform: rotate(360deg);
217
+ }
162
218
  }
163
219
 
164
220
  .hero-content {
@@ -209,7 +265,8 @@ h4 {
209
265
  .feature-grid {
210
266
  display: grid;
211
267
  gap: 0.9rem;
212
- grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
268
+ /* Mobile-first: stack. Projects can override in their own globals.css. */
269
+ grid-template-columns: 1fr;
213
270
  margin-top: 1rem;
214
271
  }
215
272
 
@@ -261,7 +318,8 @@ h4 {
261
318
  .card-grid.services {
262
319
  display: grid;
263
320
  gap: 0.9rem;
264
- grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
321
+ /* Mobile-first: stack. */
322
+ grid-template-columns: 1fr;
265
323
  margin-top: 1rem;
266
324
  }
267
325
 
@@ -281,15 +339,106 @@ h4 {
281
339
  .split.testimonials-grid {
282
340
  display: grid;
283
341
  gap: 0.9rem;
284
- grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
342
+ /* Mobile-first: stack. */
343
+ grid-template-columns: 1fr;
285
344
  margin-top: 1rem;
286
345
  }
287
346
 
347
+ .testimonials-stage {
348
+ position: relative;
349
+ margin-top: 1rem;
350
+ }
351
+
352
+ .testimonials-stage.is-navigable {
353
+ padding-inline: 2.8rem;
354
+ }
355
+
356
+ .testimonials-stage .split.testimonials-grid {
357
+ margin-top: 0;
358
+ }
359
+
360
+ .testimonial-nav {
361
+ position: absolute;
362
+ top: 50%;
363
+ transform: translateY(-50%);
364
+ width: 42px;
365
+ height: 42px;
366
+ border-radius: 999px;
367
+ border: 1px solid rgba(19, 33, 28, 0.14);
368
+ background: rgba(255, 255, 255, 0.92);
369
+ box-shadow: 0 18px 34px rgba(15, 125, 82, 0.12);
370
+ display: grid;
371
+ place-items: center;
372
+ cursor: pointer;
373
+ user-select: none;
374
+ }
375
+
376
+ .testimonial-nav span {
377
+ color: var(--orion-studio-accent);
378
+ font-size: 1.55rem;
379
+ line-height: 1;
380
+ }
381
+
382
+ .testimonial-nav--prev {
383
+ left: 0.35rem;
384
+ }
385
+
386
+ .testimonial-nav--next {
387
+ right: 0.35rem;
388
+ }
389
+
288
390
  .quote {
289
391
  font-size: 0.98rem;
392
+ line-height: 1.55;
290
393
  color: var(--orion-studio-ink);
291
394
  }
292
395
 
396
+ .testimonial-quote-mark {
397
+ display: block;
398
+ font-size: 2.2rem;
399
+ line-height: 0.8;
400
+ color: #e7b55a;
401
+ margin-bottom: 0;
402
+ opacity: 0.8;
403
+ }
404
+
405
+ .testimonial-quote-top {
406
+ display: flex;
407
+ align-items: flex-start;
408
+ justify-content: space-between;
409
+ gap: 0.65rem;
410
+ margin-bottom: 0.2rem;
411
+ }
412
+
413
+ .testimonial-quote {
414
+ display: -webkit-box;
415
+ -webkit-box-orient: vertical;
416
+ -webkit-line-clamp: 3;
417
+ overflow: hidden;
418
+ }
419
+
420
+ .testimonial-stars {
421
+ color: #e7b55a;
422
+ display: inline-flex;
423
+ font-size: 0.92rem;
424
+ gap: 0.04rem;
425
+ letter-spacing: 0.02em;
426
+ line-height: 1;
427
+ margin-top: 0.2rem;
428
+ white-space: nowrap;
429
+ }
430
+
431
+ .testimonial-stars-muted {
432
+ color: rgba(13, 74, 55, 0.25);
433
+ }
434
+
435
+ @supports not (-webkit-line-clamp: 1) {
436
+ .testimonial-quote {
437
+ display: block;
438
+ max-height: calc((3 * 1.55em) - 0.5px);
439
+ }
440
+ }
441
+
293
442
  .quote-author {
294
443
  margin-top: 0.75rem;
295
444
  display: flex;
@@ -352,6 +501,7 @@ h4 {
352
501
  border: 1px solid rgba(19, 33, 28, 0.12);
353
502
  border-radius: 18px;
354
503
  overflow: hidden;
504
+ position: relative;
355
505
  }
356
506
 
357
507
  .media-figure img {
@@ -372,7 +522,8 @@ h4 {
372
522
  .orion-stats-grid {
373
523
  display: grid;
374
524
  gap: 0.9rem;
375
- grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
525
+ /* Mobile-first: stack. */
526
+ grid-template-columns: 1fr;
376
527
  margin-top: 1rem;
377
528
  }
378
529
 
@@ -407,7 +558,8 @@ h4 {
407
558
  .orion-logo-wall {
408
559
  display: grid;
409
560
  gap: 0.8rem;
410
- grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
561
+ /* Mobile-first: stack. */
562
+ grid-template-columns: 1fr;
411
563
  margin-top: 1rem;
412
564
  }
413
565
 
@@ -437,10 +589,47 @@ h4 {
437
589
  .orion-before-after-grid {
438
590
  display: grid;
439
591
  gap: 1rem;
440
- grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
592
+ /* Mobile-first: stack. */
593
+ grid-template-columns: 1fr;
441
594
  margin-top: 1rem;
442
595
  }
443
596
 
597
+ @media (min-width: 720px) {
598
+ .feature-grid {
599
+ grid-template-columns: var(--feature-grid-template-columns, repeat(auto-fit, minmax(200px, 1fr)));
600
+ }
601
+
602
+ .card-grid.services {
603
+ grid-template-columns: var(--services-grid-template-columns, repeat(auto-fit, minmax(240px, 1fr)));
604
+ }
605
+
606
+ .split.testimonials-grid {
607
+ grid-template-columns: var(--testimonials-grid-columns, repeat(auto-fit, minmax(260px, 1fr)));
608
+ }
609
+
610
+ .testimonial-quote {
611
+ -webkit-line-clamp: 2;
612
+ }
613
+
614
+ @supports not (-webkit-line-clamp: 1) {
615
+ .testimonial-quote {
616
+ max-height: calc((2 * 1.55em) - 0.5px);
617
+ }
618
+ }
619
+
620
+ .orion-stats-grid {
621
+ grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
622
+ }
623
+
624
+ .orion-logo-wall {
625
+ grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
626
+ }
627
+
628
+ .orion-before-after-grid {
629
+ grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
630
+ }
631
+ }
632
+
444
633
  .orion-before-after-card {
445
634
  background: #fff;
446
635
  border: 1px solid rgba(13, 74, 55, 0.12);
@@ -497,3 +686,164 @@ h4 {
497
686
  gap: 0.34rem;
498
687
  padding: 0.1rem 0.95rem 0.95rem;
499
688
  }
689
+
690
+ .orion-builder-settings-root {
691
+ display: grid;
692
+ gap: 0.75rem;
693
+ }
694
+
695
+ .orion-builder-settings-summary-row {
696
+ align-items: center;
697
+ background: rgba(18, 74, 55, 0.04);
698
+ border: 1px solid rgba(13, 74, 55, 0.12);
699
+ border-radius: 12px;
700
+ display: flex;
701
+ gap: 0.5rem;
702
+ justify-content: space-between;
703
+ padding: 0.55rem 0.65rem;
704
+ position: sticky;
705
+ top: 0;
706
+ z-index: 3;
707
+ }
708
+
709
+ .orion-builder-settings-summary-title {
710
+ color: var(--orion-studio-ink);
711
+ font-size: 0.78rem;
712
+ font-weight: 800;
713
+ letter-spacing: 0.01em;
714
+ }
715
+
716
+ .orion-builder-settings-summary-actions {
717
+ display: inline-flex;
718
+ gap: 0.45rem;
719
+ }
720
+
721
+ .orion-builder-settings-mode-btn {
722
+ background: #fff;
723
+ border: 1px solid rgba(13, 74, 55, 0.2);
724
+ border-radius: 999px;
725
+ color: var(--orion-studio-muted);
726
+ cursor: pointer;
727
+ font-size: 0.73rem;
728
+ font-weight: 700;
729
+ padding: 0.28rem 0.6rem;
730
+ }
731
+
732
+ .orion-builder-settings-mode-btn.is-active {
733
+ background: #124a37;
734
+ border-color: #124a37;
735
+ color: #fff;
736
+ }
737
+
738
+ .orion-builder-settings-group {
739
+ background: #fff;
740
+ border: 1px solid rgba(13, 74, 55, 0.14);
741
+ border-radius: 12px;
742
+ overflow: hidden;
743
+ }
744
+
745
+ .orion-builder-settings-group-header {
746
+ align-items: center;
747
+ background: linear-gradient(180deg, rgba(18, 74, 55, 0.06), rgba(18, 74, 55, 0));
748
+ border: none;
749
+ color: var(--orion-studio-ink);
750
+ cursor: pointer;
751
+ display: flex;
752
+ justify-content: space-between;
753
+ padding: 0.55rem 0.65rem;
754
+ text-align: left;
755
+ width: 100%;
756
+ }
757
+
758
+ .orion-builder-settings-group-title-wrap {
759
+ display: grid;
760
+ gap: 0.12rem;
761
+ }
762
+
763
+ .orion-builder-settings-group-title {
764
+ font-size: 0.79rem;
765
+ font-weight: 800;
766
+ }
767
+
768
+ .orion-builder-settings-group-subtitle {
769
+ color: var(--orion-studio-muted);
770
+ font-size: 0.68rem;
771
+ font-weight: 600;
772
+ }
773
+
774
+ .orion-builder-settings-group-caret {
775
+ color: var(--orion-studio-muted);
776
+ font-size: 1rem;
777
+ font-weight: 700;
778
+ }
779
+
780
+ .orion-builder-settings-group-body {
781
+ border-top: 1px solid rgba(13, 74, 55, 0.08);
782
+ display: grid;
783
+ gap: 0.6rem;
784
+ padding: 0.65rem;
785
+ }
786
+
787
+ .orion-builder-settings-field-list {
788
+ display: grid;
789
+ gap: 0.55rem;
790
+ }
791
+
792
+ .orion-builder-settings-label {
793
+ color: var(--orion-studio-muted);
794
+ display: grid;
795
+ font-size: 0.74rem;
796
+ font-weight: 700;
797
+ gap: 0.33rem;
798
+ }
799
+
800
+ .orion-builder-settings-label.is-checkbox {
801
+ align-items: center;
802
+ display: grid;
803
+ gap: 0.45rem;
804
+ grid-template-columns: auto 1fr;
805
+ }
806
+
807
+ .orion-builder-settings-input {
808
+ background: #fff;
809
+ border: 1px solid rgba(13, 74, 55, 0.2);
810
+ border-radius: 10px;
811
+ color: var(--orion-studio-ink);
812
+ font-size: 0.79rem;
813
+ padding: 0.42rem 0.54rem;
814
+ width: 100%;
815
+ }
816
+
817
+ .orion-builder-settings-input.is-textarea {
818
+ min-height: 84px;
819
+ resize: vertical;
820
+ }
821
+
822
+ .orion-builder-settings-input.is-color {
823
+ height: 35px;
824
+ padding: 0.2rem;
825
+ }
826
+
827
+ .orion-builder-settings-input-split {
828
+ align-items: center;
829
+ display: grid;
830
+ gap: 0.45rem;
831
+ grid-template-columns: 1fr 78px;
832
+ }
833
+
834
+ .orion-builder-settings-empty {
835
+ border: 1px dashed rgba(13, 74, 55, 0.2);
836
+ border-radius: 12px;
837
+ color: var(--orion-studio-muted);
838
+ font-size: 0.75rem;
839
+ font-weight: 600;
840
+ padding: 0.65rem;
841
+ }
842
+
843
+ .orion-builder-content h1,
844
+ .orion-builder-content h2,
845
+ .orion-builder-content h3,
846
+ .orion-builder-content h4 {
847
+ color: var(--orion-builder-heading-color, inherit);
848
+ text-align: var(--orion-builder-heading-align, inherit);
849
+ }