Co-authored-by: Jeffrey Smith <jasafpro@gmail.com> Co-committed-by: Jeffrey Smith <jasafpro@gmail.com>
6.0 KiB
Extension CSS Contract
Version: v0.6.13 — Responsive & Spacing
This document defines the CSS contract between the Armature kernel and extension packages. Extensions must follow these rules; the kernel guarantees the listed classes and variables are stable public API.
Naming Rule
All class selectors in extension CSS (packages/{slug}/css/main.css) must start
with .ext-{slug}-. The {slug} is the package directory name.
/* Good */
.ext-my-app-sidebar { ... }
.ext-my-app-card { ... }
/* Bad — will be rejected by the linter */
.sidebar { ... }
.my-sidebar { ... }
Compound selectors: Descendant classes scoped under your .ext-{slug} root
are allowed to reference kernel classes or state modifiers:
/* Allowed — kernel class scoped under extension namespace */
.ext-my-app .sw-btn { margin-top: 8px; }
/* Allowed — state modifier on an extension element */
.ext-my-app-item.active { ... }
Run bash scripts/lint-package-css.sh to validate. The linter checks that the
first class selector in every rule starts with .ext-{slug}.
Stable Kernel Classes
Extensions may reference these classes in compound selectors. They are part of the public API and will not change without a major version bump.
Components (from sw-primitives.css)
| Class pattern | Component |
|---|---|
.sw-btn, .sw-btn--{variant}, .sw-btn--{size} |
Buttons |
.sw-input |
Text inputs |
.sw-field, .sw-field__label, .sw-field__hint |
Form fields |
.sw-dialog, .sw-dialog__header, .sw-dialog__body, .sw-dialog__footer |
Dialogs |
.sw-toast, .sw-toast-container |
Toast notifications |
.sw-menu, .sw-menu-item |
Context menus |
.sw-tabs, .sw-tab-btn |
Tab strips |
.sw-dropdown |
Custom dropdowns |
.sw-spinner |
Loading spinners |
.sw-avatar |
User avatars |
.sw-drawer |
Slide-out drawers |
.sw-banner |
Banner bars |
.sw-tooltip |
Tooltips |
Extension Mount
The extension surface container has a data-ext attribute set to the package
slug. Use this for scoping if needed:
[data-ext="my-app"] .ext-my-app-sidebar { ... }
Stable CSS Variables
All variables from variables.css are public API. Extensions should use these
instead of hardcoded colors to respect the user's theme.
Colors
| Variable | Purpose |
|---|---|
--bg |
Page background |
--bg-secondary |
Secondary/darker background |
--bg-elevated |
Elevated surface background |
--bg-raised |
Raised card background |
--bg-surface |
Surface-level background |
--bg-hover |
Hover state background |
--bg-active |
Active/pressed state background |
--bg-code |
Code block background |
--text |
Primary text color |
--text-2 |
Secondary text color |
--text-3 |
Tertiary/muted text color |
--text-on-color |
Text on colored backgrounds |
--accent |
Primary accent color |
--accent-dim |
Dimmed accent for backgrounds |
--accent-hover |
Accent hover state |
--accent-light |
Light accent variant |
--border |
Default border color |
--border-light |
Light border variant |
--border-elevated |
Border for elevated surfaces |
--danger |
Error/destructive color |
--danger-dim |
Dimmed danger background |
--danger-light |
Light danger variant |
--success |
Success/positive color |
--success-dim |
Dimmed success background |
--success-light |
Light success variant |
--warning |
Warning/caution color |
--warning-dim |
Dimmed warning background |
--warning-light |
Light warning variant |
--purple |
Purple accent |
--purple-dim |
Dimmed purple background |
Spacing
Use spacing tokens instead of hardcoded values for padding, margin, and gap. For sub-4px values (1px, 2px, 3px) used in borders and fine detail, hardcoded values are acceptable.
| Variable | Value | Computed |
|---|---|---|
--sp-1 |
0.25rem |
4px |
--sp-1h |
0.375rem |
6px |
--sp-2 |
0.5rem |
8px |
--sp-2h |
0.625rem |
10px |
--sp-3 |
0.75rem |
12px |
--sp-4 |
1rem |
16px |
--sp-5 |
1.25rem |
20px |
--sp-6 |
1.5rem |
24px |
--sp-8 |
2rem |
32px |
--sp-10 |
2.5rem |
40px |
--sp-12 |
3rem |
48px |
Example:
.ext-my-app-card {
padding: var(--sp-3) var(--sp-4); /* 12px 16px */
gap: var(--sp-2); /* 8px */
margin-bottom: var(--sp-4); /* 16px */
}
Layout & Typography
| Variable | Purpose |
|---|---|
--font |
Primary font family |
--mono |
Monospace font family |
--radius-sm |
Small border-radius (4px) — badges, inline controls |
--radius |
Default border-radius (8px) — buttons, inputs, cards |
--radius-lg |
Large border-radius (12px) — modals, dialogs, large cards |
--transition |
Default transition timing |
--shadow-lg |
Large elevation shadow |
--overlay |
Modal overlay color |
--glass |
Glassmorphism backdrop |
--input-bg |
Form input background |
--sidebar-w |
Sidebar width |
Responsive Breakpoints
The kernel uses these standard breakpoints. Extensions should use the same values for consistency.
| Name | Media Query | Use Case |
|---|---|---|
| Mobile | @media (max-width: 768px) |
Phone-sized, single column |
| Tablet | @media (max-width: 1024px) |
Tablet/small laptop, narrower sidebars |
| Desktop | Default (no query) | Full layout |
CSS custom properties cannot be used in @media queries — use the pixel
values directly.
What Is Internal
Everything not listed above is internal kernel CSS and may change between minor versions. Extensions must not depend on:
- Kernel layout classes (
.admin-*,.surface-*,.sidebar, etc.) - Kernel CSS file load order
- Specific HTML structure of the shell or topbar
- Undocumented CSS variables
Enforcement
The linter script scripts/lint-package-css.sh runs against all
packages/*/css/main.css files. It exits non-zero if any rule's first class
selector does not start with .ext-{slug}.