Design Standards
Design Standards
The standards layer of the UNVRSL Design System provides foundational CSS tokens, a global reset, and utility classes. It is the single dependency of the
ui and layouts layers.Quick start
<link rel="stylesheet" href="/design/standards/v1.css">For projects using the core.assets CDN:
<link rel="stylesheet" href="https://core.assets.medkronos.com/design/standards/v1.css">1. Color system
The entire color palette is derived from a single value:
--brand-hue. Pick one of the presets, or set any hue you like.Presets
| Variable | Hue | Preview |
--brand-hue-blue | 210° | <span style="display:inline-block;width:1.5rem;height:1.5rem;border-radius:4px;background:oklch(0.58 0.16 210deg);vertical-align:middle"></span> Blue (default) |
--brand-hue-green | 150° | <span style="display:inline-block;width:1.5rem;height:1.5rem;border-radius:4px;background:oklch(0.58 0.16 150deg);vertical-align:middle"></span> Green |
--brand-hue-purple | 270° | <span style="display:inline-block;width:1.5rem;height:1.5rem;border-radius:4px;background:oklch(0.58 0.16 270deg);vertical-align:middle"></span> Purple |
--brand-hue-red | 0° | <span style="display:inline-block;width:1.5rem;height:1.5rem;border-radius:4px;background:oklch(0.58 0.16 0deg);vertical-align:middle"></span> Red |
--brand-hue-orange | 30° | <span style="display:inline-block;width:1.5rem;height:1.5rem;border-radius:4px;background:oklch(0.58 0.16 30deg);vertical-align:middle"></span> Orange |
--brand-hue-teal | 180° | <span style="display:inline-block;width:1.5rem;height:1.5rem;border-radius:4px;background:oklch(0.58 0.16 180deg);vertical-align:middle"></span> Teal |
Choosing a palette
Set the active brand hue in your project CSS:
:root {
--brand-hue: var(--brand-hue-green);
}To use green across the whole UI:
--brand
--brand-strong
--brand-soft
--brand-faint
--brand: oklch(0.58 0.16 150deg)
--brand-strong: color-mix(in oklch, var(--brand), black 18%)
--brand-soft: color-mix(in oklch, var(--brand), white 72%)
--brand-faint: color-mix(in oklch, var(--brand), white 92%)Full token reference
| Token | Description |
--brand | Base brand color |
--brand-strong | 18% darker |
--brand-soft | 72% lighter |
--brand-faint | 92% lighter |
--complement | Opposite hue (brand + 180°) |
--complement-soft | Complement, 70% lighter |
--complement-faint | Complement, 90% lighter |
--bg | Page background |
--surface | Card / section background |
--surface-2 | One layer deeper |
--surface-3 | Two layers deeper |
--inset | Slightly darker for inset areas |
--text | Body text |
--text-strong | High emphasis text |
--text-muted | Lower emphasis (labels, hints) |
--text-faint | Least emphasis (placeholders) |
--text-on-brand | Text color when placed on brand bg |
--border | Default border |
--border-strong | Emphasized border |
--border-faint | Subtle border |
--focus-ring | Focus ring color |
--success | Green semantic |
--warning | Yellow/amber semantic |
--danger | Red semantic |
--info | Blue semantic |
Using surfaces
The surface tokens create visual hierarchy. Here they are rendered side by side:
--bg
--surface
--surface-2
--surface-3
--inset
Dark mode
The standards file includes full dark mode support via
prefers-color-scheme: dark. All surface, text, and border tokens invert cleanly while maintaining the same brand hue. No class toggles required.To simulate how your palette would look in dark mode, the system automatically inverts:
Light mode: --bg → oklch(0.98 0.01 var(--brand-hue))
Dark mode: --bg → oklch(0.15 0.015 var(--brand-hue))
Light mode: --text → oklch(0.22 0.02 var(--brand-hue))
Dark mode: --text → oklch(0.85 0.015 var(--brand-hue))2. Size scale
All spacing, typography, and radii follow a consistent 8-step scale.
Space tokens
--space-xxs: 0.125rem ( 2px)
--space-xs: 0.25rem ( 4px)
--space-s: 0.5rem ( 8px)
--space-m: 1rem (16px)
--space-l: 1.5rem (24px)
--space-xl: 2rem (32px)
--space-xxl: 3rem (48px)
--space-xxxl: 4rem (64px)Font sizes
--text-xs: 0.75rem
--text-s: 0.875rem
--text-m: 1rem
--text-l: 1.125rem
--text-xl: 1.375rem
--text-xxl: 1.75rem
--text-xxxl: 2.5remRadii
--radius-s: 0.25rem
--radius-m: 0.5rem
--radius-l: 0.75rem
--radius-xl: 1rem
--radius-full: 9999px (pill shape)Shadows
--shadow-sm: 0 1px 2px rgba(0,0,0,0.06)
--shadow-md: 0 4px 6px rgba(0,0,0,0.07), 0 2px 4px rgba(0,0,0,0.04)
--shadow-lg: 0 10px 15px rgba(0,0,0,0.08), 0 4px 6px rgba(0,0,0,0.04)
--shadow-xl: 0 20px 25px rgba(0,0,0,0.10), 0 10px 10px rgba(0,0,0,0.04)sm
md
lg
xl
Transition & opacity tokens
--opacity-muted: 0.65
--opacity-faint: 0.40
--opacity-hidden: 0
--ease-out: cubic-bezier(0.16, 1, 0.3, 1)
--ease-in-out: cubic-bezier(0.65, 0, 0.35, 1)
--duration-fast: 150ms
--duration-normal: 250ms
--duration-slow: 400ms3. Z-index system
| Token | Value | Used for |
--z-base | 0 | Normal document flow |
--z-below | -1 | Behind all content |
--z-dropdown | 100 | Dropdown menus |
--z-sticky | 200 | Sticky headers / navs |
--z-nav | 300 | Fixed navigation bars |
--z-overlay | 400 | Semi-transparent page overlays |
--z-modal | 500 | Modal dialog boxes |
--z-popover | 600 | Popovers & contextual menus |
--z-tooltip | 700 | Tooltips |
--z-toast | 800 | Toast notifications |
--z-notification | 900 | Notification banners |
--z-banner | 950 | Emergency alert banners |
--z-emergency | 1000 | Critical system alerts |
Rule: Always use these custom properties instead of raw numbers:
/* 👍 Good */
.modal { z-index: var(--z-modal); }
/* 👎 Bad */
.modal { z-index: 999999; }4. CSS reset
The reset normalises behaviour across browsers and establishes consistent defaults.
*, *::before, *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
min-height: 100dvh;
font-family: system-ui, -apple-system, 'Segoe UI', Roboto, ...;
line-height: 1.5;
-webkit-font-smoothing: antialiased;
}
img, picture, video, canvas, svg {
display: block;
max-width: 100%;
}
a {
color: var(--brand);
text-decoration: none;
}
a:hover {
color: var(--brand-strong);
text-decoration: underline;
}
button {
cursor: pointer;
border: none;
background: none;
font: inherit;
}
:focus-visible {
outline: 2px solid var(--focus-ring);
outline-offset: 2px;
}
::selection {
background: var(--brand-soft);
color: var(--text-strong);
}A custom scrollbar is also applied on WebKit browsers.
5. Utility classes
Utility classes allow rapid prototyping without writing custom CSS. They are grouped by category:
Spacing
.gap-xxs .gap-xs .gap-s .gap-m .gap-l .gap-xl .gap-xxl .gap-xxxl
.p-xxs .p-xs .p-s .p-m .p-l .p-xl .p-xxl .p-xxxl
.m-xxs .m-xs .m-s .m-m .m-l .m-xl .m-xxl .m-xxxlFlex & Grid
.flex .flex-col .flex-wrap .flex-1
.items-center .items-start
.justify-center .justify-between
.grid .grid-cols-2 .grid-cols-3 .grid-cols-4Text
.text-center .text-muted .text-faint
.text-xs .text-s .text-m .text-l .text-xl .text-xxl .text-xxxl
.weight-bold .weight-medium .truncateSurfaces & Borders
.surface .surface-2 .surface-3 .inset
.border .border-strong .border-faint
.radius-s .radius-m .radius-l .radius-full
.shadow-sm .shadow-md .shadow-lg .shadow-xlAccessibility
.sr-only — visually hidden, available to screen readersContainer
.container {
width: 100%;
max-width: 1200px;
margin-inline: auto;
padding-inline: var(--space-m);
}
/* Responsive: padding increases on larger screens */Putting it all together
A minimal page using only standards (no UI layer):
Welcome
Standards only
This page uses only the reset, tokens, and utility classes from standards/v1.css — no UI components loaded.
Card one
Built with tokens only.
Card two
Using --surface-2.
```html
<div class="container" style="padding: 2rem">
<div class="flex items-center justify-between" style="margin-bottom: 2rem">
<h1 style="font-size: var(--text-xxl)">Welcome</h1>
<span class="badge badge--brand">Standards only</span>
</div>
<p style="color: var(--text-muted)">
This page uses only tokens and utilities.
</p>
<div style="display: flex; gap: 1rem; flex-wrap: wrap">
<div class="surface" style="padding: 1.5rem; border-radius: var(--radius-m); box-shadow: var(--shadow-sm); border: 1px solid var(--border)">
<h3>Card one</h3>
<p>Built with tokens only.</p>
</div>
<div class="surface-2" style="padding: 1.5rem; border-radius: var(--radius-m); box-shadow: var(--shadow-sm); border: 1px solid var(--border)">
<h3>Card two</h3>
<p>Using --surface-2.</p>
</div>
</div>
</div>