Connection lost. Reconnecting… attempt 1 of 8
Paused. Your work is held on the server.
Could not reconnect.
This session has expired on the server.
An unhandled error has occurred.
Sedna.UI
v0.31.0 · main

Concepts

this site, not the package

What decides how an app writes CSS against this library. Everything else on this site is markup to copy.

The three tiers

One question decides a tier: who writes the markup on screen?

Tier 1 — the frame Shell, sidebar and nav, header, bottom bar, user widget, drawer, the modal shell. Separate parts the app writes and combines as it likes.
Tier 2 — the paint Tables, forms, cards, badges, buttons, panels, alerts. Pages write plain HTML and apply the classes.
Tier 3 — the surfaces A toast, the hover-hint bubble, a graph, the document in a rich-text editor. The library draws them, because there is nothing for the app to write; everything around one is tier 2.

Tiers 1 and 2 are CSS classes. There is no <DataTable>, no <AppShell>, and there will not be either. The package ships the stylesheet, the script, the icons, the token export, and a small C# surface for what markup cannot express: which nav link is the current page, typed access to the browser API, and the service registration.

Cascade layers

The whole stylesheet is inside these layers, in this order. A later layer beats an earlier one regardless of specificity, which is why the reduced-motion block sits last.

LayerPart numbersWhat lives there
sedna.tokens00–04Tokens and the theme remap blocks
sedna.base05–09Bare elements — html, body, a, code, headings
sedna.frame10–29Tier 1
sedna.paint30–79Tier 2, then RTL, forced colours and print
sedna.utilities80–89Single-purpose classes
sedna.overrides90–99Density and reduced motion — the last word
Your stylesheet is unlayered, so it always wins Whatever the specificity. .card { padding: 12px } in your own file wins with no !important and no compound selector — and use no !important against the library either, because layer order inverts for important declarations and would make the rule harder to override. If a rule here has to be overridden to make something work, report it rather than out-specify it.

One control height

--control-height-sm (28px), --control-height (36px) and --control-height-lg (44px) are the height of everything that can sit in a row with another control: buttons, icon buttons, inputs, selects, the read-only value, the input group, the stepper, the search box and the chip.

Sizing a control yourself takes two rules Keep its own padding and line box under the tier, or the tier stops deciding anything and the control grows past it. And where a wrapper draws the border — an input group does — the wrapper takes the height and the children give theirs up.

The token contract

  • Every colour resolves through a token No hex, rgb() or colour keyword anywhere outside the token blocks. A test enforces it.
  • A theme is a token remap, never a selector override The light and colour-blind blocks contain values and no rules, which is why CSS load order does not affect them.
  • Redefine only names the library declares A new -- name risks colliding with a future token. Use an app-prefixed one until yours ships.
  • Some tokens are derived --brand-tint, the three rings and --brand-glow are mixed from --brand, so redefining it carries all five.

Naming

ShapeRule
.card, .btn--go.btn--solidSemantic, lowercase-kebab, no app or vendor prefix
.sedna-row, .sedna-scrollLibrary-owned utilities that need a namespace
.tab--activeA modifier is -- on the block
go, warn, danger, info, secretSemantic families, chosen by meaning across buttons, badges and alerts
cyan, orange, tealCategorical hues with no meaning at all
A plain name is a claim on the shared namespace An app that already styles .list or .menu silently gets both rule sets merged on upgrade — no error, just a changed appearance. Every release lists the class names it adds, so grep your own CSS before bumping.

Z-order

Shared by every app. Use one of these values for a new overlay — a test fails on any other. 0 to 3 are for local stacking inside a component and are not part of the scale.

Layerz-index
Topbar, floating action button60
User widget200
Collapsed-rail flyout400
Drawer scrim480
Drawer panel490
Modal backdrop500
Spotlight510
Popover, dropdown menu, search panel550
Toast600
Hover hints, reconnect banner1000
What the numbers do not say .topbar and .user-widget establish stacking contexts, so a panel nested in either is ordered within it and cannot be lifted above the modal backdrop by z-index alone. The top layer — anything promoted by popover or dialog.showModal() — ignores z-index entirely and orders by promotion. And the drawer sits below the modal backdrop on purpose, because a modal opened from inside a drawer has to cover it.

Direction and density

Every directional property in the library is a logical one, so the whole layout mirrors from dir="rtl" on <html>. Use the switch in the header to check any page on this site.

Write the logical property and it mirrors for free Write margin-inline-start, border-inline-end, inset-inline and text-align: start and your own pages mirror for free; only transform: translateX() and a background-position percentage have no logical form, and both are handled here. data-density="compact" tightens table cells, card padding, list rows, the page's rhythm and the control heights by remapping --cell-pad-*, --card-pad-*, --list-pad-*, --page-rhythm, --page-pad and --control-height*; data-density="touch" loosens the same tokens and puts the default control at 44px. A component of your own that reads those tokens moves with them.