@prenta/admin 0.92.0 → 0.93.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 (374) hide show
  1. package/CHANGELOG.md +552 -0
  2. package/design-system/tokens.css +173 -71
  3. package/design-system/tokens.json +244 -63
  4. package/design-system/tokens.scss +203 -98
  5. package/design-system/tokens.tailwind.cjs +93 -38
  6. package/dist/AdminRoot.d.ts +27 -6
  7. package/dist/AdminRoot.d.ts.map +1 -1
  8. package/dist/AdminRoot.js.map +1 -1
  9. package/dist/__tests__/components/breakpoint-controls.render.test.d.ts +2 -0
  10. package/dist/__tests__/components/breakpoint-controls.render.test.d.ts.map +1 -0
  11. package/dist/__tests__/components/breakpoint-controls.render.test.js +51 -0
  12. package/dist/__tests__/components/breakpoint-controls.render.test.js.map +1 -0
  13. package/dist/__tests__/components/canvas-edit-tip.render.test.d.ts +2 -0
  14. package/dist/__tests__/components/canvas-edit-tip.render.test.d.ts.map +1 -0
  15. package/dist/__tests__/components/canvas-edit-tip.render.test.js +37 -0
  16. package/dist/__tests__/components/canvas-edit-tip.render.test.js.map +1 -0
  17. package/dist/__tests__/components/editor-rail.render.test.d.ts +2 -0
  18. package/dist/__tests__/components/editor-rail.render.test.d.ts.map +1 -0
  19. package/dist/__tests__/components/editor-rail.render.test.js +138 -0
  20. package/dist/__tests__/components/editor-rail.render.test.js.map +1 -0
  21. package/dist/__tests__/components/media-block.render.test.d.ts +2 -0
  22. package/dist/__tests__/components/media-block.render.test.d.ts.map +1 -0
  23. package/dist/__tests__/components/media-block.render.test.js +108 -0
  24. package/dist/__tests__/components/media-block.render.test.js.map +1 -0
  25. package/dist/__tests__/components/page-audit-panel.render.test.d.ts +2 -0
  26. package/dist/__tests__/components/page-audit-panel.render.test.d.ts.map +1 -0
  27. package/dist/__tests__/components/page-audit-panel.render.test.js +59 -0
  28. package/dist/__tests__/components/page-audit-panel.render.test.js.map +1 -0
  29. package/dist/__tests__/components/reflow-meter.render.test.d.ts +2 -0
  30. package/dist/__tests__/components/reflow-meter.render.test.d.ts.map +1 -0
  31. package/dist/__tests__/components/reflow-meter.render.test.js +94 -0
  32. package/dist/__tests__/components/reflow-meter.render.test.js.map +1 -0
  33. package/dist/__tests__/components/seo-char-count.test.js +24 -6
  34. package/dist/__tests__/components/seo-char-count.test.js.map +1 -1
  35. package/dist/__tests__/components/serp-preview.render.test.d.ts +2 -0
  36. package/dist/__tests__/components/serp-preview.render.test.d.ts.map +1 -0
  37. package/dist/__tests__/components/serp-preview.render.test.js +25 -0
  38. package/dist/__tests__/components/serp-preview.render.test.js.map +1 -0
  39. package/dist/__tests__/lib/breakpoints.test.d.ts +2 -0
  40. package/dist/__tests__/lib/breakpoints.test.d.ts.map +1 -0
  41. package/dist/__tests__/lib/breakpoints.test.js +67 -0
  42. package/dist/__tests__/lib/breakpoints.test.js.map +1 -0
  43. package/dist/__tests__/lib/canvas-edit-chrome.test.d.ts +2 -0
  44. package/dist/__tests__/lib/canvas-edit-chrome.test.d.ts.map +1 -0
  45. package/dist/__tests__/lib/canvas-edit-chrome.test.js +44 -0
  46. package/dist/__tests__/lib/canvas-edit-chrome.test.js.map +1 -0
  47. package/dist/__tests__/lib/media-format.test.d.ts +2 -0
  48. package/dist/__tests__/lib/media-format.test.d.ts.map +1 -0
  49. package/dist/__tests__/lib/media-format.test.js +70 -0
  50. package/dist/__tests__/lib/media-format.test.js.map +1 -0
  51. package/dist/__tests__/lib/page-audit-input.test.d.ts +2 -0
  52. package/dist/__tests__/lib/page-audit-input.test.d.ts.map +1 -0
  53. package/dist/__tests__/lib/page-audit-input.test.js +122 -0
  54. package/dist/__tests__/lib/page-audit-input.test.js.map +1 -0
  55. package/dist/__tests__/lib/page-editor-service.test.js +2 -0
  56. package/dist/__tests__/lib/page-editor-service.test.js.map +1 -1
  57. package/dist/__tests__/lib/page-redirect.test.d.ts +2 -0
  58. package/dist/__tests__/lib/page-redirect.test.d.ts.map +1 -0
  59. package/dist/__tests__/lib/page-redirect.test.js +26 -0
  60. package/dist/__tests__/lib/page-redirect.test.js.map +1 -0
  61. package/dist/__tests__/lib/rail-width.test.d.ts +2 -0
  62. package/dist/__tests__/lib/rail-width.test.d.ts.map +1 -0
  63. package/dist/__tests__/lib/rail-width.test.js +69 -0
  64. package/dist/__tests__/lib/rail-width.test.js.map +1 -0
  65. package/dist/__tests__/lib/reflow-baseline.test.d.ts +2 -0
  66. package/dist/__tests__/lib/reflow-baseline.test.d.ts.map +1 -0
  67. package/dist/__tests__/lib/reflow-baseline.test.js +56 -0
  68. package/dist/__tests__/lib/reflow-baseline.test.js.map +1 -0
  69. package/dist/__tests__/lib/reflow-probe.test.d.ts +2 -0
  70. package/dist/__tests__/lib/reflow-probe.test.d.ts.map +1 -0
  71. package/dist/__tests__/lib/reflow-probe.test.js +73 -0
  72. package/dist/__tests__/lib/reflow-probe.test.js.map +1 -0
  73. package/dist/__tests__/styles/canvas-container-queries.test.d.ts +2 -0
  74. package/dist/__tests__/styles/canvas-container-queries.test.d.ts.map +1 -0
  75. package/dist/__tests__/styles/canvas-container-queries.test.js +87 -0
  76. package/dist/__tests__/styles/canvas-container-queries.test.js.map +1 -0
  77. package/dist/__tests__/styles/packaging.test.d.ts +2 -0
  78. package/dist/__tests__/styles/packaging.test.d.ts.map +1 -0
  79. package/dist/__tests__/styles/packaging.test.js +31 -0
  80. package/dist/__tests__/styles/packaging.test.js.map +1 -0
  81. package/dist/__tests__/styles/tokens-drift.test.d.ts +2 -0
  82. package/dist/__tests__/styles/tokens-drift.test.d.ts.map +1 -0
  83. package/dist/__tests__/styles/tokens-drift.test.js +92 -0
  84. package/dist/__tests__/styles/tokens-drift.test.js.map +1 -0
  85. package/dist/__tests__/views/admin-renderer-compat.test.d.ts +2 -0
  86. package/dist/__tests__/views/admin-renderer-compat.test.d.ts.map +1 -0
  87. package/dist/__tests__/views/admin-renderer-compat.test.js +43 -0
  88. package/dist/__tests__/views/admin-renderer-compat.test.js.map +1 -0
  89. package/dist/__tests__/views/admin-section-renderers.test.js +52 -4
  90. package/dist/__tests__/views/admin-section-renderers.test.js.map +1 -1
  91. package/dist/__tests__/views/editor-top-bar.render.test.js +1 -1
  92. package/dist/__tests__/views/editor-top-bar.render.test.js.map +1 -1
  93. package/dist/__tests__/views/page-tab.render.test.d.ts +2 -0
  94. package/dist/__tests__/views/page-tab.render.test.d.ts.map +1 -0
  95. package/dist/__tests__/views/page-tab.render.test.js +151 -0
  96. package/dist/__tests__/views/page-tab.render.test.js.map +1 -0
  97. package/dist/__tests__/views/section-class-parity.test.d.ts +2 -0
  98. package/dist/__tests__/views/section-class-parity.test.d.ts.map +1 -0
  99. package/dist/__tests__/views/section-class-parity.test.js +81 -0
  100. package/dist/__tests__/views/section-class-parity.test.js.map +1 -0
  101. package/dist/__tests__/views/sections-panel-design-owned.render.test.d.ts +2 -0
  102. package/dist/__tests__/views/sections-panel-design-owned.render.test.d.ts.map +1 -0
  103. package/dist/__tests__/views/sections-panel-design-owned.render.test.js +86 -0
  104. package/dist/__tests__/views/sections-panel-design-owned.render.test.js.map +1 -0
  105. package/dist/components/BreakpointPicker.d.ts +18 -0
  106. package/dist/components/BreakpointPicker.d.ts.map +1 -0
  107. package/dist/components/BreakpointPicker.js +31 -0
  108. package/dist/components/BreakpointPicker.js.map +1 -0
  109. package/dist/components/CanvasEditTip.d.ts +6 -0
  110. package/dist/components/CanvasEditTip.d.ts.map +1 -0
  111. package/dist/components/CanvasEditTip.js +22 -0
  112. package/dist/components/CanvasEditTip.js.map +1 -0
  113. package/dist/components/EditorRail.d.ts +36 -0
  114. package/dist/components/EditorRail.d.ts.map +1 -0
  115. package/dist/components/EditorRail.js +104 -0
  116. package/dist/components/EditorRail.js.map +1 -0
  117. package/dist/components/EditorRailTabs.d.ts +32 -0
  118. package/dist/components/EditorRailTabs.d.ts.map +1 -0
  119. package/dist/components/EditorRailTabs.js +45 -0
  120. package/dist/components/EditorRailTabs.js.map +1 -0
  121. package/dist/components/MediaBlock.d.ts +49 -0
  122. package/dist/components/MediaBlock.d.ts.map +1 -0
  123. package/dist/components/MediaBlock.js +50 -0
  124. package/dist/components/MediaBlock.js.map +1 -0
  125. package/dist/components/ReflowMeter.d.ts +28 -0
  126. package/dist/components/ReflowMeter.d.ts.map +1 -0
  127. package/dist/components/ReflowMeter.js +42 -0
  128. package/dist/components/ReflowMeter.js.map +1 -0
  129. package/dist/components/ZoomChip.d.ts +17 -0
  130. package/dist/components/ZoomChip.d.ts.map +1 -0
  131. package/dist/components/ZoomChip.js +17 -0
  132. package/dist/components/ZoomChip.js.map +1 -0
  133. package/dist/components/breakpoint-icons.d.ts +3 -0
  134. package/dist/components/breakpoint-icons.d.ts.map +1 -0
  135. package/dist/components/breakpoint-icons.js +16 -0
  136. package/dist/components/breakpoint-icons.js.map +1 -0
  137. package/dist/components/page-tab/AuthorPicker.d.ts +31 -0
  138. package/dist/components/page-tab/AuthorPicker.d.ts.map +1 -0
  139. package/dist/components/page-tab/AuthorPicker.js +95 -0
  140. package/dist/components/page-tab/AuthorPicker.js.map +1 -0
  141. package/dist/components/page-tab/DirectiveSwitch.d.ts +38 -0
  142. package/dist/components/page-tab/DirectiveSwitch.d.ts.map +1 -0
  143. package/dist/components/page-tab/DirectiveSwitch.js +29 -0
  144. package/dist/components/page-tab/DirectiveSwitch.js.map +1 -0
  145. package/dist/components/seo/EditorSeoScoreBadge.d.ts +8 -1
  146. package/dist/components/seo/EditorSeoScoreBadge.d.ts.map +1 -1
  147. package/dist/components/seo/EditorSeoScoreBadge.js +2 -2
  148. package/dist/components/seo/EditorSeoScoreBadge.js.map +1 -1
  149. package/dist/components/seo/PageAuditPanel.d.ts +14 -0
  150. package/dist/components/seo/PageAuditPanel.d.ts.map +1 -0
  151. package/dist/components/seo/PageAuditPanel.js +59 -0
  152. package/dist/components/seo/PageAuditPanel.js.map +1 -0
  153. package/dist/components/seo/SeoCharCount.d.ts +19 -7
  154. package/dist/components/seo/SeoCharCount.d.ts.map +1 -1
  155. package/dist/components/seo/SeoCharCount.js +30 -16
  156. package/dist/components/seo/SeoCharCount.js.map +1 -1
  157. package/dist/components/seo/SeoEditorPane.d.ts +15 -1
  158. package/dist/components/seo/SeoEditorPane.d.ts.map +1 -1
  159. package/dist/components/seo/SeoEditorPane.js +118 -21
  160. package/dist/components/seo/SeoEditorPane.js.map +1 -1
  161. package/dist/components/seo/SerpPreview.d.ts +20 -0
  162. package/dist/components/seo/SerpPreview.d.ts.map +1 -0
  163. package/dist/components/seo/SerpPreview.js +6 -0
  164. package/dist/components/seo/SerpPreview.js.map +1 -0
  165. package/dist/hooks/usePageAudit.d.ts +41 -0
  166. package/dist/hooks/usePageAudit.d.ts.map +1 -0
  167. package/dist/hooks/usePageAudit.js +68 -0
  168. package/dist/hooks/usePageAudit.js.map +1 -0
  169. package/dist/hooks/useReflowGuard.d.ts +47 -0
  170. package/dist/hooks/useReflowGuard.d.ts.map +1 -0
  171. package/dist/hooks/useReflowGuard.js +52 -0
  172. package/dist/hooks/useReflowGuard.js.map +1 -0
  173. package/dist/lib/breakpoints.d.ts +51 -0
  174. package/dist/lib/breakpoints.d.ts.map +1 -0
  175. package/dist/lib/breakpoints.js +84 -0
  176. package/dist/lib/breakpoints.js.map +1 -0
  177. package/dist/lib/canvas-edit-chrome.d.ts +22 -0
  178. package/dist/lib/canvas-edit-chrome.d.ts.map +1 -0
  179. package/dist/lib/canvas-edit-chrome.js +81 -0
  180. package/dist/lib/canvas-edit-chrome.js.map +1 -0
  181. package/dist/lib/media-format.d.ts +55 -0
  182. package/dist/lib/media-format.d.ts.map +1 -0
  183. package/dist/lib/media-format.js +93 -0
  184. package/dist/lib/media-format.js.map +1 -0
  185. package/dist/lib/page-audit-input.d.ts +45 -0
  186. package/dist/lib/page-audit-input.d.ts.map +1 -0
  187. package/dist/lib/page-audit-input.js +53 -0
  188. package/dist/lib/page-audit-input.js.map +1 -0
  189. package/dist/lib/page-editor-service.d.ts +12 -0
  190. package/dist/lib/page-editor-service.d.ts.map +1 -1
  191. package/dist/lib/page-editor-service.js +6 -0
  192. package/dist/lib/page-editor-service.js.map +1 -1
  193. package/dist/lib/page-redirect.d.ts +39 -0
  194. package/dist/lib/page-redirect.d.ts.map +1 -0
  195. package/dist/lib/page-redirect.js +38 -0
  196. package/dist/lib/page-redirect.js.map +1 -0
  197. package/dist/lib/rail-width.d.ts +23 -0
  198. package/dist/lib/rail-width.d.ts.map +1 -0
  199. package/dist/lib/rail-width.js +59 -0
  200. package/dist/lib/rail-width.js.map +1 -0
  201. package/dist/lib/reflow-baseline.d.ts +45 -0
  202. package/dist/lib/reflow-baseline.d.ts.map +1 -0
  203. package/dist/lib/reflow-baseline.js +38 -0
  204. package/dist/lib/reflow-baseline.js.map +1 -0
  205. package/dist/lib/reflow-probe.d.ts +159 -0
  206. package/dist/lib/reflow-probe.d.ts.map +1 -0
  207. package/dist/lib/reflow-probe.js +228 -0
  208. package/dist/lib/reflow-probe.js.map +1 -0
  209. package/dist/lib/seo-service.d.ts +10 -0
  210. package/dist/lib/seo-service.d.ts.map +1 -1
  211. package/dist/lib/seo-service.js.map +1 -1
  212. package/dist/prenta-admin.css +1 -1
  213. package/dist/views/page-editor/CanvasMetaLine.d.ts +19 -0
  214. package/dist/views/page-editor/CanvasMetaLine.d.ts.map +1 -0
  215. package/dist/views/page-editor/CanvasMetaLine.js +23 -0
  216. package/dist/views/page-editor/CanvasMetaLine.js.map +1 -0
  217. package/dist/views/page-editor/EditorCanvas.d.ts +34 -8
  218. package/dist/views/page-editor/EditorCanvas.d.ts.map +1 -1
  219. package/dist/views/page-editor/EditorCanvas.js +68 -34
  220. package/dist/views/page-editor/EditorCanvas.js.map +1 -1
  221. package/dist/views/page-editor/EditorTopBar.d.ts +14 -1
  222. package/dist/views/page-editor/EditorTopBar.d.ts.map +1 -1
  223. package/dist/views/page-editor/EditorTopBar.js +8 -17
  224. package/dist/views/page-editor/EditorTopBar.js.map +1 -1
  225. package/dist/views/page-editor/PageSectionEditor.d.ts.map +1 -1
  226. package/dist/views/page-editor/PageSectionEditor.js +275 -53
  227. package/dist/views/page-editor/PageSectionEditor.js.map +1 -1
  228. package/dist/views/page-editor/PageTab.d.ts +36 -0
  229. package/dist/views/page-editor/PageTab.d.ts.map +1 -0
  230. package/dist/views/page-editor/PageTab.js +65 -0
  231. package/dist/views/page-editor/PageTab.js.map +1 -0
  232. package/dist/views/page-editor/SectionInspector.d.ts.map +1 -1
  233. package/dist/views/page-editor/SectionInspector.js +63 -19
  234. package/dist/views/page-editor/SectionInspector.js.map +1 -1
  235. package/dist/views/page-editor/SectionsPanel.d.ts +30 -5
  236. package/dist/views/page-editor/SectionsPanel.d.ts.map +1 -1
  237. package/dist/views/page-editor/SectionsPanel.js +38 -7
  238. package/dist/views/page-editor/SectionsPanel.js.map +1 -1
  239. package/dist/views/page-editor/SitePreviewFrame.d.ts.map +1 -1
  240. package/dist/views/page-editor/SitePreviewFrame.js +3 -0
  241. package/dist/views/page-editor/SitePreviewFrame.js.map +1 -1
  242. package/dist/views/page-editor/reflow-context.d.ts +28 -0
  243. package/dist/views/page-editor/reflow-context.d.ts.map +1 -0
  244. package/dist/views/page-editor/reflow-context.js +14 -0
  245. package/dist/views/page-editor/reflow-context.js.map +1 -0
  246. package/dist/views/page-editor/sections/ByTheNumbersSection.d.ts.map +1 -1
  247. package/dist/views/page-editor/sections/ByTheNumbersSection.js +1 -1
  248. package/dist/views/page-editor/sections/ByTheNumbersSection.js.map +1 -1
  249. package/dist/views/page-editor/sections/CtaBannerSection.d.ts.map +1 -1
  250. package/dist/views/page-editor/sections/CtaBannerSection.js +1 -1
  251. package/dist/views/page-editor/sections/CtaBannerSection.js.map +1 -1
  252. package/dist/views/page-editor/sections/FeatureHighlightSection.d.ts.map +1 -1
  253. package/dist/views/page-editor/sections/FeatureHighlightSection.js +2 -2
  254. package/dist/views/page-editor/sections/FeatureHighlightSection.js.map +1 -1
  255. package/dist/views/page-editor/sections/GallerySection.d.ts.map +1 -1
  256. package/dist/views/page-editor/sections/GallerySection.js +7 -3
  257. package/dist/views/page-editor/sections/GallerySection.js.map +1 -1
  258. package/dist/views/page-editor/sections/HeroBannerSection.js +1 -1
  259. package/dist/views/page-editor/sections/HeroBannerSection.js.map +1 -1
  260. package/dist/views/page-editor/sections/MissionSection.d.ts.map +1 -1
  261. package/dist/views/page-editor/sections/MissionSection.js +1 -1
  262. package/dist/views/page-editor/sections/MissionSection.js.map +1 -1
  263. package/dist/views/page-editor/sections/PullQuoteSection.d.ts.map +1 -1
  264. package/dist/views/page-editor/sections/PullQuoteSection.js +1 -1
  265. package/dist/views/page-editor/sections/PullQuoteSection.js.map +1 -1
  266. package/dist/views/page-editor/sections/RelatedPostsSection.d.ts.map +1 -1
  267. package/dist/views/page-editor/sections/RelatedPostsSection.js +1 -1
  268. package/dist/views/page-editor/sections/RelatedPostsSection.js.map +1 -1
  269. package/dist/views/page-editor/sections/SectionRenderer.d.ts.map +1 -1
  270. package/dist/views/page-editor/sections/SectionRenderer.js +49 -24
  271. package/dist/views/page-editor/sections/SectionRenderer.js.map +1 -1
  272. package/dist/views/page-editor/sections/admin-renderers.d.ts +47 -15
  273. package/dist/views/page-editor/sections/admin-renderers.d.ts.map +1 -1
  274. package/dist/views/page-editor/sections/admin-renderers.js +27 -15
  275. package/dist/views/page-editor/sections/admin-renderers.js.map +1 -1
  276. package/dist/views/page-editor/sections/parts.d.ts +0 -1
  277. package/dist/views/page-editor/sections/parts.d.ts.map +1 -1
  278. package/dist/views/page-editor/sections/parts.js +41 -16
  279. package/dist/views/page-editor/sections/parts.js.map +1 -1
  280. package/dist/views/page-editor/viewports.d.ts +7 -14
  281. package/dist/views/page-editor/viewports.d.ts.map +1 -1
  282. package/dist/views/page-editor/viewports.js +7 -12
  283. package/dist/views/page-editor/viewports.js.map +1 -1
  284. package/dist/views/post-editor/PostEditorCanvas.d.ts +2 -1
  285. package/dist/views/post-editor/PostEditorCanvas.d.ts.map +1 -1
  286. package/dist/views/post-editor/PostEditorCanvas.js +5 -2
  287. package/dist/views/post-editor/PostEditorCanvas.js.map +1 -1
  288. package/dist/views/post-editor/PostSectionEditor.d.ts.map +1 -1
  289. package/dist/views/post-editor/PostSectionEditor.js +2 -20
  290. package/dist/views/post-editor/PostSectionEditor.js.map +1 -1
  291. package/dist/views/post-editor/PostTemplateEditor.d.ts.map +1 -1
  292. package/dist/views/post-editor/PostTemplateEditor.js +4 -1
  293. package/dist/views/post-editor/PostTemplateEditor.js.map +1 -1
  294. package/package.json +5 -3
  295. package/src/AdminRoot.tsx +27 -6
  296. package/src/__tests__/components/breakpoint-controls.render.test.tsx +57 -0
  297. package/src/__tests__/components/canvas-edit-tip.render.test.tsx +41 -0
  298. package/src/__tests__/components/editor-rail.render.test.tsx +192 -0
  299. package/src/__tests__/components/media-block.render.test.tsx +126 -0
  300. package/src/__tests__/components/page-audit-panel.render.test.tsx +64 -0
  301. package/src/__tests__/components/reflow-meter.render.test.tsx +144 -0
  302. package/src/__tests__/components/seo-char-count.test.tsx +26 -6
  303. package/src/__tests__/components/serp-preview.render.test.tsx +32 -0
  304. package/src/__tests__/lib/breakpoints.test.ts +84 -0
  305. package/src/__tests__/lib/canvas-edit-chrome.test.ts +56 -0
  306. package/src/__tests__/lib/media-format.test.ts +89 -0
  307. package/src/__tests__/lib/page-audit-input.test.ts +144 -0
  308. package/src/__tests__/lib/page-editor-service.test.ts +2 -0
  309. package/src/__tests__/lib/page-redirect.test.ts +29 -0
  310. package/src/__tests__/lib/rail-width.test.ts +86 -0
  311. package/src/__tests__/lib/reflow-baseline.test.ts +64 -0
  312. package/src/__tests__/lib/reflow-probe.test.ts +95 -0
  313. package/src/__tests__/styles/canvas-container-queries.test.ts +103 -0
  314. package/src/__tests__/styles/packaging.test.ts +38 -0
  315. package/src/__tests__/styles/tokens-drift.test.ts +110 -0
  316. package/src/__tests__/views/admin-renderer-compat.test.ts +48 -0
  317. package/src/__tests__/views/admin-section-renderers.test.tsx +70 -4
  318. package/src/__tests__/views/editor-top-bar.render.test.tsx +1 -1
  319. package/src/__tests__/views/page-tab.render.test.tsx +226 -0
  320. package/src/__tests__/views/section-class-parity.test.ts +98 -0
  321. package/src/__tests__/views/sections-panel-design-owned.render.test.tsx +104 -0
  322. package/src/components/BreakpointPicker.tsx +114 -0
  323. package/src/components/CanvasEditTip.tsx +46 -0
  324. package/src/components/EditorRail.tsx +219 -0
  325. package/src/components/EditorRailTabs.tsx +117 -0
  326. package/src/components/MediaBlock.tsx +223 -0
  327. package/src/components/ReflowMeter.tsx +125 -0
  328. package/src/components/ZoomChip.tsx +39 -0
  329. package/src/components/breakpoint-icons.ts +17 -0
  330. package/src/components/page-tab/AuthorPicker.tsx +240 -0
  331. package/src/components/page-tab/DirectiveSwitch.tsx +86 -0
  332. package/src/components/seo/EditorSeoScoreBadge.tsx +9 -1
  333. package/src/components/seo/PageAuditPanel.tsx +192 -0
  334. package/src/components/seo/SeoCharCount.tsx +55 -24
  335. package/src/components/seo/SeoEditorPane.tsx +213 -31
  336. package/src/components/seo/SerpPreview.tsx +41 -0
  337. package/src/hooks/usePageAudit.ts +98 -0
  338. package/src/hooks/useReflowGuard.ts +96 -0
  339. package/src/lib/breakpoints.ts +107 -0
  340. package/src/lib/canvas-edit-chrome.ts +82 -0
  341. package/src/lib/media-format.ts +99 -0
  342. package/src/lib/page-audit-input.ts +104 -0
  343. package/src/lib/page-editor-service.ts +18 -0
  344. package/src/lib/page-redirect.ts +60 -0
  345. package/src/lib/rail-width.ts +58 -0
  346. package/src/lib/reflow-baseline.ts +70 -0
  347. package/src/lib/reflow-probe.ts +299 -0
  348. package/src/lib/seo-service.ts +10 -0
  349. package/src/styles/prenta-tokens.css +120 -42
  350. package/src/styles/theme.css +130 -0
  351. package/src/views/page-editor/CanvasMetaLine.tsx +50 -0
  352. package/src/views/page-editor/EditorCanvas.tsx +109 -50
  353. package/src/views/page-editor/EditorTopBar.tsx +35 -43
  354. package/src/views/page-editor/PageSectionEditor.tsx +419 -148
  355. package/src/views/page-editor/PageTab.tsx +433 -0
  356. package/src/views/page-editor/SectionInspector.tsx +82 -41
  357. package/src/views/page-editor/SectionsPanel.tsx +281 -140
  358. package/src/views/page-editor/SitePreviewFrame.tsx +3 -0
  359. package/src/views/page-editor/reflow-context.ts +43 -0
  360. package/src/views/page-editor/sections/ByTheNumbersSection.tsx +3 -2
  361. package/src/views/page-editor/sections/CtaBannerSection.tsx +3 -1
  362. package/src/views/page-editor/sections/FeatureHighlightSection.tsx +3 -2
  363. package/src/views/page-editor/sections/GallerySection.tsx +7 -3
  364. package/src/views/page-editor/sections/HeroBannerSection.tsx +2 -2
  365. package/src/views/page-editor/sections/MissionSection.tsx +4 -2
  366. package/src/views/page-editor/sections/PullQuoteSection.tsx +3 -1
  367. package/src/views/page-editor/sections/RelatedPostsSection.tsx +2 -1
  368. package/src/views/page-editor/sections/SectionRenderer.tsx +69 -29
  369. package/src/views/page-editor/sections/admin-renderers.tsx +54 -15
  370. package/src/views/page-editor/sections/parts.tsx +46 -18
  371. package/src/views/page-editor/viewports.ts +13 -26
  372. package/src/views/post-editor/PostEditorCanvas.tsx +18 -11
  373. package/src/views/post-editor/PostSectionEditor.tsx +1 -56
  374. package/src/views/post-editor/PostTemplateEditor.tsx +3 -0
@@ -0,0 +1,70 @@
1
+ import type { PageSection } from '@prenta/core/page-sections'
2
+
3
+ /**
4
+ * The content a page's sections had when they were last live.
5
+ *
6
+ * ── What "baseline" means here, and why ───────────────────────────────────
7
+ *
8
+ * The guard answers "will this edit change how the live page wraps?" — so the
9
+ * baseline has to be what is actually on the site, not what was last saved.
10
+ *
11
+ * This CMS has no draft/published split: a document carries one `status` and
12
+ * saving a PUBLISHED page updates the live content in place. So for a published
13
+ * page the live content is whatever the editor loaded, refreshed on every save
14
+ * and publish. For a page that has never been published there is no baseline at
15
+ * all, and the guard reports line counts without deltas — correctly, because
16
+ * there is no live layout to break.
17
+ *
18
+ * Deliberately NOT sourced from the versions API. Versions do hold full
19
+ * snapshots, but they record every update, so finding "the published one" means
20
+ * scanning history and guessing which entry was live — an extra request and a
21
+ * heuristic, to reconstruct something the editor already has in hand.
22
+ */
23
+ export interface ReflowBaseline {
24
+ byId: Map<string, Record<string, unknown>>
25
+ }
26
+
27
+ /**
28
+ * Snapshot section content, or `null` when the page is not live.
29
+ *
30
+ * `null` rather than an empty snapshot: an empty baseline would read as "every
31
+ * field was previously blank" and flag every line of existing copy as newly
32
+ * added.
33
+ */
34
+ export function snapshotBaseline(
35
+ sections: readonly PageSection[],
36
+ status: string,
37
+ ): ReflowBaseline | null {
38
+ if (status !== 'PUBLISHED') return null
39
+ return {
40
+ byId: new Map(sections.map((s) => [s.id, { ...(s.content ?? {}) }])),
41
+ }
42
+ }
43
+
44
+ /**
45
+ * Resolve a `data-cms-field` path against a baseline.
46
+ *
47
+ * Paths are dotted and may index arrays (`stats.0.label`), matching the markers
48
+ * the renderers emit.
49
+ *
50
+ * Returns `undefined` for anything that is not baseline text — no snapshot, a
51
+ * section added since publish, a field that did not exist, or a non-string
52
+ * value. The guard reads `undefined` as "nothing to compare against" and
53
+ * reports no delta, which is the truthful answer in every one of those cases.
54
+ */
55
+ export function baselineFieldText(
56
+ baseline: ReflowBaseline | null,
57
+ sectionId: string,
58
+ fieldPath: string,
59
+ ): string | undefined {
60
+ const content = baseline?.byId.get(sectionId)
61
+ if (!content) return undefined
62
+
63
+ let cursor: unknown = content
64
+ for (const key of fieldPath.split('.')) {
65
+ if (cursor === null || typeof cursor !== 'object') return undefined
66
+ cursor = (cursor as Record<string, unknown>)[key]
67
+ }
68
+
69
+ return typeof cursor === 'string' ? cursor : undefined
70
+ }
@@ -0,0 +1,299 @@
1
+ import { BREAKPOINTS, type BreakpointId } from './breakpoints.js'
2
+
3
+ /**
4
+ * Measures how a field's copy wraps at every breakpoint, by laying it out for
5
+ * real rather than estimating.
6
+ *
7
+ * ── Why not a class chain ─────────────────────────────────────────────────
8
+ *
9
+ * The design handoff specifies rebuilding each probe from a hardcoded list of
10
+ * wrapper classes per guarded field, and warns twice that a width cap outside
11
+ * that list makes the guard lie — at wide breakpoints only, so it looks correct
12
+ * on mobile. By the handoff's own account that list drifted twice.
13
+ *
14
+ * A chain is a second source of truth that has to track the renderers' markup
15
+ * by hand. Worse here: the prototype had semantic classes (`.pv-hero-h`), while
16
+ * these components are styled with Tailwind utility strings that Prettier's
17
+ * plugin reorders on save. And a chain written in the admin cannot describe a
18
+ * consumer's own registered renderer at all.
19
+ *
20
+ * So the probe measures the REAL element: the caller renders the actual section
21
+ * into a hidden host, and this module finds the field by its `data-cms-field`
22
+ * marker — the same attribute the click-to-edit bridge uses. There is nothing
23
+ * to keep in sync, and a renderer refactor cannot silently invalidate it.
24
+ *
25
+ * ── Why one host, resized ─────────────────────────────────────────────────
26
+ *
27
+ * Six widths are measured by resizing a single rendered copy, not by rendering
28
+ * six. Layout is recomputed either way; React reconciliation is not.
29
+ */
30
+
31
+ /** A field's wrap count at one breakpoint. */
32
+ export interface FieldLineCount {
33
+ id: BreakpointId
34
+ lines: number
35
+ }
36
+
37
+ /**
38
+ * Line count from an element's laid-out height.
39
+ *
40
+ * Falls back to `fontSize * 1.25` when `line-height` computes to `normal`,
41
+ * which it does for any element that never set one. Rounding rather than
42
+ * flooring: sub-pixel line heights accumulate, and 2.97 lines is three.
43
+ */
44
+ export function linesFromMetrics(height: number, lineHeight: number, fontSize: number): number {
45
+ const effective = Number.isFinite(lineHeight) && lineHeight > 0 ? lineHeight : fontSize * 1.25
46
+ if (!Number.isFinite(effective) || effective <= 0) return 1
47
+ // An empty field still occupies one line's worth of intent.
48
+ return Math.max(1, Math.round(height / effective))
49
+ }
50
+
51
+ /**
52
+ * How many lines an element's text actually occupies.
53
+ *
54
+ * Counts LINE BOXES via a Range over the element's contents, deduplicated by
55
+ * their top edge. Dividing the element's height by its line-height — the
56
+ * obvious approach, and what the prototype does — counts padding as text: a
57
+ * button reading "Get Started" measured 2 lines, because its vertical padding
58
+ * came to roughly another line's worth of height. Every padded element was
59
+ * over-reported, which is most CTAs and every boxed heading.
60
+ *
61
+ * Rects are deduplicated by rounded top edge because a range spanning nested
62
+ * inline elements (a `<strong>` mid-sentence, an icon in a button) yields one
63
+ * rect per fragment, not per line.
64
+ *
65
+ * Falls back to the height ratio when the range produces nothing — an element
66
+ * whose content is a single replaced node, or a layout engine that gives no
67
+ * rects for empty text.
68
+ */
69
+ export function countLines(el: HTMLElement): number {
70
+ const doc = el.ownerDocument
71
+ try {
72
+ const range = doc.createRange()
73
+ range.selectNodeContents(el)
74
+ const rects = Array.from(range.getClientRects()).filter((r) => r.height > 0)
75
+ range.detach?.()
76
+ if (rects.length > 0) {
77
+ const tops = new Set(rects.map((r) => Math.round(r.top)))
78
+ return Math.max(1, tops.size)
79
+ }
80
+ } catch {
81
+ // No Range support (or a detached document) — fall through to metrics.
82
+ }
83
+
84
+ const cs = getComputedStyle(el)
85
+ return linesFromMetrics(
86
+ el.getBoundingClientRect().height,
87
+ Number.parseFloat(cs.lineHeight),
88
+ Number.parseFloat(cs.fontSize),
89
+ )
90
+ }
91
+
92
+ /**
93
+ * The off-screen host.
94
+ *
95
+ * `left: -99999px`, never `display: none` — a hidden element has no layout, so
96
+ * every measurement would be zero. `visibility: hidden` would keep layout but
97
+ * also keep the element in the accessibility tree; moving it off-screen and
98
+ * marking it `aria-hidden` keeps it out of both the viewport and the a11y tree
99
+ * while still being laid out.
100
+ *
101
+ * MOUNT IT INSIDE `.prenta-admin`, never on `document.body`. Type tokens and
102
+ * the font stack are scoped to that root, so a host outside it lays text out in
103
+ * the document's default font and every measurement is taken at the wrong
104
+ * metrics. Caught by `e2e/reflow-probe.spec.ts` on its first run: a button
105
+ * measured 127px on the canvas and 139px in a body-mounted probe.
106
+ *
107
+ * Use `mountProbeHost` rather than appending by hand.
108
+ */
109
+ export function createProbeHost(doc: Document = document): HTMLElement {
110
+ const host = doc.createElement('div')
111
+ host.setAttribute('aria-hidden', 'true')
112
+ host.dataset.reflowProbe = 'true'
113
+ Object.assign(host.style, {
114
+ position: 'fixed',
115
+ left: '-99999px',
116
+ top: '0',
117
+ // Never inherit the rail's width — the probe sets its own per breakpoint.
118
+ width: 'auto',
119
+ pointerEvents: 'none',
120
+ })
121
+ return host
122
+ }
123
+
124
+ /**
125
+ * Attach a probe host in the only place it measures correctly.
126
+ *
127
+ * Returns a detach function. Falls back to `document.body` only when no admin
128
+ * root exists (it always does in the app) — and callers should treat a
129
+ * fallback mount as untrustworthy rather than silently measuring.
130
+ */
131
+ export function mountProbeHost(
132
+ host: HTMLElement,
133
+ doc: Document = document,
134
+ ): { detach: () => void; scoped: boolean } {
135
+ const root = doc.querySelector('.prenta-admin')
136
+ const parent = root ?? doc.body
137
+ parent.appendChild(host)
138
+ return { detach: () => host.remove(), scoped: Boolean(root) }
139
+ }
140
+
141
+ /**
142
+ * Measure one field across every breakpoint.
143
+ *
144
+ * `container` must carry the same class chain the canvas uses
145
+ * (`prenta-canvas`, which supplies the query container). Its width is set per
146
+ * breakpoint, so it must not be width-constrained by a parent.
147
+ *
148
+ * `scope` narrows to one section and is REQUIRED whenever the container holds
149
+ * more than one, because `data-cms-field` paths are unique only within a
150
+ * section — every section has a `heading` and a `body`. Without it a whole page
151
+ * silently measures the first section's field and reports it for all of them.
152
+ * (That mistake is what `e2e/reflow-probe.spec.ts` caught on its second run.)
153
+ *
154
+ * Returns `null` when the field cannot be found — the canvas is rendering a
155
+ * component without `data-cms-field` markers, so there is nothing to measure.
156
+ * Reporting a line count from the wrong element would be worse than reporting
157
+ * none: an editor reads a number as a fact.
158
+ */
159
+ export function measureFieldAcrossBreakpoints(
160
+ container: HTMLElement,
161
+ fieldPath: string,
162
+ scope?: string,
163
+ ): FieldLineCount[] | null {
164
+ const field = `[data-cms-field="${CSS.escape(fieldPath)}"]`
165
+ const selector = scope ? `${scope} ${field}` : field
166
+ if (!container.querySelector(selector)) return null
167
+
168
+ const previousWidth = container.style.width
169
+ const out: FieldLineCount[] = []
170
+
171
+ for (const bp of BREAKPOINTS) {
172
+ container.style.width = `${bp.width}px`
173
+ // Re-query inside the loop: a renderer may swap elements between layouts
174
+ // (a grid that becomes a stack can remount its children).
175
+ const el = container.querySelector(selector)
176
+ out.push({ id: bp.id, lines: el ? countLines(el as HTMLElement) : 1 })
177
+ }
178
+
179
+ container.style.width = previousWidth
180
+ return out
181
+ }
182
+
183
+ /** What a probe pass produces for one field. */
184
+ export interface FieldReflow {
185
+ current: FieldLineCount[]
186
+ baseline: FieldLineCount[]
187
+ }
188
+
189
+ /**
190
+ * Measure a field's wrapping now and as published, from the live canvas.
191
+ *
192
+ * The whole `.prenta-canvas` is cloned, not just the target section. Cloning
193
+ * the section alone would require rebuilding whatever sits between the canvas
194
+ * root and the section — which is the class-chain problem again, in a smaller
195
+ * disguise. `e2e/reflow-probe.spec.ts` asserts the whole-canvas clone
196
+ * reproduces every field's rendered width exactly; nothing asserts that for a
197
+ * hand-rebuilt wrapper.
198
+ *
199
+ * The baseline is measured by writing the published string into the SAME cloned
200
+ * element and re-measuring, rather than by rendering the published section. The
201
+ * two differ in exactly one field, so everything else — width caps, siblings,
202
+ * grid tracks — is held identical by construction rather than by hoping a second
203
+ * render matches.
204
+ *
205
+ * `baselineText` of `undefined` means the field has no published version (a new
206
+ * section), so there is no change to report and current is echoed as baseline.
207
+ *
208
+ * Returns `null` when the section or field is absent from the canvas — a
209
+ * consumer's renderer may carry no `data-cms-field` markers, and a line count
210
+ * read off the wrong element is worse than none.
211
+ */
212
+ export function probeFieldReflow(options: {
213
+ canvas: HTMLElement
214
+ sectionId: string
215
+ fieldPath: string
216
+ baselineText: string | undefined
217
+ doc?: Document
218
+ }): FieldReflow | null {
219
+ const { canvas, sectionId, fieldPath, baselineText, doc = document } = options
220
+
221
+ const sectionSel = `[data-section-id="${CSS.escape(sectionId)}"]`
222
+ const fieldSel = `${sectionSel} [data-cms-field="${CSS.escape(fieldPath)}"]`
223
+ if (!canvas.querySelector(fieldSel)) return null
224
+
225
+ const host = createProbeHost(doc)
226
+ const clone = canvas.cloneNode(true) as HTMLElement
227
+ // The canvas is scaled to fit its column. A transform does not change layout
228
+ // width, but it does scale the measured rects — and line height is read from
229
+ // a rect. Left on, every count would be off by the scale factor.
230
+ clone.style.transform = 'none'
231
+ clone.style.maxWidth = 'none'
232
+ host.appendChild(clone)
233
+
234
+ const { detach, scoped } = mountProbeHost(host, doc)
235
+ // Outside `.prenta-admin` the type tokens don't apply and every measurement
236
+ // is taken in the document's default font. Report nothing rather than that.
237
+ if (!scoped) {
238
+ detach()
239
+ return null
240
+ }
241
+
242
+ try {
243
+ const current = measureFieldAcrossBreakpoints(clone, fieldPath, sectionSel)
244
+ if (!current) return null
245
+ if (baselineText === undefined) return { current, baseline: current }
246
+
247
+ const el = clone.querySelector(fieldSel)
248
+ if (!el) return { current, baseline: current }
249
+ el.textContent = baselineText
250
+ const baseline = measureFieldAcrossBreakpoints(clone, fieldPath, sectionSel)
251
+ return { current, baseline: baseline ?? current }
252
+ } finally {
253
+ detach()
254
+ }
255
+ }
256
+
257
+ export type ReflowSeverity = 'same' | 'grew' | 'grew-badly'
258
+
259
+ /**
260
+ * Compare a field's current wrapping against its published baseline.
261
+ *
262
+ * Only growth is flagged. Copy that got shorter cannot break a layout that
263
+ * already held the longer version, so reporting it would be noise on exactly
264
+ * the edit an editor was asked to make.
265
+ */
266
+ export function reflowSeverity(current: number, baseline: number): ReflowSeverity {
267
+ const delta = current - baseline
268
+ if (delta <= 0) return 'same'
269
+ return delta === 1 ? 'grew' : 'grew-badly'
270
+ }
271
+
272
+ /**
273
+ * The breakpoint worth proofing on: the biggest jump, and on a tie the
274
+ * narrowest width. A tie means the same damage happens at several sizes, and
275
+ * the narrowest is where it is most likely to look broken.
276
+ */
277
+ export function worstBreakpoint(
278
+ current: FieldLineCount[],
279
+ baseline: FieldLineCount[],
280
+ ): BreakpointId | null {
281
+ const widthOf = (id: BreakpointId) => BREAKPOINTS.find((b) => b.id === id)?.width ?? 0
282
+ let worst: { id: BreakpointId; delta: number } | null = null
283
+
284
+ for (const c of current) {
285
+ const b = baseline.find((x) => x.id === c.id)
286
+ if (!b) continue
287
+ const delta = c.lines - b.lines
288
+ if (delta <= 0) continue
289
+ if (
290
+ !worst ||
291
+ delta > worst.delta ||
292
+ (delta === worst.delta && widthOf(c.id) < widthOf(worst.id))
293
+ ) {
294
+ worst = { id: c.id, delta }
295
+ }
296
+ }
297
+
298
+ return worst?.id ?? null
299
+ }
@@ -11,6 +11,7 @@
11
11
  import type { BrandAlignmentScoreResult } from '@prenta/core/brand-voice'
12
12
  import type { SEOAnalysisResult } from '@prenta/core/seo/analysis'
13
13
  import { cmsApi } from './api.js'
14
+ import type { MaxImagePreview } from '@prenta/core/seo/robots-directives'
14
15
 
15
16
  /**
16
17
  * `cmsApi` never throws — it returns `{ error, status }` on a network/HTTP
@@ -182,6 +183,12 @@ export interface SeoContentRecord {
182
183
  twitterImageId: string | null
183
184
  noindex: boolean
184
185
  nofollow: boolean
186
+ /** Blocks text snippets, and with them AI Overview and chat citations. */
187
+ nosnippet: boolean
188
+ /** Blocks cached copies. */
189
+ noarchive: boolean
190
+ /** Largest image preview a result may show. */
191
+ maxImagePreview: MaxImagePreview
185
192
  structuredDataType: string | null
186
193
  structuredData: Record<string, unknown> | null
187
194
  /** llms.txt curation: AUTO (heuristic), ALWAYS (pin), NEVER (exclude). */
@@ -232,6 +239,9 @@ export interface SeoFieldPayload {
232
239
  twitterImage?: string
233
240
  noindex?: boolean
234
241
  nofollow?: boolean
242
+ nosnippet?: boolean
243
+ noarchive?: boolean
244
+ maxImagePreview?: MaxImagePreview
235
245
  structuredDataType?: string
236
246
  structuredData?: Record<string, unknown>
237
247
  llmsInclude?: LlmsInclude
@@ -1,29 +1,39 @@
1
1
  /*
2
2
  * PrentaCMS design tokens — scoped to the admin root.
3
- * Source: design-system/tokens.json (v1.0).
4
- * Appearance accent overrides set --acc / --primary at runtime.
3
+ * GENERATED FILE — DO NOT EDIT. Source: design-system/tokens.json.
4
+ * Regenerate: pnpm --filter @prenta/admin generate
5
+ *
6
+ * Scoped to .prenta-admin rather than :root on purpose: the admin renders
7
+ * inside consumer applications, and custom properties resolve by INHERITANCE,
8
+ * not by specificity — a host site's :root would otherwise win against every
9
+ * admin rule reading these names. Appearance settings mutate --acc / --primary
10
+ * at runtime on this same element.
5
11
  */
6
12
 
7
13
  .prenta-admin {
8
14
  /* Surfaces */
9
- --bg: #f5f4fa;
10
- --sb: #ffffff;
11
- --card: #ffffff;
12
- --bdr: #e8e6f2;
15
+ --bg: #f5f4fa; /* App background */
16
+ --sb: #ffffff; /* Sidebar / topbar surface */
17
+ --card: #ffffff; /* Card / panel surface */
18
+ --bdr: #e8e6f2; /* Hairline border */
13
19
 
14
20
  /* Text */
15
- --txt: #1a1827;
16
- --sub: #6b6878;
17
- /* Deviates from tokens.json's #B0ADBE (2.2:1 on white — illegible). The
18
- admin uses --muted as real text (section labels, hints, icons), so it
19
- must meet WCAG AA (>=4.5:1) on --card and --bg while staying one step
20
- lighter than --sub to preserve the text hierarchy. */
21
+ --txt: #1a1827; /* Primary text */
22
+ --sub: #6b6878; /* Secondary text */
23
+ /*
24
+ * Tertiary text. The handoff value #B0ADBE is 2.2:1 on --card — below WCAG
25
+ * AA. The admin uses --muted as real text (section labels, check hints,
26
+ * canvas meta line, character counters), so it is darkened to 4.6:1 while
27
+ * staying one step lighter than --sub to preserve the hierarchy. Do not
28
+ * revert without also changing every --muted consumer to decorative use.
29
+ * Handoff value: #b0adbe — deliberately overridden.
30
+ */
21
31
  --muted: #716e83;
22
32
 
23
33
  /* Accent */
24
- --acc: #7c3aed;
25
- --acc-l: #ede9fe;
26
- --acc-m: #c4b5fd;
34
+ --acc: #7c3aed; /* Accent / interactive */
35
+ --acc-l: #ede9fe; /* Accent tint (hover/active bg) */
36
+ --acc-m: #c4b5fd; /* Accent mid (focus ring) */
27
37
 
28
38
  /* Semantic */
29
39
  --suc: #059669;
@@ -35,11 +45,7 @@
35
45
  --info: #0891b2;
36
46
  --info-l: #e0f7fa;
37
47
 
38
- /*
39
- * Page / post-type tag palette — distinct editorial hues.
40
- * Kept separate from status tokens so "pink" is not warning orange and
41
- * "blue" is not info cyan. Soft companions tint pill backgrounds.
42
- */
48
+ /* Tag palette */
43
49
  --tag-purple: #7c3aed;
44
50
  --tag-purple-soft: #f3e8ff;
45
51
  --tag-green: #0f766e;
@@ -60,56 +66,123 @@
60
66
  --ai2: #c026d3;
61
67
  --ai-soft: linear-gradient(135deg, rgba(124, 58, 237, 0.09), rgba(192, 38, 211, 0.07));
62
68
 
69
+ /* Controls */
70
+ /*
71
+ * Switch knob stays white in both themes per the design system; tokenized so
72
+ * a consumer theme can move it.
73
+ */
74
+ --toggle-thumb: #ffffff;
75
+
76
+ /* Type */
77
+ /*
78
+ * UI text. Self-hosted woff2 under design-system/fonts — never a third-party
79
+ * request, because the admin renders inside consumer applications.
80
+ */
81
+ --font-sans: 'DM Sans', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
82
+ /* Code, robots directives, token names */
83
+ --font-mono: 'DM Mono', ui-monospace, 'SFMono-Regular', monospace;
84
+ --fw-reg: 450;
85
+ --fw-med: 500;
86
+ --fw-semi: 600;
87
+ --fw-bold: 700;
88
+ --fs-page: 21px; /* Page title */
89
+ --fs-card: 14px; /* Card / section title */
90
+ --fs-body: 13px; /* Body, controls, table cells */
91
+ --fs-sub: 12px; /* Secondary / captions */
92
+ --fs-hint: 11.5px; /* Hints, metadata */
93
+ --fs-label: 10px; /* Section labels */
94
+
63
95
  /* Layout */
64
96
  --sbw: 224px;
65
97
  --sbw-col: 60px;
66
98
  --tbh: 56px;
67
- --r: 10px;
68
- --r-control: 8px;
69
- --r-sm: 6px;
70
- --r-pill: 99px;
71
99
 
72
- /* Elevation */
73
- --shd: 0 1px 2px rgba(0, 0, 0, 0.05), 0 1px 4px rgba(0, 0, 0, 0.04);
74
- --shd2: 0 4px 16px rgba(0, 0, 0, 0.1);
100
+ /* Radius */
101
+ --r-sm: 6px; /* Small buttons, badges, tags, chips-in-rows */
102
+ --r-field: 7px; /* Text inputs, textareas, selects */
103
+ /*
104
+ * Primary / secondary buttons, dropdowns. --r-control is the pre-2.0 name,
105
+ * kept resolving for existing rules.
106
+ */
107
+ --r-ctl: 8px;
108
+ --r-control: var(--r-ctl); /* deprecated alias */
109
+ --r: 10px; /* Cards and panels */
110
+ --r-fig: 12px; /* Canvas figures and media frames */
111
+ --r-pill: 99px; /* Toggles, meters, notice pills */
112
+
113
+ /* Spacing */
114
+ --sp-2: 2px;
115
+ --sp-4: 4px;
116
+ --sp-6: 6px;
117
+ --sp-8: 8px;
118
+ --sp-10: 10px;
119
+ --sp-12: 12px; /* Row padding-y */
120
+ --sp-14: 14px; /* Panel padding */
121
+ --sp-16: 16px; /* Editor header padding-x */
122
+ --sp-18: 18px; /* Canvas gutter top */
123
+ --sp-20: 20px;
124
+ --sp-24: 24px; /* Canvas gutter sides */
125
+ --sp-28: 28px;
126
+ --sp-32: 32px;
127
+ --sp-40: 40px; /* Canvas gutter bottom */
128
+
129
+ /* Control sizing */
130
+ --h-chip: 26px; /* Rail buttons, theme toggle */
131
+ --h-field: 33px; /* Text inputs and small buttons */
132
+ --h-ctl: 34px; /* Header controls: icon buttons, breakpoint trigger, zoom chip, SEO chip */
133
+
134
+ /* Border */
135
+ --bw: 1px;
136
+ --bw-ctl: 1.5px; /* Input and card border */
137
+ --bw-focus: 2px; /* Focus and active outline */
138
+ --ring: 0 0 0 3px var(--acc-m); /* Focus ring shadow */
75
139
 
76
- /* Typography */
77
- --font-sans: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
78
- --font-mono: 'DM Mono', ui-monospace, 'SFMono-Regular', monospace;
79
- --fs-page: 21px;
80
- --fs-card: 14px;
81
- --fs-body: 13px;
82
- --fs-sub: 12px;
83
- --fs-hint: 11.5px;
84
- --fs-label: 10px;
140
+ /* Elevation */
141
+ --shd: 0 1px 2px rgba(0, 0, 0, 0.05), 0 1px 4px rgba(0, 0, 0, 0.04); /* Card resting */
142
+ --shd2: 0 4px 16px rgba(0, 0, 0, 0.1); /* Popovers, modals, hover */
85
143
 
86
144
  /* Motion */
87
- --motion-fast: 0.12s;
88
- --motion-base: 0.18s;
145
+ --mo-fast: 0.12s; /* Hover, color */
146
+ --motion-fast: var(--mo-fast); /* deprecated alias */
147
+ --mo-base: 0.18s; /* Toggles, reveals */
148
+ --motion-base: var(--mo-base); /* deprecated alias */
149
+ --mo-slow: 0.22s; /* Panels, canvas scale */
150
+ --ease: cubic-bezier(0.4, 0, 0.2, 1);
151
+ /* Pre-2.0 composite. Use --mo-slow var(--ease) instead. */
89
152
  --motion-layout: 0.22s cubic-bezier(0.4, 0, 0.2, 1);
90
153
 
91
- /* Controls — the toggle thumb stays white in both modes per the design
92
- system (.tog-thumb { background: #fff }), tokenized for themeability. */
93
- --toggle-thumb: #ffffff;
154
+ /* Layering */
155
+ --z-raise: 2; /* Canvas section labels, sticky group headers */
156
+ --z-resizer: 30; /* Panel drag handle */
157
+ --z-overlay: 45; /* In-panel overlays (version history) */
158
+ --z-menu: 120; /* Dropdowns, flyouts */
159
+ --z-toast: 200;
94
160
  }
95
161
 
96
162
  .dark .prenta-admin,
97
163
  .prenta-admin.dark,
98
164
  .prenta-admin[data-theme='dark'] {
165
+ /* Surfaces */
99
166
  --bg: #0d0c18;
100
167
  --sb: #141222;
101
168
  --card: #1c1a2e;
102
169
  --bdr: #2c2a42;
103
170
 
171
+ /* Text */
104
172
  --txt: #eae8f5;
105
173
  --sub: #8e8ba8;
106
- /* Same AA deviation as light mode (tokens.json #504E68 is 2.1:1 on card). */
174
+ /*
175
+ * Same AA correction as light mode — the handoff value #504E68 is 2.1:1 on
176
+ * --card. Handoff value: #504e68 — deliberately overridden.
177
+ */
107
178
  --muted: #8784a2;
108
179
 
180
+ /* Accent */
109
181
  --acc: #9d71f0;
110
182
  --acc-l: #231950;
111
183
  --acc-m: #5e3eaa;
112
184
 
185
+ /* Semantic */
113
186
  --suc: #10b981;
114
187
  --suc-l: #022c22;
115
188
  --warn: #fbbf24;
@@ -119,6 +192,7 @@
119
192
  --info: #38bdf8;
120
193
  --info-l: #0a2838;
121
194
 
195
+ /* Tag palette */
122
196
  --tag-purple: #a78bfa;
123
197
  --tag-purple-soft: #2e1065;
124
198
  --tag-green: #2dd4bf;
@@ -134,8 +208,12 @@
134
208
  --tag-gray: #94a3b8;
135
209
  --tag-gray-soft: #1e293b;
136
210
 
211
+ /* AI */
212
+ --ai1: #7c3aed;
213
+ --ai2: #c026d3;
137
214
  --ai-soft: linear-gradient(135deg, rgba(157, 113, 240, 0.16), rgba(192, 38, 211, 0.12));
138
215
 
216
+ /* Elevation */
139
217
  --shd: 0 1px 2px rgba(0, 0, 0, 0.3), 0 1px 4px rgba(0, 0, 0, 0.2);
140
218
  --shd2: 0 4px 20px rgba(0, 0, 0, 0.45);
141
219
  }