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/_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/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/demos/full-api-demo-with-overrides.html b/demos/full-api-demo-with-overrides.html new file mode 100644 index 00000000..1c113fd8 --- /dev/null +++ b/demos/full-api-demo-with-overrides.html @@ -0,0 +1,1382 @@ + + + + + + SLASHED — Full API Demo (overridden) + + + + + + +
+

SLASHED Full API Demo

+

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 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
+
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

+ +
+ +
+

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

+
+
+
.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
+
+
+
+
+

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.
+
+
+
+
+

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
+
+
+
+
+

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
+
+
+
+
+

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
+ +
+
+
+
+

Print 4

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

Theme 2

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

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/demos/full-api-demo.html b/demos/full-api-demo.html new file mode 100644 index 00000000..f8137788 --- /dev/null +++ b/demos/full-api-demo.html @@ -0,0 +1,1381 @@ + + + + + + SLASHED — Full API Demo + + + + + +
+

SLASHED Full API Demo

+

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 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
+
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

+ +
+ +
+

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

+
+
+
.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
+
+
+
+
+

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.
+
+
+
+
+

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
+
+
+
+
+

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
+
+
+
+
+

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
+ +
+
+
+
+

Print 4

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

Theme 2

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

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/demos/generate.mjs b/demos/generate.mjs new file mode 100644 index 00000000..7903eafd --- /dev/null +++ b/demos/generate.mjs @@ -0,0 +1,707 @@ +// 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 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; + +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')} +
+
`; +} + +// ───────────────────────────────────────────────────────────────────────── +// 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 banner = withOverride + ? `
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'], + ['state', 'State classes'], + ['motion', 'Motion / animation'], + ['accessibility', 'Accessibility'], + ['print', 'Print'], + ['theme', 'Theme'], + ]; + return ` + + + + + SLASHED — Full API Demo${withOverride ? ' (overridden)' : ''} + ${overrideLink} + + + +${toolbar()} +
+

SLASHED Full API Demo

+

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

+ ${banner} + +
+

Token galleries highlights

+

Color ramps

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

Semantic / role colors

+
${semanticSwatches()}
+

Spacing scale

+ ${spacingBars()} +

Type scale

+ ${textScale()} +

Radius

+ +

Shadow

+ +
+ +${functionsSection()} + +${kinds.map(([k, t]) => classSection(k, t)).join('\n')} + +${tokenReferenceSection()} +
+ + + +`; +} + +// ───────────────────────────────────────────────────────────────────────── +const { css, handledCount } = buildOverride(); +fs.writeFileSync(path.join(OUT, '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'); + +const baseHtml = buildDemo({ withOverride: false }); +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; +if (tokenTiles !== tokens.length) { + throw new Error(`Part 2 token reference: ${tokenTiles} tiles != ${tokens.length} tokens`); +} + +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/demos/ultimate-override.css b/demos/ultimate-override.css new file mode 100644 index 00000000..649b4897 --- /dev/null +++ b/demos/ultimate-override.css @@ -0,0 +1,361 @@ +/* ============================================================================ + ULTIMATE OVERRIDE — generated by demos/generate.mjs (do not edit by hand) + SLASHED v0.6.25 + + 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: 202 of 225 knob tokens overridden. + 23 knobs are intentionally NOT perturbed (structural / + meta / sentinel) — listed with reasons at the bottom of this file. + ============================================================================ */ + +:root { + + /* 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 */ +} + +/* ---------------------------------------------------------------------------- + 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 + ---------------------------------------------------------------------------- */ diff --git a/demos/validate.mjs b/demos/validate.mjs new file mode 100644 index 00000000..2497a256 --- /dev/null +++ b/demos/validate.mjs @@ -0,0 +1,102 @@ +// 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'; +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 }); +const DEMOS = path.join(ROOT, 'demos'); +// make the runtime-injected override reachable from the temp copy +fs.copyFileSync(path.join(DEMOS, 'ultimate-override.css'), path.join(TMP, 'ultimate-override.css')); + +function localCopy(srcName, outName) { + 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(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 } }); +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 fails = []; +const snap = () => page.evaluate(() => { + const cs = getComputedStyle(document.documentElement); + const body = getComputedStyle(document.body); + 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(), + fxSections: ['functions', 'reference'].filter((id) => document.getElementById(id)).length, + }; +}); + +const click = (sel) => page.evaluate((s) => document.querySelector(s).click(), sel); + +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') }); + +// 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') }); + +// 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(() => {}); +} +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 — ${expectClasses} classes + ${expectTokens} tokens rendered; JS fills live values; dark mode restyles; override toggles live; 0 console errors.`); 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