hraness.com, sound.fish, sleepy.land, slopcamera.com, and platonik.space are five different applications with different domains, different content, and different state. They still read as one family. The reason is not a shared theme file that everyone copies; it is a rule about order. Every product’s stylesheet resolves to the same four layers in the same sequence: tokens, then reset, then component styles, then product rules. Each layer has exactly one owner, and the lower layers are not allowed to know the upper ones exist.
The practical effect is that a button on this site and a button in Soundfish are the same component with the same tokens, while a Soundfish-only surface like the piano roll gets its look from the fourth layer alone. This lesson is about how the cascade is structured, who owns which layer, and what product code is actually permitted to style.
the order
The canonical stack ships from @hraness/ui, the public browser-interface package. Its root stylesheet declares the layering explicitly:
@layer base, components;
@layer components.hraness-ui.legacy, components.hraness-ui.priority1, components.hraness-ui.priority2, components.hraness-ui.priority3, components.hraness-ui.priority4;
@import "./tokens.css";
@import "./reset.css";
@import "./components.css";
@import "../dist/stylex.css";
Two things matter here. First, the imports run in a fixed order that cannot vary per product: tokens define custom properties, the reset normalizes element behavior against those properties, and the component stylesheet consumes both. Second, the component layer is itself subdivided into a declared sublayer sequence (legacy through priority4), so internal overrides inside the package have a defined cascade position rather than competing on specificity.
On the product side, a Jungle product’s root stylesheet begins with one line, @import "@jungle/design-kit/styles.css", which pulls the same canonical core plus brand-level styles and the shared site footer. Everything the product writes after that import sits above it in source order and inside product-owned selectors. That is the entire mechanism. There is no per-product theme file, no forked component stylesheet, and no second reset.
tokens are roles, not palettes
The token file is the contract that makes “one brand, many surfaces” possible. Products do not name colors or measurements; they name roles. The color tokens are roles first:
--ui-background
--ui-foreground
--ui-card
--ui-primary
--ui-secondary
--ui-muted
--ui-border
--ui-ring
A product surface says “this region is card and its text is foreground,” never “this region is #f5f2ec.” Light and dark are not two stylesheets; they are two value sets for the same custom properties, resolved under data-theme on a selectable root. The DesignThemeProvider accepts light, dark, and system, persists the choice under hraness-design-theme-v1, and repairs an invalid stored value back to system. Server markup deliberately leaves data-theme unset so the system-first bootstrap can resolve it before paint, and a ThemeColorSync keeps the browser chrome color aligned with the resolved theme.
The same discipline applies to geometry and type. Spacing runs on a shared scale (--space-1 through --space-16), chrome uses declared insets (--layout-edge-inset at 1.5rem, --layout-chrome-inset at 0.5rem), and interactive surfaces measure themselves against shared target sizes rather than product-chosen pixel values:
| token | value | role |
|---|---|---|
--interactive-target-compact |
2.5rem |
smallest allowed target |
--interactive-target-min |
3rem |
floor under coarse pointers |
--control-height |
3.25rem |
default control |
--control-height-primary |
3.5rem |
primary actions |
--control-height-transport |
4rem |
media transport |
Under a coarse pointer the compact floor is raised to at least --interactive-target-min, so a phone layout gets larger hit targets without a single media query in product code. Type is role-mapped the same way: --ui-font-sans, --ui-font-heading, and --ui-font-mono are slots. The core defaults heading type to the system monospace stack; the Jungle layer remaps the heading role to the self-hosted Geist Mono face without touching any component.
Radius is the sharpest example of roles over names, because wrong geometry is the most common way products break a shared look. The checked roles are --jelly-radius-compact, --jelly-radius-control, --jelly-radius-card, and --jelly-radius-overlay. --control-radius is for bounded controls, --jelly-radius-card is for content-bearing surfaces, --jelly-radius-overlay is for temporary layers, and --radius-round is reserved for circles and compact single-line chips. A multiline container that reaches for control or pill geometry is a checker violation, not a style choice.
three packages, one boundary
The cascade is also a redistribution boundary, which is why three packages exist instead of one.
@hraness/ui is the product-neutral core: semantic tokens, the reset, component stylesheets, React Aria behavior, fields, actions, selection, overlays, navigation, feedback, data display, and portable icon rendering. Nothing in it knows what a Hraness product is.
@hraness/design-kit sits above it as redistributable composition: appearance and haptics, charts, syntax presentation, decorative effects, application shells, route states, and the executable design gallery that every product serves at /design.
@jungle/design-kit is a shallow facade, not a fork. It forwards the canonical public packages, supplies the private MonoLisa text and code faces, and retains a small set of compatibility router names. Products import the facade and receive the public stack plus licensed brand assets; the public packages stay clean of licensed material.
The boundary has teeth because licensing is enforced at the package line. MonoLisa ships only through the private facade. The Canvas UI Liquid effect and its vendored source were removed from the kit entirely once the Commons Clause made it unsuitable for a reusable, redistributed package. When a visual cannot be redistributed, it does not get a package home; it stays in product code or it does not ship.
what product rules may do
The fourth layer is real but narrow. Product CSS owns categorical color, page layout, and a documented set of hooks into shared components. A product may pass className to a primitive for layout, reflow or resize a SegmentedControl, and tune shared presentation through the documented custom properties: paint on shared Jelly surfaces goes through --jelly-fill and --jelly-label rather than background or border declarations, and a fixed-identity palette may map the --jungle-segmented-control-* and --jungle-collection-* hooks on a scoped class. Portalled content is handled explicitly too: DesignPortalThemeProvider.portalClassName reapplies a product’s scoped theme class to menus, modals, and tooltips after they portal, and GlobalErrorDocument.bodyClassName carries the same class into the route that replaces the root layout. Products may also reach for recipe props like PageCanvas inset="none" or shape="rectangular" instead of overriding shared radius tokens in their own CSS.
What it may not do is the longer list, and every item on it exists because a real product tried it. Product CSS may not redefine shared radius or elevation tokens, and the public --ui-* roles and the private compatibility aliases (--background, --surface, --line, --foreground, --focus) are both off-limits to global redefinition. It may not select Jelly custom-element tags or reach inside a shared host to style its internals; --jelly-radius itself must resolve from a pixel-safe role or an explicit pixel value because the Jelly host parses it as CSS pixels for canvas work. It may not paint an opaque resting background on a shared semantic control or repaint individual item states inside a selection control, since that recreates the square seams the shared surface exists to remove. It may not position a trigger and its overlay relative to each other in a way the component owns. And it may not re-export the facade’s internal router names as its own public API.
The pattern across all of these is the same: products describe what a surface is, the shared layers decide how it looks and behaves. Content and domain meaning flow up; geometry, motion, and interaction flow down.
the order is enforced
A layering rule that lives only in a document decays on the first deadline, so the boundary is a checked gate. In the monorepo behind this site, scripts/check-design-system.ts scans product stylesheets and modules for the violations above: redefined shared tokens, Jelly-internal selectors, opaque paint on semantic controls, and the rest. bun run verify:design-system extends the check into a real browser across the registered surface matrix, and design-browser-surfaces.json names hraness as the full-matrix project.
The shared footer is the proof that the cascade holds at the organization level, not only inside one app. @hraness/site-footer owns the signup form, the account link, and an immutable social order (Substack, X, LinkedIn, GitHub), and every product mounts it rather than forking it. When the same footer, the same buttons, and the same tokens appear on five domains with five different codebases, the cascade is doing its job: the brand travels because the order is fixed, and the order stays fixed because it is checked.
sources
- ui:
src/styles.cssfor the layer declaration,src/tokens.cssfor the role tokens and breakpoints,src/reset.cssfor the normalized base, andsrc/actions.tsxfor the shared primitives. - design-kit: the redistributable composition layer, including
src/react/theme.tsxforDesignThemeProviderandThemeColorSync. - site-footer: the organization-owned footer every product mounts.
- The monorepo behind this site (projects): the design-system runbook,
scripts/check-design-system.ts, anddesign-browser-surfaces.jsonthat turn the cascade into a gate.