tiles--thirds.html
<section class="tiles">
    <div class="container">
        <div class="tiles__grid -featured">
            <!-- 
                Thirds grid: 3 columns at desktop
                - (no modifier) = 1×1 small square
                - -featured = 2×2 large square  
                - -wide = 2×1 horizontal
                - -tall = 1×2 vertical
            -->
            <div class="tiles__set -thirds">
                <div class="tiles__tile">
                    <div class="tiles__media">
                        <img src="https://images.unsplash.com/photo-1557683316-973673baf926?w=400&h=400&fit=crop" alt="">
                    </div>
                </div>

                <div class="tiles__tile -featured -dark -has-content">
                    <div class="tiles__media">
                        <img src="https://images.unsplash.com/photo-1478760329108-5c3ed9d495a0?w=800&h=800&fit=crop" alt="">
                    </div>
                    <div class="tiles__overlay"></div>
                    <div class="tiles__content">
                        <h3 class="tiles__heading">Featured tile</h3>
                        <p class="tiles__description">This tile uses -featured to span 2×2</p>
                        <div class="tiles__actions">
                            <a href="#" class="button -outline">Learn More</a>
                        </div>
                    </div>
                </div>

                <div class="tiles__tile">
                    <div class="tiles__media">
                        <img src="https://images.unsplash.com/photo-1579546929518-9e396f3cc809?w=400&h=400&fit=crop" alt="">
                    </div>
                </div>
            </div>

            <!-- 
                3-column grid with staggered -short and -fill modifiers
                -fill spans 2 grid rows, -short spans 1 row: 

                Grid rows:    Col 1      Col 2      Col 3
                Row 1:      [fill-top] [short]  [fill-top]
                Row 2:      [fill-bot] [fill-top] [fill-bot]
                Row 3:      [short] [fill-bot] [short]
            -->

            <h2 class="tiles__heading">Staggered</h2>
            <div class="tiles__set -thirds -staggered">
                <!-- Tile order: fill, short, fill, fill, short, short -->
                <div class="tiles__tile -fill">
                    <div class="tiles__media">
                        <img src="https://images.unsplash.com/photo-1557683316-973673baf926?w=400&h=600&fit=crop" alt="">
                    </div>
                </div>

                <div class="tiles__tile -short">
                    <div class="tiles__media">
                        <img src="https://images.unsplash.com/photo-1478760329108-5c3ed9d495a0?w=800&h=450&fit=crop" alt="">
                    </div>
                </div>

                <div class="tiles__tile -fill">
                    <div class="tiles__media">
                        <img src="https://images.unsplash.com/photo-1579546929518-9e396f3cc809?w=400&h=600&fit=crop" alt="">
                    </div>
                </div>

                <div class="tiles__tile -fill">
                    <div class="tiles__media">
                        <img src="https://images.unsplash.com/photo-1557682250-33bd709cbe85?w=800&h=450&fit=crop" alt="">
                    </div>
                </div>

                <div class="tiles__tile -short">
                    <div class="tiles__media">
                        <img src="https://images.unsplash.com/photo-1618005182384-a83a8bd57fbe?w=400&h=600&fit=crop" alt="">
                    </div>
                </div>

                <div class="tiles__tile -short">
                    <div class="tiles__media">
                        <img src="https://images.unsplash.com/photo-1614850523296-d8c1af93d400?w=800&h=450&fit=crop" alt="">
                    </div>
                </div>
            </div>
        </div>
    </div>
</section>
index.scss
@use "@imarc/pronto/resources/styles/imported" as *;

.tiles {
    $b: &;

    padding: 2rem 0;

    &__grid {
        --columns: 1;
        --gap: var(--root-gap, 1rem);

        display: grid;
        gap: var(--gap);
        grid-template-columns: repeat(var(--columns), 1fr);
        grid-auto-flow: dense;

        @include at(md) {
            --columns: 2;
        }

        @include at(lg) {
            --columns: 4;
        }
    }

    &__tile {
        background-color: var(--tile-bg, var(--color-gray-100, #f5f5f5));
        display: grid;
        overflow: hidden;
        position: relative;

        // Position for content tiles
        &.-has-content {
            align-items: end;
        }
    }

    &__media {
        height: 100%;
        left: 0;
        position: absolute;
        top: 0;
        width: 100%;

        img,
        video {
            height: 100%;
            object-fit: cover;
            width: 100%;
        }
    }

    &__content {
        display: flex;
        flex-direction: column;
        gap: 1.5rem;
        max-width: 32rem;
        padding: 2rem;
        position: relative;
        z-index: 1;
    }

    &__heading {
        color: inherit;
        font-family: var(--root-font-family-heading);
        font-size: clamp(2rem, 5vw, 3.5rem);
        font-weight: 700;
        line-height: 1.1;
        margin: 0;
    }

    &__description {
        line-height: 1.5;
        margin: 0;
    }

    &__actions {
        display: flex;
        flex-wrap: wrap;
        gap: 1rem;
        margin-block-start: 0.5rem;
    }

    // Dark theme for tiles with dark backgrounds
    &__tile.-dark {
        color: #fff;

        #{$b}__heading,
        #{$b}__description {
            color: inherit;
        }

        .button.-outline {
            border-color: currentColor;
            color: inherit;

            &:hover {
                background-color: #fff;
                border-color: #fff;
                color: #000;
            }
        }
    }

    // Light theme for tiles with light backgrounds
    &__tile.-light {
        color: var(--root-color, #333);
    }

    // Featured layout container
    &__grid.-featured {
        display: flex;
        flex-direction: column;
        gap: var(--gap);
    }

    // ==========================================================================
    // Tile Sets - Flexible grid layouts
    // 
    // Set modifiers define the column structure:
    //   -thirds  : 3-column grid at desktop (for 1/3 + 2/3 style layouts)
    //   -halves  : 4-column grid at desktop (for 50/50 style layouts)
    //
    // Tile modifiers control spanning (work in any set):
    //   -featured : Spans 2 columns × 2 rows (large square)
    //   -wide     : Spans 2 columns × 1 row (horizontal banner)
    //   -tall     : Spans 1 column × 2 rows (vertical banner)
    //   (default) : 1 column × 1 row (small square)
    //
    // Tiles flow in DOM order with dense packing to fill gaps.
    // Add as many tiles as needed - the grid adapts automatically.
    // ==========================================================================
    &__set {
        container-type: inline-size;
        display: grid;
        gap: var(--gap);
        grid-auto-flow: dense;

        // Thirds: 3-column grid
        &.-thirds {
            --_tile-size: 100cqi; // Mobile: full width
            grid-template-columns: 1fr;

            @include at(md) {
                --_tile-size: calc((100cqi - var(--gap)) / 2);
                grid-template-columns: repeat(2, 1fr);
            }

            @include at(lg) {
                --_tile-size: calc((100cqi - var(--gap) * 2) / 3);
                grid-template-columns: repeat(3, 1fr);
            }

            // Staggered layout: uses -short (1 row) and -fill (2 rows) tiles
            // No explicit row heights - tiles define their own heights via aspect-ratio/min-height
            &.-staggered {
                // Short height = tile-width × 9/16
                --_short-height: calc(var(--_tile-size) * 0.5625);
                
                #{$b}__tile.-fill {
                    // Fill = 2 shorts + 1 gap
                    min-height: calc(var(--_short-height) * 2 + var(--gap));
                    aspect-ratio: auto;
                }
            }
        }

        // Halves: 4-column grid (good for 50/50 layouts with sub-divisions)
        &.-halves {
            --_tile-size: 100cqi; // Mobile: full width
            grid-template-columns: 1fr;

            @include at(md) {
                --_tile-size: calc((100cqi - var(--gap)) / 2);
                grid-template-columns: repeat(2, 1fr);
            }

            @include at(lg) {
                --_tile-size: calc((100cqi - var(--gap) * 3) / 4);
                grid-template-columns: repeat(4, 1fr);
            }
        }

        // =======================================================================
        // Tile modifiers - control spanning behavior
        // Small/Featured tiles use aspect-ratio: 1 for square
        // Wide/Tall tiles stretch to fill their grid area
        // =======================================================================

        // Default: 1×1 square tile
        #{$b}__tile {
            aspect-ratio: 1;
        }

        // Featured: Large 2×2 tile (still square)
        #{$b}__tile.-featured {
            grid-column: span 2;
            grid-row: span 2;
            aspect-ratio: 1;

            @include at(md, max-width) {
                grid-column: span 1;
                grid-row: span 1;
            }
        }

        // Wide: Horizontal 2×1 tile
        #{$b}__tile.-wide {
            grid-column: span 2;
            aspect-ratio: auto;
            align-self: stretch;
            // Minimum height ensures correct sizing when alone in a row
            min-height: var(--_tile-size, 200px);

            @include at(md, max-width) {
                grid-column: span 1;
                aspect-ratio: 1;
                min-height: unset;
            }
        }

        // Tall: Vertical 1×2 tile
        // Same width as a square tile, spans 2 rows
        #{$b}__tile.-tall {
            grid-row: span 2;
            aspect-ratio: auto;
            align-self: stretch;
            // Minimum height ensures correct sizing when determining grid flow
            min-height: calc(var(--_tile-size, 200px) * 2 + var(--gap));

            @include at(md, max-width) {
                grid-row: span 1;
                aspect-ratio: 1;
                min-height: unset;
            }
        }

        // Short: Compressed height tile (16:9 landscape)
        // Height = 9/16 of normal tile (56.25%)
        #{$b}__tile.-short {
            aspect-ratio: 16 / 9;

            @include at(md, max-width) {
                aspect-ratio: 1;
            }
        }

        // Fill: Spans 2 grid rows, pairs with -short tiles
        #{$b}__tile.-fill {
            grid-row: span 2;
            aspect-ratio: auto;
            align-self: stretch;

            @include at(md, max-width) {
                grid-row: span 1;
                aspect-ratio: 1;
            }
        }
    }

    // "View more" button - positioned within tile content
    &__more {
        align-items: center;
        align-self: flex-end;
        background: #fff;
        border-radius: 4px;
        border: none;
        box-shadow: 0 2px 4px rgba(0, 0, 0, 0.15);
        color: #0066ff;
        cursor: pointer;
        display: inline-flex;
        font-size: 0.875rem;
        font-weight: 500;
        gap: 0.5rem;
        margin: auto 2rem 2rem auto; // Push to bottom-right with tile padding
        padding: 0.5rem 1rem;
        position: relative;
        transition: box-shadow var(--root-duration-fast, 150ms) var(--root-ease-out);
        white-space: nowrap;
        z-index: 2;

        &:hover {
            box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
        }

        svg,
        .icon {
            fill: currentColor;
            height: 1em;
            width: 1em;
        }
    }

    // Gradient overlay for better text readability
    &__overlay {
        background: linear-gradient(
            to top,
            rgba(0, 0, 0, 0.7) 0%,
            rgba(0, 0, 0, 0.3) 50%,
            rgba(0, 0, 0, 0) 100%
        );
        inset: 0;
        position: absolute;
        z-index: 0;
    }
}