Please improve the Ren'Py game code below to have the cards in the preview deck screen be sorted by their mana then their card id.

```renpy
screen player_deck_preview(player):
    # Modal layer to catch clicks outside
    modal True

    # Invisible button covering the entire screen to close the preview
    button:
        xfill True
        yfill True
        background None
        action Hide("player_deck_preview")

    # The actual deck preview frame
    frame:
        background Frame("gui_frame", 25, 25)
        xalign 0.5
        yalign 0.5
        padding (20, 20)
        # Ensure the frame can grow to accommodate content, up to a max
        xmaximum 1300 # Max width for the frame
        ymaximum 700  # Max height for the frame

        vbox:
            spacing 15

            # Title
            text "Player's Deck ([len(player.main_deck)] cards)" size 28 xalign 0.5 color "#ffffff"

            # Scrollable area for cards if deck is large
            viewport:
                # The viewport size should be less than the frame's maximums to allow padding and title
                xsize 1200 # Fixed width for the content area of the viewport
                ysize 550  # Fixed height for the content area of the viewport
                scrollbars "vertical"
                mousewheel True

                python:
                    # Sort the deck by card ID before displaying.
                    # This uses your provided card_id function.
                    # Ensure card_id is defined in an init python block.
                    sorted_deck = sorted(player.main_deck, key=card_id)
                    
                    num_cards = len(sorted_deck)
                    # Calculate number of rows needed for 8 columns
                    # (num_cards + columns - 1) // columns
                    num_columns = 8 
                    num_rows = (num_cards + num_columns - 1) // num_columns
                
                grid num_columns num_rows:  # Explicitly define grid size (8 columns)
                    spacing 15 # Spacing between grid cells

                    # Iterate based on the actual number of cards in the sorted deck
                    for i in range(num_rows * num_columns): # Iterate enough times to fill grid cells
                        if i < num_cards:
                            $ current_card = sorted_deck[i]
                            # Each card is hoverable
                            button:
                                xsize 140  # Desired width for each card button
                                ysize 196  # Desired height for each card button
                                background None # No background for the button itself, card_preview will show the card

                                # Prevent the modal background from closing when hovering cards
                                # (or clicking, if you add a click action here for card details later)
                                action NullAction() 
                                
                                # Ensure the button itself doesn't propagate hover to the modal background
                                hover_background None 
                                
                                # Show the card using your card_preview screen
                                use card_preview(current_card, size=(140, 196), hoverable=True, no_enlarge=True)
                        else:
                            # Add an empty space (null widget) to fill the grid
                            # if the number of cards is not a multiple of num_columns.
                            # This ensures the grid layout is consistent.
                            null width 140 height 196
            
            # Close button
            textbutton "Close" action Hide("player_deck_preview") xalign 0.5 yminimum 40 style "confirm_button"
```

```renpy
screen card_preview(card, selected=False, playable=False, size=(150, 210), hoverable=False, on_field=False, no_enlarge=False):
    default outline_color = "#00ff0047" if playable else ("#ffff0047" if selected else "#00000000")
    default hover_state = [False]
    if on_field or no_enlarge:
        $ enlarged = None
    else:
        $ enlarged = selected or (hoverable and hover_state[0])
    if selected and not hover_state[0]:
        $ zoom_factor = 1.2 if enlarged else 1.0
    else:
        $ zoom_factor = 1.8 if enlarged else 1.0
    $ actual_size = (int(size[0] * zoom_factor), int(size[1] * zoom_factor))

    $ offset_x = -((actual_size[0] - size[0]) // 2) if enlarged else 0
    $ offset_y = -((actual_size[1] - size[1]) // 0.68) if enlarged else 0

    $ outline_thickness = max(1, int(size[0] * 0.015 * zoom_factor))

    frame:
        xysize actual_size
        background None
        padding (0, 0)
        
        xoffset offset_x
        yoffset offset_y

        if hoverable:
            mousearea:
                area (0, 0, actual_size[0], actual_size[1])
                unhovered SetDict(hover_state, 0, False)
                hovered [SetDict(hover_state, 0, True), SetVariable("hovered_card", card)]

        add Solid(outline_color) xpos -10 ypos -10 xsize actual_size[0] + 20 ysize actual_size[1] + 20

        fixed:
            xysize actual_size

            # Card Art
            if on_field and isinstance(card, CreatureCard):
                add "images/[card.card_id]-creature.png" xysize actual_size
            else:
                add "images/[card.card_id].png" xysize actual_size

            # Mana
            if not on_field:
                fixed:
                    xpos int(size[0] * 0.02 * zoom_factor)
                    ypos int(size[0] * 0.02 * zoom_factor)
                    xsize int(size[0] * 0.25 * zoom_factor)
                    ysize int(size[0] * 0.25 * zoom_factor)
                    text "[card.mana]" size int(size[0] * 0.15 * zoom_factor) xalign 0.5 yalign 0.5 color "#FFFFFF" outlines [(outline_thickness, "#000000", 0, 0)]

            # Attack
            if on_field:
                fixed:
                    xpos int(size[0] * 0.02 * zoom_factor)
                    ypos actual_size[1] - int(size[1] * 0.25 * zoom_factor)
                    xsize int(size[0] * 0.25 * zoom_factor)
                    ysize int(size[0] * 0.25 * zoom_factor)
                    if isinstance(card, CreatureCard):
                        $ attack_color = "#FFFFFF"
                        if hasattr(card, "original_attack"):
                            if card.attack < card.original_attack:
                                $ attack_color = "#FF4444"
                            elif card.attack > card.original_attack:
                                $ attack_color = "#44FF44"
                        text "[card.attack]" size int(size[0] * 0.20 * zoom_factor) xalign 0.5 yalign 0.5 color attack_color outlines [(outline_thickness, "#000000", 0, 0)]
            else:
                fixed:
                    xpos int(size[0] * 0.0 * zoom_factor)
                    ypos actual_size[1] - int(size[1] * 0.18 * zoom_factor)
                    xsize int(size[0] * 0.25 * zoom_factor)
                    ysize int(size[0] * 0.25 * zoom_factor)
                    if isinstance(card, CreatureCard):
                        $ attack_color = "#FFFFFF"
                        if hasattr(card, "original_attack"):
                            if card.attack < card.original_attack:
                                $ attack_color = "#FF4444"
                            elif card.attack > card.original_attack:
                                $ attack_color = "#44FF44"
                        text "[card.attack]" size int(size[0] * 0.12 * zoom_factor) xalign 0.5 yalign 0.5 color attack_color outlines [(outline_thickness, "#000000", 0, 0)]

            # Health
            if on_field:
                fixed:
                    xpos actual_size[0] - int(size[0] * 0.27 * zoom_factor)
                    ypos actual_size[1] - int(size[1] * 0.25 * zoom_factor)
                    xsize int(size[0] * 0.25 * zoom_factor)
                    ysize int(size[0] * 0.25 * zoom_factor)
                    if isinstance(card, CreatureCard):
                        $ health_color = "#FFFFFF"
                        if hasattr(card, "original_health"):
                            if card.health < card.original_health:
                                $ health_color = "#FF4444"
                            elif card.health > card.original_health:
                                $ health_color = "#44FF44"
                        text "[card.health]" size int(size[0] * 0.20 * zoom_factor) xalign 0.5 yalign 0.5 color health_color outlines [(outline_thickness, "#000000", 0, 0)]
            else:
                fixed:
                    xpos actual_size[0] - int(size[0] * 0.21 * zoom_factor)
                    ypos actual_size[1] - int(size[1] * 0.18 * zoom_factor)
                    xsize int(size[0] * 0.25 * zoom_factor)
                    ysize int(size[0] * 0.25 * zoom_factor)
                    if isinstance(card, CreatureCard):
                        $ health_color = "#FFFFFF"
                        if hasattr(card, "original_health"):
                            if card.health < card.original_health:
                                $ health_color = "#FF4444"
                            elif card.health > card.original_health:
                                $ health_color = "#44FF44"
                        text "[card.health]" size int(size[0] * 0.12 * zoom_factor) xalign 0.5 yalign 0.5 color health_color outlines [(outline_thickness, "#000000", 0, 0)]
```