Adopt the kit with an AI coding agent
Most teams meet this kit through a coding agent. Told only to "use the Novus kit", an agent guesses, and a portal ends up with its own side navigation, its own filter bar and its own idea of what blue means. This page gives the agent the same rules the kit enforces on itself, and gives you prompts to copy.
1. Give your agent the rules once
The package ships an instruction file for each agent, in the format that agent reads. Copy the one you use into your repository and your agent follows these rules in every session, without anyone restating them. Upgrading the package brings the updated rules with it.
| Agent | Copy this file | To here |
|---|---|---|
| Claude Code | novus-design-kit/agents/claude/CLAUDE.md | CLAUDE.md |
| Claude Code reads CLAUDE.md at the project root, or .claude/CLAUDE.md. It also reads AGENTS.md when no CLAUDE.md is present, so use one or the other rather than both. | ||
| GitHub Copilot | novus-design-kit/agents/copilot/copilot-instructions.md | .github/copilot-instructions.md |
| Applies to every request in the repository. | ||
| GitHub Copilot, console screens | novus-design-kit/agents/copilot/novus-design-kit.instructions.md | .github/instructions/novus-design-kit.instructions.md |
| Path-scoped. The applyTo glob limits the console rules to interface files. | ||
| Cursor | novus-design-kit/agents/cursor/novus-design-kit.mdc | .cursor/rules/novus-design-kit.mdc |
| Must keep the .mdc extension: a plain .md file in .cursor/rules is ignored. | ||
| Any AGENTS.md reader | novus-design-kit/agents/AGENTS.md | AGENTS.md |
| The cross-tool convention, read by Codex, Windsurf, Zed, Jules and others. | ||
The files are generated from one source in the kit, so they cannot disagree with each other or with this page. Do not hand edit them: upgrade the package instead, and keep your own project rules in a separate file.
2. Work in this order
- Install and wire in. The package installs from public npm with no registry setup and no token. The theme script belongs in the document head so the theme applies before first paint.
- Convert one screen, not all of them. A single converted screen shows you what the agent understood, while a whole application converted at once is unreviewable.
- Read what came back. Check the screen at 1440px and at 375px, and with JavaScript off if the screen is meant to work without it.
- Then widen. Once one screen is right, the same prompt scales to the rest, and the instruction file keeps later sessions consistent.
3. Prompts to copy
Each prompt names the real files this release ships, so the agent has no reason to invent a path. Paste one as it is.
Adopt the novus-design-kit design kit in this project.
1. Install it from public npm: npm install novus-design-kit
2. Wire it in. Each file has its own place:
- novus-design-kit/tokens.css: import once at the application root, before your own styles.
- novus-design-kit/console.css: import after tokens.css, on console and portal screens only.
- novus-design-kit/js/novus-theme.js: load in the document head, so the theme applies before first paint.
- novus-design-kit/js/novus-console.js: load at the end of the body. It enhances behaviour; every pattern still works when it does not run.
- novus-design-kit/icons/novus-icons.svg: the icon sprite, referenced from markup. Serve it over http, because a browser blocks an external sprite from a file:// page.
The markup for each pattern is in the catalog, not in the package: https://ui-kit.novustech.dev/components/overview.html
3. Convert exactly one screen to the kit, and stop there so I can review it.
4. Tell me which values in that screen had no token, if any.
Follow these rules while you work:
- Take every colour, size, spacing, radius and shadow from a token in tokens.css. If you are about to type a hex colour or a pixel value, there is a var(--...) for it.
- Surfaces are flat and monochrome: no gradients, and colour carries meaning rather than decoration.
- Use a component from the kit's catalog before writing new markup. The package ships the stylesheet, not the markup, so read the pattern's structure in the catalog at https://ui-kit.novustech.dev/components/overview.html rather than guessing it from class names.
- Short content stays on one line. Identifiers, names, chips, dates, amounts, buttons and column headers never wrap to two or three rows, and a table scrolls inside its own card instead of squeezing its columns.
- Do not cap portal text at a reading measure, and do not narrow descriptive text with a margin: a paragraph, a help line or any other descriptive copy spans the full width of its container, with inline margins of zero if any were going to be set. Only text deliberately marked as prose with the measure class takes a reading cap.
- Light is the default theme. Dark comes only from a choice the person made, which persists. Do not follow the operating system unless the app opts in explicitly.
- Header, navigation and body text render at one size. Headings step up by their documented ratio, and never further.
- Every control a person can press measures at least 44px at the 375px baseline, icon-only controls included. A control may look smaller if it carries an expanded hit area that still reaches 44px. Desktop density is a separate decision, so this floor is the phone baseline rather than every width.
- Motion is functional and lasts 0.2s or less, and it is removed under prefers-reduced-motion. The one exception is the slow ambient art on the sign-in panel, which also stops under reduced motion.
- Patterns keep working when JavaScript does not run. Menus, drawers, filter sheets and tabs are built on native elements first, with script only as an enhancement.
- Write plain copy. No em dashes anywhere in published text, and no marketing category jargon for the product. Add descriptive text only when it was asked for: no invented helper line, hint, explanation or tooltip filling a space the instruction left open. If a control needs no explanation, ship it without one.
- When generating a component, add no white space just to make a layout look symmetric: no empty element balancing one side against the other, no padding on one column to match its neighbour. Balance comes from the grid or flex rules the pattern already sets. Every other gap is deliberate too, coming from a spacing token or a container that carries it (.row spaces its children, .field pairs its label and control).
- A field's default edit mode is a real label above the control, the .field pattern. A placeholder is a hint that disappears once someone types, so it never stands in for the label, and an input ships with no placeholder-only field. Keep the placeholder for format examples, like name@novustech.com.sg.
- A field the person cannot edit carries no padlock icon. Say it with the control itself: readonly on an input the person may focus and copy from, disabled on one they cannot, and a .field__help line naming why it is locked, like Set by your administrator. The state stays legible from the styling the control already has, so no new icon joins the label.
Do not restyle anything outside the screen you convert, and do not edit files
inside node_modules.
Rebuild this screen on the novus-design-kit console patterns.
Load novus-design-kit/console.css after novus-design-kit/tokens.css, then rebuild the
screen from the shipped patterns rather than the markup that is there now:
the console shell, the grouped side navigation, the page header with its
breadcrumb and end-aligned actions, the filter bar with its sub-filter sheet and
quick chips, and the list footer with its count and page controls.
Rules that apply everywhere:
- Take every colour, size, spacing, radius and shadow from a token in tokens.css. If you are about to type a hex colour or a pixel value, there is a var(--...) for it.
- Surfaces are flat and monochrome: no gradients, and colour carries meaning rather than decoration.
- Use a component from the kit's catalog before writing new markup. The package ships the stylesheet, not the markup, so read the pattern's structure in the catalog at https://ui-kit.novustech.dev/components/overview.html rather than guessing it from class names.
- Short content stays on one line. Identifiers, names, chips, dates, amounts, buttons and column headers never wrap to two or three rows, and a table scrolls inside its own card instead of squeezing its columns.
- Do not cap portal text at a reading measure, and do not narrow descriptive text with a margin: a paragraph, a help line or any other descriptive copy spans the full width of its container, with inline margins of zero if any were going to be set. Only text deliberately marked as prose with the measure class takes a reading cap.
- Light is the default theme. Dark comes only from a choice the person made, which persists. Do not follow the operating system unless the app opts in explicitly.
- Header, navigation and body text render at one size. Headings step up by their documented ratio, and never further.
- Every control a person can press measures at least 44px at the 375px baseline, icon-only controls included. A control may look smaller if it carries an expanded hit area that still reaches 44px. Desktop density is a separate decision, so this floor is the phone baseline rather than every width.
- Motion is functional and lasts 0.2s or less, and it is removed under prefers-reduced-motion. The one exception is the slow ambient art on the sign-in panel, which also stops under reduced motion.
- Patterns keep working when JavaScript does not run. Menus, drawers, filter sheets and tabs are built on native elements first, with script only as an enhancement.
- Write plain copy. No em dashes anywhere in published text, and no marketing category jargon for the product. Add descriptive text only when it was asked for: no invented helper line, hint, explanation or tooltip filling a space the instruction left open. If a control needs no explanation, ship it without one.
- When generating a component, add no white space just to make a layout look symmetric: no empty element balancing one side against the other, no padding on one column to match its neighbour. Balance comes from the grid or flex rules the pattern already sets. Every other gap is deliberate too, coming from a spacing token or a container that carries it (.row spaces its children, .field pairs its label and control).
- A field's default edit mode is a real label above the control, the .field pattern. A placeholder is a hint that disappears once someone types, so it never stands in for the label, and an input ships with no placeholder-only field. Keep the placeholder for format examples, like name@novustech.com.sg.
- A field the person cannot edit carries no padlock icon. Say it with the control itself: readonly on an input the person may focus and copy from, disabled on one they cannot, and a .field__help line naming why it is locked, like Set by your administrator. The state stays legible from the styling the control already has, so no new icon joins the label.
Rules for console and portal screens:
- Build console screens on the shipped shell: a header carrying the product lockup and an account menu, a grouped side navigation with line icons, and a page header with a breadcrumb and end-aligned actions.
- Pick one of the kit's two console shells rather than inventing a third. The grouped side navigation is the default and suits a console with many or deep top-level areas. The top-navigation bar suits a console with a handful of sections, up to about nine, each holding a short menu. Both use the same header, the same drawer on phones, and one navigation definition.
- The account menu is the last element in a console header. Nothing sits to the right of it, at any width.
- The Novus app switcher, <novus-app-switcher>, is the first control in a console header. Nothing sits to the left of it, and it is the only grid button on the bar.
- Collapsing the side navigation leaves a rail of icons, one per destination, with the current page still marked and each icon carrying its name for assistive technology. Never hide the navigation.
- Sign-in sits on the near-white ground with the ambient line art on the brand panel, single sign-on beside the password form, and no theme toggle on the page.
- A menu, popover or tooltip belonging to a table row renders outside the table's scroll wrap, not inside it. The wrap clips what it contains, so anything that needs to overflow the table has to live beyond it.
- Lists use the filter bar with its sub-filter sheet, active chips and quick chips with counts, and they end with the list footer: a count, page controls, and rows per page.
- Charts read their colours and fonts from the tokens at render time, redraw when the theme changes, and are accompanied by the same numbers as a table so a page without scripting still answers the question.
- Every amount carries its currency and a thousands separator, and the separator is a comma: 1,250,000.00 LKR, 1,250,000.00 USD, 1,250,000.00 EUR. Never bare digits, never a space or a decimal comma where the thousands comma goes, never a rounded abbreviation standing in for a total. Within a product one currency reads one way across every screen, table, chart and export: the ISO code, LKR or USD or EUR, never a local symbol or abbreviation like Rs.
- Buttons sit in a .row, which spaces them and wraps at narrow widths; a lone button gets the same treatment, and a dialog or form foot ends the row with inline justify-content: flex-end. A button carries no margin of its own, so a button never touches another button, a field, a table or any other component, above or below it. Where the container around a row carries no spacing, give the row one.
- Two actions that answer the same moment, like Cancel and Save or Resend and Back to sign in, sit side by side in one .row, never stacked one above the other. One of the pair is .btn--primary, the next step, and the other is .btn--secondary, the fallback; never two secondaries. The secondary keeps its outline, so it still reads as a button beside the filled one. In a dialog or form foot the primary ends the row. Only a row too narrow for both may wrap.
When you are done, list anything in the original screen that has no equivalent
in the kit, instead of inventing a component for it.
Audit this screen against the novus-design-kit rules and report what
breaks them. Change nothing.
Check each of these, and for every failure give me the file, the line, the rule
it breaks, and the smallest fix:
- Take every colour, size, spacing, radius and shadow from a token in tokens.css. If you are about to type a hex colour or a pixel value, there is a var(--...) for it.
- Surfaces are flat and monochrome: no gradients, and colour carries meaning rather than decoration.
- Use a component from the kit's catalog before writing new markup. The package ships the stylesheet, not the markup, so read the pattern's structure in the catalog at https://ui-kit.novustech.dev/components/overview.html rather than guessing it from class names.
- Short content stays on one line. Identifiers, names, chips, dates, amounts, buttons and column headers never wrap to two or three rows, and a table scrolls inside its own card instead of squeezing its columns.
- Do not cap portal text at a reading measure, and do not narrow descriptive text with a margin: a paragraph, a help line or any other descriptive copy spans the full width of its container, with inline margins of zero if any were going to be set. Only text deliberately marked as prose with the measure class takes a reading cap.
- Light is the default theme. Dark comes only from a choice the person made, which persists. Do not follow the operating system unless the app opts in explicitly.
- Header, navigation and body text render at one size. Headings step up by their documented ratio, and never further.
- Every control a person can press measures at least 44px at the 375px baseline, icon-only controls included. A control may look smaller if it carries an expanded hit area that still reaches 44px. Desktop density is a separate decision, so this floor is the phone baseline rather than every width.
- Motion is functional and lasts 0.2s or less, and it is removed under prefers-reduced-motion. The one exception is the slow ambient art on the sign-in panel, which also stops under reduced motion.
- Patterns keep working when JavaScript does not run. Menus, drawers, filter sheets and tabs are built on native elements first, with script only as an enhancement.
- Write plain copy. No em dashes anywhere in published text, and no marketing category jargon for the product. Add descriptive text only when it was asked for: no invented helper line, hint, explanation or tooltip filling a space the instruction left open. If a control needs no explanation, ship it without one.
- When generating a component, add no white space just to make a layout look symmetric: no empty element balancing one side against the other, no padding on one column to match its neighbour. Balance comes from the grid or flex rules the pattern already sets. Every other gap is deliberate too, coming from a spacing token or a container that carries it (.row spaces its children, .field pairs its label and control).
- A field's default edit mode is a real label above the control, the .field pattern. A placeholder is a hint that disappears once someone types, so it never stands in for the label, and an input ships with no placeholder-only field. Keep the placeholder for format examples, like name@novustech.com.sg.
- A field the person cannot edit carries no padlock icon. Say it with the control itself: readonly on an input the person may focus and copy from, disabled on one they cannot, and a .field__help line naming why it is locked, like Set by your administrator. The state stays legible from the styling the control already has, so no new icon joins the label.
If the screen is a console or portal screen, also check:
- Build console screens on the shipped shell: a header carrying the product lockup and an account menu, a grouped side navigation with line icons, and a page header with a breadcrumb and end-aligned actions.
- Pick one of the kit's two console shells rather than inventing a third. The grouped side navigation is the default and suits a console with many or deep top-level areas. The top-navigation bar suits a console with a handful of sections, up to about nine, each holding a short menu. Both use the same header, the same drawer on phones, and one navigation definition.
- The account menu is the last element in a console header. Nothing sits to the right of it, at any width.
- The Novus app switcher, <novus-app-switcher>, is the first control in a console header. Nothing sits to the left of it, and it is the only grid button on the bar.
- Collapsing the side navigation leaves a rail of icons, one per destination, with the current page still marked and each icon carrying its name for assistive technology. Never hide the navigation.
- Sign-in sits on the near-white ground with the ambient line art on the brand panel, single sign-on beside the password form, and no theme toggle on the page.
- A menu, popover or tooltip belonging to a table row renders outside the table's scroll wrap, not inside it. The wrap clips what it contains, so anything that needs to overflow the table has to live beyond it.
- Lists use the filter bar with its sub-filter sheet, active chips and quick chips with counts, and they end with the list footer: a count, page controls, and rows per page.
- Charts read their colours and fonts from the tokens at render time, redraw when the theme changes, and are accompanied by the same numbers as a table so a page without scripting still answers the question.
- Every amount carries its currency and a thousands separator, and the separator is a comma: 1,250,000.00 LKR, 1,250,000.00 USD, 1,250,000.00 EUR. Never bare digits, never a space or a decimal comma where the thousands comma goes, never a rounded abbreviation standing in for a total. Within a product one currency reads one way across every screen, table, chart and export: the ISO code, LKR or USD or EUR, never a local symbol or abbreviation like Rs.
- Buttons sit in a .row, which spaces them and wraps at narrow widths; a lone button gets the same treatment, and a dialog or form foot ends the row with inline justify-content: flex-end. A button carries no margin of its own, so a button never touches another button, a field, a table or any other component, above or below it. Where the container around a row carries no spacing, give the row one.
- Two actions that answer the same moment, like Cancel and Save or Resend and Back to sign in, sit side by side in one .row, never stacked one above the other. One of the pair is .btn--primary, the next step, and the other is .btn--secondary, the fallback; never two secondaries. The secondary keeps its outline, so it still reads as a button beside the filled one. In a dialog or form foot the primary ends the row. Only a row too narrow for both may wrap.
Check the rendered result at 1440px and at 375px, not just the source. Report
findings in severity order, worst first, and say plainly if you found nothing.
The rules themselves
This is what the instruction files contain, and what the prompts carry. Each rule says what breaks without it and where the kit checks it, so an agent can weigh a rule rather than following it blindly.
Rules that always apply
- Take every colour, size, spacing, radius and shadow from a token in tokens.css. If you are about to type a hex colour or a pixel value, there is a var(--...) for it.
Why: hardcoded values stop tracking the kit at the next upgrade. Checked by: release gates 2 and 5, the hex and radius audits. - Surfaces are flat and monochrome: no gradients, and colour carries meaning rather than decoration.
Why: the kit is a near-flat enterprise system, and decorative colour makes status colour meaningless. Checked by: release gate 1. - Use a component from the kit's catalog before writing new markup. The package ships the stylesheet, not the markup, so read the pattern's structure in the catalog at https://ui-kit.novustech.dev/components/overview.html rather than guessing it from class names.
Why: re-implemented components miss the accessibility, dark mode and responsive behaviour the originals carry. Checked by: the component catalog at https://ui-kit.novustech.dev/components/overview.html, which carries the markup for each pattern. - Short content stays on one line. Identifiers, names, chips, dates, amounts, buttons and column headers never wrap to two or three rows, and a table scrolls inside its own card instead of squeezing its columns.
Why: wrapped identifiers and squeezed tables are the defect this kit was corrected twice to prevent. Checked by: release gate 11, the layout audit at 1440px and 375px. - Do not cap portal text at a reading measure, and do not narrow descriptive text with a margin: a paragraph, a help line or any other descriptive copy spans the full width of its container, with inline margins of zero if any were going to be set. Only text deliberately marked as prose with the measure class takes a reading cap.
Why: a reading cap, or a margin narrowing the copy, leaves text wrapping into three lines beside empty space. Checked by: release gate 14. - Light is the default theme. Dark comes only from a choice the person made, which persists. Do not follow the operating system unless the app opts in explicitly.
Why: portals were flipping to dark on first visit for anyone with a dark operating system. Checked by: js/novus-theme.js, which applies the default before first paint. - Header, navigation and body text render at one size. Headings step up by their documented ratio, and never further.
Why: a navigation smaller than the content it sits beside reads as a different product. Checked by: release gate 13. - Every control a person can press measures at least 44px at the 375px baseline, icon-only controls included. A control may look smaller if it carries an expanded hit area that still reaches 44px. Desktop density is a separate decision, so this floor is the phone baseline rather than every width.
Why: anything smaller fails on a phone and for anyone with imprecise pointing, and this rule went unenforced long enough for the kit's own screens to drift under it. Checked by: release gate 19, the layout audit's TARGET check at 375px, which measures the hit area rather than the box. - Motion is functional and lasts 0.2s or less, and it is removed under prefers-reduced-motion. The one exception is the slow ambient art on the sign-in panel, which also stops under reduced motion.
Why: decorative motion in a console gets in the way of work. Checked by: the constitution's motion rule and the reduced-motion verification runs. - Patterns keep working when JavaScript does not run. Menus, drawers, filter sheets and tabs are built on native elements first, with script only as an enhancement.
Why: a console that needs script to open its own menu fails in the environments enterprises actually run. Checked by: the JavaScript-off verification runs recorded for every Admin Kit flavor. - Write plain copy. No em dashes anywhere in published text, and no marketing category jargon for the product. Add descriptive text only when it was asked for: no invented helper line, hint, explanation or tooltip filling a space the instruction left open. If a control needs no explanation, ship it without one.
Why: the kit's copy style is checked mechanically and a stray character fails the release, and copy nobody asked for is a maintenance cost nobody agreed to. Checked by: release gates 6 and 8, the copy audits. - When generating a component, add no white space just to make a layout look symmetric: no empty element balancing one side against the other, no padding on one column to match its neighbour. Balance comes from the grid or flex rules the pattern already sets. Every other gap is deliberate too, coming from a spacing token or a container that carries it (.row spaces its children, .field pairs its label and control).
Why: space invented to look balanced is invisible to the next change, so it drifts the moment one side moves and it never had a token behind it. Checked by: the spacing tokens in tokens.css and the container patterns in the catalog. - A field's default edit mode is a real label above the control, the .field pattern. A placeholder is a hint that disappears once someone types, so it never stands in for the label, and an input ships with no placeholder-only field. Keep the placeholder for format examples, like name@novustech.com.sg.
Why: a placeholder standing in for the label is gone the moment the field is filled, so the person cannot check what they typed. Checked by: the .field pattern in the catalog, and the field and input component docs. - A field the person cannot edit carries no padlock icon. Say it with the control itself: readonly on an input the person may focus and copy from, disabled on one they cannot, and a .field__help line naming why it is locked, like Set by your administrator. The state stays legible from the styling the control already has, so no new icon joins the label.
Why: a padlock in a field is decoration that competes with the control, and it disappears from the accessibility tree, so the state it describes is left to colour alone. Checked by: the form field pattern in tokens.css, whose disabled and readonly rules mute the surface and text, and which needs no extra element.
Rules for console and portal screens
These apply to admin consoles, dashboards and portals. They do not apply to a marketing page, which is why the path-scoped formats limit them.
- Build console screens on the shipped shell: a header carrying the product lockup and an account menu, a grouped side navigation with line icons, and a page header with a breadcrumb and end-aligned actions.
Why: every screen assembled by hand drifts from the rest of the portal. Checked by: console.css and the Admin Kit reference applications. - Pick one of the kit's two console shells rather than inventing a third. The grouped side navigation is the default and suits a console with many or deep top-level areas. The top-navigation bar suits a console with a handful of sections, up to about nine, each holding a short menu. Both use the same header, the same drawer on phones, and one navigation definition.
Why: a third shell is a divergence nobody else can inherit, and the two shipped ones already cover the shapes an enterprise console takes. Checked by: the shell guidance on the Admin Kit page, and release gates 16 and 20 for the two shells. - The account menu is the last element in a console header. Nothing sits to the right of it, at any width.
Why: operators look to the far right for their own account, and anything past it is noise. Checked by: release gate 12. - The Novus app switcher, <novus-app-switcher>, is the first control in a console header. Nothing sits to the left of it, and it is the only grid button on the bar.
Why: an operator moving between Novus apps finds the switcher in one place, and two grid buttons on one bar is the confusion it replaces. Checked by: the layout audit's HEADER check. - Collapsing the side navigation leaves a rail of icons, one per destination, with the current page still marked and each icon carrying its name for assistive technology. Never hide the navigation.
Why: hiding it strands the operator with no way to move until they reopen the menu. Checked by: release gate 16. - Sign-in sits on the near-white ground with the ambient line art on the brand panel, single sign-on beside the password form, and no theme toggle on the page.
Why: authentication is the first screen anyone sees, and it now follows the same neutral ground as everything else. Checked by: release gate 17. - A menu, popover or tooltip belonging to a table row renders outside the table's scroll wrap, not inside it. The wrap clips what it contains, so anything that needs to overflow the table has to live beyond it.
Why: the wrap is a containing block, so a popover inside it is clipped instead of floating over the page. Checked by: the table pattern in the catalog at https://ui-kit.novustech.dev/components/table.html. - Lists use the filter bar with its sub-filter sheet, active chips and quick chips with counts, and they end with the list footer: a count, page controls, and rows per page.
Why: hand-built filter bars were the specific complaint that produced this pattern. Checked by: console.css and the Admin Kit reference applications. - Charts read their colours and fonts from the tokens at render time, redraw when the theme changes, and are accompanied by the same numbers as a table so a page without scripting still answers the question.
Why: a chart with baked-in colours goes wrong the moment the theme flips. Checked by: the charts pattern documented in the catalog. - Every amount carries its currency and a thousands separator, and the separator is a comma: 1,250,000.00 LKR, 1,250,000.00 USD, 1,250,000.00 EUR. Never bare digits, never a space or a decimal comma where the thousands comma goes, never a rounded abbreviation standing in for a total. Within a product one currency reads one way across every screen, table, chart and export: the ISO code, LKR or USD or EUR, never a local symbol or abbreviation like Rs.
Why: an amount without its currency is a number rather than a price, and Rs beside LKR on neighbouring screens leaves the reader working out whether they are the same money. Checked by: console.css and the Admin Kit reference applications. - Buttons sit in a .row, which spaces them and wraps at narrow widths; a lone button gets the same treatment, and a dialog or form foot ends the row with inline justify-content: flex-end. A button carries no margin of its own, so a button never touches another button, a field, a table or any other component, above or below it. Where the container around a row carries no spacing, give the row one.
Why: buttons placed as bare siblings have no spacing of their own, so they touch, and the pair reads as one broken control rather than two choices. Checked by: the .row utility in tokens.css, and the spacing of the container around it. - Two actions that answer the same moment, like Cancel and Save or Resend and Back to sign in, sit side by side in one .row, never stacked one above the other. One of the pair is .btn--primary, the next step, and the other is .btn--secondary, the fallback; never two secondaries. The secondary keeps its outline, so it still reads as a button beside the filled one. In a dialog or form foot the primary ends the row. Only a row too narrow for both may wrap.
Why: stacked actions read as a list of unrelated links, and two secondaries leave the person to guess which one moves them forward. Checked by: the .row utility and the .btn--primary and .btn--secondary variants in tokens.css, and the Button component docs.
Check a screen the way the kit checks itself
The rules tell an agent to confirm a screen at 1440px and at 375px. That is only fair if the check is available, so the kit ships the same audit it runs on its own pages. Point it at a built directory:
node node_modules/novus-design-kit/scripts/layout-audit.mjs --target dist
It renders every page at both widths in headless Chromium and reports short
content that wrapped, pages that scroll sideways on a phone, controls under the
44px floor, and the console rules for headers, navigation and sign-in. It needs
playwright-core and a Chromium; without them it says so and exits
rather than pretending to pass.
An agent that cannot render a page should say that plainly instead of reporting a check it did not run.
If the result looks wrong
- Hardcoded values crept in. Ask for a diff of every colour and size the agent introduced, then ask which token covers each one.
- New markup instead of kit components. Point the agent at the component catalog and ask it to name the component it replaced.
- Short content wrapping to two rows. That is the defect this kit was corrected twice to prevent. Ask for the audit prompt above, at both widths.
- Console screens missing the shell. The Admin Kit is the reference: four flavors, all generated from one pattern layer.