def incremental_filter(image_pool, space, style, mood, 
                        color, materials, layout, lighting):

    # Stage 1 — Tier 1: hard filter, keep top 50%
    candidates = filter_by(image_pool, [
        CLIP_MAPPINGS["space"][space],
        CLIP_MAPPINGS["color"][color],
        ", ".join([CLIP_MAPPINGS["materials"][m] for m in materials]),
    ], keep_top=0.5)

    # Stage 2 — Tier 2: re-rank, keep top 50% of remaining
    candidates = filter_by(candidates, [
        CLIP_MAPPINGS["style"][style],
        CLIP_MAPPINGS["lighting"][lighting],
    ], keep_top=0.5)

    # Stage 3 — Tier 3: final re-rank
    candidates = filter_by(candidates, [
        CLIP_MAPPINGS["layout"][layout],
        CLIP_MAPPINGS["mood"][mood],
    ], keep_top=1.0)   # keep all, just re-rank

    return candidates


def filter_by(images, descriptions, keep_top=0.5):
    scored = []
    for image in images:
        score = sum(clip_similarity(image, d) for d in descriptions)
        scored.append((image, score))

    scored.sort(key=lambda x: x[1], reverse=True)
    cutoff = max(1, int(len(scored) * keep_top))
    return [img for img, _ in scored[:cutoff]]# your code goes here