feat: improved captcha look - #2798
Conversation
Restyle the widget, image, frictionless (placeholder/PoW checkbox) and puzzle captchas into a unified Material 3 "tonal" key off the Prosopo brand purple, with a matching dark-mode scheme. - theme.ts: repurpose palette to the purple ramp + add M3 tokens (primaryContainer, surface/onSurface, muted, titleAccent, checkbox, overlay, tile, shape radii, elevation) for both light and dark - widget: M3 surface + elevation + 16px radius, purple two-tone spinner, custom-painted purple checkbox with tick (themes correctly in dark) - image: M3 card + tonal header, rounded tiles with purple selection overlay + check badge + scale-in, pill buttons, tonal reload - puzzle: theme-driven purple surface, piece, target ring and header Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Follow-up to the Material 3 purple tonal redesign. Per design feedback the
widgets were too rounded ("everything is round") and drop shadows read as
dated, so:
- shape scale dialled back: card 28->12px, full-pill buttons 100->8px,
widget 16->8px, header 18->8px, tiles 14->6px / 16->8px
- WIDGET_BORDER_RADIUS 16->8px, Modal 28->12px, puzzle surface 20->12px,
custom checkbox 8->6px
- elevation tokens flattened to none in both themes (widget, widgetHover,
card, buttonPrimary) so borders, not shadows, separate the surfaces
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- buttons use minHeight so wrapped localized labels aren't clipped - reload button hover uses a primaryContainer.hover state-layer token (visible in dark mode, unlike the brightness filter) - checkbox falls back to the native control in forced-colors mode - puzzle target/piece colors move into theme.palette.puzzle tokens, removing the hard-coded purples and isDark ternaries - drop the dead all-none elevation tokens and the CSS wired to them, plus unused grey/purple/muted palette entries - surface/onSurface/background/font colors derive from single constants - reuse the selected predicate for the tile overlay; format all files Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Reverts the styling changes from fa6e170 (style(widget): rein in roundedness and drop decorative shadows): shape scale back to the round M3 values (card 28px, pill buttons, widget 16px, header 18px, tiles 14/16px), WIDGET_BORDER_RADIUS 16px, Modal 28px, puzzle surface 20px, checkbox 8px, and the elevation tokens back to real shadows with their widget/card/button wiring (re-added where the earlier cleanup had removed the then-all-none tokens). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…+ changeset Use encodeURIComponent for the SVG data-URI tick color instead of a single-occurrence String.replace (CodeQL js/incomplete-sanitization). Add changeset for the improved captcha look across the widget packages. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Split the single tinted surface into Material 3 surface roles so the widget sits on a white surface while the dialog uses surfaceContainerHigh, and drop every drop shadow in favour of surface/outline separation. - Remove drop shadows from the widget, dialog card, modal and puzzle; hover and drag feedback now use M3 state layers and outline rings. - Add shared typography and stateLayer tokens; align the shape scale to M3. - Buttons: label-large type, 40dp height, spec padding, state-layer hover in place of a brightness filter, no resting elevation on the filled variant. - Add the missing focus indicators (3dp outline, 2dp offset, keyboard-only). - Use the onSurfaceVariant role for secondary text instead of opacity. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LYpduC2rvsLYgYM5NqNHZC
…-look # Conflicts: # packages/procaptcha-react/src/components/CaptchaComponent.tsx
The merge brought in main's new widget-skeleton, procaptcha-react and procaptcha-puzzle test suites, which pin the palette this branch replaced: a `grey` ramp that no longer exists, `#fff`/`#303030` surfaces, a shared error red, and outlined buttons. Git merged them cleanly as text but they neither compiled nor passed. Each assertion is rewritten against the role it is really about rather than re-pinned to a new hex, so the tests keep their original intent: - theme: assert the M3 role pairings (background.default is surfaceContainerHigh, contrastText is onSurface) instead of literal greys, and that both modes share one shape/type/state-layer scale. - elements: the on-page widget takes `surface`, and the checkbox spinner the outline + primary roles. - button: M3 text and filled buttons are borderless pills whose hover is a state layer, not an opaque grey fill. - puzzle: PuzzleCanvas now requires a `theme` prop. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017hPGTJ23KyDz2WuUgzz2pi
Screen.Recording.2026-08-11.at.12.41.00.mov |
…-look # Conflicts: # packages/procaptcha-react/src/components/Button.tsx
…okens #2930 landed tests that pin which palette key each element interpolates. Three of them named keys this branch deliberately moved away from: - The widget shell reads `surface`, not `background.default`. Both still exist; under M3 `background.default` is the dialog container's role (surfaceContainerHigh), which is what separates a resting affordance from a modal container. - The checkbox spinner is an M3 circular progress — a neutral `border` track with a `primary` active arc — where it used to draw the whole ring in `background.contrastText`. Assertions follow the elements; no styling changed to satisfy a test. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017hPGTJ23KyDz2WuUgzz2pi
What changedMerged Markdown / docs: none 🎉The only 1. Styling changes (the bulk of the PR)A Material 3 purple tonal theme. Values only — no API shape involved.
Components — 2. Structural changes (four, each with a reason)a. b. c. New palette keys — d. 3. Conflict resolutionOne conflict, in 4. Test updates
The assertions were pointed at the new tokens. No styling was changed to satisfy a test — in each case the element moved first and the test followed. 5. Verification
🤖 Generated with Claude Code |
Ports main's Material 3 restyle (#2798), the trusted-event gate (isEventTrusted), the selectable error label and the remounting reset() onto the vanilla DOM components, and re-points the locale and bundle tests that main added at the modules that replaced their React originals. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TdXVDYG6wybfWpMmAhqDpC
CI Check Do Not Merge
🤖 Generated with Claude Code