Design Technologist · AI-Assisted CSS Engineering

Adaptive product cards, from viewport breakpoints to self-aware widgets.

This showcase documents the complete assignment from raw semantic HTML through prompt engineering, human auditing, and a verified Adaptive Product Feature Card that uses @container and :has() instead of JavaScript-driven layout or theme state.

01Problem
02CSS Concepts
03Raw HTML
04AI Prompt
05Audit
06Final Result
07Verification
01

Why component space matters more than viewport space

The same product card must stack in a compact slot and stretch into a row when its own container permits it.

Before

Viewport media queries can make every card change at the same browser width, even when one card sits in a narrow sidebar and another sits in a wider content lane. That makes modular widgets brittle.

Modern approach

Each .card-container becomes an inline-size query container. The card checks its own checkbox state with :has(), so the dark palette belongs only to the card that was toggled.

Viewport-only breakpoints Shared theme state Injected JavaScript Unscoped selectors Fixed card heights
02

The CSS systems behind adaptive, state-aware card widgets

Six coordinated ideas let one repeated card structure respond to local space and local state.

03

The raw HTML before container-aware styling

The assignment starts with one identical product card repeated in a narrow sidebar and a wider main container.

before.html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Week 06 Lab: Adaptive Card Widget</title>
</head>
<body>

  <div class="workspace-grid">
    <!-- NARROW CONTAINER (Sidebar) -->
    <aside class="sidebar-wrapper">
      <div class="card-container">
        
        <article class="adaptive-card">
          <div class="adaptive-card__image-box">
            <img src="https://images.unsplash.com/photo-1542291026-7eec264c27ff?w=400" alt="Product Image" class="product-img">
          </div>
          <div class="adaptive-card__content">
            <h3 class="product-title">Retro Sneakers</h3>
            <p class="product-description">Premium classic athletic footwear engineered with modern perceptual cushioning.</p>
            <div class="adaptive-card__controls">
              <label class="toggle-control">
                <input type="checkbox" class="theme-checkbox">
                <span class="toggle-slider"></span>
                <span class="toggle-label">Dark Theme</span>
              </label>
            </div>
          </div>
        </article>

      </div>
    </aside>

    <!-- WIDE CONTAINER (Main Content) -->
    <main class="main-wrapper">
      <div class="card-container">
        
        <article class="adaptive-card">
          <div class="adaptive-card__image-box">
            <img src="https://images.unsplash.com/photo-1542291026-7eec264c27ff?w=400" alt="Product Image" class="product-img">
          </div>
          <div class="adaptive-card__content">
            <h3 class="product-title">Retro Sneakers</h3>
            <p class="product-description">Premium classic athletic footwear engineered with modern perceptual cushioning.</p>
            <div class="adaptive-card__controls">
              <label class="toggle-control">
                <input type="checkbox" class="theme-checkbox">
                <span class="toggle-slider"></span>
                <span class="toggle-label">Dark Theme</span>
              </label>
            </div>
          </div>
        </article>

      </div>
    </main>
  </div>

</body>
</html>

Browser defaults only

Workspace grid

Wide main container

Retro Sneakers

Product Image

Premium classic athletic footwear engineered with modern perceptual cushioning.

04

The structured prompt used to generate the stylesheet

The prompt turns the assignment blueprint into a strict CSS contract that forbids viewport-driven component sizing.

Layer 1 — Preserve the structure

Lock the supplied class names so the final CSS remains auditable against the assignment HTML.

Layer 2 — Register containers

Make each card wrapper the inline-size measurement context with container-type.

Layer 3 — Define the default card

Start with a stacked product card that works in the narrow sidebar before any query is met.

Layer 4 — Query local space

Use @container (min-width: 480px) to switch the card into a horizontal layout.

Layer 5 — Scope state with :has()

Use the checked child input to swap only the parent card's local theme variables.

Layer 6 — Audit the boundaries

Forbid JavaScript, helper classes, and viewport media queries for the component behavior.

AI prompt
Act as a senior CSS systems engineer. Generate a production-ready stylesheet for the supplied Adaptive Product Feature Card HTML without replacing its structural class system.

Implementation requirements:

1. Preserve the supplied workspace, wrapper, container, card, image, content, control, checkbox, slider, and label class names exactly so the CSS can be audited against the original HTML.

2. Register every `.card-container` as an inline-size query container with `container-type: inline-size;` so each card responds to its own available space rather than the viewport.

3. Create a default stacked `.adaptive-card` layout that works inside the narrow sidebar container, keeps the product image above the text, and avoids fixed heights or overflow-prone widths.

4. Add `@container (min-width: 480px)` rules that convert the card into a horizontal row with a clean 50/50 image-to-content distribution only when the individual card container is wide enough.

5. Use `.adaptive-card:has(.theme-checkbox:checked)` to swap local CSS custom properties for the checked card only, producing a scoped dark-theme palette without JavaScript or helper classes.

6. Style the checkbox toggle accessibly so the input remains keyboard focusable, the slider visually reflects the checked state, and the label stays readable in both card palettes.

7. Do not use viewport-based `@media` queries for the component sizing behavior, and do not add JavaScript, layout-state classes, frameworks, or generated markup.

8. Include concise comments that distinguish the container-query behavior from the state-aware `:has()` theme behavior.

Return only the complete CSS stylesheet.
05

Human audit of the generated CSS

The final code is accepted only when the selector scope, container behavior, and no-JavaScript boundary are visible in the CSS.

Container registration.card-container owns container-type: inline-size.
Local layout triggerThe row layout appears inside @container (min-width: 480px), not a viewport query.
State-scoped themeThe dark palette uses .adaptive-card:has(.theme-checkbox:checked).
No code bleedThe selector targets the card itself, so toggling the sidebar card does not affect the wide card.
Accessible toggleThe checkbox remains focusable and the slider reflects checked state through adjacent CSS.
No JavaScript dependencyThe widget uses native form state, CSS variables, and selectors only.
audited excerpt
.card-container {
  container-type: inline-size;
}

.adaptive-card {
  --card-bg: var(--adaptive-demo-card);
  --card-text: var(--adaptive-demo-card-text);

  display: flex;
  flex-direction: column;
}

.adaptive-card:has(.theme-checkbox:checked) {
  --card-bg: var(--adaptive-demo-card-dark);
  --card-text: var(--adaptive-demo-card-dark-text);
}

@container (min-width: 480px) {
  .adaptive-card {
    flex-direction: row;
    align-items: stretch;
  }

  .adaptive-card__image-box,
  .adaptive-card__content {
    flex: 1 1 50%;
  }
}
06

Final adaptive product widget

The sidebar card remains stacked while the wider card turns into a row, and each toggle controls only its own card.

Wide main container

Product Image

Retro Sneakers

Premium classic athletic footwear engineered with modern perceptual cushioning.

Container-owned layout

The narrow card keeps its column layout because its own container never reaches the query threshold.

Independent state

Each checkbox is read by its nearest parent card selector, so the other card remains unchanged.

No viewport breakpoint

The adaptive behavior follows component space instead of global browser width.

07

Technical verification before deployment

The widget is accepted only when the layout, state, scope, and accessibility checks all hold.

  1. Inspect .card-container and confirm its computed container-type is inline-size.
  2. Confirm the sidebar card remains stacked while the wide card displays as a horizontal row at desktop width.
  3. Resize the page and verify the row layout is caused by container width, not viewport media queries.
  4. Click the sidebar card's toggle and confirm only that card changes to the dark palette.
  5. Click the wide card's toggle and confirm it changes independently from the sidebar card.
  6. Search the assignment-specific CSS and confirm no viewport-based @media query controls the card sizing behavior.
  7. Search the page and confirm no local JavaScript was added for the toggle interaction.
  8. Confirm the state selector uses .adaptive-card:has(.theme-checkbox:checked).
  9. Use keyboard focus to reach each checkbox and verify a visible focus ring appears on the slider.
  10. Zoom to 200% and confirm product text, toggles, and image regions remain readable.
  11. Test near 320px and confirm the showcase has no unintended horizontal page scrolling.
  12. Verify the Section 02 concept cards open precise MDN references in a new tab.

AI drafted the CSS. Human auditing verified the container-query boundary, the :has() selector scope, and the no-JavaScript assignment rule.