@beehexa/design-rules 2611.3.2 → 2611.4.1

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 (68) hide show
  1. package/README.md +1 -1
  2. package/dist/AGENTS.md +1 -7
  3. package/dist/catalog.json +153 -125
  4. package/dist/docs/scripts/color-pairs.mjs +5 -1
  5. package/dist/docs/scripts/token-utils.mjs +16 -1
  6. package/dist/docs/src/components/ColorDemo.astro +5 -5
  7. package/dist/docs/src/components/ElevationDemo.astro +196 -0
  8. package/dist/docs/src/components/LayoutDemo.astro +1 -1
  9. package/dist/docs/src/components/OpacityDemo.astro +95 -0
  10. package/dist/docs/src/components/ShapeDemo.astro +11 -10
  11. package/dist/docs/src/components/ShapePin.astro +5 -3
  12. package/dist/docs/src/components/ZIndexDemo.astro +102 -0
  13. package/dist/docs/src/content/foundations/styles/border.mdx +3 -3
  14. package/dist/docs/src/content/foundations/styles/color/usage.mdx +11 -4
  15. package/dist/docs/src/content/foundations/styles/data-visualization.mdx +74 -6
  16. package/dist/docs/src/content/foundations/styles/elevation.mdx +66 -3
  17. package/dist/docs/src/content/foundations/styles/icons/usage.mdx +9 -6
  18. package/dist/docs/src/content/foundations/styles/layout/app-frame.mdx +10 -0
  19. package/dist/docs/src/content/foundations/styles/opacity.mdx +43 -5
  20. package/dist/docs/src/content/foundations/styles/size-and-density.mdx +7 -0
  21. package/dist/docs/src/content/foundations/styles/typography/code.mdx +1 -1
  22. package/dist/docs/src/content/foundations/styles/z-index.mdx +63 -5
  23. package/dist/docs/src/content/tools/ant-design-vue-theme.mdx +125 -18
  24. package/dist/docs/src/content/tools/application-content.mdx +42 -0
  25. package/dist/docs/src/content/tools/editors.mdx +27 -0
  26. package/dist/docs/src/content/tools/mermaid.mdx +95 -0
  27. package/dist/docs/src/content/tools/vueflow.mdx +121 -0
  28. package/dist/docs/src/content-vi/foundations/styles/border.mdx +3 -3
  29. package/dist/docs/src/content-vi/foundations/styles/color/usage.mdx +11 -4
  30. package/dist/docs/src/content-vi/foundations/styles/data-visualization.mdx +75 -6
  31. package/dist/docs/src/content-vi/foundations/styles/elevation.mdx +75 -0
  32. package/dist/docs/src/content-vi/foundations/styles/icons/usage.mdx +9 -6
  33. package/dist/docs/src/content-vi/foundations/styles/layout/app-frame.mdx +10 -0
  34. package/dist/docs/src/content-vi/foundations/styles/opacity.mdx +43 -5
  35. package/dist/docs/src/content-vi/foundations/styles/size-and-density.mdx +7 -0
  36. package/dist/docs/src/content-vi/foundations/styles/typography/code.mdx +1 -1
  37. package/dist/docs/src/content-vi/foundations/styles/z-index.mdx +63 -5
  38. package/dist/docs/src/lib/token-descriptions-vi.ts +21 -5
  39. package/dist/docs/src/styles/chrome.css +14 -14
  40. package/dist/docs/src/styles/color.css +19 -32
  41. package/dist/docs/src/styles/docs.css +18 -34
  42. package/dist/docs/src/styles/elevation.css +83 -0
  43. package/dist/docs/src/styles/global.css +1 -10
  44. package/dist/docs/src/styles/icons.css +11 -15
  45. package/dist/docs/src/styles/kit.css +112 -0
  46. package/dist/docs/src/styles/layout.css +1 -6
  47. package/dist/docs/src/styles/opacity.css +43 -0
  48. package/dist/docs/src/styles/shapes.css +15 -19
  49. package/dist/docs/src/styles/tokens.css +1282 -3
  50. package/dist/docs/src/styles/tokens.js +358 -3
  51. package/dist/docs/src/styles/typography.css +4 -7
  52. package/dist/docs/src/styles/zindex.css +56 -0
  53. package/dist/docs/tokens/border.json +1 -1
  54. package/dist/docs/tokens/color.json +57 -3
  55. package/dist/docs/tokens/content.json +19 -0
  56. package/dist/docs/tokens/diagram.json +48 -0
  57. package/dist/docs/tokens/editor.json +129 -0
  58. package/dist/docs/tokens/elevation.json +15 -5
  59. package/dist/docs/tokens/flow.json +497 -0
  60. package/dist/docs/tokens/opacity.json +9 -0
  61. package/dist/docs/tokens/resize.json +67 -0
  62. package/dist/docs/tokens/size.json +6 -0
  63. package/dist/docs/tokens/spacing.json +4 -4
  64. package/dist/docs/tokens/typography.json +5 -0
  65. package/dist/docs/tokens/visualization.json +123 -0
  66. package/dist/docs/tokens/z-index.json +49 -0
  67. package/dist/index.js +153 -125
  68. package/package.json +6 -1
package/dist/index.js CHANGED
@@ -136,8 +136,8 @@ export const catalog = [
136
136
  "status": "active",
137
137
  "releasePhase": null,
138
138
  "planned": [],
139
- "body": "import ShapeDemo from '../../../components/ShapeDemo.astro';\nimport TokenTable from '../../../components/TokenTable.astro';\n\n**Most borders are 1 px. Thicker lines mean something: selected, focused, or a status to notice.**\n\nBorder colours are colour tokens: `color.border` for dividers and cards, `color.border.bold` for the edges of inputs, checkboxes and selects. See [Tokens](/foundations/styles/color/tokens/#borders).\n\n## The widths\n\n<ShapeDemo kind=\"border-scale\" />\n\n## Examples\n\n### `border.width.default` · 1 px\n\nInputs, secondary buttons, cards, tables and dividers.\n\n<ShapeDemo kind=\"border-use\" item=\"default\" />\n\n### `border.width.selected` · 2 px\n\nThe bar under a selected tab, the bar beside a selected side navigation item, and the edge of a selected card. Always with `color.border.selected`.\n\n<ShapeDemo kind=\"border-use\" item=\"selected\" />\n\n### `border.width.focused` · 2 px\n\nThe focus ring, in `color.border.focus`, drawn 2 px outside the element (`state.focus.offset`). Draw it inside, at −2 px, when a box around the element would cut it off: menu items, table cells and tabs in a scroll area.\n\n<ShapeDemo kind=\"border-use\" item=\"focused\" />\n\n### `border.width.accent` · 4 px\n\nA status or emphasis bar on one edge: alerts and banners, a table row with an error, callouts and quotes. The box keeps its radius on all four corners and the bar follows the curve.\n\n<ShapeDemo kind=\"border-use\" item=\"accent\" />\n\n## Width and colour go together\n\n| Width | Colour | For |\n|---|---|---|\n| `border.width.default` | `color.border` or `color.border.bold` | Edges and dividers |\n| `border.width.selected` | `color.border.selected` | Selected tab, side navigation item or card |\n| `border.width.focused` | `color.border.focus` | Keyboard focus |\n| `border.width.accent` | `color.border.danger`, `.warning`, `.success`, `.info` or `.brand` | Status and emphasis bars |\n\nDon't show a state with colour alone. Selected and focused also change the width.\n\n## Do and don’t\n\n<ShapeDemo kind=\"dodont\" item=\"selected\" />\n<ShapeDemo kind=\"dodont\" item=\"accent\" />\n<ShapeDemo kind=\"dodont\" item=\"cards\" />\n\n## Code\n\n```css\n.alert {\n position: relative;\n overflow: hidden;\n border: var(--bh-border-width-default) solid var(--bh-color-border);\n border-radius: var(--bh-radius-100);\n}\n.alert::before {\n content: \"\";\n position: absolute;\n inset: 0 auto 0 0;\n width: var(--bh-border-width-accent);\n background: var(--bh-color-border-danger);\n}\n:focus-visible {\n outline: var(--bh-border-width-focused) solid var(--bh-color-border-focus);\n outline-offset: var(--bh-state-focus-offset);\n}\n```\n\n## Tokens\n\n<TokenTable prefix=\"border\" />\n\n## Related\n\n- [Radius](/foundations/styles/radius/): corner radius steps and the nesting rule.\n- [Interaction states](/foundations/styles/interaction-states/): hover, pressed, selected and disabled.\n",
140
- "raw": "---\ntitle: Border\ndescription: Four border widths, the colour each one goes with, and how the focus ring is drawn.\norder: 7\n---\nimport ShapeDemo from '../../../components/ShapeDemo.astro';\nimport TokenTable from '../../../components/TokenTable.astro';\n\n**Most borders are 1 px. Thicker lines mean something: selected, focused, or a status to notice.**\n\nBorder colours are colour tokens: `color.border` for dividers and cards, `color.border.bold` for the edges of inputs, checkboxes and selects. See [Tokens](/foundations/styles/color/tokens/#borders).\n\n## The widths\n\n<ShapeDemo kind=\"border-scale\" />\n\n## Examples\n\n### `border.width.default` · 1 px\n\nInputs, secondary buttons, cards, tables and dividers.\n\n<ShapeDemo kind=\"border-use\" item=\"default\" />\n\n### `border.width.selected` · 2 px\n\nThe bar under a selected tab, the bar beside a selected side navigation item, and the edge of a selected card. Always with `color.border.selected`.\n\n<ShapeDemo kind=\"border-use\" item=\"selected\" />\n\n### `border.width.focused` · 2 px\n\nThe focus ring, in `color.border.focus`, drawn 2 px outside the element (`state.focus.offset`). Draw it inside, at −2 px, when a box around the element would cut it off: menu items, table cells and tabs in a scroll area.\n\n<ShapeDemo kind=\"border-use\" item=\"focused\" />\n\n### `border.width.accent` · 4 px\n\nA status or emphasis bar on one edge: alerts and banners, a table row with an error, callouts and quotes. The box keeps its radius on all four corners and the bar follows the curve.\n\n<ShapeDemo kind=\"border-use\" item=\"accent\" />\n\n## Width and colour go together\n\n| Width | Colour | For |\n|---|---|---|\n| `border.width.default` | `color.border` or `color.border.bold` | Edges and dividers |\n| `border.width.selected` | `color.border.selected` | Selected tab, side navigation item or card |\n| `border.width.focused` | `color.border.focus` | Keyboard focus |\n| `border.width.accent` | `color.border.danger`, `.warning`, `.success`, `.info` or `.brand` | Status and emphasis bars |\n\nDon't show a state with colour alone. Selected and focused also change the width.\n\n## Do and don’t\n\n<ShapeDemo kind=\"dodont\" item=\"selected\" />\n<ShapeDemo kind=\"dodont\" item=\"accent\" />\n<ShapeDemo kind=\"dodont\" item=\"cards\" />\n\n## Code\n\n```css\n.alert {\n position: relative;\n overflow: hidden;\n border: var(--bh-border-width-default) solid var(--bh-color-border);\n border-radius: var(--bh-radius-100);\n}\n.alert::before {\n content: \"\";\n position: absolute;\n inset: 0 auto 0 0;\n width: var(--bh-border-width-accent);\n background: var(--bh-color-border-danger);\n}\n:focus-visible {\n outline: var(--bh-border-width-focused) solid var(--bh-color-border-focus);\n outline-offset: var(--bh-state-focus-offset);\n}\n```\n\n## Tokens\n\n<TokenTable prefix=\"border\" />\n\n## Related\n\n- [Radius](/foundations/styles/radius/): corner radius steps and the nesting rule.\n- [Interaction states](/foundations/styles/interaction-states/): hover, pressed, selected and disabled.\n",
139
+ "body": "import ShapeDemo from '../../../components/ShapeDemo.astro';\nimport TokenTable from '../../../components/TokenTable.astro';\n\n**Most borders are 1 px. Thicker lines mean something: selected, focused, or a status to notice.**\n\nBorder colours are colour tokens: `color.border` for dividers and cards, `color.border.bold` for the edges of inputs, checkboxes and selects. See [Tokens](/foundations/styles/color/tokens/#borders).\n\n## The widths\n\n<ShapeDemo kind=\"border-scale\" />\n\n## Examples\n\n### `border.width.default` · 1 px\n\nInputs, secondary buttons, cards, tables and dividers.\n\n<ShapeDemo kind=\"border-use\" item=\"default\" />\n\n### `border.width.selected` · 2 px\n\nThe bar under a selected tab, the bar beside a selected side navigation item, and the edge of a selected card. Always with `color.border.selected`.\n\n<ShapeDemo kind=\"border-use\" item=\"selected\" />\n\n### `border.width.focused` · 2 px\n\nThe focus ring, in `color.border.focus`, drawn 2 px outside the element (`state.focus.offset`). Draw it inside, at −2 px, when a box around the element would cut it off: menu items, table cells and tabs in a scroll area.\n\n<ShapeDemo kind=\"border-use\" item=\"focused\" />\n\n### `border.width.accent` · 4 px\n\nA status or emphasis bar on one edge: a table row with an error, callouts and quotes. Banners don't use it; they use a tinted background (see [Color usage](/foundations/styles/color/usage/)). The box keeps its radius on all four corners and the bar follows the curve.\n\n<ShapeDemo kind=\"border-use\" item=\"accent\" />\n\n## Width and colour go together\n\n| Width | Colour | For |\n|---|---|---|\n| `border.width.default` | `color.border` or `color.border.bold` | Edges and dividers |\n| `border.width.selected` | `color.border.selected` | Selected tab, side navigation item or card |\n| `border.width.focused` | `color.border.focus` | Keyboard focus |\n| `border.width.accent` | `color.border.danger`, `.warning`, `.success`, `.info` or `.brand` | Status and emphasis bars |\n\nDon't show a state with colour alone. Selected and focused also change the width.\n\n## Do and don’t\n\n<ShapeDemo kind=\"dodont\" item=\"selected\" />\n<ShapeDemo kind=\"dodont\" item=\"accent\" />\n<ShapeDemo kind=\"dodont\" item=\"cards\" />\n\n## Code\n\n```css\n.callout {\n position: relative;\n overflow: hidden;\n border: var(--bh-border-width-default) solid var(--bh-color-border);\n border-radius: var(--bh-radius-100);\n}\n.callout::before {\n content: \"\";\n position: absolute;\n inset: 0 auto 0 0;\n width: var(--bh-border-width-accent);\n background: var(--bh-color-border-danger);\n}\n:focus-visible {\n outline: var(--bh-border-width-focused) solid var(--bh-color-border-focus);\n outline-offset: var(--bh-state-focus-offset);\n}\n```\n\n## Tokens\n\n<TokenTable prefix=\"border\" />\n\n## Related\n\n- [Radius](/foundations/styles/radius/): corner radius steps and the nesting rule.\n- [Interaction states](/foundations/styles/interaction-states/): hover, pressed, selected and disabled.\n",
140
+ "raw": "---\ntitle: Border\ndescription: Four border widths, the colour each one goes with, and how the focus ring is drawn.\norder: 7\n---\nimport ShapeDemo from '../../../components/ShapeDemo.astro';\nimport TokenTable from '../../../components/TokenTable.astro';\n\n**Most borders are 1 px. Thicker lines mean something: selected, focused, or a status to notice.**\n\nBorder colours are colour tokens: `color.border` for dividers and cards, `color.border.bold` for the edges of inputs, checkboxes and selects. See [Tokens](/foundations/styles/color/tokens/#borders).\n\n## The widths\n\n<ShapeDemo kind=\"border-scale\" />\n\n## Examples\n\n### `border.width.default` · 1 px\n\nInputs, secondary buttons, cards, tables and dividers.\n\n<ShapeDemo kind=\"border-use\" item=\"default\" />\n\n### `border.width.selected` · 2 px\n\nThe bar under a selected tab, the bar beside a selected side navigation item, and the edge of a selected card. Always with `color.border.selected`.\n\n<ShapeDemo kind=\"border-use\" item=\"selected\" />\n\n### `border.width.focused` · 2 px\n\nThe focus ring, in `color.border.focus`, drawn 2 px outside the element (`state.focus.offset`). Draw it inside, at −2 px, when a box around the element would cut it off: menu items, table cells and tabs in a scroll area.\n\n<ShapeDemo kind=\"border-use\" item=\"focused\" />\n\n### `border.width.accent` · 4 px\n\nA status or emphasis bar on one edge: a table row with an error, callouts and quotes. Banners don't use it; they use a tinted background (see [Color usage](/foundations/styles/color/usage/)). The box keeps its radius on all four corners and the bar follows the curve.\n\n<ShapeDemo kind=\"border-use\" item=\"accent\" />\n\n## Width and colour go together\n\n| Width | Colour | For |\n|---|---|---|\n| `border.width.default` | `color.border` or `color.border.bold` | Edges and dividers |\n| `border.width.selected` | `color.border.selected` | Selected tab, side navigation item or card |\n| `border.width.focused` | `color.border.focus` | Keyboard focus |\n| `border.width.accent` | `color.border.danger`, `.warning`, `.success`, `.info` or `.brand` | Status and emphasis bars |\n\nDon't show a state with colour alone. Selected and focused also change the width.\n\n## Do and don’t\n\n<ShapeDemo kind=\"dodont\" item=\"selected\" />\n<ShapeDemo kind=\"dodont\" item=\"accent\" />\n<ShapeDemo kind=\"dodont\" item=\"cards\" />\n\n## Code\n\n```css\n.callout {\n position: relative;\n overflow: hidden;\n border: var(--bh-border-width-default) solid var(--bh-color-border);\n border-radius: var(--bh-radius-100);\n}\n.callout::before {\n content: \"\";\n position: absolute;\n inset: 0 auto 0 0;\n width: var(--bh-border-width-accent);\n background: var(--bh-color-border-danger);\n}\n:focus-visible {\n outline: var(--bh-border-width-focused) solid var(--bh-color-border-focus);\n outline-offset: var(--bh-state-focus-offset);\n}\n```\n\n## Tokens\n\n<TokenTable prefix=\"border\" />\n\n## Related\n\n- [Radius](/foundations/styles/radius/): corner radius steps and the nesting rule.\n- [Interaction states](/foundations/styles/interaction-states/): hover, pressed, selected and disabled.\n",
141
141
  "frontmatter": {
142
142
  "title": "Border",
143
143
  "description": "Four border widths, the colour each one goes with, and how the focus ring is drawn.",
@@ -245,8 +245,8 @@ export const catalog = [
245
245
  "status": "active",
246
246
  "releasePhase": null,
247
247
  "planned": [],
248
- "body": "import ColorDemo from '../../../../components/ColorDemo.astro';\n\n**Pick a token by what you are painting and what it means, not by how it looks.**\n\n<ColorDemo kind=\"example\" />\n\n## Find the token\n\n| I need | Use |\n|---|---|\n| Page background | `surface.page` |\n| Card, panel, dialog | `surface`, edge `border` |\n| Sidebar, table header, quiet area | `surface.subtle` |\n| Body text, headings, labels | `text` |\n| Descriptions, secondary table columns, navigation | `text.subtle` |\n| Metadata, timestamps, helper text, breadcrumbs | `text.subtlest` |\n| Placeholder | `text.subtlest` |\n| Link | `link`; on hover `link.hover` |\n| Icon next to text | `icon`; less important `icon.subtle` |\n| Divider, card edge | `border` |\n| Edge of an input, checkbox or select | `border.bold` |\n| Keyboard focus ring | `border.focus`, 2 px, 2 px away |\n| Primary button | `background.neutral.bold`, `text.inverse` |\n| Default button | `surface`, `border`, `text`; on hover `background.neutral.subtle.hover` |\n| Destructive button | `background.danger.bold`, `text.on-bold` |\n| Row or menu item on hover | `background.neutral.subtle.hover` |\n| Selected row, tab or menu item | `background.selected` and a second cue |\n| Current page in the navigation | `border.selected` bar, `background.selected`, `aria-current=\"page\"` |\n| Error under a field | `text.danger`, `icon.danger` |\n| Banner for a status | `background.{role}.subtle`, `border.{role}.subtle`, `text`, `icon.{role}` |\n| Status in a table row | A [label](#labels) |\n| Tooltip, toast | `surface.inverse`, `text.inverse` |\n| Layer behind a dialog or drawer | `surface.scrim` |\n| Loading placeholder | `skeleton`, sheen `skeleton.subtle` |\n| Code block | `code.background`, `code.text` |\n| Brand note | `background.brand.subtle`, `border.brand.subtle` |\n| Disabled control | `background.disabled`, `text.disabled`, `border.disabled` |\n\nNot in the table? Build the name from its four parts (see [Tokens](/foundations/styles/color/tokens/)). If no token exists, ask for one; don't pick the nearest colour.\n\n## Surfaces and backgrounds\n\n**Surfaces are the layers of a screen; backgrounds fill the things on them.**\n\n<ColorDemo kind=\"surfaces\" />\n\n`surface.scrim` goes behind dialogs and drawers only, one layer, at its own opacity.\n\n## Emphasis\n\n<ColorDemo kind=\"emphasis\" />\n\n## Status\n\n**Every status is one of five roles. Pick by what the person needs to do, and always say it in words.**\n\n### Choosing a status\n\n| Role | Use when | HexaSync examples |\n|---|---|---|\n| Info | Something is happening or worth knowing; no action needed. | Syncing, queued, importing |\n| Success | It worked. | Synced, connected, completed |\n| Warning | It works now but needs attention soon. | Partial sync, token expires in 3 days, rate limited |\n| Danger | It failed or is blocked, or the action destroys something. | Failed, disconnected, delete |\n| Neutral | Nothing is happening and nothing is wrong. | Paused, draft, skipped, archived |\n\nWarning is orange, not yellow: yellow is the brand. There is no sixth level; say the difference in words (\"Failed 3 times\").\n\n### Status colours\n\n<ColorDemo kind=\"status\" />\n\n<ColorDemo kind=\"banners\" />\n\n<ColorDemo kind=\"dodont\" item=\"warning\" />\n\n### Labels\n\n<ColorDemo kind=\"labels\" />\n\n| | Label | State label |\n|---|---|---|\n| Looks | Outline in the role's `border`, text in its `text` | Fill in the role's `bold`, text and icon in `text.on-bold` |\n| Size | 20 px, padding 6 px; large 24 px, 8 px | 32 px, padding 12 px |\n| Use | Many per screen: table rows, tags | One per page: the status the page is about |\n\n## Interaction states\n\n**Add `.hover` or `.pressed` to the token at rest; never use opacity or an overlay.**\n\n<ColorDemo kind=\"states\" />\n\n| State | Use |\n|---|---|\n| Hover, pressed | The rest token plus `.hover` or `.pressed` |\n| Selected | `background.selected` and a second cue |\n| Focus | 2 px `border.focus` ring, 2 px away |\n| Disabled | `background.disabled`, `text.disabled`, `border.disabled` |\n\nOn a row or menu item each state sits one step further from the background: hover, then selected, then selected on hover. A hovered row is always lighter than a selected one, so it never looks selected.\n\nMore on [Interaction states](/foundations/styles/interaction-states/).\n\n## Buttons\n\n<ColorDemo kind=\"actions\" />\n",
249
- "raw": "---\ntitle: Usage\ndescription: Which token to use for each part of a screen, how status, emphasis and states are coloured, and what not to do.\norder: 2\n---\nimport ColorDemo from '../../../../components/ColorDemo.astro';\n\n**Pick a token by what you are painting and what it means, not by how it looks.**\n\n<ColorDemo kind=\"example\" />\n\n## Find the token\n\n| I need | Use |\n|---|---|\n| Page background | `surface.page` |\n| Card, panel, dialog | `surface`, edge `border` |\n| Sidebar, table header, quiet area | `surface.subtle` |\n| Body text, headings, labels | `text` |\n| Descriptions, secondary table columns, navigation | `text.subtle` |\n| Metadata, timestamps, helper text, breadcrumbs | `text.subtlest` |\n| Placeholder | `text.subtlest` |\n| Link | `link`; on hover `link.hover` |\n| Icon next to text | `icon`; less important `icon.subtle` |\n| Divider, card edge | `border` |\n| Edge of an input, checkbox or select | `border.bold` |\n| Keyboard focus ring | `border.focus`, 2 px, 2 px away |\n| Primary button | `background.neutral.bold`, `text.inverse` |\n| Default button | `surface`, `border`, `text`; on hover `background.neutral.subtle.hover` |\n| Destructive button | `background.danger.bold`, `text.on-bold` |\n| Row or menu item on hover | `background.neutral.subtle.hover` |\n| Selected row, tab or menu item | `background.selected` and a second cue |\n| Current page in the navigation | `border.selected` bar, `background.selected`, `aria-current=\"page\"` |\n| Error under a field | `text.danger`, `icon.danger` |\n| Banner for a status | `background.{role}.subtle`, `border.{role}.subtle`, `text`, `icon.{role}` |\n| Status in a table row | A [label](#labels) |\n| Tooltip, toast | `surface.inverse`, `text.inverse` |\n| Layer behind a dialog or drawer | `surface.scrim` |\n| Loading placeholder | `skeleton`, sheen `skeleton.subtle` |\n| Code block | `code.background`, `code.text` |\n| Brand note | `background.brand.subtle`, `border.brand.subtle` |\n| Disabled control | `background.disabled`, `text.disabled`, `border.disabled` |\n\nNot in the table? Build the name from its four parts (see [Tokens](/foundations/styles/color/tokens/)). If no token exists, ask for one; don't pick the nearest colour.\n\n## Surfaces and backgrounds\n\n**Surfaces are the layers of a screen; backgrounds fill the things on them.**\n\n<ColorDemo kind=\"surfaces\" />\n\n`surface.scrim` goes behind dialogs and drawers only, one layer, at its own opacity.\n\n## Emphasis\n\n<ColorDemo kind=\"emphasis\" />\n\n## Status\n\n**Every status is one of five roles. Pick by what the person needs to do, and always say it in words.**\n\n### Choosing a status\n\n| Role | Use when | HexaSync examples |\n|---|---|---|\n| Info | Something is happening or worth knowing; no action needed. | Syncing, queued, importing |\n| Success | It worked. | Synced, connected, completed |\n| Warning | It works now but needs attention soon. | Partial sync, token expires in 3 days, rate limited |\n| Danger | It failed or is blocked, or the action destroys something. | Failed, disconnected, delete |\n| Neutral | Nothing is happening and nothing is wrong. | Paused, draft, skipped, archived |\n\nWarning is orange, not yellow: yellow is the brand. There is no sixth level; say the difference in words (\"Failed 3 times\").\n\n### Status colours\n\n<ColorDemo kind=\"status\" />\n\n<ColorDemo kind=\"banners\" />\n\n<ColorDemo kind=\"dodont\" item=\"warning\" />\n\n### Labels\n\n<ColorDemo kind=\"labels\" />\n\n| | Label | State label |\n|---|---|---|\n| Looks | Outline in the role's `border`, text in its `text` | Fill in the role's `bold`, text and icon in `text.on-bold` |\n| Size | 20 px, padding 6 px; large 24 px, 8 px | 32 px, padding 12 px |\n| Use | Many per screen: table rows, tags | One per page: the status the page is about |\n\n## Interaction states\n\n**Add `.hover` or `.pressed` to the token at rest; never use opacity or an overlay.**\n\n<ColorDemo kind=\"states\" />\n\n| State | Use |\n|---|---|\n| Hover, pressed | The rest token plus `.hover` or `.pressed` |\n| Selected | `background.selected` and a second cue |\n| Focus | 2 px `border.focus` ring, 2 px away |\n| Disabled | `background.disabled`, `text.disabled`, `border.disabled` |\n\nOn a row or menu item each state sits one step further from the background: hover, then selected, then selected on hover. A hovered row is always lighter than a selected one, so it never looks selected.\n\nMore on [Interaction states](/foundations/styles/interaction-states/).\n\n## Buttons\n\n<ColorDemo kind=\"actions\" />\n",
248
+ "body": "import ColorDemo from '../../../../components/ColorDemo.astro';\n\n**Pick a token by what you are painting and what it means, not by how it looks.**\n\n<ColorDemo kind=\"example\" />\n\n## Find the token\n\n| I need | Use |\n|---|---|\n| Page background | `surface.page` |\n| Card, panel | `surface`, edge `border` |\n| Menu, popover, dialog, drawer | `surface.overlay`; items inside use `surface.overlay.hover`, `.pressed`, `.selected` |\n| Global header and sidebar (same shell surface), mobile navigation drawer, table header, quiet area | `surface.subtle` |\n| Body text, headings, labels | `text` |\n| Descriptions, secondary table columns, navigation | `text.subtle` |\n| Metadata, timestamps, helper text, breadcrumbs | `text.subtlest` |\n| Placeholder | `text.subtlest` |\n| Link | `link`; on hover `link.hover` |\n| Icon next to text | `icon`; less important `icon.subtle` |\n| Divider, card edge | `border` |\n| Edge of an input, checkbox or select | `border.bold` |\n| Keyboard focus ring | `border.focus`, 2 px, 2 px away |\n| Primary button | `background.neutral.bold`, `text.inverse` |\n| Default button | `surface`, `border`, `text`; on hover `background.neutral.subtle.hover` |\n| Destructive button | `background.danger.bold`, `text.on-bold` |\n| Row or menu item on hover | `background.neutral.subtle.hover` |\n| Selected row, tab or menu item | `background.selected` and a second cue |\n| Current page in the navigation | `border.selected` bar, `background.selected`, `aria-current=\"page\"` |\n| Error under a field | `text.danger`, `icon.danger` |\n| Banner for a status | `background.{role}.subtle`, `border.{role}.subtle`, `text`, `icon.{role}` |\n| Status in a table row | A [label](#labels) |\n| Tooltip | `surface.inverse`, `text.inverse` |\n| Toast | `surface.overlay`, `text`, `icon.{role}`, shadow `elevation.shadow.overlay`; no border |\n| Switch | On: `background.neutral.bold`; off: `background.neutral`, edge `border.bold`; knob `surface` |\n| Avatar with initials | `background.neutral`, `text` |\n| Step number, count | `background.neutral.bold`, `text.inverse` |\n| Layer behind a dialog or drawer | `surface.scrim` |\n| Loading placeholder | `skeleton`, sheen `skeleton.subtle` |\n| Code block | `code.background`, `code.text` |\n| Brand note | `background.brand.subtle`, `border.brand.subtle` |\n| Disabled control | `background.disabled`, `text.disabled`, `border.disabled` |\n\nNot in the table? Build the name from its four parts (see [Tokens](/foundations/styles/color/tokens/)). If no token exists, ask for one; don't pick the nearest colour.\n\n## Surfaces and backgrounds\n\n**Surfaces are the layers of a screen; backgrounds fill the things on them.**\n\n<ColorDemo kind=\"surfaces\" />\n\n`surface.scrim` goes behind dialogs and drawers only, one layer, at its own opacity.\n\n## Emphasis\n\n<ColorDemo kind=\"emphasis\" />\n\n## Status\n\n**Every status is one of five roles. Pick by what the person needs to do, and always say it in words.**\n\n### Choosing a status\n\n| Role | Use when | HexaSync examples |\n|---|---|---|\n| Info | Something is happening or worth knowing; no action needed. | Syncing, queued, importing |\n| Success | It worked. | Synced, connected, completed |\n| Warning | It works now but needs attention soon. | Partial sync, token expires in 3 days, rate limited |\n| Danger | It failed or is blocked, or the action destroys something. | Failed, disconnected, delete |\n| Neutral | Nothing is happening and nothing is wrong. | Paused, draft, skipped, archived |\n\nWarning is orange, not yellow: yellow is the brand. There is no sixth level; say the difference in words (\"Failed 3 times\").\n\n### Status colours\n\n<ColorDemo kind=\"status\" />\n\n<ColorDemo kind=\"banners\" />\n\n<ColorDemo kind=\"dodont\" item=\"warning\" />\n\n### Labels\n\n<ColorDemo kind=\"labels\" />\n\n| | Label | State label |\n|---|---|---|\n| Looks | Outline in the role's `border`, text in its `text` | Fill in the role's `bold`, text and icon in `text.on-bold` |\n| Size | 20 px, padding 6 px; large 24 px, 8 px | 32 px, padding 12 px |\n| Use | Many per screen: status in table rows and lists | One per page: the status the page is about |\n\nA tag is not a label. A tag is something people add or remove, such as a filter or a keyword: 24 px high, radius 4 px, `border` and `text`, with a remove button. Labels show a status; people can't remove them.\n\n## Interaction states\n\n**Add `.hover` or `.pressed` to the token at rest; never use opacity or an overlay.**\n\n<ColorDemo kind=\"states\" />\n\n| State | Use |\n|---|---|\n| Hover, pressed | The rest token plus `.hover` or `.pressed` |\n| Selected | `background.selected` and a second cue |\n| Focus | 2 px `border.focus` ring, 2 px away |\n| Disabled | `background.disabled`, `text.disabled`, `border.disabled` |\n\nOn a row or menu item each state sits one step further from the background: hover, then selected, then selected on hover. A hovered row is always lighter than a selected one, so it never looks selected.\n\nMore on [Interaction states](/foundations/styles/interaction-states/).\n\n## Buttons\n\n<ColorDemo kind=\"actions\" />\n",
249
+ "raw": "---\ntitle: Usage\ndescription: Which token to use for each part of a screen, how status, emphasis and states are coloured, and what not to do.\norder: 2\n---\nimport ColorDemo from '../../../../components/ColorDemo.astro';\n\n**Pick a token by what you are painting and what it means, not by how it looks.**\n\n<ColorDemo kind=\"example\" />\n\n## Find the token\n\n| I need | Use |\n|---|---|\n| Page background | `surface.page` |\n| Card, panel | `surface`, edge `border` |\n| Menu, popover, dialog, drawer | `surface.overlay`; items inside use `surface.overlay.hover`, `.pressed`, `.selected` |\n| Global header and sidebar (same shell surface), mobile navigation drawer, table header, quiet area | `surface.subtle` |\n| Body text, headings, labels | `text` |\n| Descriptions, secondary table columns, navigation | `text.subtle` |\n| Metadata, timestamps, helper text, breadcrumbs | `text.subtlest` |\n| Placeholder | `text.subtlest` |\n| Link | `link`; on hover `link.hover` |\n| Icon next to text | `icon`; less important `icon.subtle` |\n| Divider, card edge | `border` |\n| Edge of an input, checkbox or select | `border.bold` |\n| Keyboard focus ring | `border.focus`, 2 px, 2 px away |\n| Primary button | `background.neutral.bold`, `text.inverse` |\n| Default button | `surface`, `border`, `text`; on hover `background.neutral.subtle.hover` |\n| Destructive button | `background.danger.bold`, `text.on-bold` |\n| Row or menu item on hover | `background.neutral.subtle.hover` |\n| Selected row, tab or menu item | `background.selected` and a second cue |\n| Current page in the navigation | `border.selected` bar, `background.selected`, `aria-current=\"page\"` |\n| Error under a field | `text.danger`, `icon.danger` |\n| Banner for a status | `background.{role}.subtle`, `border.{role}.subtle`, `text`, `icon.{role}` |\n| Status in a table row | A [label](#labels) |\n| Tooltip | `surface.inverse`, `text.inverse` |\n| Toast | `surface.overlay`, `text`, `icon.{role}`, shadow `elevation.shadow.overlay`; no border |\n| Switch | On: `background.neutral.bold`; off: `background.neutral`, edge `border.bold`; knob `surface` |\n| Avatar with initials | `background.neutral`, `text` |\n| Step number, count | `background.neutral.bold`, `text.inverse` |\n| Layer behind a dialog or drawer | `surface.scrim` |\n| Loading placeholder | `skeleton`, sheen `skeleton.subtle` |\n| Code block | `code.background`, `code.text` |\n| Brand note | `background.brand.subtle`, `border.brand.subtle` |\n| Disabled control | `background.disabled`, `text.disabled`, `border.disabled` |\n\nNot in the table? Build the name from its four parts (see [Tokens](/foundations/styles/color/tokens/)). If no token exists, ask for one; don't pick the nearest colour.\n\n## Surfaces and backgrounds\n\n**Surfaces are the layers of a screen; backgrounds fill the things on them.**\n\n<ColorDemo kind=\"surfaces\" />\n\n`surface.scrim` goes behind dialogs and drawers only, one layer, at its own opacity.\n\n## Emphasis\n\n<ColorDemo kind=\"emphasis\" />\n\n## Status\n\n**Every status is one of five roles. Pick by what the person needs to do, and always say it in words.**\n\n### Choosing a status\n\n| Role | Use when | HexaSync examples |\n|---|---|---|\n| Info | Something is happening or worth knowing; no action needed. | Syncing, queued, importing |\n| Success | It worked. | Synced, connected, completed |\n| Warning | It works now but needs attention soon. | Partial sync, token expires in 3 days, rate limited |\n| Danger | It failed or is blocked, or the action destroys something. | Failed, disconnected, delete |\n| Neutral | Nothing is happening and nothing is wrong. | Paused, draft, skipped, archived |\n\nWarning is orange, not yellow: yellow is the brand. There is no sixth level; say the difference in words (\"Failed 3 times\").\n\n### Status colours\n\n<ColorDemo kind=\"status\" />\n\n<ColorDemo kind=\"banners\" />\n\n<ColorDemo kind=\"dodont\" item=\"warning\" />\n\n### Labels\n\n<ColorDemo kind=\"labels\" />\n\n| | Label | State label |\n|---|---|---|\n| Looks | Outline in the role's `border`, text in its `text` | Fill in the role's `bold`, text and icon in `text.on-bold` |\n| Size | 20 px, padding 6 px; large 24 px, 8 px | 32 px, padding 12 px |\n| Use | Many per screen: status in table rows and lists | One per page: the status the page is about |\n\nA tag is not a label. A tag is something people add or remove, such as a filter or a keyword: 24 px high, radius 4 px, `border` and `text`, with a remove button. Labels show a status; people can't remove them.\n\n## Interaction states\n\n**Add `.hover` or `.pressed` to the token at rest; never use opacity or an overlay.**\n\n<ColorDemo kind=\"states\" />\n\n| State | Use |\n|---|---|\n| Hover, pressed | The rest token plus `.hover` or `.pressed` |\n| Selected | `background.selected` and a second cue |\n| Focus | 2 px `border.focus` ring, 2 px away |\n| Disabled | `background.disabled`, `text.disabled`, `border.disabled` |\n\nOn a row or menu item each state sits one step further from the background: hover, then selected, then selected on hover. A hovered row is always lighter than a selected one, so it never looks selected.\n\nMore on [Interaction states](/foundations/styles/interaction-states/).\n\n## Buttons\n\n<ColorDemo kind=\"actions\" />\n",
250
250
  "frontmatter": {
251
251
  "title": "Usage",
252
252
  "description": "Which token to use for each part of a screen, how status, emphasis and states are coloured, and what not to do.",
@@ -260,28 +260,15 @@ export const catalog = [
260
260
  "locale": "en",
261
261
  "kind": "guidance",
262
262
  "title": "Data visualization",
263
- "status": "planned",
263
+ "status": "active",
264
264
  "releasePhase": null,
265
- "planned": [
266
- "A chart palette for series, with contrast in light and dark",
267
- "Status colours in charts",
268
- "Chart types and when to use each",
269
- "Axis, legend, tooltip and number formats",
270
- "Accessible charts: not by colour alone, text alternatives"
271
- ],
272
- "body": "",
273
- "raw": "---\ntitle: \"Data visualization\"\ndescription: \"Colours, type and rules for charts, KPI tiles and other data displays.\"\norder: 13\nplanned:\n - \"A chart palette for series, with contrast in light and dark\"\n - \"Status colours in charts\"\n - \"Chart types and when to use each\"\n - \"Axis, legend, tooltip and number formats\"\n - \"Accessible charts: not by colour alone, text alternatives\"\n---\n",
265
+ "planned": [],
266
+ "body": "\n## Choose by the question\n\nUse a line chart for a value over time, a compact sparkline only beside its current\nvalue, a proportional bar for parts of a stated total, and a timeline for when\nexecutions happened. A health ring must also show its numeric score and a named\nassessment. Do not use decorative area fills, gradients, glass or pulsing failures.\n\n## Metrics, categories and status are different\n\n`visualization.metric.*` defines named operational series: total jobs, completed,\nfailed, success rate, active jobs, average execution time and queue depth. Volume\nand duration alone are not warnings. Keep units, thresholds and metric names visible.\n\n`visualization.job-type.*` defines queue-status, sync-history, polling-jobs and\ngeneric-jobs as categorical identities, never as success/warning/failure. Their\nfoundation colour aliases adapt in light and dark. Always pair colour with the\njob-type name or distinct glyph. In combined timeline mode, the outer mark encodes\njob type and the inner mark encodes status; explain both in the legend. In status\nmode, use `color.text.success`, `danger`, `info`, `warning` or neutral text by the\nactual state. Preserve visible status labels and outcome icons.\n\n`visualization.priority.1` through `.5` encode ranked queue urgency, always labelled\nP1–P5. Priority is not an execution outcome. P1 is highest; P5 is lowest. Do not\nreuse a priority colour to claim success or failure.\n\n## Geometry and typography\n\nUse `visualization.line-width`, `sparkline-width`, `grid-width`, `point-radius`\nand `hover-point-radius` for SVG series and markers. Strokes are CSS pixel\ndimensions; use a measured viewBox or non-scaling strokes to avoid distortion.\n`timeline-track-height` and `activity-track-height` set compact proportional tracks.\n`ring-size` is a CSS dimension; `ring-width` is the Ant Design percent-based stroke\nAPI, and `ring-gap` is degrees. Convert dimensions only at numeric API boundaries.\nData coordinates and measured container sizes remain data, not design tokens.\n\n`timeline-node-size` and `timeline-node-inner-size` define the outer categorical and\ninner status marks. Their `touch` and `tablet` variants preserve legibility without\nchanging the encoding. `timeline-cluster-size` sets an aggregate count mark; paint\nits boundary with the category/status role and keep its count in normal text on a\nnormal surface, never white on a theme-adapted bright mark. Use `size.target.touch`\nfor the interactive footprint, independent of the visible mark.\n`chart-height`, `chart-initial-width`, `sparkline-height`,\n`sparkline-compact-height` and `sparkline-initial-width` define plotting viewports;\ninitial widths are replaced by measured widths. `sparkline-point-radius` is the\ncompact endpoint radius. These are not data scales or axis values.\n\nUse `font.heading.large` with tabular figures for KPI values, `font.body.small` for\nmetadata, axes and tooltip copy, and `font.label.small` for legend labels.\nUse `color.border` for decorative grids, `color.text.subtle` for labels and the\nsurface/inverse text pair for tooltips. A meaningful data mark needs at least 3:1\nagainst its actual surface; normal text needs 4.5:1. Check actual theme pairs rather\nthan assuming an alias proves rendered contrast.\n\n## Labels, formats and interaction\n\nKeep locale-aware number, timestamp and duration formatting consistent with the\nadjacent table. Include units and time range; preserve timezone context. Never\nsilently turn a count into a rate or truncate a duration. Legends must name every\nshown series; a selected series needs an indicator other than colour. Tooltips\nmust stay inside the chart container and must not be the only way to read values.\nProvide an adjacent numeric summary or table for the same data and an accessible\nchart name. Keyboard-operable legend controls retain visible focus.\n\n## Traffic assessment bands\n\n`visualization.traffic.{healthy,attention,degraded,critical,unavailable,fault}.{fill,outline}`\nprovides paired band paints. Healthy means accepted traffic; attention, degraded and\ncritical describe increasing rejected-request ratio thresholds. State the thresholds\nin labels or tooltips. Attention and degraded share warning colours: use a distinct\ndash pattern and explicit labels, not colour alone. Unavailable means no requests\nto assess. Fault means internal/backend request-processing errors, not a ratio band;\nshow a separate fault count, explicit label/icon and cross-hatching. Fetch failures remain errors, not a band. Never turn missing\ndata into zero or a healthy result. Use normal `color.text` for text on subtle fills.\n",
267
+ "raw": "---\ntitle: \"Data visualization\"\ndescription: \"Colours, type and rules for charts, KPI tiles and other data displays.\"\norder: 13\n---\n\n## Choose by the question\n\nUse a line chart for a value over time, a compact sparkline only beside its current\nvalue, a proportional bar for parts of a stated total, and a timeline for when\nexecutions happened. A health ring must also show its numeric score and a named\nassessment. Do not use decorative area fills, gradients, glass or pulsing failures.\n\n## Metrics, categories and status are different\n\n`visualization.metric.*` defines named operational series: total jobs, completed,\nfailed, success rate, active jobs, average execution time and queue depth. Volume\nand duration alone are not warnings. Keep units, thresholds and metric names visible.\n\n`visualization.job-type.*` defines queue-status, sync-history, polling-jobs and\ngeneric-jobs as categorical identities, never as success/warning/failure. Their\nfoundation colour aliases adapt in light and dark. Always pair colour with the\njob-type name or distinct glyph. In combined timeline mode, the outer mark encodes\njob type and the inner mark encodes status; explain both in the legend. In status\nmode, use `color.text.success`, `danger`, `info`, `warning` or neutral text by the\nactual state. Preserve visible status labels and outcome icons.\n\n`visualization.priority.1` through `.5` encode ranked queue urgency, always labelled\nP1–P5. Priority is not an execution outcome. P1 is highest; P5 is lowest. Do not\nreuse a priority colour to claim success or failure.\n\n## Geometry and typography\n\nUse `visualization.line-width`, `sparkline-width`, `grid-width`, `point-radius`\nand `hover-point-radius` for SVG series and markers. Strokes are CSS pixel\ndimensions; use a measured viewBox or non-scaling strokes to avoid distortion.\n`timeline-track-height` and `activity-track-height` set compact proportional tracks.\n`ring-size` is a CSS dimension; `ring-width` is the Ant Design percent-based stroke\nAPI, and `ring-gap` is degrees. Convert dimensions only at numeric API boundaries.\nData coordinates and measured container sizes remain data, not design tokens.\n\n`timeline-node-size` and `timeline-node-inner-size` define the outer categorical and\ninner status marks. Their `touch` and `tablet` variants preserve legibility without\nchanging the encoding. `timeline-cluster-size` sets an aggregate count mark; paint\nits boundary with the category/status role and keep its count in normal text on a\nnormal surface, never white on a theme-adapted bright mark. Use `size.target.touch`\nfor the interactive footprint, independent of the visible mark.\n`chart-height`, `chart-initial-width`, `sparkline-height`,\n`sparkline-compact-height` and `sparkline-initial-width` define plotting viewports;\ninitial widths are replaced by measured widths. `sparkline-point-radius` is the\ncompact endpoint radius. These are not data scales or axis values.\n\nUse `font.heading.large` with tabular figures for KPI values, `font.body.small` for\nmetadata, axes and tooltip copy, and `font.label.small` for legend labels.\nUse `color.border` for decorative grids, `color.text.subtle` for labels and the\nsurface/inverse text pair for tooltips. A meaningful data mark needs at least 3:1\nagainst its actual surface; normal text needs 4.5:1. Check actual theme pairs rather\nthan assuming an alias proves rendered contrast.\n\n## Labels, formats and interaction\n\nKeep locale-aware number, timestamp and duration formatting consistent with the\nadjacent table. Include units and time range; preserve timezone context. Never\nsilently turn a count into a rate or truncate a duration. Legends must name every\nshown series; a selected series needs an indicator other than colour. Tooltips\nmust stay inside the chart container and must not be the only way to read values.\nProvide an adjacent numeric summary or table for the same data and an accessible\nchart name. Keyboard-operable legend controls retain visible focus.\n\n## Traffic assessment bands\n\n`visualization.traffic.{healthy,attention,degraded,critical,unavailable,fault}.{fill,outline}`\nprovides paired band paints. Healthy means accepted traffic; attention, degraded and\ncritical describe increasing rejected-request ratio thresholds. State the thresholds\nin labels or tooltips. Attention and degraded share warning colours: use a distinct\ndash pattern and explicit labels, not colour alone. Unavailable means no requests\nto assess. Fault means internal/backend request-processing errors, not a ratio band;\nshow a separate fault count, explicit label/icon and cross-hatching. Fetch failures remain errors, not a band. Never turn missing\ndata into zero or a healthy result. Use normal `color.text` for text on subtle fills.\n",
274
268
  "frontmatter": {
275
269
  "title": "Data visualization",
276
270
  "description": "Colours, type and rules for charts, KPI tiles and other data displays.",
277
- "order": 13,
278
- "planned": [
279
- "A chart palette for series, with contrast in light and dark",
280
- "Status colours in charts",
281
- "Chart types and when to use each",
282
- "Axis, legend, tooltip and number formats",
283
- "Accessible charts: not by colour alone, text alternatives"
284
- ]
271
+ "order": 13
285
272
  }
286
273
  },
287
274
  {
@@ -294,11 +281,11 @@ export const catalog = [
294
281
  "status": "active",
295
282
  "releasePhase": null,
296
283
  "planned": [],
297
- "body": "import TokenTable from '../../../components/TokenTable.astro';\n\n- `elevation.shadow.raised`: cards that sit on the page.\n- `elevation.shadow.overlay`: dropdowns, popovers and dialogs that float above content.\n\n## Tokens\n<TokenTable prefix=\"elevation\" />\n",
298
- "raw": "---\ntitle: Elevation\ndescription: Shadows that show which surfaces sit above others.\norder: 8\n---\nimport TokenTable from '../../../components/TokenTable.astro';\n\n- `elevation.shadow.raised`: cards that sit on the page.\n- `elevation.shadow.overlay`: dropdowns, popovers and dialogs that float above content.\n\n## Tokens\n<TokenTable prefix=\"elevation\" />\n",
284
+ "body": "import ElevationDemo from '../../../components/ElevationDemo.astro';\nimport TokenTable from '../../../components/TokenTable.astro';\n\nElevation is the distance a surface seems to have from the page, shown with a shadow and, in dark mode, a lighter background. It tells people what stands apart from the page, what is temporary, and what needs attention first.\n\n<ElevationDemo kind=\"hero\" />\n\n## How it works\n\n- **Each level is a pair: a background and a shadow.** Use the two tokens of a level together.\n- **The further from the page, the larger and softer the shadow.** A card has a faint shadow; a dialog a deep one.\n- **Three levels only.** If everything floats, nothing stands out.\n\nElevation shows how high a surface looks. [Z-index](/foundations/styles/z-index/) decides which surface is drawn on top.\n\n| Level | Background | Shadow | Use for |\n|---|---|---|---|\n| Page | `color.surface.page`, `color.surface.subtle` | none | The page, panels, tables, side navigation, headers |\n| Raised | `color.surface` | `elevation.shadow.raised` | Cards |\n| Overlay | `color.surface.overlay` | `elevation.shadow.overlay` | Menus, select lists, popovers, date pickers, toasts |\n| Modal | `color.surface.overlay` | `elevation.shadow.modal` | Dialogs, drawers, full sheets |\n\n## Page\n\nMost of the screen sits on the page with no shadow. Separate panels and tables with a `color.border` border. Side navigation and table headers use `color.surface.subtle`.\n\n<ElevationDemo kind=\"level\" item=\"page\" />\n\n## Raised\n\nFor one item people treat as a unit: a sync job, a connection, a dashboard widget. Cards keep their border, because a faint shadow can disappear on a bright screen or in high-contrast mode.\n\n<ElevationDemo kind=\"level\" item=\"raised\" />\n\n## Overlay\n\nFor things that open from a control and close again: menus, select lists, popovers. Toasts use the same surface and shadow.\n\n<ElevationDemo kind=\"level\" item=\"overlay\" />\n\n## Modal\n\nFor dialogs and drawers that block the page until people finish or cancel. A modal always sits on `color.surface.scrim`, which dims the page and shows it is unavailable.\n\n<ElevationDemo kind=\"level\" item=\"modal\" />\n\n## Dark mode\n\n**The higher the surface, the lighter it is.** A dark shadow barely shows on a dark page, so each level also gets a lighter background: page graphite 1, cards graphite 2, menus and dialogs graphite 3. The token names are the same in both themes.\n\n<ElevationDemo kind=\"dark\" />\n\n## Inside menus and dialogs\n\nRows inside a floating surface use the overlay state colours, such as `color.surface.overlay.hover`. The page's hover colour would match the menu background in dark mode and disappear. Mark a selected row with a check, not colour alone.\n\n<ElevationDemo kind=\"states\" />\n\n## Do and don’t\n\n<ElevationDemo kind=\"dodont\" item=\"pair\" />\n<ElevationDemo kind=\"dodont\" item=\"flat\" />\n<ElevationDemo kind=\"dodont\" item=\"own\" />\n<ElevationDemo kind=\"dodont\" item=\"border\" />\n\n## Tokens\n\n<TokenTable prefix=\"elevation\" />\n\n<TokenTable prefix=\"color.surface.overlay\" />\n",
285
+ "raw": "---\ntitle: Elevation\ndescription: \"How far a surface seems to sit above the page. It sets items apart, marks what is temporary and points attention at what matters now.\"\norder: 8\n---\nimport ElevationDemo from '../../../components/ElevationDemo.astro';\nimport TokenTable from '../../../components/TokenTable.astro';\n\nElevation is the distance a surface seems to have from the page, shown with a shadow and, in dark mode, a lighter background. It tells people what stands apart from the page, what is temporary, and what needs attention first.\n\n<ElevationDemo kind=\"hero\" />\n\n## How it works\n\n- **Each level is a pair: a background and a shadow.** Use the two tokens of a level together.\n- **The further from the page, the larger and softer the shadow.** A card has a faint shadow; a dialog a deep one.\n- **Three levels only.** If everything floats, nothing stands out.\n\nElevation shows how high a surface looks. [Z-index](/foundations/styles/z-index/) decides which surface is drawn on top.\n\n| Level | Background | Shadow | Use for |\n|---|---|---|---|\n| Page | `color.surface.page`, `color.surface.subtle` | none | The page, panels, tables, side navigation, headers |\n| Raised | `color.surface` | `elevation.shadow.raised` | Cards |\n| Overlay | `color.surface.overlay` | `elevation.shadow.overlay` | Menus, select lists, popovers, date pickers, toasts |\n| Modal | `color.surface.overlay` | `elevation.shadow.modal` | Dialogs, drawers, full sheets |\n\n## Page\n\nMost of the screen sits on the page with no shadow. Separate panels and tables with a `color.border` border. Side navigation and table headers use `color.surface.subtle`.\n\n<ElevationDemo kind=\"level\" item=\"page\" />\n\n## Raised\n\nFor one item people treat as a unit: a sync job, a connection, a dashboard widget. Cards keep their border, because a faint shadow can disappear on a bright screen or in high-contrast mode.\n\n<ElevationDemo kind=\"level\" item=\"raised\" />\n\n## Overlay\n\nFor things that open from a control and close again: menus, select lists, popovers. Toasts use the same surface and shadow.\n\n<ElevationDemo kind=\"level\" item=\"overlay\" />\n\n## Modal\n\nFor dialogs and drawers that block the page until people finish or cancel. A modal always sits on `color.surface.scrim`, which dims the page and shows it is unavailable.\n\n<ElevationDemo kind=\"level\" item=\"modal\" />\n\n## Dark mode\n\n**The higher the surface, the lighter it is.** A dark shadow barely shows on a dark page, so each level also gets a lighter background: page graphite 1, cards graphite 2, menus and dialogs graphite 3. The token names are the same in both themes.\n\n<ElevationDemo kind=\"dark\" />\n\n## Inside menus and dialogs\n\nRows inside a floating surface use the overlay state colours, such as `color.surface.overlay.hover`. The page's hover colour would match the menu background in dark mode and disappear. Mark a selected row with a check, not colour alone.\n\n<ElevationDemo kind=\"states\" />\n\n## Do and don’t\n\n<ElevationDemo kind=\"dodont\" item=\"pair\" />\n<ElevationDemo kind=\"dodont\" item=\"flat\" />\n<ElevationDemo kind=\"dodont\" item=\"own\" />\n<ElevationDemo kind=\"dodont\" item=\"border\" />\n\n## Tokens\n\n<TokenTable prefix=\"elevation\" />\n\n<TokenTable prefix=\"color.surface.overlay\" />\n",
299
286
  "frontmatter": {
300
287
  "title": "Elevation",
301
- "description": "Shadows that show which surfaces sit above others.",
288
+ "description": "How far a surface seems to sit above the page. It sets items apart, marks what is temporary and points attention at what matters now.",
302
289
  "order": 8
303
290
  }
304
291
  },
@@ -385,8 +372,8 @@ export const catalog = [
385
372
  "status": "active",
386
373
  "releasePhase": null,
387
374
  "planned": [],
388
- "body": "import IconDemo from '../../../../components/IconDemo.astro';\nimport ColorDemo from '../../../../components/ColorDemo.astro';\n\n**Use 16 px icons in the colour of the text, with a label, and the same icon for the same meaning everywhere.**\n\n## Sizes\n\n**Pick the size from the text next to the icon.**\n\n| Size | Use it for |\n|---|---|\n| 16 px | Default. Buttons, menus, tables, form fields, next to 14 px text. |\n| 20 px | Next to 16 px text, in toolbars and in the page header. |\n| 24 px | An icon on its own, such as a status in a card or a small empty state. |\n| 32 px | Empty states only. |\n\nDon’t use other sizes. Don’t scale an icon to fit a box: change the box.\n\n<IconDemo kind=\"dodont\" item=\"size\" />\n\n## Stroke\n\n**Keep Lucide’s stroke.** It is 2 units on the 24 grid and scales with the icon: 1.33 px at 16, 1.67 px at 20, 2 px at 24. Don’t set `stroke-width` or `absoluteStrokeWidth`. A fixed 2 px stroke fills in the small details of a 16 px icon.\n\n<IconDemo kind=\"dodont\" item=\"stroke\" />\n\n## Colour\n\n**An icon takes the colour of its text.** Icons draw with `currentColor`, so an icon in a button or a link is right without extra code. Set a colour only with a `color.icon.*` token:\n\n<ColorDemo kind=\"roles\" group=\"icon\" />\n\n- Status icons use the status token, such as `icon.danger`, and always sit next to the status in words.\n- Never give an icon a colour to decorate it, and never use the brand yellow for an icon.\n\n<IconDemo kind=\"dodont\" item=\"colour\" />\n\n## Alignment with text\n\n**Centre the icon on the line height of the text.** Use `display: flex; align-items: center`. Next to several lines, centre the icon on the first line.\n\n<IconDemo kind=\"align\" />\n\n<IconDemo kind=\"dodont\" item=\"align\" />\n\n## Spacing\n\n**The gap between an icon and its text follows the text size: 4 px next to 14 px text or smaller, 8 px next to 16 px text or larger.**\n\n| Text | Icon | Gap | Token | Where |\n|---|---|---|---|---|\n| 12 or 14 px | 16 px | 4 px | `space.050` | Small and default controls, menus, tabs, table cells |\n| 16 px or larger | 20 or 24 px | 8 px | `space.100` | Large controls, toolbars, the page header, a status in a card |\n\nSet the gap on the control with `gap`, not with a margin on the icon.\n\n<IconDemo kind=\"spacing\" />\n\n## Icon and label\n\n**Give an icon a label by default.** The label says what happens; the icon helps people find it again.\n\nUse an icon on its own only when all three are true:\n\n- The action is well known: close, search, add, edit, delete, copy, refresh, settings, filter, more, menu.\n- Space is tight, such as a table row or a toolbar.\n- The button has a name (`aria-label`) and a tooltip with the same words. See [Accessibility](/foundations/styles/icons/accessibility/).\n\n<IconDemo kind=\"dodont\" item=\"label\" />\n\n## Selected state\n\n**Lucide icons are outline only.** Show a selected item with `background.selected` and the indicator bar, not by filling the icon.\n\n<IconDemo kind=\"dodont\" item=\"selected\" />\n\n## Common actions\n\n**One icon per meaning.** Use this icon whenever you show one of these actions or objects, in every product. If a meaning is missing, ask before you choose one, so it is added here.\n\n<IconDemo kind=\"actions\" />\n\n<IconDemo kind=\"dodont\" item=\"meaning\" />\n\n## Do and don’t\n\n| Do | Don’t |\n|---|---|\n| Use 16, 20, 24 or 32 px. | Scale icons to other sizes. |\n| Keep the icon in the text colour. | Colour icons to decorate. |\n| Add a label to most icons. | Use an unfamiliar icon on its own. |\n| Use the same icon for the same meaning. | Use a different icon in each product. |\n| Use outline icons with a selected background. | Fill an icon to show it is selected. |\n| Write the status next to a status icon. | Let an icon or its colour carry the status alone. |\n| Use one icon per button. | Combine two icons into one action. |\n",
389
- "raw": "---\ntitle: Usage\ndescription: Which size to use, how stroke, colour and alignment work next to text, when an icon needs a label, and the one icon for each common Beehexa action.\norder: 2\n---\nimport IconDemo from '../../../../components/IconDemo.astro';\nimport ColorDemo from '../../../../components/ColorDemo.astro';\n\n**Use 16 px icons in the colour of the text, with a label, and the same icon for the same meaning everywhere.**\n\n## Sizes\n\n**Pick the size from the text next to the icon.**\n\n| Size | Use it for |\n|---|---|\n| 16 px | Default. Buttons, menus, tables, form fields, next to 14 px text. |\n| 20 px | Next to 16 px text, in toolbars and in the page header. |\n| 24 px | An icon on its own, such as a status in a card or a small empty state. |\n| 32 px | Empty states only. |\n\nDon’t use other sizes. Don’t scale an icon to fit a box: change the box.\n\n<IconDemo kind=\"dodont\" item=\"size\" />\n\n## Stroke\n\n**Keep Lucide’s stroke.** It is 2 units on the 24 grid and scales with the icon: 1.33 px at 16, 1.67 px at 20, 2 px at 24. Don’t set `stroke-width` or `absoluteStrokeWidth`. A fixed 2 px stroke fills in the small details of a 16 px icon.\n\n<IconDemo kind=\"dodont\" item=\"stroke\" />\n\n## Colour\n\n**An icon takes the colour of its text.** Icons draw with `currentColor`, so an icon in a button or a link is right without extra code. Set a colour only with a `color.icon.*` token:\n\n<ColorDemo kind=\"roles\" group=\"icon\" />\n\n- Status icons use the status token, such as `icon.danger`, and always sit next to the status in words.\n- Never give an icon a colour to decorate it, and never use the brand yellow for an icon.\n\n<IconDemo kind=\"dodont\" item=\"colour\" />\n\n## Alignment with text\n\n**Centre the icon on the line height of the text.** Use `display: flex; align-items: center`. Next to several lines, centre the icon on the first line.\n\n<IconDemo kind=\"align\" />\n\n<IconDemo kind=\"dodont\" item=\"align\" />\n\n## Spacing\n\n**The gap between an icon and its text follows the text size: 4 px next to 14 px text or smaller, 8 px next to 16 px text or larger.**\n\n| Text | Icon | Gap | Token | Where |\n|---|---|---|---|---|\n| 12 or 14 px | 16 px | 4 px | `space.050` | Small and default controls, menus, tabs, table cells |\n| 16 px or larger | 20 or 24 px | 8 px | `space.100` | Large controls, toolbars, the page header, a status in a card |\n\nSet the gap on the control with `gap`, not with a margin on the icon.\n\n<IconDemo kind=\"spacing\" />\n\n## Icon and label\n\n**Give an icon a label by default.** The label says what happens; the icon helps people find it again.\n\nUse an icon on its own only when all three are true:\n\n- The action is well known: close, search, add, edit, delete, copy, refresh, settings, filter, more, menu.\n- Space is tight, such as a table row or a toolbar.\n- The button has a name (`aria-label`) and a tooltip with the same words. See [Accessibility](/foundations/styles/icons/accessibility/).\n\n<IconDemo kind=\"dodont\" item=\"label\" />\n\n## Selected state\n\n**Lucide icons are outline only.** Show a selected item with `background.selected` and the indicator bar, not by filling the icon.\n\n<IconDemo kind=\"dodont\" item=\"selected\" />\n\n## Common actions\n\n**One icon per meaning.** Use this icon whenever you show one of these actions or objects, in every product. If a meaning is missing, ask before you choose one, so it is added here.\n\n<IconDemo kind=\"actions\" />\n\n<IconDemo kind=\"dodont\" item=\"meaning\" />\n\n## Do and don’t\n\n| Do | Don’t |\n|---|---|\n| Use 16, 20, 24 or 32 px. | Scale icons to other sizes. |\n| Keep the icon in the text colour. | Colour icons to decorate. |\n| Add a label to most icons. | Use an unfamiliar icon on its own. |\n| Use the same icon for the same meaning. | Use a different icon in each product. |\n| Use outline icons with a selected background. | Fill an icon to show it is selected. |\n| Write the status next to a status icon. | Let an icon or its colour carry the status alone. |\n| Use one icon per button. | Combine two icons into one action. |\n",
375
+ "body": "import IconDemo from '../../../../components/IconDemo.astro';\nimport ColorDemo from '../../../../components/ColorDemo.astro';\n\n**Use 16 px icons in the colour of the text, with a label, and the same icon for the same meaning everywhere.**\n\n## Sizes\n\n**Pick the size from the text next to the icon.**\n\n| Size | Token | Use it for |\n|---|---|---|\n| 16 px | `size.icon.default` | Default. Buttons, menus, tables, form fields, next to 14 px text. |\n| 20 px | `size.icon.medium` | Next to 16 px text, in toolbars and in the page header. |\n| 24 px | `size.icon.large` | An icon on its own, such as a status in a card or a small empty state. |\n| 32 px | `size.icon.empty` | Empty states only. |\n\nDon’t use other sizes. Don’t scale an icon to fit a box: change the box.\n\nBind these roles through CSS variables or convert them at numeric icon APIs;\nthe documented pixel sizes are not separate consumer constants.\n\n<IconDemo kind=\"dodont\" item=\"size\" />\n\n## Stroke\n\n**Keep Lucide’s stroke.** It is 2 units on the 24 grid and scales with the icon: 1.33 px at 16, 1.67 px at 20, 2 px at 24. Don’t set `stroke-width` or `absoluteStrokeWidth`. A fixed 2 px stroke fills in the small details of a 16 px icon.\n\n<IconDemo kind=\"dodont\" item=\"stroke\" />\n\n## Colour\n\n**An icon takes the colour of its text.** Icons draw with `currentColor`, so an icon in a button or a link is right without extra code. Set a colour only with a `color.icon.*` token:\n\n<ColorDemo kind=\"roles\" group=\"icon\" />\n\n- Status icons use the status token, such as `icon.danger`, and always sit next to the status in words.\n- Never give an icon a colour to decorate it, and never use the brand yellow for an icon.\n\n<IconDemo kind=\"dodont\" item=\"colour\" />\n\n## Alignment with text\n\n**Centre the icon on the line height of the text.** Use `display: flex; align-items: center`. Next to several lines, centre the icon on the first line.\n\n<IconDemo kind=\"align\" />\n\n<IconDemo kind=\"dodont\" item=\"align\" />\n\n## Spacing\n\n**The gap between an icon and its text follows the text size: 4 px next to 14 px text or smaller, 8 px next to 16 px text or larger.**\n\n| Text | Icon | Gap | Token | Where |\n|---|---|---|---|---|\n| 12 or 14 px | 16 px | 4 px | `space.050` | Small and default controls, menus, tabs, table cells |\n| 16 px or larger | 20 or 24 px | 8 px | `space.100` | Large controls, toolbars, the page header, a status in a card |\n\nSet the gap on the control with `gap`, not with a margin on the icon.\n\n<IconDemo kind=\"spacing\" />\n\n## Icon and label\n\n**Give an icon a label by default.** The label says what happens; the icon helps people find it again.\n\nUse an icon on its own only when all three are true:\n\n- The action is well known: close, search, add, edit, delete, copy, refresh, settings, filter, more, menu.\n- Space is tight, such as a table row or a toolbar.\n- The button has a name (`aria-label`) and a tooltip with the same words. See [Accessibility](/foundations/styles/icons/accessibility/).\n\n<IconDemo kind=\"dodont\" item=\"label\" />\n\n## Selected state\n\n**Lucide icons are outline only.** Show a selected item with `background.selected` and the indicator bar, not by filling the icon.\n\n<IconDemo kind=\"dodont\" item=\"selected\" />\n\n## Common actions\n\n**One icon per meaning.** Use this icon whenever you show one of these actions or objects, in every product. If a meaning is missing, ask before you choose one, so it is added here.\n\n<IconDemo kind=\"actions\" />\n\n<IconDemo kind=\"dodont\" item=\"meaning\" />\n\n## Do and don’t\n\n| Do | Don’t |\n|---|---|\n| Use 16, 20, 24 or 32 px. | Scale icons to other sizes. |\n| Keep the icon in the text colour. | Colour icons to decorate. |\n| Add a label to most icons. | Use an unfamiliar icon on its own. |\n| Use the same icon for the same meaning. | Use a different icon in each product. |\n| Use outline icons with a selected background. | Fill an icon to show it is selected. |\n| Write the status next to a status icon. | Let an icon or its colour carry the status alone. |\n| Use one icon per button. | Combine two icons into one action. |\n",
376
+ "raw": "---\ntitle: Usage\ndescription: Which size to use, how stroke, colour and alignment work next to text, when an icon needs a label, and the one icon for each common Beehexa action.\norder: 2\n---\nimport IconDemo from '../../../../components/IconDemo.astro';\nimport ColorDemo from '../../../../components/ColorDemo.astro';\n\n**Use 16 px icons in the colour of the text, with a label, and the same icon for the same meaning everywhere.**\n\n## Sizes\n\n**Pick the size from the text next to the icon.**\n\n| Size | Token | Use it for |\n|---|---|---|\n| 16 px | `size.icon.default` | Default. Buttons, menus, tables, form fields, next to 14 px text. |\n| 20 px | `size.icon.medium` | Next to 16 px text, in toolbars and in the page header. |\n| 24 px | `size.icon.large` | An icon on its own, such as a status in a card or a small empty state. |\n| 32 px | `size.icon.empty` | Empty states only. |\n\nDon’t use other sizes. Don’t scale an icon to fit a box: change the box.\n\nBind these roles through CSS variables or convert them at numeric icon APIs;\nthe documented pixel sizes are not separate consumer constants.\n\n<IconDemo kind=\"dodont\" item=\"size\" />\n\n## Stroke\n\n**Keep Lucide’s stroke.** It is 2 units on the 24 grid and scales with the icon: 1.33 px at 16, 1.67 px at 20, 2 px at 24. Don’t set `stroke-width` or `absoluteStrokeWidth`. A fixed 2 px stroke fills in the small details of a 16 px icon.\n\n<IconDemo kind=\"dodont\" item=\"stroke\" />\n\n## Colour\n\n**An icon takes the colour of its text.** Icons draw with `currentColor`, so an icon in a button or a link is right without extra code. Set a colour only with a `color.icon.*` token:\n\n<ColorDemo kind=\"roles\" group=\"icon\" />\n\n- Status icons use the status token, such as `icon.danger`, and always sit next to the status in words.\n- Never give an icon a colour to decorate it, and never use the brand yellow for an icon.\n\n<IconDemo kind=\"dodont\" item=\"colour\" />\n\n## Alignment with text\n\n**Centre the icon on the line height of the text.** Use `display: flex; align-items: center`. Next to several lines, centre the icon on the first line.\n\n<IconDemo kind=\"align\" />\n\n<IconDemo kind=\"dodont\" item=\"align\" />\n\n## Spacing\n\n**The gap between an icon and its text follows the text size: 4 px next to 14 px text or smaller, 8 px next to 16 px text or larger.**\n\n| Text | Icon | Gap | Token | Where |\n|---|---|---|---|---|\n| 12 or 14 px | 16 px | 4 px | `space.050` | Small and default controls, menus, tabs, table cells |\n| 16 px or larger | 20 or 24 px | 8 px | `space.100` | Large controls, toolbars, the page header, a status in a card |\n\nSet the gap on the control with `gap`, not with a margin on the icon.\n\n<IconDemo kind=\"spacing\" />\n\n## Icon and label\n\n**Give an icon a label by default.** The label says what happens; the icon helps people find it again.\n\nUse an icon on its own only when all three are true:\n\n- The action is well known: close, search, add, edit, delete, copy, refresh, settings, filter, more, menu.\n- Space is tight, such as a table row or a toolbar.\n- The button has a name (`aria-label`) and a tooltip with the same words. See [Accessibility](/foundations/styles/icons/accessibility/).\n\n<IconDemo kind=\"dodont\" item=\"label\" />\n\n## Selected state\n\n**Lucide icons are outline only.** Show a selected item with `background.selected` and the indicator bar, not by filling the icon.\n\n<IconDemo kind=\"dodont\" item=\"selected\" />\n\n## Common actions\n\n**One icon per meaning.** Use this icon whenever you show one of these actions or objects, in every product. If a meaning is missing, ask before you choose one, so it is added here.\n\n<IconDemo kind=\"actions\" />\n\n<IconDemo kind=\"dodont\" item=\"meaning\" />\n\n## Do and don’t\n\n| Do | Don’t |\n|---|---|\n| Use 16, 20, 24 or 32 px. | Scale icons to other sizes. |\n| Keep the icon in the text colour. | Colour icons to decorate. |\n| Add a label to most icons. | Use an unfamiliar icon on its own. |\n| Use the same icon for the same meaning. | Use a different icon in each product. |\n| Use outline icons with a selected background. | Fill an icon to show it is selected. |\n| Write the status next to a status icon. | Let an icon or its colour carry the status alone. |\n| Use one icon per button. | Combine two icons into one action. |\n",
390
377
  "frontmatter": {
391
378
  "title": "Usage",
392
379
  "description": "Which size to use, how stroke, colour and alignment work next to text, when an icon needs a label, and the one icon for each common Beehexa action.",
@@ -448,8 +435,8 @@ export const catalog = [
448
435
  "status": "active",
449
436
  "releasePhase": null,
450
437
  "planned": [],
451
- "body": "import LayoutDemo from '../../../../components/LayoutDemo.astro';\n\n**The header, the side navigation and the page header repeat on every page, in the same place and at the same size.**\n\n## Header\n\n**48 px high, across the full width. It holds what belongs to the whole product.**\n\n| Part | Value |\n|---|---|\n| Height | 48 px: a 32 px control with 8 px above and below. The 1 px line under the header is not counted |\n| Holds | Menu button (below 1024 px), logo, global search, workspace switcher, notifications, account |\n| Does not hold | The breadcrumb and page actions. They change with the page, so they go in the page header |\n\nUse the package token `layout.header.height` (`--bh-layout-header-height`) for this dimension.\nThe sidebar widths below are `layout.sidebar.expanded` and `layout.sidebar.collapsed`.\nConvert source units at numeric framework API boundaries instead of copying their values.\n\n## Side navigation\n\n**280 px open, a 64 px rail when collapsed, a drawer below 1024 px. Every Beehexa product uses the same widths.**\n\n| Window | Side navigation |\n|---|---|\n| Below 1024 px | Hidden. The menu button in the header opens it as a drawer over the page. |\n| 1024 px and up | Open at 280 px. People can collapse it to the 64 px rail, and the choice is remembered. |\n\n- **280 px** fits a label of about 31 characters at 14 px, long Vietnamese labels included.\n- **The same width in every product**, so the page starts in the same place when people move between products.\n- **No resizing.** One width keeps products alike. A resizable panel would also need a way to resize it without dragging (WCAG 2.5.7).\n- **The rail** shows icons only. Each label appears in a tooltip.\n\n### Long labels\n\n<LayoutDemo kind=\"navlabels\" />\n\n1. Write a shorter label first.\n2. If it still does not fit, cut it with an ellipsis and show the full label in a tooltip, only when it is cut.\n3. Never widen the side navigation for one label. A product whose labels are long everywhere may set one width between 240 and 320 px for the whole product, and writes it down.\n\n## Page header\n\n**The top of every page: breadcrumb, title, status and page actions.**\n\n<LayoutDemo kind=\"pageheader\" />\n\n| Row | Holds | When |\n|---|---|---|\n| Breadcrumb | The pages above this one | Below the top level |\n| Title row | The page title (`heading.large`) and a status on the left; page actions on the right, the main action last | Always |\n| Description | One line about the page | Optional |\n| Tabs or filters | Views of the same page | Optional |\n\n- **The page header spans the whole content area at every page width.** Only the content below it follows [Full, Wide or Narrow](/foundations/styles/layout/page-widths/), so the title and the page actions stay in the same place on every page.\n- The breadcrumb belongs to the page, not to the header: it changes on every page, and the header stays the same.\n- Context for the whole product, such as the workspace, goes in the header.\n\n## Side panel\n\nA panel beside the main content, such as details of a selected row, takes grid columns: 4 of 12 from 1024 px and 3 of 12 from 1440 px. Below 1024 px it opens as a drawer over the page. See the spans on [Grid](/foundations/styles/layout/grid/#spans).\n\n## Spacing of the frame\n\n**Everything in the frame lines up on two edges: 20 px from the window on the left, and the page margin.**\n\n| Between | Space |\n|---|---|\n| The window edge and the logo; the window edge and the side navigation icons | 20 px, `space.250` |\n| The side navigation items and its edges | 8 px, `space.100` |\n| One side navigation item and the next (each 32 px high) | 4 px, `space.050` |\n| The content and the side navigation, the header or the window edge | The page margin: 16, 24 or 32 px ([Grid](/foundations/styles/layout/grid/)) |\n| The breadcrumb and the title | 8 px, `space.100` |\n| The title and the description | 4 px, `space.050` |\n| The page header and the content | 24 px, `space.300` |\n\nA 20 px edge for the logo comes from the side navigation: 8 px of inset plus the 12 px side padding of a 32 px control. The logo then sits right above the icons.\n",
452
- "raw": "---\ntitle: App frame\ndescription: The header, side navigation and page header that repeat on every page, their sizes, and the spacing that lines them up.\norder: 1\n---\nimport LayoutDemo from '../../../../components/LayoutDemo.astro';\n\n**The header, the side navigation and the page header repeat on every page, in the same place and at the same size.**\n\n## Header\n\n**48 px high, across the full width. It holds what belongs to the whole product.**\n\n| Part | Value |\n|---|---|\n| Height | 48 px: a 32 px control with 8 px above and below. The 1 px line under the header is not counted |\n| Holds | Menu button (below 1024 px), logo, global search, workspace switcher, notifications, account |\n| Does not hold | The breadcrumb and page actions. They change with the page, so they go in the page header |\n\nUse the package token `layout.header.height` (`--bh-layout-header-height`) for this dimension.\nThe sidebar widths below are `layout.sidebar.expanded` and `layout.sidebar.collapsed`.\nConvert source units at numeric framework API boundaries instead of copying their values.\n\n## Side navigation\n\n**280 px open, a 64 px rail when collapsed, a drawer below 1024 px. Every Beehexa product uses the same widths.**\n\n| Window | Side navigation |\n|---|---|\n| Below 1024 px | Hidden. The menu button in the header opens it as a drawer over the page. |\n| 1024 px and up | Open at 280 px. People can collapse it to the 64 px rail, and the choice is remembered. |\n\n- **280 px** fits a label of about 31 characters at 14 px, long Vietnamese labels included.\n- **The same width in every product**, so the page starts in the same place when people move between products.\n- **No resizing.** One width keeps products alike. A resizable panel would also need a way to resize it without dragging (WCAG 2.5.7).\n- **The rail** shows icons only. Each label appears in a tooltip.\n\n### Long labels\n\n<LayoutDemo kind=\"navlabels\" />\n\n1. Write a shorter label first.\n2. If it still does not fit, cut it with an ellipsis and show the full label in a tooltip, only when it is cut.\n3. Never widen the side navigation for one label. A product whose labels are long everywhere may set one width between 240 and 320 px for the whole product, and writes it down.\n\n## Page header\n\n**The top of every page: breadcrumb, title, status and page actions.**\n\n<LayoutDemo kind=\"pageheader\" />\n\n| Row | Holds | When |\n|---|---|---|\n| Breadcrumb | The pages above this one | Below the top level |\n| Title row | The page title (`heading.large`) and a status on the left; page actions on the right, the main action last | Always |\n| Description | One line about the page | Optional |\n| Tabs or filters | Views of the same page | Optional |\n\n- **The page header spans the whole content area at every page width.** Only the content below it follows [Full, Wide or Narrow](/foundations/styles/layout/page-widths/), so the title and the page actions stay in the same place on every page.\n- The breadcrumb belongs to the page, not to the header: it changes on every page, and the header stays the same.\n- Context for the whole product, such as the workspace, goes in the header.\n\n## Side panel\n\nA panel beside the main content, such as details of a selected row, takes grid columns: 4 of 12 from 1024 px and 3 of 12 from 1440 px. Below 1024 px it opens as a drawer over the page. See the spans on [Grid](/foundations/styles/layout/grid/#spans).\n\n## Spacing of the frame\n\n**Everything in the frame lines up on two edges: 20 px from the window on the left, and the page margin.**\n\n| Between | Space |\n|---|---|\n| The window edge and the logo; the window edge and the side navigation icons | 20 px, `space.250` |\n| The side navigation items and its edges | 8 px, `space.100` |\n| One side navigation item and the next (each 32 px high) | 4 px, `space.050` |\n| The content and the side navigation, the header or the window edge | The page margin: 16, 24 or 32 px ([Grid](/foundations/styles/layout/grid/)) |\n| The breadcrumb and the title | 8 px, `space.100` |\n| The title and the description | 4 px, `space.050` |\n| The page header and the content | 24 px, `space.300` |\n\nA 20 px edge for the logo comes from the side navigation: 8 px of inset plus the 12 px side padding of a 32 px control. The logo then sits right above the icons.\n",
438
+ "body": "import LayoutDemo from '../../../../components/LayoutDemo.astro';\n\n**The header, the side navigation and the page header repeat on every page, in the same place and at the same size.**\n\nThe global header and side navigation are one continuous shell surface: both use\n`surface.subtle` (`--bh-color-surface-subtle`) in light and dark themes. The mobile\nnavigation drawer, including its logo row, uses that same surface. Do not give the\nheader `surface` while the sidebar uses `surface.subtle`. Page headers belong to\nthe content surface, not this global shell.\n\nIn a mobile navigation drawer, the logo row does not shrink. The menu occupies the\nremaining height and scrolls only when its contents do not fit. Do not give a menu\nbelow a logo row `min-height: 100%`: that adds the logo height to a full-height menu.\n\n## Header\n\n**48 px high, across the full width. It holds what belongs to the whole product.**\n\n| Part | Value |\n|---|---|\n| Height | 48 px: a 32 px control with 8 px above and below. The 1 px line under the header is not counted |\n| Holds | Menu button (below 1024 px), logo, global search, workspace switcher, notifications, account |\n| Does not hold | The breadcrumb and page actions. They change with the page, so they go in the page header |\n\nUse the package token `layout.header.height` (`--bh-layout-header-height`) for this dimension.\nThe sidebar widths below are `layout.sidebar.expanded` and `layout.sidebar.collapsed`.\nConvert source units at numeric framework API boundaries instead of copying their values.\n\n## Side navigation\n\n**280 px open, a 64 px rail when collapsed, a drawer below 1024 px. Every Beehexa product uses the same widths.**\n\n| Window | Side navigation |\n|---|---|\n| Below 1024 px | Hidden. The menu button in the header opens it as a drawer over the page. |\n| 1024 px and up | Open at 280 px. People can collapse it to the 64 px rail, and the choice is remembered. |\n\n- **280 px** fits a label of about 31 characters at 14 px, long Vietnamese labels included.\n- **The same width in every product**, so the page starts in the same place when people move between products.\n- **No resizing.** One width keeps products alike. A resizable panel would also need a way to resize it without dragging (WCAG 2.5.7).\n- **The rail** shows icons only. Each label appears in a tooltip.\n\n### Long labels\n\n<LayoutDemo kind=\"navlabels\" />\n\n1. Write a shorter label first.\n2. If it still does not fit, cut it with an ellipsis and show the full label in a tooltip, only when it is cut.\n3. Never widen the side navigation for one label. A product whose labels are long everywhere may set one width between 240 and 320 px for the whole product, and writes it down.\n\n## Page header\n\n**The top of every page: breadcrumb, title, status and page actions.**\n\n<LayoutDemo kind=\"pageheader\" />\n\n| Row | Holds | When |\n|---|---|---|\n| Breadcrumb | The pages above this one | Below the top level |\n| Title row | The page title (`heading.large`) and a status on the left; page actions on the right, the main action last | Always |\n| Description | One line about the page | Optional |\n| Tabs or filters | Views of the same page | Optional |\n\n- **The page header spans the whole content area at every page width.** Only the content below it follows [Full, Wide or Narrow](/foundations/styles/layout/page-widths/), so the title and the page actions stay in the same place on every page.\n- The breadcrumb belongs to the page, not to the header: it changes on every page, and the header stays the same.\n- Context for the whole product, such as the workspace, goes in the header.\n\n## Side panel\n\nA panel beside the main content, such as details of a selected row, takes grid columns: 4 of 12 from 1024 px and 3 of 12 from 1440 px. Below 1024 px it opens as a drawer over the page. See the spans on [Grid](/foundations/styles/layout/grid/#spans).\n\n## Spacing of the frame\n\n**Everything in the frame lines up on two edges: 20 px from the window on the left, and the page margin.**\n\n| Between | Space |\n|---|---|\n| The window edge and the logo; the window edge and the side navigation icons | 20 px, `space.250` |\n| The side navigation items and its edges | 8 px, `space.100` |\n| One side navigation item and the next (each 32 px high) | 4 px, `space.050` |\n| The content and the side navigation, the header or the window edge | The page margin: 16, 24 or 32 px ([Grid](/foundations/styles/layout/grid/)) |\n| The breadcrumb and the title | 8 px, `space.100` |\n| The title and the description | 4 px, `space.050` |\n| The page header and the content | 24 px, `space.300` |\n\nA 20 px edge for the logo comes from the side navigation: 8 px of inset plus the 12 px side padding of a 32 px control. The logo then sits right above the icons.\n",
439
+ "raw": "---\ntitle: App frame\ndescription: The header, side navigation and page header that repeat on every page, their sizes, and the spacing that lines them up.\norder: 1\n---\nimport LayoutDemo from '../../../../components/LayoutDemo.astro';\n\n**The header, the side navigation and the page header repeat on every page, in the same place and at the same size.**\n\nThe global header and side navigation are one continuous shell surface: both use\n`surface.subtle` (`--bh-color-surface-subtle`) in light and dark themes. The mobile\nnavigation drawer, including its logo row, uses that same surface. Do not give the\nheader `surface` while the sidebar uses `surface.subtle`. Page headers belong to\nthe content surface, not this global shell.\n\nIn a mobile navigation drawer, the logo row does not shrink. The menu occupies the\nremaining height and scrolls only when its contents do not fit. Do not give a menu\nbelow a logo row `min-height: 100%`: that adds the logo height to a full-height menu.\n\n## Header\n\n**48 px high, across the full width. It holds what belongs to the whole product.**\n\n| Part | Value |\n|---|---|\n| Height | 48 px: a 32 px control with 8 px above and below. The 1 px line under the header is not counted |\n| Holds | Menu button (below 1024 px), logo, global search, workspace switcher, notifications, account |\n| Does not hold | The breadcrumb and page actions. They change with the page, so they go in the page header |\n\nUse the package token `layout.header.height` (`--bh-layout-header-height`) for this dimension.\nThe sidebar widths below are `layout.sidebar.expanded` and `layout.sidebar.collapsed`.\nConvert source units at numeric framework API boundaries instead of copying their values.\n\n## Side navigation\n\n**280 px open, a 64 px rail when collapsed, a drawer below 1024 px. Every Beehexa product uses the same widths.**\n\n| Window | Side navigation |\n|---|---|\n| Below 1024 px | Hidden. The menu button in the header opens it as a drawer over the page. |\n| 1024 px and up | Open at 280 px. People can collapse it to the 64 px rail, and the choice is remembered. |\n\n- **280 px** fits a label of about 31 characters at 14 px, long Vietnamese labels included.\n- **The same width in every product**, so the page starts in the same place when people move between products.\n- **No resizing.** One width keeps products alike. A resizable panel would also need a way to resize it without dragging (WCAG 2.5.7).\n- **The rail** shows icons only. Each label appears in a tooltip.\n\n### Long labels\n\n<LayoutDemo kind=\"navlabels\" />\n\n1. Write a shorter label first.\n2. If it still does not fit, cut it with an ellipsis and show the full label in a tooltip, only when it is cut.\n3. Never widen the side navigation for one label. A product whose labels are long everywhere may set one width between 240 and 320 px for the whole product, and writes it down.\n\n## Page header\n\n**The top of every page: breadcrumb, title, status and page actions.**\n\n<LayoutDemo kind=\"pageheader\" />\n\n| Row | Holds | When |\n|---|---|---|\n| Breadcrumb | The pages above this one | Below the top level |\n| Title row | The page title (`heading.large`) and a status on the left; page actions on the right, the main action last | Always |\n| Description | One line about the page | Optional |\n| Tabs or filters | Views of the same page | Optional |\n\n- **The page header spans the whole content area at every page width.** Only the content below it follows [Full, Wide or Narrow](/foundations/styles/layout/page-widths/), so the title and the page actions stay in the same place on every page.\n- The breadcrumb belongs to the page, not to the header: it changes on every page, and the header stays the same.\n- Context for the whole product, such as the workspace, goes in the header.\n\n## Side panel\n\nA panel beside the main content, such as details of a selected row, takes grid columns: 4 of 12 from 1024 px and 3 of 12 from 1440 px. Below 1024 px it opens as a drawer over the page. See the spans on [Grid](/foundations/styles/layout/grid/#spans).\n\n## Spacing of the frame\n\n**Everything in the frame lines up on two edges: 20 px from the window on the left, and the page margin.**\n\n| Between | Space |\n|---|---|\n| The window edge and the logo; the window edge and the side navigation icons | 20 px, `space.250` |\n| The side navigation items and its edges | 8 px, `space.100` |\n| One side navigation item and the next (each 32 px high) | 4 px, `space.050` |\n| The content and the side navigation, the header or the window edge | The page margin: 16, 24 or 32 px ([Grid](/foundations/styles/layout/grid/)) |\n| The breadcrumb and the title | 8 px, `space.100` |\n| The title and the description | 4 px, `space.050` |\n| The page header and the content | 24 px, `space.300` |\n\nA 20 px edge for the logo comes from the side navigation: 8 px of inset plus the 12 px side padding of a 32 px control. The logo then sits right above the icons.\n",
453
440
  "frontmatter": {
454
441
  "title": "App frame",
455
442
  "description": "The header, side navigation and page header that repeat on every page, their sizes, and the spacing that lines them up.",
@@ -678,24 +665,15 @@ export const catalog = [
678
665
  "locale": "en",
679
666
  "kind": "guidance",
680
667
  "title": "Opacity",
681
- "status": "planned",
668
+ "status": "active",
682
669
  "releasePhase": null,
683
- "planned": [
684
- "Where transparency is allowed: the scrim behind dialogs, image overlays",
685
- "Why hover, pressed and disabled use colour steps, not opacity",
686
- "Opacity tokens, if any are needed"
687
- ],
688
- "body": "",
689
- "raw": "---\ntitle: \"Opacity\"\ndescription: \"When transparency is allowed, and why states and disabled controls use colour instead.\"\norder: 10.5\nplanned:\n - \"Where transparency is allowed: the scrim behind dialogs, image overlays\"\n - \"Why hover, pressed and disabled use colour steps, not opacity\"\n - \"Opacity tokens, if any are needed\"\n---\n",
670
+ "planned": [],
671
+ "body": "import OpacityDemo from '../../../components/OpacityDemo.astro';\nimport TokenTable from '../../../components/TokenTable.astro';\n\nOpacity sets how see-through an element is. A faded element lets the background show through, so its colour changes from screen to screen. Beehexa uses opacity in two places only: images inside something turned off, and the scrim behind dialogs.\n\n## Why controls use colour\n\n- **The background shows through.** A faded button looks different on a white card, a yellow banner and a selected row.\n- **Contrast is no longer checked.** A faded colour is a new colour, and text on it may become unreadable.\n- **Opacity multiplies.** A 40% item inside a 40% card ends up at 16%.\n\nThe disabled colour tokens, such as `color.text.disabled`, look the same on every background. See [Interaction states](/foundations/styles/interaction-states/).\n\n| I need to | Use |\n|---|---|\n| Fade a logo, avatar or illustration of something turned off | `opacity.disabled` (0.4) on the image |\n| Turn off a button, input, text or icon | The disabled colour tokens |\n| Dim the page behind a dialog or drawer | `color.surface.scrim` |\n| Fade something in or out | Opacity 0 and 1 in an animation, see [Motion](/foundations/styles/motion/) |\n\n## Images that are turned off\n\nImages have their own colours, so no colour token can change them. Fade the image; give the text `color.text.disabled`; keep the card's border. Always say \"Turned off\" in words as well.\n\n<OpacityDemo kind=\"tile\" />\n\n<OpacityDemo kind=\"screen\" />\n\n## The scrim\n\nThe scrim dims the page behind a dialog or drawer, so the dialog is the focus and the page reads as unavailable. It is a colour with transparency built in: graphite at 40% in light mode, black at 60% in dark mode, where a dark page needs more to dim. Use it as it is.\n\n<OpacityDemo kind=\"scrim\" />\n\n## Do and don’t\n\n<OpacityDemo kind=\"dodont\" item=\"container\" />\n<OpacityDemo kind=\"dodont\" item=\"controls\" />\n\n## Tokens\n\n<TokenTable prefix=\"opacity\" />\n",
672
+ "raw": "---\ntitle: \"Opacity\"\ndescription: \"How see-through something is. Used only for images inside something turned off and for the scrim behind dialogs. Controls show their state with colour.\"\norder: 10.5\n---\nimport OpacityDemo from '../../../components/OpacityDemo.astro';\nimport TokenTable from '../../../components/TokenTable.astro';\n\nOpacity sets how see-through an element is. A faded element lets the background show through, so its colour changes from screen to screen. Beehexa uses opacity in two places only: images inside something turned off, and the scrim behind dialogs.\n\n## Why controls use colour\n\n- **The background shows through.** A faded button looks different on a white card, a yellow banner and a selected row.\n- **Contrast is no longer checked.** A faded colour is a new colour, and text on it may become unreadable.\n- **Opacity multiplies.** A 40% item inside a 40% card ends up at 16%.\n\nThe disabled colour tokens, such as `color.text.disabled`, look the same on every background. See [Interaction states](/foundations/styles/interaction-states/).\n\n| I need to | Use |\n|---|---|\n| Fade a logo, avatar or illustration of something turned off | `opacity.disabled` (0.4) on the image |\n| Turn off a button, input, text or icon | The disabled colour tokens |\n| Dim the page behind a dialog or drawer | `color.surface.scrim` |\n| Fade something in or out | Opacity 0 and 1 in an animation, see [Motion](/foundations/styles/motion/) |\n\n## Images that are turned off\n\nImages have their own colours, so no colour token can change them. Fade the image; give the text `color.text.disabled`; keep the card's border. Always say \"Turned off\" in words as well.\n\n<OpacityDemo kind=\"tile\" />\n\n<OpacityDemo kind=\"screen\" />\n\n## The scrim\n\nThe scrim dims the page behind a dialog or drawer, so the dialog is the focus and the page reads as unavailable. It is a colour with transparency built in: graphite at 40% in light mode, black at 60% in dark mode, where a dark page needs more to dim. Use it as it is.\n\n<OpacityDemo kind=\"scrim\" />\n\n## Do and don’t\n\n<OpacityDemo kind=\"dodont\" item=\"container\" />\n<OpacityDemo kind=\"dodont\" item=\"controls\" />\n\n## Tokens\n\n<TokenTable prefix=\"opacity\" />\n",
690
673
  "frontmatter": {
691
674
  "title": "Opacity",
692
- "description": "When transparency is allowed, and why states and disabled controls use colour instead.",
693
- "order": 10.5,
694
- "planned": [
695
- "Where transparency is allowed: the scrim behind dialogs, image overlays",
696
- "Why hover, pressed and disabled use colour steps, not opacity",
697
- "Opacity tokens, if any are needed"
698
- ]
675
+ "description": "How see-through something is. Used only for images inside something turned off and for the scrim behind dialogs. Controls show their state with colour.",
676
+ "order": 10.5
699
677
  }
700
678
  },
701
679
  {
@@ -726,8 +704,8 @@ export const catalog = [
726
704
  "status": "active",
727
705
  "releasePhase": null,
728
706
  "planned": [],
729
- "body": "import LayoutDemo from '../../../components/LayoutDemo.astro';\nimport TokenTable from '../../../components/TokenTable.astro';\n\n**Every control comes in three heights: 24, 32 and 40 px. Controls in one row share one height.**\n\nControls are the things people click or type in: buttons, text fields, selects, segmented controls and tabs. A fixed height keeps a row of them lined up, whatever their text.\n\n<LayoutDemo kind=\"controls\" />\n\n| Size | Height | Where |\n|---|---|---|\n| Small | 24 px | Dense tables and their toolbars, filters, tags |\n| Default | 32 px | Forms, buttons, the header, toolbars, everything else |\n| Large | 40 px | Sign-in and onboarding pages. Optional for the main action on touch screens |\n\n- Keep controls of one height in one row. A 24 px button next to a 32 px field looks misaligned.\n- Set heights with the size tokens, not with padding. The text sits in the middle of the height.\n\n## Target size\n\n**Every control can be clicked in an area of at least 24 × 24 px, and tapped in 44 × 44 px on touch screens.**\n\n- 24 px is the minimum target size of WCAG 2.2 (SC 2.5.8). Every control height meets it.\n- On touch screens, keep the visible height and make the area that responds to a tap at least 44 × 44 px (`size.target.touch`).\n\n## Density\n\n**Beehexa has one density for now: default.**\n\nOne density means every screen is designed and checked at one size. A compact density may come later; it would lower control heights and spacing together, and screens that use the tokens will need no change.\n\nUntil then, make a dense table with small (24 px) controls and rows, not with smaller spacing tokens.\n\n## Tokens\n\n<TokenTable prefix=\"size\" />\n",
730
- "raw": "---\ntitle: Size and density\ndescription: The three control heights, the size of a target people can click or tap, and how dense Beehexa screens are.\norder: 5\n---\nimport LayoutDemo from '../../../components/LayoutDemo.astro';\nimport TokenTable from '../../../components/TokenTable.astro';\n\n**Every control comes in three heights: 24, 32 and 40 px. Controls in one row share one height.**\n\nControls are the things people click or type in: buttons, text fields, selects, segmented controls and tabs. A fixed height keeps a row of them lined up, whatever their text.\n\n<LayoutDemo kind=\"controls\" />\n\n| Size | Height | Where |\n|---|---|---|\n| Small | 24 px | Dense tables and their toolbars, filters, tags |\n| Default | 32 px | Forms, buttons, the header, toolbars, everything else |\n| Large | 40 px | Sign-in and onboarding pages. Optional for the main action on touch screens |\n\n- Keep controls of one height in one row. A 24 px button next to a 32 px field looks misaligned.\n- Set heights with the size tokens, not with padding. The text sits in the middle of the height.\n\n## Target size\n\n**Every control can be clicked in an area of at least 24 × 24 px, and tapped in 44 × 44 px on touch screens.**\n\n- 24 px is the minimum target size of WCAG 2.2 (SC 2.5.8). Every control height meets it.\n- On touch screens, keep the visible height and make the area that responds to a tap at least 44 × 44 px (`size.target.touch`).\n\n## Density\n\n**Beehexa has one density for now: default.**\n\nOne density means every screen is designed and checked at one size. A compact density may come later; it would lower control heights and spacing together, and screens that use the tokens will need no change.\n\nUntil then, make a dense table with small (24 px) controls and rows, not with smaller spacing tokens.\n\n## Tokens\n\n<TokenTable prefix=\"size\" />\n",
707
+ "body": "import LayoutDemo from '../../../components/LayoutDemo.astro';\nimport TokenTable from '../../../components/TokenTable.astro';\n\n**Every control comes in three heights: 24, 32 and 40 px. Controls in one row share one height.**\n\nControls are the things people click or type in: buttons, text fields, selects, segmented controls and tabs. A fixed height keeps a row of them lined up, whatever their text.\n\n<LayoutDemo kind=\"controls\" />\n\n| Size | Height | Where |\n|---|---|---|\n| Small | 24 px | Dense tables and their toolbars, filters, tags |\n| Default | 32 px | Forms, buttons, the header, toolbars, everything else |\n| Large | 40 px | Sign-in and onboarding pages. Optional for the main action on touch screens |\n\n- Keep controls of one height in one row. A 24 px button next to a 32 px field looks misaligned.\n- Set heights with the size tokens, not with padding. The text sits in the middle of the height.\n\nTwo other parts have a fixed size:\n\n| Part | Size |\n|---|---|\n| Switch | 20 px high, 36 px wide; knob 16 px |\n| Avatar | 32 px; 24 px in dense tables and lists |\n\n## Target size\n\n**Every control can be clicked in an area of at least 24 × 24 px, and tapped in 44 × 44 px on touch screens.**\n\n- 24 px is the minimum target size of WCAG 2.2 (SC 2.5.8). Every control height meets it.\n- On touch screens, keep the visible height and make the area that responds to a tap at least 44 × 44 px (`size.target.touch`).\n\n## Density\n\n**Beehexa has one density for now: default.**\n\nOne density means every screen is designed and checked at one size. A compact density may come later; it would lower control heights and spacing together, and screens that use the tokens will need no change.\n\nUntil then, make a dense table with small (24 px) controls and rows, not with smaller spacing tokens.\n\n## Tokens\n\n<TokenTable prefix=\"size\" />\n",
708
+ "raw": "---\ntitle: Size and density\ndescription: The three control heights, the size of a target people can click or tap, and how dense Beehexa screens are.\norder: 5\n---\nimport LayoutDemo from '../../../components/LayoutDemo.astro';\nimport TokenTable from '../../../components/TokenTable.astro';\n\n**Every control comes in three heights: 24, 32 and 40 px. Controls in one row share one height.**\n\nControls are the things people click or type in: buttons, text fields, selects, segmented controls and tabs. A fixed height keeps a row of them lined up, whatever their text.\n\n<LayoutDemo kind=\"controls\" />\n\n| Size | Height | Where |\n|---|---|---|\n| Small | 24 px | Dense tables and their toolbars, filters, tags |\n| Default | 32 px | Forms, buttons, the header, toolbars, everything else |\n| Large | 40 px | Sign-in and onboarding pages. Optional for the main action on touch screens |\n\n- Keep controls of one height in one row. A 24 px button next to a 32 px field looks misaligned.\n- Set heights with the size tokens, not with padding. The text sits in the middle of the height.\n\nTwo other parts have a fixed size:\n\n| Part | Size |\n|---|---|\n| Switch | 20 px high, 36 px wide; knob 16 px |\n| Avatar | 32 px; 24 px in dense tables and lists |\n\n## Target size\n\n**Every control can be clicked in an area of at least 24 × 24 px, and tapped in 44 × 44 px on touch screens.**\n\n- 24 px is the minimum target size of WCAG 2.2 (SC 2.5.8). Every control height meets it.\n- On touch screens, keep the visible height and make the area that responds to a tap at least 44 × 44 px (`size.target.touch`).\n\n## Density\n\n**Beehexa has one density for now: default.**\n\nOne density means every screen is designed and checked at one size. A compact density may come later; it would lower control heights and spacing together, and screens that use the tokens will need no change.\n\nUntil then, make a dense table with small (24 px) controls and rows, not with smaller spacing tokens.\n\n## Tokens\n\n<TokenTable prefix=\"size\" />\n",
731
709
  "frontmatter": {
732
710
  "title": "Size and density",
733
711
  "description": "The three control heights, the size of a target people can click or tap, and how dense Beehexa screens are.",
@@ -762,8 +740,8 @@ export const catalog = [
762
740
  "status": "active",
763
741
  "releasePhase": null,
764
742
  "planned": [],
765
- "body": "import TokenTable from '../../../../components/TokenTable.astro';\nimport TypeDemo from '../../../../components/TypeDemo.astro';\n\n## Font stacks\n\nUse the tokens, not your own lists.\n\n```css\n/* font.family.sans */\nfont-family: Inter, \"Noto Sans\", system-ui, sans-serif;\n\n/* font.family.mono */\nfont-family: \"JetBrains Mono\", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n```\n\nNoto Sans is the fallback because it covers Vietnamese and ₫ and is close to Inter in size (x-height 0.536 em against Inter's 0.546), so a page that falls back keeps its layout.\n\n## Getting the fonts\n\n- **On the web,** self-host the fonts. Use the Inter build from the Google Fonts repository (`github.com/google/fonts`, `ofl/inter`): it is hinted for small text on Windows and keeps every OpenType feature. Don't link the Google Fonts API: its files drop `cv05`, `cv08`, `ss02` and `zero`, and `cv05` and `cv08` are on by default (see [Numbers and codes](#numbers-and-codes)). This site serves those files, cut into Latin, Latin Extended and Vietnamese subsets.\n- **On your computer,** for Figma, slides and documents, install Inter from Google Fonts and JetBrains Mono from JetBrains. The Google Fonts build of Inter also avoids clipped accents in older Windows apps such as Office.\n- Both licences allow use in products, documents and logos.\n\n## Numbers and codes\n\n`cv05` and `cv08` are on for all Inter text. They give lowercase l a tail and uppercase I serifs, so l, I and 1 never look alike in names, IDs and keys. Turn the rest on where they help; leave body text as it is.\n\n- **Tables and changing values:** use tabular figures (`font-variant-numeric: tabular-nums`), so digits line up in columns and counters don't jitter.\n- **Codes people read or type,** such as order numbers, SKUs and API keys: add the slashed zero (`zero`) to Inter, or set them in JetBrains Mono (`code.default`). JetBrains Mono has no `cv05` or `cv08`, so code looks the same.\n\n<TypeDemo kind=\"numbers\" />\n\n<TypeDemo kind=\"features\" />\n\nEvery text style is applied with the `font` shorthand, and the shorthand resets `font-feature-settings`. So the features are set on every element from one variable, `--bh-font-features`; to add a feature, change the variable, not the property.\n\n```css\n/* Base: on every element */\n:root { --bh-font-features: \"cv05\", \"cv08\"; }\n*, ::before, ::after { font-feature-settings: var(--bh-font-features) !important; }\n\n/* Opt in where needed */\n.table-number { font-variant-numeric: tabular-nums; }\n.code-value { --bh-font-features: \"cv05\", \"cv08\", \"zero\"; }\n```\n\n## Tokens\n<TokenTable prefix=\"font\" />\n",
766
- "raw": "---\ntitle: Code\ndescription: Font stacks, getting the fonts, OpenType features for numbers and codes, and the type tokens.\norder: 3\n---\nimport TokenTable from '../../../../components/TokenTable.astro';\nimport TypeDemo from '../../../../components/TypeDemo.astro';\n\n## Font stacks\n\nUse the tokens, not your own lists.\n\n```css\n/* font.family.sans */\nfont-family: Inter, \"Noto Sans\", system-ui, sans-serif;\n\n/* font.family.mono */\nfont-family: \"JetBrains Mono\", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n```\n\nNoto Sans is the fallback because it covers Vietnamese and ₫ and is close to Inter in size (x-height 0.536 em against Inter's 0.546), so a page that falls back keeps its layout.\n\n## Getting the fonts\n\n- **On the web,** self-host the fonts. Use the Inter build from the Google Fonts repository (`github.com/google/fonts`, `ofl/inter`): it is hinted for small text on Windows and keeps every OpenType feature. Don't link the Google Fonts API: its files drop `cv05`, `cv08`, `ss02` and `zero`, and `cv05` and `cv08` are on by default (see [Numbers and codes](#numbers-and-codes)). This site serves those files, cut into Latin, Latin Extended and Vietnamese subsets.\n- **On your computer,** for Figma, slides and documents, install Inter from Google Fonts and JetBrains Mono from JetBrains. The Google Fonts build of Inter also avoids clipped accents in older Windows apps such as Office.\n- Both licences allow use in products, documents and logos.\n\n## Numbers and codes\n\n`cv05` and `cv08` are on for all Inter text. They give lowercase l a tail and uppercase I serifs, so l, I and 1 never look alike in names, IDs and keys. Turn the rest on where they help; leave body text as it is.\n\n- **Tables and changing values:** use tabular figures (`font-variant-numeric: tabular-nums`), so digits line up in columns and counters don't jitter.\n- **Codes people read or type,** such as order numbers, SKUs and API keys: add the slashed zero (`zero`) to Inter, or set them in JetBrains Mono (`code.default`). JetBrains Mono has no `cv05` or `cv08`, so code looks the same.\n\n<TypeDemo kind=\"numbers\" />\n\n<TypeDemo kind=\"features\" />\n\nEvery text style is applied with the `font` shorthand, and the shorthand resets `font-feature-settings`. So the features are set on every element from one variable, `--bh-font-features`; to add a feature, change the variable, not the property.\n\n```css\n/* Base: on every element */\n:root { --bh-font-features: \"cv05\", \"cv08\"; }\n*, ::before, ::after { font-feature-settings: var(--bh-font-features) !important; }\n\n/* Opt in where needed */\n.table-number { font-variant-numeric: tabular-nums; }\n.code-value { --bh-font-features: \"cv05\", \"cv08\", \"zero\"; }\n```\n\n## Tokens\n<TokenTable prefix=\"font\" />\n",
743
+ "body": "import TokenTable from '../../../../components/TokenTable.astro';\nimport TypeDemo from '../../../../components/TypeDemo.astro';\n\n## Font stacks\n\nUse the tokens, not your own lists.\n\n```css\n/* font.family.sans */\nfont-family: Inter, \"Noto Sans\", system-ui, sans-serif;\n\n/* font.family.mono */\nfont-family: \"JetBrains Mono\", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n```\n\nNoto Sans is the fallback because it covers Vietnamese and ₫ and is close to Inter in size (x-height 0.536 em against Inter's 0.546), so a page that falls back keeps its layout.\n\n## Getting the fonts\n\n- **On the web,** self-host the fonts. Use the Inter build from the Google Fonts repository (`github.com/google/fonts`, `ofl/inter`): it is hinted for small text on Windows and keeps every OpenType feature. Don't link the Google Fonts API: its files drop `cv05`, `cv08`, `ss02` and `zero`, and `cv05` and `cv08` are on by default (see [Numbers and codes](#numbers-and-codes)). This site serves those files, cut into Latin, Latin Extended and Vietnamese subsets.\n- **On your computer,** for Figma, slides and documents, install Inter from Google Fonts and JetBrains Mono from JetBrains. The Google Fonts build of Inter also avoids clipped accents in older Windows apps such as Office.\n- Both licences allow use in products, documents and logos.\n\n## Numbers and codes\n\n`cv05` and `cv08` are on for all Inter text. They give lowercase l a tail and uppercase I serifs, so l, I and 1 never look alike in names, IDs and keys. Turn the rest on where they help; leave body text as it is.\n\n- **Tables and changing values:** use tabular figures (`font-variant-numeric: tabular-nums`), so digits line up in columns and counters don't jitter.\n- **Codes people read or type,** such as order numbers, SKUs and API keys: add the slashed zero (`zero`) to Inter, or set them in JetBrains Mono (`code.default`). JetBrains Mono has no `cv05` or `cv08`, so code looks the same.\n\n<TypeDemo kind=\"numbers\" />\n\n<TypeDemo kind=\"features\" />\n\nEvery text style uses the `font` shorthand, which resets `font-feature-settings`. The source token `font.features` owns `\"cv05\", \"cv08\"`; generated token CSS applies `--bh-font-features` universally with `!important`. Consumers import that CSS rather than copy the base rule below. Add features through the variable, not a competing property. Keep a native 16px root and the 14px `font.body.default` role on the body.\n\n```css\n/* Base: on every element */\n:root { --bh-font-features: \"cv05\", \"cv08\"; }\n*, ::before, ::after { font-feature-settings: var(--bh-font-features) !important; }\n\n/* Opt in where needed */\n.table-number { font-variant-numeric: tabular-nums; }\n.code-value { --bh-font-features: \"cv05\", \"cv08\", \"zero\"; }\n```\n\n## Tokens\n<TokenTable prefix=\"font\" />\n",
744
+ "raw": "---\ntitle: Code\ndescription: Font stacks, getting the fonts, OpenType features for numbers and codes, and the type tokens.\norder: 3\n---\nimport TokenTable from '../../../../components/TokenTable.astro';\nimport TypeDemo from '../../../../components/TypeDemo.astro';\n\n## Font stacks\n\nUse the tokens, not your own lists.\n\n```css\n/* font.family.sans */\nfont-family: Inter, \"Noto Sans\", system-ui, sans-serif;\n\n/* font.family.mono */\nfont-family: \"JetBrains Mono\", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n```\n\nNoto Sans is the fallback because it covers Vietnamese and ₫ and is close to Inter in size (x-height 0.536 em against Inter's 0.546), so a page that falls back keeps its layout.\n\n## Getting the fonts\n\n- **On the web,** self-host the fonts. Use the Inter build from the Google Fonts repository (`github.com/google/fonts`, `ofl/inter`): it is hinted for small text on Windows and keeps every OpenType feature. Don't link the Google Fonts API: its files drop `cv05`, `cv08`, `ss02` and `zero`, and `cv05` and `cv08` are on by default (see [Numbers and codes](#numbers-and-codes)). This site serves those files, cut into Latin, Latin Extended and Vietnamese subsets.\n- **On your computer,** for Figma, slides and documents, install Inter from Google Fonts and JetBrains Mono from JetBrains. The Google Fonts build of Inter also avoids clipped accents in older Windows apps such as Office.\n- Both licences allow use in products, documents and logos.\n\n## Numbers and codes\n\n`cv05` and `cv08` are on for all Inter text. They give lowercase l a tail and uppercase I serifs, so l, I and 1 never look alike in names, IDs and keys. Turn the rest on where they help; leave body text as it is.\n\n- **Tables and changing values:** use tabular figures (`font-variant-numeric: tabular-nums`), so digits line up in columns and counters don't jitter.\n- **Codes people read or type,** such as order numbers, SKUs and API keys: add the slashed zero (`zero`) to Inter, or set them in JetBrains Mono (`code.default`). JetBrains Mono has no `cv05` or `cv08`, so code looks the same.\n\n<TypeDemo kind=\"numbers\" />\n\n<TypeDemo kind=\"features\" />\n\nEvery text style uses the `font` shorthand, which resets `font-feature-settings`. The source token `font.features` owns `\"cv05\", \"cv08\"`; generated token CSS applies `--bh-font-features` universally with `!important`. Consumers import that CSS rather than copy the base rule below. Add features through the variable, not a competing property. Keep a native 16px root and the 14px `font.body.default` role on the body.\n\n```css\n/* Base: on every element */\n:root { --bh-font-features: \"cv05\", \"cv08\"; }\n*, ::before, ::after { font-feature-settings: var(--bh-font-features) !important; }\n\n/* Opt in where needed */\n.table-number { font-variant-numeric: tabular-nums; }\n.code-value { --bh-font-features: \"cv05\", \"cv08\", \"zero\"; }\n```\n\n## Tokens\n<TokenTable prefix=\"font\" />\n",
767
745
  "frontmatter": {
768
746
  "title": "Code",
769
747
  "description": "Font stacks, getting the fonts, OpenType features for numbers and codes, and the type tokens.",
@@ -832,24 +810,15 @@ export const catalog = [
832
810
  "locale": "en",
833
811
  "kind": "guidance",
834
812
  "title": "Z-index",
835
- "status": "planned",
813
+ "status": "active",
836
814
  "releasePhase": null,
837
- "planned": [
838
- "Layer names and their order",
839
- "Which layer each overlay uses: dropdown, popover, tooltip, dialog, drawer, toast",
840
- "How layering pairs with elevation"
841
- ],
842
- "body": "",
843
- "raw": "---\ntitle: \"Z-index\"\ndescription: \"The stacking order of layers: what sits above what, from sticky headers to dialogs and toasts.\"\norder: 8.5\nplanned:\n - \"Layer names and their order\"\n - \"Which layer each overlay uses: dropdown, popover, tooltip, dialog, drawer, toast\"\n - \"How layering pairs with elevation\"\n---\n",
815
+ "planned": [],
816
+ "body": "import ZIndexDemo from '../../../components/ZIndexDemo.astro';\nimport TokenTable from '../../../components/TokenTable.astro';\n\nZ-index decides which element is drawn on top when two overlap. Beehexa uses seven named base layers instead of free numbers, so a menu never opens behind a dialog and a toast never hides under the scrim.\n\n<ZIndexDemo kind=\"stack\" />\n\n## How it works\n\n- **A higher layer covers a lower one.** Base values run from 100 to 700 in steps of 100, leaving room for explicit fullscreen and readiness roles.\n- **Pick the layer by what the element does**, not by how high a number you need.\n- **A layer only competes with its neighbours.** An element with its own z-index, transform, filter or opacity below 1 starts a new stacking context; nothing inside can rise above it. That is why a list inside a dialog is rendered inside the dialog.\n\n[Elevation](/foundations/styles/elevation/) shows how high a surface looks; z-index makes sure it is drawn on top. A menu needs both.\n\n| Layer | Token | Value | Elevation | Use for |\n|---|---|---|---|---|\n| Sticky | `z-index.sticky` | 100 | Page | Sticky table headers and toolbars |\n| Navigation | `z-index.navigation` | 200 | Page | App header, side navigation |\n| Overlay | `z-index.overlay` | 300 | Overlay | Menus, select lists, popovers |\n| Modal | `z-index.modal` | 400 | Modal | Dialogs, drawers and their scrim |\n| Spotlight | `z-index.spotlight` | 500 | Modal | Product tour, onboarding spotlight |\n| Tooltip | `z-index.tooltip` | 600 | none | Tooltips |\n| Toast | `z-index.toast` | 700 | Overlay | Toasts, the skip link |\n\n## Why this order\n\n- Menus cover the navigation they open from.\n- A modal blocks the whole page, menus included.\n- A tour can point at something inside a dialog.\n- A tooltip explains a control, wherever that control is.\n- A toast reports on the whole app, so nothing covers it.\n\n## On a screen\n\n<ZIndexDemo kind=\"screen\" />\n\nInside one component, values from 1 to 9 need no token, for example to lift the focused button in a button group.\n\n## Do and don’t\n\n<ZIndexDemo kind=\"dodont\" item=\"toast\" />\n<ZIndexDemo kind=\"dodont\" item=\"inside\" />\n<ZIndexDemo kind=\"dodont\" item=\"scrim\" />\n\n## Tokens\n\n<TokenTable prefix=\"z-index\" />\n\n## Fullscreen and framework integration\n\nThe extended roles `z-index.fullscreen` (450) and `z-index.loading` (650) cover editor/code/image takeovers and blocking application readiness respectively. Fullscreen stays below spotlight, tooltip and toast feedback; readiness covers interactive surfaces and tooltips while toast feedback and the skip link remain on top at 700.\n\nA fullscreen operational graph uses `z-index.modal` in an isolated local stacking context, not the editor takeover role. Child graph chrome uses private local ordering, so a global inspector can appear above it.\n\nThe Ant Design Vue adapter owns native component stacking: menus and select lists use the overlay band, dialogs and drawers use modal, tooltips use tooltip, and feedback uses toast. Bind its contextual `getPopupContainer` at the root ConfigProvider so a popup inside a dialog, drawer or fullscreen surface is rendered inside its owner, above the owner's scrim. Do not raise every popup globally to compensate for an incorrect container. Mark custom fullscreen hosts with `data-bh-overlay-owner`.\n\nRoot native Modal/Drawer surfaces remain in the document body for viewport geometry. Set root modal defaults from the adapter's invocation-time `getAntDesignVueModalZIndex()` (preserving an explicit caller value), and pass the live parent layer to `getAntDesignVueOverlayZIndex(fullscreen, ownerZIndex)` for nested drawers. A child uses the highest owner bound plus one, not a sum of ancestor z-index values; this keeps native confirmations above a fullscreen editor without crossing into the spotlight/feedback tiers.\n\nMonaco's detached hover, completion and parameter-hint widgets use `z-index.tooltip`. Keep the editor takeover isolated so its child chrome cannot cover global feedback. Use one `color.surface.scrim` behind a modal or image inspector, not multiple translucent layers.\n\nPreserve focus containment, focus return, Escape handling and scroll locking. Exercise the actual graph, editor hints, nested menus, inspector and loading stack; numeric ordering alone is not visual or accessibility proof.\n",
817
+ "raw": "---\ntitle: \"Z-index\"\ndescription: \"Which element is drawn on top when two overlap. Seven base layers and explicit fullscreen/readiness roles keep floating things in the same order everywhere.\"\norder: 8.5\n---\nimport ZIndexDemo from '../../../components/ZIndexDemo.astro';\nimport TokenTable from '../../../components/TokenTable.astro';\n\nZ-index decides which element is drawn on top when two overlap. Beehexa uses seven named base layers instead of free numbers, so a menu never opens behind a dialog and a toast never hides under the scrim.\n\n<ZIndexDemo kind=\"stack\" />\n\n## How it works\n\n- **A higher layer covers a lower one.** Base values run from 100 to 700 in steps of 100, leaving room for explicit fullscreen and readiness roles.\n- **Pick the layer by what the element does**, not by how high a number you need.\n- **A layer only competes with its neighbours.** An element with its own z-index, transform, filter or opacity below 1 starts a new stacking context; nothing inside can rise above it. That is why a list inside a dialog is rendered inside the dialog.\n\n[Elevation](/foundations/styles/elevation/) shows how high a surface looks; z-index makes sure it is drawn on top. A menu needs both.\n\n| Layer | Token | Value | Elevation | Use for |\n|---|---|---|---|---|\n| Sticky | `z-index.sticky` | 100 | Page | Sticky table headers and toolbars |\n| Navigation | `z-index.navigation` | 200 | Page | App header, side navigation |\n| Overlay | `z-index.overlay` | 300 | Overlay | Menus, select lists, popovers |\n| Modal | `z-index.modal` | 400 | Modal | Dialogs, drawers and their scrim |\n| Spotlight | `z-index.spotlight` | 500 | Modal | Product tour, onboarding spotlight |\n| Tooltip | `z-index.tooltip` | 600 | none | Tooltips |\n| Toast | `z-index.toast` | 700 | Overlay | Toasts, the skip link |\n\n## Why this order\n\n- Menus cover the navigation they open from.\n- A modal blocks the whole page, menus included.\n- A tour can point at something inside a dialog.\n- A tooltip explains a control, wherever that control is.\n- A toast reports on the whole app, so nothing covers it.\n\n## On a screen\n\n<ZIndexDemo kind=\"screen\" />\n\nInside one component, values from 1 to 9 need no token, for example to lift the focused button in a button group.\n\n## Do and don’t\n\n<ZIndexDemo kind=\"dodont\" item=\"toast\" />\n<ZIndexDemo kind=\"dodont\" item=\"inside\" />\n<ZIndexDemo kind=\"dodont\" item=\"scrim\" />\n\n## Tokens\n\n<TokenTable prefix=\"z-index\" />\n\n## Fullscreen and framework integration\n\nThe extended roles `z-index.fullscreen` (450) and `z-index.loading` (650) cover editor/code/image takeovers and blocking application readiness respectively. Fullscreen stays below spotlight, tooltip and toast feedback; readiness covers interactive surfaces and tooltips while toast feedback and the skip link remain on top at 700.\n\nA fullscreen operational graph uses `z-index.modal` in an isolated local stacking context, not the editor takeover role. Child graph chrome uses private local ordering, so a global inspector can appear above it.\n\nThe Ant Design Vue adapter owns native component stacking: menus and select lists use the overlay band, dialogs and drawers use modal, tooltips use tooltip, and feedback uses toast. Bind its contextual `getPopupContainer` at the root ConfigProvider so a popup inside a dialog, drawer or fullscreen surface is rendered inside its owner, above the owner's scrim. Do not raise every popup globally to compensate for an incorrect container. Mark custom fullscreen hosts with `data-bh-overlay-owner`.\n\nRoot native Modal/Drawer surfaces remain in the document body for viewport geometry. Set root modal defaults from the adapter's invocation-time `getAntDesignVueModalZIndex()` (preserving an explicit caller value), and pass the live parent layer to `getAntDesignVueOverlayZIndex(fullscreen, ownerZIndex)` for nested drawers. A child uses the highest owner bound plus one, not a sum of ancestor z-index values; this keeps native confirmations above a fullscreen editor without crossing into the spotlight/feedback tiers.\n\nMonaco's detached hover, completion and parameter-hint widgets use `z-index.tooltip`. Keep the editor takeover isolated so its child chrome cannot cover global feedback. Use one `color.surface.scrim` behind a modal or image inspector, not multiple translucent layers.\n\nPreserve focus containment, focus return, Escape handling and scroll locking. Exercise the actual graph, editor hints, nested menus, inspector and loading stack; numeric ordering alone is not visual or accessibility proof.\n",
844
818
  "frontmatter": {
845
819
  "title": "Z-index",
846
- "description": "The stacking order of layers: what sits above what, from sticky headers to dialogs and toasts.",
847
- "order": 8.5,
848
- "planned": [
849
- "Layer names and their order",
850
- "Which layer each overlay uses: dropdown, popover, tooltip, dialog, drawer, toast",
851
- "How layering pairs with elevation"
852
- ]
820
+ "description": "Which element is drawn on top when two overlap. Seven base layers and explicit fullscreen/readiness roles keep floating things in the same order everywhere.",
821
+ "order": 8.5
853
822
  }
854
823
  },
855
824
  {
@@ -1078,14 +1047,50 @@ export const catalog = [
1078
1047
  "status": "active",
1079
1048
  "releasePhase": null,
1080
1049
  "planned": [],
1081
- "body": "\nTokens and full rules are available as local `@beehexa/design-tokens` and `@beehexa/design-rules` packages. They are not released to npm yet. There is no exported `/antdv` theme subpath: keep a framework adapter in your application and derive its values from the installed token package.\n\n**Beehexa tokens are the source of truth. Ant Design Vue only reads them.**\n\nThis page is the only place where the Beehexa foundations meet Ant Design Vue. The foundation pages stay the same whatever the product is built with.\n\n## Usage\n\n```vue\n<script setup>\nimport { tokens } from '@beehexa/design-tokens';\nimport '@beehexa/design-tokens/css';\n\n// The framework adapter selects semantic roles, not a new application palette.\nconst theme = {\n token: {\n colorPrimary: tokens.light['color.background.neutral.bold'],\n colorText: tokens.light['color.text'],\n colorBorder: tokens.light['color.border'],\n fontFamily: tokens.light['font.family.sans'],\n },\n};\n</script>\n\n<template>\n <a-config-provider :theme=\"theme\">\n <App />\n </a-config-provider>\n</template>\n```\n\nThis light-mode colour/font example is not the complete theme recipe. Apply the mappings below\nin your adapter, resolve `rem` to pixels at numeric API boundaries, and recompute from\n`{ ...tokens.light, ...tokens.dark }` for dark mode and the `tokens.vi` typography alternatives\nfor Vietnamese. Read the installed rule documents before implementing states or components.\n\n## Token mapping\n\n| Ant Design token | Beehexa token |\n| --- | --- |\n| `colorPrimary` | `color.background.neutral.bold` |\n| `colorText` | `color.text` |\n| `colorBorder` | `color.border` |\n| `borderRadius` | `radius.100` |\n| `fontFamily` | `font.family.sans` |\n\n## Spacing\n\nAnt Design Vue sizes come from `sizeUnit` and `sizeStep`. Keep both at 4, so `size` is 16 px. The theme then sets each size from a [spacing](/foundations/styles/spacing/) token.\n\n| Beehexa token | Value | Ant Design Vue tokens |\n|---|---|---|\n| `space.050` | 4 px | `sizeXXS, paddingXXS, marginXXS` |\n| `space.100` | 8 px | `sizeXS, paddingXS, marginXS` |\n| `space.150` | 12 px | `sizeSM, paddingSM, marginSM` |\n| `space.200` | 16 px | `size, sizeMS, padding, margin` |\n| `space.250` | 20 px | `sizeMD, paddingMD, marginMD` |\n| `space.300` | 24 px | `sizeLG, paddingLG, marginLG` |\n| `space.400` | 32 px | `sizeXL, paddingXL, marginXL` |\n| `space.600` | 48 px | `sizeXXL, marginXXL` |\n\n`space.0`, `space.025`, `space.075`, `space.500`, `space.800` and `space.1000` have no Ant Design Vue token. Use their CSS variables in your own styles.\n\nProps that take a number, such as `size` on `a-space` and `gutter` on `a-row`, take pixels. Use a value from the scale: `<a-space :size=\"8\">`.\n\n## Control height\n\n| Beehexa token | Height | Ant Design Vue token | Component prop |\n|---|---|---|---|\n| `size.control.small` | 24 px | `controlHeightSM` | `size=\"small\"` |\n| `size.control.default` | 32 px | `controlHeight` | None |\n| `size.control.large` | 40 px | `controlHeightLG` | `size=\"large\"` |\n\nThese are Ant Design Vue’s own heights. The theme still sets each one from its size token, so a change to the token reaches the components. See [Size and density](/foundations/styles/size-and-density/).\n\n## Breakpoints\n\n**Override the `screen*` tokens with the Beehexa [breakpoints](/foundations/styles/layout/breakpoints/).** The default Ant Design Vue values are different (576, 992, 1200 and 1600 px).\n\nThe `Min` and `Max` tokens are computed from the defaults, not from your overrides. Set them too: each `Max` is the next breakpoint minus 1.\n\n| Beehexa | Value | Ant Design Vue tokens |\n|---|---|---|\n| `breakpoint.xs` | 0 | `screenXSMax: 767` |\n| `breakpoint.md` | 768 px | `screenSM`, `screenSMMin`, `screenMD`, `screenMDMin`: 768; `screenSMMax`, `screenMDMax`: 1023 |\n| `breakpoint.lg` | 1024 px | `screenLG`, `screenLGMin`: 1024; `screenLGMax`: 1439 |\n| `breakpoint.xl` | 1440 px | `screenXL`, `screenXLMin`, `screenXXL`, `screenXXLMin`: 1440 |\n\nAnt Design Vue has six breakpoints and Beehexa has four, so `sm` switches with `md`, and `xxl` with `xl`. Use the `xs`, `md`, `lg` and `xl` props of `a-col`.\n\nThe props of `a-col` and the responsive `gutter` of `a-row` then switch at the Beehexa widths. Do not use `xxxl`: its media query is malformed in Ant Design Vue 4.2.6 and never matches.\n\n## Grid\n\nAnt Design Vue divides a row into 24 parts. The Beehexa [grid](/foundations/styles/layout/grid/) has 4, 8 or 12 columns, and each one fits 24 exactly.\n\n| Beehexa grid | Window | `a-col` span |\n|---|---|---|\n| 4 columns | Below 768 px | Beehexa span × 6 |\n| 8 columns | 768 to 1023 px | Beehexa span × 3 |\n| 12 columns | 1024 px and up | Beehexa span × 2 |\n\n| Layout | Beehexa spans (4 / 8 / 12 / 12) | Props of each `a-col` |\n|---|---|---|\n| Cards, 1 to 4 a row | 4 / 4 / 4 / 3 | `:xs=\"24\" :md=\"12\" :lg=\"8\" :xl=\"6\"` |\n| Main panel | 4 / 8 / 8 / 9 | `:xs=\"24\" :lg=\"16\" :xl=\"18\"` |\n| Side panel | 4 / 8 / 4 / 3 | `:xs=\"24\" :lg=\"8\" :xl=\"6\"` |\n| Summary tile | 2 / 2 / 3 / 2 | `:xs=\"12\" :md=\"6\" :xl=\"4\"` |\n\nAnt Design Vue rows have no gutter by default. Set it from the spacing tokens, and set the page margin on the content area.\n\n```vue\n<a-row :gutter=\"[{ xs: 16, md: 24 }, { xs: 16, md: 24 }]\">\n <a-col :xs=\"24\" :md=\"12\" :lg=\"8\" :xl=\"6\">\n <OrderSummary />\n </a-col>\n</a-row>\n```\n\n## App frame\n\n| Region | Beehexa | Ant Design Vue |\n|---|---|---|\n| Header | 48 px | `<a-layout-header style=\"height: 48px; line-height: 48px\">` |\n| Side navigation, open | 280 px | `<a-layout-sider :width=\"280\">` |\n| Side navigation, collapsed | 64 px | `<a-layout-sider :collapsed-width=\"64\">` |\n\nThe header is 64 px by default and has no token for its height, so set it in the header’s style.\n\nThe `breakpoint` prop of `a-layout-sider` uses fixed widths that ignore the `screen*` tokens. Do not use it. Set `collapsed` from your own media query and the user’s choice: open from 1024 px, collapsed to the rail when the user asks, and the choice remembered. Below 1024 px, hide the sider and show the menu in `a-drawer`.\n\nSee [Layout](/foundations/styles/layout/) for the frame.\n",
1082
- "raw": "---\ntitle: Ant Design Vue theme\ndescription: Make Ant Design Vue components use Beehexa design tokens, breakpoints, grid, control heights and app frame.\norder: 3\n---\n\nTokens and full rules are available as local `@beehexa/design-tokens` and `@beehexa/design-rules` packages. They are not released to npm yet. There is no exported `/antdv` theme subpath: keep a framework adapter in your application and derive its values from the installed token package.\n\n**Beehexa tokens are the source of truth. Ant Design Vue only reads them.**\n\nThis page is the only place where the Beehexa foundations meet Ant Design Vue. The foundation pages stay the same whatever the product is built with.\n\n## Usage\n\n```vue\n<script setup>\nimport { tokens } from '@beehexa/design-tokens';\nimport '@beehexa/design-tokens/css';\n\n// The framework adapter selects semantic roles, not a new application palette.\nconst theme = {\n token: {\n colorPrimary: tokens.light['color.background.neutral.bold'],\n colorText: tokens.light['color.text'],\n colorBorder: tokens.light['color.border'],\n fontFamily: tokens.light['font.family.sans'],\n },\n};\n</script>\n\n<template>\n <a-config-provider :theme=\"theme\">\n <App />\n </a-config-provider>\n</template>\n```\n\nThis light-mode colour/font example is not the complete theme recipe. Apply the mappings below\nin your adapter, resolve `rem` to pixels at numeric API boundaries, and recompute from\n`{ ...tokens.light, ...tokens.dark }` for dark mode and the `tokens.vi` typography alternatives\nfor Vietnamese. Read the installed rule documents before implementing states or components.\n\n## Token mapping\n\n| Ant Design token | Beehexa token |\n| --- | --- |\n| `colorPrimary` | `color.background.neutral.bold` |\n| `colorText` | `color.text` |\n| `colorBorder` | `color.border` |\n| `borderRadius` | `radius.100` |\n| `fontFamily` | `font.family.sans` |\n\n## Spacing\n\nAnt Design Vue sizes come from `sizeUnit` and `sizeStep`. Keep both at 4, so `size` is 16 px. The theme then sets each size from a [spacing](/foundations/styles/spacing/) token.\n\n| Beehexa token | Value | Ant Design Vue tokens |\n|---|---|---|\n| `space.050` | 4 px | `sizeXXS, paddingXXS, marginXXS` |\n| `space.100` | 8 px | `sizeXS, paddingXS, marginXS` |\n| `space.150` | 12 px | `sizeSM, paddingSM, marginSM` |\n| `space.200` | 16 px | `size, sizeMS, padding, margin` |\n| `space.250` | 20 px | `sizeMD, paddingMD, marginMD` |\n| `space.300` | 24 px | `sizeLG, paddingLG, marginLG` |\n| `space.400` | 32 px | `sizeXL, paddingXL, marginXL` |\n| `space.600` | 48 px | `sizeXXL, marginXXL` |\n\n`space.0`, `space.025`, `space.075`, `space.500`, `space.800` and `space.1000` have no Ant Design Vue token. Use their CSS variables in your own styles.\n\nProps that take a number, such as `size` on `a-space` and `gutter` on `a-row`, take pixels. Use a value from the scale: `<a-space :size=\"8\">`.\n\n## Control height\n\n| Beehexa token | Height | Ant Design Vue token | Component prop |\n|---|---|---|---|\n| `size.control.small` | 24 px | `controlHeightSM` | `size=\"small\"` |\n| `size.control.default` | 32 px | `controlHeight` | None |\n| `size.control.large` | 40 px | `controlHeightLG` | `size=\"large\"` |\n\nThese are Ant Design Vue’s own heights. The theme still sets each one from its size token, so a change to the token reaches the components. See [Size and density](/foundations/styles/size-and-density/).\n\n## Breakpoints\n\n**Override the `screen*` tokens with the Beehexa [breakpoints](/foundations/styles/layout/breakpoints/).** The default Ant Design Vue values are different (576, 992, 1200 and 1600 px).\n\nThe `Min` and `Max` tokens are computed from the defaults, not from your overrides. Set them too: each `Max` is the next breakpoint minus 1.\n\n| Beehexa | Value | Ant Design Vue tokens |\n|---|---|---|\n| `breakpoint.xs` | 0 | `screenXSMax: 767` |\n| `breakpoint.md` | 768 px | `screenSM`, `screenSMMin`, `screenMD`, `screenMDMin`: 768; `screenSMMax`, `screenMDMax`: 1023 |\n| `breakpoint.lg` | 1024 px | `screenLG`, `screenLGMin`: 1024; `screenLGMax`: 1439 |\n| `breakpoint.xl` | 1440 px | `screenXL`, `screenXLMin`, `screenXXL`, `screenXXLMin`: 1440 |\n\nAnt Design Vue has six breakpoints and Beehexa has four, so `sm` switches with `md`, and `xxl` with `xl`. Use the `xs`, `md`, `lg` and `xl` props of `a-col`.\n\nThe props of `a-col` and the responsive `gutter` of `a-row` then switch at the Beehexa widths. Do not use `xxxl`: its media query is malformed in Ant Design Vue 4.2.6 and never matches.\n\n## Grid\n\nAnt Design Vue divides a row into 24 parts. The Beehexa [grid](/foundations/styles/layout/grid/) has 4, 8 or 12 columns, and each one fits 24 exactly.\n\n| Beehexa grid | Window | `a-col` span |\n|---|---|---|\n| 4 columns | Below 768 px | Beehexa span × 6 |\n| 8 columns | 768 to 1023 px | Beehexa span × 3 |\n| 12 columns | 1024 px and up | Beehexa span × 2 |\n\n| Layout | Beehexa spans (4 / 8 / 12 / 12) | Props of each `a-col` |\n|---|---|---|\n| Cards, 1 to 4 a row | 4 / 4 / 4 / 3 | `:xs=\"24\" :md=\"12\" :lg=\"8\" :xl=\"6\"` |\n| Main panel | 4 / 8 / 8 / 9 | `:xs=\"24\" :lg=\"16\" :xl=\"18\"` |\n| Side panel | 4 / 8 / 4 / 3 | `:xs=\"24\" :lg=\"8\" :xl=\"6\"` |\n| Summary tile | 2 / 2 / 3 / 2 | `:xs=\"12\" :md=\"6\" :xl=\"4\"` |\n\nAnt Design Vue rows have no gutter by default. Set it from the spacing tokens, and set the page margin on the content area.\n\n```vue\n<a-row :gutter=\"[{ xs: 16, md: 24 }, { xs: 16, md: 24 }]\">\n <a-col :xs=\"24\" :md=\"12\" :lg=\"8\" :xl=\"6\">\n <OrderSummary />\n </a-col>\n</a-row>\n```\n\n## App frame\n\n| Region | Beehexa | Ant Design Vue |\n|---|---|---|\n| Header | 48 px | `<a-layout-header style=\"height: 48px; line-height: 48px\">` |\n| Side navigation, open | 280 px | `<a-layout-sider :width=\"280\">` |\n| Side navigation, collapsed | 64 px | `<a-layout-sider :collapsed-width=\"64\">` |\n\nThe header is 64 px by default and has no token for its height, so set it in the header’s style.\n\nThe `breakpoint` prop of `a-layout-sider` uses fixed widths that ignore the `screen*` tokens. Do not use it. Set `collapsed` from your own media query and the user’s choice: open from 1024 px, collapsed to the rail when the user asks, and the choice remembered. Below 1024 px, hide the sider and show the menu in `a-drawer`.\n\nSee [Layout](/foundations/styles/layout/) for the frame.\n",
1050
+ "body": "\n`@beehexa/ant-design-vue-tokens` owns the reusable Ant Design Vue 4 adapter.\nUse its typed ESM API and companion CSS, backed by `@beehexa/design-tokens`.\nFrameworks are peers: `ant-design-vue@^4.2.6` and `vue@^3.3.0`; neither is bundled.\nUnreleased `0.0.0` packages use explicit local development references; only the authorized\nrelease runner stamps real package versions. Do not copy a theme palette into an application.\n\n**Beehexa tokens are the source of truth. Ant Design Vue only reads them.**\n\nThis page is the only place where the Beehexa foundations meet Ant Design Vue. The foundation pages stay the same whatever the product is built with.\n\n## Usage\n\n```vue\n<script setup lang=\"ts\">\nimport { computed, watchEffect } from 'vue';\nimport { createAntDesignVueTheme, getAntDesignVuePopupContainer } from '@beehexa/ant-design-vue-tokens';\nimport '@beehexa/design-tokens/css';\nimport '@beehexa/ant-design-vue-tokens/css';\n\nconst props = defineProps<{ dark: boolean; locale: 'en' | 'vi' }>();\nconst theme = computed(() => createAntDesignVueTheme({\n dark: props.dark, locale: props.locale\n}));\nwatchEffect(() => {\n if (typeof document === 'undefined') return;\n document.documentElement.dataset.theme = props.dark ? 'dark' : 'light';\n document.documentElement.lang = props.locale;\n});\n</script>\n\n<template>\n <a-config-provider :theme=\"theme\" :get-popup-container=\"getAntDesignVuePopupContainer\">\n <App />\n </a-config-provider>\n</template>\n```\n\n`createAntDesignVueTheme({ dark = false, locale = 'en' } = {})` returns\nthe native `ThemeConfig`. Recompute on theme/language changes; each call\nreturns a fresh object. `locale` selects source typography, not translated AntD messages.\nPass the appropriate AntD language pack through `ConfigProvider.locale`, and configure the\ndate library separately. Render native `useMessage`, `useNotification` and `useModal`\nholders in a feedback host inside the sole root provider. Bind application notify facades\nto those hook APIs; never use detached raw static feedback APIs. The factory sets\n`hashed: false` because AntD4 contextual message/notification holders otherwise retain\nstale hashes across theme/locale changes. Keep an existing notice open while switching\ndark/Vietnamese to light/English; its typography and paint must follow the active theme.\n\nKeep document `data-theme` and `lang` synchronized for teleported overlays. Import\ncompanion CSS after application/framework styles. Use a native 16px root and 14px body;\nnumeric APIs resolve source rem at 16px. The pixel entrypoint is not the dashboard path.\n\n## Overlay ownership and bounded native content\n\nTriggered popups use `getAntDesignVuePopupContainer` to stay inside their nearest native\nModal/Drawer or custom `data-bh-overlay-owner` host. Native Modal/Drawer roots remain\nbody-hosted for viewport geometry. Provider-bound modal facades default their invocation\n`zIndex` through `getAntDesignVueModalZIndex()` while preserving explicit caller values;\nthis keeps keyboard/awaited confirmations above their live owner. Nested drawers use\n`getAntDesignVueOverlayZIndex(fullscreen, ownerZIndex)` as `rootStyle.zIndex` so\nsurface and mask move together; AntD4's `zIndex` prop styles only the content wrapper.\nBody-teleported fullscreen editors/images and fullscreen native Modals capture\n`getAntDesignVueFullscreenZIndex()` before mounting their root. This combines the\nfullscreen role with above-owner ordering; a fixed450 must not fall below a nested\nnative Drawer451. Mark custom roots only once they are active, avoiding self-counting.\nTour's inline native default also requires its public\n`zIndex` prop bound to `z-index.spotlight`.\n\nThe companion CSS provides opt-in native structural contracts, not application selectors:\n\n- `bh-ant-fill-drawer` / `bh-ant-drawer-flush`: bounded body, intrinsic header/footer,\n optional zero body padding; bind through `rootClassName`.\n- `bh-ant-fill-tabs`: bounded native wrappers and active pane. Nested tabs opt in separately;\n `bh-ant-fill-tabs--scroll` enables pane scrolling and `bh-ant-tabs-mobile-inset` adds the\n source mobile inset. Inactive panes stay hidden.\n- `bh-ant-fill-spin` / `bh-ant-fill-card`: carry an existing bounded host through native wrappers.\n- `bh-ant-inspection-descriptions`: source desktop label minimum and mobile stacked rows.\n- `bh-ant-data-table`: generic pending/success/error row classes plus public `customCell`\n markers `data-bh-cell-interaction=\"editable|readonly\"` and `data-bh-cell-state=\"changed\"`.\n Native selection outranks operational row paint; changed cells keep diff paint on hover.\n `bh-ant-table-nowrap` is an independent horizontal-content opt-in.\n\nKeep custom business content and host geometry in the consumer. Do not recreate these\nnative selectors through per-page `:deep(.ant-*)`, global overrides or priority escalation.\n\n## Token mapping\n\n| Ant Design token | Beehexa token |\n| --- | --- |\n| `colorPrimary` | `color.background.neutral.bold` |\n| `colorText` | `color.text` |\n| `colorBorder` | `color.border` |\n| `borderRadius` | `radius.100` |\n| `fontFamily` | `font.family.sans` |\n\nThe adapter also pins semantic hover/pressed/disabled/link/status/selection/focus roles instead\nof allowing a framework-generated blue palette to leak through. Inputs, selects, checkboxes\nand radios use `color.border.bold` while cards/tables use `color.border`. Layout header and\nsider and mobile navigation drawer share `color.surface.subtle`; there is no separate shell palette or nested isolated\ntheme. Use `font.body.default` for table data, `font.label.small` for headers/tags,\n`font.heading.medium` for modal titles and `font.heading.small` for drawer titles.\n\n### Ant Design Vue 4 component contracts\n\n- Table reads `colorFillAlter`, `colorTextHeading`, `controlItemBgActive` and\n `controlItemBgActiveHover`. AntD5 names such as `headerBg` and `headerColor` are ignored\n by AntD Vue 4.2.6 and must not be used.\n- Menu reads `colorItem*`, `radiusItem`, `radiusSubMenuItem` and `colorActiveBar*`.\n Explicit `theme=\"dark\"` menus receive the same source roles. Selection has a visible bar,\n not a heavier label that shifts its neighbours or merely a changed fill.\n- Form controls share source outline/focus/disabled roles. Validation retains danger/warning\n text/icons and native state semantics. Do not replace meaningful input borders with divider\n hairlines.\n- Tag status presets are `success`, `processing`, `warning`, `error`; default is neutral.\n They use source foreground and outline pairs. Arbitrary hue presets are not status names.\n Badge counts are neutral; error/processing status dots retain their semantics.\n- Tooltip and Message use the inverse surface/text pair. Modal/Drawer content uses surface,\n scrim and overlay elevation. Progress is neutral by default and semantic on success/error.\n\n### Companion CSS and structural classes\n\nUse component tokens first. The package CSS fills actual AntD4 gaps: semantic label/header/title\ntypography, hard-coded submenu fill, selected bar colors, keyboard focus offsets, safe areas,\nresponsive Tour placement, reduced motion and neutral Badge count without recoloring error dots.\nApplication selectors and palette overrides belong neither in that CSS nor in a dashboard theme.\nConsumers retain genuine portal layout and scrolling mechanics only. Framework paint\nand typography fixes belong to the package, not duplicated consumer overrides.\n\n`bh-ant-tag-large` on a Tag selects the source large label (24px minimum, 8px inline padding);\nthe default is 20px minimum/6px. Both grow for Vietnamese line boxes rather than clipping marks.\n`bh-ant-tree-fill` on a Tree opts into a bounded flex host and virtual-list height; intrinsic\ntrees must not use it.\n\nFor data inspection, bind `width=\"var(--bh-ant-overlay-width)\"` and apply\n`bh-ant-inspection-modal` or Drawer `rootClassName=\"bh-ant-inspection-drawer\"`.\nAdd `bh-ant-inspection-modal--wide` / `bh-ant-inspection-drawer--wide` only for an explicit\ncontent-heavy variant. The variable selects `layout.overlay.default` / `.wide`, and `.mobile`\nbelow `breakpoint.lg`. Short confirmations and navigation drawers retain their own widths.\nFullscreen modes are Modal `wrapClassName=\"full-screen\"` and Drawer\n`rootClassName=\"fullscreen\"`; AntD4 Modal has no `rootClassName` prop. These preserve\nbounded scroll mechanics, not decoration.\n\n### Verify the actual framework\n\nExercise light/dark × English/Vietnamese with the real CSS imported: buttons and validated\ninputs/selects, ordinary/selected/hovered table row checkboxes, sorting/filter portals,\nexpanded/collapsed/horizontal and submenu navigation, form help/error, Tooltip/Message,\nModal/Drawer and default/wide/fullscreen inspection at 1023/1024px. Check keyboard focus,\ntouch hit areas, reduced motion, narrow Tour and focus return. Use\n**ỔN ĐỊNH · ẤN ĐỘ · ẪM · Ở ĐÂY CÓ ƯU ĐÃI** in controls, tags and rows.\nCompilation alone does not establish those rendering/interaction outcomes.\n\n\n## Spacing\n\nAnt Design Vue sizes come from `sizeUnit` and `sizeStep`. Keep both at 4, so `size` is 16 px. The theme then sets each size from a [spacing](/foundations/styles/spacing/) token.\n\n| Beehexa token | Value | Ant Design Vue tokens |\n|---|---|---|\n| `space.050` | 4 px | `sizeXXS, paddingXXS, marginXXS` |\n| `space.100` | 8 px | `sizeXS, paddingXS, marginXS` |\n| `space.150` | 12 px | `sizeSM, paddingSM, marginSM` |\n| `space.200` | 16 px | `size, sizeMS, padding, margin` |\n| `space.250` | 20 px | `sizeMD, paddingMD, marginMD` |\n| `space.300` | 24 px | `sizeLG, paddingLG, marginLG` |\n| `space.400` | 32 px | `sizeXL, paddingXL, marginXL` |\n| `space.600` | 48 px | `sizeXXL, marginXXL` |\n\n`space.0`, `space.025`, `space.075`, `space.500`, `space.800` and `space.1000` have no Ant Design Vue token. Use their CSS variables in your own styles.\n\nProps that take a number, such as `size` on `a-space` and `gutter` on `a-row`, take pixels. Use a value from the scale: `<a-space :size=\"8\">`.\n\n## Control height\n\n| Beehexa token | Height | Ant Design Vue token | Component prop |\n|---|---|---|---|\n| `size.control.small` | 24 px | `controlHeightSM` | `size=\"small\"` |\n| `size.control.default` | 32 px | `controlHeight` | None |\n| `size.control.large` | 40 px | `controlHeightLG` | `size=\"large\"` |\n\nThese are Ant Design Vue’s own heights. The theme still sets each one from its size token, so a change to the token reaches the components. See [Size and density](/foundations/styles/size-and-density/).\n\n## Breakpoints\n\n**Override the `screen*` tokens with the Beehexa [breakpoints](/foundations/styles/layout/breakpoints/).** The default Ant Design Vue values are different (576, 992, 1200 and 1600 px).\n\nThe `Min` and `Max` tokens are computed from the defaults, not from your overrides. Set them too: each `Max` is the next breakpoint minus 1.\n\n| Beehexa | Value | Ant Design Vue tokens |\n|---|---|---|\n| `breakpoint.xs` | 0 | `screenXSMax: 767` |\n| `breakpoint.md` | 768 px | `screenSM`, `screenSMMin`, `screenMD`, `screenMDMin`: 768; `screenSMMax`, `screenMDMax`: 1023 |\n| `breakpoint.lg` | 1024 px | `screenLG`, `screenLGMin`: 1024; `screenLGMax`: 1439 |\n| `breakpoint.xl` | 1440 px | `screenXL`, `screenXLMin`, `screenXXL`, `screenXXLMin`: 1440 |\n\nAnt Design Vue has six breakpoints and Beehexa has four, so `sm` switches with `md`, and `xxl` with `xl`. Use the `xs`, `md`, `lg` and `xl` props of `a-col`.\n\nThe props of `a-col` and the responsive `gutter` of `a-row` then switch at the Beehexa widths. Do not use `xxxl`: its media query is malformed in Ant Design Vue 4.2.6 and never matches.\n\n## Grid\n\nAnt Design Vue divides a row into 24 parts. The Beehexa [grid](/foundations/styles/layout/grid/) has 4, 8 or 12 columns, and each one fits 24 exactly.\n\n| Beehexa grid | Window | `a-col` span |\n|---|---|---|\n| 4 columns | Below 768 px | Beehexa span × 6 |\n| 8 columns | 768 to 1023 px | Beehexa span × 3 |\n| 12 columns | 1024 px and up | Beehexa span × 2 |\n\n| Layout | Beehexa spans (4 / 8 / 12 / 12) | Props of each `a-col` |\n|---|---|---|\n| Cards, 1 to 4 a row | 4 / 4 / 4 / 3 | `:xs=\"24\" :md=\"12\" :lg=\"8\" :xl=\"6\"` |\n| Main panel | 4 / 8 / 8 / 9 | `:xs=\"24\" :lg=\"16\" :xl=\"18\"` |\n| Side panel | 4 / 8 / 4 / 3 | `:xs=\"24\" :lg=\"8\" :xl=\"6\"` |\n| Summary tile | 2 / 2 / 3 / 2 | `:xs=\"12\" :md=\"6\" :xl=\"4\"` |\n\nAnt Design Vue rows have no gutter by default. Set it from the spacing tokens, and set the page margin on the content area.\n\n```vue\n<a-row :gutter=\"[{ xs: 16, md: 24 }, { xs: 16, md: 24 }]\">\n <a-col :xs=\"24\" :md=\"12\" :lg=\"8\" :xl=\"6\">\n <OrderSummary />\n </a-col>\n</a-row>\n```\n\n## App frame\n\n| Region | Beehexa | Ant Design Vue |\n|---|---|---|\n| Header | 48 px | `<a-layout-header style=\"height: 48px; line-height: 48px\">` |\n| Side navigation, open | 280 px | `<a-layout-sider :width=\"280\">` |\n| Side navigation, collapsed | 64 px | `<a-layout-sider :collapsed-width=\"64\">` |\n\nThe header is 64 px by default and has no token for its height, so set it in the header’s style.\n\nThe `breakpoint` prop of `a-layout-sider` uses fixed widths that ignore the `screen*` tokens. Do not use it. Set `collapsed` from your own media query and the user’s choice: open from 1024 px, collapsed to the rail when the user asks, and the choice remembered. Below 1024 px, hide the sider and show the menu in `a-drawer`.\n\nSee [Layout](/foundations/styles/layout/) for the frame.\n",
1051
+ "raw": "---\ntitle: Ant Design Vue theme\ndescription: Make Ant Design Vue components use Beehexa design tokens, breakpoints, grid, control heights and app frame.\norder: 3\n---\n\n`@beehexa/ant-design-vue-tokens` owns the reusable Ant Design Vue 4 adapter.\nUse its typed ESM API and companion CSS, backed by `@beehexa/design-tokens`.\nFrameworks are peers: `ant-design-vue@^4.2.6` and `vue@^3.3.0`; neither is bundled.\nUnreleased `0.0.0` packages use explicit local development references; only the authorized\nrelease runner stamps real package versions. Do not copy a theme palette into an application.\n\n**Beehexa tokens are the source of truth. Ant Design Vue only reads them.**\n\nThis page is the only place where the Beehexa foundations meet Ant Design Vue. The foundation pages stay the same whatever the product is built with.\n\n## Usage\n\n```vue\n<script setup lang=\"ts\">\nimport { computed, watchEffect } from 'vue';\nimport { createAntDesignVueTheme, getAntDesignVuePopupContainer } from '@beehexa/ant-design-vue-tokens';\nimport '@beehexa/design-tokens/css';\nimport '@beehexa/ant-design-vue-tokens/css';\n\nconst props = defineProps<{ dark: boolean; locale: 'en' | 'vi' }>();\nconst theme = computed(() => createAntDesignVueTheme({\n dark: props.dark, locale: props.locale\n}));\nwatchEffect(() => {\n if (typeof document === 'undefined') return;\n document.documentElement.dataset.theme = props.dark ? 'dark' : 'light';\n document.documentElement.lang = props.locale;\n});\n</script>\n\n<template>\n <a-config-provider :theme=\"theme\" :get-popup-container=\"getAntDesignVuePopupContainer\">\n <App />\n </a-config-provider>\n</template>\n```\n\n`createAntDesignVueTheme({ dark = false, locale = 'en' } = {})` returns\nthe native `ThemeConfig`. Recompute on theme/language changes; each call\nreturns a fresh object. `locale` selects source typography, not translated AntD messages.\nPass the appropriate AntD language pack through `ConfigProvider.locale`, and configure the\ndate library separately. Render native `useMessage`, `useNotification` and `useModal`\nholders in a feedback host inside the sole root provider. Bind application notify facades\nto those hook APIs; never use detached raw static feedback APIs. The factory sets\n`hashed: false` because AntD4 contextual message/notification holders otherwise retain\nstale hashes across theme/locale changes. Keep an existing notice open while switching\ndark/Vietnamese to light/English; its typography and paint must follow the active theme.\n\nKeep document `data-theme` and `lang` synchronized for teleported overlays. Import\ncompanion CSS after application/framework styles. Use a native 16px root and 14px body;\nnumeric APIs resolve source rem at 16px. The pixel entrypoint is not the dashboard path.\n\n## Overlay ownership and bounded native content\n\nTriggered popups use `getAntDesignVuePopupContainer` to stay inside their nearest native\nModal/Drawer or custom `data-bh-overlay-owner` host. Native Modal/Drawer roots remain\nbody-hosted for viewport geometry. Provider-bound modal facades default their invocation\n`zIndex` through `getAntDesignVueModalZIndex()` while preserving explicit caller values;\nthis keeps keyboard/awaited confirmations above their live owner. Nested drawers use\n`getAntDesignVueOverlayZIndex(fullscreen, ownerZIndex)` as `rootStyle.zIndex` so\nsurface and mask move together; AntD4's `zIndex` prop styles only the content wrapper.\nBody-teleported fullscreen editors/images and fullscreen native Modals capture\n`getAntDesignVueFullscreenZIndex()` before mounting their root. This combines the\nfullscreen role with above-owner ordering; a fixed450 must not fall below a nested\nnative Drawer451. Mark custom roots only once they are active, avoiding self-counting.\nTour's inline native default also requires its public\n`zIndex` prop bound to `z-index.spotlight`.\n\nThe companion CSS provides opt-in native structural contracts, not application selectors:\n\n- `bh-ant-fill-drawer` / `bh-ant-drawer-flush`: bounded body, intrinsic header/footer,\n optional zero body padding; bind through `rootClassName`.\n- `bh-ant-fill-tabs`: bounded native wrappers and active pane. Nested tabs opt in separately;\n `bh-ant-fill-tabs--scroll` enables pane scrolling and `bh-ant-tabs-mobile-inset` adds the\n source mobile inset. Inactive panes stay hidden.\n- `bh-ant-fill-spin` / `bh-ant-fill-card`: carry an existing bounded host through native wrappers.\n- `bh-ant-inspection-descriptions`: source desktop label minimum and mobile stacked rows.\n- `bh-ant-data-table`: generic pending/success/error row classes plus public `customCell`\n markers `data-bh-cell-interaction=\"editable|readonly\"` and `data-bh-cell-state=\"changed\"`.\n Native selection outranks operational row paint; changed cells keep diff paint on hover.\n `bh-ant-table-nowrap` is an independent horizontal-content opt-in.\n\nKeep custom business content and host geometry in the consumer. Do not recreate these\nnative selectors through per-page `:deep(.ant-*)`, global overrides or priority escalation.\n\n## Token mapping\n\n| Ant Design token | Beehexa token |\n| --- | --- |\n| `colorPrimary` | `color.background.neutral.bold` |\n| `colorText` | `color.text` |\n| `colorBorder` | `color.border` |\n| `borderRadius` | `radius.100` |\n| `fontFamily` | `font.family.sans` |\n\nThe adapter also pins semantic hover/pressed/disabled/link/status/selection/focus roles instead\nof allowing a framework-generated blue palette to leak through. Inputs, selects, checkboxes\nand radios use `color.border.bold` while cards/tables use `color.border`. Layout header and\nsider and mobile navigation drawer share `color.surface.subtle`; there is no separate shell palette or nested isolated\ntheme. Use `font.body.default` for table data, `font.label.small` for headers/tags,\n`font.heading.medium` for modal titles and `font.heading.small` for drawer titles.\n\n### Ant Design Vue 4 component contracts\n\n- Table reads `colorFillAlter`, `colorTextHeading`, `controlItemBgActive` and\n `controlItemBgActiveHover`. AntD5 names such as `headerBg` and `headerColor` are ignored\n by AntD Vue 4.2.6 and must not be used.\n- Menu reads `colorItem*`, `radiusItem`, `radiusSubMenuItem` and `colorActiveBar*`.\n Explicit `theme=\"dark\"` menus receive the same source roles. Selection has a visible bar,\n not a heavier label that shifts its neighbours or merely a changed fill.\n- Form controls share source outline/focus/disabled roles. Validation retains danger/warning\n text/icons and native state semantics. Do not replace meaningful input borders with divider\n hairlines.\n- Tag status presets are `success`, `processing`, `warning`, `error`; default is neutral.\n They use source foreground and outline pairs. Arbitrary hue presets are not status names.\n Badge counts are neutral; error/processing status dots retain their semantics.\n- Tooltip and Message use the inverse surface/text pair. Modal/Drawer content uses surface,\n scrim and overlay elevation. Progress is neutral by default and semantic on success/error.\n\n### Companion CSS and structural classes\n\nUse component tokens first. The package CSS fills actual AntD4 gaps: semantic label/header/title\ntypography, hard-coded submenu fill, selected bar colors, keyboard focus offsets, safe areas,\nresponsive Tour placement, reduced motion and neutral Badge count without recoloring error dots.\nApplication selectors and palette overrides belong neither in that CSS nor in a dashboard theme.\nConsumers retain genuine portal layout and scrolling mechanics only. Framework paint\nand typography fixes belong to the package, not duplicated consumer overrides.\n\n`bh-ant-tag-large` on a Tag selects the source large label (24px minimum, 8px inline padding);\nthe default is 20px minimum/6px. Both grow for Vietnamese line boxes rather than clipping marks.\n`bh-ant-tree-fill` on a Tree opts into a bounded flex host and virtual-list height; intrinsic\ntrees must not use it.\n\nFor data inspection, bind `width=\"var(--bh-ant-overlay-width)\"` and apply\n`bh-ant-inspection-modal` or Drawer `rootClassName=\"bh-ant-inspection-drawer\"`.\nAdd `bh-ant-inspection-modal--wide` / `bh-ant-inspection-drawer--wide` only for an explicit\ncontent-heavy variant. The variable selects `layout.overlay.default` / `.wide`, and `.mobile`\nbelow `breakpoint.lg`. Short confirmations and navigation drawers retain their own widths.\nFullscreen modes are Modal `wrapClassName=\"full-screen\"` and Drawer\n`rootClassName=\"fullscreen\"`; AntD4 Modal has no `rootClassName` prop. These preserve\nbounded scroll mechanics, not decoration.\n\n### Verify the actual framework\n\nExercise light/dark × English/Vietnamese with the real CSS imported: buttons and validated\ninputs/selects, ordinary/selected/hovered table row checkboxes, sorting/filter portals,\nexpanded/collapsed/horizontal and submenu navigation, form help/error, Tooltip/Message,\nModal/Drawer and default/wide/fullscreen inspection at 1023/1024px. Check keyboard focus,\ntouch hit areas, reduced motion, narrow Tour and focus return. Use\n**ỔN ĐỊNH · ẤN ĐỘ · ẪM · Ở ĐÂY CÓ ƯU ĐÃI** in controls, tags and rows.\nCompilation alone does not establish those rendering/interaction outcomes.\n\n\n## Spacing\n\nAnt Design Vue sizes come from `sizeUnit` and `sizeStep`. Keep both at 4, so `size` is 16 px. The theme then sets each size from a [spacing](/foundations/styles/spacing/) token.\n\n| Beehexa token | Value | Ant Design Vue tokens |\n|---|---|---|\n| `space.050` | 4 px | `sizeXXS, paddingXXS, marginXXS` |\n| `space.100` | 8 px | `sizeXS, paddingXS, marginXS` |\n| `space.150` | 12 px | `sizeSM, paddingSM, marginSM` |\n| `space.200` | 16 px | `size, sizeMS, padding, margin` |\n| `space.250` | 20 px | `sizeMD, paddingMD, marginMD` |\n| `space.300` | 24 px | `sizeLG, paddingLG, marginLG` |\n| `space.400` | 32 px | `sizeXL, paddingXL, marginXL` |\n| `space.600` | 48 px | `sizeXXL, marginXXL` |\n\n`space.0`, `space.025`, `space.075`, `space.500`, `space.800` and `space.1000` have no Ant Design Vue token. Use their CSS variables in your own styles.\n\nProps that take a number, such as `size` on `a-space` and `gutter` on `a-row`, take pixels. Use a value from the scale: `<a-space :size=\"8\">`.\n\n## Control height\n\n| Beehexa token | Height | Ant Design Vue token | Component prop |\n|---|---|---|---|\n| `size.control.small` | 24 px | `controlHeightSM` | `size=\"small\"` |\n| `size.control.default` | 32 px | `controlHeight` | None |\n| `size.control.large` | 40 px | `controlHeightLG` | `size=\"large\"` |\n\nThese are Ant Design Vue’s own heights. The theme still sets each one from its size token, so a change to the token reaches the components. See [Size and density](/foundations/styles/size-and-density/).\n\n## Breakpoints\n\n**Override the `screen*` tokens with the Beehexa [breakpoints](/foundations/styles/layout/breakpoints/).** The default Ant Design Vue values are different (576, 992, 1200 and 1600 px).\n\nThe `Min` and `Max` tokens are computed from the defaults, not from your overrides. Set them too: each `Max` is the next breakpoint minus 1.\n\n| Beehexa | Value | Ant Design Vue tokens |\n|---|---|---|\n| `breakpoint.xs` | 0 | `screenXSMax: 767` |\n| `breakpoint.md` | 768 px | `screenSM`, `screenSMMin`, `screenMD`, `screenMDMin`: 768; `screenSMMax`, `screenMDMax`: 1023 |\n| `breakpoint.lg` | 1024 px | `screenLG`, `screenLGMin`: 1024; `screenLGMax`: 1439 |\n| `breakpoint.xl` | 1440 px | `screenXL`, `screenXLMin`, `screenXXL`, `screenXXLMin`: 1440 |\n\nAnt Design Vue has six breakpoints and Beehexa has four, so `sm` switches with `md`, and `xxl` with `xl`. Use the `xs`, `md`, `lg` and `xl` props of `a-col`.\n\nThe props of `a-col` and the responsive `gutter` of `a-row` then switch at the Beehexa widths. Do not use `xxxl`: its media query is malformed in Ant Design Vue 4.2.6 and never matches.\n\n## Grid\n\nAnt Design Vue divides a row into 24 parts. The Beehexa [grid](/foundations/styles/layout/grid/) has 4, 8 or 12 columns, and each one fits 24 exactly.\n\n| Beehexa grid | Window | `a-col` span |\n|---|---|---|\n| 4 columns | Below 768 px | Beehexa span × 6 |\n| 8 columns | 768 to 1023 px | Beehexa span × 3 |\n| 12 columns | 1024 px and up | Beehexa span × 2 |\n\n| Layout | Beehexa spans (4 / 8 / 12 / 12) | Props of each `a-col` |\n|---|---|---|\n| Cards, 1 to 4 a row | 4 / 4 / 4 / 3 | `:xs=\"24\" :md=\"12\" :lg=\"8\" :xl=\"6\"` |\n| Main panel | 4 / 8 / 8 / 9 | `:xs=\"24\" :lg=\"16\" :xl=\"18\"` |\n| Side panel | 4 / 8 / 4 / 3 | `:xs=\"24\" :lg=\"8\" :xl=\"6\"` |\n| Summary tile | 2 / 2 / 3 / 2 | `:xs=\"12\" :md=\"6\" :xl=\"4\"` |\n\nAnt Design Vue rows have no gutter by default. Set it from the spacing tokens, and set the page margin on the content area.\n\n```vue\n<a-row :gutter=\"[{ xs: 16, md: 24 }, { xs: 16, md: 24 }]\">\n <a-col :xs=\"24\" :md=\"12\" :lg=\"8\" :xl=\"6\">\n <OrderSummary />\n </a-col>\n</a-row>\n```\n\n## App frame\n\n| Region | Beehexa | Ant Design Vue |\n|---|---|---|\n| Header | 48 px | `<a-layout-header style=\"height: 48px; line-height: 48px\">` |\n| Side navigation, open | 280 px | `<a-layout-sider :width=\"280\">` |\n| Side navigation, collapsed | 64 px | `<a-layout-sider :collapsed-width=\"64\">` |\n\nThe header is 64 px by default and has no token for its height, so set it in the header’s style.\n\nThe `breakpoint` prop of `a-layout-sider` uses fixed widths that ignore the `screen*` tokens. Do not use it. Set `collapsed` from your own media query and the user’s choice: open from 1024 px, collapsed to the rail when the user asks, and the choice remembered. Below 1024 px, hide the sider and show the menu in `a-drawer`.\n\nSee [Layout](/foundations/styles/layout/) for the frame.\n",
1083
1052
  "frontmatter": {
1084
1053
  "title": "Ant Design Vue theme",
1085
1054
  "description": "Make Ant Design Vue components use Beehexa design tokens, breakpoints, grid, control heights and app frame.",
1086
1055
  "order": 3
1087
1056
  }
1088
1057
  },
1058
+ {
1059
+ "id": "en/tools/application-content",
1060
+ "path": "src/content/tools/application-content.mdx",
1061
+ "documentPath": "docs/src/content/tools/application-content.mdx",
1062
+ "locale": "en",
1063
+ "kind": "guidance",
1064
+ "title": "Application content",
1065
+ "status": "active",
1066
+ "releasePhase": null,
1067
+ "planned": [],
1068
+ "body": "\n## Identity is not status\n\nA connection name, provider name or person identifies an entity. Use its readable\nname with a neutral themed tag, avatar or logo container. Do not hash names into a\nlocal colour palette or borrow success/warning/danger roles to distinguish names.\nUse operational status colours only when the displayed value actually represents\nthat status. Selected, hovered and focused identities use the ordinary interaction\nroles; the identity does not gain a second competing palette.\n\n## Partner and system marks\n\nKeep actual brand assets and their aspect ratio. Use a neutral `surface.subtle`\ncontainer, a `border` edge when needed, and `text` for textual initials. Do not\nrecreate a partner brand by colouring a fallback initial.\n\n| Content part | Source role |\n|---|---|\n| Standard partner-logo tile | `content.partner-logo.size` (40 px) |\n| Contained partner mark | `content.partner-logo.image-size` (28 px maximum) |\n| Person or permission-member avatar | `content.avatar.size` (40 px) |\n| System/provider identity container | `content.identity-mark.size` (44 px) |\n| Contained system/provider glyph | `content.identity-mark.image-size` (24 px) |\n\nThese dimensions describe the visual identity, not the interactive target. If the\nidentity is actionable, apply the source target-size and focus rules separately.\nA compact text-initial tile may use the normal control size instead of introducing\na one-off identity dimension. Numeric component/image APIs convert these source\nroles at their boundary; do not duplicate their values in consumer constants.\n\n## Empty states\n\n`content.empty-illustration.size` is a 96 px illustration container. Standard UI\nicons inside it retain the 16/20/24/32 px icon sizes described by the icon guidance;\nthe container does not authorize an arbitrary 40 px icon. Use source typography,\nspacing and semantic colours for the explanation and recovery action. Decorative\nillustrations must not be the only explanation that a list is empty or unavailable.\n",
1069
+ "raw": "---\ntitle: Application content\ndescription: Source-backed partner marks, person identities, neutral labels and empty-state illustration containers in product content.\norder: 5\n---\n\n## Identity is not status\n\nA connection name, provider name or person identifies an entity. Use its readable\nname with a neutral themed tag, avatar or logo container. Do not hash names into a\nlocal colour palette or borrow success/warning/danger roles to distinguish names.\nUse operational status colours only when the displayed value actually represents\nthat status. Selected, hovered and focused identities use the ordinary interaction\nroles; the identity does not gain a second competing palette.\n\n## Partner and system marks\n\nKeep actual brand assets and their aspect ratio. Use a neutral `surface.subtle`\ncontainer, a `border` edge when needed, and `text` for textual initials. Do not\nrecreate a partner brand by colouring a fallback initial.\n\n| Content part | Source role |\n|---|---|\n| Standard partner-logo tile | `content.partner-logo.size` (40 px) |\n| Contained partner mark | `content.partner-logo.image-size` (28 px maximum) |\n| Person or permission-member avatar | `content.avatar.size` (40 px) |\n| System/provider identity container | `content.identity-mark.size` (44 px) |\n| Contained system/provider glyph | `content.identity-mark.image-size` (24 px) |\n\nThese dimensions describe the visual identity, not the interactive target. If the\nidentity is actionable, apply the source target-size and focus rules separately.\nA compact text-initial tile may use the normal control size instead of introducing\na one-off identity dimension. Numeric component/image APIs convert these source\nroles at their boundary; do not duplicate their values in consumer constants.\n\n## Empty states\n\n`content.empty-illustration.size` is a 96 px illustration container. Standard UI\nicons inside it retain the 16/20/24/32 px icon sizes described by the icon guidance;\nthe container does not authorize an arbitrary 40 px icon. Use source typography,\nspacing and semantic colours for the explanation and recovery action. Decorative\nillustrations must not be the only explanation that a list is empty or unavailable.\n",
1070
+ "frontmatter": {
1071
+ "title": "Application content",
1072
+ "description": "Source-backed partner marks, person identities, neutral labels and empty-state illustration containers in product content.",
1073
+ "order": 5
1074
+ }
1075
+ },
1076
+ {
1077
+ "id": "en/tools/editors",
1078
+ "path": "src/content/tools/editors.mdx",
1079
+ "documentPath": "docs/src/content/tools/editors.mdx",
1080
+ "locale": "en",
1081
+ "kind": "guidance",
1082
+ "title": "Editors and resize controls",
1083
+ "status": "active",
1084
+ "releasePhase": null,
1085
+ "planned": [],
1086
+ "body": "\n## Editor canvas and syntax\n\nEditors use `editor.background` and `editor.text`, a theme-aware reading canvas. This is deliberately different from static fenced code blocks (`color.code.background` / `color.code.text`), whose dark canvas has its own paired text. Never combine the editor syntax foregrounds with that static code-block canvas.\n\nUse `editor.syntax.comment`, `.string`, `.number`, `.keyword`, `.type` and `.delimiter` for language tokens. These aliases reuse readable semantic foregrounds on the editor surface in both themes. Syntax coloring names language constructs, not operational status: a green string is not a successful operation. Keep language punctuation and text available without color. Editor gutter, line numbers, selection, line highlight and cursor have their own `editor.*` roles. Selection must retain a caret, native selection range or another non-color cue.\n\n## Diff inspection\n\nInserted lines use `editor.diff.inserted.background` with the inserted `text` annotation; removed lines use the removed pair. Keep native + / − gutter markers and accessible diff navigation. Do not add transparency to these pairs or interpret a changed value as an application failure. Ordinary code within either line keeps the theme-aware syntax foregrounds.\n\n## Numeric framework APIs\n\nMonaco and similar frameworks require resolved values, not CSS `var()` strings. Resolve the installed token mode (light plus dark overrides, and Vietnamese typography alternatives) at the framework boundary. Convert `rem` dimensions to nominal pixels using 16 px/rem while the consumer uses the package's explicit pixel CSS compatibility entrypoint; do not copy a downstream token table. `editor.font.family`, `.size`, `.lineHeight` and `.weight` carry the complete `font.code.default` recipe (14/20, Vietnamese 14/24). Configure all four, not just font size. Theme definitions must be updated when app mode changes. Preserve legitimate editor settings such as read-only, wrapping, language workers, cancellation and diff layout.\n\n## Resize controls\n\n`resize.divider` is the visible line, not its interaction area. The handle uses `resize.handle.width`, `.height`, `.radius`, `.background`, `resize.color` and `resize.grip`. Hover, focus and drag use `resize.active` on the divider; the handle uses `resize.handle.activeBackground` with `resize.activeGrip`. Keep a visible keyboard focus ring. Extend the hit region to `resize.target` and, for touch, `resize.touchTarget` without moving panel content or changing the visible divider. Keyboard-enabled separators retain orientation, value, min/max and arrow-key behavior. Do not add a decorative transition while dragging.\n\n## Fullscreen and popup ordering\n\nFullscreen editors, code viewers and image inspection use `z-index.fullscreen` (450) with isolation. Monaco completion, hover and parameter-hint widgets use `z-index.tooltip` (600); ordinary in-page popups keep framework layers inside their owner via the adapter's contextual container. Mark custom fullscreen hosts with `data-bh-overlay-owner`. Native confirmations resolve invocation-time ordering through `getAntDesignVueModalZIndex`, and nested drawers use `getAntDesignVueOverlayZIndex` with their live owner layer. Blocking global loading uses `z-index.loading` (650), below always-visible toast feedback (700). See [Z-index](/foundations/styles/z-index/) for the complete ordering. Avoid a new local z-index scale or a glass effect; custom fullscreen surfaces use semantic surfaces and image inspection uses one `color.surface.scrim` layer. Layering does not replace focus containment, Escape handling, focus return, scroll locking or reachable controls.\n",
1087
+ "raw": "---\ntitle: Editors and resize controls\ndescription: Source-backed editor syntax, diff pairs, numeric font boundaries and accessible resize handles.\norder: 6\n---\n\n## Editor canvas and syntax\n\nEditors use `editor.background` and `editor.text`, a theme-aware reading canvas. This is deliberately different from static fenced code blocks (`color.code.background` / `color.code.text`), whose dark canvas has its own paired text. Never combine the editor syntax foregrounds with that static code-block canvas.\n\nUse `editor.syntax.comment`, `.string`, `.number`, `.keyword`, `.type` and `.delimiter` for language tokens. These aliases reuse readable semantic foregrounds on the editor surface in both themes. Syntax coloring names language constructs, not operational status: a green string is not a successful operation. Keep language punctuation and text available without color. Editor gutter, line numbers, selection, line highlight and cursor have their own `editor.*` roles. Selection must retain a caret, native selection range or another non-color cue.\n\n## Diff inspection\n\nInserted lines use `editor.diff.inserted.background` with the inserted `text` annotation; removed lines use the removed pair. Keep native + / − gutter markers and accessible diff navigation. Do not add transparency to these pairs or interpret a changed value as an application failure. Ordinary code within either line keeps the theme-aware syntax foregrounds.\n\n## Numeric framework APIs\n\nMonaco and similar frameworks require resolved values, not CSS `var()` strings. Resolve the installed token mode (light plus dark overrides, and Vietnamese typography alternatives) at the framework boundary. Convert `rem` dimensions to nominal pixels using 16 px/rem while the consumer uses the package's explicit pixel CSS compatibility entrypoint; do not copy a downstream token table. `editor.font.family`, `.size`, `.lineHeight` and `.weight` carry the complete `font.code.default` recipe (14/20, Vietnamese 14/24). Configure all four, not just font size. Theme definitions must be updated when app mode changes. Preserve legitimate editor settings such as read-only, wrapping, language workers, cancellation and diff layout.\n\n## Resize controls\n\n`resize.divider` is the visible line, not its interaction area. The handle uses `resize.handle.width`, `.height`, `.radius`, `.background`, `resize.color` and `resize.grip`. Hover, focus and drag use `resize.active` on the divider; the handle uses `resize.handle.activeBackground` with `resize.activeGrip`. Keep a visible keyboard focus ring. Extend the hit region to `resize.target` and, for touch, `resize.touchTarget` without moving panel content or changing the visible divider. Keyboard-enabled separators retain orientation, value, min/max and arrow-key behavior. Do not add a decorative transition while dragging.\n\n## Fullscreen and popup ordering\n\nFullscreen editors, code viewers and image inspection use `z-index.fullscreen` (450) with isolation. Monaco completion, hover and parameter-hint widgets use `z-index.tooltip` (600); ordinary in-page popups keep framework layers inside their owner via the adapter's contextual container. Mark custom fullscreen hosts with `data-bh-overlay-owner`. Native confirmations resolve invocation-time ordering through `getAntDesignVueModalZIndex`, and nested drawers use `getAntDesignVueOverlayZIndex` with their live owner layer. Blocking global loading uses `z-index.loading` (650), below always-visible toast feedback (700). See [Z-index](/foundations/styles/z-index/) for the complete ordering. Avoid a new local z-index scale or a glass effect; custom fullscreen surfaces use semantic surfaces and image inspection uses one `color.surface.scrim` layer. Layering does not replace focus containment, Escape handling, focus return, scroll locking or reachable controls.\n",
1088
+ "frontmatter": {
1089
+ "title": "Editors and resize controls",
1090
+ "description": "Source-backed editor syntax, diff pairs, numeric font boundaries and accessible resize handles.",
1091
+ "order": 6
1092
+ }
1093
+ },
1089
1094
  {
1090
1095
  "id": "en/tools/eslint",
1091
1096
  "path": "src/content/tools/eslint.mdx",
@@ -1122,6 +1127,24 @@ export const catalog = [
1122
1127
  "order": 0
1123
1128
  }
1124
1129
  },
1130
+ {
1131
+ "id": "en/tools/mermaid",
1132
+ "path": "src/content/tools/mermaid.mdx",
1133
+ "documentPath": "docs/src/content/tools/mermaid.mdx",
1134
+ "locale": "en",
1135
+ "kind": "guidance",
1136
+ "title": "Mermaid and execution diagrams",
1137
+ "status": "active",
1138
+ "releasePhase": null,
1139
+ "planned": [],
1140
+ "body": "\nUse `@beehexa/mermaid-tokens` for every Mermaid initialization. It returns a fresh\n`MermaidConfig` from `@beehexa/design-tokens`; Mermaid remains a peer dependency.\nPass the active `dark` and `locale` on every render. A theme or language change\nrequires rendering again: SVG paint and text measurements do not update from CSS alone.\n\n```ts\nimport { createMermaidConfig, createCanvasTheme } from '@beehexa/mermaid-tokens';\n\nmermaid.initialize(createMermaidConfig({ dark: true, locale: 'vi' }));\nconst canvas = createCanvasTheme({ dark: true, locale: 'vi' });\n```\n\nThe factory secures `theme`, `look`, `themeVariables`, `themeCSS`, `fontFamily`,\n`fontSize` and `htmlLabels` before `layout`. Mermaid 12 appends this secure array\nto its own default security keys. Definition init CSS must not replace rich-card\ntoken fonts; topology, definition-owned state styles and unrelated layout directives\nremain available. This configuration contract is not a claim that a rendered smoke\nmatrix has passed.\n\n## Meaning before colour\n\n`diagram.*` roles describe an operational execution graph, not an explanatory\nbrand schematic or a chart series palette. The same roles apply to the drawing,\nits inspector and its exported artifact.\n\n- Default and indeterminate nodes use `node-*` neutral pairs.\n- `state-ran-ok` means **ran without a reported failure**, not a verified business\n success. Neutral solid paint preserves this distinction from success status,\n successful HTTP response, and warning. An HTTP response or business outcome\n still uses the appropriate success/danger role in its own status label.\n- Failed nodes use `fail-*`, with a failure marker and state text.\n- Never-reached nodes use `unreached-*` and an explicit state label; they are not\n disabled controls. Not-taken branches use `nottaken-*` plus a dashed boundary.\n- Repeat counts use the neutral `badge-*` pair. Repetition alone is not a warning.\n- Category glyphs use `tile-*`. They identify step type, not run state.\n- Selection and hover use `selection-ring` as **separate geometry outside the\n node boundary**. Never repaint a failed node to indicate that it is selected.\n- Field labels use `code-key`, values `code-value`, on `code-bg`. These descriptive\n fields are not links. Full code blocks retain the existing `color.code.*` pair.\n\nAlways keep labels, markers, shapes or dash patterns: colour alone is not evidence.\nPair foregrounds only with their named fills. Validate actual SVG text and meaningful\nline contrast in both themes; token existence does not certify a rendered diagram.\n\n## Type, space and interaction\n\n`diagram.node-font` aliases `font.body.default`, including taller Vietnamese lines.\nUse complete source font styles for node labels, inspector titles, metadata and code.\nDo not replace their weight or line height with component-specific recipes. Let\nVietnamese marks and long labels wrap without clipping. `diagram.padding` is internal\nnode padding; `diagram.export-padding` frames fitted/exported drawing bounds. Graph\ncoordinates and existing layout topology are not spacing-scale choices.\n\nThe adapter's SVG stylesheet also adapts renderer-owned execution-card labels.\nIt replaces their inline 11px/650-weight recipes with `font.heading.xsmall` and\n`font.body.small`, and removes category-tile translucent tints and inset shadows.\n`diagram.card-width`, `diagram.tile-size` and `diagram.glyph-size` retain the\nmeasurable fixed card and symbol geometry; these are not marketing display type.\nThis narrowly scoped stylesheet is the framework gap boundary, not permission for\npage CSS to override definition-owned run-state paint.\nEmbedded SVG CSS also supplies opaque source edge-label pairs and explicit\n`\"cv05\", \"cv08\"` features alongside the complete font shorthand; SVG/export must\nnot depend on the document's universal font-feature rule.\n\nAuthoring previews use `diagram.preview-height` for both split panels and\n`diagram.minimum-height` for the drawing viewport; fullscreen fills the enclosing\nhost instead. Read-only split diagrams retain a zero minimum so they shrink with\ntheir host. Structured evidence viewers use `diagram.evidence-height`; multiple\nrequest-body panes use `diagram.evidence-minimum-height` to keep every part reachable.\n\n\nUse a flat opaque sheet. No gradients, glass, decorative animation, animated\ntraversal or state transitions. Retain zoom, fit, fullscreen/escape and PNG export\ncontrols. Interaction must not overwrite definition-owned fill, stroke, dashes or\nfailure markers. Controls stay outside the captured SVG host.\n\n## Export the rendered theme\n\nResolve literal token values when drawing: Mermaid style statements cannot resolve\nCSS variables. Snapshot the rendered theme and opaque canvas background on the SVG\nhost. Export the live, fully decorated drawing at its natural bounds with\n`exportPadding`, not the transformed viewport. Preserve the snapshot even if the\napplication theme changes before the new drawing lands. Fonts, locale line height,\nstate paint and outer selection geometry must survive SVG/PNG capture. A transparent\nimage or white sheet behind dark labels is not a valid fallback.\n\nAll package source is in `tokens/diagram.json`; consumers must not maintain a\nsecond palette or copy generated token values. Local package references are for\nlocal development only until an authorized release exists.\n",
1141
+ "raw": "---\ntitle: Mermaid and execution diagrams\ndescription: Source-backed Mermaid configuration, descriptive execution states, interaction and image export.\norder: 6\n---\n\nUse `@beehexa/mermaid-tokens` for every Mermaid initialization. It returns a fresh\n`MermaidConfig` from `@beehexa/design-tokens`; Mermaid remains a peer dependency.\nPass the active `dark` and `locale` on every render. A theme or language change\nrequires rendering again: SVG paint and text measurements do not update from CSS alone.\n\n```ts\nimport { createMermaidConfig, createCanvasTheme } from '@beehexa/mermaid-tokens';\n\nmermaid.initialize(createMermaidConfig({ dark: true, locale: 'vi' }));\nconst canvas = createCanvasTheme({ dark: true, locale: 'vi' });\n```\n\nThe factory secures `theme`, `look`, `themeVariables`, `themeCSS`, `fontFamily`,\n`fontSize` and `htmlLabels` before `layout`. Mermaid 12 appends this secure array\nto its own default security keys. Definition init CSS must not replace rich-card\ntoken fonts; topology, definition-owned state styles and unrelated layout directives\nremain available. This configuration contract is not a claim that a rendered smoke\nmatrix has passed.\n\n## Meaning before colour\n\n`diagram.*` roles describe an operational execution graph, not an explanatory\nbrand schematic or a chart series palette. The same roles apply to the drawing,\nits inspector and its exported artifact.\n\n- Default and indeterminate nodes use `node-*` neutral pairs.\n- `state-ran-ok` means **ran without a reported failure**, not a verified business\n success. Neutral solid paint preserves this distinction from success status,\n successful HTTP response, and warning. An HTTP response or business outcome\n still uses the appropriate success/danger role in its own status label.\n- Failed nodes use `fail-*`, with a failure marker and state text.\n- Never-reached nodes use `unreached-*` and an explicit state label; they are not\n disabled controls. Not-taken branches use `nottaken-*` plus a dashed boundary.\n- Repeat counts use the neutral `badge-*` pair. Repetition alone is not a warning.\n- Category glyphs use `tile-*`. They identify step type, not run state.\n- Selection and hover use `selection-ring` as **separate geometry outside the\n node boundary**. Never repaint a failed node to indicate that it is selected.\n- Field labels use `code-key`, values `code-value`, on `code-bg`. These descriptive\n fields are not links. Full code blocks retain the existing `color.code.*` pair.\n\nAlways keep labels, markers, shapes or dash patterns: colour alone is not evidence.\nPair foregrounds only with their named fills. Validate actual SVG text and meaningful\nline contrast in both themes; token existence does not certify a rendered diagram.\n\n## Type, space and interaction\n\n`diagram.node-font` aliases `font.body.default`, including taller Vietnamese lines.\nUse complete source font styles for node labels, inspector titles, metadata and code.\nDo not replace their weight or line height with component-specific recipes. Let\nVietnamese marks and long labels wrap without clipping. `diagram.padding` is internal\nnode padding; `diagram.export-padding` frames fitted/exported drawing bounds. Graph\ncoordinates and existing layout topology are not spacing-scale choices.\n\nThe adapter's SVG stylesheet also adapts renderer-owned execution-card labels.\nIt replaces their inline 11px/650-weight recipes with `font.heading.xsmall` and\n`font.body.small`, and removes category-tile translucent tints and inset shadows.\n`diagram.card-width`, `diagram.tile-size` and `diagram.glyph-size` retain the\nmeasurable fixed card and symbol geometry; these are not marketing display type.\nThis narrowly scoped stylesheet is the framework gap boundary, not permission for\npage CSS to override definition-owned run-state paint.\nEmbedded SVG CSS also supplies opaque source edge-label pairs and explicit\n`\"cv05\", \"cv08\"` features alongside the complete font shorthand; SVG/export must\nnot depend on the document's universal font-feature rule.\n\nAuthoring previews use `diagram.preview-height` for both split panels and\n`diagram.minimum-height` for the drawing viewport; fullscreen fills the enclosing\nhost instead. Read-only split diagrams retain a zero minimum so they shrink with\ntheir host. Structured evidence viewers use `diagram.evidence-height`; multiple\nrequest-body panes use `diagram.evidence-minimum-height` to keep every part reachable.\n\n\nUse a flat opaque sheet. No gradients, glass, decorative animation, animated\ntraversal or state transitions. Retain zoom, fit, fullscreen/escape and PNG export\ncontrols. Interaction must not overwrite definition-owned fill, stroke, dashes or\nfailure markers. Controls stay outside the captured SVG host.\n\n## Export the rendered theme\n\nResolve literal token values when drawing: Mermaid style statements cannot resolve\nCSS variables. Snapshot the rendered theme and opaque canvas background on the SVG\nhost. Export the live, fully decorated drawing at its natural bounds with\n`exportPadding`, not the transformed viewport. Preserve the snapshot even if the\napplication theme changes before the new drawing lands. Fonts, locale line height,\nstate paint and outer selection geometry must survive SVG/PNG capture. A transparent\nimage or white sheet behind dark labels is not a valid fallback.\n\nAll package source is in `tokens/diagram.json`; consumers must not maintain a\nsecond palette or copy generated token values. Local package references are for\nlocal development only until an authorized release exists.\n",
1142
+ "frontmatter": {
1143
+ "title": "Mermaid and execution diagrams",
1144
+ "description": "Source-backed Mermaid configuration, descriptive execution states, interaction and image export.",
1145
+ "order": 6
1146
+ }
1147
+ },
1125
1148
  {
1126
1149
  "id": "en/tools/stylelint",
1127
1150
  "path": "src/content/tools/stylelint.mdx",
@@ -1140,6 +1163,24 @@ export const catalog = [
1140
1163
  "order": 1
1141
1164
  }
1142
1165
  },
1166
+ {
1167
+ "id": "en/tools/vueflow",
1168
+ "path": "src/content/tools/vueflow.mdx",
1169
+ "documentPath": "docs/src/content/tools/vueflow.mdx",
1170
+ "locale": "en",
1171
+ "kind": "guidance",
1172
+ "title": "VueFlow theme",
1173
+ "status": "active",
1174
+ "releasePhase": null,
1175
+ "planned": [],
1176
+ "body": "\n`@beehexa/vueflow-tokens` adapts the authoritative tokens to VueFlow 1. It does not copy\nVueFlow source, bundle Vue, generate graph data, or change relationship direction.\n\n## Install and apply\n\nInstall this package, `@beehexa/design-tokens`, Vue 3, and the VueFlow 1 core, controls and\nminimap peers. Load upstream core, theme, controls and minimap CSS in the lazy graph\nentry before adapter CSS; load native design-token CSS once with a 16px root/14px body.\nLocal source packages remain private `0.0.0`; that is not a registry release.\n\n```vue\n<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport { VueFlow } from '@vue-flow/core'\nimport { Background } from '@vue-flow/background'\nimport { Controls } from '@vue-flow/controls'\nimport { MiniMap } from '@vue-flow/minimap'\nimport { createVueFlowTheme } from '@beehexa/vueflow-tokens'\nimport '@beehexa/design-tokens/css'\nimport '@vue-flow/core/dist/style.css'\nimport '@vue-flow/core/dist/theme-default.css'\nimport '@vue-flow/controls/dist/style.css'\nimport '@vue-flow/minimap/dist/style.css'\nimport '@beehexa/vueflow-tokens/css'\n\nconst props = defineProps<{ dark: boolean; locale: 'en' | 'vi' }>()\nconst theme = computed(() => createVueFlowTheme(props))\n// nodes and edges remain application graph data; never recreate their IDs on theme changes.\n</script>\n\n<template>\n <VueFlow :class=\"theme.class\" :style=\"theme.style\" v-bind=\"theme.flowOptions\">\n <Background v-bind=\"theme.background\" />\n <Controls />\n <MiniMap v-bind=\"theme.minimap\" />\n </VueFlow>\n</template>\n```\n\nThe factory returns scoped variables, viewport bindings typed with `FlowProps` (not deprecated `FlowOptions`), and Background/MiniMap bindings.\nIt resolves light plus dark overrides and Vietnamese typography alternatives from the token\npackage. Recompute when theme or locale changes. Keep ready/error handlers and fit the graph\nwith padding `0.2` when the host becomes measurable or changes size. VueFlow 1's actual\n`fitViewOnInit` option is used; do not pass invented viewport option names.\n\n## Operational categories are not statuses\n\n`flow.category.*` identifies the existing product's node kinds: task blue, dependency red,\ntransformation green, validation deep red, push step gold, decision cyan, loop magenta and\ngrouped nodes purple. These categorical identities must not be interpreted as success,\nfailure or warning. Keep the node's type label and icon; colour is never its sole identity.\nA category colour does not certify the state of an execution.\n\nEach category supplies `foreground`, `background`, `border` and `hover` as an opaque paired\nlight/dark role. Use `getNodeColorPalette(category)` for CSS-backed bindings and\n`getNodeColor(nodeType)` for the frame/edge identity. These source roles replace historical\napplication-owned palettes, alpha overlays, gradients and palette-adjustment functions.\nNever append hex alpha suffixes to a CSS variable, or lighten a resolved role downstream.\n\nSelection uses `color.border.selected` plus the selected outline; keyboard focus separately\nuses `color.border.focus`, the focused border width and `state.focus.offset`. Errors use the\ndanger frame plus dashed/non-colour indication and a readable error label. Selection or focus\nmust not overwrite category identity, hide an error, or be conveyed only through colour.\nResting handles use the neutral icon role. Focus color is reserved for actual focus,\nnot an always-on connector decoration.\n\n## Custom content and geometry\n\nUse `getFlowNodeStyles(NodeType, state)` for custom node bodies. It binds semantic fonts,\nspacing, shape, categorical pairs and source dimensions. Keep custom icons, connector logos,\nlabels, handles, accessibility semantics and events in the application. Meaningful loading\nindicators may move; decorative node entrances, pulsing identities, rotating idle icons,\nhover transforms, flowing edge dashes, gradients and glass are not part of the theme.\n\n`NODE_DIMENSIONS`, `GRID_SPACING` and `TASK_DATA_LAYOUT` read `tokens/flow.json`. The scoped\noperational matrix is: task, task dependency, task transformation and task data **450×130**;\nthree groups **350×130**; validation, transformation and push step **200×130**;\ndecision **160×160**, loop **120×120**, profile **240×100**. Do not confuse task-transformation\ncards with individual transformation steps. Rendering, layout and half-dimension centering\nmust use the same source. Preserve existing graph coordinates during theme adoption.\n\nGraph layout coordinates, intrinsic sizing, flex/grid mechanics and viewport transforms are\nnot palette values. Do not arbitrarily round them to the spacing scale. Category adaptation\nmust not mutate the graph's IDs, expansion state, saved positions or relationship semantics.\n\n## Edges, controls and export\n\n`styleTargetEdge(edge, nodes)` preserves the directed edge's target identity on both stroke\nand marker, keeps other edge data, and disables decorative traversal motion. The application\nmay retain dashed lines to communicate transformation or conditional semantics. The custom\nedge renderer must consume the supplied stroke rather than replace it with an unrelated\nedge palette. `FLOW_EDGE` centralizes widths, marker size, path radius and handle size.\n\nThe CSS companion addresses actual VueFlow core/default nodes, handles, edge labels, selection,\nControls buttons and MiniMap surfaces. Controls preserve normal, hover, disabled and focus\nstates and enlarge to source touch targets for coarse pointers. Import it after upstream CSS;\nremove competing consumer-wide core/controls/minimap paint rules rather than escalating specificity.\n\nExport the current theme and font from the measured graph surface. Do not force a white\nbackground or independent system-font palette. Preserve snapshot/fit/restore, overlay filtering,\nresolution feedback and capture fallback handling. Check the real exported image, not just a\nsuccessful capture call.\n\nGraph fullscreen uses an isolated local stacking context at `z-index.modal` (400), not\n`z-index.fullscreen` (450), so global inspectors remain above it. Private child chrome\nordering such as z10/z15 stays inside that context; do not assign global1001/1002\nto graph controls. Verify real inspector/dialog ordering, Escape and focus return.\n\n## Verification\n\nExercise light and dark, English and Vietnamese, selected plus focused and error nodes,\nlong labels, every fixed dimension, target-coloured arrows, zoom/snap/fitting, expanded groups,\ncycles, narrow and fullscreen hosts, ESC exit, Controls, MiniMap and export. Calculate contrast\nfor the actual paired foreground/background and meaningful borders in each rendered theme;\nsource tokens and typed configuration alone are not accessibility or visual proof.\n",
1177
+ "raw": "---\ntitle: VueFlow theme\ndescription: Source-backed operational graph categories, paired themes, fixed geometry and VueFlow 1 integration.\norder: 5\n---\n\n`@beehexa/vueflow-tokens` adapts the authoritative tokens to VueFlow 1. It does not copy\nVueFlow source, bundle Vue, generate graph data, or change relationship direction.\n\n## Install and apply\n\nInstall this package, `@beehexa/design-tokens`, Vue 3, and the VueFlow 1 core, controls and\nminimap peers. Load upstream core, theme, controls and minimap CSS in the lazy graph\nentry before adapter CSS; load native design-token CSS once with a 16px root/14px body.\nLocal source packages remain private `0.0.0`; that is not a registry release.\n\n```vue\n<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport { VueFlow } from '@vue-flow/core'\nimport { Background } from '@vue-flow/background'\nimport { Controls } from '@vue-flow/controls'\nimport { MiniMap } from '@vue-flow/minimap'\nimport { createVueFlowTheme } from '@beehexa/vueflow-tokens'\nimport '@beehexa/design-tokens/css'\nimport '@vue-flow/core/dist/style.css'\nimport '@vue-flow/core/dist/theme-default.css'\nimport '@vue-flow/controls/dist/style.css'\nimport '@vue-flow/minimap/dist/style.css'\nimport '@beehexa/vueflow-tokens/css'\n\nconst props = defineProps<{ dark: boolean; locale: 'en' | 'vi' }>()\nconst theme = computed(() => createVueFlowTheme(props))\n// nodes and edges remain application graph data; never recreate their IDs on theme changes.\n</script>\n\n<template>\n <VueFlow :class=\"theme.class\" :style=\"theme.style\" v-bind=\"theme.flowOptions\">\n <Background v-bind=\"theme.background\" />\n <Controls />\n <MiniMap v-bind=\"theme.minimap\" />\n </VueFlow>\n</template>\n```\n\nThe factory returns scoped variables, viewport bindings typed with `FlowProps` (not deprecated `FlowOptions`), and Background/MiniMap bindings.\nIt resolves light plus dark overrides and Vietnamese typography alternatives from the token\npackage. Recompute when theme or locale changes. Keep ready/error handlers and fit the graph\nwith padding `0.2` when the host becomes measurable or changes size. VueFlow 1's actual\n`fitViewOnInit` option is used; do not pass invented viewport option names.\n\n## Operational categories are not statuses\n\n`flow.category.*` identifies the existing product's node kinds: task blue, dependency red,\ntransformation green, validation deep red, push step gold, decision cyan, loop magenta and\ngrouped nodes purple. These categorical identities must not be interpreted as success,\nfailure or warning. Keep the node's type label and icon; colour is never its sole identity.\nA category colour does not certify the state of an execution.\n\nEach category supplies `foreground`, `background`, `border` and `hover` as an opaque paired\nlight/dark role. Use `getNodeColorPalette(category)` for CSS-backed bindings and\n`getNodeColor(nodeType)` for the frame/edge identity. These source roles replace historical\napplication-owned palettes, alpha overlays, gradients and palette-adjustment functions.\nNever append hex alpha suffixes to a CSS variable, or lighten a resolved role downstream.\n\nSelection uses `color.border.selected` plus the selected outline; keyboard focus separately\nuses `color.border.focus`, the focused border width and `state.focus.offset`. Errors use the\ndanger frame plus dashed/non-colour indication and a readable error label. Selection or focus\nmust not overwrite category identity, hide an error, or be conveyed only through colour.\nResting handles use the neutral icon role. Focus color is reserved for actual focus,\nnot an always-on connector decoration.\n\n## Custom content and geometry\n\nUse `getFlowNodeStyles(NodeType, state)` for custom node bodies. It binds semantic fonts,\nspacing, shape, categorical pairs and source dimensions. Keep custom icons, connector logos,\nlabels, handles, accessibility semantics and events in the application. Meaningful loading\nindicators may move; decorative node entrances, pulsing identities, rotating idle icons,\nhover transforms, flowing edge dashes, gradients and glass are not part of the theme.\n\n`NODE_DIMENSIONS`, `GRID_SPACING` and `TASK_DATA_LAYOUT` read `tokens/flow.json`. The scoped\noperational matrix is: task, task dependency, task transformation and task data **450×130**;\nthree groups **350×130**; validation, transformation and push step **200×130**;\ndecision **160×160**, loop **120×120**, profile **240×100**. Do not confuse task-transformation\ncards with individual transformation steps. Rendering, layout and half-dimension centering\nmust use the same source. Preserve existing graph coordinates during theme adoption.\n\nGraph layout coordinates, intrinsic sizing, flex/grid mechanics and viewport transforms are\nnot palette values. Do not arbitrarily round them to the spacing scale. Category adaptation\nmust not mutate the graph's IDs, expansion state, saved positions or relationship semantics.\n\n## Edges, controls and export\n\n`styleTargetEdge(edge, nodes)` preserves the directed edge's target identity on both stroke\nand marker, keeps other edge data, and disables decorative traversal motion. The application\nmay retain dashed lines to communicate transformation or conditional semantics. The custom\nedge renderer must consume the supplied stroke rather than replace it with an unrelated\nedge palette. `FLOW_EDGE` centralizes widths, marker size, path radius and handle size.\n\nThe CSS companion addresses actual VueFlow core/default nodes, handles, edge labels, selection,\nControls buttons and MiniMap surfaces. Controls preserve normal, hover, disabled and focus\nstates and enlarge to source touch targets for coarse pointers. Import it after upstream CSS;\nremove competing consumer-wide core/controls/minimap paint rules rather than escalating specificity.\n\nExport the current theme and font from the measured graph surface. Do not force a white\nbackground or independent system-font palette. Preserve snapshot/fit/restore, overlay filtering,\nresolution feedback and capture fallback handling. Check the real exported image, not just a\nsuccessful capture call.\n\nGraph fullscreen uses an isolated local stacking context at `z-index.modal` (400), not\n`z-index.fullscreen` (450), so global inspectors remain above it. Private child chrome\nordering such as z10/z15 stays inside that context; do not assign global1001/1002\nto graph controls. Verify real inspector/dialog ordering, Escape and focus return.\n\n## Verification\n\nExercise light and dark, English and Vietnamese, selected plus focused and error nodes,\nlong labels, every fixed dimension, target-coloured arrows, zoom/snap/fitting, expanded groups,\ncycles, narrow and fullscreen hosts, ESC exit, Controls, MiniMap and export. Calculate contrast\nfor the actual paired foreground/background and meaningful borders in each rendered theme;\nsource tokens and typed configuration alone are not accessibility or visual proof.\n",
1178
+ "frontmatter": {
1179
+ "title": "VueFlow theme",
1180
+ "description": "Source-backed operational graph categories, paired themes, fixed geometry and VueFlow 1 integration.",
1181
+ "order": 5
1182
+ }
1183
+ },
1143
1184
  {
1144
1185
  "id": "vi/foundations/styles/border",
1145
1186
  "path": "src/content-vi/foundations/styles/border.mdx",
@@ -1150,8 +1191,8 @@ export const catalog = [
1150
1191
  "status": "active",
1151
1192
  "releasePhase": null,
1152
1193
  "planned": [],
1153
- "body": "import ShapeDemo from '../../../components/ShapeDemo.astro';\nimport TokenTable from '../../../components/TokenTable.astro';\n\n**Phần lớn viền là 1 px. Viền dày hơn mang ý nghĩa: đang chọn, đang focus, hoặc một trạng thái cần chú ý.**\n\nMàu viền là token màu: `color.border` cho đường phân cách và card, `color.border.bold` cho mép ô nhập, checkbox và select. Xem [Token](/vi/foundations/styles/color/tokens/#borders).\n\n## Các độ dày\n\n<ShapeDemo kind=\"border-scale\" />\n\n## Ví dụ\n\n### `border.width.default` · 1 px\n\nÔ nhập, button phụ, card, bảng và đường phân cách.\n\n<ShapeDemo kind=\"border-use\" item=\"default\" />\n\n### `border.width.selected` · 2 px\n\nThanh dưới tab đang chọn, thanh cạnh mục side nav đang chọn, và viền card đang chọn. Luôn đi cùng `color.border.selected`.\n\n<ShapeDemo kind=\"border-use\" item=\"selected\" />\n\n### `border.width.focused` · 2 px\n\nFocus ring, màu `color.border.focus`, vẽ cách phần tử 2 px về phía ngoài (`state.focus.offset`). Vẽ vào trong, ở −2 px, khi khung bao quanh sẽ cắt mất ring: mục menu, ô bảng và tab trong vùng cuộn.\n\n<ShapeDemo kind=\"border-use\" item=\"focused\" />\n\n### `border.width.accent` · 4 px\n\nThanh trạng thái hoặc nhấn mạnh ở một cạnh: alert và banner, dòng bảng bị lỗi, callout và trích dẫn. Hộp vẫn bo đủ bốn góc và thanh chạy theo đường cong.\n\n<ShapeDemo kind=\"border-use\" item=\"accent\" />\n\n## Độ dày đi cùng màu\n\n| Độ dày | Màu | Dùng cho |\n|---|---|---|\n| `border.width.default` | `color.border` hoặc `color.border.bold` | Mép và đường phân cách |\n| `border.width.selected` | `color.border.selected` | Tab, mục side nav hoặc card đang chọn |\n| `border.width.focused` | `color.border.focus` | Focus bằng bàn phím |\n| `border.width.accent` | `color.border.danger`, `.warning`, `.success`, `.info` hoặc `.brand` | Thanh trạng thái và nhấn mạnh |\n\nKhông báo trạng thái chỉ bằng màu. Đang chọn và đang focus còn đổi cả độ dày.\n\n## Nên và không nên\n\n<ShapeDemo kind=\"dodont\" item=\"selected\" />\n<ShapeDemo kind=\"dodont\" item=\"accent\" />\n<ShapeDemo kind=\"dodont\" item=\"cards\" />\n\n## Code\n\n```css\n.alert {\n position: relative;\n overflow: hidden;\n border: var(--bh-border-width-default) solid var(--bh-color-border);\n border-radius: var(--bh-radius-100);\n}\n.alert::before {\n content: \"\";\n position: absolute;\n inset: 0 auto 0 0;\n width: var(--bh-border-width-accent);\n background: var(--bh-color-border-danger);\n}\n:focus-visible {\n outline: var(--bh-border-width-focused) solid var(--bh-color-border-focus);\n outline-offset: var(--bh-state-focus-offset);\n}\n```\n\n## Token\n\n<TokenTable prefix=\"border\" />\n\n## Liên quan\n\n- [Bo góc](/vi/foundations/styles/radius/): các bậc bo góc và quy tắc lồng nhau.\n- [Trạng thái tương tác](/vi/foundations/styles/interaction-states/): hover, nhấn, đang chọn và vô hiệu.\n",
1154
- "raw": "---\ntitle: Viền\ndescription: Bốn độ dày viền, màu đi cùng mỗi độ dày, và cách vẽ focus ring.\norder: 7\n---\nimport ShapeDemo from '../../../components/ShapeDemo.astro';\nimport TokenTable from '../../../components/TokenTable.astro';\n\n**Phần lớn viền là 1 px. Viền dày hơn mang ý nghĩa: đang chọn, đang focus, hoặc một trạng thái cần chú ý.**\n\nMàu viền là token màu: `color.border` cho đường phân cách và card, `color.border.bold` cho mép ô nhập, checkbox và select. Xem [Token](/vi/foundations/styles/color/tokens/#borders).\n\n## Các độ dày\n\n<ShapeDemo kind=\"border-scale\" />\n\n## Ví dụ\n\n### `border.width.default` · 1 px\n\nÔ nhập, button phụ, card, bảng và đường phân cách.\n\n<ShapeDemo kind=\"border-use\" item=\"default\" />\n\n### `border.width.selected` · 2 px\n\nThanh dưới tab đang chọn, thanh cạnh mục side nav đang chọn, và viền card đang chọn. Luôn đi cùng `color.border.selected`.\n\n<ShapeDemo kind=\"border-use\" item=\"selected\" />\n\n### `border.width.focused` · 2 px\n\nFocus ring, màu `color.border.focus`, vẽ cách phần tử 2 px về phía ngoài (`state.focus.offset`). Vẽ vào trong, ở −2 px, khi khung bao quanh sẽ cắt mất ring: mục menu, ô bảng và tab trong vùng cuộn.\n\n<ShapeDemo kind=\"border-use\" item=\"focused\" />\n\n### `border.width.accent` · 4 px\n\nThanh trạng thái hoặc nhấn mạnh ở một cạnh: alert và banner, dòng bảng bị lỗi, callout và trích dẫn. Hộp vẫn bo đủ bốn góc và thanh chạy theo đường cong.\n\n<ShapeDemo kind=\"border-use\" item=\"accent\" />\n\n## Độ dày đi cùng màu\n\n| Độ dày | Màu | Dùng cho |\n|---|---|---|\n| `border.width.default` | `color.border` hoặc `color.border.bold` | Mép và đường phân cách |\n| `border.width.selected` | `color.border.selected` | Tab, mục side nav hoặc card đang chọn |\n| `border.width.focused` | `color.border.focus` | Focus bằng bàn phím |\n| `border.width.accent` | `color.border.danger`, `.warning`, `.success`, `.info` hoặc `.brand` | Thanh trạng thái và nhấn mạnh |\n\nKhông báo trạng thái chỉ bằng màu. Đang chọn và đang focus còn đổi cả độ dày.\n\n## Nên và không nên\n\n<ShapeDemo kind=\"dodont\" item=\"selected\" />\n<ShapeDemo kind=\"dodont\" item=\"accent\" />\n<ShapeDemo kind=\"dodont\" item=\"cards\" />\n\n## Code\n\n```css\n.alert {\n position: relative;\n overflow: hidden;\n border: var(--bh-border-width-default) solid var(--bh-color-border);\n border-radius: var(--bh-radius-100);\n}\n.alert::before {\n content: \"\";\n position: absolute;\n inset: 0 auto 0 0;\n width: var(--bh-border-width-accent);\n background: var(--bh-color-border-danger);\n}\n:focus-visible {\n outline: var(--bh-border-width-focused) solid var(--bh-color-border-focus);\n outline-offset: var(--bh-state-focus-offset);\n}\n```\n\n## Token\n\n<TokenTable prefix=\"border\" />\n\n## Liên quan\n\n- [Bo góc](/vi/foundations/styles/radius/): các bậc bo góc và quy tắc lồng nhau.\n- [Trạng thái tương tác](/vi/foundations/styles/interaction-states/): hover, nhấn, đang chọn và vô hiệu.\n",
1194
+ "body": "import ShapeDemo from '../../../components/ShapeDemo.astro';\nimport TokenTable from '../../../components/TokenTable.astro';\n\n**Phần lớn viền là 1 px. Viền dày hơn mang ý nghĩa: đang chọn, đang focus, hoặc một trạng thái cần chú ý.**\n\nMàu viền là token màu: `color.border` cho đường phân cách và card, `color.border.bold` cho mép ô nhập, checkbox và select. Xem [Token](/vi/foundations/styles/color/tokens/#borders).\n\n## Các độ dày\n\n<ShapeDemo kind=\"border-scale\" />\n\n## Ví dụ\n\n### `border.width.default` · 1 px\n\nÔ nhập, button phụ, card, bảng và đường phân cách.\n\n<ShapeDemo kind=\"border-use\" item=\"default\" />\n\n### `border.width.selected` · 2 px\n\nThanh dưới tab đang chọn, thanh cạnh mục side nav đang chọn, và viền card đang chọn. Luôn đi cùng `color.border.selected`.\n\n<ShapeDemo kind=\"border-use\" item=\"selected\" />\n\n### `border.width.focused` · 2 px\n\nFocus ring, màu `color.border.focus`, vẽ cách phần tử 2 px về phía ngoài (`state.focus.offset`). Vẽ vào trong, ở −2 px, khi khung bao quanh sẽ cắt mất ring: mục menu, ô bảng và tab trong vùng cuộn.\n\n<ShapeDemo kind=\"border-use\" item=\"focused\" />\n\n### `border.width.accent` · 4 px\n\nThanh trạng thái hoặc nhấn mạnh ở một cạnh: dòng bảng bị lỗi, callout và trích dẫn. Banner không dùng thanh này mà dùng nền nhạt theo trạng thái (xem [Cách dùng màu](/vi/foundations/styles/color/usage/)). Hộp vẫn bo đủ bốn góc và thanh chạy theo đường cong.\n\n<ShapeDemo kind=\"border-use\" item=\"accent\" />\n\n## Độ dày đi cùng màu\n\n| Độ dày | Màu | Dùng cho |\n|---|---|---|\n| `border.width.default` | `color.border` hoặc `color.border.bold` | Mép và đường phân cách |\n| `border.width.selected` | `color.border.selected` | Tab, mục side nav hoặc card đang chọn |\n| `border.width.focused` | `color.border.focus` | Focus bằng bàn phím |\n| `border.width.accent` | `color.border.danger`, `.warning`, `.success`, `.info` hoặc `.brand` | Thanh trạng thái và nhấn mạnh |\n\nKhông báo trạng thái chỉ bằng màu. Đang chọn và đang focus còn đổi cả độ dày.\n\n## Nên và không nên\n\n<ShapeDemo kind=\"dodont\" item=\"selected\" />\n<ShapeDemo kind=\"dodont\" item=\"accent\" />\n<ShapeDemo kind=\"dodont\" item=\"cards\" />\n\n## Code\n\n```css\n.callout {\n position: relative;\n overflow: hidden;\n border: var(--bh-border-width-default) solid var(--bh-color-border);\n border-radius: var(--bh-radius-100);\n}\n.callout::before {\n content: \"\";\n position: absolute;\n inset: 0 auto 0 0;\n width: var(--bh-border-width-accent);\n background: var(--bh-color-border-danger);\n}\n:focus-visible {\n outline: var(--bh-border-width-focused) solid var(--bh-color-border-focus);\n outline-offset: var(--bh-state-focus-offset);\n}\n```\n\n## Token\n\n<TokenTable prefix=\"border\" />\n\n## Liên quan\n\n- [Bo góc](/vi/foundations/styles/radius/): các bậc bo góc và quy tắc lồng nhau.\n- [Trạng thái tương tác](/vi/foundations/styles/interaction-states/): hover, nhấn, đang chọn và vô hiệu.\n",
1195
+ "raw": "---\ntitle: Viền\ndescription: Bốn độ dày viền, màu đi cùng mỗi độ dày, và cách vẽ focus ring.\norder: 7\n---\nimport ShapeDemo from '../../../components/ShapeDemo.astro';\nimport TokenTable from '../../../components/TokenTable.astro';\n\n**Phần lớn viền là 1 px. Viền dày hơn mang ý nghĩa: đang chọn, đang focus, hoặc một trạng thái cần chú ý.**\n\nMàu viền là token màu: `color.border` cho đường phân cách và card, `color.border.bold` cho mép ô nhập, checkbox và select. Xem [Token](/vi/foundations/styles/color/tokens/#borders).\n\n## Các độ dày\n\n<ShapeDemo kind=\"border-scale\" />\n\n## Ví dụ\n\n### `border.width.default` · 1 px\n\nÔ nhập, button phụ, card, bảng và đường phân cách.\n\n<ShapeDemo kind=\"border-use\" item=\"default\" />\n\n### `border.width.selected` · 2 px\n\nThanh dưới tab đang chọn, thanh cạnh mục side nav đang chọn, và viền card đang chọn. Luôn đi cùng `color.border.selected`.\n\n<ShapeDemo kind=\"border-use\" item=\"selected\" />\n\n### `border.width.focused` · 2 px\n\nFocus ring, màu `color.border.focus`, vẽ cách phần tử 2 px về phía ngoài (`state.focus.offset`). Vẽ vào trong, ở −2 px, khi khung bao quanh sẽ cắt mất ring: mục menu, ô bảng và tab trong vùng cuộn.\n\n<ShapeDemo kind=\"border-use\" item=\"focused\" />\n\n### `border.width.accent` · 4 px\n\nThanh trạng thái hoặc nhấn mạnh ở một cạnh: dòng bảng bị lỗi, callout và trích dẫn. Banner không dùng thanh này mà dùng nền nhạt theo trạng thái (xem [Cách dùng màu](/vi/foundations/styles/color/usage/)). Hộp vẫn bo đủ bốn góc và thanh chạy theo đường cong.\n\n<ShapeDemo kind=\"border-use\" item=\"accent\" />\n\n## Độ dày đi cùng màu\n\n| Độ dày | Màu | Dùng cho |\n|---|---|---|\n| `border.width.default` | `color.border` hoặc `color.border.bold` | Mép và đường phân cách |\n| `border.width.selected` | `color.border.selected` | Tab, mục side nav hoặc card đang chọn |\n| `border.width.focused` | `color.border.focus` | Focus bằng bàn phím |\n| `border.width.accent` | `color.border.danger`, `.warning`, `.success`, `.info` hoặc `.brand` | Thanh trạng thái và nhấn mạnh |\n\nKhông báo trạng thái chỉ bằng màu. Đang chọn và đang focus còn đổi cả độ dày.\n\n## Nên và không nên\n\n<ShapeDemo kind=\"dodont\" item=\"selected\" />\n<ShapeDemo kind=\"dodont\" item=\"accent\" />\n<ShapeDemo kind=\"dodont\" item=\"cards\" />\n\n## Code\n\n```css\n.callout {\n position: relative;\n overflow: hidden;\n border: var(--bh-border-width-default) solid var(--bh-color-border);\n border-radius: var(--bh-radius-100);\n}\n.callout::before {\n content: \"\";\n position: absolute;\n inset: 0 auto 0 0;\n width: var(--bh-border-width-accent);\n background: var(--bh-color-border-danger);\n}\n:focus-visible {\n outline: var(--bh-border-width-focused) solid var(--bh-color-border-focus);\n outline-offset: var(--bh-state-focus-offset);\n}\n```\n\n## Token\n\n<TokenTable prefix=\"border\" />\n\n## Liên quan\n\n- [Bo góc](/vi/foundations/styles/radius/): các bậc bo góc và quy tắc lồng nhau.\n- [Trạng thái tương tác](/vi/foundations/styles/interaction-states/): hover, nhấn, đang chọn và vô hiệu.\n",
1155
1196
  "frontmatter": {
1156
1197
  "title": "Viền",
1157
1198
  "description": "Bốn độ dày viền, màu đi cùng mỗi độ dày, và cách vẽ focus ring.",
@@ -1259,8 +1300,8 @@ export const catalog = [
1259
1300
  "status": "active",
1260
1301
  "releasePhase": null,
1261
1302
  "planned": [],
1262
- "body": "import ColorDemo from '../../../../components/ColorDemo.astro';\n\n**Chọn token theo thứ bạn đang tô và ý nghĩa của nó, không chọn theo vẻ ngoài.**\n\n<ColorDemo kind=\"example\" />\n\n## Tìm token\n\n| Tôi cần | Dùng |\n|---|---|\n| Nền trang | `surface.page` |\n| Card, panel, dialog | `surface`, viền `border` |\n| Sidebar, header của bảng, vùng nền nhạt | `surface.subtle` |\n| Chữ nội dung, tiêu đề, nhãn | `text` |\n| Mô tả, cột phụ của bảng, điều hướng | `text.subtle` |\n| Metadata, mốc thời gian, chữ hướng dẫn, breadcrumb | `text.subtlest` |\n| Placeholder | `text.subtlest` |\n| Link | `link`; khi hover `link.hover` |\n| Icon cạnh chữ | `icon`; icon ít quan trọng hơn `icon.subtle` |\n| Đường phân cách, viền card | `border` |\n| Viền của ô nhập, checkbox hoặc select | `border.bold` |\n| Viền focus khi dùng bàn phím | `border.focus`, dày 2 px, cách 2 px |\n| Nút chính | `background.neutral.bold`, `text.inverse` |\n| Nút mặc định | `surface`, `border`, `text`; khi hover `background.neutral.subtle.hover` |\n| Nút cho hành động xoá, huỷ | `background.danger.bold`, `text.on-bold` |\n| Dòng hoặc mục menu khi hover | `background.neutral.subtle.hover` |\n| Dòng, tab hoặc mục menu được chọn | `background.selected` và một dấu hiệu thứ hai |\n| Trang hiện tại trong thanh điều hướng | Vạch `border.selected`, `background.selected`, `aria-current=\"page\"` |\n| Lỗi dưới một trường nhập | `text.danger`, `icon.danger` |\n| Banner báo trạng thái | `background.{role}.subtle`, `border.{role}.subtle`, `text`, `icon.{role}` |\n| Trạng thái trong một dòng của bảng | Một [nhãn](#nhãn) |\n| Tooltip, toast | `surface.inverse`, `text.inverse` |\n| Lớp phủ sau dialog hoặc drawer | `surface.scrim` |\n| Khung chờ khi đang tải | `skeleton`, vệt sáng `skeleton.subtle` |\n| Khối code | `code.background`, `code.text` |\n| Ghi chú thương hiệu | `background.brand.subtle`, `border.brand.subtle` |\n| Control bị vô hiệu | `background.disabled`, `text.disabled`, `border.disabled` |\n\nKhông có trong bảng? Ghép tên từ bốn phần của nó (xem [Token](/vi/foundations/styles/color/tokens/)). Nếu chưa có token, hãy đề nghị thêm. Không chọn màu gần giống.\n\n## Bề mặt và nền\n\n**Bề mặt (surface) là các lớp của màn hình. Nền (background) tô cho những thứ nằm trên đó.**\n\n<ColorDemo kind=\"surfaces\" />\n\n`surface.scrim` chỉ nằm sau dialog và drawer, một lớp duy nhất, với độ mờ riêng của nó.\n\n## Mức nhấn\n\n<ColorDemo kind=\"emphasis\" />\n\n## Trạng thái\n\n**Mỗi trạng thái thuộc một trong năm vai trò. Chọn theo việc người dùng cần làm, và luôn nói rõ bằng chữ.**\n\n### Chọn trạng thái\n\n| Vai trò | Dùng khi | Ví dụ trong HexaSync |\n|---|---|---|\n| Thông tin (info) | Có việc đang diễn ra hoặc đáng biết; không cần làm gì. | Đang đồng bộ, đang chờ, đang nhập |\n| Thành công (success) | Đã chạy tốt. | Đã đồng bộ, đã kết nối, đã xong |\n| Cảnh báo (warning) | Đang chạy nhưng sắp cần xử lý. | Đồng bộ một phần, token hết hạn sau 3 ngày, bị giới hạn tần suất |\n| Nguy hiểm (danger) | Bị lỗi hoặc bị chặn, hoặc hành động sẽ xoá mất dữ liệu. | Lỗi, mất kết nối, xoá |\n| Trung tính (neutral) | Không có gì đang chạy và không có gì sai. | Tạm dừng, nháp, bỏ qua, lưu trữ |\n\nCảnh báo dùng màu cam, không dùng màu vàng, vì màu vàng là màu thương hiệu. Không có mức thứ sáu; hãy nói rõ khác biệt bằng chữ (\"Lỗi 3 lần\").\n\n### Màu trạng thái\n\n<ColorDemo kind=\"status\" />\n\n<ColorDemo kind=\"banners\" />\n\n<ColorDemo kind=\"dodont\" item=\"warning\" />\n\n### Nhãn\n\n<ColorDemo kind=\"labels\" />\n\n| | Nhãn | Nhãn trạng thái |\n|---|---|---|\n| Hình thức | Viền theo `border` của vai trò, chữ theo `text` của vai trò | Nền theo `bold` của vai trò, chữ và icon theo `text.on-bold` |\n| Kích thước | Cao 20 px, padding 6 px; cỡ lớn 24 px, 8 px | Cao 32 px, padding 12 px |\n| Dùng | Nhiều nhãn trên một màn hình: dòng trong bảng, tag | Một nhãn trên mỗi trang: trạng thái chính của trang đó |\n\n## Trạng thái tương tác\n\n**Thêm `.hover` hoặc `.pressed` vào token ở trạng thái nghỉ. Không dùng độ mờ (opacity) hay lớp phủ.**\n\n<ColorDemo kind=\"states\" />\n\n| Trạng thái | Dùng |\n|---|---|\n| Hover, nhấn | Token ở trạng thái nghỉ, thêm `.hover` hoặc `.pressed` |\n| Được chọn | `background.selected` và một dấu hiệu thứ hai |\n| Focus | Viền `border.focus` dày 2 px, cách 2 px |\n| Vô hiệu | `background.disabled`, `text.disabled`, `border.disabled` |\n\nVới dòng hoặc mục menu, mỗi trạng thái cách nền thêm một bậc: hover, rồi được chọn, rồi được chọn khi hover. Dòng đang hover luôn nhạt hơn dòng được chọn, nên không bao giờ trông như đang được chọn.\n\nXem thêm ở trang [Trạng thái tương tác](/vi/foundations/styles/interaction-states/).\n\n## Nút\n\n<ColorDemo kind=\"actions\" />\n",
1263
- "raw": "---\ntitle: Cách dùng\ndescription: Dùng token nào cho từng phần của màn hình, cách tô màu trạng thái, mức nhấn và trạng thái tương tác, và những điều không được làm.\norder: 2\n---\nimport ColorDemo from '../../../../components/ColorDemo.astro';\n\n**Chọn token theo thứ bạn đang tô và ý nghĩa của nó, không chọn theo vẻ ngoài.**\n\n<ColorDemo kind=\"example\" />\n\n## Tìm token\n\n| Tôi cần | Dùng |\n|---|---|\n| Nền trang | `surface.page` |\n| Card, panel, dialog | `surface`, viền `border` |\n| Sidebar, header của bảng, vùng nền nhạt | `surface.subtle` |\n| Chữ nội dung, tiêu đề, nhãn | `text` |\n| Mô tả, cột phụ của bảng, điều hướng | `text.subtle` |\n| Metadata, mốc thời gian, chữ hướng dẫn, breadcrumb | `text.subtlest` |\n| Placeholder | `text.subtlest` |\n| Link | `link`; khi hover `link.hover` |\n| Icon cạnh chữ | `icon`; icon ít quan trọng hơn `icon.subtle` |\n| Đường phân cách, viền card | `border` |\n| Viền của ô nhập, checkbox hoặc select | `border.bold` |\n| Viền focus khi dùng bàn phím | `border.focus`, dày 2 px, cách 2 px |\n| Nút chính | `background.neutral.bold`, `text.inverse` |\n| Nút mặc định | `surface`, `border`, `text`; khi hover `background.neutral.subtle.hover` |\n| Nút cho hành động xoá, huỷ | `background.danger.bold`, `text.on-bold` |\n| Dòng hoặc mục menu khi hover | `background.neutral.subtle.hover` |\n| Dòng, tab hoặc mục menu được chọn | `background.selected` và một dấu hiệu thứ hai |\n| Trang hiện tại trong thanh điều hướng | Vạch `border.selected`, `background.selected`, `aria-current=\"page\"` |\n| Lỗi dưới một trường nhập | `text.danger`, `icon.danger` |\n| Banner báo trạng thái | `background.{role}.subtle`, `border.{role}.subtle`, `text`, `icon.{role}` |\n| Trạng thái trong một dòng của bảng | Một [nhãn](#nhãn) |\n| Tooltip, toast | `surface.inverse`, `text.inverse` |\n| Lớp phủ sau dialog hoặc drawer | `surface.scrim` |\n| Khung chờ khi đang tải | `skeleton`, vệt sáng `skeleton.subtle` |\n| Khối code | `code.background`, `code.text` |\n| Ghi chú thương hiệu | `background.brand.subtle`, `border.brand.subtle` |\n| Control bị vô hiệu | `background.disabled`, `text.disabled`, `border.disabled` |\n\nKhông có trong bảng? Ghép tên từ bốn phần của nó (xem [Token](/vi/foundations/styles/color/tokens/)). Nếu chưa có token, hãy đề nghị thêm. Không chọn màu gần giống.\n\n## Bề mặt và nền\n\n**Bề mặt (surface) là các lớp của màn hình. Nền (background) tô cho những thứ nằm trên đó.**\n\n<ColorDemo kind=\"surfaces\" />\n\n`surface.scrim` chỉ nằm sau dialog và drawer, một lớp duy nhất, với độ mờ riêng của nó.\n\n## Mức nhấn\n\n<ColorDemo kind=\"emphasis\" />\n\n## Trạng thái\n\n**Mỗi trạng thái thuộc một trong năm vai trò. Chọn theo việc người dùng cần làm, và luôn nói rõ bằng chữ.**\n\n### Chọn trạng thái\n\n| Vai trò | Dùng khi | Ví dụ trong HexaSync |\n|---|---|---|\n| Thông tin (info) | Có việc đang diễn ra hoặc đáng biết; không cần làm gì. | Đang đồng bộ, đang chờ, đang nhập |\n| Thành công (success) | Đã chạy tốt. | Đã đồng bộ, đã kết nối, đã xong |\n| Cảnh báo (warning) | Đang chạy nhưng sắp cần xử lý. | Đồng bộ một phần, token hết hạn sau 3 ngày, bị giới hạn tần suất |\n| Nguy hiểm (danger) | Bị lỗi hoặc bị chặn, hoặc hành động sẽ xoá mất dữ liệu. | Lỗi, mất kết nối, xoá |\n| Trung tính (neutral) | Không có gì đang chạy và không có gì sai. | Tạm dừng, nháp, bỏ qua, lưu trữ |\n\nCảnh báo dùng màu cam, không dùng màu vàng, vì màu vàng là màu thương hiệu. Không có mức thứ sáu; hãy nói rõ khác biệt bằng chữ (\"Lỗi 3 lần\").\n\n### Màu trạng thái\n\n<ColorDemo kind=\"status\" />\n\n<ColorDemo kind=\"banners\" />\n\n<ColorDemo kind=\"dodont\" item=\"warning\" />\n\n### Nhãn\n\n<ColorDemo kind=\"labels\" />\n\n| | Nhãn | Nhãn trạng thái |\n|---|---|---|\n| Hình thức | Viền theo `border` của vai trò, chữ theo `text` của vai trò | Nền theo `bold` của vai trò, chữ và icon theo `text.on-bold` |\n| Kích thước | Cao 20 px, padding 6 px; cỡ lớn 24 px, 8 px | Cao 32 px, padding 12 px |\n| Dùng | Nhiều nhãn trên một màn hình: dòng trong bảng, tag | Một nhãn trên mỗi trang: trạng thái chính của trang đó |\n\n## Trạng thái tương tác\n\n**Thêm `.hover` hoặc `.pressed` vào token ở trạng thái nghỉ. Không dùng độ mờ (opacity) hay lớp phủ.**\n\n<ColorDemo kind=\"states\" />\n\n| Trạng thái | Dùng |\n|---|---|\n| Hover, nhấn | Token ở trạng thái nghỉ, thêm `.hover` hoặc `.pressed` |\n| Được chọn | `background.selected` và một dấu hiệu thứ hai |\n| Focus | Viền `border.focus` dày 2 px, cách 2 px |\n| Vô hiệu | `background.disabled`, `text.disabled`, `border.disabled` |\n\nVới dòng hoặc mục menu, mỗi trạng thái cách nền thêm một bậc: hover, rồi được chọn, rồi được chọn khi hover. Dòng đang hover luôn nhạt hơn dòng được chọn, nên không bao giờ trông như đang được chọn.\n\nXem thêm ở trang [Trạng thái tương tác](/vi/foundations/styles/interaction-states/).\n\n## Nút\n\n<ColorDemo kind=\"actions\" />\n",
1303
+ "body": "import ColorDemo from '../../../../components/ColorDemo.astro';\n\n**Chọn token theo thứ bạn đang tô và ý nghĩa của nó, không chọn theo vẻ ngoài.**\n\n<ColorDemo kind=\"example\" />\n\n## Tìm token\n\n| Tôi cần | Dùng |\n|---|---|\n| Nền trang | `surface.page` |\n| Card, panel | `surface`, viền `border` |\n| Menu, popover, dialog, drawer | `surface.overlay`; mục bên trong dùng `surface.overlay.hover`, `.pressed`, `.selected` |\n| Header toàn cục và sidebar (cùng bề mặt khung ứng dụng), drawer điều hướng mobile, header của bảng, vùng nền nhạt | `surface.subtle` |\n| Chữ nội dung, tiêu đề, nhãn | `text` |\n| Mô tả, cột phụ của bảng, điều hướng | `text.subtle` |\n| Metadata, mốc thời gian, chữ hướng dẫn, breadcrumb | `text.subtlest` |\n| Placeholder | `text.subtlest` |\n| Link | `link`; khi hover `link.hover` |\n| Icon cạnh chữ | `icon`; icon ít quan trọng hơn `icon.subtle` |\n| Đường phân cách, viền card | `border` |\n| Viền của ô nhập, checkbox hoặc select | `border.bold` |\n| Viền focus khi dùng bàn phím | `border.focus`, dày 2 px, cách 2 px |\n| Nút chính | `background.neutral.bold`, `text.inverse` |\n| Nút mặc định | `surface`, `border`, `text`; khi hover `background.neutral.subtle.hover` |\n| Nút cho hành động xoá, huỷ | `background.danger.bold`, `text.on-bold` |\n| Dòng hoặc mục menu khi hover | `background.neutral.subtle.hover` |\n| Dòng, tab hoặc mục menu được chọn | `background.selected` và một dấu hiệu thứ hai |\n| Trang hiện tại trong thanh điều hướng | Vạch `border.selected`, `background.selected`, `aria-current=\"page\"` |\n| Lỗi dưới một trường nhập | `text.danger`, `icon.danger` |\n| Banner báo trạng thái | `background.{role}.subtle`, `border.{role}.subtle`, `text`, `icon.{role}` |\n| Trạng thái trong một dòng của bảng | Một [nhãn](#nhãn) |\n| Tooltip | `surface.inverse`, `text.inverse` |\n| Toast | `surface.overlay`, `text`, `icon.{role}`, bóng `elevation.shadow.overlay`; không viền |\n| Switch | Bật: `background.neutral.bold`; tắt: `background.neutral`, viền `border.bold`; núm `surface` |\n| Avatar chữ cái đầu | `background.neutral`, `text` |\n| Số thứ tự, số đếm | `background.neutral.bold`, `text.inverse` |\n| Lớp phủ sau dialog hoặc drawer | `surface.scrim` |\n| Khung chờ khi đang tải | `skeleton`, vệt sáng `skeleton.subtle` |\n| Khối code | `code.background`, `code.text` |\n| Ghi chú thương hiệu | `background.brand.subtle`, `border.brand.subtle` |\n| Control bị vô hiệu | `background.disabled`, `text.disabled`, `border.disabled` |\n\nKhông có trong bảng? Ghép tên từ bốn phần của nó (xem [Token](/vi/foundations/styles/color/tokens/)). Nếu chưa có token, hãy đề nghị thêm. Không chọn màu gần giống.\n\n## Bề mặt và nền\n\n**Bề mặt (surface) là các lớp của màn hình. Nền (background) tô cho những thứ nằm trên đó.**\n\n<ColorDemo kind=\"surfaces\" />\n\n`surface.scrim` chỉ nằm sau dialog và drawer, một lớp duy nhất, với độ mờ riêng của nó.\n\n## Mức nhấn\n\n<ColorDemo kind=\"emphasis\" />\n\n## Trạng thái\n\n**Mỗi trạng thái thuộc một trong năm vai trò. Chọn theo việc người dùng cần làm, và luôn nói rõ bằng chữ.**\n\n### Chọn trạng thái\n\n| Vai trò | Dùng khi | Ví dụ trong HexaSync |\n|---|---|---|\n| Thông tin (info) | Có việc đang diễn ra hoặc đáng biết; không cần làm gì. | Đang đồng bộ, đang chờ, đang nhập |\n| Thành công (success) | Đã chạy tốt. | Đã đồng bộ, đã kết nối, đã xong |\n| Cảnh báo (warning) | Đang chạy nhưng sắp cần xử lý. | Đồng bộ một phần, token hết hạn sau 3 ngày, bị giới hạn tần suất |\n| Nguy hiểm (danger) | Bị lỗi hoặc bị chặn, hoặc hành động sẽ xoá mất dữ liệu. | Lỗi, mất kết nối, xoá |\n| Trung tính (neutral) | Không có gì đang chạy và không có gì sai. | Tạm dừng, nháp, bỏ qua, lưu trữ |\n\nCảnh báo dùng màu cam, không dùng màu vàng, vì màu vàng là màu thương hiệu. Không có mức thứ sáu; hãy nói rõ khác biệt bằng chữ (\"Lỗi 3 lần\").\n\n### Màu trạng thái\n\n<ColorDemo kind=\"status\" />\n\n<ColorDemo kind=\"banners\" />\n\n<ColorDemo kind=\"dodont\" item=\"warning\" />\n\n### Nhãn\n\n<ColorDemo kind=\"labels\" />\n\n| | Nhãn | Nhãn trạng thái |\n|---|---|---|\n| Hình thức | Viền theo `border` của vai trò, chữ theo `text` của vai trò | Nền theo `bold` của vai trò, chữ và icon theo `text.on-bold` |\n| Kích thước | Cao 20 px, padding 6 px; cỡ lớn 24 px, 8 px | Cao 32 px, padding 12 px |\n| Dùng | Nhiều nhãn trên một màn hình: trạng thái trong dòng bảng và danh sách | Một nhãn trên mỗi trang: trạng thái chính của trang đó |\n\nTag không phải là nhãn. Tag là thứ người dùng thêm vào hoặc gỡ ra, như bộ lọc hay từ khóa: cao 24 px, bo góc 4 px, `border` và `text`, có nút gỡ. Nhãn cho biết trạng thái, người dùng không gỡ được.\n\n## Trạng thái tương tác\n\n**Thêm `.hover` hoặc `.pressed` vào token ở trạng thái nghỉ. Không dùng độ mờ (opacity) hay lớp phủ.**\n\n<ColorDemo kind=\"states\" />\n\n| Trạng thái | Dùng |\n|---|---|\n| Hover, nhấn | Token ở trạng thái nghỉ, thêm `.hover` hoặc `.pressed` |\n| Được chọn | `background.selected` và một dấu hiệu thứ hai |\n| Focus | Viền `border.focus` dày 2 px, cách 2 px |\n| Vô hiệu | `background.disabled`, `text.disabled`, `border.disabled` |\n\nVới dòng hoặc mục menu, mỗi trạng thái cách nền thêm một bậc: hover, rồi được chọn, rồi được chọn khi hover. Dòng đang hover luôn nhạt hơn dòng được chọn, nên không bao giờ trông như đang được chọn.\n\nXem thêm ở trang [Trạng thái tương tác](/vi/foundations/styles/interaction-states/).\n\n## Nút\n\n<ColorDemo kind=\"actions\" />\n",
1304
+ "raw": "---\ntitle: Cách dùng\ndescription: Dùng token nào cho từng phần của màn hình, cách tô màu trạng thái, mức nhấn và trạng thái tương tác, và những điều không được làm.\norder: 2\n---\nimport ColorDemo from '../../../../components/ColorDemo.astro';\n\n**Chọn token theo thứ bạn đang tô và ý nghĩa của nó, không chọn theo vẻ ngoài.**\n\n<ColorDemo kind=\"example\" />\n\n## Tìm token\n\n| Tôi cần | Dùng |\n|---|---|\n| Nền trang | `surface.page` |\n| Card, panel | `surface`, viền `border` |\n| Menu, popover, dialog, drawer | `surface.overlay`; mục bên trong dùng `surface.overlay.hover`, `.pressed`, `.selected` |\n| Header toàn cục và sidebar (cùng bề mặt khung ứng dụng), drawer điều hướng mobile, header của bảng, vùng nền nhạt | `surface.subtle` |\n| Chữ nội dung, tiêu đề, nhãn | `text` |\n| Mô tả, cột phụ của bảng, điều hướng | `text.subtle` |\n| Metadata, mốc thời gian, chữ hướng dẫn, breadcrumb | `text.subtlest` |\n| Placeholder | `text.subtlest` |\n| Link | `link`; khi hover `link.hover` |\n| Icon cạnh chữ | `icon`; icon ít quan trọng hơn `icon.subtle` |\n| Đường phân cách, viền card | `border` |\n| Viền của ô nhập, checkbox hoặc select | `border.bold` |\n| Viền focus khi dùng bàn phím | `border.focus`, dày 2 px, cách 2 px |\n| Nút chính | `background.neutral.bold`, `text.inverse` |\n| Nút mặc định | `surface`, `border`, `text`; khi hover `background.neutral.subtle.hover` |\n| Nút cho hành động xoá, huỷ | `background.danger.bold`, `text.on-bold` |\n| Dòng hoặc mục menu khi hover | `background.neutral.subtle.hover` |\n| Dòng, tab hoặc mục menu được chọn | `background.selected` và một dấu hiệu thứ hai |\n| Trang hiện tại trong thanh điều hướng | Vạch `border.selected`, `background.selected`, `aria-current=\"page\"` |\n| Lỗi dưới một trường nhập | `text.danger`, `icon.danger` |\n| Banner báo trạng thái | `background.{role}.subtle`, `border.{role}.subtle`, `text`, `icon.{role}` |\n| Trạng thái trong một dòng của bảng | Một [nhãn](#nhãn) |\n| Tooltip | `surface.inverse`, `text.inverse` |\n| Toast | `surface.overlay`, `text`, `icon.{role}`, bóng `elevation.shadow.overlay`; không viền |\n| Switch | Bật: `background.neutral.bold`; tắt: `background.neutral`, viền `border.bold`; núm `surface` |\n| Avatar chữ cái đầu | `background.neutral`, `text` |\n| Số thứ tự, số đếm | `background.neutral.bold`, `text.inverse` |\n| Lớp phủ sau dialog hoặc drawer | `surface.scrim` |\n| Khung chờ khi đang tải | `skeleton`, vệt sáng `skeleton.subtle` |\n| Khối code | `code.background`, `code.text` |\n| Ghi chú thương hiệu | `background.brand.subtle`, `border.brand.subtle` |\n| Control bị vô hiệu | `background.disabled`, `text.disabled`, `border.disabled` |\n\nKhông có trong bảng? Ghép tên từ bốn phần của nó (xem [Token](/vi/foundations/styles/color/tokens/)). Nếu chưa có token, hãy đề nghị thêm. Không chọn màu gần giống.\n\n## Bề mặt và nền\n\n**Bề mặt (surface) là các lớp của màn hình. Nền (background) tô cho những thứ nằm trên đó.**\n\n<ColorDemo kind=\"surfaces\" />\n\n`surface.scrim` chỉ nằm sau dialog và drawer, một lớp duy nhất, với độ mờ riêng của nó.\n\n## Mức nhấn\n\n<ColorDemo kind=\"emphasis\" />\n\n## Trạng thái\n\n**Mỗi trạng thái thuộc một trong năm vai trò. Chọn theo việc người dùng cần làm, và luôn nói rõ bằng chữ.**\n\n### Chọn trạng thái\n\n| Vai trò | Dùng khi | Ví dụ trong HexaSync |\n|---|---|---|\n| Thông tin (info) | Có việc đang diễn ra hoặc đáng biết; không cần làm gì. | Đang đồng bộ, đang chờ, đang nhập |\n| Thành công (success) | Đã chạy tốt. | Đã đồng bộ, đã kết nối, đã xong |\n| Cảnh báo (warning) | Đang chạy nhưng sắp cần xử lý. | Đồng bộ một phần, token hết hạn sau 3 ngày, bị giới hạn tần suất |\n| Nguy hiểm (danger) | Bị lỗi hoặc bị chặn, hoặc hành động sẽ xoá mất dữ liệu. | Lỗi, mất kết nối, xoá |\n| Trung tính (neutral) | Không có gì đang chạy và không có gì sai. | Tạm dừng, nháp, bỏ qua, lưu trữ |\n\nCảnh báo dùng màu cam, không dùng màu vàng, vì màu vàng là màu thương hiệu. Không có mức thứ sáu; hãy nói rõ khác biệt bằng chữ (\"Lỗi 3 lần\").\n\n### Màu trạng thái\n\n<ColorDemo kind=\"status\" />\n\n<ColorDemo kind=\"banners\" />\n\n<ColorDemo kind=\"dodont\" item=\"warning\" />\n\n### Nhãn\n\n<ColorDemo kind=\"labels\" />\n\n| | Nhãn | Nhãn trạng thái |\n|---|---|---|\n| Hình thức | Viền theo `border` của vai trò, chữ theo `text` của vai trò | Nền theo `bold` của vai trò, chữ và icon theo `text.on-bold` |\n| Kích thước | Cao 20 px, padding 6 px; cỡ lớn 24 px, 8 px | Cao 32 px, padding 12 px |\n| Dùng | Nhiều nhãn trên một màn hình: trạng thái trong dòng bảng và danh sách | Một nhãn trên mỗi trang: trạng thái chính của trang đó |\n\nTag không phải là nhãn. Tag là thứ người dùng thêm vào hoặc gỡ ra, như bộ lọc hay từ khóa: cao 24 px, bo góc 4 px, `border` và `text`, có nút gỡ. Nhãn cho biết trạng thái, người dùng không gỡ được.\n\n## Trạng thái tương tác\n\n**Thêm `.hover` hoặc `.pressed` vào token ở trạng thái nghỉ. Không dùng độ mờ (opacity) hay lớp phủ.**\n\n<ColorDemo kind=\"states\" />\n\n| Trạng thái | Dùng |\n|---|---|\n| Hover, nhấn | Token ở trạng thái nghỉ, thêm `.hover` hoặc `.pressed` |\n| Được chọn | `background.selected` và một dấu hiệu thứ hai |\n| Focus | Viền `border.focus` dày 2 px, cách 2 px |\n| Vô hiệu | `background.disabled`, `text.disabled`, `border.disabled` |\n\nVới dòng hoặc mục menu, mỗi trạng thái cách nền thêm một bậc: hover, rồi được chọn, rồi được chọn khi hover. Dòng đang hover luôn nhạt hơn dòng được chọn, nên không bao giờ trông như đang được chọn.\n\nXem thêm ở trang [Trạng thái tương tác](/vi/foundations/styles/interaction-states/).\n\n## Nút\n\n<ColorDemo kind=\"actions\" />\n",
1264
1305
  "frontmatter": {
1265
1306
  "title": "Cách dùng",
1266
1307
  "description": "Dùng token nào cho từng phần của màn hình, cách tô màu trạng thái, mức nhấn và trạng thái tương tác, và những điều không được làm.",
@@ -1274,28 +1315,33 @@ export const catalog = [
1274
1315
  "locale": "vi",
1275
1316
  "kind": "guidance",
1276
1317
  "title": "Biểu đồ dữ liệu",
1277
- "status": "planned",
1318
+ "status": "active",
1278
1319
  "releasePhase": null,
1279
- "planned": [
1280
- "Bảng màu cho các chuỗi dữ liệu, đủ tương phản ở light và dark",
1281
- "Màu trạng thái trong biểu đồ",
1282
- "Các loại biểu đồ và khi nào dùng",
1283
- "Trục, chú giải, tooltip và định dạng số",
1284
- "Biểu đồ dễ tiếp cận: không chỉ dựa vào màu, có phần mô tả bằng chữ"
1285
- ],
1286
- "body": "",
1287
- "raw": "---\ntitle: \"Biểu đồ dữ liệu\"\ndescription: \"Màu, chữ và quy tắc cho biểu đồ, ô KPI và các cách hiển thị dữ liệu khác.\"\norder: 13\nplanned:\n - \"Bảng màu cho các chuỗi dữ liệu, đủ tương phản ở light và dark\"\n - \"Màu trạng thái trong biểu đồ\"\n - \"Các loại biểu đồ và khi nào dùng\"\n - \"Trục, chú giải, tooltip và định dạng số\"\n - \"Biểu đồ dễ tiếp cận: không chỉ dựa vào màu, có phần mô tả bằng chữ\"\n---\n",
1320
+ "planned": [],
1321
+ "body": "\n## Chọn theo câu hỏi\n\nDùng biểu đồ đường cho giá trị theo thời gian, đường xu hướng nhỏ chỉ khi đặt cạnh\ngiá trị hiện tại, thanh tỷ lệ cho các phần của một tổng đã ghi rõ, và dòng thời gian\nđể thể hiện thời điểm thực thi. Vòng sức khỏe phải có cả điểm số và nhận định bằng\nchữ. Không dùng vùng tô trang trí, chuyển sắc, hiệu ứng kính hoặc nhấp nháy lỗi.\n\n## Chỉ số, loại và trạng thái là ba ý nghĩa khác nhau\n\n`visualization.metric.*` định nghĩa các chuỗi vận hành có tên: tổng phiên chạy,\nhoàn tất, thất bại, tỷ lệ thành công, phiên đang chạy, thời gian thực thi trung bình\nvà độ sâu hàng đợi. Số lượng và thời gian tự chúng không phải cảnh báo. Luôn hiện\nđơn vị, ngưỡng và tên chỉ số.\n\n`visualization.job-type.*` định danh các loại queue-status, sync-history,\npolling-jobs và generic-jobs, không biểu thị thành công, cảnh báo hay thất bại.\nCác bí danh màu nền tảng tự thích ứng với giao diện sáng và tối. Luôn kèm tên loại\nhoặc biểu tượng riêng. Ở chế độ kết hợp của dòng thời gian, dấu ngoài thể hiện loại\nphiên và dấu trong thể hiện trạng thái; chú giải phải giải thích cả hai. Ở chế độ\ntrạng thái, dùng `color.text.success`, `danger`, `info`, `warning` hoặc chữ trung\ntính theo trạng thái thực tế. Giữ nhãn trạng thái và biểu tượng kết quả.\n\n`visualization.priority.1` đến `.5` thể hiện mức khẩn cấp của hàng đợi, luôn ghi\nP1–P5. Độ ưu tiên không phải kết quả thực thi. P1 cao nhất, P5 thấp nhất. Không\ndùng màu ưu tiên để khẳng định thành công hay thất bại.\n\n## Hình học và chữ\n\nDùng `visualization.line-width`, `sparkline-width`, `grid-width`, `point-radius`\nvà `hover-point-radius` cho đường và điểm SVG. Độ dày tính bằng pixel CSS; dùng\nviewBox theo kích thước đo được hoặc nét không co giãn để tránh méo.\n`timeline-track-height` và `activity-track-height` quy định độ dày thanh tỷ lệ.\n`ring-size` là kích thước CSS; `ring-width` là phần trăm theo API Ant Design;\n`ring-gap` tính bằng độ. Chỉ đổi kích thước thành số tại ranh giới API.\nTọa độ dữ liệu và kích thước vùng chứa đo được vẫn là dữ liệu, không phải token.\n\n`timeline-node-size` và `timeline-node-inner-size` quy định dấu ngoài cho loại và\ndấu trong cho trạng thái. Các biến thể `touch` và `tablet` giữ khả năng đọc, không\nđổi cách mã hóa. `timeline-cluster-size` quy định dấu tổng hợp số lượng; tô viền\ntheo loại hoặc trạng thái, giữ số bằng chữ thường trên nền thường, không đặt chữ\ntrắng trên màu sáng đã thích ứng với giao diện tối. Vùng tương tác dùng\n`size.target.touch`, độc lập với kích thước dấu nhìn thấy.\n`chart-height`, `chart-initial-width`, `sparkline-height`,\n`sparkline-compact-height` và `sparkline-initial-width` quy định vùng vẽ; chiều rộng\nban đầu được thay bằng số đo thực tế. `sparkline-point-radius` là bán kính điểm cuối\nnhỏ. Các kích thước này không phải thang dữ liệu hay giá trị trục.\n\nDùng `font.heading.large` cùng chữ số có độ rộng bằng nhau cho KPI,\n`font.body.small` cho siêu dữ liệu, trục và tooltip; `font.label.small` cho chú giải.\nDùng `color.border` cho lưới trang trí, `color.text.subtle` cho nhãn và cặp màu nền\nđảo/chữ đảo cho tooltip. Dấu dữ liệu có ý nghĩa cần tương phản ít nhất 3:1 trên nền\nthực tế; chữ thường cần 4,5:1. Kiểm tra từng cặp màu trong từng giao diện, không\ncoi việc dùng bí danh là bằng chứng tương phản khi hiển thị.\n\n## Nhãn, định dạng và tương tác\n\nGiữ định dạng số, thời điểm và thời lượng theo ngôn ngữ nhất quán với bảng bên\ncạnh. Hiện đơn vị và khoảng thời gian; giữ ngữ cảnh múi giờ. Không âm thầm đổi số\nđếm thành tỷ lệ hoặc cắt ngắn thời lượng. Chú giải phải đặt tên mọi chuỗi đang hiện;\nchuỗi được chọn cần dấu hiệu ngoài màu sắc. Tooltip phải nằm trong vùng biểu đồ\nvà không được là cách duy nhất để đọc giá trị. Cung cấp số tổng hợp hoặc bảng\ncùng dữ liệu bên cạnh và tên biểu đồ cho công nghệ hỗ trợ. Điều khiển chú giải\nbằng bàn phím phải giữ chỉ báo lấy nét rõ ràng.\n\n## Dải đánh giá lưu lượng\n\n`visualization.traffic.{healthy,attention,degraded,critical,unavailable,fault}.{fill,outline}`\ncung cấp cặp màu tô và viền. Healthy là lưu lượng được chấp nhận; attention, degraded\nvà critical thể hiện các ngưỡng tỷ lệ yêu cầu bị từ chối tăng dần. Ghi ngưỡng trong\nnhãn hoặc tooltip. Attention và degraded dùng chung màu cảnh báo: phân biệt bằng\nnét đứt và nhãn rõ ràng, không chỉ bằng màu. Unavailable nghĩa là không có yêu cầu\nđể đánh giá. Fault là lỗi xử lý yêu cầu nội bộ/máy chủ, không phải ngưỡng tỷ lệ\nđã đo; hiện số lỗi riêng, nhãn hoặc biểu tượng và họa tiết gạch chéo. Lỗi lấy dữ liệu là lỗi riêng. Không đổi\ndữ liệu thiếu thành số không hay kết quả tốt. Dùng `color.text` trên nền tô nhạt.\n",
1322
+ "raw": "---\ntitle: \"Biểu đồ dữ liệu\"\ndescription: \"Màu, chữ và quy tắc cho biểu đồ, ô KPI và các cách hiển thị dữ liệu khác.\"\norder: 13\n---\n\n## Chọn theo câu hỏi\n\nDùng biểu đồ đường cho giá trị theo thời gian, đường xu hướng nhỏ chỉ khi đặt cạnh\ngiá trị hiện tại, thanh tỷ lệ cho các phần của một tổng đã ghi rõ, và dòng thời gian\nđể thể hiện thời điểm thực thi. Vòng sức khỏe phải có cả điểm số và nhận định bằng\nchữ. Không dùng vùng tô trang trí, chuyển sắc, hiệu ứng kính hoặc nhấp nháy lỗi.\n\n## Chỉ số, loại và trạng thái là ba ý nghĩa khác nhau\n\n`visualization.metric.*` định nghĩa các chuỗi vận hành có tên: tổng phiên chạy,\nhoàn tất, thất bại, tỷ lệ thành công, phiên đang chạy, thời gian thực thi trung bình\nvà độ sâu hàng đợi. Số lượng và thời gian tự chúng không phải cảnh báo. Luôn hiện\nđơn vị, ngưỡng và tên chỉ số.\n\n`visualization.job-type.*` định danh các loại queue-status, sync-history,\npolling-jobs và generic-jobs, không biểu thị thành công, cảnh báo hay thất bại.\nCác bí danh màu nền tảng tự thích ứng với giao diện sáng và tối. Luôn kèm tên loại\nhoặc biểu tượng riêng. Ở chế độ kết hợp của dòng thời gian, dấu ngoài thể hiện loại\nphiên và dấu trong thể hiện trạng thái; chú giải phải giải thích cả hai. Ở chế độ\ntrạng thái, dùng `color.text.success`, `danger`, `info`, `warning` hoặc chữ trung\ntính theo trạng thái thực tế. Giữ nhãn trạng thái và biểu tượng kết quả.\n\n`visualization.priority.1` đến `.5` thể hiện mức khẩn cấp của hàng đợi, luôn ghi\nP1–P5. Độ ưu tiên không phải kết quả thực thi. P1 cao nhất, P5 thấp nhất. Không\ndùng màu ưu tiên để khẳng định thành công hay thất bại.\n\n## Hình học và chữ\n\nDùng `visualization.line-width`, `sparkline-width`, `grid-width`, `point-radius`\nvà `hover-point-radius` cho đường và điểm SVG. Độ dày tính bằng pixel CSS; dùng\nviewBox theo kích thước đo được hoặc nét không co giãn để tránh méo.\n`timeline-track-height` và `activity-track-height` quy định độ dày thanh tỷ lệ.\n`ring-size` là kích thước CSS; `ring-width` là phần trăm theo API Ant Design;\n`ring-gap` tính bằng độ. Chỉ đổi kích thước thành số tại ranh giới API.\nTọa độ dữ liệu và kích thước vùng chứa đo được vẫn là dữ liệu, không phải token.\n\n`timeline-node-size` và `timeline-node-inner-size` quy định dấu ngoài cho loại và\ndấu trong cho trạng thái. Các biến thể `touch` và `tablet` giữ khả năng đọc, không\nđổi cách mã hóa. `timeline-cluster-size` quy định dấu tổng hợp số lượng; tô viền\ntheo loại hoặc trạng thái, giữ số bằng chữ thường trên nền thường, không đặt chữ\ntrắng trên màu sáng đã thích ứng với giao diện tối. Vùng tương tác dùng\n`size.target.touch`, độc lập với kích thước dấu nhìn thấy.\n`chart-height`, `chart-initial-width`, `sparkline-height`,\n`sparkline-compact-height` và `sparkline-initial-width` quy định vùng vẽ; chiều rộng\nban đầu được thay bằng số đo thực tế. `sparkline-point-radius` là bán kính điểm cuối\nnhỏ. Các kích thước này không phải thang dữ liệu hay giá trị trục.\n\nDùng `font.heading.large` cùng chữ số có độ rộng bằng nhau cho KPI,\n`font.body.small` cho siêu dữ liệu, trục và tooltip; `font.label.small` cho chú giải.\nDùng `color.border` cho lưới trang trí, `color.text.subtle` cho nhãn và cặp màu nền\nđảo/chữ đảo cho tooltip. Dấu dữ liệu có ý nghĩa cần tương phản ít nhất 3:1 trên nền\nthực tế; chữ thường cần 4,5:1. Kiểm tra từng cặp màu trong từng giao diện, không\ncoi việc dùng bí danh là bằng chứng tương phản khi hiển thị.\n\n## Nhãn, định dạng và tương tác\n\nGiữ định dạng số, thời điểm và thời lượng theo ngôn ngữ nhất quán với bảng bên\ncạnh. Hiện đơn vị và khoảng thời gian; giữ ngữ cảnh múi giờ. Không âm thầm đổi số\nđếm thành tỷ lệ hoặc cắt ngắn thời lượng. Chú giải phải đặt tên mọi chuỗi đang hiện;\nchuỗi được chọn cần dấu hiệu ngoài màu sắc. Tooltip phải nằm trong vùng biểu đồ\nvà không được là cách duy nhất để đọc giá trị. Cung cấp số tổng hợp hoặc bảng\ncùng dữ liệu bên cạnh và tên biểu đồ cho công nghệ hỗ trợ. Điều khiển chú giải\nbằng bàn phím phải giữ chỉ báo lấy nét rõ ràng.\n\n## Dải đánh giá lưu lượng\n\n`visualization.traffic.{healthy,attention,degraded,critical,unavailable,fault}.{fill,outline}`\ncung cấp cặp màu tô và viền. Healthy là lưu lượng được chấp nhận; attention, degraded\nvà critical thể hiện các ngưỡng tỷ lệ yêu cầu bị từ chối tăng dần. Ghi ngưỡng trong\nnhãn hoặc tooltip. Attention và degraded dùng chung màu cảnh báo: phân biệt bằng\nnét đứt và nhãn rõ ràng, không chỉ bằng màu. Unavailable nghĩa là không có yêu cầu\nđể đánh giá. Fault là lỗi xử lý yêu cầu nội bộ/máy chủ, không phải ngưỡng tỷ lệ\nđã đo; hiện số lỗi riêng, nhãn hoặc biểu tượng và họa tiết gạch chéo. Lỗi lấy dữ liệu là lỗi riêng. Không đổi\ndữ liệu thiếu thành số không hay kết quả tốt. Dùng `color.text` trên nền tô nhạt.\n",
1288
1323
  "frontmatter": {
1289
1324
  "title": "Biểu đồ dữ liệu",
1290
1325
  "description": "Màu, chữ và quy tắc cho biểu đồ, ô KPI và các cách hiển thị dữ liệu khác.",
1291
- "order": 13,
1292
- "planned": [
1293
- "Bảng màu cho các chuỗi dữ liệu, đủ tương phản ở light và dark",
1294
- "Màu trạng thái trong biểu đồ",
1295
- "Các loại biểu đồ và khi nào dùng",
1296
- "Trục, chú giải, tooltip và định dạng số",
1297
- "Biểu đồ dễ tiếp cận: không chỉ dựa vào màu, có phần mô tả bằng chữ"
1298
- ]
1326
+ "order": 13
1327
+ }
1328
+ },
1329
+ {
1330
+ "id": "vi/foundations/styles/elevation",
1331
+ "path": "src/content-vi/foundations/styles/elevation.mdx",
1332
+ "documentPath": "docs/src/content-vi/foundations/styles/elevation.mdx",
1333
+ "locale": "vi",
1334
+ "kind": "guidance",
1335
+ "title": "Đổ bóng",
1336
+ "status": "active",
1337
+ "releasePhase": null,
1338
+ "planned": [],
1339
+ "body": "import ElevationDemo from '../../../components/ElevationDemo.astro';\nimport TokenTable from '../../../components/TokenTable.astro';\n\nElevation là khoảng cách mà một bề mặt trông như có so với trang, thể hiện bằng bóng đổ và ở dark mode thì thêm nền sáng hơn. Nó cho người dùng biết phần nào tách khỏi trang, phần nào chỉ hiện tạm thời, và phần nào cần chú ý trước.\n\n<ElevationDemo kind=\"hero\" />\n\n## Cách hoạt động\n\n- **Mỗi mức là một cặp: một màu nền và một bóng.** Luôn dùng hai token của cùng một mức đi với nhau.\n- **Càng xa trang, bóng càng lớn và mềm.** Card có bóng rất nhẹ, dialog có bóng đậm.\n- **Chỉ có ba mức.** Khi thứ gì cũng nổi thì không còn gì nổi bật.\n\nĐổ bóng cho thấy bề mặt trông cao bao nhiêu. [Z-index](/vi/foundations/styles/z-index/) quyết định bề mặt nào được vẽ lên trên.\n\n| Mức | Nền | Bóng | Dùng cho |\n|---|---|---|---|\n| Page | `color.surface.page`, `color.surface.subtle` | không có | Trang, panel, bảng, menu bên trái, header |\n| Raised | `color.surface` | `elevation.shadow.raised` | Card |\n| Overlay | `color.surface.overlay` | `elevation.shadow.overlay` | Menu, danh sách của select, popover, bộ chọn ngày, toast |\n| Modal | `color.surface.overlay` | `elevation.shadow.modal` | Dialog, drawer, sheet toàn màn hình |\n\n## Page\n\nPhần lớn màn hình nằm ngay trên trang, không có bóng. Tách panel và bảng bằng đường viền `color.border`. Menu bên trái và header của bảng dùng nền `color.surface.subtle`.\n\n<ElevationDemo kind=\"level\" item=\"page\" />\n\n## Raised\n\nDành cho một mục mà người dùng xem như một khối: một sync job, một kết nối, một widget trên dashboard. Card giữ đường viền, vì bóng nhẹ có thể mất hẳn trên màn hình quá sáng hoặc ở chế độ tương phản cao.\n\n<ElevationDemo kind=\"level\" item=\"raised\" />\n\n## Overlay\n\nDành cho những thứ mở ra từ một control rồi đóng lại: menu, danh sách của select, popover. Toast cũng dùng nền và bóng này.\n\n<ElevationDemo kind=\"level\" item=\"overlay\" />\n\n## Modal\n\nDành cho dialog và drawer chặn trang cho tới khi người dùng làm xong hoặc huỷ. Modal luôn nằm trên lớp phủ mờ `color.surface.scrim`, lớp này làm tối trang và cho thấy trang đang tạm khoá.\n\n<ElevationDemo kind=\"level\" item=\"modal\" />\n\n## Dark mode\n\n**Bề mặt càng cao thì nền càng sáng.** Bóng tối gần như không thấy trên nền tối, nên mỗi mức có thêm nền sáng hơn: trang graphite 1, card graphite 2, menu và dialog graphite 3. Tên token giống nhau ở cả hai theme.\n\n<ElevationDemo kind=\"dark\" />\n\n## Bên trong menu và dialog\n\nCác dòng bên trong lớp nổi dùng màu trạng thái của overlay, ví dụ `color.surface.overlay.hover`. Màu hover của trang sẽ trùng với nền menu ở dark mode và biến mất. Dòng đang chọn cần có dấu check, không chỉ dựa vào màu.\n\n<ElevationDemo kind=\"states\" />\n\n## Nên và không nên\n\n<ElevationDemo kind=\"dodont\" item=\"pair\" />\n<ElevationDemo kind=\"dodont\" item=\"flat\" />\n<ElevationDemo kind=\"dodont\" item=\"own\" />\n<ElevationDemo kind=\"dodont\" item=\"border\" />\n\n## Token\n\n<TokenTable prefix=\"elevation\" />\n\n<TokenTable prefix=\"color.surface.overlay\" />\n",
1340
+ "raw": "---\ntitle: Đổ bóng\ndescription: \"Một bề mặt trông như nằm cao bao nhiêu so với trang. Đổ bóng tách các mục khỏi trang, cho biết thứ gì chỉ hiện tạm thời và hướng sự chú ý vào điều quan trọng lúc này.\"\norder: 8\n---\nimport ElevationDemo from '../../../components/ElevationDemo.astro';\nimport TokenTable from '../../../components/TokenTable.astro';\n\nElevation là khoảng cách mà một bề mặt trông như có so với trang, thể hiện bằng bóng đổ và ở dark mode thì thêm nền sáng hơn. Nó cho người dùng biết phần nào tách khỏi trang, phần nào chỉ hiện tạm thời, và phần nào cần chú ý trước.\n\n<ElevationDemo kind=\"hero\" />\n\n## Cách hoạt động\n\n- **Mỗi mức là một cặp: một màu nền và một bóng.** Luôn dùng hai token của cùng một mức đi với nhau.\n- **Càng xa trang, bóng càng lớn và mềm.** Card có bóng rất nhẹ, dialog có bóng đậm.\n- **Chỉ có ba mức.** Khi thứ gì cũng nổi thì không còn gì nổi bật.\n\nĐổ bóng cho thấy bề mặt trông cao bao nhiêu. [Z-index](/vi/foundations/styles/z-index/) quyết định bề mặt nào được vẽ lên trên.\n\n| Mức | Nền | Bóng | Dùng cho |\n|---|---|---|---|\n| Page | `color.surface.page`, `color.surface.subtle` | không có | Trang, panel, bảng, menu bên trái, header |\n| Raised | `color.surface` | `elevation.shadow.raised` | Card |\n| Overlay | `color.surface.overlay` | `elevation.shadow.overlay` | Menu, danh sách của select, popover, bộ chọn ngày, toast |\n| Modal | `color.surface.overlay` | `elevation.shadow.modal` | Dialog, drawer, sheet toàn màn hình |\n\n## Page\n\nPhần lớn màn hình nằm ngay trên trang, không có bóng. Tách panel và bảng bằng đường viền `color.border`. Menu bên trái và header của bảng dùng nền `color.surface.subtle`.\n\n<ElevationDemo kind=\"level\" item=\"page\" />\n\n## Raised\n\nDành cho một mục mà người dùng xem như một khối: một sync job, một kết nối, một widget trên dashboard. Card giữ đường viền, vì bóng nhẹ có thể mất hẳn trên màn hình quá sáng hoặc ở chế độ tương phản cao.\n\n<ElevationDemo kind=\"level\" item=\"raised\" />\n\n## Overlay\n\nDành cho những thứ mở ra từ một control rồi đóng lại: menu, danh sách của select, popover. Toast cũng dùng nền và bóng này.\n\n<ElevationDemo kind=\"level\" item=\"overlay\" />\n\n## Modal\n\nDành cho dialog và drawer chặn trang cho tới khi người dùng làm xong hoặc huỷ. Modal luôn nằm trên lớp phủ mờ `color.surface.scrim`, lớp này làm tối trang và cho thấy trang đang tạm khoá.\n\n<ElevationDemo kind=\"level\" item=\"modal\" />\n\n## Dark mode\n\n**Bề mặt càng cao thì nền càng sáng.** Bóng tối gần như không thấy trên nền tối, nên mỗi mức có thêm nền sáng hơn: trang graphite 1, card graphite 2, menu và dialog graphite 3. Tên token giống nhau ở cả hai theme.\n\n<ElevationDemo kind=\"dark\" />\n\n## Bên trong menu và dialog\n\nCác dòng bên trong lớp nổi dùng màu trạng thái của overlay, ví dụ `color.surface.overlay.hover`. Màu hover của trang sẽ trùng với nền menu ở dark mode và biến mất. Dòng đang chọn cần có dấu check, không chỉ dựa vào màu.\n\n<ElevationDemo kind=\"states\" />\n\n## Nên và không nên\n\n<ElevationDemo kind=\"dodont\" item=\"pair\" />\n<ElevationDemo kind=\"dodont\" item=\"flat\" />\n<ElevationDemo kind=\"dodont\" item=\"own\" />\n<ElevationDemo kind=\"dodont\" item=\"border\" />\n\n## Token\n\n<TokenTable prefix=\"elevation\" />\n\n<TokenTable prefix=\"color.surface.overlay\" />\n",
1341
+ "frontmatter": {
1342
+ "title": "Đổ bóng",
1343
+ "description": "Một bề mặt trông như nằm cao bao nhiêu so với trang. Đổ bóng tách các mục khỏi trang, cho biết thứ gì chỉ hiện tạm thời và hướng sự chú ý vào điều quan trọng lúc này.",
1344
+ "order": 8
1299
1345
  }
1300
1346
  },
1301
1347
  {
@@ -1381,8 +1427,8 @@ export const catalog = [
1381
1427
  "status": "active",
1382
1428
  "releasePhase": null,
1383
1429
  "planned": [],
1384
- "body": "import IconDemo from '../../../../components/IconDemo.astro';\nimport ColorDemo from '../../../../components/ColorDemo.astro';\n\n**Dùng icon 16 px, cùng màu với chữ, có nhãn, và cùng một icon cho cùng một nghĩa ở mọi nơi.**\n\n## Cỡ\n\n**Chọn cỡ theo chữ đứng cạnh icon.**\n\n| Cỡ | Dùng cho |\n|---|---|\n| 16 px | Mặc định. Nút, menu, bảng, ô nhập, cạnh chữ 14 px. |\n| 20 px | Cạnh chữ 16 px, trong thanh công cụ và page header. |\n| 24 px | Icon đứng riêng, như trạng thái trong card hoặc trạng thái trống nhỏ. |\n| 32 px | Chỉ cho trạng thái trống. |\n\nKhông dùng cỡ khác. Không phóng to thu nhỏ icon cho vừa khung: hãy đổi khung.\n\n<IconDemo kind=\"dodont\" item=\"size\" />\n\n## Nét\n\n**Giữ nguyên nét của Lucide.** Nét dày 2 đơn vị trên lưới 24 và co giãn theo icon: 1,33 px ở cỡ 16, 1,67 px ở cỡ 20, 2 px ở cỡ 24. Không đặt `stroke-width` hay `absoluteStrokeWidth`. Nét cố định 2 px sẽ lấp mất chi tiết nhỏ của icon 16 px.\n\n<IconDemo kind=\"dodont\" item=\"stroke\" />\n\n## Màu\n\n**Icon lấy màu của chữ.** Icon vẽ bằng `currentColor`, nên icon trong nút hay link tự đúng màu mà không cần thêm code. Chỉ đặt màu bằng token `color.icon.*`:\n\n<ColorDemo kind=\"roles\" group=\"icon\" />\n\n- Icon trạng thái dùng token trạng thái, như `icon.danger`, và luôn đi kèm trạng thái viết bằng chữ.\n- Không tô màu icon để trang trí, và không bao giờ dùng màu vàng thương hiệu cho icon.\n\n<IconDemo kind=\"dodont\" item=\"colour\" />\n\n## Căn với chữ\n\n**Căn icon vào giữa line height của chữ.** Dùng `display: flex; align-items: center`. Khi chữ có nhiều dòng, căn icon vào giữa dòng đầu tiên.\n\n<IconDemo kind=\"align\" />\n\n<IconDemo kind=\"dodont\" item=\"align\" />\n\n## Khoảng cách\n\n**Khoảng cách giữa icon và chữ theo cỡ chữ: 4 px cạnh chữ 14 px trở xuống, 8 px cạnh chữ 16 px trở lên.**\n\n| Chữ | Icon | Khoảng cách | Token | Ở đâu |\n|---|---|---|---|---|\n| 12 hoặc 14 px | 16 px | 4 px | `space.050` | Control cỡ nhỏ và mặc định, menu, tab, ô trong bảng |\n| Từ 16 px trở lên | 20 hoặc 24 px | 8 px | `space.100` | Control cỡ lớn, thanh công cụ, page header, trạng thái trong card |\n\nĐặt khoảng cách trên control bằng `gap`, không dùng margin trên icon.\n\n<IconDemo kind=\"spacing\" />\n\n## Icon và nhãn\n\n**Mặc định icon có nhãn đi kèm.** Nhãn nói điều gì sẽ xảy ra; icon giúp người dùng tìm lại nhanh.\n\nChỉ dùng icon đứng riêng khi cả ba điều sau đều đúng:\n\n- Thao tác ai cũng biết: đóng, tìm kiếm, thêm, sửa, xoá, sao chép, làm mới, cài đặt, lọc, thêm tuỳ chọn, menu.\n- Chỗ hẹp, như một dòng trong bảng hay thanh công cụ.\n- Nút có tên (`aria-label`) và tooltip cùng nội dung. Xem [Khả năng tiếp cận](/vi/foundations/styles/icons/accessibility/).\n\n<IconDemo kind=\"dodont\" item=\"label\" />\n\n## Trạng thái đã chọn\n\n**Icon Lucide chỉ có dạng nét.** Thể hiện mục đã chọn bằng `background.selected` và thanh chỉ báo, không tô đặc icon.\n\n<IconDemo kind=\"dodont\" item=\"selected\" />\n\n## Thao tác thường gặp\n\n**Mỗi nghĩa một icon.** Dùng đúng icon này mỗi khi hiển thị một trong các thao tác hay đối tượng dưới đây, ở mọi sản phẩm. Nếu chưa có nghĩa bạn cần, hãy hỏi trước khi chọn, để nó được bổ sung vào đây.\n\n<IconDemo kind=\"actions\" />\n\n<IconDemo kind=\"dodont\" item=\"meaning\" />\n\n## Nên và không nên\n\n| Nên | Không nên |\n|---|---|\n| Dùng cỡ 16, 20, 24 hoặc 32 px. | Phóng to thu nhỏ icon sang cỡ khác. |\n| Giữ icon cùng màu chữ. | Tô màu icon để trang trí. |\n| Thêm nhãn cho hầu hết icon. | Dùng một icon lạ đứng riêng. |\n| Dùng cùng icon cho cùng nghĩa. | Mỗi sản phẩm dùng một icon khác nhau. |\n| Dùng icon nét với nền \"đã chọn\". | Tô đặc icon để báo đã chọn. |\n| Viết trạng thái bên cạnh icon trạng thái. | Để icon hoặc màu của nó tự báo trạng thái. |\n| Mỗi nút một icon. | Ghép hai icon thành một thao tác. |\n",
1385
- "raw": "---\ntitle: Cách dùng\ndescription: Dùng cỡ nào, nét, màu và căn chỉnh cạnh chữ hoạt động thế nào, khi nào icon cần nhãn, và icon duy nhất cho từng thao tác thường gặp ở Beehexa.\norder: 2\n---\nimport IconDemo from '../../../../components/IconDemo.astro';\nimport ColorDemo from '../../../../components/ColorDemo.astro';\n\n**Dùng icon 16 px, cùng màu với chữ, có nhãn, và cùng một icon cho cùng một nghĩa ở mọi nơi.**\n\n## Cỡ\n\n**Chọn cỡ theo chữ đứng cạnh icon.**\n\n| Cỡ | Dùng cho |\n|---|---|\n| 16 px | Mặc định. Nút, menu, bảng, ô nhập, cạnh chữ 14 px. |\n| 20 px | Cạnh chữ 16 px, trong thanh công cụ và page header. |\n| 24 px | Icon đứng riêng, như trạng thái trong card hoặc trạng thái trống nhỏ. |\n| 32 px | Chỉ cho trạng thái trống. |\n\nKhông dùng cỡ khác. Không phóng to thu nhỏ icon cho vừa khung: hãy đổi khung.\n\n<IconDemo kind=\"dodont\" item=\"size\" />\n\n## Nét\n\n**Giữ nguyên nét của Lucide.** Nét dày 2 đơn vị trên lưới 24 và co giãn theo icon: 1,33 px ở cỡ 16, 1,67 px ở cỡ 20, 2 px ở cỡ 24. Không đặt `stroke-width` hay `absoluteStrokeWidth`. Nét cố định 2 px sẽ lấp mất chi tiết nhỏ của icon 16 px.\n\n<IconDemo kind=\"dodont\" item=\"stroke\" />\n\n## Màu\n\n**Icon lấy màu của chữ.** Icon vẽ bằng `currentColor`, nên icon trong nút hay link tự đúng màu mà không cần thêm code. Chỉ đặt màu bằng token `color.icon.*`:\n\n<ColorDemo kind=\"roles\" group=\"icon\" />\n\n- Icon trạng thái dùng token trạng thái, như `icon.danger`, và luôn đi kèm trạng thái viết bằng chữ.\n- Không tô màu icon để trang trí, và không bao giờ dùng màu vàng thương hiệu cho icon.\n\n<IconDemo kind=\"dodont\" item=\"colour\" />\n\n## Căn với chữ\n\n**Căn icon vào giữa line height của chữ.** Dùng `display: flex; align-items: center`. Khi chữ có nhiều dòng, căn icon vào giữa dòng đầu tiên.\n\n<IconDemo kind=\"align\" />\n\n<IconDemo kind=\"dodont\" item=\"align\" />\n\n## Khoảng cách\n\n**Khoảng cách giữa icon và chữ theo cỡ chữ: 4 px cạnh chữ 14 px trở xuống, 8 px cạnh chữ 16 px trở lên.**\n\n| Chữ | Icon | Khoảng cách | Token | Ở đâu |\n|---|---|---|---|---|\n| 12 hoặc 14 px | 16 px | 4 px | `space.050` | Control cỡ nhỏ và mặc định, menu, tab, ô trong bảng |\n| Từ 16 px trở lên | 20 hoặc 24 px | 8 px | `space.100` | Control cỡ lớn, thanh công cụ, page header, trạng thái trong card |\n\nĐặt khoảng cách trên control bằng `gap`, không dùng margin trên icon.\n\n<IconDemo kind=\"spacing\" />\n\n## Icon và nhãn\n\n**Mặc định icon có nhãn đi kèm.** Nhãn nói điều gì sẽ xảy ra; icon giúp người dùng tìm lại nhanh.\n\nChỉ dùng icon đứng riêng khi cả ba điều sau đều đúng:\n\n- Thao tác ai cũng biết: đóng, tìm kiếm, thêm, sửa, xoá, sao chép, làm mới, cài đặt, lọc, thêm tuỳ chọn, menu.\n- Chỗ hẹp, như một dòng trong bảng hay thanh công cụ.\n- Nút có tên (`aria-label`) và tooltip cùng nội dung. Xem [Khả năng tiếp cận](/vi/foundations/styles/icons/accessibility/).\n\n<IconDemo kind=\"dodont\" item=\"label\" />\n\n## Trạng thái đã chọn\n\n**Icon Lucide chỉ có dạng nét.** Thể hiện mục đã chọn bằng `background.selected` và thanh chỉ báo, không tô đặc icon.\n\n<IconDemo kind=\"dodont\" item=\"selected\" />\n\n## Thao tác thường gặp\n\n**Mỗi nghĩa một icon.** Dùng đúng icon này mỗi khi hiển thị một trong các thao tác hay đối tượng dưới đây, ở mọi sản phẩm. Nếu chưa có nghĩa bạn cần, hãy hỏi trước khi chọn, để nó được bổ sung vào đây.\n\n<IconDemo kind=\"actions\" />\n\n<IconDemo kind=\"dodont\" item=\"meaning\" />\n\n## Nên và không nên\n\n| Nên | Không nên |\n|---|---|\n| Dùng cỡ 16, 20, 24 hoặc 32 px. | Phóng to thu nhỏ icon sang cỡ khác. |\n| Giữ icon cùng màu chữ. | Tô màu icon để trang trí. |\n| Thêm nhãn cho hầu hết icon. | Dùng một icon lạ đứng riêng. |\n| Dùng cùng icon cho cùng nghĩa. | Mỗi sản phẩm dùng một icon khác nhau. |\n| Dùng icon nét với nền \"đã chọn\". | Tô đặc icon để báo đã chọn. |\n| Viết trạng thái bên cạnh icon trạng thái. | Để icon hoặc màu của nó tự báo trạng thái. |\n| Mỗi nút một icon. | Ghép hai icon thành một thao tác. |\n",
1430
+ "body": "import IconDemo from '../../../../components/IconDemo.astro';\nimport ColorDemo from '../../../../components/ColorDemo.astro';\n\n**Dùng icon 16 px, cùng màu với chữ, có nhãn, và cùng một icon cho cùng một nghĩa ở mọi nơi.**\n\n## Cỡ\n\n**Chọn cỡ theo chữ đứng cạnh icon.**\n\n| Cỡ | Token | Dùng cho |\n|---|---|---|\n| 16 px | `size.icon.default` | Mặc định. Nút, menu, bảng, ô nhập, cạnh chữ 14 px. |\n| 20 px | `size.icon.medium` | Cạnh chữ 16 px, trong thanh công cụ và page header. |\n| 24 px | `size.icon.large` | Icon đứng riêng, như trạng thái trong card hoặc trạng thái trống nhỏ. |\n| 32 px | `size.icon.empty` | Chỉ cho trạng thái trống. |\n\nKhông dùng cỡ khác. Không phóng to thu nhỏ icon cho vừa khung: hãy đổi khung.\n\nBind các role này bằng CSS variable hoặc chuyển đổi tại API icon nhận số;\nkích thước pixel trong bảng không phải hằng số riêng để chép vào ứng dụng.\n\n<IconDemo kind=\"dodont\" item=\"size\" />\n\n## Nét\n\n**Giữ nguyên nét của Lucide.** Nét dày 2 đơn vị trên lưới 24 và co giãn theo icon: 1,33 px ở cỡ 16, 1,67 px ở cỡ 20, 2 px ở cỡ 24. Không đặt `stroke-width` hay `absoluteStrokeWidth`. Nét cố định 2 px sẽ lấp mất chi tiết nhỏ của icon 16 px.\n\n<IconDemo kind=\"dodont\" item=\"stroke\" />\n\n## Màu\n\n**Icon lấy màu của chữ.** Icon vẽ bằng `currentColor`, nên icon trong nút hay link tự đúng màu mà không cần thêm code. Chỉ đặt màu bằng token `color.icon.*`:\n\n<ColorDemo kind=\"roles\" group=\"icon\" />\n\n- Icon trạng thái dùng token trạng thái, như `icon.danger`, và luôn đi kèm trạng thái viết bằng chữ.\n- Không tô màu icon để trang trí, và không bao giờ dùng màu vàng thương hiệu cho icon.\n\n<IconDemo kind=\"dodont\" item=\"colour\" />\n\n## Căn với chữ\n\n**Căn icon vào giữa line height của chữ.** Dùng `display: flex; align-items: center`. Khi chữ có nhiều dòng, căn icon vào giữa dòng đầu tiên.\n\n<IconDemo kind=\"align\" />\n\n<IconDemo kind=\"dodont\" item=\"align\" />\n\n## Khoảng cách\n\n**Khoảng cách giữa icon và chữ theo cỡ chữ: 4 px cạnh chữ 14 px trở xuống, 8 px cạnh chữ 16 px trở lên.**\n\n| Chữ | Icon | Khoảng cách | Token | Ở đâu |\n|---|---|---|---|---|\n| 12 hoặc 14 px | 16 px | 4 px | `space.050` | Control cỡ nhỏ và mặc định, menu, tab, ô trong bảng |\n| Từ 16 px trở lên | 20 hoặc 24 px | 8 px | `space.100` | Control cỡ lớn, thanh công cụ, page header, trạng thái trong card |\n\nĐặt khoảng cách trên control bằng `gap`, không dùng margin trên icon.\n\n<IconDemo kind=\"spacing\" />\n\n## Icon và nhãn\n\n**Mặc định icon có nhãn đi kèm.** Nhãn nói điều gì sẽ xảy ra; icon giúp người dùng tìm lại nhanh.\n\nChỉ dùng icon đứng riêng khi cả ba điều sau đều đúng:\n\n- Thao tác ai cũng biết: đóng, tìm kiếm, thêm, sửa, xoá, sao chép, làm mới, cài đặt, lọc, thêm tuỳ chọn, menu.\n- Chỗ hẹp, như một dòng trong bảng hay thanh công cụ.\n- Nút có tên (`aria-label`) và tooltip cùng nội dung. Xem [Khả năng tiếp cận](/vi/foundations/styles/icons/accessibility/).\n\n<IconDemo kind=\"dodont\" item=\"label\" />\n\n## Trạng thái đã chọn\n\n**Icon Lucide chỉ có dạng nét.** Thể hiện mục đã chọn bằng `background.selected` và thanh chỉ báo, không tô đặc icon.\n\n<IconDemo kind=\"dodont\" item=\"selected\" />\n\n## Thao tác thường gặp\n\n**Mỗi nghĩa một icon.** Dùng đúng icon này mỗi khi hiển thị một trong các thao tác hay đối tượng dưới đây, ở mọi sản phẩm. Nếu chưa có nghĩa bạn cần, hãy hỏi trước khi chọn, để nó được bổ sung vào đây.\n\n<IconDemo kind=\"actions\" />\n\n<IconDemo kind=\"dodont\" item=\"meaning\" />\n\n## Nên và không nên\n\n| Nên | Không nên |\n|---|---|\n| Dùng cỡ 16, 20, 24 hoặc 32 px. | Phóng to thu nhỏ icon sang cỡ khác. |\n| Giữ icon cùng màu chữ. | Tô màu icon để trang trí. |\n| Thêm nhãn cho hầu hết icon. | Dùng một icon lạ đứng riêng. |\n| Dùng cùng icon cho cùng nghĩa. | Mỗi sản phẩm dùng một icon khác nhau. |\n| Dùng icon nét với nền \"đã chọn\". | Tô đặc icon để báo đã chọn. |\n| Viết trạng thái bên cạnh icon trạng thái. | Để icon hoặc màu của nó tự báo trạng thái. |\n| Mỗi nút một icon. | Ghép hai icon thành một thao tác. |\n",
1431
+ "raw": "---\ntitle: Cách dùng\ndescription: Dùng cỡ nào, nét, màu và căn chỉnh cạnh chữ hoạt động thế nào, khi nào icon cần nhãn, và icon duy nhất cho từng thao tác thường gặp ở Beehexa.\norder: 2\n---\nimport IconDemo from '../../../../components/IconDemo.astro';\nimport ColorDemo from '../../../../components/ColorDemo.astro';\n\n**Dùng icon 16 px, cùng màu với chữ, có nhãn, và cùng một icon cho cùng một nghĩa ở mọi nơi.**\n\n## Cỡ\n\n**Chọn cỡ theo chữ đứng cạnh icon.**\n\n| Cỡ | Token | Dùng cho |\n|---|---|---|\n| 16 px | `size.icon.default` | Mặc định. Nút, menu, bảng, ô nhập, cạnh chữ 14 px. |\n| 20 px | `size.icon.medium` | Cạnh chữ 16 px, trong thanh công cụ và page header. |\n| 24 px | `size.icon.large` | Icon đứng riêng, như trạng thái trong card hoặc trạng thái trống nhỏ. |\n| 32 px | `size.icon.empty` | Chỉ cho trạng thái trống. |\n\nKhông dùng cỡ khác. Không phóng to thu nhỏ icon cho vừa khung: hãy đổi khung.\n\nBind các role này bằng CSS variable hoặc chuyển đổi tại API icon nhận số;\nkích thước pixel trong bảng không phải hằng số riêng để chép vào ứng dụng.\n\n<IconDemo kind=\"dodont\" item=\"size\" />\n\n## Nét\n\n**Giữ nguyên nét của Lucide.** Nét dày 2 đơn vị trên lưới 24 và co giãn theo icon: 1,33 px ở cỡ 16, 1,67 px ở cỡ 20, 2 px ở cỡ 24. Không đặt `stroke-width` hay `absoluteStrokeWidth`. Nét cố định 2 px sẽ lấp mất chi tiết nhỏ của icon 16 px.\n\n<IconDemo kind=\"dodont\" item=\"stroke\" />\n\n## Màu\n\n**Icon lấy màu của chữ.** Icon vẽ bằng `currentColor`, nên icon trong nút hay link tự đúng màu mà không cần thêm code. Chỉ đặt màu bằng token `color.icon.*`:\n\n<ColorDemo kind=\"roles\" group=\"icon\" />\n\n- Icon trạng thái dùng token trạng thái, như `icon.danger`, và luôn đi kèm trạng thái viết bằng chữ.\n- Không tô màu icon để trang trí, và không bao giờ dùng màu vàng thương hiệu cho icon.\n\n<IconDemo kind=\"dodont\" item=\"colour\" />\n\n## Căn với chữ\n\n**Căn icon vào giữa line height của chữ.** Dùng `display: flex; align-items: center`. Khi chữ có nhiều dòng, căn icon vào giữa dòng đầu tiên.\n\n<IconDemo kind=\"align\" />\n\n<IconDemo kind=\"dodont\" item=\"align\" />\n\n## Khoảng cách\n\n**Khoảng cách giữa icon và chữ theo cỡ chữ: 4 px cạnh chữ 14 px trở xuống, 8 px cạnh chữ 16 px trở lên.**\n\n| Chữ | Icon | Khoảng cách | Token | Ở đâu |\n|---|---|---|---|---|\n| 12 hoặc 14 px | 16 px | 4 px | `space.050` | Control cỡ nhỏ và mặc định, menu, tab, ô trong bảng |\n| Từ 16 px trở lên | 20 hoặc 24 px | 8 px | `space.100` | Control cỡ lớn, thanh công cụ, page header, trạng thái trong card |\n\nĐặt khoảng cách trên control bằng `gap`, không dùng margin trên icon.\n\n<IconDemo kind=\"spacing\" />\n\n## Icon và nhãn\n\n**Mặc định icon có nhãn đi kèm.** Nhãn nói điều gì sẽ xảy ra; icon giúp người dùng tìm lại nhanh.\n\nChỉ dùng icon đứng riêng khi cả ba điều sau đều đúng:\n\n- Thao tác ai cũng biết: đóng, tìm kiếm, thêm, sửa, xoá, sao chép, làm mới, cài đặt, lọc, thêm tuỳ chọn, menu.\n- Chỗ hẹp, như một dòng trong bảng hay thanh công cụ.\n- Nút có tên (`aria-label`) và tooltip cùng nội dung. Xem [Khả năng tiếp cận](/vi/foundations/styles/icons/accessibility/).\n\n<IconDemo kind=\"dodont\" item=\"label\" />\n\n## Trạng thái đã chọn\n\n**Icon Lucide chỉ có dạng nét.** Thể hiện mục đã chọn bằng `background.selected` và thanh chỉ báo, không tô đặc icon.\n\n<IconDemo kind=\"dodont\" item=\"selected\" />\n\n## Thao tác thường gặp\n\n**Mỗi nghĩa một icon.** Dùng đúng icon này mỗi khi hiển thị một trong các thao tác hay đối tượng dưới đây, ở mọi sản phẩm. Nếu chưa có nghĩa bạn cần, hãy hỏi trước khi chọn, để nó được bổ sung vào đây.\n\n<IconDemo kind=\"actions\" />\n\n<IconDemo kind=\"dodont\" item=\"meaning\" />\n\n## Nên và không nên\n\n| Nên | Không nên |\n|---|---|\n| Dùng cỡ 16, 20, 24 hoặc 32 px. | Phóng to thu nhỏ icon sang cỡ khác. |\n| Giữ icon cùng màu chữ. | Tô màu icon để trang trí. |\n| Thêm nhãn cho hầu hết icon. | Dùng một icon lạ đứng riêng. |\n| Dùng cùng icon cho cùng nghĩa. | Mỗi sản phẩm dùng một icon khác nhau. |\n| Dùng icon nét với nền \"đã chọn\". | Tô đặc icon để báo đã chọn. |\n| Viết trạng thái bên cạnh icon trạng thái. | Để icon hoặc màu của nó tự báo trạng thái. |\n| Mỗi nút một icon. | Ghép hai icon thành một thao tác. |\n",
1386
1432
  "frontmatter": {
1387
1433
  "title": "Cách dùng",
1388
1434
  "description": "Dùng cỡ nào, nét, màu và căn chỉnh cạnh chữ hoạt động thế nào, khi nào icon cần nhãn, và icon duy nhất cho từng thao tác thường gặp ở Beehexa.",
@@ -1444,8 +1490,8 @@ export const catalog = [
1444
1490
  "status": "active",
1445
1491
  "releasePhase": null,
1446
1492
  "planned": [],
1447
- "body": "import LayoutDemo from '../../../../components/LayoutDemo.astro';\n\n**Header, menu bên và page header lặp lại trên mọi trang, ở cùng vị trí và cùng kích thước.**\n\n## Header\n\n**Cao 48 px, trải hết chiều ngang. Chứa những gì thuộc về cả sản phẩm.**\n\n| Phần | Giá trị |\n|---|---|\n| Chiều cao | 48 px: một control 32 px, cách 8 px phía trên và phía dưới. Đường kẻ 1 px dưới header không tính vào |\n| Chứa | Nút menu (dưới 1024 px), logo, tìm kiếm toàn cục, chuyển workspace, thông báo, tài khoản |\n| Không chứa | Breadcrumb và nút hành động của trang. Chúng đổi theo từng trang, nên nằm trong page header |\n\n## Menu bên\n\n**Rộng 280 px khi mở, thu thành rail 64 px khi gọn, thành drawer khi dưới 1024 px. Mọi sản phẩm Beehexa dùng cùng các độ rộng này.**\n\n| Cửa sổ | Menu bên |\n|---|---|\n| Dưới 1024 px | Ẩn. Nút menu trên header mở nó thành drawer phủ lên trang. |\n| Từ 1024 px trở lên | Mở ở 280 px. Người dùng có thể thu gọn thành rail 64 px, và lựa chọn này được ghi nhớ. |\n\n- **280 px** chứa vừa nhãn khoảng 31 ký tự ở cỡ 14 px, kể cả nhãn tiếng Việt dài.\n- **Cùng một độ rộng ở mọi sản phẩm**, để trang luôn bắt đầu ở cùng một chỗ khi người dùng chuyển giữa các sản phẩm.\n- **Không kéo giãn.** Một độ rộng duy nhất giữ các sản phẩm giống nhau. Panel kéo giãn được còn cần thêm cách đổi cỡ không phải kéo (WCAG 2.5.7).\n- **Rail** chỉ hiện icon. Nhãn của từng mục hiện trong tooltip.\n\n### Nhãn dài\n\n<LayoutDemo kind=\"navlabels\" />\n\n1. Trước hết, viết nhãn ngắn hơn.\n2. Nếu vẫn không vừa, cắt bằng dấu ba chấm và hiện nhãn đầy đủ trong tooltip, chỉ khi nhãn bị cắt.\n3. Không bao giờ nới rộng menu bên vì một nhãn. Sản phẩm có nhãn dài ở khắp nơi có thể chọn một độ rộng từ 240 đến 320 px cho toàn sản phẩm, và ghi lại quyết định đó.\n\n## Page header\n\n**Phần đầu của mọi trang: breadcrumb, tiêu đề, trạng thái và nút hành động của trang.**\n\n<LayoutDemo kind=\"pageheader\" />\n\n| Hàng | Chứa | Khi nào |\n|---|---|---|\n| Breadcrumb | Các trang cấp trên của trang này | Từ cấp thứ hai trở xuống |\n| Hàng tiêu đề | Tiêu đề trang (`heading.large`) và trạng thái ở bên trái; nút hành động của trang ở bên phải, nút chính đứng cuối | Luôn có |\n| Mô tả | Một dòng giới thiệu trang | Không bắt buộc |\n| Tab hoặc bộ lọc | Các góc nhìn của cùng một trang | Không bắt buộc |\n\n- **Page header trải hết vùng nội dung ở mọi độ rộng trang.** Chỉ phần nội dung bên dưới theo [Full, Wide hoặc Narrow](/vi/foundations/styles/layout/page-widths/), nên tiêu đề và nút hành động của trang luôn nằm cùng một chỗ trên mọi trang.\n- Breadcrumb thuộc về trang, không thuộc header: nó đổi theo từng trang, còn header thì giữ nguyên.\n- Ngữ cảnh của cả sản phẩm, như workspace, nằm trên header.\n\n## Panel bên\n\nPanel đặt cạnh nội dung chính, như chi tiết của dòng đang chọn, chiếm các cột của lưới: 4 trên 12 cột từ 1024 px và 3 trên 12 cột từ 1440 px. Dưới 1024 px nó mở thành drawer phủ lên trang. Xem phần span ở trang [Lưới](/vi/foundations/styles/layout/grid/#span).\n\n## Khoảng cách trong khung\n\n**Mọi thứ trong khung thẳng hàng theo hai mép: cách mép trái cửa sổ 20 px, và lề trang.**\n\n| Giữa | Khoảng cách |\n|---|---|\n| Mép cửa sổ và logo; mép cửa sổ và icon của menu bên | 20 px, `space.250` |\n| Các mục trong menu bên và mép của menu | 8 px, `space.100` |\n| Hai mục liền nhau trong menu bên (mỗi mục cao 32 px) | 4 px, `space.050` |\n| Nội dung và menu bên, header hoặc mép cửa sổ | Lề trang: 16, 24 hoặc 32 px ([Lưới](/vi/foundations/styles/layout/grid/)) |\n| Breadcrumb và tiêu đề | 8 px, `space.100` |\n| Tiêu đề và mô tả | 4 px, `space.050` |\n| Page header và nội dung | 24 px, `space.300` |\n\nMép 20 px của logo lấy từ menu bên: 8 px thụt vào cộng 12 px padding ngang của một control 32 px. Nhờ vậy logo nằm ngay trên các icon.\n",
1448
- "raw": "---\ntitle: Khung ứng dụng\ndescription: Header, menu bên và page header lặp lại trên mọi trang, kích thước của chúng, và khoảng cách giúp chúng thẳng hàng.\norder: 1\n---\nimport LayoutDemo from '../../../../components/LayoutDemo.astro';\n\n**Header, menu bên và page header lặp lại trên mọi trang, ở cùng vị trí và cùng kích thước.**\n\n## Header\n\n**Cao 48 px, trải hết chiều ngang. Chứa những gì thuộc về cả sản phẩm.**\n\n| Phần | Giá trị |\n|---|---|\n| Chiều cao | 48 px: một control 32 px, cách 8 px phía trên và phía dưới. Đường kẻ 1 px dưới header không tính vào |\n| Chứa | Nút menu (dưới 1024 px), logo, tìm kiếm toàn cục, chuyển workspace, thông báo, tài khoản |\n| Không chứa | Breadcrumb và nút hành động của trang. Chúng đổi theo từng trang, nên nằm trong page header |\n\n## Menu bên\n\n**Rộng 280 px khi mở, thu thành rail 64 px khi gọn, thành drawer khi dưới 1024 px. Mọi sản phẩm Beehexa dùng cùng các độ rộng này.**\n\n| Cửa sổ | Menu bên |\n|---|---|\n| Dưới 1024 px | Ẩn. Nút menu trên header mở nó thành drawer phủ lên trang. |\n| Từ 1024 px trở lên | Mở ở 280 px. Người dùng có thể thu gọn thành rail 64 px, và lựa chọn này được ghi nhớ. |\n\n- **280 px** chứa vừa nhãn khoảng 31 ký tự ở cỡ 14 px, kể cả nhãn tiếng Việt dài.\n- **Cùng một độ rộng ở mọi sản phẩm**, để trang luôn bắt đầu ở cùng một chỗ khi người dùng chuyển giữa các sản phẩm.\n- **Không kéo giãn.** Một độ rộng duy nhất giữ các sản phẩm giống nhau. Panel kéo giãn được còn cần thêm cách đổi cỡ không phải kéo (WCAG 2.5.7).\n- **Rail** chỉ hiện icon. Nhãn của từng mục hiện trong tooltip.\n\n### Nhãn dài\n\n<LayoutDemo kind=\"navlabels\" />\n\n1. Trước hết, viết nhãn ngắn hơn.\n2. Nếu vẫn không vừa, cắt bằng dấu ba chấm và hiện nhãn đầy đủ trong tooltip, chỉ khi nhãn bị cắt.\n3. Không bao giờ nới rộng menu bên vì một nhãn. Sản phẩm có nhãn dài ở khắp nơi có thể chọn một độ rộng từ 240 đến 320 px cho toàn sản phẩm, và ghi lại quyết định đó.\n\n## Page header\n\n**Phần đầu của mọi trang: breadcrumb, tiêu đề, trạng thái và nút hành động của trang.**\n\n<LayoutDemo kind=\"pageheader\" />\n\n| Hàng | Chứa | Khi nào |\n|---|---|---|\n| Breadcrumb | Các trang cấp trên của trang này | Từ cấp thứ hai trở xuống |\n| Hàng tiêu đề | Tiêu đề trang (`heading.large`) và trạng thái ở bên trái; nút hành động của trang ở bên phải, nút chính đứng cuối | Luôn có |\n| Mô tả | Một dòng giới thiệu trang | Không bắt buộc |\n| Tab hoặc bộ lọc | Các góc nhìn của cùng một trang | Không bắt buộc |\n\n- **Page header trải hết vùng nội dung ở mọi độ rộng trang.** Chỉ phần nội dung bên dưới theo [Full, Wide hoặc Narrow](/vi/foundations/styles/layout/page-widths/), nên tiêu đề và nút hành động của trang luôn nằm cùng một chỗ trên mọi trang.\n- Breadcrumb thuộc về trang, không thuộc header: nó đổi theo từng trang, còn header thì giữ nguyên.\n- Ngữ cảnh của cả sản phẩm, như workspace, nằm trên header.\n\n## Panel bên\n\nPanel đặt cạnh nội dung chính, như chi tiết của dòng đang chọn, chiếm các cột của lưới: 4 trên 12 cột từ 1024 px và 3 trên 12 cột từ 1440 px. Dưới 1024 px nó mở thành drawer phủ lên trang. Xem phần span ở trang [Lưới](/vi/foundations/styles/layout/grid/#span).\n\n## Khoảng cách trong khung\n\n**Mọi thứ trong khung thẳng hàng theo hai mép: cách mép trái cửa sổ 20 px, và lề trang.**\n\n| Giữa | Khoảng cách |\n|---|---|\n| Mép cửa sổ và logo; mép cửa sổ và icon của menu bên | 20 px, `space.250` |\n| Các mục trong menu bên và mép của menu | 8 px, `space.100` |\n| Hai mục liền nhau trong menu bên (mỗi mục cao 32 px) | 4 px, `space.050` |\n| Nội dung và menu bên, header hoặc mép cửa sổ | Lề trang: 16, 24 hoặc 32 px ([Lưới](/vi/foundations/styles/layout/grid/)) |\n| Breadcrumb và tiêu đề | 8 px, `space.100` |\n| Tiêu đề và mô tả | 4 px, `space.050` |\n| Page header và nội dung | 24 px, `space.300` |\n\nMép 20 px của logo lấy từ menu bên: 8 px thụt vào cộng 12 px padding ngang của một control 32 px. Nhờ vậy logo nằm ngay trên các icon.\n",
1493
+ "body": "import LayoutDemo from '../../../../components/LayoutDemo.astro';\n\n**Header, menu bên và page header lặp lại trên mọi trang, ở cùng vị trí và cùng kích thước.**\n\nHeader toàn cục và menu bên là một bề mặt khung ứng dụng liên tục: cả hai dùng\n`surface.subtle` (`--bh-color-surface-subtle`) ở giao diện sáng và tối. Drawer menu\ntrên mobile, gồm cả hàng logo, cũng dùng bề mặt này. Không dùng `surface` cho header\ntrong khi menu bên dùng `surface.subtle`. Page header thuộc bề mặt nội dung, không\nphải bề mặt khung ứng dụng toàn cục này.\n\nTrong drawer điều hướng mobile, hàng logo không bị co lại. Menu chiếm chiều cao\ncòn lại và chỉ cuộn khi nội dung không vừa. Không đặt `min-height: 100%` cho menu\nbên dưới hàng logo: cách đó cộng chiều cao logo vào một menu đã cao bằng drawer.\n\n## Header\n\n**Cao 48 px, trải hết chiều ngang. Chứa những gì thuộc về cả sản phẩm.**\n\n| Phần | Giá trị |\n|---|---|\n| Chiều cao | 48 px: một control 32 px, cách 8 px phía trên và phía dưới. Đường kẻ 1 px dưới header không tính vào |\n| Chứa | Nút menu (dưới 1024 px), logo, tìm kiếm toàn cục, chuyển workspace, thông báo, tài khoản |\n| Không chứa | Breadcrumb và nút hành động của trang. Chúng đổi theo từng trang, nên nằm trong page header |\n\n## Menu bên\n\n**Rộng 280 px khi mở, thu thành rail 64 px khi gọn, thành drawer khi dưới 1024 px. Mọi sản phẩm Beehexa dùng cùng các độ rộng này.**\n\n| Cửa sổ | Menu bên |\n|---|---|\n| Dưới 1024 px | Ẩn. Nút menu trên header mở nó thành drawer phủ lên trang. |\n| Từ 1024 px trở lên | Mở ở 280 px. Người dùng có thể thu gọn thành rail 64 px, và lựa chọn này được ghi nhớ. |\n\n- **280 px** chứa vừa nhãn khoảng 31 ký tự ở cỡ 14 px, kể cả nhãn tiếng Việt dài.\n- **Cùng một độ rộng ở mọi sản phẩm**, để trang luôn bắt đầu ở cùng một chỗ khi người dùng chuyển giữa các sản phẩm.\n- **Không kéo giãn.** Một độ rộng duy nhất giữ các sản phẩm giống nhau. Panel kéo giãn được còn cần thêm cách đổi cỡ không phải kéo (WCAG 2.5.7).\n- **Rail** chỉ hiện icon. Nhãn của từng mục hiện trong tooltip.\n\n### Nhãn dài\n\n<LayoutDemo kind=\"navlabels\" />\n\n1. Trước hết, viết nhãn ngắn hơn.\n2. Nếu vẫn không vừa, cắt bằng dấu ba chấm và hiện nhãn đầy đủ trong tooltip, chỉ khi nhãn bị cắt.\n3. Không bao giờ nới rộng menu bên vì một nhãn. Sản phẩm có nhãn dài ở khắp nơi có thể chọn một độ rộng từ 240 đến 320 px cho toàn sản phẩm, và ghi lại quyết định đó.\n\n## Page header\n\n**Phần đầu của mọi trang: breadcrumb, tiêu đề, trạng thái và nút hành động của trang.**\n\n<LayoutDemo kind=\"pageheader\" />\n\n| Hàng | Chứa | Khi nào |\n|---|---|---|\n| Breadcrumb | Các trang cấp trên của trang này | Từ cấp thứ hai trở xuống |\n| Hàng tiêu đề | Tiêu đề trang (`heading.large`) và trạng thái ở bên trái; nút hành động của trang ở bên phải, nút chính đứng cuối | Luôn có |\n| Mô tả | Một dòng giới thiệu trang | Không bắt buộc |\n| Tab hoặc bộ lọc | Các góc nhìn của cùng một trang | Không bắt buộc |\n\n- **Page header trải hết vùng nội dung ở mọi độ rộng trang.** Chỉ phần nội dung bên dưới theo [Full, Wide hoặc Narrow](/vi/foundations/styles/layout/page-widths/), nên tiêu đề và nút hành động của trang luôn nằm cùng một chỗ trên mọi trang.\n- Breadcrumb thuộc về trang, không thuộc header: nó đổi theo từng trang, còn header thì giữ nguyên.\n- Ngữ cảnh của cả sản phẩm, như workspace, nằm trên header.\n\n## Panel bên\n\nPanel đặt cạnh nội dung chính, như chi tiết của dòng đang chọn, chiếm các cột của lưới: 4 trên 12 cột từ 1024 px và 3 trên 12 cột từ 1440 px. Dưới 1024 px nó mở thành drawer phủ lên trang. Xem phần span ở trang [Lưới](/vi/foundations/styles/layout/grid/#span).\n\n## Khoảng cách trong khung\n\n**Mọi thứ trong khung thẳng hàng theo hai mép: cách mép trái cửa sổ 20 px, và lề trang.**\n\n| Giữa | Khoảng cách |\n|---|---|\n| Mép cửa sổ và logo; mép cửa sổ và icon của menu bên | 20 px, `space.250` |\n| Các mục trong menu bên và mép của menu | 8 px, `space.100` |\n| Hai mục liền nhau trong menu bên (mỗi mục cao 32 px) | 4 px, `space.050` |\n| Nội dung và menu bên, header hoặc mép cửa sổ | Lề trang: 16, 24 hoặc 32 px ([Lưới](/vi/foundations/styles/layout/grid/)) |\n| Breadcrumb và tiêu đề | 8 px, `space.100` |\n| Tiêu đề và mô tả | 4 px, `space.050` |\n| Page header và nội dung | 24 px, `space.300` |\n\nMép 20 px của logo lấy từ menu bên: 8 px thụt vào cộng 12 px padding ngang của một control 32 px. Nhờ vậy logo nằm ngay trên các icon.\n",
1494
+ "raw": "---\ntitle: Khung ứng dụng\ndescription: Header, menu bên và page header lặp lại trên mọi trang, kích thước của chúng, và khoảng cách giúp chúng thẳng hàng.\norder: 1\n---\nimport LayoutDemo from '../../../../components/LayoutDemo.astro';\n\n**Header, menu bên và page header lặp lại trên mọi trang, ở cùng vị trí và cùng kích thước.**\n\nHeader toàn cục và menu bên là một bề mặt khung ứng dụng liên tục: cả hai dùng\n`surface.subtle` (`--bh-color-surface-subtle`) ở giao diện sáng và tối. Drawer menu\ntrên mobile, gồm cả hàng logo, cũng dùng bề mặt này. Không dùng `surface` cho header\ntrong khi menu bên dùng `surface.subtle`. Page header thuộc bề mặt nội dung, không\nphải bề mặt khung ứng dụng toàn cục này.\n\nTrong drawer điều hướng mobile, hàng logo không bị co lại. Menu chiếm chiều cao\ncòn lại và chỉ cuộn khi nội dung không vừa. Không đặt `min-height: 100%` cho menu\nbên dưới hàng logo: cách đó cộng chiều cao logo vào một menu đã cao bằng drawer.\n\n## Header\n\n**Cao 48 px, trải hết chiều ngang. Chứa những gì thuộc về cả sản phẩm.**\n\n| Phần | Giá trị |\n|---|---|\n| Chiều cao | 48 px: một control 32 px, cách 8 px phía trên và phía dưới. Đường kẻ 1 px dưới header không tính vào |\n| Chứa | Nút menu (dưới 1024 px), logo, tìm kiếm toàn cục, chuyển workspace, thông báo, tài khoản |\n| Không chứa | Breadcrumb và nút hành động của trang. Chúng đổi theo từng trang, nên nằm trong page header |\n\n## Menu bên\n\n**Rộng 280 px khi mở, thu thành rail 64 px khi gọn, thành drawer khi dưới 1024 px. Mọi sản phẩm Beehexa dùng cùng các độ rộng này.**\n\n| Cửa sổ | Menu bên |\n|---|---|\n| Dưới 1024 px | Ẩn. Nút menu trên header mở nó thành drawer phủ lên trang. |\n| Từ 1024 px trở lên | Mở ở 280 px. Người dùng có thể thu gọn thành rail 64 px, và lựa chọn này được ghi nhớ. |\n\n- **280 px** chứa vừa nhãn khoảng 31 ký tự ở cỡ 14 px, kể cả nhãn tiếng Việt dài.\n- **Cùng một độ rộng ở mọi sản phẩm**, để trang luôn bắt đầu ở cùng một chỗ khi người dùng chuyển giữa các sản phẩm.\n- **Không kéo giãn.** Một độ rộng duy nhất giữ các sản phẩm giống nhau. Panel kéo giãn được còn cần thêm cách đổi cỡ không phải kéo (WCAG 2.5.7).\n- **Rail** chỉ hiện icon. Nhãn của từng mục hiện trong tooltip.\n\n### Nhãn dài\n\n<LayoutDemo kind=\"navlabels\" />\n\n1. Trước hết, viết nhãn ngắn hơn.\n2. Nếu vẫn không vừa, cắt bằng dấu ba chấm và hiện nhãn đầy đủ trong tooltip, chỉ khi nhãn bị cắt.\n3. Không bao giờ nới rộng menu bên vì một nhãn. Sản phẩm có nhãn dài ở khắp nơi có thể chọn một độ rộng từ 240 đến 320 px cho toàn sản phẩm, và ghi lại quyết định đó.\n\n## Page header\n\n**Phần đầu của mọi trang: breadcrumb, tiêu đề, trạng thái và nút hành động của trang.**\n\n<LayoutDemo kind=\"pageheader\" />\n\n| Hàng | Chứa | Khi nào |\n|---|---|---|\n| Breadcrumb | Các trang cấp trên của trang này | Từ cấp thứ hai trở xuống |\n| Hàng tiêu đề | Tiêu đề trang (`heading.large`) và trạng thái ở bên trái; nút hành động của trang ở bên phải, nút chính đứng cuối | Luôn có |\n| Mô tả | Một dòng giới thiệu trang | Không bắt buộc |\n| Tab hoặc bộ lọc | Các góc nhìn của cùng một trang | Không bắt buộc |\n\n- **Page header trải hết vùng nội dung ở mọi độ rộng trang.** Chỉ phần nội dung bên dưới theo [Full, Wide hoặc Narrow](/vi/foundations/styles/layout/page-widths/), nên tiêu đề và nút hành động của trang luôn nằm cùng một chỗ trên mọi trang.\n- Breadcrumb thuộc về trang, không thuộc header: nó đổi theo từng trang, còn header thì giữ nguyên.\n- Ngữ cảnh của cả sản phẩm, như workspace, nằm trên header.\n\n## Panel bên\n\nPanel đặt cạnh nội dung chính, như chi tiết của dòng đang chọn, chiếm các cột của lưới: 4 trên 12 cột từ 1024 px và 3 trên 12 cột từ 1440 px. Dưới 1024 px nó mở thành drawer phủ lên trang. Xem phần span ở trang [Lưới](/vi/foundations/styles/layout/grid/#span).\n\n## Khoảng cách trong khung\n\n**Mọi thứ trong khung thẳng hàng theo hai mép: cách mép trái cửa sổ 20 px, và lề trang.**\n\n| Giữa | Khoảng cách |\n|---|---|\n| Mép cửa sổ và logo; mép cửa sổ và icon của menu bên | 20 px, `space.250` |\n| Các mục trong menu bên và mép của menu | 8 px, `space.100` |\n| Hai mục liền nhau trong menu bên (mỗi mục cao 32 px) | 4 px, `space.050` |\n| Nội dung và menu bên, header hoặc mép cửa sổ | Lề trang: 16, 24 hoặc 32 px ([Lưới](/vi/foundations/styles/layout/grid/)) |\n| Breadcrumb và tiêu đề | 8 px, `space.100` |\n| Tiêu đề và mô tả | 4 px, `space.050` |\n| Page header và nội dung | 24 px, `space.300` |\n\nMép 20 px của logo lấy từ menu bên: 8 px thụt vào cộng 12 px padding ngang của một control 32 px. Nhờ vậy logo nằm ngay trên các icon.\n",
1449
1495
  "frontmatter": {
1450
1496
  "title": "Khung ứng dụng",
1451
1497
  "description": "Header, menu bên và page header lặp lại trên mọi trang, kích thước của chúng, và khoảng cách giúp chúng thẳng hàng.",
@@ -1638,24 +1684,15 @@ export const catalog = [
1638
1684
  "locale": "vi",
1639
1685
  "kind": "guidance",
1640
1686
  "title": "Độ mờ",
1641
- "status": "planned",
1687
+ "status": "active",
1642
1688
  "releasePhase": null,
1643
- "planned": [
1644
- "Chỗ được dùng độ trong suốt: lớp phủ sau dialog, lớp phủ trên ảnh",
1645
- "Vì sao hover, pressed và disabled dùng bậc màu, không dùng độ mờ",
1646
- "Token độ mờ, nếu cần"
1647
- ],
1648
- "body": "",
1649
- "raw": "---\ntitle: \"Độ mờ\"\ndescription: \"Khi nào được dùng độ trong suốt, và vì sao trạng thái và control disabled dùng màu thay vì độ mờ.\"\norder: 10.5\nplanned:\n - \"Chỗ được dùng độ trong suốt: lớp phủ sau dialog, lớp phủ trên ảnh\"\n - \"Vì sao hover, pressed và disabled dùng bậc màu, không dùng độ mờ\"\n - \"Token độ mờ, nếu cần\"\n---\n",
1689
+ "planned": [],
1690
+ "body": "import OpacityDemo from '../../../components/OpacityDemo.astro';\nimport TokenTable from '../../../components/TokenTable.astro';\n\nĐộ mờ (opacity) quyết định một thành phần trong suốt tới mức nào. Thành phần bị làm mờ sẽ để lộ nền phía sau, nên màu của nó thay đổi theo từng màn hình. Beehexa chỉ dùng độ mờ ở hai chỗ: hình ảnh của thứ đã bị tắt, và lớp phủ mờ phía sau dialog.\n\n## Vì sao control dùng màu\n\n- **Nền phía sau lộ ra.** Cùng một nút bị làm mờ nhưng trên card trắng, banner vàng hay dòng đang chọn thì trông mỗi chỗ một khác.\n- **Không còn kiểm tra được tương phản.** Màu bị làm mờ là một màu mới, chữ trên đó có thể không đọc được.\n- **Độ mờ nhân lên.** Một mục mờ 40% nằm trong card mờ 40% thì chỉ còn 16%.\n\nCác token màu disabled như `color.text.disabled` trông giống nhau trên mọi nền. Xem [Trạng thái tương tác](/vi/foundations/styles/interaction-states/).\n\n| Tôi cần | Dùng |\n|---|---|\n| Làm mờ logo, avatar hay hình minh hoạ của thứ đã bị tắt | `opacity.disabled` (0.4) trên hình ảnh |\n| Tắt một nút, ô nhập, chữ hay icon | Các token màu disabled |\n| Làm tối trang phía sau dialog hoặc drawer | `color.surface.scrim` |\n| Làm một thứ hiện dần hoặc mờ dần | Độ mờ 0 và 1 trong hiệu ứng chuyển động |\n\n## Hình ảnh của thứ đã bị tắt\n\nHình ảnh có màu riêng nên không token màu nào đổi được. Làm mờ hình ảnh; chữ dùng `color.text.disabled`; card giữ nguyên viền. Luôn ghi thêm bằng chữ, ví dụ \"Đã tắt\".\n\n<OpacityDemo kind=\"tile\" />\n\n<OpacityDemo kind=\"screen\" />\n\n## Lớp phủ mờ\n\nLớp phủ mờ làm tối trang phía sau dialog hoặc drawer, để dialog là thứ được chú ý và người dùng thấy trang đang tạm khoá. Đây là một màu có sẵn độ trong suốt: graphite 40% ở light mode, đen 60% ở dark mode, vì trang tối cần làm tối mạnh hơn mới thấy rõ. Dùng nguyên như vậy.\n\n<OpacityDemo kind=\"scrim\" />\n\n## Nên và không nên\n\n<OpacityDemo kind=\"dodont\" item=\"container\" />\n<OpacityDemo kind=\"dodont\" item=\"controls\" />\n\n## Token\n\n<TokenTable prefix=\"opacity\" />\n",
1691
+ "raw": "---\ntitle: \"Độ mờ\"\ndescription: \"Một thành phần trong suốt tới mức nào. Chỉ dùng cho hình ảnh của thứ đã bị tắt và lớp phủ mờ phía sau dialog. Control thể hiện trạng thái bằng màu.\"\norder: 10.5\n---\nimport OpacityDemo from '../../../components/OpacityDemo.astro';\nimport TokenTable from '../../../components/TokenTable.astro';\n\nĐộ mờ (opacity) quyết định một thành phần trong suốt tới mức nào. Thành phần bị làm mờ sẽ để lộ nền phía sau, nên màu của nó thay đổi theo từng màn hình. Beehexa chỉ dùng độ mờ ở hai chỗ: hình ảnh của thứ đã bị tắt, và lớp phủ mờ phía sau dialog.\n\n## Vì sao control dùng màu\n\n- **Nền phía sau lộ ra.** Cùng một nút bị làm mờ nhưng trên card trắng, banner vàng hay dòng đang chọn thì trông mỗi chỗ một khác.\n- **Không còn kiểm tra được tương phản.** Màu bị làm mờ là một màu mới, chữ trên đó có thể không đọc được.\n- **Độ mờ nhân lên.** Một mục mờ 40% nằm trong card mờ 40% thì chỉ còn 16%.\n\nCác token màu disabled như `color.text.disabled` trông giống nhau trên mọi nền. Xem [Trạng thái tương tác](/vi/foundations/styles/interaction-states/).\n\n| Tôi cần | Dùng |\n|---|---|\n| Làm mờ logo, avatar hay hình minh hoạ của thứ đã bị tắt | `opacity.disabled` (0.4) trên hình ảnh |\n| Tắt một nút, ô nhập, chữ hay icon | Các token màu disabled |\n| Làm tối trang phía sau dialog hoặc drawer | `color.surface.scrim` |\n| Làm một thứ hiện dần hoặc mờ dần | Độ mờ 0 và 1 trong hiệu ứng chuyển động |\n\n## Hình ảnh của thứ đã bị tắt\n\nHình ảnh có màu riêng nên không token màu nào đổi được. Làm mờ hình ảnh; chữ dùng `color.text.disabled`; card giữ nguyên viền. Luôn ghi thêm bằng chữ, ví dụ \"Đã tắt\".\n\n<OpacityDemo kind=\"tile\" />\n\n<OpacityDemo kind=\"screen\" />\n\n## Lớp phủ mờ\n\nLớp phủ mờ làm tối trang phía sau dialog hoặc drawer, để dialog là thứ được chú ý và người dùng thấy trang đang tạm khoá. Đây là một màu có sẵn độ trong suốt: graphite 40% ở light mode, đen 60% ở dark mode, vì trang tối cần làm tối mạnh hơn mới thấy rõ. Dùng nguyên như vậy.\n\n<OpacityDemo kind=\"scrim\" />\n\n## Nên và không nên\n\n<OpacityDemo kind=\"dodont\" item=\"container\" />\n<OpacityDemo kind=\"dodont\" item=\"controls\" />\n\n## Token\n\n<TokenTable prefix=\"opacity\" />\n",
1650
1692
  "frontmatter": {
1651
1693
  "title": "Độ mờ",
1652
- "description": "Khi nào được dùng độ trong suốt, và vì sao trạng thái và control disabled dùng màu thay vì độ mờ.",
1653
- "order": 10.5,
1654
- "planned": [
1655
- "Chỗ được dùng độ trong suốt: lớp phủ sau dialog, lớp phủ trên ảnh",
1656
- "Vì sao hover, pressed và disabled dùng bậc màu, không dùng độ mờ",
1657
- "Token độ mờ, nếu cần"
1658
- ]
1694
+ "description": "Một thành phần trong suốt tới mức nào. Chỉ dùng cho hình ảnh của thứ đã bị tắt và lớp phủ mờ phía sau dialog. Control thể hiện trạng thái bằng màu.",
1695
+ "order": 10.5
1659
1696
  }
1660
1697
  },
1661
1698
  {
@@ -1686,8 +1723,8 @@ export const catalog = [
1686
1723
  "status": "active",
1687
1724
  "releasePhase": null,
1688
1725
  "planned": [],
1689
- "body": "import LayoutDemo from '../../../components/LayoutDemo.astro';\nimport TokenTable from '../../../components/TokenTable.astro';\n\n**Mọi control có ba chiều cao: 24, 32 và 40 px. Các control trên cùng một hàng dùng chung một chiều cao.**\n\nControl là những thứ người dùng bấm vào hoặc gõ vào: nút, ô nhập, select, segmented control và tab. Chiều cao cố định giữ một hàng control thẳng hàng, dù chữ bên trong dài ngắn thế nào.\n\n<LayoutDemo kind=\"controls\" />\n\n| Cỡ | Chiều cao | Ở đâu |\n|---|---|---|\n| Nhỏ | 24 px | Bảng dày đặc và thanh công cụ của chúng, bộ lọc, tag |\n| Mặc định | 32 px | Form, nút, header, thanh công cụ, mọi chỗ còn lại |\n| Lớn | 40 px | Trang đăng nhập và onboarding. Có thể dùng cho thao tác chính trên màn hình cảm ứng |\n\n- Giữ các control cùng chiều cao trên cùng một hàng. Nút 24 px cạnh ô nhập 32 px trông bị lệch.\n- Đặt chiều cao bằng token kích thước, không dùng padding. Chữ nằm giữa chiều cao.\n\n## Vùng bấm\n\n**Mọi control đều bấm được trong vùng ít nhất 24 × 24 px, và chạm được trong vùng 44 × 44 px trên màn hình cảm ứng.**\n\n- 24 px là cỡ vùng bấm tối thiểu của WCAG 2.2 (SC 2.5.8). Mọi chiều cao control đều đạt mức này.\n- Trên màn hình cảm ứng, giữ nguyên chiều cao nhìn thấy và mở rộng vùng phản hồi khi chạm lên ít nhất 44 × 44 px (`size.target.touch`).\n\n## Mật độ\n\n**Hiện Beehexa chỉ có một mật độ: mặc định.**\n\nMột mật độ nghĩa là mọi màn hình được thiết kế và kiểm tra ở một cỡ. Mật độ gọn có thể ra sau; nó sẽ giảm chiều cao control và khoảng cách cùng lúc, và màn hình nào dùng token sẽ không cần sửa gì.\n\nTrước khi có mật độ gọn, hãy làm bảng dày đặc bằng control và dòng cỡ nhỏ (24 px), không dùng token khoảng cách nhỏ hơn.\n\n## Token\n\n<TokenTable prefix=\"size\" />\n",
1690
- "raw": "---\ntitle: Kích thước và mật độ\ndescription: Ba chiều cao control, cỡ vùng người dùng có thể bấm hoặc chạm, và mật độ của màn hình Beehexa.\norder: 5\n---\nimport LayoutDemo from '../../../components/LayoutDemo.astro';\nimport TokenTable from '../../../components/TokenTable.astro';\n\n**Mọi control có ba chiều cao: 24, 32 và 40 px. Các control trên cùng một hàng dùng chung một chiều cao.**\n\nControl là những thứ người dùng bấm vào hoặc gõ vào: nút, ô nhập, select, segmented control và tab. Chiều cao cố định giữ một hàng control thẳng hàng, dù chữ bên trong dài ngắn thế nào.\n\n<LayoutDemo kind=\"controls\" />\n\n| Cỡ | Chiều cao | Ở đâu |\n|---|---|---|\n| Nhỏ | 24 px | Bảng dày đặc và thanh công cụ của chúng, bộ lọc, tag |\n| Mặc định | 32 px | Form, nút, header, thanh công cụ, mọi chỗ còn lại |\n| Lớn | 40 px | Trang đăng nhập và onboarding. Có thể dùng cho thao tác chính trên màn hình cảm ứng |\n\n- Giữ các control cùng chiều cao trên cùng một hàng. Nút 24 px cạnh ô nhập 32 px trông bị lệch.\n- Đặt chiều cao bằng token kích thước, không dùng padding. Chữ nằm giữa chiều cao.\n\n## Vùng bấm\n\n**Mọi control đều bấm được trong vùng ít nhất 24 × 24 px, và chạm được trong vùng 44 × 44 px trên màn hình cảm ứng.**\n\n- 24 px là cỡ vùng bấm tối thiểu của WCAG 2.2 (SC 2.5.8). Mọi chiều cao control đều đạt mức này.\n- Trên màn hình cảm ứng, giữ nguyên chiều cao nhìn thấy và mở rộng vùng phản hồi khi chạm lên ít nhất 44 × 44 px (`size.target.touch`).\n\n## Mật độ\n\n**Hiện Beehexa chỉ có một mật độ: mặc định.**\n\nMột mật độ nghĩa là mọi màn hình được thiết kế và kiểm tra ở một cỡ. Mật độ gọn có thể ra sau; nó sẽ giảm chiều cao control và khoảng cách cùng lúc, và màn hình nào dùng token sẽ không cần sửa gì.\n\nTrước khi có mật độ gọn, hãy làm bảng dày đặc bằng control và dòng cỡ nhỏ (24 px), không dùng token khoảng cách nhỏ hơn.\n\n## Token\n\n<TokenTable prefix=\"size\" />\n",
1726
+ "body": "import LayoutDemo from '../../../components/LayoutDemo.astro';\nimport TokenTable from '../../../components/TokenTable.astro';\n\n**Mọi control có ba chiều cao: 24, 32 và 40 px. Các control trên cùng một hàng dùng chung một chiều cao.**\n\nControl là những thứ người dùng bấm vào hoặc gõ vào: nút, ô nhập, select, segmented control và tab. Chiều cao cố định giữ một hàng control thẳng hàng, dù chữ bên trong dài ngắn thế nào.\n\n<LayoutDemo kind=\"controls\" />\n\n| Cỡ | Chiều cao | Ở đâu |\n|---|---|---|\n| Nhỏ | 24 px | Bảng dày đặc và thanh công cụ của chúng, bộ lọc, tag |\n| Mặc định | 32 px | Form, nút, header, thanh công cụ, mọi chỗ còn lại |\n| Lớn | 40 px | Trang đăng nhập và onboarding. Có thể dùng cho thao tác chính trên màn hình cảm ứng |\n\n- Giữ các control cùng chiều cao trên cùng một hàng. Nút 24 px cạnh ô nhập 32 px trông bị lệch.\n- Đặt chiều cao bằng token kích thước, không dùng padding. Chữ nằm giữa chiều cao.\n\nHai thành phần khác có kích thước cố định:\n\n| Thành phần | Kích thước |\n|---|---|\n| Switch | Cao 20 px, rộng 36 px; núm 16 px |\n| Avatar | 32 px; 24 px trong bảng và danh sách dày |\n\n## Vùng bấm\n\n**Mọi control đều bấm được trong vùng ít nhất 24 × 24 px, và chạm được trong vùng 44 × 44 px trên màn hình cảm ứng.**\n\n- 24 px là cỡ vùng bấm tối thiểu của WCAG 2.2 (SC 2.5.8). Mọi chiều cao control đều đạt mức này.\n- Trên màn hình cảm ứng, giữ nguyên chiều cao nhìn thấy và mở rộng vùng phản hồi khi chạm lên ít nhất 44 × 44 px (`size.target.touch`).\n\n## Mật độ\n\n**Hiện Beehexa chỉ có một mật độ: mặc định.**\n\nMột mật độ nghĩa là mọi màn hình được thiết kế và kiểm tra ở một cỡ. Mật độ gọn có thể ra sau; nó sẽ giảm chiều cao control và khoảng cách cùng lúc, và màn hình nào dùng token sẽ không cần sửa gì.\n\nTrước khi có mật độ gọn, hãy làm bảng dày đặc bằng control và dòng cỡ nhỏ (24 px), không dùng token khoảng cách nhỏ hơn.\n\n## Token\n\n<TokenTable prefix=\"size\" />\n",
1727
+ "raw": "---\ntitle: Kích thước và mật độ\ndescription: Ba chiều cao control, cỡ vùng người dùng có thể bấm hoặc chạm, và mật độ của màn hình Beehexa.\norder: 5\n---\nimport LayoutDemo from '../../../components/LayoutDemo.astro';\nimport TokenTable from '../../../components/TokenTable.astro';\n\n**Mọi control có ba chiều cao: 24, 32 và 40 px. Các control trên cùng một hàng dùng chung một chiều cao.**\n\nControl là những thứ người dùng bấm vào hoặc gõ vào: nút, ô nhập, select, segmented control và tab. Chiều cao cố định giữ một hàng control thẳng hàng, dù chữ bên trong dài ngắn thế nào.\n\n<LayoutDemo kind=\"controls\" />\n\n| Cỡ | Chiều cao | Ở đâu |\n|---|---|---|\n| Nhỏ | 24 px | Bảng dày đặc và thanh công cụ của chúng, bộ lọc, tag |\n| Mặc định | 32 px | Form, nút, header, thanh công cụ, mọi chỗ còn lại |\n| Lớn | 40 px | Trang đăng nhập và onboarding. Có thể dùng cho thao tác chính trên màn hình cảm ứng |\n\n- Giữ các control cùng chiều cao trên cùng một hàng. Nút 24 px cạnh ô nhập 32 px trông bị lệch.\n- Đặt chiều cao bằng token kích thước, không dùng padding. Chữ nằm giữa chiều cao.\n\nHai thành phần khác có kích thước cố định:\n\n| Thành phần | Kích thước |\n|---|---|\n| Switch | Cao 20 px, rộng 36 px; núm 16 px |\n| Avatar | 32 px; 24 px trong bảng và danh sách dày |\n\n## Vùng bấm\n\n**Mọi control đều bấm được trong vùng ít nhất 24 × 24 px, và chạm được trong vùng 44 × 44 px trên màn hình cảm ứng.**\n\n- 24 px là cỡ vùng bấm tối thiểu của WCAG 2.2 (SC 2.5.8). Mọi chiều cao control đều đạt mức này.\n- Trên màn hình cảm ứng, giữ nguyên chiều cao nhìn thấy và mở rộng vùng phản hồi khi chạm lên ít nhất 44 × 44 px (`size.target.touch`).\n\n## Mật độ\n\n**Hiện Beehexa chỉ có một mật độ: mặc định.**\n\nMột mật độ nghĩa là mọi màn hình được thiết kế và kiểm tra ở một cỡ. Mật độ gọn có thể ra sau; nó sẽ giảm chiều cao control và khoảng cách cùng lúc, và màn hình nào dùng token sẽ không cần sửa gì.\n\nTrước khi có mật độ gọn, hãy làm bảng dày đặc bằng control và dòng cỡ nhỏ (24 px), không dùng token khoảng cách nhỏ hơn.\n\n## Token\n\n<TokenTable prefix=\"size\" />\n",
1691
1728
  "frontmatter": {
1692
1729
  "title": "Kích thước và mật độ",
1693
1730
  "description": "Ba chiều cao control, cỡ vùng người dùng có thể bấm hoặc chạm, và mật độ của màn hình Beehexa.",
@@ -1722,8 +1759,8 @@ export const catalog = [
1722
1759
  "status": "active",
1723
1760
  "releasePhase": null,
1724
1761
  "planned": [],
1725
- "body": "import TokenTable from '../../../../components/TokenTable.astro';\nimport TypeDemo from '../../../../components/TypeDemo.astro';\n\n## Font stack\n\nDùng token, không tự viết danh sách font.\n\n```css\n/* font.family.sans */\nfont-family: Inter, \"Noto Sans\", system-ui, sans-serif;\n\n/* font.family.mono */\nfont-family: \"JetBrains Mono\", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n```\n\nNoto Sans là font dự phòng vì có đủ chữ tiếng Việt và ký hiệu ₫, và có cỡ gần với Inter (x-height 0.536 em so với 0.546 của Inter), nên trang chuyển sang font dự phòng vẫn giữ bố cục.\n\n## Lấy font\n\n- **Trên web,** hãy tự host font. Dùng bản Inter trong kho Google Fonts (`github.com/google/fonts`, `ofl/inter`): bản này được hinting cho chữ nhỏ trên Windows và giữ đủ mọi tính năng OpenType. Không link tới Google Fonts API: file ở đó bỏ mất `cv05`, `cv08`, `ss02` và `zero`, trong khi `cv05` và `cv08` được bật mặc định (xem [Chữ số và mã](#chữ-số-và-mã)). Site này phục vụ các file đó, chia thành các bộ ký tự Latin, Latin Extended và tiếng Việt.\n- **Trên máy tính,** để dùng trong Figma, slide và tài liệu, cài Inter từ Google Fonts và JetBrains Mono từ JetBrains. Bản Inter của Google Fonts cũng tránh được lỗi dấu bị cắt trong các ứng dụng Windows cũ như Office.\n- Giấy phép của cả hai font đều cho phép dùng trong sản phẩm, tài liệu và logo.\n\n## Chữ số và mã\n\n`cv05` và `cv08` được bật cho mọi chữ Inter. Chúng cho chữ l thường có đuôi và chữ I hoa có chân, nên l, I và 1 không bao giờ trông giống nhau trong tên, ID và key. Bật các tính năng còn lại ở nơi cần; giữ nguyên đoạn văn.\n\n- **Bảng và giá trị thay đổi:** dùng số đều cột (`font-variant-numeric: tabular-nums`), để chữ số thẳng cột và bộ đếm không bị giật.\n- **Mã mà người dùng đọc hoặc gõ,** như mã đơn hàng, SKU và API key: thêm số 0 có gạch chéo (`zero`) cho Inter, hoặc đặt chúng bằng JetBrains Mono (`code.default`). JetBrains Mono không có `cv05` hay `cv08`, nên code trông vẫn như cũ.\n\n<TypeDemo kind=\"numbers\" />\n\n<TypeDemo kind=\"features\" />\n\nMọi text style được áp dụng bằng thuộc tính rút gọn `font`, và thuộc tính này đặt lại `font-feature-settings`. Vì vậy các tính năng được đặt trên mọi thành phần từ một biến, `--bh-font-features`; muốn thêm tính năng, hãy đổi biến, không đổi thuộc tính.\n\n```css\n/* Base: on every element */\n:root { --bh-font-features: \"cv05\", \"cv08\"; }\n*, ::before, ::after { font-feature-settings: var(--bh-font-features) !important; }\n\n/* Opt in where needed */\n.table-number { font-variant-numeric: tabular-nums; }\n.code-value { --bh-font-features: \"cv05\", \"cv08\", \"zero\"; }\n```\n\n## Token\n<TokenTable prefix=\"font\" />\n",
1726
- "raw": "---\ntitle: Code\ndescription: Font stack, cách lấy font, tính năng OpenType cho chữ số và mã, và các token chữ.\norder: 3\n---\nimport TokenTable from '../../../../components/TokenTable.astro';\nimport TypeDemo from '../../../../components/TypeDemo.astro';\n\n## Font stack\n\nDùng token, không tự viết danh sách font.\n\n```css\n/* font.family.sans */\nfont-family: Inter, \"Noto Sans\", system-ui, sans-serif;\n\n/* font.family.mono */\nfont-family: \"JetBrains Mono\", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n```\n\nNoto Sans là font dự phòng vì có đủ chữ tiếng Việt và ký hiệu ₫, và có cỡ gần với Inter (x-height 0.536 em so với 0.546 của Inter), nên trang chuyển sang font dự phòng vẫn giữ bố cục.\n\n## Lấy font\n\n- **Trên web,** hãy tự host font. Dùng bản Inter trong kho Google Fonts (`github.com/google/fonts`, `ofl/inter`): bản này được hinting cho chữ nhỏ trên Windows và giữ đủ mọi tính năng OpenType. Không link tới Google Fonts API: file ở đó bỏ mất `cv05`, `cv08`, `ss02` và `zero`, trong khi `cv05` và `cv08` được bật mặc định (xem [Chữ số và mã](#chữ-số-và-mã)). Site này phục vụ các file đó, chia thành các bộ ký tự Latin, Latin Extended và tiếng Việt.\n- **Trên máy tính,** để dùng trong Figma, slide và tài liệu, cài Inter từ Google Fonts và JetBrains Mono từ JetBrains. Bản Inter của Google Fonts cũng tránh được lỗi dấu bị cắt trong các ứng dụng Windows cũ như Office.\n- Giấy phép của cả hai font đều cho phép dùng trong sản phẩm, tài liệu và logo.\n\n## Chữ số và mã\n\n`cv05` và `cv08` được bật cho mọi chữ Inter. Chúng cho chữ l thường có đuôi và chữ I hoa có chân, nên l, I và 1 không bao giờ trông giống nhau trong tên, ID và key. Bật các tính năng còn lại ở nơi cần; giữ nguyên đoạn văn.\n\n- **Bảng và giá trị thay đổi:** dùng số đều cột (`font-variant-numeric: tabular-nums`), để chữ số thẳng cột và bộ đếm không bị giật.\n- **Mã mà người dùng đọc hoặc gõ,** như mã đơn hàng, SKU và API key: thêm số 0 có gạch chéo (`zero`) cho Inter, hoặc đặt chúng bằng JetBrains Mono (`code.default`). JetBrains Mono không có `cv05` hay `cv08`, nên code trông vẫn như cũ.\n\n<TypeDemo kind=\"numbers\" />\n\n<TypeDemo kind=\"features\" />\n\nMọi text style được áp dụng bằng thuộc tính rút gọn `font`, và thuộc tính này đặt lại `font-feature-settings`. Vì vậy các tính năng được đặt trên mọi thành phần từ một biến, `--bh-font-features`; muốn thêm tính năng, hãy đổi biến, không đổi thuộc tính.\n\n```css\n/* Base: on every element */\n:root { --bh-font-features: \"cv05\", \"cv08\"; }\n*, ::before, ::after { font-feature-settings: var(--bh-font-features) !important; }\n\n/* Opt in where needed */\n.table-number { font-variant-numeric: tabular-nums; }\n.code-value { --bh-font-features: \"cv05\", \"cv08\", \"zero\"; }\n```\n\n## Token\n<TokenTable prefix=\"font\" />\n",
1762
+ "body": "import TokenTable from '../../../../components/TokenTable.astro';\nimport TypeDemo from '../../../../components/TypeDemo.astro';\n\n## Font stack\n\nDùng token, không tự viết danh sách font.\n\n```css\n/* font.family.sans */\nfont-family: Inter, \"Noto Sans\", system-ui, sans-serif;\n\n/* font.family.mono */\nfont-family: \"JetBrains Mono\", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n```\n\nNoto Sans là font dự phòng vì có đủ chữ tiếng Việt và ký hiệu ₫, và có cỡ gần với Inter (x-height 0.536 em so với 0.546 của Inter), nên trang chuyển sang font dự phòng vẫn giữ bố cục.\n\n## Lấy font\n\n- **Trên web,** hãy tự host font. Dùng bản Inter trong kho Google Fonts (`github.com/google/fonts`, `ofl/inter`): bản này được hinting cho chữ nhỏ trên Windows và giữ đủ mọi tính năng OpenType. Không link tới Google Fonts API: file ở đó bỏ mất `cv05`, `cv08`, `ss02` và `zero`, trong khi `cv05` và `cv08` được bật mặc định (xem [Chữ số và mã](#chữ-số-và-mã)). Site này phục vụ các file đó, chia thành các bộ ký tự Latin, Latin Extended và tiếng Việt.\n- **Trên máy tính,** để dùng trong Figma, slide và tài liệu, cài Inter từ Google Fonts và JetBrains Mono từ JetBrains. Bản Inter của Google Fonts cũng tránh được lỗi dấu bị cắt trong các ứng dụng Windows cũ như Office.\n- Giấy phép của cả hai font đều cho phép dùng trong sản phẩm, tài liệu và logo.\n\n## Chữ số và mã\n\n`cv05` và `cv08` được bật cho mọi chữ Inter. Chúng cho chữ l thường có đuôi và chữ I hoa có chân, nên l, I và 1 không bao giờ trông giống nhau trong tên, ID và key. Bật các tính năng còn lại ở nơi cần; giữ nguyên đoạn văn.\n\n- **Bảng và giá trị thay đổi:** dùng số đều cột (`font-variant-numeric: tabular-nums`), để chữ số thẳng cột và bộ đếm không bị giật.\n- **Mã mà người dùng đọc hoặc gõ,** như mã đơn hàng, SKU và API key: thêm số 0 có gạch chéo (`zero`) cho Inter, hoặc đặt chúng bằng JetBrains Mono (`code.default`). JetBrains Mono không có `cv05` hay `cv08`, nên code trông vẫn như cũ.\n\n<TypeDemo kind=\"numbers\" />\n\n<TypeDemo kind=\"features\" />\n\nMọi text style dùng thuộc tính rút gọn `font`, vốn đặt lại `font-feature-settings`. Token nguồn `font.features` sở hữu `\"cv05\", \"cv08\"`; CSS token sinh tự động áp dụng `--bh-font-features` trên mọi phần tử với `!important`. Ứng dụng import CSS này, không sao chép quy tắc cơ sở bên dưới. Thêm tính năng bằng biến, không bằng thuộc tính cạnh tranh. Giữ root 16px và vai trò `font.body.default` 14px cho body.\n\n```css\n/* Base: on every element */\n:root { --bh-font-features: \"cv05\", \"cv08\"; }\n*, ::before, ::after { font-feature-settings: var(--bh-font-features) !important; }\n\n/* Opt in where needed */\n.table-number { font-variant-numeric: tabular-nums; }\n.code-value { --bh-font-features: \"cv05\", \"cv08\", \"zero\"; }\n```\n\n## Token\n<TokenTable prefix=\"font\" />\n",
1763
+ "raw": "---\ntitle: Code\ndescription: Font stack, cách lấy font, tính năng OpenType cho chữ số và mã, và các token chữ.\norder: 3\n---\nimport TokenTable from '../../../../components/TokenTable.astro';\nimport TypeDemo from '../../../../components/TypeDemo.astro';\n\n## Font stack\n\nDùng token, không tự viết danh sách font.\n\n```css\n/* font.family.sans */\nfont-family: Inter, \"Noto Sans\", system-ui, sans-serif;\n\n/* font.family.mono */\nfont-family: \"JetBrains Mono\", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n```\n\nNoto Sans là font dự phòng vì có đủ chữ tiếng Việt và ký hiệu ₫, và có cỡ gần với Inter (x-height 0.536 em so với 0.546 của Inter), nên trang chuyển sang font dự phòng vẫn giữ bố cục.\n\n## Lấy font\n\n- **Trên web,** hãy tự host font. Dùng bản Inter trong kho Google Fonts (`github.com/google/fonts`, `ofl/inter`): bản này được hinting cho chữ nhỏ trên Windows và giữ đủ mọi tính năng OpenType. Không link tới Google Fonts API: file ở đó bỏ mất `cv05`, `cv08`, `ss02` và `zero`, trong khi `cv05` và `cv08` được bật mặc định (xem [Chữ số và mã](#chữ-số-và-mã)). Site này phục vụ các file đó, chia thành các bộ ký tự Latin, Latin Extended và tiếng Việt.\n- **Trên máy tính,** để dùng trong Figma, slide và tài liệu, cài Inter từ Google Fonts và JetBrains Mono từ JetBrains. Bản Inter của Google Fonts cũng tránh được lỗi dấu bị cắt trong các ứng dụng Windows cũ như Office.\n- Giấy phép của cả hai font đều cho phép dùng trong sản phẩm, tài liệu và logo.\n\n## Chữ số và mã\n\n`cv05` và `cv08` được bật cho mọi chữ Inter. Chúng cho chữ l thường có đuôi và chữ I hoa có chân, nên l, I và 1 không bao giờ trông giống nhau trong tên, ID và key. Bật các tính năng còn lại ở nơi cần; giữ nguyên đoạn văn.\n\n- **Bảng và giá trị thay đổi:** dùng số đều cột (`font-variant-numeric: tabular-nums`), để chữ số thẳng cột và bộ đếm không bị giật.\n- **Mã mà người dùng đọc hoặc gõ,** như mã đơn hàng, SKU và API key: thêm số 0 có gạch chéo (`zero`) cho Inter, hoặc đặt chúng bằng JetBrains Mono (`code.default`). JetBrains Mono không có `cv05` hay `cv08`, nên code trông vẫn như cũ.\n\n<TypeDemo kind=\"numbers\" />\n\n<TypeDemo kind=\"features\" />\n\nMọi text style dùng thuộc tính rút gọn `font`, vốn đặt lại `font-feature-settings`. Token nguồn `font.features` sở hữu `\"cv05\", \"cv08\"`; CSS token sinh tự động áp dụng `--bh-font-features` trên mọi phần tử với `!important`. Ứng dụng import CSS này, không sao chép quy tắc cơ sở bên dưới. Thêm tính năng bằng biến, không bằng thuộc tính cạnh tranh. Giữ root 16px và vai trò `font.body.default` 14px cho body.\n\n```css\n/* Base: on every element */\n:root { --bh-font-features: \"cv05\", \"cv08\"; }\n*, ::before, ::after { font-feature-settings: var(--bh-font-features) !important; }\n\n/* Opt in where needed */\n.table-number { font-variant-numeric: tabular-nums; }\n.code-value { --bh-font-features: \"cv05\", \"cv08\", \"zero\"; }\n```\n\n## Token\n<TokenTable prefix=\"font\" />\n",
1727
1764
  "frontmatter": {
1728
1765
  "title": "Code",
1729
1766
  "description": "Font stack, cách lấy font, tính năng OpenType cho chữ số và mã, và các token chữ.",
@@ -1792,24 +1829,15 @@ export const catalog = [
1792
1829
  "locale": "vi",
1793
1830
  "kind": "guidance",
1794
1831
  "title": "Z-index",
1795
- "status": "planned",
1832
+ "status": "active",
1796
1833
  "releasePhase": null,
1797
- "planned": [
1798
- "Tên các lớp và thứ tự",
1799
- "Mỗi lớp phủ dùng lớp nào: dropdown, popover, tooltip, dialog, drawer, toast",
1800
- "Lớp và đổ bóng đi cùng nhau thế nào"
1801
- ],
1802
- "body": "",
1803
- "raw": "---\ntitle: \"Z-index\"\ndescription: \"Thứ tự các lớp chồng lên nhau: cái gì nằm trên cái gì, từ header dính đầu trang tới dialog và toast.\"\norder: 8.5\nplanned:\n - \"Tên các lớp và thứ tự\"\n - \"Mỗi lớp phủ dùng lớp nào: dropdown, popover, tooltip, dialog, drawer, toast\"\n - \"Lớp và đổ bóng đi cùng nhau thế nào\"\n---\n",
1834
+ "planned": [],
1835
+ "body": "import ZIndexDemo from '../../../components/ZIndexDemo.astro';\nimport TokenTable from '../../../components/TokenTable.astro';\n\nZ-index quyết định thành phần nào được vẽ lên trên khi hai thành phần chồng lên nhau. Beehexa dùng bảy lớp cơ sở có tên thay vì tự đặt số, để menu không bao giờ mở ra sau dialog và toast không bao giờ bị lớp phủ mờ che mất.\n\n<ZIndexDemo kind=\"stack\" />\n\n## Cách hoạt động\n\n- **Lớp cao hơn che lớp thấp hơn.** Giá trị cơ sở từ 100 tới 700, mỗi bậc cách nhau 100, chừa chỗ cho vai trò toàn màn hình và chờ chặn rõ ràng.\n- **Chọn lớp theo việc thành phần làm**, không theo con số cần cao bao nhiêu.\n- **Một lớp chỉ so với các thành phần bên cạnh.** Thành phần có z-index riêng, transform, filter hoặc opacity nhỏ hơn 1 sẽ tạo ra một ngữ cảnh chồng lớp mới; không thứ gì bên trong vượt lên trên nó được. Vì vậy danh sách trong dialog được đặt luôn bên trong dialog.\n\n[Đổ bóng](/vi/foundations/styles/elevation/) cho thấy bề mặt trông cao bao nhiêu; z-index bảo đảm nó được vẽ lên trên. Một menu cần cả hai.\n\n| Lớp | Token | Giá trị | Mức đổ bóng | Dùng cho |\n|---|---|---|---|---|\n| Sticky | `z-index.sticky` | 100 | Page | Header của bảng và thanh công cụ dính khi cuộn |\n| Navigation | `z-index.navigation` | 200 | Page | Header của app, menu bên trái |\n| Overlay | `z-index.overlay` | 300 | Overlay | Menu, danh sách của select, popover |\n| Modal | `z-index.modal` | 400 | Modal | Dialog, drawer và lớp phủ mờ phía sau |\n| Spotlight | `z-index.spotlight` | 500 | Modal | Tour hướng dẫn, vùng làm nổi bật khi onboarding |\n| Tooltip | `z-index.tooltip` | 600 | không có | Tooltip |\n| Toast | `z-index.toast` | 700 | Overlay | Toast, skip link |\n\n## Vì sao theo thứ tự này\n\n- Menu đè lên thanh điều hướng mà nó mở ra từ đó.\n- Modal chặn cả trang, kể cả menu.\n- Tour cần chỉ được vào thứ nằm trong dialog.\n- Tooltip giải thích một control, dù control đó nằm ở đâu.\n- Toast báo về cả ứng dụng, nên không gì được che nó.\n\n## Ví dụ trên một màn hình\n\n<ZIndexDemo kind=\"screen\" />\n\nBên trong một component, số từ 1 tới 9 không cần token, ví dụ để nút đang focus trong nhóm nút nằm trên các nút bên cạnh.\n\n## Nên và không nên\n\n<ZIndexDemo kind=\"dodont\" item=\"toast\" />\n<ZIndexDemo kind=\"dodont\" item=\"inside\" />\n<ZIndexDemo kind=\"dodont\" item=\"scrim\" />\n\n## Token\n\n<TokenTable prefix=\"z-index\" />\n\n## Toàn màn hình và tích hợp framework\n\nHai vai trò mở rộng `z-index.fullscreen` (450) và `z-index.loading` (650) dành cho trình sửa mã/xem mã/ảnh toàn màn hình và màn hình chờ chặn ứng dụng. Toàn màn hình vẫn nằm dưới spotlight, tooltip và toast; màn hình chờ che thành phần tương tác và tooltip, còn toast và skip link luôn trên cùng ở mức 700.\n\nĐồ thị vận hành toàn màn hình dùng `z-index.modal` trong stacking context cục bộ có `isolation`, không dùng lớp trình sửa mã. Chrome con chỉ dùng thứ tự cục bộ để inspector toàn cục vẫn xuất hiện phía trên.\n\nAdapter Ant Design Vue sở hữu thứ tự lớp native: menu và select dùng overlay, dialog và drawer dùng modal, tooltip dùng tooltip, thông báo dùng toast. Gắn `getPopupContainer` theo ngữ cảnh từ adapter vào ConfigProvider gốc để popup trong dialog, drawer hoặc màn hình toàn màn hình nằm trong chủ sở hữu, phía trên scrim. Không nâng mọi popup toàn cục để bù container sai. Đánh dấu bề mặt toàn màn hình tùy chỉnh bằng `data-bh-overlay-owner`.\n\nModal/Drawer native gốc vẫn đặt trong document body để giữ hình học viewport. Đặt zIndex mặc định của modal bằng `getAntDesignVueModalZIndex()` tại thời điểm gọi (giữ giá trị tường minh của bên gọi), và truyền lớp cha đang hoạt động vào `getAntDesignVueOverlayZIndex(fullscreen, ownerZIndex)` cho drawer lồng nhau. Lớp con dùng giới hạn chủ sở hữu cao nhất cộng một, không cộng dồn z-index của tổ tiên; nhờ vậy xác nhận native nằm trên trình sửa mã toàn màn hình nhưng dưới spotlight và thông báo.\n\nHover, completion và parameter hint tách rời của Monaco dùng `z-index.tooltip`. Cô lập trình sửa mã toàn màn hình để chrome con không che thông báo toàn cục. Chỉ dùng một `color.surface.scrim` sau modal hoặc trình xem ảnh, không chồng nhiều lớp bán trong suốt.\n\nGiữ focus containment, trả focus, Escape và khóa cuộn. Kiểm tra trực tiếp đồ thị, gợi ý trình sửa mã, menu lồng nhau, inspector và màn hình chờ; con số không tự chứng minh hiển thị hay khả năng truy cập.\n",
1836
+ "raw": "---\ntitle: \"Z-index\"\ndescription: \"Khi hai thành phần chồng lên nhau, cái nào được vẽ lên trên. Bảy lớp cơ sở và vai trò toàn màn hình/chờ chặn giữ thứ tự thống nhất.\"\norder: 8.5\n---\nimport ZIndexDemo from '../../../components/ZIndexDemo.astro';\nimport TokenTable from '../../../components/TokenTable.astro';\n\nZ-index quyết định thành phần nào được vẽ lên trên khi hai thành phần chồng lên nhau. Beehexa dùng bảy lớp cơ sở có tên thay vì tự đặt số, để menu không bao giờ mở ra sau dialog và toast không bao giờ bị lớp phủ mờ che mất.\n\n<ZIndexDemo kind=\"stack\" />\n\n## Cách hoạt động\n\n- **Lớp cao hơn che lớp thấp hơn.** Giá trị cơ sở từ 100 tới 700, mỗi bậc cách nhau 100, chừa chỗ cho vai trò toàn màn hình và chờ chặn rõ ràng.\n- **Chọn lớp theo việc thành phần làm**, không theo con số cần cao bao nhiêu.\n- **Một lớp chỉ so với các thành phần bên cạnh.** Thành phần có z-index riêng, transform, filter hoặc opacity nhỏ hơn 1 sẽ tạo ra một ngữ cảnh chồng lớp mới; không thứ gì bên trong vượt lên trên nó được. Vì vậy danh sách trong dialog được đặt luôn bên trong dialog.\n\n[Đổ bóng](/vi/foundations/styles/elevation/) cho thấy bề mặt trông cao bao nhiêu; z-index bảo đảm nó được vẽ lên trên. Một menu cần cả hai.\n\n| Lớp | Token | Giá trị | Mức đổ bóng | Dùng cho |\n|---|---|---|---|---|\n| Sticky | `z-index.sticky` | 100 | Page | Header của bảng và thanh công cụ dính khi cuộn |\n| Navigation | `z-index.navigation` | 200 | Page | Header của app, menu bên trái |\n| Overlay | `z-index.overlay` | 300 | Overlay | Menu, danh sách của select, popover |\n| Modal | `z-index.modal` | 400 | Modal | Dialog, drawer và lớp phủ mờ phía sau |\n| Spotlight | `z-index.spotlight` | 500 | Modal | Tour hướng dẫn, vùng làm nổi bật khi onboarding |\n| Tooltip | `z-index.tooltip` | 600 | không có | Tooltip |\n| Toast | `z-index.toast` | 700 | Overlay | Toast, skip link |\n\n## Vì sao theo thứ tự này\n\n- Menu đè lên thanh điều hướng mà nó mở ra từ đó.\n- Modal chặn cả trang, kể cả menu.\n- Tour cần chỉ được vào thứ nằm trong dialog.\n- Tooltip giải thích một control, dù control đó nằm ở đâu.\n- Toast báo về cả ứng dụng, nên không gì được che nó.\n\n## Ví dụ trên một màn hình\n\n<ZIndexDemo kind=\"screen\" />\n\nBên trong một component, số từ 1 tới 9 không cần token, ví dụ để nút đang focus trong nhóm nút nằm trên các nút bên cạnh.\n\n## Nên và không nên\n\n<ZIndexDemo kind=\"dodont\" item=\"toast\" />\n<ZIndexDemo kind=\"dodont\" item=\"inside\" />\n<ZIndexDemo kind=\"dodont\" item=\"scrim\" />\n\n## Token\n\n<TokenTable prefix=\"z-index\" />\n\n## Toàn màn hình và tích hợp framework\n\nHai vai trò mở rộng `z-index.fullscreen` (450) và `z-index.loading` (650) dành cho trình sửa mã/xem mã/ảnh toàn màn hình và màn hình chờ chặn ứng dụng. Toàn màn hình vẫn nằm dưới spotlight, tooltip và toast; màn hình chờ che thành phần tương tác và tooltip, còn toast và skip link luôn trên cùng ở mức 700.\n\nĐồ thị vận hành toàn màn hình dùng `z-index.modal` trong stacking context cục bộ có `isolation`, không dùng lớp trình sửa mã. Chrome con chỉ dùng thứ tự cục bộ để inspector toàn cục vẫn xuất hiện phía trên.\n\nAdapter Ant Design Vue sở hữu thứ tự lớp native: menu và select dùng overlay, dialog và drawer dùng modal, tooltip dùng tooltip, thông báo dùng toast. Gắn `getPopupContainer` theo ngữ cảnh từ adapter vào ConfigProvider gốc để popup trong dialog, drawer hoặc màn hình toàn màn hình nằm trong chủ sở hữu, phía trên scrim. Không nâng mọi popup toàn cục để bù container sai. Đánh dấu bề mặt toàn màn hình tùy chỉnh bằng `data-bh-overlay-owner`.\n\nModal/Drawer native gốc vẫn đặt trong document body để giữ hình học viewport. Đặt zIndex mặc định của modal bằng `getAntDesignVueModalZIndex()` tại thời điểm gọi (giữ giá trị tường minh của bên gọi), và truyền lớp cha đang hoạt động vào `getAntDesignVueOverlayZIndex(fullscreen, ownerZIndex)` cho drawer lồng nhau. Lớp con dùng giới hạn chủ sở hữu cao nhất cộng một, không cộng dồn z-index của tổ tiên; nhờ vậy xác nhận native nằm trên trình sửa mã toàn màn hình nhưng dưới spotlight và thông báo.\n\nHover, completion và parameter hint tách rời của Monaco dùng `z-index.tooltip`. Cô lập trình sửa mã toàn màn hình để chrome con không che thông báo toàn cục. Chỉ dùng một `color.surface.scrim` sau modal hoặc trình xem ảnh, không chồng nhiều lớp bán trong suốt.\n\nGiữ focus containment, trả focus, Escape và khóa cuộn. Kiểm tra trực tiếp đồ thị, gợi ý trình sửa mã, menu lồng nhau, inspector và màn hình chờ; con số không tự chứng minh hiển thị hay khả năng truy cập.\n",
1804
1837
  "frontmatter": {
1805
1838
  "title": "Z-index",
1806
- "description": "Thứ tự các lớp chồng lên nhau: cái gì nằm trên cái gì, từ header dính đầu trang tới dialog và toast.",
1807
- "order": 8.5,
1808
- "planned": [
1809
- "Tên các lớp và thứ tự",
1810
- "Mỗi lớp phủ dùng lớp nào: dropdown, popover, tooltip, dialog, drawer, toast",
1811
- "Lớp và đổ bóng đi cùng nhau thế nào"
1812
- ]
1839
+ "description": "Khi hai thành phần chồng lên nhau, cái nào được vẽ lên trên. Bảy lớp cơ sở và vai trò toàn màn hình/chờ chặn giữ thứ tự thống nhất.",
1840
+ "order": 8.5
1813
1841
  }
1814
1842
  }
1815
1843
  ];