@contentrain/astro-kit 0.31.0 → 0.32.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 (48) hide show
  1. package/catalog.json +2531 -345
  2. package/components/_shared/measured.ts +10 -0
  3. package/components/contact-form/ContactForm.astro +48 -12
  4. package/components/contact-form/fixtures.json +169 -9
  5. package/components/contact-form/meta.json +283 -15
  6. package/components/cta/Cta.astro +52 -12
  7. package/components/cta/fixtures.json +5 -1
  8. package/components/cta/meta.json +11 -2
  9. package/components/faq/Faq.astro +60 -17
  10. package/components/faq/fixtures.json +75 -0
  11. package/components/faq/meta.json +7 -1
  12. package/components/feature-list/FeatureList.astro +28 -4
  13. package/components/feature-list/meta.json +15 -3
  14. package/components/gallery/Gallery.astro +47 -13
  15. package/components/gallery/fixtures.json +275 -0
  16. package/components/gallery/meta.json +266 -14
  17. package/components/logo-cloud/LogoCloud.astro +85 -21
  18. package/components/logo-cloud/fixtures.json +239 -0
  19. package/components/logo-cloud/meta.json +144 -5
  20. package/components/post-card/PostCard.astro +4 -2
  21. package/components/post-card/meta.json +2 -1
  22. package/components/post-list/PostList.astro +114 -0
  23. package/components/post-list/fixtures.json +387 -0
  24. package/components/post-list/meta.json +308 -0
  25. package/components/pricing/Pricing.astro +128 -24
  26. package/components/pricing/fixtures.json +288 -4
  27. package/components/pricing/meta.json +187 -1
  28. package/components/split/Split.astro +76 -14
  29. package/components/split/fixtures.json +8 -1
  30. package/components/split/meta.json +225 -4
  31. package/components/stats/Stats.astro +42 -10
  32. package/components/stats/fixtures.json +173 -0
  33. package/components/stats/meta.json +150 -4
  34. package/components/steps/Steps.astro +36 -8
  35. package/components/steps/fixtures.json +217 -5
  36. package/components/steps/meta.json +156 -3
  37. package/components/team/Team.astro +52 -8
  38. package/components/team/fixtures.json +217 -4
  39. package/components/team/meta.json +167 -3
  40. package/components/team/team.ts +9 -0
  41. package/components/testimonial/Testimonial.astro +71 -21
  42. package/components/testimonial/fixtures.json +73 -0
  43. package/components/testimonial/meta.json +166 -3
  44. package/mapping/classic.json +7 -1
  45. package/mapping/divi.json +21 -4
  46. package/mapping/elementor.json +33 -8
  47. package/mapping/gutenberg.json +20 -4
  48. package/package.json +1 -1
package/catalog.json CHANGED
@@ -1086,7 +1086,9 @@
1086
1086
  "name": "Contact form",
1087
1087
  "description": "The contact section: heading, introduction, contact details (email, phone, address) and a Contentrain Studio form — fields, spam protection and notifications set in Studio, submissions reviewed there. Replaces form plugins; renders the details alone until the site is bound to a Studio project (a section left with only its heading is not drawn: the heading would title a form that is not there). When the owner chose another home at migration (site.config.ts `features.forms`) the form posts to their form service, or the section shows an address to write to or a link to the form on WordPress.",
1088
1088
  "category": "section",
1089
- "uses": [],
1089
+ "uses": [
1090
+ "embed"
1091
+ ],
1090
1092
  "shared": [
1091
1093
  "Section.astro",
1092
1094
  "measured.ts",
@@ -1096,10 +1098,11 @@
1096
1098
  "layout": {
1097
1099
  "options": [
1098
1100
  "split",
1099
- "stacked"
1101
+ "stacked",
1102
+ "form-only"
1100
1103
  ],
1101
1104
  "default": "split",
1102
- "description": "split: details beside the form on wide screens. stacked: one column (see align)."
1105
+ "description": "split: details beside the form on wide screens. stacked: one column (see align). form-only: only the form under its heading; details, hours and map are left out."
1103
1106
  },
1104
1107
  "align": {
1105
1108
  "options": [
@@ -1126,6 +1129,22 @@
1126
1129
  ],
1127
1130
  "default": "top",
1128
1131
  "description": "Where the heading sits. top: above the introduction and details. after: after them, as a source that writes its lead line and contact buttons first has it; beside a form it titles the form, without one it follows the details."
1132
+ },
1133
+ "detailsStyle": {
1134
+ "options": [
1135
+ "list",
1136
+ "cards"
1137
+ ],
1138
+ "default": "list",
1139
+ "description": "The ways to reach you: a plain list, or a card each (label over value)."
1140
+ },
1141
+ "panel": {
1142
+ "options": [
1143
+ "card",
1144
+ "none"
1145
+ ],
1146
+ "default": "card",
1147
+ "description": "card: the form on its own surface. none: flush on the section's background."
1129
1148
  }
1130
1149
  },
1131
1150
  "props": {
@@ -1180,6 +1199,166 @@
1180
1199
  "type": "string",
1181
1200
  "content": false,
1182
1201
  "description": "Section id; the heading gets `<id>-title`."
1202
+ },
1203
+ "hours": {
1204
+ "type": "text",
1205
+ "label": "Opening hours",
1206
+ "description": "Opening hours as written; line breaks are kept."
1207
+ },
1208
+ "socials": {
1209
+ "type": "array",
1210
+ "label": "Profile links",
1211
+ "description": "Social or profile links, shown as a row under the details.",
1212
+ "items": {
1213
+ "type": "object",
1214
+ "fields": {
1215
+ "label": {
1216
+ "type": "string",
1217
+ "label": "Label",
1218
+ "required": true,
1219
+ "description": "Visible text of the link."
1220
+ },
1221
+ "href": {
1222
+ "type": "url",
1223
+ "label": "Link",
1224
+ "required": true,
1225
+ "description": "The profile address."
1226
+ }
1227
+ }
1228
+ }
1229
+ },
1230
+ "map": {
1231
+ "type": "object",
1232
+ "label": "Map",
1233
+ "description": "A map of the address, loaded only when the reader asks (no iframe on load); the address is printed under it.",
1234
+ "fields": {
1235
+ "address": {
1236
+ "type": "string",
1237
+ "label": "Address",
1238
+ "description": "The place shown on the map."
1239
+ },
1240
+ "url": {
1241
+ "type": "url",
1242
+ "label": "Map address",
1243
+ "description": "A Google Maps embed address, when the source has one."
1244
+ },
1245
+ "title": {
1246
+ "type": "string",
1247
+ "label": "Map title",
1248
+ "required": true,
1249
+ "description": "What the map is (\"Our studio\"): its accessible name."
1250
+ }
1251
+ }
1252
+ },
1253
+ "measured": {
1254
+ "type": "object",
1255
+ "content": false,
1256
+ "description": "The source section's measured style (MeasuredStyle): frame width, padding, fill, image, columns per width, gap, text tone, radius, minimum height — all in pixels. Absent, the site's tokens; present, it wins over tone and columns. Values that are not a number, a colour or a known keyword are dropped.",
1257
+ "fields": {
1258
+ "containerPx": {
1259
+ "type": "integer",
1260
+ "min": 0,
1261
+ "max": 2560,
1262
+ "description": "The frame's content width."
1263
+ },
1264
+ "padY": {
1265
+ "type": "integer",
1266
+ "min": 0,
1267
+ "max": 400,
1268
+ "description": "Top and bottom padding."
1269
+ },
1270
+ "padX": {
1271
+ "type": "integer",
1272
+ "min": 0,
1273
+ "max": 200,
1274
+ "description": "The frame's side padding (gutter)."
1275
+ },
1276
+ "bg": {
1277
+ "type": "object",
1278
+ "description": "The section's background.",
1279
+ "fields": {
1280
+ "color": {
1281
+ "type": "string",
1282
+ "description": "Fill colour: hex, rgb(a) or hsl(a)."
1283
+ },
1284
+ "image": {
1285
+ "type": "string",
1286
+ "description": "Background image address (http(s) or root-relative), drawn behind the content."
1287
+ },
1288
+ "overlay": {
1289
+ "type": "string",
1290
+ "description": "Colour or linear/radial gradient laid over the image or the fill."
1291
+ },
1292
+ "size": {
1293
+ "type": "string",
1294
+ "description": "cover, contain or auto; anything else draws as cover."
1295
+ },
1296
+ "position": {
1297
+ "type": "string",
1298
+ "description": "One or two of center/top/bottom/left/right or percentages."
1299
+ }
1300
+ }
1301
+ },
1302
+ "columns": {
1303
+ "type": "object",
1304
+ "description": "Item columns at 390 (base), 768 (md) and 1280 (lg) px; a missing width follows the narrower one.",
1305
+ "fields": {
1306
+ "390": {
1307
+ "type": "integer",
1308
+ "min": 1,
1309
+ "max": 6,
1310
+ "description": "Phone."
1311
+ },
1312
+ "768": {
1313
+ "type": "integer",
1314
+ "min": 1,
1315
+ "max": 6,
1316
+ "description": "Tablet."
1317
+ },
1318
+ "1280": {
1319
+ "type": "integer",
1320
+ "min": 1,
1321
+ "max": 6,
1322
+ "description": "Desktop."
1323
+ }
1324
+ }
1325
+ },
1326
+ "gap": {
1327
+ "type": "integer",
1328
+ "min": 0,
1329
+ "max": 200,
1330
+ "description": "Gap between items."
1331
+ },
1332
+ "tone": {
1333
+ "type": "select",
1334
+ "options": [
1335
+ "light",
1336
+ "dark"
1337
+ ],
1338
+ "description": "What the text is set for: dark = light text on a dark band. Without it, a fill's own lightness decides."
1339
+ },
1340
+ "align": {
1341
+ "type": "select",
1342
+ "options": [
1343
+ "start",
1344
+ "center",
1345
+ "end"
1346
+ ],
1347
+ "description": "Where the heading and lead sit; read by a component whose own align is not set."
1348
+ },
1349
+ "radius": {
1350
+ "type": "integer",
1351
+ "min": 0,
1352
+ "max": 200,
1353
+ "description": "Card and item corner radius."
1354
+ },
1355
+ "minHeight": {
1356
+ "type": "integer",
1357
+ "min": 0,
1358
+ "max": 2000,
1359
+ "description": "The section's minimum height."
1360
+ }
1361
+ }
1183
1362
  }
1184
1363
  },
1185
1364
  "slots": {},
@@ -1211,7 +1390,15 @@
1211
1390
  "details": "details",
1212
1391
  "details[].label": "details[].label",
1213
1392
  "details[].value": "details[].value",
1214
- "details[].href": "details[].href"
1393
+ "details[].href": "details[].href",
1394
+ "hours": "hours",
1395
+ "socials": "socials",
1396
+ "socials[].label": "socials[].label",
1397
+ "socials[].href": "socials[].href",
1398
+ "map": "map",
1399
+ "map.address": "map.address",
1400
+ "map.url": "map.url",
1401
+ "map.title": "map.title"
1215
1402
  }
1216
1403
  },
1217
1404
  {
@@ -1222,6 +1409,7 @@
1222
1409
  "uses": [],
1223
1410
  "shared": [
1224
1411
  "Button.astro",
1412
+ "KitImage.astro",
1225
1413
  "Section.astro",
1226
1414
  "measured.ts",
1227
1415
  "types.ts"
@@ -1263,6 +1451,30 @@
1263
1451
  ],
1264
1452
  "default": "inherit",
1265
1453
  "description": "The buttons' alignment. inherit: as the layout sets it. start: at the start edge under centred heading and text (layout centered; a WordPress buttons block with no justification in a centred group). inline and stacked ignore it."
1454
+ },
1455
+ "size": {
1456
+ "options": [
1457
+ "md",
1458
+ "lg"
1459
+ ],
1460
+ "default": "md",
1461
+ "description": "md: the usual band. lg: a larger heading and more room above and below."
1462
+ },
1463
+ "align": {
1464
+ "options": [
1465
+ "start",
1466
+ "center"
1467
+ ],
1468
+ "default": "start",
1469
+ "description": "Alignment of the heading and text (the centred layout already centres them)."
1470
+ },
1471
+ "mediaSide": {
1472
+ "options": [
1473
+ "end",
1474
+ "start"
1475
+ ],
1476
+ "default": "end",
1477
+ "description": "With a picture: the side it takes on wide screens."
1266
1478
  }
1267
1479
  },
1268
1480
  "props": {
@@ -1272,11 +1484,36 @@
1272
1484
  "required": true,
1273
1485
  "description": "The call's heading (Divi CTA title, Elementor call-to-action title)."
1274
1486
  },
1487
+ "eyebrow": {
1488
+ "type": "string",
1489
+ "label": "Eyebrow",
1490
+ "description": "A short line above the heading."
1491
+ },
1275
1492
  "body": {
1276
1493
  "type": "text",
1277
1494
  "label": "Text",
1278
1495
  "description": "One or two sentences under the heading."
1279
1496
  },
1497
+ "note": {
1498
+ "type": "string",
1499
+ "label": "Small print",
1500
+ "description": "A line under the buttons (No credit card required)."
1501
+ },
1502
+ "image": {
1503
+ "type": "image",
1504
+ "label": "Image",
1505
+ "description": "A small picture beside the text; a large one belongs in a split section."
1506
+ },
1507
+ "bgImage": {
1508
+ "type": "image",
1509
+ "label": "Background image",
1510
+ "description": "A picture behind the band; the text turns light and an overlay keeps it readable."
1511
+ },
1512
+ "bgOverlay": {
1513
+ "type": "string",
1514
+ "content": false,
1515
+ "description": "The colour laid over the background image (a hex or rgb colour); default black at 55 %."
1516
+ },
1280
1517
  "actions": {
1281
1518
  "type": "array",
1282
1519
  "label": "Buttons",
@@ -1315,69 +1552,183 @@
1315
1552
  },
1316
1553
  "description": "Buttons, in order; usually one."
1317
1554
  },
1318
- "id": {
1319
- "type": "string",
1555
+ "measured": {
1556
+ "type": "object",
1320
1557
  "content": false,
1321
- "description": "Anchor id of the section; the heading gets `<id>-title`."
1322
- }
1323
- },
1324
- "slots": {},
1325
- "js": "none",
1326
- "dependencies": {},
1327
- "sources": {
1328
- "elementor": [
1329
- "elementor/call-to-action"
1330
- ],
1331
- "divi": [
1332
- "divi/et_pb_cta"
1333
- ],
1334
- "classic": [
1335
- "classic/cta"
1336
- ]
1337
- },
1338
- "a11y": "A labelled region (aria-labelledby its h2). Buttons are links with their own text. Accent tone swaps the primary button style so its contrast holds.",
1339
- "files": [
1340
- "Cta.astro"
1341
- ],
1342
- "contentFields": {
1343
- "heading": "heading",
1344
- "body": "body",
1345
- "actions": "actions",
1346
- "actions[].label": "actions[].label",
1347
- "actions[].href": "actions[].href",
1348
- "actions[].newTab": "actions[].new_tab",
1349
- "actions[].style": "actions[].style"
1350
- }
1351
- },
1352
- {
1353
- "id": "embed",
1354
- "name": "Embed",
1355
- "description": "A video, map or player from another site (YouTube, Vimeo, Google Maps, OpenStreetMap, Spotify, SoundCloud, Calendly, Typeform, Google Forms, Loom, Wistia), loaded only on click: until then a poster link to the provider's page, with no iframe, no third-party request and no cookie (YouTube through youtube-nocookie.com). Unknown providers are never framed; they stay a plain link.",
1356
- "category": "content",
1357
- "uses": [],
1358
- "shared": [
1359
- "KitImage.astro",
1360
- "types.ts"
1361
- ],
1362
- "variants": {
1363
- "aspect": {
1364
- "options": [
1365
- "auto",
1366
- "video",
1367
- "portrait",
1368
- "square",
1369
- "map"
1370
- ],
1371
- "default": "auto",
1372
- "description": "auto: 16:9 for videos, 9:16 for YouTube Shorts, 4:3 (16:9 wide) for maps, a fixed strip for audio players. The others force a ratio."
1373
- },
1374
- "width": {
1375
- "options": [
1376
- "prose",
1377
- "page"
1378
- ],
1379
- "default": "prose",
1380
- "description": "prose: as wide as the reading column. page: the full page frame."
1558
+ "description": "The source section's measured style (MeasuredStyle): frame width, padding, fill, image, columns per width, gap, text tone, radius, minimum height — all in pixels. Absent, the site's tokens; present, it wins over tone and columns. Values that are not a number, a colour or a known keyword are dropped.",
1559
+ "fields": {
1560
+ "containerPx": {
1561
+ "type": "integer",
1562
+ "min": 0,
1563
+ "max": 2560,
1564
+ "description": "The frame's content width."
1565
+ },
1566
+ "padY": {
1567
+ "type": "integer",
1568
+ "min": 0,
1569
+ "max": 400,
1570
+ "description": "Top and bottom padding."
1571
+ },
1572
+ "padX": {
1573
+ "type": "integer",
1574
+ "min": 0,
1575
+ "max": 200,
1576
+ "description": "The frame's side padding (gutter)."
1577
+ },
1578
+ "bg": {
1579
+ "type": "object",
1580
+ "description": "The section's background.",
1581
+ "fields": {
1582
+ "color": {
1583
+ "type": "string",
1584
+ "description": "Fill colour: hex, rgb(a) or hsl(a)."
1585
+ },
1586
+ "image": {
1587
+ "type": "string",
1588
+ "description": "Background image address (http(s) or root-relative), drawn behind the content."
1589
+ },
1590
+ "overlay": {
1591
+ "type": "string",
1592
+ "description": "Colour or linear/radial gradient laid over the image or the fill."
1593
+ },
1594
+ "size": {
1595
+ "type": "string",
1596
+ "description": "cover, contain or auto; anything else draws as cover."
1597
+ },
1598
+ "position": {
1599
+ "type": "string",
1600
+ "description": "One or two of center/top/bottom/left/right or percentages."
1601
+ }
1602
+ }
1603
+ },
1604
+ "columns": {
1605
+ "type": "object",
1606
+ "description": "Item columns at 390 (base), 768 (md) and 1280 (lg) px; a missing width follows the narrower one.",
1607
+ "fields": {
1608
+ "390": {
1609
+ "type": "integer",
1610
+ "min": 1,
1611
+ "max": 6,
1612
+ "description": "Phone."
1613
+ },
1614
+ "768": {
1615
+ "type": "integer",
1616
+ "min": 1,
1617
+ "max": 6,
1618
+ "description": "Tablet."
1619
+ },
1620
+ "1280": {
1621
+ "type": "integer",
1622
+ "min": 1,
1623
+ "max": 6,
1624
+ "description": "Desktop."
1625
+ }
1626
+ }
1627
+ },
1628
+ "gap": {
1629
+ "type": "integer",
1630
+ "min": 0,
1631
+ "max": 200,
1632
+ "description": "Gap between items."
1633
+ },
1634
+ "tone": {
1635
+ "type": "select",
1636
+ "options": [
1637
+ "light",
1638
+ "dark"
1639
+ ],
1640
+ "description": "What the text is set for: dark = light text on a dark band. Without it, a fill's own lightness decides."
1641
+ },
1642
+ "align": {
1643
+ "type": "select",
1644
+ "options": [
1645
+ "start",
1646
+ "center",
1647
+ "end"
1648
+ ],
1649
+ "description": "Where the heading and lead sit; read by a component whose own align is not set."
1650
+ },
1651
+ "radius": {
1652
+ "type": "integer",
1653
+ "min": 0,
1654
+ "max": 200,
1655
+ "description": "Card and item corner radius."
1656
+ },
1657
+ "minHeight": {
1658
+ "type": "integer",
1659
+ "min": 0,
1660
+ "max": 2000,
1661
+ "description": "The section's minimum height."
1662
+ }
1663
+ }
1664
+ },
1665
+ "id": {
1666
+ "type": "string",
1667
+ "content": false,
1668
+ "description": "Anchor id of the section; the heading gets `<id>-title`."
1669
+ }
1670
+ },
1671
+ "slots": {},
1672
+ "js": "none",
1673
+ "dependencies": {},
1674
+ "sources": {
1675
+ "elementor": [
1676
+ "elementor/call-to-action"
1677
+ ],
1678
+ "divi": [
1679
+ "divi/et_pb_cta"
1680
+ ],
1681
+ "classic": [
1682
+ "classic/cta"
1683
+ ]
1684
+ },
1685
+ "a11y": "A labelled region (aria-labelledby its h2). Buttons are links with their own text. Accent tone swaps the primary button style so its contrast holds.",
1686
+ "files": [
1687
+ "Cta.astro"
1688
+ ],
1689
+ "contentFields": {
1690
+ "heading": "heading",
1691
+ "eyebrow": "eyebrow",
1692
+ "body": "body",
1693
+ "note": "note",
1694
+ "image": "image",
1695
+ "bgImage": "bg_image",
1696
+ "actions": "actions",
1697
+ "actions[].label": "actions[].label",
1698
+ "actions[].href": "actions[].href",
1699
+ "actions[].newTab": "actions[].new_tab",
1700
+ "actions[].style": "actions[].style"
1701
+ }
1702
+ },
1703
+ {
1704
+ "id": "embed",
1705
+ "name": "Embed",
1706
+ "description": "A video, map or player from another site (YouTube, Vimeo, Google Maps, OpenStreetMap, Spotify, SoundCloud, Calendly, Typeform, Google Forms, Loom, Wistia), loaded only on click: until then a poster link to the provider's page, with no iframe, no third-party request and no cookie (YouTube through youtube-nocookie.com). Unknown providers are never framed; they stay a plain link.",
1707
+ "category": "content",
1708
+ "uses": [],
1709
+ "shared": [
1710
+ "KitImage.astro",
1711
+ "types.ts"
1712
+ ],
1713
+ "variants": {
1714
+ "aspect": {
1715
+ "options": [
1716
+ "auto",
1717
+ "video",
1718
+ "portrait",
1719
+ "square",
1720
+ "map"
1721
+ ],
1722
+ "default": "auto",
1723
+ "description": "auto: 16:9 for videos, 9:16 for YouTube Shorts, 4:3 (16:9 wide) for maps, a fixed strip for audio players. The others force a ratio."
1724
+ },
1725
+ "width": {
1726
+ "options": [
1727
+ "prose",
1728
+ "page"
1729
+ ],
1730
+ "default": "prose",
1731
+ "description": "prose: as wide as the reading column. page: the full page frame."
1381
1732
  }
1382
1733
  },
1383
1734
  "props": {
@@ -1469,6 +1820,30 @@
1469
1820
  "types.ts"
1470
1821
  ],
1471
1822
  "variants": {
1823
+ "layout": {
1824
+ "options": [
1825
+ "single",
1826
+ "split"
1827
+ ],
1828
+ "default": "single",
1829
+ "description": "single: the heading above one column. split: the heading and introduction stay in a left column beside the list; stacks on a phone."
1830
+ },
1831
+ "columns": {
1832
+ "options": [
1833
+ "1",
1834
+ "2"
1835
+ ],
1836
+ "default": "1",
1837
+ "description": "Columns of questions on wide screens."
1838
+ },
1839
+ "icon": {
1840
+ "options": [
1841
+ "plus",
1842
+ "chevron"
1843
+ ],
1844
+ "default": "plus",
1845
+ "description": "The marker in each question's row: a plus that turns into a cross, or a chevron that turns over."
1846
+ },
1472
1847
  "style": {
1473
1848
  "options": [
1474
1849
  "lines",
@@ -1526,6 +1901,11 @@
1526
1901
  "label": "Heading",
1527
1902
  "description": "Section heading."
1528
1903
  },
1904
+ "intro": {
1905
+ "type": "text",
1906
+ "label": "Introduction",
1907
+ "description": "A sentence under the heading."
1908
+ },
1529
1909
  "exclusive": {
1530
1910
  "type": "boolean",
1531
1911
  "default": false,
@@ -1544,68 +1924,185 @@
1544
1924
  "content": false,
1545
1925
  "description": "Emit FAQPage JSON-LD built from these items. Use on at most one FAQ per page, and only when the page is really a FAQ."
1546
1926
  },
1547
- "id": {
1548
- "type": "string",
1927
+ "measured": {
1928
+ "type": "object",
1549
1929
  "content": false,
1550
- "description": "Section id; also the exclusive group's name."
1551
- }
1552
- },
1553
- "slots": {},
1554
- "js": "none",
1555
- "dependencies": {},
1556
- "sources": {
1557
- "gutenberg": [
1558
- "core/details"
1559
- ],
1560
- "elementor": [
1561
- "elementor/accordion",
1562
- "elementor/toggle",
1563
- "elementor/nested-accordion"
1564
- ],
1565
- "divi": [
1566
- "divi/et_pb_accordion",
1567
- "divi/et_pb_toggle"
1568
- ],
1569
- "classic": [
1570
- "classic/faq"
1571
- ]
1572
- },
1573
- "a11y": "Native <details>/<summary>: keyboard operable and announced as expandable by every screen reader, with no script to fail. The plus icon is decorative. The JSON-LD answer text is the answer with its markup removed.",
1574
- "files": [
1575
- "Faq.astro"
1576
- ],
1577
- "contentFields": {
1578
- "items": "items",
1579
- "items[].question": "items[].question",
1580
- "items[].answer": "items[].answer",
1581
- "heading": "heading"
1582
- }
1583
- },
1584
- {
1585
- "id": "feature-list",
1586
- "name": "Feature list",
1587
- "description": "A list of short features, each a title and a line of text marked with an icon or a check, under an optional heading and intro. Lighter than a card grid: no images, no links.",
1588
- "category": "section",
1589
- "uses": [],
1590
- "shared": [
1591
- "Section.astro",
1592
- "measured.ts",
1593
- "types.ts"
1594
- ],
1595
- "variants": {
1596
- "columns": {
1597
- "options": [
1598
- "2",
1599
- "3",
1600
- "4"
1601
- ],
1602
- "default": "3",
1603
- "description": "Features per row on wide screens; one on phones, two on tablets."
1604
- },
1605
- "style": {
1606
- "options": [
1607
- "icon",
1608
- "check",
1930
+ "description": "The source section's measured style (MeasuredStyle): frame width, padding, fill, image, columns per width, gap, text tone, radius, minimum height — all in pixels. Absent, the site's tokens; present, it wins over tone and columns. Values that are not a number, a colour or a known keyword are dropped.",
1931
+ "fields": {
1932
+ "containerPx": {
1933
+ "type": "integer",
1934
+ "min": 0,
1935
+ "max": 2560,
1936
+ "description": "The frame's content width."
1937
+ },
1938
+ "padY": {
1939
+ "type": "integer",
1940
+ "min": 0,
1941
+ "max": 400,
1942
+ "description": "Top and bottom padding."
1943
+ },
1944
+ "padX": {
1945
+ "type": "integer",
1946
+ "min": 0,
1947
+ "max": 200,
1948
+ "description": "The frame's side padding (gutter)."
1949
+ },
1950
+ "bg": {
1951
+ "type": "object",
1952
+ "description": "The section's background.",
1953
+ "fields": {
1954
+ "color": {
1955
+ "type": "string",
1956
+ "description": "Fill colour: hex, rgb(a) or hsl(a)."
1957
+ },
1958
+ "image": {
1959
+ "type": "string",
1960
+ "description": "Background image address (http(s) or root-relative), drawn behind the content."
1961
+ },
1962
+ "overlay": {
1963
+ "type": "string",
1964
+ "description": "Colour or linear/radial gradient laid over the image or the fill."
1965
+ },
1966
+ "size": {
1967
+ "type": "string",
1968
+ "description": "cover, contain or auto; anything else draws as cover."
1969
+ },
1970
+ "position": {
1971
+ "type": "string",
1972
+ "description": "One or two of center/top/bottom/left/right or percentages."
1973
+ }
1974
+ }
1975
+ },
1976
+ "columns": {
1977
+ "type": "object",
1978
+ "description": "Item columns at 390 (base), 768 (md) and 1280 (lg) px; a missing width follows the narrower one.",
1979
+ "fields": {
1980
+ "390": {
1981
+ "type": "integer",
1982
+ "min": 1,
1983
+ "max": 6,
1984
+ "description": "Phone."
1985
+ },
1986
+ "768": {
1987
+ "type": "integer",
1988
+ "min": 1,
1989
+ "max": 6,
1990
+ "description": "Tablet."
1991
+ },
1992
+ "1280": {
1993
+ "type": "integer",
1994
+ "min": 1,
1995
+ "max": 6,
1996
+ "description": "Desktop."
1997
+ }
1998
+ }
1999
+ },
2000
+ "gap": {
2001
+ "type": "integer",
2002
+ "min": 0,
2003
+ "max": 200,
2004
+ "description": "Gap between items."
2005
+ },
2006
+ "tone": {
2007
+ "type": "select",
2008
+ "options": [
2009
+ "light",
2010
+ "dark"
2011
+ ],
2012
+ "description": "What the text is set for: dark = light text on a dark band. Without it, a fill's own lightness decides."
2013
+ },
2014
+ "align": {
2015
+ "type": "select",
2016
+ "options": [
2017
+ "start",
2018
+ "center",
2019
+ "end"
2020
+ ],
2021
+ "description": "Where the heading and lead sit; read by a component whose own align is not set."
2022
+ },
2023
+ "radius": {
2024
+ "type": "integer",
2025
+ "min": 0,
2026
+ "max": 200,
2027
+ "description": "Card and item corner radius."
2028
+ },
2029
+ "minHeight": {
2030
+ "type": "integer",
2031
+ "min": 0,
2032
+ "max": 2000,
2033
+ "description": "The section's minimum height."
2034
+ }
2035
+ }
2036
+ },
2037
+ "id": {
2038
+ "type": "string",
2039
+ "content": false,
2040
+ "description": "Section id; also the exclusive group's name."
2041
+ },
2042
+ "numbered": {
2043
+ "type": "boolean",
2044
+ "default": false,
2045
+ "content": false,
2046
+ "description": "Count the questions with a leading number, drawn by the page's style rather than written into the text."
2047
+ }
2048
+ },
2049
+ "slots": {},
2050
+ "js": "none",
2051
+ "dependencies": {},
2052
+ "sources": {
2053
+ "gutenberg": [
2054
+ "core/details"
2055
+ ],
2056
+ "elementor": [
2057
+ "elementor/accordion",
2058
+ "elementor/toggle",
2059
+ "elementor/nested-accordion"
2060
+ ],
2061
+ "divi": [
2062
+ "divi/et_pb_accordion",
2063
+ "divi/et_pb_toggle"
2064
+ ],
2065
+ "classic": [
2066
+ "classic/faq"
2067
+ ]
2068
+ },
2069
+ "a11y": "Native <details>/<summary>: keyboard operable and announced as expandable by every screen reader, with no script to fail. The plus icon is decorative. The JSON-LD answer text is the answer with its markup removed.",
2070
+ "files": [
2071
+ "Faq.astro"
2072
+ ],
2073
+ "contentFields": {
2074
+ "items": "items",
2075
+ "items[].question": "items[].question",
2076
+ "items[].answer": "items[].answer",
2077
+ "heading": "heading",
2078
+ "intro": "intro"
2079
+ }
2080
+ },
2081
+ {
2082
+ "id": "feature-list",
2083
+ "name": "Feature list",
2084
+ "description": "A list of short features, each a title and a line of text marked with an icon or a check, under an optional heading and intro. Lighter than a card grid: no images, no links.",
2085
+ "category": "section",
2086
+ "uses": [],
2087
+ "shared": [
2088
+ "Section.astro",
2089
+ "measured.ts",
2090
+ "types.ts"
2091
+ ],
2092
+ "variants": {
2093
+ "columns": {
2094
+ "options": [
2095
+ "2",
2096
+ "3",
2097
+ "4"
2098
+ ],
2099
+ "default": "3",
2100
+ "description": "Features per row on wide screens; one on phones, two on tablets."
2101
+ },
2102
+ "style": {
2103
+ "options": [
2104
+ "icon",
2105
+ "check",
1609
2106
  "list"
1610
2107
  ],
1611
2108
  "default": "icon",
@@ -1670,10 +2167,17 @@
1670
2167
  },
1671
2168
  "description": "The features, in order (Elementor icon list or icon boxes without images, Gutenberg list of features, Divi blurbs with icons)."
1672
2169
  },
1673
- "id": {
1674
- "type": "string",
2170
+ "bare": {
2171
+ "type": "boolean",
2172
+ "default": false,
1675
2173
  "content": false,
1676
- "description": "Anchor id of the section; the heading gets `<id>-title`."
2174
+ "description": "Only the list, with no section of its own; a split section uses it under its text."
2175
+ },
2176
+ "titleLevel": {
2177
+ "type": "integer",
2178
+ "default": 3,
2179
+ "content": false,
2180
+ "description": "With `bare`: the item titles' heading level (the section's plus one)."
1677
2181
  },
1678
2182
  "measured": {
1679
2183
  "type": "object",
@@ -1784,6 +2288,11 @@
1784
2288
  "description": "The section's minimum height."
1785
2289
  }
1786
2290
  }
2291
+ },
2292
+ "id": {
2293
+ "type": "string",
2294
+ "content": false,
2295
+ "description": "Anchor id of the section; the heading gets `<id>-title`."
1787
2296
  }
1788
2297
  },
1789
2298
  "slots": {},
@@ -2035,19 +2544,23 @@
2035
2544
  "layout": {
2036
2545
  "options": [
2037
2546
  "grid",
2038
- "masonry"
2547
+ "masonry",
2548
+ "row",
2549
+ "mosaic"
2039
2550
  ],
2040
2551
  "default": "grid",
2041
- "description": "grid: square crops in rows. masonry: columns that keep each image's shape."
2552
+ "description": "grid: equal tiles. masonry: columns keeping each image's height. row: a scroll-snap strip (a focusable region). mosaic: the first tile spans 2×2."
2042
2553
  },
2043
2554
  "columns": {
2044
2555
  "options": [
2045
2556
  "2",
2046
2557
  "3",
2047
- "4"
2558
+ "4",
2559
+ "5",
2560
+ "6"
2048
2561
  ],
2049
2562
  "default": "3",
2050
- "description": "Columns on wide screens; phones show two."
2563
+ "description": "Images per row on wide screens; two on phones."
2051
2564
  },
2052
2565
  "open": {
2053
2566
  "options": [
@@ -2057,6 +2570,41 @@
2057
2570
  ],
2058
2571
  "default": "popover",
2059
2572
  "description": "popover: the image opens large in place (Popover API; Escape or a click outside closes it). link: the thumbnail links to the image file (the WordPress 'link to media file'). none: images only."
2573
+ },
2574
+ "aspect": {
2575
+ "options": [
2576
+ "square",
2577
+ "4:3",
2578
+ "16:9",
2579
+ "auto"
2580
+ ],
2581
+ "default": "square",
2582
+ "description": "Tile shape (a masonry keeps each image's own)."
2583
+ },
2584
+ "gap": {
2585
+ "options": [
2586
+ "sm",
2587
+ "md",
2588
+ "lg"
2589
+ ],
2590
+ "default": "md",
2591
+ "description": "Space between tiles."
2592
+ },
2593
+ "captionStyle": {
2594
+ "options": [
2595
+ "below",
2596
+ "overlay"
2597
+ ],
2598
+ "default": "below",
2599
+ "description": "below: caption under the image. overlay: over the image foot on hover and keyboard focus, always shown below md."
2600
+ },
2601
+ "hoverEffect": {
2602
+ "options": [
2603
+ "none",
2604
+ "zoom"
2605
+ ],
2606
+ "default": "none",
2607
+ "description": "zoom: a slight scale on hover, only where reduced motion is not requested."
2060
2608
  }
2061
2609
  },
2062
2610
  "props": {
@@ -2082,6 +2630,11 @@
2082
2630
  "type": "string",
2083
2631
  "label": "Caption",
2084
2632
  "description": "Caption under the enlarged image."
2633
+ },
2634
+ "full": {
2635
+ "type": "image",
2636
+ "label": "Full-size image",
2637
+ "description": "The original file the viewer shows large, where the source links to it; otherwise the image itself."
2085
2638
  }
2086
2639
  }
2087
2640
  },
@@ -2112,55 +2665,178 @@
2112
2665
  "type": "string",
2113
2666
  "content": false,
2114
2667
  "description": "Section id, unique per page: viewer ids derive from it (`<id>-image-<n>`)."
2115
- }
2116
- },
2117
- "slots": {},
2118
- "js": "none",
2119
- "dependencies": {},
2120
- "sources": {
2121
- "gutenberg": [
2122
- "core/gallery"
2123
- ],
2124
- "elementor": [
2125
- "elementor/image-gallery",
2126
- "elementor/gallery"
2127
- ],
2128
- "divi": [
2129
- "divi/et_pb_gallery"
2130
- ],
2131
- "classic": [
2132
- "classic/gallery"
2133
- ]
2134
- },
2135
- "a11y": "A list of figures. In popover mode each thumbnail is a <button> named by the image's alt (or caption) that opens the viewer; the viewer has a visible close button, and Escape closes it, returning focus to the thumbnail. Captions are <figcaption>s.",
2136
- "files": [
2137
- "Gallery.astro"
2138
- ],
2139
- "contentFields": {
2140
- "items": "items",
2141
- "items[].image": "items[].image",
2142
- "items[].imageAlt": "items[].image_alt",
2143
- "items[].caption": "items[].caption",
2144
- "heading": "heading"
2145
- }
2146
- },
2147
- {
2148
- "id": "header",
2149
- "name": "Header",
2150
- "description": "Site header: brand (logo and/or name), navigation and an optional call-to-action button.",
2151
- "category": "chrome",
2152
- "uses": [
2153
- "nav"
2154
- ],
2155
- "shared": [
2156
- "Button.astro",
2157
- "KitImage.astro",
2158
- "types.ts"
2159
- ],
2160
- "variants": {
2161
- "layout": {
2162
- "options": [
2163
- "split",
2668
+ },
2669
+ "enlargeLabel": {
2670
+ "type": "string",
2671
+ "default": "Enlarge",
2672
+ "content": false,
2673
+ "description": "Prefix of each thumbnail button's name for screen readers (\"Enlarge: <description>\")."
2674
+ },
2675
+ "regionLabel": {
2676
+ "type": "string",
2677
+ "default": "Images",
2678
+ "content": false,
2679
+ "description": "Name of the scrolling row's region when the gallery has no heading."
2680
+ },
2681
+ "measured": {
2682
+ "type": "object",
2683
+ "content": false,
2684
+ "description": "The source section's measured style (MeasuredStyle): frame width, padding, fill, image, columns per width, gap, text tone, radius, minimum height — all in pixels. Absent, the site's tokens; present, it wins over tone and columns. Values that are not a number, a colour or a known keyword are dropped.",
2685
+ "fields": {
2686
+ "containerPx": {
2687
+ "type": "integer",
2688
+ "min": 0,
2689
+ "max": 2560,
2690
+ "description": "The frame's content width."
2691
+ },
2692
+ "padY": {
2693
+ "type": "integer",
2694
+ "min": 0,
2695
+ "max": 400,
2696
+ "description": "Top and bottom padding."
2697
+ },
2698
+ "padX": {
2699
+ "type": "integer",
2700
+ "min": 0,
2701
+ "max": 200,
2702
+ "description": "The frame's side padding (gutter)."
2703
+ },
2704
+ "bg": {
2705
+ "type": "object",
2706
+ "description": "The section's background.",
2707
+ "fields": {
2708
+ "color": {
2709
+ "type": "string",
2710
+ "description": "Fill colour: hex, rgb(a) or hsl(a)."
2711
+ },
2712
+ "image": {
2713
+ "type": "string",
2714
+ "description": "Background image address (http(s) or root-relative), drawn behind the content."
2715
+ },
2716
+ "overlay": {
2717
+ "type": "string",
2718
+ "description": "Colour or linear/radial gradient laid over the image or the fill."
2719
+ },
2720
+ "size": {
2721
+ "type": "string",
2722
+ "description": "cover, contain or auto; anything else draws as cover."
2723
+ },
2724
+ "position": {
2725
+ "type": "string",
2726
+ "description": "One or two of center/top/bottom/left/right or percentages."
2727
+ }
2728
+ }
2729
+ },
2730
+ "columns": {
2731
+ "type": "object",
2732
+ "description": "Item columns at 390 (base), 768 (md) and 1280 (lg) px; a missing width follows the narrower one.",
2733
+ "fields": {
2734
+ "390": {
2735
+ "type": "integer",
2736
+ "min": 1,
2737
+ "max": 6,
2738
+ "description": "Phone."
2739
+ },
2740
+ "768": {
2741
+ "type": "integer",
2742
+ "min": 1,
2743
+ "max": 6,
2744
+ "description": "Tablet."
2745
+ },
2746
+ "1280": {
2747
+ "type": "integer",
2748
+ "min": 1,
2749
+ "max": 6,
2750
+ "description": "Desktop."
2751
+ }
2752
+ }
2753
+ },
2754
+ "gap": {
2755
+ "type": "integer",
2756
+ "min": 0,
2757
+ "max": 200,
2758
+ "description": "Gap between items."
2759
+ },
2760
+ "tone": {
2761
+ "type": "select",
2762
+ "options": [
2763
+ "light",
2764
+ "dark"
2765
+ ],
2766
+ "description": "What the text is set for: dark = light text on a dark band. Without it, a fill's own lightness decides."
2767
+ },
2768
+ "align": {
2769
+ "type": "select",
2770
+ "options": [
2771
+ "start",
2772
+ "center",
2773
+ "end"
2774
+ ],
2775
+ "description": "Where the heading and lead sit; read by a component whose own align is not set."
2776
+ },
2777
+ "radius": {
2778
+ "type": "integer",
2779
+ "min": 0,
2780
+ "max": 200,
2781
+ "description": "Card and item corner radius."
2782
+ },
2783
+ "minHeight": {
2784
+ "type": "integer",
2785
+ "min": 0,
2786
+ "max": 2000,
2787
+ "description": "The section's minimum height."
2788
+ }
2789
+ }
2790
+ }
2791
+ },
2792
+ "slots": {},
2793
+ "js": "none",
2794
+ "dependencies": {},
2795
+ "sources": {
2796
+ "gutenberg": [
2797
+ "core/gallery"
2798
+ ],
2799
+ "elementor": [
2800
+ "elementor/image-gallery",
2801
+ "elementor/gallery"
2802
+ ],
2803
+ "divi": [
2804
+ "divi/et_pb_gallery"
2805
+ ],
2806
+ "classic": [
2807
+ "classic/gallery"
2808
+ ]
2809
+ },
2810
+ "a11y": "A list of figures. In popover mode each thumbnail is a <button> named by the image's alt (or caption) that opens the viewer; the viewer has a visible close button, and Escape closes it, returning focus to the thumbnail. Captions are <figcaption>s. A scrolling row is a labelled region with tabindex 0 so the keyboard can scroll it; thumbnail buttons are named \"Enlarge: …\". The viewer has no next/previous (it would need script).",
2811
+ "files": [
2812
+ "Gallery.astro"
2813
+ ],
2814
+ "contentFields": {
2815
+ "items": "items",
2816
+ "items[].image": "items[].image",
2817
+ "items[].imageAlt": "items[].image_alt",
2818
+ "items[].caption": "items[].caption",
2819
+ "items[].full": "items[].full",
2820
+ "heading": "heading"
2821
+ }
2822
+ },
2823
+ {
2824
+ "id": "header",
2825
+ "name": "Header",
2826
+ "description": "Site header: brand (logo and/or name), navigation and an optional call-to-action button.",
2827
+ "category": "chrome",
2828
+ "uses": [
2829
+ "nav"
2830
+ ],
2831
+ "shared": [
2832
+ "Button.astro",
2833
+ "KitImage.astro",
2834
+ "types.ts"
2835
+ ],
2836
+ "variants": {
2837
+ "layout": {
2838
+ "options": [
2839
+ "split",
2164
2840
  "centered",
2165
2841
  "brand-left"
2166
2842
  ],
@@ -2681,7 +3357,7 @@
2681
3357
  {
2682
3358
  "id": "logo-cloud",
2683
3359
  "name": "Logo cloud",
2684
- "description": "A grid of client or partner logos, each optionally linked, under an optional heading (\"Trusted by\").",
3360
+ "description": "A grid, a row or an endless strip of client or partner logos, each optionally linked, under an optional heading (\"Trusted by\").",
2685
3361
  "category": "section",
2686
3362
  "uses": [],
2687
3363
  "shared": [
@@ -2692,22 +3368,51 @@
2692
3368
  "types.ts"
2693
3369
  ],
2694
3370
  "variants": {
3371
+ "layout": {
3372
+ "options": [
3373
+ "grid",
3374
+ "row",
3375
+ "marquee"
3376
+ ],
3377
+ "default": "grid",
3378
+ "description": "grid: logos in columns. row: one line that wraps. marquee: an endless CSS-only strip that stands still for reduced motion."
3379
+ },
2695
3380
  "columns": {
2696
3381
  "options": [
2697
3382
  "2",
2698
3383
  "3",
2699
- "4"
3384
+ "4",
3385
+ "5",
3386
+ "6"
2700
3387
  ],
2701
3388
  "default": "4",
2702
- "description": "Logos per row on wide screens; two on phones, three on tablets."
3389
+ "description": "Logos per row on wide screens (grid layout); two on phones, three on tablets."
3390
+ },
3391
+ "logoHeight": {
3392
+ "options": [
3393
+ "sm",
3394
+ "md",
3395
+ "lg"
3396
+ ],
3397
+ "default": "md",
3398
+ "description": "Height of every logo (the width follows): small, medium or large."
2703
3399
  },
2704
3400
  "style": {
2705
3401
  "options": [
2706
3402
  "plain",
2707
- "grayscale"
3403
+ "grayscale",
3404
+ "mono-light"
2708
3405
  ],
2709
3406
  "default": "plain",
2710
- "description": "plain: logos in their own colours. grayscale: muted grey, full colour on hover or focus."
3407
+ "description": "plain: logos in their own colours. grayscale: muted grey, full colour on hover or focus. mono-light: drawn white, for a dark band."
3408
+ },
3409
+ "align": {
3410
+ "options": [
3411
+ "center",
3412
+ "start"
3413
+ ],
3414
+ "default": "center",
3415
+ "description": "Alignment of the heading and of the logos in a row."
2711
3416
  },
2712
3417
  "tone": {
2713
3418
  "options": [
@@ -2754,77 +3459,187 @@
2754
3459
  },
2755
3460
  "description": "The logos, in order (a Gutenberg gallery or columns of logos, Elementor image carousel/gallery of logos, Divi images)."
2756
3461
  },
2757
- "id": {
2758
- "type": "string",
3462
+ "measured": {
3463
+ "type": "object",
2759
3464
  "content": false,
2760
- "description": "Anchor id of the section; the heading gets `<id>-title`."
2761
- }
2762
- },
2763
- "slots": {},
2764
- "js": "none",
2765
- "dependencies": {},
2766
- "sources": {
2767
- "gutenberg": [
2768
- "core/gallery"
2769
- ],
2770
- "elementor": [
2771
- "elementor/image-gallery",
2772
- "elementor/image-carousel"
2773
- ],
2774
- "divi": [
2775
- "divi/et_pb_gallery"
2776
- ]
2777
- },
2778
- "a11y": "A list of logos; each logo's text is the company's name, and a linked logo is one link named by it. The section is labelled by its heading.",
2779
- "pattern": {
2780
- "summary": "row of small logos, often linked",
2781
- "signals": [
2782
- "4+ images",
2783
- "small images",
2784
- "little or no text",
2785
- "optional heading"
2786
- ]
2787
- },
2788
- "files": [
2789
- "LogoCloud.astro"
2790
- ],
2791
- "contentFields": {
2792
- "heading": "heading",
2793
- "items": "items",
2794
- "items[].image": "items[].image",
2795
- "items[].imageAlt": "items[].image_alt",
2796
- "items[].href": "items[].href"
2797
- }
2798
- },
2799
- {
2800
- "id": "nav",
2801
- "name": "Navigation",
2802
- "description": "Site navigation: an inline list with hover/focus submenus on wide screens and a toggle on narrow ones that opens a native popover drawer or a <details> dropdown. No JavaScript.",
2803
- "category": "chrome",
2804
- "uses": [],
2805
- "shared": [
2806
- "types.ts"
2807
- ],
2808
- "variants": {
2809
- "mobile": {
2810
- "options": [
2811
- "popover",
2812
- "details"
2813
- ],
2814
- "default": "popover",
2815
- "description": "Narrow-screen menu: a side drawer (Popover API) or a dropdown under the toggle."
2816
- },
2817
- "align": {
2818
- "options": [
2819
- "start",
2820
- "end",
2821
- "center"
2822
- ],
2823
- "default": "end",
2824
- "description": "Horizontal alignment of the inline list."
2825
- },
2826
- "density": {
2827
- "options": [
3465
+ "description": "The source section's measured style (MeasuredStyle): frame width, padding, fill, image, columns per width, gap, text tone, radius, minimum height — all in pixels. Absent, the site's tokens; present, it wins over tone and columns. Values that are not a number, a colour or a known keyword are dropped.",
3466
+ "fields": {
3467
+ "containerPx": {
3468
+ "type": "integer",
3469
+ "min": 0,
3470
+ "max": 2560,
3471
+ "description": "The frame's content width."
3472
+ },
3473
+ "padY": {
3474
+ "type": "integer",
3475
+ "min": 0,
3476
+ "max": 400,
3477
+ "description": "Top and bottom padding."
3478
+ },
3479
+ "padX": {
3480
+ "type": "integer",
3481
+ "min": 0,
3482
+ "max": 200,
3483
+ "description": "The frame's side padding (gutter)."
3484
+ },
3485
+ "bg": {
3486
+ "type": "object",
3487
+ "description": "The section's background.",
3488
+ "fields": {
3489
+ "color": {
3490
+ "type": "string",
3491
+ "description": "Fill colour: hex, rgb(a) or hsl(a)."
3492
+ },
3493
+ "image": {
3494
+ "type": "string",
3495
+ "description": "Background image address (http(s) or root-relative), drawn behind the content."
3496
+ },
3497
+ "overlay": {
3498
+ "type": "string",
3499
+ "description": "Colour or linear/radial gradient laid over the image or the fill."
3500
+ },
3501
+ "size": {
3502
+ "type": "string",
3503
+ "description": "cover, contain or auto; anything else draws as cover."
3504
+ },
3505
+ "position": {
3506
+ "type": "string",
3507
+ "description": "One or two of center/top/bottom/left/right or percentages."
3508
+ }
3509
+ }
3510
+ },
3511
+ "columns": {
3512
+ "type": "object",
3513
+ "description": "Item columns at 390 (base), 768 (md) and 1280 (lg) px; a missing width follows the narrower one.",
3514
+ "fields": {
3515
+ "390": {
3516
+ "type": "integer",
3517
+ "min": 1,
3518
+ "max": 6,
3519
+ "description": "Phone."
3520
+ },
3521
+ "768": {
3522
+ "type": "integer",
3523
+ "min": 1,
3524
+ "max": 6,
3525
+ "description": "Tablet."
3526
+ },
3527
+ "1280": {
3528
+ "type": "integer",
3529
+ "min": 1,
3530
+ "max": 6,
3531
+ "description": "Desktop."
3532
+ }
3533
+ }
3534
+ },
3535
+ "gap": {
3536
+ "type": "integer",
3537
+ "min": 0,
3538
+ "max": 200,
3539
+ "description": "Gap between items."
3540
+ },
3541
+ "tone": {
3542
+ "type": "select",
3543
+ "options": [
3544
+ "light",
3545
+ "dark"
3546
+ ],
3547
+ "description": "What the text is set for: dark = light text on a dark band. Without it, a fill's own lightness decides."
3548
+ },
3549
+ "align": {
3550
+ "type": "select",
3551
+ "options": [
3552
+ "start",
3553
+ "center",
3554
+ "end"
3555
+ ],
3556
+ "description": "Where the heading and lead sit; read by a component whose own align is not set."
3557
+ },
3558
+ "radius": {
3559
+ "type": "integer",
3560
+ "min": 0,
3561
+ "max": 200,
3562
+ "description": "Card and item corner radius."
3563
+ },
3564
+ "minHeight": {
3565
+ "type": "integer",
3566
+ "min": 0,
3567
+ "max": 2000,
3568
+ "description": "The section's minimum height."
3569
+ }
3570
+ }
3571
+ },
3572
+ "id": {
3573
+ "type": "string",
3574
+ "content": false,
3575
+ "description": "Anchor id of the section; the heading gets `<id>-title`."
3576
+ }
3577
+ },
3578
+ "slots": {},
3579
+ "js": "none",
3580
+ "dependencies": {},
3581
+ "sources": {
3582
+ "gutenberg": [
3583
+ "core/gallery"
3584
+ ],
3585
+ "elementor": [
3586
+ "elementor/image-gallery",
3587
+ "elementor/image-carousel"
3588
+ ],
3589
+ "divi": [
3590
+ "divi/et_pb_gallery"
3591
+ ]
3592
+ },
3593
+ "a11y": "A list of logos; each logo's text is the company's name, and a linked logo is one link named by it. The section is labelled by its heading.",
3594
+ "pattern": {
3595
+ "summary": "row of small logos, often linked",
3596
+ "signals": [
3597
+ "4+ images",
3598
+ "small images",
3599
+ "little or no text",
3600
+ "optional heading"
3601
+ ]
3602
+ },
3603
+ "files": [
3604
+ "LogoCloud.astro"
3605
+ ],
3606
+ "contentFields": {
3607
+ "heading": "heading",
3608
+ "items": "items",
3609
+ "items[].image": "items[].image",
3610
+ "items[].imageAlt": "items[].image_alt",
3611
+ "items[].href": "items[].href"
3612
+ }
3613
+ },
3614
+ {
3615
+ "id": "nav",
3616
+ "name": "Navigation",
3617
+ "description": "Site navigation: an inline list with hover/focus submenus on wide screens and a toggle on narrow ones that opens a native popover drawer or a <details> dropdown. No JavaScript.",
3618
+ "category": "chrome",
3619
+ "uses": [],
3620
+ "shared": [
3621
+ "types.ts"
3622
+ ],
3623
+ "variants": {
3624
+ "mobile": {
3625
+ "options": [
3626
+ "popover",
3627
+ "details"
3628
+ ],
3629
+ "default": "popover",
3630
+ "description": "Narrow-screen menu: a side drawer (Popover API) or a dropdown under the toggle."
3631
+ },
3632
+ "align": {
3633
+ "options": [
3634
+ "start",
3635
+ "end",
3636
+ "center"
3637
+ ],
3638
+ "default": "end",
3639
+ "description": "Horizontal alignment of the inline list."
3640
+ },
3641
+ "density": {
3642
+ "options": [
2828
3643
  "compact",
2829
3644
  "comfortable"
2830
3645
  ],
@@ -3356,6 +4171,13 @@
3356
4171
  "imageAspect": {
3357
4172
  "type": "string",
3358
4173
  "description": "The image block's aspect ratio (16 / 9) where the source sets an aspect ratio; absent, 16 / 9."
4174
+ },
4175
+ "excerptLines": {
4176
+ "type": "integer",
4177
+ "min": 2,
4178
+ "max": 4,
4179
+ "content": false,
4180
+ "description": "Clamp the excerpt to this many lines; absent, the layout's own (3 vertical, 2 otherwise)."
3359
4181
  }
3360
4182
  },
3361
4183
  "slots": {},
@@ -3384,18 +4206,29 @@
3384
4206
  ]
3385
4207
  },
3386
4208
  {
3387
- "id": "pricing",
3388
- "name": "Pricing",
3389
- "description": "Price plans side by side: name, price, period, a short description, a feature list and a button each. The featured plan is raised and badged.",
4209
+ "id": "post-list",
4210
+ "name": "Post list",
4211
+ "description": "A list of posts as cards: a grid, stacked rows, a featured first post over a grid, or a compact title-and-date list. The posts come from the site's own collection; the switches decide which parts of a card show.",
3390
4212
  "category": "section",
3391
- "uses": [],
4213
+ "uses": [
4214
+ "post-card"
4215
+ ],
3392
4216
  "shared": [
3393
- "Button.astro",
3394
4217
  "Section.astro",
3395
4218
  "measured.ts",
3396
4219
  "types.ts"
3397
4220
  ],
3398
4221
  "variants": {
4222
+ "layout": {
4223
+ "options": [
4224
+ "grid",
4225
+ "list",
4226
+ "featured",
4227
+ "compact"
4228
+ ],
4229
+ "default": "grid",
4230
+ "description": "grid: cards in columns. list: stacked horizontal cards. featured: the first post large over a grid. compact: title and date only."
4231
+ },
3399
4232
  "columns": {
3400
4233
  "options": [
3401
4234
  "2",
@@ -3403,93 +4236,583 @@
3403
4236
  "4"
3404
4237
  ],
3405
4238
  "default": "3",
3406
- "description": "Plans per row on wide screens; one on phones, two on tablets."
3407
- },
3408
- "tone": {
3409
- "options": [
3410
- "default",
3411
- "muted",
3412
- "inverse",
3413
- "accent"
3414
- ],
3415
- "default": "default",
3416
- "description": "Section background."
4239
+ "description": "Cards per row on wide screens (grid and featured)."
3417
4240
  }
3418
4241
  },
3419
4242
  "props": {
3420
4243
  "heading": {
3421
4244
  "type": "string",
3422
4245
  "label": "Heading",
3423
- "description": "Section heading above the plans."
4246
+ "description": "Section heading above the posts."
3424
4247
  },
3425
4248
  "intro": {
3426
4249
  "type": "text",
3427
4250
  "label": "Intro",
3428
4251
  "description": "A line or two under the heading."
3429
4252
  },
3430
- "plans": {
4253
+ "posts": {
3431
4254
  "type": "array",
3432
- "label": "Plans",
4255
+ "label": "Posts",
3433
4256
  "required": true,
4257
+ "content": false,
4258
+ "description": "The posts to show, newest first: from the posts collection (the query SDK), never copied from a page.",
3434
4259
  "items": {
3435
4260
  "type": "object",
3436
4261
  "fields": {
3437
- "name": {
3438
- "type": "string",
3439
- "label": "Name",
3440
- "required": true,
3441
- "description": "The plan's name."
3442
- },
3443
- "price": {
4262
+ "title": {
3444
4263
  "type": "string",
3445
- "label": "Price",
3446
- "required": true,
3447
- "description": "The price as shown, with its currency (\"$12\", \"Free\", \"On request\")."
4264
+ "required": true
3448
4265
  },
3449
- "period": {
3450
- "type": "string",
3451
- "label": "Period",
3452
- "description": "What the price is per (\"/month\")."
4266
+ "href": {
4267
+ "type": "url",
4268
+ "required": true
3453
4269
  },
3454
- "description": {
3455
- "type": "string",
3456
- "label": "Description",
3457
- "description": "One line on who the plan is for."
4270
+ "excerpt": {
4271
+ "type": "text"
3458
4272
  },
3459
- "features": {
3460
- "type": "markdown",
3461
- "label": "Features",
3462
- "description": "What the plan includes, as a markdown list."
4273
+ "date": {
4274
+ "type": "datetime"
3463
4275
  },
3464
- "ctaLabel": {
3465
- "type": "string",
3466
- "label": "Button label",
3467
- "description": "The plan's button text."
4276
+ "image": {
4277
+ "type": "object",
4278
+ "fields": {
4279
+ "src": {
4280
+ "type": "image",
4281
+ "required": true
4282
+ },
4283
+ "alt": {
4284
+ "type": "string",
4285
+ "required": true
4286
+ },
4287
+ "width": {
4288
+ "type": "integer"
4289
+ },
4290
+ "height": {
4291
+ "type": "integer"
4292
+ }
4293
+ }
3468
4294
  },
3469
- "ctaHref": {
3470
- "type": "url",
3471
- "label": "Button link",
3472
- "description": "Where the button goes."
4295
+ "category": {
4296
+ "type": "object",
4297
+ "fields": {
4298
+ "label": {
4299
+ "type": "string",
4300
+ "required": true
4301
+ },
4302
+ "href": {
4303
+ "type": "url",
4304
+ "required": true
4305
+ }
4306
+ }
3473
4307
  },
3474
- "featured": {
3475
- "type": "boolean",
3476
- "label": "Featured",
3477
- "description": "Raises the plan and gives it the badge."
4308
+ "author": {
4309
+ "type": "string"
3478
4310
  }
3479
4311
  }
3480
- },
3481
- "description": "The plans, in display order (Divi pricing tables, Elementor price table)."
4312
+ }
4313
+ },
4314
+ "showImage": {
4315
+ "type": "boolean",
4316
+ "default": true,
4317
+ "content": false,
4318
+ "description": "Show each post's cover."
4319
+ },
4320
+ "showExcerpt": {
4321
+ "type": "boolean",
4322
+ "default": true,
4323
+ "content": false,
4324
+ "description": "Show each post's excerpt."
4325
+ },
4326
+ "showAuthor": {
4327
+ "type": "boolean",
4328
+ "default": true,
4329
+ "content": false,
4330
+ "description": "Show each post's author."
4331
+ },
4332
+ "showCategory": {
4333
+ "type": "boolean",
4334
+ "default": true,
4335
+ "content": false,
4336
+ "description": "Show each post's category."
4337
+ },
4338
+ "excerptLines": {
4339
+ "type": "integer",
4340
+ "min": 2,
4341
+ "max": 4,
4342
+ "content": false,
4343
+ "description": "Clamp each excerpt to this many lines."
4344
+ },
4345
+ "locale": {
4346
+ "type": "string",
4347
+ "content": false,
4348
+ "description": "BCP 47 locale the dates are written in (site.language)."
4349
+ },
4350
+ "surface": {
4351
+ "type": "string",
4352
+ "content": false,
4353
+ "description": "plain or card: whether each post is a card of its own (post-card surface)."
4354
+ },
4355
+ "moreHref": {
4356
+ "type": "url",
4357
+ "content": false,
4358
+ "description": "Where the full archive lives; with moreLabel a link follows the list."
4359
+ },
4360
+ "moreLabel": {
4361
+ "type": "string",
4362
+ "content": false,
4363
+ "description": "Text of the archive link."
4364
+ },
4365
+ "tone": {
4366
+ "type": "string",
4367
+ "content": false,
4368
+ "description": "Section background: default, muted, inverse or accent."
4369
+ },
4370
+ "id": {
4371
+ "type": "string",
4372
+ "content": false,
4373
+ "description": "Anchor id of the section; the heading gets `<id>-title`."
4374
+ },
4375
+ "measured": {
4376
+ "type": "object",
4377
+ "content": false,
4378
+ "description": "The source section's measured style (MeasuredStyle): frame width, padding, fill, image, columns per width, gap, text tone, radius, minimum height — all in pixels. Absent, the site's tokens; present, it wins over tone and columns. Values that are not a number, a colour or a known keyword are dropped.",
4379
+ "fields": {
4380
+ "containerPx": {
4381
+ "type": "integer",
4382
+ "min": 0,
4383
+ "max": 2560,
4384
+ "description": "The frame's content width."
4385
+ },
4386
+ "padY": {
4387
+ "type": "integer",
4388
+ "min": 0,
4389
+ "max": 400,
4390
+ "description": "Top and bottom padding."
4391
+ },
4392
+ "padX": {
4393
+ "type": "integer",
4394
+ "min": 0,
4395
+ "max": 200,
4396
+ "description": "The frame's side padding (gutter)."
4397
+ },
4398
+ "bg": {
4399
+ "type": "object",
4400
+ "description": "The section's background.",
4401
+ "fields": {
4402
+ "color": {
4403
+ "type": "string",
4404
+ "description": "Fill colour: hex, rgb(a) or hsl(a)."
4405
+ },
4406
+ "image": {
4407
+ "type": "string",
4408
+ "description": "Background image address (http(s) or root-relative), drawn behind the content."
4409
+ },
4410
+ "overlay": {
4411
+ "type": "string",
4412
+ "description": "Colour or linear/radial gradient laid over the image or the fill."
4413
+ },
4414
+ "size": {
4415
+ "type": "string",
4416
+ "description": "cover, contain or auto; anything else draws as cover."
4417
+ },
4418
+ "position": {
4419
+ "type": "string",
4420
+ "description": "One or two of center/top/bottom/left/right or percentages."
4421
+ }
4422
+ }
4423
+ },
4424
+ "columns": {
4425
+ "type": "object",
4426
+ "description": "Item columns at 390 (base), 768 (md) and 1280 (lg) px; a missing width follows the narrower one.",
4427
+ "fields": {
4428
+ "390": {
4429
+ "type": "integer",
4430
+ "min": 1,
4431
+ "max": 6,
4432
+ "description": "Phone."
4433
+ },
4434
+ "768": {
4435
+ "type": "integer",
4436
+ "min": 1,
4437
+ "max": 6,
4438
+ "description": "Tablet."
4439
+ },
4440
+ "1280": {
4441
+ "type": "integer",
4442
+ "min": 1,
4443
+ "max": 6,
4444
+ "description": "Desktop."
4445
+ }
4446
+ }
4447
+ },
4448
+ "gap": {
4449
+ "type": "integer",
4450
+ "min": 0,
4451
+ "max": 200,
4452
+ "description": "Gap between items."
4453
+ },
4454
+ "tone": {
4455
+ "type": "select",
4456
+ "options": [
4457
+ "light",
4458
+ "dark"
4459
+ ],
4460
+ "description": "What the text is set for: dark = light text on a dark band. Without it, a fill's own lightness decides."
4461
+ },
4462
+ "align": {
4463
+ "type": "select",
4464
+ "options": [
4465
+ "start",
4466
+ "center",
4467
+ "end"
4468
+ ],
4469
+ "description": "Where the heading and lead sit; read by a component whose own align is not set."
4470
+ },
4471
+ "radius": {
4472
+ "type": "integer",
4473
+ "min": 0,
4474
+ "max": 200,
4475
+ "description": "Card and item corner radius."
4476
+ },
4477
+ "minHeight": {
4478
+ "type": "integer",
4479
+ "min": 0,
4480
+ "max": 2000,
4481
+ "description": "The section's minimum height."
4482
+ }
4483
+ }
4484
+ }
4485
+ },
4486
+ "slots": {},
4487
+ "js": "none",
4488
+ "dependencies": {},
4489
+ "sources": {
4490
+ "gutenberg": [
4491
+ "core/query",
4492
+ "core/latest-posts"
4493
+ ],
4494
+ "elementor": [
4495
+ "elementor/posts",
4496
+ "elementor/archive-posts"
4497
+ ],
4498
+ "divi": [
4499
+ "divi/et_pb_blog"
4500
+ ],
4501
+ "classic": [
4502
+ "classic/archive-item"
4503
+ ]
4504
+ },
4505
+ "a11y": "A <ul> of cards, each an <article> with one link (the title, stretched over the card) and a <time datetime>. Cards sit one heading level under the section heading, or at h2 when there is none. Images are decorative next to their title; the featured card keeps reading order.",
4506
+ "pattern": {
4507
+ "summary": "a repeated post card: image + title + excerpt + date, as a grid, rows or a featured first post",
4508
+ "signals": [
4509
+ "2-4 columns",
4510
+ "date text",
4511
+ "one link per card",
4512
+ "repeated card structure"
4513
+ ]
4514
+ },
4515
+ "files": [
4516
+ "PostList.astro"
4517
+ ],
4518
+ "contentFields": {
4519
+ "heading": "heading",
4520
+ "intro": "intro"
4521
+ }
4522
+ },
4523
+ {
4524
+ "id": "pricing",
4525
+ "name": "Pricing",
4526
+ "description": "Price plans side by side: name, price, period, a short description, a feature list and a button each. The featured plan is raised and badged.",
4527
+ "category": "section",
4528
+ "uses": [],
4529
+ "shared": [
4530
+ "Button.astro",
4531
+ "Section.astro",
4532
+ "measured.ts",
4533
+ "types.ts"
4534
+ ],
4535
+ "variants": {
4536
+ "columns": {
4537
+ "options": [
4538
+ "2",
4539
+ "3",
4540
+ "4"
4541
+ ],
4542
+ "default": "3",
4543
+ "description": "Plans per row on wide screens; one on phones, two on tablets."
4544
+ },
4545
+ "tone": {
4546
+ "options": [
4547
+ "default",
4548
+ "muted",
4549
+ "inverse",
4550
+ "accent"
4551
+ ],
4552
+ "default": "default",
4553
+ "description": "Section background."
4554
+ },
4555
+ "layout": {
4556
+ "options": [
4557
+ "cards",
4558
+ "table"
4559
+ ],
4560
+ "default": "cards",
4561
+ "description": "cards: plans side by side. table: one comparison table, plans as columns and features as rows (for more than four plans)."
4562
+ },
4563
+ "featureStyle": {
4564
+ "options": [
4565
+ "check",
4566
+ "dot",
4567
+ "plain"
4568
+ ],
4569
+ "default": "plain",
4570
+ "description": "The mark before each feature in the cards: a check, a dot, or the list's own bullets."
4571
+ },
4572
+ "billingToggle": {
4573
+ "options": [
4574
+ "none",
4575
+ "radio"
4576
+ ],
4577
+ "default": "none",
4578
+ "description": "radio: two labelled radios swap each plan's price for its priceAlt (monthly / yearly), with no script. The radio group is named from the section id, or a hash of the plans without one, so two toggles on a page stay independent."
4579
+ }
4580
+ },
4581
+ "props": {
4582
+ "heading": {
4583
+ "type": "string",
4584
+ "label": "Heading",
4585
+ "description": "Section heading above the plans."
4586
+ },
4587
+ "intro": {
4588
+ "type": "text",
4589
+ "label": "Intro",
4590
+ "description": "A line or two under the heading."
4591
+ },
4592
+ "plans": {
4593
+ "type": "array",
4594
+ "label": "Plans",
4595
+ "required": true,
4596
+ "items": {
4597
+ "type": "object",
4598
+ "fields": {
4599
+ "name": {
4600
+ "type": "string",
4601
+ "label": "Name",
4602
+ "required": true,
4603
+ "description": "The plan's name."
4604
+ },
4605
+ "price": {
4606
+ "type": "string",
4607
+ "label": "Price",
4608
+ "required": true,
4609
+ "description": "The price as shown, with its currency (\"$12\", \"Free\", \"On request\")."
4610
+ },
4611
+ "period": {
4612
+ "type": "string",
4613
+ "label": "Period",
4614
+ "description": "What the price is per (\"/month\")."
4615
+ },
4616
+ "description": {
4617
+ "type": "string",
4618
+ "label": "Description",
4619
+ "description": "One line on who the plan is for."
4620
+ },
4621
+ "features": {
4622
+ "type": "markdown",
4623
+ "label": "Features",
4624
+ "description": "What the plan includes, as a markdown list."
4625
+ },
4626
+ "ctaLabel": {
4627
+ "type": "string",
4628
+ "label": "Button label",
4629
+ "description": "The plan's button text."
4630
+ },
4631
+ "ctaHref": {
4632
+ "type": "url",
4633
+ "label": "Button link",
4634
+ "description": "Where the button goes."
4635
+ },
4636
+ "featured": {
4637
+ "type": "boolean",
4638
+ "label": "Featured",
4639
+ "description": "Raises the plan and gives it the badge."
4640
+ },
4641
+ "badge": {
4642
+ "type": "string",
4643
+ "label": "Badge",
4644
+ "description": "A badge text on the plan (\"Best value\"); a featured plan without one reads the section's featuredLabel."
4645
+ },
4646
+ "priceAlt": {
4647
+ "type": "string",
4648
+ "label": "Price, other period",
4649
+ "description": "The price for the other billing period (\"€150\"), shown when the toggle is on its second option."
4650
+ },
4651
+ "periodAlt": {
4652
+ "type": "string",
4653
+ "label": "Period, other period",
4654
+ "description": "What the other price is per (\"/year\")."
4655
+ }
4656
+ }
4657
+ },
4658
+ "description": "The plans, in display order (Divi pricing tables, Elementor price table)."
3482
4659
  },
3483
4660
  "featuredLabel": {
3484
4661
  "type": "string",
3485
- "default": "Most popular",
4662
+ "default": "Most popular",
4663
+ "content": false,
4664
+ "description": "Badge text on featured plans."
4665
+ },
4666
+ "id": {
4667
+ "type": "string",
4668
+ "content": false,
4669
+ "description": "Anchor id of the section; the heading gets `<id>-title`."
4670
+ },
4671
+ "compact": {
4672
+ "type": "boolean",
4673
+ "default": false,
4674
+ "content": false,
4675
+ "description": "A denser card: smaller padding, gap and price."
4676
+ },
4677
+ "includedLabel": {
4678
+ "type": "string",
4679
+ "default": "Included",
4680
+ "content": false,
4681
+ "description": "Table cell text for readers where a plan has the feature."
4682
+ },
4683
+ "notIncludedLabel": {
4684
+ "type": "string",
4685
+ "default": "Not included",
4686
+ "content": false,
4687
+ "description": "Table cell text for readers where a plan lacks the feature."
4688
+ },
4689
+ "measured": {
4690
+ "type": "object",
4691
+ "content": false,
4692
+ "description": "The source section's measured style (MeasuredStyle): frame width, padding, fill, image, columns per width, gap, text tone, radius, minimum height — all in pixels. Absent, the site's tokens; present, it wins over tone and columns. Values that are not a number, a colour or a known keyword are dropped.",
4693
+ "fields": {
4694
+ "containerPx": {
4695
+ "type": "integer",
4696
+ "min": 0,
4697
+ "max": 2560,
4698
+ "description": "The frame's content width."
4699
+ },
4700
+ "padY": {
4701
+ "type": "integer",
4702
+ "min": 0,
4703
+ "max": 400,
4704
+ "description": "Top and bottom padding."
4705
+ },
4706
+ "padX": {
4707
+ "type": "integer",
4708
+ "min": 0,
4709
+ "max": 200,
4710
+ "description": "The frame's side padding (gutter)."
4711
+ },
4712
+ "bg": {
4713
+ "type": "object",
4714
+ "description": "The section's background.",
4715
+ "fields": {
4716
+ "color": {
4717
+ "type": "string",
4718
+ "description": "Fill colour: hex, rgb(a) or hsl(a)."
4719
+ },
4720
+ "image": {
4721
+ "type": "string",
4722
+ "description": "Background image address (http(s) or root-relative), drawn behind the content."
4723
+ },
4724
+ "overlay": {
4725
+ "type": "string",
4726
+ "description": "Colour or linear/radial gradient laid over the image or the fill."
4727
+ },
4728
+ "size": {
4729
+ "type": "string",
4730
+ "description": "cover, contain or auto; anything else draws as cover."
4731
+ },
4732
+ "position": {
4733
+ "type": "string",
4734
+ "description": "One or two of center/top/bottom/left/right or percentages."
4735
+ }
4736
+ }
4737
+ },
4738
+ "columns": {
4739
+ "type": "object",
4740
+ "description": "Item columns at 390 (base), 768 (md) and 1280 (lg) px; a missing width follows the narrower one.",
4741
+ "fields": {
4742
+ "390": {
4743
+ "type": "integer",
4744
+ "min": 1,
4745
+ "max": 6,
4746
+ "description": "Phone."
4747
+ },
4748
+ "768": {
4749
+ "type": "integer",
4750
+ "min": 1,
4751
+ "max": 6,
4752
+ "description": "Tablet."
4753
+ },
4754
+ "1280": {
4755
+ "type": "integer",
4756
+ "min": 1,
4757
+ "max": 6,
4758
+ "description": "Desktop."
4759
+ }
4760
+ }
4761
+ },
4762
+ "gap": {
4763
+ "type": "integer",
4764
+ "min": 0,
4765
+ "max": 200,
4766
+ "description": "Gap between items."
4767
+ },
4768
+ "tone": {
4769
+ "type": "select",
4770
+ "options": [
4771
+ "light",
4772
+ "dark"
4773
+ ],
4774
+ "description": "What the text is set for: dark = light text on a dark band. Without it, a fill's own lightness decides."
4775
+ },
4776
+ "align": {
4777
+ "type": "select",
4778
+ "options": [
4779
+ "start",
4780
+ "center",
4781
+ "end"
4782
+ ],
4783
+ "description": "Where the heading and lead sit; read by a component whose own align is not set."
4784
+ },
4785
+ "radius": {
4786
+ "type": "integer",
4787
+ "min": 0,
4788
+ "max": 200,
4789
+ "description": "Card and item corner radius."
4790
+ },
4791
+ "minHeight": {
4792
+ "type": "integer",
4793
+ "min": 0,
4794
+ "max": 2000,
4795
+ "description": "The section's minimum height."
4796
+ }
4797
+ }
4798
+ },
4799
+ "billingMainLabel": {
4800
+ "type": "string",
4801
+ "default": "Monthly",
3486
4802
  "content": false,
3487
- "description": "Badge text on featured plans."
4803
+ "description": "First option of the billing toggle."
3488
4804
  },
3489
- "id": {
4805
+ "billingAltLabel": {
3490
4806
  "type": "string",
4807
+ "default": "Yearly",
3491
4808
  "content": false,
3492
- "description": "Anchor id of the section; the heading gets `<id>-title`."
4809
+ "description": "Second option of the billing toggle (the plans' priceAlt)."
4810
+ },
4811
+ "billingLegend": {
4812
+ "type": "string",
4813
+ "default": "Billing period",
4814
+ "content": false,
4815
+ "description": "Legend of the toggle, read to screen readers."
3493
4816
  }
3494
4817
  },
3495
4818
  "slots": {},
@@ -3506,7 +4829,7 @@
3506
4829
  "divi/et_pb_pricing_tables"
3507
4830
  ]
3508
4831
  },
3509
- "a11y": "Plans are a <ul>; each name is an <h3> under the section's <h2>, or an <h2> when the section has no heading. A featured plan is marked by a text badge and a ring, not colour alone. Buttons are links with their own label.",
4832
+ "a11y": "Plans are a <ul>; each name is an <h3> under the section's <h2>, or an <h2> when the section has no heading. A featured plan is marked by a text badge and a ring, not colour alone. Buttons are links with their own label. The table layout is a real <table> with a caption, column and row headers, and Included / Not included text in every cell; the billing toggle is a fieldset with a legend and labelled radios.",
3510
4833
  "pattern": {
3511
4834
  "summary": "repeated plan units: name + price + feature list + button",
3512
4835
  "signals": [
@@ -3530,7 +4853,10 @@
3530
4853
  "plans[].features": "plans[].features",
3531
4854
  "plans[].ctaLabel": "plans[].cta_label",
3532
4855
  "plans[].ctaHref": "plans[].cta_href",
3533
- "plans[].featured": "plans[].featured"
4856
+ "plans[].featured": "plans[].featured",
4857
+ "plans[].badge": "plans[].badge",
4858
+ "plans[].priceAlt": "plans[].price_alt",
4859
+ "plans[].periodAlt": "plans[].period_alt"
3534
4860
  }
3535
4861
  },
3536
4862
  {
@@ -3768,7 +5094,10 @@
3768
5094
  "name": "Split",
3769
5095
  "description": "An image beside a block of text — eyebrow, heading, a markdown body and buttons — on either side, stacked on phones. The media-and-text section of a landing page (Gutenberg media-text, a two-column Elementor container with an image, Divi's image + text row).",
3770
5096
  "category": "section",
3771
- "uses": [],
5097
+ "uses": [
5098
+ "embed",
5099
+ "feature-list"
5100
+ ],
3772
5101
  "shared": [
3773
5102
  "Button.astro",
3774
5103
  "KitImage.astro",
@@ -3785,6 +5114,64 @@
3785
5114
  "default": "end",
3786
5115
  "description": "Which side the image takes on wide screens: start (left in left-to-right text) or end. Phones always show it after the text."
3787
5116
  },
5117
+ "ratio": {
5118
+ "options": [
5119
+ "1:1",
5120
+ "5:7",
5121
+ "7:5"
5122
+ ],
5123
+ "default": "1:1",
5124
+ "description": "The text column's share against the image's: equal, text 5 to image 7, or text 7 to image 5."
5125
+ },
5126
+ "imageFit": {
5127
+ "options": [
5128
+ "contain",
5129
+ "cover"
5130
+ ],
5131
+ "default": "contain",
5132
+ "description": "contain: the image at its own proportions. cover: it fills the column's height."
5133
+ },
5134
+ "imageShape": {
5135
+ "options": [
5136
+ "none",
5137
+ "rounded",
5138
+ "circle"
5139
+ ],
5140
+ "default": "rounded",
5141
+ "description": "The image's corners: square, the theme's rounding, or a circle."
5142
+ },
5143
+ "imageBleed": {
5144
+ "options": [
5145
+ "none",
5146
+ "edge"
5147
+ ],
5148
+ "default": "none",
5149
+ "description": "edge: the image runs on to the edge of the screen on its side (wide screens)."
5150
+ },
5151
+ "mediaKind": {
5152
+ "options": [
5153
+ "image",
5154
+ "video"
5155
+ ],
5156
+ "default": "image",
5157
+ "description": "image: the picture. video: the picture is the poster of a video that loads only when played."
5158
+ },
5159
+ "featureStyle": {
5160
+ "options": [
5161
+ "check",
5162
+ "icon"
5163
+ ],
5164
+ "default": "check",
5165
+ "description": "The marks of the points under the text: a check, or each point's own icon."
5166
+ },
5167
+ "stackOrder": {
5168
+ "options": [
5169
+ "text-first",
5170
+ "media-first"
5171
+ ],
5172
+ "default": "text-first",
5173
+ "description": "On a phone: the text first, or the picture first."
5174
+ },
3788
5175
  "align": {
3789
5176
  "options": [
3790
5177
  "start",
@@ -3798,10 +5185,12 @@
3798
5185
  "default",
3799
5186
  "muted",
3800
5187
  "inverse",
3801
- "accent"
5188
+ "accent",
5189
+ "brand",
5190
+ "none"
3802
5191
  ],
3803
5192
  "default": "default",
3804
- "description": "Section background."
5193
+ "description": "Section background (brand: the site's brand colour; none: the page's own)."
3805
5194
  }
3806
5195
  },
3807
5196
  "props": {
@@ -3811,6 +5200,12 @@
3811
5200
  "required": true,
3812
5201
  "description": "The section heading."
3813
5202
  },
5203
+ "headingLevel": {
5204
+ "type": "integer",
5205
+ "default": 2,
5206
+ "content": false,
5207
+ "description": "The heading's level: 2 under the page title; 3 or 4 when the section sits inside another."
5208
+ },
3814
5209
  "eyebrow": {
3815
5210
  "type": "string",
3816
5211
  "label": "Eyebrow",
@@ -3886,10 +5281,162 @@
3886
5281
  },
3887
5282
  "description": "The image beside the text. Width and height, when known, let the site reserve its space."
3888
5283
  },
5284
+ "features": {
5285
+ "type": "array",
5286
+ "label": "Points",
5287
+ "items": {
5288
+ "type": "object",
5289
+ "fields": {
5290
+ "title": {
5291
+ "type": "string",
5292
+ "label": "Title",
5293
+ "required": true,
5294
+ "description": "The point, in a few words."
5295
+ },
5296
+ "text": {
5297
+ "type": "string",
5298
+ "label": "Text",
5299
+ "description": "A line about it."
5300
+ },
5301
+ "icon": {
5302
+ "type": "string",
5303
+ "label": "Icon",
5304
+ "description": "A kit icon name (check, star, bolt, shield, heart, globe, clock, chat)."
5305
+ }
5306
+ }
5307
+ },
5308
+ "description": "Short points under the text (an Elementor icon list or icon box, a Gutenberg list), each with a title and a line."
5309
+ },
5310
+ "videoUrl": {
5311
+ "type": "url",
5312
+ "label": "Video",
5313
+ "description": "A video page (YouTube, Vimeo); the image is its poster and nothing loads from the provider until it is played."
5314
+ },
5315
+ "playLabel": {
5316
+ "type": "string",
5317
+ "content": false,
5318
+ "description": "The play button's text (ui-strings embed.play)."
5319
+ },
5320
+ "measured": {
5321
+ "type": "object",
5322
+ "content": false,
5323
+ "description": "The source section's measured style (MeasuredStyle): frame width, padding, fill, image, columns per width, gap, text tone, radius, minimum height — all in pixels. Absent, the site's tokens; present, it wins over tone and columns. Values that are not a number, a colour or a known keyword are dropped.",
5324
+ "fields": {
5325
+ "containerPx": {
5326
+ "type": "integer",
5327
+ "min": 0,
5328
+ "max": 2560,
5329
+ "description": "The frame's content width."
5330
+ },
5331
+ "padY": {
5332
+ "type": "integer",
5333
+ "min": 0,
5334
+ "max": 400,
5335
+ "description": "Top and bottom padding."
5336
+ },
5337
+ "padX": {
5338
+ "type": "integer",
5339
+ "min": 0,
5340
+ "max": 200,
5341
+ "description": "The frame's side padding (gutter)."
5342
+ },
5343
+ "bg": {
5344
+ "type": "object",
5345
+ "description": "The section's background.",
5346
+ "fields": {
5347
+ "color": {
5348
+ "type": "string",
5349
+ "description": "Fill colour: hex, rgb(a) or hsl(a)."
5350
+ },
5351
+ "image": {
5352
+ "type": "string",
5353
+ "description": "Background image address (http(s) or root-relative), drawn behind the content."
5354
+ },
5355
+ "overlay": {
5356
+ "type": "string",
5357
+ "description": "Colour or linear/radial gradient laid over the image or the fill."
5358
+ },
5359
+ "size": {
5360
+ "type": "string",
5361
+ "description": "cover, contain or auto; anything else draws as cover."
5362
+ },
5363
+ "position": {
5364
+ "type": "string",
5365
+ "description": "One or two of center/top/bottom/left/right or percentages."
5366
+ }
5367
+ }
5368
+ },
5369
+ "columns": {
5370
+ "type": "object",
5371
+ "description": "Item columns at 390 (base), 768 (md) and 1280 (lg) px; a missing width follows the narrower one.",
5372
+ "fields": {
5373
+ "390": {
5374
+ "type": "integer",
5375
+ "min": 1,
5376
+ "max": 6,
5377
+ "description": "Phone."
5378
+ },
5379
+ "768": {
5380
+ "type": "integer",
5381
+ "min": 1,
5382
+ "max": 6,
5383
+ "description": "Tablet."
5384
+ },
5385
+ "1280": {
5386
+ "type": "integer",
5387
+ "min": 1,
5388
+ "max": 6,
5389
+ "description": "Desktop."
5390
+ }
5391
+ }
5392
+ },
5393
+ "gap": {
5394
+ "type": "integer",
5395
+ "min": 0,
5396
+ "max": 200,
5397
+ "description": "Gap between items."
5398
+ },
5399
+ "tone": {
5400
+ "type": "select",
5401
+ "options": [
5402
+ "light",
5403
+ "dark"
5404
+ ],
5405
+ "description": "What the text is set for: dark = light text on a dark band. Without it, a fill's own lightness decides."
5406
+ },
5407
+ "align": {
5408
+ "type": "select",
5409
+ "options": [
5410
+ "start",
5411
+ "center",
5412
+ "end"
5413
+ ],
5414
+ "description": "Where the heading and lead sit; read by a component whose own align is not set."
5415
+ },
5416
+ "radius": {
5417
+ "type": "integer",
5418
+ "min": 0,
5419
+ "max": 200,
5420
+ "description": "Card and item corner radius."
5421
+ },
5422
+ "minHeight": {
5423
+ "type": "integer",
5424
+ "min": 0,
5425
+ "max": 2000,
5426
+ "description": "The section's minimum height."
5427
+ }
5428
+ }
5429
+ },
3889
5430
  "id": {
3890
5431
  "type": "string",
3891
5432
  "content": false,
3892
5433
  "description": "Anchor id of the section; the heading gets `<id>-title`."
5434
+ },
5435
+ "sticky": {
5436
+ "type": "boolean",
5437
+ "default": false,
5438
+ "content": false,
5439
+ "description": "The picture stays in view while a long text scrolls past it (wide screens)."
3893
5440
  }
3894
5441
  },
3895
5442
  "slots": {},
@@ -3906,7 +5453,7 @@
3906
5453
  "divi/et_pb_image"
3907
5454
  ]
3908
5455
  },
3909
- "a11y": "The section is labelled by its heading. The image is a separate figure in reading order after the text; an empty description marks a decorative one.",
5456
+ "a11y": "The section is labelled by its heading. The image is a separate figure in reading order after the text; an empty description marks a decorative one. With stackOrder media-first the picture comes first on a phone by CSS order only: the DOM and so the reading order stay text first, which is right when the picture is decoration; give the picture an empty description then.",
3910
5457
  "pattern": {
3911
5458
  "summary": "image beside heading + text",
3912
5459
  "signals": [
@@ -3933,7 +5480,12 @@
3933
5480
  "image.src": "image.src",
3934
5481
  "image.alt": "image.alt",
3935
5482
  "image.width": "image.width",
3936
- "image.height": "image.height"
5483
+ "image.height": "image.height",
5484
+ "features": "features",
5485
+ "features[].title": "features[].title",
5486
+ "features[].text": "features[].text",
5487
+ "features[].icon": "features[].icon",
5488
+ "videoUrl": "video_url"
3937
5489
  }
3938
5490
  },
3939
5491
  {
@@ -3943,27 +5495,58 @@
3943
5495
  "category": "section",
3944
5496
  "uses": [],
3945
5497
  "shared": [
5498
+ "KitImage.astro",
3946
5499
  "Section.astro",
5500
+ "image.ts",
3947
5501
  "measured.ts",
3948
5502
  "types.ts"
3949
5503
  ],
3950
5504
  "variants": {
5505
+ "layout": {
5506
+ "options": [
5507
+ "grid",
5508
+ "inline"
5509
+ ],
5510
+ "default": "grid",
5511
+ "description": "grid: figures in columns. inline: one line that wraps, for two to four short figures."
5512
+ },
3951
5513
  "columns": {
3952
5514
  "options": [
3953
5515
  "2",
3954
5516
  "3",
3955
- "4"
5517
+ "4",
5518
+ "5",
5519
+ "6"
3956
5520
  ],
3957
5521
  "default": "3",
3958
- "description": "Figures per row on wide screens; two on phones."
5522
+ "description": "Figures per row on wide screens (grid layout); two on phones."
3959
5523
  },
3960
5524
  "style": {
3961
5525
  "options": [
3962
5526
  "plain",
3963
- "card"
5527
+ "card",
5528
+ "divided"
3964
5529
  ],
3965
5530
  "default": "plain",
3966
- "description": "plain: figures on the section background. card: each figure in its own box."
5531
+ "description": "plain: figures on the section background. card: each figure in its own box. divided: hairlines between the figures (across on a wide screen, above each on a phone), no box; for a single row."
5532
+ },
5533
+ "align": {
5534
+ "options": [
5535
+ "start",
5536
+ "center"
5537
+ ],
5538
+ "default": "start",
5539
+ "description": "Alignment of each figure and its label."
5540
+ },
5541
+ "valueSize": {
5542
+ "options": [
5543
+ "md",
5544
+ "lg",
5545
+ "xl",
5546
+ "display"
5547
+ ],
5548
+ "default": "lg",
5549
+ "description": "The figure's size: md, lg, xl or a display-size number."
3967
5550
  },
3968
5551
  "tone": {
3969
5552
  "options": [
@@ -4032,10 +5615,125 @@
4032
5615
  "type": "string",
4033
5616
  "label": "Suffix",
4034
5617
  "description": "Printed after the figure (`+`, `%`, `k`)."
5618
+ },
5619
+ "icon": {
5620
+ "type": "image",
5621
+ "label": "Icon",
5622
+ "description": "A small picture above the figure; decorative."
5623
+ }
5624
+ }
5625
+ },
5626
+ "description": "The figures, in order (Elementor counter, Divi number counter, a Gutenberg columns row of big numbers)."
5627
+ },
5628
+ "measured": {
5629
+ "type": "object",
5630
+ "content": false,
5631
+ "description": "The source section's measured style (MeasuredStyle): frame width, padding, fill, image, columns per width, gap, text tone, radius, minimum height — all in pixels. Absent, the site's tokens; present, it wins over tone and columns. Values that are not a number, a colour or a known keyword are dropped.",
5632
+ "fields": {
5633
+ "containerPx": {
5634
+ "type": "integer",
5635
+ "min": 0,
5636
+ "max": 2560,
5637
+ "description": "The frame's content width."
5638
+ },
5639
+ "padY": {
5640
+ "type": "integer",
5641
+ "min": 0,
5642
+ "max": 400,
5643
+ "description": "Top and bottom padding."
5644
+ },
5645
+ "padX": {
5646
+ "type": "integer",
5647
+ "min": 0,
5648
+ "max": 200,
5649
+ "description": "The frame's side padding (gutter)."
5650
+ },
5651
+ "bg": {
5652
+ "type": "object",
5653
+ "description": "The section's background.",
5654
+ "fields": {
5655
+ "color": {
5656
+ "type": "string",
5657
+ "description": "Fill colour: hex, rgb(a) or hsl(a)."
5658
+ },
5659
+ "image": {
5660
+ "type": "string",
5661
+ "description": "Background image address (http(s) or root-relative), drawn behind the content."
5662
+ },
5663
+ "overlay": {
5664
+ "type": "string",
5665
+ "description": "Colour or linear/radial gradient laid over the image or the fill."
5666
+ },
5667
+ "size": {
5668
+ "type": "string",
5669
+ "description": "cover, contain or auto; anything else draws as cover."
5670
+ },
5671
+ "position": {
5672
+ "type": "string",
5673
+ "description": "One or two of center/top/bottom/left/right or percentages."
5674
+ }
4035
5675
  }
5676
+ },
5677
+ "columns": {
5678
+ "type": "object",
5679
+ "description": "Item columns at 390 (base), 768 (md) and 1280 (lg) px; a missing width follows the narrower one.",
5680
+ "fields": {
5681
+ "390": {
5682
+ "type": "integer",
5683
+ "min": 1,
5684
+ "max": 6,
5685
+ "description": "Phone."
5686
+ },
5687
+ "768": {
5688
+ "type": "integer",
5689
+ "min": 1,
5690
+ "max": 6,
5691
+ "description": "Tablet."
5692
+ },
5693
+ "1280": {
5694
+ "type": "integer",
5695
+ "min": 1,
5696
+ "max": 6,
5697
+ "description": "Desktop."
5698
+ }
5699
+ }
5700
+ },
5701
+ "gap": {
5702
+ "type": "integer",
5703
+ "min": 0,
5704
+ "max": 200,
5705
+ "description": "Gap between items."
5706
+ },
5707
+ "tone": {
5708
+ "type": "select",
5709
+ "options": [
5710
+ "light",
5711
+ "dark"
5712
+ ],
5713
+ "description": "What the text is set for: dark = light text on a dark band. Without it, a fill's own lightness decides."
5714
+ },
5715
+ "align": {
5716
+ "type": "select",
5717
+ "options": [
5718
+ "start",
5719
+ "center",
5720
+ "end"
5721
+ ],
5722
+ "description": "Where the heading and lead sit; read by a component whose own align is not set."
5723
+ },
5724
+ "radius": {
5725
+ "type": "integer",
5726
+ "min": 0,
5727
+ "max": 200,
5728
+ "description": "Card and item corner radius."
5729
+ },
5730
+ "minHeight": {
5731
+ "type": "integer",
5732
+ "min": 0,
5733
+ "max": 2000,
5734
+ "description": "The section's minimum height."
4036
5735
  }
4037
- },
4038
- "description": "The figures, in order (Elementor counter, Divi number counter, a Gutenberg columns row of big numbers)."
5736
+ }
4039
5737
  },
4040
5738
  "id": {
4041
5739
  "type": "string",
@@ -4077,7 +5775,8 @@
4077
5775
  "items[].value": "items[].value",
4078
5776
  "items[].label": "items[].label",
4079
5777
  "items[].prefix": "items[].prefix",
4080
- "items[].suffix": "items[].suffix"
5778
+ "items[].suffix": "items[].suffix",
5779
+ "items[].icon": "items[].icon"
4081
5780
  }
4082
5781
  },
4083
5782
  {
@@ -4097,10 +5796,12 @@
4097
5796
  "layout": {
4098
5797
  "options": [
4099
5798
  "list",
4100
- "row"
5799
+ "row",
5800
+ "rail",
5801
+ "alternate"
4101
5802
  ],
4102
5803
  "default": "list",
4103
- "description": "A vertical list, or one row across the page on wide screens."
5804
+ "description": "list: a vertical list. row: across the page. rail: one rail on the start side. alternate: items alternate either side of a centre rail from md (one rail on phones); DOM order stays chronological."
4104
5805
  },
4105
5806
  "style": {
4106
5807
  "options": [
@@ -4109,6 +5810,31 @@
4109
5810
  ],
4110
5811
  "default": "numbered",
4111
5812
  "description": "A number badge before each step, or an accent rule beside it."
5813
+ },
5814
+ "kind": {
5815
+ "options": [
5816
+ "steps",
5817
+ "timeline"
5818
+ ],
5819
+ "default": "steps",
5820
+ "description": "steps: a numbered sequence. timeline: a date per item on a vertical rail (the rail layouts below; without a layout it uses rail)."
5821
+ },
5822
+ "marker": {
5823
+ "options": [
5824
+ "number",
5825
+ "dot"
5826
+ ],
5827
+ "default": "number",
5828
+ "description": "What sits on the rail: the style's number badge, or a plain dot (the timeline default). Not yet: icon and date markers, and a visual emphasis for the current item (it has aria-current and a hidden label only)."
5829
+ },
5830
+ "connector": {
5831
+ "options": [
5832
+ "none",
5833
+ "line",
5834
+ "dashed"
5835
+ ],
5836
+ "default": "line",
5837
+ "description": "The rail between items on the rail layouts."
4112
5838
  }
4113
5839
  },
4114
5840
  "props": {
@@ -4155,6 +5881,16 @@
4155
5881
  "type": "string",
4156
5882
  "label": "Image description",
4157
5883
  "description": "What the image shows; empty if decorative."
5884
+ },
5885
+ "date": {
5886
+ "type": "string",
5887
+ "label": "Date",
5888
+ "description": "A timeline's date as written (\"2019\", \"Mar 2021\"); marked up as a <time> only when it is an ISO date or a year."
5889
+ },
5890
+ "current": {
5891
+ "type": "boolean",
5892
+ "label": "Current",
5893
+ "description": "Marks the latest item (aria-current=\"step\" and a hidden \"Current\")."
4158
5894
  }
4159
5895
  }
4160
5896
  },
@@ -4164,6 +5900,122 @@
4164
5900
  "type": "string",
4165
5901
  "content": false,
4166
5902
  "description": "Anchor id of the section; the heading gets `<id>-title`."
5903
+ },
5904
+ "currentLabel": {
5905
+ "type": "string",
5906
+ "default": "Current",
5907
+ "content": false,
5908
+ "description": "Visually hidden text on the current item, so it is not shown by colour alone."
5909
+ },
5910
+ "measured": {
5911
+ "type": "object",
5912
+ "content": false,
5913
+ "description": "The source section's measured style (MeasuredStyle): frame width, padding, fill, image, columns per width, gap, text tone, radius, minimum height — all in pixels. Absent, the site's tokens; present, it wins over tone and columns. Values that are not a number, a colour or a known keyword are dropped.",
5914
+ "fields": {
5915
+ "containerPx": {
5916
+ "type": "integer",
5917
+ "min": 0,
5918
+ "max": 2560,
5919
+ "description": "The frame's content width."
5920
+ },
5921
+ "padY": {
5922
+ "type": "integer",
5923
+ "min": 0,
5924
+ "max": 400,
5925
+ "description": "Top and bottom padding."
5926
+ },
5927
+ "padX": {
5928
+ "type": "integer",
5929
+ "min": 0,
5930
+ "max": 200,
5931
+ "description": "The frame's side padding (gutter)."
5932
+ },
5933
+ "bg": {
5934
+ "type": "object",
5935
+ "description": "The section's background.",
5936
+ "fields": {
5937
+ "color": {
5938
+ "type": "string",
5939
+ "description": "Fill colour: hex, rgb(a) or hsl(a)."
5940
+ },
5941
+ "image": {
5942
+ "type": "string",
5943
+ "description": "Background image address (http(s) or root-relative), drawn behind the content."
5944
+ },
5945
+ "overlay": {
5946
+ "type": "string",
5947
+ "description": "Colour or linear/radial gradient laid over the image or the fill."
5948
+ },
5949
+ "size": {
5950
+ "type": "string",
5951
+ "description": "cover, contain or auto; anything else draws as cover."
5952
+ },
5953
+ "position": {
5954
+ "type": "string",
5955
+ "description": "One or two of center/top/bottom/left/right or percentages."
5956
+ }
5957
+ }
5958
+ },
5959
+ "columns": {
5960
+ "type": "object",
5961
+ "description": "Item columns at 390 (base), 768 (md) and 1280 (lg) px; a missing width follows the narrower one.",
5962
+ "fields": {
5963
+ "390": {
5964
+ "type": "integer",
5965
+ "min": 1,
5966
+ "max": 6,
5967
+ "description": "Phone."
5968
+ },
5969
+ "768": {
5970
+ "type": "integer",
5971
+ "min": 1,
5972
+ "max": 6,
5973
+ "description": "Tablet."
5974
+ },
5975
+ "1280": {
5976
+ "type": "integer",
5977
+ "min": 1,
5978
+ "max": 6,
5979
+ "description": "Desktop."
5980
+ }
5981
+ }
5982
+ },
5983
+ "gap": {
5984
+ "type": "integer",
5985
+ "min": 0,
5986
+ "max": 200,
5987
+ "description": "Gap between items."
5988
+ },
5989
+ "tone": {
5990
+ "type": "select",
5991
+ "options": [
5992
+ "light",
5993
+ "dark"
5994
+ ],
5995
+ "description": "What the text is set for: dark = light text on a dark band. Without it, a fill's own lightness decides."
5996
+ },
5997
+ "align": {
5998
+ "type": "select",
5999
+ "options": [
6000
+ "start",
6001
+ "center",
6002
+ "end"
6003
+ ],
6004
+ "description": "Where the heading and lead sit; read by a component whose own align is not set."
6005
+ },
6006
+ "radius": {
6007
+ "type": "integer",
6008
+ "min": 0,
6009
+ "max": 200,
6010
+ "description": "Card and item corner radius."
6011
+ },
6012
+ "minHeight": {
6013
+ "type": "integer",
6014
+ "min": 0,
6015
+ "max": 2000,
6016
+ "description": "The section's minimum height."
6017
+ }
6018
+ }
4167
6019
  }
4168
6020
  },
4169
6021
  "slots": {},
@@ -4180,7 +6032,7 @@
4180
6032
  "divi/et_pb_blurb"
4181
6033
  ]
4182
6034
  },
4183
- "a11y": "Steps are an <ol>, so their order and count are announced; the visible numbers are CSS counters, not text. Each title is an <h3> under the section's <h2>, or an <h2> when the section has no heading. The section is labelled by its heading when it has one.",
6035
+ "a11y": "Steps are an <ol>, so their order and count are announced; the visible numbers are CSS counters, not text. Each title is an <h3> under the section's <h2>, or an <h2> when the section has no heading. The section is labelled by its heading when it has one. A timeline is the same <ol>; a date is a <time datetime> only when machine-readable; the rail and dots are CSS and not in the accessibility tree.",
4184
6036
  "pattern": {
4185
6037
  "summary": "ordered sequence: numbered title + short text units",
4186
6038
  "signals": [
@@ -4201,7 +6053,9 @@
4201
6053
  "items[].title": "items[].title",
4202
6054
  "items[].text": "items[].text",
4203
6055
  "items[].image": "items[].image",
4204
- "items[].imageAlt": "items[].image_alt"
6056
+ "items[].imageAlt": "items[].image_alt",
6057
+ "items[].date": "items[].date",
6058
+ "items[].current": "items[].current"
4205
6059
  }
4206
6060
  },
4207
6061
  {
@@ -4426,10 +6280,11 @@
4426
6280
  "options": [
4427
6281
  "2",
4428
6282
  "3",
4429
- "4"
6283
+ "4",
6284
+ "5"
4430
6285
  ],
4431
6286
  "default": "3",
4432
- "description": "Columns on wide screens; one on phones, two on tablets."
6287
+ "description": "Members per row on wide screens; one on phones, two on tablets."
4433
6288
  },
4434
6289
  "style": {
4435
6290
  "options": [
@@ -4446,6 +6301,32 @@
4446
6301
  ],
4447
6302
  "default": "accent",
4448
6303
  "description": "The member's role. accent: a small accent-coloured line. plain: body-size text in the text colour, as a byline."
6304
+ },
6305
+ "layout": {
6306
+ "options": [
6307
+ "grid",
6308
+ "list",
6309
+ "featured"
6310
+ ],
6311
+ "default": "grid",
6312
+ "description": "grid: cards in columns. list: one row each, photo beside text. featured: the first member large over a grid."
6313
+ },
6314
+ "imageShape": {
6315
+ "options": [
6316
+ "square",
6317
+ "rounded",
6318
+ "circle"
6319
+ ],
6320
+ "default": "square",
6321
+ "description": "Shape of the portrait."
6322
+ },
6323
+ "align": {
6324
+ "options": [
6325
+ "start",
6326
+ "center"
6327
+ ],
6328
+ "default": "start",
6329
+ "description": "Text and socials from the start edge, or centred."
4449
6330
  }
4450
6331
  },
4451
6332
  "props": {
@@ -4496,15 +6377,152 @@
4496
6377
  "type": "url",
4497
6378
  "label": "Link",
4498
6379
  "description": "Their profile page; makes the whole entry a link."
6380
+ },
6381
+ "links": {
6382
+ "type": "array",
6383
+ "label": "Profile links",
6384
+ "description": "Addresses of the member's social profiles, in order; each is labelled by the network its host names (LinkedIn, GitHub, …).",
6385
+ "items": {
6386
+ "type": "url"
6387
+ }
4499
6388
  }
4500
6389
  }
4501
6390
  },
4502
6391
  "description": "The people, in display order (Divi team member name/position/content/image_url, Elementor image box)."
4503
6392
  },
4504
- "id": {
6393
+ "id": {
6394
+ "type": "string",
6395
+ "content": false,
6396
+ "description": "Anchor id of the section; the heading gets `<id>-title`."
6397
+ },
6398
+ "bioClamp": {
6399
+ "type": "integer",
6400
+ "min": 2,
6401
+ "max": 4,
6402
+ "content": false,
6403
+ "description": "Clamp a long bio to this many lines; the full text opens in a native <details> (\"Read more\"), no script."
6404
+ },
6405
+ "readMoreLabel": {
4505
6406
  "type": "string",
6407
+ "default": "Read more",
4506
6408
  "content": false,
4507
- "description": "Anchor id of the section; the heading gets `<id>-title`."
6409
+ "description": "Text of the bio disclosure."
6410
+ },
6411
+ "socialLabel": {
6412
+ "type": "string",
6413
+ "default": "{name} on {network}",
6414
+ "content": false,
6415
+ "description": "Accessible name of a profile link; {name} and {network} are replaced."
6416
+ },
6417
+ "measured": {
6418
+ "type": "object",
6419
+ "content": false,
6420
+ "description": "The source section's measured style (MeasuredStyle): frame width, padding, fill, image, columns per width, gap, text tone, radius, minimum height — all in pixels. Absent, the site's tokens; present, it wins over tone and columns. Values that are not a number, a colour or a known keyword are dropped.",
6421
+ "fields": {
6422
+ "containerPx": {
6423
+ "type": "integer",
6424
+ "min": 0,
6425
+ "max": 2560,
6426
+ "description": "The frame's content width."
6427
+ },
6428
+ "padY": {
6429
+ "type": "integer",
6430
+ "min": 0,
6431
+ "max": 400,
6432
+ "description": "Top and bottom padding."
6433
+ },
6434
+ "padX": {
6435
+ "type": "integer",
6436
+ "min": 0,
6437
+ "max": 200,
6438
+ "description": "The frame's side padding (gutter)."
6439
+ },
6440
+ "bg": {
6441
+ "type": "object",
6442
+ "description": "The section's background.",
6443
+ "fields": {
6444
+ "color": {
6445
+ "type": "string",
6446
+ "description": "Fill colour: hex, rgb(a) or hsl(a)."
6447
+ },
6448
+ "image": {
6449
+ "type": "string",
6450
+ "description": "Background image address (http(s) or root-relative), drawn behind the content."
6451
+ },
6452
+ "overlay": {
6453
+ "type": "string",
6454
+ "description": "Colour or linear/radial gradient laid over the image or the fill."
6455
+ },
6456
+ "size": {
6457
+ "type": "string",
6458
+ "description": "cover, contain or auto; anything else draws as cover."
6459
+ },
6460
+ "position": {
6461
+ "type": "string",
6462
+ "description": "One or two of center/top/bottom/left/right or percentages."
6463
+ }
6464
+ }
6465
+ },
6466
+ "columns": {
6467
+ "type": "object",
6468
+ "description": "Item columns at 390 (base), 768 (md) and 1280 (lg) px; a missing width follows the narrower one.",
6469
+ "fields": {
6470
+ "390": {
6471
+ "type": "integer",
6472
+ "min": 1,
6473
+ "max": 6,
6474
+ "description": "Phone."
6475
+ },
6476
+ "768": {
6477
+ "type": "integer",
6478
+ "min": 1,
6479
+ "max": 6,
6480
+ "description": "Tablet."
6481
+ },
6482
+ "1280": {
6483
+ "type": "integer",
6484
+ "min": 1,
6485
+ "max": 6,
6486
+ "description": "Desktop."
6487
+ }
6488
+ }
6489
+ },
6490
+ "gap": {
6491
+ "type": "integer",
6492
+ "min": 0,
6493
+ "max": 200,
6494
+ "description": "Gap between items."
6495
+ },
6496
+ "tone": {
6497
+ "type": "select",
6498
+ "options": [
6499
+ "light",
6500
+ "dark"
6501
+ ],
6502
+ "description": "What the text is set for: dark = light text on a dark band. Without it, a fill's own lightness decides."
6503
+ },
6504
+ "align": {
6505
+ "type": "select",
6506
+ "options": [
6507
+ "start",
6508
+ "center",
6509
+ "end"
6510
+ ],
6511
+ "description": "Where the heading and lead sit; read by a component whose own align is not set."
6512
+ },
6513
+ "radius": {
6514
+ "type": "integer",
6515
+ "min": 0,
6516
+ "max": 200,
6517
+ "description": "Card and item corner radius."
6518
+ },
6519
+ "minHeight": {
6520
+ "type": "integer",
6521
+ "min": 0,
6522
+ "max": 2000,
6523
+ "description": "The section's minimum height."
6524
+ }
6525
+ }
4508
6526
  }
4509
6527
  },
4510
6528
  "slots": {},
@@ -4521,7 +6539,7 @@
4521
6539
  "divi/et_pb_team_member"
4522
6540
  ]
4523
6541
  },
4524
- "a11y": "Members are a <ul>; each name is an <h3> under the section's <h2> (an <h2> when the section has no heading), and a linked member's link text is the name. A portrait's text defaults to the name. The section is labelled by its heading when it has one.",
6542
+ "a11y": "Members are a <ul>; each name is an <h3> under the section's <h2> (an <h2> when the section has no heading), and a linked member's link text is the name. A portrait's text defaults to the name. The section is labelled by its heading when it has one. A member with socials keeps the name link and the social links apart (no nested links); a clamped bio opens in a <details> with the whole text.",
4525
6543
  "pattern": {
4526
6544
  "summary": "repeated person units: portrait + name + role",
4527
6545
  "signals": [
@@ -4533,7 +6551,8 @@
4533
6551
  ]
4534
6552
  },
4535
6553
  "files": [
4536
- "Team.astro"
6554
+ "Team.astro",
6555
+ "team.ts"
4537
6556
  ],
4538
6557
  "contentFields": {
4539
6558
  "heading": "heading",
@@ -4544,7 +6563,8 @@
4544
6563
  "items[].bio": "items[].bio",
4545
6564
  "items[].image": "items[].image",
4546
6565
  "items[].imageAlt": "items[].image_alt",
4547
- "items[].href": "items[].href"
6566
+ "items[].href": "items[].href",
6567
+ "items[].links": "items[].links"
4548
6568
  }
4549
6569
  },
4550
6570
  {
@@ -4564,10 +6584,12 @@
4564
6584
  "layout": {
4565
6585
  "options": [
4566
6586
  "single",
4567
- "grid"
6587
+ "grid",
6588
+ "row",
6589
+ "masonry"
4568
6590
  ],
4569
6591
  "default": "grid",
4570
- "description": "single: one large centred quote (the first item stands alone; more items stack). grid: cards, up to three per row."
6592
+ "description": "single: one large centred quote (the first item stands alone; more items stack). grid: cards, up to three per row. row: a horizontal strip that scrolls and snaps, no script. masonry: columns of quotes of different lengths."
4571
6593
  },
4572
6594
  "tone": {
4573
6595
  "options": [
@@ -4596,6 +6618,32 @@
4596
6618
  ],
4597
6619
  "default": "card",
4598
6620
  "description": "card: each quote in its box (a bordered, padded card in the grid; the surface colour in a muted section). plain: the quote and who said it straight on the section, across the column, with no box, as Elementor's testimonial widget draws them."
6621
+ },
6622
+ "avatarSize": {
6623
+ "options": [
6624
+ "sm",
6625
+ "md",
6626
+ "lg"
6627
+ ],
6628
+ "default": "md",
6629
+ "description": "The portrait's size: small, medium or large."
6630
+ },
6631
+ "avatarPlace": {
6632
+ "options": [
6633
+ "start",
6634
+ "top"
6635
+ ],
6636
+ "default": "start",
6637
+ "description": "start: the portrait beside the name. top: above the quote."
6638
+ },
6639
+ "quoteMark": {
6640
+ "options": [
6641
+ "marks",
6642
+ "glyph",
6643
+ "none"
6644
+ ],
6645
+ "default": "marks",
6646
+ "description": "marks: quotation marks around the text. glyph: one large decorative mark above. none: no marks."
4599
6647
  }
4600
6648
  },
4601
6649
  "props": {
@@ -4632,6 +6680,21 @@
4632
6680
  "type": "string",
4633
6681
  "label": "Photo description",
4634
6682
  "description": "Who the photo shows; usually their name."
6683
+ },
6684
+ "rating": {
6685
+ "type": "number",
6686
+ "label": "Rating",
6687
+ "description": "Stars out of 5; leave empty for none."
6688
+ },
6689
+ "logo": {
6690
+ "type": "image",
6691
+ "label": "Company logo",
6692
+ "description": "The company's logo beside the name."
6693
+ },
6694
+ "logoAlt": {
6695
+ "type": "string",
6696
+ "label": "Company name",
6697
+ "description": "The company the logo stands for."
4635
6698
  }
4636
6699
  }
4637
6700
  },
@@ -4642,10 +6705,130 @@
4642
6705
  "label": "Heading",
4643
6706
  "description": "Section heading above the quotes."
4644
6707
  },
6708
+ "measured": {
6709
+ "type": "object",
6710
+ "content": false,
6711
+ "description": "The source section's measured style (MeasuredStyle): frame width, padding, fill, image, columns per width, gap, text tone, radius, minimum height — all in pixels. Absent, the site's tokens; present, it wins over tone and columns. Values that are not a number, a colour or a known keyword are dropped.",
6712
+ "fields": {
6713
+ "containerPx": {
6714
+ "type": "integer",
6715
+ "min": 0,
6716
+ "max": 2560,
6717
+ "description": "The frame's content width."
6718
+ },
6719
+ "padY": {
6720
+ "type": "integer",
6721
+ "min": 0,
6722
+ "max": 400,
6723
+ "description": "Top and bottom padding."
6724
+ },
6725
+ "padX": {
6726
+ "type": "integer",
6727
+ "min": 0,
6728
+ "max": 200,
6729
+ "description": "The frame's side padding (gutter)."
6730
+ },
6731
+ "bg": {
6732
+ "type": "object",
6733
+ "description": "The section's background.",
6734
+ "fields": {
6735
+ "color": {
6736
+ "type": "string",
6737
+ "description": "Fill colour: hex, rgb(a) or hsl(a)."
6738
+ },
6739
+ "image": {
6740
+ "type": "string",
6741
+ "description": "Background image address (http(s) or root-relative), drawn behind the content."
6742
+ },
6743
+ "overlay": {
6744
+ "type": "string",
6745
+ "description": "Colour or linear/radial gradient laid over the image or the fill."
6746
+ },
6747
+ "size": {
6748
+ "type": "string",
6749
+ "description": "cover, contain or auto; anything else draws as cover."
6750
+ },
6751
+ "position": {
6752
+ "type": "string",
6753
+ "description": "One or two of center/top/bottom/left/right or percentages."
6754
+ }
6755
+ }
6756
+ },
6757
+ "columns": {
6758
+ "type": "object",
6759
+ "description": "Item columns at 390 (base), 768 (md) and 1280 (lg) px; a missing width follows the narrower one.",
6760
+ "fields": {
6761
+ "390": {
6762
+ "type": "integer",
6763
+ "min": 1,
6764
+ "max": 6,
6765
+ "description": "Phone."
6766
+ },
6767
+ "768": {
6768
+ "type": "integer",
6769
+ "min": 1,
6770
+ "max": 6,
6771
+ "description": "Tablet."
6772
+ },
6773
+ "1280": {
6774
+ "type": "integer",
6775
+ "min": 1,
6776
+ "max": 6,
6777
+ "description": "Desktop."
6778
+ }
6779
+ }
6780
+ },
6781
+ "gap": {
6782
+ "type": "integer",
6783
+ "min": 0,
6784
+ "max": 200,
6785
+ "description": "Gap between items."
6786
+ },
6787
+ "tone": {
6788
+ "type": "select",
6789
+ "options": [
6790
+ "light",
6791
+ "dark"
6792
+ ],
6793
+ "description": "What the text is set for: dark = light text on a dark band. Without it, a fill's own lightness decides."
6794
+ },
6795
+ "align": {
6796
+ "type": "select",
6797
+ "options": [
6798
+ "start",
6799
+ "center",
6800
+ "end"
6801
+ ],
6802
+ "description": "Where the heading and lead sit; read by a component whose own align is not set."
6803
+ },
6804
+ "radius": {
6805
+ "type": "integer",
6806
+ "min": 0,
6807
+ "max": 200,
6808
+ "description": "Card and item corner radius."
6809
+ },
6810
+ "minHeight": {
6811
+ "type": "integer",
6812
+ "min": 0,
6813
+ "max": 2000,
6814
+ "description": "The section's minimum height."
6815
+ }
6816
+ }
6817
+ },
4645
6818
  "id": {
4646
6819
  "type": "string",
4647
6820
  "content": false,
4648
6821
  "description": "Anchor id of the section; the heading gets `<id>-title`."
6822
+ },
6823
+ "ratingLabel": {
6824
+ "type": "string",
6825
+ "content": false,
6826
+ "description": "The stars' spoken text; `{rating}` stands for the number (\"{rating} out of 5 stars\")."
6827
+ },
6828
+ "label": {
6829
+ "type": "string",
6830
+ "content": false,
6831
+ "description": "The scrolling row's name for assistive technology when there is no heading (\"Testimonials\")."
4649
6832
  }
4650
6833
  },
4651
6834
  "slots": {},
@@ -4662,7 +6845,7 @@
4662
6845
  "classic/testimonial"
4663
6846
  ]
4664
6847
  },
4665
- "a11y": "Each quote is a <figure> whose <figcaption> names the speaker; the text is in a <blockquote>. Avatars are decorative when their alt is empty. The section is labelled by its heading when it has one.",
6848
+ "a11y": "Each quote is a <figure> whose <figcaption> names the speaker; the text is in a <blockquote>. Avatars are decorative when their alt is empty. The section is labelled by its heading when it has one. Stars are one image named by the real rating (\"4.8 out of 5 stars\"); the row layout is a focusable named region.",
4666
6849
  "files": [
4667
6850
  "Testimonial.astro"
4668
6851
  ],
@@ -4673,6 +6856,9 @@
4673
6856
  "items[].role": "items[].role",
4674
6857
  "items[].avatar": "items[].avatar",
4675
6858
  "items[].avatarAlt": "items[].avatar_alt",
6859
+ "items[].rating": "items[].rating",
6860
+ "items[].logo": "items[].logo",
6861
+ "items[].logoAlt": "items[].logo_alt",
4676
6862
  "heading": "heading"
4677
6863
  }
4678
6864
  }