Web Development  

Responsive vs Adaptive Websites: A Developer’s Guide (With Real Business Code Examples)

Overview

As full-stack engineers, we don't build websites for "screens"; we make them for users, devices, networks, and business goals.

In today's world, a single web app might be opened on:

  • An Android phone with 3G for a low price

  • The iPhone Pro Max on 5G

  • A portrait-oriented iPad

  • A laptop connected to a corporate VPN

  • A 4K monitor with a 125% browser zoom

In fact, "design for desktop only" died years ago, and two approaches dominate modern user interface design:

  • Responsive Design

  • Adaptive Design

Both aim to make experiences work on different devices, but they take very different engineering paths, and choosing the wrong one can cost performance, conversions, and maintainability.

Using real business code examples, I'll explain the differences in a practical way (not theory).

What is a Responsive Website?

 Responsive websites use a single codebase and a single layout system that scales fluidly across all screen sizes.

The system relies heavily on:

  • Flexible grids (CSS Grid / Flexbox)

  • Units of measurement (%, rem, vw)

  • Media queries in CSS

  • Responsive images

Responsive design is continuous, which means the layout changes as the viewport changes, not just at fixed sizes.

The benefits of responsive design for teams

In real business environments, responsive design provides:

  • Maintaining one UI system

  • Each page should have one URL (better SEO)

  • Analytics tracking made easier

  • Long-term reduction in frontend complexity

The Pros (Responsiveness)

  • Codebase as a whole

  • The best SEO (single URL)

  • Scales well with new devices

  • Maintainability over the long term

The Cons (Responsive)

  • If done incorrectly, it may load unnecessary resources

  • A thoughtful CSS architecture is required

  • To avoid CSS chaos, complex layouts require discipline

Most "responsive design performance issues" are not responsive design issues - they are loading problems (images, videos, scripts).

 

What is an Adaptive Website?

An adaptive website is based on the idea: "Rather than stretching one layout, we serve different layouts according to the device."

Instead of one fluid UI, adaptive design uses:

  • Layouts predefined for mobile, tablet, and desktop

  • Rendering on condition

  • JavaScript or server-side logic for device detection

  • Different CSS bundles are sometimes used

Adaptive design differs from responsive design in that it is discrete.

The meaning is:

  • There is no "flow" between sizes

  • "Modes" are switched between

The Pros (Adaptive)

  • Mobile performance potential is better

  • Layouts with pixel-perfect control

  • When device types are predictable, it works well

The Cons (Adaptive)

  • Costlier maintenance

  • Testing becomes more complex

  • New screen sizes aren't handled as smoothly

Tech lead note: Adaptive is a good fit when you own the device fleet. Example: iPad-only company portal.

Responsive vs Adaptive: Key Differences

Here's the practical comparison that matters in real life.

AreaResponsiveAdaptive
LayoutFluid scalingFixed layouts
EngineeringMostly CSS + design tokensJS/server detection + different UI
UXContinuous resizingSwitches between modes
SEOSimpleCan be tricky if split URLs/layout
MaintenanceLowerHigher
PerformanceDepends on asset optimisationCan be excellent if tailored

Real Business Code Examples

Let’s use an example we actually built: an e-commerce store for fashion.

This page contains the following information:

  • Navigation at the top

  • The hero's section

  • The sidebar for filters

  • A grid of products

  • Images that are optimised

Code Example One: Responsive Business Example (E-commerce Store)

Here's what we want:

  • Grid = 1 column on mobile: filters collapse

  • A sidebar with filters appears on a tablet, with a grid of two columns

  • Grid = 3–4 columns on a desktop

Here is a link to the live demo:

Below is the source code for this example, which is also available on my GitHub account:

The code can be explored, run locally, and used as a reference for your own work.

HTML 5 (index.html)

<!doctype html>
<html lang="en-gb">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Store (Responsive)</title>
    <link rel="stylesheet" href="css/styles.css" />
  </head>
  <body>
    <header class="topbar">
      <div class="container topbar__inner">
        <h1 class="brand">LuxuryStore</h1>

        <button class="cart-btn" id="cartBtn" aria-label="Open cart">
          Cart (<span id="cartCount">0</span>)
        </button>
      </div>
    </header>

    <section class="hero">
      <div class="container">
        <h2>Luxury Collection 2026</h2>
        <p>Premium clothing for Women, Men & Kids.</p>
        <button class="cta" id="shopNewArrivalsBtn">Shop New Arrivals</button>
      </div>
    </section>

    <main class="container layout" id="store">
      <aside class="filters">
        <h3>Filters</h3>

        <label>
          <input type="checkbox" name="category" value="women" /> Women
        </label>
        <label>
          <input type="checkbox" name="category" value="men" /> Men
        </label>
        <label>
          <input type="checkbox" name="category" value="kids" /> Kids
        </label>

        <hr />

        <label>
          <input type="checkbox" name="tag" value="premium" /> Premium
        </label>
        <label> <input type="checkbox" name="tag" value="new" /> New </label>
        <label>
          <input type="checkbox" name="tag" value="limited" /> Limited
        </label>

        <button class="btn-clear" id="clearFiltersBtn" type="button">
          Clear Filters
        </button>
      </aside>

      <section style="width: 100%" aria-label="Products section">
        <div class="products-toolbar">
          <input
            id="searchInput"
            class="search-input"
            type="text"
            placeholder="Search products..."
            autocomplete="off"
            aria-label="Search products"
          />

          <select
            id="sortSelect"
            class="sort-select"
            aria-label="Sort products"
          >
            <option value="default">Sort: Default</option>
            <option value="priceLow">Price: Low to High</option>
            <option value="priceHigh">Price: High to Low</option>
            <option value="nameAZ">Name: A → Z</option>
            <option value="nameZA">Name: Z → A</option>
          </select>
        </div>

        <div
          style="
            display: flex;
            align-items: center;
            justify-content: space-between;
            margin: 0 0 12px;
          "
        >
          <h3 style="margin: 0; font-size: 16px; opacity: 0.9">
            Browse Products
          </h3>
          <p style="margin: 0; font-size: 13px; opacity: 0.65">
            LuxuryStore • 2026 Collection
          </p>
        </div>

        <section class="products" id="products"></section>
        <div class="pagination" id="pagination"></div>
      </section>
    </main>

    <div class="cart-overlay" id="cartOverlay" aria-hidden="true">
      <div class="cart-panel" role="dialog" aria-modal="true" aria-label="Cart">
        <div class="cart-panel__header">
          <h3>Your Cart</h3>
          <button class="cart-close" id="cartCloseBtn" aria-label="Close cart">
            ✕
          </button>
        </div>

        <div id="cartItems" class="cart-items"></div>

        <div class="cart-panel__footer">
          <div class="cart-total">
            Total: <strong>£<span id="cartTotal">0</span></strong>
          </div>

          <div class="cart-actions">
            <button type="button" class="btn-secondary" id="clearCartBtn">
              Clear
            </button>
            <button type="button" class="btn-primary">Checkout</button>
          </div>
        </div>
      </div>
    </div>

    <script src="js/app.js"></script>
  </body>
</html>

CSS 3 (css/styles.css)

* {
  box-sizing: border-box;
}

:root {
  --bg: #070711;
  --panel: rgba(255, 255, 255, 0.06);
  --panel2: rgba(255, 255, 255, 0.09);
  --text: rgba(255, 255, 255, 0.92);
  --muted: rgba(255, 255, 255, 0.7);
  --line: rgba(255, 255, 255, 0.12);
  --gold: #f6d365;
  --gold2: #fda085;
  --btnBorder: rgba(255, 255, 255, 0.16);
  --btnGlass: rgba(255, 255, 255, 0.08);
  --btnGlass2: rgba(255, 255, 255, 0.12);
}

html {
  scroll-behavior: smooth;
}

body {
  margin: 0;
  font-family: system-ui, Arial, sans-serif;
  background:
    radial-gradient(
      1200px 600px at 20% -10%,
      rgba(246, 211, 101, 0.08),
      transparent 60%
    ),
    radial-gradient(
      1000px 500px at 90% 10%,
      rgba(253, 160, 133, 0.06),
      transparent 60%
    ),
    var(--bg);
  color: var(--text);
}

hr {
  border: 0;
  border-top: 1px solid rgba(255, 255, 255, 0.1);
  margin: 14px 0;
}

::selection {
  background: rgba(246, 211, 101, 0.35);
  color: #0b1020;
}

.container {
  width: min(1200px, 92%);
  margin: auto;
}

.topbar {
  position: sticky;
  top: 0;
  z-index: 100;
  background: rgba(0, 0, 0, 0.7);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--line);
}

.topbar__inner {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 14px 0;
}

.brand {
  margin: 0;
  font-weight: 900;
  letter-spacing: 0.3px;
}

.hero {
  padding: 44px 0 26px;
}

.hero h2 {
  margin: 0 0 10px;
  font-size: 28px;
  line-height: 1.15;
}

.hero p {
  margin: 0 0 16px;
  opacity: 0.82;
  max-width: 60ch;
}

.layout {
  display: grid;
  grid-template-columns: 1fr;
  gap: 18px;
  padding: 18px 0 28px;
}

.filters {
  background: var(--panel);
  border: 1px solid var(--line);
  padding: 16px;
  border-radius: 16px;
}

.filters h3 {
  margin: 0 0 12px;
  font-size: 16px;
}

.filters label {
  display: flex;
  gap: 10px;
  align-items: center;
  padding: 10px 10px;
  border-radius: 12px;
  cursor: pointer;
  user-select: none;
  transition: background 180ms ease;
  color: var(--text);
  font-weight: 600;
}

.filters label:hover {
  background: rgba(255, 255, 255, 0.06);
}

.filters input[type="checkbox"] {
  width: 18px;
  height: 18px;
  accent-color: #f6d365;
}

.btn-clear {
  margin-top: 12px;
  width: 100%;
  padding: 10px 12px;
  border-radius: 12px;
  border: 1px solid rgba(255, 255, 255, 0.14);
  background: rgba(255, 255, 255, 0.06);
  color: inherit;
  cursor: pointer;
  font-weight: 700;
  transition:
    transform 180ms ease,
    box-shadow 240ms ease;
}

.btn-clear:hover {
  transform: translateY(-1px);
  box-shadow: 0 14px 28px rgba(0, 0, 0, 0.35);
}

.btn-clear:active {
  transform: translateY(0px) scale(0.98);
}

.products-toolbar {
  display: flex;
  gap: 12px;
  align-items: center;
  justify-content: space-between;
  margin: 0 0 14px;
  flex-wrap: wrap;
}

.search-input {
  flex: 1;
  min-width: 220px;
  padding: 12px 14px;
  border-radius: 14px;
  border: 1px solid rgba(255, 255, 255, 0.14);
  background: rgba(255, 255, 255, 0.06);
  color: rgba(255, 255, 255, 0.92);
  outline: none;
  transition:
    box-shadow 200ms ease,
    border-color 200ms ease;
}

.search-input::placeholder {
  color: rgba(255, 255, 255, 0.55);
}

.search-input:focus {
  border-color: rgba(246, 211, 101, 0.45);
  box-shadow: 0 0 0 4px rgba(246, 211, 101, 0.12);
}

.sort-select {
  min-width: 220px;
  padding: 12px 14px;
  border-radius: 14px;
  border: 1px solid rgba(255, 255, 255, 0.14);
  background: rgba(255, 255, 255, 0.06);
  color: rgba(255, 255, 255, 0.92);
  outline: none;
  cursor: pointer;
  transition:
    box-shadow 200ms ease,
    border-color 200ms ease;
}

.sort-select:focus {
  border-color: rgba(246, 211, 101, 0.45);
  box-shadow: 0 0 0 4px rgba(246, 211, 101, 0.12);
}

.sort-select {
  background-color: rgba(255, 255, 255, 0.06) !important;
  color: rgba(255, 255, 255, 0.92) !important;
  border: 1px solid rgba(255, 255, 255, 0.14);
  appearance: none;
  -webkit-appearance: none;
  -moz-appearance: none;
}

.sort-select option {
  background: #0b1020;
  color: rgba(255, 255, 255, 0.92);
}

.sort-select optgroup {
  background: #0b1020;
  color: rgba(255, 255, 255, 0.92);
}

.sort-select {
  padding-right: 44px;
  background-image:
    linear-gradient(45deg, transparent 50%, rgba(255, 255, 255, 0.72) 50%),
    linear-gradient(135deg, rgba(255, 255, 255, 0.72) 50%, transparent 50%);
  background-position:
    calc(100% - 18px) 55%,
    calc(100% - 12px) 55%;
  background-size:
    6px 6px,
    6px 6px;
  background-repeat: no-repeat;
}

.products {
  display: grid;
  grid-template-columns: 1fr;
  gap: 14px;
}

.card {
  position: relative;
  border-radius: 16px;
  overflow: hidden;
  border: 1px solid var(--line);
  background: var(--panel);
  transition:
    transform 200ms ease,
    box-shadow 220ms ease,
    border-color 220ms ease;
}

.card:hover {
  transform: translateY(-3px);
  border-color: rgba(246, 211, 101, 0.22);
  box-shadow: 0 18px 40px rgba(0, 0, 0, 0.45);
}

.card img {
  width: 100%;
  display: block;
  height: 280px;
  object-fit: cover;
}

.card__body {
  padding: 14px;
}

.card__body h4 {
  margin: 0 0 6px;
  font-size: 16px;
  letter-spacing: 0.2px;
}

.price {
  margin: 0;
  font-weight: 900;
  font-size: 18px;
}

.stock {
  margin: 8px 0 0;
  opacity: 0.85;
  font-size: 14px;
}

.badge-row {
  position: absolute;
  top: 12px;
  left: 12px;
  display: flex;
  gap: 8px;
  z-index: 2;
}

.badge {
  padding: 6px 10px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 900;
  letter-spacing: 0.3px;
  box-shadow: 0 12px 24px rgba(0, 0, 0, 0.25);
  border: 1px solid rgba(255, 255, 255, 0.14);
  backdrop-filter: blur(10px);
}

.badge--premium {
  background: linear-gradient(
    135deg,
    rgba(246, 211, 101, 0.95),
    rgba(253, 160, 133, 0.95)
  );
  color: #0b1020;
}

.badge--new {
  background: rgba(0, 0, 0, 0.32);
  color: rgba(255, 255, 255, 0.92);
}

.badge--limited {
  background: rgba(255, 80, 80, 0.18);
  color: rgba(255, 255, 255, 0.92);
  border-color: rgba(255, 80, 80, 0.32);
}

.cart-btn {
  position: relative;
  padding: 10px 16px;
  border-radius: 999px;
  border: 1px solid var(--btnBorder);
  background: linear-gradient(
    180deg,
    rgba(255, 255, 255, 0.12),
    rgba(255, 255, 255, 0.06)
  );
  color: var(--text);
  font-weight: 700;
  letter-spacing: 0.3px;
  cursor: pointer;
  transition:
    transform 180ms ease,
    box-shadow 220ms ease,
    border-color 220ms ease;
  box-shadow: 0 10px 26px rgba(0, 0, 0, 0.28);
  backdrop-filter: blur(10px);
}

.cart-btn:hover {
  transform: translateY(-1px);
  border-color: rgba(246, 211, 101, 0.45);
  box-shadow:
    0 16px 38px rgba(0, 0, 0, 0.34),
    0 0 0 4px rgba(246, 211, 101, 0.1);
}

.cart-btn:active {
  transform: translateY(0px) scale(0.98);
}

.cart-btn:focus-visible {
  outline: none;
  box-shadow:
    0 0 0 4px rgba(246, 211, 101, 0.22),
    0 12px 28px rgba(0, 0, 0, 0.3);
}

.cart-btn #cartCount {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 22px;
  height: 22px;
  margin-left: 6px;
  padding: 0 6px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 900;
  color: #0b1020;
  background: linear-gradient(135deg, var(--gold), var(--gold2));
  box-shadow: 0 8px 18px rgba(0, 0, 0, 0.25);
}

.add-to-cart {
  width: 100%;
  margin-top: 10px;
  padding: 11px 14px;
  border-radius: 14px;
  border: 1px solid rgba(246, 211, 101, 0.28);
  background: linear-gradient(
    135deg,
    rgba(246, 211, 101, 0.92),
    rgba(253, 160, 133, 0.92)
  );
  color: #0b1020;
  font-weight: 900;
  letter-spacing: 0.4px;
  cursor: pointer;
  transition:
    transform 160ms ease,
    box-shadow 200ms ease,
    filter 200ms ease;
  box-shadow: 0 14px 26px rgba(0, 0, 0, 0.28);
}

.add-to-cart:hover {
  transform: translateY(-2px);
  filter: brightness(1.02);
  box-shadow:
    0 18px 34px rgba(0, 0, 0, 0.34),
    0 0 0 4px rgba(246, 211, 101, 0.14);
}

.add-to-cart:active {
  transform: translateY(-1px) scale(0.99);
}

.add-to-cart:focus-visible {
  outline: none;
  box-shadow:
    0 0 0 4px rgba(246, 211, 101, 0.28),
    0 16px 30px rgba(0, 0, 0, 0.3);
}

.cta {
  margin-top: 14px;
  padding: 12px 18px;
  border-radius: 999px;
  border: 1px solid rgba(246, 211, 101, 0.35);
  background: linear-gradient(
    135deg,
    rgba(246, 211, 101, 0.95),
    rgba(253, 160, 133, 0.92)
  );
  color: #0b1020;
  font-weight: 900;
  letter-spacing: 0.35px;
  cursor: pointer;
  transition:
    transform 180ms ease,
    box-shadow 240ms ease,
    filter 220ms ease;
  box-shadow: 0 18px 35px rgba(0, 0, 0, 0.32);
}

.cta:hover {
  transform: translateY(-2px);
  filter: brightness(1.03);
  box-shadow:
    0 22px 45px rgba(0, 0, 0, 0.4),
    0 0 0 4px rgba(246, 211, 101, 0.16);
}

.cta:active {
  transform: translateY(-1px) scale(0.99);
}

.cta:focus-visible {
  outline: none;
  box-shadow:
    0 0 0 4px rgba(246, 211, 101, 0.28),
    0 18px 35px rgba(0, 0, 0, 0.32);
}

.cart-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.55);
  display: none;
  align-items: flex-end;
  justify-content: flex-end;
  z-index: 999;
}

.cart-overlay.open {
  display: flex;
}

.cart-panel {
  width: min(420px, 100%);
  height: 100%;
  background: #0b1020;
  color: var(--text);
  border-left: 1px solid rgba(255, 255, 255, 0.12);
  padding: 16px;
  display: flex;
  flex-direction: column;
}

.cart-panel__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.cart-close {
  background: transparent;
  border: 0;
  color: inherit;
  font-size: 20px;
  cursor: pointer;
}

.cart-items {
  flex: 1;
  overflow: auto;
  margin-top: 12px;
  padding-right: 6px;
}

.cart-items::-webkit-scrollbar {
  width: 8px;
}

.cart-items::-webkit-scrollbar-thumb {
  background: rgba(255, 255, 255, 0.12);
  border-radius: 999px;
}

.cart-item {
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 14px;
  padding: 12px;
  margin-bottom: 10px;
  background: rgba(255, 255, 255, 0.06);
}

.cart-item__meta {
  opacity: 0.75;
  margin-top: 4px;
  font-size: 13px;
}

.cart-item__controls {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-top: 10px;
  flex-wrap: wrap;
}

.qty-btn {
  width: 36px;
  height: 34px;
  border-radius: 10px;
  border: 1px solid rgba(255, 255, 255, 0.14);
  background: rgba(255, 255, 255, 0.08);
  color: inherit;
  cursor: pointer;
}

.qty {
  min-width: 22px;
  text-align: center;
}

.remove-btn {
  margin-left: auto;
  padding: 8px 10px;
  border-radius: 10px;
  border: 1px solid rgba(255, 255, 255, 0.14);
  background: rgba(255, 255, 255, 0.06);
  color: inherit;
  cursor: pointer;
  transition:
    transform 160ms ease,
    box-shadow 200ms ease;
}

.remove-btn:hover {
  transform: translateY(-1px);
  box-shadow: 0 14px 26px rgba(0, 0, 0, 0.35);
}

.cart-panel__footer {
  border-top: 1px solid rgba(255, 255, 255, 0.12);
  padding-top: 12px;
}

.cart-total {
  display: flex;
  justify-content: space-between;
  margin-bottom: 10px;
}

.cart-actions {
  display: flex;
  gap: 10px;
}

.btn-primary,
.btn-secondary {
  flex: 1;
  padding: 10px 12px;
  border-radius: 12px;
  cursor: pointer;
  border: 1px solid rgba(255, 255, 255, 0.14);
  color: inherit;
  font-weight: 800;
}

.btn-primary {
  background: rgba(255, 255, 255, 0.12);
}

.btn-secondary {
  background: rgba(255, 255, 255, 0.06);
}

.cart-empty {
  opacity: 0.75;
  padding: 18px 8px;
}

.pagination {
  display: flex;
  gap: 8px;
  justify-content: center;
  align-items: center;
  margin-top: 16px;
  flex-wrap: wrap;
}

.page-btn {
  min-width: 40px;
  height: 40px;
  padding: 0 12px;
  border-radius: 999px;
  border: 1px solid rgba(255, 255, 255, 0.14);
  background: rgba(255, 255, 255, 0.06);
  color: rgba(255, 255, 255, 0.92);
  cursor: pointer;
  font-weight: 800;
  transition:
    transform 160ms ease,
    box-shadow 220ms ease;
}

.page-btn:hover {
  transform: translateY(-1px);
  box-shadow: 0 14px 26px rgba(0, 0, 0, 0.35);
}

.page-btn.active {
  color: #0b1020;
  background: linear-gradient(
    135deg,
    rgba(246, 211, 101, 0.95),
    rgba(253, 160, 133, 0.92)
  );
  border-color: rgba(246, 211, 101, 0.4);
}

.page-btn:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}

@media (min-width: 768px) {
  .layout {
    grid-template-columns: 250px 1fr;
  }

  .products {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (min-width: 1100px) {
  .products {
    grid-template-columns: repeat(3, 1fr);
  }

  .hero h2 {
    font-size: 42px;
  }
}

@media (max-width: 480px) {
  .cart-btn {
    padding: 9px 12px;
    font-size: 14px;
  }

  .card img {
    height: 240px;
  }
}

JavaScript (js/app.js)

const money = (n) => Number(n || 0).toFixed(2);

const loadCart = () => {
  try {
    return JSON.parse(localStorage.getItem("luxury_cart") || "[]");
  } catch {
    return [];
  }
};

const saveCart = (cart) => {
  localStorage.setItem("luxury_cart", JSON.stringify(cart));
};

let cart = loadCart();
let products = [];

let activeQuickTag = null;
let currentPage = 1;
const pageSize = 9;

const productsEl = document.getElementById("products");
const paginationEl = document.getElementById("pagination");

const cartBtn = document.getElementById("cartBtn");
const cartOverlay = document.getElementById("cartOverlay");
const cartCloseBtn = document.getElementById("cartCloseBtn");

const cartItemsEl = document.getElementById("cartItems");
const cartCountEl = document.getElementById("cartCount");
const cartTotalEl = document.getElementById("cartTotal");

const clearCartBtn = document.getElementById("clearCartBtn");
const clearFiltersBtn = document.getElementById("clearFiltersBtn");

const filterCheckboxes = document.querySelectorAll(
  ".filters input[type='checkbox']"
);
const searchInput = document.getElementById("searchInput");
const sortSelect = document.getElementById("sortSelect");
const shopNewArrivalsBtn = document.getElementById("shopNewArrivalsBtn");

function badgeClass(name) {
  const v = (name || "").toLowerCase();
  if (v === "premium") return "badge badge--premium";
  if (v === "new") return "badge badge--new";
  if (v === "limited") return "badge badge--limited";
  return "badge";
}

function renderProducts(list) {
  if (!productsEl) return;

  productsEl.innerHTML = list
    .map((p) => {
      const tagsCsv = (p.tags || []).join(",");
      const badges = (p.badges || [])
        .map((b) => `<span class="${badgeClass(b)}">${b}</span>`)
        .join("");

      return `
        <article class="card"
          data-id="${p.id}"
          data-title="${p.title}"
          data-price="${p.price}"
          data-category="${p.category}"
          data-tags="${tagsCsv}"
          data-stock="${p.stock}"
        >
          ${badges ? `<div class="badge-row">${badges}</div>` : ""}

          <img src="${p.image}" alt="${p.alt || p.title}" />
          <div class="card__body">
            <h4>${p.title}</h4>
            <p class="price">£${p.price}</p>
            <p class="stock">Only <strong>${p.stock}</strong> left</p>
            <button class="add-to-cart">Add to Cart</button>
          </div>
        </article>
      `;
    })
    .join("");
}

function renderPagination(totalItems) {
  if (!paginationEl) return;

  const totalPages = Math.max(1, Math.ceil(totalItems / pageSize));
  if (currentPage > totalPages) currentPage = totalPages;

  let html = "";

  html += `<button class="page-btn" data-page="${currentPage - 1}" ${
    currentPage === 1 ? "disabled" : ""
  }>‹</button>`;

  for (let p = 1; p <= totalPages; p++) {
    html += `<button class="page-btn ${p === currentPage ? "active" : ""}" data-page="${p}">${p}</button>`;
  }

  html += `<button class="page-btn" data-page="${currentPage + 1}" ${
    currentPage === totalPages ? "disabled" : ""
  }>›</button>`;

  paginationEl.innerHTML = html;
}

function addToCart(product) {
  const card = document.querySelector(`.card[data-id="${product.id}"]`);
  const stock = Number(card?.dataset.stock || 9999);

  const existing = cart.find((x) => x.id === product.id);
  const currentQty = existing?.qty || 0;

  if (currentQty >= stock) {
    alert(`Sorry! Only ${stock} available for "${product.title}".`);
    return;
  }

  if (existing) existing.qty += 1;
  else cart.push({ ...product, qty: 1 });

  saveCart(cart);
  renderCart();
}

function removeFromCart(id) {
  cart = cart.filter((x) => x.id !== id);
  saveCart(cart);
  renderCart();
}

function changeQty(id, delta) {
  const item = cart.find((x) => x.id === id);
  if (!item) return;

  item.qty += delta;

  if (item.qty <= 0) {
    removeFromCart(id);
    return;
  }

  const card = document.querySelector(`.card[data-id="${id}"]`);
  const stock = Number(card?.dataset.stock || 9999);
  if (item.qty > stock) item.qty = stock;

  saveCart(cart);
  renderCart();
}

function clearCart() {
  cart = [];
  saveCart(cart);
  renderCart();
}

function renderCart() {
  const totalQty = cart.reduce((sum, x) => sum + x.qty, 0);
  const totalPrice = cart.reduce((sum, x) => sum + x.qty * x.price, 0);

  cartCountEl.textContent = totalQty;
  cartTotalEl.textContent = money(totalPrice);

  if (cart.length === 0) {
    cartItemsEl.innerHTML = `<p class="cart-empty">Your cart is empty.</p>`;
    return;
  }

  cartItemsEl.innerHTML = cart
    .map(
      (item) => `
      <div class="cart-item">
        <div class="cart-item__info">
          <strong>${item.title}</strong>
          <div class="cart-item__meta">£${money(item.price)} each</div>
        </div>

        <div class="cart-item__controls">
          <button class="qty-btn" data-action="dec" data-id="${item.id}">−</button>
          <span class="qty">${item.qty}</span>
          <button class="qty-btn" data-action="inc" data-id="${item.id}">+</button>
          <button class="remove-btn" data-action="remove" data-id="${item.id}">
            Remove
          </button>
        </div>
      </div>
    `
    )
    .join("");
}

function getSelectedFilters() {
  const selectedCategories = Array.from(
    document.querySelectorAll('input[name="category"]:checked')
  ).map((x) => x.value);

  const selectedTags = Array.from(
    document.querySelectorAll('input[name="tag"]:checked')
  ).map((x) => x.value);

  return { selectedCategories, selectedTags };
}

function matchesFilters(product, filters) {
  const categoryOk =
    filters.selectedCategories.length === 0 ||
    filters.selectedCategories.includes(product.category);

  const tags = product.tags || [];

  const tagsOk =
    filters.selectedTags.length === 0 ||
    filters.selectedTags.every((t) => tags.includes(t));

  const quickOk = !activeQuickTag || tags.includes(activeQuickTag);

  return categoryOk && tagsOk && quickOk;
}

function applyFilters() {
  const filters = getSelectedFilters();
  const search = (searchInput?.value || "").trim().toLowerCase();
  const sort = sortSelect?.value || "default";

  let visible = products.filter((p) => matchesFilters(p, filters));

  if (search) {
    visible = visible.filter((p) => p.title.toLowerCase().includes(search));
  }

  visible.sort((a, b) => {
    if (sort === "priceLow") return a.price - b.price;
    if (sort === "priceHigh") return b.price - a.price;
    if (sort === "nameAZ") return a.title.localeCompare(b.title);
    if (sort === "nameZA") return b.title.localeCompare(a.title);
    return 0;
  });

  const totalItems = visible.length;
  const totalPages = Math.max(1, Math.ceil(totalItems / pageSize));
  if (currentPage > totalPages) currentPage = totalPages;

  const start = (currentPage - 1) * pageSize;
  const paged = visible.slice(start, start + pageSize);

  renderProducts(paged);
  renderPagination(totalItems);
}

function openCart() {
  cartOverlay.classList.add("open");
  cartOverlay.setAttribute("aria-hidden", "false");
}

function closeCart() {
  cartOverlay.classList.remove("open");
  cartOverlay.setAttribute("aria-hidden", "true");
}

function showNewArrivals() {
  filterCheckboxes.forEach((cb) => (cb.checked = false));
  if (searchInput) searchInput.value = "";
  if (sortSelect) sortSelect.value = "default";

  activeQuickTag = "new";
  currentPage = 1;

  applyFilters();

  document.getElementById("products")?.scrollIntoView({
    behavior: "smooth",
    block: "start",
  });
}

async function loadProducts() {
  try {
    const res = await fetch("data/products.json");
    products = await res.json();
  } catch (e) {
    console.error("Failed to load products.json", e);
    products = [];
  }
}

productsEl.addEventListener("click", (e) => {
  const btn = e.target.closest(".add-to-cart");
  if (!btn) return;

  const card = btn.closest(".card");
  if (!card) return;

  const product = {
    id: card.dataset.id,
    title: card.dataset.title,
    price: Number(card.dataset.price || 0),
  };

  addToCart(product);
  openCart();
});

cartItemsEl.addEventListener("click", (e) => {
  const actionBtn = e.target.closest("[data-action]");
  if (!actionBtn) return;

  const action = actionBtn.dataset.action;
  const id = actionBtn.dataset.id;

  if (action === "remove") removeFromCart(id);
  if (action === "inc") changeQty(id, +1);
  if (action === "dec") changeQty(id, -1);
});

paginationEl?.addEventListener("click", (e) => {
  const btn = e.target.closest(".page-btn");
  if (!btn || btn.disabled) return;

  currentPage = Number(btn.dataset.page || 1);
  applyFilters();

  document.getElementById("products")?.scrollIntoView({
    behavior: "smooth",
    block: "start",
  });
});

cartBtn.addEventListener("click", openCart);
cartCloseBtn.addEventListener("click", closeCart);

cartOverlay.addEventListener("click", (e) => {
  if (e.target === cartOverlay) closeCart();
});

document.addEventListener("keydown", (e) => {
  if (e.key === "Escape") closeCart();
});

clearCartBtn.addEventListener("click", clearCart);

filterCheckboxes.forEach((cb) =>
  cb.addEventListener("change", () => {
    activeQuickTag = null;
    currentPage = 1;
    applyFilters();
  })
);

clearFiltersBtn.addEventListener("click", () => {
  filterCheckboxes.forEach((cb) => (cb.checked = false));
  if (searchInput) searchInput.value = "";
  if (sortSelect) sortSelect.value = "default";

  activeQuickTag = null;
  currentPage = 1;

  applyFilters();
});

if (searchInput) {
  searchInput.addEventListener("input", () => {
    activeQuickTag = null;
    currentPage = 1;
    applyFilters();
  });
}

if (sortSelect) {
  sortSelect.addEventListener("change", () => {
    activeQuickTag = null;
    currentPage = 1;
    applyFilters();
  });
}

if (shopNewArrivalsBtn) {
  shopNewArrivalsBtn.addEventListener("click", showNewArrivals);
}

(async function init() {
  renderCart();
  await loadProducts();
  applyFilters();
})();

JSON (data/products.json)

[
  {
    "id": "dress-1",
    "title": "Luxury Dress",
    "price": 89,
    "category": "women",
    "tags": ["premium", "new"],
    "stock": 6,
    "badges": ["Premium", "New"],
    "image": "https://picsum.photos/500/650?1",
    "alt": "Luxury Dress"
  },
  {
    "id": "kurta-1",
    "title": "Men Kurta",
    "price": 49,
    "category": "men",
    "tags": ["premium"],
    "stock": 10,
    "badges": ["Premium"],
    "image": "https://picsum.photos/500/650?2",
    "alt": "Men Kurta"
  },
  {
    "id": "kids-1",
    "title": "Kids Outfit",
    "price": 29,
    "category": "kids",
    "tags": ["new"],
    "stock": 12,
    "badges": ["New"],
    "image": "https://picsum.photos/500/650?3",
    "alt": "Kids Outfit"
  },
  {
    "id": "abaya-1",
    "title": "Luxury Abaya",
    "price": 99,
    "category": "women",
    "tags": ["premium", "limited"],
    "stock": 4,
    "badges": ["Premium", "Limited"],
    "image": "https://picsum.photos/500/650?4",
    "alt": "Luxury Abaya"
  },
  {
    "id": "heels-1",
    "title": "Gold Heels",
    "price": 75,
    "category": "women",
    "tags": ["premium", "new"],
    "stock": 5,
    "badges": ["Premium", "New"],
    "image": "https://picsum.photos/500/650?5",
    "alt": "Gold Heels"
  },
  {
    "id": "women-bag-1",
    "title": "Designer Handbag",
    "price": 149,
    "category": "women",
    "tags": ["premium"],
    "stock": 8,
    "badges": ["Premium"],
    "image": "https://picsum.photos/500/650?6",
    "alt": "Designer Handbag"
  },
  {
    "id": "sherwani-1",
    "title": "Premium Sherwani",
    "price": 129,
    "category": "men",
    "tags": ["premium", "limited"],
    "stock": 3,
    "badges": ["Premium", "Limited"],
    "image": "https://picsum.photos/500/650?7",
    "alt": "Premium Sherwani"
  },
  {
    "id": "men-jacket-1",
    "title": "Luxury Jacket",
    "price": 119,
    "category": "men",
    "tags": ["premium", "new"],
    "stock": 7,
    "badges": ["Premium", "New"],
    "image": "https://picsum.photos/500/650?8",
    "alt": "Luxury Jacket"
  },
  {
    "id": "watch-1",
    "title": "Gold Watch",
    "price": 199,
    "category": "men",
    "tags": ["premium", "limited"],
    "stock": 2,
    "badges": ["Premium", "Limited"],
    "image": "https://picsum.photos/500/650?9",
    "alt": "Gold Watch"
  },
  {
    "id": "kids-coat-1",
    "title": "Kids Winter Coat",
    "price": 45,
    "category": "kids",
    "tags": ["premium"],
    "stock": 9,
    "badges": ["Premium"],
    "image": "https://picsum.photos/500/650?10",
    "alt": "Kids Winter Coat"
  },
  {
    "id": "kids-shoes-1",
    "title": "Kids Sneakers",
    "price": 25,
    "category": "kids",
    "tags": [],
    "stock": 20,
    "badges": [],
    "image": "https://picsum.photos/500/650?11",
    "alt": "Kids Sneakers"
  },
  {
    "id": "kids-party-1",
    "title": "Kids Party Outfit",
    "price": 39,
    "category": "kids",
    "tags": ["premium", "new"],
    "stock": 6,
    "badges": ["Premium", "New"],
    "image": "https://picsum.photos/500/650?12",
    "alt": "Kids Party Outfit"
  },
  {
    "id": "women-coat-1",
    "title": "Women Winter Coat",
    "price": 110,
    "category": "women",
    "tags": ["limited"],
    "stock": 4,
    "badges": ["Limited"],
    "image": "https://picsum.photos/500/650?13",
    "alt": "Women Winter Coat"
  },
  {
    "id": "men-shoes-1",
    "title": "Leather Shoes",
    "price": 85,
    "category": "men",
    "tags": [],
    "stock": 14,
    "badges": [],
    "image": "https://picsum.photos/500/650?14",
    "alt": "Leather Shoes"
  },
  {
    "id": "perfume-1",
    "title": "Luxury Perfume",
    "price": 65,
    "category": "women",
    "tags": ["premium"],
    "stock": 11,
    "badges": ["Premium"],
    "image": "https://picsum.photos/500/650?15",
    "alt": "Luxury Perfume"
  }
]

Code Example Two: Adaptive Business Example (Device-Specific Mode)

It is useful to use adaptive when:

  • Mobile experiences must be extremely light

  • Sending different bundles/resources

  • Different layouts must be designed (not just resized)

Travel booking, banking, or large dashboards are examples.

Here is a link to the live demo:

Below is the source code for this example, which is also available on my GitHub account:

The code can be explored, run locally, and used as a reference for your own work.

HTML 5 (index.html)

<!doctype html>
<html lang="en-gb">
  <head>
    <meta charset="UTF-8" />
    <meta
      name="viewport"
      content="width=device-width,initial-scale=1,viewport-fit=cover"
    />
    <title>LuxuryStore (Adaptive)</title>
    <link rel="stylesheet" id="adaptive-style" />
    <meta
      name="description"
      content="Adaptive store: different bundles and layouts for mobile vs desktop."
    />
  </head>
  <body>
    <div id="app" class="app"></div>
    <script src="js/adaptive.js" defer></script>
  </body>
</html>

CSS 3

css/desktop.css

:root {
  --bg: #070711;
  --panel: rgba(255, 255, 255, 0.06);
  --text: rgba(255, 255, 255, 0.92);
  --muted: rgba(255, 255, 255, 0.72);
  --line: rgba(255, 255, 255, 0.12);
  --gold: #f6d365;
  --gold2: #fda085;
}

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  font-family:
    system-ui,
    -apple-system,
    Segoe UI,
    Roboto,
    Arial,
    sans-serif;
  background: var(--bg);
  color: var(--text);
}

.app {
  min-height: 100vh;
}

.topbar {
  position: sticky;
  top: 0;
  z-index: 10;
  background: rgba(0, 0, 0, 0.65);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--line);
  padding: 14px 0 12px;
}

.topbar__inner {
  width: min(1200px, 92%);
  margin: 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 18px;
}

.brand__name {
  font-weight: 900;
  letter-spacing: 0.5px;
}
.brand__tag {
  color: var(--muted);
  font-size: 12px;
  margin-top: 2px;
}

.top-actions {
  display: flex;
  align-items: center;
  gap: 14px;
}

.search {
  display: grid;
  grid-template-columns: 360px 220px;
  gap: 12px;
  align-items: center;
}

.search__input {
  padding: 12px 12px;
  border-radius: 14px;
  border: 1px solid var(--line);
  background: var(--panel);
  color: var(--text);
  outline: none;
}

.search__input::placeholder {
  color: rgba(255, 255, 255, 0.55);
}

.sort-select {
  padding: 12px 12px;
  border-radius: 14px;
  border: 1px solid var(--line);
  background: var(--panel);
  color: var(--text);
  cursor: pointer;
  outline: none;
  appearance: none;
  -webkit-appearance: none;
  -moz-appearance: none;
}

.sort-select option {
  background: #0b1020;
  color: var(--text);
}

.cart-btn {
  padding: 10px 16px;
  border-radius: 999px;
  border: 1px solid rgba(255, 255, 255, 0.16);
  background: linear-gradient(
    180deg,
    rgba(255, 255, 255, 0.12),
    rgba(255, 255, 255, 0.06)
  );
  color: var(--text);
  font-weight: 800;
  cursor: pointer;
}

.badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 22px;
  height: 22px;
  margin-left: 8px;
  padding: 0 8px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 900;
  color: #0b1020;
  background: linear-gradient(135deg, var(--gold), var(--gold2));
}

.layout {
  width: min(1200px, 92%);
  margin: 18px auto 28px;
  display: grid;
  grid-template-columns: 280px 1fr;
  gap: 18px;
}

.filters {
  background: var(--panel);
  border: 1px solid var(--line);
  padding: 16px;
  border-radius: 16px;
  position: sticky;
  top: 86px;
  height: fit-content;
}

.filters__title {
  margin: 0 0 12px;
  font-size: 16px;
}

.filter-group h3 {
  margin: 12px 0 10px;
  font-size: 14px;
  color: var(--muted);
}

.check {
  display: flex;
  gap: 10px;
  align-items: center;
  padding: 10px 10px;
  border-radius: 12px;
  cursor: pointer;
  user-select: none;
  border: 1px solid rgba(255, 255, 255, 0.08);
  margin-bottom: 8px;
}

.check input {
  width: 18px;
  height: 18px;
  accent-color: var(--gold);
}

.filters-actions {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
  margin-top: 12px;
}

.btn-primary,
.btn-secondary {
  padding: 12px 12px;
  border-radius: 14px;
  border: 1px solid rgba(255, 255, 255, 0.14);
  cursor: pointer;
  font-weight: 900;
}

.btn-primary {
  background: linear-gradient(
    135deg,
    rgba(246, 211, 101, 0.95),
    rgba(253, 160, 133, 0.92)
  );
  color: #0b1020;
}

.btn-secondary {
  background: rgba(255, 255, 255, 0.06);
  color: var(--text);
}

.main {
  min-width: 0;
}

.hero {
  padding: 18px 16px;
  border: 1px solid var(--line);
  background: var(--panel);
  border-radius: 18px;
  margin-bottom: 14px;
}

.hero h1 {
  margin: 0 0 6px;
  font-size: 28px;
}

.hero p {
  margin: 0 0 12px;
  color: var(--muted);
}

.hero__actions {
  display: flex;
  gap: 10px;
}

.cta {
  padding: 12px 16px;
  border-radius: 999px;
  border: 1px solid rgba(246, 211, 101, 0.35);
  background: linear-gradient(
    135deg,
    rgba(246, 211, 101, 0.95),
    rgba(253, 160, 133, 0.92)
  );
  color: #0b1020;
  font-weight: 900;
  cursor: pointer;
}

.secondary {
  padding: 12px 16px;
  border-radius: 999px;
  border: 1px solid rgba(255, 255, 255, 0.16);
  background: rgba(255, 255, 255, 0.06);
  color: var(--text);
  font-weight: 900;
  cursor: pointer;
}

.products {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 14px;
}

.card {
  border-radius: 16px;
  overflow: hidden;
  border: 1px solid var(--line);
  background: var(--panel);
  position: relative;
}

.card img {
  width: 100%;
  display: block;
  height: 240px;
  object-fit: cover;
}

.card__body {
  padding: 14px;
}

.card__title {
  margin: 0 0 8px;
  font-size: 16px;
}

.price {
  font-weight: 900;
  color: var(--gold);
  margin: 0;
}

.muted {
  color: var(--muted);
}

.btn {
  width: 100%;
  margin-top: 10px;
  padding: 11px 14px;
  border-radius: 14px;
  border: 1px solid rgba(246, 211, 101, 0.28);
  background: linear-gradient(
    135deg,
    rgba(246, 211, 101, 0.92),
    rgba(253, 160, 133, 0.92)
  );
  color: #0b1020;
  font-weight: 900;
  cursor: pointer;
}

.badge-row {
  position: absolute;
  top: 12px;
  left: 12px;
  display: flex;
  gap: 8px;
  z-index: 2;
}

.badge--premium,
.badge--new,
.badge--limited {
  padding: 6px 10px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 900;
  border: 1px solid rgba(255, 255, 255, 0.14);
}

.badge--premium {
  background: linear-gradient(
    135deg,
    rgba(246, 211, 101, 0.95),
    rgba(253, 160, 133, 0.95)
  );
  color: #0b1020;
}

.badge--new {
  background: rgba(0, 0, 0, 0.32);
  color: rgba(255, 255, 255, 0.92);
}

.badge--limited {
  background: rgba(255, 80, 80, 0.18);
  color: rgba(255, 255, 255, 0.92);
  border-color: rgba(255, 80, 80, 0.32);
}

.pagination {
  display: flex;
  gap: 8px;
  justify-content: center;
  align-items: center;
  margin-top: 16px;
  flex-wrap: wrap;
}

.page-btn {
  min-width: 40px;
  height: 40px;
  padding: 0 12px;
  border-radius: 999px;
  border: 1px solid rgba(255, 255, 255, 0.14);
  background: rgba(255, 255, 255, 0.06);
  color: rgba(255, 255, 255, 0.92);
  cursor: pointer;
  font-weight: 900;
}

.page-btn.active {
  color: #0b1020;
  background: linear-gradient(
    135deg,
    rgba(246, 211, 101, 0.95),
    rgba(253, 160, 133, 0.92)
  );
  border-color: rgba(246, 211, 101, 0.4);
}

.page-btn:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}

.footer {
  margin-top: 18px;
  padding: 12px 2px;
  color: var(--muted);
  font-size: 12px;
}

.footer__row {
  display: flex;
  justify-content: space-between;
  gap: 12px;
}

.cart-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.55);
  display: none;
  align-items: flex-end;
  justify-content: flex-end;
  z-index: 60;
}

.cart-overlay.open {
  display: flex;
}

.cart-panel {
  width: min(420px, 100%);
  height: 100%;
  background: #0b1020;
  color: var(--text);
  border-left: 1px solid var(--line);
  padding: 16px;
  display: flex;
  flex-direction: column;
}

.cart-panel__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.cart-close {
  background: transparent;
  border: 0;
  color: inherit;
  font-size: 20px;
  cursor: pointer;
}

.cart-items {
  flex: 1;
  overflow: auto;
  margin-top: 12px;
  padding-right: 6px;
}

.cart-item {
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 14px;
  padding: 12px;
  margin-bottom: 10px;
  background: rgba(255, 255, 255, 0.06);
}

.cart-item__meta {
  opacity: 0.75;
  margin-top: 4px;
  font-size: 13px;
}

.cart-item__controls {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-top: 10px;
  flex-wrap: wrap;
}

.qty-btn {
  width: 36px;
  height: 34px;
  border-radius: 10px;
  border: 1px solid rgba(255, 255, 255, 0.14);
  background: rgba(255, 255, 255, 0.08);
  color: inherit;
  cursor: pointer;
}

.qty {
  min-width: 22px;
  text-align: center;
}

.remove-btn {
  margin-left: auto;
  padding: 8px 10px;
  border-radius: 10px;
  border: 1px solid rgba(255, 255, 255, 0.14);
  background: rgba(255, 255, 255, 0.06);
  color: inherit;
  cursor: pointer;
}

.cart-panel__footer {
  border-top: 1px solid rgba(255, 255, 255, 0.12);
  padding-top: 12px;
}

.cart-total {
  display: flex;
  justify-content: space-between;
  margin-bottom: 10px;
}

.cart-actions {
  display: flex;
  gap: 10px;
}

.cart-empty {
  opacity: 0.75;
  padding: 18px 8px;
}

@media (max-width: 1100px) {
  .products {
    grid-template-columns: repeat(2, 1fr);
  }

  .search {
    grid-template-columns: 280px 220px;
  }
}

@media (max-width: 900px) {
  .layout {
    grid-template-columns: 1fr;
  }

  .filters {
    position: relative;
    top: auto;
  }

  .products {
    grid-template-columns: repeat(2, 1fr);
  }
}

css/mobile.css

:root {
  --bg: #070711;
  --panel: rgba(255, 255, 255, 0.06);
  --panel2: rgba(255, 255, 255, 0.09);
  --text: rgba(255, 255, 255, 0.92);
  --muted: rgba(255, 255, 255, 0.72);
  --line: rgba(255, 255, 255, 0.12);
  --gold: #f6d365;
  --gold2: #fda085;
}

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  font-family:
    system-ui,
    -apple-system,
    Segoe UI,
    Roboto,
    Arial,
    sans-serif;
  background:
    radial-gradient(
      900px 520px at 10% -10%,
      rgba(246, 211, 101, 0.08),
      transparent 60%
    ),
    radial-gradient(
      900px 520px at 90% 0%,
      rgba(253, 160, 133, 0.06),
      transparent 60%
    ),
    var(--bg);
  color: var(--text);
}

.app {
  min-height: 100vh;
}

.topbar {
  position: sticky;
  top: 0;
  z-index: 10;
  background: rgba(0, 0, 0, 0.7);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--line);
  padding: 14px 16px 10px;
}

.topbar__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}

.brand__name {
  font-weight: 900;
  letter-spacing: 0.4px;
}
.brand__tag {
  margin-top: 2px;
  font-size: 12px;
  color: var(--muted);
}

.icon-btn {
  position: relative;
  border: 1px solid rgba(255, 255, 255, 0.16);
  background: rgba(255, 255, 255, 0.06);
  color: var(--text);
  border-radius: 999px;
  padding: 10px 12px;
  font-weight: 900;
  cursor: pointer;
}

.badge {
  display: inline-flex;
  justify-content: center;
  align-items: center;
  min-width: 22px;
  height: 22px;
  margin-left: 6px;
  padding: 0 7px;
  border-radius: 999px;
  background: linear-gradient(135deg, var(--gold), var(--gold2));
  color: #0b1020;
  font-weight: 900;
  font-size: 12px;
}

.search {
  display: grid;
  grid-template-columns: 1fr;
  gap: 10px;
  margin-top: 10px;
}

.search__input {
  width: 100%;
  padding: 12px 12px;
  border-radius: 14px;
  border: 1px solid var(--line);
  background: var(--panel);
  color: var(--text);
  outline: none;
}

.search__input::placeholder {
  color: rgba(255, 255, 255, 0.55);
}

.sort-select {
  width: 100%;
  padding: 12px 12px;
  border-radius: 14px;
  border: 1px solid var(--line);
  background: var(--panel);
  color: var(--text);
  cursor: pointer;
  outline: none;
  appearance: none;
  -webkit-appearance: none;
  -moz-appearance: none;
}

.sort-select option {
  background: #0b1020;
  color: var(--text);
}

.content {
  padding: 14px 16px 28px;
}

.hero {
  border: 1px solid var(--line);
  background: var(--panel);
  padding: 16px;
  border-radius: 18px;
  margin-bottom: 14px;
}

.hero h1 {
  margin: 0 0 6px;
  font-size: 22px;
}
.hero p {
  margin: 0 0 14px;
  color: var(--muted);
  font-size: 13px;
  line-height: 1.5;
}

.cta {
  width: 100%;
  padding: 12px 16px;
  border-radius: 999px;
  border: 1px solid rgba(246, 211, 101, 0.35);
  background: linear-gradient(
    135deg,
    rgba(246, 211, 101, 0.95),
    rgba(253, 160, 133, 0.92)
  );
  color: #0b1020;
  font-weight: 900;
  cursor: pointer;
  box-shadow: 0 18px 32px rgba(0, 0, 0, 0.35);
  transition:
    transform 160ms ease,
    filter 200ms ease,
    box-shadow 200ms ease;
}

.cta:hover {
  transform: translateY(-1px);
  filter: brightness(1.03);
  box-shadow: 0 22px 44px rgba(0, 0, 0, 0.38);
}

.cta:active {
  transform: translateY(0px) scale(0.99);
}

.quick-filters {
  display: flex;
  gap: 10px;
  overflow: auto;
  padding: 6px 2px 12px;
  margin-bottom: 10px;
  -webkit-overflow-scrolling: touch;
}

.pill {
  white-space: nowrap;
  padding: 10px 12px;
  border-radius: 999px;
  border: 1px solid rgba(255, 255, 255, 0.14);
  background: rgba(255, 255, 255, 0.06);
  color: var(--text);
  font-weight: 900;
  cursor: pointer;
}

.pill--active {
  color: #0b1020;
  background: linear-gradient(135deg, var(--gold), var(--gold2));
  border-color: rgba(246, 211, 101, 0.4);
}

.list {
  display: grid;
  gap: 12px;
}

.item {
  border: 1px solid var(--line);
  background: var(--panel);
  border-radius: 18px;
  overflow: hidden;
}

.item__image {
  width: 100%;
  height: 220px;
  display: block;
  object-fit: cover;
}

.item__body {
  padding: 14px;
}

.item__title {
  margin: 0 0 6px;
  font-weight: 900;
  font-size: 15px;
  letter-spacing: 0.2px;
}

.item__desc {
  margin: 0 0 10px;
  color: var(--muted);
  font-size: 13px;
  line-height: 1.45;
}

.item__row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
}

.price {
  font-weight: 900;
  color: var(--gold);
  font-size: 16px;
}

.btn {
  width: 100%;
  margin-top: 12px;
  padding: 12px 14px;
  border-radius: 14px;
  border: 1px solid rgba(246, 211, 101, 0.28);
  background: linear-gradient(
    135deg,
    rgba(246, 211, 101, 0.92),
    rgba(253, 160, 133, 0.92)
  );
  color: #0b1020;
  font-weight: 900;
  cursor: pointer;
  box-shadow: 0 14px 26px rgba(0, 0, 0, 0.28);
}

.btn:active {
  transform: scale(0.99);
}

.footer {
  margin-top: 18px;
  padding: 14px 2px 0;
  font-size: 12px;
  color: var(--muted);
}

.footer__row {
  display: flex;
  justify-content: space-between;
  gap: 12px;
}

/* Cart overlay (simple mobile drawer) */
.cart-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.55);
  display: none;
  justify-content: flex-end;
  align-items: flex-end;
  z-index: 50;
}

.cart-overlay.open {
  display: flex;
}

.cart-panel {
  width: 100%;
  max-height: 90vh;
  background: #0b1020;
  border-top-left-radius: 18px;
  border-top-right-radius: 18px;
  border: 1px solid var(--line);
  padding: 14px;
  overflow: auto;
}

.cart-panel__header {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.cart-close {
  background: transparent;
  border: 0;
  color: var(--text);
  font-size: 20px;
  cursor: pointer;
}

.cart-items {
  margin-top: 12px;
  display: grid;
  gap: 10px;
}

.cart-item {
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 14px;
  padding: 12px;
  background: rgba(255, 255, 255, 0.06);
}

.cart-item__meta {
  margin-top: 6px;
  opacity: 0.75;
  font-size: 13px;
}

.cart-item__controls {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
  align-items: center;
  margin-top: 10px;
}

.qty-btn {
  width: 36px;
  height: 34px;
  border-radius: 10px;
  border: 1px solid rgba(255, 255, 255, 0.14);
  background: rgba(255, 255, 255, 0.08);
  color: var(--text);
  cursor: pointer;
  font-weight: 900;
}

.qty {
  min-width: 22px;
  text-align: center;
}

.remove-btn {
  margin-left: auto;
  padding: 8px 10px;
  border-radius: 10px;
  border: 1px solid rgba(255, 255, 255, 0.14);
  background: rgba(255, 255, 255, 0.06);
  color: var(--text);
  cursor: pointer;
  font-weight: 900;
}

.cart-panel__footer {
  border-top: 1px solid rgba(255, 255, 255, 0.12);
  margin-top: 12px;
  padding-top: 12px;
}

.cart-total {
  display: flex;
  justify-content: space-between;
  margin-bottom: 10px;
}

.cart-actions {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
}

.btn-primary,
.btn-secondary {
  padding: 12px 12px;
  border-radius: 14px;
  border: 1px solid rgba(255, 255, 255, 0.14);
  cursor: pointer;
  font-weight: 900;
}

.btn-primary {
  background: linear-gradient(
    135deg,
    rgba(246, 211, 101, 0.92),
    rgba(253, 160, 133, 0.92)
  );
  color: #0b1020;
}

.btn-secondary {
  background: rgba(255, 255, 255, 0.06);
  color: var(--text);
}

.cart-empty {
  opacity: 0.75;
  padding: 16px 6px;
}

JavaScript

js/adaptive.js

(function () {
  const styleEl = document.getElementById("adaptive-style");
  const app = document.getElementById("app");

  const BREAKPOINT = 900;

  function getMode() {
    return window.innerWidth < BREAKPOINT ? "mobile" : "desktop";
  }

  let mode = getMode();

  function load() {
    mode = getMode();
    styleEl.href = `css/${mode}.css`;

    const scriptId = "adaptive-bundle";
    const old = document.getElementById(scriptId);
    if (old) old.remove();

    const script = document.createElement("script");
    script.id = scriptId;
    script.src = `js/${mode}.bundle.js`;
    script.defer = true;

    script.onload = () => {
      if (window.AdaptiveStore?.init) window.AdaptiveStore.init(app);
    };

    document.body.appendChild(script);
  }

  function debounce(fn, wait) {
    let t;
    return (...args) => {
      clearTimeout(t);
      t = setTimeout(() => fn(...args), wait);
    };
  }

  load();

  window.addEventListener(
    "resize",
    debounce(() => {
      const newMode = getMode();
      if (newMode !== mode) load();
    }, 250)
  );
})();

js/desktop.bundle.js

 window.AdaptiveStore = (function () {
  const money = (n) => Number(n || 0).toFixed(2);

  const loadCart = () => {
    try {
      return JSON.parse(localStorage.getItem("luxury_cart") || "[]");
    } catch {
      return [];
    }
  };

  const saveCart = (cart) => {
    localStorage.setItem("luxury_cart", JSON.stringify(cart));
  };

  let cart = loadCart();
  let products = [];

  let currentPage = 1;
  const pageSize = 9;
  let activeQuickTag = null;

  function escapeHtml(input) {
    return String(input)
      .replaceAll("&", "&amp;")
      .replaceAll("<", "&lt;")
      .replaceAll(">", "&gt;")
      .replaceAll('"', "&quot;")
      .replaceAll("'", "&#039;");
  }

  function badgeClass(name) {
    const v = (name || "").toLowerCase();
    if (v === "premium") return "badge--premium";
    if (v === "new") return "badge--new";
    if (v === "limited") return "badge--limited";
    return "";
  }

  async function loadProducts() {
    try {
      const res = await fetch("data/products.json", { cache: "no-store" });
      products = await res.json();
    } catch (e) {
      console.error("Failed to load products.json", e);
      products = [];
    }
  }

  function render(root) {
    root.innerHTML = `
      <header class="topbar">
        <div class="topbar__inner">
          <div class="brand">
            <div class="brand__name">LuxuryStore</div>
            <div class="brand__tag">Adaptive Desktop • Dashboard</div>
          </div>

          <div class="top-actions">
            <div class="search">
              <input id="searchInput" class="search__input" placeholder="Search products..." autocomplete="off" />
              <select id="sortSelect" class="sort-select" aria-label="Sort products">
                <option value="default">Sort: Default</option>
                <option value="priceLow">Price: Low to High</option>
                <option value="priceHigh">Price: High to Low</option>
                <option value="nameAZ">Name: A → Z</option>
                <option value="nameZA">Name: Z → A</option>
              </select>
            </div>

            <button class="cart-btn" id="cartBtn" type="button" aria-label="Open cart">
              🛒 Cart <span class="badge"><span id="cartCount">0</span></span>
            </button>
          </div>
        </div>
      </header>

      <main class="layout">
        <aside class="filters" aria-label="Filters">
          <h2 class="filters__title">Filters</h2>

          <div class="filter-group">
            <h3>Category</h3>
            ${checkbox("category", "women", "Women")}
            ${checkbox("category", "men", "Men")}
            ${checkbox("category", "kids", "Kids")}
          </div>

          <div class="filter-group">
            <h3>Tags</h3>
            ${checkbox("tag", "premium", "Premium")}
            ${checkbox("tag", "new", "New")}
            ${checkbox("tag", "limited", "Limited")}
          </div>

          <div class="filters-actions">
            <button class="btn-secondary" id="clearFiltersBtn" type="button">Clear</button>
      
          </div>
        </aside>

        <section class="main">
          <section class="hero">
            <h1>Luxury Collection 2026</h1>
            <p>Desktop dashboard: filters, search, sort, pagination, and cart.</p>
            <div class="hero__actions">
              <button class="cta" id="shopNewArrivalsBtn" type="button">Shop New Arrivals</button>
              <button class="secondary" id="viewPremiumBtn" type="button">View Premium</button>
            </div>
          </section>

          <section class="products" id="products"></section>
          <div class="pagination" id="pagination"></div>

          <footer class="footer">
            <div class="footer__row">
              <span>© LuxuryStore</span>
              <span class="muted">Desktop bundle</span>
            </div>
          </footer>
        </section>
      </main>

      <div class="cart-overlay" id="cartOverlay" aria-hidden="true">
        <div class="cart-panel" role="dialog" aria-modal="true" aria-label="Cart">
          <div class="cart-panel__header">
            <h3>Your Cart</h3>
            <button class="cart-close" id="cartCloseBtn" type="button">✕</button>
          </div>

          <div id="cartItems" class="cart-items"></div>

          <div class="cart-panel__footer">
            <div class="cart-total">
              Total: <strong>£<span id="cartTotal">0</span></strong>
            </div>

            <div class="cart-actions">
              <button type="button" class="btn-secondary" id="clearCartBtn">Clear</button>
              <button type="button" class="btn-primary">Checkout</button>
            </div>
          </div>
        </div>
      </div>
    `;

    wire(root);
    renderCart();
    applyFilters();
  }

  function checkbox(name, value, label) {
    const id = `${name}_${value}`;
    return `
      <label class="check" for="${id}">
        <input id="${id}" type="checkbox" name="${name}" value="${value}" />
        <span>${escapeHtml(label)}</span>
      </label>
    `;
  }

  function getSelectedFilters(root) {
    const selectedCategories = Array.from(
      root.querySelectorAll('input[name="category"]:checked')
    ).map((x) => x.value);

    const selectedTags = Array.from(
      root.querySelectorAll('input[name="tag"]:checked')
    ).map((x) => x.value);

    return { selectedCategories, selectedTags };
  }

  function matchesFilters(product, filters) {
    const categoryOk =
      filters.selectedCategories.length === 0 ||
      filters.selectedCategories.includes(product.category);

    const tags = product.tags || [];

    const tagsOk =
      filters.selectedTags.length === 0 ||
      filters.selectedTags.every((t) => tags.includes(t));

    const quickOk = !activeQuickTag || tags.includes(activeQuickTag);

    return categoryOk && tagsOk && quickOk;
  }

  function renderProducts(list) {
    const productsEl = document.getElementById("products");
    if (!productsEl) return;

    productsEl.innerHTML = list
      .map((p) => {
        const badges = (p.badges || [])
          .map((b) => `<span class="${badgeClass(b)}">${escapeHtml(b)}</span>`)
          .join("");

        return `
          <article class="card"
            data-id="${escapeHtml(p.id)}"
            data-title="${escapeHtml(p.title)}"
            data-price="${p.price}"
            data-stock="${p.stock}"
          >
            ${badges ? `<div class="badge-row">${badges}</div>` : ""}

            <img src="${escapeHtml(p.image)}" alt="${escapeHtml(p.alt || p.title)}" />
            <div class="card__body">
              <h3 class="card__title">${escapeHtml(p.title)}</h3>
              <p class="price">£${money(p.price)}</p>
              <p class="muted" style="margin:6px 0 0;">Only <strong>${p.stock}</strong> left</p>
              <button class="btn add-to-cart" type="button">Add to Cart</button>
            </div>
          </article>
        `;
      })
      .join("");
  }

  function renderPagination(totalItems) {
    const paginationEl = document.getElementById("pagination");
    if (!paginationEl) return;

    const totalPages = Math.max(1, Math.ceil(totalItems / pageSize));
    if (currentPage > totalPages) currentPage = totalPages;

    let html = "";
    html += `<button class="page-btn" data-page="${currentPage - 1}" ${currentPage === 1 ? "disabled" : ""}>‹</button>`;

    for (let p = 1; p <= totalPages; p++) {
      html += `<button class="page-btn ${p === currentPage ? "active" : ""}" data-page="${p}">${p}</button>`;
    }

    html += `<button class="page-btn" data-page="${currentPage + 1}" ${currentPage === totalPages ? "disabled" : ""}>›</button>`;
    paginationEl.innerHTML = html;
  }

  function applyFilters() {
    const root = document.getElementById("app");
    const searchInput = document.getElementById("searchInput");
    const sortSelect = document.getElementById("sortSelect");

    const filters = getSelectedFilters(root);
    const search = (searchInput?.value || "").trim().toLowerCase();
    const sort = sortSelect?.value || "default";

    let visible = products.filter((p) => matchesFilters(p, filters));

    if (search) visible = visible.filter((p) => p.title.toLowerCase().includes(search));

    visible.sort((a, b) => {
      if (sort === "priceLow") return a.price - b.price;
      if (sort === "priceHigh") return b.price - a.price;
      if (sort === "nameAZ") return a.title.localeCompare(b.title);
      if (sort === "nameZA") return b.title.localeCompare(a.title);
      return 0;
    });

    const totalItems = visible.length;
    const totalPages = Math.max(1, Math.ceil(totalItems / pageSize));
    if (currentPage > totalPages) currentPage = totalPages;

    const start = (currentPage - 1) * pageSize;
    const paged = visible.slice(start, start + pageSize);

    renderProducts(paged);
    renderPagination(totalItems);
  }

  function addToCart(product) {
    const card = document.querySelector(`.card[data-id="${product.id}"]`);
    const stock = Number(card?.dataset.stock || 9999);

    const existing = cart.find((x) => x.id === product.id);
    const currentQty = existing?.qty || 0;

    if (currentQty >= stock) {
      alert(`Sorry! Only ${stock} available for "${product.title}".`);
      return;
    }

    if (existing) existing.qty += 1;
    else cart.push({ ...product, qty: 1 });

    saveCart(cart);
    renderCart();
  }

  function removeFromCart(id) {
    cart = cart.filter((x) => x.id !== id);
    saveCart(cart);
    renderCart();
  }

  function changeQty(id, delta) {
    const item = cart.find((x) => x.id === id);
    if (!item) return;

    item.qty += delta;

    if (item.qty <= 0) {
      removeFromCart(id);
      return;
    }

    const card = document.querySelector(`.card[data-id="${id}"]`);
    const stock = Number(card?.dataset.stock || 9999);
    if (item.qty > stock) item.qty = stock;

    saveCart(cart);
    renderCart();
  }

  function clearCart() {
    cart = [];
    saveCart(cart);
    renderCart();
  }

  function renderCart() {
    const cartCountEl = document.getElementById("cartCount");
    const cartTotalEl = document.getElementById("cartTotal");
    const cartItemsEl = document.getElementById("cartItems");

    const totalQty = cart.reduce((sum, x) => sum + x.qty, 0);
    const totalPrice = cart.reduce((sum, x) => sum + x.qty * x.price, 0);

    if (cartCountEl) cartCountEl.textContent = totalQty;
    if (cartTotalEl) cartTotalEl.textContent = money(totalPrice);

    if (!cartItemsEl) return;

    if (cart.length === 0) {
      cartItemsEl.innerHTML = `<p class="cart-empty">Your cart is empty.</p>`;
      return;
    }

    cartItemsEl.innerHTML = cart
      .map(
        (item) => `
          <div class="cart-item">
            <div class="cart-item__info">
              <strong>${escapeHtml(item.title)}</strong>
              <div class="cart-item__meta">£${money(item.price)} each</div>
            </div>

            <div class="cart-item__controls">
              <button class="qty-btn" data-action="dec" data-id="${escapeHtml(item.id)}" type="button">−</button>
              <span class="qty">${item.qty}</span>
              <button class="qty-btn" data-action="inc" data-id="${escapeHtml(item.id)}" type="button">+</button>
              <button class="remove-btn" data-action="remove" data-id="${escapeHtml(item.id)}" type="button">Remove</button>
            </div>
          </div>
        `
      )
      .join("");
  }

  function openCart() {
    document.getElementById("cartOverlay")?.classList.add("open");
  }

  function closeCart() {
    document.getElementById("cartOverlay")?.classList.remove("open");
  }

  function clearFilters(root) {
    root.querySelectorAll(".filters input[type='checkbox']").forEach((cb) => (cb.checked = false));
    const searchInput = document.getElementById("searchInput");
    const sortSelect = document.getElementById("sortSelect");
    if (searchInput) searchInput.value = "";
    if (sortSelect) sortSelect.value = "default";
  }

  function wire(root) {
    root.addEventListener("click", (e) => {
      if (e.target.closest("#cartBtn")) openCart();
      if (e.target.closest("#cartCloseBtn")) closeCart();
      if (e.target.closest("#clearCartBtn")) clearCart();

      if (e.target.closest("#clearFiltersBtn")) {
        activeQuickTag = null;
        currentPage = 1;
        clearFilters(root);
        applyFilters();
      }

      if (e.target.closest("#applyFiltersBtn")) {
        activeQuickTag = null;
        currentPage = 1;
        applyFilters();
      }

      if (e.target.closest("#shopNewArrivalsBtn")) {
        activeQuickTag = "new";
        currentPage = 1;
        clearFilters(root);
        applyFilters();
      }

      if (e.target.closest("#viewPremiumBtn")) {
        activeQuickTag = "premium";
        currentPage = 1;
        clearFilters(root);
        applyFilters();
      }

      const addBtn = e.target.closest(".add-to-cart");
      if (addBtn) {
        const card = addBtn.closest(".card");
        addToCart({
          id: card.dataset.id,
          title: card.dataset.title,
          price: Number(card.dataset.price || 0),
        });
        openCart();
      }

      const actionBtn = e.target.closest("[data-action]");
      if (actionBtn) {
        const action = actionBtn.dataset.action;
        const id = actionBtn.dataset.id;
        if (action === "remove") removeFromCart(id);
        if (action === "inc") changeQty(id, +1);
        if (action === "dec") changeQty(id, -1);
      }

      const pageBtn = e.target.closest(".page-btn");
      if (pageBtn && !pageBtn.disabled) {
        currentPage = Number(pageBtn.dataset.page || 1);
        applyFilters();
      }
    });

    root.addEventListener("change", (e) => {
      const cb = e.target.closest(".filters input[type='checkbox']");
      if (!cb) return;
      activeQuickTag = null;
      currentPage = 1;
      applyFilters();
    });

    document.getElementById("searchInput")?.addEventListener("input", () => {
      activeQuickTag = null;
      currentPage = 1;
      applyFilters();
    });

    document.getElementById("sortSelect")?.addEventListener("change", () => {
      activeQuickTag = null;
      currentPage = 1;
      applyFilters();
    });

    document.getElementById("cartOverlay")?.addEventListener("click", (e) => {
      if (e.target.id === "cartOverlay") closeCart();
    });

    document.addEventListener("keydown", (e) => {
      if (e.key === "Escape") closeCart();
    });
  }

  async function init(root) {
    await loadProducts();
    render(root);
  }

  return { init };
})();

js/mobile.bundle.js

 window.AdaptiveStore = (function () {
  const money = (n) => Number(n || 0).toFixed(2);

  const loadCart = () => {
    try {
      return JSON.parse(localStorage.getItem("luxury_cart") || "[]");
    } catch {
      return [];
    }
  };

  const saveCart = (cart) => {
    localStorage.setItem("luxury_cart", JSON.stringify(cart));
  };

  let cart = loadCart();
  let products = [];
  let activeCategory = null;
  let activeTag = null;

  function escapeHtml(input) {
    return String(input)
      .replaceAll("&", "&amp;")
      .replaceAll("<", "&lt;")
      .replaceAll(">", "&gt;")
      .replaceAll('"', "&quot;")
      .replaceAll("'", "&#039;");
  }

  function render(root) {
    root.innerHTML = `
      <header class="topbar">
        <div class="topbar__inner">
          <div class="brand">
            <div class="brand__name">LuxuryStore</div>
            <div class="brand__tag">Adaptive Mobile • Lightweight</div>
          </div>

          <button class="icon-btn" id="cartBtn" type="button" aria-label="Open cart">
            🛒 <span class="badge"><span id="cartCount">0</span></span>
          </button>
        </div>

        <div class="search">
          <input id="searchInput" class="search__input" type="text" placeholder="Search products..." autocomplete="off" />
        </div>
      </header>

      <main class="content">
        <section class="hero">
          <h1>Luxury Collection 2026</h1>
          <p>Fast mobile shopping experience. Minimal UI, maximum speed.</p>
          <button class="cta" id="shopNewBtn" type="button">Shop New Arrivals</button>
        </section>

        <section class="quick-filters" aria-label="Quick filters">
          <button class="pill" data-cat="women" type="button">Women</button>
          <button class="pill" data-cat="men" type="button">Men</button>
          <button class="pill" data-cat="kids" type="button">Kids</button>

          <button class="pill" data-tag="premium" type="button">Premium</button>
          <button class="pill" data-tag="new" type="button">New</button>
          <button class="pill" data-tag="limited" type="button">Limited</button>

          <button class="pill pill--ghost" id="clearFiltersBtn" type="button">Clear</button>
        </section>

        <section class="list" id="productList" aria-label="Product list"></section>

        <footer class="footer">
          <div class="footer__row">
            <span>© LuxuryStore</span>
            <span class="muted">Mobile bundle</span>
          </div>
        </footer>
      </main>

      <div class="cart-overlay" id="cartOverlay" aria-hidden="true">
        <div class="cart-panel" role="dialog" aria-modal="true">
          <div class="cart-panel__header">
            <h3>Your Cart</h3>
            <button class="cart-close" id="cartCloseBtn" type="button">✕</button>
          </div>

          <div id="cartItems" class="cart-items"></div>

          <div class="cart-panel__footer">
            <div class="cart-total">
              Total: <strong>£<span id="cartTotal">0</span></strong>
            </div>

            <div class="cart-actions">
              <button type="button" class="btn-secondary" id="clearCartBtn">Clear</button>
              <button type="button" class="btn-primary">Checkout</button>
            </div>
          </div>
        </div>
      </div>
    `;

    wire(root);
    renderProducts();
    renderCart();
  }

  function filteredProducts(search) {
    let list = [...products];

    if (activeCategory) list = list.filter((p) => p.category === activeCategory);
    if (activeTag) list = list.filter((p) => (p.tags || []).includes(activeTag));

    if (search) {
      const s = search.toLowerCase();
      list = list.filter((p) => (p.title || "").toLowerCase().includes(s));
    }

    return list;
  }

  function renderMobileItem(p) {
    return `
      <article
        class="item"
        data-id="${escapeHtml(p.id)}"
        data-title="${escapeHtml(p.title)}"
        data-price="${p.price}"
        data-stock="${p.stock || 9999}"
      >
        <img class="item__image" src="${escapeHtml(p.image)}" alt="${escapeHtml(p.alt || p.title)}" />

        <div class="item__body">
          <h3 class="item__title">${escapeHtml(p.title)}</h3>
          <p class="item__desc">${escapeHtml(p.description || "Luxury item from 2026 Collection")}</p>

          <div class="item__row">
            <div class="price">£${money(p.price)}</div>
            <div class="muted">Stock: <strong>${p.stock ?? "-"}</strong></div>
          </div>

          <button class="btn add-to-cart" type="button">Add to Cart</button>
        </div>
      </article>
    `;
  }

  function renderProducts() {
    const listEl = document.getElementById("productList");
    const search = document.getElementById("searchInput")?.value || "";
    if (!listEl) return;

    const list = filteredProducts(search);

    listEl.innerHTML = list.map(renderMobileItem).join("");

    if (list.length === 0) {
      listEl.innerHTML = `<p class="cart-empty">No matching products found.</p>`;
    }
  }

  function addToCart(product) {
    const existing = cart.find((x) => x.id === product.id);
    const currentQty = existing?.qty || 0;

    const card = document.querySelector(`.item[data-id="${product.id}"]`);
    const stock = Number(card?.dataset.stock || 9999);

    if (currentQty >= stock) {
      alert(`Sorry! Only ${stock} available for "${product.title}".`);
      return;
    }

    if (existing) existing.qty += 1;
    else cart.push({ ...product, qty: 1 });

    saveCart(cart);
    renderCart();
  }

  function changeQty(id, delta) {
    const item = cart.find((x) => x.id === id);
    if (!item) return;

    item.qty += delta;

    if (item.qty <= 0) {
      cart = cart.filter((x) => x.id !== id);
      saveCart(cart);
      renderCart();
      return;
    }

    const stockEl = document.querySelector(`.item[data-id="${id}"]`);
    const stock = Number(stockEl?.dataset.stock || 9999);

    if (item.qty > stock) item.qty = stock;

    saveCart(cart);
    renderCart();
  }

  function clearCart() {
    cart = [];
    saveCart(cart);
    renderCart();
  }

  function renderCart() {
    const cartCountEl = document.getElementById("cartCount");
    const cartTotalEl = document.getElementById("cartTotal");
    const cartItemsEl = document.getElementById("cartItems");

    const totalQty = cart.reduce((sum, x) => sum + x.qty, 0);
    const totalPrice = cart.reduce((sum, x) => sum + x.qty * x.price, 0);

    if (cartCountEl) cartCountEl.textContent = totalQty;
    if (cartTotalEl) cartTotalEl.textContent = money(totalPrice);

    if (!cartItemsEl) return;

    if (cart.length === 0) {
      cartItemsEl.innerHTML = `<p class="cart-empty">Your cart is empty.</p>`;
      return;
    }

    cartItemsEl.innerHTML = cart
      .map(
        (item) => `
        <div class="cart-item">
          <div class="cart-item__info">
            <strong>${escapeHtml(item.title)}</strong>
            <div class="cart-item__meta">£${money(item.price)} each</div>
          </div>

          <div class="cart-item__controls">
            <button class="qty-btn" data-action="dec" data-id="${escapeHtml(item.id)}" type="button">−</button>
            <span class="qty">${item.qty}</span>
            <button class="qty-btn" data-action="inc" data-id="${escapeHtml(item.id)}" type="button">+</button>
          </div>
        </div>
      `
      )
      .join("");
  }

  function openCart() {
    document.getElementById("cartOverlay")?.classList.add("open");
    document.getElementById("cartOverlay")?.setAttribute("aria-hidden", "false");
  }

  function closeCart() {
    document.getElementById("cartOverlay")?.classList.remove("open");
    document.getElementById("cartOverlay")?.setAttribute("aria-hidden", "true");
  }

  async function loadProducts() {
    try {
      const res = await fetch("data/products.json", { cache: "no-store" });
      products = await res.json();
    } catch {
      products = [];
    }
  }

  function clearActivePills(root) {
    root.querySelectorAll(".pill").forEach((x) => x.classList.remove("pill--active"));
  }

  function wire(root) {
    root.addEventListener("click", (e) => {
      if (e.target.closest("#cartBtn")) openCart();
      if (e.target.closest("#cartCloseBtn")) closeCart();
      if (e.target.closest("#clearCartBtn")) clearCart();

      if (e.target.closest("#cartOverlay") && e.target.id === "cartOverlay") closeCart();

      const pill = e.target.closest(".pill");

      if (pill && pill.dataset.cat) {
        activeCategory = activeCategory === pill.dataset.cat ? null : pill.dataset.cat;
        activeTag = null;

        clearActivePills(root);
        if (activeCategory) pill.classList.add("pill--active");

        renderProducts();
      }

      if (pill && pill.dataset.tag) {
        activeTag = activeTag === pill.dataset.tag ? null : pill.dataset.tag;
        activeCategory = null;

        clearActivePills(root);
        if (activeTag) pill.classList.add("pill--active");

        renderProducts();
      }

      if (e.target.closest("#clearFiltersBtn")) {
        activeCategory = null;
        activeTag = null;
        clearActivePills(root);

        const si = document.getElementById("searchInput");
        if (si) si.value = "";

        renderProducts();
      }

      if (e.target.closest("#shopNewBtn")) {
        activeCategory = null;
        activeTag = "new";

        clearActivePills(root);
        root.querySelector('.pill[data-tag="new"]')?.classList.add("pill--active");

        renderProducts();

        document.getElementById("productList")?.scrollIntoView({
          behavior: "smooth",
          block: "start",
        });
      }

      const addBtn = e.target.closest(".add-to-cart");
      if (addBtn) {
        const item = addBtn.closest(".item");
        addToCart({
          id: item.dataset.id,
          title: item.dataset.title,
          price: Number(item.dataset.price || 0),
        });
        openCart();
      }

      const qtyAction = e.target.closest("[data-action]");
      if (qtyAction) {
        const action = qtyAction.dataset.action;
        const id = qtyAction.dataset.id;
        if (action === "inc") changeQty(id, +1);
        if (action === "dec") changeQty(id, -1);
      }
    });

    root.querySelector("#searchInput")?.addEventListener("input", renderProducts);

    document.addEventListener("keydown", (e) => {
      if (e.key === "Escape") closeCart();
    });
  }

  async function init(root) {
    await loadProducts();
    render(root);
  }

  return { init };
})();

JSON (data/products.json)

[
  {
    "id": "dress-1",
    "title": "Luxury Dress",
    "price": 89,
    "category": "women",
    "tags": [
      "premium",
      "new"
    ],
    "badges": [
      "Premium",
      "New"
    ],
    "stock": 6,
    "image": "https://picsum.photos/500/650?1",
    "alt": "Luxury Dress",
    "description": "Elegant premium dress for special occasions."
  },
  {
    "id": "kurta-1",
    "title": "Men Kurta",
    "price": 49,
    "category": "men",
    "tags": [
      "premium"
    ],
    "badges": [
      "Premium"
    ],
    "stock": 10,
    "image": "https://picsum.photos/500/650?2",
    "alt": "Men Kurta",
    "description": "Modern classic kurta with luxury fabric."
  },
  {
    "id": "kids-1",
    "title": "Kids Outfit",
    "price": 29,
    "category": "kids",
    "tags": [
      "new"
    ],
    "badges": [
      "New"
    ],
    "stock": 12,
    "image": "https://picsum.photos/500/650?3",
    "alt": "Kids Outfit",
    "description": "Comfortable outfit for kids, perfect daily wear."
  },
  {
    "id": "abaya-1",
    "title": "Luxury Abaya",
    "price": 99,
    "category": "women",
    "tags": [
      "premium",
      "limited"
    ],
    "badges": [
      "Premium",
      "Limited"
    ],
    "stock": 4,
    "image": "https://picsum.photos/500/650?4",
    "alt": "Luxury Abaya",
    "description": "Limited edition luxury abaya with premium stitching."
  },
  {
    "id": "heels-1",
    "title": "Gold Heels",
    "price": 75,
    "category": "women",
    "tags": [
      "premium",
      "new"
    ],
    "badges": [
      "Premium",
      "New"
    ],
    "stock": 5,
    "image": "https://picsum.photos/500/650?5",
    "alt": "Gold Heels",
    "description": "Luxury gold heels for elegant evening looks."
  },
  {
    "id": "women-bag-1",
    "title": "Designer Handbag",
    "price": 149,
    "category": "women",
    "tags": [
      "premium"
    ],
    "badges": [
      "Premium"
    ],
    "stock": 8,
    "image": "https://picsum.photos/500/650?6",
    "alt": "Designer Handbag",
    "description": "Designer premium handbag with timeless style."
  },
  {
    "id": "sherwani-1",
    "title": "Premium Sherwani",
    "price": 129,
    "category": "men",
    "tags": [
      "premium",
      "limited"
    ],
    "badges": [
      "Premium",
      "Limited"
    ],
    "stock": 3,
    "image": "https://picsum.photos/500/650?7",
    "alt": "Premium Sherwani",
    "description": "Statement sherwani crafted for luxury weddings."
  },
  {
    "id": "men-jacket-1",
    "title": "Luxury Jacket",
    "price": 119,
    "category": "men",
    "tags": [
      "premium",
      "new"
    ],
    "badges": [
      "Premium",
      "New"
    ],
    "stock": 7,
    "image": "https://picsum.photos/500/650?8",
    "alt": "Luxury Jacket",
    "description": "Luxury jacket with premium fabric and fit."
  },
  {
    "id": "watch-1",
    "title": "Gold Watch",
    "price": 199,
    "category": "men",
    "tags": [
      "premium",
      "limited"
    ],
    "badges": [
      "Premium",
      "Limited"
    ],
    "stock": 2,
    "image": "https://picsum.photos/500/650?9",
    "alt": "Gold Watch",
    "description": "Premium gold watch with limited release."
  },
  {
    "id": "kids-coat-1",
    "title": "Kids Winter Coat",
    "price": 45,
    "category": "kids",
    "tags": [
      "premium"
    ],
    "badges": [
      "Premium"
    ],
    "stock": 9,
    "image": "https://picsum.photos/500/650?10",
    "alt": "Kids Winter Coat",
    "description": "Warm winter coat for kids with luxury comfort."
  },
  {
    "id": "kids-shoes-1",
    "title": "Kids Sneakers",
    "price": 25,
    "category": "kids",
    "tags": [],
    "badges": [],
    "stock": 20,
    "image": "https://picsum.photos/500/650?11",
    "alt": "Kids Sneakers",
    "description": "Comfortable sneakers for everyday kids adventures."
  },
  {
    "id": "kids-party-1",
    "title": "Kids Party Outfit",
    "price": 39,
    "category": "kids",
    "tags": [
      "premium",
      "new"
    ],
    "badges": [
      "Premium",
      "New"
    ],
    "stock": 6,
    "image": "https://picsum.photos/500/650?12",
    "alt": "Kids Party Outfit",
    "description": "Premium kids outfit designed for parties."
  },
  {
    "id": "women-coat-1",
    "title": "Women Winter Coat",
    "price": 110,
    "category": "women",
    "tags": [
      "limited"
    ],
    "badges": [
      "Limited"
    ],
    "stock": 4,
    "image": "https://picsum.photos/500/650?13",
    "alt": "Women Winter Coat",
    "description": "Limited coat with modern premium winter design."
  },
  {
    "id": "men-shoes-1",
    "title": "Leather Shoes",
    "price": 85,
    "category": "men",
    "tags": [],
    "badges": [],
    "stock": 14,
    "image": "https://picsum.photos/500/650?14",
    "alt": "Leather Shoes",
    "description": "Luxury leather shoes for formal and casual wear."
  },
  {
    "id": "perfume-1",
    "title": "Luxury Perfume",
    "price": 65,
    "category": "women",
    "tags": [
      "premium"
    ],
    "badges": [
      "Premium"
    ],
    "stock": 11,
    "image": "https://picsum.photos/500/650?15",
    "alt": "Luxury Perfume",
    "description": "Luxury fragrance with premium long-lasting notes."
  }
]

Code Example Three: Hybrid Approach (What Most Real Teams Do)

Most senior teams do this:

  • By default, responsive.

  • Techniques are used only when necessary.

Hybrid strategy example:

  • Responsive grid layout.

  • Image loading with adaptive algorithms.

  • Lazy-loaded components specific to each device.

The result is:

  • All devices have a good user experience.

  • Where it counts, best performance.

Here is a link to the live demo:

Below is the source code for this example, which is also available on my GitHub account:

The code can be explored, run locally, and used as a reference for your own work.

HTML 5 (index.html)

<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width,initial-scale=1" />
    <title>LuxuryStore (Hybrid)</title>

    <link rel="stylesheet" href="css/styles.css" />

    <meta
      name="description"
      content="Hybrid business example: responsive layout + adaptive performance optimizations."
    />
  </head>

  <body>
    <header class="topbar">
      <div class="container topbar__inner">
        <div class="brand">
          <div class="brand__name">LuxuryStore</div>
          <div class="brand__tag">
            Hybrid UI (Responsive layout + Adaptive performance)
          </div>
        </div>

        <div class="topbar__actions">
          <button class="btn btn--ghost" id="toggleFiltersBtn" type="button">
            Filters
          </button>

          <button
            class="btn btn--cart"
            id="cartBtn"
            type="button"
            aria-label="Open cart"
          >
            🛒 Cart <span class="badge" id="cartCount">0</span>
          </button>
        </div>
      </div>
    </header>

    <section class="hero">
      <div class="container hero__inner">
        <div class="hero__copy">
          <h1>Luxury Collection 2026</h1>
          <p>
            Hybrid architecture: a responsive layout for every device, plus
            adaptive loading for performance-heavy features.
          </p>

          <div class="hero__actions">
            <button
              class="btn btn--primary"
              id="shopNewArrivalsBtn"
              type="button"
            >
              Shop New Arrivals
            </button>
            <button class="btn btn--ghost" id="viewPremiumBtn" type="button">
              View Premium
            </button>
          </div>

          <div class="hero__badges">
            <span class="pill">Responsive Layout </span>
            <span class="pill">Adaptive Image Loading </span>
            <span class="pill">Desktop Enhancements</span>
          </div>
        </div>

        <picture class="hero__image">
          <source
            media="(min-width: 1100px)"
            srcset="https://picsum.photos/1100/800?hybrid=hero"
          />
          <source
            media="(min-width: 768px)"
            srcset="https://picsum.photos/850/650?hybrid=hero"
          />
          <img
            src="https://picsum.photos/600/450?hybrid=hero"
            alt="Luxury Fashion Hero"
            loading="eager"
          />
        </picture>
      </div>
    </section>

    <main class="container layout">
      <aside class="filters" id="filtersPanel" aria-label="Filters">
        <div class="filters__header">
          <h2>Filters</h2>

          <button
            type="button"
            class="filters-close"
            id="closeFiltersBtn"
            aria-label="Close filters"
          >
            ✕
          </button>
        </div>

        <div class="filter-group">
          <h3>Category</h3>

          <label class="check">
            <input type="checkbox" name="category" value="women" />
            <span>Women</span>
          </label>

          <label class="check">
            <input type="checkbox" name="category" value="men" />
            <span>Men</span>
          </label>

          <label class="check">
            <input type="checkbox" name="category" value="kids" />
            <span>Kids</span>
          </label>
        </div>

        <div class="filter-group">
          <h3>Tags</h3>

          <label class="check">
            <input type="checkbox" name="tag" value="premium" />
            <span>Premium</span>
          </label>

          <label class="check">
            <input type="checkbox" name="tag" value="new" />
            <span>New</span>
          </label>

          <label class="check">
            <input type="checkbox" name="tag" value="limited" />
            <span>Limited</span>
          </label>
        </div>

        <div class="filter-group">
          <h3>Price</h3>

          <label class="check">
            <input type="checkbox" name="price" value="under50" />
            <span>Under £50</span>
          </label>

          <label class="check">
            <input type="checkbox" name="price" value="50to150" />
            <span>£50–£150</span>
          </label>

          <label class="check">
            <input type="checkbox" name="price" value="150plus" />
            <span>£150+</span>
          </label>
        </div>

        <div class="filters-actions">
          <button type="button" id="clearFiltersBtn">Clear</button>
          <button type="button" id="applyFiltersBtn">Apply</button>
        </div>
      </aside>

      <section class="content">
        <div class="content__top">
          <h2 class="section-title">Featured Products</h2>

          <div id="desktopEnhancement" class="desktop-enhancement" hidden>
            <span class="pill pill--gold">Desktop Enhancement Enabled</span>
            <span class="muted">• quick compare mode</span>
          </div>
        </div>

        <div class="toolbar">
          <input
            id="searchInput"
            class="search"
            type="text"
            placeholder="Search products..."
            autocomplete="off"
            aria-label="Search products"
          />

          <select
            id="sortSelect"
            class="sort-select"
            aria-label="Sort products"
          >
            <option value="default">Sort: Default</option>
            <option value="priceLow">Price: Low to High</option>
            <option value="priceHigh">Price: High to Low</option>
            <option value="nameAZ">Name: A → Z</option>
            <option value="nameZA">Name: Z → A</option>
          </select>
        </div>

        <section class="grid" id="products" aria-label="Product grid"></section>
        <div class="pagination" id="pagination"></div>

        <footer class="footer">
          <div class="footer__row">
            <span>© LuxuryStore</span>
            <span class="muted">Hybrid Layout</span>
          </div>
        </footer>
      </section>
    </main>

    <div class="cart-overlay" id="cartOverlay" aria-hidden="true">
      <div class="cart-panel" role="dialog" aria-modal="true" aria-label="Cart">
        <div class="cart-panel__header">
          <h3>Your Cart</h3>
          <button
            class="cart-close"
            id="cartCloseBtn"
            aria-label="Close cart"
            type="button"
          >
            ✕
          </button>
        </div>

        <div id="cartItems" class="cart-items"></div>

        <div class="cart-panel__footer">
          <div class="cart-total">
            Total: <strong>£<span id="cartTotal">0</span></strong>
          </div>

          <div class="cart-actions">
            <button type="button" class="btn btn--ghost" id="clearCartBtn">
              Clear
            </button>
            <button type="button" class="btn btn--primary">Checkout</button>
          </div>
        </div>
      </div>
    </div>

    <script src="js/app.js"></script>
  </body>
</html>

CSS 3 (styles.css)

:root {
  --bg: #06060d;
  --surface: rgba(255, 255, 255, 0.06);
  --line: rgba(255, 255, 255, 0.12);
  --text: rgba(255, 255, 255, 0.92);
  --muted: rgba(255, 255, 255, 0.72);
  --gold: #d6b15e;
  --radius: 18px;
}

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  font-family:
    system-ui,
    -apple-system,
    Segoe UI,
    Roboto,
    Arial,
    sans-serif;
  background: var(--bg);
  color: var(--text);
}

body.no-scroll {
  overflow: hidden;
  height: 100vh;
}

.container {
  width: min(1200px, 92%);
  margin: auto;
}

.muted {
  color: var(--muted);
}

.topbar {
  position: sticky;
  top: 0;
  z-index: 50;
  backdrop-filter: blur(10px);
  background: rgba(0, 0, 0, 0.65);
  border-bottom: 1px solid var(--line);
}

.topbar__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 14px 0;
  gap: 12px;
}

.brand__name {
  font-weight: 900;
  letter-spacing: 0.5px;
}

.brand__tag {
  font-size: 12px;
  color: var(--muted);
  margin-top: 2px;
}

.topbar__actions {
  display: flex;
  align-items: center;
  gap: 10px;
}

.badge {
  background: var(--gold);
  color: var(--bg);
  font-weight: 900;
  border-radius: 999px;
  padding: 2px 10px;
  margin-left: 6px;
  font-size: 12px;
}

.btn {
  border-radius: 16px;
  padding: 12px 14px;
  border: 1px solid var(--line);
  cursor: pointer;
  font-weight: 800;
}

.btn--small {
  padding: 8px 10px;
  border-radius: 14px;
}

.btn--primary {
  border: none;
  background: var(--gold);
  color: var(--bg);
}

.btn--ghost {
  background: transparent;
  color: var(--text);
}

.btn--cart {
  background: var(--surface);
  color: var(--text);
}

.btn--full {
  width: 100%;
}

.hero {
  border-bottom: 1px solid var(--line);
  padding: 22px 0;
}

.hero__inner {
  display: grid;
  grid-template-columns: 1fr;
  gap: 18px;
  align-items: center;
}

.hero__copy h1 {
  margin: 0 0 10px;
  font-size: 30px;
}

.hero__copy p {
  margin: 0 0 14px;
  color: var(--muted);
  line-height: 1.6;
}

.hero__actions {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
}

.hero__badges {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
  margin-top: 14px;
}

.hero__image img {
  width: 100%;
  display: block;
  border-radius: var(--radius);
  border: 1px solid var(--line);
}

.pill {
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 8px 12px;
  font-size: 12px;
  color: var(--muted);
  background: rgba(255, 255, 255, 0.03);
}

.pill--gold {
  background: rgba(214, 177, 94, 0.15);
  border-color: rgba(214, 177, 94, 0.45);
  color: var(--text);
}

.layout {
  display: grid;
  grid-template-columns: 1fr;
  gap: 16px;
  padding: 18px 0;
}

.filters {
  border: 1px solid var(--line);
  background: var(--surface);
  border-radius: var(--radius);
  padding: 16px;
  color: var(--text);
}

.filters__header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 10px;
}

.filters__title {
  margin: 0;
  font-size: 18px;
  color: var(--gold);
}

.filter-group {
  margin-top: 14px;
  border-top: 1px solid rgba(255, 255, 255, 0.09);
  padding-top: 14px;
}

.filter-group h3,
.filter-group h4 {
  margin: 0 0 10px;
  font-size: 14px;
  color: var(--muted);
}

.filters label {
  display: flex;
  gap: 10px;
  align-items: center;
  margin: 10px 0;
  padding: 10px 10px;
  border-radius: 14px;
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid rgba(255, 255, 255, 0.08);
  cursor: pointer;
}

.filters label:hover {
  background: rgba(255, 255, 255, 0.06);
}

.filters input[type="checkbox"],
.filters input[type="radio"] {
  width: 18px;
  height: 18px;
  accent-color: var(--gold);
}

.filters-actions {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
  margin-top: 14px;
}

#applyFiltersBtn,
#clearFiltersBtn {
  width: 100%;
  padding: 12px 14px;
  border-radius: 16px;
  font-weight: 900;
  cursor: pointer;
  transition:
    transform 160ms ease,
    box-shadow 220ms ease,
    filter 200ms ease;
}

#clearFiltersBtn {
  border: 1px solid rgba(255, 255, 255, 0.14);
  background: rgba(255, 255, 255, 0.06);
  color: rgba(255, 255, 255, 0.92);
}

#clearFiltersBtn:hover {
  transform: translateY(-1px);
  box-shadow: 0 14px 30px rgba(0, 0, 0, 0.35);
}

#applyFiltersBtn {
  border: 1px solid rgba(214, 177, 94, 0.35);
  background: linear-gradient(
    135deg,
    rgba(214, 177, 94, 0.95),
    rgba(253, 160, 133, 0.9)
  );
  color: #0b1020;
  box-shadow: 0 16px 34px rgba(0, 0, 0, 0.32);
}

#applyFiltersBtn:hover {
  transform: translateY(-2px);
  filter: brightness(1.02);
  box-shadow:
    0 22px 44px rgba(0, 0, 0, 0.4),
    0 0 0 4px rgba(214, 177, 94, 0.14);
}

.filters-close,
#closeFiltersBtn {
  width: 42px;
  height: 42px;
  border-radius: 14px;
  border: 1px solid rgba(255, 255, 255, 0.14);
  background: rgba(255, 255, 255, 0.06);
  color: rgba(255, 255, 255, 0.92);
  cursor: pointer;
  font-size: 18px;
  font-weight: 900;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition:
    transform 160ms ease,
    box-shadow 220ms ease,
    border-color 220ms ease;
}

.filters-close:hover,
#closeFiltersBtn:hover {
  transform: translateY(-1px);
  border-color: rgba(214, 177, 94, 0.45);
  box-shadow: 0 14px 30px rgba(0, 0, 0, 0.35);
}

.content__top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  flex-wrap: wrap;
  margin-bottom: 14px;
}

.section-title {
  margin: 0;
  font-size: 20px;
  font-weight: 950;
  letter-spacing: 0.45px;
  line-height: 1;
  color: rgba(255, 255, 255, 0.92);
  padding: 12px 16px;
  border-radius: 18px;
  border: 1px solid rgba(255, 255, 255, 0.12);
  background: rgba(255, 255, 255, 0.05);
  box-shadow:
    0 18px 44px rgba(0, 0, 0, 0.28),
    0 0 0 1px rgba(214, 177, 94, 0.06);
  position: relative;
  overflow: hidden;
}

.section-title::before {
  content: "";
  position: absolute;
  inset: -1px;
  border-radius: 18px;
  pointer-events: none;
  background: linear-gradient(
    135deg,
    rgba(214, 177, 94, 0.2),
    rgba(253, 160, 133, 0.1)
  );
  opacity: 0.75;
}

.desktop-enhancement {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 10px;
  border-radius: 999px;
  background: rgba(214, 177, 94, 0.08);
  border: 1px solid rgba(214, 177, 94, 0.25);
  box-shadow: 0 12px 26px rgba(0, 0, 0, 0.22);
}

.desktop-enhancement .muted {
  font-size: 12px;
  opacity: 0.8;
}

.toolbar {
  display: flex;
  gap: 12px;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  margin: 0 0 16px;
  padding: 14px;
  border-radius: 20px;
  border: 1px solid rgba(255, 255, 255, 0.1);
  background: rgba(255, 255, 255, 0.04);
  box-shadow: 0 18px 44px rgba(0, 0, 0, 0.22);
}

#searchInput.search {
  flex: 1;
  min-width: 260px;
  height: 46px;
  padding: 0 16px;
  border-radius: 18px;
  border: 1px solid rgba(255, 255, 255, 0.14);
  background: rgba(255, 255, 255, 0.06);
  color: rgba(255, 255, 255, 0.92);
  font-size: 14px;
  font-weight: 700;
  outline: none;
  transition:
    border-color 200ms ease,
    box-shadow 200ms ease;
}

#searchInput.search::placeholder {
  color: rgba(255, 255, 255, 0.55);
  font-weight: 600;
}

#searchInput.search:focus {
  border-color: rgba(214, 177, 94, 0.55);
  box-shadow: 0 0 0 4px rgba(214, 177, 94, 0.12);
}

#sortSelect.sort-select {
  min-width: 240px;
  height: 46px;
  padding: 0 48px 0 16px;
  border-radius: 18px;
  border: 1px solid rgba(255, 255, 255, 0.14);
  background: rgba(255, 255, 255, 0.06);
  color: rgba(255, 255, 255, 0.92);
  font-size: 14px;
  font-weight: 750;
  cursor: pointer;
  outline: none;
  appearance: none;
  -webkit-appearance: none;
  -moz-appearance: none;
  transition:
    border-color 200ms ease,
    box-shadow 200ms ease;
  background-image:
    linear-gradient(45deg, transparent 50%, rgba(255, 255, 255, 0.7) 50%),
    linear-gradient(135deg, rgba(255, 255, 255, 0.7) 50%, transparent 50%);
  background-position:
    calc(100% - 20px) 50%,
    calc(100% - 14px) 50%;
  background-size:
    6px 6px,
    6px 6px;
  background-repeat: no-repeat;
}

#sortSelect.sort-select:focus {
  border-color: rgba(214, 177, 94, 0.55);
  box-shadow: 0 0 0 4px rgba(214, 177, 94, 0.12);
}

#sortSelect.sort-select option {
  background: #0b1020;
  color: rgba(255, 255, 255, 0.92);
}

.grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 14px;
  margin-top: 12px;
}

.card {
  border: 1px solid var(--line);
  background: var(--surface);
  border-radius: var(--radius);
  overflow: hidden;
}

.card img {
  width: 100%;
  display: block;
}

.card__body {
  padding: 14px;
}

.card__body h3,
.card__body h4 {
  margin: 0 0 8px;
  font-size: 16px;
}

.price {
  margin: 0 0 12px;
  font-weight: 900;
  color: var(--gold);
}

.add-to-cart,
.btn--add {
  width: 100%;
  margin-top: 10px;
  padding: 12px 14px;
  border-radius: 16px;
  border: 1px solid rgba(214, 177, 94, 0.28);
  background: linear-gradient(
    135deg,
    rgba(214, 177, 94, 0.95),
    rgba(253, 160, 133, 0.9)
  );
  color: #0b1020;
  font-weight: 900;
  letter-spacing: 0.3px;
  cursor: pointer;
  transition:
    transform 160ms ease,
    box-shadow 220ms ease,
    filter 200ms ease;
}

.add-to-cart:hover,
.btn--add:hover {
  transform: translateY(-2px);
  filter: brightness(1.02);
  box-shadow:
    0 18px 34px rgba(0, 0, 0, 0.34),
    0 0 0 4px rgba(214, 177, 94, 0.14);
}

.pagination {
  display: flex;
  gap: 8px;
  justify-content: center;
  align-items: center;
  margin: 18px 0 0;
  flex-wrap: wrap;
}

.page-btn {
  min-width: 40px;
  height: 40px;
  padding: 0 12px;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: rgba(255, 255, 255, 0.06);
  color: var(--text);
  cursor: pointer;
  font-weight: 900;
  transition:
    transform 160ms ease,
    box-shadow 220ms ease,
    border-color 220ms ease;
}

.page-btn:hover {
  transform: translateY(-1px);
  box-shadow: 0 14px 26px rgba(0, 0, 0, 0.35);
  border-color: rgba(214, 177, 94, 0.45);
}

.page-btn.active {
  color: var(--bg);
  background: linear-gradient(
    135deg,
    rgba(214, 177, 94, 0.95),
    rgba(253, 160, 133, 0.92)
  );
  border-color: rgba(214, 177, 94, 0.5);
  box-shadow: 0 18px 34px rgba(0, 0, 0, 0.34);
}

.page-btn:disabled {
  opacity: 0.45;
  cursor: not-allowed;
  transform: none;
  box-shadow: none;
}

.footer {
  margin-top: 14px;
  padding: 12px 2px;
  color: var(--muted);
  font-size: 12px;
}

.footer__row {
  display: flex;
  justify-content: space-between;
  gap: 12px;
}

.cart-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.58);
  backdrop-filter: blur(6px);
  display: none;
  align-items: flex-end;
  justify-content: flex-end;
  z-index: 999;
}

.cart-overlay.open {
  display: flex;
}

.cart-panel {
  width: min(460px, 100%);
  height: 100%;
  background: rgba(11, 16, 32, 0.96);
  color: var(--text);
  border-left: 1px solid rgba(255, 255, 255, 0.12);
  padding: 16px;
  display: flex;
  flex-direction: column;
  animation: cartSlideIn 220ms ease-out;
  box-shadow: -30px 0 80px rgba(0, 0, 0, 0.55);
}

@keyframes cartSlideIn {
  from {
    transform: translateX(18px);
    opacity: 0;
  }
  to {
    transform: translateX(0px);
    opacity: 1;
  }
}

.cart-panel__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding-bottom: 12px;
  margin-bottom: 12px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}

.cart-panel__header h3 {
  margin: 0;
  font-size: 18px;
  font-weight: 950;
  letter-spacing: 0.4px;
}

.cart-close {
  width: 42px;
  height: 42px;
  border-radius: 14px;
  border: 1px solid rgba(255, 255, 255, 0.14);
  background: rgba(255, 255, 255, 0.06);
  color: rgba(255, 255, 255, 0.92);
  cursor: pointer;
  font-size: 18px;
  font-weight: 900;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition:
    transform 160ms ease,
    box-shadow 220ms ease,
    border-color 220ms ease;
}

.cart-close:hover {
  transform: translateY(-1px);
  border-color: rgba(214, 177, 94, 0.45);
  box-shadow: 0 14px 30px rgba(0, 0, 0, 0.35);
}

.cart-items {
  flex: 1;
  overflow: auto;
  margin-top: 6px;
  padding-right: 6px;
}

.cart-item {
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 18px;
  padding: 14px;
  margin-bottom: 12px;
  background: rgba(255, 255, 255, 0.06);
  box-shadow: 0 14px 26px rgba(0, 0, 0, 0.22);
  display: grid;
  gap: 10px;
}

.cart-item__info strong {
  font-size: 14px;
  letter-spacing: 0.2px;
}

.cart-item__meta {
  opacity: 0.78;
  margin-top: 5px;
  font-size: 12px;
}

.cart-item__controls {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}

.qty-btn {
  width: 40px;
  height: 38px;
  border-radius: 14px;
  border: 1px solid rgba(255, 255, 255, 0.14);
  background: rgba(255, 255, 255, 0.07);
  color: rgba(255, 255, 255, 0.92);
  cursor: pointer;
  font-size: 16px;
  font-weight: 900;
  transition:
    transform 160ms ease,
    box-shadow 220ms ease;
}

.qty-btn:hover {
  transform: translateY(-1px);
  box-shadow: 0 14px 26px rgba(0, 0, 0, 0.25);
}

.qty {
  min-width: 28px;
  text-align: center;
  font-weight: 950;
  color: rgba(255, 255, 255, 0.92);
}

.remove-btn {
  margin-left: auto;
  padding: 10px 12px;
  border-radius: 14px;
  border: 1px solid rgba(255, 80, 80, 0.25);
  background: rgba(255, 80, 80, 0.1);
  color: rgba(255, 255, 255, 0.92);
  cursor: pointer;
  font-weight: 900;
  transition:
    transform 160ms ease,
    box-shadow 220ms ease,
    filter 200ms ease;
}

.remove-btn:hover {
  transform: translateY(-1px);
  filter: brightness(1.02);
  box-shadow: 0 16px 34px rgba(0, 0, 0, 0.32);
}

.cart-panel__footer {
  border-top: 1px solid rgba(255, 255, 255, 0.1);
  padding-top: 14px;
  margin-top: 12px;
}

.cart-total {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 12px;
  font-weight: 900;
  letter-spacing: 0.2px;
}

.cart-total strong {
  font-size: 16px;
  color: var(--gold);
}

.cart-actions {
  display: flex;
  gap: 10px;
}

.cart-empty {
  opacity: 0.82;
  padding: 18px 10px;
  border-radius: 18px;
  text-align: center;
  border: 1px dashed rgba(255, 255, 255, 0.18);
  background: rgba(255, 255, 255, 0.05);
}

@media (min-width: 768px) {
  .hero__inner {
    grid-template-columns: 1.2fr 0.8fr;
  }

  .grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (min-width: 1100px) {
  .layout {
    grid-template-columns: 280px 1fr;
    gap: 20px;
    align-items: start;
  }

  .filters {
    position: sticky;
    top: 92px;
    height: auto;
    align-self: start;
    max-height: calc(100vh - 120px);
    overflow: auto;
  }

  .grid {
    grid-template-columns: repeat(3, 1fr);
  }

  .hero__copy h1 {
    font-size: 44px;
  }
}

@media (max-width: 1099px) {
  .filters {
    display: none;
  }

  .filters.is-open {
    display: block;
    position: fixed;
    z-index: 120;
    top: 0;
    left: 0;
    right: 0;
    width: 100%;
    max-height: 100vh;
    overflow: auto;
    padding-bottom: 18px;
    border-radius: 0;
    box-shadow: 0 20px 60px rgba(0, 0, 0, 0.45);
    background: #05050b !important;
    border: 1px solid rgba(255, 255, 255, 0.14) !important;
  }

  .filters.is-open::before {
    content: "";
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.55);
    z-index: -1;
  }

  .filters.is-open .filter-group {
    border-top-color: rgba(255, 255, 255, 0.1) !important;
  }

  .filters.is-open label {
    background: rgba(255, 255, 255, 0.04) !important;
    border: 1px solid rgba(255, 255, 255, 0.1) !important;
  }

  .filters.is-open label:hover {
    background: rgba(255, 255, 255, 0.07) !important;
  }

  .filters-actions {
    grid-template-columns: 1fr;
  }

  .filters-close {
    display: inline-flex;
  }

  #toggleFiltersBtn {
    display: inline-flex;
  }
}

@media (min-width: 1100px) {
  .filters-close {
    display: none !important;
  }

  #toggleFiltersBtn {
    display: none !important;
  }
}

@media (max-width: 560px) {
  .toolbar {
    padding: 12px;
    gap: 10px;
    border-radius: 18px;
  }

  #searchInput.search,
  #sortSelect.sort-select {
    width: 100%;
    min-width: 100%;
  }

  .section-title {
    width: 100%;
    text-align: center;
  }

  .cart-panel {
    width: 100%;
    border-left: none;
    border-top: 1px solid rgba(255, 255, 255, 0.12);
  }

  .cart-actions {
    flex-direction: column;
  }

  .cart-actions .btn {
    width: 100%;
  }
}

JavaScript (app.js and desktop.bundle.js)

const EMBEDDED_PRODUCTS = [
  {
    id: "dress-1",
    title: "Luxury Dress",
    price: 89,
    category: "women",
    tags: ["premium", "new"],
    stock: 6,
    badges: ["Premium", "New"],
    image: "https://picsum.photos/500/650?1",
    alt: "Luxury Dress",
  },
  {
    id: "kurta-1",
    title: "Men Kurta",
    price: 49,
    category: "men",
    tags: ["premium"],
    stock: 10,
    badges: ["Premium"],
    image: "https://picsum.photos/500/650?2",
    alt: "Men Kurta",
  },
  {
    id: "kids-1",
    title: "Kids Outfit",
    price: 29,
    category: "kids",
    tags: ["new"],
    stock: 12,
    badges: ["New"],
    image: "https://picsum.photos/500/650?3",
    alt: "Kids Outfit",
  },
  {
    id: "abaya-1",
    title: "Luxury Abaya",
    price: 99,
    category: "women",
    tags: ["premium", "limited"],
    stock: 4,
    badges: ["Premium", "Limited"],
    image: "https://picsum.photos/500/650?4",
    alt: "Luxury Abaya",
  },
  {
    id: "heels-1",
    title: "Gold Heels",
    price: 75,
    category: "women",
    tags: ["premium", "new"],
    stock: 5,
    badges: ["Premium", "New"],
    image: "https://picsum.photos/500/650?5",
    alt: "Gold Heels",
  },
  {
    id: "women-bag-1",
    title: "Designer Handbag",
    price: 149,
    category: "women",
    tags: ["premium"],
    stock: 8,
    badges: ["Premium"],
    image: "https://picsum.photos/500/650?6",
    alt: "Designer Handbag",
  },
  {
    id: "sherwani-1",
    title: "Premium Sherwani",
    price: 129,
    category: "men",
    tags: ["premium", "limited"],
    stock: 3,
    badges: ["Premium", "Limited"],
    image: "https://picsum.photos/500/650?7",
    alt: "Premium Sherwani",
  },
  {
    id: "men-jacket-1",
    title: "Luxury Jacket",
    price: 119,
    category: "men",
    tags: ["premium", "new"],
    stock: 7,
    badges: ["Premium", "New"],
    image: "https://picsum.photos/500/650?8",
    alt: "Luxury Jacket",
  },
  {
    id: "watch-1",
    title: "Gold Watch",
    price: 199,
    category: "men",
    tags: ["premium", "limited"],
    stock: 2,
    badges: ["Premium", "Limited"],
    image: "https://picsum.photos/500/650?9",
    alt: "Gold Watch",
  },
  {
    id: "kids-coat-1",
    title: "Kids Winter Coat",
    price: 45,
    category: "kids",
    tags: ["premium"],
    stock: 9,
    badges: ["Premium"],
    image: "https://picsum.photos/500/650?10",
    alt: "Kids Winter Coat",
  },
  {
    id: "kids-shoes-1",
    title: "Kids Sneakers",
    price: 25,
    category: "kids",
    tags: [],
    stock: 20,
    badges: [],
    image: "https://picsum.photos/500/650?11",
    alt: "Kids Sneakers",
  },
  {
    id: "kids-party-1",
    title: "Kids Party Outfit",
    price: 39,
    category: "kids",
    tags: ["premium", "new"],
    stock: 6,
    badges: ["Premium", "New"],
    image: "https://picsum.photos/500/650?12",
    alt: "Kids Party Outfit",
  },
  {
    id: "women-coat-1",
    title: "Women Winter Coat",
    price: 110,
    category: "women",
    tags: ["limited"],
    stock: 4,
    badges: ["Limited"],
    image: "https://picsum.photos/500/650?13",
    alt: "Women Winter Coat",
  },
  {
    id: "men-shoes-1",
    title: "Leather Shoes",
    price: 85,
    category: "men",
    tags: [],
    stock: 14,
    badges: [],
    image: "https://picsum.photos/500/650?14",
    alt: "Leather Shoes",
  },
  {
    id: "perfume-1",
    title: "Luxury Perfume",
    price: 65,
    category: "women",
    tags: ["premium"],
    stock: 11,
    badges: ["Premium"],
    image: "https://picsum.photos/500/650?15",
    alt: "Luxury Perfume",
  },
];

function setLoading(isLoading) {
  const el = document.getElementById("loader");
  if (!el) return;
  if (isLoading) el.classList.remove("loader--hidden");
  else el.classList.add("loader--hidden");
}

(function () {
  const money = (n) => Number(n || 0).toFixed(2);

  const loadCart = () => {
    try {
      return JSON.parse(localStorage.getItem("luxury_cart") || "[]");
    } catch {
      return [];
    }
  };

  const saveCart = (cart) => {
    localStorage.setItem("luxury_cart", JSON.stringify(cart));
  };

  let cart = loadCart();
  let products = [];
  let activeQuickTag = null;
  let currentPage = 1;
  const pageSize = 9;

  const productsEl = document.getElementById("products");
  const paginationEl = document.getElementById("pagination");

  const cartBtn = document.getElementById("cartBtn");
  const cartOverlay = document.getElementById("cartOverlay");
  const cartCloseBtn = document.getElementById("cartCloseBtn");

  const cartItemsEl = document.getElementById("cartItems");
  const cartCountEl = document.getElementById("cartCount");
  const cartTotalEl = document.getElementById("cartTotal");
  const clearCartBtn = document.getElementById("clearCartBtn");

  const filtersPanel = document.getElementById("filtersPanel");
  const openFiltersBtn = document.getElementById("toggleFiltersBtn");
  const closeFiltersBtn = document.getElementById("closeFiltersBtn");

  const clearFiltersBtn = document.getElementById("clearFiltersBtn");
  const applyFiltersBtn = document.getElementById("applyFiltersBtn");

  const filterCheckboxes = document.querySelectorAll(
    '.filters input[type="checkbox"]'
  );

  const searchInput = document.getElementById("searchInput");
  const sortSelect = document.getElementById("sortSelect");

  const shopNewArrivalsBtn = document.getElementById("shopNewArrivalsBtn");
  const viewPremiumBtn = document.getElementById("viewPremiumBtn");

  function badgeClass(name) {
    const v = (name || "").toLowerCase();
    if (v === "premium") return "badge badge--premium";
    if (v === "new") return "badge badge--new";
    if (v === "limited") return "badge badge--limited";
    return "badge";
  }

  function openCart() {
    cartOverlay?.classList.add("open");
    cartOverlay?.setAttribute("aria-hidden", "false");
  }

  function closeCart() {
    cartOverlay?.classList.remove("open");
    cartOverlay?.setAttribute("aria-hidden", "true");
  }

  function isMobileMode() {
    return window.matchMedia("(max-width: 1099px)").matches;
  }

  function openFilters() {
    filtersPanel?.classList.add("is-open");
  }

  function closeFilters() {
    filtersPanel?.classList.remove("is-open");
  }

  function closeFiltersIfMobile() {
    if (isMobileMode()) closeFilters();
  }

  function renderProducts(list) {
    if (!productsEl) return;

    if (!list || list.length === 0) {
      productsEl.innerHTML = `<div class="empty-state">No products found.</div>`;
      return;
    }

    productsEl.innerHTML = list
      .map((p) => {
        const tagsCsv = (p.tags || []).join(",");
        const badgesHtml = (p.badges || [])
          .map((b) => `<span class="${badgeClass(b)}">${b}</span>`)
          .join("");

        return `
          <article class="card"
            data-id="${p.id}"
            data-title="${p.title}"
            data-price="${p.price}"
            data-category="${p.category}"
            data-tags="${tagsCsv}"
            data-stock="${p.stock}"
          >
            ${badgesHtml ? `<div class="badge-row">${badgesHtml}</div>` : ""}

            <img src="${p.image}" alt="${p.alt || p.title}" loading="lazy" />

            <div class="card__body">
              <h4>${p.title}</h4>
              <p class="price">£${money(p.price)}</p>
              <p class="stock">Only <strong>${p.stock}</strong> left</p>
              <button class="add-to-cart" type="button">Add to Cart</button>
            </div>
          </article>
        `;
      })
      .join("");
  }

  function renderPagination(totalItems) {
    if (!paginationEl) return;

    const totalPages = Math.max(1, Math.ceil(totalItems / pageSize));
    if (currentPage > totalPages) currentPage = totalPages;

    let html = "";

    html += `<button class="page-btn" data-page="${currentPage - 1}" ${
      currentPage === 1 ? "disabled" : ""
    }>‹</button>`;

    for (let p = 1; p <= totalPages; p++) {
      html += `<button class="page-btn ${
        p === currentPage ? "active" : ""
      }" data-page="${p}">${p}</button>`;
    }

    html += `<button class="page-btn" data-page="${currentPage + 1}" ${
      currentPage === totalPages ? "disabled" : ""
    }>›</button>`;

    paginationEl.innerHTML = html;
  }

  function addToCart(product) {
    const existing = cart.find((x) => x.id === product.id);
    const stock = Number(product.stock || 9999);
    const currentQty = existing?.qty || 0;

    if (currentQty >= stock) {
      alert(`Sorry! Only ${stock} available for "${product.title}".`);
      return;
    }

    if (existing) existing.qty += 1;
    else cart.push({ ...product, qty: 1 });

    saveCart(cart);
    renderCart();
  }

  function removeFromCart(id) {
    cart = cart.filter((x) => x.id !== id);
    saveCart(cart);
    renderCart();
  }

  function changeQty(id, delta) {
    const item = cart.find((x) => x.id === id);
    if (!item) return;

    item.qty += delta;

    if (item.qty <= 0) {
      removeFromCart(id);
      return;
    }

    const p = products.find((x) => x.id === id);
    const stock = Number(p?.stock || 9999);
    if (item.qty > stock) item.qty = stock;

    saveCart(cart);
    renderCart();
  }

  function clearCart() {
    cart = [];
    saveCart(cart);
    renderCart();
  }

  function renderCart() {
    const totalQty = cart.reduce((sum, x) => sum + x.qty, 0);
    const totalPrice = cart.reduce((sum, x) => sum + x.qty * x.price, 0);

    if (cartCountEl) cartCountEl.textContent = totalQty;
    if (cartTotalEl) cartTotalEl.textContent = money(totalPrice);

    if (!cartItemsEl) return;

    if (cart.length === 0) {
      cartItemsEl.innerHTML = `<p class="cart-empty">Your cart is empty.</p>`;
      return;
    }

    cartItemsEl.innerHTML = cart
      .map(
        (item) => `
          <div class="cart-item">
            <div class="cart-item__info">
              <strong>${item.title}</strong>
              <div class="cart-item__meta">£${money(item.price)} each</div>
            </div>

            <div class="cart-item__controls">
              <button class="qty-btn" data-action="dec" data-id="${item.id}" type="button">−</button>
              <span class="qty">${item.qty}</span>
              <button class="qty-btn" data-action="inc" data-id="${item.id}" type="button">+</button>
              <button class="remove-btn" data-action="remove" data-id="${item.id}" type="button">Remove</button>
            </div>
          </div>
        `
      )
      .join("");
  }

  function getSelectedFilters() {
    const selectedCategories = Array.from(
      document.querySelectorAll('input[name="category"]:checked')
    ).map((x) => x.value);

    const selectedTags = Array.from(
      document.querySelectorAll('input[name="tag"]:checked')
    ).map((x) => x.value);

    const selectedPrices = Array.from(
      document.querySelectorAll('input[name="price"]:checked')
    ).map((x) => x.value);

    return { selectedCategories, selectedTags, selectedPrices };
  }

  function matchesPriceRange(product, selectedPrices) {
    if (!selectedPrices || selectedPrices.length === 0) return true;

    const price = Number(product.price || 0);

    const under50 = price < 50;
    const between50to150 = price >= 50 && price <= 150;
    const plus150 = price > 150;

    return selectedPrices.some((range) => {
      if (range === "under50") return under50;
      if (range === "50to150") return between50to150;
      if (range === "150plus") return plus150;
      return true;
    });
  }

  function matchesFilters(product, filters) {
    const categoryOk =
      filters.selectedCategories.length === 0 ||
      filters.selectedCategories.includes(product.category);

    const tags = product.tags || [];

    const tagsOk =
      filters.selectedTags.length === 0 ||
      filters.selectedTags.every((t) => tags.includes(t));

    const quickOk = !activeQuickTag || tags.includes(activeQuickTag);
    const priceOk = matchesPriceRange(product, filters.selectedPrices);

    return categoryOk && tagsOk && quickOk && priceOk;
  }

  function applyFilters({ scroll = false } = {}) {
    const filters = getSelectedFilters();
    const search = (searchInput?.value || "").trim().toLowerCase();
    const sort = sortSelect?.value || "default";

    let visible = products.filter((p) => matchesFilters(p, filters));

    if (search) {
      visible = visible.filter((p) => p.title.toLowerCase().includes(search));
    }

    visible.sort((a, b) => {
      if (sort === "priceLow") return a.price - b.price;
      if (sort === "priceHigh") return b.price - a.price;
      if (sort === "nameAZ") return a.title.localeCompare(b.title);
      if (sort === "nameZA") return b.title.localeCompare(a.title);
      return 0;
    });

    const totalItems = visible.length;
    const totalPages = Math.max(1, Math.ceil(totalItems / pageSize));
    if (currentPage > totalPages) currentPage = totalPages;

    const start = (currentPage - 1) * pageSize;
    const paged = visible.slice(start, start + pageSize);

    renderProducts(paged);
    renderPagination(totalItems);

    if (scroll) {
      productsEl?.scrollIntoView({
        behavior: "smooth",
        block: "start",
      });
    }
  }

  async function loadProducts() {
    const banner = document.getElementById("dataStatus");

    const showBanner = (msg, kind) => {
      if (!banner) return;
      banner.textContent = msg;
      banner.dataset.kind = kind || "info";
      banner.classList.remove("status--hidden");
    };

    const urls = ["data/products.json", "./data/products.json"];

    for (const url of urls) {
      try {
        const res = await fetch(url, { cache: "no-store" });
        if (!res.ok) continue;

        const data = await res.json();
        if (Array.isArray(data) && data.length > 0) {
          products = data;
          banner?.classList.add("status--hidden");
          return;
        }
      } catch {
        // ignore
      }
    }

    products = Array.isArray(EMBEDDED_PRODUCTS) ? EMBEDDED_PRODUCTS : [];
    if (products.length > 0) {
      showBanner(
        "Loaded embedded products (products.json blocked). Run with a local server for live JSON loading.",
        "warn"
      );
    } else {
      showBanner(
        "No products could be loaded. Ensure data/products.json exists and run via local server.",
        "error"
      );
    }
  }

 
  productsEl?.addEventListener("click", (e) => {
    const btn = e.target.closest(".add-to-cart");
    if (!btn) return;

    const card = btn.closest(".card");
    if (!card) return;

    const productId = card.dataset.id;
    const p = products.find((x) => x.id === productId);
    if (!p) return;

    addToCart({
      id: p.id,
      title: p.title,
      price: Number(p.price || 0),
      stock: Number(p.stock || 9999),
    });

    openCart();
  });

 
  cartItemsEl?.addEventListener("click", (e) => {
    const actionBtn = e.target.closest("[data-action]");
    if (!actionBtn) return;

    const action = actionBtn.dataset.action;
    const id = actionBtn.dataset.id;

    if (action === "remove") removeFromCart(id);
    if (action === "inc") changeQty(id, +1);
    if (action === "dec") changeQty(id, -1);
  });

 
  paginationEl?.addEventListener("click", (e) => {
    const btn = e.target.closest(".page-btn");
    if (!btn || btn.disabled) return;

    currentPage = Number(btn.dataset.page || 1);
    applyFilters({ scroll: true });
  });

 
  cartBtn?.addEventListener("click", openCart);
  cartCloseBtn?.addEventListener("click", closeCart);

  cartOverlay?.addEventListener("click", (e) => {
    if (e.target === cartOverlay) closeCart();
  });

 
  openFiltersBtn?.addEventListener("click", openFilters);
  closeFiltersBtn?.addEventListener("click", closeFilters);

 
  document.addEventListener("click", (e) => {
    if (!isMobileMode()) return;
    if (!filtersPanel?.classList.contains("is-open")) return;

    const inside = e.target.closest("#filtersPanel");
    const toggleBtn = e.target.closest("#toggleFiltersBtn");

    if (!inside && !toggleBtn) closeFilters();
  });

 
  document.addEventListener("keydown", (e) => {
    if (e.key === "Escape") {
      closeCart();
      closeFilters();
    }
  });

  
  clearCartBtn?.addEventListener("click", clearCart);

 
  clearFiltersBtn?.addEventListener("click", () => {
    filterCheckboxes.forEach((cb) => (cb.checked = false));
    if (searchInput) searchInput.value = "";
    if (sortSelect) sortSelect.value = "default";

    activeQuickTag = null;
    currentPage = 1;

    applyFilters({ scroll: true });
    closeFiltersIfMobile();
  });

 
  applyFiltersBtn?.addEventListener("click", () => {
    activeQuickTag = null;
    currentPage = 1;

    applyFilters({ scroll: true });
    closeFiltersIfMobile();
  });

  
  filterCheckboxes.forEach((cb) =>
    cb.addEventListener("change", () => {
      activeQuickTag = null;
      currentPage = 1;
      applyFilters();
    })
  );

 
  searchInput?.addEventListener("input", () => {
    activeQuickTag = null;
    currentPage = 1;
    applyFilters();
  });

  sortSelect?.addEventListener("change", () => {
    activeQuickTag = null;
    currentPage = 1;
    applyFilters();
  });

  
  shopNewArrivalsBtn?.addEventListener("click", () => {
    filterCheckboxes.forEach((cb) => (cb.checked = false));
    if (searchInput) searchInput.value = "";
    if (sortSelect) sortSelect.value = "default";

    activeQuickTag = "new";
    currentPage = 1;

    applyFilters({ scroll: true });
  });

  viewPremiumBtn?.addEventListener("click", () => {
    filterCheckboxes.forEach((cb) => (cb.checked = false));
    if (searchInput) searchInput.value = "";
    if (sortSelect) sortSelect.value = "default";

    activeQuickTag = "premium";
    currentPage = 1;

    applyFilters({ scroll: true });
  });


  document.addEventListener("DOMContentLoaded", async () => {
    renderCart();
    setLoading(true);
    await loadProducts();
    setLoading(false);
    currentPage = 1;
    applyFilters();
  });
})();

export function initDesktopEnhancements() {
  console.log("Hybrid desktop-only module enabled ");
  document.body.classList.add("desktop-enhanced");
}

JSON (products.json)

[
  {
    "id": "dress-1",
    "title": "Luxury Dress",
    "price": 89,
    "category": "women",
    "tags": ["premium", "new"],
    "stock": 6,
    "badges": ["Premium", "New"],
    "image": "https://picsum.photos/500/650?1",
    "alt": "Luxury Dress"
  },
  {
    "id": "kurta-1",
    "title": "Men Kurta",
    "price": 49,
    "category": "men",
    "tags": ["premium"],
    "stock": 10,
    "badges": ["Premium"],
    "image": "https://picsum.photos/500/650?2",
    "alt": "Men Kurta"
  },
  {
    "id": "kids-1",
    "title": "Kids Outfit",
    "price": 29,
    "category": "kids",
    "tags": ["new"],
    "stock": 12,
    "badges": ["New"],
    "image": "https://picsum.photos/500/650?3",
    "alt": "Kids Outfit"
  },
  {
    "id": "abaya-1",
    "title": "Luxury Abaya",
    "price": 99,
    "category": "women",
    "tags": ["premium", "limited"],
    "stock": 4,
    "badges": ["Premium", "Limited"],
    "image": "https://picsum.photos/500/650?4",
    "alt": "Luxury Abaya"
  },
  {
    "id": "heels-1",
    "title": "Gold Heels",
    "price": 75,
    "category": "women",
    "tags": ["premium", "new"],
    "stock": 5,
    "badges": ["Premium", "New"],
    "image": "https://picsum.photos/500/650?5",
    "alt": "Gold Heels"
  },
  {
    "id": "women-bag-1",
    "title": "Designer Handbag",
    "price": 149,
    "category": "women",
    "tags": ["premium"],
    "stock": 8,
    "badges": ["Premium"],
    "image": "https://picsum.photos/500/650?6",
    "alt": "Designer Handbag"
  },
  {
    "id": "sherwani-1",
    "title": "Premium Sherwani",
    "price": 129,
    "category": "men",
    "tags": ["premium", "limited"],
    "stock": 3,
    "badges": ["Premium", "Limited"],
    "image": "https://picsum.photos/500/650?7",
    "alt": "Premium Sherwani"
  },
  {
    "id": "men-jacket-1",
    "title": "Luxury Jacket",
    "price": 119,
    "category": "men",
    "tags": ["premium", "new"],
    "stock": 7,
    "badges": ["Premium", "New"],
    "image": "https://picsum.photos/500/650?8",
    "alt": "Luxury Jacket"
  },
  {
    "id": "watch-1",
    "title": "Gold Watch",
    "price": 199,
    "category": "men",
    "tags": ["premium", "limited"],
    "stock": 2,
    "badges": ["Premium", "Limited"],
    "image": "https://picsum.photos/500/650?9",
    "alt": "Gold Watch"
  },
  {
    "id": "kids-coat-1",
    "title": "Kids Winter Coat",
    "price": 45,
    "category": "kids",
    "tags": ["premium"],
    "stock": 9,
    "badges": ["Premium"],
    "image": "https://picsum.photos/500/650?10",
    "alt": "Kids Winter Coat"
  },
  {
    "id": "kids-shoes-1",
    "title": "Kids Sneakers",
    "price": 25,
    "category": "kids",
    "tags": [],
    "stock": 20,
    "badges": [],
    "image": "https://picsum.photos/500/650?11",
    "alt": "Kids Sneakers"
  },
  {
    "id": "kids-party-1",
    "title": "Kids Party Outfit",
    "price": 39,
    "category": "kids",
    "tags": ["premium", "new"],
    "stock": 6,
    "badges": ["Premium", "New"],
    "image": "https://picsum.photos/500/650?12",
    "alt": "Kids Party Outfit"
  },
  {
    "id": "women-coat-1",
    "title": "Women Winter Coat",
    "price": 110,
    "category": "women",
    "tags": ["limited"],
    "stock": 4,
    "badges": ["Limited"],
    "image": "https://picsum.photos/500/650?13",
    "alt": "Women Winter Coat"
  },
  {
    "id": "men-shoes-1",
    "title": "Leather Shoes",
    "price": 85,
    "category": "men",
    "tags": [],
    "stock": 14,
    "badges": [],
    "image": "https://picsum.photos/500/650?14",
    "alt": "Leather Shoes"
  },
  {
    "id": "perfume-1",
    "title": "Luxury Perfume",
    "price": 65,
    "category": "women",
    "tags": ["premium"],
    "stock": 11,
    "badges": ["Premium"],
    "image": "https://picsum.photos/500/650?15",
    "alt": "Luxury Perfume"
  }
]

When Should You Use Each Approach?

When to choose responsive:

  • Public website/marketing website/.

  • E-commerce site.

  • Must be optimised for search engines.

  • Multiple device types are expected.

  • Long-term maintenance.

Adaptive is appropriate for the following situations:

  • It's an internal portal with controlled devices.

  • It's an internal portal with controlled devices.

  • The UI is heavy and needs to be optimised.

  • Differently for each device.

  • Devices are controlled by an internal portal.

Summary

Building for a real business isn't about responsive vs adaptive design trends - it's about delivery strategies.

  • Due to its flexibility and maintainability, responsive design is the default for most projects.

  • Performance and device-specific UX are more important than simplicity when it comes to adaptive design.

  • The best middle ground is often a hybrid approach.

  • Think like a tech lead:
    Choose what reduces risk, improves performance, and reduces long-term maintenance.

The code for this article can be found on my GitHub Repository: https://github.com/ziggyrafiq/responsive-vs-adaptive-websites-guide