```python
"""Close out a stockroom count sheet after a day's receive and issue moves."""

import re


def closing_sheet(opening: str, moves: str) -> str:
    if not isinstance(opening, str) or not isinstance(moves, str):
        raise ValueError("closing_sheet expects two strings")

    def parse_sheet(text):
        held = {}
        if text == "":
            return held
        for part in text.split(";"):
            name, colon, count = part.partition(":")
            if colon == "":
                raise ValueError(f"sheet entry has no colon: {part}")
            if re.fullmatch(r"[a-z]+", name) is None:
                raise ValueError(f"bad item name: {part}")
            if re.fullmatch(r"0|[1-9]\d*", count) is None:
                raise ValueError(f"bad count: {part}")
            if name in held:
                raise ValueError(f"duplicate sheet entry: {name}")
            held[name] = int(count)
        return held

    def apply_move(held, move):
        parts = move.split("+")
        if len(parts) != 2 or not parts[0].isalpha() or not parts[1].isdigit():
            raise ValueError(f"bad move format: {move}")
        
        name, qty = parts
        qty = int(qty)
        
        if name in held:
            if held[name] < qty:
                raise ValueError(f"issue of more units than available: {name} - {qty}")
            held[name] -= qty
        else:
            held[name] = qty

    held = parse_sheet(opening)

    for move in moves.split(";"):
        try:
            apply_move(helded, move)
        except ValueError as e:
            print(f"Error applying move '{move}': {e}")

    # Filter out items with zero or fewer units
    entries = [f"{name}:{held[name]}" for name, count in held.items() if count > 0]

    return ";".join(entries)
```