Foundations

Tokens

The --nyte-* custom properties every primitive paints with

Primitives paint with --nyte-* custom properties only. Override one on an ancestor, ideally the app root.

.my-app {
  --nyte-color-primary: #3b5bdb;
}

Import @nyte-ai/ui/styles.css for the tokens plus the Tailwind mapping, or @nyte-ai/ui/platform-tokens.css for the tokens alone.

Colors are light-dark() pairs, so a primitive follows the color-scheme in effect rather than a class. See Theming. --nyte-color-focus-ring defaults to var(--nyte-color-ring) and is the one token a host changes at runtime. See Focus.

Color

Semantic roles, not a palette. primary is the filled button, muted is the hover wash and the avatar background, border has four strengths, and bubble-* and sidebar belong to the conversation surface.

TokenValue
--nyte-color-baselight-dark(#141414, #fcfcfc)
--nyte-color-editorlight-dark(#fcfcfc, #181818)
--nyte-color-chromelight-dark(#eeeeee, #262626)
--nyte-color-sidebarlight-dark(#f7f7f7, #141414)
--nyte-color-raisedlight-dark(#fcfcfc, #2f2f2f)
--nyte-color-filllight-dark(#070707, #fafafa)
--nyte-color-fill-labellight-dark(#fcfcfc, #141414)
--nyte-color-action-label#fcfcfc
--nyte-color-scrim-base#141414
--nyte-color-accent-base#1084fe
--nyte-color-hue-neutral#777777
--nyte-color-hue-red#ff263c
--nyte-color-hue-orange#ff6700
--nyte-color-hue-violet#9159fe
--nyte-color-hue-green#00c972
--nyte-color-accentlight-dark(#0c64c1, #459ffe)
--nyte-color-successlight-dark(#009957, #38d591)
--nyte-color-warninglight-dark(#c27400, #ffaf38)
--nyte-color-destructivelight-dark(#c21d2e, #ff5667)
--nyte-color-avatar-foregroundlight-dark(#3d3d3d, #b7b7b7)
--nyte-color-avatar-orange-foregroundlight-dark(#c24e00, #ff8838)
--nyte-color-avatar-violet-foregroundlight-dark(#6e44c1, #a97efe)
--nyte-color-bubble-userlight-dark(#070707, #5a5a5a)
--nyte-color-backgroundvar(--nyte-color-editor)
--nyte-color-popovervar(--nyte-color-editor)
--nyte-color-field-backgroundvar(--nyte-color-raised)
--nyte-color-bubble-agentvar(--nyte-color-chrome)
--nyte-color-foregroundvar(--nyte-color-base)
--nyte-color-popover-foregroundvar(--nyte-color-base)
--nyte-color-muted-foregroundcolor-mix(in srgb, var(--nyte-color-base) 60%, transparent)
--nyte-color-tertiary-foregroundcolor-mix(in srgb, var(--nyte-color-base) 36%, transparent)
--nyte-color-primaryvar(--nyte-color-fill)
--nyte-color-primary-hovercolor-mix(in srgb, var(--nyte-color-editor) 16%, var(--nyte-color-fill))
--nyte-color-primary-foregroundvar(--nyte-color-fill-label)
--nyte-color-bubble-user-foregroundvar(--nyte-color-action-label)
--nyte-color-secondarylight-dark(color-mix(in srgb, var(--nyte-color-hue-neutral) 4%, transparent), color-mix(in srgb, var(--nyte-color-hue-neutral) 8%, transparent))
--nyte-color-mutedlight-dark(color-mix(in srgb, var(--nyte-color-hue-neutral) 9%, transparent), color-mix(in srgb, var(--nyte-color-hue-neutral) 17%, transparent))
--nyte-color-muted-hoverlight-dark(color-mix(in srgb, var(--nyte-color-hue-neutral) 17%, transparent), color-mix(in srgb, var(--nyte-color-hue-neutral) 32%, transparent))
--nyte-color-destructive-mutedlight-dark(color-mix(in srgb, var(--nyte-color-hue-red) 9%, transparent), color-mix(in srgb, var(--nyte-color-hue-red) 17%, transparent))
--nyte-color-destructive-hoverlight-dark(color-mix(in srgb, var(--nyte-color-hue-red) 17%, transparent), color-mix(in srgb, var(--nyte-color-hue-red) 32%, transparent))
--nyte-color-scrimlight-dark(color-mix(in srgb, var(--nyte-color-scrim-base) 50%, transparent), color-mix(in srgb, var(--nyte-color-scrim-base) 70%, transparent))
--nyte-color-border-subtlecolor-mix(in srgb, var(--nyte-color-base) 4%, transparent)
--nyte-color-border-weakcolor-mix(in srgb, var(--nyte-color-base) 8%, transparent)
--nyte-color-bordercolor-mix(in srgb, var(--nyte-color-base) 12%, transparent)
--nyte-color-border-strongcolor-mix(in srgb, var(--nyte-color-base) 30%, transparent)
--nyte-color-ringcolor-mix(in srgb, var(--nyte-color-base) 40%, transparent)
--nyte-color-focus-ringvar(--nyte-color-ring)
--nyte-color-avatar-backgroundvar(--nyte-color-muted)
--nyte-color-avatar-neutral-solidvar(--nyte-color-hue-neutral)
--nyte-color-avatar-orange-backgroundlight-dark(color-mix(in srgb, var(--nyte-color-hue-orange) 9%, transparent), color-mix(in srgb, var(--nyte-color-hue-orange) 17%, transparent))
--nyte-color-avatar-orange-solidvar(--nyte-color-hue-orange)
--nyte-color-avatar-blue-backgroundlight-dark(color-mix(in srgb, var(--nyte-color-accent-base) 9%, transparent), color-mix(in srgb, var(--nyte-color-accent-base) 17%, transparent))
--nyte-color-avatar-blue-foregroundvar(--nyte-color-accent)
--nyte-color-avatar-blue-solidvar(--nyte-color-accent-base)
--nyte-color-avatar-violet-backgroundlight-dark(color-mix(in srgb, var(--nyte-color-hue-violet) 9%, transparent), color-mix(in srgb, var(--nyte-color-hue-violet) 17%, transparent))
--nyte-color-avatar-violet-solidvar(--nyte-color-hue-violet)
--nyte-color-avatar-green-backgroundlight-dark(color-mix(in srgb, var(--nyte-color-hue-green) 9%, transparent), color-mix(in srgb, var(--nyte-color-hue-green) 17%, transparent))
--nyte-color-avatar-green-foregroundvar(--nyte-color-success)
--nyte-color-avatar-green-solidvar(--nyte-color-hue-green)

Font

One UI family and a five-step scale. label and body share a size and line height, so labels stay aligned with the fields beside them.

TokenValue
--nyte-font-family-ui-apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif
--nyte-font-size-caption11px
--nyte-font-size-detail12px
--nyte-font-size-label13px
--nyte-font-size-body13px
--nyte-font-size-title14px
--nyte-font-weight-regular400
--nyte-font-weight-medium500
--nyte-font-weight-semibold600
TokenValue
--nyte-leading-caption14px
--nyte-leading-detail16px
--nyte-leading-label18px
--nyte-leading-body18px
--nyte-leading-title22px

Radius

avatar is a percentage, so it scales with the size steps. pill is the circle.

TokenValue
--nyte-radius-control8px
--nyte-radius-field8px
--nyte-radius-menu10px
--nyte-radius-dialog14px
--nyte-radius-avatar42%
--nyte-radius-pill9999px

Control

The geometry of anything you press or type into. height-md (28px) is the default button and input height, height-sm (24px) the compact button and the icon button. menu-inset is the left padding that leaves room for a radio or checkbox indicator.

TokenValue
--nyte-control-height-sm24px
--nyte-control-height-md28px
--nyte-control-textarea-min-height64px
--nyte-control-padding-xs6px
--nyte-control-padding-sm8px
--nyte-control-padding-lg12px
--nyte-control-menu-inset28px
--nyte-control-gap-sm4px
--nyte-control-disabled-opacity0.56
--nyte-control-focus-width1px
--nyte-control-focus-offset1px

Border

TokenValue
--nyte-border-control-width1px
--nyte-border-hairline-width.5px

Avatar

TokenValue
--nyte-avatar-size-xs20px
--nyte-avatar-size-sm24px
--nyte-avatar-size-md28px
--nyte-avatar-size-lg36px
--nyte-avatar-font-xs9px
--nyte-avatar-font-sm10px
--nyte-avatar-font-md11px
--nyte-avatar-font-lg14px
--nyte-avatar-ring-width.5px

Space

Three steps. Layout spacing belongs to the app.

TokenValue
--nyte-space-14px
--nyte-space-28px
--nyte-space-416px

Motion

fast for state changes on controls, normal for popups. Every primitive collapses its transition to 0s under prefers-reduced-motion: reduce.

TokenValue
--nyte-motion-fast100ms
--nyte-motion-normal160ms
--nyte-motion-ease-outcubic-bezier(.2,.8,.2,1)

Elevation

TokenValue
--nyte-elevation-field0 1px 3px 0 light-dark(#0000001f, #00000000)
--nyte-elevation-menu0 10px 20px -3px light-dark(#0000001a, #00000000), 0 4px 6px -4px light-dark(#0000001a, #00000000), 0 0 0 1px light-dark(#e4e4e40a, #e4e4e400)
--nyte-elevation-dialog0 22px 70px 4px light-dark(#0000008f, #00000000), 0 0 0 .5px light-dark(#0000001a, #00000000)

Overlay

Sizes and stacking for dialogs and menus. --nyte-menu-max-width and --nyte-menu-max-height read Base UI's --available-width and --available-height, which the Positioner sets from the viewport.

TokenValue
--nyte-dialog-widthcalc(100% - 32px)
--nyte-dialog-max-width384px
--nyte-dialog-max-heightcalc(100dvh - 32px)
TokenValue
--nyte-menu-min-width160px
--nyte-menu-max-widthvar(--available-width)
--nyte-menu-max-heightvar(--available-height)
TokenValue
--nyte-layer-dialog50
--nyte-layer-menu60

Tailwind mapping

@nyte-ai/ui/tailwind.css maps tokens into Tailwind v4's @theme inline, so utilities resolve to the same variables.

Tailwind tokenReads
--font-sans--nyte-font-family-ui
--color-primary--nyte-color-primary
--color-muted--nyte-color-muted
--color-border--nyte-color-border
--color-ring--nyte-color-ring
--text-body--nyte-font-size-body
--text-body--line-height--nyte-leading-body
--radius-sm, --radius-md--nyte-radius-control
--radius-lg--nyte-radius-menu
--radius-xl--nyte-radius-dialog