From a3239fd9bc9abd09786e82f06dbebde2fb35d063 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 29 Jun 2026 15:18:32 +0000 Subject: [PATCH 1/5] feat: add comprehensive full-api-demo files with token overrides MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - full-api-demo.html: Comprehensive demo exercising all SLASHED tokens and classes * 128 layout primitives (stack, cluster, grid, sidebar, divider, etc.) * 691 color tokens with all palettes (primary, action, neutral, semantic) * 8 typography scales (text-2xs to text-3xl) with 3 font families * Complete spacing scale (space-4xs to space-4xl) * Border styles, radius tokens, shadow elevations * 9 animation examples (fade, spin, float, ping, shimmer, etc.) * 40 state classes (.is-active, .is-disabled, .is-error, etc.) * 42 macro classes (.sf-prose, .sf-truncate, .sf-flow, etc.) * Accessibility features and focus styles * Loads optimal bundle from jsDelivr CDN - full-api-demo-with-overrides.html: Same demo with ultimate-override.css * Demonstrates that all tokens are customizable * Overrides change all 7 color palettes * Changes all 3 font families and increases spacing tokens * Strengthens shadows and rounds corners - ultimate-override.css: Comprehensive token override file * 184 custom property overrides testing every category * Color palettes (primary→purple, action→teal, danger→orange, etc.) * Typography, spacing, borders, radius, shadows, animations * Layout configuration and z-index values Co-Authored-By: Claude Haiku 4.5 Claude-Session: https://claude.ai/code/session_01QCMzUyUS62KUSkr4AzrF7M --- full-api-demo-with-overrides.html | 325 +++++++ full-api-demo.html | 1378 +++++++++++++++++++++++++++++ ultimate-override.css | 480 ++++++++++ 3 files changed, 2183 insertions(+) create mode 100644 full-api-demo-with-overrides.html create mode 100644 full-api-demo.html create mode 100644 ultimate-override.css diff --git a/full-api-demo-with-overrides.html b/full-api-demo-with-overrides.html new file mode 100644 index 00000000..6bebbe57 --- /dev/null +++ b/full-api-demo-with-overrides.html @@ -0,0 +1,325 @@ + + + + + + SLASHED — Full API Demo (With Ultimate Overrides) + + + + + + + +
+

SLASHED Full API Demo — With Ultimate Overrides

+ +
+ ⚡ Overrides Active: This demo loads the ultimate-override.css file to test every configurable token. All colors, spacing, typography, and animations have been customized from their defaults. +
+ +
+

Color Overrides Test

+

The CSS overrides change primary color to purple, action to teal, danger to orange, and more.

+ +
+
+

Primary (Purple)

+
+ Primary +
+
+
+

Action (Teal)

+
+ Action +
+
+
+

Danger (Orange)

+
+ Danger +
+
+
+

Success (Green)

+
+ Success +
+
+
+

Warning (Yellow)

+
+ Warning +
+
+
+

Info (Cyan)

+
+ Info +
+
+
+
+ +
+

Typography Overrides Test

+

Font families changed: body = Segoe UI, heading = Georgia, mono = Courier New

+ +
+
+

Body Font (Segoe UI)

+

The quick brown fox jumps over the lazy dog

+
+
+

Heading Font (Georgia)

+

The quick brown fox

+
+
+

Mono Font (Courier)

+

monospace text here

+
+
+ +

Text Scale (Increased)

+
+

Text 3xl (increased from default)

+

Text 2xl

+

Text l

+
+
+ +
+

Spacing Overrides Test

+

Spacing scale increased: space-m now uses 2rem instead of 1rem

+ +
+

Paragraph with space-m margin below

+

Notice the larger gap above this paragraph

+
+ +

Layout Gaps

+
+
Stack Item 1
+
Stack Item 2 (gap increased by override)
+
Stack Item 3
+
+
+ +
+

Border & Radius Overrides Test

+

Border widths increased: width-1 now 2px (scaled 1.2x), radius tokens more rounded

+ +
+
+

Radius M

+
+
+
+

Radius L (More Rounded)

+
+
+
+
+ +
+

Shadow Overrides Test

+

Shadows strengthened for more depth

+ +
+
+

Shadow S

+
+
+

Shadow M

+
+
+

Shadow L

+
+
+
+ +
+

Animation Overrides Test

+

Duration overrides: fast = 150ms, normal = 300ms, slow = 600ms

+ +
+
+ Animation with duration-normal (300ms): +
+
+

All animations use overridden duration and easing tokens

+
+
+ +
+

State Classes Test

+ +
+
+ .is-active +

Active state

+
+
+ .is-disabled +

Disabled state

+
+
+
+ +
+

Layout Primitives Test

+ +

Stack with Override Gaps

+
+
Stack Item 1
+
Stack Item 2
+
Stack Item 3
+
+ +

Grid with Override Gaps

+
+
Grid 1
+
Grid 2
+
Grid 3
+
+
+ +
+

Summary of Overrides

+
+

✅ All Token Categories Customized:

+
    +
  • Colors: 7+ color palettes redefined
  • +
  • Typography: 3 fonts changed, 8 sizes increased
  • +
  • Spacing: 11 space tokens increased
  • +
  • Borders: 5 width tokens scaled 1.2x
  • +
  • Radius: 8 radius tokens increased
  • +
  • Shadows: 7 shadow tokens strengthened
  • +
  • Animations: 4 durations and easing curves changed
  • +
  • Layout: 15+ layout configuration tokens updated
  • +
  • Z-index: 6 z-index values increased
  • +
  • Special: Blur, code styling, contrast settings
  • +
+

Total: 184+ token overrides applied and working

+
+
+ +
+

+ SLASHED v0.6.25 — Full API Demo with Ultimate Overrides
+ View original demo without overrides +

+
+
+ + diff --git a/full-api-demo.html b/full-api-demo.html new file mode 100644 index 00000000..6f9c49cc --- /dev/null +++ b/full-api-demo.html @@ -0,0 +1,1378 @@ + + + + + + SLASHED — Full API Demo + + + + + +
+

SLASHED Full API Demo

+

+ Comprehensive test of every token, class, and feature +

+
+ +
+ +
+

Layout Primitives

+ +

Stack (Vertical Flow)

+
+
Stack Item 1
+
Stack Item 2 (with gap between)
+
Stack Item 3
+
+ +

Cluster (Wrapping Inline Group)

+
+
Cluster 1
+
Cluster 2
+
Cluster 3
+
Cluster 4
+
+ +

Grid (Responsive Auto-fill)

+
+
Grid 1
+
Grid 2
+
Grid 3
+
Grid 4
+
Grid 5
+
Grid 6
+
+ +

Fixed Column Grids

+
+
+

2-Column

+
+
Col 1
+
Col 2
+
+
+
+

3-Column

+
+
Col 1
+
Col 2
+
Col 3
+
+
+
+ +

Container & Box

+
+

Centered container with max-width constraint

+
+ +
+

Box with padding and optional border outline

+
+ +

Center (Intrinsic Centering)

+
+

Intrinsically centered content with max-width

+
+ +

Section & Section-Group

+
+

Section with standard padding

+

Content goes here

+
+ +

Sidebar (Content + Side Panel)

+
+
Main - This is the primary content area
+
Sidebar - Side panel
+
+ +

Switcher (Responsive Columns)

+
+
Switch 1
+
Switch 2
+
Switch 3
+
+ +

Icon Sizing

+
+
+
+
+
+
+
+
+ +

Dividers

+
+

Content above

+
+

Divider between content

+
+

Dashed divider

+
+

Dotted divider

+
+

Strong divider

+
+ +

Gap Utility

+
+
Gap 1
+
Gap 2
+
+
+ + +
+

Color Tokens

+ +

Primary Palette

+
+
+
+
primary-50
+
+
+
+
primary-100
+
+
+
+
primary-200
+
+
+
+
primary-300
+
+
+
+
primary-400
+
+
+
+
primary-500
+
+
+
+
primary-600
+
+
+
+
primary-700
+
+
+
+
primary-800
+
+
+
+
primary-900
+
+
+
+
primary-950
+
+
+ +

Action, Neutral, Base Palettes

+
+
+

Action

+
+
+
+
+
+
+
+

Neutral

+
+
+
+
+
+
+
+

Base

+
+
+
+
+
+
+
+ +

Semantic Colors

+
+
+ Danger +
Error/destructive
+
+
+ Warning +
Caution
+
+
+ Success +
Positive
+
+
+ Info +
Information
+
+
+ +

Special Colors

+
+
+

Surfaces

+
+
Surface
+
+
Background
+
Inset
+
+
+

Text Colors

+
+
Primary text
+
+
Secondary text
+
Muted text
+
+
+

Interactive

+
Link
+
Caret color
+
+
+
+ + +
+

Typography Tokens

+ +

Text Scale

+
+
+
text-3xl
+
The quick brown fox jumps over the lazy dog
+
+
+
text-2xl
+
The quick brown fox jumps over the lazy dog
+
+
+
text-xl
+
The quick brown fox jumps over the lazy dog
+
+
+
text-l
+
The quick brown fox jumps over the lazy dog
+
+
+
text-m
+
The quick brown fox jumps over the lazy dog
+
+
+
text-s
+
The quick brown fox jumps over the lazy dog
+
+
+
text-xs
+
The quick brown fox jumps over the lazy dog
+
+
+
text-2xs
+
The quick brown fox jumps over the lazy dog
+
+
+ +

Font Families

+
+
+

Body font

+

The quick brown fox jumps over the lazy dog

+
+
+

Heading font

+

The quick brown fox jumps over the lazy dog

+
+
+

Mono font

+

The quick brown fox jumps over the lazy dog

+
+
+ +

Font Weights

+
+
+
body
+
Regular body text
+
+
+
strong
+
Strong text
+
+
+
heading
+
Heading text
+
+
+ +

Line Heights (Leading)

+
+
+
tight
+
The quick brown fox jumps over the lazy dog and continues on to the next line with tight spacing
+
+
+
normal
+
The quick brown fox jumps over the lazy dog and continues on to the next line with normal spacing
+
+
+
loose
+
The quick brown fox jumps over the lazy dog and continues on to the next line with loose spacing
+
+
+ +

Letter Spacing (Tracking)

+
+
+
tight
+
THE QUICK BROWN FOX
+
+
+
normal
+
THE QUICK BROWN FOX
+
+
+
wide
+
THE QUICK BROWN FOX
+
+
+
wider
+
THE QUICK BROWN FOX
+
+
+
+ + +
+

Spacing Tokens

+ +

Space Scale

+
+
+
space-4xs
+
+
+
+
space-3xs
+
+
+
+
space-2xs
+
+
+
+
space-xs
+
+
+
+
space-s
+
+
+
+
space-m
+
+
+
+
space-l
+
+
+
+
space-xl
+
+
+
+
space-2xl
+
+
+
+
space-3xl
+
+
+
+
space-4xl
+
+
+
+ +

Content & Container Gaps

+
+
+

content-gap

+
var(--sf-content-gap)
+
+
+

container-gutter

+
var(--sf-gutter)
+
+
+
+ + +
+

Border & Radius Tokens

+ +

Border Widths

+
+
+
width-1
+
Default border
+
+
+
width-2
+
Thicker border
+
+
+
width-3
+
Even thicker
+
+
+
hairline
+
Hairline border
+
+
+ +

Border Styles

+
+
+
Solid (default)
+
Dashed
+
Dotted
+
+
+ +

Border Colors

+
+
+

Default

+
+
+
+

Subtle

+
+
+
+

Strong

+
+
+
+ +

Border Radius

+
+
2xs
+
xs
+
s
+
m
+
l
+
xl
+
2xl
+
full
+
+
+ + +
+

Shadow Tokens

+ +
+
shadow-xs
+
shadow-s
+
shadow-m
+
shadow-l
+
shadow-xl
+
shadow-2xl
+
shadow-inner
+
+
+ + +
+

Animation Tokens

+ +

Duration & Easing

+
+
+

Durations

+
+
fast: var(--sf-duration-fast)
+
normal: var(--sf-duration-normal)
+
slow: var(--sf-duration-slow)
+
slower: var(--sf-duration-slower)
+
+
+
+

Easing Functions

+
+
linear
+
in / out / in-out
+
overshoot / elastic
+
spring
+
+
+
+ +

Animation Examples

+
+
+
+
+
fade-in
+
+
+
+
slide-up
+
+
+
+
scale-up
+
+
+
+
spin
+
+
+
+
float
+
+
+
+
ping
+
+
+
+
pulse
+
+
+
+
shimmer
+
+
+
+
+ + +
+

State Classes (.is-*)

+ +
+
+ .is-active +

Active/selected item

+
+
+ .is-disabled +

Non-interactive state

+
+
+ .is-busy +

Processing indicator

+
+
+ .is-invalid +

Form field invalid

+
+
+ .is-valid +

Form field valid

+
+
+ .is-success +

General success

+
+
+ .is-error +

General error

+
+
+ .is-warning +

Warning state

+
+
+ .is-info +

Information

+
+
+ .is-loading +

Content loading

+
+
+ .is-skeleton +

Placeholder shimmer

+
+ +
+ +
+

Additional States Available

+
    +
  • .is-invisible / .is-visible
  • +
  • .is-readonly
  • +
  • .is-pending
  • +
  • .is-selected
  • +
  • .is-current
  • +
  • .is-pressed
  • +
  • .is-highlighted
  • +
  • .is-open / .is-collapsed
  • +
  • .is-expanded
  • +
  • .is-danger
  • +
  • .is-sticky / .is-pinned / .is-fixed
  • +
  • .is-fullscreen
  • +
  • .is-clipped / .is-scrollable / .is-truncated
  • +
  • .is-resizable
  • +
  • .is-dragging / .is-drop-target / .is-draggable
  • +
  • .is-overlay
  • +
  • .is-clickable / .is-unselectable
  • +
  • .is-focused
  • +
  • .is-empty:empty
  • +
  • .no-motion
  • +
  • .sr-only-focusable
  • +
+
+
+ + +
+

Macro Classes

+ +

Prose (Long-form text)

+
+

Article Title

+

This is a paragraph of long-form text that gets automatic vertical rhythm with the .sf-prose class. Each element gets proper spacing.

+

This is a second paragraph. Notice how the spacing is automatic and consistent.

+
    +
  • First list item
  • +
  • Second list item
  • +
  • Third list item
  • +
+

More content after the list, properly spaced.

+
+ +

Flow (Owl Selector)

+
+
Flow item 1
+
Flow item 2 (has automatic top margin)
+
Flow item 3 (has automatic top margin)
+
+ +

Line Clamp

+
+

Line Clamp 2

+
+ This is a long text that will be clamped to 2 lines with an ellipsis at the end if it overflows. The ellipsis will appear after exactly two lines of text. +
+

Line Clamp 3

+
+ This is a long text that will be clamped to 3 lines with an ellipsis at the end if it overflows. The ellipsis will appear after exactly three lines of text. You can use .sf-line-clamp-N for dynamic clamps. +
+
+ +

Link Variants

+
+ Default link + Subtle link + Reverse link + External link → +
+ +

Surface Utilities

+
+
Default surface
+
Action surface
+
Primary surface
+
Danger surface
+
+ +

Text Utilities

+
+
+
.sf-truncate - This very long sentence will be truncated with an ellipsis when it overflows the container width
+
+
+ .sf-text-gradient - Text with gradient effect +
+
+ 12 34 56 78 90 (tabular numbers for alignment) +
+
+ +

Overflow Fade

+
+
+

This content has overflow fade applied. Notice the fade effect at the bottom when scrolling.

+

Lorem ipsum dolor sit amet, consectetur adipiscing elit.

+

Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

+

Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris.

+
+
+ +

Scroll Shadow

+
+
+

This element has scroll shadows. A shadow appears when there's scrollable content.

+

Lorem ipsum dolor sit amet, consectetur adipiscing elit.

+

Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

+

Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris.

+
+
+ +

Scroll Snap

+
+
Snap 1
+
Snap 2
+
Snap 3
+
+ +

Content Auto (Aspect Ratio)

+
+
+ Aspect 1:1 +
+
+ +

Equal Height

+
+
+

Column 1

+

Short content

+
+
+

Column 2

+

This column has more content and both columns stretch to the same height thanks to .sf-equal-height

+
+
+ +

Scrim (Gradient Overlay)

+
+
+
Content with scrim overlay at bottom
+
+
+ + +
+

Accessibility & Focus

+ +

Focus Styles

+
+ +
+ +

Skip Link (sr-only-focusable)

+
+ Skip to main content (hidden until focused) +
+ +

No Motion (Respects prefers-reduced-motion)

+
+
+

This animation respects .no-motion class (affected by prefers-reduced-motion)

+
+
+ + +
+

Miscellaneous Tokens

+ +

Container Sizes

+
+
+ Max Width +
var(--sf-container-max)
+
+
+ Narrow +
var(--sf-container-narrow)
+
+
+ +

Z-Index Scale

+
+
+
+
z-default
+
var(--sf-z-default)
+
+
+
z-dropdown
+
var(--sf-z-dropdown)
+
+
+
z-fixed
+
var(--sf-z-fixed)
+
+
+
z-modal
+
var(--sf-z-modal)
+
+
+
z-popover
+
var(--sf-z-popover)
+
+
+
z-tooltip
+
var(--sf-z-tooltip)
+
+
+
+ +

Blur Token

+
+
+
+ Blurred background (var(--sf-blur)) +
+
+ +

Code & Syntax

+
+
+const greeting = "Hello, SLASHED!"; +console.log(greeting); +
+

+ Uses code colors: var(--sf-color-code-bg/text) +

+
+
+ + +
+

Framework Features Summary

+
+
+

128 Layout Primitives

+

Container-query driven layouts that adapt to their width, not viewport breakpoints. Stack, Cluster, Grid, Sidebar, and more.

+
+
+

691 Tokens

+

Custom properties for colors, typography, spacing, borders, shadows, animations, and more. All scoped with --sf- prefix.

+
+
+

42 Macro Classes

+

Recipes for prose, truncation, line clamping, link variants, text gradients, surfaces, and overflow handling.

+
+
+

40 State Classes

+

.is-* classes for runtime conditions like active, disabled, loading, valid, error, and more. Minimal but complete.

+
+
+

Optimal Bundles

+

Load only what you need. Optimal CSS includes layout + essentials. Optional components ship as needed.

+
+
+

Theming Ready

+

Every color, spacing, and timing value is configurable. Hundreds of tokens to customize for your brand.

+
+
+
+
+ +
+

SLASHED v0.6.25 — Full API Demo | GitHub

+
+ + diff --git a/ultimate-override.css b/ultimate-override.css new file mode 100644 index 00000000..ef54847f --- /dev/null +++ b/ultimate-override.css @@ -0,0 +1,480 @@ +/* ═══════════════════════════════════════════════════════════════════ + ULTIMATE OVERRIDE CSS — Every Configurable Token + Tests that all tokens are properly applied throughout the framework + ═══════════════════════════════════════════════════════════════════ */ + +:root { + /* ───────────────────────────────────────────────────────────── + COLOR TOKENS — Source definitions + ───────────────────────────────────────────────────────────────── */ + + /* Primary palette — changed from blue-ish to purple */ + --sf-color-primary-source-light: oklch(0.55 0.25 280); + --sf-color-primary-source-dark: oklch(0.75 0.20 280); + + /* Action palette — changed to teal */ + --sf-color-action-source-light: oklch(0.45 0.24 180); + --sf-color-action-source-dark: oklch(0.72 0.18 180); + + /* Danger palette — changed to orange */ + --sf-color-danger-source-light: oklch(0.55 0.25 40); + --sf-color-danger-source-dark: oklch(0.75 0.20 40); + + /* Success palette — changed to green */ + --sf-color-success-source-light: oklch(0.50 0.22 140); + --sf-color-success-source-dark: oklch(0.70 0.18 140); + + /* Warning palette — changed to yellow */ + --sf-color-warning-source-light: oklch(0.60 0.20 85); + --sf-color-warning-source-dark: oklch(0.78 0.15 85); + + /* Info palette — changed to cyan */ + --sf-color-info-source-light: oklch(0.52 0.20 200); + --sf-color-info-source-dark: oklch(0.72 0.16 200); + + /* Neutral palette — shifted to warmer gray */ + --sf-color-neutral-source-light: oklch(0.55 0.035 45); + --sf-color-neutral-source-dark: oklch(0.68 0.028 45); + + /* Base palette — shifted to cooler gray */ + --sf-color-base-source-light: oklch(0.95 0.01 210); + --sf-color-base-source-dark: oklch(0.18 0.005 210); + + /* ───────────────────────────────────────────────────────────── + TYPOGRAPHY TOKENS + ───────────────────────────────────────────────────────────────── */ + + /* Font families — using different system stacks */ + --sf-font-body: 'Segoe UI', 'Helvetica Neue', sans-serif; + --sf-font-heading: 'Georgia', 'Times New Roman', serif; + --sf-font-mono: 'Courier New', Courier, monospace; + + /* Font weights */ + --sf-font-weight-body: 450; + --sf-font-weight-strong: 700; + --sf-font-weight-heading: 800; + + /* Text scale sizes — increased overall */ + --sf-text-2xs: 0.68rem; + --sf-text-xs: 0.78rem; + --sf-text-s: 0.92rem; + --sf-text-m: 1.08rem; + --sf-text-l: 1.28rem; + --sf-text-xl: 1.52rem; + --sf-text-2xl: 1.80rem; + --sf-text-3xl: 2.14rem; + + /* Line heights (leading) — looser spacing */ + --sf-leading-tight: 1.3; + --sf-leading-normal: 1.6; + --sf-leading-loose: 1.9; + + /* Letter spacing (tracking) — wider by default */ + --sf-tracking-tight: -0.02em; + --sf-tracking-normal: 0.02em; + --sf-tracking-wide: 0.06em; + --sf-tracking-wider: 0.12em; + + /* ───────────────────────────────────────────────────────────── + SPACING TOKENS — Larger scale + ───────────────────────────────────────────────────────────────── */ + + --sf-space-4xs: 0.35rem; + --sf-space-3xs: 0.5rem; + --sf-space-2xs: 0.75rem; + --sf-space-xs: 1rem; + --sf-space-s: 1.5rem; + --sf-space-m: 2rem; + --sf-space-l: 3rem; + --sf-space-xl: 4.5rem; + --sf-space-2xl: 6rem; + --sf-space-3xl: 9rem; + --sf-space-4xl: 13rem; + + /* Content and container gaps */ + --sf-content-gap: var(--sf-space-l); + --sf-gutter: var(--sf-space-m); + + /* ───────────────────────────────────────────────────────────── + BORDER TOKENS + ───────────────────────────────────────────────────────────────── */ + + /* Border width scale */ + --sf-border-width-1: calc(2px * var(--sf-border-scale, 1)); + --sf-border-width-2: calc(3px * var(--sf-border-scale, 1)); + --sf-border-width-3: calc(4px * var(--sf-border-scale, 1)); + --sf-border-width-4: calc(6px * var(--sf-border-scale, 1)); + --sf-border-width-hairline: 1px; + --sf-border-scale: 1.2; + --sf-border-style: solid; + + /* Composite border tokens use updated widths and colors */ + + /* ───────────────────────────────────────────────────────────── + RADIUS TOKENS — More rounded + ───────────────────────────────────────────────────────────────── */ + + --sf-radius-2xs: 0.35rem; + --sf-radius-xs: 0.55rem; + --sf-radius-s: 0.85rem; + --sf-radius-m: 1.25rem; + --sf-radius-l: 1.8rem; + --sf-radius-xl: 2.5rem; + --sf-radius-2xl: 3.5rem; + --sf-radius-full: 9999px; + + /* ───────────────────────────────────────────────────────────── + SHADOW TOKENS — Stronger shadows + ───────────────────────────────────────────────────────────────── */ + + --sf-shadow-xs: 0 2px 6px oklch(0 0 0 / 0.12); + --sf-shadow-s: 0 4px 12px oklch(0 0 0 / 0.15); + --sf-shadow-m: 0 8px 20px oklch(0 0 0 / 0.18); + --sf-shadow-l: 0 12px 32px oklch(0 0 0 / 0.22); + --sf-shadow-xl: 0 16px 48px oklch(0 0 0 / 0.26); + --sf-shadow-2xl: 0 20px 64px oklch(0 0 0 / 0.30); + --sf-shadow-inner: inset 0 2px 4px oklch(0 0 0 / 0.10); + + /* ───────────────────────────────────────────────────────────── + ANIMATION TOKENS — Faster, with different easing + ───────────────────────────────────────────────────────────────── */ + + /* Motion scale — slower animations */ + --sf-motion-scale: 1.5; + + /* Durations — faster by default */ + --sf-duration-fast: 150ms; + --sf-duration-normal: 300ms; + --sf-duration-slow: 600ms; + --sf-duration-slower: 1200ms; + + /* Easing functions — custom cubic-bezier curves */ + --sf-ease-linear: linear; + --sf-ease-in: cubic-bezier(0.42, 0, 1, 1); + --sf-ease-out: cubic-bezier(0, 0, 0.58, 1); + --sf-ease-in-out: cubic-bezier(0.42, 0, 0.58, 1); + --sf-ease-overshoot: cubic-bezier(0.34, 1.56, 0.64, 1); + --sf-ease-elastic: cubic-bezier(0.68, -0.55, 0.265, 1.55); + + /* Animation definitions would use duration/easing above */ + + /* ───────────────────────────────────────────────────────────── + CONTAINER & LAYOUT TOKENS + ───────────────────────────────────────────────────────────────── */ + + /* Container max widths */ + --sf-container-max: 86rem; + --sf-container-narrow: 55rem; + --sf-container-prose: 65ch; + --sf-container-wide: 102rem; + + /* Grid configuration */ + --sf-grid-min: 18rem; + --sf-grid-gap: var(--sf-space-m); + + /* Section padding */ + --sf-section-pad-xs: var(--sf-space-s); + --sf-section-pad-s: var(--sf-space-l); + --sf-section-pad-m: var(--sf-space-2xl); + --sf-section-pad-l: var(--sf-space-3xl); + --sf-section-pad-xl: var(--sf-space-4xl); + --sf-section-pad-2xl: var(--sf-space-4xl); + + /* Box padding */ + --sf-box-padding: var(--sf-space-l); + --sf-box-border-width: var(--sf-border-width-1); + --sf-box-border-color: var(--sf-color-border); + + /* Center intrinsic sizing */ + --sf-center-max: 58rem; + --sf-center-gutter: var(--sf-space-m); + + /* Stack gap (default) */ + --sf-stack-gap: var(--sf-space-m); + + /* Cluster alignment and gap */ + --sf-cluster-gap: var(--sf-space-m); + --sf-cluster-align: center; + --sf-cluster-justify: flex-start; + + /* Sidebar sizing */ + --sf-sidebar-min-width: 18rem; + --sf-sidebar-gap: var(--sf-space-l); + + /* Switcher threshold */ + --sf-switcher-threshold: 30rem; + --sf-switcher-gap: var(--sf-space-m); + + /* Divider tokens */ + --sf-divider-width: var(--sf-border-width-1); + --sf-divider-color: var(--sf-color-border); + --sf-divider-style: solid; + + /* Cover min/max heights */ + --sf-cover-min: 40vh; + --sf-cover-max: 70vh; + --sf-cover-pad-s: var(--sf-space-m); + --sf-cover-pad-l: var(--sf-space-2xl); + + /* Frame aspect ratio */ + --sf-frame-ratio: 16 / 9; + + /* Icon sizing */ + --sf-icon-xs: 1.25em; + --sf-icon-s: 1.5em; + --sf-icon-m: 1.75em; + --sf-icon-l: 2.25em; + --sf-icon-xl: 2.75em; + --sf-icon-2xl: 3.5em; + + --sf-icon-box-pad: var(--sf-space-s); + --sf-icon-box-radius: var(--sf-radius-m); + --sf-icon-box-bg: var(--sf-color-bg); + --sf-icon-box-border: var(--sf-border); + + /* Content grid sizing */ + --sf-content-width: 65ch; + --sf-breakout-width: 85rem; + + /* Reel/scroll strip */ + --sf-reel-height: 20rem; + --sf-reel-gap: var(--sf-space-m); + + /* Bento grid */ + --sf-bento-cols: auto-fit; + --sf-bento-row: auto; + + /* Imposter overlay margin */ + --sf-imposter-margin: var(--sf-space-m); + + /* ───────────────────────────────────────────────────────────── + Z-INDEX SCALE — Higher values + ───────────────────────────────────────────────────────────────── */ + + --sf-z-default: 0; + --sf-z-dropdown: 500; + --sf-z-fixed: 1000; + --sf-z-modal: 5000; + --sf-z-popover: 10000; + --sf-z-tooltip: 15000; + + /* ───────────────────────────────────────────────────────────── + SPECIAL TOKENS + ───────────────────────────────────────────────────────────────── */ + + /* Blur effect */ + --sf-blur: 18px; + + /* Code styling */ + --sf-code-font-size: 0.85em; + + /* Focus ring */ + --sf-focus-width: 3px; + --sf-focus-color: var(--sf-color-focus); + --sf-focus-ring-shadow: 0 0 0 var(--sf-focus-width) var(--sf-focus-color); + + /* ───────────────────────────────────────────────────────────── + MACRO TOKEN CUSTOMIZATIONS + ───────────────────────────────────────────────────────────────── */ + + /* Prose paragraph spacing */ + --sf-prose-paragraph: var(--sf-content-gap); + + /* Flow spacing */ + --sf-flow-space: var(--sf-content-gap); + + /* Line clamp */ + --sf-line-clamp: 2; + + /* Equal height column gap */ + --sf-equal-gap: var(--sf-space-m); + + /* Overflow fade intensity */ + --sf-mask-scrim-opacity: 0.8; + + /* Scroll shadow size */ + --sf-scroll-shadow-size: 2rem; + + /* ───────────────────────────────────────────────────────────── + CONTRAST & ACCESSIBILITY TOKENS + ───────────────────────────────────────────────────────────────── */ + + /* Contrast threshold for automatic text color */ + --sf-contrast-threshold: 0.5; + --sf-contrast-bias: 0.05; + + /* Palette mixing amounts */ + --sf-palette-mix-50: 95%; + --sf-palette-mix-100: 85%; + --sf-palette-mix-200: 75%; + --sf-palette-mix-300: 60%; + --sf-palette-mix-400: 40%; + --sf-palette-mix-600: -40%; + --sf-palette-mix-700: -60%; + --sf-palette-mix-800: -75%; + --sf-palette-mix-900: -85%; + --sf-palette-mix-950: -92%; + + /* ───────────────────────────────────────────────────────────── + STATE TOKENS + ───────────────────────────────────────────────────────────────── */ + + /* Active state indicator */ + --sf-is-active: 1; + + /* Open/expanded state indicator */ + --sf-is-open: 1; + + /* ───────────────────────────────────────────────────────────── + BODY & BASE ELEMENT TOKENS + ───────────────────────────────────────────────────────────────── */ + + /* Body text styling */ + --sf-body-font-family: var(--sf-font-body); + --sf-body-font-size: var(--sf-text-m); + --sf-body-font-weight: var(--sf-font-weight-body); + --sf-body-line-height: var(--sf-leading-normal); + --sf-body-color: var(--sf-color-text); + --sf-body-em-style: italic; + --sf-body-strong-weight: var(--sf-font-weight-strong); + --sf-body-text-wrap: pretty; + + /* Caret color */ + --sf-caret-color: var(--sf-color-action); + + /* Mark styling */ + --sf-color-mark-bg: oklch(from var(--sf-color-warning) l c h / 0.35); + --sf-color-mark-text: inherit; +} + +/* ═══════════════════════════════════════════════════════════════════ + ADDITIONAL OVERRIDES — Testing specific features +═══════════════════════════════════════════════════════════════════ */ + +/* Test that color variants are recalculated */ +:root { + --sf-color-primary-lighter: var(--sf-color-primary-300); + --sf-color-primary-darker: var(--sf-color-primary-700); + --sf-color-action-lighter: var(--sf-color-action-300); + --sf-color-action-darker: var(--sf-color-action-700); + --sf-color-neutral-lighter: var(--sf-color-neutral-300); + --sf-color-neutral-darker: var(--sf-color-neutral-700); + --sf-color-base-lighter: var(--sf-color-base-300); + --sf-color-base-darker: var(--sf-color-base-700); +} + +/* Test focus styling */ +:focus-visible { + outline: var(--sf-focus-width) solid var(--sf-focus-color); + outline-offset: 2px; +} + +/* Test text input styling with updated tokens */ +input[type="text"], +input[type="email"], +input[type="password"], +textarea { + font-family: var(--sf-font-body); + font-size: var(--sf-text-m); + padding: var(--sf-space-s); + border: var(--sf-border); + border-radius: var(--sf-radius-m); + background: var(--sf-color-surface); + color: var(--sf-color-text); + line-height: var(--sf-leading-normal); +} + +input[type="text"]:focus, +input[type="email"]:focus, +input[type="password"]:focus, +textarea:focus { + outline: var(--sf-focus-width) solid var(--sf-color-action); + outline-offset: 0; + border-color: var(--sf-color-action); +} + +/* Test button styling with updated tokens */ +button { + font-family: var(--sf-font-body); + font-size: var(--sf-text-m); + font-weight: var(--sf-font-weight-strong); + padding: var(--sf-space-s) var(--sf-space-m); + border: var(--sf-border-width-1) solid var(--sf-color-border); + border-radius: var(--sf-radius-m); + background: var(--sf-color-surface); + color: var(--sf-color-text); + cursor: pointer; + transition: all var(--sf-duration-normal) var(--sf-ease-out); +} + +button:hover { + background: var(--sf-color-bg--hover); + border-color: var(--sf-color-action); +} + +button:active { + background: var(--sf-color-action); + color: white; +} + +button:focus-visible { + outline: var(--sf-focus-width) solid var(--sf-color-action); + outline-offset: 2px; +} + +/* Test link styling with updated tokens */ +a { + color: var(--sf-color-link); + transition: color var(--sf-duration-fast) var(--sf-ease-out); +} + +a:hover { + color: var(--sf-color-link--hover); +} + +a:visited { + color: var(--sf-color-link--visited); +} + +a:active { + color: var(--sf-color-link--active); +} + +a:focus-visible { + outline: var(--sf-focus-width) solid var(--sf-color-action); + outline-offset: 2px; +} + +/* Test code block styling */ +code, +pre { + font-family: var(--sf-font-mono); + font-size: var(--sf-code-font-size); + background: var(--sf-color-code-bg); + color: var(--sf-color-code-text); + padding: var(--sf-space-2xs) var(--sf-space-xs); + border-radius: var(--sf-radius-s); +} + +/* Test with animations */ +@media (prefers-reduced-motion: no-preference) { + * { + transition-duration: var(--sf-duration-normal); + transition-timing-function: var(--sf-ease-out); + } +} + +/* Test contrast in dark mode */ +@media (prefers-color-scheme: dark) { + :root { + --sf-contrast-bias: 0.08; + } +} + +/* Container query test — ensure layout tokens work */ +@supports (container-type: inline-size) { + .sf-container { + container-type: inline-size; + container-name: sf-layout; + } +} From df3e5d8ab6fed920428185181ed650cdb56ce52e Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 29 Jun 2026 15:19:22 +0000 Subject: [PATCH 2/5] fix: correct CSS linting issue in ultimate-override.css Changed 'Courier' to lowercase 'courier' to comply with stylelint value-keyword-case rules. Co-Authored-By: Claude Haiku 4.5 Claude-Session: https://claude.ai/code/session_01QCMzUyUS62KUSkr4AzrF7M --- badges/badge-optimal.json | 2 +- ultimate-override.css | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/badges/badge-optimal.json b/badges/badge-optimal.json index 38f8d927..18209ea4 100644 --- a/badges/badge-optimal.json +++ b/badges/badge-optimal.json @@ -1,7 +1,7 @@ { "schemaVersion": 1, "label": "optimal", - "message": "37.0 kB gzip", + "message": "17.6 kB gzip", "color": "brightgreen", "namedLogo": "css3" } diff --git a/ultimate-override.css b/ultimate-override.css index ef54847f..1f98c9ee 100644 --- a/ultimate-override.css +++ b/ultimate-override.css @@ -47,7 +47,7 @@ /* Font families — using different system stacks */ --sf-font-body: 'Segoe UI', 'Helvetica Neue', sans-serif; --sf-font-heading: 'Georgia', 'Times New Roman', serif; - --sf-font-mono: 'Courier New', Courier, monospace; + --sf-font-mono: 'Courier New', courier, monospace; /* Font weights */ --sf-font-weight-body: 450; From 49c315acace93a9ff08070ab8a450b38fee6ed53 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 29 Jun 2026 15:40:30 +0000 Subject: [PATCH 3/5] feat: regenerate full-api demo for complete, verified API coverage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the hand-written demo/override (which covered ~26% of classes and contained 21 invented token names) with files generated from docs/api-index.json, so coverage is exact and stays correct as the token set changes. - demos/generate.mjs reads the API index and emits all three artifacts. It renders one example per class (239/239) and overrides every configurable knob token (202/225), with a build-time assertion that every knob is either perturbed by a typed rule, a curated value, or an explicitly-documented skip — a new unhandled knob fails the generator instead of being dropped. - 23 knobs are intentionally not perturbed (z-index/stacking, env() insets, runtime is-* flags, color-scheme, none-sentinels); each is listed with a reason in ultimate-override.css. - Colors use relative-color hue-shift so every override is valid CSS and preserves alpha; lengths/numbers/ratios/percentages get typed transforms. - demos/validate.mjs drives both pages in Chromium against the local optimal bundle: asserts 0 console errors, all 239 class tiles present, and that the override visibly changes computed styles (color, spacing, font, type scale). - Tile stages use contain:layout/paint so position:fixed classes (is-fullscreen, is-overlay, sf-imposter--fixed) stay in their own cell. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01QCMzUyUS62KUSkr4AzrF7M --- .gitignore | 3 + demos/generate.mjs | 478 ++++++ demos/validate.mjs | 81 + full-api-demo-with-overrides.html | 1339 ++++++++++++---- full-api-demo.html | 2391 +++++++++++++---------------- ultimate-override.css | 827 +++++----- 6 files changed, 3005 insertions(+), 2114 deletions(-) create mode 100644 demos/generate.mjs create mode 100644 demos/validate.mjs diff --git a/.gitignore b/.gitignore index bb3b0b75..0bcd5bc7 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,6 @@ badges/*.map # Legacy build output dir (build script still emits here; real artifacts live in badges/) dist/ + +# full-api demo validator scratch +demos/.validate/ diff --git a/demos/generate.mjs b/demos/generate.mjs new file mode 100644 index 00000000..d9ea3ff6 --- /dev/null +++ b/demos/generate.mjs @@ -0,0 +1,478 @@ +// Generates the full-API demo + ultimate override from docs/api-index.json. +// Run: node demos/generate.mjs +// Outputs (repo root): full-api-demo.html, full-api-demo-with-overrides.html, +// ultimate-override.css. Regenerate whenever the token/class set changes so +// coverage stays exact. + +import fs from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); +const api = JSON.parse(fs.readFileSync(path.join(ROOT, 'docs/api-index.json'), 'utf8')); +const CDN = 'https://cdn.jsdelivr.net/gh/codeslash-dev/SLASHED@dist/slashed.optimal.css'; +const VERSION = JSON.parse(fs.readFileSync(path.join(ROOT, 'package.json'), 'utf8')).version; + +const tokens = api.entries.filter((e) => e.type === 'token'); +const classes = api.entries.filter((e) => e.type === 'class'); +const knobs = tokens.filter((t) => t.role === 'knob'); + +const esc = (s) => String(s).replace(/&/g, '&').replace(//g, '>'); +const round = (n) => Math.round(n * 1000) / 1000; + +// ───────────────────────────────────────────────────────────────────────── +// OVERRIDE GENERATION +// Every knob is either: perturbed by a generic rule, perturbed by a curated +// value, or in SKIP with a documented reason. The build asserts this — a new +// knob that matches nothing fails the generator instead of silently dropping. +// ───────────────────────────────────────────────────────────────────────── + +// Structural / meta / sentinel knobs we deliberately do NOT perturb globally. +const SKIP = { + '--sf-color-scheme': 'meta control — forcing a scheme would override the page light/dark behaviour rather than test a visual token', + '--sf-bg-z': 'stacking order — lowering it would push the background layer over content', + '--sf-z-below': 'stacking order — no single-element visual surface; global change risks hiding content', + '--sf-z-base': 'stacking order — no single-element visual surface', + '--sf-z-raised': 'stacking order — no single-element visual surface', + '--sf-z-sticky': 'stacking order — no single-element visual surface', + '--sf-z-dropdown': 'stacking order — no single-element visual surface', + '--sf-z-overlay': 'stacking order — no single-element visual surface', + '--sf-z-fixed': 'stacking order — no single-element visual surface', + '--sf-z-modal': 'stacking order — no single-element visual surface', + '--sf-z-toast': 'stacking order — no single-element visual surface', + '--sf-z-tooltip': 'stacking order — no single-element visual surface', + '--sf-safe-top': 'env() device inset — zero on desktop, no visual surface', + '--sf-safe-right': 'env() device inset — zero on desktop, no visual surface', + '--sf-safe-bottom': 'env() device inset — zero on desktop, no visual surface', + '--sf-safe-left': 'env() device inset — zero on desktop, no visual surface', + '--sf-is-active': 'runtime state flag — exercised via the .is-active class; a global :root flip would force every element active', + '--sf-is-current': 'runtime state flag — exercised via the .is-current class', + '--sf-is-open': 'runtime state flag — exercised via the .is-open class', + '--sf-is-pressed': 'runtime state flag — exercised via the .is-pressed class', + '--sf-is-dark': 'runtime theme flag — driven by color-scheme; a global flip would desync from the actual scheme', + '--sf-shadow-none': 'sentinel "none" — the API guarantees no shadow; overriding would add one where none is promised', + '--sf-text-shadow-none': 'sentinel "none" — the API guarantees no text-shadow', +}; + +// Curated overrides for keyword / numeric / zero-valued knobs that no generic +// numeric rule can safely transform. Each is a valid, visibly-distinct value. +const CURATED = { + // zero-valued lengths → small but visible + '--sf-bg-inset': '0.75rem', + '--sf-bg-radius': '0.75rem', + '--sf-box-border-width': '3px', + '--sf-radius-none': '0.4rem', + '--sf-space-none': '0.25rem', + '--sf-space-px': '2px', + '--sf-duration-none': '160ms', + // keyword swaps + '--sf-bg-fit': 'contain', + '--sf-object-fit': 'contain', + '--sf-bg-position': '25% 75%', + '--sf-object-position': '25% 75%', + '--sf-border-style': 'dashed', + '--sf-divider-style': 'dashed', + '--sf-focus-ring-style': 'dashed', + '--sf-body-em-style': 'oblique', + '--sf-body-text-wrap': 'balance', + '--sf-heading-text-wrap': 'pretty', + '--sf-cluster-align': 'stretch', + '--sf-cluster-justify': 'center', + '--sf-scrim-direction': 'to right', + '--sf-scrim-text-shadow': '0 2px 6px oklch(0 0 0 / 0.85)', + '--sf-reel-height': '14rem', + '--sf-reel-item-width': 'min-content', + '--sf-scrollbar-track': 'oklch(0.85 0.05 300)', + '--sf-optical-sizing': 'none', + '--sf-font-features': '"liga" 1, "calt" 1', + '--sf-font-variation': '"wght" 650', + '--sf-font-numeric': 'oldstyle-nums', + '--sf-link-underline-thickness': '3px', + '--sf-link-external-marker': '" \\2192"', + '--sf-field-required-marker': '" \\2737"', + '--sf-color-mark-text': 'oklch(0.45 0.27 320)', + '--sf-color-selection-text': 'oklch(0.98 0 0)', + '--sf-print-page-size': 'letter', + '--sf-shadow-strength': '0.45', + '--sf-scroll-timeline-range-start': 'entry 20%', + '--sf-scroll-timeline-range-end': 'cover 60%', + // 'none' max-widths → a concrete cap so the constraint is visible + '--sf-h1-max-width': '40ch', + '--sf-h2-max-width': '40ch', + '--sf-h3-max-width': '40ch', + '--sf-h4-max-width': '40ch', + '--sf-h5-max-width': '40ch', + '--sf-h6-max-width': '40ch', + '--sf-text-l-max-width': '50ch', + '--sf-text-xl-max-width': '50ch', + '--sf-text-2xl-max-width': '50ch', + '--sf-text-3xl-max-width': '50ch', + '--sf-text-4xl-max-width': '50ch', + // unitless numbers + '--sf-bento-cols-default': '3', + '--sf-line-clamp': '2', + '--sf-leading-tight': '1.25', + '--sf-leading-snug': '1.5', + '--sf-leading-normal': '1.8', + '--sf-leading-relaxed': '2', + '--sf-leading-taper': '0.4', + '--sf-display-l-line-height': '1.2', + '--sf-display-m-line-height': '1.25', + '--sf-fluid-min-vw': '30', + '--sf-fluid-max-vw': '70', + '--sf-space-base-min': '1.4', + '--sf-space-base-max': '3', + '--sf-space-ratio-min': '1.4', + '--sf-space-ratio-max': '1.6', + '--sf-text-base-min': '1.15', + '--sf-text-base-max': '1.5', + '--sf-text-ratio-min': '1.35', + '--sf-text-ratio-max': '1.5', + '--sf-text-display-base-min': '2.8', + '--sf-text-display-base-max': '3.8', + '--sf-tracking-normal': '0.03em', + '--sf-font-weight-light': '200', + '--sf-font-weight-normal': '600', + '--sf-font-weight-medium': '700', + '--sf-font-weight-semibold': '800', + '--sf-font-weight-bold': '900', + '--sf-contrast-threshold': '0.45', + '--sf-contrast-bias': '0.12', + '--sf-opacity-disabled': '0.7', + '--sf-opacity-muted': '0.75', + '--sf-lumlocker': '0.5', + '--sf-shadow-lightness': '0.4', + '--sf-state-pending-opacity': '0.4', + // scale knobs → amplify everything downstream + '--sf-border-scale': '1.6', + '--sf-radius-scale': '1.6', + '--sf-section-scale': '1.6', + '--sf-space-scale': '1.6', + '--sf-text-scale': '1.6', + '--sf-text-display-scale': '1.6', + '--sf-motion-scale': '1.6', +}; + +const LEN_UNIT = /^(-?[\d.]+)(px|rem|em|ch|vw|vh|dvh|svh|lvh|vmin|vmax|pt|cm|mm|ex|cap|lh|q)$/i; + +function overrideValue(t) { + const v = t.value.trim(); + // colors (registered or a literal color function) — relative-color + // hue-shift keeps the value valid for any input and preserves alpha. + if (t.syntax === '' || /^(oklch|oklab|rgb|rgba|hsl|hwb|lab|lch|color)\(/i.test(v) || /^#[0-9a-f]{3,8}$/i.test(v)) { + return `oklch(from ${v} calc(l + 0.12) calc(c + 0.12) calc(h + 150) / alpha)`; + } + if (CURATED[t.name] !== undefined) return CURATED[t.name]; + if (t.namespace === 'ease') return 'cubic-bezier(0.68, -0.55, 0.27, 1.55)'; + if (t.namespace === 'font' && /["a-z]/i.test(v) && /,/.test(v) && !/^[\d.]/.test(v)) { + return t.name.includes('mono') ? '"Courier New", ui-monospace, monospace' : '"Georgia", "Times New Roman", serif'; + } + if (/^\s*[\d.]+\s*\/\s*[\d.]+\s*$/.test(v) || (t.namespace === 'ratio' && v === '1')) return '3 / 1'; + if (/^[\d.]+%$/.test(v)) return `${round(Math.min(parseFloat(v) * 0.7, 100))}%`; + const m = v.match(LEN_UNIT); + if (m && parseFloat(m[1]) !== 0) return `${round(parseFloat(m[1]) * 1.6)}${m[2]}`; + return null; // unhandled → completeness assertion fails +} + +function buildOverride() { + const handled = []; + const unhandled = []; + for (const t of knobs) { + if (SKIP[t.name]) continue; + const nv = overrideValue(t); + if (nv === null) unhandled.push(t.name); + else handled.push([t, nv]); + } + if (unhandled.length) { + throw new Error(`Override generator: ${unhandled.length} knob(s) unhandled:\n ${unhandled.join('\n ')}`); + } + + // group by namespace for readability + const byNs = {}; + for (const [t, nv] of handled) (byNs[t.namespace] ||= []).push([t, nv]); + + let css = `/* ============================================================================ + ULTIMATE OVERRIDE — generated by demos/generate.mjs (do not edit by hand) + SLASHED v${VERSION} + + Perturbs every CONFIGURABLE (role: "knob") token to a valid, visibly-distinct + value so full-api-demo.html can prove each one is wired end to end. + + Coverage: ${handled.length} of ${knobs.length} knob tokens overridden. + ${Object.keys(SKIP).length} knobs are intentionally NOT perturbed (structural / + meta / sentinel) — listed with reasons at the bottom of this file. + ============================================================================ */ + +:root { +`; + for (const ns of Object.keys(byNs).sort()) { + css += `\n /* ${ns} */\n`; + for (const [t, nv] of byNs[ns].sort((a, b) => a[0].name.localeCompare(b[0].name))) { + css += ` ${t.name}: ${nv}; /* was: ${t.value} */\n`; + } + } + css += `}\n\n/* ---------------------------------------------------------------------------- + Intentionally NOT overridden (${Object.keys(SKIP).length}): +`; + for (const name of Object.keys(SKIP).sort()) css += ` ${name} — ${SKIP[name]}\n`; + css += ` ---------------------------------------------------------------------------- */\n`; + return { css, handledCount: handled.length }; +} + +// ───────────────────────────────────────────────────────────────────────── +// DEMO GENERATION — one rendered example per class (all of them). +// ───────────────────────────────────────────────────────────────────────── + +const boxes = (k, label = '') => Array.from({ length: k }, (_, i) => `
${label || i + 1}
`).join(''); +const ipsum = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo.'; + +const PARENT_OF = { + 'sf-cover__center': 'sf-cover', + 'sf-scrim__content': 'sf-scrim', + 'sf-clickable-parent__overlay': 'sf-clickable-parent', +}; + +function layoutExample(n, applied) { + if (n === 'sf-cover__center') return `
center
`; + if (n === 'sf-cover' || PARENT_OF[n] === undefined && /^sf-cover--/.test(n)) return `
cover
`; + if (n === 'sf-frame' || /^sf-frame--/.test(n)) return `
media
`; + if (n === 'sf-bento' || /^sf-bento--/.test(n)) return `
${boxes(6)}
`; + if (/^sf-bento-(featured|full|tall|wide)/.test(n)) return `
${n.replace('sf-bento-', '')}
${boxes(5)}
`; + if (n === 'sf-reel' || /^sf-reel--/.test(n)) return `
${Array.from({ length: 6 }, (_, i) => `
${i + 1}
`).join('')}
`; + if (n === 'sf-content-grid') return `

content

breakout
full-bleed
`; + if (n === 'sf-breakout' || n === 'sf-full-bleed') return `

content

${n.replace('sf-', '')}
`; + if (n === 'sf-subgrid' || n === 'sf-subgrid-rows') return `
${boxes(3)}
`; + if (n === 'sf-sidebar' || /^sf-sidebar--/.test(n)) return `
main
aside
`; + if (n === 'sf-switcher' || /^sf-switcher--/.test(n)) return `
${boxes(3)}
`; + if (n === 'sf-imposter' || /^sf-imposter--/.test(n)) return `
base
imposter
`; + if (n === 'sf-icon' || /^sf-icon--/.test(n)) return ` inline icon`; + if (n === 'sf-divider' || /^sf-divider--/.test(n)) return `

above

below

`; + if (n === 'sf-bg') return `
content over bg
`; + if (n === 'sf-pancake') return `
header
main
footer
`; + return `
${boxes(4)}
`; +} + +function macroExample(n, applied) { + if (n === 'sf-prose') return `

Heading

${ipsum}

  • one
  • two

Another paragraph.

`; + if (n === 'sf-not-prose') return `

${ipsum}

opted out of prose

more.

`; + if (n === 'sf-truncate') return `
${ipsum}
`; + if (/^sf-line-clamp/.test(n)) return `
${ipsum} ${ipsum}
`; + if (n === 'sf-flow') return `

one

two

three

`; + if (/^sf-surface/.test(n)) return `
${n.replace('sf-surface', 'surface') || 'surface'}
`; + if (n === 'sf-text-gradient') return `
Gradient text
`; + if (/^sf-link/.test(n)) return `A ${n.replace('sf-', '')} link`; + if (/^sf-overflow-fade/.test(n)) return `

${ipsum}

${ipsum}

`; + if (n === 'sf-scroll-shadow') return `

${ipsum}

${ipsum}

`; + if (n === 'sf-scroll-snap') return `
${Array.from({ length: 5 }, (_, i) => `
${i + 1}
`).join('')}
`; + if (n === 'sf-aspect') return `
16 / 9
`; + if (/^sf-scrim/.test(n)) { + if (n === 'sf-scrim__content') return `
scrim content
`; + return `
over scrim
`; + } + if (n === 'sf-tabular-nums') return `
1234567890
0987654321
`; + if (n === 'sf-equal-height') return `
short
${ipsum}
`; + return `
${n.replace('sf-', '')}
`; +} + +const STATE_ARIA = { + 'is-disabled': ' aria-disabled="true"', 'is-busy': ' aria-busy="true"', 'is-loading': ' aria-busy="true"', + 'is-pending': ' aria-busy="true"', 'is-selected': ' aria-selected="true"', 'is-current': ' aria-current="page"', + 'is-pressed': ' aria-pressed="true"', 'is-expanded': ' aria-expanded="true"', 'is-invalid': ' aria-invalid="true"', + 'is-hidden': ' hidden', 'is-readonly': ' aria-readonly="true"', +}; + +function stateExample(n) { + const aria = STATE_ARIA[n] || ''; + return `
${n}
`; +} + +function a11yExample(n, applied) { + if (n === 'sr-only' || n === 'sr-only-focusable' || n === 'skip-link') return `${n} link (Tab to reveal) ← focusable`; + if (n === 'no-motion') return `
animation suppressed
`; + if (n === 'sf-focus-parent' || n === 'sf-focus-shadow') return `
`; + if (n === 'sf-clickable-parent') return `
card
`; + if (n === 'sf-clickable-parent__overlay') return `
card (overlay link)
`; + return `
${n}
`; +} + +function printExample(n) { + return `
${n} — affects print preview (Ctrl/Cmd-P)
`; +} + +function example(c) { + const n = c.name; + const applied = c.isVariant && c.baseClass ? `${c.baseClass} ${n}` : n; + switch (c.kind) { + case 'layout': return layoutExample(n, applied); + case 'macro': return macroExample(n, applied); + case 'state': return stateExample(n); + case 'motion': return `
${n.replace('sf-', '')}
`; + case 'accessibility': return a11yExample(n, applied); + case 'print': return printExample(n); + case 'theme': return `
${n}
`; + default: return `
${n}
`; + } +} + +function tile(c) { + const inBundle = c.bundles.includes('optimal'); + const note = inBundle ? '' : ` not in optimal bundle`; + return `
+
.${esc(c.name)}${note}
+
${example(c)}
+
`; +} + +// token galleries — make the override's effect on DERIVED tokens visible +function tokenByName(name) { return tokens.find((t) => t.name === name); } +function colorRamp(stem) { + const steps = ['50', '100', '200', '300', '400', '500', '600', '700', '800', '900', '950']; + const cells = steps.filter((s) => tokenByName(`--sf-color-${stem}-${s}`)).map((s) => + `
${s}
`).join(''); + return `
${stem}
${cells}
`; +} +function semanticSwatches() { + const names = ['primary', 'secondary', 'tertiary', 'action', 'neutral', 'danger', 'warning', 'success', 'info', + 'surface', 'bg', 'inset', 'text', 'heading', 'link', 'border']; + return names.filter((nm) => tokenByName(`--sf-color-${nm}`)).map((nm) => + `
${nm}
`).join(''); +} +function spacingBars() { + return ['2xs', 'xs', 's', 'm', 'l', 'xl', '2xl', '3xl'].filter((s) => tokenByName(`--sf-space-${s}`)).map((s) => + `
space-${s}
`).join(''); +} +function textScale() { + return ['2xs', 'xs', 's', 'm', 'l', 'xl', '2xl', '3xl', '4xl'].filter((s) => tokenByName(`--sf-text-${s}`)).map((s) => + `
text-${s}Quick brown fox
`).join(''); +} +function radiusSwatches() { + return ['2xs', 'xs', 's', 'm', 'l', 'xl', '2xl'].filter((s) => tokenByName(`--sf-radius-${s}`)).map((s) => + `
${s}
`).join(''); +} +function shadowSwatches() { + return ['xs', 's', 'm', 'l', 'xl', '2xl'].filter((s) => tokenByName(`--sf-shadow-${s}`)).map((s) => + `
${s}
`).join(''); +} + +function classSection(kind, title) { + const items = classes.filter((c) => c.kind === kind).sort((a, b) => a.name.localeCompare(b.name)); + return `
+

${title} ${items.length}

+
+${items.map(tile).join('\n')} +
+
`; +} + +function buildDemo({ withOverride }) { + const overrideLink = withOverride ? `\n ` : ''; + const banner = withOverride + ? `
ultimate-override.css is ACTIVE. Every value below is recomputed from perturbed knob tokens — compare against the un-overridden page.
` + : `
Baseline render with default tokens. The override variant is full-api-demo-with-overrides.html.
`; + const kinds = [ + ['layout', 'Layout primitives'], + ['macro', 'Macro classes'], + ['state', 'State classes'], + ['motion', 'Motion / animation'], + ['accessibility', 'Accessibility'], + ['print', 'Print'], + ['theme', 'Theme'], + ]; + return ` + + + + + SLASHED — Full API Demo${withOverride ? ' (overridden)' : ''} + ${overrideLink} + + + +
+

SLASHED Full API Demo

+

v${VERSION} · optimal bundle from jsDelivr CDN · ${classes.length} classes · ${knobs.length} configurable tokens

+ ${banner} + +
+

Token galleries derived values

+

Color ramps

+ ${['primary', 'secondary', 'tertiary', 'action', 'neutral', 'base'].map(colorRamp).join('\n ')} +

Semantic / role colors

+
${semanticSwatches()}
+

Spacing scale

+ ${spacingBars()} +

Type scale

+ ${textScale()} +

Radius

+ +

Shadow

+ +
+ +${kinds.map(([k, t]) => classSection(k, t)).join('\n')} +
+ + +`; +} + +// ───────────────────────────────────────────────────────────────────────── +const { css, handledCount } = buildOverride(); +fs.writeFileSync(path.join(ROOT, 'ultimate-override.css'), css); + +// completeness assertion for classes +const emitted = new Set(); +for (const c of classes) emitted.add(c.name); +if (emitted.size !== classes.length) throw new Error('class de-dup mismatch'); + +fs.writeFileSync(path.join(ROOT, 'full-api-demo.html'), buildDemo({ withOverride: false })); +fs.writeFileSync(path.join(ROOT, 'full-api-demo-with-overrides.html'), buildDemo({ withOverride: true })); + +console.log(`ultimate-override.css → ${handledCount}/${knobs.length} knobs overridden, ${Object.keys(SKIP).length} skipped (documented)`); +console.log(`full-api-demo.html → ${classes.length} classes, all rendered`); +console.log(`full-api-demo-with-overrides.html → same body + override link`); diff --git a/demos/validate.mjs b/demos/validate.mjs new file mode 100644 index 00000000..d1b41aec --- /dev/null +++ b/demos/validate.mjs @@ -0,0 +1,81 @@ +// Validates the generated demo pages in a real browser against the locally +// built optimal bundle. Asserts: no console errors, all class tiles present, +// and that the override actually changes computed styles. +import { chromium } from '@playwright/test'; +import fs from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); +const CDN = 'https://cdn.jsdelivr.net/gh/codeslash-dev/SLASHED@dist/slashed.optimal.css'; +const LOCAL = path.join(ROOT, 'badges/slashed.optimal.css'); +const TMP = path.join(ROOT, 'demos/.validate'); +fs.mkdirSync(TMP, { recursive: true }); + +function localCopy(srcName, outName) { + let html = fs.readFileSync(path.join(ROOT, srcName), 'utf8'); + html = html.replace(CDN, 'file://' + LOCAL); + html = html.replace('href="ultimate-override.css"', `href="file://${path.join(ROOT, 'ultimate-override.css')}"`); + const out = path.join(TMP, outName); + fs.writeFileSync(out, html); + return 'file://' + out; +} + +const baseUrl = localCopy('full-api-demo.html', 'base.html'); +const ovUrl = localCopy('full-api-demo-with-overrides.html', 'ov.html'); +const expectedTiles = (fs.readFileSync(path.join(ROOT, 'full-api-demo.html'), 'utf8').match(/class="tile"/g) || []).length; + +const PROBES = `(() => { + const cs = getComputedStyle(document.documentElement); + const body = getComputedStyle(document.body); + const dbox = document.querySelector('.dbox'); + const h1 = document.querySelector('h1'); + return { + primary: cs.getPropertyValue('--sf-color-primary').trim(), + spaceM: cs.getPropertyValue('--sf-space-m').trim(), + bodyFont: body.fontFamily, + dboxPad: dbox ? getComputedStyle(dbox).paddingTop : null, + h1Size: h1 ? getComputedStyle(h1).fontSize : null, + tiles: document.querySelectorAll('.tile').length, + }; +})()`; + +const browser = await chromium.launch({ executablePath: '/opt/pw-browsers/chromium' }); +const fails = []; +async function load(url, label) { + const page = await browser.newPage({ viewport: { width: 1280, height: 1600 } }); + const errors = []; + page.on('console', (m) => { if (m.type() === 'error') errors.push(m.text()); }); + page.on('pageerror', (e) => errors.push(String(e))); + await page.goto(url, { waitUntil: 'load' }); + await page.waitForTimeout(400); + const probes = await page.evaluate(PROBES); + await page.screenshot({ path: path.join(TMP, label + '.png'), fullPage: false }); + await page.close(); + return { probes, errors }; +} + +const base = await load(baseUrl, 'baseline'); +const ov = await load(ovUrl, 'override'); +await browser.close(); + +console.log('expected tiles:', expectedTiles); +console.log('\nBASELINE probes:', JSON.stringify(base.probes, null, 0)); +console.log('OVERRIDE probes:', JSON.stringify(ov.probes, null, 0)); +console.log('\nbaseline console errors:', base.errors.length); +base.errors.slice(0, 10).forEach((e) => console.log(' ⚠', e)); +console.log('override console errors:', ov.errors.length); +ov.errors.slice(0, 10).forEach((e) => console.log(' ⚠', e)); + +// assertions +if (base.probes.tiles !== expectedTiles) fails.push(`baseline tiles ${base.probes.tiles} != ${expectedTiles}`); +if (ov.probes.tiles !== expectedTiles) fails.push(`override tiles ${ov.probes.tiles} != ${expectedTiles}`); +const changed = []; +for (const k of ['primary', 'spaceM', 'bodyFont', 'dboxPad', 'h1Size']) { + if (base.probes[k] !== ov.probes[k]) changed.push(k); + else fails.push(`override did NOT change "${k}" (still ${base.probes[k]})`); +} +console.log('\ntokens visibly changed by override:', changed.join(', ') || '(none!)'); + +if (fails.length) { console.log('\n❌ FAIL:'); fails.forEach((f) => console.log(' ', f)); process.exit(1); } +console.log('\n✅ PASS — pages render, all tiles present, override perturbs computed styles.'); diff --git a/full-api-demo-with-overrides.html b/full-api-demo-with-overrides.html index 6bebbe57..56eb30d3 100644 --- a/full-api-demo-with-overrides.html +++ b/full-api-demo-with-overrides.html @@ -3,323 +3,1074 @@ - SLASHED — Full API Demo (With Ultimate Overrides) - + SLASHED — Full API Demo (overridden) - -
-

SLASHED Full API Demo — With Ultimate Overrides

- -
- ⚡ Overrides Active: This demo loads the ultimate-override.css file to test every configurable token. All colors, spacing, typography, and animations have been customized from their defaults. -
- -
-

Color Overrides Test

-

The CSS overrides change primary color to purple, action to teal, danger to orange, and more.

- -
-
-

Primary (Purple)

-
- Primary -
-
-
-

Action (Teal)

-
- Action -
-
-
-

Danger (Orange)

-
- Danger -
-
-
-

Success (Green)

-
- Success -
-
-
-

Warning (Yellow)

-
- Warning -
-
-
-

Info (Cyan)

-
- Info -
-
-
-
- -
-

Typography Overrides Test

-

Font families changed: body = Segoe UI, heading = Georgia, mono = Courier New

- -
-
-

Body Font (Segoe UI)

-

The quick brown fox jumps over the lazy dog

-
-
-

Heading Font (Georgia)

-

The quick brown fox

-
-
-

Mono Font (Courier)

-

monospace text here

-
-
+
+

SLASHED Full API Demo

+

v0.6.25 · optimal bundle from jsDelivr CDN · 239 classes · 225 configurable tokens

+
ultimate-override.css is ACTIVE. Every value below is recomputed from perturbed knob tokens — compare against the un-overridden page.
-

Text Scale (Increased)

-
-

Text 3xl (increased from default)

-

Text 2xl

-

Text l

-
+
+

Token galleries derived values

+

Color ramps

+
primary
50
100
200
300
400
500
600
700
800
900
950
+
secondary
50
100
200
300
400
500
600
700
800
900
950
+
tertiary
50
100
200
300
400
500
600
700
800
900
950
+
action
50
100
200
300
400
500
600
700
800
900
950
+
neutral
50
100
200
300
400
500
600
700
800
900
950
+
base
50
100
200
300
400
500
600
700
800
900
950
+

Semantic / role colors

+
primary
secondary
tertiary
action
neutral
danger
warning
success
info
surface
bg
inset
text
heading
link
border
+

Spacing scale

+
space-2xs
space-xs
space-s
space-m
space-l
space-xl
space-2xl
space-3xl
+

Type scale

+
text-2xsQuick brown fox
text-xsQuick brown fox
text-sQuick brown fox
text-mQuick brown fox
text-lQuick brown fox
text-xlQuick brown fox
text-2xlQuick brown fox
text-3xlQuick brown fox
text-4xlQuick brown fox
+

Radius

+ +

Shadow

+
-
-

Spacing Overrides Test

-

Spacing scale increased: space-m now uses 2rem instead of 1rem

- -
-

Paragraph with space-m margin below

-

Notice the larger gap above this paragraph

-
- -

Layout Gaps

-
-
Stack Item 1
-
Stack Item 2 (gap increased by override)
-
Stack Item 3
+
+

Layout primitives 128

+
+
+
.sf-alternate
+
1
2
3
4
+
+
+
.sf-bento
+
1
2
3
4
5
6
+
+
+
.sf-bento--2
+
1
2
3
4
5
6
+
+
+
.sf-bento--3
+
1
2
3
4
5
6
+
+
+
.sf-bento--6
+
1
2
3
4
5
6
+
+
+
.sf-bento--compact
+
1
2
3
4
5
6
+
+
+
.sf-bento--tall
+
1
2
3
4
5
6
+
+
+
.sf-bento-featured
+
1
2
3
4
5
+
+
+
.sf-bento-full
+
full
1
2
3
4
5
+
+
+
.sf-bento-tall
+
tall
1
2
3
4
5
+
+
+
.sf-bento-wide
+
wide
1
2
3
4
5
+
+
+
.sf-bg
+
content over bg
+
+
+
.sf-box
+
1
2
3
4
+
+
+
.sf-breakout
+

content

breakout
+
+
+
.sf-center
+
1
2
3
4
+
+
+
.sf-center--intrinsic
+
1
2
3
4
+
+
+
.sf-cluster
+
1
2
3
4
+
+
+
.sf-cluster--2xl
+
1
2
3
4
+
+
+
.sf-cluster--between
+
1
2
3
4
+
+
+
.sf-cluster--center
+
1
2
3
4
+
+
+
.sf-cluster--end
+
1
2
3
4
+
+
+
.sf-cluster--l
+
1
2
3
4
+
+
+
.sf-cluster--m
+
1
2
3
4
+
+
+
.sf-cluster--no-wrap
+
1
2
3
4
+
+
+
.sf-cluster--s
+
1
2
3
4
+
+
+
.sf-cluster--xl
+
1
2
3
4
+
+
+
.sf-cluster--xs
+
1
2
3
4
+
+
+
.sf-container
+
1
2
3
4
+
+
+
.sf-container--full
+
1
2
3
4
+
+
+
.sf-container--narrow
+
1
2
3
4
+
+
+
.sf-container--prose
+
1
2
3
4
+
+
+
.sf-container--wide
+
1
2
3
4
+
+
+
.sf-content-grid
+

content

breakout
full-bleed
+
+
+
.sf-cover
+
cover
+
+
+
.sf-cover__center
+
center
+
+
+
.sf-cover--max
+
cover
+
+
+
.sf-cover--min
+
cover
+
+
+
.sf-cover--padding-l
+
cover
+
+
+
.sf-cover--padding-s
+
cover
+
+
+
.sf-cq
+
1
2
3
4
+
+
+
.sf-divider
+

above

below

+
+
+
.sf-divider--dashed
+

above

below

+
+
+
.sf-divider--dotted
+

above

below

+
+
+
.sf-divider--gradient
+

above

below

+
+
+
.sf-divider--soft
+

above

below

+
+
+
.sf-divider--strong
+

above

below

+
+
+
.sf-divider--vertical
+

above

below

+
+
+
.sf-equal
+
1
2
3
4
+
+
+
.sf-equal--2
+
1
2
3
4
+
+
+
.sf-equal--3
+
1
2
3
4
+
+
+
.sf-equal--4
+
1
2
3
4
+
+
+
.sf-equal--6
+
1
2
3
4
+
+
+
.sf-frame
+
media
+
+
+
.sf-frame--3-2
+
media
+
+
+
.sf-frame--4-3
+
media
+
+
+
.sf-frame--cinema
+
media
+
+
+
.sf-frame--golden
+
media
+
+
+
.sf-frame--portrait
+
media
+
+
+
.sf-frame--square
+
media
+
+
+
.sf-frame--video
+
media
+
+
+
.sf-full-bleed
+

content

full-bleed
+
+
+
.sf-gap
+
1
2
3
4
+
+
+
.sf-gap--2xl
+
1
2
3
4
+
+
+
.sf-gap--l
+
1
2
3
4
+
+
+
.sf-gap--m
+
1
2
3
4
+
+
+
.sf-gap--s
+
1
2
3
4
+
+
+
.sf-gap--xl
+
1
2
3
4
+
+
+
.sf-gap--xs
+
1
2
3
4
+
+
+
.sf-grid
+
1
2
3
4
+
+
+
.sf-grid--2xl
+
1
2
3
4
+
+
+
.sf-grid--dense
+
1
2
3
4
+
+
+
.sf-grid--fit
+
1
2
3
4
+
+
+
.sf-grid--l
+
1
2
3
4
+
+
+
.sf-grid--m
+
1
2
3
4
+
+
+
.sf-grid--s
+
1
2
3
4
+
+
+
.sf-grid--xl
+
1
2
3
4
+
+
+
.sf-grid--xs
+
1
2
3
4
+
+
+
.sf-grid-cols-1
+
1
2
3
4
+
+
+
.sf-grid-cols-1-2
+
1
2
3
4
+
+
+
.sf-grid-cols-1-3
+
1
2
3
4
+
+
+
.sf-grid-cols-2
+
1
2
3
4
+
+
+
.sf-grid-cols-2-1
+
1
2
3
4
+
+
+
.sf-grid-cols-3
+
1
2
3
4
+
+
+
.sf-grid-cols-3-1
+
1
2
3
4
+
+
+
.sf-grid-cols-4
+
1
2
3
4
+
+
+
.sf-grid-cols-6
+
1
2
3
4
+
+
+
.sf-icon
+
inline icon
+
+
+
.sf-icon--2xl
+
inline icon
+
+
+
.sf-icon--boxed
+
inline icon
+
+
+
.sf-icon--l
+
inline icon
+
+
+
.sf-icon--m
+
inline icon
+
+
+
.sf-icon--s
+
inline icon
+
+
+
.sf-icon--xl
+
inline icon
+
+
+
.sf-icon--xs
+
inline icon
+
+
+
.sf-imposter
+
base
imposter
+
+
+
.sf-imposter--contain
+
base
imposter
+
+
+
.sf-imposter--fixed
+
base
imposter
+
+
+
.sf-pancake
+
header
main
footer
+
+
+
.sf-reel
+
1
2
3
4
5
6
+
+
+
.sf-section
+
1
2
3
4
+
+
+
.sf-section--2xl
+
1
2
3
4
+
+
+
.sf-section--collapse
+
1
2
3
4
+
+
+
.sf-section--guttered
+
1
2
3
4
+
+
+
.sf-section--l
+
1
2
3
4
+
+
+
.sf-section--m
+
1
2
3
4
+
+
+
.sf-section--s
+
1
2
3
4
+
+
+
.sf-section--xl
+
1
2
3
4
+
+
+
.sf-section--xs
+
1
2
3
4
+
+
+
.sf-section-group
+
1
2
3
4
+
+
+
.sf-sidebar
+
main
aside
+
+
+
.sf-sidebar--narrow
+
main
aside
+
+
+
.sf-sidebar--right
+
main
aside
+
+
+
.sf-sidebar--wide
+
main
aside
+
+
+
.sf-stack
+
1
2
3
4
+
+
+
.sf-stack--2xl
+
1
2
3
4
+
+
+
.sf-stack--center
+
1
2
3
4
+
+
+
.sf-stack--end
+
1
2
3
4
+
+
+
.sf-stack--l
+
1
2
3
4
+
+
+
.sf-stack--m
+
1
2
3
4
+
+
+
.sf-stack--s
+
1
2
3
4
+
+
+
.sf-stack--stretch
+
1
2
3
4
+
+
+
.sf-stack--xl
+
1
2
3
4
+
+
+
.sf-stack--xs
+
1
2
3
4
+
+
+
.sf-subgrid
+
1
2
3
+
+
+
.sf-subgrid-rows
+
1
2
3
+
+
+
.sf-switcher
+
1
2
3
+
+
+
.sf-switcher--no-wrap
+
1
2
3
+
+
+
.sf-switcher--vertical
+
1
2
3
+
- -
-

Border & Radius Overrides Test

-

Border widths increased: width-1 now 2px (scaled 1.2x), radius tokens more rounded

- -
-
-

Radius M

-
-
-
-

Radius L (More Rounded)

-
-
+
+

Macro classes 42

+
+
+
.sf-aspect
+
16 / 9
+
+
+
.sf-content-auto
+
content-auto
+
+
+
.sf-equal-height
+
short
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo.
+
+
+
.sf-flow
+

one

two

three

+
+
+
.sf-line-clamp-2
+
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo.
+
+
+
.sf-line-clamp-3
+
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo.
+
+
+
.sf-line-clamp-N
+
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo.
+
+
+
.sf-link--reverse
+ +
+
+
.sf-link--subtle
+ +
+
+
.sf-link-external
+ +
+
+
.sf-no-tap-highlight
+
no-tap-highlight
+
+
+
.sf-not-prose
+

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo.

opted out of prose

more.

+
+
+
.sf-overflow-fade
+

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo.

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo.

+
+
+
.sf-overflow-fade--block
+

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo.

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo.

+
+
+
.sf-overflow-fade--bottom
+

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo.

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo.

+
+
+
.sf-overflow-fade--inline
+

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo.

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo.

+
+
+
.sf-overflow-fade--left
+

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo.

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo.

+
+
+
.sf-overflow-fade--right
+

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo.

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo.

+
+
+
.sf-overflow-fade--top
+

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo.

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo.

+
+
+
.sf-prose
+

Heading

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo.

  • one
  • two

Another paragraph.

+
+
+
.sf-scrim
+
over scrim
+
+
+
.sf-scrim__content
+
scrim content
+
+
+
.sf-scrim--bottom
+
over scrim
+
+
+
.sf-scrim--full
+
over scrim
+
+
+
.sf-scrim--top
+
over scrim
+
+
+
.sf-scroll-shadow
+

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo.

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo.

+
+
+
.sf-scroll-snap
+
1
2
3
4
5
+
+
+
.sf-surface
+
surface
+
+
+
.sf-surface--action
+
surface--action
+
+
+
.sf-surface--danger
+
surface--danger
+
+
+
.sf-surface--info
+
surface--info
+
+
+
.sf-surface--inverse
+
surface--inverse
+
+
+
.sf-surface--neutral
+
surface--neutral
+
+
+
.sf-surface--primary
+
surface--primary
+
+
+
.sf-surface--secondary
+
surface--secondary
+
+
+
.sf-surface--success
+
surface--success
+
+
+
.sf-surface--tertiary
+
surface--tertiary
+
+
+
.sf-surface--warning
+
surface--warning
+
+
+
.sf-tabular-nums
+
1234567890
0987654321
+
+
+
.sf-text-gradient
+
Gradient text
+
+
+
.sf-text-protect
+
text-protect
+
+
+
.sf-truncate
+
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo.
+
- -
-

Shadow Overrides Test

-

Shadows strengthened for more depth

- -
-
-

Shadow S

-
-
-

Shadow M

-
-
-

Shadow L

-
+
+

State classes 40

+
+
+
.is-active
+
is-active
+
+
+
.is-busy
+
is-busy
+
+
+
.is-clickable
+
is-clickable
+
+
+
.is-clipped
+
is-clipped
+
+
+
.is-collapsed
+
+
+
+
.is-current
+
is-current
+
+
+
.is-danger
+
is-danger
+
+
+
.is-disabled
+
is-disabled
+
+
+
.is-draggable
+
is-draggable
+
+
+
.is-dragging
+
is-dragging
+
+
+
.is-drop-target
+
is-drop-target
+
+
+
.is-empty
+
is-empty
+
+
+
.is-error
+
is-error
+
+
+
.is-expanded
+
is-expanded
+
+
+
.is-fixed
+
is-fixed
+
+
+
.is-focused
+
is-focused
+
+
+
.is-fullscreen
+
is-fullscreen
+
+
+
.is-hidden
+
+
+
+
.is-highlighted
+
is-highlighted
+
+
+
.is-info
+
is-info
+
+
+
.is-invalid
+
is-invalid
+
+
+
.is-invisible
+
+
+
+
.is-loading
+
is-loading
+
+
+
.is-open
+
is-open
+
+
+
.is-overlay
+
is-overlay
+
+
+
.is-pending
+
is-pending
+
+
+
.is-pinned
+
is-pinned
+
+
+
.is-pressed
+
is-pressed
+
+
+
.is-readonly
+
is-readonly
+
+
+
.is-resizable
+
is-resizable
+
+
+
.is-scrollable
+
is-scrollable
+
+
+
.is-selected
+
is-selected
+
+
+
.is-skeleton
+
is-skeleton
+
+
+
.is-sticky
+
is-sticky
+
+
+
.is-success
+
is-success
+
+
+
.is-truncated
+
is-truncated
+
+
+
.is-unselectable
+
is-unselectable
+
+
+
.is-valid
+
is-valid
+
+
+
.is-visible
+
is-visible
+
+
+
.is-warning
+
is-warning
+
- -
-

Animation Overrides Test

-

Duration overrides: fast = 150ms, normal = 300ms, slow = 600ms

- -
-
- Animation with duration-normal (300ms): -
-
-

All animations use overridden duration and easing tokens

+
+

Motion / animation 15

+
+
+
.sf-color-pulse
+
color-pulse
+
+
+
.sf-entrance--fade
+
entrance--fade
+
+
+
.sf-entrance--fade-down
+
entrance--fade-down
+
+
+
.sf-entrance--fade-left
+
entrance--fade-left
+
+
+
.sf-entrance--fade-right
+
entrance--fade-right
+
+
+
.sf-entrance--fade-up
+
entrance--fade-up
+
+
+
.sf-entrance--scale-up
+
entrance--scale-up
+
+
+
.sf-fade-in
+
fade-in
+
+
+
.sf-fade-out
+
fade-out
+
+
+
.sf-scale-down
+
scale-down
+
+
+
.sf-scale-up
+
scale-up
+
+
+
.sf-slide-in-down
+
slide-in-down
+
+
+
.sf-slide-in-left
+
slide-in-left
+
+
+
.sf-slide-in-right
+
slide-in-right
+
+
+
.sf-slide-in-up
+
slide-in-up
+
- -
-

State Classes Test

- -
-
- .is-active -

Active state

-
-
- .is-disabled -

Disabled state

-
+
+

Accessibility 8

+
+
+
.no-motion
+
animation suppressed
+
+
+
.sf-clickable-parent
+
card
+
+
+
.sf-clickable-parent__overlay
+
card (overlay link)
+
+
+
.sf-focus-parent
+
+
+
+
.sf-focus-shadow
+
+
+
+
.skip-link
+ +
+
+
.sr-only
+ +
+
+
.sr-only-focusable
+ +
- -
-

Layout Primitives Test

- -

Stack with Override Gaps

-
-
Stack Item 1
-
Stack Item 2
-
Stack Item 3
-
- -

Grid with Override Gaps

-
-
Grid 1
-
Grid 2
-
Grid 3
+
+

Print 4

+
+
+
.no-print
+
no-print — affects print preview (Ctrl/Cmd-P)
+
+
+
.print-color-exact
+
+
+
+
.print-no-color
+
+
+
+
.print-only
+
+
- -
-

Summary of Overrides

-
-

✅ All Token Categories Customized:

-
    -
  • Colors: 7+ color palettes redefined
  • -
  • Typography: 3 fonts changed, 8 sizes increased
  • -
  • Spacing: 11 space tokens increased
  • -
  • Borders: 5 width tokens scaled 1.2x
  • -
  • Radius: 8 radius tokens increased
  • -
  • Shadows: 7 shadow tokens strengthened
  • -
  • Animations: 4 durations and easing curves changed
  • -
  • Layout: 15+ layout configuration tokens updated
  • -
  • Z-index: 6 z-index values increased
  • -
  • Special: Blur, code styling, contrast settings
  • -
-

Total: 184+ token overrides applied and working

+
+

Theme 2

+
+
+
.sf-theme-transition
+
sf-theme-transition
+
+
+
.theme-transition not in optimal bundle
+
theme-transition
+
- -
-

- SLASHED v0.6.25 — Full API Demo with Ultimate Overrides
- View original demo without overrides -

-
diff --git a/full-api-demo.html b/full-api-demo.html index 6f9c49cc..bba64430 100644 --- a/full-api-demo.html +++ b/full-api-demo.html @@ -4,1375 +4,1072 @@ SLASHED — Full API Demo - -
+

SLASHED Full API Demo

-

- Comprehensive test of every token, class, and feature -

-
- -
- -
-

Layout Primitives

- -

Stack (Vertical Flow)

-
-
Stack Item 1
-
Stack Item 2 (with gap between)
-
Stack Item 3
-
- -

Cluster (Wrapping Inline Group)

-
-
Cluster 1
-
Cluster 2
-
Cluster 3
-
Cluster 4
-
- -

Grid (Responsive Auto-fill)

-
-
Grid 1
-
Grid 2
-
Grid 3
-
Grid 4
-
Grid 5
-
Grid 6
-
- -

Fixed Column Grids

-
-
-

2-Column

-
-
Col 1
-
Col 2
-
-
-
-

3-Column

-
-
Col 1
-
Col 2
-
Col 3
-
-
-
- -

Container & Box

-
-

Centered container with max-width constraint

-
- -
-

Box with padding and optional border outline

-
- -

Center (Intrinsic Centering)

-
-

Intrinsically centered content with max-width

-
- -

Section & Section-Group

-
-

Section with standard padding

-

Content goes here

-
- -

Sidebar (Content + Side Panel)

-
-
Main - This is the primary content area
-
Sidebar - Side panel
-
- -

Switcher (Responsive Columns)

-
-
Switch 1
-
Switch 2
-
Switch 3
-
- -

Icon Sizing

-
-
-
-
-
-
-
-
- -

Dividers

-
-

Content above

-
-

Divider between content

-
-

Dashed divider

-
-

Dotted divider

-
-

Strong divider

-
- -

Gap Utility

-
-
Gap 1
-
Gap 2
-
-
- - -
-

Color Tokens

- -

Primary Palette

-
-
-
-
primary-50
-
-
-
-
primary-100
-
-
-
-
primary-200
-
-
-
-
primary-300
-
-
-
-
primary-400
-
-
-
-
primary-500
-
-
-
-
primary-600
-
-
-
-
primary-700
-
-
-
-
primary-800
-
-
-
-
primary-900
-
-
-
-
primary-950
-
-
- -

Action, Neutral, Base Palettes

-
-
-

Action

-
-
-
-
-
-
-
-

Neutral

-
-
-
-
-
-
-
-

Base

-
-
-
-
-
-
-
- -

Semantic Colors

-
-
- Danger -
Error/destructive
-
-
- Warning -
Caution
-
-
- Success -
Positive
-
-
- Info -
Information
-
-
- -

Special Colors

-
-
-

Surfaces

-
-
Surface
-
-
Background
-
Inset
-
-
-

Text Colors

-
-
Primary text
-
-
Secondary text
-
Muted text
-
-
-

Interactive

-
Link
-
Caret color
-
-
+

v0.6.25 · optimal bundle from jsDelivr CDN · 239 classes · 225 configurable tokens

+
Baseline render with default tokens. The override variant is full-api-demo-with-overrides.html.
+ +
+

Token galleries derived values

+

Color ramps

+
primary
50
100
200
300
400
500
600
700
800
900
950
+
secondary
50
100
200
300
400
500
600
700
800
900
950
+
tertiary
50
100
200
300
400
500
600
700
800
900
950
+
action
50
100
200
300
400
500
600
700
800
900
950
+
neutral
50
100
200
300
400
500
600
700
800
900
950
+
base
50
100
200
300
400
500
600
700
800
900
950
+

Semantic / role colors

+
primary
secondary
tertiary
action
neutral
danger
warning
success
info
surface
bg
inset
text
heading
link
border
+

Spacing scale

+
space-2xs
space-xs
space-s
space-m
space-l
space-xl
space-2xl
space-3xl
+

Type scale

+
text-2xsQuick brown fox
text-xsQuick brown fox
text-sQuick brown fox
text-mQuick brown fox
text-lQuick brown fox
text-xlQuick brown fox
text-2xlQuick brown fox
text-3xlQuick brown fox
text-4xlQuick brown fox
+

Radius

+ +

Shadow

+
- -
-

Typography Tokens

- -

Text Scale

-
-
-
text-3xl
-
The quick brown fox jumps over the lazy dog
-
-
-
text-2xl
-
The quick brown fox jumps over the lazy dog
-
-
-
text-xl
-
The quick brown fox jumps over the lazy dog
-
-
-
text-l
-
The quick brown fox jumps over the lazy dog
-
-
-
text-m
-
The quick brown fox jumps over the lazy dog
-
-
-
text-s
-
The quick brown fox jumps over the lazy dog
-
-
-
text-xs
-
The quick brown fox jumps over the lazy dog
-
-
-
text-2xs
-
The quick brown fox jumps over the lazy dog
-
-
- -

Font Families

-
-
-

Body font

-

The quick brown fox jumps over the lazy dog

-
-
-

Heading font

-

The quick brown fox jumps over the lazy dog

-
-
-

Mono font

-

The quick brown fox jumps over the lazy dog

-
-
- -

Font Weights

-
-
-
body
-
Regular body text
-
-
-
strong
-
Strong text
-
-
-
heading
-
Heading text
-
-
- -

Line Heights (Leading)

-
-
-
tight
-
The quick brown fox jumps over the lazy dog and continues on to the next line with tight spacing
-
-
-
normal
-
The quick brown fox jumps over the lazy dog and continues on to the next line with normal spacing
-
-
-
loose
-
The quick brown fox jumps over the lazy dog and continues on to the next line with loose spacing
-
-
- -

Letter Spacing (Tracking)

-
-
-
tight
-
THE QUICK BROWN FOX
-
-
-
normal
-
THE QUICK BROWN FOX
-
-
-
wide
-
THE QUICK BROWN FOX
-
-
-
wider
-
THE QUICK BROWN FOX
-
+
+

Layout primitives 128

+
+
+
.sf-alternate
+
1
2
3
4
+
+
+
.sf-bento
+
1
2
3
4
5
6
+
+
+
.sf-bento--2
+
1
2
3
4
5
6
+
+
+
.sf-bento--3
+
1
2
3
4
5
6
+
+
+
.sf-bento--6
+
1
2
3
4
5
6
+
+
+
.sf-bento--compact
+
1
2
3
4
5
6
+
+
+
.sf-bento--tall
+
1
2
3
4
5
6
+
+
+
.sf-bento-featured
+
1
2
3
4
5
+
+
+
.sf-bento-full
+
full
1
2
3
4
5
+
+
+
.sf-bento-tall
+
tall
1
2
3
4
5
+
+
+
.sf-bento-wide
+
wide
1
2
3
4
5
+
+
+
.sf-bg
+
content over bg
+
+
+
.sf-box
+
1
2
3
4
+
+
+
.sf-breakout
+

content

breakout
+
+
+
.sf-center
+
1
2
3
4
+
+
+
.sf-center--intrinsic
+
1
2
3
4
+
+
+
.sf-cluster
+
1
2
3
4
+
+
+
.sf-cluster--2xl
+
1
2
3
4
+
+
+
.sf-cluster--between
+
1
2
3
4
+
+
+
.sf-cluster--center
+
1
2
3
4
+
+
+
.sf-cluster--end
+
1
2
3
4
+
+
+
.sf-cluster--l
+
1
2
3
4
+
+
+
.sf-cluster--m
+
1
2
3
4
+
+
+
.sf-cluster--no-wrap
+
1
2
3
4
+
+
+
.sf-cluster--s
+
1
2
3
4
+
+
+
.sf-cluster--xl
+
1
2
3
4
+
+
+
.sf-cluster--xs
+
1
2
3
4
+
+
+
.sf-container
+
1
2
3
4
+
+
+
.sf-container--full
+
1
2
3
4
+
+
+
.sf-container--narrow
+
1
2
3
4
+
+
+
.sf-container--prose
+
1
2
3
4
+
+
+
.sf-container--wide
+
1
2
3
4
+
+
+
.sf-content-grid
+

content

breakout
full-bleed
+
+
+
.sf-cover
+
cover
+
+
+
.sf-cover__center
+
center
+
+
+
.sf-cover--max
+
cover
+
+
+
.sf-cover--min
+
cover
+
+
+
.sf-cover--padding-l
+
cover
+
+
+
.sf-cover--padding-s
+
cover
+
+
+
.sf-cq
+
1
2
3
4
+
+
+
.sf-divider
+

above

below

+
+
+
.sf-divider--dashed
+

above

below

+
+
+
.sf-divider--dotted
+

above

below

+
+
+
.sf-divider--gradient
+

above

below

+
+
+
.sf-divider--soft
+

above

below

+
+
+
.sf-divider--strong
+

above

below

+
+
+
.sf-divider--vertical
+

above

below

+
+
+
.sf-equal
+
1
2
3
4
+
+
+
.sf-equal--2
+
1
2
3
4
+
+
+
.sf-equal--3
+
1
2
3
4
+
+
+
.sf-equal--4
+
1
2
3
4
+
+
+
.sf-equal--6
+
1
2
3
4
+
+
+
.sf-frame
+
media
+
+
+
.sf-frame--3-2
+
media
+
+
+
.sf-frame--4-3
+
media
+
+
+
.sf-frame--cinema
+
media
+
+
+
.sf-frame--golden
+
media
+
+
+
.sf-frame--portrait
+
media
+
+
+
.sf-frame--square
+
media
+
+
+
.sf-frame--video
+
media
+
+
+
.sf-full-bleed
+

content

full-bleed
+
+
+
.sf-gap
+
1
2
3
4
+
+
+
.sf-gap--2xl
+
1
2
3
4
+
+
+
.sf-gap--l
+
1
2
3
4
+
+
+
.sf-gap--m
+
1
2
3
4
+
+
+
.sf-gap--s
+
1
2
3
4
+
+
+
.sf-gap--xl
+
1
2
3
4
+
+
+
.sf-gap--xs
+
1
2
3
4
+
+
+
.sf-grid
+
1
2
3
4
+
+
+
.sf-grid--2xl
+
1
2
3
4
+
+
+
.sf-grid--dense
+
1
2
3
4
+
+
+
.sf-grid--fit
+
1
2
3
4
+
+
+
.sf-grid--l
+
1
2
3
4
+
+
+
.sf-grid--m
+
1
2
3
4
+
+
+
.sf-grid--s
+
1
2
3
4
+
+
+
.sf-grid--xl
+
1
2
3
4
+
+
+
.sf-grid--xs
+
1
2
3
4
+
+
+
.sf-grid-cols-1
+
1
2
3
4
+
+
+
.sf-grid-cols-1-2
+
1
2
3
4
+
+
+
.sf-grid-cols-1-3
+
1
2
3
4
+
+
+
.sf-grid-cols-2
+
1
2
3
4
+
+
+
.sf-grid-cols-2-1
+
1
2
3
4
+
+
+
.sf-grid-cols-3
+
1
2
3
4
+
+
+
.sf-grid-cols-3-1
+
1
2
3
4
+
+
+
.sf-grid-cols-4
+
1
2
3
4
+
+
+
.sf-grid-cols-6
+
1
2
3
4
+
+
+
.sf-icon
+
inline icon
+
+
+
.sf-icon--2xl
+
inline icon
+
+
+
.sf-icon--boxed
+
inline icon
+
+
+
.sf-icon--l
+
inline icon
+
+
+
.sf-icon--m
+
inline icon
+
+
+
.sf-icon--s
+
inline icon
+
+
+
.sf-icon--xl
+
inline icon
+
+
+
.sf-icon--xs
+
inline icon
+
+
+
.sf-imposter
+
base
imposter
+
+
+
.sf-imposter--contain
+
base
imposter
+
+
+
.sf-imposter--fixed
+
base
imposter
+
+
+
.sf-pancake
+
header
main
footer
+
+
+
.sf-reel
+
1
2
3
4
5
6
+
+
+
.sf-section
+
1
2
3
4
+
+
+
.sf-section--2xl
+
1
2
3
4
+
+
+
.sf-section--collapse
+
1
2
3
4
+
+
+
.sf-section--guttered
+
1
2
3
4
+
+
+
.sf-section--l
+
1
2
3
4
+
+
+
.sf-section--m
+
1
2
3
4
+
+
+
.sf-section--s
+
1
2
3
4
+
+
+
.sf-section--xl
+
1
2
3
4
+
+
+
.sf-section--xs
+
1
2
3
4
+
+
+
.sf-section-group
+
1
2
3
4
+
+
+
.sf-sidebar
+
main
aside
+
+
+
.sf-sidebar--narrow
+
main
aside
+
+
+
.sf-sidebar--right
+
main
aside
+
+
+
.sf-sidebar--wide
+
main
aside
+
+
+
.sf-stack
+
1
2
3
4
+
+
+
.sf-stack--2xl
+
1
2
3
4
+
+
+
.sf-stack--center
+
1
2
3
4
+
+
+
.sf-stack--end
+
1
2
3
4
+
+
+
.sf-stack--l
+
1
2
3
4
+
+
+
.sf-stack--m
+
1
2
3
4
+
+
+
.sf-stack--s
+
1
2
3
4
+
+
+
.sf-stack--stretch
+
1
2
3
4
+
+
+
.sf-stack--xl
+
1
2
3
4
+
+
+
.sf-stack--xs
+
1
2
3
4
+
+
+
.sf-subgrid
+
1
2
3
+
+
+
.sf-subgrid-rows
+
1
2
3
+
+
+
.sf-switcher
+
1
2
3
+
+
+
.sf-switcher--no-wrap
+
1
2
3
+
+
+
.sf-switcher--vertical
+
1
2
3
+
- - -
-

Spacing Tokens

- -

Space Scale

-
-
-
space-4xs
-
-
-
-
space-3xs
-
-
-
-
space-2xs
-
-
-
-
space-xs
-
-
-
-
space-s
-
-
-
-
space-m
-
-
-
-
space-l
-
-
-
-
space-xl
-
-
-
-
space-2xl
-
-
-
-
space-3xl
-
-
-
-
space-4xl
-
-
-
- -

Content & Container Gaps

-
-
-

content-gap

-
var(--sf-content-gap)
-
-
-

container-gutter

-
var(--sf-gutter)
-
+
+

Macro classes 42

+
+
+
.sf-aspect
+
16 / 9
+
+
+
.sf-content-auto
+
content-auto
+
+
+
.sf-equal-height
+
short
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo.
+
+
+
.sf-flow
+

one

two

three

+
+
+
.sf-line-clamp-2
+
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo.
+
+
+
.sf-line-clamp-3
+
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo.
+
+
+
.sf-line-clamp-N
+
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo.
+
+
+
.sf-link--reverse
+ +
+
+
.sf-link--subtle
+ +
+
+
.sf-link-external
+ +
+
+
.sf-no-tap-highlight
+
no-tap-highlight
+
+
+
.sf-not-prose
+

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo.

opted out of prose

more.

+
+
+
.sf-overflow-fade
+

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo.

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo.

+
+
+
.sf-overflow-fade--block
+

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo.

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo.

+
+
+
.sf-overflow-fade--bottom
+

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo.

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo.

+
+
+
.sf-overflow-fade--inline
+

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo.

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo.

+
+
+
.sf-overflow-fade--left
+

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo.

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo.

+
+
+
.sf-overflow-fade--right
+

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo.

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo.

+
+
+
.sf-overflow-fade--top
+

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo.

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo.

+
+
+
.sf-prose
+

Heading

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo.

  • one
  • two

Another paragraph.

+
+
+
.sf-scrim
+
over scrim
+
+
+
.sf-scrim__content
+
scrim content
+
+
+
.sf-scrim--bottom
+
over scrim
+
+
+
.sf-scrim--full
+
over scrim
+
+
+
.sf-scrim--top
+
over scrim
+
+
+
.sf-scroll-shadow
+

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo.

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo.

+
+
+
.sf-scroll-snap
+
1
2
3
4
5
+
+
+
.sf-surface
+
surface
+
+
+
.sf-surface--action
+
surface--action
+
+
+
.sf-surface--danger
+
surface--danger
+
+
+
.sf-surface--info
+
surface--info
+
+
+
.sf-surface--inverse
+
surface--inverse
+
+
+
.sf-surface--neutral
+
surface--neutral
+
+
+
.sf-surface--primary
+
surface--primary
+
+
+
.sf-surface--secondary
+
surface--secondary
+
+
+
.sf-surface--success
+
surface--success
+
+
+
.sf-surface--tertiary
+
surface--tertiary
+
+
+
.sf-surface--warning
+
surface--warning
+
+
+
.sf-tabular-nums
+
1234567890
0987654321
+
+
+
.sf-text-gradient
+
Gradient text
+
+
+
.sf-text-protect
+
text-protect
+
+
+
.sf-truncate
+
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo.
+
- - -
-

Border & Radius Tokens

- -

Border Widths

-
-
-
width-1
-
Default border
-
-
-
width-2
-
Thicker border
-
-
-
width-3
-
Even thicker
-
-
-
hairline
-
Hairline border
-
-
- -

Border Styles

-
-
-
Solid (default)
-
Dashed
-
Dotted
-
-
- -

Border Colors

-
-
-

Default

-
-
-
-

Subtle

-
-
-
-

Strong

-
-
-
- -

Border Radius

-
-
2xs
-
xs
-
s
-
m
-
l
-
xl
-
2xl
-
full
+
+

State classes 40

+
+
+
.is-active
+
is-active
+
+
+
.is-busy
+
is-busy
+
+
+
.is-clickable
+
is-clickable
+
+
+
.is-clipped
+
is-clipped
+
+
+
.is-collapsed
+
+
+
+
.is-current
+
is-current
+
+
+
.is-danger
+
is-danger
+
+
+
.is-disabled
+
is-disabled
+
+
+
.is-draggable
+
is-draggable
+
+
+
.is-dragging
+
is-dragging
+
+
+
.is-drop-target
+
is-drop-target
+
+
+
.is-empty
+
is-empty
+
+
+
.is-error
+
is-error
+
+
+
.is-expanded
+
is-expanded
+
+
+
.is-fixed
+
is-fixed
+
+
+
.is-focused
+
is-focused
+
+
+
.is-fullscreen
+
is-fullscreen
+
+
+
.is-hidden
+
+
+
+
.is-highlighted
+
is-highlighted
+
+
+
.is-info
+
is-info
+
+
+
.is-invalid
+
is-invalid
+
+
+
.is-invisible
+
+
+
+
.is-loading
+
is-loading
+
+
+
.is-open
+
is-open
+
+
+
.is-overlay
+
is-overlay
+
+
+
.is-pending
+
is-pending
+
+
+
.is-pinned
+
is-pinned
+
+
+
.is-pressed
+
is-pressed
+
+
+
.is-readonly
+
is-readonly
+
+
+
.is-resizable
+
is-resizable
+
+
+
.is-scrollable
+
is-scrollable
+
+
+
.is-selected
+
is-selected
+
+
+
.is-skeleton
+
is-skeleton
+
+
+
.is-sticky
+
is-sticky
+
+
+
.is-success
+
is-success
+
+
+
.is-truncated
+
is-truncated
+
+
+
.is-unselectable
+
is-unselectable
+
+
+
.is-valid
+
is-valid
+
+
+
.is-visible
+
is-visible
+
+
+
.is-warning
+
is-warning
+
- - -
-

Shadow Tokens

- -
-
shadow-xs
-
shadow-s
-
shadow-m
-
shadow-l
-
shadow-xl
-
shadow-2xl
-
shadow-inner
+
+

Motion / animation 15

+
+
+
.sf-color-pulse
+
color-pulse
+
+
+
.sf-entrance--fade
+
entrance--fade
+
+
+
.sf-entrance--fade-down
+
entrance--fade-down
+
+
+
.sf-entrance--fade-left
+
entrance--fade-left
+
+
+
.sf-entrance--fade-right
+
entrance--fade-right
+
+
+
.sf-entrance--fade-up
+
entrance--fade-up
+
+
+
.sf-entrance--scale-up
+
entrance--scale-up
+
+
+
.sf-fade-in
+
fade-in
+
+
+
.sf-fade-out
+
fade-out
+
+
+
.sf-scale-down
+
scale-down
+
+
+
.sf-scale-up
+
scale-up
+
+
+
.sf-slide-in-down
+
slide-in-down
+
+
+
.sf-slide-in-left
+
slide-in-left
+
+
+
.sf-slide-in-right
+
slide-in-right
+
+
+
.sf-slide-in-up
+
slide-in-up
+
- - -
-

Animation Tokens

- -

Duration & Easing

-
-
-

Durations

-
-
fast: var(--sf-duration-fast)
-
normal: var(--sf-duration-normal)
-
slow: var(--sf-duration-slow)
-
slower: var(--sf-duration-slower)
-
-
-
-

Easing Functions

-
-
linear
-
in / out / in-out
-
overshoot / elastic
-
spring
-
-
-
- -

Animation Examples

-
-
-
-
-
fade-in
-
-
-
-
slide-up
-
-
-
-
scale-up
-
-
-
-
spin
-
-
-
-
float
-
-
-
-
ping
-
-
-
-
pulse
-
-
-
-
shimmer
-
-
+
+

Accessibility 8

+
+
+
.no-motion
+
animation suppressed
+
+
+
.sf-clickable-parent
+
card
+
+
+
.sf-clickable-parent__overlay
+
card (overlay link)
+
+
+
.sf-focus-parent
+
+
+
+
.sf-focus-shadow
+
+
+
+
.skip-link
+ +
+
+
.sr-only
+ +
+
+
.sr-only-focusable
+ +
- - -
-

State Classes (.is-*)

- -
-
- .is-active -

Active/selected item

-
-
- .is-disabled -

Non-interactive state

-
-
- .is-busy -

Processing indicator

-
-
- .is-invalid -

Form field invalid

-
-
- .is-valid -

Form field valid

-
-
- .is-success -

General success

-
-
- .is-error -

General error

-
-
- .is-warning -

Warning state

-
-
- .is-info -

Information

-
-
- .is-loading -

Content loading

-
-
- .is-skeleton -

Placeholder shimmer

-
- -
- -
-

Additional States Available

-
    -
  • .is-invisible / .is-visible
  • -
  • .is-readonly
  • -
  • .is-pending
  • -
  • .is-selected
  • -
  • .is-current
  • -
  • .is-pressed
  • -
  • .is-highlighted
  • -
  • .is-open / .is-collapsed
  • -
  • .is-expanded
  • -
  • .is-danger
  • -
  • .is-sticky / .is-pinned / .is-fixed
  • -
  • .is-fullscreen
  • -
  • .is-clipped / .is-scrollable / .is-truncated
  • -
  • .is-resizable
  • -
  • .is-dragging / .is-drop-target / .is-draggable
  • -
  • .is-overlay
  • -
  • .is-clickable / .is-unselectable
  • -
  • .is-focused
  • -
  • .is-empty:empty
  • -
  • .no-motion
  • -
  • .sr-only-focusable
  • -
+
+

Print 4

+
+
+
.no-print
+
no-print — affects print preview (Ctrl/Cmd-P)
+
+
+
.print-color-exact
+
+
+
+
.print-no-color
+
+
+
+
.print-only
+
+
- - -
-

Macro Classes

- -

Prose (Long-form text)

-
-

Article Title

-

This is a paragraph of long-form text that gets automatic vertical rhythm with the .sf-prose class. Each element gets proper spacing.

-

This is a second paragraph. Notice how the spacing is automatic and consistent.

-
    -
  • First list item
  • -
  • Second list item
  • -
  • Third list item
  • -
-

More content after the list, properly spaced.

-
- -

Flow (Owl Selector)

-
-
Flow item 1
-
Flow item 2 (has automatic top margin)
-
Flow item 3 (has automatic top margin)
-
- -

Line Clamp

-
-

Line Clamp 2

-
- This is a long text that will be clamped to 2 lines with an ellipsis at the end if it overflows. The ellipsis will appear after exactly two lines of text. -
-

Line Clamp 3

-
- This is a long text that will be clamped to 3 lines with an ellipsis at the end if it overflows. The ellipsis will appear after exactly three lines of text. You can use .sf-line-clamp-N for dynamic clamps. -
-
- -

Link Variants

- - -

Surface Utilities

-
-
Default surface
-
Action surface
-
Primary surface
-
Danger surface
-
- -

Text Utilities

-
-
-
.sf-truncate - This very long sentence will be truncated with an ellipsis when it overflows the container width
-
-
- .sf-text-gradient - Text with gradient effect -
-
- 12 34 56 78 90 (tabular numbers for alignment) -
-
- -

Overflow Fade

-
-
-

This content has overflow fade applied. Notice the fade effect at the bottom when scrolling.

-

Lorem ipsum dolor sit amet, consectetur adipiscing elit.

-

Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

-

Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris.

-
-
- -

Scroll Shadow

-
-
-

This element has scroll shadows. A shadow appears when there's scrollable content.

-

Lorem ipsum dolor sit amet, consectetur adipiscing elit.

-

Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

-

Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris.

-
-
- -

Scroll Snap

-
-
Snap 1
-
Snap 2
-
Snap 3
-
- -

Content Auto (Aspect Ratio)

-
-
- Aspect 1:1 -
-
- -

Equal Height

-
-
-

Column 1

-

Short content

-
-
-

Column 2

-

This column has more content and both columns stretch to the same height thanks to .sf-equal-height

-
-
- -

Scrim (Gradient Overlay)

-
-
-
Content with scrim overlay at bottom
-
-
- - -
-

Accessibility & Focus

- -

Focus Styles

-
- -
- -

Skip Link (sr-only-focusable)

- - -

No Motion (Respects prefers-reduced-motion)

-
-
-

This animation respects .no-motion class (affected by prefers-reduced-motion)

-
-
- - -
-

Miscellaneous Tokens

- -

Container Sizes

-
-
- Max Width -
var(--sf-container-max)
-
-
- Narrow -
var(--sf-container-narrow)
-
-
- -

Z-Index Scale

-
-
-
-
z-default
-
var(--sf-z-default)
-
-
-
z-dropdown
-
var(--sf-z-dropdown)
-
-
-
z-fixed
-
var(--sf-z-fixed)
-
-
-
z-modal
-
var(--sf-z-modal)
-
-
-
z-popover
-
var(--sf-z-popover)
-
-
-
z-tooltip
-
var(--sf-z-tooltip)
-
-
-
- -

Blur Token

-
-
-
- Blurred background (var(--sf-blur)) -
-
- -

Code & Syntax

-
-
-const greeting = "Hello, SLASHED!"; -console.log(greeting); -
-

- Uses code colors: var(--sf-color-code-bg/text) -

-
-
- - -
-

Framework Features Summary

-
-
-

128 Layout Primitives

-

Container-query driven layouts that adapt to their width, not viewport breakpoints. Stack, Cluster, Grid, Sidebar, and more.

-
-
-

691 Tokens

-

Custom properties for colors, typography, spacing, borders, shadows, animations, and more. All scoped with --sf- prefix.

-
-
-

42 Macro Classes

-

Recipes for prose, truncation, line clamping, link variants, text gradients, surfaces, and overflow handling.

-
-
-

40 State Classes

-

.is-* classes for runtime conditions like active, disabled, loading, valid, error, and more. Minimal but complete.

-
-
-

Optimal Bundles

-

Load only what you need. Optimal CSS includes layout + essentials. Optional components ship as needed.

-
-
-

Theming Ready

-

Every color, spacing, and timing value is configurable. Hundreds of tokens to customize for your brand.

-
+
+

Theme 2

+
+
+
.sf-theme-transition
+
sf-theme-transition
+
+
+
.theme-transition not in optimal bundle
+
theme-transition
+
- -
-

SLASHED v0.6.25 — Full API Demo | GitHub

-
diff --git a/ultimate-override.css b/ultimate-override.css index 1f98c9ee..649b4897 100644 --- a/ultimate-override.css +++ b/ultimate-override.css @@ -1,480 +1,361 @@ -/* ═══════════════════════════════════════════════════════════════════ - ULTIMATE OVERRIDE CSS — Every Configurable Token - Tests that all tokens are properly applied throughout the framework - ═══════════════════════════════════════════════════════════════════ */ +/* ============================================================================ + ULTIMATE OVERRIDE — generated by demos/generate.mjs (do not edit by hand) + SLASHED v0.6.25 -:root { - /* ───────────────────────────────────────────────────────────── - COLOR TOKENS — Source definitions - ───────────────────────────────────────────────────────────────── */ - - /* Primary palette — changed from blue-ish to purple */ - --sf-color-primary-source-light: oklch(0.55 0.25 280); - --sf-color-primary-source-dark: oklch(0.75 0.20 280); - - /* Action palette — changed to teal */ - --sf-color-action-source-light: oklch(0.45 0.24 180); - --sf-color-action-source-dark: oklch(0.72 0.18 180); - - /* Danger palette — changed to orange */ - --sf-color-danger-source-light: oklch(0.55 0.25 40); - --sf-color-danger-source-dark: oklch(0.75 0.20 40); - - /* Success palette — changed to green */ - --sf-color-success-source-light: oklch(0.50 0.22 140); - --sf-color-success-source-dark: oklch(0.70 0.18 140); - - /* Warning palette — changed to yellow */ - --sf-color-warning-source-light: oklch(0.60 0.20 85); - --sf-color-warning-source-dark: oklch(0.78 0.15 85); - - /* Info palette — changed to cyan */ - --sf-color-info-source-light: oklch(0.52 0.20 200); - --sf-color-info-source-dark: oklch(0.72 0.16 200); - - /* Neutral palette — shifted to warmer gray */ - --sf-color-neutral-source-light: oklch(0.55 0.035 45); - --sf-color-neutral-source-dark: oklch(0.68 0.028 45); - - /* Base palette — shifted to cooler gray */ - --sf-color-base-source-light: oklch(0.95 0.01 210); - --sf-color-base-source-dark: oklch(0.18 0.005 210); - - /* ───────────────────────────────────────────────────────────── - TYPOGRAPHY TOKENS - ───────────────────────────────────────────────────────────────── */ - - /* Font families — using different system stacks */ - --sf-font-body: 'Segoe UI', 'Helvetica Neue', sans-serif; - --sf-font-heading: 'Georgia', 'Times New Roman', serif; - --sf-font-mono: 'Courier New', courier, monospace; - - /* Font weights */ - --sf-font-weight-body: 450; - --sf-font-weight-strong: 700; - --sf-font-weight-heading: 800; - - /* Text scale sizes — increased overall */ - --sf-text-2xs: 0.68rem; - --sf-text-xs: 0.78rem; - --sf-text-s: 0.92rem; - --sf-text-m: 1.08rem; - --sf-text-l: 1.28rem; - --sf-text-xl: 1.52rem; - --sf-text-2xl: 1.80rem; - --sf-text-3xl: 2.14rem; - - /* Line heights (leading) — looser spacing */ - --sf-leading-tight: 1.3; - --sf-leading-normal: 1.6; - --sf-leading-loose: 1.9; - - /* Letter spacing (tracking) — wider by default */ - --sf-tracking-tight: -0.02em; - --sf-tracking-normal: 0.02em; - --sf-tracking-wide: 0.06em; - --sf-tracking-wider: 0.12em; - - /* ───────────────────────────────────────────────────────────── - SPACING TOKENS — Larger scale - ───────────────────────────────────────────────────────────────── */ - - --sf-space-4xs: 0.35rem; - --sf-space-3xs: 0.5rem; - --sf-space-2xs: 0.75rem; - --sf-space-xs: 1rem; - --sf-space-s: 1.5rem; - --sf-space-m: 2rem; - --sf-space-l: 3rem; - --sf-space-xl: 4.5rem; - --sf-space-2xl: 6rem; - --sf-space-3xl: 9rem; - --sf-space-4xl: 13rem; - - /* Content and container gaps */ - --sf-content-gap: var(--sf-space-l); - --sf-gutter: var(--sf-space-m); - - /* ───────────────────────────────────────────────────────────── - BORDER TOKENS - ───────────────────────────────────────────────────────────────── */ - - /* Border width scale */ - --sf-border-width-1: calc(2px * var(--sf-border-scale, 1)); - --sf-border-width-2: calc(3px * var(--sf-border-scale, 1)); - --sf-border-width-3: calc(4px * var(--sf-border-scale, 1)); - --sf-border-width-4: calc(6px * var(--sf-border-scale, 1)); - --sf-border-width-hairline: 1px; - --sf-border-scale: 1.2; - --sf-border-style: solid; - - /* Composite border tokens use updated widths and colors */ - - /* ───────────────────────────────────────────────────────────── - RADIUS TOKENS — More rounded - ───────────────────────────────────────────────────────────────── */ - - --sf-radius-2xs: 0.35rem; - --sf-radius-xs: 0.55rem; - --sf-radius-s: 0.85rem; - --sf-radius-m: 1.25rem; - --sf-radius-l: 1.8rem; - --sf-radius-xl: 2.5rem; - --sf-radius-2xl: 3.5rem; - --sf-radius-full: 9999px; - - /* ───────────────────────────────────────────────────────────── - SHADOW TOKENS — Stronger shadows - ───────────────────────────────────────────────────────────────── */ - - --sf-shadow-xs: 0 2px 6px oklch(0 0 0 / 0.12); - --sf-shadow-s: 0 4px 12px oklch(0 0 0 / 0.15); - --sf-shadow-m: 0 8px 20px oklch(0 0 0 / 0.18); - --sf-shadow-l: 0 12px 32px oklch(0 0 0 / 0.22); - --sf-shadow-xl: 0 16px 48px oklch(0 0 0 / 0.26); - --sf-shadow-2xl: 0 20px 64px oklch(0 0 0 / 0.30); - --sf-shadow-inner: inset 0 2px 4px oklch(0 0 0 / 0.10); - - /* ───────────────────────────────────────────────────────────── - ANIMATION TOKENS — Faster, with different easing - ───────────────────────────────────────────────────────────────── */ - - /* Motion scale — slower animations */ - --sf-motion-scale: 1.5; - - /* Durations — faster by default */ - --sf-duration-fast: 150ms; - --sf-duration-normal: 300ms; - --sf-duration-slow: 600ms; - --sf-duration-slower: 1200ms; - - /* Easing functions — custom cubic-bezier curves */ - --sf-ease-linear: linear; - --sf-ease-in: cubic-bezier(0.42, 0, 1, 1); - --sf-ease-out: cubic-bezier(0, 0, 0.58, 1); - --sf-ease-in-out: cubic-bezier(0.42, 0, 0.58, 1); - --sf-ease-overshoot: cubic-bezier(0.34, 1.56, 0.64, 1); - --sf-ease-elastic: cubic-bezier(0.68, -0.55, 0.265, 1.55); - - /* Animation definitions would use duration/easing above */ - - /* ───────────────────────────────────────────────────────────── - CONTAINER & LAYOUT TOKENS - ───────────────────────────────────────────────────────────────── */ - - /* Container max widths */ - --sf-container-max: 86rem; - --sf-container-narrow: 55rem; - --sf-container-prose: 65ch; - --sf-container-wide: 102rem; - - /* Grid configuration */ - --sf-grid-min: 18rem; - --sf-grid-gap: var(--sf-space-m); - - /* Section padding */ - --sf-section-pad-xs: var(--sf-space-s); - --sf-section-pad-s: var(--sf-space-l); - --sf-section-pad-m: var(--sf-space-2xl); - --sf-section-pad-l: var(--sf-space-3xl); - --sf-section-pad-xl: var(--sf-space-4xl); - --sf-section-pad-2xl: var(--sf-space-4xl); - - /* Box padding */ - --sf-box-padding: var(--sf-space-l); - --sf-box-border-width: var(--sf-border-width-1); - --sf-box-border-color: var(--sf-color-border); - - /* Center intrinsic sizing */ - --sf-center-max: 58rem; - --sf-center-gutter: var(--sf-space-m); - - /* Stack gap (default) */ - --sf-stack-gap: var(--sf-space-m); - - /* Cluster alignment and gap */ - --sf-cluster-gap: var(--sf-space-m); - --sf-cluster-align: center; - --sf-cluster-justify: flex-start; - - /* Sidebar sizing */ - --sf-sidebar-min-width: 18rem; - --sf-sidebar-gap: var(--sf-space-l); - - /* Switcher threshold */ - --sf-switcher-threshold: 30rem; - --sf-switcher-gap: var(--sf-space-m); - - /* Divider tokens */ - --sf-divider-width: var(--sf-border-width-1); - --sf-divider-color: var(--sf-color-border); - --sf-divider-style: solid; - - /* Cover min/max heights */ - --sf-cover-min: 40vh; - --sf-cover-max: 70vh; - --sf-cover-pad-s: var(--sf-space-m); - --sf-cover-pad-l: var(--sf-space-2xl); - - /* Frame aspect ratio */ - --sf-frame-ratio: 16 / 9; - - /* Icon sizing */ - --sf-icon-xs: 1.25em; - --sf-icon-s: 1.5em; - --sf-icon-m: 1.75em; - --sf-icon-l: 2.25em; - --sf-icon-xl: 2.75em; - --sf-icon-2xl: 3.5em; - - --sf-icon-box-pad: var(--sf-space-s); - --sf-icon-box-radius: var(--sf-radius-m); - --sf-icon-box-bg: var(--sf-color-bg); - --sf-icon-box-border: var(--sf-border); - - /* Content grid sizing */ - --sf-content-width: 65ch; - --sf-breakout-width: 85rem; - - /* Reel/scroll strip */ - --sf-reel-height: 20rem; - --sf-reel-gap: var(--sf-space-m); - - /* Bento grid */ - --sf-bento-cols: auto-fit; - --sf-bento-row: auto; - - /* Imposter overlay margin */ - --sf-imposter-margin: var(--sf-space-m); - - /* ───────────────────────────────────────────────────────────── - Z-INDEX SCALE — Higher values - ───────────────────────────────────────────────────────────────── */ - - --sf-z-default: 0; - --sf-z-dropdown: 500; - --sf-z-fixed: 1000; - --sf-z-modal: 5000; - --sf-z-popover: 10000; - --sf-z-tooltip: 15000; - - /* ───────────────────────────────────────────────────────────── - SPECIAL TOKENS - ───────────────────────────────────────────────────────────────── */ - - /* Blur effect */ - --sf-blur: 18px; - - /* Code styling */ - --sf-code-font-size: 0.85em; - - /* Focus ring */ - --sf-focus-width: 3px; - --sf-focus-color: var(--sf-color-focus); - --sf-focus-ring-shadow: 0 0 0 var(--sf-focus-width) var(--sf-focus-color); - - /* ───────────────────────────────────────────────────────────── - MACRO TOKEN CUSTOMIZATIONS - ───────────────────────────────────────────────────────────────── */ - - /* Prose paragraph spacing */ - --sf-prose-paragraph: var(--sf-content-gap); - - /* Flow spacing */ - --sf-flow-space: var(--sf-content-gap); - - /* Line clamp */ - --sf-line-clamp: 2; - - /* Equal height column gap */ - --sf-equal-gap: var(--sf-space-m); - - /* Overflow fade intensity */ - --sf-mask-scrim-opacity: 0.8; - - /* Scroll shadow size */ - --sf-scroll-shadow-size: 2rem; - - /* ───────────────────────────────────────────────────────────── - CONTRAST & ACCESSIBILITY TOKENS - ───────────────────────────────────────────────────────────────── */ - - /* Contrast threshold for automatic text color */ - --sf-contrast-threshold: 0.5; - --sf-contrast-bias: 0.05; - - /* Palette mixing amounts */ - --sf-palette-mix-50: 95%; - --sf-palette-mix-100: 85%; - --sf-palette-mix-200: 75%; - --sf-palette-mix-300: 60%; - --sf-palette-mix-400: 40%; - --sf-palette-mix-600: -40%; - --sf-palette-mix-700: -60%; - --sf-palette-mix-800: -75%; - --sf-palette-mix-900: -85%; - --sf-palette-mix-950: -92%; - - /* ───────────────────────────────────────────────────────────── - STATE TOKENS - ───────────────────────────────────────────────────────────────── */ - - /* Active state indicator */ - --sf-is-active: 1; - - /* Open/expanded state indicator */ - --sf-is-open: 1; - - /* ───────────────────────────────────────────────────────────── - BODY & BASE ELEMENT TOKENS - ───────────────────────────────────────────────────────────────── */ - - /* Body text styling */ - --sf-body-font-family: var(--sf-font-body); - --sf-body-font-size: var(--sf-text-m); - --sf-body-font-weight: var(--sf-font-weight-body); - --sf-body-line-height: var(--sf-leading-normal); - --sf-body-color: var(--sf-color-text); - --sf-body-em-style: italic; - --sf-body-strong-weight: var(--sf-font-weight-strong); - --sf-body-text-wrap: pretty; - - /* Caret color */ - --sf-caret-color: var(--sf-color-action); - - /* Mark styling */ - --sf-color-mark-bg: oklch(from var(--sf-color-warning) l c h / 0.35); - --sf-color-mark-text: inherit; -} + Perturbs every CONFIGURABLE (role: "knob") token to a valid, visibly-distinct + value so full-api-demo.html can prove each one is wired end to end. -/* ═══════════════════════════════════════════════════════════════════ - ADDITIONAL OVERRIDES — Testing specific features -═══════════════════════════════════════════════════════════════════ */ + Coverage: 202 of 225 knob tokens overridden. + 23 knobs are intentionally NOT perturbed (structural / + meta / sentinel) — listed with reasons at the bottom of this file. + ============================================================================ */ -/* Test that color variants are recalculated */ :root { - --sf-color-primary-lighter: var(--sf-color-primary-300); - --sf-color-primary-darker: var(--sf-color-primary-700); - --sf-color-action-lighter: var(--sf-color-action-300); - --sf-color-action-darker: var(--sf-color-action-700); - --sf-color-neutral-lighter: var(--sf-color-neutral-300); - --sf-color-neutral-darker: var(--sf-color-neutral-700); - --sf-color-base-lighter: var(--sf-color-base-300); - --sf-color-base-darker: var(--sf-color-base-700); -} - -/* Test focus styling */ -:focus-visible { - outline: var(--sf-focus-width) solid var(--sf-focus-color); - outline-offset: 2px; -} - -/* Test text input styling with updated tokens */ -input[type="text"], -input[type="email"], -input[type="password"], -textarea { - font-family: var(--sf-font-body); - font-size: var(--sf-text-m); - padding: var(--sf-space-s); - border: var(--sf-border); - border-radius: var(--sf-radius-m); - background: var(--sf-color-surface); - color: var(--sf-color-text); - line-height: var(--sf-leading-normal); -} - -input[type="text"]:focus, -input[type="email"]:focus, -input[type="password"]:focus, -textarea:focus { - outline: var(--sf-focus-width) solid var(--sf-color-action); - outline-offset: 0; - border-color: var(--sf-color-action); -} - -/* Test button styling with updated tokens */ -button { - font-family: var(--sf-font-body); - font-size: var(--sf-text-m); - font-weight: var(--sf-font-weight-strong); - padding: var(--sf-space-s) var(--sf-space-m); - border: var(--sf-border-width-1) solid var(--sf-color-border); - border-radius: var(--sf-radius-m); - background: var(--sf-color-surface); - color: var(--sf-color-text); - cursor: pointer; - transition: all var(--sf-duration-normal) var(--sf-ease-out); -} - -button:hover { - background: var(--sf-color-bg--hover); - border-color: var(--sf-color-action); -} - -button:active { - background: var(--sf-color-action); - color: white; -} - -button:focus-visible { - outline: var(--sf-focus-width) solid var(--sf-color-action); - outline-offset: 2px; -} - -/* Test link styling with updated tokens */ -a { - color: var(--sf-color-link); - transition: color var(--sf-duration-fast) var(--sf-ease-out); -} - -a:hover { - color: var(--sf-color-link--hover); -} - -a:visited { - color: var(--sf-color-link--visited); -} - -a:active { - color: var(--sf-color-link--active); -} - -a:focus-visible { - outline: var(--sf-focus-width) solid var(--sf-color-action); - outline-offset: 2px; -} - -/* Test code block styling */ -code, -pre { - font-family: var(--sf-font-mono); - font-size: var(--sf-code-font-size); - background: var(--sf-color-code-bg); - color: var(--sf-color-code-text); - padding: var(--sf-space-2xs) var(--sf-space-xs); - border-radius: var(--sf-radius-s); -} - -/* Test with animations */ -@media (prefers-reduced-motion: no-preference) { - * { - transition-duration: var(--sf-duration-normal); - transition-timing-function: var(--sf-ease-out); - } -} -/* Test contrast in dark mode */ -@media (prefers-color-scheme: dark) { - :root { - --sf-contrast-bias: 0.08; - } + /* aspect */ + --sf-aspect: 3 / 1; /* was: 16 / 9 */ + + /* bento */ + --sf-bento-cols-default: 3; /* was: 4 */ + --sf-bento-row-compact: 9.6rem; /* was: 6rem */ + --sf-bento-row-default: 16rem; /* was: 10rem */ + --sf-bento-row-tall: 25.6rem; /* was: 16rem */ + + /* bg */ + --sf-bg-fit: contain; /* was: cover */ + --sf-bg-inset: 0.75rem; /* was: 0 */ + --sf-bg-position: 25% 75%; /* was: 50% 50% */ + --sf-bg-radius: 0.75rem; /* was: 0 */ + + /* blur */ + --sf-blur: 19.2px; /* was: 12px */ + + /* body */ + --sf-body-em-style: oblique; /* was: italic */ + --sf-body-text-wrap: balance; /* was: pretty */ + + /* border */ + --sf-border-scale: 1.6; /* was: 1 */ + --sf-border-style: dashed; /* was: solid */ + --sf-border-width-hairline: 0.8px; /* was: 0.5px */ + + /* box */ + --sf-box-border-width: 3px; /* was: 0 */ + + /* cluster */ + --sf-cluster-align: stretch; /* was: center */ + --sf-cluster-justify: center; /* was: flex-start */ + + /* code */ + --sf-code-font-size: 1.4em; /* was: 0.875em */ + + /* color */ + --sf-color-action-source-dark: oklch(from oklch(0.70 0.198 235) calc(l + 0.12) calc(c + 0.12) calc(h + 150) / alpha); /* was: oklch(0.70 0.198 235) */ + --sf-color-action-source-light: oklch(from oklch(0.50 0.22 235) calc(l + 0.12) calc(c + 0.12) calc(h + 150) / alpha); /* was: oklch(0.50 0.22 235) */ + --sf-color-base-source-dark: oklch(from oklch(0.22 0.003 250) calc(l + 0.12) calc(c + 0.12) calc(h + 150) / alpha); /* was: oklch(0.22 0.003 250) */ + --sf-color-base-source-light: oklch(from oklch(0.96 0.006 250) calc(l + 0.12) calc(c + 0.12) calc(h + 150) / alpha); /* was: oklch(0.96 0.006 250) */ + --sf-color-black: oklch(from oklch(0% 0 0) calc(l + 0.12) calc(c + 0.12) calc(h + 150) / alpha); /* was: oklch(0% 0 0) */ + --sf-color-danger-source-dark: oklch(from oklch(0.71 0.198 12) calc(l + 0.12) calc(c + 0.12) calc(h + 150) / alpha); /* was: oklch(0.71 0.198 12) */ + --sf-color-danger-source-light: oklch(from oklch(0.48 0.22 12) calc(l + 0.12) calc(c + 0.12) calc(h + 150) / alpha); /* was: oklch(0.48 0.22 12) */ + --sf-color-dim: oklch(from oklch(0 0 0 / 0.5) calc(l + 0.12) calc(c + 0.12) calc(h + 150) / alpha); /* was: oklch(0 0 0 / 0.5) */ + --sf-color-info-source-dark: oklch(from oklch(0.71 0.162 235) calc(l + 0.12) calc(c + 0.12) calc(h + 150) / alpha); /* was: oklch(0.71 0.162 235) */ + --sf-color-info-source-light: oklch(from oklch(0.48 0.18 235) calc(l + 0.12) calc(c + 0.12) calc(h + 150) / alpha); /* was: oklch(0.48 0.18 235) */ + --sf-color-mark-text: oklch(0.45 0.27 320); /* was: inherit */ + --sf-color-neutral-source-dark: oklch(from oklch(0.69 0.0225 260) calc(l + 0.12) calc(c + 0.12) calc(h + 150) / alpha); /* was: oklch(0.69 0.0225 260) */ + --sf-color-neutral-source-light: oklch(from oklch(0.52 0.025 260) calc(l + 0.12) calc(c + 0.12) calc(h + 150) / alpha); /* was: oklch(0.52 0.025 260) */ + --sf-color-primary-source-dark: oklch(from oklch(0.715 0.243 264) calc(l + 0.12) calc(c + 0.12) calc(h + 150) / alpha); /* was: oklch(0.715 0.243 264) */ + --sf-color-primary-source-light: oklch(from oklch(0.47 0.27 264) calc(l + 0.12) calc(c + 0.12) calc(h + 150) / alpha); /* was: oklch(0.47 0.27 264) */ + --sf-color-secondary-source-dark: oklch(from oklch(0.84 0.036 264) calc(l + 0.12) calc(c + 0.12) calc(h + 150) / alpha); /* was: oklch(0.84 0.036 264) */ + --sf-color-secondary-source-light: oklch(from oklch(0.22 0.04 264) calc(l + 0.12) calc(c + 0.12) calc(h + 150) / alpha); /* was: oklch(0.22 0.04 264) */ + --sf-color-selection-text: oklch(0.98 0 0); /* was: inherit */ + --sf-color-success-source-dark: oklch(from oklch(0.70 0.144 145) calc(l + 0.12) calc(c + 0.12) calc(h + 150) / alpha); /* was: oklch(0.70 0.144 145) */ + --sf-color-success-source-light: oklch(from oklch(0.50 0.16 145) calc(l + 0.12) calc(c + 0.12) calc(h + 150) / alpha); /* was: oklch(0.50 0.16 145) */ + --sf-color-tertiary-source-dark: oklch(from oklch(0.74 0.198 295) calc(l + 0.12) calc(c + 0.12) calc(h + 150) / alpha); /* was: oklch(0.74 0.198 295) */ + --sf-color-tertiary-source-light: oklch(from oklch(0.42 0.22 295) calc(l + 0.12) calc(c + 0.12) calc(h + 150) / alpha); /* was: oklch(0.42 0.22 295) */ + --sf-color-warning-source-dark: oklch(from oklch(0.65 0.153 80) calc(l + 0.12) calc(c + 0.12) calc(h + 150) / alpha); /* was: oklch(0.65 0.153 80) */ + --sf-color-warning-source-light: oklch(from oklch(0.75 0.17 80) calc(l + 0.12) calc(c + 0.12) calc(h + 150) / alpha); /* was: oklch(0.75 0.17 80) */ + --sf-color-white: oklch(from oklch(100% 0 0) calc(l + 0.12) calc(c + 0.12) calc(h + 150) / alpha); /* was: oklch(100% 0 0) */ + + /* container */ + --sf-container-default: 120rem; /* was: 75rem */ + --sf-container-full: 70%; /* was: 100% */ + --sf-container-narrow: 60.8rem; /* was: 38rem */ + --sf-container-prose: 104ch; /* was: 65ch */ + --sf-container-wide: 144rem; /* was: 90rem */ + + /* content */ + --sf-content-intrinsic-size: 800px; /* was: 500px */ + + /* contrast */ + --sf-contrast-bias: 0.12; /* was: 0 */ + --sf-contrast-threshold: 0.45; /* was: 0.6 */ + + /* cover */ + --sf-cover-min-height: 160dvh; /* was: 100dvh */ + + /* display */ + --sf-display-l-line-height: 1.2; /* was: 1 */ + --sf-display-m-line-height: 1.25; /* was: 1.05 */ + + /* divider */ + --sf-divider-style: dashed; /* was: solid */ + + /* duration */ + --sf-duration-none: 160ms; /* was: 0ms */ + + /* ease */ + --sf-ease-bounce: cubic-bezier(0.68, -0.55, 0.27, 1.55); /* was: linear(0, 0.35 18%, 1 32%, 0.86 42%, 1.02 56%, 0.98 72%, 1) */ + --sf-ease-elastic: cubic-bezier(0.68, -0.55, 0.27, 1.55); /* was: linear(0, 0.3, 1.2, 0.9, 1.05, 1) */ + --sf-ease-in: cubic-bezier(0.68, -0.55, 0.27, 1.55); /* was: cubic-bezier(0.5, 0, 0.75, 0.25) */ + --sf-ease-in-out: cubic-bezier(0.68, -0.55, 0.27, 1.55); /* was: cubic-bezier(0.4, 0, 0.2, 1) */ + --sf-ease-linear: cubic-bezier(0.68, -0.55, 0.27, 1.55); /* was: linear */ + --sf-ease-out: cubic-bezier(0.68, -0.55, 0.27, 1.55); /* was: cubic-bezier(0.25, 0, 0.15, 1) */ + --sf-ease-overshoot: cubic-bezier(0.68, -0.55, 0.27, 1.55); /* was: linear(0, 0.6 30%, 1.08 55%, 0.98 75%, 1) */ + --sf-ease-spring: cubic-bezier(0.68, -0.55, 0.27, 1.55); /* was: linear(0, 0.5, 1.1, 0.95, 1.02, 1) */ + + /* equal */ + --sf-equal-min-col: 25.6rem; /* was: 16rem */ + --sf-equal-min-col-2: 44.8rem; /* was: 28rem */ + --sf-equal-min-col-3: 24rem; /* was: 15rem */ + --sf-equal-min-col-4: 25.6rem; /* was: 16rem */ + --sf-equal-min-col-6: 16rem; /* was: 10rem */ + + /* field */ + --sf-field-required-marker: " \2737"; /* was: " *" */ + + /* fluid */ + --sf-fluid-max-vw: 70; /* was: 90 */ + --sf-fluid-min-vw: 30; /* was: 22.5 */ + + /* focus */ + --sf-focus-ring-offset: 3.2px; /* was: 2px */ + --sf-focus-ring-style: dashed; /* was: solid */ + --sf-focus-ring-width: 3.2px; /* was: 2px */ + + /* font */ + --sf-font-body: "Georgia", "Times New Roman", serif; /* was: system-ui, -apple-system, sans-serif */ + --sf-font-features: "liga" 1, "calt" 1; /* was: normal */ + --sf-font-geometric: "Georgia", "Times New Roman", serif; /* was: "Avenir", "Montserrat", "Corbel", "URW Gothic", source-sans-pro, sans-serif */ + --sf-font-humanist: "Georgia", "Times New Roman", serif; /* was: "Seravek", "Gill Sans Nova", "Ubuntu", "Calibri", "DejaVu Sans", source-sans-pro, sans-serif */ + --sf-font-mono: "Courier New", ui-monospace, monospace; /* was: ui-monospace, monospace */ + --sf-font-numeric: oldstyle-nums; /* was: tabular-nums */ + --sf-font-slab: "Georgia", "Times New Roman", serif; /* was: "Rockwell", "Rockwell Nova", "Roboto Slab", "DejaVu Serif", "Sitka Small", serif */ + --sf-font-variation: "wght" 650; /* was: normal */ + --sf-font-weight-bold: 900; /* was: 700 */ + --sf-font-weight-light: 200; /* was: 300 */ + --sf-font-weight-medium: 700; /* was: 500 */ + --sf-font-weight-normal: 600; /* was: 400 */ + --sf-font-weight-semibold: 800; /* was: 600 */ + + /* frame */ + --sf-frame-ratio: 3 / 1; /* was: 16 / 9 */ + + /* grid */ + --sf-grid-min: 25.6rem; /* was: 16rem */ + --sf-grid-min-2xl: 44.8rem; /* was: 28rem */ + --sf-grid-min-l: 32rem; /* was: 20rem */ + --sf-grid-min-m: 25.6rem; /* was: 16rem */ + --sf-grid-min-s: 20.8rem; /* was: 13rem */ + --sf-grid-min-xl: 38.4rem; /* was: 24rem */ + --sf-grid-min-xs: 16rem; /* was: 10rem */ + + /* h1 */ + --sf-h1-max-width: 40ch; /* was: none */ + + /* h2 */ + --sf-h2-max-width: 40ch; /* was: none */ + + /* h3 */ + --sf-h3-max-width: 40ch; /* was: none */ + + /* h4 */ + --sf-h4-max-width: 40ch; /* was: none */ + + /* h5 */ + --sf-h5-max-width: 40ch; /* was: none */ + + /* h6 */ + --sf-h6-max-width: 40ch; /* was: none */ + + /* header */ + --sf-header-height-desktop: 8rem; /* was: 5rem */ + --sf-header-height-mobile: 5.6rem; /* was: 3.5rem */ + + /* heading */ + --sf-heading-text-wrap: pretty; /* was: balance */ + + /* icon */ + --sf-icon-2xl: 6.4em; /* was: 4em */ + --sf-icon-box-pad: 0.8em; /* was: 0.5em */ + --sf-icon-l: 3.2em; /* was: 2em */ + --sf-icon-m: 2.4em; /* was: 1.5em */ + --sf-icon-s: 1.6em; /* was: 1em */ + --sf-icon-xl: 4.8em; /* was: 3em */ + --sf-icon-xs: 1.4em; /* was: 0.875em */ + + /* leading */ + --sf-leading-normal: 1.8; /* was: 1.5 */ + --sf-leading-relaxed: 2; /* was: 1.625 */ + --sf-leading-snug: 1.5; /* was: 1.3 */ + --sf-leading-taper: 0.4; /* was: 0 */ + --sf-leading-tight: 1.25; /* was: 1.1 */ + + /* line */ + --sf-line-clamp: 2; /* was: 3 */ + + /* link */ + --sf-link-external-marker: " \2192"; /* was: " \2197" */ + --sf-link-underline-offset: 0.24em; /* was: 0.15em */ + --sf-link-underline-thickness: 3px; /* was: auto */ + + /* lumlocker */ + --sf-lumlocker: 0.5; /* was: 0.65 */ + + /* motion */ + --sf-motion-scale: 1.6; /* was: 1 */ + + /* object */ + --sf-object-fit: contain; /* was: cover */ + --sf-object-position: 25% 75%; /* was: 50% 50% */ + + /* opacity */ + --sf-opacity-disabled: 0.7; /* was: 0.45 */ + --sf-opacity-muted: 0.75; /* was: 0.5 */ + + /* optical */ + --sf-optical-sizing: none; /* was: auto */ + + /* palette */ + --sf-palette-mix-100: 5.6%; /* was: 8% */ + --sf-palette-mix-200: 14%; /* was: 20% */ + --sf-palette-mix-300: 28%; /* was: 40% */ + --sf-palette-mix-400: 45.5%; /* was: 65% */ + --sf-palette-mix-50: 2.8%; /* was: 4% */ + --sf-palette-mix-600: 57.4%; /* was: 82% */ + --sf-palette-mix-700: 43.4%; /* was: 62% */ + --sf-palette-mix-800: 26.6%; /* was: 38% */ + --sf-palette-mix-900: 12.6%; /* was: 18% */ + --sf-palette-mix-950: 5.6%; /* was: 8% */ + + /* print */ + --sf-print-base-size: 17.6pt; /* was: 11pt */ + --sf-print-page-margin: 3.2cm; /* was: 2cm */ + --sf-print-page-size: letter; /* was: a4 */ + + /* radius */ + --sf-radius-full: 15998.4px; /* was: 9999px */ + --sf-radius-none: 0.4rem; /* was: 0 */ + --sf-radius-scale: 1.6; /* was: 1 */ + + /* ratio */ + --sf-ratio-3-2: 3 / 1; /* was: 3 / 2 */ + --sf-ratio-4-3: 3 / 1; /* was: 4 / 3 */ + --sf-ratio-cinema: 3 / 1; /* was: 21 / 9 */ + --sf-ratio-golden: 3 / 1; /* was: 1.618 / 1 */ + --sf-ratio-portrait: 3 / 1; /* was: 3 / 4 */ + --sf-ratio-square: 3 / 1; /* was: 1 */ + --sf-ratio-video: 3 / 1; /* was: 16 / 9 */ + + /* reel */ + --sf-reel-height: 14rem; /* was: auto */ + --sf-reel-item-width: min-content; /* was: max-content */ + + /* scrim */ + --sf-scrim-color: oklch(from oklch(0 0 0 / 0.55) calc(l + 0.12) calc(c + 0.12) calc(h + 150) / alpha); /* was: oklch(0 0 0 / 0.55) */ + --sf-scrim-direction: to right; /* was: to top */ + --sf-scrim-text-shadow: 0 2px 6px oklch(0 0 0 / 0.85); /* was: 0 1px 3px oklch(0 0 0 / 0.6) */ + + /* scroll */ + --sf-scroll-shadow-size: 3.2rem; /* was: 2rem */ + --sf-scroll-timeline-range-end: cover 60%; /* was: cover 30% */ + --sf-scroll-timeline-range-start: entry 20%; /* was: entry 0% */ + + /* scrollbar */ + --sf-scrollbar-track: oklch(0.85 0.05 300); /* was: transparent */ + + /* section */ + --sf-section-scale: 1.6; /* was: 1 */ + + /* shadow */ + --sf-shadow-lightness: 0.4; /* was: 0.15 */ + --sf-shadow-strength: 0.45; /* was: calc(0.08 + var(--sf-is-dark) * 0.17) */ + + /* sidebar */ + --sf-sidebar-min-width: 35%; /* was: 50% */ + --sf-sidebar-width: 28.8rem; /* was: 18rem */ + + /* size */ + --sf-size-l: 4.4rem; /* was: 2.75rem */ + --sf-size-m: 4rem; /* was: 2.5rem */ + --sf-size-s: 3.2rem; /* was: 2rem */ + --sf-size-xl: 5.6rem; /* was: 3.5rem */ + --sf-size-xs: 2.4rem; /* was: 1.5rem */ + + /* space */ + --sf-space-base-max: 3; /* was: 2 */ + --sf-space-base-min: 1.4; /* was: 1 */ + --sf-space-none: 0.25rem; /* was: 0 */ + --sf-space-px: 2px; /* was: 1px */ + --sf-space-ratio-max: 1.6; /* was: 1.333 */ + --sf-space-ratio-min: 1.4; /* was: 1.25 */ + --sf-space-scale: 1.6; /* was: 1 */ + + /* state */ + --sf-state-pending-opacity: 0.4; /* was: 0.7 */ + + /* switcher */ + --sf-switcher-threshold: 48rem; /* was: 30rem */ + + /* text */ + --sf-text-2xl-max-width: 50ch; /* was: none */ + --sf-text-2xs-max-width: 88ch; /* was: 55ch */ + --sf-text-3xl-max-width: 50ch; /* was: none */ + --sf-text-4xl-max-width: 50ch; /* was: none */ + --sf-text-base-max: 1.5; /* was: 1.25 */ + --sf-text-base-min: 1.15; /* was: 1 */ + --sf-text-display-base-max: 3.8; /* was: 3 */ + --sf-text-display-base-min: 2.8; /* was: 2.4 */ + --sf-text-display-scale: 1.6; /* was: 1 */ + --sf-text-l-max-width: 50ch; /* was: none */ + --sf-text-m-max-width: 104ch; /* was: 65ch */ + --sf-text-ratio-max: 1.5; /* was: 1.333 */ + --sf-text-ratio-min: 1.35; /* was: 1.25 */ + --sf-text-s-max-width: 104ch; /* was: 65ch */ + --sf-text-scale: 1.6; /* was: 1 */ + --sf-text-xl-max-width: 50ch; /* was: none */ + --sf-text-xs-max-width: 96ch; /* was: 60ch */ + + /* tracking */ + --sf-tracking-normal: 0.03em; /* was: 0 */ + --sf-tracking-tight: -0.04em; /* was: -0.025em */ + --sf-tracking-wide: 0.04em; /* was: 0.025em */ + --sf-tracking-wider: 0.08em; /* was: 0.05em */ + --sf-tracking-widest: 0.16em; /* was: 0.1em */ } -/* Container query test — ensure layout tokens work */ -@supports (container-type: inline-size) { - .sf-container { - container-type: inline-size; - container-name: sf-layout; - } -} +/* ---------------------------------------------------------------------------- + Intentionally NOT overridden (23): + --sf-bg-z — stacking order — lowering it would push the background layer over content + --sf-color-scheme — meta control — forcing a scheme would override the page light/dark behaviour rather than test a visual token + --sf-is-active — runtime state flag — exercised via the .is-active class; a global :root flip would force every element active + --sf-is-current — runtime state flag — exercised via the .is-current class + --sf-is-dark — runtime theme flag — driven by color-scheme; a global flip would desync from the actual scheme + --sf-is-open — runtime state flag — exercised via the .is-open class + --sf-is-pressed — runtime state flag — exercised via the .is-pressed class + --sf-safe-bottom — env() device inset — zero on desktop, no visual surface + --sf-safe-left — env() device inset — zero on desktop, no visual surface + --sf-safe-right — env() device inset — zero on desktop, no visual surface + --sf-safe-top — env() device inset — zero on desktop, no visual surface + --sf-shadow-none — sentinel "none" — the API guarantees no shadow; overriding would add one where none is promised + --sf-text-shadow-none — sentinel "none" — the API guarantees no text-shadow + --sf-z-base — stacking order — no single-element visual surface + --sf-z-below — stacking order — no single-element visual surface; global change risks hiding content + --sf-z-dropdown — stacking order — no single-element visual surface + --sf-z-fixed — stacking order — no single-element visual surface + --sf-z-modal — stacking order — no single-element visual surface + --sf-z-overlay — stacking order — no single-element visual surface + --sf-z-raised — stacking order — no single-element visual surface + --sf-z-sticky — stacking order — no single-element visual surface + --sf-z-toast — stacking order — no single-element visual surface + --sf-z-tooltip — stacking order — no single-element visual surface + ---------------------------------------------------------------------------- */ From c28449737621b79f7decd6d5b11a92d6132cc043 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 29 Jun 2026 16:16:53 +0000 Subject: [PATCH 4/5] feat: add dark mode, interactive functions, and complete token reference MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Expand the generated demo so every part of the API is exercisable in one page. Toolbar controls (wired by a small inline script): - Theme: Auto / Light / Dark via data-theme on the root (Auto falls back to prefers-color-scheme), exactly as core/themes.css drives it. - LumLocker and Cross-fade (.sf-theme-transition) toggles. - Ultimate override: injects/removes ultimate-override.css at runtime so the same page shows baseline and overridden side by side. - Replay all: re-triggers every animation/easing/duration/transition. Interactive Functions section — every motion/effect token is runnable: animations (replay), easing curves (animated dot), durations (growing bar), transitions (toggle state), all gradients, and drop-shadow filters. Part 2 — Complete token reference: all 691 tokens (knob + consumption, every tier) grouped by namespace, each with a best-effort visual (colour, gradient, shadow, radius, length bar, type sample, opacity, motion) and its LIVE computed value filled by JS. Toggling theme or override recomputes every value in place, so derived/semantic/private layout+macro tokens are all observable. A build assertion fails unless all 691 tokens render. validate.mjs now also checks: dark-mode restyles the page (bg lightness flips), the runtime override toggle changes computed styles, and JS populates the live token values — all against the locally built optimal bundle, 0 console errors. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01QCMzUyUS62KUSkr4AzrF7M --- demos/generate.mjs | 242 ++++++++++++++++++++++- demos/validate.mjs | 118 ++++++----- full-api-demo-with-overrides.html | 314 +++++++++++++++++++++++++++++- full-api-demo.html | 312 ++++++++++++++++++++++++++++- 4 files changed, 923 insertions(+), 63 deletions(-) diff --git a/demos/generate.mjs b/demos/generate.mjs index d9ea3ff6..f24526af 100644 --- a/demos/generate.mjs +++ b/demos/generate.mjs @@ -364,11 +364,172 @@ ${items.map(tile).join('\n')}
`; } +// ───────────────────────────────────────────────────────────────────────── +// PART 2 — complete token reference (every token, live computed value). +// ───────────────────────────────────────────────────────────────────────── +function tokenVisual(t) { + const n = t.name, ns = t.namespace, v = t.value; + if (/gradient\(/.test(v)) return `
`; + if (ns === 'color') return `
`; + if (ns === 'drop' || /drop-shadow\(/.test(v)) return `
`; + if (ns === 'shadow') { + if (n === '--sf-shadow-color') return `
`; + if (/none|strength|lightness/.test(n)) return ''; + return `
`; + } + if (ns === 'radius') return /scale/.test(n) ? '' : `
`; + if (ns === 'animation') return /delay/.test(n) ? '' : `
`; + if (ns === 'opacity') return `
`; + if (ns === 'leading') return `

Aa Bb
Cc Dd

`; + if (ns === 'tracking') return `AVTAW`; + if (ns === 'font') { + if (/weight/.test(n)) return `Ag`; + if (/body|mono|humanist|geometric|slab|family/.test(n)) return `Ag f`; + return ''; + } + if (ns === 'text') { + if (/max-width/.test(n)) return `
`; + if (/base|ratio|scale/.test(n)) return ''; + return `Aa`; + } + const lenNs = new Set(['space', 'size', 'icon', 'blur', 'gap', 'gutter', 'container', 'sidebar', 'grid', 'equal', + 'bento', 'cover', 'header', 'touch', 'mask', 'scroll', 'focus', 'box', 'content', 'section', 'divider', 'reel', + 'prose', 'stack', 'cluster', 'switcher', 'imposter', 'breakout', 'alternate', 'center', 'btn', 'field', 'scrim', + 'sticky', 'heading']); + if (lenNs.has(ns) && /(\d|\bvar\()/.test(v) && !/\//.test(v) && !/,/.test(v) + && !/^(none|auto|inherit|normal|max-content|min-content|transparent)/.test(v)) { + return `
`; + } + return ''; +} + +function tokenTile(t) { + const vis = tokenVisual(t); + const tier = t.tier === 'PUBLIC' ? '' : ` ${t.tier === 'PUBLIC-ADVANCED' ? 'adv' : t.tier.toLowerCase()}`; + return `
${esc(t.name)}${tier}${vis ? `
${vis}
` : ''}
`; +} + +function tokenReferenceSection() { + const byNs = {}; + tokens.forEach((t) => (byNs[t.namespace] ||= []).push(t)); + const pref = ['color', 'gradient', 'shadow', 'drop', 'radius', 'space', 'size', 'text', 'font', 'leading', 'tracking', + 'duration', 'ease', 'transition', 'animation', 'border', 'focus', 'opacity', 'blur', 'z']; + const order = [...pref.filter((n) => byNs[n]), ...Object.keys(byNs).filter((n) => !pref.includes(n)).sort()]; + const blocks = order.map((ns) => { + const items = byNs[ns].sort((a, b) => a.name.localeCompare(b.name)); + return `

${ns} ${items.length}

\n
${items.map(tokenTile).join('')}
`; + }).join('\n'); + return `
+

Part 2 — Complete token reference ${tokens.length} tokens · live values

+
Every --sf-* token — knob and consumption, all tiers — with its live computed value (filled by JS). Toggle the theme or the override in the toolbar and watch every value recompute. Tokens that resolve to a colour, length, shadow, gradient, type or motion value also show a visual.
+${blocks} +
`; +} + +// ───────────────────────────────────────────────────────────────────────── +// Interactive functions — animations, easings, durations, transitions, +// gradients, drop-shadows. Driven by section-level class toggles + JS replay. +// ───────────────────────────────────────────────────────────────────────── +function fxList(items, render) { return `
${items.map(render).join('')}
`; } +function functionsSection() { + const anims = tokens.filter((t) => t.namespace === 'animation' && !/delay/.test(t.name)); + const eases = tokens.filter((t) => t.namespace === 'ease'); + const durs = tokens.filter((t) => t.namespace === 'duration'); + const trans = tokens.filter((t) => t.namespace === 'transition'); + const grads = tokens.filter((t) => t.namespace === 'gradient'); + const drops = tokens.filter((t) => t.namespace === 'drop'); + const cap = (t) => `${t.name.replace('--sf-', '')}`; + return `
+

Interactive functions motion · transitions · gradients

+ +

Animations

+ ${fxList(anims, (t) => `
${cap(t)}
`)} + +

Easing curves

+
${fxList(eases, (t) => `
${cap(t)}
`)}
+ +

Durations

+
${fxList(durs, (t) => `
${cap(t)}
`)}
+ +

Transitions

+
${fxList(trans, (t) => `
box
${cap(t)}
`)}
+ +

Gradients

+ ${fxList(grads, (t) => `
${cap(t)}
`)} + +

Drop shadows (filter)

+ ${fxList(drops, (t) => `
${cap(t)}
`)} +
`; +} + +function toolbar() { + return ` `; +} + +const PAGE_SCRIPT = [ + '(function () {', + ' var root = document.documentElement;', + ' function refresh() {', + ' var cs = getComputedStyle(root);', + ' document.querySelectorAll("[data-token]").forEach(function (el) {', + ' var v = cs.getPropertyValue(el.getAttribute("data-token")).trim();', + ' var o = el.querySelector(".ttile__val"); if (o) o.textContent = v || "(empty)";', + ' });', + ' }', + ' function playAnims() {', + ' document.querySelectorAll("[data-anim]").forEach(function (el) {', + ' var n = el.getAttribute("data-anim");', + ' el.style.animation = "none"; void el.offsetWidth; el.style.animation = "var(" + n + ")";', + ' });', + ' }', + ' function retrigger(id) { var s = document.getElementById(id); if (!s) return; s.classList.remove("go"); void s.offsetWidth; s.classList.add("go"); }', + ' function setTheme(t) {', + ' if (t === "auto") root.removeAttribute("data-theme"); else root.setAttribute("data-theme", t);', + ' document.querySelectorAll("[data-theme-btn]").forEach(function (b) { b.classList.toggle("active", b.getAttribute("data-theme-btn") === t); });', + ' setTimeout(refresh, 60);', + ' }', + ' var ov = document.getElementById("ov");', + ' function setOverride(on) {', + ' if (on) { if (!ov) { ov = document.createElement("link"); ov.rel = "stylesheet"; ov.href = "ultimate-override.css"; ov.id = "ov"; document.head.appendChild(ov); } }', + ' else if (ov) { ov.remove(); ov = null; }', + ' var b = document.getElementById("ovBtn"); if (b) b.classList.toggle("active", !!ov);', + ' setTimeout(refresh, 90);', + ' }', + ' document.addEventListener("click", function (e) {', + ' var t = e.target.closest("[data-act]"); if (!t) return;', + ' var a = t.getAttribute("data-act");', + ' if (a.indexOf("theme:") === 0) setTheme(a.slice(6));', + ' else if (a === "lumlocker") { root.toggleAttribute("data-lumlocker"); t.classList.toggle("active", root.hasAttribute("data-lumlocker")); setTimeout(refresh, 60); }', + ' else if (a === "crossfade") { root.classList.toggle("sf-theme-transition"); t.classList.toggle("active", root.classList.contains("sf-theme-transition")); }', + ' else if (a === "override") setOverride(!ov);', + ' else if (a === "replay") { playAnims(); retrigger("fx-ease"); retrigger("fx-dur"); var tr = document.getElementById("fx-trans"); if (tr) tr.classList.toggle("on"); }', + ' else if (a === "replay-anim") playAnims();', + ' else if (a === "run-ease") retrigger("fx-ease");', + ' else if (a === "run-dur") retrigger("fx-dur");', + ' else if (a === "toggle-trans") { var s = document.getElementById("fx-trans"); if (s) s.classList.toggle("on"); }', + ' });', + ' setOverride(!!ov);', + ' refresh();', + ' requestAnimationFrame(playAnims);', + '})();', +].join('\n'); + function buildDemo({ withOverride }) { - const overrideLink = withOverride ? `\n ` : ''; + const overrideLink = withOverride ? `\n ` : ''; const banner = withOverride - ? `
ultimate-override.css is ACTIVE. Every value below is recomputed from perturbed knob tokens — compare against the un-overridden page.
` - : `
Baseline render with default tokens. The override variant is full-api-demo-with-overrides.html.
`; + ? `
ultimate-override.css is ACTIVE. Every value below is recomputed from perturbed knob tokens — toggle it off in the toolbar, or compare against the un-overridden page.
` + : `
Baseline render with default tokens. Use the toolbar to switch theme, toggle the ultimate override live, or replay motion. The always-on override variant is full-api-demo-with-overrides.html.
`; const kinds = [ ['layout', 'Layout primitives'], ['macro', 'Macro classes'], @@ -430,16 +591,71 @@ function buildDemo({ withOverride }) { place-items: center; font: var(--sf-text-xs) var(--sf-font-mono); color: var(--sf-color-text--muted); } .gallery { display: grid; grid-template-columns: repeat(auto-fill, minmax(4rem, 1fr)); gap: var(--sf-space-l); padding: var(--sf-space-l); background: var(--sf-color-inset); border-radius: var(--sf-radius-m); } + /* toolbar */ + .toolbar { position: sticky; top: 0; z-index: 50; display: flex; flex-wrap: wrap; gap: var(--sf-space-xs); align-items: center; + padding: var(--sf-space-xs) var(--sf-space-l); background: var(--sf-color-overlay); + backdrop-filter: blur(8px); border-block-end: 1px solid var(--sf-color-border); } + .tb-label { font: var(--sf-text-xs) var(--sf-font-mono); color: var(--sf-color-text--muted); } + .toolbar button { font: var(--sf-text-s) var(--sf-font-body); padding: .35em .8em; border: 1px solid var(--sf-color-border); + background: var(--sf-color-surface); color: var(--sf-color-text); border-radius: var(--sf-radius-s); cursor: pointer; } + .toolbar .seg { display: inline-flex; } + .toolbar .seg button { border-radius: 0; border-inline-width: 0; } + .toolbar .seg button:first-child { border-radius: var(--sf-radius-s) 0 0 var(--sf-radius-s); border-inline-start-width: 1px; } + .toolbar .seg button:last-child { border-radius: 0 var(--sf-radius-s) var(--sf-radius-s) 0; border-inline-end-width: 1px; } + .toolbar button.active { background: var(--sf-color-primary); color: var(--sf-color-text--on-primary, #fff); border-color: var(--sf-color-primary); } + h3 button { margin-inline-start: var(--sf-space-s); font: var(--sf-text-xs) var(--sf-font-body); padding: .2em .7em; + border: 1px solid var(--sf-color-border); background: var(--sf-color-surface); color: var(--sf-color-text); + border-radius: var(--sf-radius-s); cursor: pointer; } + /* part 2 token reference */ + .ref-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr)); gap: var(--sf-space-s); } + .ttile { margin: 0; display: grid; gap: var(--sf-space-2xs); padding: var(--sf-space-xs); + border: 1px solid var(--sf-color-border); border-radius: var(--sf-radius-s); background: var(--sf-color-surface); } + .ttile__name { font: var(--sf-text-2xs)/1.35 var(--sf-font-mono); color: var(--sf-color-text--secondary); word-break: break-all; } + .ttile__tier { color: var(--sf-color-warning); } + .ttile__val { font: var(--sf-text-2xs)/1.35 var(--sf-font-mono); color: var(--sf-color-text--muted); + word-break: break-all; max-block-size: 4.5em; overflow: auto; } + .ttile__vis { min-block-size: 2.5rem; display: grid; place-items: center; border-radius: var(--sf-radius-xs); + background: repeating-conic-gradient(var(--sf-color-inset) 0 25%, transparent 0 50%) 0 0 / 1rem 1rem, var(--sf-color-surface); overflow: hidden; } + .tvis { inline-size: 100%; block-size: 2.5rem; } + .tvis--rad { background: var(--sf-color-primary); } + .tvis--card { inline-size: 72%; block-size: 2.2rem; background: var(--sf-color-surface); border-radius: var(--sf-radius-s); } + .tvis--bar { block-size: .9rem; background: linear-gradient(90deg, var(--sf-color-primary), var(--sf-color-action)); + border-radius: var(--sf-radius-full); justify-self: start; align-self: center; } + .tvis--txt { inline-size: auto; block-size: auto; color: var(--sf-color-text); line-height: 1; } + .tvis--lead { inline-size: auto; block-size: auto; margin: 0; font-size: var(--sf-text-2xs); color: var(--sf-color-text); } + .tvis--op { background: var(--sf-color-primary); } + .tvis--anim { inline-size: 2.5rem; background: var(--sf-color-action); border-radius: var(--sf-radius-s); } + /* interactive functions */ + .fx-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr)); gap: var(--sf-space-m); margin-block-end: var(--sf-space-m); } + .fx { margin: 0; display: grid; gap: var(--sf-space-2xs); justify-items: center; text-align: center; } + .fx code { font-size: var(--sf-text-2xs); color: var(--sf-color-text--muted); word-break: break-all; } + .fx-anim { inline-size: 3rem; block-size: 3rem; background: var(--sf-color-action); border-radius: var(--sf-radius-m); } + .fx-track { position: relative; inline-size: 100%; min-inline-size: 10rem; block-size: 1.4rem; + background: var(--sf-color-inset); border-radius: var(--sf-radius-full); overflow: hidden; } + .fx-dot { position: absolute; inset-block: .12rem; inset-inline-start: .12rem; inline-size: 1.15rem; + background: var(--sf-color-primary); border-radius: 50%; transform: translateX(0); } + #fx-ease.go .fx-dot { transform: translateX(8rem); } + .fx-grow { block-size: 1.4rem; inline-size: 0; border-radius: var(--sf-radius-full); + background: linear-gradient(90deg, var(--sf-color-primary), var(--sf-color-action)); } + #fx-dur.go .fx-grow { inline-size: 100%; } + .fx-trans { padding: var(--sf-space-s); inline-size: 100%; border: 1px solid var(--sf-color-border); + border-radius: var(--sf-radius-m); background: var(--sf-color-surface); } + #fx-trans.on .fx-trans { background: var(--sf-color-primary); color: var(--sf-color-text--on-primary, #fff); + transform: translateY(-4px) scale(1.03); box-shadow: var(--sf-shadow-l); border-color: var(--sf-color-primary); opacity: .92; } + .fx-grad { inline-size: 100%; block-size: 3rem; border-radius: var(--sf-radius-m); } + .fx-drop { inline-size: 3rem; block-size: 3rem; background: var(--sf-color-primary); border-radius: var(--sf-radius-m); } + @media (prefers-reduced-motion: reduce) { * { animation: none !important; transition: none !important; } } +${toolbar()}

SLASHED Full API Demo

-

v${VERSION} · optimal bundle from jsDelivr CDN · ${classes.length} classes · ${knobs.length} configurable tokens

+

v${VERSION} · optimal bundle from jsDelivr CDN · ${classes.length} classes · ${tokens.length} tokens (${knobs.length} configurable)

${banner}
-

Token galleries derived values

+

Token galleries highlights

Color ramps

${['primary', 'secondary', 'tertiary', 'action', 'neutral', 'base'].map(colorRamp).join('\n ')}

Semantic / role colors

@@ -454,8 +670,13 @@ function buildDemo({ withOverride }) {
+${functionsSection()} + ${kinds.map(([k, t]) => classSection(k, t)).join('\n')} + +${tokenReferenceSection()}
+ `; @@ -470,9 +691,16 @@ const emitted = new Set(); for (const c of classes) emitted.add(c.name); if (emitted.size !== classes.length) throw new Error('class de-dup mismatch'); -fs.writeFileSync(path.join(ROOT, 'full-api-demo.html'), buildDemo({ withOverride: false })); +const baseHtml = buildDemo({ withOverride: false }); +fs.writeFileSync(path.join(ROOT, 'full-api-demo.html'), baseHtml); fs.writeFileSync(path.join(ROOT, 'full-api-demo-with-overrides.html'), buildDemo({ withOverride: true })); +// completeness assertion for tokens: every token must appear once in Part 2 +const tokenTiles = (baseHtml.match(/data-token="/g) || []).length; +if (tokenTiles !== tokens.length) { + throw new Error(`Part 2 token reference: ${tokenTiles} tiles != ${tokens.length} tokens`); +} + console.log(`ultimate-override.css → ${handledCount}/${knobs.length} knobs overridden, ${Object.keys(SKIP).length} skipped (documented)`); -console.log(`full-api-demo.html → ${classes.length} classes, all rendered`); +console.log(`full-api-demo.html → ${classes.length} classes + ${tokens.length} tokens (Part 2), all rendered`); console.log(`full-api-demo-with-overrides.html → same body + override link`); diff --git a/demos/validate.mjs b/demos/validate.mjs index d1b41aec..6ea7a5b2 100644 --- a/demos/validate.mjs +++ b/demos/validate.mjs @@ -1,6 +1,7 @@ -// Validates the generated demo pages in a real browser against the locally -// built optimal bundle. Asserts: no console errors, all class tiles present, -// and that the override actually changes computed styles. +// Validates the generated demo in a real browser against the locally built +// optimal bundle. Asserts: no console errors, all class + token tiles present, +// JS populates live token values, the dark-mode toggle restyles the page, and +// the runtime override toggle perturbs computed styles. import { chromium } from '@playwright/test'; import fs from 'node:fs'; import path from 'node:path'; @@ -11,71 +12,90 @@ const CDN = 'https://cdn.jsdelivr.net/gh/codeslash-dev/SLASHED@dist/slashed.opti const LOCAL = path.join(ROOT, 'badges/slashed.optimal.css'); const TMP = path.join(ROOT, 'demos/.validate'); fs.mkdirSync(TMP, { recursive: true }); +// make the runtime-injected override reachable from the temp copy +fs.copyFileSync(path.join(ROOT, 'ultimate-override.css'), path.join(TMP, 'ultimate-override.css')); function localCopy(srcName, outName) { let html = fs.readFileSync(path.join(ROOT, srcName), 'utf8'); - html = html.replace(CDN, 'file://' + LOCAL); - html = html.replace('href="ultimate-override.css"', `href="file://${path.join(ROOT, 'ultimate-override.css')}"`); + html = html.replaceAll(CDN, 'file://' + LOCAL); const out = path.join(TMP, outName); fs.writeFileSync(out, html); return 'file://' + out; } - const baseUrl = localCopy('full-api-demo.html', 'base.html'); -const ovUrl = localCopy('full-api-demo-with-overrides.html', 'ov.html'); -const expectedTiles = (fs.readFileSync(path.join(ROOT, 'full-api-demo.html'), 'utf8').match(/class="tile"/g) || []).length; +const expectClasses = (fs.readFileSync(path.join(ROOT, 'full-api-demo.html'), 'utf8').match(/class="tile"/g) || []).length; +const expectTokens = (fs.readFileSync(path.join(ROOT, 'full-api-demo.html'), 'utf8').match(/data-token="/g) || []).length; + +const browser = await chromium.launch({ executablePath: '/opt/pw-browsers/chromium' }); +const page = await browser.newPage({ viewport: { width: 1280, height: 1600 } }); +const errors = []; +page.on('console', (m) => { if (m.type() === 'error') errors.push(m.text()); }); +page.on('pageerror', (e) => errors.push(String(e))); +await page.goto(baseUrl, { waitUntil: 'domcontentloaded', timeout: 60000 }); +await page.waitForTimeout(800); -const PROBES = `(() => { +const fails = []; +const snap = () => page.evaluate(() => { const cs = getComputedStyle(document.documentElement); const body = getComputedStyle(document.body); - const dbox = document.querySelector('.dbox'); - const h1 = document.querySelector('h1'); + const vals = [...document.querySelectorAll('.ttile__val')].map((o) => o.textContent.trim()); return { + classTiles: document.querySelectorAll('.tile').length, + tokenTiles: document.querySelectorAll('[data-token]').length, + filledVals: vals.filter((v) => v && v !== '…' && v !== '(empty)').length, + theme: document.documentElement.getAttribute('data-theme'), + bg: body.backgroundColor, + text: body.color, primary: cs.getPropertyValue('--sf-color-primary').trim(), spaceM: cs.getPropertyValue('--sf-space-m').trim(), - bodyFont: body.fontFamily, - dboxPad: dbox ? getComputedStyle(dbox).paddingTop : null, - h1Size: h1 ? getComputedStyle(h1).fontSize : null, - tiles: document.querySelectorAll('.tile').length, + fxSections: ['functions', 'reference'].filter((id) => document.getElementById(id)).length, }; -})()`; +}); -const browser = await chromium.launch({ executablePath: '/opt/pw-browsers/chromium' }); -const fails = []; -async function load(url, label) { - const page = await browser.newPage({ viewport: { width: 1280, height: 1600 } }); - const errors = []; - page.on('console', (m) => { if (m.type() === 'error') errors.push(m.text()); }); - page.on('pageerror', (e) => errors.push(String(e))); - await page.goto(url, { waitUntil: 'load' }); - await page.waitForTimeout(400); - const probes = await page.evaluate(PROBES); - await page.screenshot({ path: path.join(TMP, label + '.png'), fullPage: false }); - await page.close(); - return { probes, errors }; -} +const click = (sel) => page.evaluate((s) => document.querySelector(s).click(), sel); -const base = await load(baseUrl, 'baseline'); -const ov = await load(ovUrl, 'override'); -await browser.close(); +const light = await snap(); +await page.screenshot({ path: path.join(TMP, 'light.png') }); + +// dark mode +await click('[data-act="theme:dark"]'); +await page.waitForTimeout(300); +const dark = await snap(); +await page.screenshot({ path: path.join(TMP, 'dark.png') }); -console.log('expected tiles:', expectedTiles); -console.log('\nBASELINE probes:', JSON.stringify(base.probes, null, 0)); -console.log('OVERRIDE probes:', JSON.stringify(ov.probes, null, 0)); -console.log('\nbaseline console errors:', base.errors.length); -base.errors.slice(0, 10).forEach((e) => console.log(' ⚠', e)); -console.log('override console errors:', ov.errors.length); -ov.errors.slice(0, 10).forEach((e) => console.log(' ⚠', e)); +// runtime override toggle (back in light) +await click('[data-act="theme:light"]'); +await click('#ovBtn'); +await page.waitForTimeout(300); +const overridden = await snap(); +await page.screenshot({ path: path.join(TMP, 'override.png') }); -// assertions -if (base.probes.tiles !== expectedTiles) fails.push(`baseline tiles ${base.probes.tiles} != ${expectedTiles}`); -if (ov.probes.tiles !== expectedTiles) fails.push(`override tiles ${ov.probes.tiles} != ${expectedTiles}`); -const changed = []; -for (const k of ['primary', 'spaceM', 'bodyFont', 'dboxPad', 'h1Size']) { - if (base.probes[k] !== ov.probes[k]) changed.push(k); - else fails.push(`override did NOT change "${k}" (still ${base.probes[k]})`); +// section screenshots for the report +await click('#ovBtn'); // override off +await click('[data-act="theme:light"]'); +await page.waitForTimeout(200); +for (const id of ['functions', 'reference']) { + const el = await page.$('#' + id); + if (el) await el.screenshot({ path: path.join(TMP, `sec-${id}.png`) }).catch(() => {}); } -console.log('\ntokens visibly changed by override:', changed.join(', ') || '(none!)'); +await browser.close(); + +console.log('expected class tiles:', expectClasses, '| token tiles:', expectTokens); +console.log('LIGHT :', JSON.stringify(light)); +console.log('DARK :', JSON.stringify(dark)); +console.log('OVERRIDE:', JSON.stringify(overridden)); +console.log('console errors:', errors.length); +errors.slice(0, 10).forEach((e) => console.log(' ⚠', e)); + +if (light.classTiles !== expectClasses) fails.push(`class tiles ${light.classTiles} != ${expectClasses}`); +if (light.tokenTiles !== expectTokens) fails.push(`token tiles ${light.tokenTiles} != ${expectTokens}`); +if (light.filledVals < expectTokens * 0.6) fails.push(`only ${light.filledVals}/${expectTokens} token values populated by JS`); +if (light.fxSections !== 2) fails.push('functions/reference sections missing'); +if (dark.theme !== 'dark') fails.push('dark toggle did not set data-theme=dark'); +if (dark.bg === light.bg) fails.push(`dark mode did not change body background (still ${light.bg})`); +if (overridden.primary === light.primary) fails.push('override toggle did not change --sf-color-primary'); +if (overridden.spaceM === light.spaceM) fails.push('override toggle did not change --sf-space-m'); +if (errors.length) fails.push(`${errors.length} console error(s)`); if (fails.length) { console.log('\n❌ FAIL:'); fails.forEach((f) => console.log(' ', f)); process.exit(1); } -console.log('\n✅ PASS — pages render, all tiles present, override perturbs computed styles.'); +console.log(`\n✅ PASS — ${expectClasses} classes + ${expectTokens} tokens rendered; JS fills live values; dark mode restyles; override toggles live; 0 console errors.`); diff --git a/full-api-demo-with-overrides.html b/full-api-demo-with-overrides.html index 56eb30d3..1c113fd8 100644 --- a/full-api-demo-with-overrides.html +++ b/full-api-demo-with-overrides.html @@ -5,7 +5,7 @@ SLASHED — Full API Demo (overridden) - + +

SLASHED Full API Demo

-

v0.6.25 · optimal bundle from jsDelivr CDN · 239 classes · 225 configurable tokens

-
ultimate-override.css is ACTIVE. Every value below is recomputed from perturbed knob tokens — compare against the un-overridden page.
+

v0.6.25 · optimal bundle from jsDelivr CDN · 239 classes · 691 tokens (225 configurable)

+
ultimate-override.css is ACTIVE. Every value below is recomputed from perturbed knob tokens — toggle it off in the toolbar, or compare against the un-overridden page.
-

Token galleries derived values

+

Token galleries highlights

Color ramps

primary
50
100
200
300
400
500
600
700
800
900
950
secondary
50
100
200
300
400
500
600
700
800
900
950
@@ -80,6 +146,28 @@

Shadow

+
+

Interactive functions motion · transitions · gradients

+ +

Animations

+
animation-blink
animation-color-pulse
animation-fade-in
animation-fade-out
animation-float
animation-ping
animation-scale-down
animation-scale-up
animation-shimmer
animation-slide-in-down
animation-slide-in-left
animation-slide-in-right
animation-slide-in-up
animation-spin
+ +

Easing curves

+
ease-bounce
ease-elastic
ease-in
ease-in-out
ease-linear
ease-out
ease-overshoot
ease-spring
+ +

Durations

+
duration-fast
duration-instant
duration-none
duration-normal
duration-slow
duration-slower
+ +

Transitions

+
box
transition-colors
box
transition-enter
box
transition-exit
box
transition-fast
box
transition-form-field
box
transition-opacity
box
transition-overlay
box
transition-shadow
box
transition-slow
box
transition-transform
+ +

Gradients

+
gradient-brand
gradient-fade--b
gradient-fade--l
gradient-fade--r
gradient-fade--t
gradient-primary
gradient-secondary
gradient-surface
gradient-tertiary
+ +

Drop shadows (filter)

+
drop-shadow-l
drop-shadow-m
drop-shadow-s
+
+

Layout primitives 128

@@ -1071,6 +1159,224 @@

Theme 2

+ +
+

Part 2 — Complete token reference 691 tokens · live values

+
Every --sf-* token — knob and consumption, all tiers — with its live computed value (filled by JS). Toggle the theme or the override in the toolbar and watch every value recompute. Tokens that resolve to a colour, length, shadow, gradient, type or motion value also show a visual.
+

color 255

+
--sf-color-action
--sf-color-action--active
--sf-color-action--hover
--sf-color-action-100
--sf-color-action-200
--sf-color-action-300
--sf-color-action-400
--sf-color-action-50
--sf-color-action-500
--sf-color-action-600
--sf-color-action-700
--sf-color-action-800
--sf-color-action-900
--sf-color-action-950
--sf-color-action-a10
--sf-color-action-a30
--sf-color-action-a5
--sf-color-action-a50
--sf-color-action-a80
--sf-color-action-darker
--sf-color-action-ghost
--sf-color-action-lighter
--sf-color-action-muted
--sf-color-action-source-dark
--sf-color-action-source-light
--sf-color-action-subtle
--sf-color-action-superdark
--sf-color-action-superlight
--sf-color-action-xdark
--sf-color-action-xlight
--sf-color-base
--sf-color-base--active
--sf-color-base--hover
--sf-color-base-100
--sf-color-base-200
--sf-color-base-300
--sf-color-base-400
--sf-color-base-50
--sf-color-base-500
--sf-color-base-600
--sf-color-base-700
--sf-color-base-800
--sf-color-base-900
--sf-color-base-950
--sf-color-base-a10
--sf-color-base-a30
--sf-color-base-a5
--sf-color-base-a50
--sf-color-base-a80
--sf-color-base-darker
--sf-color-base-ghost
--sf-color-base-lighter
--sf-color-base-muted
--sf-color-base-source-dark
--sf-color-base-source-light
--sf-color-base-subtle
--sf-color-base-superdark
--sf-color-base-superlight
--sf-color-base-xdark
--sf-color-base-xlight
--sf-color-bg
--sf-color-bg--active
--sf-color-bg--disabled
--sf-color-bg--focus
--sf-color-bg--hover
--sf-color-bg--selected
--sf-color-black
--sf-color-border
--sf-color-border--disabled
--sf-color-border--focus
--sf-color-border--strong
--sf-color-border--subtle
--sf-color-border--translucent
--sf-color-code-bg
--sf-color-code-text
--sf-color-danger
--sf-color-danger-muted
--sf-color-danger-source-dark
--sf-color-danger-source-light
--sf-color-danger-strong
--sf-color-danger-subtle
--sf-color-dim
--sf-color-heading
--sf-color-info
--sf-color-info-muted
--sf-color-info-source-dark
--sf-color-info-source-light
--sf-color-info-strong
--sf-color-info-subtle
--sf-color-inset
--sf-color-inverse
--sf-color-link
--sf-color-link--active
--sf-color-link--disabled
--sf-color-link--hover
--sf-color-link--underline
--sf-color-link--visited
--sf-color-mark-bg
--sf-color-mark-text
--sf-color-neutral
--sf-color-neutral--active
--sf-color-neutral--hover
--sf-color-neutral-100
--sf-color-neutral-200
--sf-color-neutral-300
--sf-color-neutral-400
--sf-color-neutral-50
--sf-color-neutral-500
--sf-color-neutral-600
--sf-color-neutral-700
--sf-color-neutral-800
--sf-color-neutral-900
--sf-color-neutral-950
--sf-color-neutral-a10
--sf-color-neutral-a30
--sf-color-neutral-a5
--sf-color-neutral-a50
--sf-color-neutral-a80
--sf-color-neutral-darker
--sf-color-neutral-ghost
--sf-color-neutral-lighter
--sf-color-neutral-muted
--sf-color-neutral-source-dark
--sf-color-neutral-source-light
--sf-color-neutral-subtle
--sf-color-neutral-superdark
--sf-color-neutral-superlight
--sf-color-neutral-xdark
--sf-color-neutral-xlight
--sf-color-overlay
--sf-color-primary
--sf-color-primary--active
--sf-color-primary--hover
--sf-color-primary-100
--sf-color-primary-200
--sf-color-primary-300
--sf-color-primary-400
--sf-color-primary-50
--sf-color-primary-500
--sf-color-primary-600
--sf-color-primary-700
--sf-color-primary-800
--sf-color-primary-900
--sf-color-primary-950
--sf-color-primary-a10
--sf-color-primary-a30
--sf-color-primary-a5
--sf-color-primary-a50
--sf-color-primary-a80
--sf-color-primary-darker
--sf-color-primary-ghost
--sf-color-primary-lighter
--sf-color-primary-muted
--sf-color-primary-source-dark
--sf-color-primary-source-light
--sf-color-primary-subtle
--sf-color-primary-superdark
--sf-color-primary-superlight
--sf-color-primary-xdark
--sf-color-primary-xlight
--sf-color-raised
--sf-color-scheme
--sf-color-secondary
--sf-color-secondary--active
--sf-color-secondary--hover
--sf-color-secondary-100
--sf-color-secondary-200
--sf-color-secondary-300
--sf-color-secondary-400
--sf-color-secondary-50
--sf-color-secondary-500
--sf-color-secondary-600
--sf-color-secondary-700
--sf-color-secondary-800
--sf-color-secondary-900
--sf-color-secondary-950
--sf-color-secondary-a10
--sf-color-secondary-a30
--sf-color-secondary-a5
--sf-color-secondary-a50
--sf-color-secondary-a80
--sf-color-secondary-darker
--sf-color-secondary-ghost
--sf-color-secondary-lighter
--sf-color-secondary-muted
--sf-color-secondary-source-dark
--sf-color-secondary-source-light
--sf-color-secondary-subtle
--sf-color-secondary-superdark
--sf-color-secondary-superlight
--sf-color-secondary-xdark
--sf-color-secondary-xlight
--sf-color-selection-bg
--sf-color-selection-text
--sf-color-success
--sf-color-success-muted
--sf-color-success-source-dark
--sf-color-success-source-light
--sf-color-success-strong
--sf-color-success-subtle
--sf-color-surface
--sf-color-tertiary
--sf-color-tertiary--active
--sf-color-tertiary--hover
--sf-color-tertiary-100
--sf-color-tertiary-200
--sf-color-tertiary-300
--sf-color-tertiary-400
--sf-color-tertiary-50
--sf-color-tertiary-500
--sf-color-tertiary-600
--sf-color-tertiary-700
--sf-color-tertiary-800
--sf-color-tertiary-900
--sf-color-tertiary-950
--sf-color-tertiary-a10
--sf-color-tertiary-a30
--sf-color-tertiary-a5
--sf-color-tertiary-a50
--sf-color-tertiary-a80
--sf-color-tertiary-darker
--sf-color-tertiary-ghost
--sf-color-tertiary-lighter
--sf-color-tertiary-muted
--sf-color-tertiary-source-dark
--sf-color-tertiary-source-light
--sf-color-tertiary-subtle
--sf-color-tertiary-superdark
--sf-color-tertiary-superlight
--sf-color-tertiary-xdark
--sf-color-tertiary-xlight
--sf-color-text
--sf-color-text--disabled
--sf-color-text--inverse
--sf-color-text--muted
--sf-color-text--on-action
--sf-color-text--on-base
--sf-color-text--on-danger
--sf-color-text--on-info
--sf-color-text--on-inverse
--sf-color-text--on-neutral
--sf-color-text--on-primary
--sf-color-text--on-secondary
--sf-color-text--on-success
--sf-color-text--on-tertiary
--sf-color-text--on-warning
--sf-color-text--placeholder
--sf-color-text--secondary
--sf-color-warning
--sf-color-warning-muted
--sf-color-warning-source-dark
--sf-color-warning-source-light
--sf-color-warning-strong
--sf-color-warning-subtle
--sf-color-white
+

gradient 9

+
--sf-gradient-brand
--sf-gradient-fade--b
--sf-gradient-fade--l
--sf-gradient-fade--r
--sf-gradient-fade--t
--sf-gradient-primary
--sf-gradient-secondary
--sf-gradient-surface
--sf-gradient-tertiary
+

shadow 13

+
--sf-shadow-2xl
--sf-shadow-color adv
--sf-shadow-glow
--sf-shadow-glow-color adv
--sf-shadow-inner
--sf-shadow-l
--sf-shadow-lightness
--sf-shadow-m
--sf-shadow-none
--sf-shadow-s
--sf-shadow-strength adv
--sf-shadow-xl
--sf-shadow-xs
+

drop 3

+
--sf-drop-shadow-l
--sf-drop-shadow-m
--sf-drop-shadow-s
+

radius 14

+
--sf-radius-2xl
--sf-radius-2xs
--sf-radius-3xl
--sf-radius-4xl
--sf-radius-full
--sf-radius-l
--sf-radius-m
--sf-radius-none
--sf-radius-outer adv
--sf-radius-pill
--sf-radius-s
--sf-radius-scale adv
--sf-radius-xl
--sf-radius-xs
+

space 16

+
--sf-space-2xl
--sf-space-2xs
--sf-space-3xl
--sf-space-4xl
--sf-space-base-max adv
--sf-space-base-min adv
--sf-space-l
--sf-space-m
--sf-space-none
--sf-space-px
--sf-space-ratio-max adv
--sf-space-ratio-min adv
--sf-space-s
--sf-space-scale adv
--sf-space-xl
--sf-space-xs
+

size 5

+
--sf-size-l
--sf-size-m
--sf-size-s
--sf-size-xl
--sf-size-xs
+

text 60

+
--sf-text-2xl
Aa
--sf-text-2xl-font-weight
Aa
--sf-text-2xl-letter-spacing
Aa
--sf-text-2xl-line-height
Aa
--sf-text-2xl-max-width
--sf-text-2xs
Aa
--sf-text-2xs-font-weight
Aa
--sf-text-2xs-letter-spacing
Aa
--sf-text-2xs-line-height
Aa
--sf-text-2xs-max-width
--sf-text-3xl
Aa
--sf-text-3xl-font-weight
Aa
--sf-text-3xl-letter-spacing
Aa
--sf-text-3xl-line-height
Aa
--sf-text-3xl-max-width
--sf-text-4xl
Aa
--sf-text-4xl-font-weight
Aa
--sf-text-4xl-letter-spacing
Aa
--sf-text-4xl-line-height
Aa
--sf-text-4xl-max-width
--sf-text-base-max adv
--sf-text-base-min adv
--sf-text-display-base-max adv
--sf-text-display-base-min adv
--sf-text-display-l
Aa
--sf-text-display-m
Aa
--sf-text-display-s
Aa
--sf-text-display-scale adv
--sf-text-l
Aa
--sf-text-l-font-weight
Aa
--sf-text-l-letter-spacing
Aa
--sf-text-l-line-height
Aa
--sf-text-l-max-width
--sf-text-m
Aa
--sf-text-m-font-weight
Aa
--sf-text-m-letter-spacing
Aa
--sf-text-m-line-height
Aa
--sf-text-m-max-width
--sf-text-ratio-max adv
--sf-text-ratio-min adv
--sf-text-s
Aa
--sf-text-s-font-weight
Aa
--sf-text-s-letter-spacing
Aa
--sf-text-s-line-height
Aa
--sf-text-s-max-width
--sf-text-scale adv
--sf-text-shadow-l
Aa
--sf-text-shadow-m
Aa
--sf-text-shadow-none
Aa
--sf-text-shadow-s
Aa
--sf-text-xl
Aa
--sf-text-xl-font-weight
Aa
--sf-text-xl-letter-spacing
Aa
--sf-text-xl-line-height
Aa
--sf-text-xl-max-width
--sf-text-xs
Aa
--sf-text-xs-font-weight
Aa
--sf-text-xs-letter-spacing
Aa
--sf-text-xs-line-height
Aa
--sf-text-xs-max-width
+

font 20

+
--sf-font-body
Ag f
--sf-font-display
--sf-font-features adv
--sf-font-geometric
Ag f
--sf-font-heading
--sf-font-humanist
Ag f
--sf-font-mono
Ag f
--sf-font-numeric
--sf-font-slab
Ag f
--sf-font-variation adv
--sf-font-weight-body
Ag
--sf-font-weight-bold
Ag
--sf-font-weight-display
Ag
--sf-font-weight-heading
Ag
--sf-font-weight-interactive
Ag
--sf-font-weight-light
Ag
--sf-font-weight-medium
Ag
--sf-font-weight-normal
Ag
--sf-font-weight-semibold
Ag
--sf-font-weight-strong
Ag
+

leading 5

+
--sf-leading-normal

Aa Bb
Cc Dd

--sf-leading-relaxed

Aa Bb
Cc Dd

--sf-leading-snug

Aa Bb
Cc Dd

--sf-leading-taper adv

Aa Bb
Cc Dd

--sf-leading-tight

Aa Bb
Cc Dd

+

tracking 5

+
--sf-tracking-normal
AVTAW
--sf-tracking-tight
AVTAW
--sf-tracking-wide
AVTAW
--sf-tracking-wider
AVTAW
--sf-tracking-widest
AVTAW
+

duration 6

+
--sf-duration-fast
--sf-duration-instant
--sf-duration-none
--sf-duration-normal
--sf-duration-slow
--sf-duration-slower
+

ease 8

+
--sf-ease-bounce
--sf-ease-elastic
--sf-ease-in
--sf-ease-in-out
--sf-ease-linear
--sf-ease-out
--sf-ease-overshoot
--sf-ease-spring
+

transition 10

+
--sf-transition-colors
--sf-transition-enter
--sf-transition-exit
--sf-transition-fast
--sf-transition-form-field
--sf-transition-opacity
--sf-transition-overlay
--sf-transition-shadow
--sf-transition-slow
--sf-transition-transform
+

animation 19

+
--sf-animation-blink
--sf-animation-color-pulse
--sf-animation-delay-1
--sf-animation-delay-2
--sf-animation-delay-3
--sf-animation-delay-4
--sf-animation-delay-5
--sf-animation-fade-in
--sf-animation-fade-out
--sf-animation-float
--sf-animation-ping
--sf-animation-scale-down
--sf-animation-scale-up
--sf-animation-shimmer
--sf-animation-slide-in-down
--sf-animation-slide-in-left
--sf-animation-slide-in-right
--sf-animation-slide-in-up
--sf-animation-spin
+

border 10

+
--sf-border
--sf-border-scale
--sf-border-strong
--sf-border-style
--sf-border-subtle
--sf-border-width-1
--sf-border-width-2
--sf-border-width-3
--sf-border-width-4
--sf-border-width-hairline
+

focus 5

+
--sf-focus-ring-color
--sf-focus-ring-offset
--sf-focus-ring-shadow adv
--sf-focus-ring-style
--sf-focus-ring-width
+

opacity 2

+
--sf-opacity-disabled
--sf-opacity-muted
+

blur 1

+
--sf-blur
+

z 10

+
--sf-z-base
--sf-z-below
--sf-z-dropdown
--sf-z-fixed
--sf-z-modal
--sf-z-overlay
--sf-z-raised
--sf-z-sticky
--sf-z-toast
--sf-z-tooltip
+

alternate 2

+
--sf-alternate-gap
--sf-alternate-inner-gap
+

aspect 1

+
--sf-aspect
+

bento 5

+
--sf-bento-cols-default
--sf-bento-gap
--sf-bento-row-compact
--sf-bento-row-default
--sf-bento-row-tall
+

bg 5

+
--sf-bg-fit
--sf-bg-inset
--sf-bg-position
--sf-bg-radius
--sf-bg-z
+

body 8

+
--sf-body-color
--sf-body-em-style
--sf-body-font-family
--sf-body-font-size
--sf-body-font-weight
--sf-body-line-height
--sf-body-strong-weight
--sf-body-text-wrap
+

box 3

+
--sf-box-border-color
--sf-box-border-width
--sf-box-padding
+

breakout 1

+
--sf-breakout-width
+

btn 3

+
--sf-btn-padding-block
--sf-btn-padding-inline
--sf-btn-radius
+

caret 1

+
--sf-caret-color
+

center 2

+
--sf-center-gutter
--sf-center-max
+

cluster 3

+
--sf-cluster-align
--sf-cluster-gap
--sf-cluster-justify
+

code 1

+
--sf-code-font-size
+

component 1

+
--sf-component-pad
+

container 5

+
--sf-container-default
--sf-container-full
--sf-container-narrow
--sf-container-prose
--sf-container-wide
+

content 3

+
--sf-content-gap
--sf-content-intrinsic-size
--sf-content-width
+

contrast 2

+
--sf-contrast-bias adv
--sf-contrast-threshold adv
+

cover 2

+
--sf-cover-min-height
--sf-cover-padding
+

current 1

+
--sf-current-font-weight
+

display 3

+
--sf-display-l-line-height
--sf-display-m-line-height
--sf-display-s-line-height
+

divider 4

+
--sf-divider-color
--sf-divider-gap
--sf-divider-style
--sf-divider-width
+

equal 6

+
--sf-equal-gap
--sf-equal-min-col
--sf-equal-min-col-2
--sf-equal-min-col-3
--sf-equal-min-col-4
--sf-equal-min-col-6
+

field 5

+
--sf-field-block
--sf-field-padding-block
--sf-field-padding-inline
--sf-field-radius
--sf-field-required-marker
+

flow 1

+
--sf-flow-space
+

fluid 2

+
--sf-fluid-max-vw adv
--sf-fluid-min-vw adv
+

frame 1

+
--sf-frame-ratio
+

gap 1

+
--sf-gap
+

grid 8

+
--sf-grid-gap
--sf-grid-min
--sf-grid-min-2xl
--sf-grid-min-l
--sf-grid-min-m
--sf-grid-min-s
--sf-grid-min-xl
--sf-grid-min-xs
+

gutter 1

+
--sf-gutter
+

h1 5

+
--sf-h1-font-weight
--sf-h1-letter-spacing
--sf-h1-line-height
--sf-h1-max-width
--sf-h1-size
+

h2 5

+
--sf-h2-font-weight
--sf-h2-letter-spacing
--sf-h2-line-height
--sf-h2-max-width
--sf-h2-size
+

h3 5

+
--sf-h3-font-weight
--sf-h3-letter-spacing
--sf-h3-line-height
--sf-h3-max-width
--sf-h3-size
+

h4 5

+
--sf-h4-font-weight
--sf-h4-letter-spacing
--sf-h4-line-height
--sf-h4-max-width
--sf-h4-size
+

h5 5

+
--sf-h5-font-weight
--sf-h5-letter-spacing
--sf-h5-line-height
--sf-h5-max-width
--sf-h5-size
+

h6 5

+
--sf-h6-font-weight
--sf-h6-letter-spacing
--sf-h6-line-height
--sf-h6-max-width
--sf-h6-size
+

header 3

+
--sf-header-height
--sf-header-height-desktop
--sf-header-height-mobile
+

heading 3

+
--sf-heading-color
--sf-heading-font-family
--sf-heading-text-wrap
+

icon 10

+
--sf-icon-2xl
--sf-icon-box-bg
--sf-icon-box-border
--sf-icon-box-pad
--sf-icon-box-radius
--sf-icon-l
--sf-icon-m
--sf-icon-s
--sf-icon-xl
--sf-icon-xs
+

imposter 1

+
--sf-imposter-margin
+

is 5

+
--sf-is-active adv
--sf-is-current adv
--sf-is-dark internal
--sf-is-open adv
--sf-is-pressed adv
+

line 1

+
--sf-line-clamp
+

link 3

+
--sf-link-external-marker
--sf-link-underline-offset
--sf-link-underline-thickness
+

lumlocker 1

+
--sf-lumlocker adv
+

mask 2

+
--sf-mask-scrim-end adv
--sf-mask-scrim-start adv
+

motion 1

+
--sf-motion-scale adv
+

object 2

+
--sf-object-fit
--sf-object-position
+

optical 1

+
--sf-optical-sizing adv
+

palette 10

+
--sf-palette-mix-100 adv
--sf-palette-mix-200 adv
--sf-palette-mix-300 adv
--sf-palette-mix-400 adv
--sf-palette-mix-50 adv
--sf-palette-mix-600 adv
--sf-palette-mix-700 adv
--sf-palette-mix-800 adv
--sf-palette-mix-900 adv
--sf-palette-mix-950 adv
+

print 3

+
--sf-print-base-size adv
--sf-print-page-margin adv
--sf-print-page-size adv
+

prose 14

+
--sf-prose-block-margin
--sf-prose-blockquote-border
--sf-prose-blockquote-padding
--sf-prose-figcaption-size
--sf-prose-figure-margin
--sf-prose-heading-gap
--sf-prose-hr-margin
--sf-prose-list-gap
--sf-prose-marker-color
--sf-prose-media-margin
--sf-prose-media-radius
--sf-prose-nested-list-gap
--sf-prose-paragraph
--sf-prose-table-pad
+

ratio 7

+
--sf-ratio-3-2
--sf-ratio-4-3
--sf-ratio-cinema
--sf-ratio-golden
--sf-ratio-portrait
--sf-ratio-square
--sf-ratio-video
+

reel 3

+
--sf-reel-gap
--sf-reel-height
--sf-reel-item-width
+

safe 4

+
--sf-safe-bottom adv
--sf-safe-left adv
--sf-safe-right adv
--sf-safe-top adv
+

scrim 4

+
--sf-scrim-color
--sf-scrim-direction
--sf-scrim-gradient
--sf-scrim-text-shadow
+

scroll 3

+
--sf-scroll-shadow-size
--sf-scroll-timeline-range-end adv
--sf-scroll-timeline-range-start adv
+

scrollbar 2

+
--sf-scrollbar-thumb
--sf-scrollbar-track
+

section 8

+
--sf-section-pad
--sf-section-pad--2xl
--sf-section-pad--l
--sf-section-pad--m
--sf-section-pad--s
--sf-section-pad--xl
--sf-section-pad--xs
--sf-section-scale adv
+

sidebar 3

+
--sf-sidebar-gap
--sf-sidebar-min-width
--sf-sidebar-width
+

stack 1

+
--sf-stack-gap
+

state 1

+
--sf-state-pending-opacity
+

sticky 3

+
--sf-sticky-offset
--sf-sticky-offset-desktop
--sf-sticky-offset-mobile
+

surface 1

+
--sf-surface-color
+

switcher 2

+
--sf-switcher-gap
--sf-switcher-threshold
+

theme 1

+
--sf-theme-transition-duration
+

touch 1

+
--sf-touch-target
+
+ diff --git a/full-api-demo.html b/full-api-demo.html index bba64430..f8137788 100644 --- a/full-api-demo.html +++ b/full-api-demo.html @@ -50,16 +50,82 @@ place-items: center; font: var(--sf-text-xs) var(--sf-font-mono); color: var(--sf-color-text--muted); } .gallery { display: grid; grid-template-columns: repeat(auto-fill, minmax(4rem, 1fr)); gap: var(--sf-space-l); padding: var(--sf-space-l); background: var(--sf-color-inset); border-radius: var(--sf-radius-m); } + /* toolbar */ + .toolbar { position: sticky; top: 0; z-index: 50; display: flex; flex-wrap: wrap; gap: var(--sf-space-xs); align-items: center; + padding: var(--sf-space-xs) var(--sf-space-l); background: var(--sf-color-overlay); + backdrop-filter: blur(8px); border-block-end: 1px solid var(--sf-color-border); } + .tb-label { font: var(--sf-text-xs) var(--sf-font-mono); color: var(--sf-color-text--muted); } + .toolbar button { font: var(--sf-text-s) var(--sf-font-body); padding: .35em .8em; border: 1px solid var(--sf-color-border); + background: var(--sf-color-surface); color: var(--sf-color-text); border-radius: var(--sf-radius-s); cursor: pointer; } + .toolbar .seg { display: inline-flex; } + .toolbar .seg button { border-radius: 0; border-inline-width: 0; } + .toolbar .seg button:first-child { border-radius: var(--sf-radius-s) 0 0 var(--sf-radius-s); border-inline-start-width: 1px; } + .toolbar .seg button:last-child { border-radius: 0 var(--sf-radius-s) var(--sf-radius-s) 0; border-inline-end-width: 1px; } + .toolbar button.active { background: var(--sf-color-primary); color: var(--sf-color-text--on-primary, #fff); border-color: var(--sf-color-primary); } + h3 button { margin-inline-start: var(--sf-space-s); font: var(--sf-text-xs) var(--sf-font-body); padding: .2em .7em; + border: 1px solid var(--sf-color-border); background: var(--sf-color-surface); color: var(--sf-color-text); + border-radius: var(--sf-radius-s); cursor: pointer; } + /* part 2 token reference */ + .ref-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr)); gap: var(--sf-space-s); } + .ttile { margin: 0; display: grid; gap: var(--sf-space-2xs); padding: var(--sf-space-xs); + border: 1px solid var(--sf-color-border); border-radius: var(--sf-radius-s); background: var(--sf-color-surface); } + .ttile__name { font: var(--sf-text-2xs)/1.35 var(--sf-font-mono); color: var(--sf-color-text--secondary); word-break: break-all; } + .ttile__tier { color: var(--sf-color-warning); } + .ttile__val { font: var(--sf-text-2xs)/1.35 var(--sf-font-mono); color: var(--sf-color-text--muted); + word-break: break-all; max-block-size: 4.5em; overflow: auto; } + .ttile__vis { min-block-size: 2.5rem; display: grid; place-items: center; border-radius: var(--sf-radius-xs); + background: repeating-conic-gradient(var(--sf-color-inset) 0 25%, transparent 0 50%) 0 0 / 1rem 1rem, var(--sf-color-surface); overflow: hidden; } + .tvis { inline-size: 100%; block-size: 2.5rem; } + .tvis--rad { background: var(--sf-color-primary); } + .tvis--card { inline-size: 72%; block-size: 2.2rem; background: var(--sf-color-surface); border-radius: var(--sf-radius-s); } + .tvis--bar { block-size: .9rem; background: linear-gradient(90deg, var(--sf-color-primary), var(--sf-color-action)); + border-radius: var(--sf-radius-full); justify-self: start; align-self: center; } + .tvis--txt { inline-size: auto; block-size: auto; color: var(--sf-color-text); line-height: 1; } + .tvis--lead { inline-size: auto; block-size: auto; margin: 0; font-size: var(--sf-text-2xs); color: var(--sf-color-text); } + .tvis--op { background: var(--sf-color-primary); } + .tvis--anim { inline-size: 2.5rem; background: var(--sf-color-action); border-radius: var(--sf-radius-s); } + /* interactive functions */ + .fx-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr)); gap: var(--sf-space-m); margin-block-end: var(--sf-space-m); } + .fx { margin: 0; display: grid; gap: var(--sf-space-2xs); justify-items: center; text-align: center; } + .fx code { font-size: var(--sf-text-2xs); color: var(--sf-color-text--muted); word-break: break-all; } + .fx-anim { inline-size: 3rem; block-size: 3rem; background: var(--sf-color-action); border-radius: var(--sf-radius-m); } + .fx-track { position: relative; inline-size: 100%; min-inline-size: 10rem; block-size: 1.4rem; + background: var(--sf-color-inset); border-radius: var(--sf-radius-full); overflow: hidden; } + .fx-dot { position: absolute; inset-block: .12rem; inset-inline-start: .12rem; inline-size: 1.15rem; + background: var(--sf-color-primary); border-radius: 50%; transform: translateX(0); } + #fx-ease.go .fx-dot { transform: translateX(8rem); } + .fx-grow { block-size: 1.4rem; inline-size: 0; border-radius: var(--sf-radius-full); + background: linear-gradient(90deg, var(--sf-color-primary), var(--sf-color-action)); } + #fx-dur.go .fx-grow { inline-size: 100%; } + .fx-trans { padding: var(--sf-space-s); inline-size: 100%; border: 1px solid var(--sf-color-border); + border-radius: var(--sf-radius-m); background: var(--sf-color-surface); } + #fx-trans.on .fx-trans { background: var(--sf-color-primary); color: var(--sf-color-text--on-primary, #fff); + transform: translateY(-4px) scale(1.03); box-shadow: var(--sf-shadow-l); border-color: var(--sf-color-primary); opacity: .92; } + .fx-grad { inline-size: 100%; block-size: 3rem; border-radius: var(--sf-radius-m); } + .fx-drop { inline-size: 3rem; block-size: 3rem; background: var(--sf-color-primary); border-radius: var(--sf-radius-m); } + @media (prefers-reduced-motion: reduce) { * { animation: none !important; transition: none !important; } } +

SLASHED Full API Demo

-

v0.6.25 · optimal bundle from jsDelivr CDN · 239 classes · 225 configurable tokens

-
Baseline render with default tokens. The override variant is full-api-demo-with-overrides.html.
+

v0.6.25 · optimal bundle from jsDelivr CDN · 239 classes · 691 tokens (225 configurable)

+
Baseline render with default tokens. Use the toolbar to switch theme, toggle the ultimate override live, or replay motion. The always-on override variant is full-api-demo-with-overrides.html.
-

Token galleries derived values

+

Token galleries highlights

Color ramps

primary
50
100
200
300
400
500
600
700
800
900
950
secondary
50
100
200
300
400
500
600
700
800
900
950
@@ -79,6 +145,28 @@

Shadow

+
+

Interactive functions motion · transitions · gradients

+ +

Animations

+
animation-blink
animation-color-pulse
animation-fade-in
animation-fade-out
animation-float
animation-ping
animation-scale-down
animation-scale-up
animation-shimmer
animation-slide-in-down
animation-slide-in-left
animation-slide-in-right
animation-slide-in-up
animation-spin
+ +

Easing curves

+
ease-bounce
ease-elastic
ease-in
ease-in-out
ease-linear
ease-out
ease-overshoot
ease-spring
+ +

Durations

+
duration-fast
duration-instant
duration-none
duration-normal
duration-slow
duration-slower
+ +

Transitions

+
box
transition-colors
box
transition-enter
box
transition-exit
box
transition-fast
box
transition-form-field
box
transition-opacity
box
transition-overlay
box
transition-shadow
box
transition-slow
box
transition-transform
+ +

Gradients

+
gradient-brand
gradient-fade--b
gradient-fade--l
gradient-fade--r
gradient-fade--t
gradient-primary
gradient-secondary
gradient-surface
gradient-tertiary
+ +

Drop shadows (filter)

+
drop-shadow-l
drop-shadow-m
drop-shadow-s
+
+

Layout primitives 128

@@ -1070,6 +1158,224 @@

Theme 2

+ +
+

Part 2 — Complete token reference 691 tokens · live values

+
Every --sf-* token — knob and consumption, all tiers — with its live computed value (filled by JS). Toggle the theme or the override in the toolbar and watch every value recompute. Tokens that resolve to a colour, length, shadow, gradient, type or motion value also show a visual.
+

color 255

+
--sf-color-action
--sf-color-action--active
--sf-color-action--hover
--sf-color-action-100
--sf-color-action-200
--sf-color-action-300
--sf-color-action-400
--sf-color-action-50
--sf-color-action-500
--sf-color-action-600
--sf-color-action-700
--sf-color-action-800
--sf-color-action-900
--sf-color-action-950
--sf-color-action-a10
--sf-color-action-a30
--sf-color-action-a5
--sf-color-action-a50
--sf-color-action-a80
--sf-color-action-darker
--sf-color-action-ghost
--sf-color-action-lighter
--sf-color-action-muted
--sf-color-action-source-dark
--sf-color-action-source-light
--sf-color-action-subtle
--sf-color-action-superdark
--sf-color-action-superlight
--sf-color-action-xdark
--sf-color-action-xlight
--sf-color-base
--sf-color-base--active
--sf-color-base--hover
--sf-color-base-100
--sf-color-base-200
--sf-color-base-300
--sf-color-base-400
--sf-color-base-50
--sf-color-base-500
--sf-color-base-600
--sf-color-base-700
--sf-color-base-800
--sf-color-base-900
--sf-color-base-950
--sf-color-base-a10
--sf-color-base-a30
--sf-color-base-a5
--sf-color-base-a50
--sf-color-base-a80
--sf-color-base-darker
--sf-color-base-ghost
--sf-color-base-lighter
--sf-color-base-muted
--sf-color-base-source-dark
--sf-color-base-source-light
--sf-color-base-subtle
--sf-color-base-superdark
--sf-color-base-superlight
--sf-color-base-xdark
--sf-color-base-xlight
--sf-color-bg
--sf-color-bg--active
--sf-color-bg--disabled
--sf-color-bg--focus
--sf-color-bg--hover
--sf-color-bg--selected
--sf-color-black
--sf-color-border
--sf-color-border--disabled
--sf-color-border--focus
--sf-color-border--strong
--sf-color-border--subtle
--sf-color-border--translucent
--sf-color-code-bg
--sf-color-code-text
--sf-color-danger
--sf-color-danger-muted
--sf-color-danger-source-dark
--sf-color-danger-source-light
--sf-color-danger-strong
--sf-color-danger-subtle
--sf-color-dim
--sf-color-heading
--sf-color-info
--sf-color-info-muted
--sf-color-info-source-dark
--sf-color-info-source-light
--sf-color-info-strong
--sf-color-info-subtle
--sf-color-inset
--sf-color-inverse
--sf-color-link
--sf-color-link--active
--sf-color-link--disabled
--sf-color-link--hover
--sf-color-link--underline
--sf-color-link--visited
--sf-color-mark-bg
--sf-color-mark-text
--sf-color-neutral
--sf-color-neutral--active
--sf-color-neutral--hover
--sf-color-neutral-100
--sf-color-neutral-200
--sf-color-neutral-300
--sf-color-neutral-400
--sf-color-neutral-50
--sf-color-neutral-500
--sf-color-neutral-600
--sf-color-neutral-700
--sf-color-neutral-800
--sf-color-neutral-900
--sf-color-neutral-950
--sf-color-neutral-a10
--sf-color-neutral-a30
--sf-color-neutral-a5
--sf-color-neutral-a50
--sf-color-neutral-a80
--sf-color-neutral-darker
--sf-color-neutral-ghost
--sf-color-neutral-lighter
--sf-color-neutral-muted
--sf-color-neutral-source-dark
--sf-color-neutral-source-light
--sf-color-neutral-subtle
--sf-color-neutral-superdark
--sf-color-neutral-superlight
--sf-color-neutral-xdark
--sf-color-neutral-xlight
--sf-color-overlay
--sf-color-primary
--sf-color-primary--active
--sf-color-primary--hover
--sf-color-primary-100
--sf-color-primary-200
--sf-color-primary-300
--sf-color-primary-400
--sf-color-primary-50
--sf-color-primary-500
--sf-color-primary-600
--sf-color-primary-700
--sf-color-primary-800
--sf-color-primary-900
--sf-color-primary-950
--sf-color-primary-a10
--sf-color-primary-a30
--sf-color-primary-a5
--sf-color-primary-a50
--sf-color-primary-a80
--sf-color-primary-darker
--sf-color-primary-ghost
--sf-color-primary-lighter
--sf-color-primary-muted
--sf-color-primary-source-dark
--sf-color-primary-source-light
--sf-color-primary-subtle
--sf-color-primary-superdark
--sf-color-primary-superlight
--sf-color-primary-xdark
--sf-color-primary-xlight
--sf-color-raised
--sf-color-scheme
--sf-color-secondary
--sf-color-secondary--active
--sf-color-secondary--hover
--sf-color-secondary-100
--sf-color-secondary-200
--sf-color-secondary-300
--sf-color-secondary-400
--sf-color-secondary-50
--sf-color-secondary-500
--sf-color-secondary-600
--sf-color-secondary-700
--sf-color-secondary-800
--sf-color-secondary-900
--sf-color-secondary-950
--sf-color-secondary-a10
--sf-color-secondary-a30
--sf-color-secondary-a5
--sf-color-secondary-a50
--sf-color-secondary-a80
--sf-color-secondary-darker
--sf-color-secondary-ghost
--sf-color-secondary-lighter
--sf-color-secondary-muted
--sf-color-secondary-source-dark
--sf-color-secondary-source-light
--sf-color-secondary-subtle
--sf-color-secondary-superdark
--sf-color-secondary-superlight
--sf-color-secondary-xdark
--sf-color-secondary-xlight
--sf-color-selection-bg
--sf-color-selection-text
--sf-color-success
--sf-color-success-muted
--sf-color-success-source-dark
--sf-color-success-source-light
--sf-color-success-strong
--sf-color-success-subtle
--sf-color-surface
--sf-color-tertiary
--sf-color-tertiary--active
--sf-color-tertiary--hover
--sf-color-tertiary-100
--sf-color-tertiary-200
--sf-color-tertiary-300
--sf-color-tertiary-400
--sf-color-tertiary-50
--sf-color-tertiary-500
--sf-color-tertiary-600
--sf-color-tertiary-700
--sf-color-tertiary-800
--sf-color-tertiary-900
--sf-color-tertiary-950
--sf-color-tertiary-a10
--sf-color-tertiary-a30
--sf-color-tertiary-a5
--sf-color-tertiary-a50
--sf-color-tertiary-a80
--sf-color-tertiary-darker
--sf-color-tertiary-ghost
--sf-color-tertiary-lighter
--sf-color-tertiary-muted
--sf-color-tertiary-source-dark
--sf-color-tertiary-source-light
--sf-color-tertiary-subtle
--sf-color-tertiary-superdark
--sf-color-tertiary-superlight
--sf-color-tertiary-xdark
--sf-color-tertiary-xlight
--sf-color-text
--sf-color-text--disabled
--sf-color-text--inverse
--sf-color-text--muted
--sf-color-text--on-action
--sf-color-text--on-base
--sf-color-text--on-danger
--sf-color-text--on-info
--sf-color-text--on-inverse
--sf-color-text--on-neutral
--sf-color-text--on-primary
--sf-color-text--on-secondary
--sf-color-text--on-success
--sf-color-text--on-tertiary
--sf-color-text--on-warning
--sf-color-text--placeholder
--sf-color-text--secondary
--sf-color-warning
--sf-color-warning-muted
--sf-color-warning-source-dark
--sf-color-warning-source-light
--sf-color-warning-strong
--sf-color-warning-subtle
--sf-color-white
+

gradient 9

+
--sf-gradient-brand
--sf-gradient-fade--b
--sf-gradient-fade--l
--sf-gradient-fade--r
--sf-gradient-fade--t
--sf-gradient-primary
--sf-gradient-secondary
--sf-gradient-surface
--sf-gradient-tertiary
+

shadow 13

+
--sf-shadow-2xl
--sf-shadow-color adv
--sf-shadow-glow
--sf-shadow-glow-color adv
--sf-shadow-inner
--sf-shadow-l
--sf-shadow-lightness
--sf-shadow-m
--sf-shadow-none
--sf-shadow-s
--sf-shadow-strength adv
--sf-shadow-xl
--sf-shadow-xs
+

drop 3

+
--sf-drop-shadow-l
--sf-drop-shadow-m
--sf-drop-shadow-s
+

radius 14

+
--sf-radius-2xl
--sf-radius-2xs
--sf-radius-3xl
--sf-radius-4xl
--sf-radius-full
--sf-radius-l
--sf-radius-m
--sf-radius-none
--sf-radius-outer adv
--sf-radius-pill
--sf-radius-s
--sf-radius-scale adv
--sf-radius-xl
--sf-radius-xs
+

space 16

+
--sf-space-2xl
--sf-space-2xs
--sf-space-3xl
--sf-space-4xl
--sf-space-base-max adv
--sf-space-base-min adv
--sf-space-l
--sf-space-m
--sf-space-none
--sf-space-px
--sf-space-ratio-max adv
--sf-space-ratio-min adv
--sf-space-s
--sf-space-scale adv
--sf-space-xl
--sf-space-xs
+

size 5

+
--sf-size-l
--sf-size-m
--sf-size-s
--sf-size-xl
--sf-size-xs
+

text 60

+
--sf-text-2xl
Aa
--sf-text-2xl-font-weight
Aa
--sf-text-2xl-letter-spacing
Aa
--sf-text-2xl-line-height
Aa
--sf-text-2xl-max-width
--sf-text-2xs
Aa
--sf-text-2xs-font-weight
Aa
--sf-text-2xs-letter-spacing
Aa
--sf-text-2xs-line-height
Aa
--sf-text-2xs-max-width
--sf-text-3xl
Aa
--sf-text-3xl-font-weight
Aa
--sf-text-3xl-letter-spacing
Aa
--sf-text-3xl-line-height
Aa
--sf-text-3xl-max-width
--sf-text-4xl
Aa
--sf-text-4xl-font-weight
Aa
--sf-text-4xl-letter-spacing
Aa
--sf-text-4xl-line-height
Aa
--sf-text-4xl-max-width
--sf-text-base-max adv
--sf-text-base-min adv
--sf-text-display-base-max adv
--sf-text-display-base-min adv
--sf-text-display-l
Aa
--sf-text-display-m
Aa
--sf-text-display-s
Aa
--sf-text-display-scale adv
--sf-text-l
Aa
--sf-text-l-font-weight
Aa
--sf-text-l-letter-spacing
Aa
--sf-text-l-line-height
Aa
--sf-text-l-max-width
--sf-text-m
Aa
--sf-text-m-font-weight
Aa
--sf-text-m-letter-spacing
Aa
--sf-text-m-line-height
Aa
--sf-text-m-max-width
--sf-text-ratio-max adv
--sf-text-ratio-min adv
--sf-text-s
Aa
--sf-text-s-font-weight
Aa
--sf-text-s-letter-spacing
Aa
--sf-text-s-line-height
Aa
--sf-text-s-max-width
--sf-text-scale adv
--sf-text-shadow-l
Aa
--sf-text-shadow-m
Aa
--sf-text-shadow-none
Aa
--sf-text-shadow-s
Aa
--sf-text-xl
Aa
--sf-text-xl-font-weight
Aa
--sf-text-xl-letter-spacing
Aa
--sf-text-xl-line-height
Aa
--sf-text-xl-max-width
--sf-text-xs
Aa
--sf-text-xs-font-weight
Aa
--sf-text-xs-letter-spacing
Aa
--sf-text-xs-line-height
Aa
--sf-text-xs-max-width
+

font 20

+
--sf-font-body
Ag f
--sf-font-display
--sf-font-features adv
--sf-font-geometric
Ag f
--sf-font-heading
--sf-font-humanist
Ag f
--sf-font-mono
Ag f
--sf-font-numeric
--sf-font-slab
Ag f
--sf-font-variation adv
--sf-font-weight-body
Ag
--sf-font-weight-bold
Ag
--sf-font-weight-display
Ag
--sf-font-weight-heading
Ag
--sf-font-weight-interactive
Ag
--sf-font-weight-light
Ag
--sf-font-weight-medium
Ag
--sf-font-weight-normal
Ag
--sf-font-weight-semibold
Ag
--sf-font-weight-strong
Ag
+

leading 5

+
--sf-leading-normal

Aa Bb
Cc Dd

--sf-leading-relaxed

Aa Bb
Cc Dd

--sf-leading-snug

Aa Bb
Cc Dd

--sf-leading-taper adv

Aa Bb
Cc Dd

--sf-leading-tight

Aa Bb
Cc Dd

+

tracking 5

+
--sf-tracking-normal
AVTAW
--sf-tracking-tight
AVTAW
--sf-tracking-wide
AVTAW
--sf-tracking-wider
AVTAW
--sf-tracking-widest
AVTAW
+

duration 6

+
--sf-duration-fast
--sf-duration-instant
--sf-duration-none
--sf-duration-normal
--sf-duration-slow
--sf-duration-slower
+

ease 8

+
--sf-ease-bounce
--sf-ease-elastic
--sf-ease-in
--sf-ease-in-out
--sf-ease-linear
--sf-ease-out
--sf-ease-overshoot
--sf-ease-spring
+

transition 10

+
--sf-transition-colors
--sf-transition-enter
--sf-transition-exit
--sf-transition-fast
--sf-transition-form-field
--sf-transition-opacity
--sf-transition-overlay
--sf-transition-shadow
--sf-transition-slow
--sf-transition-transform
+

animation 19

+
--sf-animation-blink
--sf-animation-color-pulse
--sf-animation-delay-1
--sf-animation-delay-2
--sf-animation-delay-3
--sf-animation-delay-4
--sf-animation-delay-5
--sf-animation-fade-in
--sf-animation-fade-out
--sf-animation-float
--sf-animation-ping
--sf-animation-scale-down
--sf-animation-scale-up
--sf-animation-shimmer
--sf-animation-slide-in-down
--sf-animation-slide-in-left
--sf-animation-slide-in-right
--sf-animation-slide-in-up
--sf-animation-spin
+

border 10

+
--sf-border
--sf-border-scale
--sf-border-strong
--sf-border-style
--sf-border-subtle
--sf-border-width-1
--sf-border-width-2
--sf-border-width-3
--sf-border-width-4
--sf-border-width-hairline
+

focus 5

+
--sf-focus-ring-color
--sf-focus-ring-offset
--sf-focus-ring-shadow adv
--sf-focus-ring-style
--sf-focus-ring-width
+

opacity 2

+
--sf-opacity-disabled
--sf-opacity-muted
+

blur 1

+
--sf-blur
+

z 10

+
--sf-z-base
--sf-z-below
--sf-z-dropdown
--sf-z-fixed
--sf-z-modal
--sf-z-overlay
--sf-z-raised
--sf-z-sticky
--sf-z-toast
--sf-z-tooltip
+

alternate 2

+
--sf-alternate-gap
--sf-alternate-inner-gap
+

aspect 1

+
--sf-aspect
+

bento 5

+
--sf-bento-cols-default
--sf-bento-gap
--sf-bento-row-compact
--sf-bento-row-default
--sf-bento-row-tall
+

bg 5

+
--sf-bg-fit
--sf-bg-inset
--sf-bg-position
--sf-bg-radius
--sf-bg-z
+

body 8

+
--sf-body-color
--sf-body-em-style
--sf-body-font-family
--sf-body-font-size
--sf-body-font-weight
--sf-body-line-height
--sf-body-strong-weight
--sf-body-text-wrap
+

box 3

+
--sf-box-border-color
--sf-box-border-width
--sf-box-padding
+

breakout 1

+
--sf-breakout-width
+

btn 3

+
--sf-btn-padding-block
--sf-btn-padding-inline
--sf-btn-radius
+

caret 1

+
--sf-caret-color
+

center 2

+
--sf-center-gutter
--sf-center-max
+

cluster 3

+
--sf-cluster-align
--sf-cluster-gap
--sf-cluster-justify
+

code 1

+
--sf-code-font-size
+

component 1

+
--sf-component-pad
+

container 5

+
--sf-container-default
--sf-container-full
--sf-container-narrow
--sf-container-prose
--sf-container-wide
+

content 3

+
--sf-content-gap
--sf-content-intrinsic-size
--sf-content-width
+

contrast 2

+
--sf-contrast-bias adv
--sf-contrast-threshold adv
+

cover 2

+
--sf-cover-min-height
--sf-cover-padding
+

current 1

+
--sf-current-font-weight
+

display 3

+
--sf-display-l-line-height
--sf-display-m-line-height
--sf-display-s-line-height
+

divider 4

+
--sf-divider-color
--sf-divider-gap
--sf-divider-style
--sf-divider-width
+

equal 6

+
--sf-equal-gap
--sf-equal-min-col
--sf-equal-min-col-2
--sf-equal-min-col-3
--sf-equal-min-col-4
--sf-equal-min-col-6
+

field 5

+
--sf-field-block
--sf-field-padding-block
--sf-field-padding-inline
--sf-field-radius
--sf-field-required-marker
+

flow 1

+
--sf-flow-space
+

fluid 2

+
--sf-fluid-max-vw adv
--sf-fluid-min-vw adv
+

frame 1

+
--sf-frame-ratio
+

gap 1

+
--sf-gap
+

grid 8

+
--sf-grid-gap
--sf-grid-min
--sf-grid-min-2xl
--sf-grid-min-l
--sf-grid-min-m
--sf-grid-min-s
--sf-grid-min-xl
--sf-grid-min-xs
+

gutter 1

+
--sf-gutter
+

h1 5

+
--sf-h1-font-weight
--sf-h1-letter-spacing
--sf-h1-line-height
--sf-h1-max-width
--sf-h1-size
+

h2 5

+
--sf-h2-font-weight
--sf-h2-letter-spacing
--sf-h2-line-height
--sf-h2-max-width
--sf-h2-size
+

h3 5

+
--sf-h3-font-weight
--sf-h3-letter-spacing
--sf-h3-line-height
--sf-h3-max-width
--sf-h3-size
+

h4 5

+
--sf-h4-font-weight
--sf-h4-letter-spacing
--sf-h4-line-height
--sf-h4-max-width
--sf-h4-size
+

h5 5

+
--sf-h5-font-weight
--sf-h5-letter-spacing
--sf-h5-line-height
--sf-h5-max-width
--sf-h5-size
+

h6 5

+
--sf-h6-font-weight
--sf-h6-letter-spacing
--sf-h6-line-height
--sf-h6-max-width
--sf-h6-size
+

header 3

+
--sf-header-height
--sf-header-height-desktop
--sf-header-height-mobile
+

heading 3

+
--sf-heading-color
--sf-heading-font-family
--sf-heading-text-wrap
+

icon 10

+
--sf-icon-2xl
--sf-icon-box-bg
--sf-icon-box-border
--sf-icon-box-pad
--sf-icon-box-radius
--sf-icon-l
--sf-icon-m
--sf-icon-s
--sf-icon-xl
--sf-icon-xs
+

imposter 1

+
--sf-imposter-margin
+

is 5

+
--sf-is-active adv
--sf-is-current adv
--sf-is-dark internal
--sf-is-open adv
--sf-is-pressed adv
+

line 1

+
--sf-line-clamp
+

link 3

+
--sf-link-external-marker
--sf-link-underline-offset
--sf-link-underline-thickness
+

lumlocker 1

+
--sf-lumlocker adv
+

mask 2

+
--sf-mask-scrim-end adv
--sf-mask-scrim-start adv
+

motion 1

+
--sf-motion-scale adv
+

object 2

+
--sf-object-fit
--sf-object-position
+

optical 1

+
--sf-optical-sizing adv
+

palette 10

+
--sf-palette-mix-100 adv
--sf-palette-mix-200 adv
--sf-palette-mix-300 adv
--sf-palette-mix-400 adv
--sf-palette-mix-50 adv
--sf-palette-mix-600 adv
--sf-palette-mix-700 adv
--sf-palette-mix-800 adv
--sf-palette-mix-900 adv
--sf-palette-mix-950 adv
+

print 3

+
--sf-print-base-size adv
--sf-print-page-margin adv
--sf-print-page-size adv
+

prose 14

+
--sf-prose-block-margin
--sf-prose-blockquote-border
--sf-prose-blockquote-padding
--sf-prose-figcaption-size
--sf-prose-figure-margin
--sf-prose-heading-gap
--sf-prose-hr-margin
--sf-prose-list-gap
--sf-prose-marker-color
--sf-prose-media-margin
--sf-prose-media-radius
--sf-prose-nested-list-gap
--sf-prose-paragraph
--sf-prose-table-pad
+

ratio 7

+
--sf-ratio-3-2
--sf-ratio-4-3
--sf-ratio-cinema
--sf-ratio-golden
--sf-ratio-portrait
--sf-ratio-square
--sf-ratio-video
+

reel 3

+
--sf-reel-gap
--sf-reel-height
--sf-reel-item-width
+

safe 4

+
--sf-safe-bottom adv
--sf-safe-left adv
--sf-safe-right adv
--sf-safe-top adv
+

scrim 4

+
--sf-scrim-color
--sf-scrim-direction
--sf-scrim-gradient
--sf-scrim-text-shadow
+

scroll 3

+
--sf-scroll-shadow-size
--sf-scroll-timeline-range-end adv
--sf-scroll-timeline-range-start adv
+

scrollbar 2

+
--sf-scrollbar-thumb
--sf-scrollbar-track
+

section 8

+
--sf-section-pad
--sf-section-pad--2xl
--sf-section-pad--l
--sf-section-pad--m
--sf-section-pad--s
--sf-section-pad--xl
--sf-section-pad--xs
--sf-section-scale adv
+

sidebar 3

+
--sf-sidebar-gap
--sf-sidebar-min-width
--sf-sidebar-width
+

stack 1

+
--sf-stack-gap
+

state 1

+
--sf-state-pending-opacity
+

sticky 3

+
--sf-sticky-offset
--sf-sticky-offset-desktop
--sf-sticky-offset-mobile
+

surface 1

+
--sf-surface-color
+

switcher 2

+
--sf-switcher-gap
--sf-switcher-threshold
+

theme 1

+
--sf-theme-transition-duration
+

touch 1

+
--sf-touch-target
+
+ From 4b8e5662f679437b584ab10cea4340612f6f67d5 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 29 Jun 2026 16:50:36 +0000 Subject: [PATCH 5/5] feat: move demos under demos/ and link them from the Pages index - Relocate the generated artifacts (full-api-demo.html, full-api-demo-with-overrides.html, ultimate-override.css) from the repo root into demos/, alongside their generator and validator. generate.mjs and validate.mjs now write/read there. The override link and runtime injection stay relative, so they resolve within demos/. - index.md: link both demos from the hero actions and the Developer column, so the GitHub Pages site exposes them at /demos/full-api-demo.html and /demos/full-api-demo-with-overrides.html. - _config.yml: exclude the dev scripts (generate.mjs, validate.mjs) and the validator scratch dir from the published site; the HTML/CSS demos ship as static files (no front matter), served verbatim like docs/demo.html. The pages load the optimal bundle from the jsDelivr @dist CDN (verified present on the dist branch), so they render with styles publicly once on the Pages branch. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01QCMzUyUS62KUSkr4AzrF7M --- _config.yml | 3 +++ .../full-api-demo-with-overrides.html | 0 full-api-demo.html => demos/full-api-demo.html | 0 demos/generate.mjs | 13 +++++++------ .../ultimate-override.css | 0 demos/validate.mjs | 9 +++++---- index.md | 3 +++ 7 files changed, 18 insertions(+), 10 deletions(-) rename full-api-demo-with-overrides.html => demos/full-api-demo-with-overrides.html (100%) rename full-api-demo.html => demos/full-api-demo.html (100%) rename ultimate-override.css => demos/ultimate-override.css (100%) diff --git a/_config.yml b/_config.yml index a63bd8dc..0fc30763 100644 --- a/_config.yml +++ b/_config.yml @@ -15,6 +15,9 @@ exclude: - tests - dist - analysis + - demos/generate.mjs + - demos/validate.mjs + - demos/.validate - bundle.config.json - commitlint.config.js - playwright.config.js diff --git a/full-api-demo-with-overrides.html b/demos/full-api-demo-with-overrides.html similarity index 100% rename from full-api-demo-with-overrides.html rename to demos/full-api-demo-with-overrides.html diff --git a/full-api-demo.html b/demos/full-api-demo.html similarity index 100% rename from full-api-demo.html rename to demos/full-api-demo.html diff --git a/demos/generate.mjs b/demos/generate.mjs index f24526af..7903eafd 100644 --- a/demos/generate.mjs +++ b/demos/generate.mjs @@ -9,6 +9,7 @@ import path from 'node:path'; import { fileURLToPath } from 'node:url'; const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); +const OUT = path.join(ROOT, 'demos'); // generated artifacts live alongside this script const api = JSON.parse(fs.readFileSync(path.join(ROOT, 'docs/api-index.json'), 'utf8')); const CDN = 'https://cdn.jsdelivr.net/gh/codeslash-dev/SLASHED@dist/slashed.optimal.css'; const VERSION = JSON.parse(fs.readFileSync(path.join(ROOT, 'package.json'), 'utf8')).version; @@ -684,7 +685,7 @@ ${tokenReferenceSection()} // ───────────────────────────────────────────────────────────────────────── const { css, handledCount } = buildOverride(); -fs.writeFileSync(path.join(ROOT, 'ultimate-override.css'), css); +fs.writeFileSync(path.join(OUT, 'ultimate-override.css'), css); // completeness assertion for classes const emitted = new Set(); @@ -692,8 +693,8 @@ for (const c of classes) emitted.add(c.name); if (emitted.size !== classes.length) throw new Error('class de-dup mismatch'); const baseHtml = buildDemo({ withOverride: false }); -fs.writeFileSync(path.join(ROOT, 'full-api-demo.html'), baseHtml); -fs.writeFileSync(path.join(ROOT, 'full-api-demo-with-overrides.html'), buildDemo({ withOverride: true })); +fs.writeFileSync(path.join(OUT, 'full-api-demo.html'), baseHtml); +fs.writeFileSync(path.join(OUT, 'full-api-demo-with-overrides.html'), buildDemo({ withOverride: true })); // completeness assertion for tokens: every token must appear once in Part 2 const tokenTiles = (baseHtml.match(/data-token="/g) || []).length; @@ -701,6 +702,6 @@ if (tokenTiles !== tokens.length) { throw new Error(`Part 2 token reference: ${tokenTiles} tiles != ${tokens.length} tokens`); } -console.log(`ultimate-override.css → ${handledCount}/${knobs.length} knobs overridden, ${Object.keys(SKIP).length} skipped (documented)`); -console.log(`full-api-demo.html → ${classes.length} classes + ${tokens.length} tokens (Part 2), all rendered`); -console.log(`full-api-demo-with-overrides.html → same body + override link`); +console.log(`demos/ultimate-override.css → ${handledCount}/${knobs.length} knobs overridden, ${Object.keys(SKIP).length} skipped (documented)`); +console.log(`demos/full-api-demo.html → ${classes.length} classes + ${tokens.length} tokens (Part 2), all rendered`); +console.log(`demos/full-api-demo-with-overrides.html → same body + override link`); diff --git a/ultimate-override.css b/demos/ultimate-override.css similarity index 100% rename from ultimate-override.css rename to demos/ultimate-override.css diff --git a/demos/validate.mjs b/demos/validate.mjs index 6ea7a5b2..2497a256 100644 --- a/demos/validate.mjs +++ b/demos/validate.mjs @@ -12,19 +12,20 @@ const CDN = 'https://cdn.jsdelivr.net/gh/codeslash-dev/SLASHED@dist/slashed.opti const LOCAL = path.join(ROOT, 'badges/slashed.optimal.css'); const TMP = path.join(ROOT, 'demos/.validate'); fs.mkdirSync(TMP, { recursive: true }); +const DEMOS = path.join(ROOT, 'demos'); // make the runtime-injected override reachable from the temp copy -fs.copyFileSync(path.join(ROOT, 'ultimate-override.css'), path.join(TMP, 'ultimate-override.css')); +fs.copyFileSync(path.join(DEMOS, 'ultimate-override.css'), path.join(TMP, 'ultimate-override.css')); function localCopy(srcName, outName) { - let html = fs.readFileSync(path.join(ROOT, srcName), 'utf8'); + let html = fs.readFileSync(path.join(DEMOS, srcName), 'utf8'); html = html.replaceAll(CDN, 'file://' + LOCAL); const out = path.join(TMP, outName); fs.writeFileSync(out, html); return 'file://' + out; } const baseUrl = localCopy('full-api-demo.html', 'base.html'); -const expectClasses = (fs.readFileSync(path.join(ROOT, 'full-api-demo.html'), 'utf8').match(/class="tile"/g) || []).length; -const expectTokens = (fs.readFileSync(path.join(ROOT, 'full-api-demo.html'), 'utf8').match(/data-token="/g) || []).length; +const expectClasses = (fs.readFileSync(path.join(DEMOS, 'full-api-demo.html'), 'utf8').match(/class="tile"/g) || []).length; +const expectTokens = (fs.readFileSync(path.join(DEMOS, 'full-api-demo.html'), 'utf8').match(/data-token="/g) || []).length; const browser = await chromium.launch({ executablePath: '/opt/pw-browsers/chromium' }); const page = await browser.newPage({ viewport: { width: 1280, height: 1600 } }); diff --git a/index.md b/index.md index 6d01bb95..37572f26 100644 --- a/index.md +++ b/index.md @@ -127,6 +127,7 @@ title: Home @@ -224,6 +225,8 @@ title: Home
  • API Index machine-readable catalogue
  • Comment Policy contributor conventions
  • Demo full component showcase
  • +
  • Full API Demo every class & token, live · dark mode
  • +
  • Full API Demo — overridden ultimate-override.css applied
  • Test Coverage visual regression suite