/* =====================================================================
   QALAM E MANSOORI — LUXURY DESIGN SYSTEM
   Editorial, quiet-luxury visual language for a bespoke calligraphy atelier.
   Palette: warm ivory + deep charcoal + gold accent (NOT all-black).
===================================================================== */

:root {
  --ivory: #f6f2ea;
  --ivory-deep: #efe8da;
  --charcoal: #2a2620;
  --charcoal-soft: #4a463d;
  --black: #161410;
  --gold: #a9772f;
  --gold-light: #c99a4f;
  --gold-pale: #e7d3ac;
  --border: rgba(42, 38, 32, 0.12);
  --border-strong: rgba(169, 119, 47, 0.4);

  --font-head: 'Cormorant Garamond', Georgia, serif;
  --font-body: 'Jost', sans-serif;

  --transition: 0.35s cubic-bezier(0.25, 0.46, 0.45, 0.94);
  --container: 1240px;
}

/* ---------------------------------------------------------------------
   RESET / BASE
--------------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }

/* Defensive overflow containment — on phones a stray sub-pixel from a grid
   gap, a marquee track, or a fixed-position element can push document
   width a few px past the viewport, showing up as a thin scrollable strip
   on the right edge. Clipping it here is standard practice and harmless. */
html { overflow-x: hidden; max-width: 100%; }

body {
  background: var(--ivory);
  color: var(--charcoal);
  font-family: var(--font-body);
  font-weight: 300;
  line-height: 1.7;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
  max-width: 100%;
  position: relative;
}

/* GeneratePress ships a "separate containers" / sidebar-reserved layout
   mode (body classes like right-sidebar, separate-containers,
   header-aligned-left get added automatically from the Customizer's
   layout settings even though this child theme's templates never use a
   sidebar). That mode treats #primary as a floating "card" narrower than
   the viewport, leaving a margin around it that shows GeneratePress's own
   neutral off-white background instead of this theme's ivory — visible on
   phones as a persistent grey/blank strip down one edge of every section,
   including the full-bleed dark hero. Since every template here is fully
   custom and always full-width, force the content column back to 100%
   and make the base background match ours everywhere as a safety net. */
html, body { background: var(--ivory); }
#primary,
.site-main,
.site-content,
#content,
.inside-article {
  width: 100% !important;
  max-width: 100% !important;
  margin-left: 0 !important;
  margin-right: 0 !important;
  padding-left: 0 !important;
  padding-right: 0 !important;
  float: none !important;
}

/* Form fields and buttons default to an intrinsic min-width in flex/grid
   rows (this is what caused the newsletter form to push the whole page
   wider than the screen on phones — see NEWSLETTER section below). Reset
   that globally so no input/button can force horizontal overflow. */
input, select, textarea, button { min-width: 0; max-width: 100%; }

/* Defensive: flex-wrap alone doesn't reliably wrap children on mobile —
   flex items default to min-width:auto (their content's intrinsic width),
   which can silently prevent wrapping and push the whole row past the
   viewport, especially once a web font swaps in and text metrics change
   after initial layout. Applies min-width:0 to direct children of every
   flex-wrap row in this stylesheet so they can always wrap/shrink. */
.qem-hero-stats > *,
.qem-hero-btns > *,
.qem-promo-inner > *,
.qem-filter-tabs > *,
.qem-product-trust-badges > *,
.qem-contact-details > *,
.qem-footer-bottom > * {
  min-width: 0;
}

a { text-decoration: none; color: inherit; }
img { max-width: 100%; height: auto; display: block; }

h1, h2, h3, h4 {
  font-family: var(--font-head);
  font-weight: 500;
  color: var(--charcoal);
  line-height: 1.2;
}

.qem-container {
  max-width: var(--container);
  margin: 0 auto;
  padding: 0 28px;
}

.qem-eyebrow {
  font-size: 0.68rem;
  font-weight: 500;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--gold);
  margin-bottom: 12px;
  display: block;
}

.qem-section-title {
  font-size: clamp(1.9rem, 3.6vw, 2.8rem);
}
.qem-section-title em { font-style: italic; color: var(--gold); }

.qem-section-header {
  text-align: center;
  max-width: 600px;
  margin: 0 auto 56px;
}

.qem-gold-line {
  width: 46px;
  height: 1px;
  background: var(--gold);
  margin: 0 auto 20px;
}

/* ---------------------------------------------------------------------
   BUTTONS
--------------------------------------------------------------------- */
.qem-btn-primary,
.woocommerce a.button,
.woocommerce button.button,
.woocommerce #respond input#submit {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  background: var(--charcoal);
  color: var(--ivory) !important;
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  padding: 15px 32px;
  border: 1px solid var(--charcoal) !important;
  border-radius: 0 !important;
  cursor: pointer;
  transition: var(--transition);
}
.qem-btn-primary:hover,
.woocommerce a.button:hover,
.woocommerce button.button:hover {
  background: var(--gold) !important;
  border-color: var(--gold) !important;
  color: var(--black) !important;
}

.qem-btn-outline {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  background: transparent;
  color: var(--charcoal);
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  padding: 14px 30px;
  border: 1px solid var(--border-strong);
  cursor: pointer;
  transition: var(--transition);
}
.qem-btn-outline:hover { border-color: var(--gold); color: var(--gold); }

/* ---------------------------------------------------------------------
   NAVIGATION (overrides GeneratePress menu defaults)
--------------------------------------------------------------------- */
#site-navigation,
.main-navigation {
  background: var(--black) !important;
  border-bottom: 1px solid rgba(231, 211, 172, 0.15);
}
/* Our header is fixed to the true viewport top, so when a logged-in admin
   is viewing the front end WordPress's own fixed admin toolbar (#wpadminbar)
   sits on top of it at the same position — push the header down by the
   toolbar's height so it's never hidden behind it. Only applies when
   logged in; visitors never see this. */
body.admin-bar .main-navigation { top: 32px !important; }
@media screen and (max-width: 782px) {
  body.admin-bar .main-navigation { top: 46px !important; }
}
.main-navigation a {
  font-family: var(--font-body);
  font-size: 0.68rem;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ivory) !important;
}
.main-navigation a:hover { color: var(--gold-light) !important; }
.site-logo .site-title,
.site-title a {
  font-family: var(--font-head) !important;
  font-weight: 600 !important;
  color: var(--ivory) !important;
}

/* ---------------------------------------------------------------------
   MOBILE NAVIGATION
   The header markup already renders a .menu-toggle button and wraps the
   menu in <nav class="main-nav-menu"> (see header.php); main.js already
   toggles a "qem-nav-open" class on click. What was missing entirely was
   the CSS to actually collapse the menu into a hamburger below this
   breakpoint — without it, all nav links tried to fit on one line and
   either overflowed or wrapped illegibly on phones.
--------------------------------------------------------------------- */
@media (max-width: 860px) {
  .qem-container { flex-wrap: nowrap; }
  .menu-toggle { display: flex !important; z-index: 1001; }
  .main-nav-menu {
    position: fixed;
    top: 93px; /* sits below the header row instead of using padding-top,
                  which (combined with box-sizing:border-box) would force
                  a minimum rendered height even at max-height:0 and paint
                  a black box straight over the logo */
    left: 0;
    right: 0;
    max-height: 0;
    overflow: hidden;
    background: var(--black);
    transition: max-height .35s ease;
    z-index: 1000;
  }
  .main-nav-menu.qem-nav-open { max-height: calc(100vh - 93px); overflow-y: auto; }
  .nav-links {
    flex-direction: column !important;
    gap: 0 !important;
    padding: 6px 28px 28px !important;
  }
  .nav-links li { width: 100%; }
  .nav-links a { display: block; padding: 15px 0; border-bottom: 1px solid rgba(231, 211, 172, 0.12); }
  .menu-toggle span { transition: transform .25s ease, opacity .25s ease; }
  .menu-toggle[aria-expanded="true"] span:nth-child(1) { transform: translateY(6px) rotate(45deg); }
  .menu-toggle[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
  .menu-toggle[aria-expanded="true"] span:nth-child(3) { transform: translateY(-6px) rotate(-45deg); }
  body.admin-bar .main-nav-menu { top: 139px; }
}

/* Breadcrumbs */
.qem-breadcrumbs { padding: 18px 0; font-size: 0.72rem; color: var(--charcoal-soft); }
.qem-breadcrumbs ol { list-style: none; display: flex; gap: 6px; padding: 0; margin: 0; }
.qem-breadcrumbs a { color: var(--gold); }
.qem-breadcrumbs li:not(:last-child)::after { content: '/'; margin-left: 6px; color: var(--border-strong); }

/* ---------------------------------------------------------------------
   HERO
--------------------------------------------------------------------- */
.qem-hero {
  position: relative;
  min-height: 92vh;
  display: flex;
  align-items: center;
  overflow: hidden;
  background: var(--black);
}

/* Cinematic crossfade background — a stack of full-bleed photos/video, one
   slide at a time faded in via .is-active (see initHeroCrossfade in
   main.js). Deliberately slow (see the transition duration below) so
   scenes dissolve into each other rather than cutting or sliding — that
   slow dissolve is what reads as "expensive" rather than a cheap slider. */
.qem-hero-bg-stack { position: absolute; inset: 0; z-index: 0; background: var(--black); }
.qem-hero-bg-slide {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity 1.8s ease;
}
.qem-hero-bg-slide.is-active { opacity: 1; }
.qem-hero-bg-slide img,
.qem-hero-bg-slide video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* These are tall, portrait framed-art photos being cropped into a much
     wider/shorter hero band, so *some* top/bottom crop is unavoidable with
     object-fit:cover. Plain "center" cut into the top of the frame; an
     earlier attempt at 15% overcorrected and cut into the bottom of the
     frame instead. 32% splits the difference — keeps the full frame (or
     very close to it) in view top and bottom on most viewport ratios. */
  object-position: center 32%;
}
/* Left-to-right darkening so the eyebrow/heading/CTA text on the left
   stays legible no matter how bright the underlying photo is, while the
   right side of each photo stays visible. */
.qem-hero-bg-stack::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 1;
  background:
    linear-gradient(90deg, rgba(10, 9, 8, 0.82) 0%, rgba(10, 9, 8, 0.55) 38%, rgba(10, 9, 8, 0.15) 65%, rgba(10, 9, 8, 0.35) 100%),
    linear-gradient(0deg, rgba(10, 9, 8, 0.45) 0%, transparent 30%);
}

.qem-hero-content {
  position: relative;
  z-index: 2;
  display: grid;
  grid-template-columns: 1fr;
  gap: 60px;
  align-items: center;
  /* .qem-hero-content also carries the .qem-container class, which sets
     padding: 0 28px for the standard page gutter. Because this rule is
     declared AFTER .qem-container in the stylesheet with equal
     specificity, its padding shorthand used to win outright — including
     the 0 left/right values — silently zeroing out the gutter only on
     the hero. That's why hero text/stats sat pinned flush against the
     screen edges (looked "cut off") while every other section, which
     just uses plain .qem-container, kept its normal padding. Using
     padding-top/bottom only here (instead of the shorthand) leaves
     .qem-container's left/right padding untouched. */
  padding-top: 90px;
  padding-bottom: 60px;
  /* .qem-hero is display:flex; without this, a flex item with no
     flex-grow shrinks to fit its own content's intrinsic width instead
     of filling the row. That shrunk box then gets auto-centered (extra
     space becomes left/right margin) while its own children (which
     assume they have the full row to lay out in) push past its right
     edge — clipped by .qem-hero's overflow:hidden. Net visual effect:
     the whole hero block appears shifted right with a gap on the left
     and content cut off on the right, especially on mobile single-
     column layout. Forcing full width removes the shrink-to-fit. */
  width: 100%;
  max-width: 100%;
  box-sizing: border-box;
}
.qem-hero-text { max-width: 620px; }
.qem-hero-eyebrow {
  display: flex; align-items: center; gap: 12px;
  font-size: 0.62rem; letter-spacing: 0.28em; text-transform: uppercase;
  color: var(--gold-pale); margin-bottom: 18px;
}
.qem-hero-eyebrow::before { content: ''; width: 30px; height: 1px; background: var(--gold-pale); }
.qem-hero-title {
  font-size: clamp(2.4rem, 5vw, 3.8rem);
  font-weight: 400;
  margin-bottom: 20px;
  color: #fff;
  text-shadow: 0 2px 24px rgba(0, 0, 0, 0.35);
}
.qem-hero-title em { font-style: italic; color: var(--gold-pale); }
.qem-hero-desc { font-size: 0.92rem; color: rgba(255, 255, 255, 0.82); max-width: 420px; margin-bottom: 30px; }
.qem-hero-btns { display: flex; gap: 16px; flex-wrap: wrap; margin-bottom: 34px; }
.qem-hero-stats { display: flex; flex-wrap: wrap; gap: 34px; padding-top: 26px; border-top: 1px solid rgba(255, 255, 255, 0.22); max-width: 100%; }
.qem-hero-stats > div { min-width: 0; flex: 0 1 auto; }
.qem-hero-stat-num { font-family: var(--font-head); font-size: 1.7rem; color: var(--gold-pale); white-space: nowrap; }
.qem-hero-stat-label { font-size: 0.6rem; letter-spacing: 0.1em; text-transform: uppercase; color: rgba(255, 255, 255, 0.7); margin-top: 2px; white-space: nowrap; }

/* .qem-hero-stats is shared by the homepage hero (dark photo background,
   so pale gold + translucent-white read fine) and the About Us page (plain
   ivory background), where that same pale gold/white was invisible. The
   About page marks its copy of this block with .qem-stats-on-light so it
   gets dark, readable colours instead without touching the homepage hero. */
.qem-stats-on-light .qem-hero-stat-num { color: var(--gold); }
.qem-stats-on-light .qem-hero-stat-label { color: var(--charcoal-soft); }

/* .qem-btn-outline's global styling (dark charcoal text/border) assumes a
   light background — invisible against the hero's dark photo backdrop, so
   it's overridden to a light outline button only inside the hero. */
.qem-hero .qem-btn-outline { color: #fff; border-color: rgba(255, 255, 255, 0.55); }
.qem-hero .qem-btn-outline:hover { border-color: var(--gold-pale); color: var(--gold-pale); }

@media (max-width: 480px) {
  .qem-hero-stats { gap: 18px; }
}

.qem-hero-art { position: relative; display: flex; align-items: center; justify-content: center; }
.qem-hero-art-frame {
  position: relative; width: 100%; max-width: 440px; aspect-ratio: 3/4;
  background: linear-gradient(145deg, var(--charcoal) 0%, var(--black) 100%);
  display: flex; align-items: center; justify-content: center;
  box-shadow: 0 30px 70px rgba(22, 20, 16, 0.25);
}
.qem-hero-badge {
  position: absolute; bottom: -16px; left: 24px;
  background: var(--gold); color: var(--black);
  font-size: 0.6rem; font-weight: 600; letter-spacing: 0.14em; text-transform: uppercase;
  padding: 9px 18px;
}

@media (max-width: 900px) {
  .qem-hero-content { grid-template-columns: 1fr; }
  .qem-hero-art { order: -1; }
}

/* ---------------------------------------------------------------------
   MARQUEE STRIP
--------------------------------------------------------------------- */
.qem-marquee { background: var(--charcoal); overflow: hidden; padding: 12px 0; }
.qem-marquee-track { display: flex; white-space: nowrap; animation: qem-marquee 24s linear infinite; }
.qem-marquee-track span { font-size: 0.62rem; letter-spacing: 0.2em; text-transform: uppercase; color: var(--gold-pale); padding: 0 30px; flex-shrink: 0; }
@keyframes qem-marquee { 0% { transform: translateX(0); } 100% { transform: translateX(-50%); } }

/* ---------------------------------------------------------------------
   COLLECTIONS
--------------------------------------------------------------------- */
.qem-collections { padding: 100px 0; }
.qem-collections-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px; }
.qem-collection-card { position: relative; overflow: hidden; aspect-ratio: 4/5; cursor: pointer; background: var(--charcoal); border-radius: 4px; }
.qem-collection-card img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: center; transition: transform .7s ease; }
.qem-collection-card:hover img { transform: scale(1.06); }
.qem-collection-overlay { position: absolute; inset: 0; background: linear-gradient(to top, rgba(22,20,16,0.92) 0%, rgba(22,20,16,0.15) 60%, transparent 100%); }
.qem-collection-info { position: absolute; bottom: 0; left: 0; right: 0; padding: 22px; }
.qem-collection-tag { font-size: 0.58rem; letter-spacing: 0.22em; text-transform: uppercase; color: var(--gold-light); margin-bottom: 6px; display: block; }
.qem-collection-title { font-family: var(--font-head); font-size: 1.15rem; color: var(--ivory); }

@media (max-width: 900px) {
  .qem-collections-grid { grid-template-columns: 1fr 1fr; gap: 12px; }
}

@media (max-width: 560px) {
  .qem-collections-grid { grid-template-columns: 1fr; }
}

/* ---------------------------------------------------------------------
   BRAND STORY / CRAFTSMANSHIP
--------------------------------------------------------------------- */
.qem-story { padding: 100px 0; background: var(--ivory-deep); }
.qem-story-grid { display: grid; grid-template-columns: 1fr 1.1fr; gap: 70px; align-items: center; }
.qem-story-frame { aspect-ratio: 4/5; background: linear-gradient(145deg, var(--charcoal), var(--black)); overflow: hidden; }
.qem-story-frame img { width: 100%; height: 100%; object-fit: cover; }
.qem-story-lead { font-family: var(--font-head); font-size: 1.3rem; font-style: italic; margin-bottom: 18px; }
.qem-story-body { font-size: 0.88rem; color: var(--charcoal-soft); margin-bottom: 26px; }
.qem-story-values { display: flex; flex-direction: column; gap: 16px; margin-bottom: 30px; }
.qem-value-item { display: flex; gap: 14px; align-items: flex-start; }
.qem-value-icon { color: var(--gold); font-size: 1rem; margin-top: 2px; }
.qem-value-item strong { display: block; font-size: 0.78rem; margin-bottom: 2px; }
.qem-value-item span { font-size: 0.76rem; color: var(--charcoal-soft); }

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

/* ---------------------------------------------------------------------
   CUSTOM COMMISSION SECTION (homepage teaser + dedicated landing page)
--------------------------------------------------------------------- */
.qem-commission { padding: 100px 0; background: var(--charcoal); color: var(--ivory); }
.qem-commission .qem-eyebrow { color: var(--gold-light); }
.qem-commission .qem-section-title { color: var(--ivory); }
.qem-commission-grid { display: grid; grid-template-columns: 1fr 1.5fr; gap: 70px; align-items: start; }
.qem-commission-desc { font-size: 0.86rem; color: rgba(246, 242, 234, 0.65); margin: 18px 0 30px; max-width: 380px; }
.qem-order-steps { display: flex; flex-direction: column; gap: 20px; }
.qem-order-step { display: flex; gap: 16px; }
.qem-step-num { width: 28px; height: 28px; flex-shrink: 0; border: 1px solid var(--border-strong); display: flex; align-items: center; justify-content: center; font-family: var(--font-head); font-size: 0.8rem; color: var(--gold-light); }
.qem-step-title { font-size: 0.72rem; font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase; margin-bottom: 3px; }
.qem-step-desc { font-size: 0.74rem; color: rgba(246, 242, 234, 0.55); }

.qem-order-form { background: rgba(255, 255, 255, 0.03); border: 1px solid rgba(246, 242, 234, 0.12); padding: 40px; }
.qem-form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 18px; }
.qem-form-group { display: flex; flex-direction: column; gap: 7px; }
.qem-form-group.full { grid-column: 1 / -1; }
.qem-form-label { font-size: 0.6rem; font-weight: 500; letter-spacing: 0.16em; text-transform: uppercase; color: var(--gold-light); }
.qem-order-form input,
.qem-order-form select,
.qem-order-form textarea {
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid rgba(246, 242, 234, 0.15);
  color: var(--ivory);
  font-size: 0.82rem;
  padding: 13px 15px;
  width: 100%;
}
.qem-order-form textarea { resize: vertical; min-height: 90px; }

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

/* ---------------------------------------------------------------------
   PROMO BANNER
--------------------------------------------------------------------- */
.qem-promo { padding: 56px 0; background: var(--gold-pale); }
.qem-promo-inner { display: flex; align-items: center; justify-content: space-between; gap: 24px; flex-wrap: wrap; }
.qem-promo-inner h3 { font-size: 1.5rem; margin: 6px 0; }

/* ---------------------------------------------------------------------
   PRODUCTS GRID — reused for both homepage featured products and
   WooCommerce shop archive (ul.products)
--------------------------------------------------------------------- */
.qem-products,
ul.products {
  display: grid !important;
  grid-template-columns: repeat(4, 1fr) !important;
  gap: 36px 24px !important;
  list-style: none !important;
  margin: 0 !important;
  padding: 0 !important;
}
@media (max-width: 900px) {
  .qem-products, ul.products { grid-template-columns: 1fr 1fr !important; }
}
@media (max-width: 480px) {
  .qem-products, ul.products { grid-template-columns: 1fr !important; }
}

/* Real bug: WooCommerce's core CSS puts an old float-layout clearfix
   (content:" "; display:table;) on ul.products::before/::after. Because
   display:table isn't display:none, that pseudo-element is still a real
   box — and since ul.products is now a grid container, it becomes an
   actual (invisible) grid item that silently claims row 1 / column 1,
   pushing every real product over by one cell and leaving the top-left
   slot blank. Clearfixes are meaningless in a grid layout anyway, so
   just switch them off. */
.qem-products::before,
.qem-products::after,
ul.products::before,
ul.products::after {
  content: none !important;
  display: none !important;
}

.qem-products li.product,
ul.products li.product {
  background: none !important;
  border: none !important;
  padding: 0 !important;
  display: flex !important;
  flex-direction: column !important;
  /* WooCommerce's own core stylesheet (loaded after ours) sets
     `li.product { width: 22.65%; float: left; margin-right: 3.8%; }`
     for its default float-based grid. Our grid uses the <ul> itself
     (display:grid, grid-template-columns) to lay out columns, so that
     leftover percentage width instead shrinks each card down to ~22%
     of its already-sized grid cell — this was the real cause of the
     whole product grid rendering as a row of tiny thumbnails. Force
     the card to fill its grid cell fully and kill the float/margin. */
  width: 100% !important;
  max-width: 100% !important;
  float: none !important;
  margin: 0 !important;
}

/* The whole card (image+title+price) is wrapped in a single <a> by
   WooCommerce (and by our own homepage featured-products template,
   which reuses the same "unstyled <a>" pattern). Browsers default that
   to blue + underline; our sitewide `a { color:inherit }` reset should
   already cover this, but WooCommerce's own stylesheet loads after ours
   and re-applies its blue link colour with matching specificity — so
   pin it here explicitly, !important, to guarantee it never reverts to
   a "wall of blue links" look. This also covers the homepage's
   .qem-products grid, which was missed the first time these fixes were
   written (they only targeted ul.products, WooCommerce's own markup) —
   that's why the homepage "Featured Pieces" grid still showed raw blue
   underlined titles running straight into the price with no spacing. */
.qem-products li.product a.woocommerce-loop-product__link,
.qem-products li.product a,
ul.products li.product a.woocommerce-loop-product__link,
ul.products li.product a {
  color: inherit !important;
  text-decoration: none !important;
}

/* Real bug: cards with a short (1-line) title vs a long (2-line) title
   showed "Add to Cart" buttons sitting at different heights across the
   same row. Cause: WooCommerce wraps image+title+price in a single <a>
   that is display:block, not flex — so `.price { margin-top:auto }`
   below had zero effect, since auto-margins only work inside a flex/grid
   formatting context. Making this wrapper itself a flex column that
   grows to fill the remaining space in the card (li is already flex
   column) restores the auto-margin's effect, so price+button are always
   pinned to the same bottom line regardless of title length. Also
   covers the homepage grid's plain <a> (no woocommerce-loop-product__link
   class there), so title and price get proper spacing instead of
   running together on one line. */
.qem-products li.product > a,
ul.products li.product a.woocommerce-loop-product__link {
  display: flex !important;
  flex-direction: column !important;
  flex: 1 1 auto !important;
}

/* Real bug: WooCommerce's <img> ships with width/height attributes from
   its thumbnail size, and without an explicit width:100% here the image
   renders at that tiny intrinsic size (was ~61px) instead of filling the
   grid column — this alone was the cause of the whole grid looking small
   and cramped. */
.qem-products li.product img,
ul.products li.product img {
  display: block !important;
  width: 100% !important;
  height: auto !important;
  aspect-ratio: 4/5;
  object-fit: cover;
  margin-bottom: 16px !important;
  background: var(--ivory-deep);
  transition: var(--transition);
}
.qem-products li.product a:hover img,
ul.products li.product a:hover img { opacity: 0.88; }

.qem-products li.product .onsale,
ul.products li.product .onsale {
  position: absolute;
  top: 12px; left: 12px;
  background: var(--gold) !important;
  color: var(--black) !important;
  font-size: 0.6rem !important;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  font-weight: 600;
  padding: 5px 10px !important;
  border-radius: 0 !important;
  min-height: 0 !important;
  min-width: 0 !important;
  line-height: 1 !important;
}
.qem-products li.product,
ul.products li.product { position: relative !important; }

.qem-products li.product .woocommerce-loop-product__title,
ul.products li.product .woocommerce-loop-product__title {
  font-family: var(--font-head) !important;
  font-size: 1rem !important;
  font-weight: 500 !important;
  color: var(--charcoal) !important;
  margin: 0 0 8px !important;
  line-height: 1.35 !important;
  /* Long product titles (several run 90+ characters) would otherwise
     dominate the card and push prices at wildly different heights across
     a row — clamp to 2 lines so every card reads the same height. */
  display: -webkit-box !important;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.qem-products li.product .price,
ul.products li.product .price {
  font-size: 0.88rem !important;
  color: var(--charcoal) !important;
  margin-top: auto !important;
  display: block !important;
}
.qem-products li.product .price del,
ul.products li.product .price del {
  color: var(--charcoal-soft) !important;
  opacity: 0.65;
  text-decoration: line-through;
  font-size: 0.82em;
  margin-right: 8px;
}
.qem-products li.product .price ins,
ul.products li.product .price ins {
  text-decoration: none !important;
  color: var(--gold) !important;
  font-weight: 600;
}

.qem-products li.product a.button,
.qem-products li.product a.add_to_cart_button,
ul.products li.product a.button,
ul.products li.product a.add_to_cart_button {
  display: inline-block !important;
  margin-top: 14px !important;
  background: var(--black) !important;
  color: var(--ivory) !important;
  border: 1px solid var(--black) !important;
  font-size: 0.65rem !important;
  letter-spacing: 0.1em !important;
  text-transform: uppercase !important;
  text-align: center;
  padding: 12px 18px !important;
  white-space: nowrap;
  transition: var(--transition);
}
.qem-products li.product a.button:hover,
.qem-products li.product a.add_to_cart_button:hover,
ul.products li.product a.button:hover,
ul.products li.product a.add_to_cart_button:hover {
  background: var(--gold) !important;
  border-color: var(--gold) !important;
  color: var(--black) !important;
}

/* ---------------------------------------------------------------------
   SHOP HERO — big heading + subtext + two CTAs, modelled after a
   reference artist site's shop hero (reworded in our own brand voice),
   sitting above the wave carousel. Only shown on the main /shop/ page,
   page 1 — see archive-product.php. Category/tag archives keep the
   older, simpler header untouched.
--------------------------------------------------------------------- */
.qem-shop-hero {
  padding: 150px 0 50px;
  text-align: center;
}
.qem-shop-hero .qem-breadcrumbs { justify-content: center; }
.qem-shop-hero-title {
  font-family: var(--font-head);
  font-weight: 500;
  color: var(--charcoal);
  font-size: clamp(2.2rem, 5vw, 3.6rem);
  line-height: 1.15;
  max-width: 780px;
  margin: 0 auto 20px;
}
.qem-shop-hero-title em { font-style: italic; color: var(--gold); }
.qem-shop-hero-subtitle {
  font-size: 1rem;
  color: var(--charcoal-soft);
  max-width: 540px;
  line-height: 1.75;
  margin: 0 auto 36px;
}
.qem-shop-hero-actions {
  display: flex;
  gap: 16px;
  justify-content: center;
  flex-wrap: wrap;
}

/* ---------------------------------------------------------------------
   SHOP ARCHIVE — wave carousel. A continuously auto-scrolling strip of
   artwork photos where each slide's rotation/lift/scale is recalculated
   every animation frame based on its live position relative to the
   viewport centre, producing the curved "wave" presentation the owner
   asked to match from a reference artist site (see main.js
   initWaveCarousel). Centre slides sit tall and flat; slides further
   from centre rotate away and dip down, like a shallow arc.
--------------------------------------------------------------------- */
.qem-wave-wrap {
  position: relative;
  overflow: hidden;
  padding: 10px 0 100px;
  background: var(--ivory);
}
.qem-wave-viewport {
  overflow: hidden;
  padding: 40px 0 60px;
  /* Without a perspective context, each slide's rotateY() just squashes
     it flat in 2D instead of tilting away in 3D — this is what actually
     produces the curved "wave" look (see initWaveCarousel in main.js). */
  perspective: 1400px;
}
.qem-wave-track {
  display: flex;
  gap: 24px;
  width: max-content;
  will-change: transform;
  transform-style: preserve-3d;
}
.qem-wave-slide {
  position: relative;
  flex: 0 0 auto;
  width: 320px;
  aspect-ratio: 4/5;
  display: block;
  overflow: hidden;
  background: var(--ivory-deep);
  box-shadow: 0 24px 44px rgba(30, 26, 20, 0.16);
  transition: box-shadow var(--transition);
  will-change: transform;
}
.qem-wave-slide:hover { box-shadow: 0 28px 52px rgba(30, 26, 20, 0.24); }
.qem-wave-slide img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  pointer-events: none;
}
@media (max-width: 700px) {
  .qem-shop-hero { padding: 130px 0 36px; }
  .qem-wave-slide { width: 220px; }
  .qem-wave-viewport { padding: 24px 0 40px; }
}

.qem-filter-tabs { display: flex; justify-content: center; gap: 10px; flex-wrap: wrap; margin-bottom: 50px; }
.qem-filter-btn { background: none; border: 1px solid var(--border); color: var(--charcoal-soft); font-size: 0.68rem; letter-spacing: 0.1em; text-transform: uppercase; padding: 10px 20px; cursor: pointer; transition: var(--transition); }
.qem-filter-btn.active, .qem-filter-btn:hover { border-color: var(--gold); color: var(--gold); }

/* ---------------------------------------------------------------------
   SINGLE PRODUCT PAGE
--------------------------------------------------------------------- */
.qem-product-trust-badges { display: flex; gap: 20px; flex-wrap: wrap; margin: 24px 0; padding: 20px 0; border-top: 1px solid var(--border); border-bottom: 1px solid var(--border); }
.qem-trust-badge { display: flex; align-items: center; gap: 8px; font-size: 0.68rem; letter-spacing: 0.05em; color: var(--charcoal-soft); }

.qem-sticky-atc {
  position: sticky; bottom: 0; z-index: 20;
  background: var(--ivory); border-top: 1px solid var(--border);
  padding: 14px 0; display: none;
}
.qem-sticky-atc.is-visible { display: block; }

.qem-product-tabs-editorial { margin-top: 60px; }
.qem-product-tabs-editorial h3 { font-size: 1.3rem; margin-bottom: 14px; }

/* ---------------------------------------------------------------------
   TESTIMONIALS
--------------------------------------------------------------------- */
.qem-reviews { padding: 100px 0; background: var(--ivory-deep); overflow: hidden; }
.qem-reviews-slider-wrap { position: relative; margin-top: 40px; overflow: hidden; }
.qem-reviews-slider { display: flex; gap: 20px; transition: transform 0.6s cubic-bezier(.25,.46,.45,.94); }
.qem-review-card { min-width: calc(33.33% - 14px); background: var(--ivory); border: 1px solid var(--border); padding: 30px; flex-shrink: 0; }
.qem-review-stars { color: var(--gold); font-size: 0.8rem; margin-bottom: 14px; }
.qem-review-text { font-size: 0.82rem; color: var(--charcoal-soft); font-style: italic; margin-bottom: 22px; }
.qem-review-author { display: flex; align-items: center; gap: 12px; }
.qem-review-avatar { width: 38px; height: 38px; border-radius: 50%; background: var(--gold); color: var(--black); display: flex; align-items: center; justify-content: center; font-family: var(--font-head); font-weight: 600; }
.qem-review-name { font-family: var(--font-head); font-size: 0.95rem; }
.qem-review-loc { font-size: 0.62rem; color: var(--charcoal-soft); }
.qem-slider-controls { display: flex; justify-content: center; align-items: center; gap: 16px; margin-top: 34px; }
.qem-slider-btn { width: 40px; height: 40px; border: 1px solid var(--border-strong); background: none; cursor: pointer; }
.qem-slider-btn:hover { background: var(--gold); color: var(--black); border-color: var(--gold); }
.qem-slider-dots { display: flex; gap: 7px; }
.qem-slider-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--border-strong); cursor: pointer; }
.qem-slider-dot.active { background: var(--gold); width: 18px; border-radius: 3px; }

@media (max-width: 900px) { .qem-review-card { min-width: 100%; } }

/* ---------------------------------------------------------------------
   NEWSLETTER / CONTACT
--------------------------------------------------------------------- */
.qem-newsletter { padding: 90px 0; background: var(--charcoal); color: var(--ivory); text-align: center; }
.qem-newsletter .qem-section-title { color: var(--ivory); }
.qem-newsletter p { font-size: 0.85rem; color: rgba(246,242,234,0.6); max-width: 440px; margin: 16px auto 32px; }
.qem-newsletter-form { display: flex; flex-wrap: wrap; gap: 0; max-width: 420px; margin: 0 auto 34px; }
.qem-newsletter-form input[type="email"] { flex: 1 1 180px; min-width: 0; background: rgba(255,255,255,0.05); border: 1px solid rgba(246,242,234,0.2); border-right: none; color: var(--ivory); padding: 14px 16px; font-size: 0.82rem; }
.qem-contact-details { display: flex; justify-content: center; gap: 30px; flex-wrap: wrap; }
.qem-contact-link { font-size: 0.75rem; color: rgba(246,242,234,0.7); }
.qem-contact-link:hover { color: var(--gold-light); }

/* ---------------------------------------------------------------------
   FOOTER
--------------------------------------------------------------------- */
.qem-footer, #colophon { background: var(--black) !important; color: rgba(246,242,234,0.7); padding: 70px 0 26px; }
.qem-footer-grid { display: grid; grid-template-columns: 1.5fr 1fr 1fr 1fr; gap: 40px; padding-bottom: 44px; border-bottom: 1px solid rgba(246,242,234,0.1); }
.qem-footer-logo { font-family: var(--font-head); font-size: 1.3rem; color: var(--ivory); margin-bottom: 14px; }
.qem-footer-col-title { font-size: 0.65rem; letter-spacing: 0.14em; text-transform: uppercase; color: var(--gold-light); margin-bottom: 14px; }
.qem-footer-links li { margin-bottom: 9px; list-style: none; }
.qem-footer-links a:hover { color: var(--gold-light); }
.qem-footer-bottom { display: flex; justify-content: space-between; flex-wrap: wrap; gap: 12px; padding-top: 24px; font-size: 0.7rem; }

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

/* ---------------------------------------------------------------------
   WHATSAPP FAB
--------------------------------------------------------------------- */
.qem-whatsapp-fab {
  position: fixed; bottom: 24px; right: 24px; width: 54px; height: 54px;
  border-radius: 50%; background: #25d366; display: flex; align-items: center; justify-content: center;
  z-index: 998; box-shadow: 0 8px 24px rgba(0,0,0,0.25);
}

/* ---------------------------------------------------------------------
   SCROLL REVEAL (progressive enhancement — content is visible by
   default; JS only ADDS a subtle entrance animation when it manages to
   run. This matters because caching/optimization plugins (e.g. LiteSpeed
   Cache's "delay JS until interaction") can postpone script execution
   indefinitely — content must never depend on JS to become visible.)
--------------------------------------------------------------------- */
/* Content is ALWAYS fully visible (opacity is never manipulated here —
   that proved unreliable in production due to cache/JS-timing races).
   JS only adds a small, purely decorative slide-up via transform; if JS
   never runs or runs late, the element simply sits at its final resting
   position the whole time — nothing to hide, nothing that can get stuck. */
.qem-reveal { opacity: 1; }
.qem-reveal.qem-js-ready { transform: translateY(14px); transition: transform .6s ease; }
.qem-reveal.qem-js-ready.is-visible { transform: translateY(0); }

/* ---------------------------------------------------------------------
   SINGLE PRODUCT PAGE — CONTRAST FIX
   The Elementor product template (Bosa Elementor for WooCommerce) was
   built with near-white text (title/price/short description/Add to Cart
   button all around #e4e4e4–#ffffff) meant for a dark background, but the
   actual page background here is white/ivory — so on every single
   product page the title, price, short description and Add to Cart
   button render almost invisible. Force readable dark colors, scoped
   only to body.single-product so it can't affect any intentionally-dark
   section elsewhere (e.g. the homepage hero).
--------------------------------------------------------------------- */
body.single-product .product_title,
body.single-product .entry-summary h1,
body.single-product .summary h1 {
  color: var(--charcoal) !important;
}
/* NOTE: this template is built entirely from Elementor widgets
   (elementor-location-single) — there is NO .summary/.entry-summary
   wrapper on this site, so any rule scoped under those classes never
   matched anything and the price kept rendering in the kit's original
   near-white color. The real wrapper is
   .elementor-widget-woocommerce-product-price, but to also catch the
   same white-on-ivory price bug on the "Related products" cards further
   down the page, these rules target .price directly (still scoped to
   body.single-product so nothing outside product pages is touched). */
body.single-product .price,
body.single-product .price bdi,
body.single-product .woocommerce-Price-amount {
  color: var(--charcoal) !important;
}
body.single-product .price del,
body.single-product .price del bdi {
  color: var(--charcoal-soft) !important;
  opacity: 0.6;
}
body.single-product .price ins,
body.single-product .price ins bdi {
  color: var(--gold) !important;
  text-decoration: none;
}
body.single-product .woocommerce-product-details__short-description,
body.single-product .woocommerce-product-details__short-description p,
body.single-product .entry-summary p,
body.single-product .entry-summary li {
  color: var(--charcoal-soft) !important;
}
body.single-product a.single_add_to_cart_button,
body.single-product button.single_add_to_cart_button {
  background: var(--charcoal) !important;
  color: var(--ivory) !important;
  border-color: var(--charcoal) !important;
}
body.single-product a.single_add_to_cart_button:hover,
body.single-product button.single_add_to_cart_button:hover {
  background: var(--gold) !important;
  color: var(--ivory) !important;
}
body.single-product .quantity input.qty {
  color: var(--charcoal) !important;
  border-color: var(--border-strong) !important;
}
body.single-product .woocommerce-product-details__short-description strong,
body.single-product .entry-summary strong {
  color: var(--charcoal) !important;
}

/* ---------------------------------------------------------------------
   CHECKOUT — ORDER SUMMARY LAYOUT FIX
   The WooCommerce Blocks checkout's order-summary row is a flex layout
   (image | description | price), but the description column (product
   name) was left at its default `flex: 0 1 auto`, so it never grows to
   fill the available space — long product titles collapse to ~48px wide
   and wrap one or two letters per line, making the order summary look
   broken. Let the description column grow and shrink normally, and
   allow it to actually wrap within that width instead of overflowing.
--------------------------------------------------------------------- */
.wc-block-components-order-summary-item__description {
  flex: 1 1 auto !important;
  min-width: 0 !important;
}
.wc-block-components-order-summary-item__individual-prices,
.wc-block-components-order-summary-item__total-price {
  flex: 0 0 auto !important;
  white-space: nowrap;
}

/* ---------------------------------------------------------------------
   SINGLE PRODUCT PAGE — QUIET-LUXURY REDRESS
   Owner asked for a warmer, editorial product page (cream backdrop
   instead of stark white, gallery that reads as "gallery" not "generic
   product photo") closer to reference sites like aadilabedi.com — same
   ivory/charcoal/gold system already used across the rest of the site.
--------------------------------------------------------------------- */
body.single-product #content,
body.single-product .site-content,
body.single-product div.product {
  background: var(--ivory) !important;
}
/* Our nav is position:fixed over the true viewport top (see NAVIGATION
   section above), but the Elementor "Single Product" template that renders
   every product page has no top clearance for it — the product title and
   gallery start high enough in the document flow to render partly *behind*
   the fixed nav (measured ~50px of overlap live). Every single-product page
   has this bug, not just one product; every other template on the site
   (homepage hero, shop hero, About page, etc.) already has its own
   hand-added top padding for exactly this reason — this is the one
   template that was missing it. */
body.single-product div.product.elementor-location-single {
  padding-top: 70px;
}
body.single-product .woocommerce-product-gallery {
  background: var(--ivory-deep);
  padding: 18px;
  border-radius: 2px;
}
/* WooCommerce core CSS ships .woocommerce-product-gallery with opacity:0 as
   its default state, then relies on JS (flexslider init in
   frontend/single-product.min.js) to flip an inline style to opacity:1 once
   the slider is ready. On this site a cached/CDN-mirrored copy of that core
   CSS is re-asserting opacity:0 with higher priority than the inline style,
   so product gallery images silently upload fine but never become visible.
   Force it visible unconditionally so this can never regress. */
body.single-product .woocommerce-product-gallery,
body.single-product .woocommerce-product-gallery .flex-viewport,
body.single-product .woocommerce-product-gallery__wrapper,
body.single-product .woocommerce-product-gallery img:not(.zoomImg) {
  opacity: 1 !important;
}

/* Fix: the rule above must not force the JS-generated zoom overlay clone
   (.zoomImg, injected by jquery.zoom on hover) to stay opacity:1 — that
   broke the zoom-out fade when the mouse leaves the product image. */
body.single-product .woocommerce-product-gallery .zoomImg {
  opacity: 0 !important;
}
body.single-product .woocommerce-product-gallery:hover .zoomImg {
  opacity: 1 !important;
}
body.single-product .woocommerce-product-gallery__image img {
  border-radius: 2px;
}
body.single-product .flex-control-thumbs li img {
  border-radius: 2px;
  opacity: 0.65;
  transition: opacity .3s ease;
}
body.single-product .flex-control-thumbs li img.flex-active,
body.single-product .flex-control-thumbs li:hover img {
  opacity: 1;
}

/* "Related products" heading was rendering white-on-white (same
   Elementor dark-template leftover as the title/price bug above) —
   force it dark and give the whole related-products block breathing
   room and the same ivory backdrop. */
body.single-product .related.products,
body.single-product .up-sells.upsells.products {
  background: var(--ivory);
  padding-top: 40px;
}
body.single-product .related.products > h2,
body.single-product .up-sells.upsells.products > h2 {
  color: var(--charcoal) !important;
  font-family: var(--font-head);
  font-size: 1.8rem;
  margin-bottom: 24px;
}

/* Description/Reviews tab panel — the Elementor widget box around the
   WooCommerce tabs was styled with a solid black background (with white
   text) as part of the original dark-hero-themed kit; on our ivory
   single-product page that reads as a jarring black box. Recolor the
   whole panel to match the ivory system instead. */
body.single-product .elementor-widget-container:has(.woocommerce-tabs) {
  background: var(--ivory) !important;
}
body.single-product .woocommerce-tabs p,
body.single-product .woocommerce-tabs li,
body.single-product .woocommerce-tabs td,
body.single-product .woocommerce-tabs th,
body.single-product .woocommerce-tabs span {
  color: var(--charcoal-soft) !important;
}
body.single-product .woocommerce-tabs strong,
body.single-product .woocommerce-tabs b {
  color: var(--charcoal) !important;
}
