@nadicodeai/design-system 12.1.88 → 12.1.90

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 (2) hide show
  1. package/DESIGN.md +22 -10
  2. package/package.json +1 -1
package/DESIGN.md CHANGED
@@ -368,7 +368,7 @@ The neutral spine carries grounds, chrome, text and every control: `{colors.ink}
368
368
  - **Text**: `{colors.ink}` for headings and primary text, `{colors.body}` for supporting text, which clears AA on every canvas. `{colors.muted}` is for placeholders and disabled or inactive text only, never for descriptions, labels or help. These roles distinguish purpose, not a guaranteed contrast step: their similar neutrals keep supporting text and placeholders near the Geist reference while both meet our AA text floor.
369
369
  - **Lines**: `{colors.line}` is the one decorative 1 px divider and is deliberately quiet. `{colors.input}` is the boundary of a field or any control whose edge identifies it (an input, a select, a checkbox, a radio), and clears the 3:1 non-text floor. A button is identified by its label, so an outline or secondary button's edge is the `{colors.line}` hairline, never `{colors.input}`. Never darken a decorative line locally to make it act as a control edge.
370
370
  - **Focus** (`{colors.focus-ring}`): a full-opacity outline of `{spacing.focus-outline-width}` at `{spacing.focus-outline-offset}`, the maximum-contrast neutral on each ground, never a box-shadow ring and never a hue.
371
- - **Interaction states** are contrast steps on the spine. Hover takes the `accent` role (`{colors.canvas-soft-2}`) and a selected row the `muted` role (`{colors.canvas-soft}`); a control's own hover is a step inside its family, as `{colors.action-hover}` is. Persistent navigation marks the current destination with `{colors.navigation-selection-bg}` and `{colors.navigation-selection-fg}`, and local tabs mark the current view with the same pair through the `selection` role.
371
+ - **Interaction states** are contrast steps on the spine. Hover takes the `accent` role (`{colors.canvas-soft-2}`) and a selected row the `muted` role (`{colors.canvas-soft}`); a control's own hover is a step inside its family, as `{colors.action-hover}` is. Persistent navigation marks the current destination with `{colors.navigation-selection-bg}` and `{colors.navigation-selection-fg}`, and local tabs mark the current view with the same pair through the `selection` role. A segmented choice, such as the theme switcher's tiles, marks its chosen option with that pair too, and the fill never comes without its foreground: on the `selection` ground, a radio's on-primary label reads white on near-white in light and black on black in dark.
372
372
  - **Scrim** (`{colors.scrim}`): the modal overlay, black in both themes at the `scrim-opacity` material value, never blurred: the page behind steps back and the panel in front keeps its full contrast; an overlay never greys the page.
373
373
 
374
374
  ### Colour as stage
@@ -669,7 +669,7 @@ Every example and consuming surface covers its reachable populated, empty, loadi
669
669
  | [Description](https://vercel.com/geist/description) | Component: `ObjectFacts`, `SettingsFactsSection`, `TableValue`. | [Card](https://ui.shadcn.com/docs/components/base/card) title/description or [Item](https://ui.shadcn.com/docs/components/base/item); semantic description list for key/value facts. | Key/value object facts in a semantic definition list. Static metadata is not a two-column comparison table. Key names the fact; value retains exact identifiers, links or copy action. Unknown uses accessible dash, zero remains zero. Long prose may use a block fact. |
670
670
  | [Destructive Action Modal](https://vercel.com/geist/destructive-action-modal) | Component for ordinary confirmation: `ConfirmDialog`; gap for typed-name confirmation. | [Alert Dialog](https://ui.shadcn.com/docs/components/base/alert-dialog) + [Field](https://ui.shadcn.com/docs/components/base/field) and Input for typed verification. | Name object, irreversible effects and recovery before destructive command. Keep failed mutation open, preserve focus and prevent duplicate commit. Use the [ConfirmDialog owner](../ui/src/components/confirm-dialog.tsx) for ordinary confirmation. A typed-name gate for a high-stakes operation needs a shared extension before a surface promises it. |
671
671
  | [Dots Menu](https://vercel.com/geist/dots-menu) | Component: `ActionMenu` and `DropdownMenuCommand`. | [Dropdown Menu](https://ui.shadcn.com/docs/components/base/dropdown-menu) + named icon Button. | One discoverable overflow trigger for secondary record actions. Name whose actions the [ActionMenu owner](../ui/src/components/action-menu.tsx) opens and supply real menu commands. Keep the target easy to hit and the menu inside the viewport. |
672
- | [Drawer](https://vercel.com/geist/drawer) | Component: low-level `Drawer` family; `FormDrawer` owns substantial right-side form workflows. | [Drawer](https://ui.shadcn.com/docs/components/base/drawer) pattern; keep our Base UI implementation. | Geist uses mobile bottom drawers; do not silently call our right-side form behavior identical. Choose one shared adaptive recipe if parity is adopted. Preserve dirty fields, visible footer actions, contained scroll, dismissal and focus return. Destructive decisions use a blocking confirmation. |
672
+ | [Drawer](https://vercel.com/geist/drawer) | Component: low-level `Drawer` family; `FormDrawer` owns the right-side drawer for a catalog or a setup in steps ([Menus and commands](#menus-and-commands)). | [Drawer](https://ui.shadcn.com/docs/components/base/drawer) pattern; keep our Base UI implementation. | Geist uses mobile bottom drawers; do not silently call our right-side form behavior identical. Choose one shared adaptive recipe if parity is adopted. Preserve dirty fields, visible footer actions, contained scroll, dismissal and focus return. Destructive decisions use a blocking confirmation. |
673
673
  | [Empty State](https://vercel.com/geist/empty-state) | Component: [EmptyState](../ui/src/components/empty-state.tsx), following the [absence contract](#elevation--depth). | [Empty](https://ui.shadcn.com/docs/components/base/empty) + appropriate action. | Absence, unmatched filters and failed fetch are different states. First-use action exists only with permission and a real creation path. Search offers clear/reset; failure offers actual recovery. Put outside an empty table body. Permission/upgrade/cleared variants are not exported and must not be faked as noResults. |
674
674
  | [Entity](https://vercel.com/geist/entity) | Component: `ItemGroup`, `Item`, `ItemMedia`, `ItemContent`, `ItemTitle`, `ItemDescription`, `ItemActions`; domain `CatalogEntry`, `AgentListRow`. | [Item](https://ui.shadcn.com/docs/components/base/item) with media, content and actions. | Descriptive row with identity, secondary detail and action, not sortable comparative columns. Use divided group for peers and one coherent hit target with independent nested controls. Skeleton matches row geometry. Primary direct action may remain visible; secondary commands use overflow. |
675
675
  | [Error](https://vercel.com/geist/error) | Component: `FieldError`, `MessageNotice`, `EmptyState kind="failed"`, `FeedbackState` for existing owned surfaces. | [Field](https://ui.shadcn.com/docs/components/base/field) error or [Alert](https://ui.shadcn.com/docs/components/base/alert) at the relevant scope. | Put field validation by field, action failure by action, failed read where content would be. State what failed, retained work and concrete recovery. Catalog-resolved messages own product wording. Diagnostic identifier only when available; never raw exception or fake error ID. Async failure is announced without stealing useful input. |
@@ -729,7 +729,7 @@ These shared components also follow the same foundations, although Geist does no
729
729
  | `Sidebar`, `DashboardShell`, `DesktopShell`, `PortalSidebarFrame` | Persistent product navigation and workspace chrome. The product owns destinations and active state; the shell owns compact behavior, landmarks and layout. Never add a competing sidebar to a page. |
730
730
  | `NavigationMenu` | A site's grouped navigation links, with genuine destinations and usable keyboard paths. Product object views use shared tabs; commands use a menu. |
731
731
  | `Menubar` | A persistent application command bar with related menus. Use only when the workspace has that command model; do not substitute it for website navigation or a row's actions. |
732
- | `Popover` | A bounded contextual control such as filters or a scope chooser. Name its trigger, keep essential meaning visible outside hover, and restore focus when it closes. A short independently saved record form uses `FormDialog`; a substantial workflow may use `FormDrawer`. |
732
+ | `Popover` | A bounded contextual control such as filters or a scope chooser. Name its trigger, keep essential meaning visible outside hover, and restore focus when it closes. Which form surface a job takes is decided in [Menus and commands](#menus-and-commands). |
733
733
  | `InputOTP` and its group/slot parts | A fixed-length verification code. Keep one logical input with paste and keyboard behavior, a visible label, invalid/retry state and a real resend policy. The product owns length, expiry and submission. |
734
734
  | `Carousel` | A finite horizontal rail where adjacent media or items have a meaningful sequence. Give previous/next controls clear names and boundaries; preserve keyboard access and reduced motion. A sortable record collection uses a table or entity list. |
735
735
  | `ResizablePanelGroup`, `ResizablePanel`, `ResizableHandle` | A workspace with genuinely adjustable panes. Keep keyboard resizing, meaningful minimum sizes, readable content and a compact alternative. The product owns persistence of pane sizes. |
@@ -749,11 +749,12 @@ Choose the owner for the whole task. Keep its slots and state handling together
749
749
  | --- | --- | --- |
750
750
  | Independently saved settings | `ReadingColumn` → `SettingsSection` → `SettingsField`; Portal selects the configuration width and form presentation through `SettingsPage` and its `SettingsSection` adapter. `SettingsForm` and `SettingsSubmitButton` own native form dirty/pending state. `footerHint` and `footer` stay in the recessed strip. | Values, validation, dirty/pending state, local Save, retained input and failure. Header and content share one body plane; the footer has one seam. |
751
751
  | Read-only facts | `SettingsFactsSection` or `ObjectFacts`, with `TableValue` for missing facts. | Label/value pairs, actual timestamps, identifier format, links and permission-aware actions. Unknown remains distinct from zero. |
752
+ | Entity collection | `CollectionPage`: the title's actions, search and sort, then rows that identify themselves (`RecordIdentity` with its `detail`, a status only for the exception, `RecordTime`), the row's command or menu, an action's failure inside its row, the edit inside its row, and its loading, empty and no-match states. | The records, what each one says, its commands as data, its catalogue message when an action fails, and the edit form. Never its own toolbar, table, rows or menus. |
752
753
  | Comparable collection | `PageHeader`/`PageActions`, `CollectionToolbar`, `DataTable` within `TableCard` when framed. | Stable record IDs, columns, visible headings, search/filter/sort, URL state, row commands, pagination and `empty`. Numeric columns align at the trailing edge; totals and paging use their own footer zone. |
753
754
  | Descriptive entity list | `ItemGroup divided` with `ItemMedia`, `ItemContent`, `ItemTitle`, `ItemDescription`, `ItemActions`; domain owners include `AgentListRow` and `CatalogEntry`. | Identity, a short description, categorical facts, one primary task and secondary menu. Long values wrap or truncate predictably; a row never gains a second nested hit target by accident. |
754
755
  | Overview figures | `CardRow` with `KpiCard` or the chosen chart card. | Measurement, unit, comparison period, truthful delta and stable categorical assignment. Related cards align; status colour and series colour retain different meanings. |
755
756
  | Object workspace | `ObjectOverview`, `ObjectIdentity`, `ObjectFacts`, `ObjectSection` and shared tabs. | The actual object, scope, hierarchy, sections, routes and commands. Agent identity retains its orb and the Agent-specific composition. |
756
- | Short create/edit form | `FormDialog` with Field parts; Portal binds it through `ActionDialogForm`. Substantial workflows explicitly select `FormDrawer`. | Submit operation, labels, validation, dirty state, retained input, permissions and dismissal policy. Use the owned scroll body and fixed footer; do not nest another overlay. |
757
+ | Short form: a new record, or one or two values from a command | `FormDialog` with Field parts; Portal binds it through `ActionDialogForm`. A record in a list edits inside its row (Entity collection); a catalog or a setup in steps uses `FormDrawer` ([Menus and commands](#menus-and-commands)). | Submit operation, labels, validation, dirty state, retained input, permissions and dismissal policy. Use the owned scroll body and fixed footer; do not nest another overlay. |
757
758
  | Destructive confirmation | `ConfirmDialog`; the app's confirm-action adapter. | Named target, real consequence, labels, pending state, failure and operation. Typed-name verification is not a supported prop; extend the owner when that capability is needed. |
758
759
  | Global commands or record actions | `CommandDialog` for cross-resource search; `ActionMenu` and `DropdownMenuCommand` for one record. | Real commands, grouping, permissions, disabled reasons and keyboard shortcuts. Choose by scope; keep the destructive group last. |
759
760
  | Absence or failed read | `EmptyState` through `DataTable.empty` or the affected content region; `MessageNotice` for persistent conditions. | First use, nothing yet, no matches or failed read, with the real recovery action. Empty state belongs outside the semantic table body. |
@@ -788,16 +789,27 @@ Keep Geist's hierarchy, control metrics, typography roles, neutral surface zones
788
789
 
789
790
  ### Menus and commands
790
791
 
791
- A record's primary destination is its visible name or a labelled link. Navigation is never hidden in its action menu. Keep the main task visible: Edit can expand a row in place, as in Vercel Domains; Connect belongs beside an available connection. Additional mutations use an end-aligned `ActionMenu`, with destructive commands after a separator. A menu is not required when the row has no secondary mutations. Disabled commands retain an explanation. The three-dot trigger is a `{spacing.control-height}` ghost icon button. Menu rows put the label first and a decorative icon at the trailing edge; a destructive command never becomes the loudest repeated action.
792
+ A record's primary destination is its visible name or a labelled link. Navigation is never hidden in its action menu. Keep the main task visible: Edit opens the record inside its row, as in Vercel Domains; Connect belongs beside an available connection. Additional mutations use an end-aligned `ActionMenu`, with destructive commands after a separator. A menu is not required when the row has no secondary mutations. Disabled commands retain an explanation. The three-dot trigger is a `{spacing.control-height}` ghost icon button. Menu rows put the label first and a decorative icon at the trailing edge; a destructive command never becomes the loudest repeated action.
792
793
 
793
- Choose the surface from the task. Settings use a centred column of independently saved `SettingsSection` fieldsets with labels above bounded controls. A short row action uses `FormDialog`; editing a fact on a detail page stays in place. An invitation can be an inline fieldset above the member directory. A substantial workflow that needs persistent context may opt into `FormDrawer`. Confirmation of a consequence uses `ConfirmDialog`. A dedicated workflow page remains a page. Never select a drawer merely because an action accepts input. These choices follow the live Vercel General settings, Members and Domains pages and the [Geist Modal](https://vercel.com/geist/modal) and [Fieldset](https://vercel.com/geist/fieldset) patterns.
794
+ Choose the surface by where the thing being changed is shown and how big the job is. Each surface has one owner:
795
+
796
+ | The person wants to | Surface | Owner | Example |
797
+ | --- | --- | --- | --- |
798
+ | Change a record shown in a list | Its row opens into the form, with Cancel and Save in the form's footer; the other rows stay where they are | `CollectionPage`'s `editor` with `RowEditForm` | Vercel Domains › Edit; a connected channel's Settings |
799
+ | Change a fact on a record's own page or card | In place: a pencil turns the fact into its field, saved by the card's Save | `AgentProfileCard`; `SettingsSection` on a settings page | An Agent's name and description |
800
+ | Add a record through a few fields, or change one or two values from a command | A centred dialog | `FormDialog`; the Portal's `ActionDialogForm` | Add password, Add MCP server |
801
+ | Choose from a catalog, or set up in several steps with a wait | A drawer at the right edge, the page still behind it | `FormDrawer` with `job="catalog" \| "steps"` | Vercel Domains › Add; Add skill from the Library; Telegram's QR setup |
802
+ | Do a workflow a person could link to | Its own page | The page's composition | Vercel Add New › Project; New Agent |
803
+ | Confirm a consequence | A confirmation | `ConfirmDialog` | Remove, Disconnect |
804
+
805
+ A record already on screen is never edited in a dialog or a drawer, and a drawer is never chosen because an action takes input: `FormDrawer` requires a `job`, `"catalog"` or `"steps"`, and owns its one width, 560 px (the full width on a compact screen), which no caller sets. A settings page is the Configuration composition. These choices follow the live Vercel Domains, Projects and settings pages and the [Geist Modal](https://vercel.com/geist/modal) and [Fieldset](https://vercel.com/geist/fieldset) patterns.
794
806
 
795
807
  Collection search and filters stay immediately above their rows. The title row holds the collection's primary action, unless an inline form already exposes that task. Scope selectors preserve the authorized organization or account. Filters do not compete with primary actions. The account menu identifies the signed-in person and exposes their account settings, theme and language.
796
808
 
797
809
 
798
810
  ### Tables and missing values
799
811
 
800
- A table is native table structure: 40 px rows for comparable facts and 48 px rows for entity collections. Visible headings use 14 px / 20 px at weight 500 in a 36 px row; numeric columns align to the trailing edge with tabular figures. A collection row is one line: the record's identity and at most about five facts, and anything more lives on the record's page. Column headings are visible by default and remain visible when people compare or sort values. A compact entity collection whose cells identify themselves may keep accessible headings visually hidden with `showColumnHeaders={false}`; choose this exception deliberately. A simple descriptive list uses `ItemGroup` and `Item` instead of table semantics. The table inherits its enclosing surface, whose Card owns the outer edge; a visible header and every record except the last end with a quiet 1 px `border` divider. An interactive body row takes the full `accent` fill on hover, on keyboard focus within it and while its menu is open; a passive table does not imply an action on hover; a selected row takes `muted`; headers and footers never highlight. A collection fits its container without sideways scrolling: identity and actions keep their columns, and supporting facts move into a detail row inside the same record before the table gets cramped. The identity column claims up to a third of the table, gives supporting columns more room in a wide comparison, gives it back down to a floor, and holds its name on one line: a long name ends in an ellipsis and is whole in its title, as a dashboard row does. A fact holds one line at its own width; a status sentence in a figure column wraps at word boundaries while the figure keeps its numeric alignment. A column of words, such as a summary or a sentence, holds one line up to a cap of `16rem`, shrinks to a floor of its own in a narrow table, and past the cap ends in an ellipsis, whole in its title, as a long name does. A document's table, such as a legal page's, is read whole instead: its columns take the `wraps` option, so their words wrap and the row grows, and it shows its header row. In the compact layout every cell but the identity wraps between words. Text anywhere in the product breaks between words, and inside a word only when that word alone cannot fit a line; a machine string such as a hash or a key may break at any character. One categorical fact in a row, such as an installation or a partner, is a `Tag`: a 24 px pill with its mark, dashed when the fact states an absence. An app in a row is its brand mark in the 28 px tile.
812
+ A table is native table structure: 40 px rows for comparable facts and 48 px rows for entity collections. Visible headings use 14 px / 20 px at weight 500 in a 36 px row; numeric columns align to the trailing edge with tabular figures. A collection row is one line: the record's identity and at most about five facts, and anything more lives on the record's page. Column headings are visible by default and remain visible when people compare or sort values. A compact entity collection whose cells identify themselves may keep accessible headings visually hidden with `showColumnHeaders={false}`; choose this exception deliberately. `CollectionPage` (`@nadicodeai/ui/components/collection-page`) is the entity collection whole, and it makes that exception by drawing rows that identify themselves: the record's name with one muted line saying what it is or where it comes from (`RecordIdentity`'s `detail`, such as "Company skill · every Agent has it"); a status only when it tells the row apart from the others; a time in its verb's sentence (`RecordTime`: "Updated 3 hours ago", the date after a week, the exact moment in its title); one command that is not destructive as a button and otherwise the row's menu; an action that failed or was refused as its catalogue message inside its own row, with its next step, never a notice under the row; and an edit open inside its row. A screen gives it the records and what each one says, never its own toolbar, table, rows or menus. A simple descriptive list uses `ItemGroup` and `Item` instead of table semantics. The table inherits its enclosing surface, whose Card owns the outer edge; a visible header and every record except the last end with a quiet 1 px `border` divider. An interactive body row takes the full `accent` fill on hover, on keyboard focus within it and while its menu is open; a passive table does not imply an action on hover; a selected row takes `muted`; headers and footers never highlight. A collection fits its container without sideways scrolling: identity and actions keep their columns, and supporting facts move into a detail row inside the same record before the table gets cramped. The identity column claims up to a third of the table, gives supporting columns more room in a wide comparison, gives it back down to a floor, and holds its name on one line: a long name ends in an ellipsis and is whole in its title, as a dashboard row does. A fact holds one line at its own width; a status sentence in a figure column wraps at word boundaries while the figure keeps its numeric alignment. A column of words, such as a summary or a sentence, holds one line up to a cap of `16rem`, shrinks to a floor of its own in a narrow table, and past the cap ends in an ellipsis, whole in its title, as a long name does. A document's table, such as a legal page's, is read whole instead: its columns take the `wraps` option, so their words wrap and the row grows, and it shows its header row. In the compact layout every cell but the identity wraps between words. Text anywhere in the product breaks between words, and inside a word only when that word alone cannot fit a line; a machine string such as a hash or a key may break at any character. One categorical fact in a row, such as an installation or a partner, is a `Tag`: a 24 px pill with its mark, dashed when the fact states an absence. An app in a row is its brand mark in the 28 px tile.
801
813
 
802
814
  An unknown or not-applicable value in a table, a comparison list or a set of facts is a muted `—` with screen-reader text, in the same slot as a present value; zero stays zero. An absent report is not `None`: `None` is only for a complete report that found nothing. A stale value keeps its last reading with a short `Stale` qualifier. Loading, failure, missing permission and actionable setup each keep their own visible state and never turn into a dash. Essential reasons and actions never live only in a hover tooltip.
803
815
 
@@ -817,7 +829,7 @@ The Portal, Nadia and Alveare draw every status with the one `StatusBadge` in `@
817
829
 
818
830
  ### System activity
819
831
 
820
- Who does the work decides how it looks. An Agent's work is that Agent's orb in its state and a sentence saying what it does. The system's own work never takes an orb:
832
+ Who does the work decides how it looks. An Agent's work is that Agent's orb in its state and a sentence saying what it does. The system's own work never takes an orb; inside a conversation there is no system's work, only hers and the person's ("Agent orbs"):
821
833
 
822
834
  | The wait | What shows |
823
835
  | --- | --- |
@@ -850,7 +862,7 @@ An Agent is its orb, in every product; there is no other Agent picture. An orb i
850
862
  - **States.** Idle turns at its form's own pace and breathes. Working and thinking move with their cue, the ribbon around working and three dots above thinking, waiting holds, blocked makes one interrupted effort and stops, and done celebrates once and settles back into idle. A surface that only knows a machine checked in draws idle. No state draws a circle around the orb, and a label names the state wherever the exact state matters.
851
863
  - **Status and ambient.** An orb that stands for an Agent shows its real state. An orb in decorative artwork, such as a sign-in picture, takes ambient motion: its form moves at its own pace with no state pose or cue, and it claims no activity.
852
864
  - **Reduced motion.** Movement stops; a thinking or working orb breathes between full ink and 0.45 opacity so busy still reads as busy, and an ambient orb holds still.
853
- - **In a conversation.** Her states are the conversation's own: the orb in its header follows them, and every mark of her activity in the thread is her own orb in her real state, never another Agent's figure, a spinner, a ticker or a pulse. Her steps and tool calls hold still and say in words what they do or did, with a tool's kind as a decorative icon beside the words and no state of its own; a system wait inside the thread is the waiting line ("System activity"), the outcome of a step or a request is the `StatusBadge`, and a failed turn is the `MessageNotice`. Ruled by the owner on 11 October 2026: the Agent's states are the chat's default states, not random icons.
865
+ - **In a conversation.** Her states are the conversation's own: the orb in its header follows them, and every mark of her activity in the thread is her own orb in her real state, never another Agent's figure, a spinner, a ticker or a pulse. Her steps and tool calls hold still and say in words what they do or did, with a tool's kind as a decorative icon beside the words and no state of its own; the outcome of a step or a request is the `StatusBadge`, and a failed turn is the `MessageNotice`. A conversation has two actors, her and the person, and every wait in it belongs to one of them. Everything she does, including what follows the person's approval or answer, is her orb in its state: working once Run is pressed, thinking once a question is answered, waiting while an approval or a question waits for the person, blocked when a turn fails, done once when she finishes. The person's own action in progress shows on what they made: a file fills as it uploads, the microphone shows it records. A pressed control keeps its place and changes only its word. The waiting line is for the window's own loading, outside the conversation. Ruled by the owner on 11 October 2026: the Agent's states are the chat's default states, not random icons; and on 13 October 2026: the person never meets "the app" in a conversation, only the Agent.
854
866
 
855
867
  Text sits beside an orb, never on it.
856
868
 
@@ -916,7 +928,7 @@ The clear space is one stroke width of the rendered logo on every side. The mini
916
928
  - **Website.** The page grammar is "The website column": full-bleed sections on white, soft and black grounds, alternating, with product views on them. Its cards are outlined; its product views take their real heights.
917
929
  - **Portal.** A product shell on the workspace ground, built from the page compositions and the package components, with `globals.css` giving every elevated surface its tone.
918
930
  - **Nadia.** Nadia draws her own window through Hermes's `window.shell` area, inside Hermes's app, which owns Tailwind and its own surface layering. Nadia's theme paints Hermes's roles with the shared `semantic` roles and core radii, and imports `@nadicodeai/ui/components.css` with the design system's host stylesheet, so the package components render with the same recipes and glass. The window follows the operating system's material where the system composites it. Hermes answers reduced motion by cutting every transition and animation; Nadia's stylesheet gives her own parts, the package overlays, the entry screen and the waiting line, the reduced-motion policy in "Motion" back.
919
- Her conversation is one centred column of `56rem` holding her replies, the person's messages and the chat bar: her reply is plain text across the column, only the person's message is a bubble, on the `raised` step at the column's trailing edge, and the chat bar floats over the messages as the lightest step, in glass. The selected Agent row carries the sidebar's selected fill, as the Agents list draws it.
931
+ Her conversation is one centred column of `56rem` holding her replies, the person's messages and the chat bar: her reply is plain text across the column, only the person's message is a bubble, grey (`{colors.canvas-soft-2}`) at the `raised` height in both modes, at the column's trailing edge, and the chat bar floats over the messages as the lightest step, in glass. The selected Agent row carries the sidebar's selected fill, as the Agents list draws it.
920
932
  - **Alveare.** The desktop keeps Buzz's components and layout, styled through an adapter as Nadia styles Hermes: Buzz's colour roles read the shared `semantic` roles, every text takes a type role, and Buzz's shared components take the package's geometry, states, focus and motion, over the design system's host stylesheet and `@nadicodeai/ui/components.css`.
921
933
 
922
934
  ## Do's and Don'ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nadicodeai/design-system",
3
- "version": "12.1.88",
3
+ "version": "12.1.90",
4
4
  "type": "module",
5
5
  "publishConfig": {
6
6
  "access": "public"