@super-ic/foundation
v0.2.4
Published
The SuperIC token substrate: the semantic token map every other @super-ic package resolves through, plus the CSS custom-property layer (tokens.css) that makes those names real for external consumers.
Readme
@super-ic/foundation
The SuperIC token substrate. Two things ship here and every other @super-ic
package resolves through them:
tokens.css, the CSS custom-property layer: unprefixed properties on:root, light and dark themes, and Sandbrock, NeighborShare and Solentra scopes.FoundationTokens, a typed map of semantic names tovar(--token)strings, so component code names a role (color.actionPrimary) and never a hex.
The package has no dependencies and no peer dependencies. It is the peer that
@super-ic/brand-contracts, @super-ic/product-shell, @super-ic/app-patterns
and @super-ic/web-patterns declare.
Install
npm install @super-ic/foundationThe one mandatory import
import "@super-ic/foundation/tokens.css";Import it once, at the application root, before any @super-ic component
renders. Every pattern package reads custom properties that only this sheet
defines. Without it, var(--surface) resolves to nothing, the browser falls
back to its defaults, and nothing throws.
Import order matters when you also run Tailwind:
@import "tailwindcss";
@import "@super-ic/foundation/tokens.css";
@import "@super-ic/foundation/tailwind.css";Select a supported brand and theme at the application boundary. Product CSS must not redeclare governed foundation properties or maintain a private tenant palette. Contribute missing roles or brand scopes to the canonical foundation source, generate the outputs, and consume a verified package version. Product adapters continue to own their approved page composition, copy and data.
What the stylesheet declares
The file and the SuperIC application's generated CSS regions both derive from
design-system/foundation/source.json. Neither output is hand-edited. The
stylesheet binds in this order:
| Selector | Role |
| --- | --- |
| :root | Light values, so a document with no theme attribute still resolves. |
| [data-theme="light"], .light | Explicit light. Same values as :root. |
| [data-theme="dark"], .dark | Dark. Rebinds the semantic layer (--background, --foreground, --surface, --muted, --border, --primary, and their neighbours). |
| [data-tenant="sandbrock"], [data-brand="sandbrock"], [data-brand="neighborshare"] | The eleven brand palette values, explicit brand accents, neutral action and focus roles, and tenant typography bindings. |
| the dark variants of the tenant selectors | Dark neutral action, foreground and focus pairs. |
| [data-brand="solentra"], [data-tenant="solentra"] and dark variants | Solentra gold, cream and ink palette, accessible gold accents, neutral controls and Geist typography. |
| [data-brand="neighborshare"], [data-tenant="neighborshare"] and dark variants | NeighborShare yellow accents, neutral controls, Inter body and Plus Jakarta Sans headings. |
Use either brand attribute or tenant attribute; both are not required. For
Solentra and NeighborShare, explicit local data-theme="light" takes precedence
over a dark ancestor. Page structure and imagery remain tenant-specific.
The :root layer groups into:
- Semantic colour:
--background,--foreground,--surface,--surface-2,--content-secondary,--muted,--muted-2,--muted-foreground,--border,--input,--ring,--primary,--primary-foreground,--primary-hover,--primary-pressed,--secondary,--accent,--destructive,--success,--warning,--info,--card,--popover,--sidebar-*,--chart-1to--chart-5. - Colour ramps:
--gray-0to--gray-950,--blue-*,--teal-*,--purple-*,--red-*, each at the 0, 50, 100 to 950 steps. - Type ramp:
--type-<role>-family|size|line-height|weight|trackingfordisplay-large,display-small,h1toh6,body-large|medium|small,subtext,caption,label,overline,button,numeric,code, plus--font-body,--font-heading,--font-inter-display,--tracking-display. - Space and layout:
--space-unit,--container-max,--container-gutter,--section-pad-y*,--header-offset,--control-height-xs|sm|md|lg,--icon-size-sm|md|lg. - Radius:
--radius,--radius-xsto--radius-2xl,--radius-card,--radius-card-frame,--radius-card-inset. - Elevation and controls:
--elev-card,--elev-pill,--shadow-sm|lg,--shadow-intensity,--control-border,--control-elevation*,--control-highlight,--control-track,--surface-border,--surface-inset,--well-edge. - Motion:
--dur-micro|hover|register|measure|draw|structure,--ease-signal,--motion-hover-duration,--motion-ease-quiet,--stagger-unit.
Values use oklch() and color-mix(in oklab, ...).
Browser floor: Chrome 111, Safari 16.4, Firefox 113. Older
engines drop those declarations and the property resolves to nothing.
Collision risk
The properties are unprefixed on purpose: --background, --primary,
--border, --ring, --radius and the rest share names with shadcn/ui and
most Tailwind theme presets. If your application already declares those:
- Your later
:rootwins, per the import order above. Check that the grammar matches. This sheet writes resolved colours (hex,oklch(),color-mix()); shadcn presets write bare HSL triplets consumed throughhsl(var(--x)). A triplet placed into a foundation slot, or a foundation colour placed into a triplet slot, renders the wrong colour without an error. - Tailwind v4 generates no
bg-border,ring-ringorring-offset-backgroundutilities from this sheet by itself. Map the properties you need in your@theme inlineblock. - Not every token has a light and dark pair on the semantic layer. The Enterprise, inverted and block-accent surface sets now belong to the canonical source registry and are generated for the supported themes and tenant scopes. Particle and logo decoration remains product-owned.
Self-hosted web fonts
Tenant fonts ship through an explicit optional stylesheet:
import "@super-ic/foundation/tokens.css";
import "@super-ic/foundation/fonts/tenants.css";
// Include this for the base SuperIC brand and code roles:
import "@super-ic/foundation/fonts/superic.css";Import font sheets directly from the application layout or JavaScript entry so
the bundler can resolve their relative font assets. Keep these imports outside
the Tailwind compiler entry. A CSS transformer that flattens nested @import
without preserving source locations can leave broken font URLs in a static build.
Verify built asset responses and actual glyph fonts, not just development mode.
This binds the actual Plus Jakarta Sans heading and Inter body families used
by Sandbrock Share and NeighborShare. It includes normal and italic weights
400, 500, 600, 700 and 800 and the upstream Unicode subsets. Browsers fetch only
the faces and subsets in use. Import it once at the application root so dialogs,
menus and other portals have the same available fonts. It makes no network
request to Google or Fontsource. Glyphs outside the supplied subsets, or weights
outside this range, use normal CSS fallback and matching behavior.
The unmodified WOFF2 assets come from Fontsource 5.2.8. Full SIL Open Font
License 1.1 notices accompany both families under fonts/licenses/. Public
fonts/manifest.json records the source versions, licenses, Unicode ranges and
SHA256 of every file. The prepack check rejects missing or changed assets and
stale generated font declarations. fonts/files/* is exported for a bundler's
asset URL imports or an explicit preload; resolve the URL through your build
system rather than assuming a deployment path.
For base SuperIC display/body and code roles, import
@super-ic/foundation/fonts/superic.css as well. This registers the unmodified
Fontsource 5.2.8 variable fonts under the canonical Geist and Geist Mono
token names. Both support weights 100-900. Geist is normal style; Geist Mono
also supplies italic. The same manifest and complete OFL notices cover them.
No local-machine font is required. Inter Display remains an optional fallback
name, not a shipped dependency. tokens.css stays a font-free token layer.
Font-family strings alone do not prove correct rendering: browser verification
must inspect the font used for actual glyphs after document.fonts.ready.
Within either tenant, display and heading roles bind to --font-heading; body,
labels, buttons and numeric roles bind to --font-body. These bindings work in
nested tenant subtrees. Native font delivery and licensing notices are a
separate integration step after web completion.
The typed token map
import {
Foundation,
FoundationTokens,
FOUNDATION_CONTRACT_VERSION,
foundationToken,
} from "@super-ic/foundation";
FoundationTokens.color.actionPrimary; // "var(--primary)"
FoundationTokens.focus.outline; // "2px solid var(--ring)"
foundationToken("color", "surface"); // "var(--surface)"
foundationToken("color", "nope"); // throws: unknown foundation token
FOUNDATION_CONTRACT_VERSION; // "0.2.0"Groups: color, typography, space, radius, elevation, focus,
motion, charts. Foundation is the same map wrapped with
contractVersion and tokens. Color roles resolve through custom properties;
some geometry and motion values are CSS literals.
color.success and color.warning are feedback surface fills, independent of
chart series. Their explicit aliases are color.successSurface and
color.warningSurface. Pair these fills with color.statusContent for text.
Do not use a surface fill as text color or infer status meaning from a chart.
Tenant primary controls use the neutral foreground/background pair and a
neutral focus ring. Sage remains available through --brand-accent,
--brand-accent-strong and --brand-accent-quiet for explicit brand context.
Entry points
| Specifier | Contents |
| --- | --- |
| @super-ic/foundation | FoundationTokens, Foundation, foundationToken, FOUNDATION_CONTRACT_VERSION, FoundationTokenGroup |
| @super-ic/foundation/tokens.css | The generated custom-property layer |
| @super-ic/foundation/fonts/tenants.css | Optional self-hosted tenant font declarations |
| @super-ic/foundation/fonts/superic.css | Optional self-hosted SuperIC font declarations |
| @super-ic/foundation/fonts/manifest.json | Source, license and asset hashes |
| @super-ic/foundation/fonts/files/* | Font assets for bundler URLs and preloads |
Package shape
ESM only ("type": "module"). sideEffects is ["**/*.css"], so bundlers
keep the stylesheet import and tree-shake the rest. The tarball is dist/,
css/, fonts/ including licenses, this README and the manifest: no TypeScript
sources, no tests and no build state. prepack regenerates and checks tokens.css against its source
before building, so a published sheet is never stale.
Versioning
FOUNDATION_CONTRACT_VERSION tracks the package version. Adding a property is
a minor change. Renaming or removing one, or changing a semantic value's
grammar, is a breaking change for every downstream @super-ic package.
SuperIC tenant and supplementary type
Use data-tenant="superic" or data-brand="superic" with explicit data-theme="light" or "dark". An explicit light tenant restores its palette inside an ambient dark or other tenant scope. Default controls remain neutral. SuperIC brand artwork uses --brand-accent; secondary copy uses --muted-foreground. --muted and --accent remain quiet interaction surfaces, not text or brand-fill roles.
FoundationTokens.typography.bodyCompact is 15px and annotation is 13px at the default root size. micro (11px) and nano (10px) are supplementary diagram/data annotation only. Never use micro or nano for body copy, form labels, input text, or sole instructions.
The canonical utility bridge also owns --control-s (12ch), --control-m (24ch), --control-l (min(100%, 400px)), and radius 3xl/4xl (2.2/2.6 times the base radius). Existing art window/overlap radii remain 0.5/0.75rem.
Public typography and enterprise cards
The normal @super-ic/foundation/tokens.css import includes generated
typography.css, also available as a dedicated public subpath. Utilities bind
font family, size, weight, tracking and line height directly to registered roles:
type-display-large, type-display-small, type-h1 through type-h6,
type-body-large, type-body-medium, type-body-small, type-subtext,
type-caption, type-label, type-overline, type-button, type-numeric and
type-code. Numeric uses tabular figures. No class forces uppercase.
Body-compact, annotation, micro and nano remain size tokens; they do not yet have
complete family/weight/line-height role records and therefore gain no invented
utility class. Micro/nano remain supplementary diagram or data annotations.
Shared enterprise cards bind surface/foreground to the current tenant and both secondary text variables to its accessible muted foreground. The Tailwind bridge exports enterprise background and foreground utilities. Solentra preserves cream primary controls and ink in both themes, its five glass adapter bindings, and framework Geist variables when supplied (named Geist fallbacks otherwise). The foreground focus ring is retained in light mode; dark mode preserves gold: gold measures only 2.16:1 against the light canvas and 2.47:1 against the light card, below the 3:1 focus boundary.
For Solentra cutover, remove duplicate shared tenant palette/control/type-role,
glass and enterprise declarations and the duplicated .type-* utility plumbing
after adopting this candidate. Remove the local --light-canvas pin and use the
public Solentra background. Retain product container 75rem, gutter 1.5rem, section
padding 3/4/4rem, responsive composition, framework font variable providers and
.solentra-wordmark. The missing vector wordmark is still a delivery gap.
