SLASHED Full API Demo
- v0.7.3 · optimal-components bundle from jsDelivr CDN · 324 classes · 729 tokens (238 configurable)
+ v0.7.5 · optimal-components bundle from jsDelivr CDN · 324 classes · 729 tokens (238 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.
diff --git a/demos/ultimate-override.css b/demos/ultimate-override.css
index fabf3279..bdc26606 100644
--- a/demos/ultimate-override.css
+++ b/demos/ultimate-override.css
@@ -1,6 +1,6 @@
/* ============================================================================
ULTIMATE OVERRIDE — generated by demos/generate.mjs (do not edit by hand)
- SLASHED v0.7.3
+ SLASHED v0.7.5
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.
diff --git a/docs/layout.md b/docs/layout.md
index bc581104..fcfa3a77 100644
--- a/docs/layout.md
+++ b/docs/layout.md
@@ -5,7 +5,7 @@ SLASHED ships breakpoint-free, container-query-driven layout primitives in the
per-instance tokens you can override inline (`style="--sf-stack-gap: …"`).
Tokens are declared in `core/tokens.layout.css`.
-All primitives are demoed in [`demo.html`](demo.html).
+All primitives are demoed in the [layout coverage page](test-coverage-3-layout.html).
## The primitives
diff --git a/docs/motion.md b/docs/motion.md
index 4141c509..b90c3421 100644
--- a/docs/motion.md
+++ b/docs/motion.md
@@ -5,7 +5,7 @@ SLASHED ships animation primitives in the `slashed.motion` layer
`@media (prefers-reduced-motion: no-preference)` -- users who prefer
reduced motion see no animation from the framework.
-All animations are demoed in [`demo.html`](demo.html).
+All animations are demoed in the [macros & states coverage page](test-coverage-4-macros-states.html).
## Design principles
diff --git a/docs/states.md b/docs/states.md
index 4b676169..f23e2cbf 100644
--- a/docs/states.md
+++ b/docs/states.md
@@ -6,7 +6,7 @@ They live in the `slashed.states` layer, are single-class / low-specificity,
and set the **minimum** needed to communicate the state; components layer
visuals on top.
-All states are exercised in [`demo.html`](demo.html).
+All states are exercised in the [macros & states coverage page](test-coverage-4-macros-states.html).
## Reference
diff --git a/index.html b/index.html
index e7d66b41..abd934a1 100644
--- a/index.html
+++ b/index.html
@@ -65,6 +65,11 @@
letter-spacing: var(--sf-tracking-tight);
}
.site-nav .brand b { color: var(--sf-color-primary); }
+ /* The header is a nav bar, not a content section: .sf-section--xs still
+ resolves to the section rhythm scale (--sf-space-xl ≈ 3.25rem a side),
+ which stacks a ~150px-tall band around a 49px nav. Pin it to a compact,
+ symmetric bar instead — the gutter (inline padding) stays. */
+ header:has(.site-nav) { padding-block: var(--sf-space-s); }
/* The link cluster is the part that has room to give: on narrow
viewports it's dropped in favor of the primary CTA + theme toggle,
instead of wrapping into three cramped rows. */
@@ -116,7 +121,7 @@
color: var(--sf-color-heading);
margin: 0;
}
- .al { display: inline-flex; align-items: baseline; cursor: default; }
+ .al { position: relative; display: inline-flex; align-items: baseline; cursor: default; }
.al b {
background-image: var(--sf-gradient-brand);
background-clip: text;
@@ -130,49 +135,52 @@
font-weight: var(--sf-font-weight-light);
margin-inline: 0.1em;
}
- @media (any-hover: hover) {
- /* Per-word widths (ch). Each word expands to exactly --w, and the
- centered row is counter-shifted by --w/2, so the hovered letter
- stays put under the cursor instead of sliding onto a neighbour
- and re-firing the hover. */
- .al:nth-of-type(1) { --w: 8.2ch; }
- .al:nth-of-type(2) { --w: 3.1ch; }
- .al:nth-of-type(3) { --w: 6ch; }
- .al:nth-of-type(4) { --w: 7.8ch; }
- .al:nth-of-type(5) { --w: 4.3ch; }
- .al:nth-of-type(6) { --w: 5ch; }
- .al:nth-of-type(7) { --w: 9.8ch; }
+ /* Gate the collapsed/unfold interaction on a PRIMARY input that can
+ actually hover (a fine pointer), not `any-hover` — which is true on
+ hybrid devices (touchscreen laptops, a phone with a stylus/mouse)
+ even while the user is touching, which would strand the acronym in
+ its collapsed state with no touch way to reveal the words. Touch /
+ coarse-pointer devices keep the default in-flow state above, where
+ every word is already shown. */
+ @media (hover: hover) and (pointer: fine) {
+ /* Collapsed to the tight letter-row; each word unfolds on hover.
+ The unfolded text is taken OUT OF FLOW — absolutely positioned and
+ revealed with clip-path — so unfolding a word changes the size and
+ position of nothing else. No letter ever moves under the cursor, so
+ a hovered word can't slide onto a neighbour and re-fire the hover.
+ (The old approach animated real width and tried to counter-shift the
+ centered row by a hardcoded per-word amount; the amounts couldn't
+ match the real glyph widths, so siblings leapt and re-triggered.) */
.acronym-hero {
- /* Never wrap mid-interaction, and cap the size — relative to the
- hero's own container, with a floor so a hover-capable device
- at a narrow width (a resized browser, a laptop touchscreen)
- never shrinks below a readable size — so the widest unfolded
- word still fits the row on one line. */
- flex-wrap: nowrap;
- row-gap: 0;
- font-size: max(2.75rem, min(var(--sf-text-4xl), 4.4cqi));
+ /* Never wrap mid-interaction; cap the size relative to the hero's
+ own container, with a readable floor for narrow hover-capable
+ viewports (resized browser, laptop touchscreen). */
+ flex-wrap: nowrap;
+ row-gap: 0;
+ /* Floor sized so the longest unfolded word (Deterministic) still
+ fits the hero without clipping on narrow hover-capable widths. */
+ font-size: max(2.4rem, min(var(--sf-text-4xl), 4.4cqi));
line-height: var(--sf-display-l-line-height);
- transition: translate var(--sf-duration-slow) var(--sf-ease-out);
}
.al { white-space: nowrap; }
.al .rest {
- display: inline-block;
- width: 0;
- opacity: 0;
- overflow: hidden;
- transition: width var(--sf-duration-slow) var(--sf-ease-out),
- opacity var(--sf-duration-normal) var(--sf-ease-out);
+ position: absolute;
+ inset-block-start: 0;
+ inset-inline-start: 100%; /* immediately after the bold letter */
+ width: max-content;
+ opacity: 0;
+ clip-path: inset(0 100% 0 0); /* hidden by clip, so it occupies no layout space */
+ transition: clip-path var(--sf-duration-slow) var(--sf-ease-out),
+ opacity var(--sf-duration-normal) var(--sf-ease-out);
+ }
+ /* The unfolded word overlays its dimmed neighbours cleanly. */
+ .al:hover { z-index: 1; }
+ .al:hover .rest {
+ opacity: 1;
+ clip-path: inset(0 0 0 0);
+ transition-delay: 60ms;
}
- .al:hover .rest { width: var(--w); opacity: 1; transition-delay: 120ms; }
.acronym-hero:hover .al:not(:hover) b { opacity: 0.35; }
- .acronym-hero:has(.al:hover) { transition-delay: 120ms; }
- .acronym-hero:has(.al:nth-of-type(1):hover) { translate: calc(8.2ch / 2) 0; }
- .acronym-hero:has(.al:nth-of-type(2):hover) { translate: calc(3.1ch / 2) 0; }
- .acronym-hero:has(.al:nth-of-type(3):hover) { translate: calc(6ch / 2) 0; }
- .acronym-hero:has(.al:nth-of-type(4):hover) { translate: calc(7.8ch / 2) 0; }
- .acronym-hero:has(.al:nth-of-type(5):hover) { translate: calc(4.3ch / 2) 0; }
- .acronym-hero:has(.al:nth-of-type(6):hover) { translate: calc(5ch / 2) 0; }
- .acronym-hero:has(.al:nth-of-type(7):hover) { translate: calc(9.8ch / 2) 0; }
}
@media (prefers-reduced-motion: reduce) {
.acronym-hero, .al b, .al .rest { transition: none; }
@@ -365,9 +373,11 @@
.doc-list a small { color: var(--sf-color-text--muted); margin-inline-start: var(--sf-space-2xs); }
.footer-meta, .footer-meta a { color: var(--sf-color-text--muted); font-size: var(--sf-text-xs); }
- /* The hover hint only makes sense where hovering is a thing. */
+ /* The hover hint only makes sense where hovering is a thing — and it
+ must match the interaction gate above, or a hybrid touch device
+ would see "hover the name" over an already-unfolded acronym. */
.hover-hint { display: none; }
- @media (any-hover: hover) { .hover-hint { display: inline; } }
+ @media (hover: hover) and (pointer: fine) { .hover-hint { display: inline; } }
.eyebrow {
font-size: var(--sf-text-xs);
@@ -393,7 +403,7 @@