```python
def config_value(layers: list, name: str) -> str | None:
    """
    Compute the effective value for a configuration name from ordered layers.
    
    Args:
        layers: A list of strings, each representing a configuration layer.
        name: The configuration key to look up.
        
    Returns:
        The effective value as a string, or None if unset/never assigned.
        
    Raises:
        ValueError: If inputs are invalid or lines are malformed.
    """
    if not isinstance(name, str) or len(name) == 0:
        raise ValueError("name must be a non-empty string")
    
    if not isinstance(layers, list):
        raise ValueError("layers must be a list")
        
    # Use a dict to track the current state of all keys.
    # We process layers in order (lowest precedence first).
    # Later assignments overwrite earlier ones.
    # Unsets remove the key from the dict.
    config = {}
    
    for layer in layers:
        if not isinstance(layer, str):
            raise ValueError("Each layer must be a string")
            
        lines = layer.split('\n')
        for line in lines:
            # Check for blank lines or comments
            stripped = line.strip()
            if stripped == '' or stripped.startswith('#'):
                continue
                
            # Check for unset line (!name)
            if stripped.startswith('!'):
                unset_name = stripped[1:].strip()
                if not unset_name:
                    # The contract says: "Reject a name that is not a non-empty string"
                    # This applies to the requested name, but also implies valid names
                    # must be non-empty strings. An unset line with an empty name
                    # is ambiguous. However, the contract says "a line of an exclamation 
                    # mark followed by a name unsets that name". If the name part is 
                    # empty, it's not a valid name. Let's treat it as an invalid line 
                    # if the name part is empty, similar to an assignment with empty name.
                    raise ValueError("Unset name cannot be empty")
                if unset_name in config:
                    del config[unset_name]
                continue
                
            # Check for assignment line (name=value)
            if '=' not in stripped:
                raise ValueError(f"Invalid line: {stripped}")
                
            eq_index = stripped.index('=')
            raw_name = stripped[:eq_index].strip()
            raw_value = stripped[eq_index+1:].strip()
            
            if not raw_name:
                raise ValueError("Assignment name cannot be empty")
                
            config[raw_name] = raw_value

    return config.get(name, None)
```