Public/Add-DhFilterCard.ps1

function Add-DhFilterCard {
    <#
    .SYNOPSIS
        Add a clickable card grid that filters a target table.

    .DESCRIPTION
        Renders a row of clickable cards — each card represents a distinct value
        from a field in the target table. Clicking a card instantly filters the
        table to show only matching rows. An active filter banner appears below
        the grid with a Clear Filter button.

        The cards are independent of the table data: you supply them explicitly
        so they can include display labels, counts, icons, and sub-labels that
        differ from the raw field values.

        Use -MultiFilter to allow more than one card to be active simultaneously.

    .PARAMETER Report Dashboard object from New-DhDashboard.
    .PARAMETER Id Unique identifier (alphanumeric, - or _).
    .PARAMETER Title Section heading shown above the cards.
    .PARAMETER TargetTableId TableId of the table to filter.
    .PARAMETER FilterField Field name in the target table to match against.
    .PARAMETER Cards
        Array of card hashtables:
          @{
              Label = 'Card display name' # REQUIRED
              Value = 'match-value' # REQUIRED — matched against FilterField
              SubLabel = 'Secondary label' # optional
              Count = 42 # optional — badge top-right of card
              Icon = 'X' # optional
          }

    .PARAMETER MultiFilter Allow multiple cards active simultaneously ($false).
    .PARAMETER ShowCount Show count badge on cards (default $true).

    .EXAMPLE
        # Filter a table by a grouping field
        $locationCards = $servers | Group-Object Location | ForEach-Object {
            @{ Label = $_.Name; Value = $_.Name; Count = $_.Count }
        }
        Add-DhFilterCard -Report $report -Id 'loc-filter' `
            -Title 'Filter by Location' `
            -TargetTableId 'servers' -FilterField 'Location' `
            -Cards $locationCards

    .EXAMPLE
        # Multi-select filter (multiple cards can be active at once)
        Add-DhFilterCard -Report $report -Id 'env-filter' `
            -Title 'Filter by Environment' `
            -TargetTableId 'resources' -FilterField 'Environment' `
            -MultiFilter $true `
            -Cards @(
                @{ Label = 'Production'; Value = 'prod'; Count = 45 }
                @{ Label = 'Staging'; Value = 'stg'; Count = 12 }
                @{ Label = 'Development'; Value = 'dev'; Count = 30 }
            )
    #>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory)] [System.Collections.Specialized.OrderedDictionary] $Report,
        [Parameter(Mandatory)]
        [ValidatePattern('^[A-Za-z0-9_-]+$')]
        [string]   $Id,
        [Parameter(Mandatory)] [string]    $Title,
        [Parameter(Mandatory)] [string]    $TargetTableId,
        [Parameter(Mandatory)] [string]    $FilterField,
        [Parameter(Mandatory)] [object[]]  $Cards,
        [switch]   $MultiFilter,
        [bool]     $ShowCount   = $true,
        [string]   $NavGroup    = ''    # primary nav group label (enables two-tier nav)
    )

    if (-not $Report.Contains('Blocks')) {
        $Report['Blocks'] = [System.Collections.Generic.List[hashtable]]::new()
    }

    if ($Report.Tables -and -not ($Report.Tables | Where-Object { $_.Id -eq $TargetTableId })) {
        throw "Add-DhFilterCard: Target table '$TargetTableId' not found. Add the table before the filter grid."
    }

    $normCards = foreach ($card in $Cards) {
        $c = @{} + $card
        if (-not $c.Contains('SubLabel')) { $c['SubLabel'] = '' }
        if (-not $c.Contains('Count'))    { $c['Count']    = $null }
        if (-not $c.Contains('Icon'))     { $c['Icon']     = '' }
        $c
    }

    $Report.Blocks.Add([ordered]@{
        BlockType     = 'filtercardgrid'
        Id            = $Id
        Title         = $Title
        TargetTableId = $TargetTableId
        FilterField   = $FilterField
        Cards         = @($normCards)
        MultiFilter   = $MultiFilter
        ShowCount     = $ShowCount
        NavGroup      = $NavGroup
    })
    Write-Verbose "Add-DhFilterCard: '$Id' -> table '$TargetTableId' on field '$FilterField' ($(@($normCards).Count) cards)."
}