Both drew small text in the raw accent, which misses the contrast floor on
a dark surface. They now blend the accent toward the text colour, as the
unselected tab already does.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A Button rendered as a link emitted aria-pressed="", which is not allowed
on a link and fails an accessibility check on every page that uses one
for a secondary action. A link has no pressed state, so the attribute is
gone from that branch; a real button still carries it.
An unselected tab used the muted text colour, which does not reach 4.5:1
against the tab strip at this size. It now blends back toward the text
colour, and the selected tab still reads as selected through its surface,
accent and shadow.
The visual contract manifest is regenerated to match.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A component that renders a list, such as FeatureGrid, passes each item
into a child: title={item.title || item.label || "Feature"}. The
compiler decided whether that attribute needed a client binding by
searching the expression for each prop name, so `item.label` matched the
grid's own `label` prop and a binding was emitted.
On hydration the binding is re-evaluated where the loop item is out of
scope, so the expression fell through to its default and replaced the
server's value: every card's title became "Feature". A name after a dot
belongs to whatever precedes it, so it no longer counts as a reference.
Timeline headings follow the same idea: its items were always h4, which
skipped a level and broke the heading order of a page that gives the
timeline no title of its own. They now take h3 in that case.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Carries the rollback refusal in db and the matching CLI message, together
with the auth, captcha, csr, dev-server, dev-toolbar, ui and validation
changes that were already in the working tree, since publishing stages
from it and those files would otherwise ship without being recorded here.
@wrnexus/auth 0.8.28 -> 0.8.29
@wrnexus/captcha 0.8.15 -> 0.8.16
@wrnexus/cli 0.8.64 -> 0.8.65
@wrnexus/csr 0.8.37 -> 0.8.38
@wrnexus/db 0.8.20 -> 0.8.21
@wrnexus/dev-server 0.8.60 -> 0.8.61
@wrnexus/dev-toolbar 0.8.17 -> 0.8.18
@wrnexus/ui 0.8.75 -> 0.8.76
@wrnexus/validation 0.8.12 -> 0.8.13
Also declares Event among the browser globals captcha's client asset
already lists, which was the last lint failure, and reformats four files.
typecheck, lint, 1998 tests and format:check all pass.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A parent writing @focus on a component tag never heard that component's
own input or button take focus. The runtime bound every output-named DOM
fallback listener in the bubble phase, and focus and blur do not bubble,
so the event fired on the descendant and stopped there. Nothing errored --
the binding simply did nothing.
That made a whole class of declared outputs undeliverable: button.focus,
button.blur, TextLink.focus, TextLink.blur, WysiwygEditor.focus and
WysiwygEditor.blur all advertised events they could never send.
The ui ratchet for outputs nothing emits excluded natively-named outputs
on the grounds that a native event reaches the root anyway. That holds for
click and change, which bubble, and was wrong for focus and blur. Binding
those two in the capture phase makes the exclusion honest rather than
convenient; the ratchet's comment now says so.
Also documents WysiwygEditor as the chrome shell it is: it emits none of
its four outputs itself, it forwards whatever the slotted control raises.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>