j3w1/theme implementation brief — file-input 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/file-input.json spec: spec/components/file-input.md site: https://j3w1.github.io/theme/reference/#c-file-input maturity: stable priority: R1 Summary: A native file input behind a label styled as a secondary button, optionally inside a drop zone, with a list of chosen files and per-file errors. 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): button.bg rgb(0 0 0 / 0%) ({color.action.secondary.bg}) use button.text #ffa2a7 ({color.action.secondary.text}) use button.border #a3676b ({color.action.secondary.border}) use button.bg-hover #630f0d ({color.action.secondary.hover-bg}) use button.bg-pressed #420f0c ({color.action.secondary.pressed-bg}) use button.ring #e53935 ({color.interaction.focus.ring}) use button.border-invalid #e53935 ({color.status.danger.border}) use button.text-disabled #8a5559 ({color.text.disabled}) use button.border-disabled #7d1310 ({color.border.disabled}) use button.bg-disabled #160b0b ({color.interaction.disabled.bg}) use zone.border #e53935 ({color.interaction.drop-target}) use zone.bg-drop-target rgb(145 20 16 / 12%) ({color.interaction.marquee}) use zone.hint #bd787d ({color.text.muted}) use label.text #ffa2a7 ({color.text.bright}) use status.text #bd787d ({color.text.muted}) use list.text #e99499 ({color.text.default}) use list.divider #2b0e0d ({color.border.divider}) use-and-report (D-008) list.size #ad7175 ({color.text.subtle}) use list.error #f73f35 ({color.status.danger.text}) use remove.text #e99499 ({color.action.tertiary.text}) use remove.bg-hover #1c0a09 ({color.action.tertiary.hover-bg}) use progress.track #420f0c ({color.interaction.pressed.bg}) use progress.stripe #7d1310 ({color.action.primary.bg}) use help.text #bd787d ({color.text.muted}) use message.text #f73f35 ({color.status.danger.text}) use States: default, hover, focus-visible, drop-target, invalid, disabled, loading default: button: 1px {color.action.secondary.border} outline, text {color.action.secondary.text}; zone: 1px dashed {color.interaction.drop-target} [—] hover: button background → {color.action.secondary.hover-bg}; border unchanged [cursor: pointer] focus-visible: ring 1px dashed {color.interaction.focus.ring} at −2px on the button (the input has focus) [the ring] drop-target: root fill {color.interaction.marquee}; border 1px dashed {color.interaction.drop-target} [dashed pattern; the hint text changes to "Release to add"] invalid: button border 2px {color.status.danger.border}; message with the ✕ glyph; a failed row shows its own ✕ [border width 1 → 2px; glyphs; `aria-invalid`] disabled: button text {color.text.disabled}, border {color.border.disabled}, background {color.interaction.disabled.bg}; the zone's dashes take {color.border.disabled}; no hover [`disabled`; cursor: not-allowed] loading: a static bar of 45° stripes, {color.action.primary.bg} on {color.interaction.pressed.bg}, below the row; the button stays enabled [`aria-busy`; the status text reads "Uploading n files"; no animation] Keyboard: Tab / Shift+Tab: Reaches the native input (drawn as the button), then each remove button in the list. Enter / Space: Opens the host file chooser from the input. Delete / Backspace: On a focused remove button, same as activating it. Escape: Closes the host chooser (host behaviour). ARIA: native named by two