j3w1/theme implementation brief — radio-group theme: j3w1-theme 1.1.0 profile: default sourceDigest: sha256-C+iD5Q7l0XPU/boMj003wPbPLBOq3C3ZM7s4OfzJ6mc= pin: https://raw.githubusercontent.com/j3w1/theme/v1.1.0/exports/components/radio-group.json spec: spec/components/radio-group.md site: https://j3w1.github.io/theme/reference/#c-radio-group maturity: stable priority: R1 Summary: A fieldset of native radios for one exclusive choice; each radio is a 16px square that fills with the primary action colour and an inner square when checked. Use the pinned approved default profile. Pending roles in that profile use-and-report their decision IDs; this does not approve them. Proposed profiles are preview-only and blocked for delivery. Heritage profiles are historical-only. Deprecated or heritage roles are blocked for new approved-profile mappings. Consume roles within their documented scope, never primitives. Release numbering does not approve profiles or tokens. Tokens (resolved): box.bg #000000 ({color.surface.input}) use box.border #a3676b ({color.border.control}) use-and-report (D-007) box.bg-hover #1c0a09 ({color.interaction.hover.bg}) use box.ring #e53935 ({color.interaction.focus.ring}) use box.bg-checked #7d1310 ({color.action.primary.bg}) use box.bg-checked-hover #911410 ({color.action.primary.hover-bg}) use box.dot #f4eeee ({color.action.primary.text}) use box.ring-checked #ffa2a7 ({color.interaction.focus.ring-container}) use box.border-invalid #e53935 ({color.status.danger.border}) use box.bg-disabled #160b0b ({color.interaction.disabled.bg}) use box.border-disabled #7d1310 ({color.border.disabled}) use box.dot-disabled #8a5559 ({color.text.disabled}) use text.default #e99499 ({color.text.default}) use text.disabled #8a5559 ({color.text.disabled}) use legend.text #ffa2a7 ({color.text.bright}) use legend.required-mark #f73f35 ({color.status.danger.text}) use message.text #f73f35 ({color.status.danger.text}) use State dependency disclosures: D-007 States: default, hover, focus-visible, checked, checked+focus-visible, disabled, invalid, required default: 16px square, 1px {color.border.control} on {color.surface.input}; text {color.text.default} [—] hover: box background → {color.interaction.hover.bg}; a checked box → {color.action.primary.hover-bg} [cursor: pointer; hover-capable pointers only] focus-visible: ring 1px dashed {color.interaction.focus.ring} at −2px around the box [the ring] checked: box fills {color.action.primary.bg}; an 8px inner square in {color.action.primary.text}; border stays {color.border.control} [the inner square; `checked`] checked+focus-visible: the fill and a ring in {color.interaction.focus.ring-container} [inner square and ring] disabled: boxes {color.interaction.disabled.bg} with 1px {color.border.disabled}; inner square and text {color.text.disabled} [`disabled`; cursor: not-allowed] invalid: every box border 2px {color.status.danger.border}; message with the ✕ glyph [border width 1 → 2px; glyph; `aria-invalid`] required: `*` after the legend in {color.status.danger.text} plus visually hidden "required" [`required`; the mark] Keyboard: Tab / Shift+Tab: Enters the group on the checked radio, or the first when none is checked; leaves it entirely. Up / Down / Left / Right: Moves the check to the previous or next radio and selects it (native); wraps at the ends. Space: Checks the focused radio when none is checked. ARIA: native inside
with (https://www.w3.org/WAI/ARIA/apg/patterns/radio/) Responsive: Vertical groups stack at every width. The horizontal variant wraps into rows at 320px and keeps a 16px gap between options. RTL mirrors the box to the inline start and reverses the row. Portability: native sharing a name, each inside a