@kerfjs/ui 5.0.0-beta.53 → 5.0.0-beta.55

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 (152) hide show
  1. package/README.md +4 -2
  2. package/ai/application-ui-diagnostic-ids-v1.json +1 -0
  3. package/ai/component-catalog-v2.json +138 -5
  4. package/ai/component-catalog-v2.schema.json +2 -1
  5. package/ai/component-catalog.json +208 -16
  6. package/ai/public-api-signatures-v1.md +462 -39
  7. package/ai/skill.md +28 -20
  8. package/ai/webawesome-jsx-signatures-v1.md +1 -1
  9. package/analyzer/index.mjs +48 -0
  10. package/analyzer/loud-pairs.d.mts +49 -0
  11. package/analyzer/loud-pairs.mjs +357 -0
  12. package/dist/app-tab.d.ts +7 -5
  13. package/dist/app-tab.js +1 -1
  14. package/dist/browser/popup-menu.js +3 -0
  15. package/dist/catalog-resources.d.ts +1 -1
  16. package/dist/catalog.d.ts +10 -4
  17. package/dist/catalog.js +243 -300
  18. package/dist/catalog.js.map +1 -1
  19. package/dist/{chunk-7IUSV4XG.js → chunk-24PHKUR3.js} +2 -2
  20. package/dist/chunk-24PHKUR3.js.map +1 -0
  21. package/dist/{chunk-EKYZCRCX.js → chunk-3CGQ7ZNO.js} +54 -22
  22. package/dist/chunk-3CGQ7ZNO.js.map +1 -0
  23. package/dist/{chunk-UKKSMZYT.js → chunk-46263QLK.js} +51 -1
  24. package/dist/chunk-46263QLK.js.map +1 -0
  25. package/dist/chunk-4BIMLITI.js +92 -0
  26. package/dist/chunk-4BIMLITI.js.map +1 -0
  27. package/dist/{chunk-NDUGJ4TU.js → chunk-5NDQABWK.js} +1 -1
  28. package/dist/{chunk-NDUGJ4TU.js.map → chunk-5NDQABWK.js.map} +1 -1
  29. package/dist/{chunk-ZK5EGVFP.js → chunk-5OLVUEND.js} +12 -2
  30. package/dist/chunk-5OLVUEND.js.map +1 -0
  31. package/dist/{chunk-CMUIXJZM.js → chunk-BSKEH3UC.js} +2 -2
  32. package/dist/{chunk-CMUIXJZM.js.map → chunk-BSKEH3UC.js.map} +1 -1
  33. package/dist/chunk-EAX2GSS4.js +384 -0
  34. package/dist/chunk-EAX2GSS4.js.map +1 -0
  35. package/dist/chunk-KH6VUGHU.js +399 -0
  36. package/dist/chunk-KH6VUGHU.js.map +1 -0
  37. package/dist/{chunk-BJJKFVWW.js → chunk-LZXQVUGN.js} +2 -2
  38. package/dist/chunk-LZXQVUGN.js.map +1 -0
  39. package/dist/chunk-N7FHFNT6.js +55 -0
  40. package/dist/chunk-N7FHFNT6.js.map +1 -0
  41. package/dist/{chunk-CCMKJWLX.js → chunk-NE5JAOQS.js} +7 -7
  42. package/dist/chunk-NE5JAOQS.js.map +1 -0
  43. package/dist/chunk-PSHUSWQH.js +18 -0
  44. package/dist/chunk-PSHUSWQH.js.map +1 -0
  45. package/dist/{chunk-KPNTVB7A.js → chunk-R754MHXX.js} +3 -3
  46. package/dist/{chunk-KPNTVB7A.js.map → chunk-R754MHXX.js.map} +1 -1
  47. package/dist/{chunk-HJKRCKDR.js → chunk-RNRUVPJ3.js} +4 -2
  48. package/dist/chunk-RNRUVPJ3.js.map +1 -0
  49. package/dist/{chunk-VOCPXGQN.js → chunk-VHADGP3B.js} +9 -8
  50. package/dist/chunk-VHADGP3B.js.map +1 -0
  51. package/dist/chunk-XQV2B4IL.js +14 -0
  52. package/dist/chunk-XQV2B4IL.js.map +1 -0
  53. package/dist/collapsible-panel.d.ts +46 -15
  54. package/dist/collapsible-panel.js +42 -10
  55. package/dist/collapsible-panel.js.map +1 -1
  56. package/dist/floating-toolbar.d.ts +5 -2
  57. package/dist/floating-toolbar.js +1 -1
  58. package/dist/index.d.ts +1 -0
  59. package/dist/index.js +20 -18
  60. package/dist/list-header.js +1 -1
  61. package/dist/list-inset-text.d.ts +7 -1
  62. package/dist/list-inset-text.js +2 -1
  63. package/dist/panel-toolbar-BFQxFITu.d.ts +52 -0
  64. package/dist/popup-menu-register.d.ts +9 -0
  65. package/dist/popup-menu-register.js +30 -0
  66. package/dist/popup-menu-register.js.map +1 -0
  67. package/dist/popup-menu.d.ts +71 -0
  68. package/dist/popup-menu.js +3 -0
  69. package/dist/popup-menu.js.map +1 -0
  70. package/dist/resizable-region.d.ts +4 -1
  71. package/dist/resizable-region.js +1 -1
  72. package/dist/split-view.js +1 -1
  73. package/dist/state-banner.js +1 -1
  74. package/dist/styles/catalog/components/catalog-example.css +0 -16
  75. package/dist/styles/catalog/components/catalog-stage.css +8 -13
  76. package/dist/styles/catalog/components/catalog.css +8 -18
  77. package/dist/styles/catalog.css +0 -5
  78. package/dist/styles/collapsible-panel.css +88 -10
  79. package/dist/styles/floating-toolbar.css +11 -6
  80. package/dist/styles/popup-menu.css +12 -0
  81. package/dist/styles/resizable-region.css +81 -13
  82. package/dist/styles/state-banner.css +13 -4
  83. package/dist/styles/styles.css +1 -0
  84. package/dist/styles/tab-bar.css +31 -3
  85. package/dist/styles/toolbar-control-group.css +13 -0
  86. package/dist/styles/toolbar.css +43 -2
  87. package/dist/styles/workbench.css +503 -10
  88. package/dist/text.js +1 -1
  89. package/dist/token-search-field.d.ts +10 -1
  90. package/dist/token-search-field.js +1 -1
  91. package/dist/{types-CEsieBZi.d.ts → types-D6vzj-VT.d.ts} +15 -0
  92. package/dist/wire-catalog.d.ts +13 -1
  93. package/dist/wire-catalog.js +18 -3
  94. package/dist/wire-catalog.js.map +1 -1
  95. package/dist/wire-resizable-regions.d.ts +2 -1
  96. package/dist/wire-resizable-regions.js +2 -1
  97. package/dist/wire-sidebar.js +6 -3
  98. package/dist/wire-sidebar.js.map +1 -1
  99. package/dist/wire-tab-bars.js +1 -1
  100. package/dist/wire-token-search-fields.js +1 -1
  101. package/dist/wire-workbench.d.ts +109 -0
  102. package/dist/wire-workbench.js +6 -0
  103. package/dist/wire-workbench.js.map +1 -0
  104. package/dist/workbench.d.ts +166 -6
  105. package/dist/workbench.js +11 -104
  106. package/dist/workbench.js.map +1 -1
  107. package/docs/accessibility.md +66 -10
  108. package/docs/app-layouts.md +12 -1
  109. package/docs/catalog.md +27 -9
  110. package/docs/collapsible-panel.md +114 -1
  111. package/docs/component-contract.md +2 -2
  112. package/docs/component-selection.md +41 -23
  113. package/docs/design/templates/state-banner/danger-dark.svg +1 -1
  114. package/docs/design/templates/state-banner/danger.svg +1 -1
  115. package/docs/design/templates/state-banner/info-dark.svg +1 -1
  116. package/docs/design/templates/state-banner/info.svg +1 -1
  117. package/docs/design/templates/state-banner/success-dark.svg +1 -1
  118. package/docs/design/templates/state-banner/success.svg +1 -1
  119. package/docs/design/templates/state-banner/warning-dark.svg +1 -1
  120. package/docs/design/templates/state-banner/warning.svg +1 -1
  121. package/docs/design/templates/state-banner-dark.svg +1 -1
  122. package/docs/design/templates/state-banner.svg +1 -1
  123. package/docs/document-baseline.md +4 -0
  124. package/docs/layout.md +10 -1
  125. package/docs/recipes.md +48 -39
  126. package/docs/surface-scaffold.md +1 -1
  127. package/docs/type-contracts.md +2 -1
  128. package/docs/ui-analyzer.md +94 -19
  129. package/docs/ui-doctor.md +6 -0
  130. package/docs/ux-demo.md +7 -3
  131. package/docs/webawesome-theme.md +11 -2
  132. package/docs/workbench.md +388 -8
  133. package/llms.txt +13 -8
  134. package/package.json +17 -2
  135. package/ux-demo/recipes/app-shell.tsx +141 -223
  136. package/ux-demo/recipes/collapsible-sidebar.tsx +48 -78
  137. package/ux-demo/recipes/list-detail-dialog.tsx +150 -54
  138. package/ux-demo/recipes/mount-recipe.ts +0 -5
  139. package/ux-demo/recipes/types.ts +0 -1
  140. package/dist/chunk-7IUSV4XG.js.map +0 -1
  141. package/dist/chunk-BJJKFVWW.js.map +0 -1
  142. package/dist/chunk-CCMKJWLX.js.map +0 -1
  143. package/dist/chunk-EKYZCRCX.js.map +0 -1
  144. package/dist/chunk-HJKRCKDR.js.map +0 -1
  145. package/dist/chunk-UKKSMZYT.js.map +0 -1
  146. package/dist/chunk-VOCPXGQN.js.map +0 -1
  147. package/dist/chunk-ZK5EGVFP.js.map +0 -1
  148. package/dist/styles/catalog/components/catalog-detail.css +0 -35
  149. package/dist/styles/catalog/components/catalog-resource-footer.css +0 -37
  150. package/dist/styles/catalog/components/catalog-secondary-sections.css +0 -38
  151. package/dist/styles/catalog/components/catalog-section-list.css +0 -22
  152. package/dist/styles/catalog/components/catalog-sidebar.css +0 -82
@@ -23,9 +23,49 @@ Import the panel CSS (`@kerfjs/ui/collapsible-panel.css`) alongside `foundation.
23
23
  through the transform alone instead of transitioning from a changing layout
24
24
  origin and snapping at the end. The app owns the `collapsed` signal; `size`
25
25
  overrides the CSS default width/height.
26
+ A collapsed panel renders `inert` together with `aria-hidden="true"`, straight
27
+ from `collapsed`, so neither Tab, a pointer, nor assistive technology reaches
28
+ content that has slid out of view, and focusing a control can never scroll
29
+ the clipped content back into view. `inert` does not affect rendering, so the
30
+ slide-out still animates; expanding removes both attributes in the same
31
+ render. `aria-hidden` alone had left the panel's controls focusable inside a
32
+ hidden subtree; it stays beside `inert` so the emptied landmark is hidden
33
+ even from tooling that does not prune inert subtrees. Do not add your own
34
+ `inert`, `aria-hidden`, or `tabindex` to hide the content. The
35
+ `restoreControl` renders outside the panel and stays reachable.
26
36
  Reusable shell policies are typed props: `separator`, `collapseMotion`,
27
37
  `contentOverflow`, and `presentation`. A collapsed panel may also receive a
28
- `restoreControl`, which Kerf places at the safe-area-aware `restorePosition`.
38
+ `restoreControl`, which Kerf places at the safe-area-aware `restorePosition`
39
+ corner of the panel's own container (the element holding the panel), never
40
+ of the viewport, so an embedded panel's control stays inside it and scrolls
41
+ with it. While the control shows, that container becomes its containing block
42
+ and isolates its stacking (an app's own `position` on the container still
43
+ wins). The corner is inset by `--kui-collapsible-panel-restore-inset` plus the
44
+ container's edge insets, and it owns that inset, so a `FloatingToolbar` hosting
45
+ the control floats from the corner without adding its own. When the same
46
+ container also holds an expanded inline bottom drawer — a bottom
47
+ `CollapsiblePanel` or a bottom `ResizableRegion` (`axis="vertical"`,
48
+ `edge="start"`) — as a direct child, or inside one of its direct children
49
+ (the app's work-area column), the corner floats that inset above the
50
+ drawer's top edge instead of over the drawer, and returns to the container's
51
+ bottom when the drawer collapses. It follows the drawer through CSS anchor
52
+ positioning, so a drag-resize moves it too; an engine without anchor
53
+ positioning keeps the container's bottom corner. A drawer nested deeper,
54
+ inside the work area's own content, belongs to that content and does not move
55
+ the corner. The corner stacks beneath open overlays: an open overlay is the
56
+ page's top layer, so it covers another panel's restore control as it covers
57
+ the rest of the page, including under the compact overlay's backdrop. The
58
+ control takes `--kui-collapsible-panel-restore-z`, which defaults to two less
59
+ than `--kui-collapsible-panel-overlay-z` (38); the backdrop defaults to one
60
+ less (39), so moving the overlay z-index moves both. Escape, a backdrop
61
+ press, or the panel's own close control reveals the control again, and a
62
+ collapsed overlay leaves it clickable. `ResizableRegion`'s `restoreControl`
63
+ follows the same rules, two below `--kui-resizable-region-overlay-z` (39).
64
+ A collapsed `ResizableRegion` likewise renders `inert` and `aria-hidden` on
65
+ the region itself (and `inert` on its `.kui-resizable-region__content`
66
+ wrapper), so its label leaves the accessibility tree with its content; its
67
+ separator is already hidden while collapsed, and the restore control stays
68
+ outside the region.
29
69
  Overlay presentation also clamps fixed-size animated content to the configured
30
70
  responsive overlay maximum, so a remembered desktop size cannot escape a narrow
31
71
  viewport.
@@ -72,6 +112,61 @@ Import the panel CSS (`@kerfjs/ui/collapsible-panel.css`) alongside `foundation.
72
112
 
73
113
  Returns a disposer. Retain it and call it on teardown.
74
114
 
115
+ ## Panel toolbars and relocated controls
116
+
117
+ Give a panel a `toolbar` (the same roles as a
118
+ [Workbench panel toolbar](workbench.md#panel-toolbars)) and it composes its own
119
+ top toolbar over a `Pane`, with an optional `footer` below its content:
120
+
121
+ - `title` and `panelOnly` groups lead it and are available only while it is open;
122
+ - `constant` groups and the standard `toggle: { action, name }` trail it.
123
+
124
+ A standalone panel does not own the rest of the screen, so the app places a
125
+ `CollapsiblePanelRelocated` in its own work-area toolbar: it renders the panel's
126
+ `constant` groups and toggle while the panel is collapsed, and nothing while it
127
+ is open. Put it first in the leading zone for a left rail, last in the trailing
128
+ zone for a right rail, and last in a bottom toolbar for a bottom drawer. With no
129
+ bottom toolbar, pass it inside a `FloatingToolbar` as the drawer's
130
+ `restoreControl`.
131
+
132
+ ```tsx
133
+ const toolbar: CollapsiblePanelToolbar = {
134
+ label: "Navigator",
135
+ panelOnly: <NewFileGroup />,
136
+ constant: <SearchGroup />,
137
+ toggle: { action: "toggle-nav", name: "navigator" },
138
+ };
139
+
140
+ <Row fill gap="none">
141
+ <CollapsiblePanel id="nav" side="left" collapsed={navCollapsed.value} toolbar={toolbar}>
142
+ <Files />
143
+ </CollapsiblePanel>
144
+ <List flex>
145
+ <Pane
146
+ header={
147
+ <Toolbar
148
+ label="Editor"
149
+ leading={
150
+ <>
151
+ <CollapsiblePanelRelocated panelId="nav" side="left" collapsed={navCollapsed.value} toolbar={toolbar} />
152
+ <ToolbarText text="Editor" size="xlarge" />
153
+ </>
154
+ }
155
+ />
156
+ }
157
+ >
158
+ <Editor />
159
+ </Pane>
160
+ </List>
161
+ </Row>;
162
+ ```
163
+
164
+ Wire it with `wireSidebar` (`toggleAction` is the toggle's `action`): closing the
165
+ panel from its own toggle hands focus to the relocated toggle, even when the app
166
+ renders it a frame later, and opening it moves focus into the panel. Each toggle
167
+ carries a stable `data-key`, so the morph never reuses a focused toggle's button
168
+ for another control as it moves.
169
+
75
170
  ## Compact initial state
76
171
 
77
172
  A compact overlay is transient chrome the user summons, like a slide-over
@@ -181,6 +276,15 @@ const stop = wireSidebar(app, {
181
276
  });
182
277
  ```
183
278
 
279
+ ## Sizing in a flex layout
280
+
281
+ An expanded panel holds its `size` in a flex row or column (`flex-shrink: 0`):
282
+ its content keeps that fixed size so collapsing slides it out instead of
283
+ squeezing it, and a shrunk track would only clip the content's trailing edge.
284
+ Give the sibling work area `min-width: 0` / `min-height: 0` (a `Pane` or
285
+ `List flex` already has it) so it is the region that gives way, and switch the
286
+ panel to the compact overlay (`wireSidebar`) where the viewport cannot hold it.
287
+
184
288
  ## Safe areas
185
289
 
186
290
  A panel grows by the unsafe inset of the edge it docks to and pads its content
@@ -214,3 +318,12 @@ It is covered end-to-end across Chromium, Firefox, and WebKit by
214
318
  move/restore, the compact overlay + Escape/backdrop dismiss, the Tab trap, and
215
319
  the compact initial state across first load and wide/compact crossings),
216
320
  alongside the component/wire unit tests.
321
+
322
+ The focused [CollapsiblePanel route](../ux-demo/?component=collapsible-panel)
323
+ ([TSX source](../ux-demo/demos/collapsible-panel.tsx)) also has a **Restore
324
+ control** example: a bottom drawer that starts collapsed, with a
325
+ `FloatingToolbar` `restoreControl` in its frame's bottom-end corner and its
326
+ own hide toggle in the drawer header. Both toggles share one `data-action`,
327
+ and the catalog wires them with `wireSidebar`, so the corner control really
328
+ restores the drawer and focus moves between the two. It is covered by
329
+ `tests/browser/app-layout-catalog.spec.ts` at wide and compact widths.
@@ -356,8 +356,8 @@ stay inside the available toolbar width. Set `visibility="compact-only"` for a
356
356
  group that replaces wider toolbar controls below the Toolbar's compact container
357
357
  breakpoint; do not hide the group with an application class. Reach for
358
358
  `wa-button` only when you need
359
- a Web Awesome feature, chiefly the `slot="trigger"` button of a `wa-dropdown`
360
- popup menu. For a compact mixed-content group, set `nestedDropdown`; a
359
+ a Web Awesome feature; a popup menu is a `PopupMenu`, which renders its own
360
+ trigger. For a compact mixed-content group, set `nestedDropdown`; a
361
361
  text-and-caret trigger grows to its intrinsic width while an icon-only trigger
362
362
  can remain square. A compact icon `<button>` is a 32px circle, so a selected
363
363
  compact segment never becomes an oval. An icon-only `Select` joins a group as
@@ -151,19 +151,20 @@ an upstream component or recipe request.
151
151
  | One-pane navigation — `NavStack` | A compact flow pushes into details while keeping earlier views mounted, or a single-pane screen needs the same stable layout contract. | Do not use it when list and detail should remain visible together; use `SplitView`. Do not use it alone for co-equal top-level destinations; use one stack per `TabScaffold` tab. | Keep the ordered view array controlled, put view-specific bottom chrome on each view (or use the component fallback), import its CSS explicitly, and call `wireNavStack` for back delegation, content-slide/chrome-cross-fade transitions, and focus move/restore. Mark a preferred initial target with `data-nav-focus` when DOM order is insufficient. | View keys/content/titles, push and pop actions, preferred initial focus targets, and per-view or persistent bottom toolbar content. | `@kerfjs/ui/nav-stack` | [App-layout decision matrix](./app-layouts.md#decision-matrix) |
152
152
  | Responsive list-detail — `SplitView` | A primary list and related detail belong together on roomy devices but become a one-pane drill-down on compact devices. | Do not use it for a single linear flow or a multi-panel editor shell. | Provide controlled selection/detail state and device class; opt into resize wiring only when the separator is user adjustable. | Selection, detail content, compact back action, device policy, and optional persisted width. | `@kerfjs/ui/split-view` | [App-layout decision matrix](./app-layouts.md#decision-matrix) |
153
153
  | Compact top-level destinations — `TabScaffold` | A handset or portrait-tablet app has two to five co-equal destinations whose scenes and nested navigation must remain mounted across switches. | Do not use it for document tabs, reorderable work items, or a desktop navigation rail. | Keep the active id controlled, import its CSS explicitly, and call `wireTabScaffold`; commonly place one `NavStack` in each tab scene. | Destination definitions, active id, routing, persistence, and roomy-device replacement. | `@kerfjs/ui/tab-scaffold` | [App-layout decision matrix](./app-layouts.md#decision-matrix) |
154
- | Desktop multi-panel workspace — `Workbench` | A desktop-class tool needs a central work area plus independently collapsible navigator, inspector, or console regions. | Do not shrink the full shell onto compact devices or use it for one standalone panel. | Render only the required rails/drawer, keep collapse state controlled, and replace peripheral regions with stacks or overlays below desktop sizes. | Panel presence/content, collapsed states, sizes, persistence, responsive replacement, and controls. | `@kerfjs/ui/workbench` | [Workbench](./workbench.md) |
154
+ | Desktop multi-panel workspace — `Workbench` | A desktop-class tool needs a central work area plus independently collapsible navigator, inspector, or console regions. | Do not shrink the full shell onto compact devices or use it for one standalone panel. | Render only the required rails/drawer, keep collapse state controlled, and replace peripheral regions with stacks or overlays below desktop sizes. Opt a panel into drag/keyboard resizing with `resizable` and call `wireWorkbench` with its size signal. | Panel presence/content, collapsed states, sizes, persistence, responsive replacement, and controls. | `@kerfjs/ui/workbench` | [Workbench](./workbench.md) |
155
155
  | Standalone rail or drawer — `CollapsiblePanel` | One left/right rail or bottom drawer needs controlled collapse without adopting the complete `Workbench` shell. | Do not use it for several coordinated workspace panels or retain an empty icon-only rail while collapsed. | Pair it with `CollapsiblePanelToggle`; call `wireSidebar` for focus transfer, Escape/backdrop dismissal, compact overlay trapping, and persistence integration. | Panel content/size, collapsed state, toggle placement, persistence, and compact policy. | `@kerfjs/ui/collapsible-panel` | [App-layout decision matrix](./app-layouts.md#decision-matrix) |
156
156
  | Lowered content surface — `SunkenPanel` | A main work area or nested content group needs one visually lowered surface with a compact inset and vertical stack. | Do not use it merely to add padding, as a replacement for `Pane` anatomy, or around children that already own the same outer surface. | Compose the application-owned content as children, choose the default `rounded` shape or `square` for a flush edge-to-edge area, and pass `ariaLabel` only when the surface is a distinct named region. | Region semantics, accessible name, shape, scroll ownership, child ordering, and content. | `@kerfjs/ui/sunken-panel` | [SunkenPanel](./sunken-panel.md) |
157
157
  | Menu composition | Navigation sections need full-size rows and the same content-item geometry as every other pane. | Do not add sidebar-specific wrapper padding, shrink targets to icon size, nest an interactive trailing control in `ListItem`, or use a chevron on a row that does not disclose content. Use ordinary links for a different navigation contract. | Compose `ListHeader`, `ListItem`, and `ListActionRow` in `.kui-content`; use `ListHeader` toggle mode with real controlled content, and use `.kui-content-item` for other surfaces plus a pane footer for toolbar actions. | Information architecture, disclosure content and state, responsive drawer/shell behavior, and token overrides. | `@kerfjs/ui/layout.css` | [Pane geometry](../README.md#pane-and-content-geometry) |
158
158
  | Resizable application pane — `ResizableRegion`, `clampRegionSize`, `resizeRegionFromPointer` | A controlled split pane needs the Kerf separator, collapse state, pointer plus keyboard resizing, or a product-specific decorative grip. | Do not use it for static equal columns; use `Grid`. Use application CSS grid for static asymmetric or intrinsic tracks. Prefer it over Web Awesome `wa-split-panel` unless that component's distinct API is required. Keep `handleIcon` noninteractive. | Call `wireResizableRegions` from `@kerfjs/ui/wire-resizable-regions` once and retain its disposer. | Size signal, min/max policy, collapse policy, persistence, and optional decorative handle icon. | `@kerfjs/ui/resizable-region` | [ResizableRegion contract](./accessibility.md#resizableregion) |
159
159
  | One application tab — `AppTab` | A controlled app tab needs selection, close, drag, leading/trailing anatomy, compact/segmented/icon-only presentation, label truncation, safe domain metadata, or a product-specific close glyph. | Do not render it alone or use it for a small settings choice; compose in `TabBar`, or use `SegmentedControl`. Keep `closeIcon` noninteractive. | Compose in `TabBar`; let `wireTabBars` manage interaction. Put only domain `data-*` values in `rootAttributes`; use typed appearance props instead of descendant CSS. | Tab identity, order, selection, close policy, content, domain metadata values, and outer placement. | `@kerfjs/ui/app-tab` | [Tabs contract](./accessibility.md#tabs) |
160
160
  | Application tab strip — `TabBar`, `wireTabBars`, `reorderTabs` | Tabs switch page regions and may overflow, close, reorder, fill a segmented inspector strip, sit beside a trailing action, or keep that adjacent action distinct from a far-edge end action. | Do not use it for a compact local view toggle; use `SegmentedControl`. Do not use it for a long choice list; use `Select`. Prefer it over Web Awesome `wa-tab-group`, `wa-tab`, and `wa-tab-panel` for Kerf app tabs. | Call `wireTabBars` once, retain the disposer, and apply `onReorder` synchronously; `reorderTabs` is the default array helper. Combine `trailingPlacement="adjacent"` with `end` for split actions; TabBar owns the shrinking/scrolling tab geometry and keeps both actions visible. Choose typed presentation/allocation props while the parent owns outer placement. | Ordered tabs, selection, panels, routing, closing, persistence, action content, and outer placement. | `@kerfjs/ui/tab-bar` plus `@kerfjs/ui/wire-tab-bars` | [Tabs contract](./accessibility.md#tabs) |
161
- | Panel, dialog, or page heading — `Toolbar` + `ToolbarText` | A panel, dialog, or page needs an extra-large title, optional icon, grouped trailing actions, and optional supporting copy. | Do not add a private heading wrapper or bespoke layout. The toolbar supplies structure, not modal behavior; use an application overlay or Web Awesome `wa-dialog` for that behavior. | Connect title/supporting-copy ids to the host, group controls, and delegate actions. **For a page or view title set `headingLevel` (usually `1`)** on `ToolbarText`; omit it for a dialog title referenced by `aria-labelledby`. | Open state, focus lifecycle, dismissal, controls, ids, copy, and heading level. | `@kerfjs/ui/toolbar` + `@kerfjs/ui/toolbar-text` | [Toolbar headings](./accessibility.md#toolbar-headings) |
161
+ | Panel, dialog, or page heading — `Toolbar` + `ToolbarText` | A panel, dialog, or page needs an extra-large title, optional icon, grouped trailing actions, and optional supporting copy. | Do not add a private heading wrapper or bespoke layout. The toolbar supplies structure, not modal behavior; use an application overlay or Web Awesome `wa-dialog` for that behavior. In a narrow peripheral rail or drawer, where xlarge would truncate at the panel's minimum size, use the default `ToolbarText` size as pane identity. | Connect title/supporting-copy ids to the host, group controls, and delegate actions. **For a page or view title set `headingLevel` (usually `1`)** on `ToolbarText`; omit it for a dialog title referenced by `aria-labelledby`. | Open state, focus lifecycle, dismissal, controls, ids, copy, and heading level. | `@kerfjs/ui/toolbar` + `@kerfjs/ui/toolbar-text` | [Toolbar headings](./accessibility.md#toolbar-headings) |
162
162
  | Dialog or popup geometry — `DialogSurface`, `PopupSurface` | Recurring Web Awesome dialogs need standard sizes/presentations/body/footer insets, or dropdown menus need list-compatible inset ownership. | Do not use these wrappers as generic layout or to replace native dialog/dropdown behavior. Avoid consumer `::part()` overrides and do not stack a dialog body inset around list-owned child geometry. | Wrap one `wa-dialog` or `wa-dropdown`; choose the typed geometry while retaining native labeling, open state, focus, dismissal, and menu semantics. Compose a dialog body as a `List` by default, use `bodyInset="none"` when its children own list geometry, and wrap bare prose in `ListInsetText`. | State, focus lifecycle, dismissal, labels, content, and outer placement. | `@kerfjs/ui/surface-scaffold` | [Surface scaffolds](./surface-scaffold.md) |
163
163
  | Key/value facts — `ValueTable`, `ValueTableRow` | Read-only labels and values form a semantic definition list, optionally with a leading icon. | Do not use it for editable form fields or a row/column data grid; use native form or table semantics. | Compose typed `ValueTableRow` entries; pass `icon` when a 24px leading icon adds useful context. | Values, formatting, icon meaning, and empty/loading policy. | `@kerfjs/ui/value-table` | [Component ownership](./component-contract.md#ownership-boundaries) |
164
164
  | Indeterminate activity — `LoadingSpinner` | A Kerf surface needs compact, labeled or decorative indeterminate progress. | Do not use it for known progress; use Web Awesome `wa-progress-bar` or `wa-progress-ring`. Direct Web Awesome UI may use `wa-spinner`; do not mix spinner systems within one surface. | None; pass a label when the spinner conveys status. | Loading lifecycle and adjacent status copy. | `@kerfjs/ui/loading-spinner` | [Accessibility](./accessibility.md#shared-rules) |
165
165
  | Loading placeholder — `Skeleton` + a component's `placeholder` prop | A value or a whole component is still loading and should hold its space as a subtle, unanimated block, keeping the layout stable — an inspector or detail view rendering its real chrome with per-record values absent. | Do not use it for known progress (use `LoadingSpinner`), do not animate it, and do not hand-rebuild a component's empty state — set `placeholder` on the component instead. Prefer it over `wa-skeleton`, which the pure-Kerf primitives avoid to stay Web-Awesome-free. | Set `placeholder` on a value-bearing component (`Select`, `ListHeader`, `ListItem`, `ValueTableRow`, `SegmentedControl`, `StateBanner`, `AppTab`, `ToolbarText`, `ListActionRow`) to render skeletons in its value slots with interactivity disabled; use the standalone `Skeleton` for a custom slot. | Loading lifecycle, which slots are unknown, and announcing the loading region. | `@kerfjs/ui/skeleton` | [Accessibility](./accessibility.md#shared-rules) |
166
- | Value selection — `Select` | A controlled form, toolbar, or compact navigation value comes from a moderate or long choice list, possibly grouped, icon-bearing, icon-only when closed, or truncating. | Do not use it for commands; use a real action menu. Do not use it for a small visible choice set; use `SegmentedControl`. Prefer it over direct `wa-select`, `wa-option`, or value-like `wa-dropdown`/`wa-dropdown-item` composition. | Import `@kerfjs/ui/select/register` once for registration and current-request animation ownership; listen for standard input/change events. Do not add consumer popup timing or positioning repairs. Use typed presentation props rather than consumer `::part()` overrides; let the parent own placement. | Controlled value, validation, choices, domain mapping, and outer placement. | `@kerfjs/ui/select` | [Web Awesome integration](../README.md#web-awesome-theme) |
166
+ | Command menu — `PopupMenu` | A short list of commands sits behind one trigger, such as a toolbar sort or More menu, optionally grouped under headings and dividers with item icons. | Do not use it to choose a persistent value; use `Select`. Do not hand-write `wa-dropdown`/`wa-dropdown-item` markup for an action menu. | Import `@kerfjs/ui/popup-menu/register` once. Place it in a `single` `ToolbarControlGroup` with `nestedDropdown` and a `menuInset`, or wrap it in `PopupSurface` outside a toolbar. Handle item `action`s by delegation. | Commands, enabled state, and reactions to opening or closing. | `@kerfjs/ui/popup-menu` | [Toolbar composition](#toolbar-composition) |
167
+ | Value selection — `Select` | A controlled form, toolbar, or compact navigation value comes from a moderate or long choice list, possibly grouped, icon-bearing, icon-only when closed, or truncating. | Do not use it for commands; use `PopupMenu`. Do not use it for a small visible choice set; use `SegmentedControl`. Prefer it over direct `wa-select`, `wa-option`, or value-like `wa-dropdown`/`wa-dropdown-item` composition. | Import `@kerfjs/ui/select/register` once for registration and current-request animation ownership; listen for standard input/change events. Do not add consumer popup timing or positioning repairs. Use typed presentation props rather than consumer `::part()` overrides; let the parent own placement. | Controlled value, validation, choices, domain mapping, and outer placement. | `@kerfjs/ui/select` | [Web Awesome integration](../README.md#web-awesome-theme) |
167
168
  | Small exclusive choice — `SegmentedControl` | A few visible choices switch a compact view or setting, with toolbar, rounded, or pill presentation. | Do not use it for tabpanel semantics; use `TabBar`. Do not use it for many choices; use `Select`. Prefer it over `wa-button-group` when the controls select one value. | Delegate its action, read `data-segment-value`, update `value`, and rerender. | Controlled value, labels, action, and persistence. | `@kerfjs/ui/segmented-control` | [SegmentedControl contract](./accessibility.md#segmentedcontrol) |
168
169
  | Structured search editor — `TokenSearchField`, `readTokenSearchField`, `placeTokenSearchCaret`, `wireTokenSearchFields` | Free text and ordered, editable, removable filter tokens share one searchbox; enable `collapsible` when an empty, unfocused field should reduce to one iconic action, standalone or in a toolbar group. | Do not use it for ordinary text entry; use a native input or Web Awesome `wa-input`. Do not use it when filters belong in separate form controls. | Read DOM-owned text on input, empty `textContent` on clear, and use `placeTokenSearchCaret` after explicit controlled focus changes. Call `wireTokenSearchFields` from `@kerfjs/ui/wire-token-search-fields` once so Enter submits without adding a line break and keyboard chip deletion restores focus plus the text-relative caret after controlled replacement. In `collapsible` mode it also manages the transient expand/collapse/focus by default (activate to reveal + focus, Escape or empty blur to collapse); bind the field's `expanded` to the signal on the returned handle (`handle.expanded(id)`) or adopt your own via `collapsible.signals`, and opt out per behavior only when the app must own it. | Parsing, suggestions, tokens, query execution, results, announcements, and — only if overriding the default — the collapsible `expanded` signal. | `@kerfjs/ui/token-search-field` | [TokenSearchField contract](./accessibility.md#tokensearchfield) |
169
170
  | Persistent inline status — `StateBanner` | A neutral, info, pop, success, warning, or danger message belongs next to the affected work; pop highlights featured or novel content without implying status. | Do not use pop as a success, warning, or danger substitute. Do not use StateBanner for a no-content screen; use `EmptyState`. Do not use it for transient confirmation; use a toast. Web Awesome `wa-callout` is the ecosystem alternative for Web Awesome-owned content. | Delegate an optional action; choose alert urgency only for attention-requiring failure. Use the optional tone-tinted `badge` for a terse count or status beside the title, not as the only expression of meaning. | State mapping, message lifetime, retry/action behavior, badge content, and copy. | `@kerfjs/ui/state-banner` | [Feedback accessibility](./accessibility.md#shared-rules) |
@@ -186,12 +187,23 @@ an upstream component or recipe request.
186
187
  - A `ResizableRegion` overlay automatically clamps both its track and fixed-size
187
188
  animated content to the responsive overlay maximum. Set the policy and maximum
188
189
  on the component instead of adding application descendant width/height fixes.
190
+ It paints `--kui-color-surface` itself (an inline region stays transparent),
191
+ so do not add a background to make an overlay opaque.
192
+ - Give `Workbench` panels a `toolbar` (title, panel-only groups, constant
193
+ groups, and a standard `toggle`) and the work area a `mainToolbar` /
194
+ `mainBottomToolbar`: the Workbench moves a closed panel's constant groups
195
+ and toggle into the work area's toolbar, so never hand-place or duplicate
196
+ panel toggles. See [Workbench panel toolbars](workbench.md#panel-toolbars).
189
197
  - Configure application panels through the shared `separator`, `collapseMotion`,
190
198
  `contentOverflow`, `presentation`, `restoreControl`, and `restorePosition`
191
199
  props on `ResizableRegion`, `Workbench` panels, and `CollapsiblePanel`. These
192
200
  cover separator suppression, one-reflow collapse with composited motion,
193
201
  bottom-drawer popups, compact overlays or replacements, and safe-area restore
194
- placement without descendant `.kui-*` overrides. `wireSidebar` also accepts a
202
+ placement without descendant `.kui-*` overrides. A `Workbench` rail's
203
+ or bottom drawer's `responsiveOverlayAt` (like `ResizableRegion`'s
204
+ `responsiveFillAt`) switches it to an overlay below a container breakpoint
205
+ without a device-class check.
206
+ `wireSidebar` also accepts a
195
207
  hidden compact replacement and keeps compact overlays exclusive by default.
196
208
  - `TokenSearchField` is a structured editor. A native input or `wa-input` is the right answer for ordinary text.
197
209
 
@@ -207,8 +219,12 @@ toolbar geometry, hover/pressed treatment, and grouping. `SegmentedControl`,
207
219
  **inside** a `ToolbarControlGroup`, not loose in the zone. For a page, panel, or
208
220
  dialog heading, put an extra-large `ToolbarText` directly in the leading zone,
209
221
  optionally preceded by a grouped icon, and group trailing actions. Keep supporting
210
- copy below as app-owned content. A bottom divider is enabled by default. Set
211
- `dividerSides=""` for none, or
222
+ copy below as app-owned content. Size the title to its track: a narrow
223
+ peripheral rail or drawer (a navigator, inspector, or console beside a work
224
+ area that carries the extra-large title, often with its own close control in
225
+ the header) labels itself with the default size, because extra-large truncates
226
+ there — "Inspector" becomes "Ins…" in a 160px rail. A bottom divider is
227
+ enabled by default. Set `dividerSides=""` for none, or
212
228
  use the canonical physical-edge combinations (`t`, `r`, `b`, `l`, in that
213
229
  order—for example `tr` or `trbl`) when the toolbar owns other separator edges.
214
230
 
@@ -216,29 +232,31 @@ Common toolbar patterns:
216
232
 
217
233
  | Want | Put in the zone | Notes |
218
234
  | ----------------------------- | -------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- |
219
- | Identity or title text | `<ToolbarText text="…" size="large" />` (or `xlarge` for a page/panel title) | Wrap in a `single` borderless group only when it must align with adjacent control pills |
235
+ | Identity or title text | `<ToolbarText text="…" size="large" />` (or `xlarge` for a page/panel title that fits) | Wrap in a `single` borderless group only when it must align with adjacent control pills |
220
236
  | One or more icon/text buttons | `<ToolbarControlGroup>{buttons}</ToolbarControlGroup>` | Use `buttonAppearance="push"` for toggle buttons with `aria-pressed`; `single` for a lone control |
221
237
  | An exclusive view switch | `<ToolbarControlGroup><SegmentedControl … /></ToolbarControlGroup>` | Not `TabBar`, which switches tabpanels |
222
238
  | A value list | `<ToolbarControlGroup><Select … /></ToolbarControlGroup>` | Register `@kerfjs/ui/select/register` once; use `focusRingOwner="group"` so focus follows the group's geometry |
239
+ | A command menu | `<ToolbarControlGroup single nestedDropdown><PopupMenu … /></ToolbarControlGroup>` | Register `@kerfjs/ui/popup-menu/register` once; set `menuInset` on the group |
223
240
  | A collapsible search box | `<ToolbarControlGroup single><TokenSearchField collapsible … /></ToolbarControlGroup>` | The group animates the iconic ↔ expanded states; `wireTokenSearchFields` manages expand/collapse/focus by default |
224
241
 
225
- A **popup menu in a toolbar** is a `single` `ToolbarControlGroup` wrapping a Web
226
- Awesome `wa-dropdown`: its `slot="trigger"` `wa-button` is the toolbar button and
227
- the `wa-dropdown-item`s are the menu. Keep the dropdown's managed light-DOM
228
- children under `data-morph-skip-children` so kerf does not reconcile Web Awesome's
229
- own DOM.
242
+ A **popup menu in a toolbar** is a `PopupMenu` (`@kerfjs/ui/popup-menu`) in a
243
+ `single` `ToolbarControlGroup` with `nestedDropdown`; the group sizes the trigger
244
+ as a toolbar button and `menuInset` sets the menu's inset. `PopupMenu` renders the
245
+ Web Awesome dropdown, its trigger, and its typed items (commands, headings, and
246
+ dividers), and keeps Web Awesome's managed children out of the morph. Register
247
+ `@kerfjs/ui/popup-menu/register` once. Do not hand-write `wa-dropdown` markup for a
248
+ menu.
230
249
 
231
250
  ```tsx
232
- <ToolbarControlGroup single>
233
- <wa-dropdown placement="bottom-start" data-morph-skip-children>
234
- <wa-button slot="trigger" appearance="plain" with-caret aria-label="Sort">
235
- <LucideIcon icon={ArrowDownAZ} name="arrow-down-a-z" />
236
- </wa-button>
237
- <wa-dropdown-item data-action="sort-recent">
238
- Recently updated
239
- </wa-dropdown-item>
240
- <wa-dropdown-item data-action="sort-priority">Priority</wa-dropdown-item>
241
- </wa-dropdown>
251
+ <ToolbarControlGroup single nestedDropdown menuInset="compact">
252
+ <PopupMenu
253
+ label="Sort"
254
+ icon={<LucideIcon icon={ArrowDownAZ} name="arrow-down-a-z" />}
255
+ items={[
256
+ { label: "Recently updated", action: "sort-recent" },
257
+ { label: "Priority", action: "sort-priority" },
258
+ ]}
259
+ />
242
260
  </ToolbarControlGroup>
243
261
  ```
244
262
 
@@ -302,7 +320,7 @@ right primitive.
302
320
 
303
321
  | Web Awesome choice | Kerf decision |
304
322
  | ------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
305
- | `wa-button`, `wa-dropdown`, `wa-dropdown-item` | Use buttons and command menus for actions. Use `ListItem` for a navigation row and `Select` when the user chooses a value. |
323
+ | `wa-button`, `wa-dropdown`, `wa-dropdown-item` | Use buttons for actions and `PopupMenu` for a command menu, never raw dropdown markup. Use `ListItem` for a navigation row and `Select` for a value. |
306
324
  | `wa-button-group` | Use only for exceptional grouped actions; use `SegmentedControl` for one-of-many selection. |
307
325
  | `wa-input`, `wa-tag` | Use for ordinary text and tags; use `TokenSearchField` only when text and ordered filter tokens form one editor. |
308
326
  | `wa-select`, `wa-option` | Use `Select`, which owns Kerf spacing, controlled rendering, icon stability, and explicit registration. |
@@ -1 +1 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 560 116" width="560" height="116"><defs><clipPath id="cp0"><rect x="37" y="35" width="16" height="16.4"/></clipPath><clipPath id="cp2"><rect x="61" y="44.4" width="362.7" height="13"/></clipPath><clipPath id="ct3"><rect x="61" y="29.4" width="67.5" height="15"/></clipPath><clipPath id="ct4"><rect x="61" y="44.4" width="362.7" height="13"/></clipPath><clipPath id="ct5"><rect x="431.7" y="29" width="71.3" height="28.8"/></clipPath></defs><rect x="28" y="20" width="484" height="46.8" rx="12" fill="rgb(44,30,32)"/><rect x="28.5" y="20.5" width="483" height="46" rx="11.5" fill="none" stroke="rgb(101,37,40)" stroke-width="1"/><g clip-path="url(#cp0)"><g color="rgb(255, 160, 162)"><clipPath id="svgic1"><rect x="37" y="35.4" width="16" height="16"/></clipPath><g clip-path="url(#svgic1)"><g transform="translate(37 35.39)scale(.66667)"><circle cx="12" cy="12" r="10" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(255, 160, 162)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><line x1="12" x2="12" y1="8" y2="12" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(255, 160, 162)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><line x1="12" x2="12.01" y1="16" y2="16" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(255, 160, 162)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/></g></g></g></g><text x="61" y="41.39" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="12" font-weight="700" fill="rgb(255,160,162)">Build failed</text><g clip-path="url(#cp2)"><g clip-path="url(#ct4)"><text x="61" y="55.39" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="11" fill="rgb(255,160,162)">Step “test” exited with code 1.</text></g></g><rect x="431.7" y="29" width="71.3" height="28.8" rx="14.4" fill="rgba(28,28,30,0.52)"/><rect x="432.5" y="29.5" width="70" height="28" rx="13.9" fill="none" stroke="rgb(255,160,162)" stroke-width="1"/><text x="443.88" y="47.89" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="11" font-weight="650" fill="rgb(255,160,162)">View log</text></svg>
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 560 116" width="560" height="116"><defs><clipPath id="cp0"><rect x="37" y="35" width="16" height="16.4"/></clipPath><clipPath id="ct2"><rect x="61" y="29.4" width="67.5" height="15"/></clipPath><clipPath id="cp3"><rect x="61" y="44.4" width="158.6" height="13"/></clipPath><clipPath id="ct4"><rect x="61" y="44.4" width="158.6" height="13"/></clipPath><clipPath id="ct5"><rect x="431.7" y="29" width="71.3" height="28.8"/></clipPath></defs><rect x="28" y="20" width="484" height="46.8" rx="12" fill="rgb(44,30,32)"/><rect x="28.5" y="20.5" width="483" height="46" rx="11.5" fill="none" stroke="rgb(101,37,40)" stroke-width="1"/><g clip-path="url(#cp0)"><g color="rgb(255, 160, 162)"><clipPath id="svgic1"><rect x="37" y="35.4" width="16" height="16"/></clipPath><g clip-path="url(#svgic1)"><g transform="translate(37 35.39)scale(.66667)"><circle cx="12" cy="12" r="10" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(255, 160, 162)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><line x1="12" x2="12" y1="8" y2="12" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(255, 160, 162)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><line x1="12" x2="12.01" y1="16" y2="16" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(255, 160, 162)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/></g></g></g></g><text x="61" y="41.39" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="12" font-weight="700" fill="rgb(255,160,162)">Build failed</text><g clip-path="url(#cp3)"><g clip-path="url(#ct4)"><text x="61" y="55.39" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="11" fill="rgb(255,160,162)">Step “test” exited with code 1.</text></g></g><rect x="431.7" y="29" width="71.3" height="28.8" rx="14.4" fill="rgba(28,28,30,0.52)"/><rect x="432.5" y="29.5" width="70" height="28" rx="13.9" fill="none" stroke="rgb(255,160,162)" stroke-width="1"/><text x="443.88" y="47.89" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="11" font-weight="650" fill="rgb(255,160,162)">View log</text></svg>
@@ -1 +1 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 560 116" width="560" height="116"><defs><clipPath id="cp0"><rect x="37" y="35" width="16" height="16.4"/></clipPath><clipPath id="cp2"><rect x="61" y="44.4" width="362.7" height="13"/></clipPath><clipPath id="ct3"><rect x="61" y="29.4" width="67.5" height="15"/></clipPath><clipPath id="ct4"><rect x="61" y="44.4" width="362.7" height="13"/></clipPath><clipPath id="ct5"><rect x="431.7" y="29" width="71.3" height="28.8"/></clipPath></defs><rect x="28" y="20" width="484" height="46.8" rx="12" fill="rgb(254,237,238)"/><rect x="28.5" y="20.5" width="483" height="46" rx="11.5" fill="none" stroke="rgb(249,173,175)" stroke-width="1"/><g clip-path="url(#cp0)"><g color="rgb(194, 11, 32)"><clipPath id="svgic1"><rect x="37" y="35.4" width="16" height="16"/></clipPath><g clip-path="url(#svgic1)"><g transform="translate(37 35.39)scale(.66667)"><circle cx="12" cy="12" r="10" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(194, 11, 32)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><line x1="12" x2="12" y1="8" y2="12" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(194, 11, 32)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><line x1="12" x2="12.01" y1="16" y2="16" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(194, 11, 32)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/></g></g></g></g><text x="61" y="41.39" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="12" font-weight="700" fill="rgb(194,11,32)">Build failed</text><g clip-path="url(#cp2)"><g clip-path="url(#ct4)"><text x="61" y="55.39" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="11" fill="rgb(194,11,32)">Step “test” exited with code 1.</text></g></g><rect x="431.7" y="29" width="71.3" height="28.8" rx="14.4" fill="rgba(255,255,255,0.52)"/><rect x="432.5" y="29.5" width="70" height="28" rx="13.9" fill="none" stroke="rgb(194,11,32)" stroke-width="1"/><text x="443.88" y="47.89" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="11" font-weight="650" fill="rgb(194,11,32)">View log</text></svg>
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 560 116" width="560" height="116"><defs><clipPath id="cp0"><rect x="37" y="35" width="16" height="16.4"/></clipPath><clipPath id="ct2"><rect x="61" y="29.4" width="67.5" height="15"/></clipPath><clipPath id="cp3"><rect x="61" y="44.4" width="158.6" height="13"/></clipPath><clipPath id="ct4"><rect x="61" y="44.4" width="158.6" height="13"/></clipPath><clipPath id="ct5"><rect x="431.7" y="29" width="71.3" height="28.8"/></clipPath></defs><rect x="28" y="20" width="484" height="46.8" rx="12" fill="rgb(254,237,238)"/><rect x="28.5" y="20.5" width="483" height="46" rx="11.5" fill="none" stroke="rgb(249,173,175)" stroke-width="1"/><g clip-path="url(#cp0)"><g color="rgb(194, 11, 32)"><clipPath id="svgic1"><rect x="37" y="35.4" width="16" height="16"/></clipPath><g clip-path="url(#svgic1)"><g transform="translate(37 35.39)scale(.66667)"><circle cx="12" cy="12" r="10" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(194, 11, 32)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><line x1="12" x2="12" y1="8" y2="12" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(194, 11, 32)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><line x1="12" x2="12.01" y1="16" y2="16" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(194, 11, 32)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/></g></g></g></g><text x="61" y="41.39" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="12" font-weight="700" fill="rgb(194,11,32)">Build failed</text><g clip-path="url(#cp3)"><g clip-path="url(#ct4)"><text x="61" y="55.39" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="11" fill="rgb(194,11,32)">Step “test” exited with code 1.</text></g></g><rect x="431.7" y="29" width="71.3" height="28.8" rx="14.4" fill="rgba(255,255,255,0.52)"/><rect x="432.5" y="29.5" width="70" height="28" rx="13.9" fill="none" stroke="rgb(194,11,32)" stroke-width="1"/><text x="443.88" y="47.89" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="11" font-weight="650" fill="rgb(194,11,32)">View log</text></svg>
@@ -1 +1 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 560 116" width="560" height="116"><defs><clipPath id="cp0"><rect x="37" y="35" width="16" height="16.4"/></clipPath><clipPath id="cp2"><rect x="61" y="44.4" width="368.6" height="13"/></clipPath><clipPath id="ct3"><rect x="61" y="29.4" width="116.7" height="15"/></clipPath><clipPath id="ct4"><rect x="61" y="44.4" width="368.6" height="13"/></clipPath><clipPath id="ct5"><rect x="437.6" y="29" width="65.4" height="28.8"/></clipPath></defs><rect x="28" y="20" width="484" height="46.8" rx="12" fill="rgb(34,43,48)"/><rect x="28.5" y="20.5" width="483" height="46" rx="11.5" fill="none" stroke="rgb(53,92,109)" stroke-width="1"/><g clip-path="url(#cp0)"><g color="rgb(138, 203, 255)"><clipPath id="svgic1"><rect x="37" y="35.4" width="16" height="16"/></clipPath><g clip-path="url(#svgic1)"><g transform="translate(37 35.39)scale(.66667)"><circle cx="12" cy="12" r="10" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(138, 203, 255)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><line x1="12" x2="12" y1="8" y2="12" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(138, 203, 255)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><line x1="12" x2="12.01" y1="16" y2="16" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(138, 203, 255)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/></g></g></g></g><text x="61" y="41.39" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="12" font-weight="700" fill="rgb(138,203,255)">Draft not published</text><g clip-path="url(#cp2)"><g clip-path="url(#ct4)"><text x="61" y="55.39" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="11" fill="rgb(138,203,255)">Changes are saved but only visible to your team.</text></g></g><rect x="437.6" y="29" width="65.4" height="28.8" rx="14.4" fill="rgba(28,28,30,0.52)"/><rect x="438.5" y="29.5" width="64" height="28" rx="13.9" fill="none" stroke="rgb(138,203,255)" stroke-width="1"/><text x="449.83" y="47.89" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="11" font-weight="650" fill="rgb(138,203,255)">Publish</text></svg>
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 560 116" width="560" height="116"><defs><clipPath id="cp0"><rect x="37" y="35" width="16" height="16.4"/></clipPath><clipPath id="ct2"><rect x="61" y="29.4" width="116.7" height="15"/></clipPath><clipPath id="cp3"><rect x="61" y="44.4" width="254.4" height="13"/></clipPath><clipPath id="ct4"><rect x="61" y="44.4" width="254.4" height="13"/></clipPath><clipPath id="ct5"><rect x="437.6" y="29" width="65.4" height="28.8"/></clipPath></defs><rect x="28" y="20" width="484" height="46.8" rx="12" fill="rgb(34,43,48)"/><rect x="28.5" y="20.5" width="483" height="46" rx="11.5" fill="none" stroke="rgb(53,92,109)" stroke-width="1"/><g clip-path="url(#cp0)"><g color="rgb(138, 203, 255)"><clipPath id="svgic1"><rect x="37" y="35.4" width="16" height="16"/></clipPath><g clip-path="url(#svgic1)"><g transform="translate(37 35.39)scale(.66667)"><circle cx="12" cy="12" r="10" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(138, 203, 255)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><line x1="12" x2="12" y1="8" y2="12" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(138, 203, 255)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><line x1="12" x2="12.01" y1="16" y2="16" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(138, 203, 255)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/></g></g></g></g><text x="61" y="41.39" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="12" font-weight="700" fill="rgb(138,203,255)">Draft not published</text><g clip-path="url(#cp3)"><g clip-path="url(#ct4)"><text x="61" y="55.39" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="11" fill="rgb(138,203,255)">Changes are saved but only visible to your team.</text></g></g><rect x="437.6" y="29" width="65.4" height="28.8" rx="14.4" fill="rgba(28,28,30,0.52)"/><rect x="438.5" y="29.5" width="64" height="28" rx="13.9" fill="none" stroke="rgb(138,203,255)" stroke-width="1"/><text x="449.83" y="47.89" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="11" font-weight="650" fill="rgb(138,203,255)">Publish</text></svg>
@@ -1 +1 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 560 116" width="560" height="116"><defs><clipPath id="cp0"><rect x="37" y="35" width="16" height="16.4"/></clipPath><clipPath id="cp2"><rect x="61" y="44.4" width="368.6" height="13"/></clipPath><clipPath id="ct3"><rect x="61" y="29.4" width="116.7" height="15"/></clipPath><clipPath id="ct4"><rect x="61" y="44.4" width="368.6" height="13"/></clipPath><clipPath id="ct5"><rect x="437.6" y="29" width="65.4" height="28.8"/></clipPath></defs><rect x="28" y="20" width="484" height="46.8" rx="12" fill="rgb(235,244,252)"/><rect x="28.5" y="20.5" width="483" height="46" rx="11.5" fill="none" stroke="rgb(166,207,242)" stroke-width="1"/><g clip-path="url(#cp0)"><g color="rgb(26, 93, 207)"><clipPath id="svgic1"><rect x="37" y="35.4" width="16" height="16"/></clipPath><g clip-path="url(#svgic1)"><g transform="translate(37 35.39)scale(.66667)"><circle cx="12" cy="12" r="10" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(26, 93, 207)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><line x1="12" x2="12" y1="8" y2="12" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(26, 93, 207)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><line x1="12" x2="12.01" y1="16" y2="16" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(26, 93, 207)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/></g></g></g></g><text x="61" y="41.39" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="12" font-weight="700" fill="rgb(26,93,207)">Draft not published</text><g clip-path="url(#cp2)"><g clip-path="url(#ct4)"><text x="61" y="55.39" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="11" fill="rgb(26,93,207)">Changes are saved but only visible to your team.</text></g></g><rect x="437.6" y="29" width="65.4" height="28.8" rx="14.4" fill="rgba(255,255,255,0.52)"/><rect x="438.5" y="29.5" width="64" height="28" rx="13.9" fill="none" stroke="rgb(26,93,207)" stroke-width="1"/><text x="449.83" y="47.89" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="11" font-weight="650" fill="rgb(26,93,207)">Publish</text></svg>
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 560 116" width="560" height="116"><defs><clipPath id="cp0"><rect x="37" y="35" width="16" height="16.4"/></clipPath><clipPath id="ct2"><rect x="61" y="29.4" width="116.7" height="15"/></clipPath><clipPath id="cp3"><rect x="61" y="44.4" width="254.4" height="13"/></clipPath><clipPath id="ct4"><rect x="61" y="44.4" width="254.4" height="13"/></clipPath><clipPath id="ct5"><rect x="437.6" y="29" width="65.4" height="28.8"/></clipPath></defs><rect x="28" y="20" width="484" height="46.8" rx="12" fill="rgb(235,244,252)"/><rect x="28.5" y="20.5" width="483" height="46" rx="11.5" fill="none" stroke="rgb(166,207,242)" stroke-width="1"/><g clip-path="url(#cp0)"><g color="rgb(26, 93, 207)"><clipPath id="svgic1"><rect x="37" y="35.4" width="16" height="16"/></clipPath><g clip-path="url(#svgic1)"><g transform="translate(37 35.39)scale(.66667)"><circle cx="12" cy="12" r="10" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(26, 93, 207)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><line x1="12" x2="12" y1="8" y2="12" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(26, 93, 207)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><line x1="12" x2="12.01" y1="16" y2="16" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(26, 93, 207)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/></g></g></g></g><text x="61" y="41.39" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="12" font-weight="700" fill="rgb(26,93,207)">Draft not published</text><g clip-path="url(#cp3)"><g clip-path="url(#ct4)"><text x="61" y="55.39" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="11" fill="rgb(26,93,207)">Changes are saved but only visible to your team.</text></g></g><rect x="437.6" y="29" width="65.4" height="28.8" rx="14.4" fill="rgba(255,255,255,0.52)"/><rect x="438.5" y="29.5" width="64" height="28" rx="13.9" fill="none" stroke="rgb(26,93,207)" stroke-width="1"/><text x="449.83" y="47.89" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="11" font-weight="650" fill="rgb(26,93,207)">Publish</text></svg>
@@ -1 +1 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 560 116" width="560" height="116"><defs><clipPath id="cp0"><rect x="37" y="35" width="16" height="16"/></clipPath><clipPath id="cp2"><rect x="61" y="44" width="434" height="13"/></clipPath><clipPath id="ct3"><rect x="61" y="29" width="132.1" height="15"/></clipPath><clipPath id="ct4"><rect x="61" y="44" width="434" height="13"/></clipPath></defs><rect x="28" y="20" width="484" height="46" rx="12" fill="rgb(31,52,38)"/><rect x="28.5" y="20.5" width="483" height="45" rx="11.5" fill="none" stroke="rgb(40,113,59)" stroke-width="1"/><g clip-path="url(#cp0)"><g color="rgb(99, 230, 133)"><clipPath id="svgic1"><rect x="37" y="35" width="16" height="16"/></clipPath><g clip-path="url(#svgic1)"><g transform="translate(37 35)scale(.66667)"><circle cx="12" cy="12" r="10" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(99, 230, 133)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><path d="m16 9-5.5 5.5L8 12" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(99, 230, 133)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/></g></g></g></g><text x="61" y="41" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="12" font-weight="700" fill="rgb(99,230,133)">Deployment complete</text><g clip-path="url(#cp2)"><g clip-path="url(#ct4)"><text x="61" y="55" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="11" fill="rgb(99,230,133)">production.example.com is serving the new build.</text></g></g></svg>
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 560 116" width="560" height="116"><defs><clipPath id="cp0"><rect x="37" y="35" width="16" height="16"/></clipPath><clipPath id="ct2"><rect x="61" y="29" width="132.1" height="15"/></clipPath><clipPath id="cp3"><rect x="61" y="44" width="259.7" height="13"/></clipPath><clipPath id="ct4"><rect x="61" y="44" width="259.7" height="13"/></clipPath></defs><rect x="28" y="20" width="484" height="46" rx="12" fill="rgb(31,52,38)"/><rect x="28.5" y="20.5" width="483" height="45" rx="11.5" fill="none" stroke="rgb(40,113,59)" stroke-width="1"/><g clip-path="url(#cp0)"><g color="rgb(99, 230, 133)"><clipPath id="svgic1"><rect x="37" y="35" width="16" height="16"/></clipPath><g clip-path="url(#svgic1)"><g transform="translate(37 35)scale(.66667)"><circle cx="12" cy="12" r="10" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(99, 230, 133)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><path d="m16 9-5.5 5.5L8 12" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(99, 230, 133)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/></g></g></g></g><text x="61" y="41" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="12" font-weight="700" fill="rgb(99,230,133)">Deployment complete</text><g clip-path="url(#cp3)"><g clip-path="url(#ct4)"><text x="61" y="55" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="11" fill="rgb(99,230,133)">production.example.com is serving the new build.</text></g></g></svg>
@@ -1 +1 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 560 116" width="560" height="116"><defs><clipPath id="cp0"><rect x="37" y="35" width="16" height="16"/></clipPath><clipPath id="cp2"><rect x="61" y="44" width="434" height="13"/></clipPath><clipPath id="ct3"><rect x="61" y="29" width="132.1" height="15"/></clipPath><clipPath id="ct4"><rect x="61" y="44" width="434" height="13"/></clipPath></defs><rect x="28" y="20" width="484" height="46" rx="12" fill="rgb(227,247,232)"/><rect x="28.5" y="20.5" width="483" height="45" rx="11.5" fill="none" stroke="rgb(154,227,172)" stroke-width="1"/><g clip-path="url(#cp0)"><g color="rgb(0, 121, 44)"><clipPath id="svgic1"><rect x="37" y="35" width="16" height="16"/></clipPath><g clip-path="url(#svgic1)"><g transform="translate(37 35)scale(.66667)"><circle cx="12" cy="12" r="10" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(0, 121, 44)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><path d="m16 9-5.5 5.5L8 12" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(0, 121, 44)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/></g></g></g></g><text x="61" y="41" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="12" font-weight="700" fill="rgb(0,121,44)">Deployment complete</text><g clip-path="url(#cp2)"><g clip-path="url(#ct4)"><text x="61" y="55" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="11" fill="rgb(0,121,44)">production.example.com is serving the new build.</text></g></g></svg>
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 560 116" width="560" height="116"><defs><clipPath id="cp0"><rect x="37" y="35" width="16" height="16"/></clipPath><clipPath id="ct2"><rect x="61" y="29" width="132.1" height="15"/></clipPath><clipPath id="cp3"><rect x="61" y="44" width="259.7" height="13"/></clipPath><clipPath id="ct4"><rect x="61" y="44" width="259.7" height="13"/></clipPath></defs><rect x="28" y="20" width="484" height="46" rx="12" fill="rgb(227,247,232)"/><rect x="28.5" y="20.5" width="483" height="45" rx="11.5" fill="none" stroke="rgb(154,227,172)" stroke-width="1"/><g clip-path="url(#cp0)"><g color="rgb(0, 121, 44)"><clipPath id="svgic1"><rect x="37" y="35" width="16" height="16"/></clipPath><g clip-path="url(#svgic1)"><g transform="translate(37 35)scale(.66667)"><circle cx="12" cy="12" r="10" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(0, 121, 44)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><path d="m16 9-5.5 5.5L8 12" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(0, 121, 44)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/></g></g></g></g><text x="61" y="41" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="12" font-weight="700" fill="rgb(0,121,44)">Deployment complete</text><g clip-path="url(#cp3)"><g clip-path="url(#ct4)"><text x="61" y="55" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="11" fill="rgb(0,121,44)">production.example.com is serving the new build.</text></g></g></svg>
@@ -1 +1 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 560 116" width="560" height="116"><defs><clipPath id="cp0"><rect x="37" y="35" width="16" height="16.4"/></clipPath><clipPath id="cp2"><rect x="61" y="44.4" width="362.1" height="13"/></clipPath><clipPath id="ct3"><rect x="61" y="29.4" width="166.1" height="15"/></clipPath><clipPath id="ct4"><rect x="61" y="44.4" width="362.1" height="13"/></clipPath><clipPath id="ct5"><rect x="431.1" y="29" width="71.9" height="28.8"/></clipPath></defs><rect x="28" y="20" width="484" height="46.8" rx="12" fill="rgb(48,44,27)"/><rect x="28.5" y="20.5" width="483" height="46" rx="11.5" fill="none" stroke="rgb(251,221,104)" stroke-width="1"/><g clip-path="url(#cp0)"><g color="rgb(255, 216, 74)"><clipPath id="svgic1"><rect x="37" y="35.4" width="16" height="16"/></clipPath><g clip-path="url(#svgic1)"><g transform="translate(37 35.39)scale(.66667)"><path d="m21.7 18-8-14a2 2 0 0 0-3.4 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.7-3" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(255, 216, 74)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><path d="M12 9v4" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(255, 216, 74)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><path d="M12 17z" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(255, 216, 74)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/></g></g></g></g><text x="61" y="41.39" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="12" font-weight="700" fill="rgb(255,216,74)">Approaching your plan limit</text><g clip-path="url(#cp2)"><g clip-path="url(#ct4)"><text x="61" y="55.39" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="11" fill="rgb(255,216,74)">You have used 92% of this month’s build minutes.</text></g></g><rect x="431.1" y="29" width="71.9" height="28.8" rx="14.4" fill="rgba(28,28,30,0.52)"/><rect x="431.5" y="29.5" width="71" height="28" rx="13.9" fill="none" stroke="rgb(255,216,74)" stroke-width="1"/><text x="443.28" y="47.89" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="11" font-weight="650" fill="rgb(255,216,74)">Upgrade</text></svg>
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 560 116" width="560" height="116"><defs><clipPath id="cp0"><rect x="37" y="35" width="16" height="16.4"/></clipPath><clipPath id="ct2"><rect x="61" y="29.4" width="166.1" height="15"/></clipPath><clipPath id="cp3"><rect x="61" y="44.4" width="261" height="13"/></clipPath><clipPath id="ct4"><rect x="61" y="44.4" width="261" height="13"/></clipPath><clipPath id="ct5"><rect x="431.1" y="29" width="71.9" height="28.8"/></clipPath></defs><rect x="28" y="20" width="484" height="46.8" rx="12" fill="rgb(48,44,27)"/><rect x="28.5" y="20.5" width="483" height="46" rx="11.5" fill="none" stroke="rgb(251,221,104)" stroke-width="1"/><g clip-path="url(#cp0)"><g color="rgb(255, 216, 74)"><clipPath id="svgic1"><rect x="37" y="35.4" width="16" height="16"/></clipPath><g clip-path="url(#svgic1)"><g transform="translate(37 35.39)scale(.66667)"><path d="m21.7 18-8-14a2 2 0 0 0-3.4 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.7-3" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(255, 216, 74)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><path d="M12 9v4" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(255, 216, 74)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><path d="M12 17z" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(255, 216, 74)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/></g></g></g></g><text x="61" y="41.39" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="12" font-weight="700" fill="rgb(255,216,74)">Approaching your plan limit</text><g clip-path="url(#cp3)"><g clip-path="url(#ct4)"><text x="61" y="55.39" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="11" fill="rgb(255,216,74)">You have used 92% of this month’s build minutes.</text></g></g><rect x="431.1" y="29" width="71.9" height="28.8" rx="14.4" fill="rgba(28,28,30,0.52)"/><rect x="431.5" y="29.5" width="71" height="28" rx="13.9" fill="none" stroke="rgb(255,216,74)" stroke-width="1"/><text x="443.28" y="47.89" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="11" font-weight="650" fill="rgb(255,216,74)">Upgrade</text></svg>
@@ -1 +1 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 560 116" width="560" height="116"><defs><clipPath id="cp0"><rect x="37" y="35" width="16" height="16.4"/></clipPath><clipPath id="cp2"><rect x="61" y="44.4" width="362.1" height="13"/></clipPath><clipPath id="ct3"><rect x="61" y="29.4" width="166.1" height="15"/></clipPath><clipPath id="ct4"><rect x="61" y="44.4" width="362.1" height="13"/></clipPath><clipPath id="ct5"><rect x="431.1" y="29" width="71.9" height="28.8"/></clipPath></defs><rect x="28" y="20" width="484" height="46.8" rx="12" fill="rgb(255,250,232)"/><rect x="28.5" y="20.5" width="483" height="46" rx="11.5" fill="none" stroke="rgb(160,131,13)" stroke-width="1"/><g clip-path="url(#cp0)"><g color="rgb(143, 94, 0)"><clipPath id="svgic1"><rect x="37" y="35.4" width="16" height="16"/></clipPath><g clip-path="url(#svgic1)"><g transform="translate(37 35.39)scale(.66667)"><path d="m21.7 18-8-14a2 2 0 0 0-3.4 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.7-3" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(143, 94, 0)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><path d="M12 9v4" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(143, 94, 0)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><path d="M12 17z" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(143, 94, 0)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/></g></g></g></g><text x="61" y="41.39" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="12" font-weight="700" fill="rgb(143,94,0)">Approaching your plan limit</text><g clip-path="url(#cp2)"><g clip-path="url(#ct4)"><text x="61" y="55.39" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="11" fill="rgb(143,94,0)">You have used 92% of this month’s build minutes.</text></g></g><rect x="431.1" y="29" width="71.9" height="28.8" rx="14.4" fill="rgba(255,255,255,0.52)"/><rect x="431.5" y="29.5" width="71" height="28" rx="13.9" fill="none" stroke="rgb(143,94,0)" stroke-width="1"/><text x="443.28" y="47.89" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="11" font-weight="650" fill="rgb(143,94,0)">Upgrade</text></svg>
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 560 116" width="560" height="116"><defs><clipPath id="cp0"><rect x="37" y="35" width="16" height="16.4"/></clipPath><clipPath id="ct2"><rect x="61" y="29.4" width="166.1" height="15"/></clipPath><clipPath id="cp3"><rect x="61" y="44.4" width="261" height="13"/></clipPath><clipPath id="ct4"><rect x="61" y="44.4" width="261" height="13"/></clipPath><clipPath id="ct5"><rect x="431.1" y="29" width="71.9" height="28.8"/></clipPath></defs><rect x="28" y="20" width="484" height="46.8" rx="12" fill="rgb(255,250,232)"/><rect x="28.5" y="20.5" width="483" height="46" rx="11.5" fill="none" stroke="rgb(160,131,13)" stroke-width="1"/><g clip-path="url(#cp0)"><g color="rgb(143, 94, 0)"><clipPath id="svgic1"><rect x="37" y="35.4" width="16" height="16"/></clipPath><g clip-path="url(#svgic1)"><g transform="translate(37 35.39)scale(.66667)"><path d="m21.7 18-8-14a2 2 0 0 0-3.4 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.7-3" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(143, 94, 0)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><path d="M12 9v4" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(143, 94, 0)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><path d="M12 17z" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(143, 94, 0)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/></g></g></g></g><text x="61" y="41.39" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="12" font-weight="700" fill="rgb(143,94,0)">Approaching your plan limit</text><g clip-path="url(#cp3)"><g clip-path="url(#ct4)"><text x="61" y="55.39" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="11" fill="rgb(143,94,0)">You have used 92% of this month’s build minutes.</text></g></g><rect x="431.1" y="29" width="71.9" height="28.8" rx="14.4" fill="rgba(255,255,255,0.52)"/><rect x="431.5" y="29.5" width="71" height="28" rx="13.9" fill="none" stroke="rgb(143,94,0)" stroke-width="1"/><text x="443.28" y="47.89" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="11" font-weight="650" fill="rgb(143,94,0)">Upgrade</text></svg>