The 'Code Segment (CS)' and 'Offset (IP)' arguments were declared as
'number' ingredients, so they were parsed with parseFloat and rejected
hexadecimal input such as '0xABC' with:
Invalid ingredient value. Not a number: NaN
However, SetBasePosition already parses both values with parseInt(x, 16)
and GetPosition renders them back out with toString(16), so these fields
have always been hexadecimal. The two conversions cancel out visually,
which is why the mismatch went unnoticed. It is observable though: a code
segment entered as '24' becomes 36 decimal internally, which crosses the
documented 'CS >= 36 switches 32-bit output to SEG:OFFSET' threshold.
Both arguments are now 'string' ingredients parsed by a dedicated helper
that accepts bare ('ABC'), prefixed ('0xABC') and suffixed ('ABCh') hex,
and rejects anything else with a named error instead of a NaN message.
The code segment is left-padded to four digits because SetBasePosition
reads it via slice(length - 4), which silently truncated shorter values
('ABC' was read as 'C').
Existing recipes are unaffected: the default is unchanged and numeric
argument values from saved recipes are still handled.
Fixes#2720