Skip to content

refactor(web): give every card a .frost class, wrap the docs rail in one, and make the blur work again - #79

Merged
jnahian merged 2 commits into
mainfrom
refactor/web-frost-class
Sep 9, 2026
Merged

jnahian merged 2 commits into
mainfrom
refactor/web-frost-class

Conversation

@jnahian

@jnahian jnahian commented Sep 9, 2026

Copy link
Copy Markdown
Owner

The ask was a class for backdrop-filter: blur(2px) used on every card. The
blur turned out to already exist — as a hand-maintained selector list in
global.css — and to have stopped rendering in every browser but Safari.

The class

A new card had to be added to that selector list to get frosted, which is how
.cta__panel, .step and .clog__cta ended up without it, and how
.arch__card, .req__card and .scut__row stayed on it long after the rules
they named were deleted.

The list is now a .frost class carried in the markup. .btn, .pill and
.cta__code stay on the rule — they always frost and are not cards, so tagging
every call site would be noise. Faq.astro's hand-rolled copy of the same two
declarations goes away with it.

Searching for cards by name missed two: .step and .clog__cta are card-shaped
but named neither *card* nor *panel*, and .clog__cta is gradient-backed so
it does not match on background: var(--surface) either. Both were found by
shape instead — border-radius plus a 1px border.

The docs rail becomes a card

The rail was the one navigation surface on the site drawn as bare text on the
page background, while the hub's page grid, the changelog entries and the FAQ
all sat on a card. It now reuses the shared patterns rather than restating them:
.card carries the radius, surface and border, .frost the blur, and the only
new declaration is the rail's own padding.

The card sits on .docsnav, not on .docsnav__panel inside it — .docsnav is
the sticky scroll container, so the frame stays put while a long index scrolls
within it. On the panel the borders would have scrolled away with the content.

Below 900px it is undone: there the rail collapses to a single control and
.docsnav__toggle already carries its own deliberately opaque surface. The blur
has to be undone by hand along with it — .frost is a class, not a media query,
and over a transparent box it would smear a band of the article behind the
toggle.

The blur was dead outside Safari

esbuild's CSS minifier treats backdrop-filter and -webkit-backdrop-filter as
one property and keeps whichever is written last. Every declaration here was
written standard-first, so the build shipped only the prefixed form — which
Chrome has since removed and Firefox never had. The built CSS carried 0
unprefixed declarations against 5 prefixed, and Chrome's parser discarded all of
them, taking the nav glass, .filter and .qa-list down with the cards.

All five pairs are now prefix-first, so the standard property survives
minification.

Tradeoff: Safari <18 loses the blur, where previously everyone but Safari
had lost it. The alternative that keeps both — cssMinify: 'lightningcss' with
browser targets, and deleting every hand-written prefix — is a larger change to
the CSS build; happy to do it instead if the Safari 16–17 slice matters more.

The ordering reads like a typo, so it is commented where it lives and noted in
web/CLAUDE.md for the two scoped blocks far from that comment.

Verification

Against the built output in Chrome 152:

before after
.nav glass none blur(18px) saturate(1.6)
every card none blur(2px)
.filter, .qa-list, .btn, .cta__code none blur(2px)

Built CSS went from 0 standard / 5 prefixed to 5 standard / 0 prefixed.
Diffing the built HTML against main: no card lost the class, three gained
it
(.cta__panel, .step ×4, .clog__cta).

The rail was checked at three states — desktop, mobile collapsed, mobile open —
plus a short viewport where the index overflows and scrolls inside the frame.

Left alone deliberately: .filter (a search input, not a card), .qa-list
(plugin-generated — editing rehype-faq-accordion.mjs drags in the content-cache
hazard for a cosmetic dedupe), and .kbd__cli (a code block, sibling to the
already-frosted .cta__code). All three still get the ordering fix.

🤖 Generated with Claude Code

https://claude.ai/code/session_01WqUXC6nL5bayNL1cTrnFzw

… again

The blur was already applied, as a hand-maintained selector list in
global.css. A new card had to be added to that list to get frosted, which
is how .cta__panel, .step and .clog__cta ended up without it, and how
.arch__card, .req__card and .scut__row stayed on it long after the rules
they named were deleted.

Replace the list with a .frost class carried in the markup. .btn, .pill
and .cta__code stay on the rule: they always frost and are not cards, so
tagging every call site would be noise. Faq.astro's hand-rolled copy of
the same two declarations goes away with it.

Finding the cards by name missed two of them — .step and .clog__cta are
card-shaped but named neither *card* nor *panel*, and .clog__cta is
gradient-backed so it does not match on `background: var(--surface)`
either. They were found by shape instead: border-radius plus a 1px
border.

The blur itself had stopped rendering outside Safari. esbuild's CSS
minifier treats backdrop-filter and -webkit-backdrop-filter as one
property and keeps whichever is written last; every declaration here was
written standard-first, so the build shipped only the prefixed form —
which Chrome has since removed and Firefox never had. The built CSS
carried 0 unprefixed declarations against 5 prefixed, and Chrome's parser
dropped them all, taking the nav glass, .filter and .qa-list with it.

Swap all five pairs to prefix-first so the standard property survives.
Safari <18 loses the blur, where before everyone but Safari had. The
order reads like a typo, so it is commented where it lives and noted in
web/CLAUDE.md for the two scoped blocks far from that comment.

Verified in Chrome 152 against the built output: nav is back to
blur(18px) saturate(1.6), every card computes blur(2px), and a diff of
the built HTML against main shows no card lost the class and three
gained it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WqUXC6nL5bayNL1cTrnFzw
@jnahian jnahian added the web The marketing site under web/ (and the docs pages it renders) label Sep 9, 2026
The rail was the one navigation surface on the site drawn as bare text on
the page background, while everything beside it — the hub's page grid, the
changelog entries, the FAQ — sat on a card.

It reuses the shared patterns rather than restating them: .card carries the
radius, surface and border, .frost the blur, and the only new declaration is
the rail's own padding.

The card goes on .docsnav rather than on .docsnav__panel inside it. .docsnav
is the sticky scroll container, so the frame stays put while a long index
scrolls within it; on the panel the borders would have scrolled out of view
with the content.

Below 900px it is undone. There the rail collapses to a single control and
.docsnav__toggle already carries its own deliberately opaque surface, so a
card would frame a button that is one already. The blur has to be undone by
hand with it: .frost is a class, not a media query, and over a transparent
box it would smear a band of the article behind the toggle.

Checked in Chrome at three states — desktop, mobile collapsed, mobile open —
plus a short viewport where the index overflows and scrolls inside the frame.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WqUXC6nL5bayNL1cTrnFzw
@jnahian jnahian changed the title refactor(web): give every card a .frost class, and make the blur work again refactor(web): give every card a .frost class, wrap the docs rail in one, and make the blur work again Sep 9, 2026
@jnahian
jnahian merged commit fbf9cd1 into main Sep 9, 2026
1 check passed
@jnahian
jnahian deleted the refactor/web-frost-class branch September 9, 2026 13:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

web The marketing site under web/ (and the docs pages it renders)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant