SchOS/docs/niveus/REFERENCE.md
Nexoniarz 6490e5c759 site: rebuilt on Niveus, and the palette stops being a copy
Niveus is the interface language the project uses from here on -- this site
first, applications after it. Rebuilding the site on it is what proves the
system is one, rather than a folder of CSS with a README.

**`style.css` is gone.** 21 KB that transcribed include/theme.h by hand:
palette, type scale, shadows, spacing, every component. The intent was right --
"a site describing an operating system should look like the operating system"
-- and the mechanism was a copy, which means two files that have to be kept in
step by remembering to. What replaced it is `app.css`, which is layout and
nothing else, and one declaration in each page:

    :root { --nv-brand: #7C5CFF; }

That is SCH_ACCENT. Niveus derives the accent and its states, the link colour,
the focus ring, the tint in the greys and how far the status colours lean, for
light and dark both. One number to keep true instead of forty.

**The site is now adaptive.** Dark by default, because the OS is dark, with a
Light/Dark/Auto group in the bar that is real. The choice is kept in
localStorage and re-applied by an inline script before first paint, so the page
never renders in one appearance and corrects itself while you watch.

**PSOGM keeps its one purple, and now says so structurally.** #4B1D9A is
spelled the way Niveus spells a subtree with its own colour -- `data-nv-brand`
with its own `--nv-brand` on that section -- so every role inside re-derives
from it rather than being painted on. Still exactly one place, which is what
branding/README.md asks for.

Content is unchanged; what changed is what it is made of. Cards are `.nv-card`,
tags are `.nv-badge`, the support table is `.nv-table`, the crash section is a
`.nv-bed`, and the docs reader's two rails are `.nv-nav--vertical` with the
current document marked by `aria-current` rather than a class of our own.
`docs.js` emits `.nv-table` and `.nv-code`, so a change to the system reaches
the documentation too.

Three things were found by looking at it in a browser rather than by reading
it, and all three are the same mistake: **a `.nv-card` carries no padding of
its own -- its parts do.** The stat tiles, the "One ISO, one stick" band and
the card headers were all built from bare children, so numbers ran to the card
edge, the USB mark hung off it, and a title and its badge sat at opposite ends
of a row meant for a title and a trailing slot. Where the component had a right
way to say it, the markup now says it that way; where it did not -- a tile has
no parts -- `app.css` supplies the padding and says why.

Checked: every nv- class used across the three pages and docs.js exists in the
CSS, every token referenced by app.css is defined, and app.css contains no hex
value at all. Niveus's own tools/check.py passes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-23 14:40:09 +02:00

19 KiB

Niveus — reference

Every class, token, attribute and function the system exposes, with the name the rest of the industry uses for it.

Two audiences:

  • People. Find the thing you mean by its usual name, then use the class beside it.
  • Models. This file is the whole API. Hand it over on its own and an assistant can build correct Niveus markup without seeing the CSS: it does not need to know how .nv-nav-tabs works, only that a tab list is spelled that way here. Nothing below is aspirational — tools/check.py fails if a class exists in the CSS and is missing from this file.

Everything ships inside the niveus cascade layer, so unlayered application styles win without !important.

<link rel="stylesheet" href="dist/niveus.css">
<script src="niveus/niveus.js" defer></script>   <!-- optional -->
<html data-theme="dark">                          <!-- omit to follow the OS -->
<style>:root { --nv-brand: #d92e3f; }</style>     <!-- the whole identity -->

Button

Class Known as Does
.nv-button button, secondary button Raised surface. The default; use it for anything that is not the action.
.nv-button--primary filled / CTA button The single affirmative action in a view.
.nv-button--subtle tonal button Accent-tinted fill, no elevation. Mid-emphasis.
.nv-button--ghost text / quiet button No material until hovered. Lowest emphasis.
.nv-button--danger destructive button Irreversible actions only.
.nv-button--frosted glass button For use over imagery or frosted chrome.
.nv-button--float FAB, overlay control Floats over content: grows on hover instead of lifting, and keeps its own positioning via --nv-button-offset.
.nv-button--sm .nv-button--lg size variants 28px and 44px; default is 36px.
.nv-button--icon icon button Square. Requires aria-label.
.nv-button--pill pill button Fully rounded.
.nv-button--block full-width button Fills its container.
.nv-button__icon button icon slot Sizes an inline SVG to the label.
.nv-button-group segmented control, button group Buttons sharing edges; only outer corners round.

States come from the element: disabled, aria-disabled, aria-busy="true" (shows a spinner and keeps the width), aria-pressed for toggles.

Form controls

Class Known as Does
.nv-field form field, form group Label + control + hint, correctly spaced.
.nv-field__label field label Add data-optional="(optional)" to append a muted suffix.
.nv-field__hint helper text Guidance below the control.
.nv-field__error validation message Pair with aria-invalid="true" + aria-describedby.
.nv-input text field, form control input, textarea and select. Inset material.
.nv-input--sm .nv-input--lg size variants Match the button sizes.
.nv-input--color color well / swatch input input[type=color] as a square swatch.
.nv-input-group input with adornment Wrapper for a field with a prefix or suffix.
.nv-input-group__affix prefix / suffix adornment Sits inside the field's recess. First child = leading, last = trailing.
.nv-select select, dropdown Wrapper that draws the chevron around a native select.nv-input.
.nv-checkbox checkbox Native input, custom mark. Supports :indeterminate.
.nv-radio radio button Native input, custom mark.
.nv-switch toggle switch Inset track, elevated thumb that travels.
.nv-choice control with inline label <label> wrapping a control and its text.

Card

Class Known as Does
.nv-card card, panel Resting container at elevation 1.
.nv-card--elevated raised card Elevation 2 — read before its surroundings.
.nv-card--floating floating card Elevation 3.
.nv-card--inset well, sunken panel Recessed into its parent.
.nv-card--frosted glass card Translucent, for use over imagery or a bed.
.nv-card--interactive clickable card Lifts on hover, sinks on press.
.nv-card--flush edge-to-edge card Removes part padding, for media or tables.
.nv-card__header card header
.nv-card__title card title
.nv-card__subtitle card subtitle, supporting text
.nv-card__body card content
.nv-card__footer card actions
.nv-card__footer--plain undivided card actions Drops the divider above the footer.
.nv-card__media card media 16:9 image slot.
.nv-card__link stretched link Expands one link's hit area over the whole card.
.nv-card-grid responsive card grid Auto-fitting, equal-height columns.

Dialog

Built on native <dialog>; open with showModal() or nv.openDialog().

Class Known as Does
.nv-dialog modal dialog Elevation 4 over a blurred scrim. Focus trap and Escape are the platform's.
.nv-dialog--sheet bottom sheet Enters from the block end, flush to the edges.
.nv-dialog--compact .nv-dialog--wide width variants 24rem / 44rem; default 30rem.
.nv-dialog__header dialog header
.nv-dialog__title dialog title Point aria-labelledby at it.
.nv-dialog__description dialog supporting text
.nv-dialog__body dialog content The only scrolling region.
.nv-dialog__footer dialog actions
.nv-dialog__footer--divided grounded dialog actions For a footer sitting over scrollable content.
.nv-dialog__close close button Optical alignment for a ghost icon button.

Menu

Built on the popover attribute and anchor positioning. Trigger and menu name the same anchor through --nv-anchor.

Class Known as Does
.nv-menu dropdown menu, popover menu Frosted surface anchored to its trigger.
.nv-menu-trigger menu button Sets anchor-name from --nv-anchor.
.nv-menu__item menu item aria-checked="true" draws a tick.
.nv-menu__item--danger destructive menu item
.nv-menu__label menu section label / group heading
.nv-menu__separator menu divider
.nv-menu__shortcut keyboard shortcut hint, accelerator Trailing muted text.

Navigation

Class Known as Does
.nv-nav app bar, navigation bar, header Frosted, sticky chrome.
.nv-nav--vertical sidebar, side navigation Full-height, solid; drops the translucency.
.nv-nav--plain solid bar Opaque instead of frosted.
.nv-nav--static non-sticky bar
.nv-nav--inline inline nav group A navigation used inside content, not as chrome.
.nv-nav__brand brand / logo lockup
.nv-nav__list nav list
.nv-nav__item nav item, nav link Selected via aria-current, aria-selected or --active.
.nv-nav__item--active active nav item For when no ARIA state fits.
.nv-nav__section nav section heading
.nv-nav__icon nav icon slot
.nv-nav__badge count badge, notification badge
.nv-nav__spacer flexible spacer Pushes what follows to the end.
.nv-nav-tabs tab list, segmented tabs Inset track; the selected tab lifts out of it.
.nv-tab-panel tab panel Carries the shared content name so panels cross-fade.
.nv-breadcrumbs breadcrumbs

Disclosure

Class Known as Does
.nv-disclosure disclosure, accordion item A <details> whose height animates open and closed.
.nv-disclosure--plain bare disclosure No surface of its own.
.nv-disclosure__summary disclosure trigger The <summary>.
.nv-disclosure__chevron chevron, caret Rotates rather than swapping glyphs.
.nv-disclosure__body disclosure content
.nv-disclosure-group accordion Stacked disclosures sharing hairlines.
.nv-collapse collapsible region Same relationship for markup that cannot be a <details>. Toggle data-open.

Scroller

Class Known as Does
.nv-scroller-frame carousel frame Positions the controls; holds the track.
.nv-scroller carousel, snap scroller, rail Horizontal row with scroll snapping and fading edges.
.nv-scroller--auto content-width items Items size to content instead of the track.

Set --nv-scroller-item for item width, --nv-scroller-fade for the edge fade.

Badge

Class Known as Does
.nv-badge badge, chip, tag, status pill Non-interactive statement of state.
.nv-badge--accent accent badge
.nv-badge--success .nv-badge--warning .nv-badge--danger status badges Tone follows the semantic role.
.nv-badge--solid filled badge For the one badge that must be seen first.
.nv-badge--count count badge Tabular, borderless, min two digits.
.nv-badge--square square badge
.nv-badge__dot status dot

Table

Class Known as Does
.nv-table-frame table wrapper Scrolls sideways so the page does not have to.
.nv-table data table
.nv-table--compact dense table
.nv-table--interactive clickable rows
.nv-table__number numeric cell End-aligned, tabular figures.
.nv-table__actions row actions cell Shrinks to content.

Bed

Class Known as Does
.nv-bed showcase surface, patterned backdrop Ground that is visibly not ordinary background: for regions the user should look at. Gives translucent materials something to be translucent against.
.nv-bed--quiet subdued bed No hatch, softer blooms.
.nv-bed--vivid emphatic bed
.nv-bed--single single-hue bed One color instead of three.
.nv-bed--flush full-bleed bed Square, no side borders.
.nv-bed__label bed label, eyebrow

Set --nv-bed-tint to lead with a color other than the accent.

Surface, material and elevation

Class Known as Does
.nv-surface surface, panel Plain container on the solid material.
.nv-material-solid opaque surface Content lives here. The default.
.nv-material-elevated raised surface Separated from its context.
.nv-material-inset recessed surface Fields, wells, tracks.
.nv-material-frosted frosted glass, blur backdrop Chrome that content passes under.
.nv-material-glass glass Contextual layers where content behind must stay legible.
.nv-elevation-0 .nv-elevation-1 .nv-elevation-2 elevation / z-depth flush · resting · raised
.nv-elevation-3 .nv-elevation-4 .nv-elevation-5 elevation / z-depth floating · lifted · overlay
.nv-elevation-inset-sm .nv-elevation-inset-md .nv-elevation-inset-lg inner shadow Recessed surfaces.
.nv-divider divider, separator, rule
.nv-divider--vertical column rule Stretches to its flex row.

Material and elevation are independent: combine freely.

Type roles

Class Known as Size
.nv-display display, hero text 38px
.nv-heading heading 24px
.nv-title title, subheading 17px
.nv-body body copy 15px
.nv-label label, UI text 13px
.nv-caption caption, secondary text 12px
.nv-overline overline, eyebrow, kicker 12px uppercase
.nv-code code, monospace 13px
.nv-text-primary .nv-text-secondary .nv-text-tertiary text color roles Emphasis, not size.
.nv-text-accent .nv-text-success .nv-text-warning .nv-text-danger semantic text colors

Layout utilities

Class Known as Does
.nv-container page container, wrapper Max width + gutters.
.nv-stack stack, vertical rhythm Column with a gap.
.nv-stack--tight .nv-stack--loose stack density
.nv-cluster cluster, wrap row Wrapping row, vertically centred.
.nv-cluster--tight dense cluster
.nv-cluster--between spread cluster Pushes children to both ends.
.nv-truncate ellipsis, text truncation One line with an ellipsis.
.nv-prose prose, measure Readable line length and leading.
.nv-visually-hidden screen-reader-only, sr-only Available to assistive tech, invisible on screen.
.nv-continuous cross-fading region Content that should cross-fade in place when it changes.
.nv-carried (view-transition class) Applied to nav items so they ride above a travelling marker.
.nv-travelling (view-transition class) Applied to a selection marker so it travels below the labels.

Tokens

Names are stable; values are not. Never state a color, shadow, radius, size or duration directly — reference the token.

Color roles

--nv-color- +

background  background-subtle  surface  surface-elevated  surface-inset
surface-hover  surface-active  scrim

text-primary  text-secondary  text-tertiary  text-disabled  text-inverted
border-subtle  border  border-strong

accent  accent-hover  accent-active  accent-subtle  accent-subtle-hover
accent-border  accent-text  on-accent

success  success-hover  success-subtle  success-border  success-text  on-success
warning  warning-hover  warning-subtle  warning-border  warning-text  on-warning
danger   danger-hover  danger-active  danger-subtle  danger-border
danger-text  on-danger

shadow-ambient  shadow-penumbra  shadow-umbra  shadow-inset
highlight  highlight-strong  elevation-tint-1 … -5
material-frosted  material-glass  material-border
focus-ring  focus-ring-contrast  selection

on-* is the text that goes on top of that color, and is derived — never set it by hand.

Color inputs

Token Default Does
--nv-brand #4f6cff The one color everything derives from.
--nv-brand-tint 4% How much brand bleeds into the greys.
--nv-brand-harmony 12% How far status colors lean towards the brand.
--nv-contrast-pivot 0.7 Lightness where a color can no longer carry a label.
--nv-contrast-dark / -light 0.53 / 0.78 How far either side a color is pushed.

--nv-palette-{neutral|accent|success|warning|danger}-{0…1000} are raw values. Components must never reference them.

Scales

Family Steps
--nv-space- 0 px 0-5 1 1-5 2 2-5 3 4 5 6 7 8 10 12 14 16 20 24 32 (suffix = px ÷ 4)
--nv-radius- none xs sm md lg xl 2xl full, plus nested-md nested-lg
--nv-font-size- 2xs xs sm md lg xl 2xl 3xl 4xl 5xl
--nv-font-weight- regular medium semibold bold
--nv-line-height- tight snug normal relaxed
--nv-letter-spacing- tighter tight normal wide wider
--nv-font- display heading title body label caption code (composite shorthands)
--nv-font-family- sans mono
--nv-measure -narrow · --nv-measure · -wide
--nv-control-height- sm md lg — also control-padding- and control-gap-
--nv-elevation- 0 1 2 3 4 5, inset-sm inset-md inset-lg
--nv-highlight- top top-strong edge
--nv-blur- sm md lg xl — also backdrop-frosted backdrop-glass backdrop-scrim
--nv-material- {solid,elevated,inset,frosted,glass}-{bg,border,shadow}

Motion

Family Steps
--nv-duration- instant fast quick normal slow slower travel expand theme
--nv-ease- standard entrance exit spring emphasized linear
--nv-transition- colors depth control surface expand (composites)
displacement --nv-lift-hover --nv-press-depth --nv-travel-sm/md/lg

prefers-reduced-motion collapses every duration and displacement at the token level. Components never opt in individually.

Other

--nv-focus-ring · --nv-focus-ring-width · --nv-border-width · --nv-border-width-strong · --nv-target-min · --nv-layout-gutter · --nv-layout-max-width · --nv-selection-name · --nv-anchor · --nv-button-offset · --nv-bed-tint · --nv-scroller-item · --nv-scroller-fade · --nv-content-name


JavaScript

niveus.js is optional and dependency-free; it exposes window.nv. Without it everything still renders — state changes simply arrive instead of travelling.

Function Signature Does
nv.transition (update, { direction, kind }) => Promise Runs update inside a view transition so the change can be followed. direction is "forward"/"backward"; kind: "theme" slows the cross-fade. Falls back to running update directly under reduced motion or without API support.
nv.setTheme ("light" | "dark" | "system") => Promise Cross-fades the whole surface into the new appearance and fires nv:theme on <html>.
nv.syncThemeControls (theme) => void Sets aria-pressed on every [data-nv-theme].
nv.openDialog (dialog | id, trigger?) => dialog showModal(), plus a transform origin so the dialog expands out of its trigger.
nv.selectTab (tablist, tab) => Promise Moves selection and its panel, with direction.
nv.initScroller (frame) => void Wires one scroller's controls.
nv.liftLabels (scope) => void Names navigation items so a travelling marker passes behind them.
nv.wire (scope = document) => void Applies all of the below. Runs once on load; call again after injecting markup.
nv.prefersReducedMotion () => boolean

Data attributes

Attribute On Does
data-theme <html> light / dark. Absent follows the OS.
data-nv-brand any element Re-derives the whole color set for that subtree.
data-nv-theme button Sets the appearance when clicked.
data-nv-dialog button Opens the dialog with that id, from itself.
data-nv-close button Closes its dialog or popover.
data-nv-tabs tablist Wires [role=tab] children to their aria-controls panels, with arrow keys.
data-nv-scroller .nv-scroller-frame Wires its [data-nv-scroll="prev"|"next"] controls.
data-scrolled .nv-nav Set by the application on scroll; gives the bar its shadow.
data-nv-direction <html> Set during a transition by nv.transition.
data-nv-transition <html> "theme" during an appearance change.

Rules that bite

  1. view-transition-name must be unique per document. A duplicate makes the browser skip the transition entirely. Each selection group needs its own --nv-selection-name; .nv-nav-tabs defaults to nv-tabs-selection and everything else to nv-selection, which is enough for one of each per page.
  2. A menu and its trigger must name the same anchor through --nv-anchor, and the value must be unique per pair.
  3. Only one .nv-tab-panel may be visible at a time — hide the rest with hidden. They share one content name.
  4. Never reference --nv-palette-* from application code. It is raw, and does not adapt to the appearance.
  5. A floating control positioned with translate needs .nv-button--float and --nv-button-offset, or the hover lift overwrites its position.
  6. Icon-only buttons need aria-label. The system gives them a 44px target but cannot give them a name.

Made by Nexoniarz.