    .ifndef WITH_COSMETIC_UI
    .equ WITH_COSMETIC_UI,0
    .endif
    .ifndef WITH_REFINEMENTS
    .equ WITH_REFINEMENTS,0
    .endif
| Actual preseason modal. Native controller input and native font/canvas.
| Persistent transactions use the independently checked234000 engine.
| WorkE000..E7FF, speculativeE800..EFFF. Modal-only state/textF100..F1FF,
| free-agent ownership bitsetF200..F267. Rebuild native menu context on exit.
    .equ WORK,0xFFFFE000
    .equ CLUB,0xFFFFF100
    .equ SCREEN,0xFFFFF102
    .equ SEL,0xFFFFF104
    .equ SOURCE,0xFFFFF106
    .equ LEAGUE,0xFFFFF108
    .equ ERROR,0xFFFFF10A
    .equ COUNT,0xFFFFF10C
    .equ PAGE,0xFFFFF10E
    .equ UID,0xFFFFF110
    .equ ENABLED,0xFFFFF112
    .equ TEXT,0xFFFFF160
    .equ USED,0xFFFFF200
    .equ OVR_SORTED,0x23BA00
    .equ POSX,0xFFFFB028
    .equ POSY,0xFFFFB02A
    .equ ATTR,0xFFFFB02C
    .equ VALUE,0xFFFFF85C
    .text
    .globl _start
_start:
    bra.w enter
    .if WITH_COSMETIC_UI
    bra.w money
    bra.w player_text
    .else
    .endif
enter:
    tst.w 0xFFFFF06C
    beq.w ordinary
    tst.w 0xFFFFF84C
    bne.w ordinary
    cmpi.l #0x5345534E,0xFFFFE3E0
    bne.s empty_header
    tst.w 0xFFFFE3E8
    bne.w ordinary
    bra.s eligible_header
empty_header:
    cmpi.w #2,0xFFFFE3F0          | Fresh native boot has no SESN header yet.
    bne.w ordinary
eligible_header:
    jsr 0x254000
    move.w VALUE,ENABLED
    move.w 0xFFFFF06A,LEAGUE
    move.w 0xFFFFD04C,CLUB
    cmpi.w #31,CLUB
    bhi.w ordinary
    tst.w ENABLED
    beq.s load_record
    jsr 0x2FC004                   | Native canvas writes E36A: BEFORE work load.
load_record:
    move.w LEAGUE,%d0
    lea WORK,%a0
    jsr 0x234018
    tst.l %d0
    bmi.w load_error
    bne.s loaded
    tst.w ENABLED
    beq.w ordinary
    lea 0x238000,%a0
    lea WORK,%a1
    move.w #511,%d0
initial_copy:
    move.l (%a0)+,(%a1)+
    dbra %d0,initial_copy
    move.w LEAGUE,%d0
    move.b %d0,WORK+5
    lea WORK,%a0
    jsr 0x234004
    move.w %d0,WORK+16
    not.w %d0
    move.w %d0,WORK+18
    bsr.w save
    beq.w load_error
loaded:
    moveq #0,%d0
    move.b WORK+6,%d0
    cmp.w ENABLED,%d0
    beq.s enabled_ready
    move.w ENABLED,%d3
    addq.w #3,%d3
    move.w LEAGUE,%d0
    lea WORK,%a0
    moveq #0,%d4
    jsr 0x234020
    cmpi.l #1,%d0
    bne.w load_error
    bsr.w save
    beq.w load_error
enabled_ready:
    tst.w ENABLED
    beq.w continue_game
    clr.w SCREEN
    clr.w SEL
    clr.w SOURCE
    clr.w ERROR
    bsr.w redraw
    bclr #2,0xFFFFBF78
    move.w #0x18,0xFFFFBD26
    move.w #0x79,-(%sp)
    jsr 0x11156
release:
    jsr 0x175D8
    jsr 0x11340
    move.w %d3,-(%sp)             | D3 is held input; D0 includes idle direction8.
    jsr 0x11358
    or.w (%sp)+,%d3
    tst.w %d3
    bne.s release
    bra.w loop
load_error:
    | Fail closed. No invalid roster/funds are allowed into a native match.
    jsr MENU_FORCE
    jsr 0x236028
    moveq #1,%d0
    rts
ordinary:
    moveq #0,%d0
    rts
continue_game:
    jsr MENU_FORCE
    jsr 0x236028
    moveq #0,%d0
    rts
save:
    move.w LEAGUE,%d0
    lea WORK,%a0
    jsr 0x23401C
    tst.l %d0
    rts
keys:
    jsr 0x175D8
    jsr 0x11340
    move.w %d1,-(%sp)
    jsr 0x11358
    or.w (%sp)+,%d1
    rts
loop:
    bsr.s keys
    .if WITH_REFINEMENTS
    btst #4,%d1                    | Xbox A = native B: same back convention.
    bne.w back
    btst #7,%d1                    | Start finishes the root; backs out of lists.
    beq.s not_start
    tst.w SCREEN
    bne.w back
    bra.w ready
not_start:
    .endif
    btst #6,%d1
    bne.w back
    .if !WITH_REFINEMENTS
    btst #5,%d1
    bne.w back
    .endif
    btst #0,%d1
    bne.w up
    btst #1,%d1
    bne.w down
    tst.w SCREEN
    beq.s select_key
    cmpi.w #1,SCREEN
    bne.s select_key
    btst #2,%d1
    bne.w previous_source
    btst #3,%d1
    bne.w next_source
select_key:
    .if WITH_REFINEMENTS
    andi.w #0x20,%d1              | Xbox B = native C selects/buys/sells.
    .else
    andi.w #0x90,%d1              | Fresh Start or native pass B.
    .endif
    beq.s loop
    tst.w SCREEN
    bne.w trade
    move.w SEL,%d0
    cmpi.w #2,%d0
    beq.w ready
    addq.w #1,%d0
    move.w %d0,SCREEN
    clr.w SEL
    clr.w ERROR
    bra.w redraw_loop
back:
    tst.w SCREEN
    beq.w load_error
    clr.w SCREEN
    clr.w SEL
    clr.w ERROR
    bra.w redraw_loop
up:
    tst.w SEL
    beq.w loop
    subq.w #1,SEL
    bra.w redraw_loop
down:
    move.w COUNT,%d0
    subq.w #1,%d0
    cmp.w SEL,%d0
    bls.w loop
    addq.w #1,SEL
    bra.w redraw_loop
previous_source:
    subq.w #1,SOURCE
    bpl.s source_ready
    move.w #32,SOURCE
    bra.s source_ready
next_source:
    addq.w #1,SOURCE
    cmpi.w #33,SOURCE
    blo.s source_ready
    clr.w SOURCE
source_ready:
    clr.w SEL
    clr.w ERROR
    bra.w redraw_loop
trade:
    tst.w COUNT
    beq.w loop
    move.w SEL,%d0
    bsr.w uid_at
    cmpi.w #0xFFFF,%d0
    beq.w loop
    move.w %d0,UID
    move.w %d0,%d2
    move.w CLUB,%d1
    cmpi.w #2,SCREEN
    beq.s sell_action
    moveq #1,%d3
    bra.s perform_trade
sell_action:
    moveq #0,%d3
perform_trade:
    move.w LEAGUE,%d0
    moveq #0,%d4
    lea WORK,%a0
    jsr 0x234020
    cmpi.l #1,%d0
    bne.w refused
    bsr.w save
    beq.w load_error
    clr.w ERROR
    bra.w redraw_loop
refused:
    move.w #4,ERROR
    cmpi.w #1,SCREEN
    bne.w redraw_loop
    move.w CLUB,%d0
    cmp.w SOURCE,%d0
    bne.s not_owned
    move.w #5,ERROR
    bra.w redraw_loop
not_owned:
    mulu.w #52,%d0
    lea WORK+32,%a0
    adda.l %d0,%a0
    cmpi.w #0xFFFF,50(%a0)
    beq.s check_money
    move.w #2,ERROR
    bra.w redraw_loop
check_money:
    move.w UID,%d0
    jsr 0x234000
    move.w CLUB,%d1
    lsl.w #2,%d1
    lea WORK+1696,%a0
    cmp.l (%a0,%d1.w),%d0
    bls.w redraw_loop
    move.w #3,ERROR
    bra.w redraw_loop
ready:
    move.w LEAGUE,%d0
    moveq #2,%d3
    moveq #0,%d4
    lea WORK,%a0
    jsr 0x234020
    cmpi.l #2,%d0
    beq.w continue_game
    cmpi.l #1,%d0
    bne.w refused
    bsr.w save
    beq.w load_error
    bra.w continue_game
redraw_loop:
    bsr.w redraw
    bra.w loop

| A2=actual source/user row, or free-agent map. No fictional placeholder slots.
row:
    move.w SOURCE,%d0
    cmpi.w #2,SCREEN
    bne.s source_row
    move.w CLUB,%d0
source_row:
    mulu.w #52,%d0
    lea WORK+32,%a2
    adda.l %d0,%a2
    rts
clear_membership:
    lea USED,%a0
    moveq #25,%d0
clear_used:
    clr.l (%a0)+
    dbra %d0,clear_used
    rts
build_used:
    bsr.s clear_membership
    lea WORK+32,%a1
    move.w #831,%d3
used_next:
    moveq #0,%d0
    move.w (%a1)+,%d0
    cmpi.w #831,%d0
    bhi.s used_skip
    move.w %d0,%d1
    lsr.w #3,%d0
    andi.w #7,%d1
    lea USED,%a0
    bset %d1,(%a0,%d0.w)
used_skip:
    dbra %d3,used_next
    rts
is_free:
    move.w %d0,%d1
    lsr.w #3,%d1
    move.w %d0,%d2
    andi.w #7,%d2
    lea USED,%a0
    btst %d2,(%a0,%d1.w)
    bne.s unavailable
    lea 0x239B80,%a0
    cmpi.b #0xFF,(%a0,%d0.w)
    rts
unavailable:
    cmp.w %d0,%d0                 | Z1 unavailable; Z0 means available.
    rts
count:
    clr.w COUNT
    tst.w SCREEN
    bne.s roster_count
    move.w #3,COUNT
    rts
roster_count:
    cmpi.w #1,SCREEN
    bne.s club_count
    cmpi.w #32,SOURCE
    bne.s club_count
    bsr.s build_used
    moveq #0,%d0
free_count:
    bsr.s is_free
    beq.s free_count_next
    addq.w #1,COUNT
free_count_next:
    addq.w #1,%d0
    cmpi.w #832,%d0
    blo.s free_count
    rts
club_count:
    bsr.w clear_membership
    bsr.w row
    moveq #25,%d3
club_count_next:
    moveq #0,%d0
    move.w (%a2)+,%d0
    cmpi.w #831,%d0
    bhi.s counted
    move.w %d0,%d1
    lsr.w #3,%d0
    andi.w #7,%d1
    lea USED,%a0
    bset %d1,(%a0,%d0.w)
    addq.w #1,COUNT
    dbra %d3,club_count_next
counted:
    rts
| Project the current source membership through a separate global OVR order.
| Never reorder WORK's persistent roster slots: native lineups/stat identities
| retain their role-aware layout. Equal OVR sorts by canonical UID.
uid_at:
    cmp.w COUNT,%d0
    bhs.s uid_missing
    move.w %d0,%d4
    moveq #0,%d5
    cmpi.w #1,SCREEN
    bne.s uid_scan_start
    cmpi.w #32,SOURCE
    bne.s uid_scan_start
    moveq #1,%d5
uid_scan_start:
    lea OVR_SORTED,%a3
    moveq #0,%d6
uid_scan:
    moveq #0,%d0
    move.w (%a3)+,%d0
    tst.w %d5
    beq.s uid_membership
    bsr.w is_free
    beq.s uid_scan_next
    bra.s uid_available
uid_membership:
    move.w %d0,%d1
    lsr.w #3,%d1
    move.w %d0,%d2
    andi.w #7,%d2
    lea USED,%a0
    btst %d2,(%a0,%d1.w)
    beq.s uid_scan_next
uid_available:
    subq.w #1,%d4
    bmi.s uid_done
uid_scan_next:
    addq.w #1,%d6
    cmpi.w #831,%d6
    blo.s uid_scan
uid_missing:
    move.w #0xFFFF,%d0
uid_done:
    rts

redraw:
    bsr.w count
    move.w COUNT,%d0
    cmp.w SEL,%d0
    bhi.s selection_valid
    subq.w #1,%d0
    bpl.s clamp_selection
    moveq #0,%d0
clamp_selection:
    move.w %d0,SEL
selection_valid:
    move.w #0x8000,ATTR
    moveq #3,%d7
clear_line:
    move.w %d7,POSY
    move.w #1,POSX
    lea blank(%pc),%a1
    jsr 0x11BA4
    addq.w #1,%d7
    cmpi.w #27,%d7
    blo.s clear_line
    move.w #1,POSY
    move.w #10,POSX
    lea title(%pc),%a1
    jsr 0x11BA4
    move.w #3,POSY
    move.w #3,POSX
    lea budget(%pc),%a1
    jsr 0x11BA4
    move.w CLUB,%d0
    lsl.w #2,%d0
    lea WORK+1696,%a0
    move.l (%a0,%d0.w),%d0
    .if WITH_COSMETIC_UI
    lea TEXT,%a0
    bsr.w money
    .else
    lea TEXT+9,%a0
    moveq #7,%d1
    bsr.w decimal
    lea TEXT+2,%a0
    moveq #7,%d1
    bsr.w trim_zeroes
    move.w #9,TEXT
    .endif
    lea TEXT,%a1
    jsr 0x11BA4
    .if WITH_COSMETIC_UI
    move.w #4,POSY
    move.w #3,POSX
    lea club_label(%pc),%a1
    jsr 0x11BA4
    .else
    move.w #23,POSX
    .endif
    move.w CLUB,%d0
    bsr.w club_name
    tst.w SCREEN
    bne.w draw_roster
    moveq #0,%d7
draw_home:
    move.w %d7,%d0
    mulu.w #3,%d0
    addi.w #10,%d0
    move.w %d0,POSY
    move.w #8,POSX
    move.w #0x8000,ATTR
    cmp.w SEL,%d7
    bne.s home_colour
    move.w #0xE000,ATTR
home_colour:
    cmp.w SEL,%d7
    bne.s home_label
    move.w #6,POSX
    lea marker(%pc),%a1
    jsr 0x11BA4
    move.w #8,POSX
home_label:
    move.w %d7,%d0
    lsl.w #2,%d0
    lea home_labels(%pc),%a0
    movea.l (%a0,%d0.w),%a1
    jsr 0x11BA4
    addq.w #1,%d7
    cmpi.w #3,%d7
    blo.s draw_home
    bra.w draw_footer
draw_roster:
    move.w #5,POSY
    move.w #3,POSX
    lea selling(%pc),%a1
    cmpi.w #2,SCREEN
    beq.s roster_title
    lea buying(%pc),%a1
roster_title:
    jsr 0x11BA4
    move.w #6,POSY
    move.w #3,POSX
    move.w SOURCE,%d0
    cmpi.w #2,SCREEN
    bne.s source_name
    move.w CLUB,%d0
source_name:
    bsr.w club_name
    move.w #7,POSY
    move.w #3,POSX
    lea columns(%pc),%a1
    jsr 0x11BA4
    move.w SEL,%d0
    andi.w #0xFFF8,%d0
    move.w %d0,PAGE
    moveq #0,%d7
    tst.w COUNT
    bne.s draw_player
    move.w #10,POSY
    move.w #3,POSX
    lea empty(%pc),%a1
    jsr 0x11BA4
    bra.w draw_footer
draw_player:
    move.w PAGE,%d0
    add.w %d7,%d0
    cmp.w COUNT,%d0
    bhs.w draw_footer
    bsr.w uid_at
    bsr.w player_text
    move.w #0x8000,ATTR
    move.w PAGE,%d0
    add.w %d7,%d0
    cmp.w SEL,%d0
    bne.s player_colour
    move.w #0xE000,ATTR
player_colour:
    move.w %d7,%d0
    mulu.w #2,%d0
    addi.w #9,%d0
    move.w %d0,POSY
    move.w PAGE,%d0
    add.w %d7,%d0
    cmp.w SEL,%d0
    bne.s no_player_marker
    move.w #1,POSX
    lea marker(%pc),%a1
    jsr 0x11BA4
no_player_marker:
    move.w #3,POSX
    lea TEXT,%a1
    jsr 0x11BA4
    addq.w #1,%d7
    cmpi.w #8,%d7
    blo.s draw_player
draw_footer:
    move.w #0x8000,ATTR
    move.w #25,POSY
    move.w #1,POSX
    lea help(%pc),%a1
    .if WITH_REFINEMENTS
    tst.w SCREEN
    beq.s help_ready
    lea help_buy(%pc),%a1
    cmpi.w #1,SCREEN
    beq.s help_ready
    lea help_sell(%pc),%a1
help_ready:
    .endif
    jsr 0x25D004
    jsr 0x11BA4
    tst.w ERROR
    beq.s draw_done
    move.w #24,POSY
    move.w #1,POSX
    move.w ERROR,%d0
    subq.w #1,%d0
    lsl.w #2,%d0
    lea error_labels(%pc),%a0
    movea.l (%a0,%d0.w),%a1
    jsr 0x11BA4
draw_done:
    jsr 0x25D000
    rts

club_name:
    cmpi.w #32,%d0
    bne.s actual_club
    lea free_agents(%pc),%a1
    jmp 0x11BA4
actual_club:
    lsl.w #2,%d0
    lea 0x30E,%a0
    movea.l (%a0,%d0.w),%a1
    adda.w 4(%a1),%a1
    jmp 0x11BA4

player_text:
    move.w %d0,UID
    lea TEXT+2,%a0
    moveq #35,%d1
text_clear:
    move.b #32,(%a0)+
    dbra %d1,text_clear
    move.w #38,TEXT
    move.w UID,%d0
    lsl.w #2,%d0
    lea 0x238800,%a0
    movea.l (%a0,%d0.w),%a1
    move.w (%a1)+,%d1
    subq.w #3,%d1
    cmpi.w #19,%d1
    bls.s name_size
    moveq #19,%d1
name_size:
    lea TEXT+2,%a0
name_copy:
    move.b (%a1)+,%d2
    beq.s name_done
    move.b %d2,(%a0)+
    dbra %d1,name_copy
name_done:
    move.w UID,%d0
    lea 0x239B80,%a0
    moveq #0,%d1
    move.b (%a0,%d0.w),%d1
    lea roles(%pc),%a0
    move.b (%a0,%d1.w),TEXT+23
    lea 0x239EC0,%a0
    moveq #0,%d1
    move.b (%a0,%d0.w),%d1
    move.l %d1,%d0
    lea TEXT+27,%a0
    moveq #2,%d1
    .if WITH_COSMETIC_UI
    bsr.w decimal
    .else
    bsr.s decimal
    .endif
    lea TEXT+25,%a0
    moveq #2,%d1
    bsr.w trim_zeroes
    move.w UID,%d0
    jsr 0x234000
    .if WITH_COSMETIC_UI
    lea TEXT+48,%a0
    bsr.w money
    cmpi.w #10,%d1
    bhi.s price_overflow
    lea TEXT+38,%a0
    suba.w %d1,%a0
    lea TEXT+50,%a1
    subq.w #1,%d1
    bra.s price_copy
price_overflow:
    | Immutable OVR0..99 prices fit10. Fail visibly without touching adjacent
    | fields even if a diagnostic/corrupt price exceeds that declared bound.
    .else
    lea TEXT+33,%a0
    moveq #5,%d1
    bsr.s decimal
    .endif
    lea TEXT+28,%a0
    .if WITH_COSMETIC_UI
    lea money_overflow(%pc),%a1
    moveq #9,%d1
price_copy:
    move.b (%a1)+,(%a0)+
    dbra %d1,price_copy
    .else
    moveq #5,%d1
    bsr.w trim_zeroes
    .endif
    rts
    .if WITH_COSMETIC_UI

    .else
    .endif
trim_zeroes:
    subq.w #2,%d1
trim_next:
    cmpi.b #48,(%a0)
    bne.s trim_done
    move.b #32,(%a0)+
    dbra %d1,trim_next
trim_done:
    rts
decimal:
    movem.l %d2-%d4,-(%sp)
    subq.w #1,%d1
decimal_digit:
    move.l %d0,%d2
    swap %d0
    andi.l #0xFFFF,%d0
    divu.w #10,%d0
    move.w %d0,%d3
    clr.w %d0
    move.w %d2,%d0
    divu.w #10,%d0
    move.w %d0,%d2
    swap %d0
    addi.b #48,%d0
    move.b %d0,-(%a0)
    move.w %d3,%d0
    swap %d0
    move.w %d2,%d0
    dbra %d1,decimal_digit
    movem.l (%sp)+,%d2-%d4
    rts
    .if WITH_COSMETIC_UI
| Unsigned32-bit internal units -> whole USD at1000 dollars per unit.
| No multiplication: group the units, then append .000. This supports even
| UINT32_MAX as $4.294.967.295.000 without overflowing32-bit arithmetic.
| D0=input preserved; A0=packet destination preserved (21bytes incl terminator).
| D1=payload length returned; all other registers preserved. No persistent RAM.
money:
    move.w %sr,-(%sp)
    movem.l %d0/%d2-%d6/%a0-%a2,-(%sp)
    move.l %d0,%d5
    movea.l %a0,%a2
    suba.w #12,%sp
    movea.l %sp,%a1
    lea 10(%sp),%a0
    moveq #10,%d1
    bsr.w decimal
    moveq #10,%d2
money_skip:
    cmpi.w #1,%d2
    beq.s money_digits
    cmpi.b #48,(%a1)
    bne.s money_digits
    addq.l #1,%a1
    subq.w #1,%d2
    bra.s money_skip
money_digits:
    lea 2(%a2),%a0
    move.b #36,(%a0)+
    tst.l %d5
    bne.s money_groups
    move.b #48,(%a0)+
    bra.s money_done
money_groups:
    move.l %d2,%d3
    divu.w #3,%d3
    swap %d3
    tst.w %d3
    bne.s money_copy
    moveq #3,%d3
money_copy:
    move.b (%a1)+,(%a0)+
    subq.w #1,%d2
    beq.s money_thousands
    subq.w #1,%d3
    bne.s money_copy
    move.b #46,(%a0)+
    moveq #3,%d3
    bra.s money_copy
money_thousands:
    move.b #46,(%a0)+
    move.b #48,(%a0)+
    move.b #48,(%a0)+
    move.b #48,(%a0)+
money_done:
    clr.b (%a0)
    move.l %a0,%d1
    sub.l %a2,%d1
    move.w %d1,(%a2)
    subq.w #2,%d1
    adda.w #12,%sp
    movem.l (%sp)+,%d0/%d2-%d6/%a0-%a2
    move.w (%sp)+,%sr
    rts
money_overflow: .ascii "$OVERFLOW "
    .even
club_label: .word 8
    .ascii "Club: "

    .else
    .endif
roles: .ascii "GLCRFD"
    .even
home_labels: .long buy,sell,start
error_labels: .long blocked,full_roster,no_money,position_needed,already_owned
title: .word 22
    .ascii "PRESEASON TRANSFERS "
    .even
budget: .word 10
    .ascii "Budget: "
buy: .word 14
    .ascii "Buy players "
sell: .word 14
    .ascii "Sell players"
start: .word 18
    .ascii "Ready for season"
buying: .word 38
    .ascii "Buy: Left/Right changes source club "
    .even
selling: .word 20
    .ascii "Sell your players "
    .even
    .if WITH_COSMETIC_UI
columns: .word 38
    .ascii "PLAYER               P OVR PRICE USD"
    .if (.-columns)!=38
    .error "Currency column header must remain36 native characters"
    .endif
    .else
columns: .word 34
    .ascii "PLAYER               P OVR PRICE"
    .endif
    .even
help:
    .if WITH_REFINEMENTS
    .word 34
    .ascii "A Back B Select Start Ready     "
    .even
help_buy: .word 34
    .ascii "A/Start Back B Buy L/R Club     "
    .even
help_sell: .word 34
    .ascii "A/Start Back B Sell             "
    .even
    .else
    .word 32
    .ascii "Start/Pass: Select   A/C: Back"
    .endif
    .even
blocked: .word 42
    .ascii "Transfer blocked by budget/roster rules "
    .even
blank: .word 40
    .ascii "                                      "
    .even

full_roster: .word 36
    .ascii "Roster full - sell a player first "
    .even
no_money: .word 34
    .ascii "Not enough money for this player"
    .even
position_needed: .word 36
    .ascii "Club needs this position or player"
    .even
already_owned: .word 30
    .ascii "Already plays for your club "
    .even
empty: .word 22
    .ascii "No available players"
    .even
free_agents: .word 14
    .ascii "Free agents "
marker: .word 4
    .ascii "* "
