.shop-layout {
  max-width: var(--shop-max-width);
  margin: 0 auto;
  padding: 44px 48px;
  display: grid;
  grid-template-columns: var(--shop-sidebar-width) 1fr;
  gap: 40px;
  align-items: start;
}
@media (max-width: 979px) { .shop-layout { grid-template-columns: 1fr; } }
@media (max-width: 639px) { .shop-layout { padding: 24px 20px; gap: 24px; } }

.filter-sidebar {
  background: var(--color-white);
  border-radius: var(--radius-category-card);
  padding: 28px 24px;
  position: sticky;
  top: 130px;
}
@media (max-width: 979px) { .filter-sidebar { position: static; } }
.filter-sidebar__title { font-family: var(--font-serif); font-size: 17px; margin-bottom: 20px; display: flex; align-items: center; justify-content: space-between; }
.filter-sidebar__close { display: none; background: none; border: none; cursor: pointer; color: var(--color-text-dark); width: 32px; height: 32px; align-items: center; justify-content: center; }

/* Mobile filter trigger + bottom sheet -- real bug fix: the sidebar
   above used to render as a full-height card stacked directly above the
   product grid on every mobile page load, the "huge desktop sidebar
   above the products" anti-pattern. Desktop is completely untouched
   (everything below is inside max-width:979px). */
.filter-trigger { display: none; }
.filter-overlay { display: none; }
.sort-trigger, .sort-overlay, .sort-sheet { display: none; }
@media (max-width: 979px) {
  .filter-trigger {
    display: flex; align-items: center; justify-content: center; gap: 8px;
    width: calc(100% - 40px); margin: 20px auto 0;
    height: 48px; border-radius: var(--radius-button);
    background: var(--color-charcoal-primary); color: var(--color-beige-light);
    border: none; font-size: 12.5px; font-weight: 700; letter-spacing: .06em;
    cursor: pointer;
  }
  .filter-sidebar__close { display: flex; }
  .filter-overlay {
    display: block;
    position: fixed; inset: 0; z-index: 220;
    background: rgba(10, 9, 8, 0);
    transition: background 260ms ease;
  }
  .filter-overlay.is-open { background: rgba(10, 9, 8, .55); }
  .filter-sidebar {
    position: fixed; inset: auto 0 0 0; z-index: 221;
    max-height: 85vh;
    border-radius: 20px 20px 0 0;
    overflow-y: auto;
    padding: 20px 20px max(20px, env(safe-area-inset-bottom));
    transform: translateY(100%);
    transition: transform 300ms cubic-bezier(0.22, 1, 0.36, 1);
  }
  .filter-sidebar.is-open { transform: translateY(0); }
  /* Drag-handle affordance, purely visual -- signals "this sheet can be
     dismissed" the way a real bottom sheet does, even without wiring up
     an actual drag gesture (overlay-click/close-button/Escape already
     cover dismissal). */
  .filter-sidebar::before {
    content: "";
    display: block;
    width: 36px; height: 4px; border-radius: 2px;
    background: rgba(0, 0, 0, .15);
    margin: 0 auto 16px;
  }
  .filter-sidebar__actions { display: flex; gap: 10px; margin-top: 8px; }
  .filter-sidebar__actions .btn { margin: 0; flex: 1; min-width: 0; width: auto; }

  /* Sort bottom sheet (mobile motion overhaul, 2026-08-21) -- same real
     translateY(100%)->0 sheet pattern as .filter-sidebar above, now
     referencing the shared motion tokens instead of the filter sheet's
     own hardcoded 300ms/260ms (that one is untouched/unregressed on
     purpose; new work uses the consolidated tokens going forward). */
  .sort-trigger { display: flex; width: auto; margin: 0; padding: 0 20px; flex: 1; }
  #shop-sort-select { display: none; }
  .sort-overlay {
    display: block;
    position: fixed; inset: 0; z-index: 220;
    background: rgba(10, 9, 8, 0);
    transition: background var(--motion-normal) ease;
  }
  .sort-overlay.is-open { background: rgba(10, 9, 8, .55); }
  .sort-sheet {
    display: block;
    position: fixed; inset: auto 0 0 0; z-index: 221;
    background: var(--color-white);
    border-radius: 20px 20px 0 0;
    padding: 20px 20px max(20px, env(safe-area-inset-bottom));
    transform: translateY(100%);
    transition: transform var(--motion-normal) var(--ease-premium);
  }
  .sort-sheet.is-open { transform: translateY(0); }
  .sort-sheet::before {
    content: "";
    display: block;
    width: 36px; height: 4px; border-radius: 2px;
    background: rgba(0, 0, 0, .15);
    margin: 0 auto 16px;
  }
  .sort-sheet__title {
    font-family: var(--font-serif); font-size: 17px; margin-bottom: 12px;
    display: flex; align-items: center; justify-content: space-between;
  }
  .sort-option {
    display: flex; align-items: center; justify-content: space-between;
    width: 100%; text-align: left; background: none; border: none;
    padding: 14px 4px; min-height: 44px; font-size: 14.5px;
    color: var(--color-text-dark); cursor: pointer;
    border-bottom: 1px solid rgba(0,0,0,.06);
  }
  .sort-option:last-child { border-bottom: none; }
  .sort-option.is-active { color: var(--color-gold-accent); font-weight: 700; }
  .sort-option svg { color: var(--color-gold-accent); flex-shrink: 0; }
}
.filter-group { margin-bottom: 26px; }
.filter-group__label { font-size: 12px; font-weight: 700; letter-spacing: .06em; color: var(--color-text-dark-dim-2); margin-bottom: 14px; text-transform: uppercase; }
.filter-group label.filter-option { display: flex; align-items: center; gap: 10px; padding: 9px 0; cursor: pointer; font-size: 13.5px; }
/* The real filter sidebar only ever renders type=radio for
   category/leather and type=range for price -- type=checkbox doesn't
   actually exist anywhere in filter_sidebar.html, confirmed by
   inspecting the real live DOM. The original rule here silently matched
   nothing; radio is the one that actually needed the size bump. */
.filter-group input[type=checkbox], .filter-group input[type=radio] { accent-color: var(--color-gold-accent); width: 18px; height: 18px; }
.filter-group input[type=range] { width: 100%; accent-color: var(--color-gold-accent); }
/* Real subcategories (Bifold Wallets, Crossbody Bags, etc.) nested under
   their parent -- indented and slightly smaller so the hierarchy reads
   at a glance without a second heading per group. */
.filter-subgroup { padding-left: 26px; margin-top: -2px; margin-bottom: 4px; }
.filter-group label.filter-option.filter-option--child { font-size: 12.5px; padding: 6px 0; }
.filter-option--child input[type=radio] { width: 15px; height: 15px; }
.filter-option__swatch { width: 15px; height: 15px; border-radius: 50%; flex-shrink: 0; border: 1px solid rgba(0,0,0,.15); }

.shop-toolbar {
  display: flex; justify-content: space-between; align-items: center;
  margin-bottom: 26px; flex-wrap: wrap; gap: 14px;
}
.shop-toolbar__count { font-size: 13.5px; color: var(--color-text-dark-dim); }
.shop-toolbar__controls { display: flex; gap: 14px; align-items: center; flex-wrap: wrap; }
.shop-toolbar__controls input, .shop-toolbar__controls select {
  border: 1px solid #ddd; border-radius: 8px; padding: 10px 14px; font-size: 13px; outline: none; background: var(--color-white);
}

.pagination { display: flex; gap: 8px; justify-content: center; margin-top: 40px; }
.pagination a, .pagination span {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 36px; height: 36px; border-radius: 8px;
  font-size: 13px; border: 1px solid #ddd; color: var(--color-text-dark);
}
.pagination .is-current { background: var(--color-charcoal-primary); color: var(--color-beige-light); border-color: var(--color-charcoal-primary); }

/* User-reported and confirmed live: despite its own name, this had a
   hardcoded DARK charcoal background (var(--color-charcoal-primary))
   -- a jarring solid-black rectangle sitting inside the otherwise
   light-themed Shop/Collections pages (both wrapped in .bg-light,
   base.css) instead of the light styling its name promises. Its
   .trust-bar__item .label also inherited home.css's dark-page default
   (color: var(--color-beige-light), a near-white) via the shared
   .trust-bar__item class, plus a redundant inline
   style="color:#F5F2EC" in the templates on top of that -- exactly
   the light-on-dark pairing this section's own background made
   necessary, which is precisely backwards once the background is
   fixed to be genuinely light. Reusing the same tokens the rest of
   this light page already uses (.filter-group__label etc., above in
   this file) instead of inventing new ones. */
/* User-reported follow-up, confirmed live: even after the color fix
   above, items rendered as icon-above-text blocks with no gap and
   wrapped 1/2/1 per row instead of a clean grid. Root cause: this
   whole component's REAL layout -- display:flex, align-items:center,
   gap, min-width, label/sub font sizing -- lives entirely in
   home.css's own .trust-bar__item rule (measured live:
   getComputedStyle returned display:block here). Shop/Collections
   never load home.css at all (only base.html's global stylesheets +
   this file) -- confirmed by grepping every <link> both pages
   actually include -- so .trust-bar__item had zero real layout on
   this page, just whatever a bare <div> defaults to. This scopes a
   complete, self-contained copy of that layout to .trust-strip-light
   instead of depending on a stylesheet this page was never going to
   load. */
.trust-strip-light {
  background: var(--color-beige-light);
  padding: 34px 48px;
  display: flex; flex-wrap: wrap; gap: 24px; justify-content: space-around;
}
.trust-strip-light .trust-bar__item { display: flex; align-items: center; gap: 12px; min-width: 200px; color: var(--color-brown-leather); }
.trust-strip-light .trust-bar__item .label { font-size: 13px; font-weight: 600; color: var(--color-text-dark) !important; }
.trust-strip-light .trust-bar__item .sub { font-size: 11.5px; color: var(--color-text-dark-dim-2); }
@media (max-width: 639px) {
  /* Same "flat 48px padding, no mobile override" gap already found and
     fixed elsewhere this session -- 96px eaten from a 375px viewport
     left ~279px, not enough room for even two 200px-min-width items,
     so they wrapped 1/2/1 by wrapping happenstance rather than a
     deliberate grid. A real 2-column grid reads as intentional. */
  .trust-strip-light { padding: 24px 20px; display: grid; grid-template-columns: 1fr 1fr; gap: 20px; }
  .trust-strip-light .trust-bar__item { min-width: 0; }
}
