/* =====================================================================
   ProdigixTheme - styles.css
   Clean, modern, mobile-responsive nopCommerce 4.90 theme.

   Colors are driven by CSS custom properties (--pdx-*). The
   Nop.Plugin.Prodigix.Theme1 plugin injects a <style> block in <head>
   that sets these from admin-configured settings; the values below are
   just fallback defaults so the theme still looks correct if the
   plugin is ever disabled.
   ===================================================================== */

:root {
  --pdx-primary: #2A6FDB;
  --pdx-secondary: #1B4C9C;
  --pdx-header-bg: #FFFFFF;
  --pdx-header-text: #22262A;
  --pdx-subheading: #5B6472;
  --pdx-button-bg: #2A6FDB;
  --pdx-button-text: #FFFFFF;
  --pdx-button-hover-bg: #1B4C9C;
  --pdx-footer-bg: #22262A;
  --pdx-footer-text: #C9CED6;
  --pdx-footer-title-color: #FFFFFF;
  --pdx-drawer-header-bg: #FFFFFF;
  --pdx-drawer-bg: #FFFFFF;
  --pdx-button-radius: 0px;
  /* Configure > Images > "Image corner radius" - plain product-photo thumbnails only (cart/
     wishlist line-item thumbnail, product details main image + thumbnail strip, "recently viewed
     products" thumbnails) - deliberately separate from --pdx-card-radius below, which only ever
     affects product CARD containers on grid listings. */
  --pdx-image-radius: 8px;
  --pdx-header2-bg: #FFFFFF;
  --pdx-header2-text: #2A2E34;
  --pdx-card-title-color: #2A2E34;
  --pdx-card-title-hover-color: #2A6FDB;
  --pdx-card-desc-color: #6B7280;
  --pdx-card-details-bg: #FFFFFF;
  --pdx-card-radius: 10px;
  --pdx-card-price-color: #2A6FDB;
  --pdx-card-old-price-color: #6B7280;
  --pdx-card-cart-bg: #2A6FDB;
  --pdx-card-cart-text: #FFFFFF;
  --pdx-card-cart-hover-bg: #1B4C9C;
  --pdx-card-border-width: 0px;
  --pdx-card-border-color: #E4E7EC;
  --pdx-subcat-bg: #F7F8FA;
  --pdx-subcat-text: #2A2E34;
  --pdx-section-bg-categories: #FFFFFF;
  --pdx-section-bg-featured: #FFFFFF;
  --pdx-section-bg-bestsellers: #FFFFFF;
  --pdx-section-bg-image-categories: none;
  --pdx-section-bg-image-featured: none;
  --pdx-section-bg-image-bestsellers: none;
  --pdx-section-bg-news: #FFFFFF;
  --pdx-section-bg-polls: #FFFFFF;
  --pdx-section-bg-image-news: none;
  --pdx-section-bg-image-polls: none;

  /* Structural tokens - not admin-configurable, but centralized here */
  --pdx-body-bg: #F7F8FA;
  --pdx-surface: #FFFFFF;
  --pdx-border: #E4E7EC;
  --pdx-text: #2A2E34;
  --pdx-text-muted: #6B7280;
  --pdx-danger: #D5323F;
  --pdx-success: #1E8E5A;
  --pdx-radius: 10px;
  --pdx-radius-sm: 6px;
  --pdx-shadow: 0 1px 2px rgba(16, 24, 40, .06), 0 1px 3px rgba(16, 24, 40, .08);
  --pdx-shadow-md: 0 4px 12px rgba(16, 24, 40, .10);
  --pdx-container: 1280px;
  /* separate from --pdx-container above (which caps the page's main content column) so the
     header's own two bars (.header-top-inner, .header-lower - see "HEADER" section below) can be
     a different width without dragging the rest of the site's content along with it. Wider than
     --pdx-container by default so the header reads as a full-width band relative to the narrower
     content column beneath it. */
  --pdx-header-container: 1380px;
  --pdx-font: "Montserrat", sans-serif;
  --pdx-drawer-padding: 24px;
  /* shared slide-out panel width for the cart/search/mobile-menu drawers (see .flyout-cart,
     .search-drawer, .menu-container .menu) at tablet size and up - all three now match this one
     value (previously 400px/460px/320px respectively - three different widths) rather than each
     hardcoding their own. Value matches what .search-drawer used to be, per spec ("the width of
     search on tablet"). Below 767px this is overridden to 100% for all three instead - see that
     @media block further down. */
  --pdx-drawer-width: 460px;
}

/* =========================== RESET =========================== */

* { margin: 0; padding: 0; text-decoration: none; box-sizing: border-box; }
html { -webkit-text-size-adjust: none; scroll-behavior: smooth; }
ol, ul { list-style: none; }
a img { border: none; }
img { max-width: 100%; display: block; }
script { display: none !important; }

button,
input[type="button"],
input[type="submit"],
input[type="reset"] {
  -webkit-appearance: none;
  border-radius: var(--pdx-button-radius, 0px);
}

/* =========================== BASE =========================== */

body {
  max-width: 100%;
  overflow-x: hidden;
  background-color: var(--pdx-body-bg);
  font: 15px/1.55 var(--pdx-font);
  color: var(--pdx-text);
  -webkit-font-smoothing: antialiased;
}

/* background-scroll lock while any slide-out drawer (cart/search/mobile menu) is open - toggled
   by pdxToggleDrawer()/pdxCloseDrawers() in _Header.cshtml. Without this, once a drawer's own
   scrollable region (e.g. ".flyout-cart .items") reached the top or bottom of ITS content, wheel/
   touch scroll had nowhere left to go on that element and chained through to the next scrollable
   ancestor - the page behind the drawer - which looked like "the cart isn't scrolling, the body
   behind it is" even though the drawer's own list scrolled correctly right up until that point. */
body.pdx-drawer-open { overflow-y: hidden; }

h1, h2, h3, h4, h5, h6 {
  font-weight: 600;
  line-height: 1.25;
  color: var(--pdx-text);
}

h1 { font-size: 28px; }
h2, .title { font-size: 20px; color: var(--pdx-subheading); }
h3 { font-size: 17px; color: var(--pdx-subheading); }

a { color: var(--pdx-primary); cursor: pointer; transition: color .15s ease; }
a:hover { color: var(--pdx-secondary); }
a img { opacity: .999; }

p { margin-bottom: 12px; }

table { width: 100%; border-collapse: collapse; }

/* Configure > Inputs and Buttons > "Form control corner radius" (Theme1Settings.
   FormControlBorderRadius) - var(--pdx-input-radius, var(--pdx-radius-sm)) so a plain, un-admin-
   configured value (--pdx-input-radius unset, e.g. if the plugin is ever disabled) still falls
   back to this theme's existing hardcoded 6px design token, same fallback pattern already used for
   --pdx-card-radius/--pdx-button-radius. Applied here to the base text/email/tel/password/number/
   search input + textarea + select rule (every generic form field sitewide: login, register,
   address, checkout, product page quantity box, etc) and, further down, to the two other real
   <select> dropdowns that have their own more specific overriding rule (.product-page-size/
   .product-sorting "Sort by"/"Display" selects, and .custom-wishlist-dropdown) plus
   .product-mobile-filter-trigger (a <button>, not a form control, but deliberately styled to
   visually match the selects beside it - see that rule's own comment). Deliberately NOT applied to
   --pdx-radius-sm's other, non-form-control uses elsewhere in this file (menu/dropdown panels,
   thumbnails, icon buttons, etc) - those keep the plain design-system token, unaffected by this
   setting. Also NOT applied to .search-box input[type="search"] (deliberately pill-shaped,
   border-radius:999px) or the search-drawer's autocomplete suggestion list (a menu, not a form
   control) - see those rules' own comments. */
input[type="text"],
input[type="email"],
input[type="tel"],
input[type="password"],
input[type="number"],
input[type="search"],
textarea,
select {
  height: 42px;
  width: 100%;
  border: 1px solid var(--pdx-border);
  border-radius: var(--pdx-input-radius, var(--pdx-radius-sm));
  padding: 0 12px;
  font-size: 14px;
  font-family: var(--pdx-font);
  background: var(--pdx-surface);
  color: var(--pdx-text);
  transition: border-color .15s ease, box-shadow .15s ease;
}

textarea { height: auto; padding: 10px 12px; }

input:focus, textarea:focus, select:focus {
  outline: none;
  border-color: var(--pdx-primary);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--pdx-primary) 18%, transparent);
}

/* =========================== LAYOUT =========================== */

.master-wrapper-page { display: flex; flex-direction: column; min-height: 100vh; }
.master-wrapper-content { flex: 1 0 auto; width: 100%; max-width: var(--pdx-container); margin: 0 auto; padding: 24px 20px 48px; }

/* the homepage's full-bleed Swiper banner (.nop-slider) sits at the very top of .page-body,
   inside .master-wrapper-content - its own top padding otherwise leaves a grey gap between the
   sticky header and the banner. "html-home-page" is a body class core adds via
   NopHtml.AppendPageCssClassParts in Home/Index.cshtml, so this only affects the homepage.
   padding-bottom:0 for the same reason at the OTHER end of the page: whichever homepage section
   renders last (Featured products/Best sellers/News/Polls/Categories, depending on admin
   ordering) can also be set full-bleed - .master-wrapper-content's own 48px bottom padding was
   leaving that same grey gap between it and the footer, below the full-bleed section's own
   background. Non-homepage pages keep the normal 48px bottom padding - their content (product
   grids, cart, etc.) isn't full-bleed and relies on it for breathing room above the footer. */
.html-home-page .master-wrapper-content { padding-top: 0; padding-bottom: 0; }

/*
  .master-column-wrapper (from _Root.cshtml) is the ONE true flex container nopCommerce uses for
  layout. It holds either just <section class="center-1"> (single-column pages, e.g. homepage)
  OR <aside class="side-2"> + <section class="center-2"> as siblings (two/three-column pages).
  .center-1/.center-2/.side-2 are never nested inside one another - giving .center-1 its own
  "display:flex" (as an earlier version of this file did) turns it into a shrink-to-fit flex item
  instead of a full-width block, which breaks full-bleed children (like the homepage banner) that
  rely on this container being centered on the page.
*/
.master-column-wrapper { display: flex; flex-wrap: wrap; align-items: flex-start; gap: 32px; width: 100%; }

.center-1 { flex: 1 1 100%; min-width: 0; width: 100%; }
.center-2 { flex: 1 1 0%; min-width: 0; }
.side-2 { flex: 0 0 260px; }

/* core renders @section Breadcrumb as the FIRST child of .master-column-wrapper, a sibling of
   .side-2 (filter sidebar) and .center-2 (product grid) in that same flex row - see
   _ColumnsTwo.cshtml's own "@await RenderSectionAsync("Breadcrumb", false)" call, which lands
   inside .master-column-wrapper via _Root.cshtml's @RenderBody(). Left completely unstyled,
   .breadcrumb had no width/flex-basis of its own, so it behaved as an ordinary shrink-to-fit flex
   item sized to its own content - sitting to the LEFT of the sidebar and product grid in that
   same row, instead of spanning the page above them. flex:1 1 100% forces it onto its own
   full-width row (.master-column-wrapper already has flex-wrap:wrap - see above), which pushes
   .side-2/.center-2 down onto the row below it, matching every other page's breadcrumb placement
   (product detail, manufacturer, etc. - all share this same _ColumnsTwo layout). */
.breadcrumb { flex: 1 1 100%; width: 100%; margin-bottom: 20px; }
.breadcrumb ul { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.breadcrumb li { display: flex; align-items: center; gap: 6px; }
.breadcrumb a { color: var(--pdx-text-muted); font-size: 14px; font-weight: 500; }
.breadcrumb a:hover { color: var(--pdx-primary); }
.breadcrumb .current-item { color: var(--pdx-text); font-weight: 600; font-size: 14px; }
.breadcrumb .delimiter { color: var(--pdx-text-muted); font-size: 13px; }

.page.home-page,
.page-body { width: 100%; }

@media (max-width: 991px) {
  .master-column-wrapper { flex-direction: column; }
  /* .side-2's own mobile behavior (full-width stacked block vs. slide-out drawer) is now defined
     entirely in the SIDEBAR (.side-2) BLOCKS section below, alongside the rest of its mobile
     drawer CSS, rather than split across two places in the file. */

  /* .center-2 needs an explicit width here, unlike .breadcrumb (which already has "width: 100%"
     above) - without one, this rule reproduces a real bug: switching .master-column-wrapper to
     "flex-direction: column" at this breakpoint swaps its axes, so WIDTH becomes the CROSS axis.
     The cross axis is governed by "align-items: flex-start" (see the base rule above), which sizes
     items via shrink-to-fit/fit-content rather than stretching them - unless the item has an
     explicit width of its own, exactly like .breadcrumb does. .center-2 never had one; it only had
     "flex: 1 1 0%", which controls the MAIN axis (now vertical/height at this breakpoint), not the
     cross axis. So without this rule, .center-2's width falls back to fit-content, sized off its
     own content's intrinsic/max-content width - which "looks correct" by coincidence on a normal
     category page (a full product grid's max-content width comfortably exceeds the available
     space, so fit-content clamps down to it) but visibly SHRINKS on a category with no products
     (e.g. all products removed/out of stock, and no enabled filters, so .side-2's own content is
     also empty) since the only remaining content is the comparatively narrow subcategories
     carousel, whose small intrinsic width is what fit-content then resolves to. Confirmed live via
     browser devtools: .center-2 measured ~160px (and its carousel items rendered undersized to
     match) on an emptied category before this rule, vs. a correct full-width 375px after it -
     matching a normal, populated category exactly. (.side-2 is unaffected either way since it's
     "position: fixed" and out of flow here - see the SIDEBAR (.side-2) BLOCKS section below.) */
  .center-2 { width: 100%; }
}

/* =========================== SIDEBAR (.side-2) BLOCKS =========================== */

/*
  Category/Manufacturer/Vendor Navigation, Recently Viewed Products, Popular Tags, the Community
  Poll (LeftColumnPoll), and the catalog filters (price/specs/manufacturer, via the
  "CatalogFilters" section) render into .side-2 on catalog listing pages, inside the
  ".side-2-drawer-body" wrapper (see Views/Shared/_ColumnsTwo.cshtml, a theme override of core -
  that wrapper exists purely for the mobile drawer state, further below, and has no effect on
  this desktop styling). The nav/tags/poll blocks are core markup, unmodified, each already
  rendering <section class="block block-X"><h2 class="title">...<div class="listbox">... (see
  each component's own Default.cshtml under Views/Shared/Components/*NavigationViewComponent,
  PopularProductTags, RecentlyViewedProductsBlock, PollBlock, VendorNavigation). The catalog
  filters DON'T natively use those class names (core's _FilterManufacturerBox.cshtml/
  _FilterSpecsBox.cshtml/_FilterPriceBox.cshtml use "filter-title"/"filter-content"/"group"
  instead) - Themes/Nexus/Views/Catalog/ has theme overrides of those three views that add
  "title"/"listbox"/"list" alongside core's own classes so they render through this SAME set of
  rules too, rather than needing a parallel set of lookalike declarations (see the CATALOG
  FILTERS block further below for the checkbox/label-specific additions those need on top of
  this shared base).
*/

/* section title: uppercase, bold, dark - overrides the generic "h2, .title" rule further up this
   file (20px, --pdx-subheading), which is sized for page/homepage-section headings, not a
   compact sidebar list */
.side-2 .block .title {
  font-size: 15px;
  font-weight: 700;
  color: var(--pdx-text);
  text-transform: uppercase;
  letter-spacing: .04em;
  margin-bottom: 16px;
}

/* light gray divider BETWEEN sections (not after the last one) - padding-bottom on every block
   plus a border-bottom, with the last block's own border/padding zeroed out so the sidebar
   doesn't end on a stray trailing line */
.side-2 .block {
  padding-bottom: 24px;
  margin-bottom: 24px;
  border-bottom: 1px solid var(--pdx-border);
}
.side-2 .block:last-child {
  padding-bottom: 0;
  margin-bottom: 0;
  border-bottom: none;
}

/* Category / Manufacturer / Vendor navigation + Recently viewed products - plain vertical link
   lists, one per line, dark text (not the theme's link-blue) with primary-color hover, matching
   the reference layout's understated look. */
.side-2 .block .listbox > ul.list > li,
.side-2 .block .listbox .sublist > li {
  margin-bottom: 12px;
}
.side-2 .block .listbox > ul.list > li:last-child { margin-bottom: 0; }
.side-2 .block .listbox a {
  color: var(--pdx-text);
  font-size: 14px;
}
.side-2 .block .listbox a:hover { color: var(--pdx-primary); }
.side-2 .block .listbox li.active > a { color: var(--pdx-primary); font-weight: 600; }

/* nested subcategory list - indented, slightly smaller/muted, matching a typical nested-nav look */
.side-2 .block .sublist {
  margin-top: 10px;
  margin-left: 14px;
}
.side-2 .block .sublist a { font-size: 13px; color: var(--pdx-text-muted); }
.side-2 .block .sublist a:hover { color: var(--pdx-primary); }

/*
  Catalog filters (Filter by attributes / Filter by manufacturer / price range) - Nexus theme
  overrides of Nop.Web/Views/Catalog/_FilterManufacturerBox.cshtml, _FilterSpecsBox.cshtml,
  _FilterPriceBox.cshtml (Themes/Nexus/Views/Catalog/) add "title"/"listbox"/"list" classes
  alongside core's own "filter-title"/"filter-content"/"group" classes, so these blocks reuse
  the EXACT SAME .side-2 .block .title / .listbox rules above instead of a parallel set of
  lookalike declarations - per spec, "styled the same ... use the same classes". The outer
  wrapper (_CatalogFilters.cshtml, core, unmodified) already renders "<section class=\"block
  product-filters\">" as a direct child of .side-2, so it already picks up the divider/spacing
  rules above with no changes needed there.

  Checkbox items (manufacturer list, spec attribute values) aren't plain <a> links like
  Category/Manufacturer nav, so the shared ".listbox a" color/size rule is extended to labels
  too, laid out as an inline checkbox+label row rather than a block-level link.
*/
.side-2 .block .listbox label {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  color: var(--pdx-text);
  font-size: 14px;
  cursor: pointer;
}
.side-2 .block .listbox label:hover { color: var(--pdx-primary); }
/* the checkbox and its label are SIBLINGS inside <li class="item"> (input isn't wrapped by the
   label - see the theme's _FilterManufacturerBox.cshtml/_FilterSpecsBox.cshtml overrides), so
   the row itself - not the label - has to be the flex container laying them out side by side.
   An earlier version made the LABEL "display: flex" (block-level flex, not inline-flex) instead
   of this rule - that turned the label into its own full-width block, which pushed it onto a new
   line below the checkbox rather than sitting next to it (the exact "checkbox on top, text below"
   bug this replaces). label itself stays inline-flex (see above) only to align a color swatch +
   text together WITHIN itself for color-attribute items - it never controls this row's layout. */
.side-2 .block .listbox li.item {
  display: flex;
  align-items: center;
  gap: 8px;
}
.side-2 .block .listbox input[type="checkbox"] {
  width: 16px;
  height: 16px;
  flex: 0 0 auto;
  accent-color: var(--pdx-primary);
  cursor: pointer;
}
/* color-swatch attribute values (Model's ColorSquaresRgb) - the swatch itself sits inline before
   the label text, reusing .attribute-square from the checkout-attributes color-square styling
   further below for a consistent square-swatch look across the site. */
.side-2 .block .listbox .attribute-square {
  display: inline-block;
  width: 16px;
  height: 16px;
  flex: 0 0 auto;
  border-radius: var(--pdx-radius-sm);
  border: 1px solid var(--pdx-border);
}

/* spec attribute name (e.g. "Color", "Size") - a small muted sub-heading above that attribute's
   own set of checkbox values, matching the nested .sublist treatment's weight/size further below
   rather than introducing a one-off rule; margin-top separates each attribute group from the
   previous one's values (not needed before the first group). */
.side-2 .block .listbox .group-name {
  margin-bottom: 8px;
  font-size: 13px;
  font-weight: 700;
  color: var(--pdx-text-muted);
  text-transform: uppercase;
  letter-spacing: .03em;
}
.side-2 .block .listbox .product-spec-group + .product-spec-group .group-name { margin-top: 16px; }

/* spacing + divider between the three possible filter types (price / specs / manufacturer) when
   more than one is enabled at once - core's _CatalogFilters.cshtml renders them as plain adjacent
   siblings inside the shared ".block product-filters" wrapper with no separation of their own.
   Mirrors the exact same padding/margin/border-bottom shape ".side-2 .block"/".side-2 .block:
   last-child" use further up this file, so a divider appears BETWEEN filter types (e.g. "Filter
   by attributes" / "Filter by manufacturer") the same way it already does between top-level
   .side-2 blocks - an earlier version only added margin-top with no border, which is why that
   in-between divider was missing even though the divider AFTER the whole filters group (between
   the last filter type and Categories below it) was already showing correctly (that one comes
   from the OUTER ".block product-filters" wrapper's own .side-2 .block styling, untouched here). */
.product-filters .product-filter {
  padding-bottom: 24px;
  margin-bottom: 24px;
  border-bottom: 1px solid var(--pdx-border);
}
.product-filters .product-filter:last-child {
  padding-bottom: 0;
  margin-bottom: 0;
  border-bottom: none;
}

/* "View all" (Manufacturers/Vendors, when the sidebar list is truncated) */
.side-2 .block .view-all { margin-top: 14px; }
.side-2 .block .view-all a {
  color: var(--pdx-primary);
  font-size: 13px;
  font-weight: 600;
}

/* Popular tags - flex-wrapped pill chips, matching the reference image, instead of core's plain
   inline <ul><li> list. Core's PopularProductTags/Default.cshtml (unmodified) sets a per-tag
   inline "font-size:X%" (proportional to how popular each tag is) directly on each <a> - left
   alone (no font-size override on the anchor itself) so that default core behavior actually shows
   through, as requested; an earlier version of this rule normalized every chip to a fixed 12px via
   "font-size: 12px !important", which defeated it. The 14px set below lives on the UL instead -
   inline styles win over any class rule for the SAME property on the SAME element, so putting
   font-size on the anchor would just get overridden by its own inline "font-size:X%"; percentages
   resolve against the INHERITED (parent) font-size, so this is the only place a baseline can
   actually take effect. 14px matches the sidebar nav links just above (.side-2 .block .listbox a)
   so the least-popular tags (100%) render at the same size as "Categories"/"Manufacturers" links. */
.side-2 .block-popular-tags .tags ul {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  font-size: 14px;
}
.side-2 .block-popular-tags .tags li { list-style: none; }
.side-2 .block-popular-tags .tags a {
  display: inline-block;
  padding: 8px 14px;
  background: var(--pdx-body-bg);
  border: 1px solid #a6a6a6;
  border-radius: 0;
  color: var(--pdx-text);
  font-weight: 400;
  white-space: nowrap;
  transition: color .15s ease, border-color .15s ease;
}
.side-2 .block-popular-tags .tags a:hover {
  color: var(--pdx-primary);
  border-color: var(--pdx-primary);
}

/*
  Product Tags "view all" page (/producttag/all, reached via Popular Tags' own "View all" link
  just above, when the sidebar list is truncated - see that component's "@if (Model.TotalTags >
  Model.Tags.Count)" check) - core's ProductTagsAll.cshtml renders a plain "<ul class="product-
  tags-list"><li><a class="producttag" style="font-size:X%">..." (unmodified), the SAME per-tag
  font-size-percentage mechanism as Popular Tags above but a different markup shape (no nested
  ".tags" wrapper, and a page-level ".product-tags-all-page" body class instead of ".side-2"), so
  it needs its own copy of the same pill-chip treatment rather than being able to share the
  ".side-2 .block-popular-tags .tags a" selector. Kept visually identical to Popular Tags on
  purpose, per spec ("show all tags visibly as they are under popular tags").
*/
.product-tags-all-page .product-tags-list {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  font-size: 14px;
}
.product-tags-all-page .product-tags-list a.producttag {
  display: inline-block;
  padding: 8px 14px;
  background: var(--pdx-body-bg);
  border: 1px solid #a6a6a6;
  border-radius: 0;
  color: var(--pdx-text);
  font-weight: 400;
  white-space: nowrap;
  transition: color .15s ease, border-color .15s ease;
}
.product-tags-all-page .product-tags-list a.producttag:hover {
  color: var(--pdx-primary);
  border-color: var(--pdx-primary);
}

/*
  .side-2-drawer-header/-title/-close/-body: markup added by this theme's own
  Views/Shared/_ColumnsTwo.cshtml override (core renders .side-2's content directly, with no
  header and no wrapping body element). ".side-2-drawer-header" is hidden by default here
  (desktop, where .side-2 is a normal in-flow sidebar, not a drawer) exactly like
  ".menu-drawer-header" in the MAIN NAVIGATION section further below - shown, and actually laid
  out as a drawer header, only within the mobile drawer block right below. ".side-2-drawer-body"
  is a plain block on desktop (no padding/scroll of its own - it's purely a structural wrapper
  there) so wrapping the existing sidebar content in it changes nothing above 991px.
*/
.side-2-drawer-header { display: none; }
.side-2-drawer-body { display: block; }
/* "Show results" fixed bottom button (Views/Shared/_ColumnsTwo.cshtml, this theme) - same
   display:none-on-desktop treatment as the header above, for the same reason (nothing to "show
   results" for when .side-2 is a normal, always-visible, non-drawer sidebar). */
.side-2-drawer-footer { display: none; }

/*
  Mobile: .side-2 (catalog filters, category/manufacturer/vendor navigation, recently viewed,
  popular tags, poll) becomes a right-edge slide-out drawer instead of a full-width block stacked
  below the product grid, opened by the new "Filter" button this theme's _CatalogSelectors.cshtml
  override adds to .product-selectors (see the CATALOG SELECTORS section further below) - matches
  .flyout-cart/.search-drawer/.menu-container .menu exactly: same position:fixed/width (shared
  --pdx-drawer-width)/height/border/shadow shape, same quick opacity-fade open/close (NOT a
  slide/transform, despite "slide-out" - see .active below), same shared .drawer-backdrop, same
  pdxToggleDrawer()/pdxCloseDrawers() JS (see _Header.cshtml; every trigger that opens one of
  those other three drawers also lists ".side-2" in its own "close these others" selector, and
  vice versa, so only one drawer is ever open at a time). 991px matches the breakpoint the
  ".master-column-wrapper { flex-direction: column }" rule above already uses - below that width
  there's no room for .side-2 to sit beside .center-2 as an inline sidebar any more, which is
  exactly when a drawer (rather than a stacked block) is wanted instead.
*/
@media (max-width: 991px) {
  aside.side-2 {
    position: fixed;
    top: 0;
    right: 0;
    z-index: 300;
    display: flex;
    flex-direction: column;
    width: var(--pdx-drawer-width);
    max-width: 90vw;
    height: 100dvh;
    margin: 0;
    padding: 0;
    background: var(--pdx-drawer-bg, #FFFFFF);
    border-left: 1px solid var(--pdx-border);
    box-shadow: -12px 0 32px rgba(16, 24, 40, .18);
    overflow: hidden;
    opacity: 0;
    visibility: hidden;
    transition: opacity .15s ease, visibility .15s ease;
  }
  aside.side-2.active { opacity: 1; visibility: visible; }

  /* matches .flyout-cart-header/.search-drawer-header/.menu-drawer-header's shape exactly,
     including reuse of the same --pdx-drawer-padding token so mobile's own smaller padding (see
     the shared @media (max-width: 767px) override further up this file) applies here too, with
     no separate override needed. */
  .side-2-drawer-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    flex: 0 0 auto;
    padding: var(--pdx-drawer-padding) var(--pdx-drawer-padding) 16px;
    background: var(--pdx-drawer-header-bg, #FFFFFF);
    border-bottom: 1px solid var(--pdx-border);
  }
  .side-2-drawer-title { font-size: 22px; color: var(--pdx-text); }
  .side-2-drawer-close {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    border: 1px solid var(--pdx-border);
    border-radius: 999px;
    background: transparent;
    color: var(--pdx-text-muted);
    cursor: pointer;
  }
  .side-2-drawer-close:hover { background: var(--pdx-body-bg); color: var(--pdx-text); }

  /* scrollable drawer body - everything that used to render directly inside .side-2 (filters,
     nav, tags, poll) now renders inside this wrapper instead (see _ColumnsTwo.cshtml), which
     supplies its own padding/scroll now that .side-2 itself has none, mirroring
     ".flyout-cart .items"' identical role in the cart drawer. */
  .side-2-drawer-body {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    padding: var(--pdx-drawer-padding);
  }

  /*
    "+"/"−" expand-collapse indicator on each section's own title ("Filter by attributes"/
    "Filter by manufacturer"/price/"Categories"/"Manufacturers"/"Vendors"/"Recently viewed
    products"/"Popular tags"/poll - every ".block .title" inside the drawer body) - mirrors
    .footer-menu__toggle::after's exact "+"/"\2212" shape (see FOOTER section further below)
    applied here instead via a class toggled directly on .title by _ColumnsTwo.cshtml's own
    script, rather than a separate wrapping element. Collapsed by default (content hidden, "+"
    shown) - matches .footer-menu__list/.footer-menu--active's own default-collapsed shape.
    Scoped to ".side-2-drawer-body" specifically (not a bare ".side-2 .block .title"), so this has
    no effect outside the mobile drawer state even though the underlying markup is identical -
    desktop's existing ".side-2 .block .title" rule (SIDEBAR (.side-2) BLOCKS section above) is
    completely untouched, still a plain non-interactive heading with everything always expanded.
  */
  .side-2-drawer-body .block .title {
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
  }
  .side-2-drawer-body .block .title::after {
    content: "+";
    flex: 0 0 auto;
    font-size: 20px;
    line-height: 1;
    font-weight: 400;
  }
  .side-2-drawer-body .block .title.pdx-collapsible-active::after { content: "\2212"; }
  /* the collapsible target is ".listbox" for the catalog filter boxes (once the "listbox" class
     is added - see this theme's _FilterManufacturerBox.cshtml/_FilterSpecsBox.cshtml overrides -
     alongside core's own "filter-content") AND every nav/tags/poll block (core, unmodified,
     already rendering ".listbox" with no theme changes needed), but ".filter-content" alone for
     the price filter specifically, which has no "listbox" class of its own (see
     _FilterPriceBox.cshtml's own comment) - both selectors are listed so every section collapses
     correctly regardless of which class(es) its own content wrapper happens to carry. */
  .side-2-drawer-body .block .listbox,
  .side-2-drawer-body .block .filter-content {
    display: none;
  }
  .side-2-drawer-body .block .title.pdx-collapsible-active ~ .listbox,
  .side-2-drawer-body .block .title.pdx-collapsible-active ~ .filter-content {
    display: block;
  }

  /*
    Fixed "Show results" bar - third direct child of .side-2 (Views/Shared/_ColumnsTwo.cshtml),
    a sibling of the header/body above. flex:0 0 auto pins it to its natural height at the BOTTOM
    of .side-2's own flex column (same technique .side-2-drawer-header uses to pin to the TOP),
    so it stays fixed in place while only .side-2-drawer-body (flex:1 1 auto) scrolls underneath
    it - functionally "fixed to the bottom of the screen" per spec, since .side-2 itself is
    already position:fixed and fills the viewport height (100dvh) at this breakpoint. Right-
    aligned per spec ("bottom fixed button right aligned").
  */
  .side-2-drawer-footer {
    display: flex;
    justify-content: flex-end;
    flex: 0 0 auto;
    padding: 16px var(--pdx-drawer-padding);
    background: var(--pdx-drawer-bg, #FFFFFF);
    border-top: 1px solid var(--pdx-border);
  }
  /* Uses the SAME admin-configurable settings regular buttons do (--pdx-primary/--pdx-button-
     radius - see Nop.Plugin.Prodigix.Theme.Nexus's ThemeStyles/Default.cshtml, which sets both
     from Theme1Settings.PrimaryColor/ButtonBorderRadius) rather than the dedicated
     --pdx-button-bg/--pdx-button-hover-bg pair ".button-1"/".button-2"/".btn" use (BUTTONS
     section further below) - per spec ("use the configuration settings for primary color and
     radius for buttons"), specifically PRIMARY color, not the separate "Button background color"
     setting. --pdx-button-text (the configured primary-button TEXT color) is reused for contrast
     against whatever primary color an admin picks, since spec didn't call out a separate text
     color setting for this button and every other button-shaped element in the theme already
     pairs a background color with that same text-color variable. */
  .side-2-drawer-show-results {
    background: var(--pdx-primary);
    color: var(--pdx-button-text);
    border: none;
    border-radius: var(--pdx-button-radius, 0px);
    padding: 10px 24px;
    font-size: 14px;
    font-weight: 600;
    cursor: pointer;
  }
  .side-2-drawer-show-results:hover { opacity: .9; }
}

/* =========================== HEADER =========================== */

/*
  Admin-only bar shown above everything when logged in as an admin/impersonating a customer -
  core's AdminHeaderLinksViewComponent (Views/Shared/Components/AdminHeaderLinks/Default.cshtml,
  unmodified) renders <nav class="admin-header-links"><a class="administration">...</a></nav>.
  Unstyled by default (left-aligned, default text color); given a fixed, non-configurable dark
  band per spec, distinct from the two theme-color-driven header bars below it.
*/
.admin-header-links {
  display: block;
  text-align: center;
  background: #444444;
  color: #FFFFFF;
  padding: 8px 20px;
  font-size: 13px;
}
.admin-header-links a { color: #FFFFFF; font-weight: 600; }
.admin-header-links a:hover { opacity: .85; }
.admin-header-links .impersonate { display: inline-flex; align-items: center; gap: 10px; margin-right: 16px; }

/*
  Two-tier header (see _Header.cshtml override for the markup rationale):
   .header-top      - Section 1: store selectors, plus secondary account actions
                       (login/register/logout) and private messages (search/account/wishlist/cart
                       links technically render here too, before a script relocates all four down
                       to Section 2 - see _Header.cshtml). Plain block, NOT sticky - scrolls away
                       normally. Background/text driven by --pdx-header-bg/--pdx-header-text
                       (admin label: "Section 1").
   .header (sticky)  - Section 2: logo + main menu + search + account + wishlist + cart, one row,
                       pinned via plain CSS position:sticky (same technique nopCommerce's own
                       "loom" theme uses for its equivalent ".header-sticky" bar - no JS/
                       scroll-listener needed). Background/text driven by
                       --pdx-header2-bg/--pdx-header2-text (admin label: "Section 2"). Dropdown
                       panels (.menu__grid-view/.menu__list-view) always keep the regular dark
                       --pdx-text on their own white background regardless of what Section 2's
                       colors are set to - see the "MAIN NAVIGATION" section below for why that's
                       scoped separately from the top-level menu bar text.
*/

.header-top {
  background: var(--pdx-header-bg);
  color: var(--pdx-header-text);
  font-size: 13px;
}

.header-top-inner {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 20px;
  max-width: var(--pdx-header-container);
  margin: 0 auto;
  /* small 4px vertical breathing room + 20px side padding, inset from --pdx-header-container's
     own edges - matches .header-lower's padding shape below so both bars line up consistently */
  padding: 4px 20px;
}

.header-selectors-wrapper { display: flex; align-items: center; gap: 16px; }

/*
  Header dropdown selectors: language (Nop.Plugin.Prodigix.Theme1.Components.
  LanguageSelectorViewComponent, a full replacement for core's own component - see that class and
  _Header.cshtml for why) and currency (ProdigixTheme's own Views/Shared/Components/
  CurrencySelector/Default.cshtml override of core's view) both render the SAME markup shape - a
  ".pdx-dropdown-trigger" button + a ".pdx-selector-panel" list - instead of a native <select>,
  so they look and behave identically. Neither is a real <select> (language needs an <img> flag
  inside each option, which a native <option> can't render at all, and currency was restyled to
  match rather than diverge) - the open/close toggle is real markup driven by the shared
  pdxToggleSelectorDropdown() JS in _Header.cshtml, not a native browser popup.
*/
.pdx-dropdown { position: relative; display: flex; align-items: center; }
.pdx-dropdown-trigger {
  display: flex;
  align-items: center;
  gap: 6px;
  border: none;
  background: transparent;
  padding: 0 16px 0 0;
  margin: 0;
  color: var(--pdx-header-text);
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
}
.pdx-dropdown-trigger .pdx-lang-flag { width: 20px; height: 14px; object-fit: cover; border-radius: 2px; display: block; }
/* language dropdown only: the two-letter SEO code (Model's UniqueSeoCode) comes back from the
   database lowercase - uppercased here for display only, to match the rest of the header's
   all-caps labels (.header-links-wrapper a, .header-cart-wrapper #topcartlink a, etc.); the
   currency trigger's text is a full currency name/symbol pattern, not a short code, so it isn't
   part of this rule and keeps its normal casing. */
.pdx-lang-code { text-transform: uppercase; }
.pdx-selector-caret {
  position: absolute;
  right: 2px;
  top: 50%;
  width: 6px;
  height: 6px;
  margin-top: -5px;
  border-right: 2px solid var(--pdx-header-text);
  border-bottom: 2px solid var(--pdx-header-text);
  transform: rotate(45deg);
  pointer-events: none;
}

/* the option list - real markup (not a native popup), toggled open via the ".active" class
   pdxToggleSelectorDropdown() (in _Header.cshtml) adds/removes on the ".pdx-dropdown" wrapper */
.pdx-selector-panel {
  position: absolute;
  top: 100%;
  right: 0;
  z-index: 200;
  min-width: 90px;
  margin-top: 10px;
  padding: 6px;
  background: var(--pdx-surface);
  border: 1px solid var(--pdx-border);
  border-radius: var(--pdx-radius-sm);
  box-shadow: var(--pdx-shadow-md);
  opacity: 0;
  visibility: hidden;
  transform: translateY(6px);
  transition: opacity .15s ease, transform .15s ease, visibility .15s;
}
.pdx-dropdown.active .pdx-selector-panel { opacity: 1; visibility: visible; transform: translateY(0); }
.pdx-selector-panel li { list-style: none; }
.pdx-selector-panel a {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 10px;
  border-radius: var(--pdx-radius-sm);
  color: var(--pdx-text);
  font-size: 13px;
  font-weight: 600;
  white-space: nowrap;
}
/* fixed light gray for both hover AND the currently-selected row, always - not the admin-
   configurable --pdx-primary (which can be set to any color, including a red that read as an
   error/alert state here rather than a neutral "this one's active" highlight) */
.pdx-selector-panel a:hover,
.pdx-selector-panel a.selected {
  background: #EBF0F5;
  color: var(--pdx-text);
}
.pdx-selector-panel .pdx-lang-flag { width: 20px; height: 14px; object-fit: cover; border-radius: 2px; flex: 0 0 auto; }
.header-links-wrapper { display: flex; align-items: center; gap: 16px; position: relative; }
.header-links-wrapper ul { display: flex; align-items: center; gap: 20px; }
.header-links-wrapper a {
  display: flex;
  align-items: center;
  gap: 6px;
  color: var(--pdx-header-text);
  font-weight: 600;
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: .02em;
  white-space: nowrap;
}
/* .cart-qty/.wishlist-qty no longer live inside .header-links at all (both relocated into
   .header-cart-wrapper - see HeaderLinks/Default.cshtml's script, and the ".header-cart-wrapper"
   rules further below for their circular-badge styling) - only inbox-unread (private messages)
   still uses this dimmed/lighter-weight inline-text treatment. */
.header-links .inbox-unread { opacity: .85; font-weight: 400; text-transform: none; }

.header-search-trigger {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  padding: 0;
  border: none;
  background: transparent;
  color: var(--pdx-header-text);
  cursor: pointer;
}
.header-search-trigger:hover { opacity: .75; }

.header.header-sticky {
  position: sticky;
  top: 0;
  z-index: 150;
  background: var(--pdx-header2-bg, #FFFFFF);
  border-bottom: 1px solid var(--pdx-border);
  box-shadow: var(--pdx-shadow);
}

.header-lower {
  display: flex;
  align-items: center;
  gap: 32px;
  max-width: var(--pdx-header-container);
  margin: 0 auto;
  padding: 10px 20px;
}

.header-logo { flex: 0 0 auto; }
.header-logo img { max-height: 44px; width: auto; }

.header-menu-wrapper { flex: 1 1 auto; min-width: 0; }

/* search trigger (relocated by class selector - see HeaderLinks/Default.cshtml's script and its
   own comment in _Header.cshtml), "My account" trigger (#topaccountlink), wishlist trigger
   (#topwishlistlink), and cart trigger (#topcartlink) - all relocated here in that order, left to
   right - plus the #flyout-cart drawer, all live in this wrapper - see _Header.cshtml for why.
   display:flex + gap lays the four icons out side by side; the drawer itself is position:fixed
   (see .flyout-cart further below) so it's taken out of this flex flow entirely and doesn't need
   any explicit ordering here. */
.header-cart-wrapper { display: flex; align-items: center; gap: 8px; flex: 0 0 auto; position: relative; }
/* the account/wishlist/cart <li>s lose their inherited "list-style: none" (set on their original
   parent <ul> in .header-links) once relocated out of that <ul> into this plain <div> wrapper,
   which is why a bullet marker (list-style-type defaults to "disc") would otherwise reappear
   here. The search trigger isn't an <li> at all (see HeaderLinks/Default.cshtml - it's OUR OWN
   <button>, not core markup), so it never needed this rule in the first place. */
.header-cart-wrapper #topcartlink,
.header-cart-wrapper #topwishlistlink,
.header-cart-wrapper #topaccountlink { list-style: none; }
/* the search trigger keeps its own base sizing/color from .header-search-trigger's rule further
   above (it has to stay usable there too, briefly, before this page's relocation script runs) -
   this override just brings it up to the same 32px box and Section-2 text color the other three
   icons use once it's actually sitting in this wrapper, so all four read as one consistent row. */
.header-cart-wrapper .header-search-trigger { width: 32px; height: 32px; color: var(--pdx-header2-text, var(--pdx-text)); }
/*
  Search / account / wishlist / cart trigger icons: a plain magnifying-glass/person/heart/bag
  outline (the heart path is the same one used for "Add to wishlist" on product cards - see
  _ProductBox.cshtml's add-to-wishlist-button, for visual consistency), with wishlist and cart
  additionally carrying a small circular quantity badge overlapping their bottom-right corner -
  account and search have no count to show, so neither gets a badge. This replaces the old text
  labels + inline "(1)" counts (see HeaderLinks/Default.cshtml for the markup - text labels
  removed entirely, aria-label added on each <a>/<button> instead so the links are still
  announced to screen readers). Each *-qty span is ALWAYS rendered (see that view for why - each
  is also core's AjaxCart update target, which can only fill an existing element, not create one)
  and is left genuinely empty when the cart/wishlist has 0 items; "*-qty:empty" below is what
  actually hides it in that case, not a Razor @if anymore, so an empty cart/wishlist shows just
  the bare icon and the badge un-hides itself the instant a number is written into it (by
  first-page-render OR by an AJAX add, including the very first item). Both badges share the same
  admin-configurable --pdx-primary (Configure > Colors > "Primary color"), not a fixed
  brand-independent color, so they always match the rest of the theme's accent color, and each
  other.
*/
.header-cart-wrapper #topcartlink a,
.header-cart-wrapper #topwishlistlink a,
.header-cart-wrapper #topaccountlink a {
  display: flex;
  align-items: center;
  color: var(--pdx-header2-text, var(--pdx-text));
}
.header-cart-wrapper .cart-icon-wrap,
.header-cart-wrapper .wishlist-icon-wrap,
.header-cart-wrapper .account-icon-wrap {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
}
.header-cart-wrapper .cart-icon,
.header-cart-wrapper .wishlist-icon,
.header-cart-wrapper .account-icon { display: block; }
.header-cart-wrapper #topcartlink .cart-qty,
.header-cart-wrapper #topwishlistlink .wishlist-qty {
  position: absolute;
  bottom: -4px;
  right: -6px;
  width: 20px;
  height: 20px;
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: var(--pdx-primary);
  color: #fff;
  font-size: 10px;
  font-weight: 700;
  line-height: 1;
  border: 2px solid var(--pdx-header2-bg, #FFFFFF);
}
.header-cart-wrapper #topcartlink .cart-qty:empty,
.header-cart-wrapper #topwishlistlink .wishlist-qty:empty { display: none; }

@media (max-width: 1000px) {
  .header-lower { flex-wrap: wrap; justify-content: space-between; }
  .header-menu-wrapper { flex: 1 1 100%; order: 10; }

  /* logo shrunk down to leave more room for the search/account/wishlist/cart/hamburger icon row
     it now shares its own top line with (the menu itself wraps to its own full-width line below,
     via order:10 above - it's this icon row, not the actual menu items, competing with the logo
     for space at this breakpoint). Further reduced again at the 767px phone breakpoint below. */
  .header-logo img { max-height: 34px; }

  /* wishlist hidden entirely on mobile per spec - it still gets relocated into
     .header-cart-wrapper along with the other icons (see HeaderLinks/Default.cshtml's script),
     it's just not shown there below this breakpoint. Scoped to inside .header-cart-wrapper (its
     post-relocation home) rather than the bare #topwishlistlink id, purely for clarity/symmetry
     with the other .header-cart-wrapper-scoped rules around it - an id selector would work
     identically here since ids are unique regardless of container. */
  .header-cart-wrapper #topwishlistlink { display: none; }

  /* the main menu's toggle button (.menu__toggle) is relocated into .header-cart-wrapper on
     mobile too (see HeaderLinks/Default.cshtml's script), landing rightmost - to the right of
     cart - per spec. Its base rule (further down, in MAIN NAVIGATION) is sized/padded for its
     ORIGINAL full-width accordion-bar context; this override brings it up to the same 32px icon
     box the other three icons use once it's actually sitting in this row, so all four (well,
     three visible - wishlist is hidden here) plus the toggle read as one consistent row. */
  .header-cart-wrapper .menu__toggle { width: 32px; height: 32px; padding: 0; justify-content: center; }
}

@media (max-width: 767px) {
  .header-top-inner { flex-wrap: wrap; justify-content: center; padding: 6px 16px; }
  .header-lower { padding: 12px 16px; gap: 16px; }
  /* smaller again than the 1000px breakpoint's 34px - the icon row's own gap/padding also
     shrinks here (.header-lower's gap above, .header-cart-wrapper's gap further down), so less
     logo width is needed to keep everything on one line without crowding. */
  .header-logo img { max-height: 28px; }
}

/* shared dimmed backdrop for all three slide-out panels (cart + search + mobile menu) - a real,
   separate sibling element rather than a ::before pseudo-element on each drawer. A ::before with
   z-index:-1 sounds like "furthest back", but CSS stacking rules actually paint a stacking-
   context root's OWN background at the very bottom layer, with negative-z-index children painting
   in the layer ABOVE that - so it was rendering over each drawer's own background fill instead of
   behind it. Toggled by pdxToggleDrawer()/pdxCloseDrawers() in _Header.cshtml alongside whichever
   drawer is open; clicking it closes whatever's open. Fades at the same .15s speed as the panels
   themselves (see .flyout-cart/.search-drawer/.menu-container .menu) so backdrop and panel appear
   together rather than the backdrop visibly lagging behind a faster panel fade.
*/
.drawer-backdrop {
  position: fixed;
  inset: 0;
  z-index: 250;
  background: rgba(15, 23, 42, .45);
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity .15s ease, visibility .15s ease;
}
.drawer-backdrop.active { opacity: 1; visibility: visible; pointer-events: auto; }

/* slide-out shopping cart drawer - #flyout-cart markup comes from this theme's own
   FlyoutShoppingCart/Default.cshtml override (see that file); toggled the same way core's
   markup always was - JS in HeaderLinks/Default.cshtml adds/removes ".active" on hover/focus of
   #topcartlink or #flyout-cart itself. Opens/closes via a quick opacity fade (NOT a
   slide/transform) per spec - see .active below.
   display:flex/flex-direction:column + overflow:hidden (rather than the drawer itself
   scrolling) is what makes the header stay pinned at the top and the totals/buttons stay pinned
   at the bottom while only the middle item list scrolls - see ".flyout-cart .items" further
   below, which is the actual scrolling element now. Padding is applied per-child instead of once
   on this outer box, since the header/footer pieces need to bleed to the drawer's edges (the
   negative-margin trick on .flyout-cart-header) while the scrollable items region needs its own
   independent padding that doesn't get clipped when it scrolls. */
.flyout-cart {
  position: fixed;
  top: 0;
  right: 0;
  z-index: 300;
  width: var(--pdx-drawer-width);
  max-width: 90vw;
  height: 100dvh;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  background: var(--pdx-drawer-bg, #FFFFFF);
  border-left: 1px solid var(--pdx-border);
  box-shadow: -12px 0 32px rgba(16, 24, 40, .18);
  overflow: hidden;
  opacity: 0;
  visibility: hidden;
  transition: opacity .15s ease, visibility .15s ease;
}
.flyout-cart.active { opacity: 1; visibility: visible; }

/* header row: title + item count on the left, close (×) button on the right - markup added by
   this theme's FlyoutShoppingCart/Default.cshtml override (core has neither). flex:0 0 auto pins
   it to its natural height at the top of #flyout-cart's flex column (see above) so it never
   scrolls with the items. Horizontal padding matches --pdx-drawer-padding (rather than the outer
   drawer supplying it via its own padding, now that #flyout-cart has none of its own - see
   above) so it still lines up with the totals/buttons footer's matching padding further down. */
.flyout-cart-header {
  flex: 0 0 auto;
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
  padding: var(--pdx-drawer-padding) var(--pdx-drawer-padding) 16px;
  background: var(--pdx-drawer-header-bg, #FFFFFF);
  border-bottom: 1px solid var(--pdx-border);
}
.flyout-cart-title { font-size: 22px; color: var(--pdx-text); }
.flyout-cart-subtitle { font-size: 13px; color: var(--pdx-primary); font-weight: 600; margin-top: 4px; }
.flyout-cart-close {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border: 1px solid var(--pdx-border);
  border-radius: 999px;
  background: transparent;
  color: var(--pdx-text-muted);
  cursor: pointer;
}
.flyout-cart-close:hover { background: var(--pdx-body-bg); color: var(--pdx-text); }

/* the scrollable region - flex:1 1 auto makes this the one part of the drawer that grows/
   shrinks and scrolls, now that #flyout-cart itself is overflow:hidden and .mini-shopping-cart
   (its direct child, see further below) is a flex column too; min-height:0 is required on a flex
   child for overflow-y:auto to actually kick in instead of the child just growing to fit its
   content. Horizontal padding lives here (not on #flyout-cart anymore) so it scrolls together
   with the items rather than being clipped at the drawer's edge. Scrollbar hidden across engines
   (scrollbar-width for Firefox, -ms-overflow-style for old Edge, ::-webkit-scrollbar for Chrome/
   Safari) - the drawer still scrolls via wheel/touch/keyboard, there's just no visible track/thumb
   per spec. */
.flyout-cart .items {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 0 var(--pdx-drawer-padding);
  scrollbar-width: none;
  -ms-overflow-style: none;
}
.flyout-cart .items::-webkit-scrollbar { display: none; }

/* a 1px light-gray divider under EVERY item, including the last one (border-bottom, not
   border-top - matches the reference design, which shows a line separating each product all the
   way down through the last one, unlike the top-cart-page table which only needed lines between
   rows). */
.flyout-cart .item {
  position: relative;
  display: flex;
  gap: 12px;
  /* right padding makes room for .flyout-cart-item-remove (see below), which sits pinned to this
     row's right edge - without it the button would overlap the price/quantity text */
  padding: 14px 34px 14px 0;
  border-bottom: 1px solid var(--pdx-border);
}
/* square corners on the product thumbnail per spec (was var(--pdx-radius-sm)) */
.flyout-cart .picture img { width: 64px; height: 64px; object-fit: cover; border-radius: 0; }
.flyout-cart .product { flex: 1 1 auto; min-width: 0; }
.flyout-cart .product .name a { font-size: 14px; font-weight: 600; color: var(--pdx-text); }
.flyout-cart .attributes { font-size: 12px; color: var(--pdx-text-muted); margin-top: 0px; }
/* unit price + quantity lines - core renders these as two separate <div class="price">/
   <div class="quantity"> (see the FlyoutShoppingCart override), NOT a single combined element -
   an earlier version of this rule targeted a ".qty-price" class that doesn't exist anywhere in
   the actual markup and so never matched anything; these two divs were rendering completely
   unstyled (inheriting the theme's base 15px body text and its 1.55 line-height, which is what
   made the gap under the product name read as too loose). Smaller text + tight line-height +
   a small margin-top (instead of the loose default line-height alone) keeps each item row compact. */
.flyout-cart .price,
.flyout-cart .quantity {
  font-size: 12px;
  line-height: 1.3;
  margin-top: 2px;
  color: var(--pdx-text-muted);
}
.flyout-cart .price span,
.flyout-cart .quantity span { color: var(--pdx-text); font-weight: 600; }

/* per-item remove button (Themes/ProdigixTheme/Views/Shared/Components/FlyoutShoppingCart/
   Default.cshtml, this theme's own override of core's markup - not present in core at all) -
   pinned to the row's top-right corner, a plain muted trash icon rather than a bordered circle
   button (unlike table.cart .remove-btn on the full cart page) since this row is already compact
   and a heavier button would compete with the picture/price for attention. Click handling is
   delegated JS in _Header.cshtml (pdxRemoveFlyoutCartItem), since this whole drawer gets replaced
   wholesale via innerHTML swap after add-to-cart/remove AJAX calls - a directly-bound handler
   would be lost the moment that happens. */
.flyout-cart-item-remove {
  position: absolute;
  top: 14px;
  right: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  padding: 0;
  border: none;
  background: transparent;
  color: var(--pdx-text-muted);
  cursor: pointer;
}
.flyout-cart-item-remove:hover { color: var(--pdx-danger); }
.flyout-cart-item-remove:disabled { opacity: .5; cursor: default; }
.flyout-cart-item-remove svg { display: block; pointer-events: none; }

/* subtotal row - a plain, unboxed text row (see the ".cart-footer .totals" card rule under
   SHOPPING CART PAGE further below, which is deliberately scoped to NOT catch this element,
   since the two are unrelated despite sharing a class name). Bold throughout (label AND amount -
   font-weight on the row itself, not just the <strong> around the amount) with no colon after
   the label (the view's own text no longer includes one). Pinned to the bottom of the drawer via
   flex:0 0 auto - a sibling of the scrollable .items above inside .mini-shopping-cart's flex
   column (see that rule below), so it never scrolls out of view. */
.flyout-cart .totals {
  flex: 0 0 auto;
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  padding: 16px var(--pdx-drawer-padding) 0;
  border-top: 1px solid var(--pdx-border);
  font-size: 15px;
  font-weight: 700;
}
.flyout-cart .totals strong { font-size: 18px; }

/* pin the "View cart" / checkout buttons to the bottom of the drawer, directly below the
   totals row above (no divider between them - just spacing, matching the reference design) */
.flyout-cart .mini-shopping-cart {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
}
.flyout-cart .buttons {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-top: 16px;
  padding: 0 var(--pdx-drawer-padding) var(--pdx-drawer-padding);
}
.flyout-cart .buttons button { width: 100%; }

/* empty-cart state: fills the remaining space below the header (.mini-shopping-cart is already a
   flex column via the rule above) and centers the icon+message as a single group, both
   horizontally and vertically - flex-direction:column with align-items/justify-content:center
   means the group's top edge (the icon) is what's centered as a unit, not the text baseline.
   padding-top nudges the centered group up from true center; the small "gap" pulls the message
   in close under the icon rather than floating in the middle of the remaining space. */
.flyout-cart-empty {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding-top: 24px;
  text-align: center;
  color: var(--pdx-text-muted);
}
.flyout-cart-empty svg { color: var(--pdx-text); flex: 0 0 auto; }
.flyout-cart-empty-text { font-size: 26px; font-weight: 700; color: var(--pdx-text); }

@media (max-width: 767px) {
  /* smaller drawer padding on mobile - .flyout-cart-header/.search-drawer-header automatically
     stay in sync since they're calc()'d from this same variable, not a separate hardcoded value */
  :root { --pdx-drawer-padding: 16px; }
  /* !important here is deliberate and load-bearing, not a lazy override: .search-drawer's own
     width rule (further down, in its own dedicated section) and .menu-container .menu's own
     width rule (later still, in MAIN NAVIGATION) both have the EXACT SAME specificity as this
     selector (a single class each). Per plain CSS cascade, when multiple same-specificity rules
     all apply at a given viewport, whichever one appears LAST in the source file wins - which has
     nothing to do with whether it's inside a @media block or not. Since those other two
     declarations physically appear later in this file than this override, an unqualified rule
     here would silently lose to them below 767px - this was a real, previously-unnoticed bug for
     .search-drawer specifically (it never actually reached 100% width on phones, unlike
     .flyout-cart, whose own width rule happens to sit earlier in the file) and part of why the
     drawers stopped matching each other (now four: cart/search/menu, plus .side-2's own filter
     drawer, added later - same reasoning applies to it too). !important sidesteps needing every
     drawer's own section to stay in a fragile "defined-before-this-override" file order forever. */
  .flyout-cart, .search-drawer, .menu-container .menu, aside.side-2 { width: 100% !important; max-width: none !important; }
  .flyout-cart .buttons { gap: 8px; }
  .flyout-cart .buttons button { padding-left: 16px; padding-right: 16px; }
  .flyout-cart .totals { font-size: 14px; }
  .flyout-cart-empty svg { width: 108px; height: 108px; }
  .flyout-cart-empty-text { font-size: 21px; }
}

/* slide-out search drawer - mirrors .flyout-cart's structure exactly (position:fixed, dimmed
   shared backdrop), triggered by .header-search-trigger in .header-top via the shared
   pdxToggleDrawer() helper (defined inline in _Header.cshtml). Opens/closes via the same quick
   opacity fade .flyout-cart uses (NOT a slide/transform) per spec - see .active below. The actual
   search form/autocomplete markup is core's unmodified SearchBoxViewComponent - see the big
   comment at the top of _Header.cshtml for why its ".search-box" wrapper class has to stay
   exactly that. */
.search-drawer {
  position: fixed;
  top: 0;
  right: 0;
  z-index: 300;
  width: var(--pdx-drawer-width);
  max-width: 90vw;
  height: 100vh;
  padding: var(--pdx-drawer-padding);
  background: var(--pdx-drawer-bg, #FFFFFF);
  border-left: 1px solid var(--pdx-border);
  box-shadow: -12px 0 32px rgba(16, 24, 40, .18);
  overflow-y: auto;
  opacity: 0;
  visibility: hidden;
  transition: opacity .15s ease, visibility .15s ease;
}
.search-drawer.active { opacity: 1; visibility: visible; }

.search-drawer-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin: calc(-1 * var(--pdx-drawer-padding)) calc(-1 * var(--pdx-drawer-padding)) 16px;
  padding: var(--pdx-drawer-padding) var(--pdx-drawer-padding) 16px;
  background: var(--pdx-drawer-header-bg, #FFFFFF);
  border-bottom: 1px solid var(--pdx-border);
}
.search-drawer-title { font-size: 22px; color: var(--pdx-text); }
.search-drawer-close {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border: 1px solid var(--pdx-border);
  border-radius: 999px;
  background: transparent;
  color: var(--pdx-text-muted);
  cursor: pointer;
}
.search-drawer-close:hover { background: var(--pdx-body-bg); color: var(--pdx-text); }

/* the actual <form>#small-search-box-form (core markup) inside .search-box */
.search-drawer .search-box { position: relative; }
.search-drawer .search-box form { display: flex; flex-direction: column; gap: 10px; }
.search-drawer input.search-box-text {
  width: 100%;
  height: 46px;
  font-size: 15px;
  padding: 0 16px;
}
.search-drawer .search-box-category { height: 46px; }
/* no search button per spec - Enter still submits the (unmodified) core form, autocomplete
   selection still navigates directly, so hiding this loses no functionality */
.search-drawer .search-box-button { display: none; }

/* nopCommerce's built-in autocomplete (jQuery UI widget, gated by Admin > Catalog Settings
   "Search autocomplete enabled" / "Number of autocomplete products to display" - see
   SearchBox/Default.cshtml, unmodified). It's appended into ".search-box" (appendTo: '.search-box'
   in that script) which is why results land directly under the input, inside this drawer. jQuery
   UI applies width as an inline style and fairly aggressive default styling, hence the
   !important overrides below - same pattern nopCommerce's own DefaultClean theme uses. */
.search-drawer .ui-autocomplete {
  position: absolute !important;
  width: 100% !important;
  max-height: 70vh;
  overflow-y: auto;
  margin-top: 6px;
  background: var(--pdx-surface);
  border: 1px solid var(--pdx-border) !important;
  border-radius: var(--pdx-radius);
  box-shadow: var(--pdx-shadow-md);
  padding: 6px !important;
  font: inherit;
  z-index: 10;
}
.search-drawer .ui-autocomplete li { border-top: 1px solid var(--pdx-border); }
.search-drawer .ui-autocomplete li:first-child { border-top: none; }
.search-drawer .ui-autocomplete a {
  display: flex !important;
  align-items: center;
  gap: 10px;
  margin: 0 !important;
  border: none !important;
  border-radius: var(--pdx-radius-sm) !important;
  background: none !important;
  padding: 10px !important;
  line-height: normal !important;
  color: var(--pdx-text) !important;
  font-size: 14px;
}
.search-drawer .ui-autocomplete a:hover,
.search-drawer .ui-autocomplete a:focus,
.search-drawer .ui-autocomplete a.ui-state-focus { background-color: var(--pdx-body-bg) !important; }
.search-drawer .ui-autocomplete img {
  display: inline-block;
  width: 40px;
  height: 40px;
  object-fit: cover;
  border-radius: var(--pdx-radius-sm);
  flex: 0 0 auto;
}
.ui-helper-hidden-accessible { display: none !important; }

/* simple CSS spinner while an autocomplete request is in flight - jQuery UI adds this class to
   the input itself; core themes normally point it at an image asset we don't have, so a small
   inline-SVG-free spinner via border animation is used instead */
.search-drawer .ui-autocomplete-loading {
  background-image: none !important;
  position: relative;
}
.search-drawer .ui-autocomplete-loading::after {
  content: "";
  position: absolute;
  right: 14px;
  top: 50%;
  width: 16px;
  height: 16px;
  margin-top: -8px;
  border: 2px solid var(--pdx-border);
  border-top-color: var(--pdx-primary);
  border-radius: 50%;
  animation: pdx-spin .6s linear infinite;
}
@keyframes pdx-spin { to { transform: rotate(360deg); } }

/* "Recommended products" (best sellers) list shown inside the search drawer while the search box
   is empty - see SearchDrawerBestSellersViewComponent (Nop.Plugin.Prodigix.Theme1) for the query
   and Views/Shared/Components/SearchDrawerBestSellers/Default.cshtml for the markup/show-hide
   script. Laid out to match the reference "Recommended products" design: thumbnail, name (links
   to the product), truncated description, price, and a square "+" link on the right that also
   goes to the product page. */
.search-drawer-recommended { margin-top: 24px; }
.search-drawer-recommended-title {
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--pdx-text);
  margin-bottom: 12px;
}
.search-drawer-recommended-item {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 14px 0;
  border-top: 1px solid var(--pdx-border);
}
.search-drawer-recommended-list .search-drawer-recommended-item:first-child { border-top: none; padding-top: 0; }
.search-drawer-recommended-picture {
  flex: 0 0 auto;
  display: block;
  width: 56px;
  height: 56px;
  border: 1px solid var(--pdx-border);
  border-radius: var(--pdx-radius-sm);
  overflow: hidden;
}
.search-drawer-recommended-picture img { width: 100%; height: 100%; object-fit: cover; }
.search-drawer-recommended-info { flex: 1 1 auto; min-width: 0; }
.search-drawer-recommended-name {
  display: block;
  font-size: 14px;
  font-weight: 700;
  color: var(--pdx-text);
}
.search-drawer-recommended-name:hover { color: var(--pdx-primary); }
.search-drawer-recommended-description {
  font-size: 13px;
  color: var(--pdx-text-muted);
  margin-top: 2px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.search-drawer-recommended-price { font-size: 14px; font-weight: 600; color: var(--pdx-text); margin-top: 4px; }
.search-drawer-recommended-link {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border: 1px solid var(--pdx-border);
  border-radius: var(--pdx-button-radius, 0px);
  color: var(--pdx-text);
}
.search-drawer-recommended-link:hover { border-color: var(--pdx-primary); color: var(--pdx-primary); }

.search-box input[type="text"],
.search-box input[type="search"] { border-radius: 999px; padding-left: 18px; }

/* =========================== MAIN NAVIGATION (nopCommerce 4.90 menu builder) =========================== */

/*
  nopCommerce 4.90+ themes render the menu via MainMenuViewComponent using the class structure
  below (see Nop.Web/Views/Shared/Components/MainMenu/*.cshtml) - NOT a plain <ul><li> nav. The
  submenu panels (.menu__grid-view / .menu__list-view) are always present in the DOM; it's CSS
  that's responsible for hiding them until hover/focus (desktop) or a click toggling
  ".menu-dropdown--active" (mobile). Earlier versions of this stylesheet never styled those two
  classes at all, so submenus rendered inline/expanded permanently. This section ports the real
  behavior from nopCommerce's own DefaultClean theme (Nop.Web/Themes/DefaultClean), restyled with
  our own color variables. public.menu.js (loaded automatically by MainMenuViewComponent) supplies
  the click/toggle JS, untouched. ONE view override exists on top of this CSS-only styling: this
  theme's own Views/Shared/Components/MainMenu/Default.cshtml always renders the mobile
  .menu__toggle as a hamburger icon rather than core's plain Model.Name text (an admin-configurable
  menu name added in nopCommerce 4.90's Content Management > Menus) - see that file's own comment
  for the full rationale, and .menu__toggle/.menu__toggle-icon below for the icon's styling.
*/

.header-menu-wrapper { position: relative; }
.menu-container { width: 100%; }
.menu { font-size: 14px; overflow: hidden; }

/* mobile: hamburger toggle for the whole menu - always a plain three-line icon
   (.menu__toggle-icon below), regardless of the menu's admin-configured name (core's Model.Name -
   see MainMenu/Default.cshtml override in this theme, and that view's own comment for the full
   rationale: this toggle only ever renders inside the icon-sized mobile row alongside
   search/account/wishlist/cart, which has room for an icon but not a text label of arbitrary
   length). display:flex here (rather than plain text's implicit inline flow) centers the icon
   vertically within the same 14px/20px padding box core's plain-text button used. */
.menu__toggle {
  display: flex;
  align-items: center;
  width: 100%;
  padding: 14px 20px;
  font-weight: 600;
  cursor: pointer;
  color: var(--pdx-header2-text, var(--pdx-text));
}
.menu__toggle-icon { display: block; }

/* drawer title + close button, direct child of .menu (see MainMenu/Default.cshtml's own comment
   for why it has to be a direct child rather than a separate wrapper) - display:none by default
   so it doesn't become a stray extra flex item in desktop's horizontal .menu bar (which only
   styles .menu > .menu__item as nav items); shown (and actually styled as a drawer header) only
   within the mobile @media block further below, once .menu itself becomes the slide-out panel. */
.menu-drawer-header { display: none; }

/* mobile: each item is a full-width accordion row */
.menu__item {
  width: 100%;
  display: block;
  color: var(--pdx-text);
  background: var(--pdx-surface);
  border-top: 1px solid var(--pdx-border);
}
.menu > .menu__item:first-child { border-top: none; }
.menu__item:not(.menu-dropdown) { padding: 12px 20px; }

.menu__item-toggle {
  display: flex;
  justify-content: space-between;
  align-items: center;
  width: 100%;
  border: none;
  background: transparent;
  padding: 12px 20px;
  cursor: pointer;
  -webkit-appearance: none;
}

.menu__item-toggle::after {
  content: "";
  width: 8px;
  height: 8px;
  margin-left: 8px;
  border-right: 2px solid var(--pdx-text-muted);
  border-bottom: 2px solid var(--pdx-text-muted);
  transform: rotate(45deg);
  transition: transform .2s ease;
}

/* mobile: collapsible panels - collapsed via 0fr row, expanded via .menu-dropdown--active */
.menu-dropdown {
  display: grid;
  grid-template-rows: min-content 0fr;
  transition: grid-template-rows .25s ease;
}
.menu-dropdown--active { grid-template-rows: min-content 1fr; }
.menu-dropdown--active > .menu__item-toggle::after { transform: rotate(-135deg); }

.menu__grid-view, .menu__list-view {
  position: relative;
  overflow: hidden;
  padding: 0 20px;
  background: var(--pdx-body-bg);
}

.menu__group { display: flex; flex-direction: column; padding: 10px 0; }
.menu__group-title { font-size: 15px; font-weight: 600; padding: 8px 0; color: var(--pdx-subheading); }
.menu__group > .menu__link { display: none; }

.menu__link {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 0;
  line-height: 1.4;
  color: var(--pdx-text);
  cursor: pointer;
  text-align: left;
}
.menu__link:hover { color: var(--pdx-primary); }
.menu__link--inactive { pointer-events: none; cursor: default; }

/* top-level menu items only (SHOP/TRAVEL/etc in the header's second row) - not the dropdown
   panel links inside .menu__grid-view/.menu__list-view, which stay normal case/weight for
   readability in a denser list. Scoped the same way the Section-2 text-color rule below is
   (direct children of .menu, at both breakpoints since mobile's accordion rows use the same
   .menu__link markup as desktop's top-level bar). */
.menu > .menu__item > .menu__link,
.menu > .menu__item > .menu__item-toggle .menu__link {
  text-transform: uppercase;
  font-weight: 700;
  letter-spacing: .03em;
}

.menu__image-link { display: inline-block; }
.menu__image { width: 100%; border-radius: var(--pdx-radius-sm); }

/*
  Mobile slide-out menu drawer (<=1000px, matching the breakpoint .menu__toggle is visible at -
  see the @media (min-width: 1001px) block further below, which hides .menu__toggle and switches
  .menu back to a plain horizontal bar). Converts .menu from core's inline accordion (the
  .menu-dropdown/.menu-dropdown--active grid-row-collapse rules above) into a panel pinned to the
  right edge of the viewport, matching .flyout-cart/.search-drawer exactly - same position:fixed/
  width (--pdx-drawer-width, shared with those two - see :root)/height/border/shadow shape, same
  quick opacity-fade open/close (NOT a slide/transform - see .active below), same shared
  .drawer-backdrop, same pdxToggleDrawer()/pdxCloseDrawers() JS (see _Header.cshtml). See
  MainMenu/Default.cshtml's own comment for why the toggle button's click handling had to move out
  of core's mainMenu.init() call to make this work once that button gets relocated into
  .header-cart-wrapper.
*/
@media (max-width: 1000px) {
  .menu-container .menu {
    position: fixed;
    top: 0;
    right: 0;
    z-index: 300;
    width: var(--pdx-drawer-width);
    max-width: 90vw;
    height: 100vh;
    margin: 0;
    padding: 0;
    background: var(--pdx-drawer-bg, #FFFFFF);
    border-left: 1px solid var(--pdx-border);
    box-shadow: -12px 0 32px rgba(16, 24, 40, .18);
    overflow-y: auto;
    opacity: 0;
    visibility: hidden;
    transition: opacity .15s ease, visibility .15s ease;
  }
  .menu-container .menu.active { opacity: 1; visibility: visible; }

  /* matches .flyout-cart-header/.search-drawer-header's shape exactly, including reuse of the
     same --pdx-drawer-padding token so mobile's own smaller padding (see the shared @media
     (max-width: 767px) override elsewhere in this file) applies here automatically too, without
     a separate override. Unlike those two, no negative-margin "bleed to the drawer's edge" trick
     is needed - this header is already the first thing inside .menu's own padding-free box,
     rather than being nested inside an already-padded drawer body like flyout-cart's is. */
  .menu-drawer-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: var(--pdx-drawer-padding) var(--pdx-drawer-padding) 16px;
    background: var(--pdx-drawer-header-bg, #FFFFFF);
    border-bottom: 1px solid var(--pdx-border);
  }
  .menu-drawer-title { font-size: 22px; color: var(--pdx-text); }
  .menu-drawer-close {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    border: 1px solid var(--pdx-border);
    border-radius: 999px;
    background: transparent;
    color: var(--pdx-text-muted);
    cursor: pointer;
  }
  .menu-drawer-close:hover { background: var(--pdx-body-bg); color: var(--pdx-text); }

  /* .menu__toggle was relocated out entirely (into .header-cart-wrapper - see HeaderLinks/
     Default.cshtml's script) and .menu itself, now position:fixed above, contributes no in-flow
     height to its ancestors - so .header-menu-wrapper/.menu-container/<nav> (the
     .menu-dropdown grid, originally sized to fit the toggle + collapsible panel) end up with
     nothing left in normal flow to size against and should already collapse to ~0 height on
     their own. Zeroed explicitly here anyway, defensively, rather than relying on that being
     exactly right in every browser. */
  .header-menu-wrapper,
  .menu-container,
  .menu-container.menu-dropdown { margin: 0; padding: 0; min-height: 0; }
}

@media (min-width: 1001px) {
  /* .menu-container/.menu now live inside .header-menu-wrapper, a flex child of .header-lower
     alongside the logo and cart (see _Header.cshtml) - so unlike the old standalone full-width
     menu bar, they no longer need their own max-width/margin:auto self-centering; they just fill
     whatever space .header-lower's flexbox gives that slot, starting right after the logo. */
  .menu-container { padding: 0; }

  .menu {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-start;
    align-items: stretch;
    overflow: visible; /* .menu has overflow:hidden in the mobile-first base rule (needed for the
                           accordion collapse animation); on desktop that same rule clips the
                           absolutely-positioned dropdown panels, which are still DOM descendants
                           of .menu even though they're positioned relative to .menu__item - so it
                           must be reset back to visible here or submenus render invisibly. */
  }

  .menu__toggle { display: none; }
  .menu-dropdown { display: inline-block; }

  .menu > .menu__item {
    width: auto;
    border-top: none;
    background: transparent;
  }

  /*
    ".menu__item" is the positioning anchor for its own submenu (.menu__grid-view/.menu__list-view
    are direct children of it - see _MenuItem.Grid.cshtml/_MenuItem.List.cshtml) so the dropdown
    opens directly below the specific item being hovered, not the whole menu bar. It's also a flex
    container itself so its content (.menu__link, or .menu__item-toggle for dropdown items) is
    vertically centered no matter how tall neighboring items are.
  */
  .menu__item {
    position: relative;
    width: fit-content;
    display: flex;
    align-items: center;
    border-top: none;
  }
  .menu__item:not(.menu-dropdown) { padding: 0; }

  .menu__item-toggle {
    display: inline-flex;
    align-items: center;
    width: auto;
    padding: 14px;
  }
  .menu__item-toggle::after { display: none; }

  /* top-level bar text (Section 2) vs. dropdown panel text: dropdown panels
     (.menu__grid-view/.menu__list-view) always render on their own white background regardless
     of what Section 2's colors are set to (see .menu__link's base rule earlier in this file,
     which stays --pdx-text for readability there), so only the DIRECT top-level children of
     .menu get the Section-2-configurable text color here - not every .menu__link everywhere. */
  .menu > .menu__item > .menu__link,
  .menu > .menu__item > .menu__item-toggle .menu__link { color: var(--pdx-header2-text, var(--pdx-text)); }

  /* items WITH children nest .menu__link inside .menu__item-toggle (which already carries the
     14px padding above) - so the link itself must NOT also be padded, or dropdown items end up
     taller than plain items (double padding), which is what pushed plain items' text to the top
     of the row. Items WITHOUT children render .menu__link directly, so they get the padding
     themselves via the second rule below. */
  .menu__item-toggle .menu__link { padding: 0; }
  .menu__item:not(.menu-dropdown) > .menu__link { padding: 14px; }

  /* desktop: submenu panels are absolutely positioned and hidden until hover/focus - square
     corners (border-radius:0, was var(--pdx-radius)) per spec, and "top: calc(100% + 4px)"
     (was a bare "top: 100%", i.e. flush against the menu bar's own bottom edge) nudges the panel
     down slightly so it overlaps the parent bar less - it still opens on hover/focus of the
     .menu__item itself (not just the panel), so this small gap doesn't reintroduce a "mouse
     leaves the item before reaching the panel" dead zone. */
  .menu__grid-view {
    position: absolute;
    top: calc(100% + 4px);
    left: 0;
    width: max-content;
    min-width: 320px;
    max-width: min(640px, 90vw);
    z-index: 1000;
    display: flex;
    flex-wrap: wrap;
    gap: 20px;
    padding: 20px;
    background: var(--pdx-surface);
    border: 1px solid var(--pdx-border);
    border-radius: 0;
    box-shadow: var(--pdx-shadow-md);
    opacity: 0;
    visibility: hidden;
    transform: translateY(8px);
    transition: opacity .2s ease, transform .2s ease, visibility .2s;
  }

  .menu__list-view {
    position: absolute;
    top: calc(100% + 4px);
    left: 0;
    min-width: 220px;
    z-index: 1000;
    padding: 10px 0;
    background: var(--pdx-surface);
    border: 1px solid var(--pdx-border);
    border-radius: 0;
    box-shadow: var(--pdx-shadow-md);
    opacity: 0;
    visibility: hidden;
    transform: translateY(8px);
    transition: opacity .2s ease, transform .2s ease, visibility .2s;
  }

  .menu__list-view .menu__list-view { top: -10px; left: 100%; }
  .menu__list-view .menu__item { position: relative; display: block; width: 100%; }
  .menu__list-view .menu__link { padding: 8px 16px; }
  .menu__list-view .menu__link:hover { background: var(--pdx-body-bg); }

  .menu__item:focus-within > .menu__grid-view,
  .menu__item:hover > .menu__item-toggle + .menu__grid-view,
  .menu__item:hover .menu__grid-view {
    opacity: 1;
    visibility: visible;
    transform: translateY(0);
  }

  .menu__item:focus-within > .menu__list-view,
  .menu__item:hover > .menu__list-view {
    opacity: 1;
    visibility: visible;
    transform: translateY(0);
  }

  .menu__group { flex: 1 1 0; padding: 0; }
  .menu__group-title { text-align: center; }

  .menu__item:hover > .menu__item-toggle .menu__link,
  .menu__item-toggle:hover .menu__link { color: var(--pdx-primary); }
}

/* =========================== HOMEPAGE BANNER (Widgets.Swiper, full width) =========================== */

/*
  The homepage banner slider comes from the standard "Widgets.Swiper" plugin (all Prodigix
  themes use it), which renders <div class="swiper nop-slider"> into the "home_page_top" widget
  zone. IMPORTANT: that plugin's PublicInfo.cshtml prints its own <link href="swiper-bundle.min.css">
  inline in the page body (not in <head>), so its CSS - including ".swiper { margin-left: auto;
  margin-right: auto }" - loads AFTER this stylesheet in the cascade. At equal specificity
  (.swiper vs .nop-slider are both single-class selectors) the later rule wins, which silently
  cancels a plain margin-based full-bleed override. So, matching how Flexo solves this:
   - use "left" positioning (not margin) to do the actual breakout, since .swiper only sets
     margin-left/margin-right, not left/position
   - prefix with "body" to raise specificity above the plugin's bare ".swiper"/".nop-slider" rules
     regardless of load order
   - !important on max-width, since some Swiper builds cap it at 100%
*/
body .nop-slider {
  position: relative;
  width: 100vw;
  left: calc(-50vw + 50%);
  max-width: none !important;
  margin: 0 auto 32px;
  overflow: hidden;
}

body .nop-slider .swiper-slide {
  position: relative;
  /* height = the same 21:7 aspect ratio as before (width/3), expressed via calc() instead of the
     "aspect-ratio" property, plus a flat +60px on top - aspect-ratio alone can only ever produce
     a value proportional to width, so a literal "60px taller than before at any given width"
     needs to be added as its own separate term rather than folded into the ratio. !important on
     both height and min-height for the same reason as max-width above: Widgets.Swiper's own
     bundled CSS loads after ours (it prints its <link> inline in the body, not <head>), and its
     rules can otherwise silently win at equal specificity - this was why the mobile override
     below wasn't reliably taking effect. */
  height: calc(100vw / 3 + 60px) !important;
  min-height: 280px !important;
  background: var(--pdx-body-bg);
}

body .nop-slider .swiper-slide img,
body .nop-slider .slider-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  max-width: none !important; /* the plugin's own styles.css sets .slider-img { max-width: 100% } */
}

body .nop-slider .swiper-pagination-bullet-active { background: var(--pdx-primary); }

@media (max-width: 767px) {
  /* DefaultClean's own styles.css has NO .nop-slider rules at all - confirmed by checking it
     directly - it relies entirely on Widgets.Swiper's own bundled CSS, which has no forced
     height/object-fit either. That's why it scales naturally there: the image just renders at
     its own aspect ratio, shrinking proportionally with the container width. Our fixed-height +
     object-fit:cover rules above (added for the desktop "full width, 60px taller" look) fight
     that on mobile - forcing every image into the same rigid ratio crops it instead of letting it
     scale down like the stock behavior does. So on mobile specifically, we drop back to auto
     height and let the image set its own proportional size, same as DefaultClean/stock. */
  body .nop-slider .swiper-slide {
    height: auto !important;
    min-height: 0 !important;
  }
  body .nop-slider .swiper-slide img,
  body .nop-slider .slider-img {
    position: static;
    height: auto !important;
    object-fit: unset;
  }
}

/* =========================== BUTTONS =========================== */

.button-1, .button-2, .btn,
input[type="submit"],
input[type="button"] {
  display: inline-block;
  background: var(--pdx-button-bg);
  color: var(--pdx-button-text);
  border: none;
  padding: 11px 22px;
  font-size: 14px;
  font-weight: 600;
  border-radius: var(--pdx-button-radius, 0px);
  cursor: pointer;
  transition: background-color .15s ease, transform .05s ease;
}

.button-1:hover, .button-2:hover, .btn:hover,
input[type="submit"]:hover,
input[type="button"]:hover {
  background: var(--pdx-button-hover-bg);
  color: var(--pdx-button-text);
}

.button-1:active, .button-2:active, .btn:active { transform: translateY(1px); }

.product-box-add-to-cart-button { width: 100%; }

.add-to-compare-list-button,
.add-to-wishlist-button,
.email-a-friend-button,
.update-wishlist-button,
.wishlist-add-to-cart-button,
.email-a-friend-wishlist-button {
  background: transparent;
  color: var(--pdx-text);
  border: 1px solid var(--pdx-border);
}
/* Hover swaps text/icon/border to the site primary color (icon follows automatically - the
   .overview-buttons icon pseudo-elements below are drawn with "background-color: currentColor",
   so they inherit whatever "color" is set here) while keeping the background white/transparent -
   no fill on hover, just the outline + label + icon going to --pdx-primary. Wishlist page's
   Update Wishlist/Add to Cart/Email a Friend buttons (.wishlist-content .buttons, see WISHLIST
   PAGE section) share this same outline treatment for visual consistency with the product detail
   page's Add to Wishlist button. */
.add-to-compare-list-button:hover,
.add-to-wishlist-button:hover,
.email-a-friend-button:hover,
.update-wishlist-button:hover,
.wishlist-add-to-cart-button:hover,
.email-a-friend-wishlist-button:hover {
  background: transparent;
  color: var(--pdx-primary);
  border-color: var(--pdx-primary);
}

/* Icon + label buttons: Add to Wishlist (heart), Add to Cart (plus), Email a Friend (envelope),
   Add to Compare List (plus, same glyph as Add to Cart) - same icons on both the product detail
   page (.add-to-wishlist-button/.add-to-cart-button/.email-a-friend-button/
   .add-to-compare-list-button) and the wishlist page (.update-wishlist-button/
   .wishlist-add-to-cart-button/.email-a-friend-wishlist-button). Icon markup is an inline <svg>
   (matching this theme's existing line-icon pattern - see _ProductBox.cshtml's
   add-to-wishlist-button heart and the header search icon in _Header.cshtml) placed before the
   button's text node in each view, so simple flex + gap is enough to lay icon and label out
   side by side with the icon on the left; stroke="currentColor" on each svg means it automatically
   follows the button's own text color above, hover included, with no extra color rule needed here. */
.add-to-wishlist-button,
.add-to-cart-button,
.email-a-friend-button,
.add-to-compare-list-button,
.update-wishlist-button,
.wishlist-add-to-cart-button,
.email-a-friend-wishlist-button {
  display: inline-flex;
  align-items: center;
  gap: 8px;
}
.add-to-wishlist-button svg,
.add-to-cart-button svg,
.email-a-friend-button svg,
.add-to-compare-list-button svg,
.update-wishlist-button svg,
.wishlist-add-to-cart-button svg,
.email-a-friend-wishlist-button svg {
  flex: 0 0 auto;
  width: 16px;
  height: 16px;
}

/* =========================== PROTECTPAY SAVED PAYMENT METHODS - THEME OVERRIDES ===========================
   Nop.Plugin.Prodigix.ProtectPay's CustomerPaymentMethodList view component (Views/Shared/
   Components/CustomerPaymentMethodList/Default.cshtml) ships its own hardcoded "<style>" block
   inline in that partial's markup (dark uppercase ".protectpay-pm-btn"/".protectpay-pm-btn-delete"
   buttons), rendered wherever the component is invoked on the page (Layout = null - no head
   asset bundling). Because that "<style>" tag is emitted in the page body, it comes AFTER this
   theme's own styles.css <link> in document order, so for any selector of equal specificity the
   plugin's inline rule normally wins the cascade regardless of what's added here. The three rules
   below use !important specifically to guarantee they win instead, restyling the plugin's buttons
   to match this theme's own button language:
     - .protectpay-pm-btn        -> exact copy of .button-1 (see BUTTONS section above)
     - .protectpay-pm-add-btn    -> exact copy of .add-to-cart-button (button-1 + icon-flex layout
                                     + its fixed height/padding); added alongside the existing
                                     "protectpay-pm-btn" class on the "Use a new card/account"
                                     button (id="protectpay-pm-add-btn" in Default.cshtml) so this
                                     rule's !important declarations win over the base
                                     ".protectpay-pm-btn" rule immediately above for the properties
                                     both set (source order, same specificity)
     - .protectpay-pm-btn-delete -> exact copy of .add-to-wishlist-button's outline treatment;
                                     already present in the plugin's own markup/JS alongside
                                     "protectpay-pm-btn" on every Delete button (both the
                                     server-rendered ones and the ones the component's JS builds
                                     dynamically for each saved payment method), so no markup
                                     change was needed for this one.
   Each rule also explicitly resets the plugin inline style's "text-transform: uppercase" and
   "min-width" (button-1/add-to-cart-button/add-to-wishlist-button use neither) since CSS cascades
   per-property, not per-rule - simply overriding background/padding/color would otherwise leave
   those two leftover from the plugin's original declaration. */
.protectpay-pm-btn {
  display: inline-block !important;
  min-width: 0 !important;
  text-align: left !important;
  text-transform: none !important;
  background: var(--pdx-button-bg) !important;
  color: var(--pdx-button-text) !important;
  border: none !important;
  padding: 11px 22px !important;
  font-size: 14px !important;
  font-weight: 600 !important;
  border-radius: var(--pdx-button-radius, 0px) !important;
  cursor: pointer !important;
  transition: background-color .15s ease, transform .05s ease !important;
}
.protectpay-pm-btn:hover {
  background: var(--pdx-button-hover-bg) !important;
  color: var(--pdx-button-text) !important;
}
.protectpay-pm-btn:active { transform: translateY(1px) !important; }

.protectpay-pm-add-btn {
  display: inline-flex !important;
  align-items: center !important;
  gap: 8px !important;
  height: 46px !important;
  padding: 0 32px !important;
  font-size: 14px !important;
}

.protectpay-pm-btn-delete {
  background: transparent !important;
  color: var(--pdx-text) !important;
  border: 1px solid var(--pdx-border) !important;
}
.protectpay-pm-btn-delete:hover {
  background: transparent !important;
  color: var(--pdx-primary) !important;
  border-color: var(--pdx-primary) !important;
}

/* =========================== HOMEPAGE SECTION LAYOUTS (Categories / Featured products / Best sellers) =========================== */

/*
  Each of the three near-identical homepage sections (Categories, Featured products, Best
  sellers) can independently be "Standard" (a plain CSS grid) or "Carousel" (Owl Carousel) at
  each of two breakpoints (desktop/mobile) - see Theme1Settings' Categories*/FeaturedProducts*/
  BestSellers* properties. Since a section's desktop and mobile modes can differ (e.g. Standard on
  desktop, Carousel on mobile), the theme's view overrides for all three sections render BOTH the
  standard-grid markup and the carousel markup only when actually needed, and tag whichever one(s)
  they render with .pdx-show-desktop and/or .pdx-show-mobile - these two classes are generic and
  reused by all three sections rather than each needing its own responsive-visibility CSS:
   - element has ONLY .pdx-show-desktop  -> hidden below 768px
   - element has ONLY .pdx-show-mobile   -> hidden at/above 768px
   - element has BOTH (single mode used at both breakpoints) -> never hidden
  Items-per-row for whichever mode is active at a given breakpoint is set via the same
  --pdx-cols-desktop/--pdx-cols-mobile custom properties (inline, per-section) that drive both
  the standard grid's column count and, for carousels, get read by the owlCarousel() init script
  as the "items" value for that breakpoint - so admins only manage one items-per-row number per
  breakpoint regardless of which mode is chosen.

  BUG FIX (Standard-grid-mode-shows-one-big-item): an earlier version of this block also forced
  "display: block !important" on whichever variant SHOULD be visible at a given breakpoint (not
  just "display: none !important" on the one that shouldn't). That's wrong for the Standard-grid
  variant specifically - its own ".item-grid:not(.owl-carousel) { display: grid; ... }" rule
  (further below) needs display:grid to actually lay out as a grid, and "display: block
  !important" on the SAME element (higher specificity via !important, regardless of which rule
  physically comes first in the file) overrode that back to a plain block box - every .item-box
  child then stacked full-width top to bottom instead of forming a grid, which is what read as
  "one giant item" (really just the first of several full-width stacked items, cropped in a
  screenshot). This only ever fired for a section in MIXED mode (desktop=Standard, mobile=
  Carousel, or vice versa) - an element carrying only ONE of the two classes - since an element
  carrying BOTH classes (single mode used at both breakpoints) was never touched by either rule to
  begin with. Fixed by only ever forcing "display: none !important" to HIDE the wrong variant, and
  never forcing a display value to show the right one - by default (no override at all), a shown
  element keeps whatever display value ITS OWN rules give it (grid for Standard, Owl Carousel's
  own display for its variant), rather than this generic visibility toggle overwriting it.
*/
@media (max-width: 767px) {
  .pdx-show-desktop:not(.pdx-show-mobile) { display: none !important; }
}
@media (min-width: 768px) {
  .pdx-show-mobile:not(.pdx-show-desktop) { display: none !important; }
}

/* =========================== PRODUCT GRID =========================== */

/*
  .product-grid is the OUTER wrapping <section> that also contains the "Featured products" <h2
  class="title"> as a SIBLING of .item-grid (see HomepageProducts/Default.cshtml) - it must stay
  a plain block so the title stacks above the products. Only .item-grid (the actual card
  container) gets the grid layout. An earlier version of this file applied display:grid to BOTH
  selectors, which turned the title and the whole product list into two side-by-side grid cells
  (title squeezed into column 1) - that's what caused the "title next to a narrow product list"
  bug on the homepage.
*/
.product-grid,
.category-grid { width: 100%; }

/*
  Featured Products / Best Sellers (.product-grid) and Categories, on the homepage specifically,
  get a full-bleed background color that reaches both edges of the browser window, independent of
  --pdx-container - same breakout technique already used for the homepage banner (.nop-slider):
  the outer box is stretched to 100vw and shifted left by half the viewport width via "left:
  calc(-50vw + 50%)", which only works because these sections already sit inside a width:100%
  ancestor chain (.center-1/.master-column-wrapper/.master-wrapper-content), i.e. the same
  precondition the banner already relies on. Every DIRECT child (the title, and whichever
  .item-grid variant(s) are rendered - see the "HOMEPAGE SECTION LAYOUTS" comment above for why
  there can be more than one) is then re-constrained back to --pdx-container width, centered, with
  the same 20px side padding .master-wrapper-content uses - so the actual cards/title still line
  up exactly with the rest of the page's content, only the color band behind them is wider.

  IMPORTANT: this section targets ".home-page-category-grid" specifically, NOT the bare
  ".category-grid" class - core's own category detail page (CategoryTemplate.
  ProductsInGridOrLines.cshtml, unmodified) renders its subcategories block as
  "<div class="category-grid sub-category-grid">", i.e. it carries "category-grid" too, purely as
  a base/tile-styling class shared with the homepage component (see ".category-grid .item-box"
  further below, which both usages still legitimately share for the tile look itself - image,
  title, hover zoom). An earlier version of this rule targeted the bare ".category-grid" class,
  which meant the homepage's admin-configurable Categories background color/image/FullWidthBackground
  settings (Theme1Settings.CategoriesSectionBackgroundColor etc) were ALSO being applied to that
  subcategory grid on every category listing page - admin changes made for the homepage's
  Categories section were silently bleeding onto an unrelated page. HomepageCategories/
  Default.cshtml (this theme's own override) renders its own wrapping <section> with BOTH
  "category-grid" and "home-page-category-grid" - .home-page-category-grid is the one this rule
  (and the matching per-request block in ThemeStyles/Default.cshtml, and the CategoriesFullWidthBackground
  toggle) is actually scoped to, so only the homepage component is affected; the category page's
  ".sub-category-grid" gets its own independent, non-admin-driven styling instead - see that rule
  further below, right after this block.

  IMPORTANT: RelatedProducts/ProductsAlsoPurchased on the product detail page also render a
  "<... class="... product-grid">" wrapper (see those two theme overrides) and were NOT part of
  this request, so they must keep their normal (non-full-bleed) layout - which is why the rule
  below targets .home-page-category-grid/.home-page-product-grid/.home-page-bestsellers
  specifically rather than the bare .product-grid class those two also share.

  Background color and image are both admin-configurable PER SECTION (Categories / Featured
  products / Best sellers each have their own Theme1Settings.*SectionBackgroundColor and
  *SectionBackgroundImageUrl, rather than shared values) - .product-grid alone can't distinguish
  Featured products from Best sellers since both render that same base class, so the actual
  background is set below via each section's more specific wrapper class
  (.home-page-product-grid / .home-page-bestsellers / .home-page-category-grid), each reading its
  own --pdx-section-bg-*/--pdx-section-bg-image-* custom properties (set in the plugin's injected
  <style> block). The image (when set) layers over the color, same as CodeInjector's per-block
  background does - the color still shows through anywhere the image is transparent or hasn't
  loaded.

  IMPORTANT: this rule targets .home-page-category-grid/.home-page-product-grid/
  .home-page-bestsellers DIRECTLY (no ".home-page" ancestor prefix) - an earlier version used
  ".home-page .category-grid" etc, a DESCENDANT selector requiring an ancestor element carrying
  the literal class "home-page" with .category-grid nested inside it as a separate element. In the
  actual rendered markup here, these wrapper classes carry all their own classes directly on
  themselves with no such "home-page"-classed ancestor wrapping them that way, so the old
  descendant-selector version silently matched nothing at all - not even the background-color.
  Dropping the ".home-page" prefix fixes that; it's safe because these three class names are
  already homepage-specific on their own (unlike bare .product-grid, which Related Products/
  Products Also Purchased also use on the product detail page - see the IMPORTANT note above for
  why those two are deliberately excluded from this rule instead).

  IMPORTANT: as of the FullWidthBackground toggle work, this ENTIRE rule block (padding,
  background-size/position/repeat, background-color/image, and the "> *" content re-alignment
  rule) is a FALLBACK ONLY - the authoritative, always-current version of all of this is rendered
  per-request in
  Nop.Plugin.Prodigix.Theme1/Views/Shared/Components/ThemeStyles/Default.cshtml's
  <style id="pdx-theme1-sections"> block, which has proven far more reliable to keep in sync with
  admin changes than this static file. The rules below only matter if that plugin is disabled;
  don't assume editing them here will change what's actually visible on the live site.
*/
.home-page-category-grid,
.home-page-product-grid,
.home-page-bestsellers {
  padding: 40px 0;
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
}
.home-page-category-grid { background-color: var(--pdx-section-bg-categories, #FFFFFF); background-image: var(--pdx-section-bg-image-categories, none); }
.home-page-product-grid { background-color: var(--pdx-section-bg-featured, #FFFFFF); background-image: var(--pdx-section-bg-image-featured, none); }
.home-page-bestsellers { background-color: var(--pdx-section-bg-bestsellers, #FFFFFF); background-image: var(--pdx-section-bg-image-bestsellers, none); }
/* content re-alignment: always applied regardless of the FullWidthBackground toggle above - when
   full-bleed, this re-constrains content back to the theme's normal container width/padding after
   the outer box breaks out to 100vw; when contained, the outer box never moves in the first place,
   so this is effectively a no-op centering rule (max-width only bites if the ambient width would
   otherwise exceed it) but still supplies the same 20px side padding either way, so content lines
   up identically in both modes instead of depending on whichever ancestor padding happens to be
   in play. */
.home-page-category-grid > *,
.home-page-product-grid > *,
.home-page-bestsellers > * {
  max-width: var(--pdx-container);
  margin-left: auto;
  margin-right: auto;
  padding-left: 0px;
  padding-right: 0px;
}

/*
  Category detail page's OWN subcategory grid (e.g. /apparel showing Shoes/Clothing/Accessories) -
  core's CategoryTemplate.ProductsInGridOrLines.cshtml (unmodified) renders this as
  "<div class="category-grid sub-category-grid">". Styled independently from the homepage
  Categories section above on purpose (per spec) - plain, contained (never full-bleed), no
  admin-configurable background color/image, no ties to Theme1Settings.Categories* at all. Only
  the tile-level look (.category-grid .item-box further below) is still shared between the two,
  since that's just the reusable "category tile" component styling, not a homepage-only setting.
  Modest top/bottom spacing here since this section sits between the page's breadcrumb/title above
  and "Featured products"/the product list below, neither of which supply their own separating
  margin. Editing this rule affects ONLY the category detail page - never the homepage.
*/
.sub-category-grid { margin-bottom: 32px; }

/*
  Admin-configurable background/text color for the subcategory tile grid specifically (Configure >
  Product Listings > Subcategories > "Subcategory grid background color"/"Subcategory tile text
  color" - Theme1Settings.SubCategoriesBackgroundColor/SubCategoriesTextColor, rendered as
  --pdx-subcat-bg/--pdx-subcat-text at :root by ThemeStyles/Default.cshtml). Deliberately scoped
  to ".category-grid.sub-category-grid" itself (background + padding) and ".category-grid.sub-
  category-grid .item-box .title a" (text) specifically - NOT the bare ".category-grid .item-box"
  rule above, which is shared with the homepage's Categories section (.home-page-category-grid
  .item-box) and must stay completely unaffected by this feature. Higher specificity than that
  shared rule (two classes vs one on the ancestor) is what lets this override win for subcategory
  tiles without touching the homepage section's own title color (--pdx-card-title-color).

  IMPORTANT: background-color AND padding both live on ".category-grid.sub-category-grid" (the
  OUTER wrapper) - NOT on ".item-grid" itself. An earlier version put both on ".item-grid"
  instead, which is harmless for the Standard-grid variant (a plain CSS Grid container) but broke
  the Owl-Carousel variant on mobile: that SAME .item-grid element is also the exact element Owl
  Carousel initializes and measures ("#subcategory-grid-carousel" - see the theme's
  CategoryTemplate.ProductsInGridOrLines.cshtml override), and Owl Carousel computes its internal
  stage/item widths from that element's OWN width. Padding directly on Owl's root element threw
  off that math on mobile specifically (never on desktop's Standard grid, which has no such JS
  measuring step) - reported as oversized product images overflowing to the right further down
  the page, once the miscalculated carousel width pushed the whole page into unwanted horizontal
  scroll. Moving padding out to the wrapper (a plain, JS-untouched div) fixes this while keeping
  the exact same visual padding around the grid/carousel content.
*/
.category-grid.sub-category-grid {
  background-color: var(--pdx-subcat-bg, #F7F8FA);
  padding: 20px 14px 10px 14px;
  /* extra safety net alongside the fix above: clips any residual sub-pixel/rounding overshoot
     from Owl Carousel's own width calculations so it can never push this section (or anything
     below it on the page, like the product listing) into horizontal scroll on mobile. */
  overflow-x: hidden;
}
.category-grid.sub-category-grid .item-box .title a {
  color: var(--pdx-subcat-text, #2A2E34);
}
.category-grid.sub-category-grid .item-box .title a:hover {
  color: var(--pdx-card-title-hover-color, var(--pdx-primary));
}

/*
  Belt-and-suspenders fix for a reported mobile bug: with SubCategoriesDesktopLayoutMode=Standard
  and SubCategoriesMobileLayoutMode=Carousel (a genuinely MIXED-mode combination - the theme view
  override renders BOTH the Standard-grid and Owl-Carousel markup in this case, tagging each with
  .pdx-show-desktop/.pdx-show-mobile so the generic 'HOMEPAGE SECTION LAYOUTS' rules above hide
  whichever one does not belong at the current breakpoint - see that section's own comment), the
  Standard-grid variant was still visible ABOVE the working carousel on mobile instead of being
  hidden. The generic .pdx-show-desktop:not(.pdx-show-mobile)/.pdx-show-mobile:not(.pdx-show-
  desktop) rules should already cover this on their own, and do for the three homepage sections -
  this reinforces the exact same rule pair with a selector scoped to (and far higher specificity
  than) .category-grid.sub-category-grid specifically, so there is no possible ambiguity for THIS
  element regardless of cascade/specificity interactions elsewhere in the file.
*/
@media (max-width: 767px) {
  .category-grid.sub-category-grid .item-grid.pdx-show-desktop:not(.pdx-show-mobile) {
    display: none !important;
  }
}
@media (min-width: 768px) {
  .category-grid.sub-category-grid .item-grid.pdx-show-mobile:not(.pdx-show-desktop) {
    display: none !important;
  }
}

/* =========================== CATALOG SELECTORS (Display / Sort by / Grid-List view) =========================== */

/*
  Core's _CatalogSelectors.cshtml (Nop.Web/Views/Catalog) renders "<div class="product-
  selectors">" containing three independent blocks, in this DOM order: .product-viewmode
  (grid/list toggle), .product-sorting ("Order by" dropdown), .product-page-size ("Display"
  dropdown) - immediately before the product grid on every listing page (category, manufacturer,
  search, product tags, vendor - all share this same partial via _CatalogSelectors). Left
  completely unstyled before (plain stacked, left-aligned browser-default <select> elements) -
  this section lays out that row above the grid per spec (see below) and restyles each control
  into a compact bordered pill/icon-button.
  Requested visual order (Sort by at the left edge, Display next to the grid/list icons at the
  right edge) differs from core's own DOM order (viewmode, sorting, page-size) - reordered via
  flexbox "order"/margin below rather than touching the markup, since no actual DOM change is
  needed to achieve it (see the layout comment directly below for how the left/right split works).
  Themes/Nexus/Views/Catalog/_CatalogSelectors.cshtml is now a theme override of that core file
  (previously unmodified/CSS-only) - the ONLY markup change it makes is a new
  ".product-mobile-filter-trigger" button, first child of ".product-selectors", that opens .side-2
  as a slide-out drawer on mobile (see that button's own rules, and .side-2's mobile drawer CSS in
  the SIDEBAR (.side-2) BLOCKS section above) - it doesn't touch the three core blocks below at
  all, so everything already documented in this section still applies unchanged.
*/
/*
  Layout: "Sort by" pinned to the LEFT edge; "Display" sits directly beside the grid/list icons,
  both pushed to the RIGHT edge - per spec ("pull sort by to the left edge and display will be
  next to the grid icon"). justify-content:flex-start plus a flex "order" on each child would
  normally leave every child bunched together at the left - the actual left/right split comes from
  margin-left:auto on .product-page-size (Display), which (per standard flex auto-margin behavior)
  consumes all remaining free space immediately BEFORE that element, shoving it and everything
  ordered after it (the viewmode icons) over to the row's right edge, while Sort by (order:1, no
  auto margin) stays put at the left. */
.product-selectors {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-start;
  gap: 20px;
  margin-bottom: 20px;
}

.product-selectors .product-sorting { order: 1; }
.product-selectors .product-page-size { order: 2; margin-left: auto; }
.product-selectors .product-viewmode { order: 3; }

/* mobile-only "Filter" trigger, first child of .product-selectors (see this theme's
   Views/Catalog/_CatalogSelectors.cshtml override) - opens .side-2 as a slide-out drawer (see
   that class's own mobile CSS in the SIDEBAR (.side-2) BLOCKS section above). Hidden by default
   here (desktop, where .side-2 already sits inline as a normal sidebar and there's nothing for
   this button to do) - shown, reordered to the row's left edge, only within the
   @media (max-width: 991px) block further below, the SAME breakpoint .side-2 itself switches to
   a drawer at. Sized/styled to match the Sort by/Display pill selects next to it (same 38px
   height, same border/radius/font). */
.product-mobile-filter-trigger {
  display: none;
  align-items: center;
  gap: 8px;
  height: 38px;
  padding: 0 14px;
  border: 1px solid var(--pdx-border);
  border-radius: var(--pdx-input-radius, var(--pdx-radius-sm));
  background: var(--pdx-surface);
  font-size: 14px;
  font-weight: 600;
  color: var(--pdx-text);
  cursor: pointer;
}
.product-mobile-filter-trigger svg { flex: 0 0 auto; }
.product-mobile-filter-trigger:hover { border-color: var(--pdx-primary); color: var(--pdx-primary); }

.product-page-size,
.product-sorting {
  display: flex;
  align-items: center;
  gap: 10px;
}
.product-page-size > span:first-child,
.product-sorting > span:first-child {
  font-size: 14px;
  font-weight: 500;
  color: var(--pdx-text-muted);
  white-space: nowrap;
}
/* the "X items per page" suffix text core renders after the Display dropdown isn't part of the
   requested design (which shows only the dropdown itself) - visually hidden but left in the DOM
   for screen readers, same off-screen technique as .skip in the ACCESSIBILITY section further
   down this file. span:last-of-type (not :last-child) since the <select> sits between the two
   spans, so the label span isn't actually this element's last child element overall. */
.product-page-size span:last-of-type {
  position: absolute;
  left: -9999px;
  top: auto;
}

.product-page-size select,
.product-sorting select {
  -webkit-appearance: none;
  -moz-appearance: none;
  appearance: none;
  width: auto;
  height: 38px;
  margin: 0;
  padding: 0 30px 0 14px;
  border: 1px solid var(--pdx-border);
  border-radius: var(--pdx-input-radius, var(--pdx-radius-sm));
  background: var(--pdx-surface) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' fill='none' stroke='%236B7280' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") no-repeat right 12px center;
  background-size: 10px 6px;
  font-size: 14px;
  font-weight: 600;
  color: var(--pdx-text);
  cursor: pointer;
}
.product-page-size select { min-width: 70px; }
.product-sorting select { min-width: 150px; }
.product-page-size select:focus,
.product-sorting select:focus {
  outline: none;
  border-color: var(--pdx-primary);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--pdx-primary) 18%, transparent);
}

/* grid/list view-mode toggle - core renders each as a plain text anchor (literal "Grid"/"List"
   text, no icon markup at all - see .viewmode-icon in _CatalogSelectors.cshtml). The text stays
   in the DOM (it's the anchor's accessible name, also mirrored in its title attribute) but is
   visually replaced with an icon via ::before + a CSS mask, so icon-only buttons don't need a
   view override either. */
.product-viewmode { display: flex; align-items: center; gap: 4px; }
.product-viewmode > span:first-child {
  position: absolute;
  left: -9999px;
  top: auto;
}
.viewmode-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  font-size: 0;
  line-height: 0;
  border: none;
  border-radius: var(--pdx-radius-sm);
  background: transparent;
  color: var(--pdx-text-muted);
}
.viewmode-icon::before {
  content: "";
  display: block;
  width: 16px;
  height: 16px;
  background-color: currentColor;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-position: center;
  mask-position: center;
  -webkit-mask-size: contain;
  mask-size: contain;
}
/* nine distinct rounded squares (3x3), matching the reference "grid view" icon - an earlier
   version of this mask used touching 6x6 rects with no gap between them (x positions 3/9/15,
   each 6 wide - i.e. 3-9/9-15/15-21, zero gap), which rendered as one solid 18x18 block instead
   of nine separate squares. Gapped positions (1/9/17, each 6 wide, rx for slightly rounded
   corners) fix that. */
.viewmode-icon.grid::before {
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Crect x='1' y='1' width='6' height='6' rx='1.2'/%3E%3Crect x='9' y='1' width='6' height='6' rx='1.2'/%3E%3Crect x='17' y='1' width='6' height='6' rx='1.2'/%3E%3Crect x='1' y='9' width='6' height='6' rx='1.2'/%3E%3Crect x='9' y='9' width='6' height='6' rx='1.2'/%3E%3Crect x='17' y='9' width='6' height='6' rx='1.2'/%3E%3Crect x='1' y='17' width='6' height='6' rx='1.2'/%3E%3Crect x='9' y='17' width='6' height='6' rx='1.2'/%3E%3Crect x='17' y='17' width='6' height='6' rx='1.2'/%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Crect x='1' y='1' width='6' height='6' rx='1.2'/%3E%3Crect x='9' y='1' width='6' height='6' rx='1.2'/%3E%3Crect x='17' y='1' width='6' height='6' rx='1.2'/%3E%3Crect x='1' y='9' width='6' height='6' rx='1.2'/%3E%3Crect x='9' y='9' width='6' height='6' rx='1.2'/%3E%3Crect x='17' y='9' width='6' height='6' rx='1.2'/%3E%3Crect x='1' y='17' width='6' height='6' rx='1.2'/%3E%3Crect x='9' y='17' width='6' height='6' rx='1.2'/%3E%3Crect x='17' y='17' width='6' height='6' rx='1.2'/%3E%3C/svg%3E");
}
.viewmode-icon.list::before {
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Crect x='3' y='4' width='4' height='4'/%3E%3Crect x='10' y='4' width='11' height='4'/%3E%3Crect x='3' y='10' width='4' height='4'/%3E%3Crect x='10' y='10' width='11' height='4'/%3E%3Crect x='3' y='16' width='4' height='4'/%3E%3Crect x='10' y='16' width='11' height='4'/%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Crect x='3' y='4' width='4' height='4'/%3E%3Crect x='10' y='4' width='11' height='4'/%3E%3Crect x='3' y='10' width='4' height='4'/%3E%3Crect x='10' y='10' width='11' height='4'/%3E%3Crect x='3' y='16' width='4' height='4'/%3E%3Crect x='10' y='16' width='11' height='4'/%3E%3C/svg%3E");
}
.viewmode-icon:hover { color: var(--pdx-text); background: var(--pdx-body-bg); }
.viewmode-icon.selected { color: var(--pdx-primary); background: color-mix(in srgb, var(--pdx-primary) 10%, transparent); }

/*
  Mobile: "Filter" trigger pinned to the row's LEFT edge; "Sort by" and "Display" grouped
  together at the RIGHT edge, with their label text removed, per spec ("remove the sort by and
  display text and put them next to one another right aligned ... add a new Filter button ...
  left aligned"). Matches .side-2's own 991px drawer breakpoint above, since this row's whole
  point on mobile is to trigger that drawer.
  Same auto-margin technique .product-page-size already uses on desktop (see above), just moved
  to the new Filter trigger instead: margin-right:auto on the trigger (order:0, first item)
  consumes all remaining free space immediately AFTER it, shoving every sibling ordered after it
  (Sort by, Display, viewmode) over to the row's right edge as one group - so Display's own
  desktop margin-left:auto has to be cancelled here, or the two auto margins would fight each
  other and split the group apart again.
*/
@media (max-width: 991px) {
  .product-mobile-filter-trigger { display: inline-flex; order: 0; margin-right: auto; }
  .product-selectors .product-sorting { order: 1; }
  .product-selectors .product-page-size { order: 2; margin-left: 0; }
  .product-selectors .product-viewmode { order: 3; }

  /* "Sort by"/"Display" label text - same visually-hidden-but-still-accessible technique
     ".product-page-size span:last-of-type" (the "X items per page" suffix) already uses above,
     rather than removing the text from the DOM outright. */
  .product-sorting > span:first-child,
  .product-page-size > span:first-child {
    position: absolute;
    left: -9999px;
    top: auto;
  }
}

@media (max-width: 767px) {
  .product-selectors { justify-content: space-between; gap: 12px; margin-bottom: 16px; }
  .product-page-size,
  .product-sorting { gap: 6px; }
  .product-sorting select { min-width: 0; }
}

/* =========================== PRODUCT GRID (item-grid columns) =========================== */

/* .item-grid:not(.owl-carousel) is the plain CSS-grid layout, used both for category/manufacturer
   listing pages (which always use a fixed 4-column layout - untouched by the settings below) and
   for the three admin-configurable homepage sections when their mode is "Standard". Column count
   comes from --pdx-cols-desktop/--pdx-cols-mobile, set inline per-section by each theme view
   override (Categories/FeaturedProducts/BestSellers) based on the matching Theme1Settings values;
   the "4"/"2" fallbacks here are only used on pages that don't set those variables at all (i.e.
   don't have admin-configurable columns), like plain category/manufacturer listings. */
.item-grid:not(.owl-carousel) {
  display: grid;
  grid-template-columns: repeat(var(--pdx-cols-desktop, 4), 1fr);
  gap: 20px;
}

@media (max-width: 767px) {
  .item-grid:not(.owl-carousel) { grid-template-columns: repeat(var(--pdx-cols-mobile, 2), 1fr); gap: 12px; }
}

/*
  List view (Model.ViewMode == "list", set by the grid/list toggle in _CatalogSelectors.cshtml -
  see .viewmode-icon/.product-viewmode above, and public.catalogproducts.js's own "viewmode" URL
  param handling, core, unmodified). Core's _ProductsInGridOrLines.cshtml swaps the OUTER wrapper
  class between "product-grid" (default) and "product-list" depending on Model.ViewMode, but
  renders the exact same ".item-grid"/".item-box"/".product-item" markup either way - it does NOT
  add any list-specific class to .item-grid itself (confirmed directly in that file). The
  unconditional ".item-grid:not(.owl-carousel) { display: grid; ... }" rule above therefore always
  won regardless of which wrapper class was actually present, which is why clicking the list icon
  correctly changed the URL param and re-fetched the markup with "product-list" instead of
  "product-grid", but visually nothing changed - the CSS never looked at that wrapper class at all
  before this block. ".product-list .item-grid" has the same specificity as the rule above it, so
  placing this AFTER it in the file is what makes it win for list mode specifically. Single-column
  stacked rows, product image on the left at a fixed width (matching nopCommerce's own DefaultClean
  theme's list view) and details on the right, instead of the square grid card.
*/
.product-list .item-grid {
  display: flex;
  flex-direction: column;
  gap: 16px;
}
.product-list .item-box { width: 100%; }
.product-list .product-item { flex-direction: row; }
.product-list .product-item .picture {
  flex: 0 0 220px;
  width: 220px;
  aspect-ratio: 1 / 1;
}
.product-list .product-item .details { flex: 1 1 auto; }

@media (max-width: 600px) {
  /* narrow phones: fall back to a stacked (picture-on-top) card, same shape as grid mode, rather
     than squeezing a fixed 220px-wide image next to a cramped details column */
  .product-list .product-item { flex-direction: column; }
  .product-list .product-item .picture { width: 100%; flex-basis: auto; }
}

/* Owl Carousel's own base CSS lays out slides with float:left (not flex/grid), which is exactly
   why items with different amounts of title/description text end up different heights within a
   carousel row - floated elements never stretch to match a sibling's height, unlike flex or grid
   items. Converting .owl-stage to flex (overriding the float) makes .owl-item, and everything
   inside it, stretch to the row's tallest item by default - the standard, well-known fix for this
   exact Owl Carousel limitation. */
.owl-carousel .owl-stage { display: flex; }
.owl-carousel .owl-item {
  float: none;
  height: auto;
  /* Owl Carousel's own JS sets each .owl-item's WIDTH inline (in px, computed as container-width
     / "items" setting) - normally sufficient on its own, but once the stage above is switched to
     display:flex, a flex item's WIDTH property only becomes its flex-basis when flex-basis
     computes to "auto"; flex-shrink defaults to 1, so browsers remain free to shrink/grow that
     basis to reconcile rounding across the row instead of honoring the exact px value Owl set.
     Reported specifically on the Subcategories carousel on mobile (items not confining themselves
     to the configured 1-2 per row, images rendering at an oversized, overflowing size) after the
     "equal height" flex conversion above - other Owl carousels in this theme use the same
     structure and may be latently affected too, just not yet reported. flex-shrink/flex-grow:0
     here removes the ambiguity: the item's WIDTH is the only thing left that can size it, exactly
     matching what Owl's JS actually calculated, with no flex-driven reinterpretation of that
     number. */
  flex-shrink: 0;
  flex-grow: 0;
}

/*
  Deterministic override for the Subcategories carousel specifically (#subcategory-grid-carousel,
  ".category-grid.sub-category-grid .owl-item") - the flex-shrink/flex-grow:0 fix above should be
  sufficient on its own, but this carousel was STILL reported showing images at an oversized,
  overflowing size instead of confining to the configured 1-2 items per row, even after that fix
  was deployed.

  CORRECTED APPROACH: an earlier version of this rule used a plain PERCENTAGE
  ("width: calc(100% / var(--pdx-cols-mobile, 2))"), which was itself wrong and made the problem
  worse, not better - a percentage on ".owl-item" resolves against ITS CONTAINING BLOCK, which is
  ".owl-stage" (the flex container from the rule above), NOT the visible carousel viewport.
  ".owl-stage" is deliberately given a LARGE inline width by Owl's own JS (roughly itemWidth x
  total item count, so the stage can be slid/transformed to reveal different items) - it is
  intentionally much wider than what's actually visible. So "100% / 2" was computing half of that
  already-inflated stage width, not half of the visible carousel - if Owl's original per-item math
  was already close to correct (roughly half the visible width), the resulting stage ended up
  around 2x the visible width, and dividing THAT by 2 again landed right back at full-viewport-
  width per item, reproducing the same "oversized, overflowing" symptom via a different mechanism.

  The fix: CSS container query units ("cqw"), which - unlike "%" - resolve against a specific
  ancestor you designate via "container-type", not simply the immediate parent. Marking the
  CAROUSEL ITSELF ("#subcategory-grid-carousel", i.e. ".item-grid.owl-carousel" - the element with
  its own correct, un-inflated rendered width) as a query container, then sizing ".owl-item" in
  "cqw" (relative to THAT container's width, not ".owl-stage"'s), gives the exact intended pixel
  size regardless of whatever width ".owl-stage" ends up with internally. Requires container-query
  support (Chrome 105+/Firefox 110+/Safari 16+, i.e. every browser in real-world use in 2026).
  "!important" is still required/safe for the same reason as before: Owl's own per-item sizing is
  a plain (non-!important) inline style, and an !important rule in an author stylesheet always
  wins over a non-!important inline style for the same property. Same trade-off as before: Owl's
  internal slide/transform math still uses ITS OWN computed width for drag/nav/dot positioning,
  which could drift slightly out of sync with this CSS-forced width in edge cases - accepted over
  the alternative of images visibly overflowing the viewport. Scoped to Subcategories only (not
  the shared .owl-carousel .owl-item rule above) since that's the only carousel actually reported
  broken; apply the same pattern to the homepage sections' own carousel ids if the same symptom
  ever turns up there.
*/
.category-grid.sub-category-grid .item-grid.owl-carousel {
  container-type: inline-size;
}
.category-grid.sub-category-grid .owl-item {
  width: calc(100cqw / var(--pdx-cols-mobile, 2)) !important;
}
@media (min-width: 768px) {
  .category-grid.sub-category-grid .owl-item {
    width: calc(100cqw / var(--pdx-cols-desktop, 4)) !important;
  }
}

/*
  CSS Grid DOES stretch grid items (.item-box) to equal row height by default - but .item-box is
  just a plain block div, so stretching IT doesn't automatically stretch its CHILD (.product-item)
  to fill that space too; .product-item was just sitting at its own natural content height inside
  a taller, invisible .item-box, leaving the visible cards themselves uneven even though the grid
  cells around them were technically equal. This is what caused prices to land at different
  heights across a row in the plain "Standard" grid mode, not just inside Owl Carousel. Making
  .item-box a flex column (in both modes - the rule isn't scoped to .owl-carousel) fixes both at
  once by making .product-item explicitly fill its parent's full stretched height.
  .category-grid .item-box has its own separate, more specific rule ("display:block;
  text-align:center") further down for category tiles, which don't have this problem (no variable-
  height price/button row to align) - that rule's higher specificity (.category-grid .item-box vs
  plain .item-box) keeps it safely unaffected by this change.

  height:100% added below for the Owl Carousel path specifically: ".owl-stage { display:flex }"
  (further down) stretches ".owl-item" itself to the row's tallest sibling, but .item-box is only
  a BLOCK CHILD of .owl-item, not the flex item being stretched - so without an explicit height it
  still sat at its own natural content height inside a taller, invisible .owl-item, reproducing
  the exact same "equal invisible container, uneven visible card" symptom described above for CSS
  Grid, just one DOM level further down. Confirmed via getBoundingClientRect(): a 1-line-title card
  (394.5px) sitting inside a row where sibling 2-line-title cards forced .owl-item to 414px, before
  this fix. Harmless in Grid mode - .item-box there is already stretched to the row's height by the
  grid itself (per the comment above), so height:100% just restates the height it already has.
*/
.item-box { display: flex; width: 100%; height: 100%; }
.item-box .product-item { flex: 1 1 auto; width: 100%; }

/* Owl Carousel navigation arrows / dots, restyled to match the theme's color variables instead
   of the library's plain default black/white look */
.owl-carousel .owl-nav { position: absolute; top: -56px; right: 0; display: flex; gap: 8px; }
.owl-carousel .owl-nav button.owl-prev,
.owl-carousel .owl-nav button.owl-next {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  background: var(--pdx-body-bg) !important;
  color: var(--pdx-text) !important;
  font-size: 18px;
  line-height: 1;
}
.owl-carousel .owl-nav button.owl-prev:hover,
.owl-carousel .owl-nav button.owl-next:hover { background: var(--pdx-primary) !important; color: var(--pdx-button-text) !important; }
.owl-carousel .owl-nav button.disabled { opacity: .4; pointer-events: none; }
.owl-carousel .owl-dots { text-align: center; margin-top: 16px; }
/* each dot is a real <button class="owl-dot"><span></span></button> (Owl Carousel's own markup) -
   only ".owl-dot span" (the actual circle) was ever styled below, so the <button> itself kept the
   browser's native button chrome (white background, border, padding) showing through as a square
   box around each dot. Reset the button to a bare, unstyled hit target so only the circle shows. */
.owl-carousel .owl-dots .owl-dot {
  display: inline-block;
  padding: 0;
  margin: 0;
  border: none;
  background: none;
  cursor: pointer;
}
.owl-carousel .owl-dots .owl-dot span {
  display: inline-block;
  width: 8px;
  height: 8px;
  margin: 0 4px;
  border-radius: 50%;
  background: var(--pdx-border);
}
.owl-carousel .owl-dots .owl-dot.active span { background: var(--pdx-primary); }
.owl-carousel .item-box { padding: 0 6px; }

/* the featured-products carousel needs equal-height cards (Owl Carousel sizes every item in a row
   to the tallest one). Description length is capped in HomepageProducts/Default.cshtml (50 chars
   + ellipsis) specifically to keep that variance small, rather than hiding it outright - other
   product listing pages (category/manufacturer grids, best sellers, etc.) show the untruncated
   description as core does, since they don't have this height-matching constraint. */

.product-item {
  background: var(--pdx-surface);
  border-radius: var(--pdx-card-radius, var(--pdx-radius));
  /* admin-configurable border (Configure > Product cards > "Card border width"/"Card border
     color") - defaults to 0px (no visible border), since a 0-width border still participates in
     layout with box-sizing:border-box (set globally in the RESET section above) so it never
     shifts card sizing when toggled on/off. */
  border: var(--pdx-card-border-width, 0px) solid var(--pdx-card-border-color, #E4E7EC);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  transition: box-shadow .15s ease, border-color .15s ease;
}
.product-item:hover { box-shadow: var(--pdx-shadow-md); }

.product-item .picture { position: relative; aspect-ratio: 1 / 1; overflow: hidden; background: var(--pdx-body-bg); }
.product-item .picture img { width: 100%; height: 100%; object-fit: cover; transition: transform .3s ease; }
.product-item:hover .picture img { transform: scale(1.04); }

/* wishlist / compare - small round icon buttons pinned to the picture's top-right corner,
   hidden until the card is hovered/focused - same trigger as the "Add to cart" bar below */
.product-item-icons {
  position: absolute;
  top: 12px;
  right: 12px;
  z-index: 2;
  display: flex;
  flex-direction: column;
  gap: 8px;
  opacity: 0;
  visibility: hidden;
  transition: opacity .2s ease, visibility .2s ease;
}
.product-item:hover .product-item-icons,
.product-item:focus-within .product-item-icons { opacity: 1; visibility: visible; }
.product-item-icon {
  width: 34px;
  height: 34px;
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  border: none;
  border-radius: 50%;
  background: var(--pdx-surface);
  color: var(--pdx-text);
  box-shadow: var(--pdx-shadow);
  cursor: pointer;
  transition: background-color .15s ease, color .15s ease;
}
.product-item-icon:hover { background: var(--pdx-primary); color: var(--pdx-button-text); }

/* "Add to cart" - a floating button-style bar inset from the picture's edges, hidden fully
   below the picture by default (translateY(100%), clipped by .picture's own overflow:hidden) and
   sliding up into that inset position on hover/focus of anywhere on the card. Uses its own
   admin-configurable colors (--pdx-card-cart-*) rather than the general theme button colors, so
   it can be styled independently from cart/checkout buttons elsewhere. */
.product-item-cart-overlay {
  position: absolute;
  left: 12px;
  right: 12px;
  bottom: 12px;
  z-index: 2;
  width: auto; /* .product-box-add-to-cart-button (see BUTTONS section) sets width:100% on this
                  same element - explicit width fights with left+right positioning on an
                  absolutely-positioned box (only one of left/right/width can actually be honored),
                  which is what pushed the button flush against one edge. Overriding back to auto
                  here lets left+right jointly determine the width again, as intended. */
  margin: 0;
  padding: 14px;
  background: var(--pdx-card-cart-bg, var(--pdx-button-bg));
  color: var(--pdx-card-cart-text, var(--pdx-button-text));
  font-size: 13px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .05em;
  text-align: center;
  border: none;
  border-radius: var(--pdx-button-radius, 0px);
  cursor: pointer;
  transform: translateY(calc(100% + 12px));
  transition: transform .25s ease, background-color .15s ease;
}
.product-item-cart-overlay:hover { background: var(--pdx-card-cart-hover-bg, var(--pdx-button-hover-bg)); }
.product-item:hover .product-item-cart-overlay,
.product-item:focus-within .product-item-cart-overlay { transform: translateY(0); }

.product-item .details { padding: 14px; display: flex; flex-direction: column; gap: 0; flex: 1; background: var(--pdx-card-details-bg, var(--pdx-surface)); }
/* .product-title is an <h2> - the generic "h2, .title { font-size: 20px }" rule elsewhere in this
   file would otherwise give it an oversized line box (sized for 20px text) even though the link
   inside it renders at 15px, which reads as a phantom gap under the title. Setting the h2's own
   font-size/line-height here (not just the <a> inside it) removes that invisible extra space -
   this was the actual cause of the title/description gap not fully closing before. */
/* line-clamp caps the title to 2 lines regardless of length, so even within an already
   equal-height card (via the Owl Carousel fix above, or CSS Grid's default stretch behavior),
   the price/buttons still line up at a consistent vertical position instead of shifting around
   based on whether a given product's title happens to wrap to one line or two. */
.product-item .product-title { font-size: 15px; line-height: 1.3; }
.product-item .product-title a {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  color: var(--pdx-card-title-color, var(--pdx-text));
  font-size: 15px;
  font-weight: 600;
}
.product-item .product-title a:hover { color: var(--pdx-card-title-hover-color, var(--pdx-primary)); }

/* no gap between title and description (per spec); .details' own flex "gap" is 0 for exactly
   that reason, so the ~8px gap before price/buttons has to be restored explicitly on .add-info
   instead - .sku/.product-rating-box (optional, only shown depending on catalog settings) get a
   small margin-top too so they don't end up flush against the title if they happen to render. */
.product-item .description { font-size: 13px; color: var(--pdx-card-desc-color, var(--pdx-text-muted)); margin-top: 0; }
.product-item .sku,
.product-item .product-rating-box { margin-top: 4px; }
/* pin price/buttons to the bottom of the card - margin-top:auto on a flex child in a column
   flex container consumes all remaining free space above it, so .add-info always sits flush
   against the bottom of .details regardless of how many lines the title/description above it
   take up. Without this, two cards with different title/description lengths would have their
   prices land at different heights even though the cards themselves are the same height (fixed
   separately via the Owl Carousel flex fix and title line-clamp above). */
.product-item .add-info { margin-top: auto; padding-top: 8px; }

.prices { display: flex; align-items: baseline; gap: 8px; margin-top: 4px; }
.prices .actual-price { font-size: 18px; font-weight: 700; color: var(--pdx-card-price-color, var(--pdx-primary)); }
.prices .old-price { font-size: 13px; color: var(--pdx-card-old-price-color, var(--pdx-text-muted)); text-decoration: line-through; }

.product-item .buttons { display: flex; flex-direction: column; gap: 6px; margin-top: 8px; }

/* category tiles (HomepageCategories/HomepageCategoriesViewComponent) - core ships these
   completely unstyled (just <article class="item-box"><h2 class="title">...<div
   class="picture">...), so this gives them the same card treatment as .product-item for visual
   consistency, without needing a details/price/button area they don't have. */
.category-grid .item-box {
  display: block;
  text-align: center;
}
.category-grid .item-box .picture {
  aspect-ratio: 1 / 1;
  overflow: hidden;
  border-radius: var(--pdx-card-radius, var(--pdx-radius));
  background: var(--pdx-body-bg);
  margin-bottom: 12px;
}
.category-grid .item-box .picture img { width: 100%; height: 100%; object-fit: cover; transition: transform .3s ease; }
.category-grid .item-box:hover .picture img { transform: scale(1.04); }
.category-grid .item-box .title { margin-bottom: 0; }
.category-grid .item-box .title a { color: var(--pdx-card-title-color, var(--pdx-text)); font-size: 15px; font-weight: 600; }
.category-grid .item-box .title a:hover { color: var(--pdx-card-title-hover-color, var(--pdx-primary)); }

/* =========================== PAGE TITLES / SECTIONS =========================== */

.page-title h1 { margin-bottom: 20px; }
.title { color: var(--pdx-subheading); margin-bottom: 16px; }

/* section headings for each homepage widget zone (Featured products, Bestsellers, News, Polls,
   category tiles, etc. - see HomepageProducts/HomepageBestSellers/HomepageNews/HomepagePolls/
   HomepageCategories, all of which render their heading as <h2 class="title">) are centered.
   Scoped to .home-page specifically so other pages' ".title" usages (footer columns, sidebar
   blocks, etc.) are unaffected. */
.home-page .title { text-align: center; }

/* spacing between each homepage widget zone (Featured products, Best sellers, News, Polls,
   Categories, etc.) - each one renders as its own top-level element directly inside .page-body
   (see Home/Index.cshtml: every @@await Component.InvokeAsync(...) call there streams its own
   wrapping element straight into .page-body, with no extra wrapper div per call), so a generic
   rule via the adjacent-sibling combinator covers all of them without needing to know each
   section's specific class name. Currently 0px (no added gap) - sections rely on their own
   internal padding, if any, for separation. */
.home-page .page-body > * + * { margin-top: 0px; }

/* =========================== HOMEPAGE NEWS =========================== */

/*
  Core's HomepageNews/Default.cshtml (Nop.Web, unmodified) already renders clean, semantic markup
  - <section class="news-list-homepage"><div class="news-items"><article class="news-item">
  <header class="news-head"><a class="news-title"><h3>...<time class="news-date">...<section
  class="news-body">[html]...<footer class="buttons"><a class="read-more">... - so unlike the
  product cards, no view override was needed here, just CSS targeting the existing classes. Cards
  reuse the same --pdx-card-* variables as product cards for visual consistency across the
  homepage, even though these are a different admin settings surface (no per-section colors were
  requested for News, just "layout and styling").
*/
.news-items {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 20px;
}

.news-item {
  background: var(--pdx-card-details-bg, var(--pdx-surface));
  border-radius: var(--pdx-card-radius, var(--pdx-radius));
  padding: 24px;
  display: flex;
  flex-direction: column;
  box-shadow: var(--pdx-shadow);
  transition: box-shadow .15s ease;
}
.news-item:hover { box-shadow: var(--pdx-shadow-md); }

.news-head { margin-bottom: 8px; }
.news-title { display: block; }
.news-title h3 {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  color: var(--pdx-card-title-color, var(--pdx-text));
  font-size: 18px;
  margin-bottom: 4px;
}
.news-title:hover h3 { color: var(--pdx-card-title-hover-color, var(--pdx-primary)); }
.news-date {
  display: block;
  font-size: 12px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--pdx-primary);
}
/* core's date text on the homepage/list cards is literally "-2026, ..." (a leading hyphen baked
   into the resource string, see HomepageNews/Default.cshtml: "-@item.CreatedOn...") - hidden here
   rather than editing the resource, since that hyphen reads oddly as a standalone label. Scoped to
   ".news-head .news-date" (the wrapper both the homepage cards and the /news archive list use)
   rather than the bare ".news-date" class - the single news article page (NewsItem.cshtml) reuses
   the same "news-date" class on its own <time> but WITHOUT a leading hyphen and WITHOUT a
   .news-head wrapper, so an unscoped rule here was silently eating the first digit of that page's
   real date text (e.g. "2026" rendering as "026") - see the NEWS ARTICLE PAGE section below. */
.news-head .news-date::first-letter { font-size: 0; }

/* scoped to ".news-item .news-body" (the excerpt-card wrapper used on the homepage and /news
   archive list) rather than the bare ".news-body" class - NewsItem.cshtml (the single article
   page) reuses that same "news-body" class on its <article> wrapping the FULL article HTML
   (Model.Full), a completely different context from these 3-line-clamped excerpt cards. An
   unscoped rule here was silently clamping every full article's body text to 3 lines - see the
   NEWS ARTICLE PAGE section below for that page's own, unclamped styling. */
.news-item .news-body {
  color: var(--pdx-card-desc-color, var(--pdx-text-muted));
  font-size: 14px;
  flex: 1 1 auto;
  margin-top: 8px;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.news-item .news-body p { margin-bottom: 0; }

.news-item .buttons { margin-top: 16px; }
.news-item .read-more {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  color: var(--pdx-primary);
  font-weight: 600;
  font-size: 14px;
}
.news-item .read-more::after { content: "\2192"; transition: transform .15s ease; }
.news-item .read-more:hover::after { transform: translateX(3px); }

/*
  Background color/image/sizing for the News widget zone - admin-configurable via
  Theme1Settings.NewsSectionBackgroundColor/NewsSectionBackgroundImageUrl. .news-list-homepage is
  the single top-level element core renders for this zone (see the big comment above).

  IMPORTANT: as of the FullWidthBackground toggle work, this entire rule (including the "> *"
  content re-alignment rule) is a FALLBACK ONLY - the authoritative, always-current version is
  rendered per-request in ThemeStyles/Default.cshtml's <style id="pdx-theme1-sections"> block,
  which has proven far more reliable to keep in sync with admin changes than this static file.
*/
.news-list-homepage {
  padding: 40px 0;
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
  background-color: var(--pdx-section-bg-news, #FFFFFF);
  background-image: var(--pdx-section-bg-image-news, none);
}
.news-list-homepage > * {
  max-width: var(--pdx-container);
  margin-left: auto;
  margin-right: auto;
  padding-left: 20px;
  padding-right: 20px;
}
.news-list-homepage .view-all { text-align: center; margin-top: 32px; }
.news-list-homepage .view-all a {
  display: inline-block;
  padding: 11px 28px;
  border: 1px solid var(--pdx-border);
  border-radius: var(--pdx-button-radius, 0px);
  color: var(--pdx-text);
  font-weight: 600;
  font-size: 14px;
}
.news-list-homepage .view-all a:hover { border-color: var(--pdx-primary); color: var(--pdx-primary); }

@media (max-width: 991px) {
  .news-items { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 767px) {
  .news-items { grid-template-columns: 1fr; gap: 16px; }
}

/* =========================== HOMEPAGE COMMUNITY POLL =========================== */

/*
  Core's HomepagePolls/Default.cshtml + _Poll.cshtml (Nop.Web, unmodified) already renders clean
  markup per poll - <div class="poll"><strong class="poll-display-text">(question)<ul
  class="poll-options"|"poll-results"><li class="answer">... - again styled entirely via CSS, no
  view override, so the existing AJAX voting script (in _Poll.cshtml) is completely untouched.
  Multiple polls can render on the homepage at once; each becomes its own centered card, stacked
  with a gap, narrower than a full-width section since a poll is just a short question and a
  handful of options - a full-width bar of radio buttons would look sparse and be harder to scan.
*/
/*
  Background color/image/sizing for the Community Poll widget zone - admin-configurable via
  Theme1Settings.PollsSectionBackgroundColor/PollsSectionBackgroundImageUrl. .home-page-polls is a
  flex container with align-items:center, so each individual .poll card (which keeps its own
  narrower max-width:520px, set further below) stays centered within whatever width the section
  ends up at - no "> *" re-constraining rule is needed here, unlike the grid-based sections above.

  IMPORTANT: as of the FullWidthBackground toggle work, this entire rule is a FALLBACK ONLY - the
  authoritative, always-current version is rendered per-request in ThemeStyles/Default.cshtml's
  <style id="pdx-theme1-sections"> block, which has proven far more reliable to keep in sync with
  admin changes than this static file.
*/
.home-page-polls {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 20px;
  /* 10px left/right - unlike the product/category/news sections above, this one has no
     "> *" content re-alignment rule of its own (the poll card centers itself via this element's
     own align-items:center instead), so side padding lives directly on .home-page-polls -
     without it, the poll card (width:100% up to its own max-width:520px further below) runs
     edge-to-edge on any mobile viewport under 520px wide once this section goes full-bleed. Kept
     in sync with the authoritative version of this rule in Nop.Plugin.Prodigix.Theme1's
     ThemeStyles/Default.cshtml - see the IMPORTANT note below. */
  padding: 40px 10px;
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
  background-color: var(--pdx-section-bg-polls, #FFFFFF);
  background-image: var(--pdx-section-bg-image-polls, none);
}

.poll {
  width: 100%;
  max-width: 520px;
  background: var(--pdx-card-details-bg, var(--pdx-surface));
  border-radius: var(--pdx-card-radius, var(--pdx-radius));
  padding: 28px;
  box-shadow: var(--pdx-shadow);
}

.poll-display-text {
  display: block;
  font-size: 18px;
  font-weight: 700;
  color: var(--pdx-card-title-color, var(--pdx-text));
  margin-bottom: 18px;
}

/* before voting: radio options, styled as full-width selectable rows rather than bare browser
   radio buttons, so the whole row (not just the tiny native radio) is an obvious click target.
   Core's markup (_Poll.cshtml) renders <input> and <label> as SIBLINGS inside <li class="answer">
   (label uses a "for" attribute, doesn't wrap the input) - so .answer itself, not the label, has
   to be the styled row/flex container for the input and label to sit side by side inside it. */
.poll-options .answer {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 14px;
  margin-bottom: 10px;
  border: 1px solid var(--pdx-border);
  border-radius: var(--pdx-radius-sm);
  cursor: pointer;
  transition: border-color .15s ease, background-color .15s ease;
}
.poll-options .answer:hover { border-color: var(--pdx-primary); background: var(--pdx-body-bg); }
.poll-options .answer:has(input:checked) { border-color: var(--pdx-primary); background: var(--pdx-body-bg); }
.poll-options .answer input[type="radio"] { accent-color: var(--pdx-primary); width: 16px; height: 16px; flex: 0 0 auto; }
.poll-options .answer label { flex: 1 1 auto; font-size: 14px; cursor: pointer; }

.poll .buttons { margin-top: 16px; display: flex; align-items: center; gap: 12px; }
.poll .please-wait { font-size: 13px; color: var(--pdx-text-muted); }
.poll-vote-error { color: var(--pdx-danger); font-size: 13px; margin-top: 10px; }

/* after voting: each option becomes a percentage row with a filled bar behind the text (built
   with a linear-gradient rather than an extra element, since the percentage is baked into the
   translated result-line text, not a separate value core exposes for a real progress-bar div) */
.poll-results .answer {
  position: relative;
  padding: 10px 14px;
  margin-bottom: 8px;
  border-radius: var(--pdx-radius-sm);
  background: var(--pdx-body-bg);
  font-size: 14px;
  overflow: hidden;
}
.poll-total-votes { display: block; margin-top: 14px; font-size: 13px; color: var(--pdx-text-muted); }

@media (max-width: 767px) {
  /* belt-and-suspenders alongside .home-page-polls's own 10px side padding above: this keeps the
     card itself 10px off both edges of whatever it's sitting in, rather than relying entirely on
     the parent section's padding actually reaching this element (a full-bleed section's padding
     can get shadowed by later same-selector rules, caching of the per-request ThemeStyles output,
     etc.) - width:calc(100% - 20px) + margin auto is self-contained and doesn't depend on that. */
  .poll { width: calc(100% - 20px); margin-left: auto; margin-right: auto; }
}

@media (max-width: 480px) {
  .poll { padding: 20px; }
}

/* =========================== PRODUCT DETAIL PAGE =========================== */

/*
  Modeled on the layout Flexo's own product detail page uses (confirmed against
  ClaudeWorkingFolder/Themes/Flexo/Content/css/styles.css: a two-column split - a narrower fixed-
  ish gallery column and a wider flexible overview column, roughly 30/70 to 44/55 depending on
  breakpoint) - reimplemented with flexbox here instead of Flexo's float-based columns, since the
  rest of this theme is flex/grid throughout. All classes below are core nopCommerce markup
  (Views/Product/ProductTemplate.Simple.cshtml and its partials, Nop.Web, unmodified) - the
  overall page structure barely differs from Flexo's own version of that same file, so no view
  override was needed for the main page itself, only for RelatedProducts/ProductsAlsoPurchased
  (see those two files) to add the carousel behavior CSS alone can't provide.
*/

.product-essential {
  display: flex;
  flex-wrap: wrap;
  gap: 40px;
  padding-bottom: 32px;
  margin-bottom: 32px;
  border-bottom: 1px solid var(--pdx-border);
}

.gallery { flex: 1 1 380px; max-width: 460px; }
.overview { flex: 2 1 420px; min-width: 280px; }

/* main image + click-to-swap thumbnails (Magnific Popup lightbox, core JS - untouched). Both use
   Configure > Images > "Image corner radius" (--pdx-image-radius) - NOT --pdx-card-radius, which
   is reserved for product CARD containers on grid listings only. */
.gallery .picture-gallery { position: relative; }
.gallery .picture {
  aspect-ratio: 1 / 1;
  overflow: hidden;
  border-radius: var(--pdx-image-radius, var(--pdx-radius));
  background: var(--pdx-body-bg);
  margin-bottom: 12px;
  display: flex;
  align-items: center;
  justify-content: center;
}
.gallery .picture img { width: 100%; height: 100%; object-fit: contain; }
.gallery .picture-thumbs { display: flex; flex-wrap: wrap; gap: 10px; }
.gallery .picture-thumbs .thumb-item {
  width: 72px;
  height: 72px;
  flex: 0 0 auto;
  border: 1px solid var(--pdx-border);
  border-radius: var(--pdx-image-radius, var(--pdx-radius-sm));
  overflow: hidden;
  cursor: pointer;
  transition: border-color .15s ease, opacity .15s ease;
}
.gallery .picture-thumbs .thumb-item:hover { border-color: var(--pdx-primary); opacity: .85; }
.gallery .picture-thumbs .thumb-item img { width: 100%; height: 100%; object-fit: cover; }

.overview .product-name h1 { font-size: 28px; margin-bottom: 12px; }
.overview .short-description { color: var(--pdx-card-desc-color, var(--pdx-text-muted)); margin-bottom: 16px; line-height: 1.6; }

/* star rating - core only outputs an inline width:X% on a plain <div> (no sprite/font classes),
   so the stars themselves are drawn here with stacked unicode glyphs: a muted "empty" layer
   (::before on .rating) and a primary-colored "filled" layer clipped to that inline width
   (::before on the inner div) laid exactly on top of it via position:absolute. */
.product-reviews-overview { display: flex; align-items: center; gap: 12px; margin-bottom: 16px; flex-wrap: wrap; }
.product-review-box .rating {
  position: relative;
  display: inline-block;
  width: 90px;
  height: 16px;
  font-size: 16px;
  line-height: 1;
  letter-spacing: 2px;
  color: var(--pdx-border);
}
.product-review-box .rating::before { content: "\2605\2605\2605\2605\2605"; }
.product-review-box .rating > div { position: absolute; top: 0; left: 0; overflow: hidden; white-space: nowrap; color: #F5A623; }
.product-review-box .rating > div::before { content: "\2605\2605\2605\2605\2605"; }
.product-review-links a { font-size: 13px; font-weight: 600; }
.product-review-links.add-review a { color: var(--pdx-primary); }

.overview .manufacturers,
.overview .availability { font-size: 14px; margin-bottom: 10px; }
.overview .availability .label,
.additional-details .label { color: var(--pdx-text-muted); margin-right: 4px; }
.overview .availability .value { font-weight: 600; }

.additional-details { display: flex; flex-direction: column; gap: 4px; margin-bottom: 16px; font-size: 13px; }
.additional-details .value { color: var(--pdx-text); font-weight: 600; }

/* price block */
.overview .prices { margin: 16px 0; }
.overview .prices label { color: var(--pdx-text-muted); font-weight: 500; font-size: 13px; margin-right: 6px; }
.overview .prices .old-product-price { color: var(--pdx-card-old-price-color, var(--pdx-text-muted)); font-size: 15px; margin-bottom: 4px; }
.overview .prices .old-product-price span:last-child { text-decoration: line-through; }
.overview .prices .product-price,
.overview .prices .non-discounted-price { font-size: 30px; font-weight: 700; color: var(--pdx-card-price-color, var(--pdx-primary)); }
.overview .prices .discounted-price { font-size: 22px; font-weight: 700; color: var(--pdx-success); margin-top: 4px; }
.overview .prices .call-for-price { font-size: 22px; font-weight: 700; color: var(--pdx-card-price-color, var(--pdx-primary)); }
.overview .tax-shipping-info { display: block; font-size: 13px; color: var(--pdx-text-muted); margin-top: 6px; }

/* add to cart */
.add-to-cart-panel { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin: 16px 0; }
.qty-label { font-weight: 600; font-size: 14px; }
.qty-dropdown { width: 90px; height: 46px; flex: 0 0 auto; }
.add-to-cart-button { height: 46px; padding: 0 32px; font-size: 14px; }
.min-qty-notification { font-size: 13px; color: var(--pdx-text-muted); margin-bottom: 10px; }

/* +/- stepper (Themes/Nexus/Views/Product/_AddToCart.cshtml, a Nexus-only view override - core
   ships a plain ".qty-input" text box here with no increment/decrement UI). Reuses the exact same
   ".product-quantity"/".quantity.up"/".quantity.down" component the cart page's row stepper is
   built from (see this file's "SHOPPING CART PAGE" section for that component's original
   ".cart"-scoped sizing) - only the SIZE differs here, to match this page's existing 46px-tall
   qty/button row instead of the cart table's more compact 38px row. */
.add-to-cart-panel .product-quantity {
  display: inline-flex;
  align-items: stretch;
  height: 46px;
  border: 1px solid var(--pdx-border);
  border-radius: var(--pdx-radius-sm);
  overflow: hidden;
  flex: 0 0 auto;
}
.add-to-cart-panel .product-quantity .qty-input {
  width: 48px;
  height: 100%;
  border: none;
  border-left: 1px solid var(--pdx-border);
  border-right: 1px solid var(--pdx-border);
  border-radius: 0;
  text-align: center;
  padding: 0;
  font-weight: 600;
}
.add-to-cart-panel .product-quantity .qty-input:focus { box-shadow: inset 0 0 0 1px var(--pdx-primary); }
.add-to-cart-panel .product-quantity .quantity {
  width: 40px;
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--pdx-body-bg);
  color: var(--pdx-text);
  font-size: 16px;
  font-weight: 700;
  cursor: pointer;
  user-select: none;
}
.add-to-cart-panel .product-quantity .quantity:hover { background: var(--pdx-border); }

/* wishlist / compare / email a friend */
.overview-buttons { display: flex; flex-wrap: wrap; gap: 10px; margin: 30px 0 0 0; }
.overview-buttons .button-2 { height: 44px; padding: 0 20px; }

/* Share widget (Views/Product/_ShareButton.cshtml, core, unmodified - renders
   "<div class="product-share-button">" wrapping the ShareThis-hosted widget markup/script from
   Model.PageShareCode). The old selector here, ".overview .share-button", never actually matched
   this element (core renders "product-share-button", not "share-button") so this spacing was
   silently a no-op - fixed to the real class, with a small margin-top to separate it from
   ".overview-buttons" above without crowding into it.
   ShareThis's own hosted CSS renders its icon row centered (".sharethis-inline-share-buttons" gets
   "text-align: center" from ShareThis's stylesheet, via the "st-center" class it adds to that div) -
   overridden to left-aligned here to match the left-aligned buttons/content above it. !important
   because ShareThis's stylesheet is injected by their own async widget script, so it can end up
   loading AFTER this stylesheet despite matching specificity, which would otherwise let their rule
   win the cascade on load order alone. */
.overview .product-share-button { margin-top: 10px; text-align: left; }
.overview .product-share-button .sharethis-inline-share-buttons { text-align: left !important; }

/* rich HTML long description */
.full-description { margin: 32px 0; line-height: 1.7; color: var(--pdx-text); }
.full-description img { border-radius: var(--pdx-radius-sm); max-width: 100%; height: auto; }
.full-description h2, .full-description h3 { margin: 20px 0 10px; }
.full-description p:last-child { margin-bottom: 0; }

/* specs table + tags */
.product-collateral { display: flex; flex-direction: column; gap: 32px; margin-top: 40px; }
.product-specs-box,
.product-tags-box {
  background: var(--pdx-card-details-bg, var(--pdx-surface));
  border-radius: var(--pdx-card-radius, var(--pdx-radius));
  padding: 24px;
  box-shadow: var(--pdx-shadow);
}
.product-specs-box .table-wrapper { overflow-x: auto; }
.product-specs-box .data-table { width: 100%; border-collapse: collapse; }
.product-specs-box .hidden-row { display: none; }
.product-specs-box .spec-name,
.product-specs-box .spec-value { padding: 12px 16px; border-bottom: 1px solid var(--pdx-border); font-size: 14px; text-align: left; }
.product-specs-box .spec-name { color: var(--pdx-text-muted); width: 30%; }
.product-specs-box .spec-group-name { padding: 10px 16px; font-weight: 700; background: var(--pdx-body-bg); }

.product-tags-box .product-tags-list ul { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.product-tags-box .tag { display: inline-block; }
.product-tags-box .tag a.producttag {
  display: inline-block;
  padding: 6px 14px;
  border-radius: 999px;
  background: var(--pdx-body-bg);
  color: var(--pdx-text);
  font-size: 13px;
  font-weight: 600;
}
.product-tags-box .tag a.producttag:hover { background: var(--pdx-primary); color: #fff; }
.product-tags-box .tag span { font-size: 12px; color: var(--pdx-text-muted); }
.product-tags-box .separator { display: none; }

/* ==========================================================================
   PRODUCT TABS (Overview / Specifications / Tags)
   Nexus theme override (Views/Product/ProductTemplate.Simple.cshtml) combines
   the full-description, product specifications, and product tags sections
   into a single tabbed component. .product-collateral is now the tab
   container (nav + panels) rather than a stack of independently-boxed
   sections. The .product-specs-box/.product-tags-box rules above still style
   the table/tag markup *inside* each panel, but the outer background/
   padding/shadow now lives on .product-tabs-panels, so it's neutralized
   below on the individual boxes to avoid a "box inside a box" double border.
   ========================================================================== */
.product-collateral { display: block; margin-top: 40px; }

.product-tabs-nav {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 20px;
}
.product-tab-trigger {
  appearance: none;
  -webkit-appearance: none;
  border: none;
  background: transparent;
  padding: 8px 12px;
  border-radius: 999px;
  font-size: 14px;
  font-weight: 600;
  color: var(--pdx-text-muted);
  cursor: pointer;
  transition: background-color .15s ease, color .15s ease;
}
.product-tab-trigger:hover { color: var(--pdx-text); }
.product-tab-trigger.active {
  background: var(--pdx-primary);
  color: #FFFFFF;
  font-weight: 700;
}

.product-tabs-panels {
  background: var(--pdx-card-details-bg, var(--pdx-surface));
  border-radius: var(--pdx-card-radius, var(--pdx-radius));
}
.product-tab-panel { display: none; padding: 0px; }
.product-tab-panel.active { display: block; }

/* panels reuse the .full-description / .product-specs-box / .product-tags-box
   rules for their inner content, but now sit inside .product-tabs-panels, so
   their own background/padding/shadow/margin and redundant internal
   headings are dropped to avoid doubling up with the shared panel container
   and the tab label above it */
.product-tabs-panels .full-description { margin: 0; }
.product-tabs-panels .product-specs-box,
.product-tabs-panels .product-tags-box {
  background: none;
  border-radius: 0;
  padding: 0;
  box-shadow: none;
}
.product-tabs-panels .product-specs-box .title,
.product-tabs-panels .product-tags-box .title { display: none; }

/* Related products / Products also purchased - both carousels (see the RelatedProducts/
   ProductsAlsoPurchased theme overrides); the actual card styling is already fully covered by
   the shared .product-grid/.item-grid/.owl-carousel/.product-item rules earlier in this file, so
   only page-level spacing is needed here. */
.product-details-page .also-purchased-products-grid,
.product-details-page .related-products-grid { margin-top: 48px; }

/*
  Product reviews + "Write your own review" form (Views/Product/_ProductReviews.cshtml, core,
  unmodified). The existing review list uses the same star-rating technique as the overview
  summary above (.product-review-box .rating, already styled). The write-review form's fields
  (label + input rows, and the Bad/radios/Excellent rating row) are centered as one narrow column
  inside a light gray box, matching the reference layout - label text right-aligned beside each
  input rather than stacked above it.
*/
.product-reviews { margin-top: 48px; }
.write-review .title { text-align: left; padding-bottom: 20px; margin-bottom: 0; border-bottom: 1px solid var(--pdx-border); }

/* Review list now lives inside the "Reviews" tab panel (.product-tabs-panels .product-review-list -
   see the theme's _ProductReviewsList.cshtml partial) and is restyled to read as individual review
   cards: a reviewer icon + name row, a star row with the title close beside it, a muted
   "Reviewed on ..." date line, the review body copy, then "Was this review helpful?" kept at the
   bottom of every review - matching the reference layout supplied. .product-tab-panel padding is 0
   (see above) and .product-review-list itself is unstyled (no padding/background of its own), so
   the reviews sit flush with the tab panel edge; each .product-review-item supplies its own
   vertical spacing below. Core's numeric rating value (e.g. "5")
   that core prints as literal text inside the star element is left out of the markup entirely here
   (same as core's own _ProductReviewOverview.cshtml summary, which never printed it) - the filled
   star glyphs already communicate the rating, and core's plain-text digit was rendering right after
   the star icons. */
.product-review-item {
  padding: 20px 0;
  border-bottom: 1px solid var(--pdx-border);
}
.product-review-item:first-child { padding-top: 0; }
.product-review-item:last-child { border-bottom: none; padding-bottom: 0; }

/* Reviewer icon (the customer's avatar photo if set, otherwise a generic person-silhouette
   placeholder drawn inline via SVG - core ships no default-avatar asset) + name, shown above the
   star/title row per the reference layout. */
.review-author { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; }
.review-author-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  background: var(--pdx-border);
  overflow: hidden;
  flex: 0 0 auto;
}
.review-author-icon .avatar-img { width: 100%; height: 100%; object-fit: cover; }
.review-author-icon .default-avatar-icon { width: 20px; height: 20px; fill: none; stroke: var(--pdx-surface); stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.review-author-name { font-size: 13px; font-weight: 600; color: var(--pdx-text); }
.review-author-name a { color: var(--pdx-primary); }

.review-item-head { display: flex; align-items: center; justify-content: flex-start; gap: 6px; margin-bottom: 6px; }
.review-item-head .product-review-box .rating { width: 96px; height: 18px; font-size: 18px; }
.review-title strong { font-size: 15px; font-weight: 700; color: var(--pdx-card-title-color, var(--pdx-text)); }

.review-meta { font-size: 13px; color: var(--pdx-text-muted); margin-bottom: 12px; }

.review-text { display: flex; gap: 16px; }
.review-text .text-body { flex: 1 1 auto; color: var(--pdx-card-desc-color, var(--pdx-text)); line-height: 1.7; }
.review-text .text-body p { margin: 0 0 12px; }
.review-text .text-body p:last-child { margin-bottom: 0; }

.no-reviews { color: var(--pdx-text-muted); font-size: 14px; }

/* "Was this review helpful?" control (Views/Shared/_ProductReviewHelpfulness.cshtml, core,
   unmodified) - restyled as small muted pill buttons, kept at the bottom of every review. */
.product-review-helpfulness { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; margin-top: 14px; font-size: 13px; color: var(--pdx-text-muted); }
.product-review-helpfulness .vote-options { display: flex; align-items: center; gap: 6px; }
.product-review-helpfulness .vote {
  cursor: pointer;
  padding: 3px 12px;
  border: 1px solid var(--pdx-border);
  border-radius: 20px;
  font-size: 12px;
  font-weight: 600;
  color: var(--pdx-text);
  transition: background .15s ease, border-color .15s ease;
}
.product-review-helpfulness .vote:hover { background: var(--pdx-body-bg); border-color: var(--pdx-primary); }
.product-review-helpfulness .vote-stats { font-size: 12px; }
.product-review-helpfulness .result { font-size: 12px; color: var(--pdx-success); margin-left: 4px; }

.write-review { margin-top: 40px; }
.write-review .fieldset {
  background: var(--pdx-body-bg);
  background-color: #f8f8f8;
  border-radius: var(--pdx-card-radius, var(--pdx-radius));
  padding: 32px 24px;
  margin-top: 24px;
}
.write-review .form-fields { max-width: 560px; margin: 0 auto; }
.write-review .message-error { color: var(--pdx-danger); margin-bottom: 16px; }

.write-review .inputs { display: flex; align-items: flex-start; gap: 16px; margin-bottom: 20px; }
.write-review .inputs label { flex: 0 0 130px; padding-top: 12px; text-align: right; font-size: 14px; color: var(--pdx-text); }
.write-review .inputs input.review-title,
.write-review .inputs textarea.review-text { flex: 1 1 auto; }
.write-review .inputs textarea.review-text { min-height: 140px; resize: vertical; }
.write-review .required { color: var(--pdx-danger); font-weight: 700; margin-left: 4px; }
.write-review .inputs .field-validation-error { display: block; width: 100%; margin-top: 4px; margin-left: 146px; font-size: 12px; color: var(--pdx-danger); }

/* rating row: "Bad" (red) - 5 radios - "Excellent" (green), the whole row centered as a unit,
   matching the reference image - not stretched edge-to-edge across the box */
.write-review .review-rating { display: flex; align-items: center; gap: 16px; margin-bottom: 24px; }
.write-review .review-rating .name-description { flex: 0 0 130px; text-align: right; }
.write-review .review-rating .name-description label { font-size: 14px; color: var(--pdx-text); }
.write-review .rating-wrapper { flex: 1 1 auto; display: flex; align-items: center; justify-content: center; gap: 10px; }
.write-review .rating-wrapper .label { font-size: 14px; font-weight: 600; }
.write-review .rating-wrapper .label.first { color: var(--pdx-danger); }
.write-review .rating-wrapper .label.last { color: var(--pdx-success); }
.write-review .rating-options { display: flex; align-items: center; gap: 8px; }
.write-review .rating-options input[type="radio"] { width: 18px; height: 18px; margin: 0; accent-color: var(--pdx-primary); }

.write-review .buttons { text-align: center; margin-top: 28px; }
.write-review .write-product-review-button { padding: 13px 36px; }

@media (max-width: 767px) {
  .write-review .inputs,
  .write-review .review-rating { flex-direction: column; align-items: stretch; gap: 8px; }
  .write-review .inputs label,
  .write-review .review-rating .name-description { flex: 1 1 auto; text-align: left; padding-top: 0; }
  .write-review .inputs .field-validation-error { margin-left: 0; }
  .write-review .rating-wrapper { justify-content: flex-start; flex-wrap: wrap; }

  .product-essential { flex-direction: column; gap: 24px; padding-bottom: 24px; margin-bottom: 24px; }
  .gallery { max-width: none; }
  .overview .product-name h1 { font-size: 22px; }
  .overview .prices .product-price,
  .overview .prices .non-discounted-price { font-size: 24px; }
}

/* =========================== RECENTLY VIEWED PRODUCTS BLOCK =========================== */
/* Views/Shared/Components/RecentlyViewedProductsBlock/Default.cshtml (core, unmodified) -
   "<section class="block block-recently-viewed-products"><h2 class="title">...</h2>
   <div class="listbox"><ul class="list"><li><a class="product-picture">...</a>
   <a class="product-name">...</a></li></ul></div></section>". Deliberately unscoped (not
   nested under ".side-2") since this widget can be placed in any widget zone, including the
   product-details page's own sidebar-less layout - the existing ".side-2 .block" rules only
   ever apply when this happens to land inside that specific sidebar column. */
.block-recently-viewed-products { margin-top: 24px; }
.block-recently-viewed-products .title { font-size: 18px; font-weight: 700; color: var(--pdx-text); margin-bottom: 16px; }
/* Fixed 64px tile, NOT a responsive grid that stretches to fill its container - core renders this
   block's thumbnail at a small, fixed server-side picture size (confirmed live: the actual <img>
   file is only 64x64px), so the earlier "minmax(140px, 1fr)" grid was upscaling that 64x64 source
   up to ~258x258 to fill the sidebar column width, producing a blurry, oversized thumbnail that
   was much larger than how this block rendered before it had any CSS at all. A fixed 64px tile
   keeps every thumbnail at (approximately) its native resolution regardless of which widget zone/
   column width this block ends up in.

   flex-direction:column (not the earlier row + flex-wrap:wrap) - this block only ever renders in
   narrow sidebar columns (.side-2, product-details sidebar), so wrapping tiles into a horizontal
   flow packed several-per-row read as a cramped mini-grid there; stacking one tile per row down
   the column matches every other sidebar block on this theme (manufacturer/category nav, tags,
   etc.) and reads as a simple vertical list regardless of how many recently-viewed products there
   are.

   Each row (li) is itself a ROW flex (thumbnail left, name to its right, per the reference
   layout requested) - not a column - so .product-picture's old margin-bottom:8px (spacing for a
   stacked thumbnail-over-text tile) became margin-right instead, and .product-name grows to fill
   the remaining row width (flex:1 1 auto) so multi-line names wrap next to the thumbnail rather
   than under it. */
.block-recently-viewed-products .listbox .list {
  display: flex;
  flex-direction: column;
  gap: 16px;
  list-style: none;
  margin: 0;
  padding: 0;
}
.block-recently-viewed-products .listbox .list li { display: flex; flex-direction: row; align-items: flex-start; width: 100%; }
.block-recently-viewed-products .product-picture {
  display: block;
  flex: 0 0 64px;
  width: 64px;
  height: 64px;
  max-width: none;
  overflow: hidden;
  border: 1px solid var(--pdx-border);
  /* Configure > Images > "Image corner radius" (Theme1Settings.ImageCornerRadius) */
  border-radius: var(--pdx-image-radius, var(--pdx-radius));
  margin-right: 12px;
  background: var(--pdx-body-bg);
}
.block-recently-viewed-products .product-picture img { width: 100%; height: 100%; max-width: none; object-fit: contain; }
.block-recently-viewed-products .product-name {
  display: block;
  flex: 1 1 auto;
  min-width: 0;
  font-size: 12px;
  color: var(--pdx-text);
  text-decoration: none;
  line-height: 1.4;
}
.block-recently-viewed-products .product-name:hover { color: var(--pdx-primary); }

@media (max-width: 767px) {
  .block-recently-viewed-products .listbox .list { gap: 12px; }
}

/* =========================== NEWS ARTICLE PAGE (/news/some-article) =========================== */

/*
  Single news article page (Views/News/NewsItem.cshtml, core, unmodified) - reached via the
  "read-more"/"Details" link on the homepage News section and the /news archive list. Two-column
  layout (Layout = "_ColumnsTwo"), so the markup below lives inside .center-2 alongside whatever
  sidebar widgets (if any) render in .side-2 - no view override needed, core's markup is already
  clean semantic HTML: .page-title > h1, then .page-body > time.news-date, article.news-body
  (Model.Full, rich HTML), then the optional comment form (.new-comment) and comment list
  (.comment-list). Reuses the same --pdx-card-*/--pdx-text tokens as the rest of the site (product
  reviews, write-a-review form) for visual consistency, rather than introducing new ones.
*/

.news-item-page .page-body { max-width: 820px; margin: 0 auto; }

/* the date sits directly under the h1 with no .news-head wrapper here (unlike the homepage/list
   excerpt cards), so it gets its own spacing + divider rather than the compact card treatment */
.news-item-page .news-date {
  margin-bottom: 24px;
  padding-bottom: 20px;
  border-bottom: 1px solid var(--pdx-border);
}

/* full article body - plain readable prose, matching .full-description on the product detail
   page (same line-height/color/image-radius treatment) rather than the excerpt cards' small
   muted, line-clamped look */
.news-item-page .news-body {
  color: var(--pdx-text);
  font-size: 15px;
  line-height: 1.7;
}
.news-item-page .news-body img { border-radius: var(--pdx-radius-sm); max-width: 100%; height: auto; }
.news-item-page .news-body h2,
.news-item-page .news-body h3 { margin: 24px 0 12px; }
.news-item-page .news-body p { margin-bottom: 14px; }
.news-item-page .news-body p:last-child { margin-bottom: 0; }
.news-item-page .news-body a { text-decoration: underline; }
.news-item-page .news-body ul,
.news-item-page .news-body ol { margin: 0 0 14px 20px; }
.news-item-page .news-body blockquote {
  margin: 20px 0;
  padding-left: 16px;
  border-left: 3px solid var(--pdx-primary);
  color: var(--pdx-text-muted);
  font-style: italic;
}

/* "Leave your comment" form - same card/field treatment as .write-review on the product detail
   page (light gray box, centered narrow column, label-left/input-right rows) for consistency
   across the site's two comment/review forms. */
.new-comment { margin-top: 48px; }
.new-comment > .title {
  text-align: left;
  padding-bottom: 20px;
  margin-bottom: 0;
  border-bottom: 1px solid var(--pdx-border);
}
.new-comment .notifications .message-error { color: var(--pdx-danger); margin-top: 16px; }
.new-comment .notifications .result {
  margin-top: 16px;
  padding: 12px 16px;
  background: var(--pdx-body-bg);
  border-radius: var(--pdx-radius-sm);
  color: var(--pdx-success);
  font-size: 14px;
}
.new-comment form {
  background: var(--pdx-body-bg);
  border-radius: var(--pdx-card-radius, var(--pdx-radius));
  padding: 32px 24px;
  margin-top: 24px;
}
.new-comment .form-fields { max-width: 560px; margin: 0 auto; }
.new-comment .inputs { margin-bottom: 20px; }
.new-comment .inputs label {
  display: block;
  margin-bottom: 6px;
  font-size: 14px;
  font-weight: 600;
  color: var(--pdx-text);
}
.new-comment .inputs .enter-comment-text { min-height: 140px; resize: vertical; }
.new-comment .required { color: var(--pdx-danger); font-weight: 700; margin-left: 4px; }
.new-comment .buttons { text-align: center; margin-top: 8px; }
.new-comment .news-item-add-comment-button { padding: 13px 36px; }

/* existing comment list - avatar + username on the left, comment content on the right, matching
   the product review list's card rhythm (divider-separated rows, no boxed background) */
.comment-list { margin-top: 48px; }
.comment-list > .title {
  text-align: left;
  padding-bottom: 20px;
  margin-bottom: 0;
  border-bottom: 1px solid var(--pdx-border);
}
.news-comment {
  display: flex;
  gap: 16px;
  padding: 24px 0;
  border-bottom: 1px solid var(--pdx-border);
}
.news-comment .user-info {
  flex: 0 0 64px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  text-align: center;
}
.news-comment .username { font-size: 13px; font-weight: 600; color: var(--pdx-text); }
.news-comment .avatar-img { width: 48px; height: 48px; border-radius: 50%; object-fit: cover; }
.news-comment .comment-content { flex: 1 1 auto; min-width: 0; }
.news-comment .comment-time { font-size: 12px; color: var(--pdx-text-muted); margin-bottom: 6px; }
.news-comment .comment-time label { font-weight: 600; margin-right: 4px; }
.news-comment .comment-title strong { font-size: 15px; color: var(--pdx-card-title-color, var(--pdx-text)); }
.news-comment .comment-body { margin-top: 6px; color: var(--pdx-card-desc-color, var(--pdx-text-muted)); line-height: 1.6; }

@media (max-width: 767px) {
  .news-item-page .page-body { max-width: none; }
  .new-comment .inputs label { margin-bottom: 6px; }
  .news-comment { flex-direction: column; gap: 10px; }
  .news-comment .user-info { flex-direction: row; flex: 0 0 auto; }
}

/* =========================== SHOPPING CART PAGE (/cart) =========================== */

/*
  Core's ShoppingCart/Cart.cshtml (Nop.Web, unmodified) just wraps the OrderSummary view
  component (Views/Shared/Components/OrderSummary/Default.cshtml, also unmodified) in
  <div class="page shopping-cart-page">...<div class="page-body">. That same OrderSummary
  component is reused (in reduced/non-editable form) on the checkout confirm page and order
  details, so most rules below apply there too rather than being truly cart-only - no view
  override was needed anywhere in this flow, it's all core markup styled via CSS, same approach
  as News/Polls/product reviews.
*/

/* checkout progress steps - only rendered on /cart when Admin > Configuration > Settings > Order
   Settings > "One page checkout" is DISABLED (Cart.cshtml's own "@if (!Model.OnePageCheckoutEnabled)"
   - core's CheckoutProgress/Default.cshtml, unmodified, also reused unchanged at the top of every
   classic multi-step checkout page: billing address, shipping method, payment method, confirm).
   Styled as a flat underline stepper (no circles/numbers) to match this theme's existing minimal
   text-link treatment elsewhere (.breadcrumb) rather than a heavier wizard-style widget. */
.order-progress { margin-bottom: 32px; }
.order-progress ul { display: flex; flex-wrap: wrap; }
.order-progress li {
  flex: 1 1 0;
  min-width: 90px;
  text-align: center;
  padding-bottom: 14px;
  border-bottom: 3px solid var(--pdx-border);
}
.order-progress li a { display: block; font-size: 13px; font-weight: 600; color: var(--pdx-text-muted); }
.order-progress li.active-step { border-bottom-color: var(--pdx-primary); }
.order-progress li.active-step a { color: var(--pdx-primary); }
.order-progress li.inactive-step a { pointer-events: none; cursor: default; }

.order-summary-content { width: 100%; }

/* billing/shipping/payment summary - core's _OrderReviewData.cshtml (unmodified), rendered as the
   first child of .order-summary-content whenever Model.OrderReviewData.Display is true. Not shown
   on the plain /cart page itself (nothing to summarize yet), but this is the SAME shared
   OrderSummary component /cart uses (see this section's intro comment) - it's what renders one
   step later at Checkout > Confirm and again on Order Details, so it gets the same card treatment
   as everything else here rather than being left as unstyled core markup one click past cart. */
.order-review-data { display: flex; flex-wrap: wrap; gap: 24px; margin-bottom: 32px; }
.billing-info-wrap,
.shipping-info-wrap {
  flex: 1 1 320px;
  min-width: 0;
  background: var(--pdx-surface);
  border: 1px solid var(--pdx-border);
  border-radius: var(--pdx-card-radius, var(--pdx-radius));
  padding: 24px;
  display: flex;
  flex-direction: column;
  gap: 20px;
}
.billing-info .title,
.payment-method-info .title,
.shipping-info .title,
.shipping-method-info .title {
  font-size: 15px;
  color: var(--pdx-text);
  padding-bottom: 12px;
  margin-bottom: 0;
  border-bottom: 1px solid var(--pdx-border);
}
.info-list li { font-size: 14px; color: var(--pdx-text-muted); line-height: 1.7; }
.info-list li.name { font-weight: 600; color: var(--pdx-text); }
.info-list .label { font-weight: 600; color: var(--pdx-text); margin-right: 4px; }
.info-list .value { color: var(--pdx-text-muted); }


/* generic message boxes - core reuses "message-error"/"message-success"/"message-failure" across
   many unrelated features (cart-level + per-item warnings here, coupon/gift-card apply results,
   the estimate-shipping popup's failure text) - styled once, globally, rather than per-context.
   More specific existing rules (e.g. ".write-review .message-error", ".new-comment .notifications
   .message-error") still win over this by specificity where a different treatment was already
   wanted there. */
.message-error,
.message-success,
.message-failure {
  padding: 12px 16px;
  border-radius: var(--pdx-radius-sm);
  font-size: 13px;
  margin-bottom: 16px;
}
.message-error { background: color-mix(in srgb, var(--pdx-danger) 10%, transparent); color: var(--pdx-danger); }
.message-error ul { list-style: disc; margin-left: 18px; }
.message-error li { margin-bottom: 2px; }
.message-success { background: color-mix(in srgb, var(--pdx-success) 10%, transparent); color: var(--pdx-success); }
.message-failure { background: color-mix(in srgb, var(--pdx-danger) 10%, transparent); color: var(--pdx-danger); }

/* the cart table itself lives inside a plain card - background/border/radius match every other
   "boxed content" surface in the theme (product-specs-box, poll, news-item, etc.) */
.table-wrapper {
  background: var(--pdx-surface);
  border: 1px solid var(--pdx-border);
  border-radius: var(--pdx-card-radius, var(--pdx-radius));
  overflow: hidden;
  margin-bottom: 24px;
}
@media (max-width: 359px) { .table-wrapper { overflow-x: auto; } }

table.cart thead th {
  padding: 14px 16px;
  background: var(--pdx-body-bg);
  border-bottom: 1px solid var(--pdx-border);
  color: var(--pdx-text-muted);
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .03em;
  text-align: left;
}
table.cart thead th.unit-price,
table.cart thead th.quantity,
table.cart thead th.subtotal,
table.cart thead th.remove-from-cart { text-align: center; }

table.cart tbody tr { border-top: 1px solid var(--pdx-border); }
table.cart tbody tr:first-child { border-top: none; }
table.cart tbody td { padding: 16px; vertical-align: middle; font-size: 14px; }
table.cart tbody td.unit-price,
table.cart tbody td.quantity,
table.cart tbody td.subtotal,
table.cart tbody td.remove-from-cart { text-align: center; }

/* Explicit column widths (table-layout stays "auto" - only these five columns get a width, PRODUCT
   is deliberately left unset so it absorbs whatever's left).
   Without this, the browser's own auto-layout surplus-space distribution badly favors PRICE over
   PRODUCT: PRODUCT's cell holds ordinary wrappable text (the product name), and Chromium's
   auto-layout apparently only counts a wrappable cell's *minimum* content width (its longest single
   word) when handing out left-over table width, not the full unwrapped name - so PRODUCT was
   getting pinned to ~118px (wrapping long names onto 4-5 lines) while PRICE, sized only by a couple
   of narrow "$40.00" spans, was handed most of the row's remaining ~700-1200px. Confirmed live: with
   no explicit widths, "Nike Floral Roshe Customized Running Shoes" wrapped 5 lines wide while PRICE
   sat mostly empty. Giving the narrow columns real widths below is what makes PRODUCT actually get
   the leftover space that was always meant for it. */
table.cart th.product,
table.cart td.product { width: 42%; }
table.cart th.unit-price,
table.cart td.unit-price { width: 14%; }
table.cart th.subtotal,
table.cart td.subtotal { width: 12%; }
table.cart th.quantity,
table.cart td.quantity { width: 160px; }
table.cart th.remove-from-cart,
table.cart td.remove-from-cart { width: 70px; }

/* labels core renders inside every td specifically for the mobile stacked layout further below -
   hidden on desktop, where the header row already labels each column */
table.cart .td-title { display: none; }

/* shared by BOTH the cart AND wishlist tables - Views/ShoppingCart/Wishlist.cshtml (core,
   unmodified) renders its own line items in a "<table class="cart">" too, so every ".cart"-scoped
   rule in this section already applies to both pages without needing a separate ".wishlist"
   selector anywhere - see this file's "WISHLIST PAGE" section further down for the handful of
   rules that genuinely are wishlist-only (the extra add-to-cart column, multi-wishlist tabs,
   share-link row, etc). */
table.cart td.product-picture img {
  width: 72px;
  height: 72px;
  /* core's colgroup gives this column "<col width="1" />" (see the SKU comment below - same auto-
     layout column-sizing behavior), and the RESET section's generic "img { max-width: 100% }"
     (which is relative to that squeezed column) would otherwise clamp this image's rendered width
     to well under 72px while height stays fixed at 72px, producing a visibly non-square, vertically
     -cropped thumbnail - confirmed live on /cart (43.58px x 72px instead of 72x72). max-width:none
     here overrides that reset so the explicit 72px width above always wins. */
  max-width: none;
  object-fit: cover;
  /* Configure > Images > "Image corner radius" (Theme1Settings.ImageCornerRadius) - deliberately
     NOT --pdx-card-radius (that token is reserved for product CARD containers on grid listings
     only) so this thumbnail can be tuned independently of those cards. */
  border-radius: var(--pdx-image-radius, var(--pdx-radius));
  border: 1px solid var(--pdx-border);
}

/* SKU column - hidden rather than removed from core's Cart.cshtml markup (both "th.sku" and
   "td.sku" share this one class), keeping this page CSS-only like the rest of the cart flow.
   Hiding the cells is enough for the table's auto layout to collapse the column entirely; the
   "<col>" this shares column position with needs no matching change. */
table.cart .sku { display: none; }

table.cart td.product .product-name { font-size: 14px; font-weight: 600; color: var(--pdx-text); }
table.cart td.product .product-name:hover { color: var(--pdx-primary); }

/* attribute/recurring/rental info - core's item.AttributeInfo is raw HTML (FormatAttributes()),
   styled generically here regardless of the exact tags it emits */
table.cart .attributes,
table.cart .recurring-info,
table.cart .rental-info { margin-top: 6px; font-size: 12px; line-height: 1.6; color: var(--pdx-text-muted); }
table.cart .attributes dt { font-weight: 600; }

table.cart .edit-item { margin-top: 6px; }
table.cart .edit-item a { font-size: 12px; font-weight: 600; }

table.cart .message-error { margin: 8px 0 0; padding: 8px 12px; font-size: 12px; }

table.cart .vendor-name { font-size: 13px; color: var(--pdx-text-muted); }

table.cart .product-unit-price,
table.cart .product-subtotal { font-weight: 700; color: var(--pdx-text); }
table.cart .discount { margin-top: 4px; font-size: 12px; color: var(--pdx-success); }
table.cart .discount-additional-info { font-size: 11px; color: var(--pdx-text-muted); }

/* quantity: either a plain <select> (item.AllowedQuantities.Count > 0) or a stepper
   (+ / input / -) - only one of the two ever renders per item, per core's own @if. Overrides the
   generic ".qty-dropdown { width:90px; height:46px }" rule from the product detail page (higher
   specificity here, via the ".cart" ancestor) down to a size that fits a table row; the stepper's
   own ".qty-input" is sized independently below, it was never part of that generic rule. */
.cart .qty-dropdown { width: 84px; height: 38px; margin: 0 auto; }
.cart .product-quantity {
  display: inline-flex;
  align-items: stretch;
  border: 1px solid var(--pdx-border);
  border-radius: var(--pdx-radius-sm);
  overflow: hidden;
  height: 38px;
  /* the quantity column's colgroup entry is "<col width="1" />" (same as the product-picture
     column above) - combined with "overflow: hidden" here, the table's automatic column-layout
     algorithm was free to treat this element's minimum content width as 0 and collapse the whole
     stepper down to ~2px (confirmed live: +/- buttons and input all invisible on both /cart and
     /wishlist). min-width pins it to its natural content size (44px input + 2x32px buttons + 2px
     border) so the column can never shrink below it. */
  min-width: 108px;
}
.cart .qty-input {
  width: 44px;
  height: 100%;
  border: none;
  border-left: 1px solid var(--pdx-border);
  border-right: 1px solid var(--pdx-border);
  border-radius: 0;
  text-align: center;
  padding: 0;
  font-weight: 600;
}
.cart .qty-input:focus { box-shadow: inset 0 0 0 1px var(--pdx-primary); }
/* Scoped to ".product-quantity .quantity" (not just ".cart .quantity") on purpose: core's own
   markup ALSO uses the literal class "quantity" on the column's own <th>/<td>
   ("<th class="quantity">"/"<td class="quantity">", see Views/Shared/Components/OrderSummary/
   Default.cshtml and this theme's Wishlist.cshtml override) - a bare ".cart .quantity" rule here
   matched those table cells too, not just the +/- glyph divs it was meant for, which forced
   display:flex/width:32px/font-size:15px onto the "QTY." header cell itself (breaking the table's
   column-width auto-layout badly enough that PRICE ballooned to fill most of the row while
   PRODUCT(S) - meant to take all the leftover space - stayed pinned near its minimum width) and
   made the "QTY." header render visibly larger than the other column headers. ".product-quantity"
   only ever wraps the actual up/down glyph divs, never the th/td, so scoping through it targets
   exactly the right elements. */
.cart .product-quantity .quantity {
  width: 32px;
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--pdx-body-bg);
  color: var(--pdx-text);
  font-size: 15px;
  font-weight: 700;
  cursor: pointer;
  user-select: none;
}
.cart .product-quantity .quantity:hover { background: var(--pdx-border); }

/* +/- glyph AND left-to-right order are both shared, UNSCOPED, across every stepper that reuses
   this ".quantity.up"/".quantity.down" pair - this cart row version (sizing above, ".cart"-scoped)
   and the Nexus-only add-to-cart-panel stepper further down this file (Themes/Nexus/Views/Product/
   _AddToCart.cshtml, its own sizing in this file's "add to cart" section). Keeping the icon
   content and the order fix unscoped means any future page that reuses this same component gets
   both automatically, with no risk of the icon silently missing the way it did here before this
   comment was written (an earlier version left "content:" scoped to ".cart .quantity.up/down"
   only, which drew empty buttons - no "+"/"-" at all - the moment this component was reused
   outside ".cart", on the add-to-cart-panel).
   Order specifically: core's own Cart.cshtml markup (unmodified) renders "up" before "down" in
   the DOM - reordered here via flexbox `order` (rather than a view override, keeping the cart
   page itself CSS-only) so it reads minus-first/plus-last either way, matching the reference
   design. The add-to-cart-panel version already places "down" first in its own markup, but gets
   the same order values too so both stay in sync if that markup ever changes. */
.quantity.up::before { content: "+"; }
.quantity.down::before { content: "\2212"; }
.quantity.down { order: -1; }
.quantity.up { order: 1; }

/* remove - the checkbox stays visually hidden (core toggles it via JS when the button below is
   clicked; the server only needs it present/checked, not seen) - the actual click target is the
   button, restyled as a small round icon button matching .product-item-icon/.flyout-cart-close's
   shape elsewhere in the theme */
table.cart input[type="checkbox"][name="removefromcart"] { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }
table.cart .remove-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  padding: 0;
  border: 1px solid var(--pdx-border);
  border-radius: 50%;
  background: transparent;
  color: var(--pdx-text-muted);
  cursor: pointer;
}
table.cart .remove-btn::before { content: "\2715"; font-size: 13px; line-height: 1; }
table.cart .remove-btn:hover { background: var(--pdx-danger); border-color: var(--pdx-danger); color: #fff; }

.tax-shipping-info {
  padding: 12px 16px;
  margin-bottom: 24px;
  background: var(--pdx-body-bg);
  border-radius: var(--pdx-radius-sm);
  font-size: 13px;
  color: var(--pdx-text-muted);
}
.tax-shipping-info a { font-weight: 600; }

/* update-cart / continue-shopping / estimate-shipping row above the checkout-attributes block.
   core hides "Update cart" via an inline style="display:none" (revealed by its own JS the moment
   a quantity actually changes) - left alone here, just laid out for when it does show. */
/* Cart page 2-column layout: left column stacks ".cart-options" (Continue shopping/Estimate
   shipping + Gift wrapping) above ".cart-collaterals" (Discount Code/Gift Cards); right column is
   the order totals card, spanning both left-column rows so its TOP aligns with the Continue
   shopping/Estimate shipping button row instead of starting further down the page below Gift
   wrapping. Needs the ".cart-summary-grid" wrapper div added around ".cart-options"/".cart-footer"
   in this theme's OrderSummary/Default.cshtml override (core's own version has no such wrapper -
   see that file's own comment). ".cart-footer" itself becomes "display: contents" so its actual
   children (".cart-collaterals" and ".totals") join ".cart-options" as direct items of this same
   grid, rather than being nested one level deeper inside their own flex box.
   Scoped to ".shopping-cart-page" only - the checkout confirmation page reuses this exact same
   OrderSummary component (with no ".cart-collaterals", since Model.IsEditable is false there) and
   is untouched: the wrapper div carries no styling outside this page, so it's inert there. */
.shopping-cart-page .cart-summary-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 420px;
  column-gap: 24px;
  align-items: start;
}
.shopping-cart-page .cart-options { grid-column: 1; grid-row: 1; }
.shopping-cart-page .cart-footer { display: contents; }
.shopping-cart-page .cart-collaterals { grid-column: 1; grid-row: 2; }
.shopping-cart-page .cart-footer .totals { grid-column: 2; grid-row: 1 / span 2; }

.cart-options { margin-bottom: 24px; }
/* .common-buttons (Continue shopping / Estimate shipping) and .checkout-attributes (e.g. "Gift
   wrapping") are SIBLINGS inside the same .cart-options wrapper above - that wrapper's own
   margin-bottom only adds space AFTER the whole group (before .cart-footer), not BETWEEN these two
   children, so without a margin here the button row sits flush against "Gift wrapping" right below
   it. */
.common-buttons { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; margin-bottom: 24px; }
.common-buttons .button-2 { height: 44px; display: inline-flex; align-items: center; padding: 0 20px; }

/* estimate-shipping trigger renders as a plain <a>, not a <button.button-2> like its siblings -
   given the same visual treatment (border style, matching .add-to-wishlist-button/
   .add-to-compare-list-button elsewhere) so it reads as part of the same row of actions */
.estimate-shipping-button {
  display: inline-flex;
  align-items: center;
  height: 44px;
  padding: 0 20px;
  border: 1px solid var(--pdx-border);
  border-radius: var(--pdx-button-radius, 0px);
  color: var(--pdx-text);
  font-size: 14px;
  font-weight: 600;
}
.estimate-shipping-button:hover { border-color: var(--pdx-primary); color: var(--pdx-primary); }

/* checkout attributes (gift wrap, special instructions, etc. - Admin > Configuration > Checkout
   attributes) - a plain <dl> of dt/dd pairs, one per attribute; dd's actual control varies by
   AttributeControlType (see _CheckoutAttributes.cshtml) but every variant is covered generically
   below rather than per-type, since most stores only ever use a handful of these at once. */
.checkout-attributes {
  margin-bottom: 4px;
  /* same panel treatment as ".coupon-box"/".giftcard-box" below (Discount Code/Gift Cards) */
  background-color: #f9f9f9;
  padding: 20px;
}
.checkout-attributes dt { margin-bottom: 8px; font-size: 14px; font-weight: 600; color: var(--pdx-text); }
.checkout-attributes dt:not(:first-child) { margin-top: 20px; }
.checkout-attributes .required { color: var(--pdx-danger); margin-left: 2px; }
.checkout-attributes dd select,
.checkout-attributes dd textarea,
.checkout-attributes dd input.textbox { max-width: 420px; }
.checkout-attributes .option-list { display: flex; flex-direction: column; gap: 8px; }
.checkout-attributes .option-list li { display: flex; align-items: center; gap: 8px; }
.checkout-attributes .option-list input[type="radio"],
.checkout-attributes .option-list input[type="checkbox"] { width: 16px; height: 16px; accent-color: var(--pdx-primary); }
.checkout-attributes .option-list label { font-size: 14px; }
.checkout-attributes .attribute-squares { flex-direction: row; flex-wrap: wrap; }
.checkout-attributes .attribute-square-container { display: inline-block; width: 28px; height: 28px; border-radius: 50%; border: 2px solid var(--pdx-border); overflow: hidden; cursor: pointer; }
.checkout-attributes .selected-value .attribute-square-container { border-color: var(--pdx-primary); }
.checkout-attributes .attribute-square { display: block; width: 100%; height: 100%; }
.checkout-attributes .attribute-squares input[type="radio"] { position: absolute; opacity: 0; width: 1px; height: 1px; }

.selected-checkout-attributes { margin-bottom: 24px; font-size: 13px; color: var(--pdx-text-muted); }
.selected-checkout-attributes:empty { display: none; }

/* product detail page attributes (e.g. https://.../build-your-own-computer's Processor/RAM/HDD/
   OS/Software) - Views/Product/_ProductAttributes.cshtml (core, unmodified), the exact same
   dl>dt/dd + ul.option-list/.attribute-squares markup ".checkout-attributes" above targets, just
   under its own ".attributes" wrapper class instead of ".checkout-attributes" - so this mirrors
   that block's rules 1:1 (native radio/checkbox + accent-color, circular color/image swatches,
   etc) for consistency between the two attribute-collection surfaces, rather than inventing a
   second design for what's structurally the same feature. Was previously completely unstyled
   (plain browser-default radio/checkbox list, no spacing between attribute groups) - restyled to
   match the reference Flexo theme's level of polish for this same feature; Flexo achieves that via
   Bootstrap's custom-control checkbox/radio component, but this reuses Nexus's own existing
   accent-color-based control styling instead (see ".checkout-attributes" above, ".poll-options",
   ".terms-of-service", etc) since that's already this theme's established sitewide pattern for
   every other native checkbox/radio - same clean, well-spaced result without introducing a second,
   Bootstrap-flavored control style used nowhere else in the theme. Deliberately does NOT cover the
   out-of-stock-combination ".disabled"/".tooltip-container"/".not-available-text" states that
   ColorSquares/ImageSquares can render - same "most stores only ever use a handful of these"
   reasoning as the checkout-attributes comment above; can be added later if a product actually
   needs it. */
.attributes { margin: 20px 0 6px; }
.attributes dt { margin-bottom: 8px; font-size: 14px; font-weight: 600; color: var(--pdx-text); }
.attributes dt:not(:first-child) { margin-top: 20px; }
.attributes .required { color: var(--pdx-danger); margin-left: 2px; }
.attributes .attribute-description { margin-top: 4px; font-size: 13px; font-weight: 400; color: var(--pdx-text-muted); }
.attributes .option-list { display: flex; flex-direction: column; gap: 8px; }
.attributes .option-list li { display: flex; align-items: center; gap: 8px; }
.attributes .option-list input[type="radio"],
.attributes .option-list input[type="checkbox"] { width: 16px; height: 16px; accent-color: var(--pdx-primary); flex: 0 0 auto; }
.attributes .option-list label { font-size: 14px; cursor: pointer; }
.attributes .attribute-squares { flex-direction: row; flex-wrap: wrap; }
.attributes .attribute-square-container { display: inline-block; width: 28px; height: 28px; border-radius: 50%; border: 2px solid var(--pdx-border); overflow: hidden; cursor: pointer; }
.attributes .selected-value .attribute-square-container { border-color: var(--pdx-primary); }
.attributes .attribute-square { display: block; width: 100%; height: 100%; }
.attributes .attribute-squares input[type="radio"] { position: absolute; opacity: 0; width: 1px; height: 1px; }
.attributes .qty-box { display: inline-flex; align-items: center; gap: 6px; margin-top: 6px; font-size: 13px; color: var(--pdx-text-muted); }
.attributes .qty-box input { width: 56px; height: 32px; padding: 0 8px; text-align: center; }
.attributes dd input.textbox,
.attributes dd textarea { max-width: 420px; }

/* footer: deals (coupon/gift-card) on the left, order totals + checkout on the right - matches
   the layout most cart pages use. .cart-collaterals only renders when Model.IsEditable (see
   OrderSummary/Default.cshtml), so on non-editable contexts (order details) .totals simply takes
   the full row instead since it has no sibling to share it with. */
.cart-footer { display: flex; flex-wrap: wrap; align-items: flex-start; gap: 24px; }
.cart-collaterals {
  flex: 1 1 380px;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 20px;
  /* space below the Gift Cards box before whatever comes next - on desktop this is harmless (it's
     the last thing in the left grid column, see ".shopping-cart-page .cart-collaterals" above),
     but on mobile (where ".cart-summary-grid" collapses to plain stacked flow) ".totals" follows
     immediately after this in the DOM, so without this it sat flush against the Gift Cards box. */
  margin-bottom: 20px;
}

/* ".cart-collaterals" only ever has one direct child (".deals" - see OrderSummary/Default.cshtml)
   so its own "gap: 20px" above never actually applies between the Discount Code/Gift Cards boxes
   inside ".deals" - previously un-styled, so "Gift Cards" sat flush against the Discount Code
   input row right above it. This is the rule that actually needs the gap. */
.deals { display: flex; flex-direction: column; gap: 20px; }

/* Flush-left like ".checkout-attributes" (Gift wrapping) above, no border - just a light gray
   fill so each box reads as its own panel; the 20px padding also puts 20px of breathing room
   below the coupon-code input/button row (the last thing in the box, when no success/failure
   message is showing). ".deals" (not this rule) is what keeps the 20px gap between the two
   boxes - untouched here. */
.coupon-box,
.giftcard-box {
  background-color: #f9f9f9;
  padding: 20px;
}
.coupon-box .title,
.giftcard-box .title { font-size: 15px; color: var(--pdx-text); margin-bottom: 4px; }
.coupon-box .hint,
.giftcard-box .hint { font-size: 12px; color: var(--pdx-text-muted); margin-bottom: 12px; }
.coupon-box .coupon-code,
.giftcard-box .coupon-code { display: flex; gap: 8px; }
.coupon-box .coupon-code input,
.giftcard-box .coupon-code input {
  flex: 1 1 auto;
  width: auto;
  /* capped to the same width as the Gift wrapping dropdown/textbox above
     (".checkout-attributes dd select/textarea/input.textbox { max-width: 420px; }") */
  max-width: 420px;
}
.coupon-box .coupon-code .button-2,
.giftcard-box .coupon-code .button-2 {
  /* fixed, matching width for both "Apply coupon"/"Add gift card" (previously sized to their own
     text, so "Add gift card" - the longer label - came out wider than "Apply coupon") - slightly
     wider than either button's natural content width. */
  flex: 0 0 150px;
  white-space: nowrap;
}
.coupon-box .current-code,
.giftcard-box .current-code {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin-top: 10px;
  padding: 8px 12px;
  background: var(--pdx-body-bg);
  border-radius: var(--pdx-radius-sm);
  font-size: 13px;
}
.coupon-box .remove-discount-button,
.giftcard-box .remove-gift-card-button {
  width: 22px;
  height: 22px;
  flex: 0 0 auto;
  border: none;
  border-radius: 50%;
  background: var(--pdx-surface);
  color: var(--pdx-text-muted);
  cursor: pointer;
}
.coupon-box .remove-discount-button::before,
.giftcard-box .remove-gift-card-button::before { content: "\2715"; font-size: 11px; }
.coupon-box .remove-discount-button:hover,
.giftcard-box .remove-gift-card-button:hover { color: var(--pdx-danger); }

/* order totals card - a single bordered box; every direct child (.total-info, and whichever of
   .min-amount-warning/.terms-of-service/.checkout-buttons/.addon-buttons actually render - see
   OrderSummary/Default.cshtml's own @if chain) shares one consistent 20px padding and a dashed
   divider between whichever pieces are actually present, rather than each needing its own
   border/radius handled individually.
   IMPORTANT: scoped to ".cart-footer .totals", NOT bare ".totals" - core's FlyoutShoppingCart/
   Default.cshtml (the header's mini-cart drawer) also renders a plain, unrelated
   <div class="totals">Subtotal: <strong>...</strong></div> with none of this structure. An
   earlier version of this rule was unscoped and leaked this card treatment (white background,
   border, padding) onto that drawer, visually breaking it. ".cart-footer" only exists on the
   full cart/checkout-confirm page, never inside the flyout drawer, so this scoping is safe. */
.cart-footer .totals {
  flex: 1 1 340px;
  max-width: 420px;
  background: var(--pdx-surface);
  border: 1px solid var(--pdx-border);
  border-radius: var(--pdx-card-radius, var(--pdx-radius));
  overflow: hidden;
}
.cart-footer .totals > * { padding: 20px; }
.cart-footer .totals > * + * { border-top: 1px dashed var(--pdx-border); }

table.cart-total { width: 100%; }
table.cart-total tbody { display: flex; flex-direction: column; }
table.cart-total tr { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; padding: 6px 0; }
table.cart-total td { display: block; padding: 0; }
table.cart-total label { font-size: 14px; color: var(--pdx-text-muted); }
table.cart-total .value-summary,
table.cart-total .cart-total-right span { font-size: 14px; font-weight: 600; color: var(--pdx-text); }
table.cart-total .selected-shipping-method { display: block; font-size: 12px; color: var(--pdx-text-muted); margin-top: 2px; }
table.cart-total tr.order-total { margin-top: 8px; padding-top: 14px; border-top: 1px solid var(--pdx-border); }
table.cart-total tr.order-total label,
table.cart-total tr.order-total .value-summary { font-size: 18px; font-weight: 700; color: var(--pdx-text); }
table.cart-total tr.earn-reward-points label,
table.cart-total tr.earn-reward-points .value-summary { font-size: 12px; color: var(--pdx-text-muted); font-weight: 400; }
table.cart-total .giftcard-remaining { display: block; font-size: 11px; color: var(--pdx-text-muted); }
table.cart-total .remove-gift-card-button {
  display: inline-flex;
  width: 18px;
  height: 18px;
  margin-left: 4px;
  border: none;
  border-radius: 50%;
  background: var(--pdx-body-bg);
  color: var(--pdx-text-muted);
  cursor: pointer;
  vertical-align: middle;
}
table.cart-total .remove-gift-card-button::before { content: "\2715"; font-size: 9px; }

.min-amount-warning { color: var(--pdx-danger); font-size: 13px; }

.terms-of-service { display: flex; align-items: center; gap: 8px; font-size: 13px; }
.terms-of-service input[type="checkbox"] { width: 16px; height: 16px; accent-color: var(--pdx-primary); flex: 0 0 auto; }
.terms-of-service .read { font-weight: 600; }

.checkout-buttons .checkout-button { width: 100%; height: 48px; font-size: 15px; }
.checkout-buttons .checkout-disabled { text-align: center; color: var(--pdx-text-muted); font-size: 13px; }

/* payment-method buttons (PayPal Express, etc.) - rarely configured, so this box is often just
   an empty (but still rendered - see OrderSummary/Default.cshtml's unconditional wrapper div)
   sliver at the bottom of the card when none are active; harmless, matches this theme's existing
   pattern of leaving genuinely rare/empty core wrappers unstyled rather than fighting them with
   :empty tricks that don't reliably match whitespace-only markup. */
.addon-buttons { display: flex; flex-direction: column; gap: 8px; }

/* empty-cart state - mirrors the plain, centered treatment used elsewhere for "no results" style
   messages in this theme */
.no-data {
  padding: 48px 20px;
  text-align: center;
  color: var(--pdx-text-muted);
  font-size: 16px;
  background: var(--pdx-surface);
  border: 1px solid var(--pdx-border);
  border-radius: var(--pdx-card-radius, var(--pdx-radius));
}

/* cross-sell products shown below the cart footer once at least one item is added - reuses the
   theme's existing .product-grid/.item-grid/.item-box card styling verbatim (see PRODUCT GRID
   section above); only page-specific spacing is added here */
.order-summary-content .cross-sells { margin-top: 40px; }
.order-summary-content .cross-sells .title { text-align: center; }

/* estimate-shipping popup (Magnific Popup modal, triggered by .estimate-shipping-button above) -
   the library handles positioning/backdrop via its own bundled CSS (magnific-popup.css, loaded by
   _EstimateShippingPopUp.cshtml); only the CONTENT card itself is restyled here to match the
   theme rather than the library's plain default box. */
.estimate-shipping-popup {
  max-width: 640px;
  margin: 40px auto;
  padding: 28px;
  background: var(--pdx-surface);
  border-radius: var(--pdx-card-radius, var(--pdx-radius));
}
.ship-to-title,
.choose-shipping-title { font-size: 16px; margin-bottom: 14px; }
.choose-shipping-title { margin-top: 24px; }
.estimate-shipping-row { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; }
.estimate-shipping-row.shipping-address .estimate-shipping-row-item { flex: 1 1 160px; }
.estimate-shipping-address-control { height: 44px; }
.shipping-options { border: 1px solid var(--pdx-border); border-radius: var(--pdx-radius-sm); overflow: hidden; margin-top: 12px; }
.shipping-options-header { background: var(--pdx-body-bg); }
.shipping-options-header .estimate-shipping-row { padding: 10px 14px; }
.shipping-options-header .estimate-shipping-row-item-radio { flex: 0 0 20px; }
.shipping-header-item { flex: 1 1 0; font-size: 12px; font-weight: 700; text-transform: uppercase; letter-spacing: .03em; color: var(--pdx-text-muted); }
.shipping-options-body .estimate-shipping-row { padding: 12px 14px; border-top: 1px solid var(--pdx-border); }
.shipping-options-body .shipping-item { flex: 1 1 0; font-size: 14px; }
.shipping-options-body .no-shipping-options { padding: 16px 14px; text-align: center; color: var(--pdx-text-muted); font-size: 13px; }
.apply-shipping-button-container { margin-top: 20px; text-align: right; }
.apply-shipping-button-container .message-failure { margin: 10px 0 0; text-align: left; }

@media (max-width: 767px) {
  /* mobile: table.cart converts into a stack of card-style rows, one per line item - thead is
     hidden entirely and each td becomes its own labeled row using the ".td-title" text core
     already renders in every cell specifically for this purpose (see the desktop rule above that
     hides it) - the same responsive pattern nopCommerce's own stock themes use for this table. */
  table.cart thead { display: none; }
  table.cart, table.cart tbody, table.cart tr, table.cart td { display: block; width: 100%; }
  table.cart tbody tr { padding: 16px; border-top: 1px solid var(--pdx-border); }
  table.cart td { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 6px 0; text-align: right; }
  table.cart .td-title {
    display: inline-block;
    flex: 0 0 auto;
    font-size: 12px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .03em;
    color: var(--pdx-text-muted);
  }
  table.cart td.product-picture { justify-content: center; padding-bottom: 12px; }
  /* "width: 100%" here is necessary, not decorative - ".product" carries its own desktop column
     width ("table.cart td.product { width: 42%; }" above), which is MORE specific than the
     generic "table.cart td { ... width: 100%; }" mobile rule right above this block, so that
     100% never actually won on mobile without repeating it here at equal specificity. Left the
     item description/attributes stuck at 42% width instead of using the full row. */
  table.cart td.product { display: block; width: 100%; text-align: left; padding: 8px 0; }
  table.cart td.remove-from-cart { justify-content: center; padding-top: 12px; }

  /* collapse the desktop 2-column ".cart-summary-grid" back to plain stacked flow - options,
     then collaterals, then totals, in DOM order (see the grid rule above) */
  .shopping-cart-page .cart-summary-grid { display: block; }
  .shopping-cart-page .cart-footer { display: block; }
  .shopping-cart-page .cart-options,
  .shopping-cart-page .cart-collaterals,
  .shopping-cart-page .cart-footer .totals { grid-column: auto; grid-row: auto; }

  .cart-footer { flex-direction: column; }
  .cart-footer .totals { max-width: none; width: 100%; }
  .common-buttons { flex-direction: column; align-items: stretch; }
  .common-buttons .button-2,
  .estimate-shipping-button { width: 100%; justify-content: center; }
  .estimate-shipping-popup { margin: 20px; padding: 20px; }
  .estimate-shipping-row.shipping-address { flex-direction: column; align-items: stretch; }
  .estimate-shipping-row.shipping-address .estimate-shipping-row-item { width: 100%; }
  .shipping-options-header { display: none; }
  .shipping-options-body .estimate-shipping-row { flex-direction: column; align-items: flex-start; gap: 4px; }
}

/* =========================== CHECKOUT (One Page Checkout + classic multi-page) ===========================
   Neither this theme nor its Views/ folder override any checkout view (see Themes/Nexus/Views/,
   which only overrides Catalog/Product/Shared/ShoppingCart) - every page below, both One Page
   Checkout's accordion (OnePageCheckout.cshtml + its Opc*.cshtml partials) AND every step of the
   classic multi-step flow (BillingAddress/ShippingAddress/ShippingMethod/PaymentMethod/PaymentInfo/
   Confirm.cshtml, used when Admin > Configuration > Settings > Order Settings > "One page checkout"
   is disabled) is core's stock Nop.Web markup, styled entirely from here - same CSS-only approach
   already used for /cart. Verified against the reference Flexo theme's own copies of these same
   views: byte-for-byte identical to core once Flexo's added vendor license-header comment is
   accounted for, i.e. Flexo doesn't actually customize this markup either, it re-styles the exact
   same DOM this section targets.
   The shared OrderSummary component (order totals, billing/shipping/payment summary cards,
   cart-footer) and ".checkout-attributes"/".order-progress" (the multi-page step bar, and OPC's
   own numbered accordion header re-uses the same "order-progress"-adjacent core component for
   nothing - OPC's stepper is its own ".opc .step-title" markup, styled further down) are already
   covered by the SHOPPING CART PAGE section above, since core reuses those same partials/
   components on every checkout page - nothing further needed for them here. */

.checkout-page .page-title { margin-bottom: 24px; }

.checkout-page .section { margin-bottom: 28px; }
.checkout-page .section:last-child { margin-bottom: 0; }
.checkout-page .section > .title { margin-bottom: 16px; }
.checkout-page .section.order-summary > .title { margin-bottom: 20px; }

/* ship-to-same-address (billing step, both flows) / pickup-in-store (shipping address+method
   steps) - both render as "<p|div class="selector custom-checkbox">"; see the CUSTOM CONTROLS
   block below for the checkbox itself. */
.checkout-page .ship-to-same-address,
.checkout-page .pickup-in-store { margin-bottom: 24px; }
.checkout-page .ship-to-same-address .selector,
.checkout-page .pickup-in-store .selector { font-weight: 600; }
.checkout-page .pickup-in-store .description { margin-top: 8px; font-size: 13px; color: var(--pdx-text-muted); }

.vat-wrap { margin-bottom: 20px; }
.vat-number-warning { display: block; margin-top: 6px; font-size: 13px; color: var(--pdx-danger); }

/* every "Continue"/"Next"/"Back"/"Save"/"Cancel"/"Confirm" button row on every checkout page and
   OPC step shares this one class, so one broad rule covers all of them (OPC's own ".opc .buttons"
   further down only adds what's genuinely OPC-specific, the back-link + please-wait spacing).
   Right-aligned + generously spaced from whatever's above it, and from each other, per feedback on
   the confirm step's Back/Confirm pair; ".order-completed .buttons" further down still overrides
   back to centered for that page specifically (later in file = wins the specificity tie). */
.checkout-page .buttons { display: flex; flex-wrap: wrap; align-items: center; justify-content: flex-end; gap: 20px; margin-top: 28px; }

/* the order totals card (".cart-footer .totals", from the shared OrderSummary component - see the
   SHOPPING CART PAGE section above) is the only child of ".cart-footer" on every checkout page
   (".cart-collaterals" - coupon/gift-card - only renders when Model.IsEditable, which checkout's
   own invocations of this component never set), so it drifts to the left by default; pushed to the
   right instead, matching the right-aligned buttons above it, per feedback. */
.checkout-page .cart-footer { justify-content: flex-end; }

/* Core's OrderSummaryViewComponent (Views/Shared/Components/OrderSummary/Default.cshtml, unmodified)
   reuses the literal class name "product-quantity" for BOTH the real editable +/- stepper (a <div>,
   only when Model.IsEditable - i.e. the actual /cart page) AND the plain read-only quantity text (a
   <span>, everywhere this component is read-only - every checkout page's order-summary/confirm
   table, order details, etc). The SHOPPING CART PAGE section's ".cart .product-quantity" stepper
   rule (bordered box, fixed height/min-width) was written for the <div> case and was unintentionally
   also boxing up the plain <span> case wherever this same table.cart markup is reused read-only,
   making a plain number look like a live input on the checkout confirm page. Un-boxes it back down
   to plain text matching the Unit price/Item total columns beside it - ".cart span.product-quantity"
   is one tag-qualifier more specific than the original ".cart .product-quantity", so it wins. */
.cart span.product-quantity {
  display: inline;
  border: none;
  background: none;
  height: auto;
  min-width: 0;
  padding: 0;
  font-weight: 700;
  color: var(--pdx-text);
}

/* ===== native radio/checkbox controls =====
   Core's checkout markup wraps every radio/checkbox in Bootstrap's custom-control shape
   ("<div class="custom-radio"><input class="custom-control-input">...<label
   class="custom-control-label">...") - ship-to-same-address, pickup-in-store, shipping method,
   payment method, use-reward-points and terms-of-service (the last already styled by its own
   ".terms-of-service" rule in the SHOPPING CART PAGE section, unaffected by this) all use it.
   Unlike Flexo, this theme never loads bootstrap.min.css, so ".custom-control-input" is NOT
   position:absolute/opacity:0 hidden the way it would be under real Bootstrap - it's already a
   plain, visible native input. This just sizes/colors it to match every other native radio/
   checkbox sitewide (accent-color, same as ".checkout-attributes .option-list", ".attributes
   .option-list", etc.) instead of leaving it at browser-default size, rather than reimplementing
   Bootstrap's ::before/::after custom-control visual in raw CSS. */
.custom-radio,
.custom-checkbox { display: flex; align-items: center; gap: 8px; }
.custom-control-input[type="radio"],
.custom-control-input[type="checkbox"] {
  width: 16px;
  height: 16px;
  margin: 0;
  flex: 0 0 auto;
  accent-color: var(--pdx-primary);
  cursor: pointer;
}
.custom-control-label { font-size: 14px; color: var(--pdx-text); cursor: pointer; }

/* ===== One Page Checkout accordion (OnePageCheckout.cshtml - "<ol class="opc" id="checkout-
   steps">", each step a "<li class="tab-section[ allow]">") =====
   "allow" marks a step the accordion JS (public.accordion.js, unmodified core asset - already
   present/working, confirmed live) has unlocked - i.e. every step up to and including the current
   one; future steps stay locked/dim until reached. Styled as a stack of cards (this theme's
   standard surface/border/radius treatment) rather than Flexo's dark, flush-jointed wizard strip,
   to match the rest of the site. */
ol.opc {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.opc .tab-section {
  background: var(--pdx-surface);
  border: 1px solid var(--pdx-border);
  border-radius: var(--pdx-card-radius, var(--pdx-radius));
  overflow: hidden;
}
.opc .step-title { display: flex; align-items: center; gap: 12px; padding: 16px 20px; }
.opc .tab-section.allow .step-title { cursor: pointer; }
.opc .step-title .number {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  flex: 0 0 auto;
  border-radius: 50%;
  background: var(--pdx-body-bg);
  color: var(--pdx-text-muted);
  font-size: 13px;
  font-weight: 700;
}
.opc .tab-section.allow .step-title .number { background: var(--pdx-primary); color: var(--pdx-button-text, #fff); }
.opc .step-title .title { margin: 0; font-size: 16px; color: var(--pdx-text-muted); }
.opc .tab-section.allow .step-title .title { color: var(--pdx-text); }
/* per feedback, everything inside a step's panel is centered (closer to Flexo's original centered
   checkout layout) rather than left-aligned. "text-align: center" alone only centers inline
   content/text (step labels, "Select an address" prompts, etc - it's inherited down into every
   nested block automatically); the handful of flex rows and fixed-max-width blocks nested inside
   (address picker row, the new-address form card, method-list, checkbox/radio rows) each need
   their own explicit centering below since text-align doesn't reposition block-level flex
   children or auto-margin boxes by itself. The ".opc .buttons" action row is deliberately left
   out of this - it keeps the explicit right-alignment from the Back/Confirm button feedback
   above, since "center everything" was about the panel's content, not re-litigating that. */
.opc .step.a-item { padding: 20px; border-top: 1px solid var(--pdx-border); text-align: center; }

.opc .section { margin-bottom: 24px; }
.opc .section:last-child { margin-bottom: 0; }
.opc .back-link { margin: 0; order: -1; }
/* same outline treatment as the product detail page's Email a friend/Add to Wishlist/Add to
   Compare buttons (BUTTONS section above, ".email-a-friend-button" etc: transparent fill, 1px
   border, swaps to primary color on hover) per feedback, rather than a bare text link - back-link
   is a plain "<a>", not a "<button class="button-2">" like those, so it needs its own copy of that
   same shape (height/padding/radius) rather than picking it up for free the way those do. */
.opc .back-link a {
  display: inline-flex;
  align-items: center;
  height: 42px;
  padding: 0 22px;
  border: 1px solid var(--pdx-border);
  border-radius: var(--pdx-button-radius, 0px);
  background: transparent;
  color: var(--pdx-text);
  font-size: 14px;
  font-weight: 600;
}
.opc .back-link a:hover { background: transparent; color: var(--pdx-primary); border-color: var(--pdx-primary); }
.opc .back-link small { display: none; }
.opc .please-wait { font-size: 13px; color: var(--pdx-text-muted); }

.opc .select-billing-address > label,
.opc .select-shipping-address > label { display: block; margin-bottom: 12px; font-size: 15px; font-weight: 600; color: var(--pdx-text); }

/* ship-to-same-address / pickup-in-store / terms-of-service checkboxes inside OPC panels: each is
   a block-level flex row (".custom-radio"/".custom-checkbox", CUSTOM CONTROLS block above) that
   fills the panel's full width, so centering the panel's text alone doesn't recenter the
   checkbox+label as a unit - needs its own justify-content. Scoped to ".opc" so the sitewide
   checkbox styling (cart terms-of-service, checkout-attributes options, etc) stays left-aligned
   as before. */
.opc .custom-radio,
.opc .custom-checkbox { justify-content: center; }

/* OPC's existing-address picker: a <select> of saved addresses + Edit/Delete/Continue buttons, in
   place of the multi-page flow's address-card grid further down (core's own UX difference between
   the two flows, not something this theme invented). */
.opc-select-address-container { display: flex; flex-wrap: wrap; justify-content: center; align-items: center; gap: 10px; margin-top: 8px; margin-left: auto; margin-right: auto; }
.opc-select-address-container .address-select { width: auto; flex: 1 1 320px; }
.opc-select-address-container .button-1 { flex: 0 0 auto; height: 42px; padding: 0 20px; }

.select-billing-address .min-amount-warning,
.select-shipping-address .min-amount-warning { display: block; margin-bottom: 8px; }

/* ===== Multi-page checkout: existing-address selection as a card grid
   (BillingAddress.cshtml/ShippingAddress.cshtml - "<div class="address-grid"><div
   class="address-item">...") - same card treatment as the ADDRESS LIST PAGE section above, just
   applied directly to "address-item" since core's checkout markup doesn't add the
   ".address-list-page" wrapper class Customer/Addresses.cshtml does (it reuses that literal class
   name only for the inner Edit/Delete button row, confusingly - scoped to
   ".address-item .address-list-page" below so it can't be confused with the real address-list
   page). ===== */
.address-grid { display: grid; grid-template-columns: 1fr; gap: 20px; margin-bottom: 20px; }
@media (min-width: 768px) { .address-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1024px) { .address-grid { grid-template-columns: repeat(3, 1fr); } }
.address-item {
  position: relative;
  border: 1px solid var(--pdx-border);
  border-radius: var(--pdx-radius-sm);
  padding: 20px;
  background: var(--pdx-surface);
  display: flex;
  flex-direction: column;
}
.address-item .address-list-page { position: absolute; top: 16px; right: 16px; display: flex; gap: 6px; }
.address-item .address-list-page .button-2 { height: 30px; padding: 0 10px; font-size: 12px; }
.address-box { list-style: none; margin: 0 0 16px; padding: 0 60px 0 0; font-size: 14px; line-height: 1.7; color: var(--pdx-text-muted); }
.address-box .name { font-size: 16px; font-weight: 700; color: var(--pdx-text); }
.address-box label { font-weight: 600; color: var(--pdx-text); margin-right: 4px; }
.select-button { margin-top: auto; padding-top: 12px; }
.select-button .button-1 { width: 100%; }

/* ===== New address form (both flows share core's "_CreateOrUpdateAddress" partial under
   "enter-address" - same field markup as the ADDRESS EDIT PAGE section above, "edit-address"
   there vs "enter-address" here, so this mirrors that section's label-above/required-inline
   layout for a consistent field style sitewide instead of reinventing it here). ===== */
.checkout-page .title-text { font-size: 18px; }
.enter-address .edit-address { max-width: 480px; }
.enter-address .inputs { display: flex; flex-wrap: wrap; align-items: baseline; column-gap: 6px; margin-bottom: 20px; }
.enter-address .inputs:last-child { margin-bottom: 0; }
.enter-address .inputs > label { order: 1; margin-bottom: 6px; font-size: 14px; font-weight: 600; color: var(--pdx-text); }
.enter-address .inputs > .required { order: 2; margin: 0 0 6px; font-size: 13px; font-weight: 700; color: var(--pdx-danger); }
.enter-address .inputs > *:not(label):not(.required) { order: 3; flex: 1 1 100%; }
.enter-address .inputs .field-validation-error { display: block; margin-top: 4px; font-size: 12px; color: var(--pdx-danger); }

/* OPC panel-centering (see ".opc .step.a-item" above): the address form is a fixed max-width
   card, so centering it needs its own auto side-margins (text-align on the ancestor doesn't
   reposition a block with an explicit width) - same "max-width + margin: 0 auto" pattern already
   used sitewide for centered form cards (".write-review .form-fields", ".new-comment
   .form-fields", etc). Field rows and labels inside stay left-aligned (text-align: left) once
   the card itself is centered on the page, since a centered *label* above a *left-aligned* input
   reads oddly - only the card as a whole recenters, matching those other centered-form patterns.
   Scoped to ".opc" so the multi-page flow's new-address form (untouched by this request) keeps
   its existing left-aligned layout. */
.opc .enter-address .edit-address { margin: 0 auto; text-align: left; }

/* ===== shipping method / payment method selection (shared class names, both flows) =====
   Was a vertical stack (flex-direction: column); per feedback this is now a centered, wrapping
   row instead - each method card gets a comfortable fixed-ish width (flex-basis, allowed to
   shrink on narrow viewports) rather than stretching edge-to-edge, and the row itself is
   centered rather than left-packed, so a single method (the common case - most stores only
   have one shipping/payment option configured) sits centered in the panel instead of pinned to
   the left edge. */
.method-list { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; justify-content: center; gap: 10px; }
.method-list > li { flex: 0 1 320px; border: 1px solid var(--pdx-border); border-radius: var(--pdx-radius-sm); padding: 14px 16px; transition: border-color .15s ease; }
/* progressive enhancement only - browsers without :has() just keep the plain border; the radio
   itself is still visibly checked (native accent-color dot) either way. */
.method-list > li:has(.custom-control-input:checked) { border-color: var(--pdx-primary); }
.method-name { display: flex; align-items: center; gap: 12px; }
.method-list .custom-control-label { font-size: 14px; font-weight: 600; color: var(--pdx-text); }
.method-description { margin-top: 8px; padding-left: 28px; font-size: 13px; color: var(--pdx-text-muted); }
.multiple-locations { margin-top: 12px; font-size: 13px; color: var(--pdx-text-muted); }

.payment-logo { flex: 0 0 auto; }
.payment-logo img { max-height: 32px; width: auto; }
.payment-details { flex: 1 1 auto; min-width: 0; }
.payment-description { margin-top: 6px; font-size: 13px; color: var(--pdx-text-muted); }

.use-reward-points { margin-bottom: 20px; }

/* ===== payment info step - the actual field markup varies per payment plugin (Component.
   InvokeAsync(Model.PaymentViewComponent)), most render a plain label/input table - covered
   generically rather than per-plugin, same reasoning as ".checkout-attributes" above. ===== */
.payment-info .info table { width: 100%; }
.payment-info .info table td { padding: 8px 0; vertical-align: top; }
.payment-info .info table td:first-child { width: 220px; padding-right: 16px; font-weight: 600; color: var(--pdx-text); }

/* ===== confirm order step ===== */
.confirm-order .min-order-warning { display: block; margin-bottom: 16px; font-size: 14px; font-weight: 600; color: var(--pdx-danger); }

/* OPC confirm step's billing/shipping/payment recap cards (".order-review-data", SHOPPING CART
   PAGE section above - shared with /cart and Order Details) are a flex row that packs to the
   left by default; centered here to match the rest of the OPC panel-centering above. The totals
   card just below it (".cart-footer") deliberately keeps the right-alignment from the earlier
   Back/Confirm feedback - not part of this centering pass. */
.opc .order-review-data { justify-content: center; }

/* ===== pickup-in-store (shipping address + shipping method steps) ===== */
.pickup-points { margin-bottom: 24px; }
.select-pickup-point { margin-bottom: 16px; }
.select-pickup-point .address-select { max-width: 480px; }
.single-pickup-point { margin-top: 8px; font-size: 13px; color: var(--pdx-text-muted); }
.single-pickup-point.name { margin-top: 0; font-size: 15px; font-weight: 700; color: var(--pdx-text); }
.pickup-points-map { margin-top: 16px; border-radius: var(--pdx-radius-sm); overflow: hidden; }

/* ===== order completed (/checkout/completed) ===== */
.order-completed {
  text-align: center;
  padding: 40px 20px;
  background: var(--pdx-surface);
  border: 1px solid var(--pdx-border);
  border-radius: var(--pdx-card-radius, var(--pdx-radius));
}
.order-completed .title { margin-bottom: 16px; }
.order-completed .details { margin-bottom: 24px; }
.order-completed .order-number { font-size: 16px; margin-bottom: 8px; }
.order-completed .details-link a { font-weight: 600; }
.order-completed .buttons { justify-content: center; }

/* ===== multi-page checkout: confirm page (/checkout/confirm) ===== */
/* Core's Confirm.cshtml (unmodified) renders ".section.confirm-order" (terms-of-service checkbox
   + the Confirm button + captcha) BEFORE ".section.order-summary" (the totals) in the markup -
   per feedback the Confirm button should sit at the very bottom of the page, under the totals,
   instead. Reordered here with flexbox rather than a view override: the two sections' shared
   parent becomes a flex column and each section gets an explicit order (lower = earlier), which
   swaps their visual sequence without touching Confirm.cshtml. Any widget-zone content between
   them (CheckoutConfirmTop/Bottom, almost always empty on this site) keeps the default order: 0,
   so it still renders above both - only the two sections themselves are being swapped. */
.order-confirm-page .checkout-data { display: flex; flex-direction: column; }
.order-confirm-page .checkout-data .section.confirm-order { order: 2; }
.order-confirm-page .checkout-data .section.order-summary { order: 1; }

@media (max-width: 767px) {
  .opc-select-address-container .button-1,
  .opc-select-address-container .address-select { flex: 1 1 100%; }
  .address-item .address-list-page { position: static; justify-content: flex-end; margin-bottom: 12px; }
  .payment-info .info table td:first-child { width: auto; display: block; padding-bottom: 2px; }
  .payment-info .info table td { display: block; }
}

/* =========================== WISHLIST PAGE (/wishlist) =========================== */
/* Views/ShoppingCart/Wishlist.cshtml (core, but see this theme's own
   Themes/Nexus/Views/ShoppingCart/Wishlist.cshtml override, which adds the missing +/- stepper
   markup around the plain quantity <input> - core's own wishlist view ships that input bare, with
   no wrapping ".product-quantity"/up/down divs at all, unlike the cart page). Renders the exact
   same "<table class="cart">" markup as the cart page, so every ".cart"-scoped rule already defined
   above in the SHOPPING CART PAGE section (row layout, .product-picture image sizing/radius,
   .qty-input/.product-quantity stepper sizing+glyphs, mobile stacked-row layout, etc) applies here
   unchanged with zero duplication. Only the handful of rules below are genuinely wishlist-only. */

/* "Add to cart" checkbox column - only rendered when Model.DisplayAddToCart */
table.cart th.add-to-cart,
table.cart td.add-to-cart { text-align: center; width: 40px; }
table.cart td.add-to-cart input[type="checkbox"] { width: 18px; height: 18px; margin: 0; accent-color: var(--pdx-primary); }

/* per-row "move to a different wishlist" dropdown - only when multiple wishlists are enabled */
.custom-wishlist { margin-top: 10px; }
.custom-wishlist .td-title { font-size: 12px; font-weight: 700; text-transform: uppercase; letter-spacing: .03em; color: var(--pdx-text-muted); margin-bottom: 4px; }
.custom-wishlist-dropdown { height: 34px; padding: 0 8px; border: 1px solid var(--pdx-border); border-radius: var(--pdx-input-radius, var(--pdx-radius-sm)); background: var(--pdx-body-bg); color: var(--pdx-text); font-size: 13px; }

/* action-button row under the table: Update Wishlist / Add to Cart / Email a Friend / Delete Wishlist */
.wishlist-content .buttons { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 20px; }
.wishlist-content .buttons .button-2 { padding: 12px 24px; }

/* multi-wishlist tab bar above the table (Model.AllowMultipleWishlist) */
.button-row { display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: 20px; }
.custom-wishlist-button { padding: 10px 20px; border-radius: var(--pdx-button-radius, 0px); }

/* shareable wishlist URL row shown below the buttons when the list is editable */
.share-info {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  margin-top: 20px;
  padding: 14px 16px;
  background: #F8F8F8;
  border: 1px solid var(--pdx-border);
  border-radius: var(--pdx-radius-sm);
}
.share-info .share-label { font-size: 13px; font-weight: 700; color: var(--pdx-text); }
.share-info .share-link { font-size: 13px; color: var(--pdx-primary); word-break: break-all; }
.share-info .share-link:hover { text-decoration: underline; }

@media (max-width: 767px) {
  table.cart th.add-to-cart,
  table.cart td.add-to-cart { width: auto; justify-content: flex-start; }
  .wishlist-content .buttons { flex-direction: column; align-items: stretch; }
  .wishlist-content .buttons .button-2 { width: 100%; justify-content: center; }
  .button-row { flex-direction: column; align-items: stretch; }
}

/* =========================== LOGIN PAGE (/login) =========================== */

/*
  Core's Customer/Login.cshtml (Nop.Web, unmodified - the Nexus theme has no view override for
  this page, so this is pure CSS against core's stock markup/classes) renders two independent
  boxes inside ".customer-blocks": ".new-wrapper" (register / guest-checkout prompt) and
  ".returning-wrapper.fieldset" (the actual login form). Both get the same boxed-"fieldset"
  treatment already used for this theme's other forms (.write-review .fieldset, .new-comment
  form - background/border-radius/shadow via the shared --pdx-* surface tokens), laid out side by
  side on desktop and stacked on mobile so the page reads as one consistent "card" pair rather
  than the unstyled default two-stacked-blocks core ships with.
*/
.login-page .page-title h1 { text-align: center; }

.login-page .customer-blocks {
  display: flex;
  flex-wrap: wrap;
  align-items: stretch;
  gap: 24px;
  margin-top: 8px;
}

.login-page .new-wrapper,
.login-page .returning-wrapper {
  flex: 1 1 360px;
  background: var(--pdx-surface);
  border: 1px solid var(--pdx-border);
  border-radius: var(--pdx-card-radius, var(--pdx-radius));
  box-shadow: var(--pdx-shadow);
  padding: 32px 28px;
}

/* register/guest-checkout prompt reads as a secondary/quieter panel (dashed border, page
   background fill, no shadow) so the returning-customer form on the other side keeps visual
   priority - matches how this theme already differentiates primary vs. secondary actions
   elsewhere (.button-1/.button-2, .add-to-wishlist-button's outline treatment, etc.). */
.login-page .new-wrapper {
  background: var(--pdx-body-bg);
  border-style: dashed;
  box-shadow: none;
}

.login-page .new-wrapper .title,
.login-page .returning-wrapper .title {
  text-align: left;
  padding-bottom: 16px;
  margin-bottom: 20px;
  border-bottom: 1px solid var(--pdx-border);
  color: var(--pdx-text);
}

.login-page .new-wrapper .text { color: var(--pdx-text-muted); line-height: 1.6; margin-bottom: 24px; }
.login-page .new-wrapper .buttons { display: flex; flex-wrap: wrap; gap: 12px; }
.login-page .new-wrapper .buttons .button-1 { flex: 1 1 auto; text-align: center; }

/* login form fields - stacked label-above-input rows, same convention as .new-comment .inputs
   (this form is a single narrow column, unlike .write-review's wider label-left/input-right
   layout, so the stacked pattern reads better here). */
.login-page .form-fields { width: 100%; }

.login-page .inputs { margin-bottom: 18px; }
.login-page .inputs label {
  display: block;
  margin-bottom: 6px;
  font-size: 14px;
  font-weight: 600;
  color: var(--pdx-text);
}
.login-page .inputs .field-validation-error { display: block; margin-top: 4px; font-size: 12px; color: var(--pdx-danger); }

/* password field + show/hide toggle (core's own .password-eye span, toggled via the login
   page's inline script) - icon rendered the same currentColor-mask way as .viewmode-icon further
   up this file, so no image asset is needed. */
.login-page .login-password { position: relative; }
.login-page .login-password .password { padding-right: 42px; }
.login-page .password-eye {
  position: absolute;
  top: 0;
  right: 0;
  width: 42px;
  height: 42px;
  cursor: pointer;
}
.login-page .password-eye::before {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 18px;
  height: 18px;
  transform: translate(-50%, -50%);
  background-color: var(--pdx-text-muted);
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-position: center;
  mask-position: center;
  -webkit-mask-size: contain;
  mask-size: contain;
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M12 5C5 5 1 12 1 12s4 7 11 7 11-7 11-7-4-7-11-7Zm0 11a4 4 0 1 1 0-8 4 4 0 0 1 0 8Z'/%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M12 5C5 5 1 12 1 12s4 7 11 7 11-7 11-7-4-7-11-7Zm0 11a4 4 0 1 1 0-8 4 4 0 0 1 0 8Z'/%3E%3C/svg%3E");
}
.login-page .password-eye:hover::before { background-color: var(--pdx-text); }
.login-page .password-eye.password-eye-open::before {
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M12 5C5 5 1 12 1 12s4 7 11 7 11-7 11-7-4-7-11-7Zm0 11a4 4 0 1 1 0-8 4 4 0 0 1 0 8Z'/%3E%3Crect x='2' y='10.5' width='20' height='3' rx='1.5' transform='rotate(-32 12 12)'/%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M12 5C5 5 1 12 1 12s4 7 11 7 11-7 11-7-4-7-11-7Zm0 11a4 4 0 1 1 0-8 4 4 0 0 1 0 8Z'/%3E%3Crect x='2' y='10.5' width='20' height='3' rx='1.5' transform='rotate(-32 12 12)'/%3E%3C/svg%3E");
}

/* remember-me checkbox + forgot-password link row - checkbox sizing/accent matches the theme's
   other bare checkboxes (.terms-of-service, .checkout-attributes .option-list) */
.login-page .inputs.reversed {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 22px;
}
.login-page .inputs.reversed input[type="checkbox"] { width: 16px; height: 16px; accent-color: var(--pdx-primary); }
.login-page .inputs.reversed label { margin: 0; font-size: 13px; font-weight: 500; color: var(--pdx-text-muted); }
.login-page .forgot-password { margin-left: auto; }
.login-page .forgot-password a { font-size: 13px; font-weight: 600; }

.login-page .captcha-box { margin-bottom: 18px; }

.login-page .returning-wrapper .message-error { margin-bottom: 18px; }
.login-page .returning-wrapper .buttons { margin-top: 4px; }
.login-page .returning-wrapper .login-button { width: 100%; padding: 13px 22px; }

.login-page .external-authentication { margin-top: 32px; text-align: center; }

@media (max-width: 767px) {
  .login-page .customer-blocks { flex-direction: column; }
  .login-page .new-wrapper,
  .login-page .returning-wrapper { padding: 24px 20px; }
}

/* =========================== ACCOUNT PAGES (/customer/info, etc.) =========================== */

/*
  Core's Customer/Info.cshtml (Nop.Web, unmodified - the Nexus theme has no view override for this
  or the other /customer/* pages, so this is pure CSS against core's stock markup/classes) renders
  each section of the form as its own "<section class="fieldset"><h2 class="title">...
  <div class="form-fields">..." block - Personal Details, Company Details, Address, Contact
  Information, Newsletter, Options, Preferences, Associated External Auth, GDPR consent - inside
  ".page.account-page.customer-info-page .page-body".

  Scoped to ".customer-info-page" specifically (the page class core adds via
  NopHtml.AppendPageCssClassParts("html-customer-info-page")/"html-account-page", rendered as
  "<div class="page account-page customer-info-page">") rather than the broader ".account-page",
  which also covers Addresses/Orders/ChangePassword/Register/etc - so this only touches the page
  requested, without changing ".write-review"/".login-page", which already have their own boxed-
  "fieldset" treatment elsewhere in this file (same background/border/radius/shadow surface
  tokens, same label-above-input convention, same bare-native-control + accent-color pattern for
  radios/checkboxes as .write-review .rating-options/.checkout-attributes .option-list/.login-page
  .inputs.reversed) - reused here rather than re-invented, just scoped to this page.
*/

.customer-info-page .page-body { display: flex; flex-direction: column; gap: 20px; }

.customer-info-page .fieldset {
  background: var(--pdx-surface);
  padding: 28px 0 4px;
}

.customer-info-page .fieldset .title {
  text-align: left;
  padding-bottom: 16px;
  margin-bottom: 20px;
  border-bottom: 1px solid var(--pdx-border);
  color: var(--pdx-text);
}

.customer-info-page .form-fields { max-width: 480px; }

/* Each "<div class="inputs"><label>...</label>[<span class="required">*</span>]<input/etc>
   <span class="field-validation-*">...</span></div>" row is a flex-wrap row rather than plain
   block stacking so the required asterisk can sit directly beside its label (same DOM order core
   already renders, just reflowed - no view override needed) while the actual control still drops
   to its own full-width line below: label/required share line 1 (their natural content width,
   nothing else claims flex-basis:100% so nothing forces them apart), then the ":not(label):not(
   .required)" rule gives EVERY other direct child (input/select/textarea/.gender/
   .date-picker-wrapper/.attributes/readonly-username/email-to-revalidate/validation message/etc -
   deliberately generic so every field type on this page is covered without enumerating each one)
   flex-basis:100%, which forces it onto its own new flex line. */
.customer-info-page .inputs {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  column-gap: 6px;
  margin-bottom: 20px;
}
.customer-info-page .inputs:last-child { margin-bottom: 0; }
.customer-info-page .inputs > label {
  order: 1;
  margin-bottom: 6px;
  font-size: 14px;
  font-weight: 600;
  color: var(--pdx-text);
}
.customer-info-page .inputs > .required {
  order: 2;
  margin: 0 0 6px;
  font-size: 13px;
  font-weight: 700;
  color: var(--pdx-danger);
}
.customer-info-page .inputs > *:not(label):not(.required) { order: 3; flex: 1 1 100%; }
.customer-info-page .inputs .field-validation-error {
  display: block;
  margin-top: 4px;
  font-size: 12px;
  color: var(--pdx-danger);
}

/* Date of birth - core's nop-date-picker tag helper wraps its 3 <select>s in its own
   "<div class="date-picker-wrapper">" (already picked up as this ".inputs" row's one full-width
   child via the ":not(label):not(.required)" rule above); this just lays those 3 selects out as
   one row instead of each falling onto its own line (they'd otherwise each hit the theme's global
   "select { width: 100% }" base rule - see BASE section - same as any other select on this page). */
.customer-info-page .date-picker-wrapper { display: flex; gap: 6px; }
.customer-info-page .date-picker-wrapper select { width: auto; flex: 1 1 0; }

/* Gender radios: core renders each option as "<span class="male|female|Neutral"><input
   type="radio">...<label class="forcheckbox">...</label></span>" - no shared "custom-radio"-style
   wrapper class, so this targets the raw elements directly rather than a component class. Same
   bare-native-control + accent-color treatment as the rest of the theme's radios/checkboxes
   (.write-review .rating-options, .checkout-attributes .option-list, .login-page .inputs.reversed)
   rather than a fully custom ::before/::after control. */
.customer-info-page .gender { display: flex; flex-wrap: wrap; align-items: center; gap: 20px; margin-top: 4px; }
.customer-info-page .gender span { display: flex; align-items: center; gap: 6px; }
.customer-info-page .gender input[type="radio"] { width: 16px; height: 16px; margin: 0; accent-color: var(--pdx-primary); }
.customer-info-page .gender .forcheckbox {
  display: inline;
  margin: 0;
  font-size: 14px;
  font-weight: 500;
  color: var(--pdx-text);
  cursor: pointer;
}

/* Newsletter checkbox list ("Subscribe to newsletter" section) - core renders each row as
   "<li><label>Name</label><input type="hidden">...<input class="form-check-input"
   type="checkbox">...</li>", label BEFORE the checkbox in markup order; "order" puts the checkbox
   first visually without fighting that DOM order (the hidden input takes no box either way). */
.customer-info-page .attributes ul { display: flex; flex-direction: column; gap: 10px; }
.customer-info-page .attributes li { display: flex; align-items: center; gap: 8px; }
.customer-info-page .attributes li label {
  order: 2;
  display: inline;
  margin: 0;
  font-size: 14px;
  font-weight: 500;
  color: var(--pdx-text);
  cursor: pointer;
}
.customer-info-page .attributes li input[type="checkbox"] {
  order: 1;
  width: 16px;
  height: 16px;
  margin: 0;
  accent-color: var(--pdx-primary);
}

/* GDPR consent checkboxes (further down, "Account.UserAgreement" section) - core renders
   "<div class="inputs accept-consent"><input type="checkbox">...<label>Message</label></div>",
   checkbox and label as the ONLY two direct children of this same ".inputs" element (unlike every
   other field row above, there's no separate label-only row here) - "order"/"flex: 1 1 100%" from
   the general ".inputs > *:not(label):not(.required)" rule above would otherwise still apply to
   this checkbox (that rule's own specificity is lower, but it's never overridden below since nothing
   else here redeclares "order"/"flex"), forcing it onto its own full-width line same as any other
   field's control; explicitly reset to keep checkbox+label side by side instead. */
.customer-info-page .inputs.accept-consent {
  display: flex;
  align-items: flex-start;
  gap: 8px;
}
.customer-info-page .inputs.accept-consent input[type="checkbox"] {
  order: 0;
  flex: 0 0 auto;
  margin: 0;
  margin-top: 3px;
  width: 16px;
  height: 16px;
  accent-color: var(--pdx-primary);
  flex-shrink: 0;
}
.customer-info-page .inputs.accept-consent label {
  display: inline;
  margin: 0;
  font-size: 14px;
  font-weight: 500;
  color: var(--pdx-text);
  cursor: pointer;
}

.customer-info-page .readonly-username { display: inline-block; padding: 0 2px; font-size: 14px; color: var(--pdx-text-muted); }
.customer-info-page .email-to-revalidate { font-size: 14px; color: var(--pdx-text-muted); }
.customer-info-page .email-to-revalidate-note,
.customer-info-page .vat-note { display: block; margin-top: 6px; font-size: 13px; color: var(--pdx-text-muted); }
.customer-info-page .vat-status { display: block; margin-top: 6px; font-size: 13px; color: var(--pdx-text); }

.customer-info-page .account-signature-text { min-height: 100px; resize: vertical; }

/* Associated External Auth table - same boxed "table-wrapper" surface as the rest of the theme
   (cart, product specs), just with its own th/td rules since no sitewide generic ".data-table"
   exists (every other table on this theme styles its own th/td directly, same convention here). */
.customer-info-page .table-wrapper {
  overflow-x: auto;
  margin-bottom: 4px;
}
.customer-info-page .data-table { width: 100%; border-collapse: collapse; font-size: 14px; }
.customer-info-page .data-table th {
  padding: 10px 12px;
  text-align: left;
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .03em;
  color: var(--pdx-text-muted);
  border-bottom: 1px solid var(--pdx-border);
  white-space: nowrap;
}
.customer-info-page .data-table td {
  padding: 12px;
  border-bottom: 1px solid var(--pdx-border);
  color: var(--pdx-text);
}
.customer-info-page .data-table td.remove a { color: var(--pdx-danger); font-weight: 600; }
.customer-info-page .add-more-external-records { font-size: 14px; color: var(--pdx-text-muted); margin-top: 12px; }
.customer-info-page .add-more-external-records a { word-break: break-all; }

.customer-info-page .buttons { display: flex; justify-content: flex-start; margin-top: 4px; }
.customer-info-page .save-customer-info-button { padding: 13px 32px; }

@media (max-width: 767px) {
  .customer-info-page .fieldset { padding: 22px 0 4px; }
  .customer-info-page .form-fields { max-width: none; }
  .customer-info-page .gender { gap: 14px; }
}

/* =========================== CHANGE PASSWORD PAGE ===========================
   Mirrors .customer-info-page's flat/borderless fieldset treatment above (no card border/shadow,
   left-aligned with the "My Account" page title, required asterisk pulled up next to the label via
   flex "order") rather than generalizing that page's selectors, since core's stock
   Customer/ChangePassword.cshtml (Nop.Web, unmodified, no theme view override) has its own small
   wrinkles .customer-info-page doesn't: no "<h2 class="title">" in its one fieldset, an always-
   rendered (sometimes empty) ".warnings" block for expired/must-change-password notices, and the
   "Old password" input is wrapped together with a "Forgot password?" link in
   "<div class="form-input-wrapper">" rather than being a bare input. */
.change-password-page .page-body { display: flex; flex-direction: column; gap: 20px; }

.change-password-page .fieldset {
  background: var(--pdx-surface);
  border-radius: var(--pdx-card-radius, var(--pdx-radius));
  padding: 28px 0 4px;
}

.change-password-page .form-fields { max-width: 480px; }

.change-password-page .warnings:empty { display: none; }
.change-password-page .warnings p {
  margin: 0 0 16px;
  padding: 10px 14px;
  border-radius: var(--pdx-radius-sm, 4px);
  background: color-mix(in srgb, var(--pdx-danger) 10%, transparent);
  color: var(--pdx-danger);
  font-size: 14px;
}

.change-password-page .inputs { margin-bottom: 20px; display: flex; flex-wrap: wrap; align-items: center; }
.change-password-page .inputs:last-child { margin-bottom: 0; }

.change-password-page .inputs label {
  order: 1;
  display: block;
  margin: 0 6px 6px 0;
  font-size: 14px;
  font-weight: 600;
  color: var(--pdx-text);
}
.change-password-page .required { order: 2; display: inline-block; margin: 0 0 6px; font-size: 13px; font-weight: 700; color: var(--pdx-danger); }
.change-password-page .inputs > input,
.change-password-page .inputs > .form-input-wrapper {
  order: 3;
  flex: 0 0 100%;
}
.change-password-page .inputs > span:not(.required) {
  order: 4;
  flex: 0 0 100%;
}
.change-password-page .inputs .field-validation-error {
  display: block;
  margin-top: 4px;
  font-size: 12px;
  color: var(--pdx-danger);
}

.change-password-page .change-password-recovery-link {
  margin-top: 8px;
  font-size: 13px;
}
.change-password-page .change-password-recovery-link a { color: var(--pdx-primary); }

.change-password-page .buttons { display: flex; justify-content: flex-start; margin-top: 4px; }
.change-password-page .change-password-button { padding: 13px 32px; }

@media (max-width: 767px) {
  .change-password-page .fieldset { padding: 22px 0 4px; }
  .change-password-page .form-fields { max-width: none; }
}

/* =========================== EMAIL A FRIEND PAGE ===========================
   Core's Product/ProductEmailAFriend.cshtml (Nop.Web, unmodified - the Nexus theme has no view
   override for this page) renders "<div class="page email-a-friend-page"><div class="page-title">
   <h1>...</h1></div><div class="page-body"><div class="title"><h2><a class="product">...</a></h2>
   </div>..." - a product-name sub-header - then either a single "<section class="fieldset">
   <div class="form-fields">..." block (no "<h2 class="title">" inside it, same wrinkle as
   Customer/ChangePassword.cshtml above) with the friend-email/your-email/personal-message inputs,
   or, once sent, a "<div class="result">...</div>" success message in its place.

   Mirrors .customer-info-page/.change-password-page's flat/borderless fieldset treatment (no card
   border/shadow, required asterisk pulled up next to the label via flex "order", label-above-input
   rows) for consistency across this theme's account/utility forms, rather than the boxed-card
   variant used by .write-review/.login-page. The product-name sub-header reuses the sitewide
   ".title { color: var(--pdx-subheading); margin-bottom: 16px; }" rule (further above) as its base
   and just adds the same bottom-border treatment ".new-comment > .title" uses elsewhere in this
   file, so it reads as a divider between the page's own <h1> and the form below it. */
.email-a-friend-page .page-body { display: flex; flex-direction: column; gap: 20px; }

.email-a-friend-page .page-body > .title {
  padding-bottom: 16px;
  margin-bottom: 0;
  border-bottom: 1px solid var(--pdx-border);
}
.email-a-friend-page .page-body > .title h2 { margin: 0; font-size: 18px; }
.email-a-friend-page .page-body > .title a.product { color: var(--pdx-text); }
.email-a-friend-page .page-body > .title a.product:hover { color: var(--pdx-primary); }

.email-a-friend-page .fieldset {
  background: var(--pdx-surface);
  border-radius: var(--pdx-card-radius, var(--pdx-radius));
  padding: 28px 0 4px;
}

.email-a-friend-page .form-fields { max-width: 480px; }

.email-a-friend-page .inputs { margin-bottom: 20px; display: flex; flex-wrap: wrap; align-items: center; }
.email-a-friend-page .inputs:last-child { margin-bottom: 0; }

.email-a-friend-page .inputs label {
  order: 1;
  display: block;
  margin: 0 6px 6px 0;
  font-size: 14px;
  font-weight: 600;
  color: var(--pdx-text);
}
.email-a-friend-page .required { order: 2; display: inline-block; margin: 0 0 6px; font-size: 13px; font-weight: 700; color: var(--pdx-danger); }
.email-a-friend-page .inputs > input,
.email-a-friend-page .inputs > textarea {
  order: 3;
  flex: 0 0 100%;
}
.email-a-friend-page .inputs > span:not(.required) {
  order: 4;
  flex: 0 0 100%;
}
.email-a-friend-page .inputs .field-validation-error {
  display: block;
  margin-top: 4px;
  font-size: 12px;
  color: var(--pdx-danger);
}
/* core reuses the "your-email" class on both the YourEmailAddress <input> and the PersonalMessage
   <textarea> (a quirk of core's own markup, not this theme) - scope the min-height/resize to the
   textarea element specifically so it doesn't also apply to the <input>. */
.email-a-friend-page textarea.your-email { min-height: 120px; resize: vertical; }

.email-a-friend-page .result {
  margin-top: 4px;
  padding: 12px 16px;
  background: color-mix(in srgb, var(--pdx-success) 10%, transparent);
  color: var(--pdx-success);
  border-radius: var(--pdx-radius-sm);
  font-size: 14px;
}

.email-a-friend-page .buttons { display: flex; justify-content: flex-start; margin-top: 4px; }
.email-a-friend-page .send-email-a-friend-button { padding: 13px 32px; }

@media (max-width: 767px) {
  .email-a-friend-page .fieldset { padding: 22px 0 4px; }
  .email-a-friend-page .form-fields { max-width: none; }
}

/* =========================== ORDER HISTORY PAGE ===========================
   Restyled to match .address-list-page's card treatment below: Core's stock
   Nop.Web/Views/Order/CustomerOrders.cshtml (unmodified - neither Nexus nor Flexo override this
   view) renders each order as "<div class="section order-item"><h2 class="title">Order Number:
   X</h2><ul class="info">...</ul><div class="buttons">...</div></div>" inside ".order-list" - same
   shape as an ".address-item" card. Each ".order-item" gets its own bordered (no fill - unlike
   ".address-item" this card intentionally has no background color) card, and the Details/Return
   Item(s) buttons - each "font-size: 0" rather than removed, so a screen reader still announces
   "Order details"/"Return items" - become icon-only controls pinned to the card's top-right
   corner via the same "position: absolute against a position: relative card" + mask-image
   technique ".address-list-page .buttons" uses. Unlike the address list (3-column grid), the
   order list stays a 2-column grid at desktop widths - see the media query below. */
.order-list-page .page-body { display: flex; flex-direction: column; gap: 4px; }

.order-list-page .order-filters { margin-bottom: 20px; }
.order-list-page .order-filters__row { display: flex; flex-wrap: wrap; align-items: center; justify-content: flex-end; gap: 10px; }
.order-list-page .order-filters__label { font-size: 14px; font-weight: 600; color: var(--pdx-text); }
.order-list-page .order-filters__input { width: auto; min-width: 160px; }

.order-list-page .order-item {
  position: relative;
  margin: 0 0 24px;
  border: 1px solid var(--pdx-border);
  border-radius: var(--pdx-radius-sm);
  padding: 20px;
}
.order-list-page .order-item:last-child { margin-bottom: 0; }

.order-list-page .order-item .title {
  margin: 0 0 12px;
  padding-right: 64px;
  font-size: 16px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .02em;
  color: var(--pdx-text);
}

.order-list-page .info {
  list-style: none;
  margin: 0;
  padding: 0;
  font-size: 14px;
  line-height: 1.8;
  color: var(--pdx-text-muted);
}
.order-list-page .info .order-status,
.order-list-page .info .order-date,
.order-list-page .info .order-total { color: var(--pdx-text); font-weight: 500; }

.order-list-page .buttons {
  position: absolute;
  top: 16px;
  right: 16px;
  display: flex;
  gap: 2px;
  margin: 0;
}
.order-list-page .button-2 {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  padding: 0;
  border: none;
  border-radius: var(--pdx-radius-sm);
  background: transparent;
  font-size: 0;
  line-height: 0;
  color: var(--pdx-text-muted);
  cursor: pointer;
}
.order-list-page .button-2::before {
  content: "";
  display: block;
  width: 16px;
  height: 16px;
  background-color: currentColor;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-position: center;
  mask-position: center;
  -webkit-mask-size: contain;
  mask-size: contain;
}
/* Same "three bars" mask as .viewmode-icon.list::before above - reused for visual consistency
   rather than drawing a second near-identical list glyph. */
.order-list-page .order-details-button { color: var(--pdx-text); }
.order-list-page .order-details-button:hover { background: color-mix(in srgb, var(--pdx-text) 8%, transparent); }
.order-list-page .order-details-button::before {
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Crect x='3' y='4' width='4' height='4'/%3E%3Crect x='10' y='4' width='11' height='4'/%3E%3Crect x='3' y='10' width='4' height='4'/%3E%3Crect x='10' y='10' width='11' height='4'/%3E%3Crect x='3' y='16' width='4' height='4'/%3E%3Crect x='10' y='16' width='11' height='4'/%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Crect x='3' y='4' width='4' height='4'/%3E%3Crect x='10' y='4' width='11' height='4'/%3E%3Crect x='3' y='10' width='4' height='4'/%3E%3Crect x='10' y='10' width='11' height='4'/%3E%3Crect x='3' y='16' width='4' height='4'/%3E%3Crect x='10' y='16' width='11' height='4'/%3E%3C/svg%3E");
}
.order-list-page .return-items-button { color: var(--pdx-primary); }
.order-list-page .return-items-button:hover { background: color-mix(in srgb, var(--pdx-primary) 10%, transparent); }
.order-list-page .return-items-button::before {
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M3 12h16M13 6l6 6-6 6' fill='none' stroke='%23000' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M3 12h16M13 6l6 6-6 6' fill='none' stroke='%23000' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}

.order-list-page .no-data { padding: 20px 0; color: var(--pdx-text-muted); }

/* =====================================================================
   Pager - shared nopCommerce component (Views/Shared/Components/Pager),
   reused as-is on every paged listing site-wide: category/search product
   grids, order history, reward points history, forums, etc. Previously
   unstyled here, so each <li> stacked on its own line (default block
   display). Styled to match the Flexo reference theme's pill treatment
   (see ClaudeWorkingFolder\Themes\Flexo\Content\css\styles.css ~line
   2527), but using Nexus's own admin-configurable design tokens instead
   of Flexo's fixed colors - the current/selected page uses --pdx-primary
   (Configure > Colors > "Primary color"), matching Flexo's use of its
   own primary-color variable for the current page. */
.pager {
  margin: 0 0 20px;
}

.pager ul {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 8px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.pager li {
  display: inline-flex;
}

.pager li.total-summary {
  width: 100%;
  justify-content: center;
  text-align: center;
  margin-bottom: 4px;
  color: var(--pdx-text-muted);
  font-size: 14px;
}

.pager li a,
.pager li span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 35px;
  height: 35px;
  padding: 0 12px;
  border: 1px solid var(--pdx-card-border-color, #E4E7EC);
  background-color: var(--pdx-body-bg, #F7F8FA);
  border-radius: 50px;
  font-size: 14px;
  line-height: 1;
  color: var(--pdx-text);
  cursor: pointer;
  transition: background-color .15s ease, color .15s ease, border-color .15s ease;
}

/* Current page renders as a bare <span> (no class) inside li.current-page -
   give it the primary-color treatment, same selector approach Flexo uses. */
.pager li span {
  border-color: transparent;
  background-color: var(--pdx-primary);
  color: var(--pdx-button-text);
}

.pager li a:hover {
  border-color: transparent;
  background-color: var(--pdx-card-border-color, #E4E7EC);
  color: var(--pdx-text);
}

.order-list-page .pager { margin-top: 24px; }

/* My account > Product reviews (core's Nop.Web/Views/Product/CustomerProductReviews.cshtml,
   unmodified - page class "my-product-reviews-list-page"). The review list here reuses the same
   ".product-review-item" cards as the product detail page's Reviews tab (styled in the PRODUCT
   REVIEWS section above), with the shared ".pager" (styled above) immediately following the last
   item - previously with no top spacing of its own, so the pager pills sat flush against the last
   review's bottom edge. Same fix as ".order-list-page .pager" above: a page-scoped margin-top. */
.my-product-reviews-list-page .pager { margin-top: 24px; }

/* Desktop: lay ".order-list" out as a 2-column grid (unlike ".address-list"'s 3-column grid) -
   the existing ".order-item" rules above (title/info/buttons, all unconditional now that the
   buttons are small top-right icons rather than full-width text links) are untouched below
   768px, where ".order-list" stays plain block flow and each card's own "margin-bottom"
   (from the base ".order-item" rule above) is what spaces the stacked rows.

   BUG FIX (uneven card heights): at this breakpoint ".order-list" becomes a grid, and grid's
   default "align-items: stretch" stretches every item's MARGIN box to fill its row track, then
   subtracts that item's own margin to get its border-box (card) height. Left relying on each
   card's own 24px margin-bottom for the row gap (as this rule used to), that's fine for every
   card EXCEPT the very last one overall - ".order-item:last-child" zeroes its margin-bottom (to
   avoid a trailing gap below the final row), so in the last row that card's stretched margin box
   keeps its full row-track height with nothing subtracted, while its row-sibling still loses 24px
   to its own margin - the two cards in that last row end up different heights even though their
   content is identical (see WISHLIST/ORDER HISTORY PAGE testing). Fixed the same way
   ".address-list-page .address-list" already avoids this below: gap on the grid container instead
   of margin on each item, with the item's own margin-bottom zeroed out at this breakpoint so it
   never factors into stretch at all. */
@media (min-width: 768px) {
  .order-list-page .order-list {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    column-gap: 30px;
    row-gap: 24px;
  }
  .order-list-page .order-item { margin-bottom: 0; }
}

/* =========================== ADDRESS LIST PAGE ===========================
   Core's stock Nop.Web/Views/Customer/Addresses.cshtml (unmodified) renders each address as
   "<div class="section address-item"><h2 class="title">Name</h2><ul class="info">...</ul>
   <div class="buttons"><button class="button-2 edit-address-button">Edit</button>
   <button class="button-2 delete-address-button">Delete</button></div></div>" inside
   "<div class="address-list">". Laid out here as a 3-column grid (1 column under 768px); each
   ".address-item" gets its own bordered card, and the Edit/Delete buttons - each "font-size: 0"
   rather than removed, so a screen reader still announces "Edit"/"Delete" - become icon-only
   controls pinned to the card's top-right corner via the same "position: absolute against a
   position: relative card" + mask-image technique used for .order-list-page's buttons/icons
   above. */
.address-list-page .address-list {
  display: grid;
  grid-template-columns: 1fr;
  gap: 20px;
  margin: 0 0 24px;
  padding: 0;
  list-style: none;
}

.address-list-page .address-item {
  position: relative;
  margin: 0;
  border: 1px solid var(--pdx-border);
  border-radius: var(--pdx-radius-sm);
  padding: 20px;
  background: var(--pdx-surface);
}

.address-list-page .address-item .title {
  margin: 0 0 12px;
  padding-right: 64px;
  font-size: 18px;
  font-weight: 700;
  color: var(--pdx-text);
}

.address-list-page .info {
  list-style: none;
  margin: 0;
  padding: 0;
  font-size: 14px;
  line-height: 1.7;
  color: var(--pdx-text-muted);
}

.address-list-page .buttons {
  position: absolute;
  top: 16px;
  right: 16px;
  display: flex;
  gap: 2px;
  margin: 0;
}

.address-list-page .button-2 {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  padding: 0;
  border: none;
  border-radius: var(--pdx-radius-sm);
  background: transparent;
  font-size: 0;
  line-height: 0;
  color: var(--pdx-text-muted);
  cursor: pointer;
}
.address-list-page .button-2::before {
  content: "";
  display: block;
  width: 16px;
  height: 16px;
  background-color: currentColor;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-position: center;
  mask-position: center;
  -webkit-mask-size: contain;
  mask-size: contain;
}

.address-list-page .edit-address-button { color: var(--pdx-text); }
.address-list-page .edit-address-button:hover { background: color-mix(in srgb, var(--pdx-text) 8%, transparent); }
.address-list-page .edit-address-button::before {
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 20h9M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4L16.5 3.5z' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 20h9M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4L16.5 3.5z' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}

.address-list-page .delete-address-button { color: var(--pdx-primary); }
.address-list-page .delete-address-button:hover { background: color-mix(in srgb, var(--pdx-primary) 10%, transparent); }
.address-list-page .delete-address-button::before {
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M3 6h18M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2m3 0v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6h14zM10 11v6M14 11v6' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M3 6h18M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2m3 0v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6h14zM10 11v6M14 11v6' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}

.address-list-page .add-button { margin: 0; text-align: left; }

@media (min-width: 768px) {
  .address-list-page .address-list { grid-template-columns: repeat(3, 1fr); }
}

/* My account > Testimonials (Nop.Plugin.Prodigix.Testimonials' Views/Testimonial/Index.cshtml)
   reuses this same ".address-list-page"/".address-list"/".address-item" card markup (same shape
   as the real Addresses page above), so it inherits all of the card/button styling above for free.
   It's tagged with an extra "testimonial-list-page" class (added alongside "address-list-page",
   not instead of it) so its grid can be overridden to 2 columns - matching the Order History
   page's 2-column layout (see ".order-list-page .order-list" above) - without touching the real
   3-column Addresses page, which shares the exact same "address-list-page"/"address-list" classes.
   Declared after the 3-column rule above so it wins for this page. */
@media (min-width: 768px) {
  .testimonial-list-page .address-list { grid-template-columns: repeat(2, 1fr); }
}

/* =========================== ADDRESS EDIT PAGE ===========================
   Matches .customer-info-page's label/input layout (required asterisk pulled up next to the
   label via flex "order", left-aligned with the "My Account" page title) - see that section's
   comments for the general mechanism. Core's Nop.Web/Views/Customer/AddressEdit.cshtml +
   Views/Shared/_CreateOrUpdateAddress.cshtml (both unmodified) don't use the ".fieldset"/
   ".form-fields"/h2-".title" wrapper .customer-info-page has - the address fields sit directly in
   "<div class="edit-address">", and "<div class="buttons">" is a sibling of that at the
   ".page-body" level (same relationship .customer-info-page's ".buttons" has to its last
   ".fieldset") - so this reuses the same ".inputs" pattern without needing a fieldset shell.
   ".option-list" is Views/Shared/_AddressAttributes.cshtml's radio/checkbox list for custom
   address attributes (store-dependent; may not exist for every store), included alongside
   input/select/textarea so it also gets pushed to its own full-width row under the label. */
.address-edit-page .page-body { display: flex; flex-direction: column; gap: 20px; }

.address-edit-page .edit-address { max-width: 480px; }

.address-edit-page .inputs {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  column-gap: 6px;
  margin-bottom: 20px;
}
.address-edit-page .inputs:last-child { margin-bottom: 0; }
.address-edit-page .inputs > label {
  order: 1;
  margin-bottom: 6px;
  font-size: 14px;
  font-weight: 600;
  color: var(--pdx-text);
}
.address-edit-page .inputs > .required {
  order: 2;
  margin: 0 0 6px;
  font-size: 13px;
  font-weight: 700;
  color: var(--pdx-danger);
}
.address-edit-page .inputs > *:not(label):not(.required) { order: 3; flex: 1 1 100%; }
.address-edit-page .inputs .field-validation-error {
  display: block;
  margin-top: 4px;
  font-size: 12px;
  color: var(--pdx-danger);
}

.address-edit-page .buttons { display: flex; justify-content: flex-start; margin-top: 4px; }
.address-edit-page .save-address-button { padding: 13px 32px; }

/* =========================== ACCOUNT DATA TABLES ===========================
   Reward Points History (/rewardpoints/history), Recurring Payments (/customer/recurringpayments),
   Downloadable Products, and Back In Stock Subscriptions - four core Nop.Web account pages, none
   overridden by this theme, that each render their own "<div class="table-wrapper"><table
   class="data-table">...</table></div>" (same wrapper/table class names /cart's own table and
   .customer-info-page's Associated External Auth table already use - see ".table-wrapper" further
   above for the shared bordered-card surface every one of these gets for free, and
   ".customer-info-page .data-table" for the precedent this section follows: no sitewide generic
   ".data-table" rule exists, every page styles its own th/td directly).

   Styled here to match "table.cart"'s desktop look specifically (uppercase muted header row on
   var(--pdx-body-bg), border-top dividers between rows, 16px cell padding, 14px body text) per
   request, rather than the more compact ".customer-info-page .data-table" variant. None of these
   four core views render a per-cell ".td-title" label span the way table.cart/.order-details-page
   .data-table do, so replicating THEIR mobile "stack into labeled rows" behavior isn't possible
   without new theme view overrides for all four pages just to add that markup; instead, each gets
   ".table-wrapper { overflow-x: auto; }" at its own page scope so a wide table scrolls horizontally
   on narrow screens rather than squeezing/breaking - the same fallback ".customer-info-page" itself
   already uses for its own (also label-less) table. */

/* --- Reward Points History: "date"/"points"/"points-balance"/"message"/"endDate" columns --- */
.reward-points-page .table-wrapper { overflow-x: auto; }
.reward-points-page .data-table { width: 100%; border-collapse: collapse; }
.reward-points-page .data-table thead th {
  padding: 14px 16px;
  background: var(--pdx-body-bg);
  border-bottom: 1px solid var(--pdx-border);
  color: var(--pdx-text-muted);
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .03em;
  text-align: left;
  white-space: nowrap;
}
.reward-points-page .data-table thead th.points,
.reward-points-page .data-table thead th.points-balance { text-align: center; }
.reward-points-page .data-table tbody tr { border-top: 1px solid var(--pdx-border); }
.reward-points-page .data-table tbody tr:first-child { border-top: none; }
.reward-points-page .data-table tbody td { padding: 16px; vertical-align: middle; font-size: 14px; color: var(--pdx-text); }
.reward-points-page .data-table tbody td.points,
.reward-points-page .data-table tbody td.points-balance { text-align: center; font-weight: 600; }
.reward-points-page .data-table tbody td.message { color: var(--pdx-text-muted); }

/* --- Recurring Payments: core's Views/Order/CustomerRecurringPayments.cshtml renders this page
   with the SAME "order-list-page" page class as the real Order History page (core's own choice,
   not this theme's) - safe to scope plain ".order-list-page .data-table" below since the real
   Order History page has no ".data-table" of its own (it's card-based, see ORDER HISTORY PAGE
   above), so nothing there can collide with these rules. Columns: start-date/cycle-info/
   next-payment/total-cycles/cycles-remaining/initial-order, plus optional retry/cancel action
   columns (each only rendered when at least one row can retry/cancel, per core's own @if). */
.order-list-page .data-table { width: 100%; border-collapse: collapse; }
.order-list-page .data-table thead th {
  padding: 14px 16px;
  background: var(--pdx-body-bg);
  border-bottom: 1px solid var(--pdx-border);
  color: var(--pdx-text-muted);
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .03em;
  text-align: left;
  white-space: nowrap;
}
.order-list-page .data-table thead th.total-cycles,
.order-list-page .data-table thead th.cycles-remaining,
.order-list-page .data-table thead th.retry,
.order-list-page .data-table thead th.cancel { text-align: center; }
.order-list-page .data-table tbody tr { border-top: 1px solid var(--pdx-border); }
.order-list-page .data-table tbody tr:first-child { border-top: none; }
.order-list-page .data-table tbody td { padding: 16px; vertical-align: middle; font-size: 14px; color: var(--pdx-text); }
.order-list-page .data-table tbody td.total-cycles,
.order-list-page .data-table tbody td.cycles-remaining,
.order-list-page .data-table tbody td.retry,
.order-list-page .data-table tbody td.cancel { text-align: center; }
.order-list-page .data-table .button-2 { padding: 8px 14px; font-size: 12px; white-space: nowrap; }
/* Cancel is destructive - same solid-danger-red exception the Cancel Order button on
   .order-details-page's page-title already uses, rather than the theme's normal button fill. */
.order-list-page .data-table .cancel-recurring-order-button { background: var(--pdx-danger); color: var(--pdx-button-text); }
.order-list-page .data-table .cancel-recurring-order-button:hover { filter: brightness(0.88); }

/* --- Downloadable Products: "order"/"date"/"product"/"download" columns --- */
.downloadable-products-page .table-wrapper { overflow-x: auto; }
.downloadable-products-page .data-table { width: 100%; border-collapse: collapse; }
.downloadable-products-page .data-table thead th {
  padding: 14px 16px;
  background: var(--pdx-body-bg);
  border-bottom: 1px solid var(--pdx-border);
  color: var(--pdx-text-muted);
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .03em;
  text-align: left;
  white-space: nowrap;
}
.downloadable-products-page .data-table tbody tr { border-top: 1px solid var(--pdx-border); }
.downloadable-products-page .data-table tbody tr:first-child { border-top: none; }
.downloadable-products-page .data-table tbody td { padding: 16px; vertical-align: middle; font-size: 14px; color: var(--pdx-text); }
.downloadable-products-page .data-table td.product a { font-weight: 600; color: var(--pdx-text); }
.downloadable-products-page .data-table td.product a:hover { color: var(--pdx-primary); }
.downloadable-products-page .data-table td.product .attributes { margin-top: 4px; font-size: 12px; color: var(--pdx-text-muted); }
.downloadable-products-page .data-table td.download > div + div { margin-top: 4px; }
.downloadable-products-page .data-table td.download a { font-weight: 600; }

/* --- Back In Stock Subscriptions: "select-boxes" (checkbox)/"product" columns --- */
.back-in-stock-subscription-list-page .description { margin-bottom: 16px; font-size: 14px; color: var(--pdx-text-muted); }
.back-in-stock-subscription-list-page .table-wrapper { overflow-x: auto; }
.back-in-stock-subscription-list-page .data-table { width: 100%; border-collapse: collapse; }
.back-in-stock-subscription-list-page .data-table thead th {
  padding: 14px 16px;
  background: var(--pdx-body-bg);
  border-bottom: 1px solid var(--pdx-border);
  color: var(--pdx-text-muted);
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .03em;
  text-align: left;
}
.back-in-stock-subscription-list-page .data-table thead th.select-boxes,
.back-in-stock-subscription-list-page .data-table tbody td.select-boxes { text-align: center; width: 48px; }
.back-in-stock-subscription-list-page .data-table tbody tr { border-top: 1px solid var(--pdx-border); }
.back-in-stock-subscription-list-page .data-table tbody tr:first-child { border-top: none; }
.back-in-stock-subscription-list-page .data-table tbody td { padding: 16px; vertical-align: middle; font-size: 14px; color: var(--pdx-text); }
.back-in-stock-subscription-list-page .data-table tbody td.select-boxes input[type="checkbox"],
.back-in-stock-subscription-list-page .data-table thead th.select-boxes input[type="checkbox"] { width: 18px; height: 18px; margin: 0; accent-color: var(--pdx-primary); }
.back-in-stock-subscription-list-page .data-table td.product a { font-weight: 600; color: var(--pdx-text); }
.back-in-stock-subscription-list-page .data-table td.product a:hover { color: var(--pdx-primary); }
.back-in-stock-subscription-list-page .buttons { margin-top: 16px; }

/* =========================== ORDER DETAILS PAGE ===========================
   Matches /cart's product-table and order-totals-box treatment (see "table.cart"/".cart-footer
   .totals" above). Core's Nop.Web/Views/Order/Details.cshtml (unmodified) is its own hand-rolled
   markup, not the shared OrderSummary component /cart and checkout-confirm use - so none of that
   existing CSS reaches this page on its own. It happens to reuse several of the SAME class names
   as "table.cart" for the Product(s) line-item table ("<table class="data-table">" here vs
   "table.cart" there, but matching "td.product"/"td.unit-price"/"td.quantity"/".vendor-name"/
   ".product-unit-price"/".product-quantity"/".product-subtotal" cell classes, and the same mobile
   "td-title" label pattern) and an entirely separate "<table class="cart-total">" for the totals,
   which already gets cart's row styling for free (that rule isn't scoped to .cart-page) - it's
   only missing the bordered card the totals table sits in on /cart, added below via
   ".order-details-page .section.totals" directly (no separate ".total-info" card needed here since
   ".actions" - the Reorder/Return Items buttons - is the only other child, so the whole ".totals"
   section becomes the card, mirroring ".cart-footer .totals" 1:1). ".data-table" itself is left
   unscoped-generic on purpose - .customer-info-page already uses that class for its own, much
   narrower Associated-External-Auth table, so every rule below is scoped to
   ".order-details-page .data-table" specifically.

   Header/overview/address-columns treatment below is modeled on the reference Flexo theme's own
   order-details page (ClaudeWorkingFolder\Themes\Flexo, local-only, never deployed - see that
   theme's styles.css ".order-details-page .page-title"/".order-overview"/".order-details-area"
   rules, ~line 6110 there): the Print/PDF/Cancel links and the Order #/date/status/total summary
   are centered under the page title instead of left-aligned, and the billing/shipping cards
   (already boxed via the unscoped ".billing-info-wrap, .shipping-info-wrap" rule shared with
   /cart + checkout-confirm above) sit side by side in a 2-up row instead of stacking full-width -
   same "flex: 1 1 320px" children, just given an actual flex row to sit in via
   ".order-details-area" (Flexo does this with float/percentage widths at its own >=768px
   breakpoint; reproduced here with flex-wrap so it flows continuously instead of snapping at one
   fixed width, matching how ".order-review-data" already handles the identical cards on /cart).
   Unlike Flexo's own black/white outline treatment for these buttons, Print/PDF Invoice are kept
   on the theme's normal ".button-1"/".button-2" primary-color fill (var(--pdx-button-bg), same as
   Reorder below and every other button on the site) - only their size/spacing is customized here
   to sit as a compact, centered pair under the title instead of Flexo's own colors. */
.order-details-page .page-title { text-align: center; }
.order-details-page .page-title h1 { margin: 0 0 20px; }

.order-details-page .page-title .button-2 {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 140px;
  height: 40px;
  margin: 0 6px 10px;
  padding: 0 24px;
  font-size: 13px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .04em;
}
/* Cancel is destructive, so it's the one exception to the shared primary-color fill above - solid
   danger-red instead of the site's primary blue, same "filled button, no border" shape otherwise. */
.order-details-page .page-title .cancel-order-button {
  background: var(--pdx-danger);
  color: var(--pdx-button-text);
}
.order-details-page .page-title .cancel-order-button:hover {
  filter: brightness(0.88);
}

.order-details-page .order-overview-content li { font-size: 14px; color: var(--pdx-text-muted); line-height: 1.8; }
.order-details-page .order-overview-content .order-total strong { color: var(--pdx-text); }

.order-details-page .order-details-area {
  display: flex;
  flex-wrap: wrap;
  gap: 24px;
}

.order-details-page .section .title {
  text-align: left;
  margin-bottom: 16px;
  color: var(--pdx-text);
}

/* .order-overview = "Order #X" + the order-date/status/total list, sitting between the Print/PDF
   buttons (inside .page-title, above) and the billing/shipping boxes (.order-details-area, below)
   - margin on both sides since it has no border/background of its own to visually separate it. */
.order-details-page .order-overview { margin: 20px 0 24px; text-align: center; }

/* Space between the billing/shipping boxes now comes from ".order-details-area"'s own "gap: 24px"
   (added above) - it handles both the row gap between the two side-by-side cards on wide screens
   and the gap between stacked rows once they wrap on narrow ones, so no per-card margin is needed.
   ".order-details-area" keeps its own margin-bottom for the space before "Product(s)". */
.order-details-page .order-details-area { margin-bottom: 24px; }

.order-details-page .data-table { width: 100%; border-collapse: collapse; }

.order-details-page .data-table thead th {
  padding: 14px 16px;
  background: var(--pdx-body-bg);
  border-bottom: 1px solid var(--pdx-border);
  color: var(--pdx-text-muted);
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .03em;
  text-align: left;
}
.order-details-page .data-table thead th.picture,
.order-details-page .data-table thead th.price,
.order-details-page .data-table thead th.quantity,
.order-details-page .data-table thead th.total { text-align: center; }

.order-details-page .data-table tbody tr { border-top: 1px solid var(--pdx-border); }
.order-details-page .data-table tbody tr:first-child { border-top: none; }
.order-details-page .data-table tbody td { padding: 16px; vertical-align: middle; font-size: 14px; }
.order-details-page .data-table tbody td.picture,
.order-details-page .data-table tbody td.unit-price,
.order-details-page .data-table tbody td.quantity,
.order-details-page .data-table tbody td.total { text-align: center; }

.order-details-page .data-table th.product,
.order-details-page .data-table td.product { width: auto; }
.order-details-page .data-table th.vendor,
.order-details-page .data-table td.vendor { width: 14%; }
.order-details-page .data-table th.price,
.order-details-page .data-table td.unit-price { width: 14%; }
.order-details-page .data-table th.quantity,
.order-details-page .data-table td.quantity { width: 120px; }
.order-details-page .data-table th.total,
.order-details-page .data-table td.total { width: 14%; }

.order-details-page .data-table .td-title { display: none; }

/* hidden rather than removed from core's markup, same as "table.cart .sku" above - keeps this
   page CSS-only and matches /cart's chosen look exactly (cart never shows a SKU column at all) */
.order-details-page .data-table .sku { display: none; }

.order-details-page .data-table td.picture img {
  width: 72px;
  height: 72px;
  max-width: none;
  object-fit: cover;
  border-radius: var(--pdx-image-radius, var(--pdx-radius));
  border: 1px solid var(--pdx-border);
}

.order-details-page .data-table td.product em { font-style: normal; }
.order-details-page .data-table td.product a { font-size: 14px; font-weight: 600; color: var(--pdx-text); }
.order-details-page .data-table td.product a:hover { color: var(--pdx-primary); }
.order-details-page .data-table .attributes,
.order-details-page .data-table .rental-info { margin-top: 6px; font-size: 12px; line-height: 1.6; color: var(--pdx-text-muted); }
.order-details-page .data-table .vendor-name { font-size: 13px; color: var(--pdx-text-muted); }
.order-details-page .data-table .product-unit-price,
.order-details-page .data-table .product-subtotal { font-weight: 700; color: var(--pdx-text); }
.order-details-page .data-table .download { margin-top: 6px; font-size: 12px; }
.order-details-page .data-table .download a { font-weight: 600; }

/* order totals card - same bordered-box-with-dashed-dividers treatment as ".cart-footer .totals"
   above; ".total-info" (the totals table) and ".actions" (Reorder/Return Items) are its only two
   possible children, so the whole ".section.totals" becomes the card rather than needing a
   separate inner wrapper. Right-aligned + capped at the same 420px width cart uses, since this
   page has no coupon/gift-card box to share the row with. */
.order-details-page .section.totals {
  max-width: 420px;
  margin: 0 0 24px auto;
  background: var(--pdx-surface);
  border: 1px solid var(--pdx-border);
  border-radius: var(--pdx-card-radius, var(--pdx-radius));
  overflow: hidden;
}
.order-details-page .section.totals > * { padding: 20px; }
.order-details-page .section.totals > * + * { border-top: 1px dashed var(--pdx-border); }

.order-details-page .actions { display: flex; flex-direction: column; gap: 10px; }
.order-details-page .actions .button-1,
.order-details-page .actions .button-2 { width: 100%; }
/* Reorder (".button-1", rendered first when both are allowed) stays the theme's solid primary
   button; Return Items (".button-2") gets the same outline treatment as the PDF/Print links in
   ".page-title" above so the two actions read as primary vs. secondary, matching Flexo's
   solid-first-button / outline-others convention for this same button group. */
.order-details-page .actions .button-2 {
  background: transparent;
  border: 1px solid var(--pdx-border);
  color: var(--pdx-text);
}
.order-details-page .actions .button-2:hover {
  background: var(--pdx-body-bg);
  border-color: var(--pdx-text);
  color: var(--pdx-text);
}

@media (max-width: 767px) {
  .order-details-page .section.totals { max-width: none; margin-left: 0; }

  /* space above "Product(s)" now that .order-details-area's own margin-bottom (added above)
     covers the general case - kept as its own mobile-only bump since the stacked billing/shipping
     boxes push everything down further here than on wider layouts. */
  .order-details-page .section.products { margin-top: 8px; }

  /* mobile: same card-of-stacked-rows conversion as "table.cart" below - thead is visually hidden
     and each td's own ".td-title" label takes its place. ".data-table tbody td" (2 type selectors)
     otherwise beats a plain ".data-table td" override here on specificity regardless of source
     order - CSS-in-media-query is still just CSS, media queries don't add specificity - so its
     "padding: 16px" (set once, above, for the desktop table) would otherwise keep winning here.
     Repeating "tbody" below is what actually lets this padding take over on mobile, and the
     smaller value (was 16px) is what pulls the image/name/price/quantity/total rows closer
     together within each item, per feedback that the stacked mobile rows read too spread out. */
  .order-details-page .data-table thead { display: none; }
  .order-details-page .data-table,
  .order-details-page .data-table tbody,
  .order-details-page .data-table tr,
  .order-details-page .data-table td { display: block; width: 100%; }
  .order-details-page .data-table tbody tr { padding: 14px; border-top: 1px solid var(--pdx-border); }
  .order-details-page .data-table tbody td { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 3px 0; text-align: right; }
  .order-details-page .data-table .td-title {
    display: inline-block;
    font-size: 12px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .03em;
    color: var(--pdx-text-muted);
  }
  .order-details-page .data-table td.picture { justify-content: center; padding-bottom: 8px; }
  .order-details-page .data-table td.product { display: block; text-align: left; padding: 4px 0; }
}

/* =========================== FOOTER =========================== */

.footer {
  background: var(--pdx-footer-bg);
  color: var(--pdx-footer-text);
}
.footer a { color: var(--pdx-footer-text); }
.footer a:hover { color: #fff; }

.footer-upper {
  max-width: var(--pdx-container);
  margin: 0 auto;
  padding: 40px 20px;
  display: flex;
  flex-wrap: wrap;
  gap: 32px;
}
.footer-block { flex: 1 1 200px; }
.footer-block .title { color: var(--pdx-footer-title-color, var(--pdx-footer-text)); font-size: 15px; opacity: .9; margin-bottom: 12px; }

/* logo column - always the first child of .footer-upper (see this theme's Footer/Default.cshtml
   override), to the left of the menu-builder columns and the follow-us/newsletter column, so the
   footer always shows the store logo regardless of how many menu columns an admin configures. */
.footer-block.footer-logo { flex: 0 1 200px; }
.footer-block.footer-logo img { max-width: 160px; height: auto; }

/*
  nopCommerce 4.90's footer menu builder (FooterMenuViewComponent) is a SEPARATE component from
  the old ".footer-block .title" structure above (which only ever covered the "Follow Us" block) -
  it renders <nav class="footer-navigation"><div class="footer-menu"><h2 class="footer-menu__title
  footer-menu__toggle">...<div class="footer-menu__list">...<div class="footer-menu__item">
  <a class="footer-menu__link">. This was never styled at all before, which is why
  --pdx-footer-title-color only affected the "Follow Us" heading and not the actual menu-builder
  footer columns. Mobile collapse/expand mirrors the main nav's .menu-dropdown--active pattern -
  core's own script already does `mainMenu.init('.footer-navigation .footer-menu__toggle',
  'footer-menu--active')` (see FooterMenu/Default.cshtml), toggling "footer-menu--active" on the
  parent .footer-menu; only the CSS reacting to that class was missing.
*/
.footer-navigation { display: flex; flex-wrap: wrap; gap: 32px; flex: 1 1 auto; }
.footer-menu { flex: 1 1 160px; }
.footer-menu__title {
  color: var(--pdx-footer-title-color, var(--pdx-footer-text));
  font-size: 15px;
  opacity: .9;
  margin-bottom: 12px;
  cursor: default;
}
.footer-menu__item { margin-bottom: 8px; }
.footer-menu__link { font-size: 14px; }

@media (max-width: 767px) {
  /* stack every menu-builder column full-width, one per row, directly under the logo (see this
     theme's Footer/Default.cshtml override for why the logo is always .footer-upper's first
     child) - core's own .footer-navigation is flex-wrap:wrap by default (see the base rule
     above), which on a narrow screen was cramming multiple .footer-menu columns side by side
     instead of stacking them. */
  .footer-navigation { flex-direction: column; gap: 0; width: 100%; }
  .footer-menu { width: 100%; flex: 1 1 auto; padding: 14px 0; }
  /* divider between consecutive sections (not before the first - the logo/icons above already
     supply their own separation via .footer-upper's gap) */
  .footer-menu + .footer-menu { border-top: 1px solid rgba(255, 255, 255, .1); }

  /* collapsed accordion on mobile - .footer-menu__toggle is the same element as
     .footer-menu__title, so the cursor/plus-minus indicator only make sense to add at this
     breakpoint. A plain "+"/"\2212" (minus) character pinned to the row's right edge via
     justify-content:space-between, rather than the main nav's rotated-chevron treatment
     (.menu__item-toggle::after further up this file) - matches the flat +/- style requested. */
  .footer-menu__title { margin-bottom: 0; }
  .footer-menu__toggle {
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
  }
  .footer-menu__toggle::after {
    content: "+";
    flex: 0 0 auto;
    font-size: 20px;
    line-height: 1;
    font-weight: 400;
  }
  .footer-menu--active .footer-menu__toggle::after { content: "\2212"; }
  .footer-menu__list { display: none; padding-top: 12px; }
  .footer-menu--active .footer-menu__list { display: block; }
}

/* Follow Us icons - circular icon-only buttons (see this theme's SocialButtons/Default.cshtml
   override, which swaps core's plain text links for inline SVG brand glyphs) - same rounded
   icon-button language used elsewhere in the theme (.product-item-icon, .flyout-cart-close,
   header search/account/wishlist/cart triggers), just sized down slightly (32px) and dark-on-
   footer instead of surface-on-light, since these sit on the dark --pdx-footer-bg rather than a
   white card. */
.follow-us .social { margin-bottom: 20px; }
.networks { display: flex; flex-wrap: wrap; gap: 10px; }
.networks li { list-style: none; }
.networks a {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  background: rgba(255, 255, 255, .08);
  color: var(--pdx-footer-text);
}
.networks a:hover { background: var(--pdx-primary); color: #fff; }
.networks svg { display: block; pointer-events: none; }

@media (max-width: 767px) {
  /* "Follow Us" heading text disappears on mobile - only the (already-conditional, see this
     theme's Footer/Default.cshtml override) enabled social icons remain visible, no label above
     them. .follow-us .social itself is untouched (still renders/hidden the same way it does on
     desktop depending on whether any network link is actually set), just its own heading text. */
  .follow-us .social .title { display: none; }
}

/* Newsletter signup (Views/Shared/Components/NewsletterBox/Default.cshtml, core, unmodified) -
   core lays the email input and "Subscribe" button out as plain adjacent siblings inside
   ".newsletter-email" with no spacing between them; since input[type="email"] is set to
   width:100% by this theme's own base input rule (see BASE section), the button wraps onto its
   own line directly under the input with no gap at all otherwise. flex-direction:column + gap
   adds that spacing regardless of how the two end up stacking; align-items:flex-start keeps the
   button at its own natural (unstretched) width rather than being forced to the column's full
   width by flex's default "stretch" behavior - the input still reaches full width on its own via
   its existing width:100% rule, so only the button's sizing needed this override. */
.newsletter-email { display: flex; flex-direction: column; align-items: flex-start; gap: 12px; }

.footer-lower {
  border-top: 1px solid rgba(255, 255, 255, .1);
  max-width: var(--pdx-container);
  margin: 0 auto;
  padding: 18px 20px;
  display: flex;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 8px;
  font-size: 13px;
  opacity: .85;
}

@media (max-width: 767px) {
  .footer-upper { flex-direction: column; gap: 24px; padding: 28px 20px; }
  /* .footer-block's flex-basis (200px, set to size these as fixed-WIDTH columns in the desktop
     row layout - see the base ".footer-block"/".footer-block.footer-logo" rules above) becomes a
     fixed HEIGHT once flex-direction switches to column here - flex-basis always sizes along
     whichever axis is the container's current main axis, so the same 200px that used to mean
     "this column is 200px wide" now means "this block is 200px tall", regardless of how little
     content it actually has. That's what was leaving a large empty gap under the logo (whose
     .footer-block.footer-logo carries the 200px basis) and under the follow-us icons (whose
     plain .footer-block also carries it). Resetting both back to flex-basis:auto lets each
     block's height come from its actual content instead - ".footer-block.footer-logo" needs its
     own explicit override here since it's a more specific selector than the base ".footer-block"
     rule and would otherwise keep winning even inside this same media query. */
  .footer-block,
  .footer-block.footer-logo { flex-basis: auto; }
  .footer-lower { flex-direction: column; text-align: center; }
}

/* =========================== ACCESSIBILITY =========================== */

.skip {
  position: absolute;
  left: -9999px;
  top: auto;
}
.skip:focus {
  position: static;
  display: inline-block;
  padding: 8px 12px;
  background: var(--pdx-primary);
  color: #fff;
}
