Delete the example's stylesheet - #23
Merged
Merged
Conversation
JedimEmO
added a commit
that referenced
this pull request
Jul 25, 2026
From review of #22. All three were real; two of them undercut the exact guarantee the feature exists to provide. Animation variants did not register their keyframes --------------------------------------------------- dwkeyframes! called ensure() from the generated class, but a modified form — hover:animate-x, [&::before]:animate-x — compiles the declaration *text* into a fresh class and never touches that class. Those animations referenced a @Keyframes rule that was never injected. Registration now hangs off the declaration text: the emitted *_RAW is an AnimationDecl whose Deref registers, rather than a plain &str. Codegen is unchanged — `.raw(&*IDENT)` derefs either one to `&str` — so every path dwclass! can take is covered. I had documented this as a known hole; it was too central to leave. dwclass! silently discarded what it could not parse -------------------------------------------------- Two bugs compounded here. `many0` stops at the first unparseable class and reports success with the remainder untouched, and parse_class_string ignored that remainder. One malformed class therefore deleted itself *and every class after it*, with no diagnostic — the precise failure mode dwclass! exists to prevent. It now refuses, naming the offending text. And the declaration-body parser used a character allow-list built on nom's `is_alphanumeric`, which takes a u8 — so `c as u8` truncated every multi-byte character and `[content:'→']` could not parse. Combined with the above, PR #23's own docs example silently compiled to zero classes. The body is now a deny-list of the four bracket delimiters, since a CSS value can hold any character. Also dropped the `_`-means-space rewrite. Spaces already work inside the brackets, so it bought nothing and corrupted `var(--brand_color)`. Composed pseudo-element utilities clobbered explicit content ------------------------------------------------------------ Every before:/after: utility has to emit a content, or nothing renders. But each utility is its own class with its own rule, so the literal `content: ""` from `before:absolute` won by source order over the `content: 'x'` from `before:[content:'x']`. I claimed raw()'s append semantics made Tailwind's --tw-content indirection unnecessary. That was wrong: appending only orders declarations *within* one class, not across composed utilities. Content now goes through --dw-content, so the content declaration is identical in every class and only the value varies. content-empty / content-none set the property for the same reason. Tests ----- 42 native (up from 29), including the dwkeyframes! parser and codegen, which previously had none. Browser suite is 12 (up from 9); the three new cases are the exact probes from the review, each verified failing before the fix. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
JedimEmO
added a commit
that referenced
this pull request
Jul 25, 2026
From review of #23. Deleting styles.rs removed a `transform: none !important` rule that suppressed the spotlight tilt under prefers-reduced-motion, and nothing replaced it — the blanket clamp in index.html only shortens transitions and animations, so pointer movement still tilted cards, just instantly. The README claimed otherwise. A @media block cannot help here: the tilt and the magnetic drift are style_signal writes, so the preference has to be read in Rust. Both now take it as a signal — which also means a preference changed while the page is open takes effect immediately, where the old !important rule needed a reload to matter for anything JS-driven. Verified in Chrome by hovering a card under both settings: no-preference rotateX(2.03deg) rotateY(-2.41deg) reduce rotateX(0deg) rotateY(0deg) Also corrects two doc claims that the #22 fixes invalidated: values are no longer underscore-rewritten, and pseudo-element content composes through a custom property rather than by source order. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
JedimEmO
force-pushed
the
example-drop-raw-css
branch
from
July 25, 2026 13:42
d5f75c5 to
6267c91
Compare
JedimEmO
added a commit
that referenced
this pull request
Jul 25, 2026
From review of #22. All three were real; two of them undercut the exact guarantee the feature exists to provide. Animation variants did not register their keyframes --------------------------------------------------- dwkeyframes! called ensure() from the generated class, but a modified form — hover:animate-x, [&::before]:animate-x — compiles the declaration *text* into a fresh class and never touches that class. Those animations referenced a @Keyframes rule that was never injected. Registration now hangs off the declaration text: the emitted *_RAW is an AnimationDecl whose Deref registers, rather than a plain &str. Codegen is unchanged — `.raw(&*IDENT)` derefs either one to `&str` — so every path dwclass! can take is covered. I had documented this as a known hole; it was too central to leave. dwclass! silently discarded what it could not parse -------------------------------------------------- Two bugs compounded here. `many0` stops at the first unparseable class and reports success with the remainder untouched, and parse_class_string ignored that remainder. One malformed class therefore deleted itself *and every class after it*, with no diagnostic — the precise failure mode dwclass! exists to prevent. It now refuses, naming the offending text. And the declaration-body parser used a character allow-list built on nom's `is_alphanumeric`, which takes a u8 — so `c as u8` truncated every multi-byte character and `[content:'→']` could not parse. Combined with the above, PR #23's own docs example silently compiled to zero classes. The body is now a deny-list of the four bracket delimiters, since a CSS value can hold any character. Also dropped the `_`-means-space rewrite. Spaces already work inside the brackets, so it bought nothing and corrupted `var(--brand_color)`. Composed pseudo-element utilities clobbered explicit content ------------------------------------------------------------ Every before:/after: utility has to emit a content, or nothing renders. But each utility is its own class with its own rule, so the literal `content: ""` from `before:absolute` won by source order over the `content: 'x'` from `before:[content:'x']`. I claimed raw()'s append semantics made Tailwind's --tw-content indirection unnecessary. That was wrong: appending only orders declarations *within* one class, not across composed utilities. Content now goes through --dw-content, so the content declaration is identical in every class and only the value varies. content-empty / content-none set the property for the same reason. Tests ----- 42 native (up from 29), including the dwkeyframes! parser and codegen, which previously had none. Browser suite is 12 (up from 9); the three new cases are the exact probes from the review, each verified failing before the fix. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
JedimEmO
force-pushed
the
dwind-keyframes-and-arbitrary-values
branch
from
July 25, 2026 13:44
5fc0334 to
064b5f9
Compare
JedimEmO
added a commit
that referenced
this pull request
Jul 25, 2026
From review of #23. Deleting styles.rs removed a `transform: none !important` rule that suppressed the spotlight tilt under prefers-reduced-motion, and nothing replaced it — the blanket clamp in index.html only shortens transitions and animations, so pointer movement still tilted cards, just instantly. The README claimed otherwise. A @media block cannot help here: the tilt and the magnetic drift are style_signal writes, so the preference has to be read in Rust. Both now take it as a signal — which also means a preference changed while the page is open takes effect immediately, where the old !important rule needed a reload to matter for anything JS-driven. Verified in Chrome by hovering a card under both settings: no-preference rotateX(2.03deg) rotateY(-2.41deg) reduce rotateX(0deg) rotateY(0deg) Also corrects two doc claims that the #22 fixes invalidated: values are no longer underscore-rewritten, and pseudo-element content composes through a custom property rather than by source order. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
JedimEmO
force-pushed
the
example-drop-raw-css
branch
from
July 25, 2026 13:44
6267c91 to
f8dfceb
Compare
JedimEmO
added a commit
that referenced
this pull request
Jul 25, 2026
From review of #22. All three were real; two of them undercut the exact guarantee the feature exists to provide. Animation variants did not register their keyframes --------------------------------------------------- dwkeyframes! called ensure() from the generated class, but a modified form — hover:animate-x, [&::before]:animate-x — compiles the declaration *text* into a fresh class and never touches that class. Those animations referenced a @Keyframes rule that was never injected. Registration now hangs off the declaration text: the emitted *_RAW is an AnimationDecl whose Deref registers, rather than a plain &str. Codegen is unchanged — `.raw(&*IDENT)` derefs either one to `&str` — so every path dwclass! can take is covered. I had documented this as a known hole; it was too central to leave. dwclass! silently discarded what it could not parse -------------------------------------------------- Two bugs compounded here. `many0` stops at the first unparseable class and reports success with the remainder untouched, and parse_class_string ignored that remainder. One malformed class therefore deleted itself *and every class after it*, with no diagnostic — the precise failure mode dwclass! exists to prevent. It now refuses, naming the offending text. And the declaration-body parser used a character allow-list built on nom's `is_alphanumeric`, which takes a u8 — so `c as u8` truncated every multi-byte character and `[content:'→']` could not parse. Combined with the above, PR #23's own docs example silently compiled to zero classes. The body is now a deny-list of the four bracket delimiters, since a CSS value can hold any character. Also dropped the `_`-means-space rewrite. Spaces already work inside the brackets, so it bought nothing and corrupted `var(--brand_color)`. Composed pseudo-element utilities clobbered explicit content ------------------------------------------------------------ Every before:/after: utility has to emit a content, or nothing renders. But each utility is its own class with its own rule, so the literal `content: ""` from `before:absolute` won by source order over the `content: 'x'` from `before:[content:'x']`. I claimed raw()'s append semantics made Tailwind's --tw-content indirection unnecessary. That was wrong: appending only orders declarations *within* one class, not across composed utilities. Content now goes through --dw-content, so the content declaration is identical in every class and only the value varies. content-empty / content-none set the property for the same reason. Tests ----- 42 native (up from 29), including the dwkeyframes! parser and codegen, which previously had none. Browser suite is 12 (up from 9); the three new cases are the exact probes from the review, each verified failing before the fix. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
JedimEmO
force-pushed
the
dwind-keyframes-and-arbitrary-values
branch
from
July 25, 2026 13:44
064b5f9 to
2ba788b
Compare
JedimEmO
added a commit
that referenced
this pull request
Jul 25, 2026
From review of #23. Deleting styles.rs removed a `transform: none !important` rule that suppressed the spotlight tilt under prefers-reduced-motion, and nothing replaced it — the blanket clamp in index.html only shortens transitions and animations, so pointer movement still tilted cards, just instantly. The README claimed otherwise. A @media block cannot help here: the tilt and the magnetic drift are style_signal writes, so the preference has to be read in Rust. Both now take it as a signal — which also means a preference changed while the page is open takes effect immediately, where the old !important rule needed a reload to matter for anything JS-driven. Verified in Chrome by hovering a card under both settings: no-preference rotateX(2.03deg) rotateY(-2.41deg) reduce rotateX(0deg) rotateY(0deg) Also corrects two doc claims that the #22 fixes invalidated: values are no longer underscore-rewritten, and pseudo-element content composes through a custom property rather than by source order. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
JedimEmO
force-pushed
the
example-drop-raw-css
branch
2 times, most recently
from
July 25, 2026 13:52
42e7ed6 to
08f8276
Compare
JedimEmO
added a commit
that referenced
this pull request
Jul 25, 2026
From review of #23. Deleting styles.rs removed a `transform: none !important` rule that suppressed the spotlight tilt under prefers-reduced-motion, and nothing replaced it — the blanket clamp in index.html only shortens transitions and animations, so pointer movement still tilted cards, just instantly. The README claimed otherwise. A @media block cannot help here: the tilt and the magnetic drift are style_signal writes, so the preference has to be read in Rust. Both now take it as a signal — which also means a preference changed while the page is open takes effect immediately, where the old !important rule needed a reload to matter for anything JS-driven. Verified in Chrome by hovering a card under both settings: no-preference rotateX(2.03deg) rotateY(-2.41deg) reduce rotateX(0deg) rotateY(0deg) Also corrects two doc claims that the #22 fixes invalidated: values are no longer underscore-rewritten, and pseudo-element content composes through a custom property rather than by source order. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
JedimEmO
force-pushed
the
example-drop-raw-css
branch
from
July 25, 2026 13:52
08f8276 to
9d82855
Compare
JedimEmO
added a commit
that referenced
this pull request
Jul 25, 2026
From re-review of #23. The previous commit gated spotlight_tilt but not magnetic — I ran a scripted patch that reported success without checking it had matched, and my browser probe only hovered a spotlight card, so neither caught it. magnetic is used on every CTA on the site. Both decisions are now pure functions with unit tests, so the rule is a plain assertion rather than something only a hovering browser can check. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
styles.rs is gone — all 297 lines of it. The site renders identically. What replaced it, using the capabilities added in the previous commit: - The 12 @Keyframes move to keyframes.rs as a single dwkeyframes! block. Ones used as bare classes get #[animation(...)]; the ones composed with a runtime delay are referenced through the handle, whose Display registers the rule. The dead dwind-glow-drift keyframe is dropped. - The pointer spotlight — a ::before glow and a masked ::after ring, both parked at --sx/--sy — is now dwclass! variants. content: "" is supplied automatically, and the four co-dependent mask declarations use the [property:value] escape hatch. Verified in a browser: the computed ::before background tracks the cursor. - The scroll-reveal cascade, including the parent-state .reveal-in > * rules and the :nth-child stagger, is child-selector variants on the container. The container no longer needs a marker class at all. - Scrollbars become [&::-webkit-scrollbar-thumb]: variants, the marquee's hover-pause becomes [&:hover > *]: — the classic "hover the parent, animate the child" case that no element-level class can express — and the glass panel and gradient-text sheen become named mixins. 40 inline .style() calls that duplicated utilities dwind already had (position, z-index, text-decoration, font: inherit, ...) are now dwclass!. The only CSS left is the <style> block in index.html, and it holds only document-level things: font families, :root colour-scheme, ::selection, a site-wide :focus-visible ring, and the blanket prefers-reduced-motion clamp. The .reveal-section override there is deleted along with the class. Docs gain the two capabilities that were previously undiscoverable: the Pseudoclasses page now covers ::before/::after variants and arbitrary declarations with live examples, and the Animation page covers dwkeyframes! and the @((prefers-reduced-motion: reduce)) conditional. Verified: 19 routes clean with no console errors, no horizontal overflow at 1440px or 390px, reduced motion honoured, ⌘K palette and the signal lab unchanged (10 -> 75 property writes on a slider drag). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
From review of #23. Deleting styles.rs removed a `transform: none !important` rule that suppressed the spotlight tilt under prefers-reduced-motion, and nothing replaced it — the blanket clamp in index.html only shortens transitions and animations, so pointer movement still tilted cards, just instantly. The README claimed otherwise. A @media block cannot help here: the tilt and the magnetic drift are style_signal writes, so the preference has to be read in Rust. Both now take it as a signal — which also means a preference changed while the page is open takes effect immediately, where the old !important rule needed a reload to matter for anything JS-driven. Verified in Chrome by hovering a card under both settings: no-preference rotateX(2.03deg) rotateY(-2.41deg) reduce rotateX(0deg) rotateY(0deg) Also corrects two doc claims that the #22 fixes invalidated: values are no longer underscore-rewritten, and pseudo-element content composes through a custom property rather than by source order. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
From re-review of #23. The previous commit gated spotlight_tilt but not magnetic — I ran a scripted patch that reported success without checking it had matched, and my browser probe only hovered a spotlight card, so neither caught it. magnetic is used on every CTA on the site. Both decisions are now pure functions with unit tests, so the rule is a plain assertion rather than something only a hovering browser can check. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
JedimEmO
force-pushed
the
example-drop-raw-css
branch
from
July 25, 2026 14:12
fb663ea to
787972f
Compare
JedimEmO
changed the base branch from
dwind-keyframes-and-arbitrary-values
to
main
July 25, 2026 14:29
This was referenced Jul 25, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #22 (which is stacked on #21). Retarget as the stack lands.
examples/webpage/src/styles.rsis gone — all 297 lines of it. The site renders identically.What replaced it
The 12
@keyframesmove tokeyframes.rsas onedwkeyframes!block. The ones used as bare classes get#[animation(...)]; the ones composed with a runtime delay are referenced through the handle, whoseDisplayregisters the rule:The dead
dwind-glow-driftkeyframe — declared, never used — is dropped.The pointer spotlight is the interesting one. A
::beforeglow and a masked::afterring, both parked at--sx/--sy, now expressed entirely asdwclass!variants.content: ""is supplied automatically; the four co-dependent mask declarations use the escape hatch:Verified in a real browser — the computed
::beforebackground tracks the cursor:radial-gradient(352px at 24.83….The scroll-reveal cascade — parent-state
.reveal-in > *rules plus:nth-childstagger — is child-selector variants on the container. The container no longer needs a marker class at all.Scrollbars become
[&::-webkit-scrollbar-thumb]:variants. The marquee's hover-pause becomes[&:hover > *]:[animation-play-state:paused]— the classic "hover the parent, animate the child" case that no element-level class can express. Glass panels and the gradient-text sheen become named mixins.40 inline
.style()calls that duplicated utilities dwind already had (position9×,text-decoration: none6×,font: inherit4×,z-index, …) are nowdwclass!. That part was never a library gap — the example just wasn't written carefully.What honestly stays raw
The
<style>block inindex.html, holding only document-level things: font families,:rootcolour-scheme,::selection, a site-wide:focus-visiblering, and the blanketprefers-reduced-motionclamp. The.reveal-sectionoverride there is deleted along with the class.The film-grain
feTurbulencedata URI stays an inline.style()— it's a one-off asset, not a reusable value.Docs
The two capabilities that already worked but were undiscoverable are now taught, with live examples:
::before/::aftervariants and arbitrary declarations (conic gradient,writing-mode, a--accentcustom property read back throughvar()).dwkeyframes!, the handle-Displaypattern for runtime delays, and@((prefers-reduced-motion: reduce)).Verification
19 routes clean with no console errors; no horizontal overflow at 1440px or 390px; reduced motion honoured; ⌘K palette and the signal lab unchanged (10 → 75 property writes on a slider drag). Screenshots are pixel-identical to the pre-migration build.
🤖 Generated with Claude Code