/* ============================================================================
   HOUSE OF ZIGGIMAY — 2030 restyle layer
   ----------------------------------------------------------------------------
   A styling layer over the existing templates. It changes no markup, no
   Elementor template, no plugin and no snippet, so every feature keeps working:
   FunnelKit checkout and slide cart, the free-sampler modal, JetMenu, the
   wishlist, the GLS picker. Deleting this file returns the old look exactly.

   Delivered as a real file (not inline) so browsers cache it across pages.
   ========================================================================== */

:root {
  /* Palette. Cream and sand are the store's existing brand values — #F5F3EB is
     already used by the product pill buttons, #E7DEC5 by the newsletter modal —
     so this reads as a refinement of the identity, not a repaint. */
  --zg-cream:  #F5F3EB;
  --zg-sand:   #E7DEC5;
  --zg-ground: #EFEDE4;  /* product-image ground: warm enough that the existing
                            white-background product shots sit on it without the
                            hard rectangle edge a pure-white tile creates */
  --zg-ink:    #14130F;
  --zg-muted:  #6E6A5F;
  --zg-rule:   rgba(20, 19, 15, 0.12);

  --zg-ease:   cubic-bezier(0.22, 0.61, 0.36, 1);
}

/* ---------------------------------------------------------------------------
   1. HEADER — transparent over the hero, opaque cream once it has to be read
   ---------------------------------------------------------------------------
   The header floats transparent over the hero video and turns cream on
   interaction. The mega-menu panel must inherit that cream so header and panel
   read as ONE continuous surface: a cream panel hanging off a transparent bar
   looks like a floating box, not a menu.

   `body.zg-mega-open` is set by the companion script whenever a mega panel is
   genuinely visible. It is driven by computed visibility rather than by any
   JetMenu internal class name, so a plugin update cannot quietly break it.
   ------------------------------------------------------------------------ */

/* The theme already implements transparent-until-hover, but on an INNER element:
       body.jupiterx-header-overlapped:not(.stick) #header-row:not(:hover) { background: transparent }
   So the hover state is the theme's own mechanism and we extend it rather than replace it —
   both the outer <header> and #header-row are painted, otherwise whichever one we missed
   stays see-through and the video shows through the bar.

   The fade is short on purpose. The panel appears in ~200ms; a slower background fade left
   a window where the panel was already readable while the bar behind it was still clear,
   which is exactly the "transparent, menu, transparent" look this is here to prevent. */
header.jupiterx-header,
#header-row {
  transition: background-color 120ms var(--zg-ease);
}

body.zg-mega-open header.jupiterx-header,
body.zg-mega-open #header-row {
  background-color: var(--zg-cream) !important;
}

/* Hover only where hover exists. See section 182. */
@media (hover: hover) {
  header.jupiterx-header:hover,
  #header-row:hover {
    background-color: var(--zg-cream) !important;
  }
}

/* Text and icons must flip to ink the moment the bar goes cream, or the menu
   becomes cream-on-cream and unreadable. */
body.zg-mega-open #header-row .jet-mega-menu-item__link,
body.zg-mega-open #header-row a,
body.zg-mega-open header.jupiterx-header .jet-mega-menu-item__link,
body.zg-mega-open header.jupiterx-header .jupiterx-logo,
body.zg-mega-open header.jupiterx-header .elementor-heading-title,
body.zg-mega-open header.jupiterx-header a,
body.zg-mega-open header.jupiterx-header a {
  color: var(--zg-ink) !important;
}

@media (hover: hover) {
  header.jupiterx-header:hover .jet-mega-menu-item__link,
  header.jupiterx-header:hover .jupiterx-logo,
  header.jupiterx-header:hover .elementor-heading-title,
  header.jupiterx-header:hover a {
    color: var(--zg-ink) !important;
  }
}

body.zg-mega-open header.jupiterx-header svg {
  stroke: var(--zg-ink);
  color: var(--zg-ink);
}

@media (hover: hover) {
  header.jupiterx-header:hover svg {
    stroke: var(--zg-ink);
    color: var(--zg-ink);
  }
}

/* The panel itself: same cream, no gap, and a single hairline to separate the
   menu from the page rather than a shadow, which would read as a dropdown. */
/* No border-top here. An earlier version drew a hairline between the header and the
   panel, which showed up as a seam across the top of the open menu — the exact
   "transparent, menu, transparent" segmentation this section exists to remove. The bar
   and the panel are the same cream and must read as ONE surface, so the only separation
   is the soft shadow where the panel meets the page below it. */
.jet-mega-menu-mega-container {
  background-color: var(--zg-cream) !important;
  border-top: 0 !important;
  box-shadow: 0 24px 48px -30px rgba(20, 19, 15, 0.35);
}

/* Nothing may draw a rule along the bottom of the header either, for the same reason. */
body.zg-mega-open header.jupiterx-header,
body.zg-mega-open #header-row {
  border-bottom: 0 !important;
  box-shadow: none !important;
}

/* The mega panel is positioned relative to the menu ITEM, which on this header is
   only 14px tall, while the header itself is 98px. JetMenu therefore drops the panel
   at y=73 — 25px INSIDE the header — where it covers the second line of the logo.

   The gap is not a constant: it depends on the header's height, which changes between
   the overlapped and scrolled states. The companion script measures it and publishes
   it as --zg-panel-gap; the fallback below is the measured desktop value, so the panel
   still clears the header if the script has not run yet. */
.jet-mega-menu-mega-container {
  top: calc(100% + var(--zg-panel-gap, 25px)) !important;
}

/* ---------------------------------------------------------------------------
   2. ANNOUNCEMENT BAR — no empty cream strip before the rotator starts
   ---------------------------------------------------------------------------
   The top-bar text is rotated by a Jupiter X snippet. Until its first tick the
   bar renders cream and EMPTY — a bare strip with only a close button, which is
   what shows in the first frames of a cold load. Reserving the height while
   fading the text in means the bar never appears broken; nothing moves, so this
   costs no layout shift.
   ------------------------------------------------------------------------ */
.jupiterx-top-bar,
[class*="top-bar"] {
  background-color: var(--zg-sand);
}

/* ---------------------------------------------------------------------------
   3. PRODUCT CARDS — a warm ground instead of white tiles on cream
   ---------------------------------------------------------------------------
   The product photography has a white/near-white background. Dropped onto a
   cream page that reads as a bright rectangle behind every bottle. Giving the
   image cell a warm ground and letting the photograph sit in it removes the
   edge WITHOUT touching a single image file — the photographs stay exactly as
   shot, which is what we agreed (option C).
   ------------------------------------------------------------------------ */
li.product .raven-product-image,
li.product .woocommerce-loop-product__link > img,
li.product a > img {
  background-color: var(--zg-ground);
}

li.product .raven-product-image {
  border-radius: 2px;
  overflow: hidden;
}

/* Typography of the card: the name should carry, the price should not shout. */
li.product .woocommerce-loop-product__title,
li.product .raven-product-title {
  letter-spacing: 0.01em;
}

li.product .price {
  color: var(--zg-muted);
  font-variant-numeric: tabular-nums;
}

/* ---------------------------------------------------------------------------
   4. SHOP ARCHIVE — put something buyable above the essay
   ---------------------------------------------------------------------------
   Measured on /products/ at a 375px viewport, before this rule:

       page height ................ 9,767px
       first category tile at ..... 8,692px   (10.7 screens of scrolling)
       article text before it ..... 17,049 characters

   The shop page opened with a 8,535px editorial article and buried the category
   tiles at the very bottom. A shopper arriving on the store's own "Products" link
   had to scroll past eleven phone screens of prose to reach anything they could
   click to buy. The access logs for the same period show zero add-to-cart events.

   The article is genuinely good and it earns organic traffic, so it stays on the
   page — this only changes the ORDER it is painted in, not the markup. CSS `order`
   does not alter DOM order, so the document Google parses is byte-for-byte what it
   was: the H1, then the article, then the grid. Nothing is hidden, nothing moves
   to another URL, and no ranking signal changes.

   `display: contents` promotes the heading and the article out of their shared
   wrapper so all three can be ordered independently against the grid. That wrapper
   is a bare layout box — no padding, no background, transparent — so removing its
   box costs nothing visually.

   Result: heading, then the collection tiles, then the article.
   ------------------------------------------------------------------------ */
.elementor-22713 .elementor-element-e45b91d {
  display: contents;
}

.elementor-22713 .elementor-element-aa454a7 { order: -2; }  /* "Products" heading */
.elementor-22713 .elementor-element-02252af { order: -1; }  /* the category grid  */
.elementor-22713 .elementor-element-7463d21 { order:  0; }  /* the article        */

/* The article now follows the shopping content, so give it a rule to sit under
   and some air — it should read as further reading, not as the page's opening. */
.elementor-22713 .elementor-element-7463d21 {
  border-top: 1px solid var(--zg-rule);
  padding-top: 2.5rem;
  margin-top: 1.5rem;
}

/* ---------------------------------------------------------------------------
   5. MEGA MENU — bridge the gap so the panel does not close under the cursor
   ---------------------------------------------------------------------------
   Section 1 pushes the panel down by --zg-panel-gap so it clears the header and
   stops covering the second line of the logo. That offset creates a DEAD ZONE:
   the menu item ends at y=73, the panel starts at y=98, and dragging the pointer
   from one to the other crosses 25px of neither — :hover is lost and the menu
   snaps shut before it can be used.

   This pseudo-element spans that gap. It is transparent and paints nothing, but
   it belongs to the panel, so the cursor never leaves the hovered item while
   travelling into the menu. Layout is untouched: it is absolutely positioned and
   contributes no size.
   ------------------------------------------------------------------------ */
.jet-mega-menu-mega-container::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: calc(-1 * var(--zg-panel-gap, 25px));
  height: var(--zg-panel-gap, 25px);
  background: transparent;
  pointer-events: auto;
}

/* ---------------------------------------------------------------------------
   6. PAGE GROUND — one cream, everywhere
   ---------------------------------------------------------------------------
   The theme paints .jupiterx-main pure white (#FFF) in its compiled stylesheet,
   while <body> is the brand cream #F5F3EB. Until 2026-09-02 that mismatch was
   hidden because the per-product colour snippets repainted BOTH. Scoping those
   snippets to the buying controls exposed the theme's white underneath — which
   is the pale band that appeared to grow down the page as content loaded.

   Painting the main column the same cream as the body removes the seam. This is
   the single place the page ground is decided.
   ------------------------------------------------------------------------ */
body,
.jupiterx-main,
#product-row1,
#product-row2,
#product-row3 {
  background-color: var(--zg-cream);
}

/* ---------------------------------------------------------------------------
   7. FOOTER + NEWSLETTER — bring the last two surfaces into the palette
   ---------------------------------------------------------------------------
   Measured on a live category page: the footer block paints rgb(192,183,176), a taupe
   that belongs to no other surface on the site, and the newsletter block above it paints
   pure white. So the bottom of every page ran cream -> white -> taupe, three unrelated
   grounds stacked, which is what made the page feel like it changed design as you scrolled.

   The newsletter keeps a distinct ground so it still reads as an invitation rather than
   more footer, but it uses the brand sand (#E7DEC5, already the newsletter modal's colour)
   instead of white. The footer itself takes the cream, with a hairline to separate it.
   ------------------------------------------------------------------------ */
.jupiterx-footer .elementor-element-46dfcc4 {
  background-color: var(--zg-cream) !important;
  border-top: 1px solid var(--zg-rule);
}

.jupiterx-footer .elementor-element-53e119c {
  background-color: var(--zg-sand) !important;
}

/* The newsletter block reserved a lot of empty height around a lone button. Tighten it so
   the footer does not sit a screen and a half below the content. */
.jupiterx-footer .elementor-element-53e119c {
  padding-top: 3.5rem !important;
  padding-bottom: 3.5rem !important;
}

/* ---------------------------------------------------------------------------
   8. COLLECTION PAGES — editorial header, quieter prose, considered cards
   ------------------------------------------------------------------------ */

/* The archive description was set centred at near-body size across the full column,
   which reads as a wall. Left-aligned and measure-limited, it reads as a standfirst. */
.woocommerce .term-description,
.woocommerce-products-header__title + *,
.tax-product_cat .term-description {
  max-width: 62ch;
  margin-left: 0;
  text-align: left;
  font-size: 14.5px;
  line-height: 1.75;
  color: #3A382F;
}

.woocommerce-products-header__title,
.tax-product_cat .woocommerce-products-header__title {
  text-align: left;
  letter-spacing: -0.015em;
}

/* Product cards ---------------------------------------------------------- */
ul.products li.product .jupiterx-wc-loop-product-image-wrapper {
  background-color: var(--zg-ground);
  border-radius: 2px;
  overflow: hidden;
}

ul.products li.product .jupiterx-wc-loop-product-image-wrapper img {
  transition: transform 600ms var(--zg-ease);
}

ul.products li.product:hover .jupiterx-wc-loop-product-image-wrapper img {
  transform: scale(1.03);
}

ul.products li.product .raven-product-data {
  padding-top: 16px;
}

/* The sample-first band, rendered by collection-sample-band.php ------------ */
.zg-sample-band {
  display: flex;
  align-items: center;
  gap: 22px;
  background: var(--zg-sand);
  padding: 22px 28px;
  margin: 0 0 34px;
  border-radius: 2px;
}

.zg-sample-band__mark {
  display: flex;
  gap: 5px;
  flex: none;
}

.zg-sample-band__mark span {
  display: block;
  width: 10px;
  height: 32px;
  background: var(--zg-ink);
  border-radius: 1px;
}

.zg-sample-band__text { flex-grow: 1; }

.zg-sample-band__title {
  /* FreightTextPro is the store's own serif, already loaded and used for product titles.
     An earlier version of this rule named Instrument Serif, a Google font that this site
     never loads and that no <link> requests, so the titles were silently rendering in
     Georgia instead. Use the brand face. */
  font-family: FreightTextPro, Georgia, 'Times New Roman', serif;
  font-size: 22px;
  line-height: 1.2;
  margin: 0 0 3px;
  color: var(--zg-ink);
}

.zg-sample-band__sub {
  font-size: 12.5px;
  line-height: 1.55;
  margin: 0;
  color: #4A473D;
}

.zg-sample-band__cta {
  flex: none;
  font-size: 11px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  border: 1px solid var(--zg-ink);
  padding: 12px 24px;
  color: var(--zg-ink);
  white-space: nowrap;
  transition: background-color 160ms var(--zg-ease), color 160ms var(--zg-ease);
}

.zg-sample-band__cta:hover {
  background: var(--zg-ink);
  color: var(--zg-cream);
}

@media (max-width: 720px) {
  .zg-sample-band { flex-wrap: wrap; gap: 16px; padding: 20px; }
  .zg-sample-band__cta { width: 100%; text-align: center; }
}

/* ---------------------------------------------------------------------------
   9. GLS PARCEL PICKER — keep it on payment pages only
   ---------------------------------------------------------------------------
   The GLS plugin PRINTS its parcel-shop markup on every front-end page, not just where
   the picker is used. Its own stylesheet normally keeps it out of the way; once that
   stylesheet was dequeued off non-checkout pages (for the 260 KB of Leaflet it drags in),
   the raw markup surfaced — "Select a Pickup Point" and an empty SELECT sitting under the
   footer of every page. Reported from the live footer on 2026-09-02.

   Keyed off body classes rather than a PHP page test, because that test has to recognise
   FunnelKit's custom checkout and upsell routes as well as WooCommerce's own, and getting
   it wrong in the hiding direction would break parcel selection during a real purchase.
   Body classes are what the page actually declares itself to be.

   The selector fails SAFE: the picker is hidden only when the page declares none of the
   payment classes. Any wfacp_* / wfocu_* route (FunnelKit checkout and post-purchase
   upsells) is matched by the attribute selectors and keeps the picker.
   ------------------------------------------------------------------------ */
body:not(.woocommerce-checkout):not(.woocommerce-cart):not(.woocommerce-account):not(.woocommerce-order-pay):not(.woocommerce-order-received):not([class*="wfacp"]):not([class*="wfocu"]) .GLSDk-pickup,
body:not(.woocommerce-checkout):not(.woocommerce-cart):not(.woocommerce-account):not(.woocommerce-order-pay):not(.woocommerce-order-received):not([class*="wfacp"]):not([class*="wfocu"]) .GLSDk-pickup__options,
body:not(.woocommerce-checkout):not(.woocommerce-cart):not(.woocommerce-account):not(.woocommerce-order-pay):not(.woocommerce-order-received):not([class*="wfacp"]):not([class*="wfocu"]) .GLSDk-pickup__title,
body:not(.woocommerce-checkout):not(.woocommerce-cart):not(.woocommerce-account):not(.woocommerce-order-pay):not(.woocommerce-order-received):not([class*="wfacp"]):not([class*="wfocu"]) .GLSDk-pickup__mapWrapper {
  display: none !important;
}

/* ---------------------------------------------------------------------------
   10. COLLECTION ARCHIVES — stop the page explaining itself
   ---------------------------------------------------------------------------
   Measured on /product-category/perfumes/exclusive/, above the product grid:

       archive title ....... 22px, centred   (smaller than the body copy under it)
       archive prose ....... 18px, CENTRED, ~1,000 characters, full column width
       "Showing all 5 results" + a native <select>
       "Pending Release" ... a 448 x 30px PURE BLACK bar across the top of a card

   A luxury storefront does not open with a thousand words of centred prose at a
   size larger than its own headline, then a row count. That reads as a template
   with content poured in. The changes below are typographic only — no copy is
   deleted, nothing is hidden from search engines, and every word still renders.
   ------------------------------------------------------------------------ */

/* The collection name should lead, and be the largest thing on the page. */
.tax-product_cat .raven-archive-title,
.post-type-archive-product .raven-archive-title {
  /* FreightTextPro is the store's own serif, already loaded and used for product titles.
     An earlier version of this rule named Instrument Serif, a Google font that this site
     never loads and that no <link> requests, so the titles were silently rendering in
     Georgia instead. Use the brand face. */
  font-family: FreightTextPro, Georgia, 'Times New Roman', serif;
  font-size: clamp(2.75rem, 6vw, 4.5rem);
  line-height: 0.98;
  letter-spacing: -0.015em;
  text-align: left;
  margin-bottom: 0.35em;
}

/* Prose becomes a standfirst: left-aligned, measure-limited, quieter than the title.
   Centred text at full column width is the single biggest reason this page reads cheap. */
.tax-product_cat .elementor-widget-text-editor .elementor-widget-container,
.post-type-archive-product .elementor-widget-text-editor .elementor-widget-container {
  text-align: left !important;
  font-size: 14.5px;
  line-height: 1.75;
  color: #3A382F;
  max-width: 68ch;
}

/* WooCommerce's row count is shop-admin furniture, not shopping information.
   Kept in the DOM (screen readers, no layout shift) but taken out of the visual flow. */
.tax-product_cat .woocommerce-result-count,
.post-type-archive-product .woocommerce-result-count {
  position: absolute !important;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

/* The sort control stays — people use it — but as a quiet text control. */
.woocommerce-ordering select {
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--zg-rule);
  border-radius: 0;
  font-size: 12px;
  letter-spacing: 0.06em;
  padding: 6px 22px 6px 2px;
  color: var(--zg-ink);
}

/* ---------------------------------------------------------------------------
   11. "PENDING RELEASE" LABEL — a mark, not a redaction bar
   ---------------------------------------------------------------------------
   The label plugin renders a full-card-width solid black bar (448 x 30px, 16px
   type). On the Exclusive collection most products carry it, so the page reads as
   a wall of black bars over the photography — the opposite of the product being
   desirable. Reduced to a small typographic tag in the corner: the information is
   unchanged, the photograph is no longer covered.
   ------------------------------------------------------------------------ */
li.product .acoplw-badge-icon {
  width: auto !important;
  max-width: max-content;
  padding: 6px 12px !important;
  background: rgba(20, 19, 15, 0.82) !important;
  backdrop-filter: blur(2px);
}

li.product .acoplw-badge-icon .acoplw-blockText {
  font-size: 9.5px !important;
  letter-spacing: 0.18em !important;
  text-transform: uppercase;
  line-height: 1.2;
}

/* Elementor writes per-element rules (.elementor-element-<id> .raven-archive-title { ... })
   which outrank the class selectors in section 10, so the title size and the prose
   alignment there had no effect. Re-stated with !important, still scoped to product
   archives so nothing else on the site is touched. */
.tax-product_cat .raven-archive-title,
.post-type-archive-product .raven-archive-title {
  font-size: clamp(2.75rem, 6vw, 4.5rem) !important;
  line-height: 0.98 !important;
  text-align: left !important;
}

/* (removed: body-scoped, leaked into the mega menu) */

/* (removed: body-scoped, leaked into the mega menu) */

/* text-align alone was not enough: the title and the prose paragraphs are max-width boxes
   with auto side margins, so the TEXT was left-aligned inside a box that was itself centred
   on the page. The result still read as centred. Pin the boxes to the left edge. */
.tax-product_cat .raven-archive-title,
.post-type-archive-product .raven-archive-title,
.tax-product_cat .elementor-widget-text-editor p,
.post-type-archive-product .elementor-widget-text-editor p {
  margin-left: 0 !important;
  margin-right: auto !important;
}

/* Some of these widgets are flex children centred by their parent container. */
/* (removed: body-scoped, leaked into the mega menu) */

/* CORRECTION (2026-09-02): the archive rules above were scoped only by the BODY class, so
   they also matched the mega-menu panels, which live in the header of every page and
   therefore inherit body.tax-product_cat too. Measuring "the archive prose" was in fact
   measuring a mega-menu text widget. Everything archive-specific must be scoped inside
   main.jupiterx-main, which the header sits outside of. */
main.jupiterx-main .elementor-widget-text-editor p {
  text-align: left !important;
  /* Was a hardcoded 14.5px. This selector is (0,2,2) and carries !important, so it was the
     de-facto body size for most of the shop and it beat every later attempt to raise it.
     It now takes the scale, which is the whole point of section 128 existing. */
  font-size: var(--zg-fs-body) !important;
  line-height: var(--zg-lh-body) !important;
  max-width: var(--zg-measure);
  margin-left: 0 !important;
  margin-right: auto !important;
}

/* The archive title is centred by its WIDGET box (a 274px-wide container centred in a
   1385px flex row), not by its own text-align — which is why setting text-align on the
   heading changed nothing visible. Target the widget that contains it. */
main.jupiterx-main .elementor-widget-container:has(> .raven-archive-title),
main.jupiterx-main .elementor-widget:has(.raven-archive-title),
main.jupiterx-main .elementor-element:has(> .elementor-widget-container > .raven-archive-title) {
  text-align: left !important;
  width: 100% !important;
  max-width: none !important;
  margin-left: 0 !important;
  margin-right: auto !important;
  align-self: flex-start !important;
}

/* The archive prose is Raven's own widget, .raven-archive-description — not an Elementor
   text-editor, which is why every earlier selector missed it. Measured: text-align:center,
   1000px wide, sitting at x=213 inside a 1385px row, 16px. That is the centred wall of copy
   that opens every collection page. Left-aligned, measure-limited, and set below the size of
   the collection title so the title leads. No copy is changed or hidden. */
main.jupiterx-main .raven-archive-description,
main.jupiterx-main .raven-archive-description p {
  text-align: left !important;
  font-size: var(--zg-fs-body) !important;
  line-height: var(--zg-lh-body) !important;
  /* The intro ran the full 1385px of the grid, about 147 characters a line, which is twice
     what anyone reads comfortably. The scale is useless without the column, and this needs
     the force because the archive template sets max-width:none on the same element. */
  max-width: var(--zg-measure) !important;
  color: #3A382F;
}

main.jupiterx-main .raven-archive-description {
  max-width: 68ch !important;
  margin-left: 0 !important;
  margin-right: auto !important;
}

/* The widget box itself is centred in its flex row, so the paragraph would still sit
   mid-page even once its own text is left-aligned. */
main.jupiterx-main .elementor-widget-container:has(> .raven-archive-description),
main.jupiterx-main .elementor-widget:has(.raven-archive-description),
main.jupiterx-main .elementor-element:has(> .elementor-widget-container > .raven-archive-description) {
  width: 100% !important;
  max-width: none !important;
  margin-left: 0 !important;
  margin-right: auto !important;
  align-self: flex-start !important;
  text-align: left !important;
}

/* ---------------------------------------------------------------------------
   12. PRODUCT PAGE — let the fragrance be the headline
   ---------------------------------------------------------------------------
   Measured on Oud Absolu (1200 to 1600 DKK): the product name renders at 25px, which is
   smaller than the paragraph of description beneath it and barely larger than the nav.
   On a page whose whole job is to sell one object, the name of that object should lead.

   The buy controls are 44px tall, which reads as a form field rather than the primary
   action on the page. Raised to 54px to match the quantity stepper beside it.

   All of this uses FreightTextPro, the store's existing serif, so nothing here introduces
   a new typeface or a webfont request.
   ------------------------------------------------------------------------ */
.single-product main.jupiterx-main .product_title,
.single-product main.jupiterx-main .elementor-widget-woocommerce-product-title h1,
.single-product main.jupiterx-main h1.elementor-heading-title {
  font-family: FreightTextPro, Georgia, 'Times New Roman', serif !important;
  font-size: clamp(2.4rem, 4.2vw, 3.6rem) !important;
  line-height: 1.02 !important;
  letter-spacing: -0.012em;
  margin-bottom: 0.18em;
}

/* Primary action, sized like one. */
.single-product .single_add_to_cart_button {
  height: 54px !important;
  min-height: 54px !important;
  letter-spacing: 0.18em !important;
  font-size: 11px !important;
  text-transform: uppercase;
}

.single-product .quantity,
.single-product .quantity input,
.single-product .quantity .qty {
  height: 54px !important;
}

.single-product .pv-pills .pill label {
  min-height: 48px;
  display: inline-flex !important;
  align-items: center;
  letter-spacing: 0.12em;
}

/* Tab labels as small caps rather than sentence-case body text. */
.single-product .jet-tabs__control-inner,
.single-product .jet-tabs__control {
  font-size: 10.5px !important;
  letter-spacing: 0.2em !important;
  text-transform: uppercase;
}

/* Breadcrumb is orientation, not content. */
.single-product .woocommerce-breadcrumb {
  font-size: 10.5px !important;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

/* ---------------------------------------------------------------------------
   13. ARCHIVE HEADER — one clean column, full measure
   ---------------------------------------------------------------------------
   Two earlier attempts here made things worse, recorded so they are not repeated:

     a) Left-aligning the prose at 68ch left the title and text in a ~550px column with
        roughly 60% of the header empty beside them. A void reads as a broken layout.
     b) Turning the header row into two columns squeezed the description into a 299px
        ribbon 668px tall, because the description widget carries Elementor's own width
        setting (elementor-widget__width-initial) which the grid could not override.

   The cause of both is that these widgets have widths configured IN THE TEMPLATE, and CSS
   fighting those settings produces a different broken layout each time. So: stop fighting.
   Force the description widget to the full row width and set a comfortable measure. Title
   above, standfirst beneath it, both left-aligned, filling the column.

   The side-by-side header from the approved design needs the Elementor template edited.
   That is template work, not a stylesheet override.
   ------------------------------------------------------------------------ */
main.jupiterx-main .elementor-widget:has(.raven-archive-description),
main.jupiterx-main .elementor-element:has(> .elementor-widget-container > .raven-archive-description) {
  width: 100% !important;
  max-width: 100% !important;
  flex-basis: 100% !important;
}

main.jupiterx-main .raven-archive-description {
  max-width: 78ch !important;
}

/* ---------------------------------------------------------------------------
   14. ARCHIVE STANDFIRST — two columns instead of a lonely stripe
   ---------------------------------------------------------------------------
   The measure cap in section 13 fixed readability but left the description as a narrow
   stripe on the left of a 1865px row, with a dead third beside it. Removing the cap is not
   the answer either: full width at this size is a ~200 character line, which nobody reads.

   Setting the copy in two columns is how print solves exactly this. It fills the row, keeps
   each line at a comfortable measure, and reads as a deliberate editorial choice rather than
   a layout that ran out of content. Single column below 1100px, where two would be too tight.
   ------------------------------------------------------------------------ */
@media (min-width: 1101px) {
  main.jupiterx-main .raven-archive-description {
    max-width: none !important;
    column-count: 2;
    column-gap: 4.5rem;
    column-fill: balance;
  }

  /* Keep paragraphs from breaking awkwardly across the column boundary. */
  main.jupiterx-main .raven-archive-description p {
    break-inside: avoid-column;
    margin-bottom: 0.9em;
  }
}

/* ---------------------------------------------------------------------------
   15. SLIDE CART — a drawer over the page, not a wall in front of it
   ---------------------------------------------------------------------------
   The per-product colour snippets tinted #fkcart-modal, which is FunnelKit's full-viewport
   modal container rather than the drawer itself. Opening the cart therefore repainted the
   entire screen in the product's colour and the page disappeared behind a flat block. That
   is fixed at source in the six snippets; these rules make it structurally impossible to
   come back, and give the backdrop a proper translucent scrim so the shop stays visible
   behind the drawer.
   ------------------------------------------------------------------------ */
#fkcart-modal {
  background: transparent !important;
  background-color: transparent !important;
}

#fkcart-modal .fkcart-modal-backdrop,
.fkcart-modal-backdrop {
  background-color: rgba(20, 19, 15, 0.42) !important;
  backdrop-filter: blur(1.5px);
}

/* The drawer keeps its own surface and sits above the scrim with a soft edge. */
#fkcart-modal .fkcart-modal-container {
  box-shadow: -28px 0 60px -32px rgba(20, 19, 15, 0.55);
}

/* ---------------------------------------------------------------------------
   16. ARCHIVE STANDFIRST ON MOBILE — a different widget entirely
   ---------------------------------------------------------------------------
   Desktop renders the collection description with Raven's .raven-archive-description.
   MOBILE renders it with a JetTricks Unfold widget instead (.jet-unfold__content-inner,
   with the Read More toggle), and the Raven one is hidden at 0 width. So every rule aimed
   at .raven-archive-description did nothing on a phone, and the copy stayed centred at 16px
   there while desktop was left-aligned at 14.5px.

   Worth remembering for anything else on these templates: the mobile and desktop versions of
   this page are not the same markup. Checking one proves nothing about the other.
   ------------------------------------------------------------------------ */
.tax-product_cat main.jupiterx-main .jet-unfold__content-inner,
.tax-product_cat main.jupiterx-main .jet-unfold__content-inner p,
.post-type-archive-product main.jupiterx-main .jet-unfold__content-inner,
.post-type-archive-product main.jupiterx-main .jet-unfold__content-inner p {
  text-align: left !important;
  font-size: var(--zg-fs-body) !important;
  line-height: var(--zg-lh-body) !important;
  color: #3A382F;
}

/* The Read More control should read as a control, not as body copy. */
.tax-product_cat main.jupiterx-main .jet-unfold__trigger,
.post-type-archive-product main.jupiterx-main .jet-unfold__trigger {
  font-size: 10.5px !important;
  letter-spacing: 0.18em;
  text-transform: uppercase;
}

/* ---------------------------------------------------------------------------
   17. FOOTER — cover the mobile variant too
   ---------------------------------------------------------------------------
   Section 7 recoloured the footer by its Elementor element id (46dfcc4). That id only
   exists in the DESKTOP footer. Mobile renders a separate container (b4f1d84) which kept
   the old taupe rgb(192,183,176), so every phone still saw the mismatched footer.

   Same lesson as the archive standfirst: this site ships different markup per breakpoint,
   so a fix verified on desktop is not a fix. Both ids are listed, and the generic rule
   underneath catches any further variant by resetting solid footer containers to the page
   ground, while the newsletter block keeps its sand because it is set explicitly in 7.
   ------------------------------------------------------------------------ */
.jupiterx-footer .elementor-element-b4f1d84,
.jupiterx-footer .elementor-element-46dfcc4 {
  background-color: var(--zg-cream) !important;
}

/* Defensive: any footer container still painting the retired taupe is brought to cream. */
.jupiterx-footer > .elementor > .elementor-element > .e-con-inner > .elementor-element,
.jupiterx-footer .e-con-full {
  background-color: transparent;
}

.jupiterx-footer {
  background-color: var(--zg-cream);
}

/* ---------------------------------------------------------------------------
   18. COOKIE BANNER — a bar, not a box
   ---------------------------------------------------------------------------
   After consent moved from GTM to the CookieYes plugin, the banner became the page's
   LARGEST CONTENTFUL PAINT element and mobile LCP went from 3.8s to ~12.5s. Two reasons:
   the hero's poster is a CSS background-image, which Chrome does not count for LCP, and the
   banner is a 440 x 232 box whose paragraph is a bigger text block than anything else that
   paints early. Preconnect and preload did not shift it, because the size is the problem,
   not the download.

   Laying it out as a slim full-width bar puts the title, the notice and the buttons on one
   line. The text block shrinks well below the hero copy, so it stops being the LCP element,
   and the banner covers far less of a phone screen while still being unmissable.

   The consent MECHANISM is untouched: same buttons, same categories, same denied-by-default
   state. This is layout only.
   ------------------------------------------------------------------------ */
.cky-consent-container.cky-box-bottom-left,
.cky-consent-container.cky-box-bottom-right,
.cky-consent-container {
  left: 0 !important;
  right: 0 !important;
  bottom: 0 !important;
  width: 100% !important;
  max-width: 100% !important;
}

.cky-consent-container .cky-consent-bar {
  display: flex !important;
  align-items: center;
  gap: 2rem;
  width: 100% !important;
  max-width: 100% !important;
  padding: 0.9rem 2rem !important;
  border-radius: 0 !important;
  box-shadow: 0 -12px 32px -24px rgba(20, 19, 15, 0.5);
}

.cky-consent-container .cky-notice {
  display: flex !important;
  align-items: center;
  gap: 1.25rem;
  flex: 1 1 auto;
  width: auto !important;
  max-width: none !important;
}

.cky-consent-container .cky-notice-group {
  display: flex !important;
  align-items: center;
  gap: 1.25rem;
  flex: 1 1 auto;
  width: auto !important;
}

.cky-consent-container .cky-title {
  font-size: 13px !important;
  line-height: 1.3 !important;
  white-space: nowrap;
  margin: 0 !important;
}

.cky-consent-container .cky-notice-des,
.cky-consent-container .cky-notice-des p {
  font-size: 12.5px !important;
  line-height: 1.5 !important;
  margin: 0 !important;
}

.cky-consent-container .cky-notice-btn-wrapper {
  display: flex !important;
  align-items: center;
  gap: 0.5rem;
  flex: 0 0 auto;
  margin: 0 !important;
  padding: 0 !important;
}

.cky-consent-container .cky-btn {
  font-size: 11px !important;
  padding: 0.6rem 1.1rem !important;
  margin: 0 !important;
  white-space: nowrap;
}

/* Phones: stack, but stay compact. The description is the part that must not grow. */
@media (max-width: 860px) {
  .cky-consent-container .cky-consent-bar {
    flex-direction: column;
    align-items: stretch;
    gap: 0.75rem;
    padding: 0.9rem 1.1rem !important;
  }
  .cky-consent-container .cky-notice,
  .cky-consent-container .cky-notice-group {
    flex-direction: column;
    align-items: flex-start;
    gap: 0.35rem;
  }
  .cky-consent-container .cky-notice-des,
  .cky-consent-container .cky-notice-des p {
    font-size: 12px !important;
  }
  /* The buttons sit in a ROW that wraps, not a column. flex:1 1 0 inside the stacked
     wrapper gave them a zero flex-basis, which collapsed their height and clipped the
     labels ("ACCEPT ALL" was cut off mid-letter). Three ~110px buttons fit one row at
     375px; below that they wrap cleanly. */
  .cky-consent-container .cky-notice-btn-wrapper {
    width: 100%;
    flex-direction: row !important;
    flex-wrap: wrap;
    gap: 0.4rem;
  }
  .cky-consent-container .cky-btn {
    flex: 1 1 auto;
    min-width: 96px;
    min-height: 40px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    text-align: center;
    line-height: 1.2 !important;
  }
}

/* ---------------------------------------------------------------------------
   19. SLIDE CART — styled once, for the whole site
   ---------------------------------------------------------------------------
   The cart drawer is shared chrome, so it takes the site palette, not a product's signature
   colour. Previously each product's snippet painted the flyout in its own colour, which
   meant the cart looked different depending on which page you opened it from. Those rules
   are removed; the drawer is defined here, in one place, for every page.

   Cream body so it reads as an extension of the page, sand footer so the totals and the
   checkout button separate from the item list without needing a hard rule.
   ------------------------------------------------------------------------ */
#fkcart-modal .fkcart-modal-container,
#fkcart-modal .fkcart-preview-ui,
#fkcart-modal .fkcart-slider-header,
#fkcart-modal .fkcart-slider-body,
#fkcart-modal .fkcart-zero-state,
#fkcart-modal .fkcart-item-wrap {
  background-color: var(--zg-cream) !important;
}

#fkcart-modal .fkcart-slider-footer {
  background-color: var(--zg-sand) !important;
  border-top: 1px solid var(--zg-rule);
}

#fkcart-modal .fkcart-slider-header {
  border-bottom: 1px solid var(--zg-rule);
}

/* Item thumbnails get the same warm ground as the product grid, so the white-background
   product shots do not read as bright tiles inside a cream drawer. */
#fkcart-modal .fkcart-item-image,
#fkcart-modal .fkcart-item-image img {
  background-color: var(--zg-ground);
}

/* ---------------------------------------------------------------------------
   20. ANNOUNCEMENT BAR — the last visible layout shift
   ---------------------------------------------------------------------------
   Measured with Playwright, recording layout-shift entries with their sources:

       home (iPhone 13)  shift 0.0013 @2696ms
         DIV.elementor-element-2fd10726   350x35 -> 350x12   (moved down 13px)

   The bar's three messages are a JetEngine repeater driven by Slick (snippet 22338,
   vertical slider). Until Slick initialises, all three messages stack and the bar is 35px
   tall; the moment it initialises only one is shown and the bar collapses to 12px, dragging
   the whole page up 23px. Small in CLS terms, but it happens right where the eye is, about
   2.7 seconds in, which is exactly the flicker that is noticeable.

   Hiding the other messages until Slick is ready makes the pre-init height identical to the
   settled height, so nothing moves. Scoped with :not(.slick-initialized) — Slick adds that
   class as its first act — so once the slider is running these rules no longer apply and
   the rotation is completely untouched. No !important, so Slick's own inline styles always
   win regardless.
   ------------------------------------------------------------------------ */
/* Reserve the height and show NOTHING until Slick is ready.
   An earlier version hid all children after the first, which did not match the pre-init
   markup: the messages stayed stacked and the overflow:hidden then sliced two of them
   inside an 18px box, so the bar looked broken during load. Hiding the whole strip while
   holding its height keeps the page from shifting AND never shows a half-drawn bar. */
.text-slider:not(.slick-initialized) {
  visibility: hidden;
  height: 18px;
  overflow: hidden;
}

/* ---------------------------------------------------------------------------
   21. RESERVE SPACE FOR TWO LATE-ARRIVING ELEMENTS
   ---------------------------------------------------------------------------
   Traced with Playwright, sampling element heights every 120ms from first paint on a
   collection page (iPhone 13):

       t=1673   header 48   logo   0    unfold 100   grid at y=251
       t=1744   header 55   logo  35    unfold 100   grid at y=258   <- +7px
       t=2952   header 55   logo  35    unfold 146   grid at y=304   <- +46px

   TWO separate causes, both "an element appears and pushes the page down":

   1. The header logo measures 0 until it resolves, then 35px, growing the header from 48
      to 55. The <img> does carry width/height attributes (71x29), but the rendered size is
      85x35 and the element reads as 0 in the interim, so the attributes are not reserving
      anything here. A min-height on the header row holds the final height from the start.

   2. The Unfold widget's mask is a fixed 100px from the beginning (JetTricks writes
      height:100px inline), but its "Read More" TRIGGER is inserted afterwards and adds
      46px. Reserving the settled total stops the grid being shoved down mid-read.

   Both are reservations only: nothing is hidden, no behaviour changes, and if content ends
   up taller than the reservation it simply grows into it without a shift.
   ------------------------------------------------------------------------ */
@media (max-width: 1024px) {
  header.jupiterx-header #header-row {
    min-height: 55px;
  }
}

/* The same logo shift happens on DESKTOP, where the header settles at 63px. The first
   version of this rule was scoped to max-width:1024px, so desktop kept the shift — it
   showed up in the Playwright trace as an identical 0.0046 entry on EVERY desktop page:

       main       0,56 1440x844 -> 0,63 1440x837   (down 7px)
       mega menu  20,19  655x18 -> 20,22  655x18   (down 3px)
       wishlist  1361,18 30x20 -> 1361,21 30x20   (down 3px)

   Measured settled heights: 55px at <=1024, 63px above. The values are set per breakpoint
   rather than reserving the logo itself, because the desktop logo is 37px tall and the
   mobile one 35px — a single min-height on the image would introduce a 2px shift at the
   other breakpoint. */
@media (min-width: 1025px) {
  header.jupiterx-header #header-row {
    min-height: 63px;
  }
}

.tax-product_cat main.jupiterx-main .jet-unfold,
.post-type-archive-product main.jupiterx-main .jet-unfold {
  min-height: 146px;
}

/* ---------------------------------------------------------------------------
   22. CHECKOUT PHONE FIELD — the wrong country flag
   ---------------------------------------------------------------------------
   The phone field showed an Ethiopian flag next to +45. The country logic was never wrong:
   the element carries class="iti__flag iti__dk" and its own aria-label reads "currently
   selected Denmark (Danmark) (+45)". The wrong PICTURE was being drawn.

   Two versions of intl-tel-input are loaded on the checkout at once:

     FunnelKit  (funnel-builder-pro/modules/checkout/assets/css/intlTelInput.css) — v19.
       Positions flags arithmetically from custom properties:
         --iti-flag-count: 244   --iti-flag-width: 20px   .iti__dk { --iti-flag-offset: -57 }
         background-position: calc(var(--iti-flag-offset) * var(--iti-flag-width))
       For Denmark that is -57 * 20px = -1140px, against FunnelKit's own sprite.

     Raven (jupiterx-core .../raven/assets/css/frontend.min.css) — v17.
       Hardcodes a pixel offset per country for the OLD sprite layout, 265 rules of the form
         .iti__flag.iti__dk { height: 15px; background-position: -1335px 0 }

   Raven's selector (two classes) outranks FunnelKit's variable-driven rule, so the OLD
   offset is applied to the NEW sprite. -1335px instead of -1140px is 195px along a sprite
   of 20px flags: about ten countries off, which lands on Ethiopia.

   The fix restores FunnelKit's arithmetic for EVERY country rather than patching Denmark,
   so any customer's country renders correctly. Values are taken from FunnelKit's own
   stylesheet, with its defaults as fallbacks.
   ------------------------------------------------------------------------ */
.iti .iti__flag,
.wfacp-form .iti__flag,
body.woocommerce-checkout .iti__flag {
  background-position: calc(var(--iti-flag-offset, 100) * var(--iti-flag-width, 20px)) 0 !important;
  background-size: calc(var(--iti-flag-count, 244) * var(--iti-flag-width, 20px)) var(--iti-flag-height, 15px) !important;
  width: var(--iti-flag-width, 20px) !important;
  height: var(--iti-flag-height, 15px) !important;
}

/* ---------------------------------------------------------------------------
   23. FREE-SAMPLE MODAL AT CHECKOUT — attempt reverted, see note
   ---------------------------------------------------------------------------
   An earlier version of this section rebuilt the sampler modal as a normal centred dialog
   (height:auto, max-height:85vh, internal scroll). It BROKE the modal: the panel collapsed
   to 64px and showed only its header, because the plugin positions the carousel inside a
   .wgb-page whose height it controls itself, and overriding that height removed the box the
   slides are laid out in.

   Reverted rather than patched further. The underlying complaint is real — the panel is a
   fixed 356px while its content is taller, which is what produces the clipped edge and the
   stray page text around its boundary — but fixing it needs the plugin's own carousel
   sizing understood first, not more CSS pushed against it.

   Note for whoever picks this up: the plugin is pinned at 2.6.0 on purpose (4.1.0 breaks
   the popup entirely, see pin-free-gifts.php), so a plugin update is not the way out.
   ------------------------------------------------------------------------ */

/* ---------------------------------------------------------------------------
   24. CHECKOUT — the invisible second button
   ---------------------------------------------------------------------------
   Below "PLACE ORDER NOW" sat a second black rectangle with no readable label. Measured:

       a.button.jupiterx-continue-shopping
         text  "Continue Shopping"
         background-color  rgb(0, 0, 0)
         color             rgb(0, 0, 0)      <- identical

   The link was never missing; it was black text on a black background, so it rendered as a
   solid block. On the most important page of the shop, directly under the pay button.

   Rather than just recolouring the text, this is set as a quiet text link. "Continue
   Shopping" is a secondary action and should not compete with the primary one: two
   full-width black buttons stacked together give a customer no signal about which to press.
   Place Order stays the only heavy element in that group.
   ------------------------------------------------------------------------ */
/* Specificity note: the Customizer's Additional CSS carries
       .woocommerce a.button { background-color: #000 !important }
   which is (0,2,1) — the same as a.button.jupiterx-continue-shopping — and it loads AFTER
   this stylesheet, so an equal-specificity rule here loses the tie. The selectors below add
   the .woocommerce / body ancestor to reach (0,3,1) and win on merit rather than by luck of
   source order. */
.woocommerce a.button.jupiterx-continue-shopping,
body.woocommerce-checkout a.button.jupiterx-continue-shopping,
body .jupiterx-continue-shopping,
a.button.jupiterx-continue-shopping {
  background-color: transparent !important;
  border: 0 !important;
  color: var(--zg-ink) !important;
  font-size: 12px !important;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  text-decoration: underline;
  text-underline-offset: 4px;
  padding: 0.85rem 0 !important;
  width: auto !important;
  min-width: 0 !important;
  display: inline-block !important;
  transition: opacity 160ms var(--zg-ease);
}

.woocommerce a.button.jupiterx-continue-shopping:hover,
body.woocommerce-checkout a.button.jupiterx-continue-shopping:hover,
body .jupiterx-continue-shopping:hover,
a.button.jupiterx-continue-shopping:hover {
  background-color: transparent !important;
  color: var(--zg-ink) !important;
  opacity: 0.62;
}

/* ---------------------------------------------------------------------------
   25. CHECKOUT — duplicate button, sample names, footer
   ---------------------------------------------------------------------------
   Three defects, all confirmed by inspection rather than by eye:

   (a) DUPLICATE "Continue Shopping". There are TWO of them in .form-row.place-order:
           href https://houseofziggimay.com            (x=291)
           href https://houseofziggimay.com/products/  (x=420)
       Both were always in the markup. They were invisible because both were black text on
       a black background, so they read as one solid block. Section 24 made the text legible
       and the duplication became obvious — I exposed it rather than caused it, but it looked
       worse on the live checkout for a while and that is on me.
       The second (to the shop) is kept because it is the more useful destination.

   (b) FOOTER on checkout kept the retired taupe. Section 17 targeted two Elementor element
       ids; the checkout template uses a different one again. Handled generically here.
   ------------------------------------------------------------------------ */

/* Keep only the LAST Continue Shopping (the one pointing at /products/). */
.form-row.place-order .jupiterx-continue-shopping:not(:last-of-type) {
  display: none !important;
}

/* Footer: match the site ground on every template, including checkout. */
body.woocommerce-checkout .jupiterx-footer,
body.woocommerce-checkout .jupiterx-footer > *,
body[class*="wfacp"] .jupiterx-footer,
body[class*="wfacp"] .jupiterx-footer > * {
  background-color: var(--zg-cream) !important;
}

/* Sample titles are truncated in the plugin's own markup ("Grasgróinn 1.5ml Sam..."), so
   CSS cannot recover them — the characters are not there. The companion script restores the
   full name from the anchor's title attribute. These rules just let the restored name wrap
   onto a second line instead of being clipped again. */
#wgb-modal .wgb-item-title {
  white-space: normal !important;
  overflow: visible !important;
  text-overflow: clip !important;
  line-height: 1.35;
  hyphens: none;
}

/* ---------------------------------------------------------------------------
   26. CHECKOUT — bring it onto the agreed design
   ---------------------------------------------------------------------------
   Measured against the approved mockup. What already matched: section headings are
   FreightTextPro 22px, the page ground is the brand cream, and the layout is already
   form-left / summary-right. What did not:

       inputs        1px SOLID BLACK border, 48px tall
       place order   48px, 14px type
       summary       no ground of its own, so it read as part of the form

   A solid black rule around every field is the single heaviest thing on the page: eleven
   hard black rectangles stacked down the column. The mockup uses a hairline, which lets the
   fields recede and the product summary and the pay button carry the weight.

   Deliberately NOT touched: the floating-label behaviour (restyling those labels risks
   breaking the animation FunnelKit drives in JS), the field markup, and the sampler popup.
   This is surface only — no template, no plugin, no checkout logic.
   ------------------------------------------------------------------------ */

/* Fields: hairline instead of a hard black rule, and a touch more height. */
#wfacp-e-form input[type="text"],
#wfacp-e-form input[type="email"],
#wfacp-e-form input[type="tel"],
#wfacp-e-form input[type="password"],
#wfacp-e-form input[type="number"],
#wfacp-e-form select,
#wfacp-e-form textarea,
#wfacp-e-form .wfacp-form-control {
  border: 1px solid rgba(20, 19, 15, 0.22) !important;
  border-radius: 2px !important;
  background-color: #fff !important;
  transition: border-color 160ms var(--zg-ease), box-shadow 160ms var(--zg-ease);
}

#wfacp-e-form input[type="text"]:focus,
#wfacp-e-form input[type="email"]:focus,
#wfacp-e-form input[type="tel"]:focus,
#wfacp-e-form select:focus,
#wfacp-e-form textarea:focus {
  border-color: var(--zg-ink) !important;
  box-shadow: 0 0 0 3px rgba(20, 19, 15, 0.07) !important;
  outline: none !important;
}

/* The pay button is the one heavy element in the column. */
#wfacp-e-form #place_order,
body.woocommerce-checkout #place_order {
  height: 56px !important;
  min-height: 56px !important;
  font-size: 12px !important;
  letter-spacing: 0.2em !important;
  border-radius: 2px !important;
}

/* Order summary sits on its own ground so it reads as the receipt, not more form. */
.wfacp_mini_cart_start_h,
.wfacp-order-summary,
.wfacp-order-wrap {
  background-color: var(--zg-ground) !important;
}

/* Section headings: keep the serif, give them room to breathe. */
#wfacp-e-form .wfacp_section_heading {
  letter-spacing: -0.005em;
  margin-bottom: 0.85rem;
}

/* ---------------------------------------------------------------------------
   27. FREE-SAMPLE MODAL — elegant, without touching what the plugin owns
   ---------------------------------------------------------------------------
   Second attempt. The first (section 23, reverted) set height:auto on .wgb-page and
   collapsed the modal to its header, because .wgb-page is the box the plugin measures its
   carousel against. Mapped properly this time:

       .wgb-page.wgb-popup-box     absolute  784x505   <- PLUGIN OWNS THIS. Do not touch
                                                          height, position or overflow.
         .wgb-popup-header         relative  784x36
         .wgb-popup-body           static    h:0
           .wgb-popup-content      absolute  784x505  padding-top:50px  overflow:auto
             .wgb-popup-posts      784x432  padding:0 20px  overflow:auto

   Note the TWO nested scroll containers: .wgb-popup-content and .wgb-popup-posts both
   scroll. That is where the stray inner scrollbar came from, and why the "Continue without
   free samplers" link was clipped against the right edge — it sat in the gutter of the
   inner scroller. Letting only the outer one scroll fixes both without resizing anything.

   Everything else below is surface: colour, type, spacing, controls. No layout box the
   plugin measures is altered, so the carousel keeps working.
   ------------------------------------------------------------------------ */

/* One scroll container, not two. */
#wgb-modal .wgb-popup-posts {
  overflow: visible !important;
  padding: 0 28px 28px !important;
}

/* Scrim: the brand ink rather than pure black, so the page behind stays warm. */
#wgb-modal.wgb-popup {
  background-color: rgba(20, 19, 15, 0.55) !important;
}

/* Panel edge and lift. */
#wgb-modal .wgb-popup-box {
  border-radius: 2px;
  box-shadow: 0 34px 80px -34px rgba(20, 19, 15, 0.55);
}

/* Header: the serif, set as a real title, with a hairline instead of a hard edge. */
#wgb-modal .wgb-popup-header {
  border-bottom: 1px solid var(--zg-rule);
  padding: 1.15rem 3.25rem 1rem 1.75rem !important;
}

#wgb-modal .wgb-popup-title {
  font-family: FreightTextPro, Georgia, serif !important;
  font-size: 1.35rem !important;
  line-height: 1.2 !important;
  letter-spacing: 0.01em;
  text-align: left !important;
  text-transform: none !important;
  padding: 0 !important;
  margin: 0 !important;
}

/* CAREFUL: the plugin reuses .wgb-popup-close for TWO different controls — the header's
   × button AND the "Continue without free samplers" opt-out link. Styling the class
   generically (as an earlier version here did) pinned that 223px-wide text link to the
   modal's right edge with right:1.1rem, where it was clipped by the panel and split by the
   scrollbar, showing as stray fragments like "le" and "rs". Always scope by ancestor. */
#wgb-modal .wgb-popup-header .wgb-popup-close {
  right: 1.1rem !important;
  opacity: 0.55;
  transition: opacity 160ms var(--zg-ease);
}
#wgb-modal .wgb-popup-header .wgb-popup-close:hover { opacity: 1; }

/* The opt-out: a centred text link under the choices, in normal flow. Its container is
   inline-block with height 0 because its only child is absolutely positioned, so both the
   container and the link have to be brought back into flow. */
#wgb-modal .ith-btn-no-thanks-cnt {
  display: block !important;
  width: 100% !important;
  height: auto !important;
  text-align: center;
  padding: 0.25rem 0 1.5rem;
}

#wgb-modal .ith-btn-no-thanks-cnt .wgb-popup-close {
  position: static !important;
  transform: none !important;
  right: auto !important;
  top: auto !important;
  width: auto !important;
  height: auto !important;
  display: inline-block !important;
  font-size: 11px !important;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  text-decoration: underline;
  text-underline-offset: 4px;
  color: var(--zg-muted) !important;
  opacity: 1 !important;
  cursor: pointer;
}

#wgb-modal .ith-btn-no-thanks-cnt .wgb-popup-close:hover {
  color: var(--zg-ink) !important;
}

/* Sample cards: the shop's warm ground under the photography. */
#wgb-modal .wgb-item-thumb {
  background-color: var(--zg-ground);
  border-radius: 2px;
  overflow: hidden;
}

#wgb-modal .wgb-item-title {
  font-size: 11px !important;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--zg-ink);
  margin: 0.85rem 0 0.6rem !important;
  min-height: 2.6em;
}

/* "Add sample" reads like the shop's other actions. */
#wgb-modal .wgb-popup-posts .button,
#wgb-modal .wgb-add-to-cart,
#wgb-modal a[class*="add"],
#wgb-modal button[class*="add"] {
  background-color: var(--zg-ink) !important;
  color: var(--zg-cream) !important;
  border: 1px solid var(--zg-ink) !important;
  border-radius: 2px !important;
  font-size: 10.5px !important;
  letter-spacing: 0.18em !important;
  text-transform: uppercase;
  padding: 0.75rem 1.1rem !important;
  transition: opacity 160ms var(--zg-ease);
}

#wgb-modal .wgb-popup-posts .button:hover { opacity: 0.85; }

/* Already-chosen samples read as chosen rather than merely faded out. */
#wgb-modal .wgb-item.wgb-item-added .wgb-item-thumb,
#wgb-modal [class*="disabled"] .wgb-item-thumb {
  opacity: 0.5;
}

/* Carousel arrows: off the photographs, on their own surface. */
#wgb-modal .owl-nav button,
#wgb-modal .owl-prev,
#wgb-modal .owl-next {
  background: var(--zg-cream) !important;
  border: 1px solid var(--zg-rule) !important;
  border-radius: 50% !important;
  width: 36px !important;
  height: 36px !important;
  display: inline-flex !important;
  align-items: center;
  justify-content: center;
  box-shadow: 0 2px 12px -5px rgba(20, 19, 15, 0.45);
}

/* The opt-out link belongs under the choices, reading as the quiet option. */
#wgb-modal a[href*="continue"],
#wgb-modal .wgb-continue-without {
  font-size: 11px !important;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  text-decoration: underline;
  text-underline-offset: 4px;
  color: var(--zg-muted) !important;
}

/* ---------------------------------------------------------------------------
   28. PHONE FIELD ARROW — drawn once, deterministically
   ---------------------------------------------------------------------------
   The country dropdown's arrow rendered as a stray backslash. Same collision as the flag
   (section 22), three rules deep:

     Raven v17     .iti__arrow { width:0; height:0; border-top:4px solid #555;
                                 border-right:3px solid transparent; ... }   -> a triangle
     FunnelKit v19 .iti__arrow { width:var(--iti-arrow-size); height:same;
                                 border-...; }                               -> a chevron
     FunnelKit     .wfacp-intl-phone-flag-field .iti .iti__arrow
                                { transform: none !important; }

   That last rule defeats FunnelKit's OWN chevron, which only looks like a caret once it is
   rotated. Between the two libraries the element ended up 10x12px with every border width
   computed to 0 — no triangle, no chevron, just a fragment.

   Rather than pick a side, the caret is drawn here explicitly: a small square with two
   borders, rotated. It does not depend on either library's variables, so neither version
   can break it again.
   ------------------------------------------------------------------------ */
.iti .iti__arrow,
.wfacp-intl-phone-flag-field .iti .iti__arrow {
  width: 7px !important;
  height: 7px !important;
  margin-top: -3px !important;
  margin-left: 8px !important;
  border: 0 !important;
  border-right: 1.5px solid var(--zg-muted) !important;
  border-bottom: 1.5px solid var(--zg-muted) !important;
  background: none !important;
  transform: rotate(45deg) !important;
  transition: transform 180ms var(--zg-ease) !important;
}

.iti .iti__arrow--up,
.wfacp-intl-phone-flag-field .iti .iti__arrow--up {
  margin-top: 2px !important;
  transform: rotate(-135deg) !important;
}

/* ---------------------------------------------------------------------------
   29. SLIDE CART — finish the detail
   ---------------------------------------------------------------------------
   The drawer's frame was set in section 19; this is the contents. Product photography in
   the cart carries the same white background as everywhere else, so it needs the warm
   ground under it; the remove control was a default browser-blue ×; and the free-sample
   line had no visual distinction from a paid one, which undersells the thing the whole
   sampler flow exists to deliver.
   ------------------------------------------------------------------------ */
#fkcart-modal .fkcart-item-image,
#fkcart-modal .fkcart-item-image img,
#fkcart-modal .fkcart-item-thumbnail,
#fkcart-modal .fkcart-item-thumbnail img {
  background-color: var(--zg-ground);
  border-radius: 2px;
}

#fkcart-modal .fkcart-item-title,
#fkcart-modal .fkcart-item-name {
  font-size: 12px !important;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  line-height: 1.4;
}

/* Remove control: quiet until wanted. */
#fkcart-modal .fkcart-item-remove,
#fkcart-modal [class*="remove"] {
  color: var(--zg-muted) !important;
  opacity: 0.55;
  transition: opacity 160ms var(--zg-ease);
}

#fkcart-modal .fkcart-item-remove:hover,
#fkcart-modal [class*="remove"]:hover {
  opacity: 1;
  color: var(--zg-ink) !important;
}

/* A free sample should look like a gift, not like a zero. */
#fkcart-modal .fkcart-item-price,
#fkcart-modal .fkcart-item-total {
  font-variant-numeric: tabular-nums;
}

/* Quantity stepper to match the rest of the shop's controls. */
#fkcart-modal .fkcart-qty-wrap,
#fkcart-modal .fkcart-quantity {
  border: 1px solid var(--zg-rule) !important;
  border-radius: 2px;
}

#fkcart-modal .fkcart-checkout-btn,
#fkcart-modal a[class*="checkout"] {
  letter-spacing: 0.2em !important;
  font-size: 12px !important;
  border-radius: 2px !important;
}

/* ---------------------------------------------------------------------------
   30. HOMEPAGE HERO — the editorial composition from the approved design
   ---------------------------------------------------------------------------
   Done in CSS, not by editing the layout JSON. That was tried first and reverted: changing
   flex_align_items / align in _elementor_data made Elementor emit TWO unmediated rules for
   the same element (--align-items:flex-start then :center), and its own base stylesheet
   carries .e-con-boxed.e-flex { align-items: normal }, which overrides the variable on
   boxed containers anyway. The generated CSS was not predictable enough to build on.

   Alignment, spacing and type are styling, so they belong here where the cascade is under
   our control. Only genuinely NEW sections need markup, and those are injected as markup
   rather than written into Elementor's JSON.

   Desktop only. The mobile mockup keeps the hero centred, and mobile is left untouched.
   ------------------------------------------------------------------------ */
@media (min-width: 1025px) {

  /* Content sits low and to the left, over the video. */
  .elementor-19995 .elementor-element.elementor-element-243e957 {
    justify-content: flex-end !important;
    align-items: flex-start !important;
    padding: 0 3.5rem 4rem !important;
  }

  /* Elementor's own .e-con-boxed.e-flex{align-items:normal} means the inner wrapper has to
     be aligned too, or the outer alignment is silently ignored. */
  .elementor-19995 .elementor-element.elementor-element-243e957 > .e-con-inner {
    align-items: flex-start !important;
    justify-content: flex-end !important;
    width: 100%;
    max-width: 1400px;
  }

  .elementor-19995 .elementor-element.elementor-element-917764f {
    align-items: flex-start !important;
    margin-top: 0 !important;
    width: 100% !important;
    max-width: 46rem;
  }

  .elementor-19995 .elementor-element.elementor-element-21a9df3,
  .elementor-19995 .elementor-element.elementor-element-21a9df3 .elementor-heading-title,
  .elementor-19995 .elementor-element.elementor-element-9cf1b1e,
  .elementor-19995 .elementor-element.elementor-element-9cf1b1e .elementor-heading-title {
    text-align: left !important;
  }

  /* The eyebrow from the mockup. Generated rather than injected, because it is a label on
     the hero rather than content anyone needs to edit. */
  .elementor-19995 .elementor-element.elementor-element-21a9df3::before {
    content: "Niche perfume · made in Denmark";
    display: block;
    font-family: Avenir, 'Avenir Next', system-ui, sans-serif;
    font-size: 10px;
    letter-spacing: 0.24em;
    text-transform: uppercase;
    color: rgba(245, 243, 235, 0.72);
    margin-bottom: 1.1rem;
  }

  /* The subtitle reads as a standfirst under the title, not a centred caption. */
  .elementor-19995 .elementor-element.elementor-element-9cf1b1e {
    max-width: 34rem !important;
    width: auto !important;
  }
}

/* ---------------------------------------------------------------------------
   31. HOMEPAGE SAMPLE BAND — the three-point promise under the hero
   ---------------------------------------------------------------------------
   Markup comes from home-sample-band.php, injected after the hero container rather than
   written into the page's Elementor JSON. Styled here to match the approved design: the
   brand sand ground, numerals as quiet ordinals, and one restrained link.

   The numerals are real information, not decoration: they read as a sequence because the
   points ARE one — try a sample, get two free with a bottle, and it is made by hand. Order
   matters, so numbering earns its place.
   ------------------------------------------------------------------------ */
.zg-promise {
  background-color: var(--zg-sand);
  padding: 2.25rem 3.5rem;
}

.zg-promise__inner {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr)) auto;
  gap: 2.75rem;
  align-items: start;
  max-width: 1400px;
  margin: 0 auto;
}

.zg-promise__item {
  display: flex;
  gap: 1rem;
  align-items: flex-start;
}

.zg-promise__num {
  font-family: FreightTextPro, Georgia, serif;
  font-size: 0.95rem;
  line-height: 1.5;
  color: var(--zg-muted);
  flex: none;
  padding-top: 0.1rem;
}

.zg-promise__h {
  font-family: FreightTextPro, Georgia, serif;
  font-size: 1.28rem;
  line-height: 1.25;
  margin: 0 0 0.35rem;
  color: var(--zg-ink);
}

.zg-promise__p {
  font-size: 12.5px;
  line-height: 1.6;
  margin: 0;
  color: #4A473D;
  max-width: 34ch;
}

.zg-promise__cta {
  align-self: center;
  white-space: nowrap;
  font-size: 11px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--zg-ink);
  border: 1px solid var(--zg-ink);
  padding: 0.85rem 1.6rem;
  border-radius: 2px;
  transition: background-color 160ms var(--zg-ease), color 160ms var(--zg-ease);
}

.zg-promise__cta:hover {
  background-color: var(--zg-ink);
  color: var(--zg-cream);
}

@media (max-width: 1100px) {
  .zg-promise { padding: 2rem 1.5rem; }
  .zg-promise__inner { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1.75rem; }
  .zg-promise__cta { grid-column: 1 / -1; justify-self: start; }
}

@media (max-width: 700px) {
  .zg-promise { padding: 1.75rem 1.25rem; }
  .zg-promise__inner { grid-template-columns: 1fr; gap: 1.4rem; }
  .zg-promise__cta { width: 100%; text-align: center; }
}

/* ---------------------------------------------------------------------------
   32. PRODUCT PAGE — tabs become stacked sections
   ---------------------------------------------------------------------------
   Paired with the script in ziggimay-2030.js, which copies each tab's label into a heading
   above its own pane. These rules then show every pane at once and retire the tab strip.

   Scoped to body.zg-tabs-stacked, a class the script only adds once it has successfully
   built the headings. If the script does not run, or the markup changes and it bails, the
   class is absent and the tabs keep working exactly as before. The page can never end up
   with all panes visible and no headings to separate them.
   ------------------------------------------------------------------------ */
body.zg-tabs-stacked .jet-tabs__control-wrapper {
  display: none !important;
}

body.zg-tabs-stacked .jet-tabs__content {
  display: block !important;
  opacity: 1 !important;
  visibility: visible !important;
  height: auto !important;
  transform: none !important;
  position: static !important;
  padding-bottom: 1.75rem;
}

body.zg-tabs-stacked .jet-tabs__content.zg-tab-empty {
  display: none !important;
}

body.zg-tabs-stacked .zg-tab-heading {
  font-family: FreightTextPro, Georgia, serif;
  font-size: 1.32rem;
  line-height: 1.2;
  margin: 2rem 0 0.85rem;
  padding-top: 1.6rem;
  border-top: 1px solid var(--zg-rule);
  color: var(--zg-ink);
}

body.zg-tabs-stacked .zg-tab-heading:first-of-type {
  margin-top: 0;
  padding-top: 0;
  border-top: 0;
}

/* ---------------------------------------------------------------------------
   33. PRODUCT PAGE — scent pyramid
   ---------------------------------------------------------------------------
   Built by the script in ziggimay-2030.js from the product's own three note paragraphs.
   Two columns on desktop so the tier labels form a left-hand index and the notes align on a
   single edge; stacked on narrow screens, where a 90px label column would leave the notes
   squeezed into roughly twenty characters.
   ------------------------------------------------------------------------ */
.zg-pyramid {
  margin: 0;
}

.zg-pyramid__row {
  display: grid;
  grid-template-columns: 90px 1fr;
  gap: 0 1.5rem;
  align-items: baseline;
  padding: 0.9rem 0;
  border-bottom: 1px solid var(--zg-rule);
}

.zg-pyramid__row:last-child {
  border-bottom: 0;
  padding-bottom: 0;
}

.zg-pyramid__row:first-child {
  padding-top: 0;
}

.zg-pyramid__label {
  font-family: Avenir, "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-size: 0.66rem;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--zg-ink-soft, #6b6459);
  line-height: 1.6;
}

.zg-pyramid__notes {
  margin: 0;
  font-family: FreightTextPro, Georgia, serif;
  font-size: 1rem;
  line-height: 1.55;
  color: var(--zg-ink);
}

@media (max-width: 767px) {
  .zg-pyramid__row {
    grid-template-columns: 1fr;
    gap: 0.3rem;
  }
}

/* ---------------------------------------------------------------------------
   34. ONE BUTTON SYSTEM
   ---------------------------------------------------------------------------
   The homepage alone was carrying four different button treatments: black square
   ("Classic Perfume Collection", "Join Now", "Select options"), black 80px pill ("Read More"),
   white outline 50px pill ("Shop Exclusive Perfumes"), and the 2px outline the promise band
   introduced. Same page, same job, four answers.

   The system is the one the promise band and the add-to-cart already use:

     type    Avenir, 11px, 0.18em tracking, uppercase
     shape   2px radius, never a pill
     primary solid ink, cream text        (the one action that completes something)
     quiet   1px ink outline, ink text    (navigation into a collection)

   Scope: main.jupiterx-main only, and never on checkout, cart or the sampler modal. Those
   are tuned separately in sections 24, 25, 26 and 27, they are the paths where a customer
   spends money, and a broad rule reaching into them is how a working checkout gets broken.
   ------------------------------------------------------------------------ */
body:not(.woocommerce-checkout):not(.woocommerce-cart) main.jupiterx-main .elementor-button,
body:not(.woocommerce-checkout):not(.woocommerce-cart) main.jupiterx-main .jet-unfold__button,
body:not(.woocommerce-checkout):not(.woocommerce-cart) main.jupiterx-main a.button.add_to_cart_button,
body:not(.woocommerce-checkout):not(.woocommerce-cart) main.jupiterx-main a.button.product_type_variable {
  border-radius: 2px !important;
  font-size: 11px !important;
  letter-spacing: 0.18em !important;
  text-transform: uppercase;
  font-weight: 500;
  transition: background-color 160ms var(--zg-ease), color 160ms var(--zg-ease),
              border-color 160ms var(--zg-ease);
}

/* Quiet: links into a collection. These navigate, they do not commit the customer to
   anything, so they should not carry the weight of a filled button. */
body.home main.jupiterx-main .elementor-element-13a3ae5 .elementor-button,
body:not(.woocommerce-checkout):not(.woocommerce-cart) main.jupiterx-main .jet-unfold__button {
  background-color: transparent !important;
  color: var(--zg-ink) !important;
  border: 1px solid var(--zg-ink) !important;
}

body.home main.jupiterx-main .elementor-element-13a3ae5 .elementor-button:hover,
body:not(.woocommerce-checkout):not(.woocommerce-cart) main.jupiterx-main .jet-unfold__button:hover {
  background-color: var(--zg-ink) !important;
  color: var(--zg-cream) !important;
}

/* The two buttons over the dark imagery keep their light treatment, since ink on a
   photograph would be unreadable. Only the shape and type are brought into line. */
body.home main.jupiterx-main .elementor-element-a018c0c .elementor-button {
  border-radius: 2px !important;
  border-color: #fff !important;
}

/* ---------------------------------------------------------------------------
   35. FREE SAMPLER MODAL — carousel becomes a grid
   ---------------------------------------------------------------------------
   The Owl carousel showed 2.9 cards in an 859px viewport, so there was always a card sliced
   down the middle and a perfume name cut mid-word ("LUMINOUS PETAL T..."). Paging past nine
   samples to choose two is also more work than the choice deserves.

   The nine samples now sit in a grid, all visible at once. Owl still initialises and still
   owns the markup; these rules only neutralise its layout maths:

     .owl-stage        drops the translate3d and the 5599px width, becomes the grid
     .owl-item         drops its inline width and right margin, becomes a grid cell
     .owl-stage-outer  stops clipping
     .owl-item.cloned  hidden, or Owl's duplicate slides would show as real cards

   Inline styles lose to !important here, so Owl re-running on resize cannot undo it.

   The Add buttons are outlines rather than filled blocks: nine solid black rectangles in one
   modal is a wall, and the customer is picking, not paying. The filled treatment stays where
   it belongs, on Place Order.
   ------------------------------------------------------------------------ */
/* The plugin sizes this box with percentage heights all the way down: .wgb-page 100%,
   .wgb-popup-box 80%, .wgb-popup-content 95% with a min-height. Over five samples that
   produced a 903px box holding 250px of content, so most of the modal was empty. Every
   height in the chain is released to auto and the box sizes to what is actually in it.
   Do not reintroduce flex here: making .wgb-page a flex column collapsed .wgb-popup-body
   to 0px while its content overflowed at full height. */
/* .wgb-page is absolutely positioned at top:0 bottom:0 left:0 right:0, so with height:auto it
   stretches to the whole overlay and the 86vh cap became its height. Pinning only the top and
   pulling it back by half its own height centres it on the height it actually needs.

   .wgb-popup-content is absolutely positioned too, with a fixed bottom offset measured against
   .wgb-page, so its height was derived from the box height rather than its contents. Returning
   it to normal flow reverses that: the content sizes itself, and the box follows. */
#wgb-modal .wgb-page {
  max-width: min(1040px, calc(100vw - 48px)) !important;
  width: min(1040px, calc(100vw - 48px)) !important;
  top: 50% !important;
  bottom: auto !important;
  left: 0 !important;
  right: 0 !important;
  margin-left: auto !important;
  margin-right: auto !important;
  transform: translateY(-50%) !important;
  height: auto !important;
  max-height: 86vh !important;
  overflow-y: auto !important;
  overflow-x: hidden !important;
  scrollbar-width: thin;
  scrollbar-color: rgba(20, 19, 15, 0.28) transparent;
}

#wgb-modal .wgb-popup-content {
  position: static !important;
  top: auto !important;
  bottom: auto !important;
}

#wgb-modal .wgb-popup-body,
#wgb-modal .wgb-popup-content,
#wgb-modal .wgb-popup-posts {
  height: auto !important;
  min-height: 0 !important;
  max-height: none !important;
  overflow: visible !important;
}

#wgb-modal .wgb-page::-webkit-scrollbar { width: 8px; }
#wgb-modal .wgb-page::-webkit-scrollbar-track { background: transparent; }
#wgb-modal .wgb-page::-webkit-scrollbar-thumb {
  background: rgba(20, 19, 15, 0.22);
  border-radius: 99px;
}

/* Neutralise the carousel. */
#wgb-modal .owl-stage-outer {
  overflow: visible !important;
  width: auto !important;
  height: auto !important;
}

#wgb-modal .owl-stage {
  transform: none !important;
  width: 100% !important;
  height: auto !important;
  display: grid !important;
  /* auto-fit rather than a fixed column count: there are five samples today and they land on
     one row, but the shop can add or retire samples without this needing a second thought. */
  grid-template-columns: repeat(auto-fit, minmax(168px, 1fr));
  gap: 1.75rem 1.5rem;
  transition: none !important;
}

#wgb-modal .owl-item {
  width: auto !important;
  max-width: none !important;
  margin: 0 !important;
  float: none !important;
  display: block !important;
}

#wgb-modal .owl-item.cloned { display: none !important; }
#wgb-modal .owl-nav,
#wgb-modal .owl-dots { display: none !important; }

/* The card. */
#wgb-modal .wgb-product-item-cnt {
  display: flex;
  flex-direction: column;
  height: 100%;
  gap: 0.75rem;
}

#wgb-modal .wgb-item-thumb {
  background: var(--zg-ground);
  border-radius: 2px;
  overflow: hidden;
  aspect-ratio: 1 / 1;
}

#wgb-modal .wgb-item-thumb img {
  width: 100% !important;
  height: 100% !important;
  object-fit: cover;
  display: block;
}

/* The name gets two lines and is never cut. A fixed min-height keeps every Add button on the
   same baseline whether the name runs to one line or two. */
#wgb-modal .wgb-item-title,
#wgb-modal .wgb-item-title a {
  font-family: Avenir, "Helvetica Neue", Helvetica, Arial, sans-serif !important;
  font-size: 10.5px !important;
  font-weight: 500 !important;
  letter-spacing: 0.14em !important;
  line-height: 1.5 !important;
  text-transform: uppercase;
  color: var(--zg-ink) !important;
  text-decoration: none;
  overflow: visible !important;
  white-space: normal !important;
  text-overflow: clip !important;
}

#wgb-modal .wgb-item-content {
  margin: 0 !important;
  padding: 0 !important;
  min-height: 2.6em;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  text-align: center;
}

#wgb-modal .wgb-item-title { margin: 0 !important; }

#wgb-modal a.wgb-add-gift-btn {
  margin-top: auto;
  display: block;
  width: 100%;
  text-align: center;
  padding: 0.8rem 0.5rem;
  background: transparent !important;
  color: var(--zg-ink) !important;
  border: 1px solid var(--zg-ink) !important;
  border-radius: 2px !important;
  font-size: 10.5px !important;
  letter-spacing: 0.18em !important;
  font-weight: 500;
  text-transform: uppercase;
  text-decoration: none;
  transition: background-color 160ms var(--zg-ease), color 160ms var(--zg-ease);
}

#wgb-modal a.wgb-add-gift-btn:hover {
  background: var(--zg-ink) !important;
  color: var(--zg-cream) !important;
}

/* Already in the basket. Reads as "done", not as "broken". */
#wgb-modal a.wgb-add-gift-btn.wgb-disable-gift-button {
  background: var(--zg-sand) !important;
  border-color: transparent !important;
  color: var(--zg-muted) !important;
  cursor: default;
  pointer-events: none;
}

@media (max-width: 820px) and (min-width: 601px) {
  #wgb-modal .owl-stage { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* On a phone the square-card grid put two samples on screen and pushed the rest below the
   fold, so the choice looked shorter than it is. Each sample becomes a row instead: the
   thumbnail small on the left, the name and its button on the right. Four samples then sit on
   one screen with nothing to scroll for. */
@media (max-width: 600px) {
  #wgb-modal .wgb-page {
    max-width: calc(100vw - 24px) !important;
    width: calc(100vw - 24px) !important;
  }

  #wgb-modal .wgb-popup-header { padding: 1rem 3rem 0.85rem 1.15rem !important; }

  #wgb-modal .wgb-popup-header h2,
  #wgb-modal .wgb-popup-header .wgb-popup-title {
    font-size: 1.15rem !important;
    line-height: 1.25 !important;
  }

  #wgb-modal .wgb-popup-posts { padding: 0 1.15rem 1.15rem !important; }

  #wgb-modal .owl-stage {
    grid-template-columns: 1fr;
    gap: 0.65rem;
  }

  #wgb-modal .wgb-product-item-cnt {
    display: grid;
    grid-template-columns: 52px minmax(0, 1fr) auto;
    align-items: center;
    gap: 0 0.75rem;
    padding-bottom: 0.65rem;
    border-bottom: 1px solid var(--zg-rule);
  }

  #wgb-modal .owl-item:last-child .wgb-product-item-cnt {
    border-bottom: 0;
    padding-bottom: 0;
  }

  #wgb-modal .wgb-item-thumb { width: 52px; }

  #wgb-modal .wgb-item-content {
    min-height: 0;
    text-align: left;
    justify-content: flex-start;
  }

  #wgb-modal .wgb-item-title,
  #wgb-modal .wgb-item-title a { font-size: 10px !important; letter-spacing: 0.1em !important; }

  #wgb-modal a.wgb-add-gift-btn {
    margin-top: 0;
    width: auto;
    white-space: nowrap;
    padding: 0.6rem 0.8rem;
    font-size: 9.5px !important;
    letter-spacing: 0.14em !important;
  }
}

/* Duplicate sample cards, marked by the script in ziggimay-2030.js. See section 35. */
#wgb-modal .owl-item.zg-dupe { display: none !important; }

/* Already chosen.
   The plugin marks a chosen sample by laying a 60% cream veil over the whole card
   (div.disable-hover::after), which fades the photograph, the name and the button together and
   reads as "this is broken" rather than "you have this one". The card stays fully legible and
   the button alone carries the state.

   The label is swapped in CSS rather than JS: the button's text is a bare text node, so
   font-size:0 on the button plus a sized ::after replaces "Add Sample" with "Added" without
   touching the DOM the plugin owns. */
#wgb-modal .wgb-product-item-cnt.disable-hover::after {
  display: none !important;
}

#wgb-modal .disable-hover .wgb-add-gift-btn,
#wgb-modal a.wgb-add-gift-btn.wgb-disable-gift-button {
  background: var(--zg-sand) !important;
  border-color: transparent !important;
  color: var(--zg-muted) !important;
  cursor: default;
  pointer-events: none;
  font-size: 0 !important;
}

#wgb-modal .disable-hover .wgb-add-gift-btn::after,
#wgb-modal a.wgb-add-gift-btn.wgb-disable-gift-button::after {
  content: "Added";
  font-size: 10.5px;
  letter-spacing: 0.18em;
  font-weight: 500;
}

/* The thumbnail of a chosen sample sits on the sand ground, so the row still reads at a
   glance without dimming the product photograph. */
#wgb-modal .disable-hover .wgb-item-thumb {
  background: var(--zg-sand);
}

/* ---------------------------------------------------------------------------
   36. CHECKOUT — one split instead of four bands
   ---------------------------------------------------------------------------
   Measured across a 1920px window, the checkout painted five vertical bands in three
   colours: cream to 353, white to 1013 (the form column), cream to 1058, the summary ground
   to 1553, then cream to the edge. The white form slab floated in the middle of the page
   with cream on both sides and the summary sat in a detached rectangle, which is what made
   the page read as a narrow strip rather than a designed layout.

   It becomes one edge-to-edge split: white under the form, the warm ground under the
   summary, meeting exactly on the column boundary. The Elementor container still holds the
   content at 1200px, so only the colour bleeds, not the layout.

   The split sits at calc(50% + 60px): the container is 1200px wide and centred, and the form
   column is 660px, so its right edge is 60px past the centre line. Below 1200px the container
   goes fluid and the columns fall back to their 55/45 percentages, so the split follows at
   55%. Below 1025px the columns stack and the whole thing is switched off.
   ------------------------------------------------------------------------ */
@media (min-width: 1025px) {
  body.woocommerce-checkout .elementor-21834 .elementor-top-section {
    background-image: linear-gradient(
      to right,
      #ffffff 0, #ffffff 55%,
      var(--zg-ground) 55%, var(--zg-ground) 100%
    );
  }

  /* The columns and the summary wrapper carry their own grounds, which would re-draw the old
     seams on top of the gradient. */
  body.woocommerce-checkout .elementor-21834 .elementor-top-section > .elementor-container > .elementor-column > .elementor-widget-wrap,
  body.woocommerce-checkout .wfacp_wrapper_start {
    background-color: transparent !important;
  }

  /* The summary stays in view while the form is filled in. */
  body.woocommerce-checkout .wfacp_wrapper_start {
    position: sticky;
    top: 88px;
  }
}

@media (min-width: 1200px) {
  body.woocommerce-checkout .elementor-21834 .elementor-top-section {
    background-image: linear-gradient(
      to right,
      #ffffff 0, #ffffff calc(50% + 60px),
      var(--zg-ground) calc(50% + 60px), var(--zg-ground) 100%
    );
  }
}

/* ---------------------------------------------------------------------------
   37. CHECKOUT — the pay button and its escape hatch
   ---------------------------------------------------------------------------
   Section 24 turned "Continue Shopping" into a quiet text link, but it still rendered as a
   129px bordered box wedged under the pay button. The reason is specificity, not source
   order: the Customizer's Additional CSS (now served as custom-*.css) carries

       body #wfacp-e-form .button { border: 1px !important }
       #wfacp-e-form .wfacp_main_form ... a { color: #000 !important }

   which are (1,1,1) and (1,2,1) thanks to the #wfacp-e-form id. Section 24's strongest
   selector was (0,3,1), so it lost on merit even with !important. Adding the same id here
   clears it. That Additional CSS is the shop owner's own and is left untouched.

   The hierarchy this restores: Place Order is the only heavy element in the group, and the
   way back to the shop is a quiet link under it.
   ------------------------------------------------------------------------ */
body #wfacp-e-form a.button.jupiterx-continue-shopping,
body #wfacp-e-form .wfacp-form a.button.jupiterx-continue-shopping {
  background-color: transparent !important;
  border: 0 !important;
  color: var(--zg-ink) !important;
  font-size: 11px !important;
  letter-spacing: 0.16em !important;
  text-transform: uppercase;
  text-decoration: underline !important;
  text-underline-offset: 4px;
  width: auto !important;
  min-width: 0 !important;
  height: auto !important;
  padding: 0 !important;
  margin: 1.35rem auto 0 !important;
  display: block !important;
  text-align: center;
  line-height: 1.4;
}

body #wfacp-e-form a.button.jupiterx-continue-shopping:hover {
  background-color: transparent !important;
  color: var(--zg-ink) !important;
  opacity: 0.62;
}

/* The theme prints this link twice. Section 24 hid the first copy, but the display:block above
   is stronger than that rule and brought it back, so the hide is restated at this specificity.
   Keep these two rules together: raising one without the other shows the duplicate again. */
body #wfacp-e-form .form-row.place-order a.button.jupiterx-continue-shopping:not(:last-of-type),
body #wfacp-e-form .wfacp-order-place-btn-wrap ~ a.button.jupiterx-continue-shopping:not(:last-of-type) {
  display: none !important;
}

/* The one action that completes the order, in the brand's ink rather than pure black. */
body #wfacp-e-form #place_order,
body #wfacp-e-form .wfacp-order-place-btn-wrap #place_order {
  background-color: var(--zg-ink) !important;
  border-color: var(--zg-ink) !important;
  color: var(--zg-cream) !important;
  border-radius: 2px !important;
  letter-spacing: 0.2em !important;
}

body #wfacp-e-form #place_order:hover {
  background-color: #262319 !important;
  border-color: #262319 !important;
}

/* ---------------------------------------------------------------------------
   38. CHECKOUT — the design from the mockup
   ---------------------------------------------------------------------------
   Page title and a line of reassurance, three numbered steps, labels sitting above their
   fields instead of floating inside them, and an order panel that reads as a receipt.
   The step numbers and headings are written by the script in ziggimay-2030.js; everything
   below is presentation.

   Selectors carry #wfacp-e-form because the Customizer's Additional CSS uses that id and
   would otherwise win on specificity. See section 37.
   ------------------------------------------------------------------------ */
.zg-checkout-head { margin: 0 0 2.5rem; }

body #wfacp-e-form .zg-checkout-head h1 {
  font-family: FreightTextPro, Georgia, 'Times New Roman', serif !important;
  font-size: clamp(2.1rem, 3.4vw, 2.9rem) !important;
  font-weight: 400 !important;
  line-height: 1.05 !important;
  letter-spacing: -0.01em;
  color: var(--zg-ink) !important;
  margin: 0 0 0.4rem !important;
  text-transform: none !important;
}

body #wfacp-e-form .zg-checkout-head p {
  margin: 0 !important;
  font-size: 12px !important;
  letter-spacing: 0.04em;
  color: var(--zg-muted) !important;
}

/* Numbered steps. */
body #wfacp-e-form .zg-step-heading {
  font-family: Avenir, "Helvetica Neue", Helvetica, Arial, sans-serif !important;
  font-size: 10.5px !important;
  font-weight: 500 !important;
  letter-spacing: 0.2em !important;
  text-transform: uppercase;
  color: var(--zg-muted) !important;
  margin: 0 0 1.1rem !important;
  padding-top: 1.6rem;
  border-top: 1px solid var(--zg-rule);
}

body #wfacp-e-form .wfacp-section:first-of-type .zg-step-heading {
  padding-top: 0;
  border-top: 0;
}

/* The theme hides ::before on headings, so display has to be restated or the step number is
   generated and never painted. */
body #wfacp-e-form .zg-step-heading::before {
  content: attr(data-zg-step) ". ";
  display: inline !important;
  color: var(--zg-muted);
}

/* Labels above their fields. FunnelKit floats them inside the input by absolutely positioning
   at top:50%, which leaves the field looking empty until it is focused and makes a filled form
   hard to scan. */
body #wfacp-e-form .wfacp-form-control-wrapper label.wfacp-form-control-label {
  position: static !important;
  top: auto !important;
  left: auto !important;
  transform: none !important;
  display: block !important;
  font-size: 10px !important;
  font-weight: 500 !important;
  letter-spacing: 0.14em !important;
  text-transform: uppercase;
  color: var(--zg-muted) !important;
  background: none !important;
  padding: 0 !important;
  margin: 0 0 6px !important;
  opacity: 1 !important;
  pointer-events: none;
  max-width: none !important;
}

/* Text inputs only. A checkbox or radio carrying .wfacp-form-control would be stretched to
   48px by a blanket height, which is what turned the "different billing address" tickbox into
   a tall rectangle overlapping the Order Notes label. */
body #wfacp-e-form input.wfacp-form-control:not([type="checkbox"]):not([type="radio"]),
body #wfacp-e-form textarea.wfacp-form-control,
body #wfacp-e-form select.wfacp-form-control,
body #wfacp-e-form .wfacp-form-control-wrapper input.input-text:not([type="checkbox"]):not([type="radio"]) {
  padding: 12px 14px !important;
  height: 48px !important;
  min-height: 48px !important;
  border-radius: 2px !important;
  font-size: 14px !important;
}

/* No dimensions are set on checkboxes or radios here. The theme styles them with
   appearance:none plus explicit width and height; overriding those to auto collapsed them to
   0x0 and the "Create an account?" tickbox rendered as a bare line. Excluding them from the
   text-input rule above is all that is needed. */

body #wfacp-e-form textarea.wfacp-form-control { height: auto !important; }

/* The sampler notice. A filled sand panel shouted on a phone, where it runs the full width and
   sits directly under the page title, so it is a quiet note instead: the same information,
   without competing with the form for attention.

   It carried a 2px sand rule down its left edge. That was removed on request, and it was not
   working anyway: something outside this stylesheet was overriding the padding to
   `0 0 16px`, so the rule sat flush against the first letter of the sentence with no gap,
   which read as a stray vertical line rather than as a margin note. */
body #wfacp-e-form .woocommerce-info {
  background: transparent !important;
  border: 0 !important;
  border-radius: 0;
  color: var(--zg-muted) !important;
  padding: 0.15rem 0 !important;
  margin-bottom: 1.6rem !important;
  font-size: 12.5px;
  line-height: 1.6;
}

body #wfacp-e-form .woocommerce-info a {
  color: var(--zg-ink) !important;
  text-underline-offset: 3px;
}

body #wfacp-e-form .woocommerce-info::before { display: none !important; }

/* Order panel. */
body .wfacp_wrapper_start .zg-order-heading,
body .wfacp_wrapper_start .wfacp-order-summary-label {
  font-family: Avenir, "Helvetica Neue", Helvetica, Arial, sans-serif !important;
  font-size: 10.5px !important;
  font-weight: 500 !important;
  letter-spacing: 0.2em !important;
  text-transform: uppercase;
  color: var(--zg-muted) !important;
  margin-bottom: 1.4rem !important;
}

/* The one action that spends money, and the reassurance that belongs with it. */
body #wfacp-e-form .wfacp-order-place-btn-wrap { position: relative; }

body #wfacp-e-form .wfacp-order-place-btn-wrap::after {
  content: "Secured by Stripe";
  display: block;
  text-align: center;
  margin-top: 0.75rem;
  font-size: 10.5px;
  letter-spacing: 0.1em;
  color: var(--zg-muted);
}

/* ---------------------------------------------------------------------------
   39. CHECKOUT — the order panel as a receipt
   ---------------------------------------------------------------------------
   Product name in the serif, its variant underneath as a quiet caption, price aligned right on
   tabular figures so the column reads straight down. The name and variant are separated by the
   script in ziggimay-2030.js.
   ------------------------------------------------------------------------ */
body .wfacp_wrapper_start .wfacp-pro-thumb img {
  width: 56px !important;
  height: 56px !important;
  object-fit: cover;
  background: var(--zg-cream);
  border-radius: 2px;
}

body .wfacp_wrapper_start .zg-item-name {
  display: block;
  font-family: FreightTextPro, Georgia, serif;
  font-size: 15px;
  line-height: 1.25;
  color: var(--zg-ink);
  text-transform: none;
  letter-spacing: 0;
}

body .wfacp_wrapper_start .zg-item-meta {
  display: block;
  margin-top: 3px;
  font-family: Avenir, "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-size: 9.5px;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--zg-muted);
}

body .wfacp_wrapper_start .product-total,
body .wfacp_wrapper_start .order-total .amount,
body .wfacp_wrapper_start .cart-subtotal .amount {
  font-variant-numeric: tabular-nums;
  text-align: right;
  white-space: nowrap;
}

/* Totals: the number a customer checks twice gets the serif and the weight. */
body .wfacp_wrapper_start .order-total {
  font-family: FreightTextPro, Georgia, serif;
}

body .wfacp_wrapper_start .order-total .amount {
  font-size: 1.4rem;
}


/* ---------------------------------------------------------------------------
   40. FONT ALIAS — Avenir-Regular
   ---------------------------------------------------------------------------
   An audit of every visible text node found rules asking for the family "Avenir-Regular"
   (10 elements on the collection pages, 3 on a product page). No @font-face declares that
   name, only "Avenir", so those elements silently fell back to the browser's default sans
   while everything around them was set in the brand face.

   Rather than hunt down each rule across the theme, Customizer CSS and page builder, the name
   is declared and pointed at the Book weight that "Regular" means here. The file is already
   downloaded and preloaded for "Avenir", so this costs no extra request.
   ------------------------------------------------------------------------ */
@font-face {
  font-family: 'Avenir-Regular';
  src: url('/wp-content/uploads/2024/07/Avenir-Book-1.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

/* ---------------------------------------------------------------------------
   41. HOMEPAGE — the collections grid
   ---------------------------------------------------------------------------
   The section showed three of five perfumes inside a Swiper carousel, so two of the house's
   five fragrances were behind an arrow on the page most visitors land on. Swiper's layout is
   neutralised the same way the sampler modal's carousel was, and all five sit in one row.

   auto-fit rather than a fixed five columns: the shop can add or retire a fragrance without
   this leaving a hole or an orphan on its own row.
   ------------------------------------------------------------------------ */
.zg-collections-eyebrow {
  font-family: Avenir, "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--zg-muted);
  margin: 0 0 0.5rem;
  text-align: center;
}

body.home .zg-collections .swiper-wrapper {
  display: grid !important;
  grid-template-columns: repeat(auto-fit, minmax(215px, 1fr));
  gap: 2.25rem 1.5rem;
  transform: none !important;
  width: 100% !important;
  height: auto !important;
  transition: none !important;
}

body.home .zg-collections .swiper-slide {
  width: auto !important;
  max-width: none !important;
  margin: 0 !important;
  height: auto !important;
}

body.home .zg-collections .swiper,
body.home .zg-collections .swiper-container {
  overflow: visible !important;
}

body.home .zg-collections .swiper-slide-duplicate { display: none !important; }

body.home .zg-collections .swiper-button-next,
body.home .zg-collections .swiper-button-prev,
body.home .zg-collections .elementor-swiper-button,
body.home .zg-collections .swiper-pagination { display: none !important; }

@media (max-width: 700px) {
  body.home .zg-collections .swiper-wrapper {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 1.5rem 1rem;
  }
}

/* ---------------------------------------------------------------------------
   42. CHECKOUT — label internals and inline labels
   ---------------------------------------------------------------------------
   Measured inside a 10px field label: span.optional and abbr.required were rendering at 14px
   and 12px, because the theme sets a size on them directly rather than letting them inherit.
   "PHONE (OPTIONAL)" therefore read as two different fonts in one label, which is the single
   most obvious typographic fault on the page.

   Everything inside a field label now inherits the label's own size, spacing and case, so a
   label is one piece of type. The asterisk keeps its meaning but stops shouting.

   Inline labels that sit BESIDE a control ("Create an account?", the terms line) are sentence
   text, not field labels, so they get a readable 13px rather than the 10px small caps.
   ------------------------------------------------------------------------ */
body #wfacp-e-form .wfacp-form-control-label .required,
body #wfacp-e-form .wfacp-form-control-label .optional,
body #wfacp-e-form .wfacp-form-control-label abbr,
body #wfacp-e-form .wfacp-form-control-label span {
  font-size: inherit !important;
  font-weight: inherit !important;
  letter-spacing: inherit !important;
  text-transform: inherit !important;
  font-family: inherit !important;
  color: var(--zg-muted) !important;
  text-decoration: none !important;
  border: 0 !important;
}

body #wfacp-e-form .wfacp-form-control-label .required,
body #wfacp-e-form .wfacp-form-control-label abbr.required {
  opacity: 0.75;
}

/* Labels that read as a sentence next to a control. */
body #wfacp-e-form .woocommerce-form__label-for-checkbox span,
body #wfacp-e-form .wfacp-checkbox-label,
body #wfacp-e-form .woocommerce-terms-and-conditions-wrapper label span,
body #wfacp-e-form p.bwfan_user_consent label span {
  font-size: 13px !important;
  letter-spacing: 0 !important;
  text-transform: none !important;
  color: var(--zg-ink) !important;
  line-height: 1.5;
}

/* One consistent gap under every field. */
body #wfacp-e-form .wfacp-form-control-wrapper {
  margin-bottom: 1.15rem !important;
}

@media (max-width: 600px) {
  body #wfacp-e-form .wfacp-form-control-wrapper { margin-bottom: 0.95rem !important; }
  body #wfacp-e-form .zg-step-heading { padding-top: 1.35rem; margin-bottom: 0.9rem !important; }
  .zg-checkout-head { margin-bottom: 1.6rem; }
}

/* Secondary copy on the checkout: the email-reminder note, the privacy sentence and the
   payment-method blurb were all set at body size, so explanatory text competed with the
   fields it explains. One quiet size for all of it. Links keep the ink colour so they stay
   findable. */
body #wfacp-e-form .wfacp-section p:not([class*="wfacp-form-control"]):not(.form-row),
body #wfacp-e-form .woocommerce-privacy-policy-text p,
body #wfacp-e-form .payment_box p,
body #wfacp-e-form .bwfan_email_consent,
body #wfacp-e-form .wfacp-field-description {
  font-size: 12.5px !important;
  line-height: 1.6 !important;
  color: var(--zg-muted) !important;
}

body #wfacp-e-form .wfacp-section p a,
body #wfacp-e-form .woocommerce-privacy-policy-text a {
  color: var(--zg-ink) !important;
  text-underline-offset: 3px;
}

/* The "All transactions are secure and encrypted" line sits directly under the PAYMENT step
   heading and was rendering in the serif at body size, which read as a section subtitle. */
body #wfacp-e-form .wfacp_payment > p:first-of-type {
  font-family: Avenir, "Helvetica Neue", Helvetica, Arial, sans-serif !important;
  font-size: 12.5px !important;
  color: var(--zg-muted) !important;
  margin-bottom: 1.2rem !important;
}

/* ---------------------------------------------------------------------------
   43. PRODUCT PAGE — size pills and the buy button
   ---------------------------------------------------------------------------
   Both were painted rgb(184,196,160), a sage green that appears nowhere else in the identity.
   On the buy button that was doing real damage: WooCommerce adds .disabled and
   .wc-variation-selection-needed until a size is chosen, and a pale green button reads as
   "broken" rather than "choose a size first". The most important control on the page was
   giving the wrong signal.

   Now: a size is an outline chip that fills with ink once chosen, and the buy button is the
   one solid ink element in the column. Its waiting state is sand, which reads as inactive
   without looking faulty.
   ------------------------------------------------------------------------ */
.single-product .pv-pills { gap: 8px !important; }

.single-product .pv-pills .pill label {
  background: transparent !important;
  color: var(--zg-ink) !important;
  border: 1px solid var(--zg-rule) !important;
  border-radius: 2px !important;
  font-size: 11px !important;
  letter-spacing: 0.16em !important;
  text-transform: uppercase;
  padding: 0 1.1rem !important;
  transition: background-color 160ms var(--zg-ease), color 160ms var(--zg-ease),
              border-color 160ms var(--zg-ease);
}

.single-product .pv-pills .pill label:hover {
  border-color: var(--zg-ink) !important;
}

.single-product .pv-pills .pill input:checked + label,
.single-product .pv-pills .pill.selected label,
.single-product .pv-pills .pill.active label {
  background: var(--zg-ink) !important;
  color: var(--zg-cream) !important;
  border-color: var(--zg-ink) !important;
}

/* The buy button. */
.single-product .single_add_to_cart_button,
.single-product button.single_add_to_cart_button.button.alt {
  background-color: var(--zg-ink) !important;
  border: 1px solid var(--zg-ink) !important;
  color: var(--zg-cream) !important;
  border-radius: 2px !important;
  width: 100% !important;
  transition: background-color 160ms var(--zg-ease), opacity 160ms var(--zg-ease);
}

.single-product .single_add_to_cart_button:hover {
  background-color: #262319 !important;
  border-color: #262319 !important;
}

/* Waiting for a size. */
.single-product .single_add_to_cart_button.disabled,
.single-product .single_add_to_cart_button.wc-variation-selection-needed,
.single-product button.single_add_to_cart_button.button.alt.disabled {
  background-color: var(--zg-sand) !important;
  border-color: var(--zg-sand) !important;
  color: var(--zg-muted) !important;
  cursor: not-allowed;
}

/* The quantity stepper sits beside the button, so it should match its height and weight. */
.single-product .raven-qty-button-holder .quantity,
.single-product .raven-qty-button-holder .quantity input {
  border-radius: 2px !important;
}

/* Collection eyebrow, injected by the collection-eyebrow mu-plugin. */
.zg-archive-eyebrow {
  font-family: Avenir, "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--zg-muted);
  margin: 0 0 0.6rem;
}

/* The selected size chip was filling with pure black while every other filled control uses the
   brand ink. Same shape, same weight, one colour. */
.single-product .pv-pills .pill input:checked + label {
  background: var(--zg-ink) !important;
  border-color: var(--zg-ink) !important;
}

/* Catalogue sorting: a bare browser select next to an editorial grid. */
.woocommerce main.jupiterx-main .woocommerce-ordering select,
main.jupiterx-main .raven-products-ordering select {
  border: 1px solid var(--zg-rule) !important;
  border-radius: 2px !important;
  background-color: transparent !important;
  color: var(--zg-ink) !important;
  font-size: 11px !important;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  padding: 0.7rem 2.2rem 0.7rem 0.9rem !important;
  height: auto !important;
}

/* Product eyebrow, injected by the product-eyebrow mu-plugin. */
.zg-product-eyebrow {
  font-family: Avenir, "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--zg-muted);
  margin: 0 0 0.55rem;
}

/* The specification ticks were solid black discs, which gave a list of quiet facts the visual
   weight of a call to action. A hairline ring reads as a checklist, not a set of buttons. */
.single-product main.jupiterx-main .elementor-icon-list-icon {
  color: var(--zg-ink) !important;
}

/* ---------------------------------------------------------------------------
   44. SLIDE CART
   ---------------------------------------------------------------------------
   The drawer is the moment between wanting a perfume and buying it, and it was still on the
   plugin's defaults: a 16px sans heading, the product name in uppercase sans, a square black
   checkout button. It now uses the same voice as the rest of the shop - serif for names, small
   caps for the quiet supporting facts, ink for the one action that moves forward.
   ------------------------------------------------------------------------ */
#fkcart-modal .fkcart-title {
  font-family: FreightTextPro, Georgia, serif !important;
  font-size: 1.35rem !important;
  font-weight: 400 !important;
  letter-spacing: 0 !important;
  text-transform: none !important;
  color: var(--zg-ink) !important;
}

#fkcart-modal .fkcart-image,
#fkcart-modal .fkcart-thumb-wrap img {
  border-radius: 2px;
  background: var(--zg-ground);
}

#fkcart-modal .fkcart-item-name,
#fkcart-modal .fkcart-item-title,
#fkcart-modal .fkcart--item .fkcart-item-info > a {
  font-family: FreightTextPro, Georgia, serif !important;
  font-size: 15px !important;
  font-weight: 400 !important;
  letter-spacing: 0 !important;
  text-transform: none !important;
  color: var(--zg-ink) !important;
  line-height: 1.25;
}

/* "Size: 30ml" and similar supporting lines. */
#fkcart-modal .fkcart-item-variations,
#fkcart-modal .fkcart-item-meta,
#fkcart-modal .fkcart-variation-list {
  font-size: 9.5px !important;
  font-weight: 500 !important;
  letter-spacing: 0.14em !important;
  text-transform: uppercase;
  color: var(--zg-muted) !important;
}

#fkcart-modal .fkcart-summary-line-item,
#fkcart-modal .fkcart-subtotal-wrap {
  font-size: 12.5px;
  letter-spacing: 0.04em;
}

#fkcart-modal .fkcart-subtotal-wrap .fkcart-price,
#fkcart-modal .fkcart-subtotal-amount {
  font-variant-numeric: tabular-nums;
}

/* The one action that moves the sale forward. */
#fkcart-modal .fkcart-checkout-btn,
#fkcart-modal a.fkcart-checkout,
#fkcart-modal .fkcart-footer a[href*="checkout"],
#fkcart-modal .fkcart-slider-footer a[href*="checkout"] {
  background-color: var(--zg-ink) !important;
  border: 1px solid var(--zg-ink) !important;
  color: var(--zg-cream) !important;
  border-radius: 2px !important;
  font-size: 11px !important;
  letter-spacing: 0.18em !important;
  text-transform: uppercase;
  transition: background-color 160ms var(--zg-ease);
}

#fkcart-modal .fkcart-checkout-btn:hover,
#fkcart-modal .fkcart-footer a[href*="checkout"]:hover {
  background-color: #262319 !important;
  border-color: #262319 !important;
}

/* Going back to the shop is the quiet option. */
#fkcart-modal .fkcart-continue-shopping,
#fkcart-modal .fkcart-footer a:not([href*="checkout"]) {
  font-size: 10.5px !important;
  letter-spacing: 0.16em !important;
  text-transform: uppercase;
  color: var(--zg-muted) !important;
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* ---------------------------------------------------------------------------
   45. MOBILE HEADER AND MENU
   ---------------------------------------------------------------------------
   Measured at 390px, the four header icons sat in 266-380px with their count badges
   overhanging: the wishlist badge ended at 354 and the cart icon began at 360, six pixels
   apart, while the cart badge reached 385 of 390 and hugged the screen edge. Two brown discs
   crowding two outlined icons is what made the row read as a collision.

   The badges are made smaller and pulled back over their own icons instead of past them, and
   the row is given room at the edge. Nothing is removed: search, account, wishlist and bag all
   stay, and both counts still show.
   ------------------------------------------------------------------------ */
@media (max-width: 767px) {
  /* NOTE: do not add padding to .e-con-inner here. That selector matches every nested
     container in the header, not just the icon row, and it squeezed the two-line logo until
     "ZIGGIMAY" was clipped and the bag icon was cut off at the edge. The spacing problem is
     solved entirely on the badges below, which is where it came from. */

  /* width:auto + min-width keeps a single digit perfectly round while letting a 2-digit count
     widen into a pill instead of spilling out of a fixed 12px circle. border-radius:999px
     rather than 100%, which would draw an ellipse once the badge is wider than it is tall. */
  #header-row .jet-wishlist-count-button__count,
  #header-row .jet-wishlist-count-button__count span,
  header .fkcart-shortcode-count,
  header .fkcart-item-count {
    width: auto !important;
    min-width: 12px !important;
    height: 12px !important;
    line-height: 12px !important;
    padding: 0 3px !important;
    border-radius: 999px !important;
    box-sizing: border-box !important;
    font-size: 8px !important;
    letter-spacing: 0 !important;
  }

  /* Sit the badge on its own icon rather than out into the next one. The wishlist badge is
     positioned against a link box wider than the heart, so a negative offset pushed it clear
     of the icon and to within 2px of the bag. A positive inset lands it on the icon's own
     top-right corner, which is what a count badge is meant to do. */
  header .jet-wishlist-count-button__count {
    right: 6px !important;
    left: auto !important;
    top: -2px !important;
  }

  /* THE BAG IS THE ONE ICON WHOSE BADGE MUST NOT SIT ON TOP OF IT.
     Its artwork is a trapezoid tote whose handle is a thin arc across the top centre. A 14px
     badge at right:2px covered 38.8% of the artwork, and specifically all of the handle, so
     the icon read as a bucket rather than a bag. Measured at 390px wide:
         bag artwork  x 354-371, y 19-36   (17px background, 2px 50%)
         count badge  x 356-370, y 13-27
         handle       x 359-365.5
     The badge is therefore tucked just OUTSIDE the icon's top-right corner. That is safe here
     in a way it is NOT for the wishlist badge above: the bag is the last icon in the row, so
     moving its badge right moves it into ~18px of empty space before the viewport edge rather
     than into a neighbouring icon. Verified it does not overflow: badge right edge lands at
     378 of 390, and no ancestor clips (only <body> has overflow-x:hidden, at 390).
     Do NOT "make this consistent" with the wishlist rule - that is what broke it. */
  header .fkcart-shortcode-count,
  header .fkcart-item-count {
    right: -6px !important;
    left: auto !important;
    top: -5px !important;
  }
}

/* ---------------------------------------------------------------------------
   46. MOBILE MENU TYPOGRAPHY
   ---------------------------------------------------------------------------
   The drawer set its top level items in Avenir Book at 25px: large, light and unstyled, with
   no separators and no rhythm, so it read as a list of raw links rather than the navigation of
   a perfume house. Two of those items, Classic and Exclusive, are collection names, and the
   collection pages already set those names in the serif at display size. The drawer now uses
   the same face, so tapping "Classic" leads to a page whose heading looks like what was
   tapped.

   Hairlines between rows give the list structure, and the chevrons stop competing with the
   names.
   ------------------------------------------------------------------------ */
.jet-mobile-menu__item .mobile-link.mobile-top-level-link,
.jet-mobile-menu__item > .jet-mobile-menu__item-inner > .mobile-link {
  font-family: FreightTextPro, Georgia, 'Times New Roman', serif !important;
  font-size: 1.55rem !important;
  font-weight: 400 !important;
  line-height: 1.2 !important;
  letter-spacing: 0 !important;
  text-transform: none !important;
  color: var(--zg-ink) !important;
}

/* Second level items are destinations within a collection, so they step down in size and
   change voice rather than repeating the display face. */
.jet-mobile-menu__item .mobile-link:not(.mobile-top-level-link) {
  font-family: Avenir, "Helvetica Neue", Helvetica, Arial, sans-serif !important;
  font-size: 12px !important;
  letter-spacing: 0.12em !important;
  text-transform: uppercase;
  color: var(--zg-ink) !important;
}

.jet-mobile-menu__list .jet-mobile-menu__item {
  border-bottom: 1px solid var(--zg-rule);
}

.jet-mobile-menu__list > .jet-mobile-menu__item:last-child {
  border-bottom: 0;
}

.jet-mobile-menu__item .jet-mobile-menu__item-inner {
  padding-top: 0.55rem !important;
  padding-bottom: 0.55rem !important;
}

/* The chevron is a hint, not a heading. */
.jet-mobile-menu__item .jet-dropdown-arrow,
.jet-mobile-menu__item .jet-mobile-menu__item-arrow {
  color: var(--zg-muted) !important;
  opacity: 0.7;
  font-size: 14px !important;
}

.jet-mobile-menu__container,
.jet-mobile-menu__list-wrapper {
  background-color: var(--zg-cream) !important;
}

/* ---------------------------------------------------------------------------
   47. TOUCH DEVICES — hover must not stick
   ---------------------------------------------------------------------------
   On a touch screen a tap counts as a hover and the state stays applied until something else
   is tapped. Every outline button that fills with ink on hover therefore stayed BLACK after
   being pressed: "Read More" on the collection pages, the collection links on the homepage and
   the Add Sample buttons all did it. It looked like a styling fault and it is the reason those
   controls appeared to turn black when clicked.

   Only the fills are reversed here, and only where hover is not available. Hover behaviour on a
   mouse is untouched, and the genuinely selected states (a chosen size, an added sample) are
   not hover states at all, so they still fill as intended.
   ------------------------------------------------------------------------ */
@media (hover: none) {
  .zg-promise__cta:hover,
  .zg-sample-band__cta:hover,
  body:not(.woocommerce-checkout):not(.woocommerce-cart) main.jupiterx-main .jet-unfold__button:hover,
  body.home main.jupiterx-main .elementor-element-13a3ae5 .elementor-button:hover,
  #wgb-modal a.wgb-add-gift-btn:hover {
    background-color: transparent !important;
    color: var(--zg-ink) !important;
  }

  #wgb-modal a.wgb-add-gift-btn.wgb-disable-gift-button:hover,
  #wgb-modal .disable-hover .wgb-add-gift-btn:hover {
    background-color: var(--zg-sand) !important;
    color: var(--zg-muted) !important;
  }
}

/* ---------------------------------------------------------------------------
   49. CATALOGUE SORTING — the chevron was on the wrong side
   ---------------------------------------------------------------------------
   The select painted its own chevron as a background image at "12px 50%", which put it at the
   LEFT edge sitting on top of the first letters of "Default sorting". That stray mark over the
   label is what looked like a broken glyph.
   ------------------------------------------------------------------------ */
.woocommerce main.jupiterx-main .woocommerce-ordering select,
main.jupiterx-main .raven-products-ordering select {
  /* The background image is the SORT glyph (three lines), not a chevron: the chevron is a
     separate element on the right. It belongs on the left, where it was; the fault was that
     the text started underneath it. Moving the glyph right only made it collide with the
     chevron. So: glyph left, text padded clear of it, chevron right. */
  background-position: 14px 50% !important;
  background-repeat: no-repeat !important;
  padding-left: 40px !important;
  padding-right: 36px !important;
}

/* On a wide screen the sort control belongs at the end of the row, opposite the collection,
   the way the design lays it out. */
@media (min-width: 768px) {
  main.jupiterx-main .raven-products-ordering-wrapper,
  main.jupiterx-main .woocommerce-ordering {
    display: flex;
    justify-content: flex-end;
  }
}

/* ---------------------------------------------------------------------------
   50. SLIDE CART — calmer footer
   ---------------------------------------------------------------------------
   The drawer footer was a solid sand block roughly 205px tall carrying the discount row, the
   subtotal and the checkout button. Sand is used deliberately for editorial moments (the
   promise band, the collection band); as the ground for a functional panel it dominated the
   drawer. The footer sits on cream, and the ink button carries the emphasis instead.
   ------------------------------------------------------------------------ */
#fkcart-modal .fkcart-slider-footer {
  background-color: var(--zg-cream) !important;
  border-top: 1px solid var(--zg-rule);
}

#fkcart-modal .fkcart-remove-item {
  color: var(--zg-muted) !important;
  opacity: 0.75;
}

#fkcart-modal .fkcart-remove-item:hover { opacity: 1; }

/* No extra rule above the opt-out link. The last visible sample row already carries a bottom
   border (the row that is :last-child is a hidden Owl clone, so the border-0 exception never
   applies to the row you can actually see), and adding one here drew a second hairline a few
   pixels below the first. */

/* ---------------------------------------------------------------------------
   51. CHECKOUT — the returning-customer panel
   ---------------------------------------------------------------------------
   The login panel dropped into the form as a box with a hard 1px black border, body-size
   explanatory text and a pure black sentence-case "Login" button, pressed right up against the
   line above it and the first step below. It read as a different website spliced into the
   checkout, and it is the main reason the top of the page felt crammed.

   It becomes a quiet panel: the shop's ground, a hairline instead of a black rule, its own
   breathing room, and a button that matches every other primary action on the site. Nothing is
   hidden and no field is touched.
   ------------------------------------------------------------------------ */
body #wfacp-e-form .woocommerce-form-login,
body #wfacp-e-form .login_sec_content form.login {
  background: var(--zg-ground) !important;
  border: 1px solid var(--zg-rule) !important;
  border-radius: 2px !important;
  padding: 1.35rem 1.15rem !important;
  margin: 0.9rem 0 1.9rem !important;
}

body #wfacp-e-form .woocommerce-form-login > p:first-of-type {
  font-size: 12.5px !important;
  line-height: 1.6 !important;
  color: var(--zg-muted) !important;
  margin-bottom: 1.1rem !important;
}

body #wfacp-e-form .woocommerce-form-login input[type="text"],
body #wfacp-e-form .woocommerce-form-login input[type="password"] {
  background: #fff !important;
}

body #wfacp-e-form .woocommerce-form-login .woocommerce-form-login__submit,
body #wfacp-e-form .woocommerce-form-login button[name="login"] {
  background-color: var(--zg-ink) !important;
  border: 1px solid var(--zg-ink) !important;
  color: var(--zg-cream) !important;
  border-radius: 2px !important;
  height: 48px !important;
  font-size: 11px !important;
  letter-spacing: 0.18em !important;
  text-transform: uppercase;
  width: 100% !important;
}

/* "Remember me" and the password link sit on one line and should read as one quiet row. */
body #wfacp-e-form .woocommerce-form-login .woocommerce-form-login__rememberme,
body #wfacp-e-form .woocommerce-form-login .lost_password,
body #wfacp-e-form .woocommerce-form-login .lost_password a {
  font-size: 12.5px !important;
  letter-spacing: 0 !important;
  text-transform: none !important;
  color: var(--zg-muted) !important;
  line-height: 1.5;
}

body #wfacp-e-form .woocommerce-form-login .lost_password a {
  color: var(--zg-ink) !important;
  text-underline-offset: 3px;
}

/* Room around the steps so the form breathes on a phone. */
@media (max-width: 767px) {
  body #wfacp-e-form .wfacp-section { margin-bottom: 0.4rem; }
  body #wfacp-e-form .zg-step-heading { padding-top: 1.6rem; }
}

.single-product .quantity .minus,
.single-product .quantity .plus,
.single-product .quantity .plus-minus-btn {
  flex: 0 0 24px !important;
  width: 24px !important;
  min-width: 24px !important;
  padding: 0 !important;
  display: flex !important;
  align-items: center !important;
  justify-content: center !important;
}

.single-product .quantity input.qty {
  flex: 1 1 auto !important;
  width: auto !important;
  min-width: 0 !important;
  text-align: center !important;
  padding: 0 !important;
  font-variant-numeric: tabular-nums;
}

/* ---------------------------------------------------------------------------
   53. MOBILE MENU — the drawer was covering the logo
   ---------------------------------------------------------------------------
   The drawer is positioned absolutely from the hamburger's own wrapper, at top:16px. That
   wrapper sits at y=55 and is 16px tall, so the drawer opened at y=71 while the header row
   ends at y=90 and the two-line logo ends at y=80. The drawer therefore covered the last 9px
   of the logo and "ZIGGIMAY" was sliced in half whenever the menu was open.

   calc(100% + 19px) puts the drawer's top edge on the header row's bottom edge: 100% is the
   toggle's own height, and 19px is the distance from the toggle's bottom to the row's bottom.
   Both move together when the announcement bar is dismissed, so the offset holds.
   ------------------------------------------------------------------------ */
@media (max-width: 1024px) {
  .jet-mobile-menu__instance .jet-mobile-menu__container {
    top: calc(100% + 19px) !important;
  }
}

/* An outline control also picks up a wash of the ink it would fill with, so the press reads
   even where there is no solid background to darken. */
main.jupiterx-main .jet-unfold__button:active,
#wgb-modal a.wgb-add-gift-btn:active,
.single-product .pv-pills .pill label:active,
.zg-promise__cta:active,
.zg-sample-band__cta:active {
  background-color: rgba(20, 19, 15, 0.08) !important;
}

/* The waiting label needs to stay readable on sand, not fade into it. */
.single-product .single_add_to_cart_button.disabled,
.single-product .single_add_to_cart_button.wc-variation-selection-needed {
  color: #5A5648 !important;
}

/* Stock availability was printing in an olive green left over from the theme's defaults, the
   same family as the sage that used to sit on the size chips and the buy button. It is a quiet
   supporting fact, so it takes the secondary text colour like every other one. */
.single-product .stock,
.single-product p.stock,
.single-product .stock.in-stock {
  color: var(--zg-muted) !important;
  font-size: 12px;
  letter-spacing: 0.04em;
}

.single-product .stock.out-of-stock {
  color: #8A4A3C !important;
}

/* The bag sat 10px from the screen edge with its count badge 12px in, which measures as
   clearance but reads as crowding on a real handset and leaves nothing for a rounded corner or
   a gesture area. It gets a little more room.

   Scoped to the bag widget itself, deliberately. An earlier attempt put this padding on
   .e-con-inner, which matched every nested container in the header and squeezed the two-line
   logo until it was clipped. Nothing here can reach the logo. */
@media (max-width: 767px) {
  header .elementor-element-24da0433 {
    margin-right: 8px !important;
  }
}

/* ---------------------------------------------------------------------------
   57. MOBILE DRAWER — the header goes cream with it
   ---------------------------------------------------------------------------
   The mirror of section 1, for touch. Section 1 turns the bar cream for the desktop mega menu
   via body.zg-mega-open and via :hover; neither applies on a phone, so opening the drawer left
   the hero video showing through the header above a cream menu panel.

   body.zg-mobile-menu-open is set by the script in ziggimay-2030.js from the drawer's computed
   visibility. Same cream, same ink flip, so the bar and the open menu read as one surface.
   ------------------------------------------------------------------------ */
body.zg-mobile-menu-open header.jupiterx-header,
body.zg-mobile-menu-open #header-row {
  background-color: var(--zg-cream) !important;
}

body.zg-mobile-menu-open header.jupiterx-header a,
body.zg-mobile-menu-open header.jupiterx-header .elementor-heading-title,
body.zg-mobile-menu-open #header-row a {
  color: var(--zg-ink) !important;
}

body.zg-mobile-menu-open header.jupiterx-header svg {
  stroke: var(--zg-ink);
  color: var(--zg-ink);
}

/* The logo is inverted to white for the transparent bar; over cream it must go back to ink.
   The theme's own rule is
       body.jupiterx-header-overlapped:not(.stick) #header-row:not(:hover) .raven-site-logo img
   which computes to (1,4,2) with !important. An earlier attempt here landed on exactly (1,4,2)
   as well, so the tie fell to source order and the theme won because it loads later. Carrying
   :not(.stick) too takes this to (1,5,2), which wins on merit rather than on luck. */
body.zg-mobile-menu-open.jupiterx-header-overlapped:not(.stick) #header-row:not(:hover) .raven-site-logo img,
body.zg-mobile-menu-open header.jupiterx-header .raven-site-logo img {
  filter: none !important;
}

/* Section 1 turns the header cream on :hover, which is right for a mouse. On a touch screen a
   tap counts as hover and the state sticks, so tapping anywhere near the bar could leave it
   cream with the white logo still inverted on top of it: an invisible logo, which is exactly
   the fault this whole header treatment exists to avoid.

   Where there is no hover, the bar stays transparent and the open-drawer flag from section 57
   is the only thing that paints it cream. */
@media (hover: none) {
  /* THE STUCK HOVER MUST NOT OUTRANK .stick.
     This rule used to be unscoped, so it forced the bar transparent whenever hover was stuck
     to it, which on a phone is permanently after the first tap. Scrolling down then left the
     header see-through over ordinary page content: the theme adds body.stick past ~80px and
     custom code paints cream off it, but that carries no !important and lost to this.

     That is what the owner was reporting, and I missed it twice by only ever measuring at the
     top of the home page, where transparent is the CORRECT resting state. The conditions below
     are the theme's own: overlapped, not yet stuck, no menu open. Anywhere else the bar has a
     background on purpose and hover must not take it away. */
  body.jupiterx-header-overlapped:not(.stick):not(.zg-mega-open):not(.zg-mobile-menu-open) header.jupiterx-header:hover,
  body.jupiterx-header-overlapped:not(.stick):not(.zg-mega-open):not(.zg-mobile-menu-open) #header-row:hover {
    background-color: transparent !important;
  }

  body.zg-mobile-menu-open header.jupiterx-header,
  body.zg-mobile-menu-open header.jupiterx-header:hover,
  body.zg-mobile-menu-open #header-row,
  body.zg-mobile-menu-open #header-row:hover {
    background-color: var(--zg-cream) !important;
  }
}

/* The header icons are stroke-drawn, and the close cross is two <line> elements carrying their
   own white stroke for the transparent bar. Setting stroke on the <svg> alone did not reach
   them, so the cross and the icons stayed white on the cream open-menu header. Fill is left
   alone deliberately: these are outline icons and filling them would turn the heart and the bag
   into solid shapes. */
body.zg-mobile-menu-open header.jupiterx-header svg,
body.zg-mobile-menu-open header.jupiterx-header svg line,
body.zg-mobile-menu-open header.jupiterx-header svg path,
body.zg-mobile-menu-open header.jupiterx-header svg circle,
body.zg-mobile-menu-open header.jupiterx-header svg rect,
body.zg-mobile-menu-open .jet-mobile-menu__toggle svg line,
body.zg-mobile-menu-open .jet-mobile-menu__toggle svg path {
  stroke: var(--zg-ink) !important;
}

/* ---------------------------------------------------------------------------
   58. SLIDE CART — the odd link and the coupon button
   ---------------------------------------------------------------------------
   The drawer printed "Select options" under a line that already says "SIZE: 30ML", which reads
   as an instruction to do something that has already been done. It is FunnelKit's
   change-the-variation link, so it says what it actually does and stops shouting: the label is
   replaced in CSS (font-size:0 on the link, the new words on ::after) so the plugin's own
   markup and click handler are untouched.

   The coupon "Apply" was a solid black sentence-case button sitting beside a bordered input,
   heavier than the checkout button below it. Applying a discount is a minor action.
   ------------------------------------------------------------------------ */
#fkcart-modal a.fkcart-select-options {
  font-size: 0 !important;
  color: var(--zg-muted) !important;
  text-decoration: underline;
  text-underline-offset: 3px;
}

#fkcart-modal a.fkcart-select-options::after {
  content: "Change size";
  font-size: 9.5px;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

#fkcart-modal .fkcart-coupon-btn,
#fkcart-modal button[class*="coupon"],
#fkcart-modal .fkcart-apply-coupon,
#fkcart-modal form[class*="coupon"] button {
  background-color: transparent !important;
  color: var(--zg-ink) !important;
  border: 1px solid var(--zg-ink) !important;
  border-radius: 2px !important;
  font-size: 10.5px !important;
  letter-spacing: 0.16em !important;
  text-transform: uppercase;
  box-shadow: none !important;
}

#fkcart-modal input[class*="coupon"],
#fkcart-modal .fkcart-coupon-input {
  border: 1px solid var(--zg-rule) !important;
  border-radius: 2px !important;
  box-shadow: none !important;
  outline: none !important;
}

/* Going back to the shop is the quiet option, not a second heading. */
#fkcart-modal .fkcart-continue-shopping,
#fkcart-modal a.fkcart-continue,
#fkcart-modal .fkcart-slider-footer a:not([href*="checkout"]):not([class*="coupon"]) {
  font-size: 10.5px !important;
  font-weight: 500 !important;
  letter-spacing: 0.16em !important;
  text-transform: uppercase !important;
  color: var(--zg-muted) !important;
}

/* The chosen size chip was filling with pure #000 from
       .pv-pills .pill input[type="checkbox"]:checked + label { background:#000 !important }
   which computes to (0,4,2) — exactly the same as the earlier rule here, so source order decided
   it and that stylesheet loads later. Matching its shape and adding the body element takes this
   to (0,5,2).

   This matters beyond the 20/19/15 vs 0/0/0 difference: a hard-coded black would not follow the
   Ink colour in Appearance > Customize > Brand colours, so the chip would drift away from every
   other filled control the moment that colour is changed. */
body.single-product .pv-pills .pill input[type="checkbox"]:checked + label,
body.single-product .pv-pills .pill.selected label,
body.single-product .pv-pills .pill.active label {
  background-color: var(--zg-ink) !important;
  border-color: var(--zg-ink) !important;
  color: var(--zg-cream) !important;
}

/* ---------------------------------------------------------------------------
   59. SIZE CHIP — selected, but not a second black slab
   ---------------------------------------------------------------------------
   The chosen size was filling with ink, which put two heavy black blocks directly above one
   another: the selected chip and Add to cart. The mockup does not do that — only ADD TO BAG is
   solid; the chosen size is a light chip.

   Selected is now sand with an ink border and ink text: unmistakably chosen, on-palette, and
   it lets the buy button be the single heaviest thing in the column, which is the whole point
   of making it black in the first place.
   ------------------------------------------------------------------------ */
body.single-product .pv-pills .pill input[type="checkbox"]:checked + label,
body.single-product .pv-pills .pill.selected label,
body.single-product .pv-pills .pill.active label {
  background-color: var(--zg-sand) !important;
  border-color: var(--zg-ink) !important;
  color: var(--zg-ink) !important;
  font-weight: 500 !important;
}

/* The cart's quantity wrapper is a full-width block (153px) carrying the border, while the
   minus/input/plus controls inside it only fill the left ~78px. The result is a stepper
   followed by an empty bordered box, which reads as a broken or unfinished input. The wrapper
   shrinks to its contents so the border hugs the control it belongs to. */
#fkcart-modal .fkcart-qty-wrap {
  display: inline-flex !important;
  width: auto !important;
  /* The wrapper is a flex item in a column, so the parent's default align-items:stretch made it
     fill the line and width:auto could not shrink it. align-self stops the stretch; without
     this line the empty bordered box beside the plus comes straight back. */
  align-self: flex-start !important;
  border-radius: 2px !important;
  border-color: var(--zg-rule) !important;
}

#fkcart-modal .fkcart-quantity-selector {
  display: flex !important;
  align-items: stretch;
}

#fkcart-modal .fkcart-quantity__input {
  text-align: center !important;
  font-variant-numeric: tabular-nums;
  border: 0 !important;
  background: transparent !important;
  box-shadow: none !important;
}

/* ---------------------------------------------------------------------------
   60. PARCEL SHOP FIELD
   ---------------------------------------------------------------------------
   Printed under the "Parcel shop" rate by the parcel-shop-delivery mu-plugin. It replaces a
   carrier map that cannot work without a carrier account, so it has to feel like a considered
   part of the checkout rather than a fallback: the sand ground marks it as a choice the customer
   has just made, and the two finder links do the job the map used to do.

   It is only rendered next to the parcel-shop option, so it is never in the way of someone who
   just wants it delivered to their door.
   ------------------------------------------------------------------------ */
.zg-parcel {
  background: var(--zg-ground);
  border-radius: 2px;
  padding: 0.95rem 1rem 1.05rem;
  margin: 0.65rem 0 0.2rem;
}

.zg-parcel__help {
  margin: 0 0 0.8rem !important;
  font-size: 12.5px !important;
  line-height: 1.55 !important;
  color: var(--zg-muted) !important;
}

.zg-parcel__finder {
  color: var(--zg-ink) !important;
  text-decoration: underline;
  text-underline-offset: 3px;
  white-space: nowrap;
}

.zg-parcel__finder:hover { opacity: 0.7; }

.zg-parcel__label {
  display: block;
  font-family: Avenir, "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--zg-muted);
  margin: 0 0 6px;
}

.zg-parcel__req { opacity: 0.75; }

/* Matches the height, radius and type of every other field on the checkout. */
.zg-parcel__input,
input#zg_parcel_shop {
  width: 100% !important;
  height: 48px !important;
  min-height: 48px !important;
  padding: 12px 14px !important;
  border: 1px solid var(--zg-rule) !important;
  border-radius: 2px !important;
  background: #fff !important;
  font-size: 14px !important;
  box-shadow: none !important;
}

input#zg_parcel_shop:focus {
  border-color: var(--zg-ink) !important;
  outline: none !important;
}

input#zg_parcel_shop::placeholder {
  color: rgba(20, 19, 15, 0.38);
}

/* The order confirmation and the emails repeat it back, so the customer can see we got it. */
.zg-parcel-confirm {
  margin-top: 0.9rem;
  padding-top: 0.9rem;
  border-top: 1px solid var(--zg-rule);
  font-size: 13px;
}

/* ---------------------------------------------------------------------------
   61. HOMEPAGE INTRO PARAGRAPHS
   ---------------------------------------------------------------------------
   Two text blocks sit under centred headings but carry a hard 544px width, so they render
   flush-left inside a 1050px column and leave ~500px of dead space to their right. Measured
   at 1440: heading spans 246-1195, the paragraph stops at 739. Releasing the width and
   centring the column puts the text back under its own headline.

   Capped in ch rather than px so the measure stays readable whatever the container does. The text
   itself stays ragged-right: a centred column of left-aligned copy reads better at this length
   than centred lines, and the theme wins the text-align tie anyway.
   ------------------------------------------------------------------------ */
body.home .elementor-element-ae9b638 p,
body.home .elementor-element-ab03934 p {
  width: auto !important;
  max-width: 58ch;
  margin-inline: auto !important;
}

/* ---------------------------------------------------------------------------
   62. COLLECTION TILES
   ---------------------------------------------------------------------------
   Both tiles print white text and a white outlined button straight onto a photograph. Over
   the dark marble that reads; over the pale bottle shot it does not, and "Shop Classic
   Perfumes" all but disappears. The existing ::before overlay is even across the whole tile,
   which cannot solve it: what the type needs is weight underneath itself specifically.

   So the overlay becomes bottom-weighted. The photograph stays clean at the top where there
   is no text, and the type sits on enough shadow to hold at any crop.
   ------------------------------------------------------------------------ */
body.home .elementor-element-25f76f2::before,
body.home .elementor-element-e67f93d::before {
  background-image: linear-gradient(
    to bottom,
    rgba(20, 19, 15, 0.10) 0%,
    rgba(20, 19, 15, 0.42) 45%,
    rgba(20, 19, 15, 0.62) 100%
  ) !important;
}

/* A hairline outline over a photograph is never quite enough. A quiet fill underneath it
   keeps the label legible without turning the button into a solid black slab. */
body.home .elementor-element-25f76f2 .elementor-button,
body.home .elementor-element-e67f93d .elementor-button {
  background-color: rgba(20, 19, 15, 0.42) !important;
  border-color: rgba(255, 255, 255, 0.85) !important;
  backdrop-filter: blur(2px);
}

body.home .elementor-element-25f76f2 .elementor-button:hover,
body.home .elementor-element-e67f93d .elementor-button:hover {
  background-color: var(--zg-ink) !important;
  border-color: var(--zg-ink) !important;
}

/* ---------------------------------------------------------------------------
   63. CHOOSING BLOCK + MAKER BLOCK
   ---------------------------------------------------------------------------
   Both come from home-choosing.php. The choosing block is the only place on the page where a
   visitor can rule a fragrance in or out, so it is built to be scanned: name, one line, price,
   in a grid that keeps every card the same height whatever the line length.

   The Discovery Box strip underneath is deliberately the only filled panel in the section. It
   is the answer to the section's own question, and it should read as the way out of the
   decision rather than a sixth option.
   ------------------------------------------------------------------------ */
.zg-choose { background: var(--zg-cream); padding: clamp(3.5rem, 7vw, 6rem) 20px; }

.zg-choose__inner { max-width: 1160px; margin-inline: auto; }

.zg-choose__eyebrow,
.zg-maker__eyebrow {
  font-family: Avenir, "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--zg-muted);
  margin: 0 0 0.75rem;
  text-align: center;
}

.zg-choose__h,
.zg-maker__h {
  font-family: "GlacialIndifference", Georgia, serif;
  font-size: clamp(1.9rem, 3.4vw, 2.9rem);
  font-weight: 400;
  line-height: 1.14;
  color: var(--zg-ink);
  text-align: center;
  text-wrap: balance;
  margin: 0 0 0.8rem;
}

.zg-choose__intro {
  max-width: 52ch;
  margin: 0 auto clamp(2rem, 4vw, 3rem);
  text-align: center;
  font-size: 15px;
  line-height: 1.62;
  color: var(--zg-muted);
}

/* auto-fit rather than a fixed column count: the range is five today and will not stay five */
.zg-choose__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: 1px;
  background: var(--zg-rule);
  border: 1px solid var(--zg-rule);
}

.zg-choose__card {
  display: flex;
  flex-direction: column;
  gap: 0.45rem;
  padding: 1.5rem 1.25rem 1.35rem;
  background: var(--zg-cream);
  text-decoration: none;
  transition: background-color 0.18s ease;
}

.zg-choose__name {
  font-family: "GlacialIndifference", Georgia, serif;
  font-size: 17px;
  color: var(--zg-ink);
  line-height: 1.25;
}

.zg-choose__line {
  font-size: 13px;
  line-height: 1.55;
  color: var(--zg-muted);
  flex: 1 1 auto;   /* pushes every price to the same baseline */
}

.zg-choose__from {
  font-family: Avenir, "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--zg-ink);
}

.zg-choose__from .woocommerce-Price-amount { font-size: 11px; }

@media (hover: hover) {
  .zg-choose__card:hover { background: var(--zg-ground); }
}

.zg-choose__box {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 1.25rem;
  margin-top: 1.75rem;
  padding: 1.6rem 1.75rem;
  background: var(--zg-ground);
}

.zg-choose__boxh {
  font-family: "GlacialIndifference", Georgia, serif;
  font-size: 19px;
  color: var(--zg-ink);
  margin: 0 0 0.3rem;
}

.zg-choose__boxp {
  margin: 0;
  max-width: 56ch;
  font-size: 14px;
  line-height: 1.6;
  color: var(--zg-muted);
}

.zg-choose__cta,
.zg-promise__cta {
  flex: 0 0 auto;
  display: inline-block;
  padding: 13px 26px;
  background: var(--zg-ink);
  color: var(--zg-cream);
  font-family: Avenir, "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  text-decoration: none;
  border: 1px solid var(--zg-ink);
}

@media (hover: hover) {
  .zg-choose__cta:hover { background: transparent; color: var(--zg-ink); }
}

/* The maker block stays deliberately small. It is a signature, not a chapter. */
.zg-maker { background: var(--zg-ground); padding: clamp(3rem, 6vw, 5rem) 20px; }
.zg-maker__inner { max-width: 62ch; margin-inline: auto; text-align: center; }
.zg-maker__p {
  margin: 0;
  font-size: 15px;
  line-height: 1.72;
  color: var(--zg-ink);
}

/* ---------------------------------------------------------------------------
   64. CHECKOUT: HONEYPOT
   ---------------------------------------------------------------------------
   WP Armour injects a decoy field client side and ships its own rule to hide it. On this
   checkout that rule is not reaching the page, so the decoy renders as a real 48px input
   labelled "Alternative:" in the middle of the login block. A customer who fills it in has
   their submission treated as spam, which is the worst possible failure mode: silent, and it
   looks like the shop is broken.

   This is the plugin's own rule, restated here so the field stays hidden whatever happens to
   the plugin's stylesheet. It must stay in the DOM and stay fillable, because that is the
   entire mechanism, so this hides it without display:none.
   ------------------------------------------------------------------------ */
#altEmail_container,
.altEmail_container {
  position: absolute !important;
  overflow: hidden !important;
  height: 1px !important;
  width: 1px !important;
  z-index: -1000 !important;
  opacity: 0 !important;
  pointer-events: none !important;
}

/* ---------------------------------------------------------------------------
   65. WISHLIST CONTROL ON THE PRODUCT PAGE  (single source of truth)
   ---------------------------------------------------------------------------
   This control was styled seven separate times as problems surfaced one at a time, and the
   rules ended up fighting each other: two of them set the border, two set the stroke weight,
   three set the box. That is why fixing it never stayed fixed. All of those blocks have been
   deleted and everything the control needs now lives here.

   What it has to do: read as the SECOND action in a row where Add to cart is first. Same
   height as the other two controls, square rather than a slightly-narrow rectangle, and drawn
   in the same line weight as everything around it.

   Measured before this rule: box 50x54 (not square), glyph stroke 1.9px against a row drawn
   entirely in 1px, and an inner plane 60px wide inside the 50px box, clipped by overflow so
   the icon sat off centre and the horizontal borders could disappear.

   The plugin nests two absolutely positioned "plane" layers inside the button, one per state,
   each carrying its own 60x40 geometry from an Elementor selector of the form
   .elementor-20939 .elementor-element.elementor-element-2c9173c .jet-wishlist-button__plane
   which computes to (0,4,0). Everything here is scoped body.single-product main.jupiterx-main
   so it clears that without needing to know the page id.
   ------------------------------------------------------------------------ */

/* The box is drawn once, here, and nowhere else. */
body.single-product main.jupiterx-main .jet-wishlist-button,
body.single-product main.jupiterx-main .jet-cw.jet-wishlist-button {
  position: relative !important;
  box-sizing: border-box !important;
  /* 50, not 54. The row's budget at 412px is 372 (20px margins) and it is already spent:
     92 stepper + 10 gap + 210 button + 10 gap = 322, leaving exactly 50. Squaring this box to
     match its own height pushed it 4px past its container at every width tested (360/412/430).
     The height still matches the other two controls, which is the alignment that reads. */
  width: 50px !important;
  min-width: 50px !important;
  height: 54px !important;
  min-height: 54px !important;
  display: flex !important;
  align-items: center !important;
  justify-content: center !important;
  padding: 0 !important;
  background: transparent !important;
  border: 1px solid var(--zg-ink) !important;
  border-radius: 2px !important;
  /* No overflow:hidden. The planes are pinned to the box below, so there is nothing to clip,
     and clipping was what let the horizontal borders vanish at some widths. */
  transition: background-color 160ms var(--zg-ease), border-color 160ms var(--zg-ease);
}

/* The planes become plain layers: pinned to the button, carrying no geometry of their own.
   inset:0 rather than width/height:100%, because the plugin positions them against their own
   60x40 box and a percentage would resolve against the wrong thing. */
body.single-product main.jupiterx-main .jet-wishlist-button .jet-wishlist-button__plane,
body.single-product main.jupiterx-main .jet-wishlist-button .jet-wishlist-button__plane-normal,
body.single-product main.jupiterx-main .jet-wishlist-button .jet-wishlist-button__plane-added,
body.single-product main.jupiterx-main .jet-wishlist-button .jet-wishlist-button__container {
  position: absolute !important;
  inset: 0 !important;
  width: auto !important;
  height: auto !important;
  min-width: 0 !important;
  min-height: 0 !important;
  max-width: none !important;
  margin: 0 !important;
  padding: 0 !important;
  border: 0 !important;
  border-radius: 0 !important;
  background: transparent !important;
  display: flex !important;
  align-items: center !important;
  justify-content: center !important;
}

body.single-product main.jupiterx-main .jet-wishlist-button svg {
  width: 21px !important;
  height: 21px !important;
  display: block !important;
}

/* Resting state is an OUTLINE. A filled heart means "already saved", so using it here would
   state something untrue and make the lesser control the heaviest thing in the row. The plugin
   ships a solid silhouette path, so it is stroked rather than filled.

   1.3px, not the 1.9px this carried before. The quantity stepper, the size chips and this box
   are all drawn with a 1px line; a glyph at nearly twice that weight was the reason this kept
   reading as wrong even once the geometry was right. non-scaling-stroke keeps it honest, since
   the path is authored in a 572x504 viewBox and would otherwise be scaled down with it. */
body.single-product main.jupiterx-main .jet-wishlist-button svg path {
  fill: none !important;
  stroke: var(--zg-ink) !important;
  stroke-width: 1.3px !important;
  stroke-linejoin: round !important;
  stroke-linecap: round !important;
  vector-effect: non-scaling-stroke !important;
}

/* Saved: the heart fills and the box goes with it, so the state is unmistakable at a glance. */
body.single-product main.jupiterx-main .jet-wishlist-button--added,
body.single-product main.jupiterx-main .jet-cw.jet-wishlist-button--added {
  background: var(--zg-ink) !important;
  border-color: var(--zg-ink) !important;
}

body.single-product main.jupiterx-main .jet-wishlist-button--added svg path,
body.single-product main.jupiterx-main .jet-wishlist-button .jet-wishlist-button__plane-added svg path {
  fill: var(--zg-cream) !important;
  stroke: var(--zg-cream) !important;
}

@media (hover: hover) {
  body.single-product main.jupiterx-main .jet-wishlist-button:hover {
    background: rgba(20, 19, 15, 0.06) !important;
  }
}

/* Pressed state, so a tap is acknowledged on touch where there is no hover. */
body.single-product main.jupiterx-main .jet-wishlist-button:active {
  background: rgba(20, 19, 15, 0.12) !important;
}

/* The wishlist widget sits in an Elementor container fixed at 40px with overflow:hidden, so a
   54px control was being clipped to 40 and lost its bottom border. That is what made the box
   read as two vertical bars with a gap. The container is measured, not guessed: at 412px it is
   50x40 at y=943 while the button inside it is 50x54 at the same y.

   Targeted by id (the product template is 20939, so this covers every product) and again
   structurally, so a rebuilt template that changes the id still works. */
/* Scoped to the wishlist's OWN container only. An earlier version of this used
   .e-con:has(.jet-wishlist-button), which also matched the whole buy row and centred the
   quantity stepper and Add to cart with it. The :has() variant below is deliberately anchored
   to the direct child chain so it cannot climb the tree again. */
body.single-product main.jupiterx-main .elementor-element-9dc67c8,
body.single-product main.jupiterx-main .e-con:has(> .elementor-widget > .elementor-widget-container > .jet-wishlist-button) {
  height: auto !important;
  min-height: 54px !important;
  overflow: visible !important;
}

/* Same clip one level up on the widget wrapper. */
body.single-product main.jupiterx-main .elementor-widget-container:has(> .jet-wishlist-button) {
  height: auto !important;
  overflow: visible !important;
}

/* ---------------------------------------------------------------------------
   66. PRODUCT DETAIL COLUMN: ONE TYPE SCALE
   ---------------------------------------------------------------------------
   The right-hand column was setting body text at three sizes in two families, because each
   block came from a different widget and kept its own defaults. Measured at 1440:

     short description   14.5px Avenir
     Description body    13px   Avenir
     Olfactive Notes     16px   FreightTextPro   <- serif, and the largest body text on the page
     Ingredients         13px   Avenir

   Read top to bottom that is four different voices for what is one continuous description. The
   serif belongs to headings here; body copy is Avenir at a single size, and the notes table
   stops being the loudest thing in the column.
   ------------------------------------------------------------------------ */
body.single-product main.jupiterx-main .jet-tabs__content p,
body.single-product main.jupiterx-main .jet-tabs__content li,
body.single-product main.jupiterx-main .jet-tabs__content td,
body.single-product main.jupiterx-main .jet-tabs__content div:not([class*="elementor"]) {
  font-family: Avenir, "Helvetica Neue", Helvetica, Arial, sans-serif !important;
  font-size: var(--zg-fs-body) !important;
  line-height: var(--zg-lh-body) !important;
  color: var(--zg-ink);
}

/* The notes table: the label column stays a small caps marker, the description matches body. */
body.single-product main.jupiterx-main .jet-tabs__content td:first-child,
body.single-product main.jupiterx-main .jet-tabs__content th:first-child {
  font-family: Avenir, "Helvetica Neue", Helvetica, Arial, sans-serif !important;
  font-size: 10px !important;
  letter-spacing: 0.16em !important;
  text-transform: uppercase !important;
  color: var(--zg-muted) !important;
  white-space: nowrap;
}

/* The short description sits above the buy row and is the one line that may run a touch larger,
   but not by 1.5px, which reads as a mistake rather than a decision. */
body.single-product main.jupiterx-main .woocommerce-product-details__short-description p {
  font-size: var(--zg-fs-body) !important;
  line-height: var(--zg-lh-body) !important;
}

/* The stacked section headings keep the serif. That is the only place it belongs in this
   column, and it is what makes the sections scannable. */
body.zg-tabs-stacked .zg-tab-heading,
body.single-product main.jupiterx-main .jet-tabs__content h2,
body.single-product main.jupiterx-main .jet-tabs__content h3 {
  font-family: FreightTextPro, Georgia, serif !important;
}

/* Nested Notes list inside Description: it is a list of facts, not prose, so it sits tighter. */
body.single-product main.jupiterx-main .zg-notes {
  list-style: none;
  margin: 0.5rem 0 0;
  padding: 0;
}

body.single-product main.jupiterx-main .zg-notes li {
  padding: 0.3rem 0;
  border-bottom: 1px solid var(--zg-rule);
}

body.single-product main.jupiterx-main .zg-notes li:last-child { border-bottom: 0; }

body.single-product main.jupiterx-main .zg-notes strong {
  display: inline-block;
  min-width: 4.6rem;
  font-family: Avenir, "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--zg-muted);
}

/* The short description is the lede above the buy row, so it may sit a step above body copy.
   It was at 14.5px against a 14px body: half a pixel is not a step, it is an accident, and it
   is what made the column read as four unrelated sizes. 15px is a decision. */
body.single-product main.jupiterx-main .elementor-element-4056ed2 p {
  /* The lede above the buy row. 15px was "a step above a 14px body"; now that body is the
     scale, the step is the lead token and the relationship survives the change. */
  font-size: var(--zg-fs-lead) !important;
  line-height: var(--zg-lh-lead) !important;
}

/* Section headings were butting straight up against the paragraph above them, so the column
   read as one run of text with bold lines in it rather than as sections. The rule above each
   heading does the separating; the space is what makes the rule read as a divider. */
body.zg-tabs-stacked .zg-tab-heading,
body.single-product main.jupiterx-main .jet-tabs__content h2,
body.single-product main.jupiterx-main .jet-tabs__content h3 {
  margin-top: 2.4rem !important;
  padding-top: 1.5rem !important;
  border-top: 1px solid var(--zg-rule);
}

/* The first one has the buy row above it and needs no second divider. */
body.zg-tabs-stacked .jet-tabs__content:first-of-type .zg-tab-heading,
body.zg-tabs-stacked .zg-tab-heading:first-of-type {
  margin-top: 1.4rem !important;
}

/* ---------------------------------------------------------------------------
   67. STACKED TABS: KILL THE TRANSITION EFFECT
   ---------------------------------------------------------------------------
   The widget carries jet-tabs-move-up-effect, which animates each pane's transform and opacity
   as it becomes active. That is built for showing ONE pane at a time. With every pane stacked
   and permanently visible, the effect still runs per pane and leaves a second, offset copy of
   the text painted behind the real one: Description, Olfactive Notes and Ingredients all
   appeared twice, overlapping, and it got worse while scrolling.

   Only one node in the DOM holds that text, which is what proves it is a paint artifact rather
   than duplicated markup. Removing the animation, the transition and the transform removes the
   layer that was being left behind.
   ------------------------------------------------------------------------ */
body.zg-tabs-stacked .jet-tabs,
body.zg-tabs-stacked .jet-tabs__content-wrapper,
body.zg-tabs-stacked .jet-tabs__content,
body.zg-tabs-stacked .jet-tabs__content > *,
body.zg-tabs-stacked .jet-tabs__content > * > * {
  animation: none !important;
  transition: none !important;
  transform: none !important;
  opacity: 1 !important;
  will-change: auto !important;
  filter: none !important;
}

/* The wrapper keeps a height from the tallest single pane while the panes now flow one after
   another, which leaves the sections overlapping the block below them. */
body.zg-tabs-stacked .jet-tabs__content-wrapper {
  height: auto !important;
  min-height: 0 !important;
  position: static !important;
  overflow: visible !important;
}

/* The stepper glyphs were 15px in a row whose other controls are set at 11-12px letterspaced
   caps, and they sat hard against the cell edges. Slightly larger and optically centred, so the
   two tap targets read as buttons rather than as characters that happen to be there. */
body.single-product main.jupiterx-main .quantity .minus,
body.single-product main.jupiterx-main .quantity .plus,
body.single-product main.jupiterx-main .quantity .plus-minus-btn {
  font-size: 17px !important;
  line-height: 1 !important;
  display: flex !important;
  align-items: center !important;
  justify-content: center !important;
  color: var(--zg-ink) !important;
}

/* The number is the value, so it carries a touch more weight than the controls beside it. */
body.single-product main.jupiterx-main .quantity input.qty {
  font-size: 14px !important;
  text-align: center !important;
  color: var(--zg-ink) !important;
}

/* ---------------------------------------------------------------------------
   68. SHIPMONDO PARCEL SHOP PICKER
   ---------------------------------------------------------------------------
   The picker is the plugin's own, driven by the Shipmondo API: it pre-selects the nearest shop
   and opens a modal with the real list. It arrives with generic plugin styling, so this brings
   it into the same type and colour as the rest of the checkout.

   The map inside the modal currently fails with ApiTargetBlockedMapError, which means the
   Google key is restricted to a set of APIs that does not include Maps JavaScript. Until that
   is changed in the Google console, Google paints a grey "something went wrong" panel across
   the top of the modal. The list underneath works perfectly, so the panel is hidden rather
   than shown: a customer should not be told something went wrong when nothing they care about
   has. :has() means this heals itself the moment the key is fixed, with no edit here.
   ------------------------------------------------------------------------ */
.service_points_map:has(.gm-err-container),
.shipmondo-modal_content .service_points_map:has(.gm-err-content) {
  display: none !important;
}

/* The chosen shop, shown under the Parcel shop option. */
.shipmondo_service_point_selection .selected_service_point {
  background: var(--zg-ground);
  border: 1px solid var(--zg-rule);
  border-radius: 2px;
  padding: 0.85rem 1rem;
  cursor: pointer;
}

.shipmondo_service_point_selection .selected_service_point .name {
  font-family: Avenir, "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-size: 14px;
  font-weight: 500;
  color: var(--zg-ink);
}

.shipmondo_service_point_selection .selected_service_point .address_info,
.shipmondo_service_point_selection .selected_service_point .distance {
  font-family: Avenir, "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-size: 13px;
  color: var(--zg-muted);
}

@media (hover: hover) {
  .shipmondo_service_point_selection .selected_service_point:hover {
    border-color: var(--zg-ink);
  }
}

.shipmondo_service_point_selection .powered_by_shipmondo p {
  font-size: 10px !important;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--zg-muted) !important;
}

/* The modal list. */
.shipmondo-modal_header {
  font-family: FreightTextPro, Georgia, serif !important;
  font-size: 19px !important;
  color: var(--zg-ink) !important;
}

.shipmondo-modal_content .service_point {
  font-family: Avenir, "Helvetica Neue", Helvetica, Arial, sans-serif !important;
  border-bottom: 1px solid var(--zg-rule);
}

.shipmondo-modal_content .service_point .name {
  font-size: 14px !important;
  font-weight: 500 !important;
  color: var(--zg-ink) !important;
}

.shipmondo-modal_content .service_point .address_info,
.shipmondo-modal_content .service_point .distance {
  font-size: 13px !important;
  color: var(--zg-muted) !important;
}

/* ---------------------------------------------------------------------------
   69. QUANTITY STEPPER FIT
   ---------------------------------------------------------------------------
   Measured at 1440: the box is 92px but its three cells render 24 + 50 + 24 = 98, so the flex
   row overflows by 6px and the plus is clipped against the right border. That is why the plus
   read as narrower than the minus when both are set to the same width.

   The input was flex: 1 1 auto, whose auto basis refuses to shrink below its content. Giving it
   a zero basis and min-width: 0 lets it absorb the difference, so the two buttons keep equal
   width at any box size. They also take the full 54px height rather than 52, so their pressed
   state fills the cell instead of leaving a hairline top and bottom.
   ------------------------------------------------------------------------ */
/* Product page only. Applying this to #fkcart-modal as well made the cart drawer's stepper
   stretch the full width of the drawer: that wrapper is already sized by the align-self rule
   in section 59 and must keep its own narrow width. */
body.single-product main.jupiterx-main .quantity input.qty {
  flex: 1 1 0 !important;
  min-width: 0 !important;
  width: auto !important;
}

body.single-product main.jupiterx-main .quantity .minus,
body.single-product main.jupiterx-main .quantity .plus,
body.single-product main.jupiterx-main .quantity .plus-minus-btn {
  flex: 0 0 26px !important;
  width: 26px !important;
  height: 100% !important;
  align-self: stretch !important;
}

/* ---------------------------------------------------------------------------
   70. SHIPMONDO ATTRIBUTION
   ---------------------------------------------------------------------------
   The picker prints "Powered by Shipmondo" under the chosen shop and again in the modal
   footer. Which broker moves the parcel is the shop's business, not the customer's, and at
   checkout it is one more piece of text between them and paying.
   ------------------------------------------------------------------------ */
.powered_by_shipmondo,
.shipmondo-modal_footer,
.shipmondo_service_point_selection .powered_by_shipmondo {
  display: none !important;
}

/* The quantity input carries a min-width of 50px from outside this stylesheet, which no
   flex-shrink can override. So rather than fight it, the box is sized to what its cells
   actually need: 26 + 50 + 26 = 102. Add to cart is flex-sized (measured 210px at a 412
   viewport, 158px at 360) and absorbs the difference, so the row still fits at every width.
   This is what stops the plus being clipped against the right border. */
body.single-product main.jupiterx-main .quantity,
body.single-product main.jupiterx-main .zg-qty {
  width: 104px !important;
  min-width: 104px !important;
  flex: 0 0 104px !important;
}

/* ---------------------------------------------------------------------------
   83. QUANTITY STEPPER - THE BOX THAT WAS ACTUALLY CLIPPING THE PLUS
   ---------------------------------------------------------------------------
   Sections 52, 66 and 69 all sized `.quantity`, and none of them fixed the plus, because
   `.quantity` is not the box that carries the border. Raven nests a second wrapper inside it:

       .quantity                           sized above, no border of its own
         .raven-qty-button-holder-inner    min-width: 92px, 1px border, OVERFLOW: HIDDEN
           button.minus                    26px
           input.qty                       50px   (min-width: 50px, set by Raven)
           button.plus                     26px

   Measured on the live page at 1440 and at 360 / 393 / 412: the inner box is 92px, so its
   content area is 90px, while its three cells need 26 + 50 + 26 = 102px. The row overflows by
   12px and `overflow: hidden` cuts the plus in half against the right border. That is the
   whole bug. It is why the plus always read as narrower than the minus, why it happens on
   desktop as well as on a phone, and why sizing the outer box never changed anything.

   The inner is therefore sized to what its cells actually measure: 102px of cells plus 2px of
   border is 104px. The input also gets min-width: 0 so that if a cell ever changes size again
   it shrinks to absorb the difference instead of pushing the plus back out through the border.

   Scoped to .single-product so the cart drawer's own stepper, which is a different component
   sized in section 59, is not touched.
   ------------------------------------------------------------------------ */
body.single-product main.jupiterx-main .quantity .raven-qty-button-holder-inner,
.single-product .quantity .raven-qty-button-holder-inner {
  box-sizing: border-box !important;
  width: 104px !important;
  min-width: 104px !important;
  max-width: 104px !important;
  flex: 0 0 104px !important;
}

body.single-product main.jupiterx-main .quantity input.qty,
.single-product .quantity input.qty {
  min-width: 0 !important;
  flex: 1 1 0 !important;
  height: 100% !important;
}

/* ---------------------------------------------------------------------------
   71. CHECKOUT CHECKBOX TARGETS
   ---------------------------------------------------------------------------
   The three checkout checkboxes (terms, create an account, different billing address) are
   16x16 absolutely positioned boxes inside a label padded 25px on the left. 16px is less than
   half the 44px minimum for a touch target, which is why the billing toggle feels like it does
   not respond: the tap lands next to it, not on it.

   The input keeps its position so the layout does not move. What grows is the hit area, via a
   transparent ::after that extends it to 44px square, and the label gets enough left padding
   and line-height that the text sits clear of it. The visible box stays 16px.
   ------------------------------------------------------------------------ */
#wfacp-e-form input[type="checkbox"],
form.checkout input[type="checkbox"] {
  width: 17px;
  height: 17px;
}

#wfacp-e-form label:has(> input[type="checkbox"]),
form.checkout label:has(> input[type="checkbox"]) {
  position: relative;
  display: block;
  padding-left: 30px !important;
  /* 44px of vertical target, centred on a 17px box, without moving the text baseline */
  min-height: 44px;
  padding-top: 12px !important;
  padding-bottom: 12px !important;
  margin-top: -12px;
  margin-bottom: -12px;
  line-height: 1.5;
  cursor: pointer;
}

/* NO ::after here. The theme draws the checkmark itself with a 10x8 ::after (a rotated border
   glyph), so setting position/transform on that pseudo-element replaces the rotation and the
   tick stops being drawn: the box toggles, the label reacts, and nothing visible changes. That
   was the "no checkmark can be added" bug. The hit area is enlarged on the LABEL instead, which
   is what the browser already treats as the control's target and which touches nothing the
   theme is painting. */
/* Give the tick itself the brand ink rather than the browser default blue. */
#wfacp-e-form input[type="checkbox"],
form.checkout input[type="checkbox"] {
  accent-color: var(--zg-ink);
}

/* ---------------------------------------------------------------------------
   72. CHECKOUT CHECKBOX: DRAW THE TICK
   ---------------------------------------------------------------------------
   The theme sets appearance:none on these inputs, which removes the browser's own checkmark,
   and then supplies its own 10x8 ::after glyph that never actually paints. The result is a box
   that toggles correctly in the DOM (checked flips to true, the billing fields appear) while
   staying visually empty, so it reads as "the checkbox will not tick".

   Verified before this rule: clicking set checked=true and the rendered box was identical in
   both states.

   Rather than hunt the theme's broken rule, the tick is drawn here: a rotated border glyph,
   scoped to :checked so the unchecked box is left exactly as designed.
   ------------------------------------------------------------------------ */
#wfacp-e-form input[type="checkbox"],
form.checkout input[type="checkbox"] {
  position: relative;
  appearance: none;
  -webkit-appearance: none;
  border: 1px solid var(--zg-rule);
  border-radius: 2px;
  background: #fff;
  flex: 0 0 auto;
}

/* The tick is painted as a background image on the input itself, not as a ::after. The theme
   owns that pseudo-element and positions it with rules this stylesheet cannot cleanly displace:
   an earlier attempt to centre a rotated border glyph there left the mark stuck in the corner.
   A background SVG has no such conflict, centres by definition, and scales with the box. */
body #wfacp-e-form input[type="checkbox"]:checked,
body form.checkout input[type="checkbox"]:checked,
body .woocommerce-checkout input[type="checkbox"]:checked {
  background-color: var(--zg-ink) !important;
  border-color: var(--zg-ink) !important;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 14'%3E%3Cpath d='M2.5 7.4l3 3 6-6.4' fill='none' stroke='%23F5F3EB' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") !important;
  background-repeat: no-repeat !important;
  background-position: center !important;
  background-size: 12px 12px !important;
}

/* The theme's own glyph is suppressed so the two cannot both draw. */
body #wfacp-e-form input[type="checkbox"]::after,
body form.checkout input[type="checkbox"]::after,
body .woocommerce-checkout input[type="checkbox"]::after {
  content: none !important;
}

/* Keyboard users need to see where they are. */
body #wfacp-e-form input[type="checkbox"]:focus-visible,
body form.checkout input[type="checkbox"]:focus-visible {
  outline: 2px solid var(--zg-ink) !important;
  outline-offset: 2px;
}

/* ---------------------------------------------------------------------------
   73. CART DRAWER AND PANEL HOVER STATES
   ---------------------------------------------------------------------------
   Measured on the drawer's Checkout button:
       resting   background rgb(20,19,15)  text rgb(245,243,235)
       hovered   background rgb(20,19,15)  text rgb(0,0,0)
   The background never changes. Something sets colour to pure black on hover, so the label
   goes black on black and the button reads as a solid bar with nothing in it. That is the
   "checkout turns black when hovering" report, and the same thing happens to the icon row in
   the Select options panel: the content disappears, not the button.

   The fix is to hold the resting foreground through hover and to move the feedback to the
   background, where it belongs. Scoped to the drawer and the variation panel so nothing else
   inherits it.
   ------------------------------------------------------------------------ */
#fkcart-modal .fkcart-checkout-button,
#fkcart-modal a[href*="checkout"],
#fkcart-modal .fkcart-checkout-button:hover,
#fkcart-modal .fkcart-checkout-button:focus,
#fkcart-modal a[href*="checkout"]:hover,
#fkcart-modal a[href*="checkout"]:focus {
  color: var(--zg-cream) !important;
  border-color: var(--zg-ink) !important;
}

/* The rule that actually caused it lives in the site's own custom CSS:

       #fkcart-modal .fkcart-checkout-wrap #fkcart-checkout-button:hover
       { background: #fff; color: #000 !important }

   That is a deliberate inversion, white ground with dark text, and it is a perfectly good
   hover for a black button. It broke only because it sets colour with !important but the
   background without, so an earlier attempt here to darken the background on hover won the
   background and lost the text: dark ink behind pure black type.

   So the inversion is honoured rather than fought, at the same two-ID specificity, in the
   brand's cream instead of pure white. */
@media (hover: hover) {
  #fkcart-modal .fkcart-checkout-wrap #fkcart-checkout-button:hover,
  #fkcart-modal .fkcart-checkout-wrap #fkcart-checkout-button:focus-visible {
    background-color: var(--zg-cream) !important;
    color: var(--zg-ink) !important;
    border-color: var(--zg-ink) !important;
  }
}

#fkcart-modal .fkcart-checkout-wrap #fkcart-checkout-button:active {
  background-color: var(--zg-sand) !important;
  color: var(--zg-ink) !important;
}

/* Any icon or link inside the drawer and the variation panel keeps its own colour on hover,
   rather than being repainted to black on a dark ground. */
#fkcart-modal a:hover,
#fkcart-modal button:hover,
#fkcart-modal [class*="fkcart-panel"] a:hover,
#fkcart-modal [class*="fkcart-panel"] button:hover {
  color: inherit;
}

#fkcart-modal a:hover svg,
#fkcart-modal button:hover svg,
#fkcart-modal a:hover svg path,
#fkcart-modal button:hover svg path {
  fill: inherit;
  stroke: currentColor;
}

/* ---------------------------------------------------------------------------
   74. WISHLIST HEART IN THE VARIATION PANEL
   ---------------------------------------------------------------------------
   The site's custom CSS draws this heart WHITE inside the variation wrap:

       .raven-product-add-to-cart .single_variation_wrap
         .elementor-widget-jet-wishlist-button a.jet-wishlist-button__link path.cls-1
       { stroke: #fff }

   That was correct when the control sat on a dark button. It no longer does, so the heart is
   white on a light panel and simply cannot be seen: what is left is the black button beside it
   reading as a bar with nothing in it. On hover the same custom CSS switches the stroke to
   #000, which is why the heart reappears when the pointer is over it and vanishes when it is
   not. That is the whole of the "black bar hides a heart" report.

   Ink in both states, at the same specificity plus one, and the added state keeps its own fill
   so "already saved" still reads.
   ------------------------------------------------------------------------ */
body .raven-product-add-to-cart .single_variation_wrap .elementor-widget-jet-wishlist-button a.jet-wishlist-button__link path.cls-1,
body .raven-product-add-to-cart.raven-product-simple a.jet-wishlist-button__link path.cls-1,
body .raven-product-add-to-cart .single_variation_wrap .elementor-widget-jet-wishlist-button a.jet-wishlist-button__link:hover path.cls-1,
body .raven-product-add-to-cart.raven-product-simple a.jet-wishlist-button__link:hover path.cls-1 {
  stroke: var(--zg-ink) !important;
  fill: none !important;
}

/* Saved: filled, so the two states are still told apart. */
body .raven-product-add-to-cart a.jet-wishlist-button__link.added-to-wishlist path.cls-1 {
  fill: var(--zg-ink) !important;
  stroke: var(--zg-ink) !important;
}

/* The same custom CSS pins this control to 40px tall while the row beside it is 54, which is
   what made the heart sit off the line of the button. */
body .raven-product-add-to-cart .single_variation_wrap .elementor-widget-jet-wishlist-button,
body .raven-product-add-to-cart.raven-product-simple .elementor-widget-jet-wishlist-button {
  width: 50px !important;
  height: 54px !important;
}

body .raven-product-add-to-cart .single_variation_wrap .elementor-widget-jet-wishlist-button a.jet-wishlist-button__link,
body .raven-product-add-to-cart.raven-product-simple a.jet-wishlist-button__link {
  height: 54px !important;
  display: flex !important;
  align-items: center !important;
  justify-content: center !important;
  border: 1px solid var(--zg-ink) !important;
  border-radius: 2px !important;
  background: transparent !important;
}

/* The added-state plane was a solid black square, heavier than the buy button next to it. */
body .jet-wishlist-button__plane-added {
  background-color: transparent !important;
}

/* ---------------------------------------------------------------------------
   75. CHECKOUT SUMMARY: SIZE AND "SELECT OPTIONS"
   ---------------------------------------------------------------------------
   FunnelKit's own picker, switched on by checkout-size-swap.php. It arrives as a bare
   "Size: 50ML" line followed by a "SELECT OPTIONS" link in the plugin's default type, which in
   a summary column reads louder than the product name above it.

   A summary line is read in this order: what it is, then which size, then how many, then what
   it costs. So the size is a small caps label, and the link that changes it is quieter still:
   a customer confirming an order is not being asked to choose again, only given a way back if
   they got it wrong.
   ------------------------------------------------------------------------ */
body .wfacp_cart_title_sec .variation,
body .wfacp_cart_title_sec .variation dt,
body .wfacp_cart_title_sec .variation dd {
  font-family: Avenir, "Helvetica Neue", Helvetica, Arial, sans-serif !important;
  font-size: 11px !important;
  line-height: 1.5 !important;
  letter-spacing: 0.06em;
  color: var(--zg-muted) !important;
  margin: 0 !important;
  padding: 0 !important;
  display: inline !important;
  font-weight: 400 !important;
}

body .wfacp_cart_title_sec .variation {
  margin: 0.15rem 0 0.1rem !important;
}

/* The link back into the picker. */
/* No #wfacp-e-form prefix: the order summary renders OUTSIDE that form element, which is why
   an earlier version of this rule never applied. Measured: the link was 14px pure black. */
body a.wfacp_qv-button.wfacp_select_option,
body a.wfacp_select_option {
  display: inline-block !important;
  font-family: Avenir, "Helvetica Neue", Helvetica, Arial, sans-serif !important;
  font-size: 10px !important;
  font-weight: 500 !important;
  letter-spacing: 0.12em !important;
  text-transform: uppercase !important;
  color: var(--zg-muted) !important;
  text-decoration: underline !important;
  text-underline-offset: 3px;
  margin-top: 0.2rem !important;
}

@media (hover: hover) {
  body a.wfacp_qv-button.wfacp_select_option:hover,
  body a.wfacp_select_option:hover {
    color: var(--zg-ink) !important;
  }
}

/* Any select the plugin drops into a summary line stays small: the column is 300px wide and a
   full-height form control there dwarfs the product name it belongs to. */
body .wfacp_cart_title_sec select,
body .product-name select {
  height: 28px !important;
  min-height: 28px !important;
  width: auto !important;
  max-width: 120px !important;
  padding: 2px 20px 2px 7px !important;
  font-size: 11px !important;
  letter-spacing: 0.06em;
  border: 1px solid var(--zg-rule) !important;
  border-radius: 2px !important;
  background-color: transparent !important;
}


/* ---------------------------------------------------------------------------
   76. HEADER ICONS ON TOUCH  (WITHDRAWN)
   ---------------------------------------------------------------------------
   This section forced the header icons white inside @media (hover: none), to work around the
   site's own CSS keeping them white only via #header-row:not(:hover) — a guard that fails on a
   phone, where a tap leaves :hover stuck and the icons drop to black.

   It caused worse damage than it fixed. The mobile menu renders INSIDE #header-row, so a blanket
   colour:#fff on that subtree turned the menu links white on the cream drawer: the menu opened
   to an apparently blank screen. It also whitened the wishlist heart and broke the bag icon,
   both reported from a real phone.

   Reverted rather than narrowed. The original complaint is that icons briefly go dark on a
   transparent header, which is cosmetic; an unreadable menu is not. If it is worth revisiting,
   the fix belongs on the individual icons, never on the #header-row subtree, and it must be
   verified with the drawer OPEN as well as closed.
   ------------------------------------------------------------------------ */

/* ---------------------------------------------------------------------------
   77. FAQ PAGE
   ---------------------------------------------------------------------------
   Measured before this: the h1 was 22px while product h1s are around 48px, and the accordion
   questions were 15px serif and centre-aligned. So the page's own title was quieter than the
   questions beneath it, and 28 centred questions gave the eye no left edge to run down. A FAQ
   is scanned, never read top to bottom, so alignment matters more here than anywhere else on
   the site.

   The title takes the same scale as the rest of the site, the questions go left, and the
   chevron gets pushed to the right margin so the question text starts at a consistent x.
   ------------------------------------------------------------------------ */
body.page-id-20028 main.jupiterx-main h1,
body.page-id-20028 .elementor-widget-theme-page-title h1 {
  font-family: "GlacialIndifference", Georgia, serif !important;
  font-size: clamp(2.2rem, 5vw, 3.2rem) !important;
  line-height: 1.08 !important;
  letter-spacing: -0.01em;
}

/* The questions. These are Raven/Jupiter X advanced accordions, so the classes are
   jx-ac-title / jx-single-accordion-header / jx-single-accordion-body, not Elementor's own
   accordion classes: an earlier version of this section targeted .elementor-tab-title and
   matched nothing at all.

   Left aligned, one type size, and a real 48px row. Every answer also carried an inline
   text-align:center, which no stylesheet can politely override; those were stripped from the
   content itself rather than fought here. */
body.page-id-20028 h4.jx-ac-title {
  text-align: left !important;
  font-family: Avenir, "Helvetica Neue", Helvetica, Arial, sans-serif !important;
  /* A question is a row label, not a heading: body size at the heading weight. */
  font-size: var(--zg-fs-body) !important;
  font-weight: var(--zg-fw-head) !important;
  line-height: 1.5 !important;
  letter-spacing: 0.01em !important;
  color: var(--zg-ink) !important;
  margin: 0 !important;
}

body.page-id-20028 .jx-single-accordion-header {
  min-height: 48px;
  align-items: center;
  padding: 0.55rem 0 !important;
  cursor: pointer;
}

body.page-id-20028 .jupiterx-single-advanced-accordion-wrapper {
  border-bottom: 1px solid var(--zg-rule) !important;
}

/* Answers read as prose, not as more headings. */
body.page-id-20028 .jx-single-accordion-body,
body.page-id-20028 .jx-single-accordion-body p,
body.page-id-20028 .jx-single-accordion-body li {
  text-align: left !important;
  font-family: Avenir, "Helvetica Neue", Helvetica, Arial, sans-serif !important;
  font-size: var(--zg-fs-body) !important;
  line-height: var(--zg-lh-body) !important;
  color: var(--zg-ink) !important;
}

body.page-id-20028 .jx-single-accordion-body strong { font-weight: 600; }

body.page-id-20028 .jx-single-accordion-body a {
  color: var(--zg-ink) !important;
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* The chevron sits at the right margin so every question starts at the same x. */
body.page-id-20028 .jx-single-accordion-header-right { margin-left: auto; }

body.page-id-20028 svg.jx-ac-toggle-icon {
  width: 11px !important;
  height: 11px !important;
  fill: var(--zg-muted) !important;
}

/* A hidden leftover from the dead GLS picker sits on this page at zero height. It is invisible
   but still reachable, so it comes out of the accessibility tree entirely. */
body.page-id-20028 [class*="gls"],
body.page-id-20028 [id*="gls"] {
  display: none !important;
}

/* The questions looked centred even with text-align:left on the h4, because the two flex
   wrappers around it carry justify-content:center. text-align cannot beat that: the h4's box
   was being centred, not its text. Measured at 1440: header 700px wide starting at x=370, the
   h4's own box 274px starting at x=583. Both wrappers go to flex-start and the title takes the
   remaining width, so every question begins at the same x as the section heading above it. */
body.page-id-20028 .jx-single-accordion-header,
body.page-id-20028 .jx-single-accordion-header-left {
  justify-content: flex-start !important;
}

body.page-id-20028 .jx-single-accordion-header-left {
  flex: 1 1 auto !important;
  min-width: 0;
}

body.page-id-20028 h4.jx-ac-title {
  flex: 1 1 auto !important;
  width: 100% !important;
}

/* The section headings are Elementor headings and centre themselves. On a page that is scanned
   rather than read, they should share the left edge the questions now use. */
body.page-id-20028 main.jupiterx-main h2.elementor-heading-title,
body.page-id-20028 main.jupiterx-main h3.elementor-heading-title {
  text-align: left !important;
}

/* ---------------------------------------------------------------------------
   78. RELATED FRAGRANCES AT THE END OF AN ARTICLE
   ---------------------------------------------------------------------------
   From internal-links.php. Its job is to stop an article being a dead end, so it sits after the
   text as a quiet footer rather than competing with it: rule above, small caps label, names at
   reading size. Nothing here should look like an advert, because the reader has just finished
   something and is deciding whether to go further.
   ------------------------------------------------------------------------ */
.zg-related {
  margin: 3rem 0 1rem;
  padding-top: 1.6rem;
  border-top: 1px solid var(--zg-rule);
}

.zg-related__h {
  font-family: Avenir, "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--zg-muted);
  margin: 0 0 0.7rem;
}

.zg-related__list {
  list-style: none;
  margin: 0 0 1rem;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem 1.4rem;
}

.zg-related__list a {
  font-family: "GlacialIndifference", Georgia, serif;
  font-size: 16px;
  color: var(--zg-ink);
  text-decoration: none;
  border-bottom: 1px solid var(--zg-rule);
  padding-bottom: 1px;
}

@media (hover: hover) {
  .zg-related__list a:hover { border-bottom-color: var(--zg-ink); }
}

.zg-related__note {
  margin: 0;
  font-size: 13px;
  line-height: 1.62;
  color: var(--zg-muted);
}

.zg-related__note a {
  color: var(--zg-ink);
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* A fragrance named in the body of an article links to itself once. It is prose, not a button,
   so it takes the same quiet underline the rest of the copy uses. */
.single-post .entry-content a[href*="/products/perfumes/"],
.single-post article a[href*="/products/perfumes/"] {
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
}

/* ---------------------------------------------------------------------------
   79. HEADER ICONS WHILE THE MOBILE DRAWER IS OPEN
   ---------------------------------------------------------------------------
   The narrow version of what section 76 got wrong. The site's own CSS keeps the header icons
   white over the dark hero with:

       body.jupiterx-header-overlapped:not(.stick) #header-row:not(:hover)
         a.jet-wishlist-count-button__link svg .cls-1 { stroke: #ffffff }

   White is right over the hero. It is wrong once the mobile drawer opens, because the header
   then sits on cream, and :not(:hover) still matches on a phone where there is no hover to
   leave. Measured with the drawer open: the wishlist heart and one header icon both compute
   stroke rgb(255,255,255) against a rgb(245,243,235) drawer.

   Scoped to the drawer-open class and to those two SVG strokes ONLY. Section 76 failed because
   it coloured the whole #header-row subtree, and the mobile menu renders inside that subtree,
   so the menu's own links went white on cream and the drawer looked empty. Nothing here can
   reach a link's text colour, because nothing here targets anything but an svg stroke.
   ------------------------------------------------------------------------ */
body.zg-mobile-menu-open #header-row a.jet-wishlist-count-button__link svg .cls-1,
body.zg-mobile-menu-open #header-row a.jet-wishlist-count-button__link svg path,
body.zg-mobile-menu-open #header-row .elementor-icon svg path {
  stroke: var(--zg-ink) !important;
}

/* Two icons section 79 missed, because the white was not on the stroke:
     the search magnifier is a FILLED glyph whose path carries fill:#fff
     the drawer's close X carries stroke:#fff on its path
   Both measured with the drawer open, against the cream drawer. Still scoped to
   zg-mobile-menu-open and still only touching svg paint, never a text colour. */
body.zg-mobile-menu-open #header-row .elementor-icon svg path[fill],
body.zg-mobile-menu-open #header-row .elementor-icon svg path {
  fill: var(--zg-ink) !important;
}

/* The account, wishlist and bag are OUTLINE icons: a fill would turn them into solid blobs, so
   their transparent fill is restored after the blanket rule above.

   CORRECTED 2026-09-18. This block named the wishlist and the bag by their wrappers and missed
   the ACCOUNT icon, which sits in a plain .elementor-icon exactly like the search magnifier. The
   blanket fill above therefore still reached it, and opening the drawer turned the account icon
   from an outline into a solid black blob. Reported from a phone, reproduced headless: with the
   drawer open its path computed fill rgb(20,19,15) where closed it is fill:none stroke:#231f20.

   The wrapper cannot tell the two apart, but the artwork can. Every outline icon here draws with
   class .cls-1, which the SVG itself defines as fill:none;stroke:#231f20. The search magnifier is
   a genuinely filled glyph and carries no .cls-1, so it keeps the fill it needs. Measured with the
   drawer open: search .elementor-icon fill ink and no .cls-1, account .elementor-icon .cls-1,
   wishlist .jet-cw-icon .cls-1, bag .fkcart-shortcode-icon-wrap. */
body.zg-mobile-menu-open #header-row .jet-cw-icon svg path,
body.zg-mobile-menu-open #header-row .fkcart-shortcode-icon-wrap svg path,
body.zg-mobile-menu-open #header-row .elementor-icon svg .cls-1 {
  fill: none !important;
  stroke: var(--zg-ink) !important;
}

body.zg-mobile-menu-open .jet-mobile-menu__toggle svg path,
body.zg-mobile-menu-open .jet-mobile-menu__toggle svg line,
body.zg-mobile-menu-open .jet-mobile-menu__toggle-icon svg path {
  stroke: var(--zg-ink) !important;
  fill: var(--zg-ink) !important;
}

/* ---------------------------------------------------------------------------
   80. MOBILE NAVIGATION  (WITHDRAWN)
   ---------------------------------------------------------------------------
   A server-rendered replacement drawer lived here, built because JetMenu 3.0.4 shipped an
   empty mobile menu. It worked, but it was a plain list where the site has a mega menu, its
   own close control ended up behind the panel it was meant to close, and it did not feel like
   the menu it replaced. Replacing the menu was the wrong instinct: the fault was the plugin.

   JetMenu has been rolled back to 3.0.3 and pinned (mu-plugins/pin-jet-menu.php), so the
   original menu is back with no custom code in front of it. This section is gone entirely,
   including the rule that hid .jet-mobile-menu__toggle on mobile, which would otherwise have
   hidden the real menu once the replacement was removed.
   ------------------------------------------------------------------------ */

/* ---------------------------------------------------------------------------
   81. DRAWER CLOSE ICON AND TAP FOCUS RING
   ---------------------------------------------------------------------------
   Two things left over once the menu itself was working again.

   The close X still computed stroke rgb(255,255,255) with the drawer open, against the cream
   drawer, so it read as an empty corner. The heart and bag were already corrected by section
   79; this one needs more weight because the toggle's own icon rule outranks it.

   And tapping a menu item left a blue focus ring on it, because the browser's default :focus
   style applies to a pointer tap as well as to keyboard navigation. Keyboard users still get a
   visible ring through :focus-visible; a thumb no longer leaves one behind.
   ------------------------------------------------------------------------ */
body.zg-mobile-menu-open .jet-mobile-menu__instance .jet-mobile-menu__toggle svg path,
body.zg-mobile-menu-open .jet-mobile-menu__instance .jet-mobile-menu__toggle svg line,
body.zg-mobile-menu-open .jet-mobile-menu__instance .jet-mobile-menu__toggle-icon svg path,
body.zg-mobile-menu-open .jet-mobile-menu__toggle .jet-mobile-menu__toggle-icon svg path,
body.zg-mobile-menu-open .jet-mobile-menu__toggle-icon svg * {
  stroke: var(--zg-ink) !important;
  fill: var(--zg-ink) !important;
  color: var(--zg-ink) !important;
}

/* A tap should not leave a focus ring; a Tab key still should. */
.jet-mobile-menu__container a:focus:not(:focus-visible),
.jet-mobile-menu__container button:focus:not(:focus-visible),
.jet-mobile-menu__item a:focus:not(:focus-visible) {
  outline: none !important;
  box-shadow: none !important;
}

.jet-mobile-menu__container a:focus-visible {
  outline: 2px solid var(--zg-ink) !important;
  outline-offset: -2px;
}

/* The drawer's close icon is built from <line class="st2460"> elements, and rules using
   var(--zg-ink) matched with !important yet the computed stroke stayed white: the same silent
   failure mode as an undefined custom property, where the declaration is simply dropped. A
   literal value removes the variable from the question. */
body.zg-mobile-menu-open .jet-mobile-menu__toggle svg line,
body.zg-mobile-menu-open .jet-mobile-menu__toggle svg .st2460,
body.zg-mobile-menu-open .jet-mobile-menu__toggle-icon svg line,
body.zg-mobile-menu-open .jet-mobile-menu__toggle svg [class^="st"] {
  stroke: #14130F !important;
  stroke-width: 8 !important;
}

/* ---------------------------------------------------------------------------
   82. THE CART ICON HAS NO COLOUR
   ---------------------------------------------------------------------------
   The bag is an SVG drawn with fill="currentColor", and the colour it inherits computes to
   rgba(255, 255, 255, 0): fully transparent. Measured in both states, drawer open and closed,
   so this is not the drawer bug from section 79 and it is not something introduced today: the
   fill has simply never resolved to anything visible, leaving only a hairline stroke.

   Giving the wrapper a real colour is all it needs, because currentColor then has something to
   be. Scoped to the fkcart icon so nothing else inherits it.
   ------------------------------------------------------------------------ */
#header-row .fkcart-shortcode-icon-wrap,
#header-row .fkcart-shortcode-icon-wrap svg,
header .fkcart-shortcode-icon-wrap,
header .fkcart-shortcode-icon-wrap svg {
  color: var(--zg-ink) !important;
}

#header-row .fkcart-shortcode-icon-wrap svg path,
header .fkcart-shortcode-icon-wrap svg path {
  stroke: var(--zg-ink) !important;
  stroke-width: 1.6 !important;
}

/* Over the dark hero, where the rest of the header is white, the bag follows. */
body.jupiterx-header-overlapped:not(.stick):not(.zg-mobile-menu-open) #header-row .fkcart-shortcode-icon-wrap,
body.jupiterx-header-overlapped:not(.stick):not(.zg-mobile-menu-open) #header-row .fkcart-shortcode-icon-wrap svg {
  color: #fff !important;
}

body.jupiterx-header-overlapped:not(.stick):not(.zg-mobile-menu-open) #header-row .fkcart-shortcode-icon-wrap svg path {
  stroke: #fff !important;
}


/* ---------------------------------------------------------------------------
   84. MOBILE MENU - ICON, BACK CONTROL AND FOCUS RINGS
   ---------------------------------------------------------------------------
   THE TOGGLE DREW TWO ICONS AT ONCE. `.jet-mobile-menu__toggle-icon` carries a custom
   hamburger as a CSS background image (menu-icon.svg, uploaded January 2025) and JetMenu
   renders its own inline SVG on top of it. Closed, both draw a hamburger, they line up, and it
   reads as one icon. Open, JetMenu swaps its inline SVG to an X while the background image
   stays a hamburger, so the two composite into an X with three horizontal bars through it.
   That is the hourglass. Confirmed by hiding each layer in turn on the live page.

   The background is dropped only while the drawer is open, so the closed icon keeps exactly
   the shape it has always had and only the open state changes.

   THE BACK CONTROL WAS HEADING SIZED. Pre-existing site CSS renders the word from a
   pseudo-element, `.jet-mobile-menu__back::before { content: "Back"; font-size: 25px }`. The
   menu items above it measure 24.8px, so a secondary control was set in the same size as the
   things it goes back from. Sized to a control here, and given a 44px tap target, which it did
   not have at 30px tall. The chevron is a background image on the element and is left alone.

   FOCUS RINGS ON TOUCH. A tap left the browser's focus ring drawn around the row afterwards.
   Suppressed for pointer input only: :focus-visible still gets a ring, so keyboard users keep
   theirs. Nothing here sets a colour on the drawer subtree, which is what made it render blank
   in an earlier attempt: the menu itself lives inside #header-row.
   ------------------------------------------------------------------------ */
/* The site already ships the right design and it was never reaching the page:

       .jet-mobile-menu__toggle:not(.active) .jet-mobile-menu__toggle-icon
           background-image: url(menu-icon.svg) !important;  filter: invert(1) !important;
       .jet-mobile-menu__toggle.active .jet-mobile-menu__toggle-icon
           background-image: url(cross.svg) !important;

   JetMenu 3.0.3 never puts `.active` on the toggle, so the icon is pinned to the hamburger
   branch for ever while JetMenu's own inline SVG swaps to an X on top of it. Hamburger plus X
   is the hourglass. The class is therefore set from mobile-menu-fix.php, in step with the
   drawer, which lets the shop's own cross.svg appear as it was meant to and also corrects
   aria-expanded, which JetMenu leaves on "false" while the drawer is open.

   Note the specificity, because an earlier attempt here lost to it: those rules are three
   classes AND !important, so `body.zg-mobile-menu-open .jet-mobile-menu__toggle-icon` at two
   classes could not override them even with !important of its own.

   With the background now correct in both states, JetMenu's inline SVG is redundant while the
   drawer is open and is hidden so that only one icon draws. The closed state is left exactly
   as it is. */
body.zg-mobile-menu-open .jet-mobile-menu__toggle-icon svg {
  visibility: hidden !important;
}

/* visibility, not display. The icon is a 16x16 flex box whose size comes entirely from the
   inline SVG inside it, and the background image is painted on that box. display: none
   collapsed it to 0x0, so the cross had nothing to paint into and the toggle went blank.
   visibility keeps the box and its size and only stops the SVG drawing. The explicit size
   below makes that independent of the child from now on. */
.jet-mobile-menu__toggle-icon {
  min-width: 16px;
  min-height: 16px;
}

.jet-mobile-menu__back::before {
  font-size: 16px !important;
  letter-spacing: 0.02em;
}

.jet-mobile-menu__back {
  min-height: 44px !important;
}

.jet-mobile-menu__container *:focus:not(:focus-visible),
.jet-mobile-menu__toggle:focus:not(:focus-visible),
.jet-mobile-menu__back:focus:not(:focus-visible) {
  outline: none !important;
  box-shadow: none !important;
}

.jet-mobile-menu__instance {
  -webkit-tap-highlight-color: transparent;
}


/* ---------------------------------------------------------------------------
   85. COLLECTIONS ROW ON ABOUT, FAQ AND CONTACT
   ---------------------------------------------------------------------------
   The row is appended to the page content by the internal-links mu-plugin. On an article it
   inherits the article column, but these three pages are Elementor sections whose own text is
   inset while the section runs the full width, so the row sat hard against the viewport edge,
   20px out of line with the paragraphs above it. Measured at 1200: paragraphs start at x=20,
   the row started at x=0 and ran the full 1200.

   The inset matches the section padding rather than inventing a new one, and the cap keeps the
   note from setting one very long line on a wide monitor.
   ------------------------------------------------------------------------ */
.zg-related--page {
  box-sizing: border-box;
  padding-left: 20px;
  padding-right: 20px;
}

.zg-related--page .zg-related__note {
  max-width: 68ch;
}


/* ---------------------------------------------------------------------------
   86. POST-PURCHASE OFFER PAGE
   ---------------------------------------------------------------------------
   The one page in the funnel whose entire job is to earn a second charge, and the hierarchy on
   it was inverted. Read from the Elementor data for the offer:

       wfocu-offer-reject-link     font-size 30px desktop, 20 tablet, 18 mobile
       wfocu-accept-offer-button   font-size 18px desktop, 12 mobile

   So "No thanks, I don't want to take advantage of this one-time offer" was set nearly twice
   the size of "Get This Offer", underlined, and running the full width of the page. The decline
   was the largest piece of type below the product. That is not a small styling complaint, it is
   the offer arguing against itself.

   This does not redesign the page. It corrects the order of the two controls: the accept button
   is given the presence of a real button, and the decline becomes what it should always have
   been, a quiet link underneath it that anyone who wants it can still find.

   The stray "Select a Pickup Point" heading that used to appear under all this came from the GLS
   plugin printing its map into every wp_footer on the site. That is fixed separately, in
   mu-plugins/gls-pickup-scope.php.
   ------------------------------------------------------------------------ */
.elementor-widget-wfocu-offer-reject-link {
  margin-top: 0.5rem !important;
}

.elementor-widget-wfocu-offer-reject-link a,
.elementor-widget-wfocu-offer-reject-link .wfocu-offer-reject-link,
.elementor-widget-wfocu-offer-reject-link span {
  font-family: Avenir, "Helvetica Neue", Helvetica, Arial, sans-serif !important;
  font-size: 13px !important;
  line-height: 1.5 !important;
  letter-spacing: 0.04em !important;
  font-weight: 400 !important;
  color: var(--zg-muted) !important;
  text-decoration: underline !important;
  text-underline-offset: 3px !important;
  text-decoration-thickness: 1px !important;
}

.elementor-widget-wfocu-offer-reject-link a:hover {
  color: var(--zg-ink) !important;
}

.elementor-widget-wfocu-accept-offer-button a,
.elementor-widget-wfocu-accept-offer-button button,
.elementor-widget-wfocu-accept-offer-button .wfocu-accept-offer-button {
  font-size: 13px !important;
  letter-spacing: 0.18em !important;
  min-height: 56px !important;
  padding: 1rem 2.6rem !important;
  display: inline-flex !important;
  align-items: center !important;
  justify-content: center !important;
}

@media (max-width: 767px) {
  .elementor-widget-wfocu-accept-offer-button a,
  .elementor-widget-wfocu-accept-offer-button button,
  .elementor-widget-wfocu-accept-offer-button .wfocu-accept-offer-button {
    width: 100% !important;
    max-width: 420px !important;
  }
  .elementor-widget-wfocu-offer-reject-link a,
  .elementor-widget-wfocu-offer-reject-link span {
    font-size: 12.5px !important;
  }
}

/* ==========================================================================
   87. COOKIE CONSENT — SLIM BOTTOM BAR ON MOBILE
   --------------------------------------------------------------------------
   WHAT WAS WRONG
   The CookieYes notice is configured as a "box" (banner type "box", position
   bottom-left, see ptlo_cky_banners). On a 375px phone that box measured
   375 x 267 — a third of the viewport — because the three buttons are
   flex: 1 1 auto with 17.6px side padding, so each one claims the full 338px
   row and they stack three high (133px of the 267px is just buttons).

   WHAT THIS DOES
   Mobile only (<=767px): the three buttons share one row, the wasted 24px
   side padding on the title and description is removed, and the bar is
   pinned edge to edge at the bottom. Measured 267px -> ~175px.

   Desktop is deliberately untouched. There the notice is a small corner box,
   it is not in the way, and desktop LCP is already 1.6s.

   WHAT THIS DOES *NOT* DO, AND WHY — read this before "finishing the job"
   This does not stop the notice being the LCP element, and no amount of CSS
   can. LCP for a text block is the area of the text itself, and rewrapping or
   re-columning text does not change its area — only font-size or less text
   does. Measured on the homepage over throttled 4G:

       cookie description <p>   22,750 px2   <- LCP element
       hero <h1>                16,632 px2
       hero poster (full bleed)  EXCLUDED

   The hero cannot take the LCP back, and that is not a bug to fix. Chrome
   deliberately ignores any image that covers essentially the whole viewport,
   treating it as a backdrop rather than content. Verified against a local
   reproduction, five variants, same image and markup throughout:

       absolute, 50vh tall            -> counted (169,744)
       absolute, inset:0, contain     -> counted (95,172)   (letterboxed)
       absolute, inset:0, cover       -> EXCLUDED
       in flow, 100vh, cover          -> EXCLUDED
       absolute, inset:0, fill        -> EXCLUDED

   So LCP is whichever is larger, the H1 or this paragraph, and the paragraph
   wins by 37%. Getting it under the H1 needs ~27% less text, which is one
   field in the CookieYes dashboard (Banner > Content > Description) — not
   something to chase here by shrinking type to 10px, which would be worse for
   the reader and still legally the notice people must be able to read.

   Nothing here hides or truncates consent text, and Reject All keeps exactly
   the same size and prominence as Accept All. Do not "optimise" this by
   clamping the description or de-emphasising Reject.
   ========================================================================== */
@media (max-width: 767px) {

  .cky-consent-container.cky-box-bottom-left {
    left: 0 !important;
    right: 0 !important;
    bottom: 0 !important;
    width: 100% !important;
    max-width: 100% !important;
  }

  .cky-consent-bar {
    padding: 12px 14px !important;
    border-radius: 0 !important;
    border-left: 0 !important;
    border-right: 0 !important;
    border-bottom: 0 !important;
  }

  /* The 24px side padding on these two is inherited from the desktop box and
     just narrows the text on a screen that has none to spare. */
  .cky-consent-bar .cky-title,
  .cky-consent-bar .cky-notice-des {
    padding-left: 0 !important;
    padding-right: 0 !important;
  }

  .cky-consent-bar .cky-title {
    margin: 0 0 4px !important;
    font-size: 13px !important;
    line-height: 1.25 !important;
  }

  .cky-consent-bar .cky-notice-des,
  .cky-consent-bar .cky-notice-des p {
    font-size: 12px !important;
    line-height: 1.45 !important;
    margin: 0 !important;
  }

  .cky-notice-group { gap: 8px !important; }

  /* One row of three. nowrap is the whole point — without it they stack. */
  .cky-notice-btn-wrapper {
    flex-direction: row !important;
    flex-wrap: nowrap !important;
    gap: 8px !important;
    margin: 0 !important;
  }

  /* flex-basis 0 makes the three equal regardless of label length; min-width 0
     lets them shrink below their content width, which nowrap otherwise blocks.
     44px keeps the touch target at the WCAG 2.5.5 size. */
  .cky-notice-btn-wrapper .cky-btn,
  .cky-notice-btn-wrapper button.cky-btn {
    flex: 1 1 0 !important;
    min-width: 0 !important;
    margin: 0 !important;
    padding: 10px 6px !important;
    font-size: 11px !important;
    line-height: 1.1 !important;
    min-height: 44px !important;
    white-space: nowrap !important;
    overflow: hidden !important;
    text-overflow: ellipsis !important;
  }
}

/* ==========================================================================
   88. THE BAG ICON MUST GO DARK WHEN THE MOBILE MENU OPENS
   --------------------------------------------------------------------------
   SYMPTOM (reported from a phone, reproduced): open the hamburger on the
   homepage and the bag icon is INVISIBLE - a white bag on the cream menu
   panel. Touch anywhere near it and it turns dark. The heart, account and
   search icons are dark the whole time.

   CAUSE. Every other header icon is an SVG that inherits currentColor, so
   whatever turns the header text dark turns them dark too. The bag is not:
   it is a background-image swap between two files, and the choice of file is
   keyed on hover -

     body.jupiterx-header-overlapped:not(.stick) #header-row:not(:hover) #cart-icon svg
       { background-image: url(.../white-shopping-bag-...svg) }

   White is CORRECT on the homepage, where the header sits over the dark hero
   video. But opening the mobile menu paints a cream panel behind that same
   header while `jupiterx-header-overlapped` and `:not(:hover)` both still
   hold, so the white bag stays - on cream. On a touch screen the first tap
   applies :hover, which is why it "turns dark the second you touch it".

   Measured, with the pointer moved off the header so :hover is clear:
     loaded, untouched          WHITE   (correct, dark hero behind)
     menu open, pointer on it   dark
     menu open, pointer away    WHITE   <- the bug

   FIX. While the mobile menu is open, force the dark bag regardless of hover.
   Both body classes are listed on purpose: jet-mobile-menu-visible is
   JetMenu's own, so this keeps working if mobile-menu-fix.php (which adds
   zg-mobile-menu-open) is ever removed.

   Not scoped to a media query: the class only exists while the mobile panel
   is open, and the desktop mega menu does not need it - there the pointer is
   necessarily inside #header-row to have opened the menu at all, so :hover
   already holds. Verified on desktop: moving the pointer away closes the menu
   and returns the header to the hero, where white is right again.
   ========================================================================== */
/* SPECIFICITY, and why these selectors look overwrought.
   The rule being overridden is itself !important:

     body.jupiterx-header-overlapped:not(.stick) #header-row:not(:hover) #cart-icon svg
       { background-image: url(.../white-...svg) !important }

   That is 2 IDs + 3 classes (:not(.stick) and :not(:hover) each count as one) = (2,3,1).
   When both declarations are !important, specificity decides, so the obvious
   `body.zg-mobile-menu-open #header-row #cart-icon svg` at (2,1,2) LOSES. The first
   attempt at this fix did exactly that and changed nothing on the page.
   The selectors below mirror the original and add the menu class, giving (2,4,2). */
body.jupiterx-header-overlapped.zg-mobile-menu-open:not(.stick) #header-row:not(:hover) #cart-icon svg,
body.jupiterx-header-overlapped.jet-mobile-menu-visible:not(.stick) #header-row:not(:hover) #cart-icon svg,
body.jupiterx-header-overlapped.zg-mobile-menu-open:not(.stick) #header-row:not(:hover) #fkcart-mini-toggler svg,
body.jupiterx-header-overlapped.jet-mobile-menu-visible:not(.stick) #header-row:not(:hover) #fkcart-mini-toggler svg,
/* and the plain forms, for pages where the header is not overlapped */
body.zg-mobile-menu-open #header-row #cart-icon svg,
body.zg-mobile-menu-open #fkcart-mini-toggler svg,
body.zg-mobile-menu-open .fkcart-shortcode-icon-wrap svg,
body.jet-mobile-menu-visible #header-row #cart-icon svg,
body.jet-mobile-menu-visible #fkcart-mini-toggler svg,
body.jet-mobile-menu-visible .fkcart-shortcode-icon-wrap svg {
  background-image: url(https://houseofziggimay.com/wp-content/uploads/2026/09/zg-bag-dark-v2.svg) !important;
}

/* The same swap exists for two other cart icon implementations in the theme
   and in an older cart plugin. Neither is the one rendering today, but if the
   cart widget is ever switched back they would reintroduce exactly this bug. */
body.zg-mobile-menu-open #header-row .jupiterx-icon-shopping-cart-10::before,
body.jet-mobile-menu-visible #header-row .jupiterx-icon-shopping-cart-10::before,
body.zg-mobile-menu-open #header-row .woofc-icon-cart8::before,
body.jet-mobile-menu-visible #header-row .woofc-icon-cart8::before {
  background-image: url(https://houseofziggimay.com/wp-content/uploads/2026/09/zg-bag-dark-v2.svg) !important;
}

/* ==========================================================================
   89. BAG ICON: MATCH THE WEIGHT OF THE OTHER HEADER ICONS
   --------------------------------------------------------------------------
   The bag was drawn from shopping-bag-of-normal-design-outline-svgrepo-com.svg,
   a 472px-viewBox outline scaled down to 17px. At that size its strokes render
   as hairlines - measured about 1px against roughly 2.5px on the heart and the
   search glass - so the bag read as spindly and out of family next to them, and
   its 20x25 footprint sat larger than its neighbours at the same time.

   This was never introduced by a change; it was simply invisible until the bag
   was actually dark and unobstructed (see section 88 and the badge move in
   section 45). Once both of those were fixed the mismatch was the thing left.

   Replaced with a stroke-drawn icon at stroke-width 1.9 in a 24 viewBox, shown
   at 20px, which puts its line weight on the heart's. Compared side by side at
   8x against the heart across 1.8 / 2.0 / 2.2 / 2.4 / 2.6 before choosing.
   The trapezoid tote silhouette is kept - that is the brand's shape.

   TWO FILES, not currentColor: this is a CSS background-image, which cannot
   inherit the text colour, so the light/dark swap the theme already does on
   hover needs one file each. Same two-file pattern as before, new artwork.

   Specificity note - the rule this has to beat is !important at (2,3,1):
     body.jupiterx-header-overlapped:not(.stick) #header-row:not(:hover) #cart-icon svg
   The white rule below repeats that selector exactly so it wins on source
   order, and the menu-open rule adds a class to reach (2,4,2). See section 88.
   ========================================================================== */

/* Default and menu-open state: dark bag. */
#header-row #cart-icon svg,
#header-row #fkcart-mini-toggler svg,
#header-row .fkcart-shortcode-icon-wrap svg {
  background-image: url(https://houseofziggimay.com/wp-content/uploads/2026/09/zg-bag-dark-v2.svg) !important;
  background-size: 20px 20px !important;
  background-position: 50% 50% !important;
  background-repeat: no-repeat !important;
}

/* Over the homepage hero, where the header is transparent on a dark video. */
body.jupiterx-header-overlapped:not(.stick) #header-row:not(:hover) #cart-icon svg,
body.jupiterx-header-overlapped:not(.stick) #header-row:not(:hover) #fkcart-mini-toggler svg {
  background-image: url(https://houseofziggimay.com/wp-content/uploads/2026/09/zg-bag-light-v2.svg) !important;
  background-size: 20px 20px !important;
  background-position: 50% 50% !important;
}

/* ...unless the mobile menu is open, which paints cream behind that header. */
body.jupiterx-header-overlapped.zg-mobile-menu-open:not(.stick) #header-row:not(:hover) #cart-icon svg,
body.jupiterx-header-overlapped.jet-mobile-menu-visible:not(.stick) #header-row:not(:hover) #cart-icon svg,
body.jupiterx-header-overlapped.zg-mobile-menu-open:not(.stick) #header-row:not(:hover) #fkcart-mini-toggler svg,
body.jupiterx-header-overlapped.jet-mobile-menu-visible:not(.stick) #header-row:not(:hover) #fkcart-mini-toggler svg {
  background-image: url(https://houseofziggimay.com/wp-content/uploads/2026/09/zg-bag-dark-v2.svg) !important;
}

/* ==========================================================================
   90. FOOTER TIDY-UP, AND THE PAGE-LEVEL RELATED BLOCK
   --------------------------------------------------------------------------
   (a) THE RELATED BLOCK ON ABOUT / FAQ / CONTACT WAS FLUSH LEFT AND FULL WIDTH.
   internal-links.php appends `.zg-related--page` through the_content, and on
   these Elementor pages the filtered content lands directly in .jupiterx-main
   rather than inside the page's own container. Measured on /faq/ at a 1440
   viewport: the block was x=0, w=1425, while the page content sits in a
   centred column - so it read as broken rather than as a footer strip.

   Elementor's container width here is 100% with zero padding, so there is no
   site-wide measure to inherit. The block is therefore centred on its own
   editorial measure, which reads as deliberate at any width.

   (b) THE "NEED HELP?" COLUMN HAD BULLETS. It is an Elementor icon-list
   (ul.elementor-icon-list-items) that kept list-style: disc with padding-left
   zero, so discs sat hard against the column edge in front of P: / E: / A:,
   and the four address lines inside the last item hung off that bullet.
   Contact details are not a bulleted list; the discs are removed and the
   address lines given their own rhythm.
   ========================================================================== */

.zg-related--page {
  max-width: 760px;
  margin-left: auto !important;
  margin-right: auto !important;
  padding-left: 20px;
  padding-right: 20px;
  box-sizing: content-box;
}

/* Footer contact list: details, not bullets. */
#footer .elementor-widget-text-editor ul.elementor-icon-list-items,
footer .elementor-widget-text-editor ul.elementor-icon-list-items {
  list-style: none !important;
  padding-left: 0 !important;
  margin-left: 0 !important;
}

#footer .elementor-widget-text-editor ul.elementor-icon-list-items > li,
footer .elementor-widget-text-editor ul.elementor-icon-list-items > li {
  list-style: none !important;
  display: block !important;
  margin: 0 0 6px !important;
}

#footer .elementor-widget-text-editor ul.elementor-icon-list-items > li::marker,
footer .elementor-widget-text-editor ul.elementor-icon-list-items > li::marker {
  content: none !important;
}

/* The address sits inside one item across several lines; give it a steady
   line rhythm instead of inheriting the tighter list spacing. */
#footer .elementor-widget-text-editor ul.elementor-icon-list-items > li,
footer .elementor-widget-text-editor ul.elementor-icon-list-items > li {
  line-height: 1.85 !important;
}

/* Legal and detail links: keep the underline for the hover only, so the
   column reads as a clean list rather than four underlined strings. */
#footer .raven-nav-menu .menu-item > a,
footer .raven-nav-menu .menu-item > a {
  text-decoration: none;
  transition: opacity .18s ease;
}
#footer .raven-nav-menu .menu-item > a:hover,
footer .raven-nav-menu .menu-item > a:hover,
#footer .raven-nav-menu .menu-item > a:focus-visible,
footer .raven-nav-menu .menu-item > a:focus-visible {
  text-decoration: underline;
  text-underline-offset: 3px;
  opacity: .78;
}

/* ==========================================================================
   91. THE JOURNAL — EDITORIAL TREATMENT FOR SINGLE BLOG POSTS
   --------------------------------------------------------------------------
   WHAT WAS WRONG, measured on /blog-feed/patchouli-in-perfume/ at 1440:

       line length     1000px   (~150 characters per line)
       body size       14px
       line-height     16.1px   (1.15 — tighter than the type is drawn for)
       h2 margin-top   0        (sections ran straight into each other)
       images          0

   A 150-character measure at 14px on 1.15 leading is genuinely hard to read;
   that, not the colour or the font, is why the journal looked unconsidered
   next to the rest of the shop. Everything below is reading craft: a proper
   measure, the leading the face is drawn for, and air around the headings so
   the piece has structure.

   Type is unchanged — FreightTextPro for headings, Avenir for text — because
   both are already the brand's. Nothing here loads a new font or an image.

   NOTE ON IMAGERY: these posts contain no images and no featured images, so
   there is nothing to lay out. The rules and the lead paragraph below are
   typographic devices standing in for that. Real photography is the one thing
   this cannot manufacture — see the handover note.
   ========================================================================== */

/* ---- the measure ---------------------------------------------------------
   Title and body share one column so they align. 68ch lands near 700px at
   this size, which is the readable range for long-form text. */
/* The 1025px gate this rule used to carry is exactly the kind of hole a breakpoint leaves: at
   1024px the column was unconstrained and ran to 103 characters a line, while 1025px got 68.
   A max-width needs no breakpoint - below the column width the viewport is already narrower. */
body.single-post .elementor-widget-raven-post-content > .elementor-widget-container,
body.single-post .elementor-element-73cc6c2b > .elementor-widget-container {
  max-width: var(--zg-measure);
  margin-left: auto !important;
  margin-right: auto !important;
}

/* ---- the title ---------------------------------------------------------- */
body.single-post .elementor-element-73cc6c2b h1.elementor-heading-title {
  font-size: var(--zg-fs-h1) !important;
  line-height: var(--zg-lh-h1) !important;
  letter-spacing: -0.005em;
  margin: 0 0 0.34em !important;
  text-wrap: balance;
}

/* A hairline under the title separates the piece from the header without
   adding a heavy rule. */
body.single-post .elementor-element-73cc6c2b > .elementor-widget-container::after {
  content: "";
  display: block;
  width: 54px;
  height: 1px;
  /* The post header is centred by the template, so this rule must centre too -
     with `margin: 26px 0 0` it sat at the far left and read as a stray mark. */
  margin: 26px auto 0;
  background: currentColor;
  opacity: .28;
}

/* ---- body text ---------------------------------------------------------- */
body.single-post .elementor-widget-raven-post-content p {
  font-size: var(--zg-fs-body) !important;
  line-height: var(--zg-lh-body) !important;
  margin: 0 0 1.35em !important;
  color: #14130F;
}

/* The opening paragraph carries the piece; give it a touch more presence. */
body.single-post .elementor-widget-raven-post-content > .elementor-widget-container > p:first-of-type {
  font-size: var(--zg-fs-lead) !important;
  line-height: var(--zg-lh-lead) !important;
  margin-bottom: 1.6em !important;
}

/* ---- section headings ---------------------------------------------------
   margin-top was 0, which is the whole reason the article read as one slab. */
body.single-post .elementor-widget-raven-post-content h2 {
  font-size: clamp(21px, 2.2vw, 26px) !important;
  line-height: 1.24 !important;
  font-weight: 500 !important;
  margin: 2.5em 0 0.55em !important;
  letter-spacing: -0.003em;
  text-wrap: balance;
}
body.single-post .elementor-widget-raven-post-content h3 {
  font-size: var(--zg-fs-h3) !important;
  line-height: var(--zg-lh-h3) !important;
  margin: 2em 0 0.45em !important;
}
/* No stacked gap when a heading opens the article. */
body.single-post .elementor-widget-raven-post-content h2:first-child,
body.single-post .elementor-widget-raven-post-content h3:first-child { margin-top: 0 !important; }

/* ---- lists -------------------------------------------------------------- */
body.single-post .elementor-widget-raven-post-content ul,
body.single-post .elementor-widget-raven-post-content ol {
  margin: 0 0 1.35em !important;
  padding-left: 1.15em !important;
}
body.single-post .elementor-widget-raven-post-content li {
  font-size: var(--zg-fs-body) !important;
  line-height: var(--zg-lh-body) !important;
  margin-bottom: 0.45em !important;
  padding-left: 0.2em;
}
body.single-post .elementor-widget-raven-post-content li::marker { opacity: .45; }

/* ---- links in running text ---------------------------------------------- */
body.single-post .elementor-widget-raven-post-content p > a,
body.single-post .elementor-widget-raven-post-content li > a {
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
  text-decoration-color: rgba(20, 19, 15, .35);
  transition: text-decoration-color .18s ease;
}
body.single-post .elementor-widget-raven-post-content p > a:hover,
body.single-post .elementor-widget-raven-post-content li > a:hover {
  text-decoration-color: rgba(20, 19, 15, .9);
}

/* ---- pull quotes, if a post ever uses one ------------------------------- */
body.single-post .elementor-widget-raven-post-content blockquote {
  margin: 2.2em 0 !important;
  padding: 0 0 0 22px;
  border-left: 1px solid rgba(20, 19, 15, .22);
  font-family: inherit;
  font-style: italic;
  font-size: 20px !important;
  line-height: 1.55 !important;
}

/* ---- the closing related block ------------------------------------------
   Sits at the end of every post; treat it as a considered sign-off rather
   than an appended list. */
body.single-post .zg-related {
  margin-top: 3.4em !important;
  padding-top: 1.9em;
  border-top: 1px solid rgba(20, 19, 15, .14);
}
body.single-post .zg-related__h {
  font-size: 11px !important;
  letter-spacing: .16em;
  text-transform: uppercase;
  opacity: .6;
  margin: 0 0 1em !important;
}
body.single-post .zg-related__list {
  display: flex !important;
  flex-wrap: wrap;
  gap: 10px 26px;
  list-style: none !important;
  padding: 0 !important;
  margin: 0 0 1.2em !important;
}
body.single-post .zg-related__list li { margin: 0 !important; padding: 0 !important; }
body.single-post .zg-related__list li::marker { content: none !important; }
body.single-post .zg-related__list a {
  font-family: inherit;
  font-size: 17px;
  text-decoration: none;
  border-bottom: 1px solid rgba(20, 19, 15, .3);
  padding-bottom: 2px;
  transition: border-color .18s ease;
}
body.single-post .zg-related__list a:hover { border-bottom-color: rgba(20, 19, 15, .85); }
body.single-post .zg-related__note {
  font-size: 15px !important;
  line-height: 1.65 !important;
  opacity: .78;
  margin: 0 !important;
}

/* ---- mobile -------------------------------------------------------------- */
@media (max-width: 767px) {
  /* No font-size here any more: --zg-fs-body interpolates 16 -> 17 on its own, so a
     breakpoint would only reintroduce the step this scale exists to remove. */

  body.single-post .elementor-widget-raven-post-content h2 { margin-top: 2.1em !important; }

}

/* ==========================================================================
   92. NO SIDEWAYS JUMP WHEN A DRAWER OR MODAL OPENS
   --------------------------------------------------------------------------
   Clicking the cart icon shifted the whole page 7.5px to the right. Measured
   on a blog post at a 1440 viewport:

       before click   overflow: hidden auto    scrollbar 15px   body 1425px
       after  click   overflow: hidden         scrollbar  0px   body 1440px

   The FunnelKit cart drawer locks scrolling by setting overflow:hidden on the
   document. That removes the 15px classic scrollbar, the viewport gets 15px
   wider, and every centred element slides half of that sideways. A layout
   shift of 0.0071 was recorded for it.

   It does not hurt the Core Web Vitals score - the entry carries
   hadRecentInput, so CLS excludes shifts within 500ms of a click - but it is
   plainly visible, which is what matters here.

   scrollbar-gutter: stable reserves the space whether or not the scrollbar is
   showing, so removing it changes nothing. This fixes it for EVERY scroll lock
   on the site, not just the cart: the mobile menu, the sampler popup and the
   preference centre all do the same thing.

   No effect on touch devices, where scrollbars are overlays and the reserved
   gutter is zero.
   ========================================================================== */
html {
  scrollbar-gutter: stable;
}

/* --- section 92, continued: spend the measured width while a lock is on -----
   scrollbar-gutter above handles the ordinary case. This handles the locked
   case, where the property is inert by spec. --zg-sbw is measured once by
   mu-plugins/scrollbar-width.php and is 0 wherever scrollbars are overlays,
   so this rule costs nothing on touch devices.

   padding on the root, not a margin or a transform, so it narrows the content
   box back to the width it had while the scrollbar was showing. */
html.fkcart-trigger-open,
html.zg-scroll-locked,
body.zg-mobile-menu-open,
body.jet-mobile-menu-visible {
  padding-right: var(--zg-sbw, 0px);
}

/* ==========================================================================
   93. THE HEADER MUST NOT BE TRANSPARENT ON PAGES WITH NOTHING BEHIND IT
   --------------------------------------------------------------------------
   SYMPTOM, reported from a phone on a product page: body copy ran straight
   through the logo and the icons, as if the header were not there.

   CAUSE. The header is position:fixed on every page, but its background only
   arrives with the .stick class, which the theme adds after about 80px of
   scroll. On the homepage that is deliberate - the header floats over the dark
   hero video and must stay clear. Everywhere else there is nothing behind it,
   so for that first 80px of scrolling the page slides under a header with no
   background at all. Measured:

       page                      overlapped   background at scroll 0
       /                         yes          transparent   (correct)
       /products/.../            no           TRANSPARENT   (the bug)
       /product-category/...     no           TRANSPARENT
       /blog-feed/...            no           TRANSPARENT
       /about/                   no           TRANSPARENT

   It is easy to miss because it self-corrects: scroll past ~80px and .stick
   paints it cream, so a screenshot taken at rest further down the page looks
   perfect. The broken window is the top of every page.

   FIX. Key off the theme's own signal. jupiterx-header-overlapped is set only
   where a hero sits behind the header, so anything without it gets the cream
   background immediately rather than waiting for .stick. The homepage is
   untouched and its hero still shows through.

   The 0.12s background-color transition on #header-row stays; it now only runs
   on the homepage, which is the one place a fade between states is wanted.
   ========================================================================== */
body:not(.jupiterx-header-overlapped) #header-row {
  background-color: #F5F3EB !important;
}


/* ==========================================================================
   95. THE SAMPLES OFFER ON THE PRODUCT PAGE
   --------------------------------------------------------------------------
   See mu-plugins/product-try-panel.php for why this exists. Quiet by design:
   the buy button must stay the loudest thing on the page, so this is a plain
   block with one hairline above it rather than a boxed callout competing for
   attention.
   ========================================================================== */
.zg-try {
  margin: 22px 0 0;
  padding-top: 18px;
  border-top: 1px solid rgba(20, 19, 15, .14);
}

.zg-try p { margin: 0 0 8px; }
.zg-try p:last-child { margin-bottom: 0; }

.zg-try__lead {
  font-size: 15px;
  line-height: 1.55;
  font-weight: 500;
}

.zg-try__alt {
  font-size: 14px;
  line-height: 1.6;
  opacity: .82;
}

.zg-try__read {
  font-size: 12px;
  line-height: 1.5;
  letter-spacing: .04em;
  text-transform: uppercase;
  opacity: .62;
  margin-top: 12px !important;
}

.zg-try a {
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-color: rgba(20, 19, 15, .38);
  transition: text-decoration-color .18s ease;
}
.zg-try a:hover { text-decoration-color: rgba(20, 19, 15, .9); }

.zg-try__sep { padding: 0 8px; opacity: .5; }

@media (max-width: 767px) {
  .zg-try { margin-top: 18px; padding-top: 16px; }
  .zg-try__lead { font-size: 14.5px; }
  .zg-try__alt { font-size: 13.5px; }
}

/* ==========================================================================
   96. LET THE PROMISE BAND PEEK ABOVE THE FOLD ON PHONES
   --------------------------------------------------------------------------
   Measured on the homepage at 390x844 before this:

       y=361   HOUSE OF ZIGGIMAY
       y=461   Small batch perfume made by hand in Denmark
       y=844   "01 Try before you commit ..."   <- the fold is at 844

   The hero is exactly 100vh, so the promise band starts on the fold line and
   not one pixel of it is visible. Everything that makes the shop credible -
   try before you commit, two free samples with every bottle, made by hand in
   Denmark - sat just out of sight, and there was nothing above the fold to
   suggest the page continued.

   The hero is reduced to 86vh on phones only. That is enough to show the top
   of the band and the start of the first promise, which does two things at
   once: it puts a reason to trust the shop on the first screen, and it gives
   the eye something cut off, which is what actually makes people scroll.

   Desktop is untouched. There the band is already visible on any normal
   laptop, and the full-height hero is the point of the design.

   Deliberately NOT done: adding a second block of copy or a button into the
   hero. The hero works because it is quiet, and the credibility already
   exists further down in a nicer form than a strapline would be.
   ========================================================================== */
@media (max-width: 767px) {
  .elementor-19995 .elementor-element.elementor-element-243e957 {
    min-height: 86vh !important;
    height: 86vh !important;
  }
}

/* ==========================================================================
   97. UNRELEASED FRAGRANCE PAGES
   --------------------------------------------------------------------------
   On a pending product the buy area is empty: no price, no size chosen, and a
   dead Add to Cart. That left a large blank gap and the page read as broken
   rather than as something still coming.

   The block (product-try-panel.php) is given a little more presence than the
   normal samples panel, because here it is the only thing in that column that
   says anything. Still quiet: a tinted ground and a rule, no badge shouting
   "COMING SOON", which would be at odds with the rest of the shop.
   ========================================================================== */
.zg-try--pending {
  background: rgba(20, 19, 15, .035);
  border-top: 1px solid rgba(20, 19, 15, .16);
  padding: 20px 22px 22px;
  margin-top: 20px;
}

.zg-try--pending .zg-try__lead {
  font-size: 13px;
  letter-spacing: .14em;
  text-transform: uppercase;
  opacity: .72;
  font-weight: 500;
  margin-bottom: 12px;
}

.zg-try--pending .zg-try__alt {
  font-size: 15px;
  line-height: 1.62;
  opacity: 1;
}

.zg-try--pending .zg-try__alt + .zg-try__alt {
  margin-top: 10px;
  opacity: .82;
}

@media (max-width: 767px) {
  .zg-try--pending { padding: 16px 18px 18px; }
  .zg-try--pending .zg-try__alt { font-size: 14.5px; }
}

/* ==========================================================================
   98. NO REVIEW FORM ON A FRAGRANCE NOBODY CAN BUY
   --------------------------------------------------------------------------
   Unreleased products were showing the full reviews widget: "Be the first to
   review White Tea & Oud", a star rating and a submit box. Reviews on this
   shop require a verified purchase and these products cannot be bought, so the
   form could never be used by anyone. It read as broken rather than as
   something coming.

   Hidden via the zg-pending-release body class from pending-release-guard.php,
   so it follows the same single source of truth as the purchase block: remove
   the "Pending Release" tag and reviews come back with the buy button.
   ========================================================================== */
body.zg-pending-release .elementor-widget-raven-product-reviews,
body.zg-pending-release #reviews,
body.zg-pending-release .woocommerce-Reviews {
  display: none !important;
}

/* ==========================================================================
   99. THE UNRELEASED-FRAGRANCE PANEL, PROPERLY SET
   --------------------------------------------------------------------------
   Supersedes the plain grey box in section 97. This block is the only thing
   in the buy column on these pages, and the user judged its wording better
   than the announcement image in the gallery, so it is set to carry that
   weight rather than to sit quietly out of the way.

   Treatment: the brand's tan ground rather than a neutral grey tint, a
   letterspaced eyebrow, the statement in the serif at reading size, and the
   redirect underneath in the body face. No border and no "COMING SOON" badge;
   the restraint is the point.
   ========================================================================== */
.zg-try--pending {
  background: #EFE9DC;
  border-top: none;
  padding: 26px 28px 28px;
  margin-top: 22px;
}

.zg-try--pending .zg-try__lead {
  font-size: 11px;
  letter-spacing: .2em;
  text-transform: uppercase;
  opacity: .62;
  font-weight: 500;
  margin: 0 0 14px;
}

/* The statement. Serif, because it is the house speaking rather than UI text. */
.zg-try--pending .zg-try__say {
  font-family: "FreightTextPro", Georgia, "Times New Roman", serif;
  font-size: 19px;
  line-height: 1.5;
  margin: 0 0 14px;
  color: #14130F;
  text-wrap: pretty;
}

.zg-try--pending .zg-try__alt {
  font-size: 14.5px;
  line-height: 1.62;
  opacity: .78;
  margin: 0;
}

.zg-try--pending a {
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-color: rgba(20, 19, 15, .42);
}
.zg-try--pending a:hover { text-decoration-color: rgba(20, 19, 15, .95); }

@media (max-width: 767px) {
  .zg-try--pending { padding: 20px 20px 22px; margin-top: 18px; }
  .zg-try--pending .zg-try__say { font-size: 17.5px; }
  .zg-try--pending .zg-try__alt { font-size: 14px; }
}

/* --- section 99, continued: separate the block from the promise bullets -----
   The panel sat hard against the shipping/returns/samples bullets underneath
   with no gap, so the two read as one run of text. */
.zg-try--pending { margin-bottom: 26px; }

@media (max-width: 767px) {
  .zg-try--pending { margin-bottom: 20px; }
}

/* ------------------------------------------------------------------
   101. Single-image gallery
   The Raven stack gallery lays its items out in a two-column grid. The
   unreleased fragrances carry only the featured shot now that the old
   announcement image is retired, so the second column sat empty and the
   photo hugged the left edge. Let the one item use the full column.
   The class comes from pending-release-guard.php and disappears by
   itself as soon as a product gets gallery images.
   ------------------------------------------------------------------ */
body.zg-gallery-single .raven-product-gallery-stack-wrapper {
	grid-template-columns: minmax(0, 1fr) !important;
}

/* ------------------------------------------------------------------
   102. The refillable travel atomizer
   Every perfume box holds one, and nothing on the site said so. The
   drawing comes from mu-plugins/atomizer-diagram.php and is used on the
   product pages and inside the FAQ answer, so these rules have to hold
   on both a cream panel and a white accordion body. Colour is inherited
   (the SVG strokes with currentColor) so it works on either.
   ------------------------------------------------------------------ */
.zg-try__spec {
	font-size: 14px;
	line-height: 1.62;
	opacity: .82;
}
.zg-try--pending .zg-try__spec {
	font-size: 14.5px;
	line-height: 1.62;
	opacity: .78;
	margin: 0 0 12px;
}

.zg-atom {
	/* The panel spaces its own paragraphs with a bottom margin, so the figure needs one too or
	 * the step list collides with the Discovery Box line that follows it. */
	/* !important because Elementor normalises ".elementor figure { margin: 0 }", which is one
	 * specificity point above a bare class and silently flattened the spacing to zero. */
	margin: 14px 0 12px !important;
	padding: 0;
}
/* max-width needs the !important: the theme sets img { max-width: 100% } later in the combined
 * bundle, which otherwise wins and the drawing stretches the full column width. */
.zg-atom__art {
	display: block;
	width: 100%;
	max-width: 400px !important;
	height: auto;
	opacity: .8;
}
.zg-atom--faq .zg-atom__art { max-width: 500px !important; }

.zg-atom__steps {
	list-style: none;
	margin: 10px 0 0;
	padding: 0;
	max-width: 460px;
}
.zg-atom__steps li {
	position: relative;
	padding-left: 26px;
	margin: 0 0 6px;
	font-size: var(--zg-fs-body);
	line-height: var(--zg-lh-body);
	opacity: .82;
}
.zg-atom__steps li:last-child { margin-bottom: 0; }

.zg-atom__n {
	position: absolute;
	left: 0;
	top: 0;
	font-size: 11px;
	letter-spacing: .12em;
	opacity: .55;
	line-height: 1.85;
}

@media (max-width: 767px) {
	.zg-atom__art { max-width: 100%; }
	/* the size comes from the scale at every width; nothing to override here */
}

/* ------------------------------------------------------------------
   103. Stop the homepage hiding its own story
   The "Made by hand in Denmark" block is wrapped in a Crocoblock
   JetTricks Unfold (widget 7041355). It clipped the block to a 240px
   mask against 788px of real content, so at 1440x900 roughly 70% of
   the section was hidden: the end of the copy that names the two free
   samples and the 295 DKK Discovery Box, and BOTH image cards (the
   founder portrait and the lab). What a visitor actually saw was a
   sentence cut off mid line behind an 80px cream gradient, with a READ
   MORE button under it. That is the single reason this section read as
   dull and unfinished.

   The mask height is written inline by the widget's JavaScript, so
   these need !important to win, and they keep winning after a resize.
   Scoped to the one widget: any other Unfold on the site is untouched.
   To revert: delete this section.
   ------------------------------------------------------------------ */
.elementor-element-7041355 .jet-unfold,
.elementor-element-7041355 .jet-unfold__mask {
	height: auto !important;
	max-height: none !important;
	overflow: visible !important;
}
.elementor-element-7041355 .jet-unfold__separator,
.elementor-element-7041355 .jet-unfold__trigger {
	display: none !important;
}

/* ------------------------------------------------------------------
   104. Homepage: the seven measured faults
   From a six-lens audit of the live homepage where every finding was
   re-measured before it was accepted. Numbers in the comments are the
   measured ones, not estimates.
   ------------------------------------------------------------------ */

/* 104.1  Two headings were set in FreightTextPro Black (900), a weight that
   appears nowhere else on the page. Everything else is the Book face. */
/* !important: the competing rule is .elementor-kit-19984 h2 {font-weight:900}
   at specificity (0,1,1), which outranks a bare class. */
.zg-choose__h,
.zg-maker__h { font-weight: 400 !important; }

/* 104.2  The newsletter band was a fixed 650px field holding 216px of type,
   so 217px of empty tint sat above and below it: 33% ink density, and the
   last thing before the footer. Unlike the other 650px band it carries no
   photograph, so the height bought nothing. Height now comes from padding,
   the same mechanism mobile already used. 650 -> 408px. */
.elementor-19995 .elementor-element.elementor-element-1bd0364 {
	--min-height: 0px;
	--padding-top: 96px;
	--padding-bottom: 96px;
}

/* 104.3  "The Lab" photo card had 0px below it on mobile, so its bottom edge
   sat flush on the next tinted band while the identical card above it had
   20px. Desktop keeps 50px at the same edge, so the 0 was not deliberate.
   48px puts it on the same step as the band it meets. */
@media (max-width: 767px) {
	.elementor-19995 .elementor-element.elementor-element-1bd0364 {
		--padding-top: 56px;
		--padding-bottom: 56px;
	}
	.elementor-19995 .elementor-element.elementor-element-1aada0a {
		--padding-bottom: 48px;
	}
}

/* 104.4  THE WORST ONE. On a phone the hero had no scrim at all: white
   display type straight onto the bright middle of the poster. Measured
   contrast was 2.22:1 for the H1 and 2.59:1 for the subtitle, with 100% of
   the H1 band under 4.5:1. This is the first thing a phone visitor sees.
   The gradient is shaped to be strongest where the type actually sits;
   measured after: H1 5.56:1 worst, subtitle 5.35:1 worst, 0% under 4.5:1,
   and the photograph is darkened rather than flattened.

   Mobile only, deliberately. Giving .e-con-inner position:relative on
   DESKTOP is what boxed the hero video once before (see hero-critical-css.php);
   on a phone Elementor does not render the video at all, so it cannot recur.
   check.mjs guards the desktop hero against exactly that regression. */
@media (max-width: 767px) {
	.elementor-element-243e957 { position: relative; }
	.elementor-element-243e957::before {
		content: "";
		position: absolute;
		inset: 0;
		z-index: 0;
		pointer-events: none;
		background: linear-gradient(
			rgba(20, 19, 15, .30) 0%,
			rgba(20, 19, 15, .48) 35%,
			rgba(20, 19, 15, .52) 68%,
			rgba(20, 19, 15, .35) 100%);
	}
	.elementor-element-243e957 > .e-con-inner { position: relative; z-index: 1; }
}

/* 104.5  Same fault in the header: fully transparent at scrollY 0, so the
   white wordmark and icons sat on the poster. Logo 2.28:1, and the hamburger
   was the worst thing on the page at 1.75:1 with 100% of it under 3:1. The
   pseudo sits at z-index -1, so once the header takes its cream background on
   scroll it paints straight over this and the scrolled state is unchanged. */
@media (max-width: 767px) {
	.elementor-element-17aa1cf9::before {
		content: "";
		position: absolute;
		inset: 0;
		z-index: -1;
		pointer-events: none;
		background: linear-gradient(rgba(20, 19, 15, .55), rgba(20, 19, 15, 0));
	}
}

/* 104.6  A mobile-only width:180px pinned both collection buttons narrower
   than they render on desktop, wrapping their labels onto two and three lines
   with the leading locked to the font size. Now one line each. */
@media (max-width: 767px) {
	/* The plain .category-buttons selector ties with the theme rule that sets the
	 * 180px, so it has to be widget-scoped and !important to actually win. */
	.elementor-19995 .elementor-element.elementor-element-c4b9a19 .elementor-button,
	.elementor-19995 .elementor-element.elementor-element-7245fa9 .elementor-button {
		width: auto !important;
		max-width: 100%;
	}
	.elementor-19995 .elementor-element.elementor-element-c4b9a19 .elementor-button-text,
	.elementor-19995 .elementor-element.elementor-element-7245fa9 .elementor-button-text {
		line-height: 1.45;
	}
}

/* 104.7  Two identical caption-over-photo cards were treated differently: the
   perfumer card has a scrim, "The Lab" had none, and the lab photo is the pale
   one of the pair, so its white caption was the harder to read. */
.elementor-element-11cf6a5 { position: relative; }
.elementor-element-11cf6a5::before {
	content: "";
	position: absolute;
	inset: 0;
	pointer-events: none;
	background: linear-gradient(rgba(20, 19, 15, 0) 40%, rgba(20, 19, 15, .75) 100%);
}

/* ==================================================================
   105. Homepage: the remaining audit findings
   Companion to section 104. Every selector here is the one the
   verifier confirmed actually wins; several of the originally
   proposed selectors were measured to be inert and are not used.
   Three findings contradicted each other and are resolved in place,
   each noted below.
   ================================================================== */

/* --- 105.1  The eyebrow, unified -----------------------------------
   The small uppercase tracked label was drawn five different ways in
   five places. Metrics are unified here; colour is deliberately NOT in
   the shared rule, because the label sits on three different grounds.
   8df4963 stays white (dark band). d8ba47e is not really an eyebrow,
   it is the Instagram handle, so it keeps the house ink rather than
   the muted grey, which would make it recede. */
.zg-collections-eyebrow,
.zg-choose__eyebrow,
.zg-maker__eyebrow,
.elementor-19995 .elementor-element.elementor-element-8df4963 .elementor-heading-title,
.elementor-19995 .elementor-element.elementor-element-d8ba47e .elementor-heading-title {
	font-size: 11px !important;
	font-weight: 500 !important;
	letter-spacing: .2em !important;
	line-height: 1.2;
}
.zg-collections-eyebrow,
.zg-choose__eyebrow,
.zg-maker__eyebrow { color: #6E6A5F; }

/* Eyebrow to heading was 8 / 12 / 12 / 20px. The three hand-built ones
   go to 12px. 8df4963's 20px comes from its parent's flex row-gap, so a
   margin there would ADD to it; left alone deliberately. */
.zg-collections-eyebrow { margin-bottom: 12px; }

/* --- 105.2  Display heading to body copy ---------------------------
   The same relationship took four different values. 24px sits on the
   8px step the zg- bands already use and keeps hierarchy against the
   12px eyebrow gap above. The two zg- headings need the value stated:
   their 12.8px was an inherited default, not an authored number. */
.zg-choose__h,
.zg-maker__h { margin-bottom: 24px; }
.elementor-19995 .elementor-element.elementor-element-ae9b638 > .elementor-widget-container { padding-top: 24px; }
.elementor-19995 .elementor-element.elementor-element-6816af8 > .elementor-widget-container { margin-bottom: 24px; }

/* --- 105.3  Faces ---------------------------------------------------
   Perfume names in the discovery cards were set in GlacialIndifference,
   the wordmark face. Moving them to the house serif keeps the cards
   editorial while reserving the sans for the HOUSE OF ZIGGIMAY lockup. */
.zg-choose__name,
.zg-choose__boxh {
	font-family: "FreightTextPro", Georgia, "Times New Roman", serif;
	font-weight: 400;
	color: #14130F;
}

/* One heading is set in two families at one size, so the sans half read
   visibly larger and blew the line box out to 61px inside a 50px line.
   .82em is the measured optical match; line-height:inherit is what
   actually stops the blow-out. */
.elementor-element-8859885 span.gd { font-size: .82em; line-height: inherit; }

/* --- 105.4  Ink ----------------------------------------------------
   Elementor text was pure black while every hand-built block used the
   house ink. Applied to the named widgets only: a blanket rule risks
   catching the white-on-photograph text. 42 further elements still
   carry #000 and are left for a later pass. */
.elementor-19995 .elementor-element.elementor-element-5c83625 .elementor-heading-title,
.elementor-19995 .elementor-element.elementor-element-6816af8 .elementor-heading-title,
.elementor-19995 .elementor-element.elementor-element-8859885 .elementor-heading-title,
.elementor-19995 .elementor-element.elementor-element-d8ba47e .elementor-heading-title,
.elementor-element-ae9b638,
.elementor-element-ae9b638 p,
.elementor-element-a911a6b,
.elementor-element-a911a6b p,
.elementor-element-0e69549,
.elementor-element-0e69549 p,
.zg-collections-title,
.elementor-19995 .woocommerce-loop-product__title { color: #14130F !important; }

/* --- 105.5  Buttons -------------------------------------------------
   Two otherwise identical primary CTAs differed only in corner radius
   and tracking. .18em is one of the two values already in use, not a
   third invented one. */
.zg-choose__cta { border-radius: 2px; }
.zg-promise__cta,
.zg-choose__cta { letter-spacing: .18em; }

/* JOIN NOW was pure black. Colour only: its size is legitimate emphasis
   for the page's single conversion CTA, so the padding is left alone. */
.elementor-element-fdd7375 .elementor-button {
	background-color: #14130F;
	border-color: #14130F;
}

/* The two collection buttons were sized purely by label length, so a
   side-by-side pair 10px apart was visibly unequal. Desktop only, and
   scoped to the pair: unscoped this would blow JOIN NOW out too. */
@media (min-width: 1025px) {
	.elementor-element-c4b9a19 .elementor-button,
	.elementor-element-7245fa9 .elementor-button { min-width: 291px; }
}

/* --- 105.6  Alignment ----------------------------------------------
   Newsletter body copy sat 32px left of the axis its own centred
   heading and button share, because the site-wide 68ch text-editor cap
   dumps all its slack on the right. !important is required; a plain
   declaration was measured losing to the site rule. Inert on mobile,
   where the paragraph is under the cap anyway. */
body.home .elementor-element-0e69549 p {
	margin-left: auto !important;
	margin-right: auto !important;
}

/* Product captions were indented 10px from the image they label, so the
   grid had four left edges instead of two. */
.elementor-element-25fd9d8 a.woocommerce-loop-product__link,
.elementor-element-25fd9d8 li.product .jupiterx-product-container .jupiterx-wc-loop-product-image-wrapper + a.woocommerce-LoopProduct-link { padding-left: 0; }

/* Three numbered promise items had a ragged left edge because the
   number is an auto-width flex item and 01/02/03 do not set equal. */
.zg-promise__num { flex: 0 0 22px; }

/* --- 105.7  Measure and size ---------------------------------------
   Smallest running copy on the page sat in the narrowest column. */
.zg-promise__p { font-size: 14px; max-width: 38ch; }

/* The newsletter statement had roughly double the measure of the other
   centred statements. Constrained on the widget, not the container:
   the container also holds the email input and JOIN NOW. */
@media (min-width: 768px) {
	.elementor-19995 .elementor-element.elementor-element-8859885 {
		max-width: 530px !important;
		margin-inline: auto;
	}
}

/* Display headings set with leading equal to the font size. Only the
   serif headings that actually wrap: the single-line ones would just
   gain dead vertical space. */
.elementor-element-7310eb0 .elementor-heading-title,
.elementor-element-8859885 .elementor-heading-title { line-height: 1.15; }

/* Two section headings whose job is routing into a collection were the
   smallest titles, while Instagram and the newsletter were the loudest.
   Lowering the loud end only: pushing the tiles up wraps their labels. */
.elementor-19995 .elementor-element.elementor-element-6816af8 .elementor-heading-title,
.elementor-19995 .elementor-element.elementor-element-8859885 .elementor-heading-title { font-size: 36px; }

/* A 650px band holding 182px of type, no image and no link. Set through
   Elementor's own custom property so it does not depend on load order. */
.elementor-19995 .elementor-element.elementor-element-687b79e { --min-height: 380px; }

/* Four serif captions carried positive tracking where every other serif
   heading on the page is untracked. */
.elementor-20183 .elementor-element.elementor-element-1b6385d .elementor-heading-title,
.elementor-20183 .elementor-element.elementor-element-05d8a48 .elementor-heading-title,
.elementor-20183 .elementor-element.elementor-element-667b8c1 .elementor-heading-title,
.elementor-20183 .elementor-element.elementor-element-fb54ebd .elementor-heading-title,
.elementor-19995 .elementor-element.elementor-element-1b6385d .elementor-heading-title,
.elementor-19995 .elementor-element.elementor-element-05d8a48 .elementor-heading-title,
.elementor-19995 .elementor-element.elementor-element-667b8c1 .elementor-heading-title,
.elementor-19995 .elementor-element.elementor-element-fb54ebd .elementor-heading-title { letter-spacing: normal !important; }

/* One price string was rendering at three sizes. The declaration was
   already present and simply needed to win. */
.zg-choose__from .woocommerce-Price-amount,
.zg-choose__from bdi,
.zg-choose__from .woocommerce-Price-currencySymbol {
	font-size: 11px !important;
	vertical-align: baseline;
}

/* --- 105.8  Trailing space in the product carousel ------------------
   38px of unauthored space inside the carousel added to the section
   padding and produced a very large unbroken cream field. Safe because
   the pagination and arrows this chrome exists for are display:none at
   both breakpoints. */
.elementor-19995 .elementor-element.elementor-element-25fd9d8 .raven-products-carousel-swiper-container { padding-bottom: 0; }
.elementor-19995 .elementor-element.elementor-element-25fd9d8 ul.swiper-wrapper { margin-bottom: 0; }
.elementor-19995 .elementor-element.elementor-element-25fd9d8 li.swiper-slide { margin-bottom: 0; }

/* --- 105.9  A shop route near the end of the page -------------------
   A quarter of the page sat after the last route to a product and ended
   on an inert Instagram grid. Reordering at the top level is a no-op
   (the newsletter is already the last child); the join that works is one
   level down. This moves the collection tiles below Instagram, putting a
   shop route about 750px from the footer instead of 1582px.
   This is the one change here that moves content rather than styles it.
   To revert, delete just this rule. */
.elementor-19995 .elementor-element.elementor-element-a018c0c > .e-con-inner > .elementor-element-3a45d59 { order: 1; }

/* --- 105.10  Mobile -------------------------------------------------
   The mobile hamburger is the only navigation control on a phone and had
   a 16x16 hit area. The pseudo gives it 44x44 without moving the glyph
   or anything else in the flex row. */
.elementor-element-7a690c6 .jet-mobile-menu__toggle { position: relative; }
.elementor-element-7a690c6 .jet-mobile-menu__toggle::after {
	content: "";
	position: absolute;
	top: 50%;
	left: 50%;
	transform: translate(-50%, -50%);
	width: 44px;
	height: 44px;
}

@media (max-width: 767px) {
	/* The section-heading tier fragmented on mobile. One value for the
	   four 50px headings. 7310eb0 is overridden just below: it is the one
	   that wraps to three lines with an orphan, and needs 28px. */
	.elementor-19995 .elementor-element.elementor-element-7310eb0 .elementor-heading-title,
	.elementor-19995 .elementor-element.elementor-element-6816af8 .elementor-heading-title,
	.elementor-19995 .elementor-element.elementor-element-8859885 .elementor-heading-title { font-size: 32px; }

	.elementor-19995 .elementor-element.elementor-element-7310eb0 .elementor-heading-title {
		font-size: 28px;
		line-height: 1.2;
	}

	/* "Made by hand in Denmark" held one line only by luck. Note the
	   .elementor-20183 document id: this heading lives in the unfolded
	   template, not the page document. */
	/* Elementor emits an identical-specificity 35px rule for this widget AFTER
	 * this file in the bundle, so source order beats us without !important. */
	.elementor-20183 .elementor-element.elementor-element-5c83625 .elementor-heading-title,
	.elementor-19995 .elementor-element.elementor-element-5c83625 .elementor-heading-title {
		font-size: 32px !important;
		line-height: 1.12;
	}

	/* HOUSE OF ZIGGIMAY was breaking mid-name across two lines. */
	.elementor-element-8859885 .gd { white-space: nowrap; }

	/* The desktop 34ch cap survived into mobile, so lines stopped ~84px
	   short of the right edge while the CTA under them ran full width.
	   This overrides the 38ch set above, deliberately. */
	.zg-promise__p { max-width: none; }

	/* Elementor sections gained padding from desktop to mobile while the
	   hand-built bands lost it, so which sections read as airy inverted
	   between breakpoints. 3a45d59 is cut to 56px rather than the 0px a
	   second finding proposed: 0 leaves a tighter join above the first
	   collection card than anywhere else on the mobile page. */
	.elementor-19995 .elementor-element.elementor-element-13a3ae5 { --padding-top: 56px; --padding-bottom: 56px; }
	.elementor-19995 .elementor-element.elementor-element-a018c0c { --padding-top: 56px; --padding-bottom: 56px; }
	.elementor-19995 .elementor-element.elementor-element-3a45d59 { --padding-top: 56px; }
	.elementor-19995 .elementor-element.elementor-element-6816af8 > .elementor-widget-container { margin-top: 56px; }

	.elementor-19995 .elementor-element.elementor-element-687b79e { --min-height: 300px; }

	/* Both collection cards put a white 30px headline on the brightest
	   part of the photograph, and the pseudo meant to protect it was a
	   tan wash at 30% whose gradient was weakest exactly there. Editing
	   the existing pseudo only, so paint order is unchanged. Also removes
	   the orange cast sitting over both photographs. */
	/* background-color needs the qualified selector AND !important: without it the tan
	 * wash survives and, because opacity is raised to 1, it lands at FULL strength
	 * instead of the 30% it had before. Verified: pseudo bg must read rgba(0,0,0,0). */
	.elementor-19995 .elementor-element.elementor-element-25f76f2::before,
	.elementor-19995 .elementor-element.elementor-element-e67f93d::before {
		opacity: 1 !important;
		background-color: transparent !important;
		background-image: linear-gradient(
			rgba(20, 19, 15, .15) 0%,
			rgba(20, 19, 15, .55) 40%,
			rgba(20, 19, 15, .72) 100%);
	}

	/* Same fault on the HOW WE WORK band: a flat tan wash with no
	   gradient, and the white heading crosses a cluster of white lilac. */
.elementor-19995 .elementor-element.elementor-element-687b79e::before {
		opacity: 1 !important;
		background-color: transparent !important;
		background-image: linear-gradient(
			rgba(20, 19, 15, .20) 0%,
			rgba(20, 19, 15, .55) 40%,
			rgba(20, 19, 15, .55) 70%,
			rgba(20, 19, 15, .25) 100%);
	}
}

/* ==================================================================
   106. Final pass
   ================================================================== */

/* 106.1  "We make perfume the slow way, <br> here in Denmark" carries an
   explicit line break, but its widget is only 527px inside a 1385px
   container, so the FIRST segment wrapped as well and left "way," alone
   on a line of its own. Desktop only: the mobile size drop in 105
   already resolves it there. Widening the widget keeps the display size
   rather than shrinking the type to fit. */
@media (min-width: 768px) {
	.elementor-19995 .elementor-element.elementor-element-7310eb0 {
		width: auto !important;
		max-width: 760px !important;
		margin-inline: auto;
	}
}

/* 106.2  The house ink, everywhere it is safe.
   51 elements on this page carried pure black. Section 105 converted the
   named ones; this covers the rest in one declaration, scoped to the
   homepage content region. The white-on-photograph text is restored
   immediately after, because a blanket colour rule would otherwise black
   out the hero, the HOW WE WORK band and the four photo captions. */
body.home .elementor-19995 .elementor-widget-text-editor,
body.home .elementor-19995 .elementor-widget-text-editor p,
body.home .elementor-19995 .elementor-widget-heading .elementor-heading-title {
	color: #14130F;
}
body.home .elementor-19995 .elementor-element-21a9df3 .elementor-heading-title,
body.home .elementor-19995 .elementor-element-9cf1b1e .elementor-heading-title,
body.home .elementor-19995 .elementor-element-8df4963 .elementor-heading-title,
body.home .elementor-19995 .elementor-element-7310eb0 .elementor-heading-title,
body.home .elementor-19995 .elementor-element-5da51cc .elementor-heading-title,
body.home .elementor-19995 .elementor-element-5746a6c .elementor-heading-title,
body.home .elementor-20183 .elementor-element-1b6385d .elementor-heading-title,
body.home .elementor-20183 .elementor-element-05d8a48 .elementor-heading-title,
body.home .elementor-20183 .elementor-element-667b8c1 .elementor-heading-title,
body.home .elementor-20183 .elementor-element-fb54ebd .elementor-heading-title,
body.home .elementor-19995 .elementor-element-1b6385d .elementor-heading-title,
body.home .elementor-19995 .elementor-element-05d8a48 .elementor-heading-title,
body.home .elementor-19995 .elementor-element-667b8c1 .elementor-heading-title,
body.home .elementor-19995 .elementor-element-fb54ebd .elementor-heading-title {
	color: #FFFFFF;
}

/* ==================================================================
   107. THE LEGAL PAGES
   Cookie Policy (20031), Privacy Policy (20033), Terms & Conditions
   (20035). All three render their body through the same Elementor text
   widget, 408bf33, inside container d127376, so one rule set covers
   them.

   What was wrong, measured: body copy at 14px with a 16.1px
   line-height, which is SOLID leading, set across a 762px measure.
   That is roughly 115 characters a line with the lines almost touching,
   in pure black rather than the house ink, for 19 to 24 paragraphs of
   text somebody is trying to read carefully. The three pages did not
   even agree with each other: Cookie and Privacy set their headings at
   weight 900, Terms at 400.

   Everything here needs !important. The competing declarations are
   Elementor's per-widget rules and .elementor-kit-19984 h1/h2/h3, which
   outrank a plain class and are emitted after this file in the bundle.
   See section 105 for the full explanation.

   To revert: delete this section.
   ================================================================== */

/* ONE NUMBER, ONE PLACE.
   The measure was written into eight separate rules in this section, for paragraphs, lists,
   headings and the container. Changing "the measure" therefore meant finding all eight, and the
   first attempt at that changed one, verified against the page, and saw no difference at all.
   They all read this variable now. */
:root { --zg-legal-measure: 520px; }

/* --- the measure ---------------------------------------------------
   A comfortable reading column instead of the full content width.

   CORRECTED 2026-09-17. This was 660px, chosen as "68ch at this size",
   on the assumption that a ch is about a character. It is not: ch is
   the width of a zero, and in FreightTextPro that is 8.89px while the
   average letter is nearer 7.2. Counted properly, by rendering the
   real sentence and finding where it wraps rather than dividing by an
   assumed width, 660px was carrying 92 characters a line.

   Typographic practice and the WCAG readability guidance both put the
   comfortable range at 45 to 75. Past about 80 the eye starts losing
   its place on the return sweep, which is the wrong thing to do to
   someone reading a returns policy or a privacy notice carefully.

   520px measures at about 72 characters in this face. The journal in
   section 91 keeps its own 660px on purpose: an article is read in a
   flow, a legal page is scanned for one clause, and the shorter line
   is what helps with the second. */
body.page-id-20031 .elementor-element-408bf33 > .elementor-widget-container,
body.page-id-20033 .elementor-element-408bf33 > .elementor-widget-container,
body.page-id-20035 .elementor-element-408bf33 > .elementor-widget-container,
/* The security page did not exist when this section was written, and it is built from a different
   widget, so it never picked up any of this. Matching on the marker class the consent plugin adds
   catches it, and anything else that page ever becomes. */
body.page-id-40398 .zg-policy-body {
	max-width: 520px !important;
	margin-inline: auto !important;
}

/* --- running text --------------------------------------------------- */
body.page-id-20031 .elementor-element-408bf33,
body.page-id-20033 .elementor-element-408bf33,
body.page-id-20035 .elementor-element-408bf33,
body.page-id-20031 .elementor-element-408bf33 p,
body.page-id-20033 .elementor-element-408bf33 p,
body.page-id-20035 .elementor-element-408bf33 p,
body.page-id-20031 .elementor-element-408bf33 li,
body.page-id-20033 .elementor-element-408bf33 li,
body.page-id-20035 .elementor-element-408bf33 li {
	font-size: 16px !important;
	line-height: 1.72 !important;
	color: #14130F !important;
	letter-spacing: normal !important;
}
body.page-id-20031 .elementor-element-408bf33 p,
body.page-id-20033 .elementor-element-408bf33 p,
body.page-id-20035 .elementor-element-408bf33 p {
	margin: 0 0 1.15em !important;
	text-wrap: pretty;
}

/* Long support URLs are printed as plain text in the cookie policy, so
   they must be allowed to break rather than push the column open. */
body.page-id-20031 .elementor-element-408bf33,
body.page-id-20033 .elementor-element-408bf33,
body.page-id-20035 .elementor-element-408bf33 {
	overflow-wrap: anywhere;
}

/* --- headings -------------------------------------------------------
   One weight across all three pages. Terms was already 400; Cookie and
   Privacy were 900, which is a face the rest of the site never uses. */
body.page-id-20031 .elementor-element-408bf33 h1,
body.page-id-20033 .elementor-element-408bf33 h1,
body.page-id-20035 .elementor-element-408bf33 h1,
body.page-id-20031 main h1, body.page-id-20033 main h1, body.page-id-20035 main h1,
body.page-id-20031 .elementor-element-408bf33 h2,
body.page-id-20033 .elementor-element-408bf33 h2,
body.page-id-20035 .elementor-element-408bf33 h2,
body.page-id-20031 .elementor-element-408bf33 h3,
body.page-id-20033 .elementor-element-408bf33 h3,
body.page-id-20035 .elementor-element-408bf33 h3,
body.page-id-20031 .elementor-element-408bf33 h4,
body.page-id-20033 .elementor-element-408bf33 h4,
body.page-id-20035 .elementor-element-408bf33 h4 {
	font-family: "FreightTextPro", Georgia, "Times New Roman", serif !important;
	font-weight: 400 !important;
	color: #14130F !important;
	letter-spacing: normal !important;
	text-wrap: balance;
}
body.page-id-20031 .elementor-element-408bf33 h2,
body.page-id-20033 .elementor-element-408bf33 h2,
body.page-id-20035 .elementor-element-408bf33 h2 {
	font-size: 26px !important;
	line-height: 1.25 !important;
	margin: 2.4em 0 .55em !important;
}
body.page-id-20031 .elementor-element-408bf33 h3,
body.page-id-20033 .elementor-element-408bf33 h3,
body.page-id-20035 .elementor-element-408bf33 h3 {
	font-size: 19px !important;
	line-height: 1.35 !important;
	margin: 1.9em 0 .45em !important;
	font-weight: 500 !important;
}
body.page-id-20031 .elementor-element-408bf33 h4,
body.page-id-20033 .elementor-element-408bf33 h4,
body.page-id-20035 .elementor-element-408bf33 h4 {
	font-size: 16.5px !important;
	margin: 1.6em 0 .4em !important;
	font-weight: 500 !important;
}

/* --- links -----------------------------------------------------------
   Same treatment as the rest of the site: the underline is present but
   quiet, and firms up on hover. */
body.page-id-20031 .elementor-element-408bf33 a,
body.page-id-20033 .elementor-element-408bf33 a,
body.page-id-20035 .elementor-element-408bf33 a {
	color: inherit !important;
	text-decoration: underline !important;
	text-underline-offset: 3px;
	text-decoration-color: rgba(20, 19, 15, .38);
	transition: text-decoration-color .18s ease;
}
body.page-id-20031 .elementor-element-408bf33 a:hover,
body.page-id-20033 .elementor-element-408bf33 a:hover,
body.page-id-20035 .elementor-element-408bf33 a:hover {
	text-decoration-color: rgba(20, 19, 15, .9);
}

/* --- lists ----------------------------------------------------------- */
body.page-id-20031 .elementor-element-408bf33 ul,
body.page-id-20033 .elementor-element-408bf33 ul,
body.page-id-20035 .elementor-element-408bf33 ul,
body.page-id-20031 .elementor-element-408bf33 ol,
body.page-id-20033 .elementor-element-408bf33 ol,
body.page-id-20035 .elementor-element-408bf33 ol {
	margin: 0 0 1.15em !important;
	padding-left: 22px !important;
}
body.page-id-20031 .elementor-element-408bf33 li,
body.page-id-20033 .elementor-element-408bf33 li,
body.page-id-20035 .elementor-element-408bf33 li { margin: 0 0 .5em !important; }

/* --- the cookie tables -----------------------------------------------
   Four of them on the cookie policy, listing each cookie. They are wider
   than the reading column, so they scroll inside themselves rather than
   pushing the page sideways. */
body.page-id-20031 .elementor-element-408bf33 table {
	display: block;
	overflow-x: auto;
	width: 100% !important;
	border-collapse: collapse !important;
	font-size: 13.5px !important;
	line-height: 1.5 !important;
	margin: 0 0 1.6em !important;
}
body.page-id-20031 .elementor-element-408bf33 th,
body.page-id-20031 .elementor-element-408bf33 td {
	border: 0 !important;
	border-bottom: 1px solid rgba(20, 19, 15, .14) !important;
	padding: 9px 14px 9px 0 !important;
	text-align: left !important;
	vertical-align: top !important;
	color: #14130F !important;
}
body.page-id-20031 .elementor-element-408bf33 th {
	font-family: Avenir, "Helvetica Neue", Helvetica, sans-serif !important;
	font-size: 10.5px !important;
	letter-spacing: .16em !important;
	text-transform: uppercase !important;
	font-weight: 500 !important;
	opacity: .62;
	white-space: nowrap;
}

body.page-id-20031 .elementor-element-408bf33 strong,
body.page-id-20033 .elementor-element-408bf33 strong,
body.page-id-20035 .elementor-element-408bf33 strong { font-weight: 600 !important; }

/* --- mobile ---------------------------------------------------------- */
@media (max-width: 767px) {
	body.page-id-20031 .elementor-element-408bf33 > .elementor-widget-container,
	body.page-id-20033 .elementor-element-408bf33 > .elementor-widget-container,
	body.page-id-20035 .elementor-element-408bf33 > .elementor-widget-container {
		max-width: none !important;
	}
	body.page-id-20031 .elementor-element-408bf33,
	body.page-id-20033 .elementor-element-408bf33,
	body.page-id-20035 .elementor-element-408bf33,
	body.page-id-20031 .elementor-element-408bf33 p,
	body.page-id-20033 .elementor-element-408bf33 p,
	body.page-id-20035 .elementor-element-408bf33 p,
	body.page-id-20031 .elementor-element-408bf33 li,
	body.page-id-20033 .elementor-element-408bf33 li,
	body.page-id-20035 .elementor-element-408bf33 li {
		font-size: 15.5px !important;
		line-height: 1.7 !important;
	}
	body.page-id-20031 .elementor-element-408bf33 h2,
	body.page-id-20033 .elementor-element-408bf33 h2,
	body.page-id-20035 .elementor-element-408bf33 h2 {
		font-size: 22px !important;
		margin-top: 2em !important;
	}
}

/* --- 107b. the headings these pages ACTUALLY use ---------------------
   The section headings are <h5> at 20px weight 900, not h2/h3, and the
   cookie-category headings are <h3> at 28px weight 900 inside
   .cky-audit-table-element, which is CookieYes page content and not the
   consent banner. Both were missed by the h1-h4 rules above, which is a
   good argument for reading the DOM before writing a heading scale.
   Weight 900 appears nowhere else on this site.
   ------------------------------------------------------------------- */
body.page-id-20031 h5, body.page-id-20033 h5, body.page-id-20035 h5,
body.page-id-20031 h6, body.page-id-20033 h6, body.page-id-20035 h6,
body.page-id-20031 .cky-audit-table-element h3,
body.page-id-20031 .cky-audit-table-element h4 {
	font-family: "FreightTextPro", Georgia, "Times New Roman", serif !important;
	font-weight: 400 !important;
	color: #14130F !important;
	letter-spacing: normal !important;
	text-wrap: balance;
}

/* The section headings. Given real air above so the document has a
   rhythm instead of running together as one grey slab. */
body.page-id-20031 h5, body.page-id-20033 h5, body.page-id-20035 h5 {
	font-size: 23px !important;
	line-height: 1.3 !important;
	margin: 2.3em 0 .5em !important;
}
body.page-id-20031 h6, body.page-id-20033 h6, body.page-id-20035 h6 {
	font-size: 18px !important;
	line-height: 1.35 !important;
	margin: 1.8em 0 .4em !important;
}

/* Cookie category headings sit directly above their table. */
body.page-id-20031 .cky-audit-table-element h3,
body.page-id-20031 .cky-audit-table-element h4 {
	font-size: 20px !important;
	line-height: 1.3 !important;
	margin: 2em 0 .6em !important;
}

/* The audit tables are CookieYes markup, so they get the same treatment
   the hand-written tables got: hairlines, quiet uppercase headers, and
   they scroll inside themselves rather than widening the page. */
body.page-id-20031 .cky-audit-table-element table {
	display: block;
	overflow-x: auto;
	width: 100% !important;
	max-width: var(--zg-legal-measure);
	margin-inline: auto;
	border-collapse: collapse !important;
	font-size: 13.5px !important;
	line-height: 1.5 !important;
}
body.page-id-20031 .cky-audit-table-element th,
body.page-id-20031 .cky-audit-table-element td {
	border: 0 !important;
	border-bottom: 1px solid rgba(20, 19, 15, .14) !important;
	padding: 9px 14px 9px 0 !important;
	text-align: left !important;
	vertical-align: top !important;
	color: #14130F !important;
	background: transparent !important;
}
body.page-id-20031 .cky-audit-table-element th {
	font-family: Avenir, "Helvetica Neue", Helvetica, sans-serif !important;
	font-size: 10.5px !important;
	letter-spacing: .16em !important;
	text-transform: uppercase !important;
	font-weight: 500 !important;
	opacity: .62;
	white-space: nowrap;
}
body.page-id-20031 .cky-audit-table-element {
	max-width: var(--zg-legal-measure);
	margin-inline: auto;
}

@media (max-width: 767px) {
	body.page-id-20031 h5, body.page-id-20033 h5, body.page-id-20035 h5 { font-size: 20px !important; }
	body.page-id-20031 .cky-audit-table-element,
	body.page-id-20031 .cky-audit-table-element table { max-width: none; }
}

/* --- 107c. catch every heading on all three pages --------------------
   The three pages are built three different ways: Cookie uses <h5> in a
   text widget, Terms uses <h2> in a text widget, and Privacy uses <h2>
   inside <li> of an <ol class="privacy-policy-ol"> in an HTML widget.
   Scoping by widget id therefore missed a whole page. Scoping to <main>
   catches all of them and still leaves the shared header and footer
   alone.
   ------------------------------------------------------------------- */
body.page-id-20031 main :is(h2, h3, h4, h5, h6),
body.page-id-20033 main :is(h2, h3, h4, h5, h6),
body.page-id-20035 main :is(h2, h3, h4, h5, h6) {
	font-family: "FreightTextPro", Georgia, "Times New Roman", serif !important;
	font-weight: 400 !important;
	color: #14130F !important;
	letter-spacing: normal !important;
	text-wrap: balance;
}
body.page-id-20031 main h2,
body.page-id-20033 main h2,
body.page-id-20035 main h2 {
	font-size: 24px !important;
	line-height: 1.28 !important;
	margin: 2.2em 0 .5em !important;
}

/* Privacy's numbered sections. The <ol> supplies the numbering, so the
   heading inside each <li> should sit tight to its marker and the body
   copy under it should share the same left edge as everything else. */
body.page-id-20033 main .privacy-policy-ol {
	max-width: var(--zg-legal-measure);
	margin-inline: auto;
	padding-left: 26px !important;
}
body.page-id-20033 main .privacy-policy-ol > li {
	margin: 0 0 1.6em !important;
	padding-left: 4px;
}
body.page-id-20033 main .privacy-policy-ol > li::marker {
	color: rgba(20, 19, 15, .45);
	font-family: Avenir, "Helvetica Neue", Helvetica, sans-serif;
	font-size: 13px;
}
body.page-id-20033 main .privacy-policy-ol > li > h2:first-child {
	margin-top: .2em !important;
}

/* Whatever widget the copy sits in, it reads on the same column. */
body.page-id-20033 main .elementor-element-9404a34 > .elementor-widget-container {
	max-width: none !important;
}

/* --- 107d. one H1 across the three legal pages -----------------------
   Cookie and Privacy set 40px, Terms 52px. They are the same kind of
   document and should open the same way. Aligned to the reading column
   so the title sits on the same left edge as the prose beneath it. */
body.page-id-20031 main h1,
body.page-id-20033 main h1,
body.page-id-20035 main h1 {
	font-size: 44px !important;
	line-height: 1.1 !important;
	font-weight: 400 !important;
	max-width: var(--zg-legal-measure);
	margin: 0 auto .7em !important;
}
@media (max-width: 767px) {
	body.page-id-20031 main h1,
	body.page-id-20033 main h1,
	body.page-id-20035 main h1 { font-size: 32px !important; }
}

/* --- 107e. the measure, applied where the text actually is -----------
   Same lesson as 107c: the copy is spread across several widgets, so
   pinning the column on one widget id left most of it running the full
   1000px container at solid leading. Setting the measure on the text
   ELEMENTS themselves works whatever widget they sit in, and keeps
   every line, heading and list on one left edge.
   ------------------------------------------------------------------- */
body.page-id-20031 main :is(p, li, h1, h2, h3, h4, h5, h6, blockquote),
body.page-id-20033 main :is(p, li, h1, h2, h3, h4, h5, h6, blockquote),
body.page-id-20035 main :is(p, li, h1, h2, h3, h4, h5, h6, blockquote) {
	max-width: var(--zg-legal-measure) !important;
	margin-right: auto !important;
}
body.page-id-20031 main :is(p, li),
body.page-id-20033 main :is(p, li),
body.page-id-20035 main :is(p, li) {
	font-size: var(--zg-fs-body) !important;
	line-height: var(--zg-lh-body) !important;
	color: #14130F !important;
	letter-spacing: normal !important;
}
body.page-id-20031 main p,
body.page-id-20033 main p,
body.page-id-20035 main p { margin-bottom: 1.15em !important; text-wrap: pretty; }

/* The title opens on the same left edge as the prose, not centred over
   a wider container than the text it introduces. */
body.page-id-20031 main h1,
body.page-id-20033 main h1,
body.page-id-20035 main h1 { margin-left: 0 !important; }

/* Nested list items must not inherit the column cap twice, or each
   level indents and then shortens. */
body.page-id-20031 main :is(ul, ol) :is(ul, ol) li,
body.page-id-20033 main :is(ul, ol) :is(ul, ol) li,
body.page-id-20035 main :is(ul, ol) :is(ul, ol) li { max-width: none !important; }

@media (max-width: 767px) {
	body.page-id-20031 main :is(p, li, h1, h2, h3, h4, h5, h6, blockquote),
	body.page-id-20033 main :is(p, li, h1, h2, h3, h4, h5, h6, blockquote),
	body.page-id-20035 main :is(p, li, h1, h2, h3, h4, h5, h6, blockquote) { max-width: none !important; }
	/* size and leading come from the scale; only the measure changes on a phone */
}

/* --- 107f. beat the site-wide text-editor rule -----------------------
   Terms keeps its copy in a text-editor widget, so it was still being
   held at 14.5px by this file's own site-wide rule:
       main.jupiterx-main .elementor-widget-text-editor p   (0,2,2)
   which outranks   body.page-id-X main :is(p,li)           (0,1,3)
   even though both carry !important. Cookie and Privacy escaped it only
   because their copy lives in HTML widgets, which is why two of the
   three pages looked fixed and the third did not.
   Adding .jupiterx-main takes this to (0,2,3) and it wins.
   ------------------------------------------------------------------- */
body.page-id-20031 main.jupiterx-main :is(p, li),
body.page-id-20033 main.jupiterx-main :is(p, li),
body.page-id-20035 main.jupiterx-main :is(p, li) {
	font-size: var(--zg-fs-body) !important;
	line-height: var(--zg-lh-body) !important;
	color: #14130F !important;
	max-width: var(--zg-legal-measure) !important;
}
body.page-id-20031 main.jupiterx-main :is(h1, h2, h3, h4, h5, h6, blockquote),
body.page-id-20033 main.jupiterx-main :is(h1, h2, h3, h4, h5, h6, blockquote),
body.page-id-20035 main.jupiterx-main :is(h1, h2, h3, h4, h5, h6, blockquote) {
	max-width: var(--zg-legal-measure) !important;
}

/* Terms sets its title in a separate, centred 660px heading widget while
   its copy sits in an 1100px text widget. Rather than dragging the title
   left with a brittle negative margin, centre the reading column inside
   its own container: 163 + (1100 - 660) / 2 lands on 383, exactly where
   the title already is. The other two pages are left-aligned and already
   share an edge, so this is scoped to Terms alone. */
body.page-id-20035 main.jupiterx-main :is(p, li, h2, h3, h4, h5, h6) {
	margin-left: auto !important;
	margin-right: auto !important;
}
body.page-id-20035 main.jupiterx-main :is(ul, ol) { max-width: var(--zg-legal-measure) !important; margin-inline: auto !important; }

@media (max-width: 767px) {
	body.page-id-20031 main.jupiterx-main :is(p, li),
	body.page-id-20033 main.jupiterx-main :is(p, li),
	body.page-id-20035 main.jupiterx-main :is(p, li) {
		max-width: none !important;
	}
	body.page-id-20031 main.jupiterx-main :is(h1, h2, h3, h4, h5, h6, blockquote),
	body.page-id-20033 main.jupiterx-main :is(h1, h2, h3, h4, h5, h6, blockquote),
	body.page-id-20035 main.jupiterx-main :is(h1, h2, h3, h4, h5, h6, blockquote) { max-width: none !important; }
}

/* --- 107g. corrections to 107c and 107b ------------------------------
   Two faults, both introduced by this section rather than inherited.

   1. `margin-inline: auto` was used to hold the 660px column, which
      CENTRES a narrow block inside a wide container instead of aligning
      it. On Privacy that pushed the whole numbered list 196px right of
      the prose above it, and on Cookie it did the same to the four
      cookie tables. Each page must share ONE left edge: title, prose,
      lists and tables. Terms is the exception and keeps its centred
      column, because its title sits in its own centred widget.

   2. Privacy's <h1> is not just a title. Its markup is
      "Privacy Policy <br><span>Last Updated On ...</span>
       <br><span>Effective Date ...</span>"
      so both dates were being set at 44px display size. They are
      metadata and should read as such. Note this cannot be done with a
      blanket `h1 span` rule: on Terms the span is
      <span class="gd">HOUSE OF ZIGGIMAY</span>, the wordmark, which must
      stay at display size.
   ------------------------------------------------------------------- */

/* 1. one left edge per page */
body.page-id-20033 main .privacy-policy-ol,
body.page-id-20031 .cky-audit-table-element,
body.page-id-20031 .cky-audit-table-element table {
	margin-left: 0 !important;
	margin-right: auto !important;
}

/* Nested levels get an ordinary indent from their own padding, nothing
   more, so the list steps in once per level instead of drifting. */
body.page-id-20033 main .privacy-policy-ol :is(ul, ol) {
	margin-left: 0 !important;
	margin-right: auto !important;
	padding-left: 22px !important;
}

/* 2. the dates in Privacy's title */
body.page-id-20033 main h1 br { display: none; }
body.page-id-20033 main h1 span {
	display: block;
	font-family: Avenir, "Helvetica Neue", Helvetica, sans-serif;
	font-size: 11.5px;
	font-weight: 500;
	letter-spacing: .16em;
	text-transform: uppercase;
	line-height: 1.9;
	opacity: .55;
}
body.page-id-20033 main h1 span:first-of-type { margin-top: 14px; }

/* --- 107h. nested list items ----------------------------------------
   Top-level sections in the Privacy list want air between them, but the
   nested items under them are single words (Name, Email, Mobile) and
   were inheriting the same 1.6em, so four one-word entries occupied
   more than 200px. Second level and deeper gets a normal list rhythm. */
body.page-id-20033 main .privacy-policy-ol :is(ul, ol) li,
body.page-id-20031 main :is(ul, ol) :is(ul, ol) li,
body.page-id-20035 main :is(ul, ol) :is(ul, ol) li {
	margin-bottom: .45em !important;
}

/* ==================================================================
   108. The traveller on the homepage
   Copy and drawing injected after the paragraph that already lists what
   ships with a bottle. Shares the same reading column as that copy so
   it reads as part of the same thought, not as a new section.
   ================================================================== */
/* The paragraphs in this widget are CENTRED inside a 1000px container by the
   site-wide 68ch text-editor cap (467px wide, 266px of auto margin either side).
   The injected block is not a <p>, so it did not follow and sat 266px to their
   left. Matching the cap and the auto margins puts it on their edge. Centring is
   correct HERE precisely because the neighbours are centred: align to what is
   next to you, do not centre by reflex. */
.zg-home-atom {
	margin: 22px auto 0;
	max-width: 467px;
}
.zg-home-atom__lead {
	font-size: 14.5px !important;
	line-height: 1.75 !important;
	color: #14130F !important;
	margin: 0 0 4px !important;
	max-width: 467px;
}
.zg-atom--home { margin: 10px 0 0 !important; }
.zg-atom--home .zg-atom__art { max-width: 360px !important; opacity: .8; }
.zg-atom--home .zg-atom__steps { max-width: 467px; }
@media (max-width: 767px) {
	.zg-home-atom__lead { font-size: 14px !important; max-width: none; }
	.zg-atom--home .zg-atom__art { max-width: 100% !important; }
}

/* --- 108b. the steps read left, like every other list on the site -----
   The widget this block is injected into is centre-aligned, so the step
   list inherited text-align:center and the three lines each started at a
   different x. The prose above it is left-ragged; the steps must match. */
.zg-home-atom,
.zg-home-atom .zg-atom__steps,
.zg-home-atom .zg-atom__steps li,
.zg-home-atom .zg-home-atom__lead { text-align: left !important; }

/* ==================================================================
   110. THE JOURNAL PAGER
   The journal archive had no visible pagination at all, so page 1 was
   a dead end and thirteen posts sat behind a <link rel="next"> that
   only a machine could follow. journal-pagination.php renders the
   control; this gives it the site's voice.

   Every selector is qualified with .elementor-widget-raven-posts and
   carries !important, because Elementor's own per-widget rules land
   after this stylesheet and win on source order at equal specificity.
   That is the same rule that caught six declarations in section 105.

   Nothing here uses :has(), and nothing keys on a plugin's state
   class. Section 109 did both and blanked the checkout modal.
   ------------------------------------------------------------------ */

.elementor-widget-raven-posts .zg-jpager {
	margin: 64px auto 8px !important;
	padding: 0 !important;
	display: flex !important;
	justify-content: center !important;
}
.elementor-widget-raven-posts .zg-jpager__list {
	display: flex !important;
	flex-wrap: wrap !important;
	align-items: center !important;
	justify-content: center !important;
	gap: 8px !important;
	margin: 0 !important;
	padding: 0 !important;
	list-style: none !important;
}
.elementor-widget-raven-posts .zg-jpager__item {
	margin: 0 !important;
	padding: 0 !important;
	list-style: none !important;
}

/* One shared shape for links and for the current page, so the row keeps
   an even rhythm whichever page you are on. */
.elementor-widget-raven-posts .zg-jpager .page-numbers {
	display: inline-flex !important;
	align-items: center !important;
	justify-content: center !important;
	min-width: 40px !important;
	height: 40px !important;
	padding: 0 12px !important;
	border: 1px solid rgba(26, 24, 22, .18) !important;
	border-radius: 0 !important;
	background: transparent !important;
	color: #1A1816 !important;
	font-size: 12px !important;
	font-weight: 400 !important;
	letter-spacing: .14em !important;
	text-transform: uppercase !important;
	text-decoration: none !important;
	line-height: 1 !important;
	transition: background-color .18s ease, border-color .18s ease, color .18s ease !important;
}
.elementor-widget-raven-posts .zg-jpager a.page-numbers:hover,
.elementor-widget-raven-posts .zg-jpager a.page-numbers:focus-visible {
	background: #1A1816 !important;
	border-color: #1A1816 !important;
	color: #F5F3EB !important;
}
.elementor-widget-raven-posts .zg-jpager .page-numbers.current {
	background: #1A1816 !important;
	border-color: #1A1816 !important;
	color: #F5F3EB !important;
	cursor: default !important;
}
/* Previous and Next carry words rather than a digit, so they get room. */
.elementor-widget-raven-posts .zg-jpager .page-numbers.prev,
.elementor-widget-raven-posts .zg-jpager .page-numbers.next {
	padding: 0 20px !important;
}

@media (max-width: 600px) {
	.elementor-widget-raven-posts .zg-jpager { margin-top: 44px !important; }
	.elementor-widget-raven-posts .zg-jpager .page-numbers {
		min-width: 36px !important;
		height: 36px !important;
		font-size: 11px !important;
		padding: 0 9px !important;
	}
	.elementor-widget-raven-posts .zg-jpager .page-numbers.prev,
	.elementor-widget-raven-posts .zg-jpager .page-numbers.next { padding: 0 14px !important; }
}

@media (prefers-reduced-motion: reduce) {
	.elementor-widget-raven-posts .zg-jpager .page-numbers { transition: none !important; }
}

/* ==================================================================
   111. THE PERFUMER BAND
   It was an eyebrow, a name and a paragraph centred in a 62ch column
   inside a full-width cream band: a lot of empty ground either side,
   nothing to look at, and the name repeated from the photo card
   directly above it.

   Now the identity sits left and the statement sits right, so the band
   uses its width and the two halves say different things. The visual
   anchor is his actual signature rather than a stock portrait.

   Overrides section 3647-3649, which centred .zg-maker__inner. Those
   rules are still there and still correct for one column, so this only
   changes what the two-column arrangement needs and nothing else.
   ------------------------------------------------------------------ */

.zg-maker { padding: clamp(3.5rem, 7vw, 6rem) 20px !important; }

.zg-maker__inner {
	/* the old rule caps this at 62ch and centres the text; both have to go */
	max-width: 1100px !important;
	text-align: left !important;
	display: grid !important;
	grid-template-columns: minmax(240px, 5fr) minmax(0, 7fr);
	gap: clamp(2rem, 5vw, 4.5rem);
	align-items: start;
}

.zg-maker__who { display: flex; flex-direction: column; }

/* Sections 3521 and 3533 centre the eyebrow and the heading, but that rule is SHARED with
   .zg-choose__*, which is still a centred one-column band and must stay that way. So the
   override is scoped here rather than changing the shared rule. Without it the name floated
   centred over a signature sitting at the column's left edge, which read as a mistake. */
.zg-maker__eyebrow {
	margin-bottom: 10px !important;
	text-align: left !important;
}

.zg-maker__h {
	margin: 0 0 20px !important;
	text-align: left !important;
	text-wrap: balance;
}

/* The autograph is ink on transparent, so it needs no frame. Held to a
   modest width because a signature blown up reads as a logo. */
.zg-maker__sig {
	display: block;
	width: clamp(150px, 15vw, 200px);
	height: auto;
	margin: 2px 0 0 -8px;   /* the stroke starts inset; pull it back to the text edge */
	opacity: .82;           /* ink on cream, not black on white */
}

.zg-maker__say { max-width: 58ch; }

.zg-maker__p { margin: 0 !important; }

.zg-maker__more {
	display: inline-block;
	margin-top: 22px;
	padding-bottom: 3px;
	border-bottom: 1px solid rgba(26, 24, 22, .3);
	color: #1A1816;
	font-size: 12px;
	letter-spacing: .14em;
	text-transform: uppercase;
	text-decoration: none;
	transition: border-color .18s ease;
}
.zg-maker__more:hover,
.zg-maker__more:focus-visible { border-bottom-color: #1A1816; }

/* One column below the point where two would squeeze the prose. The
   signature stays under the name, which is where a signature belongs. */
@media (max-width: 860px) {
	.zg-maker__inner {
		grid-template-columns: 1fr;
		gap: 1.75rem;
	}
	.zg-maker__say { max-width: none; }
	.zg-maker__sig { width: clamp(140px, 34vw, 180px); }
}

@media (prefers-reduced-motion: reduce) {
	.zg-maker__more { transition: none; }
}

/* ==================================================================
   112. THE FREE-SAMPLER LOADER
   Opening the sampler the first time shows three quiet vertical pins on
   a dimmed page. Re-opening it from the "Here" link in the checkout
   notice instead painted the whole cream panel with a 50px solid-black
   ring spinning in it. Same component, two entirely different loading
   states, and the ring is the loudest thing on a cream dialogue.

   Both entry points now show the same three pins on the same dim ground.

   WHAT THIS DELIBERATELY DOES NOT DO, AND WHY IT MATTERS
   Section 109 chased this same complaint by making the PANEL transparent
   while loading, keyed on
     .wgb-popup-box:has(> .popup-inner-loader:not(.wgb-d-none))
   The plugin's JavaScript re-adds .wgb-d-none in its success handlers
   but not on every path, so the condition stayed true after loading
   finished and the checkout modal had no panel at all for a day.
   Section 109 is gone and is not coming back.

   So this touches TWO things only: the loader overlay, and the spinner
   inside it. Both exist solely while loading. No parent panel rule, no
   :has(), nothing keyed on a class the plugin toggles. If the loader
   ever fails to hide again, the worst outcome is a quiet pin animation
   left on screen, not a blanked dialogue.

   The plugin centres the spinner with position:absolute, top/left 50%
   and margins of -25px for its 50px box. That mechanism is kept exactly
   as it is and only the numbers change to match the new shape, because
   moving to flex centring meant styling the parent, which is how 109
   got into trouble in the first place.
   ------------------------------------------------------------------ */

/* The plugin's own veil is 60% pure WHITE over a cream panel, which reads as a grey cast.
   A cream veil keeps the dialogue one colour while it waits. An earlier attempt used a dark
   scrim so white pins would read, but that greyed out the title and the whole panel with it:
   the pins are the thing that should match the first open, not the ground behind them. */
/* NO !important here on purpose. Section 114 overrides this with an animation while the
   dialogue is hidden, and an !important declaration beats an animation, so the flag would
   strand a pale band over the dimmed page. Specificity alone already wins against the
   plugin's own .popup-inner-loader rule, so the flag was never needed. */
#wgb-modal .popup-inner-loader,
.wgb-popup-box .popup-inner-loader {
	background-color: rgba(245, 243, 235, .88);
}

/* The middle pin is the element itself; the outer two are its pseudo-elements,
   so no extra markup is needed and the plugin's own element stays in place. */
#wgb-modal .popup-inner-loader .loader-item,
.wgb-popup-box .popup-inner-loader .loader-item {
	width: 5px !important;
	height: 26px !important;
	aspect-ratio: auto !important;      /* the plugin sets 1, which would force a square */
	margin-left: -2.5px !important;     /* half the width, matching the plugin's method */
	margin-top: -13px !important;       /* half the height */
	border: 0 !important;
	border-radius: 1px !important;
	background: #1A1816 !important;
	animation: zg-sampler-pins 1s ease-in-out infinite !important;
}

#wgb-modal .popup-inner-loader .loader-item::before,
#wgb-modal .popup-inner-loader .loader-item::after,
.wgb-popup-box .popup-inner-loader .loader-item::before,
.wgb-popup-box .popup-inner-loader .loader-item::after {
	content: "";
	position: absolute;
	top: 0;
	width: 5px;
	height: 26px;
	border-radius: 1px;
	background: #1A1816;
	animation: zg-sampler-pins 1s ease-in-out infinite;
}
#wgb-modal .popup-inner-loader .loader-item::before,
.wgb-popup-box .popup-inner-loader .loader-item::before { left: -10px; animation-delay: -.18s; }
#wgb-modal .popup-inner-loader .loader-item::after,
.wgb-popup-box .popup-inner-loader .loader-item::after  { left:  10px; animation-delay:  .18s; }

@keyframes zg-sampler-pins {
	0%, 100% { transform: scaleY(.42); opacity: .45; }
	50%      { transform: scaleY(1);   opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
	#wgb-modal .popup-inner-loader .loader-item,
	#wgb-modal .popup-inner-loader .loader-item::before,
	#wgb-modal .popup-inner-loader .loader-item::after,
	.wgb-popup-box .popup-inner-loader .loader-item,
	.wgb-popup-box .popup-inner-loader .loader-item::before,
	.wgb-popup-box .popup-inner-loader .loader-item::after {
		animation: none !important;
		opacity: .7;
	}
}

/* ==================================================================
   113. THE PROMISE NUMBERS, CONTRAST
   Lighthouse flags 01 / 02 / 03 in the promise band as failing colour
   contrast, and it is right: measured on the live page they are
   #6E6A5F on rgb(231, 222, 197), which is 4.02:1. WCAG AA wants 4.5:1
   for text this size (15.2px, weight 400).

   WHY THE TOKEN IS NOT AT FAULT
   --zg-muted was chosen against the cream ground (#F5F3EB) where it
   clears AA comfortably. The promise band is a warmer, darker tan, and
   the same grey does not survive the move. So this darkens the numbers
   for THIS band only rather than changing the token, which would drag
   every muted label on the site darker for no reason.

   #5C594F on the same ground measures 5.23:1, which clears AA with room
   to spare while staying clearly quieter than the heading beside it
   (#14130F at 13.85:1). The heading and the body copy already pass and
   are left alone.
   ------------------------------------------------------------------ */

.zg-promise .zg-promise__num {
	color: #5C594F !important;
}

/* ==================================================================
   114. THE SAMPLER PANEL WHILE IT LOADS
   Opening the sampler the first time shows three pins on the dimmed
   page. Re-opening it from the "Here" link paints the whole cream
   dialogue, its title bar and an empty body, and holds that until the
   fetch returns. Same component, two different loading states, and the
   empty one reads as a dialogue that failed to load.

   This hides the dialogue's chrome while it loads so both entry points
   look the same. The pins are untouched: they live inside
   .popup-inner-loader, which this does not style.

   WHY THIS IS SAFE WHERE SECTION 109 WAS NOT
   109 used the same :has() condition to hold the panel transparent for
   as long as the plugin's loading class was present. The plugin does
   not always put .wgb-d-none back, so the condition stayed true, and
   the checkout modal had no panel at all for a day.

   The condition here is identical. The difference is that the hiding
   is done by a ONE-SHOT ANIMATION with no `forwards`:

     - loading finishes quickly  -> selector stops matching, normal style
     - the class never clears    -> the animation ends after 3s and the
                                    element falls back to its NORMAL
                                    computed style, which is the visible
                                    dialogue

   Both outcomes end with the panel visible. There is no state for the
   plugin to strand, because time ends it, not a class. Deliberately no
   `animation-fill-mode: forwards`: reverting to the plugin's own styles
   is the whole point, and it means no value has to be guessed here.


   WHY THE CONDITION ALSO TESTS FOR AN EMPTY BODY
   The loading class is set for THREE different things, and hiding the
   dialogue is only right for two of them. Measured on the live site:

     first load of the checkout   loading, .wgb-popup-posts empty     hide
     re-opened from "Here"        loading, .wgb-popup-posts empty     hide
     ADD SAMPLE inside the modal  loading, .wgb-popup-posts POPULATED  do not hide

   Without the second test the dialogue also vanished for about a second
   and a half every time a customer added a sample: they clicked a button
   and the thing they clicked disappeared, leaving three pins on a dimmed
   page. That is worse than the mismatch this section exists to fix.

   So the veil applies only while there is nothing to show yet. Once the
   samples are on screen the plugin's own cream loader washes over them
   and the dialogue stays exactly where the customer left it.

   Nothing changes width, height, position or overflow, so every
   measurement the plugin makes while loading is the one it gets after.
   ------------------------------------------------------------------ */

.wgb-popup-box:has(> .popup-inner-loader:not(.wgb-d-none)):not(:has(.wgb-popup-posts > *)) {
	animation: zg-sampler-veil 3s linear;
}
.wgb-popup-box:has(> .popup-inner-loader:not(.wgb-d-none)):not(:has(.wgb-popup-posts > *)) > .wgb-popup-header,
.wgb-popup-box:has(> .popup-inner-loader:not(.wgb-d-none)):not(:has(.wgb-popup-posts > *)) > .wgb-popup-body {
	animation: zg-sampler-hide 3s steps(1);
}

@keyframes zg-sampler-veil {
	0%, 100% {
		background-color: transparent;
		background-image: none;
		box-shadow: none;
		border-color: transparent;
	}
}

@keyframes zg-sampler-hide {
	0%, 100% { visibility: hidden; }
}

/* With the dialogue invisible the page's own dim backdrop is the ground,
   so the loader must not lay a second veil over it. */
.wgb-popup-box:has(> .popup-inner-loader:not(.wgb-d-none)):not(:has(.wgb-popup-posts > *)) .popup-inner-loader {
	animation: zg-sampler-clear 3s linear;
}
@keyframes zg-sampler-clear {
	0%, 100% { background-color: transparent; }
}

@media (prefers-reduced-motion: reduce) {
	/* the animation is a timed state change, not motion, so it stays */
	.wgb-popup-box:has(> .popup-inner-loader:not(.wgb-d-none)):not(:has(.wgb-popup-posts > *)) { animation-duration: 3s; }
}

/* ==================================================================
   115. ONE SPINNER, NOT TWO
   The owner asked whether the three loading pins look the same on the
   first load, on a reload and on the "Here" link. Measured on the live
   checkout, they did not, and the reason is that this plugin has TWO
   loaders and shows BOTH at the same time:

     .wgb-popup-loading            an inline SVG, three rects, fill #fff
     .popup-inner-loader           three divs, restyled ink by 112

   custom-jquery-gift.js turns them on together (lines 108 + 112, and
   248 + 250), so which one a customer actually sees is a stacking
   accident. Measured at the dialogue centre with elementsFromPoint:
   the white SVG paints on top on the first load, the ink divs paint on
   top from the "Here" link. Sampling the screenshots confirmed it,
   pure white pixels in one state and ink in the other. Section 112 had
   only ever restyled one of the two, which is why the mismatch survived
   it.

   THE FIX IS TO HAVE ONE SPINNER
   The SVG is hidden and the restyled divs are the only loader left, so
   every state shows the same three bars at the same size with the same
   animation. This is safe because the SVG is never shown on its own:
   both of its show() calls are immediately preceded by the divs being
   un-hidden, so hiding it cannot leave a customer with no spinner at
   all. Verified by grep across the whole plugin, PHP and JS.

   COLOUR FOLLOWS THE GROUND, WHICH IS THE ONLY THING THAT VARIES
   While the dialogue is veiled (section 114) the ground is the page's
   own dim scrim, and the reference the owner approved on the first load
   was white bars on exactly that. Once the samples are on screen the
   ground is the cream dialogue, where white would be invisible, so the
   bars stay ink there. Same shape, same size, same rhythm throughout;
   only the colour follows what is behind it.

   WHY #wgb-modal IS ON THESE SELECTORS
   Section 112 sets the middle bar through `#wgb-modal ... .loader-item`.
   An ID beats any number of classes, and !important on both sides does
   not change the order, so a class-only rule here coloured the two
   pseudo-element bars white and left the middle one ink. Matching the
   ID is what makes all three bars change together.
   ------------------------------------------------------------------ */

/* THE SVG STAYS. Hiding it was wrong and the screenshots caught it: on the first load the
   div pins sit UNDERNEATH the modal's own scrim (elementsFromPoint at the dialogue centre
   returns the scrim, not the pins), so the SVG is the only spinner that paints there. With it
   hidden the first load and a reload showed a dim page and nothing else. Both loaders are
   left visible, and the colour rule below makes them look the same instead.

   Their geometry already matches closely enough to be indistinguishable: the SVG bars are 6px
   wide and animate 16-25.6px tall, 10px apart; the divs are 5px wide, animate 11-26px tall,
   10px apart. */

/* Veiled dialogue means the dim page is the ground: match the first-load white. */
#wgb-modal .wgb-popup-box:has(> .popup-inner-loader:not(.wgb-d-none)):not(:has(.wgb-popup-posts > *)) .loader-item,
#wgb-modal .wgb-popup-box:has(> .popup-inner-loader:not(.wgb-d-none)):not(:has(.wgb-popup-posts > *)) .loader-item::before,
#wgb-modal .wgb-popup-box:has(> .popup-inner-loader:not(.wgb-d-none)):not(:has(.wgb-popup-posts > *)) .loader-item::after {
	background: #FFFFFF !important;
}

/* ==================================================================
   116. THE DISCOVERY BOX BAND
   The Instagram feed used to sit here. Measured on the live page, the
   stretch between the perfumer band and the collection tiles was about
   870px carrying only that feed, including the largest empty run on the
   whole homepage (196px, immediately above "Follow us on instagram").
   The Discovery Box is what turns a stranger who cannot smell anything
   into a customer, and it had no presence beyond a grey strip.

   Type is matched to the band above it rather than invented: the
   neighbouring h2 measures FreightTextPro 400 at 46.4px on the live
   page, so the heading here uses the same face and weight and a clamp
   that lands in the same place. An earlier draft used a --zg-display
   token that does not exist on this site and fell back to a heavy
   serif, which looked nothing like the rest of the page.

   The markup comes from mu-plugins/home-discovery-band.php. Deleting
   that file removes the band and restores the Instagram feed, so this
   section simply stops matching anything.
   ------------------------------------------------------------------ */

.zg-dbox {
	background: var(--zg-cream);
	/* Asymmetric on purpose. The container below brings its own top padding, so a symmetric
	   bottom left a 206px hole against a page whose other section gaps measure 138-161px.
	   Trimmed here rather than on the neighbour, which is Elementor's and not ours to touch. */
	padding: clamp(3.5rem, 7vw, 6rem) 20px clamp(1.5rem, 2.5vw, 2.25rem);
}

.zg-dbox__inner {
	max-width: 1160px;
	margin-inline: auto;
	display: grid;
	grid-template-columns: minmax(0, 0.95fr) minmax(0, 1fr);
	gap: clamp(2rem, 5vw, 4.5rem);
	align-items: center;
}

.zg-dbox__art img,
.zg-dbox__img {
	display: block;
	width: 100%;
	height: auto;
}

.zg-dbox__eyebrow {
	font-size: 11px;
	letter-spacing: .18em;
	text-transform: uppercase;
	color: var(--zg-muted);
	margin: 0 0 .9rem;
}

.zg-dbox__h {
	font-family: FreightTextPro, Georgia, serif;
	font-weight: 400;
	font-size: clamp(2rem, 3.3vw, 2.9rem);
	line-height: 1.16;
	margin: 0 0 1.1rem;
	color: var(--zg-ink);
}

.zg-dbox__intro {
	max-width: 46ch;
	margin: 0 0 1.5rem;
	line-height: 1.7;
}

/* The fragrances the box contains, so the offer is legible without a click. */
.zg-dbox__list {
	list-style: none;
	margin: 0 0 1.6rem;
	padding: 0;
	display: flex;
	flex-wrap: wrap;
	gap: .45rem .5rem;
}

.zg-dbox__list li {
	font-size: 11px;
	letter-spacing: .12em;
	text-transform: uppercase;
	color: var(--zg-ink);
	border: 1px solid rgba(20, 19, 15, .16);
	padding: .42rem .7rem;
}

.zg-dbox__price {
	margin: 0 0 1.5rem;
	font-size: 15px;
	color: var(--zg-ink);
}

.zg-dbox__price span { color: var(--zg-muted); }

/* The same flat ink button the rest of the page uses. */
.zg-dbox__cta {
	display: inline-block;
	background: #1A1816;
	color: #F5F3EB;
	font-size: 11px;
	letter-spacing: .16em;
	text-transform: uppercase;
	text-decoration: none;
	padding: 1rem 1.9rem;
	border: 1px solid #1A1816;
	transition: background .18s ease, color .18s ease;
}

@media (hover: hover) {
	.zg-dbox__cta:hover { background: transparent; color: var(--zg-ink); }
}

.zg-dbox__note {
	margin: 1.4rem 0 0;
	font-size: 13px;
	line-height: 1.65;
	color: var(--zg-muted);
	max-width: 44ch;
}

@media (max-width: 860px) {
	.zg-dbox__inner { grid-template-columns: 1fr; gap: 2rem; }
	.zg-dbox__art { max-width: 460px; }
}

/* The follow link, now in the footer contact column with the phone and the email.
   It inherits that block's uppercase 13px treatment, so only the underline is set here. */
.zg-foot-social { margin: 0; }
.zg-foot-social a { text-decoration: none; border-bottom: 1px solid currentColor; }

/* Blanking the Instagram widgets empties them but leaves their Elementor wrappers, and those
   wrappers keep their own padding and margins. Measured after the first install: a 316px empty
   run between this band and the collection tiles, and the page ended up 154px TALLER than
   before rather than shorter. Hiding the wrappers themselves is what actually removes the band.
   These ids are the same five widgets home-discovery-band.php blanks, plus the container that
   held the feed. They exist only on the homepage. */
.elementor-element-6816af8,   /* "Follow us on instagram"   */
.elementor-element-a911a6b,   /* the paragraph under it     */
.elementor-element-aee69ab,   /* the Instagram glyph        */
.elementor-element-d8ba47e,   /* "@HOUSEOFZIGGIMAY"         */
.elementor-element-7bee93b {  /* the container that held the feed */
	display: none !important;
}


/* ==================================================================
   117. THE CHOOSING BLOCK, UNRULED
   The owner asked whether the homepage looks like a luxury site. The
   honest answer was no, not consistently, and this block was the worst
   offender: five bordered columns of small uppercase text with
   "FROM 1000 DKK" printed on every one. A ruled data table is a spec
   sheet, and it sat exactly where somebody is deciding what to buy.

   Nothing is added here. The rules, the panel and the boxes are taken
   away, the names move from small uppercase to the reading serif the
   headings use, and home-choosing.php now prints one quiet price line
   for the whole group instead of five labels.

   The grid is pinned to five columns. Without that, removing the card
   padding let it reflow to four and orphan the fifth fragrance on its
   own row.
   ------------------------------------------------------------------ */

.zg-choose__grid {
	border: 0;
	background: transparent;
	grid-template-columns: repeat(5, minmax(0, 1fr));
	gap: clamp(1.2rem, 2.4vw, 2.4rem);
}

.zg-choose__card {
	border: 0;
	background: transparent;
	padding: 0;
}

.zg-choose__name {
	font-family: FreightTextPro, Georgia, serif;
	font-size: 19px;
	font-weight: 400;
	letter-spacing: 0;
	text-transform: none;
	margin-bottom: .5rem;
}

.zg-choose__line { line-height: 1.7; }

.zg-choose__pricenote {
	margin: 1.8rem 0 0;
	font-size: 13px;
	letter-spacing: .04em;
	color: var(--zg-muted);
}

@media (max-width: 900px) {
	.zg-choose__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 520px) {
	.zg-choose__grid { grid-template-columns: 1fr; }
}

/* The fragrances in the Discovery Box band, as a sentence rather than pills. */
.zg-dbox__names {
	margin: 0 0 1.5rem;
	max-width: 46ch;
	line-height: 1.7;
	color: var(--zg-muted);
}

/* The choosing block and the Discovery Box band are one thought, so they should not read as
   two sections stacked. Both conditions are structural rather than keyed on any transient
   class: if the band ever fails to render (the box unpurchasable, say), the selectors simply
   stop matching and the normal section padding returns on its own. */
.zg-choose:has(+ .zg-dbox) { padding-bottom: clamp(1rem, 2vw, 1.75rem); }
.zg-choose + .zg-dbox      { padding-top:    clamp(1rem, 2vw, 1.75rem); }

/* ==================================================================
   118. THE DISCOVERY BOX BAND, FULL BLEED
   Supersedes the boxed layout in section 116 now that the band carries
   a real photograph instead of a packshot.

   The photograph was taken on a warm grey surface, roughly
   rgb(186,181,178), against this section's cream rgb(245,243,235).
   Boxed, it reads as a rectangle pasted onto the page, which is the
   exact fault the old packshot had. Full bleed removes the problem
   instead of fighting it: the picture runs to the edge of the viewport
   with only ONE edge against the copy, which is how the collection
   cards and the Sigurd/Lab pair already treat photography here. The
   owner's photograph is not retouched.

   THE PICTURE IS NEVER CROPPED
   The frame carries the SAME 16/9 as the source at every width, so
   `cover` has nothing to cut. The first version set that only inside
   the mobile media query and left desktop on a tall min-height, which
   sliced the base of the box and the top of the lid off; the owner had
   to point out that mobile showed the whole package and desktop did
   not. There is no min-height here on purpose: it is what made the
   frame taller than the picture in the first place.

   The copy is held to a reading measure and centred in its column.
   Left full width it drifted against a wide empty margin.
   ------------------------------------------------------------------ */

.zg-dbox { padding: 0; }

.zg-dbox__inner {
	max-width: none;
	margin: 0;
	grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
	gap: 0;
	align-items: center;
}

.zg-dbox__art {
	position: relative;
	/* Back to 16/9. Cropping to 4/3 enlarged the box, which was not what was wanted: the size
	   was right, the two columns were simply too far apart. The distance came from the cut-out's
	   own empty right margin, so it is fixed in the IMAGE (the box is shifted across its frame
	   toward the copy, same scale) rather than by changing this frame. */
	aspect-ratio: 16 / 9;
	max-width: none;
}

.zg-dbox__art img,
.zg-dbox__img {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.zg-dbox__copy {
	padding: clamp(2rem, 4vw, 3.5rem) clamp(1.5rem, 4vw, 4rem);
	align-self: center;
	max-width: 34rem;
	/* Left aligned in its column, not centred. `margin-inline: auto` centred a 34rem block in a
	   column roughly half the viewport, so the copy drifted right and left a dead channel
	   between it and the photograph. The measure is unchanged; only where the block sits. */
	margin-inline: 0 auto;
}

@media (max-width: 860px) {
	.zg-dbox__inner { grid-template-columns: 1fr; }
	.zg-dbox__copy {
		padding: 2.25rem 20px 2.75rem;
		margin-inline: 0;
		max-width: none;
	}
}

/* WooCommerce inserts its own "View cart" link straight after any successful ajax add-to-cart
   button. Next to this band's button it arrives unstyled and inline, crammed against the
   button's right edge, and it is redundant anyway: FunnelKit's drawer slides open on the same
   event and already shows the cart with a way to check out. Hidden rather than suppressed in
   PHP so nothing has to fight WooCommerce's own script for control of its markup.

   The `loading` state is left alone: Woo's own spinner on it is the right feedback for the
   moment between the click and the drawer. */
.zg-dbox__copy .added_to_cart,
.zg-dbox__copy .wc-forward {
	display: none !important;
}

/* ==================================================================
   119. THE HOMEPAGE TRIMS AGREED 2026-09-07
   Four decisions taken off a set of side-by-side mockups. The PHP half
   lives in mu-plugins/home-refine.php and home-sample-band.php; this is
   only the presentation.

   EVERY RULE HERE IS !important ON PURPOSE. Elementor emits per-widget
   CSS at (0,4,0) AFTER this stylesheet, so a plain `.elementor-element-x`
   at (0,1,0) loses every time. This is the same pattern the newsletter
   measure fix at 105.7 uses.
   ------------------------------------------------------------------ */

/* --- 119.1  The promise band, unnumbered -------------------------
   01/02/03 claimed a sequence that does not exist. A short rule keeps
   the vertical rhythm the numerals gave each column without asserting
   an order. .zg-promise__num no longer renders; its rules above are
   left in place and are simply inert. */
.zg-promise__rule {
	display: block;
	width: 26px;
	height: 1px;
	background: rgba(20, 19, 15, 0.26);
	margin: 0.15rem 0 0.85rem;
}

/* --- 119.2  The fragrance row ------------------------------------
   This row sat on the palest ground on the page, between the hero and
   the dark foliage band, so the one thing the page is actually selling
   had the least presence on it. Two changes, neither of which touches
   the photographs: the ground is deepened two steps off the cream, and
   the cards are given room to breathe.

   THE FRAME STAYS SQUARE. A 4:5 frame was tried first, to make the
   bottles stand taller. The source packshots are 500x500, so `contain`
   letterboxed every one of them with a pale strip above and below,
   which reads as a broken image rather than as a taller card. `cover`
   would have cropped the tilted cap out of the composition. The photos
   are square, so the frame is square. */
.elementor-19995 .elementor-element.elementor-element-25fd9d8 {
	background: #EFEAE0 !important;
	padding: 3rem 1.6rem 2.4rem !important;
}

.elementor-19995 .elementor-element.elementor-element-25fd9d8 .jupiterx-wc-loop-product-image {
	aspect-ratio: 1 / 1 !important;
	display: flex !important;
	align-items: center !important;
	justify-content: center !important;
	background: #F7F4EC !important;
}

.elementor-19995 .elementor-element.elementor-element-25fd9d8 .jupiterx-wc-loop-product-image img {
	width: 100% !important;
	height: 100% !important;
	object-fit: contain !important;
}

/* The name carried the same weight as the category label under it. */
.elementor-19995 .elementor-element.elementor-element-25fd9d8 .woocommerce-loop-product__title {
	font-size: 1.06rem !important;
	margin-top: 0.9rem !important;
}

/* "From" is set quieter than the number it introduces, so the price
   still reads as a number first. */
.elementor-19995 .elementor-element.elementor-element-25fd9d8 .zg-from {
	color: var(--zg-muted, #6E6A5F);
}

/* --- 119.3  "Made by hand in Denmark" ----------------------------
   Centred text makes the eye hunt for the start of every line, which is
   why this was the hardest block on the page to read. Left aligned at a
   normal measure, the block itself still centred in the column.

   Applied to the container rather than to one widget: the copy is split
   across two text-editor widgets (ae9b638 and ab03934) and both need it. */
.elementor-19995 .elementor-element.elementor-element-d2dafa0 .elementor-widget-text-editor {
	text-align: left !important;
	/* min(), not a bare 64ch. This widget is a flex item, so a max-width wider than the
	   phone viewport does not cap it, it GROWS the box: measured 711px inside a 372px
	   container, and the heading and the two photographs below were dragged out with it.
	   The page did not scroll sideways, so nothing looked wrong until a phone rendered it. */
	max-width: min(64ch, 100%) !important;
	margin-inline: auto !important;
}

.elementor-19995 .elementor-element.elementor-element-d2dafa0 .elementor-widget-text-editor p {
	margin: 0 0 0.9rem;
}

/* ==================================================================
   120. A TAP SHOULD NOT SELECT THE THING YOU TAPPED
   Reported from a phone: a blue rectangle around a mobile menu
   category, and around the bag icon in the header.

   It is not a tap highlight. -webkit-tap-highlight-color is already
   transparent site-wide (normalize sets it on html). It is the TEXT
   SELECTION. These elements compute `user-select: auto`, so a tap held
   even slightly on Android turns into a long press, selects the word,
   and Chrome paints its selection colour plus two drag handles. On
   Android that selection is blue, which is why it reads as a stray
   blue rectangle that belongs to no part of this design.

   Reproduced by selecting a menu item's contents through the CDP
   session: the rectangle appears exactly where the owner photographed
   it. Headless Chrome paints the selection grey rather than blue, so
   the colour differs from the phone but the box is the same box.

   Only the chrome is made unselectable: the header and anything in the
   mobile menu. Running copy, prices, the address and the fragrance
   names stay selectable, because people do copy those.
   ------------------------------------------------------------------ */

#header-row,
#header-row *,
[class*="jet-mobile-menu"],
[class*="jet-mobile-menu"] * {
	-webkit-user-select: none;
	user-select: none;
}

/* The search field inside the header is the one thing in there that
   must stay selectable, or you cannot edit what you typed. */
#header-row input,
#header-row textarea {
	-webkit-user-select: text;
	user-select: text;
}

/* ---------------------------------------------------------------------------
   121. TOUCH TARGETS THAT A THUMB CAN ACTUALLY HIT
   ---------------------------------------------------------------------------
   A mobile audit across eleven page and viewport combinations found the same defect on every
   page: the header controls are drawn at icon size and have no hit area beyond it. Measured at
   390px, account 20x18, wishlist 28x20, cart 20x25, search 20x20. The minimum a thumb can be
   expected to hit is 40px, and 44px is the figure both Apple and Google publish. The hamburger
   already passes at 40x44 because someone gave it an expander; nothing else did.

   HOW, and why not the obvious way. Setting width/height on these anchors would push the icons
   apart: at 390px the account and wishlist glyphs sit ten pixels from each other and the row
   also carries the logo, so four 44px boxes do not fit without redrawing the header. Instead
   each control gets padding, and an equal negative margin cancels it. The hit box grows by 16px
   across and 24px down; every glyph stays exactly where it was and no sibling moves. That
   matters here more than usual, because this header has been broken and repaired several times
   over (sections 88 and 104.5) and a layout shift would be a regression, not a fix.

   NO ::before OR ::after ON THE ICONS. Elementor draws icon fonts with ::before, FunnelKit
   hangs the cart count off the toggler, and section 71 records what happens when you claim a
   pseudo-element a plugin is already painting with: the tick silently stops being drawn. The
   padding trick touches nothing either of them owns.

   The FunnelKit cart toggler is deliberately left out. Its count badge is absolutely positioned
   against the toggler box, and it took two attempts to stop that badge covering the bag handle
   in the first place. Padding the toggler would move the badge with it. It stays at 20x25 until
   its badge can be re-measured properly, and that is a conscious exclusion, not an oversight.
   ------------------------------------------------------------------------ */

@media (max-width: 1024px) {

  /* Header: account, wishlist and the search trigger. Padding out, margin back in. */
  /* Scoped by component, not by header class. The markup carries TWO headers, an outer
     jupiterx one and Elementor's own `header.elementor-20020`, and these controls live in the
     Elementor one, so a `header.jupiterx-header` prefix silently matched nothing. */
  /* VERTICAL ONLY, and that is a deliberate retreat. The first version of this rule also
     padded 8px horizontally with a -8px margin to cancel it. Measured afterwards, that put the
     account icon's box at x = -8, i.e. outside the header container. Nothing visibly broke and
     all 56 checks passed, but this header has been broken and repaired twice before and the
     owner has reported it twice, so buying ~16px of horizontal target at the cost of boxes that
     hang outside their container is the wrong trade. The header row is 55px tall and the glyphs
     are ~20px, so the vertical half is free: it needs no negative margin, cannot overflow, and
     takes the targets from 18-20px to 42px of height, which is where a thumb actually misses. */
  #my-accout-icon .elementor-icon-wrapper > a.elementor-icon,
  .jet-wishlist-count-button__link,
  #header-icon-row .elementor-icon-wrapper > a.elementor-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding-block: 12px;
    margin-block: -12px;
  }

  /* The logo measured 85x36, four pixels under. It is a block-level link with room above and
     below inside a 55px row, so it only needs the vertical half. */
  .raven-site-logo-link {
    display: inline-block;
    padding-block: 6px;
    margin-block: -6px;
  }

  /* Journal cards. The date and category links, and Read More, were all under 20px tall. */
  .raven-post-meta a.raven-post-meta-item,
  .raven-post-meta .raven-post-categories a,
  a.raven-post-button {
    display: inline-block;
    padding-block: 11px;
    margin-block: -11px;
  }

  /* The collection page's unfold control is a div with role=button, 24px tall. */
  .jet-unfold__trigger .jet-unfold__button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 44px;
  }

  /* The consent bar's policy link sits inline in a sentence at 17px tall. Line-height gives it
     the height without breaking the paragraph's rhythm, because the surrounding text already
     wraps at this width. */
  .cky-notice-des a.cky-policy {
    display: inline-block;
    padding-block: 11px;
    margin-block: -11px;
  }
}

/* The count badges read white on khaki at 3.62:1, under the 4.5:1 needed at 8px. Darkening the
   fill is the smaller change: the numeral stays white, which is what every other badge state on
   the site assumes, and the khaki was never a brand colour, only a default. */
/* !important because both plugins ship this colour at a specificity we cannot outrank from a
   stylesheet loaded before theirs: FunnelKit paints the cart count from its own bundle and
   JetWishlist from a widget rule. Measured 3.62:1 before, 5.1:1 after, against white. */
div.fkcart-shortcode-count.fkcart-item-count,
.jet-wishlist-count-button .jet-wishlist-count-button__count {
  background-color: #6E6A5F !important;
}

/* ---------------------------------------------------------------------------
   122. THE DENMARK BUYING GUIDE
   ---------------------------------------------------------------------------
   /buying-niche-perfume-in-denmark/ is a hand-built page with no Elementor on it, which is
   deliberate: the three Danish pages built the same way in September were the lightest on the
   site. The owner's objection to those was never speed, it was that a plain page looks unstyled
   next to a photographic one. So this styles the raw h2/p/ul the page ships, using the brand
   variables rather than inventing a second visual language.

   Why the page exists: Search Console shows the shop already ranking position 1 to 8 for Danish
   stockist queries ("hvor kan man kobe X i danmark", "X forhandler") that click at 4.3 to 7.7
   percent against a 1.95 percent site average, all of them landing on the homepage, which
   answers the wrong question. This page answers it.
   ------------------------------------------------------------------------ */

body.page .zg-guide {
  max-width: var(--zg-measure);
  margin: 0 auto;
  padding: clamp(2rem, 6vw, 4.5rem) clamp(1.15rem, 5vw, 2rem) clamp(3rem, 8vw, 6rem);
  color: var(--zg-ink);
  font-size: var(--zg-fs-body);
  line-height: var(--zg-lh-body);
  /* 68ch, from --zg-measure, is the same column every long-form page uses. */
}

body.page .zg-guide p {
  margin: 0 0 1.35em;
}

/* The standfirst carries the promise of the page, so it is set larger and quieter, the same
   relationship the collection pages use between title and intro. */
body.page .zg-guide__standfirst {
  /* 19px at the top end, which is what the journal's lead paragraph uses. It was 21.6px, a size
     that appears nowhere else. */
  font-size: var(--zg-fs-lead);
  line-height: var(--zg-lh-lead);
  color: var(--zg-muted);
  margin-bottom: 2.6em;
  text-wrap: pretty;
}

body.page .zg-guide h2 {
  /* Same correction as the h1, and the same source: the journal's own h2 is
     clamp(21px, 2.2vw, 26px) at weight 500. */
  font-weight: var(--zg-fw-head);
  font-size: var(--zg-fs-h2);
  line-height: var(--zg-lh-h2);
  letter-spacing: -0.01em;
  margin: 2.9em 0 0.75em;
  text-wrap: balance;
}

/* A hairline above each heading gives the page the sectioned rhythm the journal has, without
   adding a device the rest of the site does not use. The first one is suppressed because a rule
   directly under the standfirst reads as a divider the page does not need. */
body.page .zg-guide h2::before {
  content: "";
  display: block;
  width: 2.25rem;
  border-top: 1px solid var(--zg-rule);
  margin-bottom: 1.5em;
}

body.page .zg-guide h2:first-of-type::before {
  display: none;
}

body.page .zg-guide__checks {
  list-style: none;
  margin: 0 0 1.6em;
  padding: 0;
}

body.page .zg-guide__checks li {
  position: relative;
  padding-left: 1.4rem;
  margin-bottom: 0.85em;
}

/* WAS A SHORT RULE, NOW A DOT.
   The marker was an 11px border-top, chosen in section 119 to match the promise band. No em dash
   was ever involved: measured on the live page the marker is content:"" with a border, and the
   page's copy contains zero em and zero en dashes.

   It still had to go. Stacked down the left margin of a seven-item list, eleven identical short
   rules read as a column of em dashes, and the owner reported the page as breaking the no-em-dash
   rule on sight. A marker that makes clean copy look machine-written fails at the only job it
   has. The promise band keeps the rule device: one horizontal line as ornament is not a list.

   4px, same ink, aligned to the first line's optical centre rather than its box. */
body.page .zg-guide__checks li::before {
  content: "";
  position: absolute;
  left: 0.15rem;
  top: 0.62em;
  width: 4px;
  height: 4px;
  border: 0;
  border-radius: 50%;
  background: var(--zg-ink);
}

body.page .zg-guide__checks strong {
  font-weight: 600;
}

/* One bold for the whole page. The checklist declared 600 and everything else inherited 700;
   Avenir ships 400, 500 and 700 here, so both resolve to the same file and the difference was
   never visible - but the page should still say one thing. */
body.page .zg-guide strong { font-weight: 600; }

body.page .zg-guide a {
  color: var(--zg-ink);
  text-decoration: underline;
  text-underline-offset: 0.18em;
  text-decoration-thickness: 1px;
  text-decoration-color: var(--zg-rule);
}

@media (hover: hover) {
  body.page .zg-guide a:hover { text-decoration-color: var(--zg-ink); }
}

body.page .zg-guide__close {
  margin-top: 2.6em;
  padding-top: 1.6em;
  border-top: 1px solid var(--zg-rule);
  /* It is a closing paragraph and it reads as one, so it is body copy, not a caption. */
  font-size: var(--zg-fs-body);
  line-height: var(--zg-lh-body);
  color: var(--zg-muted);
}

/* The theme prints no h1 on a default-template page: the title lives only in <title>. A page
   with twelve h2s and no h1 reads to a crawler as a fragment of something else, so the heading
   ships inside the content rather than relying on the template. */
body.page .zg-guide__h1 {
  /* Weight matters more than size here. Nothing set a font-weight, so the theme's default for a
     raw h1 on a default-template page applied: FreightTextPro 900, a real black cut that is
     loaded and is used nowhere else on the site. Beside the journal (500) and /about/ (400) the
     page read as a different typeface. Matched to the journal's title, which is the closest
     relative this page has: same clamp, same weight. */
  font-weight: var(--zg-fw-head);
  font-size: var(--zg-fs-h1);
  line-height: var(--zg-lh-h1);
  letter-spacing: -0.02em;
  margin: 0 0 0.55em;
  text-wrap: balance;
  color: var(--zg-ink);
}

/* ---------------------------------------------------------------------------
   123. FURTHER READING LINE
   ---------------------------------------------------------------------------
   Appended after the related-fragrances row on the eight articles where "where do I actually
   buy this" is the reader's likely next question. It sits BELOW .zg-related, which already
   draws the hairline that separates the article from its footer matter, so this must not draw
   a second one: two rules stacked a few lines apart read as a mistake. Quiet, small, and using
   the same muted ink as the related block's label.
   ------------------------------------------------------------------------ */

/* Scoped and !important to match, not to bully. The journal's own body rule earlier in this
   file is `body.single-post .elementor-widget-raven-post-content p` carrying
   `font-size:17px !important; line-height:1.78 !important; margin:0 0 1.35em !important`,
   because Elementor's per-widget CSS is (0,4,0) and lands after this stylesheet. A bare
   `.zg-further` therefore lost on all three properties and the line rendered as ordinary body
   copy. Matching that selector's shape and force is the only way to win without raising the
   specificity war further. */
body.single-post .elementor-widget-raven-post-content p.zg-further,
.zg-further {
  margin: 1.1rem 0 2.5rem !important;
  font-size: var(--zg-fs-small) !important;
  line-height: var(--zg-lh-small) !important;
  color: var(--zg-muted);
}

.zg-further strong {
  font-family: Avenir, "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--zg-muted);
  display: block;
  margin-bottom: 0.4rem;
}

.zg-further a {
  color: var(--zg-ink);
  text-decoration: underline;
  text-underline-offset: 0.16em;
  text-decoration-thickness: 1px;
  text-decoration-color: var(--zg-rule);
}

@media (hover: hover) {
  .zg-further a:hover { text-decoration-color: var(--zg-ink); }
}

/* ---------------------------------------------------------------------------
   124. THE WISHLIST COUNT BADGE IS TWO SHAPES, NOT ONE
   ---------------------------------------------------------------------------
   Reported as "square on favourite" on desktop and a badge sitting on the heart on
   mobile. Both are the same structural fault, measured on the live site:

       desktop 1440   outer div 16x16 radius:0     bg #6E6A5F   <- the square
                      inner span 16x16 radius:50%  bg #8F866D   <- circle inside it
       mobile   390   outer div 18x12 radius:999px bg #6E6A5F
                      inner span 12x12
                      heart svg x318-336, badge x322-340, overlapping 16% of the icon

   The markup is <div class="count"><span>0</span></div> and BOTH elements are
   painted. On desktop the outer div is only rounded inside the max-width:767px
   block in section 45, so above 767px it stays a square with a circle drawn inside
   it and the corners show. That is the square.

   The 18px width on mobile is the same double-styling: section 45 gives the outer
   div padding 0 3px AND gives the inner span min-width 12px, so the badge measures
   12 + 6 = 18 and turns into a pill that leans onto the heart.

   The inner span's #8F866D is not in the palette either. The bag badge next to it
   is a single 12px disc in --zg-muted, which is what this should have matched all
   along.

   Fix: the outer div goes back to being an unpainted positioning wrapper and the
   span becomes the one disc, at both widths. A single digit stays a circle; a
   two-digit count widens into a pill because the width is driven by min-width plus
   padding rather than a fixed size.

   Specificity note: the plugin sets top with !important at (0,2,0) via
   .jet-wishlist-count-button--count-top-right, and section 45 tries to beat it from
   (0,1,1) and loses, which is why the measured top was -8px and not the -2px that
   rule asks for. Everything here is anchored on #header-row so the id wins the
   first specificity column outright and the values are actually the ones applied.
   ------------------------------------------------------------------------ */

/* The wrapper stops being a shape: no fill, no padding, no size of its own. */
#header-row .jet-wishlist-count-button__count {
  background: none !important;
  background-color: transparent !important;
  padding: 0 !important;
  min-width: 0 !important;
  width: auto !important;
  height: auto !important;
  border-radius: 0 !important;
  line-height: 1 !important;
}

/* The span is the badge. Same disc as the bag, same colour, at every width. */
#header-row .jet-wishlist-count-button__count span {
  display: flex !important;
  align-items: center !important;
  justify-content: center !important;
  box-sizing: border-box !important;
  width: auto !important;
  min-width: 16px !important;
  height: 16px !important;
  padding: 0 4px !important;
  border-radius: 999px !important;
  background: var(--zg-muted, #6E6A5F) !important;
  color: var(--zg-cream, #F5F3EB) !important;
  /* 11px, not 9: the scale floor, and the bag badge beside it is 11. Raised 2026-09-23. */
  font-size: 11px !important;
  font-weight: 400 !important;
  line-height: 1 !important;
  letter-spacing: 0 !important;
}

/* Tuck it to the heart's own top-right corner. The heart is not the last icon in
   the row, so unlike the bag this must not travel further right: measured at 390px
   the badge ends at 340 and the bag badge begins at 366, leaving 26px of daylight. */
#header-row .jet-wishlist-count-button__count {
  top: -6px !important;
  right: 2px !important;
  left: auto !important;
  bottom: auto !important;
}

@media (max-width: 767px) {
  /* 12px on mobile to match the bag badge beside it, which section 45 sets to 12. */
  #header-row .jet-wishlist-count-button__count span {
    min-width: 14px !important;
    height: 14px !important;
    padding: 0 3px !important;
    /* 10px, not 8. The circle grows 12 to 14 to carry it without clipping. */
    font-size: 10px !important;
  }

  #header-row .jet-wishlist-count-button__count {
    top: -4px !important;
    right: 4px !important;
  }
}

/* ---------------------------------------------------------------------------
   125. THE CHECKOUT BUTTON GOES BLANK WHILE IT LOADS
   ---------------------------------------------------------------------------
   Reported as "when clicked the button just turns black". It is not stuck: the
   button is a 358x46 bar in --zg-ink, and FunnelKit's own loading state sets

       .fkcart-loading { color: transparent }
       #fkcart-checkout-button.fkcart-loading div, ... * { color: transparent !important }

   so the label and the order total both vanish and leave an unlabelled black slab
   with a 16px spinner in the middle. Checkout answers in roughly 0.8-1.1s measured
   from here, so that blank state is on screen long enough to read as a hang.

   Keeping the words on the button while it works is the whole fix. The spinner is
   left exactly as FunnelKit draws it; only the text is brought back, dimmed, so it
   still reads as busy rather than as finished. Nothing here changes the button's
   behaviour or its href.
   ------------------------------------------------------------------------ */
.fkcart-panel .fkcart-checkout-button.fkcart-loading,
.fkcart-panel .fkcart-checkout-button.fkcart-loading div,
.fkcart-panel .fkcart-checkout-button.fkcart-loading span,
.fkcart-panel a.fkcart-loading,
.fkcart-panel a.fkcart-loading div,
.fkcart-panel a.fkcart-loading span,
#fkcart-modal .fkcart-checkout-wrap #fkcart-checkout-button.fkcart-loading div,
#fkcart-modal .fkcart-checkout-wrap #fkcart-checkout-button.fkcart-loading div * {
  color: var(--zg-cream, #F5F3EB) !important;
  opacity: 0.45;
}

/* The spinner sits dead centre, so give the label room to sit clear of it rather
   than have the two overlap. */
.fkcart-panel .fkcart-checkout-button.fkcart-loading,
.fkcart-panel a.fkcart-loading {
  padding-left: 34px !important;
}

/* ---------------------------------------------------------------------------
   126. PRODUCT NAMES IN THE COLLECTION GRID
   ---------------------------------------------------------------------------
   Measured on the Classic grid at 390px: Avenir 13px/15.6px, letter-spacing 1px,
   uppercase, in pure rgb(0,0,0).

   Two things are off rather than merely a matter of taste. The colour is pure
   black while every other surface on the site is --zg-ink #14130F, so the names
   are the only true black on the page and they sit harder than the logo above
   them. And at 15.6px the leading is tighter than the cap height wants, which is
   what makes the two-line names, VERDANT ZEN BREW and WHITE TEA DEL MAR, look
   cramped against the "Classic" line under them.

   SPECIFICITY: the black and the 1px tracking are not coming from the theme, they
   come from Elementor's per-widget stylesheet:

       .elementor-21107 .elementor-element.elementor-element-2312fb2
       .raven-wc-products-custom ul.products .woocommerce-loop-product__title
           { color: var(--e-global-color-text); letter-spacing: 1px }

   That is (0,6,1) and it is emitted AFTER this file, so a plain (0,2,1) selector
   here loses. A first attempt at this section set all three properties without
   !important and only line-height landed, precisely because Elementor's rule does
   not set line-height and does set the other two. Hence !important on the two it
   contests, and none on the one it does not.
   ------------------------------------------------------------------------ */
li.product .woocommerce-loop-product__title,
li.product h2.woocommerce-loop-product__title,
.jupiterx-products-wrapper .woocommerce-loop-product__title {
  color: var(--zg-ink, #14130F) !important;
  letter-spacing: 0.12em !important;
  line-height: 1.45;
}

@media (max-width: 767px) {
  li.product .woocommerce-loop-product__title,
  .jupiterx-products-wrapper .woocommerce-loop-product__title {
    line-height: 1.5;
    margin-bottom: 2px;
  }
}

/* ---------------------------------------------------------------------------
   127. PRODUCT CARD TYPOGRAPHY ON MOBILE
   ---------------------------------------------------------------------------
   Measured on the homepage carousel at 390px:

     h2.woocommerce-loop-product__title   Avenir 16.96px/24.59px w500 ls2.04px UPPER  #14130F
     span.posted_in  ("Exclusive")        Avenir 14px/21px      w400 ls normal        #000
     span.zg-from    ("From")             Avenir 14px           w400                  #6E6A5F
     price + DKK                          Avenir 14px / 12px    w400                  #000

   Three things read as flat rather than composed. The collection label is pure black
   at the same size and weight as the price, so it competes with the product name
   directly beneath the image instead of introducing it. Nothing is the site's ink
   (#14130F) except the name, which this file already fixed. And 2.04px of tracking on
   a 17px line is what pushes VERDANT ZEN BREW and WHITE TEA DEL MAR onto two lines
   with a loose, uneven rag.

   The card is given the order it should have had: a quiet eyebrow, then the name, then
   the price. The label becomes small, muted and widely tracked, which is the same
   treatment the uppercase labels elsewhere on the site get; the name comes down a
   little and loses some tracking so two-word fragrances hold together; the price
   settles onto the ink with lining figures so the columns align.

   Not touched: the uppercase name itself. It is the house's convention across the
   collection pages and the drawer, so it stays uppercase rather than being quietly
   restyled into something else.
   ------------------------------------------------------------------------ */

/* The collection label, everywhere: an eyebrow, not a second price line.
   Elementor sets colour on these from its per-widget sheet at (0,6,1), hence
   !important on the properties it contests and none on the ones it does not. */
li.product .posted_in,
li.product span.posted_in,
.jupiterx-products-wrapper .posted_in {
  display: block;
  font-size: 10px !important;
  line-height: 1.4;
  font-weight: 500 !important;
  letter-spacing: 0.18em !important;
  text-transform: uppercase;
  color: var(--zg-muted, #6E6A5F) !important;
  margin-top: 2px;
}

/* The price sits on the ink like everything else, with lining figures so the
   "From 1000" / "From 1200" column does not wobble between cards. */
li.product .price,
li.product .price .woocommerce-Price-amount,
li.product .woocommerce-Price-amount,
.jupiterx-products-wrapper .woocommerce-Price-amount {
  color: var(--zg-ink, #14130F) !important;
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
}

li.product .zg-from {
  color: var(--zg-muted, #6E6A5F);
}

@media (max-width: 767px) {
  /* 15px with 0.08em keeps two-word names on one line more often, and when they do
     wrap the tighter leading holds the two lines together as a single block rather
     than two loose rows. */
  /* Specificity note: section 126 above sets letter-spacing on
     `li.product h2.woocommerce-loop-product__title`, which is (0,2,2). A plain
     `li.product .woocommerce-loop-product__title` here is (0,2,1) and loses to it even
     with !important, which is exactly what happened on the first attempt: the
     line-height landed (126 does not set it) while font-size and tracking did not.
     Matching 126's shape settles it. */
  /* The homepage carousel pins this at 1.06rem from section 62, at (0,4,0), so the
     selector has to be repeated here or the size silently does not apply. That rule
     exists because "the name carried the same weight as the category label under it";
     the label above is now a 10px muted eyebrow, so the name no longer has to be
     oversized to out-rank it, and the reason for the pin is met a better way.
     Sizing does NOT fix the two-line names, and it was wrong to think it would. At
     390px the title column is 131px wide while VERDANT ZEN BREW needs 170px on one
     line; it still overflows at 13px. Long names wrap here whatever the size, so the
     job is to make two lines look deliberate rather than to chase one: hence the
     1.32 leading, which sets the pair as a single block, and the smaller size, which
     is better proportioned to a 131px column. */
  li.product h2.woocommerce-loop-product__title,
  li.product .woocommerce-loop-product__title,
  .jupiterx-products-wrapper h2.woocommerce-loop-product__title,
  .elementor-19995 .elementor-element.elementor-element-25fd9d8 .woocommerce-loop-product__title {
    font-size: 15px !important;
    line-height: 1.32 !important;
    letter-spacing: 0.08em !important;
    margin-top: 10px;
    margin-bottom: 3px;
    /* pretty, not balance. Balance splits a name into two even lines rather than
       letting it fill the first; with a column this narrow the names wrap either way,
       and pretty gives the better rag on the ones that do. */
    text-wrap: pretty;
  }

  li.product .posted_in,
  .jupiterx-products-wrapper .posted_in {
    font-size: 9.5px !important;
    letter-spacing: 0.2em !important;
    margin-bottom: 4px;
  }

  li.product .price,
  .jupiterx-products-wrapper .price {
    font-size: 13px;
  }
}

/* 121.  MOBILE HEADER: the icon cluster butts against the wordmark.
   ------------------------------------------------------------------------
   Measured at 390x844 on 2026-09-14: the logo occupies x=153-238 and the icon
   container (.elementor-element-723012ea, display:flex, column-gap:10px) starts at
   x=238 — the exact pixel the logo ends. The first icon lands at 258, so the whole
   clearance between wordmark and search icon is 20px, and the four icons spend
   30px of the strip on gaps between themselves.

   Tightening the inter-icon gap to 6px returns 12px to the left of the cluster,
   moving the first icon to about 270 and roughly halving the crowding, without
   changing any icon's size or hit area. Scoped to phones; the desktop header has
   room and is untouched.

   Fully qualified + !important because Elementor emits its own per-widget rule for
   this element AFTER this stylesheet in the bundle (see section 104 notes).
   Nothing here touches colour: colouring anything inside #header-row is what blanked
   the mobile menu once before. */

@media (max-width: 480px) {
  #header-row .elementor-element.elementor-element-723012ea {
    column-gap: 6px !important;
  }
}

/* 120.  COLLECTION INTROS: the empty right-hand column.
   ------------------------------------------------------------------------
   Section 3 already sets `column-count: 2` on .raven-archive-description and it has
   never once taken effect, because the same block sets `break-inside: avoid-column`
   on its paragraphs and every collection intro on this site is ONE <p> carrying <br>
   line breaks rather than several <p>s (measured: p count=1, br count=4, 1207 chars).
   A single unbreakable block cannot fill two columns, so all the copy stacks into
   column one and column two renders empty. That empty column is the void to the right
   of the text on /product-category/perfumes/classic/ and /exclusive/.

   Fix: let a LONE paragraph flow. Archives whose description really is several
   paragraphs keep avoid-column, so nothing that already works changes.

   Three columns above 1600px because two columns across the full 1865px container
   give a ~110-character measure, which reads worse than the bug did. The left edge
   does not move: this site keeps one left edge per page (section 1).

   Re-applied 2026-09-14 after being reverted during an unrelated investigation.
   Verified by before/after element geometry at 390, 1440 and 1920px: the ONLY pages
   that change are the two collection archives, and only inside the intro block. */

@media (min-width: 1025px) {
  main.jupiterx-main .raven-archive-description p:first-child:last-child {
    -webkit-column-break-inside: auto !important;
    break-inside: auto !important;
  }
}

@media (min-width: 1600px) {
  main.jupiterx-main .raven-archive-description {
    column-count: 3 !important;
    column-gap: 3.75rem !important;
  }
}

/* 122.  WISHLIST BUTTON INSIDE THE FUNNELKIT "SELECT OPTIONS" DRAWER.
   ------------------------------------------------------------------------
   Section 88's wishlist styling is all scoped to `body.single-product
   main.jupiterx-main`. FunnelKit renders its own copy of the buy row inside the
   slide-cart drawer, which is appended OUTSIDE main, so not one of those rules
   reaches it. Measured 2026-09-14 on the drawer instance:
       w=388 h=32  background rgba(0,0,0,0)  border 0px  path stroke rgb(35,31,32)
       inMain=false  inFkcart=true
   A dark outline heart with no background of its own, sitting on the drawer's dark
   bar: invisible until hover, which is what the owner reported.

   This mirrors the product-page resting and saved states onto the drawer copy only.
   Scoped through [class*="fkcart"] so the product-page button, which is already
   correct, is untouched. Cosmetic only: no layout, no behaviour, no checkout code. */

body [class*="fkcart"] .jet-wishlist-button,
body [class*="fkcart"] .jet-cw.jet-wishlist-button {
  background: var(--zg-cream) !important;
  border: 1px solid var(--zg-ink) !important;
  border-radius: 0 !important;
}

/* Resting is an OUTLINE heart. A filled heart means "already saved" (section 88). */
body [class*="fkcart"] .jet-wishlist-button svg path,
body [class*="fkcart"] .jet-cw.jet-wishlist-button svg path {
  fill: none !important;
  stroke: var(--zg-ink) !important;
}

body [class*="fkcart"] .jet-wishlist-button--added,
body [class*="fkcart"] .jet-cw.jet-wishlist-button--added {
  background: var(--zg-ink) !important;
  border-color: var(--zg-ink) !important;
}

body [class*="fkcart"] .jet-wishlist-button--added svg path,
body [class*="fkcart"] .jet-wishlist-button .jet-wishlist-button__plane-added svg path {
  fill: var(--zg-cream) !important;
  stroke: var(--zg-cream) !important;
}

@media (hover: hover) {
  body [class*="fkcart"] .jet-wishlist-button:hover,
  body [class*="fkcart"] .jet-cw.jet-wishlist-button:hover {
    background: rgba(20, 19, 15, 0.06) !important;
  }
}

/* ---------------------------------------------------------------------------
   64. THE NAV LABELS OVER THE HERO
   ---------------------------------------------------------------------------
   The bar is transparent on the home page by design, so the white labels sit directly on the
   video. Measured with the footage actually loaded, "Classic" reads white on rgb(202,182,182),
   which is 1.93:1 where 4.5 is the minimum for text that size. Nothing else on the page fails
   once the images are in, so this is the last one.

   A short wash at the top of the bar, fading out well before it ends. It is explicitly removed
   when the bar goes cream on hover or with a mega panel open, because the labels turn ink in
   those states and ink on a dark wash would be the same mistake in reverse.
   ------------------------------------------------------------------------ */
/* Held in a custom property because section 182 has to restore this exact value on a phone,
   and two copies of a gradient are two things to keep in step. */
body.home {
  --zg-hero-scrim: linear-gradient(
    to bottom,
    rgba(14, 13, 10, 0.68) 0%,
    rgba(14, 13, 10, 0.34) 55%,
    rgba(14, 13, 10, 0) 100%
  );
}

body.home #header-row {
  background-image: var(--zg-hero-scrim);
}

/* The drawer flag is here too. Once hover stopped clearing the scrim on a phone, an open
   drawer painted a cream bar with the dark wash still sitting on top of it, because a
   background-image paints OVER its own background-color. */
body.home.zg-mega-open #header-row,
body.home.zg-mega-open header.jupiterx-header,
body.home.zg-mobile-menu-open #header-row,
body.home.zg-mobile-menu-open header.jupiterx-header {
  background-image: none !important;
}

@media (hover: hover) {
  body.home #header-row:hover,
  body.home header.jupiterx-header:hover {
    background-image: none !important;
  }
}

/* ---------------------------------------------------------------------------
   80. THE MOBILE DRAWER PANELS
   ---------------------------------------------------------------------------
   Tapping a top level item in the mobile drawer opens the DESKTOP mega menu template, because
   the Jupiter X JetMenu widget has use-mobile-device-render on. That is why the drawer changed
   character on the way in: the top row is the house serif at 24.8px (span.jet-menu-label,
   FreightTextPro) and everything inside a panel was Avenir 17px, which is body copy, not
   navigation. The owner described it as the menu being broken style wise, and it is.

   Everything here is scoped to .jet-mobile-menu__template-content, a container that exists ONLY
   inside the mobile drawer. The desktop mega menu renders the same templates somewhere else, so
   nothing below can reach it. Verified by measuring the desktop header after the change.

   Four things, each one measured before it was written:

   1. TYPOGRAPHY. Panel links take the same serif as the top level, one step down, so moving from
      level one to level two is a change of depth and not a change of typeface.
   2. GROUP LABELS. The panel headings ("About", "Perfumes") carry elementor-hidden-tablet and
      elementor-hidden-mobile, so the drawer showed two unlabelled lists run together. They come
      back here as small muted eyebrows, which is what they are for.
   3. THE PROSE. The Help panel rendered a text-editor widget 391px tall containing three FAQ
      questions and their answers. A navigation drawer navigates; the answers are one tap away on
      /faq/, which the panel already links to. Hidden in the drawer only, so the desktop panel
      keeps its editorial block.
   4. THE PICTURES. Each panel carries a 352x352 image. Kept, because the house is a visual one,
      but capped so a tap into Explore does not become a page of photograph.
   ------------------------------------------------------------------------ */

/* 1. the links themselves */
.jet-mobile-menu__template-content a.raven-menu-item,
.jet-mobile-menu__template-content .raven-nav-menu a {
  font-family: "FreightTextPro", Georgia, serif !important;
  font-size: 19px !important;
  font-weight: 400 !important;
  line-height: 1.35 !important;
  letter-spacing: 0 !important;
  text-transform: none !important;
  color: var(--zg-ink) !important;
  padding: 13px 0 !important;
  display: block !important;
}

/* a hairline between rows, matching the divider the top level already uses */
.jet-mobile-menu__template-content .raven-nav-menu li + li > a.raven-menu-item {
  border-top: 1px solid var(--zg-rule);
}

/* 2. the group labels, back from elementor-hidden-mobile and restyled as eyebrows */
.jet-mobile-menu__template-content .elementor-widget-heading.elementor-hidden-mobile,
.jet-mobile-menu__template-content .elementor-widget-heading.elementor-hidden-tablet {
  display: block !important;
}
.jet-mobile-menu__template-content .elementor-widget-heading.elementor-hidden-mobile .elementor-heading-title,
.jet-mobile-menu__template-content .elementor-widget-heading.elementor-hidden-tablet .elementor-heading-title {
  font-family: "Jost", "Avenir Next", system-ui, sans-serif !important;
  font-size: 10.5px !important;
  letter-spacing: 0.22em !important;
  text-transform: uppercase !important;
  color: var(--zg-muted) !important;
  margin: 22px 0 4px !important;
}

/* 3. Prose stays out of a navigation drawer by default, because a drawer navigates. The three
   collection panels are the exception the owner asked for on 2026-09-25: each carries two short
   lines saying what the collection is (217 to 258 characters), which is what a first time visitor
   needs before tapping through. Help keeps its 691 characters of FAQ out, /faq/ is one tap away
   and the panel already links to it. Explore has no text widget at all, so it is unaffected.
   Scoped per template id, so a panel added later inherits the hidden default, not the exception. */
.jet-mobile-menu__template-content .elementor-widget-text-editor {
  display: none !important;
}
.jet-mobile-menu__template-content .elementor-24100 .elementor-widget-text-editor,
.jet-mobile-menu__template-content .elementor-24113 .elementor-widget-text-editor,
.jet-mobile-menu__template-content .elementor-24116 .elementor-widget-text-editor {
  display: block !important;
}

/* Reading copy, so it takes the serif at body size instead of the 14px sans the desktop panel
   hands it, which would read as foreign beside the serif panel links set in 1 above. Elementor
   writes its own typography at .elementor-element.elementor-element-XXX .elementor-widget-container
   p, which is (0,3,1); adding .elementor-widget-container here makes this (0,4,1) so it wins on
   specificity rather than on source order. */
.jet-mobile-menu__template-content .elementor-24100 .elementor-widget-text-editor .elementor-widget-container p,
.jet-mobile-menu__template-content .elementor-24113 .elementor-widget-text-editor .elementor-widget-container p,
.jet-mobile-menu__template-content .elementor-24116 .elementor-widget-text-editor .elementor-widget-container p {
  font-family: "FreightTextPro", Georgia, serif !important;
  font-size: 17px !important;
  font-weight: 400 !important;
  line-height: 1.5 !important;
  color: var(--zg-ink) !important;
  margin: 2px 0 14px !important;
}

/* 4. keep the photograph, stop it taking the whole screen */
.jet-mobile-menu__template-content .elementor-widget-image img {
  max-height: 190px !important;
  width: 100% !important;
  object-fit: cover !important;
}

/* 5. Some panel rows are heading widgets carrying a link rather than menu items, so rule 1 above
   never reached them: "Frequently Asked Questions" in the Help panel stayed Avenir and underlined
   while the rows beside it were serif. Same treatment, minus the underline, so a link is a link
   wherever the template happens to have built it. The image-overlay headings are excluded, they
   are handled in 6. */
.jet-mobile-menu__template-content .elementor-widget-heading:not(.elementor-absolute) .elementor-heading-title a {
  font-family: "FreightTextPro", Georgia, serif !important;
  font-size: 19px !important;
  font-weight: 400 !important;
  color: var(--zg-ink) !important;
  text-decoration: none !important;
  border-bottom: 0 !important;
}

/* 6. The headings sitting ON the panel photographs are ink, which was chosen against the pale
   bottle shot in Explore. Over the black and white portrait in Help the same ink reads as nothing
   at all: "ABOUT US" was dark grey on a dark photograph. A scrim plus cream is the one treatment
   that holds on both a pale and a dark picture, so neither has to be special cased. */
.jet-mobile-menu__template-content .elementor-widget-image {
  position: relative;
}
.jet-mobile-menu__template-content .elementor-widget-image::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(to bottom, rgba(14, 13, 10, 0) 35%, rgba(14, 13, 10, 0.55) 100%);
  pointer-events: none;
}
.jet-mobile-menu__template-content .elementor-widget-heading.elementor-absolute .elementor-heading-title {
  color: var(--zg-cream) !important;
  font-family: "Jost", "Avenir Next", system-ui, sans-serif !important;
  font-size: 12px !important;
  letter-spacing: 0.2em !important;
  text-transform: uppercase !important;
}

/* ---------------------------------------------------------------------------
   128. THE TYPE SCALE: one set of sizes, fluid from 360px to 4K
   ---------------------------------------------------------------------------
   Written 2026-09-20 after the owner asked for a standard that holds on every screen. Before
   this, a sweep of eight page types at six widths found text rendering at 9.5, 10, 10.5, 11,
   12, 13, 14, 14.5, 15, 16, 17, 18.4, 19, 21, 22, 24, 26, 27.5, 30, 40, 44, 46 and 48px, with
   heading weights of 300, 400, 500 and 900. That is not a system, it is an accumulation.

   SEVEN STEPS, AND NOTHING BETWEEN THEM

     label   11 -> 12    eyebrows, badges, meta. Uppercase and tracked, never a sentence.
     small   14 -> 15    captions, notes, secondary lines under a name.
     body    16 -> 17    anything a customer is expected to READ. 16 is the floor on a phone.
     lead    18 -> 19    the standfirst under a title, one per page.
     h3      19 -> 21
     h2      21 -> 26
     h1      30 -> 46

   WHY clamp() AND NOT BREAKPOINTS. A breakpoint makes type correct at 390 and 1440 and wrong
   at 700. Each step below interpolates continuously with vw, so there is no width at which the
   page is between sizes. The minimum holds below 360px and the maximum holds above ~1050px, so
   a 4K screen gets the same measured line as a laptop rather than a poster.

   THE THREE RULES THAT MAKE IT WORK ON A PHONE
     1. Reading copy never renders below 16px. Not 15.5, not 14 "because it is a short line".
     2. Line length stays under about 72 characters: the scale is useless if the column is not
        also constrained, so long-form containers carry a max-width in ch.
     3. Line-height travels with the size: 1.7 for body, tightening to 1.14 at h1. Set as a
        unitless ratio so it scales with the fluid size instead of fighting it.

   WEIGHTS: 400 for copy, 500 for headings, 600 for emphasis. Avenir here ships 400, 500 and
   700 only, so 600 resolves to the 700 file; it is written as 600 so the intent is one value.
   FreightTextPro also ships a 900 black cut, and a raw h1 on a hand-built page inherits it by
   default. Never let that happen again: state the weight.

   SCOPE. This section governs the bands and pages built in this stylesheet. Elementor holds
   its own per-widget typography at (0,4,0) and lands after this file, so widget text is
   corrected below only where it breaks rule 1, and only on phones, with matching force.
   ------------------------------------------------------------------------ */

:root {
  /* step            min      fluid                      max   */
  --zg-fs-label: clamp(11px,  10.45px + 0.15vw,          12px);
  --zg-fs-small: clamp(14px,  13.46px + 0.15vw,          15px);
  --zg-fs-body:  clamp(16px,  15.46px + 0.15vw,          17px);
  --zg-fs-lead:  clamp(18px,  17.46px + 0.15vw,          19px);
  --zg-fs-h3:    clamp(19px,  17.92px + 0.30vw,          21px);
  --zg-fs-h2:    clamp(21px,   2.20vw,                   26px);
  --zg-fs-h1:    clamp(30px,   4.40vw,                   46px);

  --zg-lh-label: 1.2;
  --zg-lh-small: 1.6;
  --zg-lh-body:  1.7;
  --zg-lh-lead:  1.55;
  --zg-lh-h3:    1.3;
  --zg-lh-h2:    1.24;
  --zg-lh-h1:    1.14;

  --zg-fw-copy:  400;
  --zg-fw-head:  500;
  --zg-fw-bold:  600;

  --zg-measure:  68ch;   /* long-form column: about 68 characters, inside the 45-75 that reads */
}

/* ---- the steps, as classes, so a new block can opt in by name ------------ */
.zg-t-label { font-size: var(--zg-fs-label); line-height: var(--zg-lh-label); font-weight: var(--zg-fw-head); letter-spacing: 0.16em; text-transform: uppercase; }
.zg-t-small { font-size: var(--zg-fs-small); line-height: var(--zg-lh-small); }
.zg-t-body  { font-size: var(--zg-fs-body);  line-height: var(--zg-lh-body); }
.zg-t-lead  { font-size: var(--zg-fs-lead);  line-height: var(--zg-lh-lead); }

/* ---- the bands this stylesheet owns, mapped onto the steps --------------- */
/* Each of these carried its own hand-picked size. They are listed rather than wildcarded so
   that adding a band is a deliberate act, and so this section reads as the inventory it is. */

/* eyebrows: the small tracked line that names a section */
body .zg-choose__eyebrow,
body .zg-related__h,
body .zg-maker__eyebrow,
body .zg-collections-eyebrow,
body .zg-product-eyebrow,
body .zg-dbox__eyebrow {
  font-size: var(--zg-fs-label);
  line-height: var(--zg-lh-label);
}

/* leads: one per band, the sentence under the heading */
body .zg-choose__intro,
body .zg-dbox__intro,
body .zg-home-atom__lead,
body .zg-guide__standfirst {
  font-size: var(--zg-fs-lead);
  line-height: var(--zg-lh-lead);
}

/* reading copy */
body .zg-promise__p,
body .zg-maker__p,
body .zg-dbox__note,
body .zg-related__note,
body .zg-guide__close,
body .zg-guide p,
body .zg-guide li {
  font-size: var(--zg-fs-body);
  line-height: var(--zg-lh-body);
}

/* secondary lines: a scent line under a name, a note under a price */
body .zg-choose__line,
/* The trust list under the buy row: six short labels, not sentences. */
main.jupiterx-main li.jet-listing-dynamic-repeater__item,
body .zg-dbox__names,
body .zg-dbox__price,
body .zg-related__list li,
body .zg-retn p {
  font-size: var(--zg-fs-small);
  line-height: var(--zg-lh-small);
}

/* headings this stylesheet sets directly */
body .zg-choose__h,
body .zg-dbox__h,
body .zg-maker__h,
body .zg-promise__h,
/* Elementor's own heading widgets in the content area. `.elementor-kit-19984 h2` is (0,1,1)
   and lands after this file, so a bare class loses on source order even when it ties on
   specificity. The header is outside main.jupiterx-main, so the mega menu and the mobile
   drawer are untouched; h1 is left alone because the two h1s on this site are display type. */
main.jupiterx-main :is(h2, h3).elementor-heading-title,
/* WooCommerce prints the review form heading itself, outside any widget. */
main.jupiterx-main #reply-title,
main.jupiterx-main #review_form h3,
main.jupiterx-main h3.jupiterx-product-review-header {
  font-size: var(--zg-fs-h2);
  line-height: var(--zg-lh-h2);
  font-weight: var(--zg-fw-head) !important;
}
body .zg-guide__h1 { font-size: var(--zg-fs-h1); line-height: var(--zg-lh-h1); font-weight: var(--zg-fw-head); }
body .zg-guide h2  { font-size: var(--zg-fs-h2); line-height: var(--zg-lh-h2); font-weight: var(--zg-fw-head); }
body .zg-guide h3  { font-size: var(--zg-fs-h3); line-height: var(--zg-lh-h3); font-weight: var(--zg-fw-head); }

/* ---- headings this file does not own, dragged onto the weights -----------
   Same fault as the guide had, in two more places. Neither of these rules existed to set a
   weight, so the theme default applied: the product page's stacked section headings rendered
   in the FreightTextPro 900 black cut, and the collection tiles' titles in a 300 light. A page
   using 300, 400, 500 and 900 of the same family does not read as one house. */
body.zg-tabs-stacked .zg-tab-heading,
body.single-product main.jupiterx-main .jet-tabs__content h2,
body.single-product main.jupiterx-main .jet-tabs__content h3 {
  font-weight: var(--zg-fw-head) !important;
  font-size: var(--zg-fs-h3) !important;
  line-height: var(--zg-lh-h3) !important;
}

/* The tile title keeps its own compact size, which the grid depends on: only the weight was
   wrong. Product card sizing is deliberate and measured elsewhere, so nothing here touches it. */
main.jupiterx-main h2.woocommerce-loop-category__title {
  font-weight: var(--zg-fw-head) !important;
}

/* ---- content headings on the pages built in Elementor --------------------
   Legal, About and the FAQ render their headings at 400 while the journal and the guide use
   500. One weight for a heading, so the pages read as the same publication. The two display
   exceptions are deliberate and stay: the homepage wordmark, which is the brand lockup in
   GlacialIndifference, and the product title, which is display type sized by its template. */
body.page-id-20031 main.jupiterx-main :is(h1, h2, h3),
body.page-id-20033 main.jupiterx-main :is(h1, h2, h3),
body.page-id-20035 main.jupiterx-main :is(h1, h2, h3),
body.page-id-20028 main.jupiterx-main :is(h2, h3),
body.page-id-20026 main.jupiterx-main :is(h1, h2, h3) {
  font-weight: var(--zg-fw-head) !important;
}
/* and their sizes, which sat at 44/24/22 against the scale's 46/26/21 */
body.page-id-20031 main.jupiterx-main h1,
body.page-id-20033 main.jupiterx-main h1,
body.page-id-20035 main.jupiterx-main h1,
body.page-id-20026 main.jupiterx-main h1 { font-size: var(--zg-fs-h1) !important; line-height: var(--zg-lh-h1) !important; }
body.page-id-20031 main.jupiterx-main h2,
body.page-id-20033 main.jupiterx-main h2,
body.page-id-20035 main.jupiterx-main h2,
body.page-id-20028 main.jupiterx-main h2,
body.page-id-20026 main.jupiterx-main h2 { font-size: var(--zg-fs-h2) !important; line-height: var(--zg-lh-h2) !important; }
body.page-id-20031 main.jupiterx-main h3,
body.page-id-20033 main.jupiterx-main h3,
body.page-id-20035 main.jupiterx-main h3,
body.page-id-20028 main.jupiterx-main h3,
body.page-id-20026 main.jupiterx-main h3 { font-size: var(--zg-fs-h3) !important; line-height: var(--zg-lh-h3) !important; }

/* The pending-release badge is drawn by Acowebs and came out in system-ui, the only text on
   the shop still rendering in a browser default. Size and colour are its own; the face is ours. */
main.jupiterx-main .acoplw-badge,
main.jupiterx-main .acoplw-blockText,
main.jupiterx-main .acoplw-blockText *,
li.product .acoplw-badge-icon .acoplw-blockText { font-family: Avenir, "Helvetica Neue", Helvetica, Arial, sans-serif !important; }

/* ---- the backstop --------------------------------------------------------
   The surfaces this file names by selector now take their size from the scale directly: the
   site-wide text-editor rule, the archive description and its mobile Unfold twin, the product
   tabs, short description and lede, the FAQ accordion, the journal and the legal pages. This
   block is only a floor for Elementor text this stylesheet has never named, so that a widget
   added next month cannot land at 14px on a phone unnoticed. It reaches text-editor and
   post-content widgets only, so product cards, prices, buttons, badges and the FunnelKit cart
   are out of its way by construction rather than by a list of exceptions that would rot. */
@media (max-width: 767px) {
  body .elementor-widget-text-editor p,
  body .elementor-widget-text-editor li,
  body .elementor-widget-theme-post-content p,
  body .elementor-widget-theme-post-content li {
    font-size: var(--zg-fs-body) !important;
    line-height: var(--zg-lh-body) !important;
  }
}

/* ---------------------------------------------------------------------------
   129. TOUCH TARGETS: THE LAST FOUR UNDER THE WCAG 2.2 MINIMUM
   ---------------------------------------------------------------------------
   Section 121 grew the header controls in September and stated that the hamburger "already
   passes at 40x44 because someone gave it an expander". Measured again on 2026-09-20 at 390px:
   it does not. `.jet-mobile-menu__toggle` is **16x16** with `cursor: pointer` and no padding at
   any width, which is the smallest tap target on the site and also the most important one on a
   phone. Either the expander was lost in a JetMenu update or the claim was measured on the icon
   wrapper rather than on the toggle.

   WCAG 2.2 AA 2.5.8 asks for 24x24 CSS px as a minimum, with an exception for targets whose
   spacing leaves a 24px circle clear. These sit 6-10px apart, so the exception does not apply.
   Apple's HIG asks 44pt and Material asks 48dp; those are comfort figures, not conformance.

   The mechanism is section 121's, unchanged: padding out, an equal negative margin back in, so
   the hit box grows and nothing moves by a pixel. Horizontal padding is kept to 2px on the
   account icon because 8px once put its box at x = -8, outside the header container.

   NOT TOUCHED, and deliberately: the FunnelKit cart toggler at 20x25. Its count badge is
   positioned against the toggler, and moving that badge took two attempts to get right
   ([[header bag icon]]). It needs the badge re-measured in the same pass, which is a separate
   change with its own verification, not a line tacked onto this one.
   ------------------------------------------------------------------------ */

/* The hamburger: 16x16 to 44x44, glyph unmoved. 44 rather than 24 because this one control
   opens the whole navigation on a phone, and check.mjs allows up to 48. */
.jet-mobile-menu__toggle {
  padding: 14px !important;
  margin: -14px !important;
}

/* Account: 20x42 already, so only the width is short. 2px each side takes it to 24. */
@media (max-width: 1024px) {
  #my-accout-icon .elementor-icon-wrapper > a.elementor-icon {
    padding-inline: 2px;
    margin-inline: -2px;
  }

  /* Wishlist: 28 wide is fine, 20 tall is four short. Section 121's rule names this selector
     already and computes to padding 0 on it, so the vertical padding never landed; stating it
     here with force rather than guessing which later rule reset it. */
  a.jet-wishlist-count-button__link {
    display: inline-flex !important;
    align-items: center !important;
    padding-block: 12px !important;
    margin-block: -12px !important;
  }
}

/* The skip link is 95x16 and only visible while focused, which is exactly when a keyboard or
   switch user needs it to be a real target. Padding costs nothing: it is off-screen until then. */
.jupiterx-a11y-skip-navigation-link {
  padding: 6px 10px !important;
}

/* The one standalone text link that is a target rather than part of a sentence: it sits after
   the maker paragraph as a call to action, so the inline exception in 2.5.8 does not cover it.
   3px of vertical padding, cancelled, takes 18px to 24px without moving the baseline. */
.zg-maker__more,
.zg-related__more {
  display: inline-block;
  padding-block: 5px;
  margin-block: -5px;
}

/* Breadcrumbs and post meta: links 11 to 16px tall. They sit on their own line rather than
   inside a sentence, so 2.5.8's inline exception does not cover them either. Padding only,
   cancelled, so no row moves. */
main.jupiterx-main [class*="breadcrumb"] a,
main.jupiterx-main [class*="post-info"] a,
main.jupiterx-main [class*="post-date"] a,
main.jupiterx-main a:has(> .raven-post-meta-item) {
  display: inline-block;
  padding-block: 7px;
  margin-block: -7px;
}

/* The review consent checkbox is 17x17 drawn by the theme. A checkbox is a target like any
   other, and this one gates whether a customer can leave the shop its first review. */
main.jupiterx-main #jupiterx-product-review-acceptance {
  /* min-*, not width: the theme sets a width on it that wins, and a checkbox that has been
     given a height but not a width is still a 17px target. */
  min-width: 24px !important;
  min-height: 24px !important;
  width: 24px !important;
  height: 24px !important;
  flex: none !important;
}

/* ---------------------------------------------------------------------------
   130. THE AUDO TAKE: warmer copy ink, italic emphasis, tighter band leading
   ---------------------------------------------------------------------------
   Everything in this section is gated on `body.zg-audo`, which is added by the mu-plugin
   `zg-audo-type.php`. Delete that file and every rule below stops matching: the site returns
   to exactly what it was, with no CSS to unpick and nothing else touched. That is the whole
   reason for the class.

   WHERE IT COMES FROM. audocph.com measured on 2026-09-20: Century Old Style at weight 400
   only, ink rgb(47,43,35) on rgb(245,243,235), body 16px on 1.3 leading, 60ch measure, and
   italics where most shops put a button. The cream is already identical to ours.

   WHAT IS ADOPTED, AND WHAT IS NOT.
     Adopted: the warm ink on COPY (headings keep the near-black, so the hierarchy gains a
       little contrast instead of losing it), italic emphasis in the journal and the guide,
       1.55 leading on band copy, and weight 400 on the big h1 only.
     Refused: weight 400 on h2 and h3. Audo can run one weight because their headings sit alone
       above a full-bleed photograph; ours sit twelve pixels above a paragraph in the same
       family, and at 21px the 400 flattens the hierarchy rather than quieting it. The h1 at
       30-46px carries itself, so it takes the 400.
     Refused: italics in the FAQ, the returns terms and shipping copy. That copy is skimmed for
       a fact and bold is doing a job there.
   ------------------------------------------------------------------------ */

body.zg-audo {
  --zg-copy: #2F2B23;   /* Audo's measured ink. 12.6:1 on the cream, against the 4.5:1 required. */
}

/* ---- 1. the warm ink, on running copy only ------------------------------ */
body.zg-audo .zg-guide,
body.zg-audo .zg-promise__p,
body.zg-audo .zg-maker__p,
body.zg-audo .zg-dbox__note,
body.zg-audo .zg-dbox__intro,
body.zg-audo .zg-related__note,
body.zg-audo .zg-choose__intro,
body.zg-audo .zg-home-atom__lead,
body.zg-audo .zg-atom__steps li { color: var(--zg-copy); }

/* The three surfaces the first pass missed, found by mapping every ink actually painted on
   copy: the product page's "try before you buy" band, which was still pure black; the
   collection intro, which had a fourth ink of its own (#3A382F); and the FAQ answers, which
   were left out of the first pass along with their bold. The bold stays, the ink does not. */
body.zg-audo .zg-try__lead,
body.zg-audo .zg-try__spec,
body.zg-audo .zg-try__own,
body.zg-audo .zg-try__alt,
body.zg-audo .zg-try__read,
body.zg-audo main.jupiterx-main .raven-archive-description,
body.zg-audo main.jupiterx-main .raven-archive-description p,
body.zg-audo main.jupiterx-main .jet-unfold__content-inner p,
body.zg-audo.page-id-20028 .jx-single-accordion-body,
body.zg-audo.page-id-20028 .jx-single-accordion-body p,
body.zg-audo.page-id-20028 .jx-single-accordion-body li,
body.zg-audo main.jupiterx-main .elementor-widget-text-editor p,
body.zg-audo.single-post .elementor-widget-raven-post-content p,
body.zg-audo.single-post .elementor-widget-raven-post-content li,
body.zg-audo.page-id-20031 main.jupiterx-main :is(p, li),
body.zg-audo.page-id-20033 main.jupiterx-main :is(p, li),
body.zg-audo.page-id-20035 main.jupiterx-main :is(p, li),
body.zg-audo.single-product main.jupiterx-main .jet-tabs__content p,
body.zg-audo.single-product main.jupiterx-main .jet-tabs__content li {
  color: var(--zg-copy) !important;
}

/* The guide's colour is set on its container so the copy inherits it, which also caught its
   headings. Headings keep the near-black: the point of warming the ink was contrast between
   the two, not a page that is uniformly softer. */
body.zg-audo .zg-guide :is(h1, h2, h3),
body.zg-audo .zg-guide__h1 { color: var(--zg-ink); }

/* ---- 2. italic emphasis, editorial pages only ---------------------------
   Scoped to paragraphs: the guide's checklist labels are instructions, not emphasis, and they
   keep their weight. */
body.zg-audo.single-post .elementor-widget-raven-post-content p strong,
body.zg-audo .zg-guide p strong {
  font-family: FreightTextPro, Georgia, serif !important;
  font-style: italic !important;
  font-weight: 400 !important;
  font-size: 1.06em !important;   /* 18px against the 17px it sits in, matching the lead step */
  letter-spacing: 0;
}

/* ---- 3. band copy at 1.55, the article still at 1.7 --------------------- */
body.zg-audo .zg-promise__p,
body.zg-audo .zg-maker__p,
body.zg-audo .zg-dbox__note,
body.zg-audo .zg-related__note,
body.zg-audo .zg-atom__steps li { line-height: 1.55; }

/* ---- 4. weight 400 on the h1 only --------------------------------------- */
body.zg-audo .zg-guide__h1,
body.zg-audo.single-post .elementor-element-73cc6c2b h1.elementor-heading-title,
body.zg-audo.page-id-20031 main.jupiterx-main h1,
body.zg-audo.page-id-20033 main.jupiterx-main h1,
body.zg-audo.page-id-20035 main.jupiterx-main h1,
body.zg-audo.page-id-20026 main.jupiterx-main h1 { font-weight: 400 !important; }

/* ---- 5. the call to action reads as a line of the text, not a button ---- */
body.zg-audo .zg-maker__more,
body.zg-audo .zg-related__more {
  font-family: FreightTextPro, Georgia, serif;
  font-style: italic;
  font-weight: 400;
  font-size: var(--zg-fs-lead);
  text-decoration-thickness: .5px;
  text-underline-offset: .2em;
}

/* ---------------------------------------------------------------------------
   131. ONE NEAR-BLACK FOR HEADINGS
   ---------------------------------------------------------------------------
   Not taste, and therefore not behind the zg-audo switch: mapping the inks actually painted on
   2026-09-20 found headings rendering in THREE different blacks depending on the template -
   rgb(0,0,0) on the journal, the product title, the About title and seven FAQ questions,
   rgb(17,17,17) on one collection heading, and --zg-ink rgb(20,19,15) everywhere else. Nobody
   chose that; it accumulated. The token is the one that was chosen, so everything takes it.

   Card titles and anything painted over an image are left alone: white-on-photograph is a
   deliberate colour, not drift.
   ------------------------------------------------------------------------ */
main.jupiterx-main :is(h1, h2, h3):not(.woocommerce-loop-product__title):not([class*="overlay"] *),
main.jupiterx-main h4.jx-ac-title {
  color: var(--zg-ink);
}
body.single-post .elementor-element-73cc6c2b h1.elementor-heading-title,
body.single-post .elementor-widget-raven-post-content :is(h2, h3) {
  color: var(--zg-ink) !important;
}

/* ---------------------------------------------------------------------------
   132. THE PRODUCT PAGE SPEAKS IN ONE VOICE
   ---------------------------------------------------------------------------
   The owner read the Oud Absolu page and said it looks like several fonts. It does. Measured at
   1440 on 2026-09-20, one page carried:

     Avenir 17 / 1.7      the description and the tabs          (correct, the body step)
     FreightTextPro 15/500  the six trust labels under the buy row: the SERIF, on a label list
     GlacialIndifference 14 the price: the WORDMARK face, which belongs to the logo alone
     Avenir 13 / 1.54     the scent line under the title
     Avenir 15 / 1.55 / 500, 14 / 1.62, 14 / 1.15, 14 / 1.6, 12 / 1.5
                          five different settings inside the single "try before you buy" band
     Avenir 15 / 1.6      the returns note, in a fifth ink

   None of that was a decision. This section puts every one of them on the scale from section
   128. It is conformance, not taste, so it is NOT behind the zg-audo switch: turning that off
   returns the inks and the italics, and leaves the page speaking in one voice.
   ------------------------------------------------------------------------ */

/* The trust list is a row of labels, so it takes the label voice: Avenir, not the serif. */
main.jupiterx-main li.jet-listing-dynamic-repeater__item,
main.jupiterx-main li.jet-listing-dynamic-repeater__item * {
  font-family: Avenir, "Helvetica Neue", Helvetica, Arial, sans-serif !important;
  font-weight: 400 !important;
}

/* The price was set in GlacialIndifference, which is the wordmark face and belongs to the logo
   and nothing else. Size and position are left exactly as they are. */
body.single-product main.jupiterx-main p.elementor-heading-title {
  font-family: Avenir, "Helvetica Neue", Helvetica, Arial, sans-serif !important;
}

/* The scent line under the title is the page's lede and was two steps below body copy. */
body.single-product main.jupiterx-main .elementor-element-4056ed2 :is(p, div.elementor-widget-container) {
  font-size: var(--zg-fs-lead) !important;
  line-height: var(--zg-lh-lead) !important;
}

/* One setting for the try band, which had five. The closing line stays a caption. */
.zg-try__lead,
.zg-try__spec,
.zg-try__own,
.zg-try__alt {
  font-size: var(--zg-fs-body);
  line-height: var(--zg-lh-body);
  font-weight: 400;
}
.zg-try__read {
  font-size: var(--zg-fs-small);
  line-height: var(--zg-lh-small);
}

/* The returns note is fine print under the buy button: the small step, in the muted ink the
   rest of the site uses for exactly this job, rather than a colour of its own. */
.zg-retn p {
  font-size: var(--zg-fs-small);
  line-height: var(--zg-lh-small);
  color: var(--zg-muted);
}

/* ---------------------------------------------------------------------------
   133. ONE SHELL FOR THE READING PAGES
   ---------------------------------------------------------------------------
   The owner: "these pages are not following any corporate style and need to align". Measured at
   1440 on 2026-09-20, the three reading templates put their text column in three places:

     guide     578px wide, gutters 281 left / 581 right      off-centre
     journal   529px wide, gutters 448 / 463                 centred
     legal     520px wide, gutters 213 / 708                 hard left, 708px of empty cream

   Three different left edges on three pages of the same shop. The measure itself was already
   right on all three (68, 72 and 68 real characters, counted by rendering each page's own prose
   in its own font rather than trusting the ch unit, which is the width of a zero and about 20
   per cent wider than an average letter here), so this changes where the column sits, not how
   wide it reads.

   ONE COLUMN, CENTRED, EVERYWHERE. 540px lands all three between 70 and 74 characters. Section
   1 of this stylesheet keeps one left edge per page, and that still holds for the shop pages
   with their bands and grids; a standalone page of text with no imagery beside it is a
   different object, and pinning it to the far left of a 1440px screen reads as unfinished
   rather than as a decision.

   The hairline above each h2 is the guide's device, from section 122. It is the only structural
   mark these pages carry, so the other two take it as well: same rule, same 2.25rem width, same
   suppression on the first heading, where a rule under the standfirst would read as a divider
   the page does not need.
   ------------------------------------------------------------------------ */

/* min(), not a flat 540: on a 390px phone a fixed 540 made the copy 150px wider than the
   screen and only the container's overflow hid it. The column is the smaller of the measure
   and what the device actually has. */
:root { --zg-measure-read: min(540px, 100%); }

/* --- the column, in one place -------------------------------------------- */
/* The guide is rendered by the theme's blog layout, so it sits inside .jupiterx-primary, a
   75% column with an empty 25% sidebar beside it. Centring inside that column still leaves the
   text a long way left of the page centre (measured x=300 against a page centre of 450), which
   is why this page never looked aligned with the journal. Unlock the column on this page only;
   the empty sidebar has nothing in it to displace. */
body.page-id-40367 .jupiterx-primary {
  max-width: 100% !important;
  flex: 0 0 100% !important;
}
/* Its own padding sits inside the max-width, so the column is stated as the measure plus the
   padding, or the text ends up 60px narrower than the other two. */
body.page .zg-guide {
  max-width: calc(var(--zg-measure-read) + 2 * clamp(1.15rem, 5vw, 2rem));
  margin-inline: auto;
}

body.single-post .elementor-widget-raven-post-content > .elementor-widget-container,
body.single-post .elementor-element-73cc6c2b > .elementor-widget-container {
  max-width: var(--zg-measure-read);
}

/* The legal pages carry their measure on each block rather than on a wrapper (section 107), so
   centring means auto margins on the same blocks. */
body.page-id-20031 main.jupiterx-main :is(p, li, h1, h2, h3, ul, ol),
body.page-id-20033 main.jupiterx-main :is(p, li, h1, h2, h3, ul, ol),
body.page-id-20035 main.jupiterx-main :is(p, li, h1, h2, h3, ul, ol) {
  max-width: var(--zg-measure-read) !important;
  margin-inline: auto !important;
}
/* A list item must not re-centre inside its own list, or the bullets step inwards. */
body.page-id-20031 main.jupiterx-main :is(li),
body.page-id-20033 main.jupiterx-main :is(li),
body.page-id-20035 main.jupiterx-main :is(li) {
  max-width: none !important;
  margin-inline: 0 !important;
}

/* The cookie policy keeps its body in a `.zg-policy-body` wrapper that an earlier section left
   660px wide with `margin: 0 340px 0 0`, so its paragraphs centred inside a block that was
   itself pinned left: measured 170px left of that page's own h1. The wrapper takes the column
   and the auto margins, and its paragraphs then fill it. */
main.jupiterx-main .zg-policy-body {
  max-width: var(--zg-measure-read) !important;
  margin-inline: auto !important;
}

/* --- the section mark, shared -------------------------------------------- */
body.page-id-20031 main.jupiterx-main h2::before,
body.page-id-20033 main.jupiterx-main h2::before,
body.page-id-20035 main.jupiterx-main h2::before,
body.single-post .elementor-widget-raven-post-content h2::before {
  content: "";
  display: block;
  width: 2.25rem;
  border-top: 1px solid var(--zg-rule);
  margin-bottom: 1.5em;
}
body.page-id-20031 main.jupiterx-main h2:first-of-type::before,
body.page-id-20033 main.jupiterx-main h2:first-of-type::before,
body.page-id-20035 main.jupiterx-main h2:first-of-type::before,
body.single-post .elementor-widget-raven-post-content h2:first-child::before {
  display: none;
}

/* NO standfirst treatment on the legal pages, deliberately. It was tried here on 2026-09-20
   and removed the same hour: the opening line of a privacy policy is the first sentence of the
   policy, not a lede, and setting it at 19px in the muted ink also tripped check.mjs, which
   samples the first paragraph to assert that legal copy is at least 15.5px on 1.6 leading. The
   guide keeps its standfirst because it has a real one, marked up as such. */

/* Headings in the product tabs had `margin-bottom: 0` and sat directly on top of their first
   paragraph, while the paragraphs below them had 14px between each other. That is what made
   the column still read as unsettled after the sizes were fixed: no air under a heading, air
   everywhere else. The journal's rhythm is 0.55em under an h2 and 0.45em under an h3, so the
   product takes the same. */
body.single-product main.jupiterx-main .jet-tabs__content h2,
body.zg-tabs-stacked .zg-tab-heading {
  margin-bottom: 0.55em !important;
}
body.single-product main.jupiterx-main .jet-tabs__content h3 {
  margin-bottom: 0.45em !important;
}

/* ---------------------------------------------------------------------------
   134. THE FAQ JOINS THE READING PAGES
   ---------------------------------------------------------------------------
   Measured 2026-09-20: the accordion itself is already one clean 700px column at x363, which
   is dead centre of the 1425px content area, so the structure was never the problem. What set
   the page apart was the header: its h1 and its category headings are centred, while the
   guide, the journal and the three legal pages all set the title hard against the left edge of
   their column. One page centring its title and five not is the kind of difference you feel
   without being able to name it.

   The accordion keeps 700px rather than the 540px of the prose pages. A row of question and
   answer is a list, not a paragraph: at 540 the questions would wrap onto two lines and the
   page would grow by a third for nothing.
   ------------------------------------------------------------------------ */

body.page-id-20028 main.jupiterx-main :is(h1, h2) {
  text-align: left !important;
}

/* The same hairline the other reading pages carry above a section. The first category needs
   none: it sits directly under the title, where a rule reads as a divider rather than a mark. */
body.page-id-20028 main.jupiterx-main h2::before {
  content: "";
  display: block;
  width: 2.25rem;
  border-top: 1px solid var(--zg-rule);
  margin-bottom: 1.5em;
}
body.page-id-20028 main.jupiterx-main h2:first-of-type::before { display: none; }

/* Title and accordion share one left edge: the title block is centred as a 700px column so it
   starts where the questions start. */
body.page-id-20028 main.jupiterx-main :is(h1, h2) {
  /* width, not just max-width: these headings are shrink-to-fit, so the h1 measured 97px and
     stayed centred by its parent no matter what max-width said. */
  display: block;
  width: 700px;
  max-width: 100%;
  margin-inline: auto;
}

/* ---------------------------------------------------------------------------
   135. THE READING SHELL, BY RULE INSTEAD OF BY PAGE ID
   ---------------------------------------------------------------------------
   Sections 128 to 134 named page ids: 20031, 20033, 20035, 20028, 40367. That is precisely how
   /security-and-data-protection/ reached 2026-09-20 still rendering its h1 in FreightTextPro
   **900**, its copy in pure black and its h2 at weight 400, sitting in the same footer as three
   legal pages that were correct. /contact/ had a 22px centred title and copy on two different
   left edges. A list of ids cannot cover the page nobody remembered.

   `zg-read-shell.php` adds `body.zg-read` to every single post and every page except the seven
   on its deny list (homepage, about, products, cart, checkout, my-account, wishlist), so a page
   published next month is in the house style the day it goes up. Everything below is keyed on
   that class alone.

   Figures and images are deliberately NOT constrained to the column: the journal sets a wide
   image above a narrow text column and that is a good pattern, not drift.
   ------------------------------------------------------------------------ */

body.zg-read main.jupiterx-main :is(h1, h2, h3, h4, p, ul, ol, blockquote) {
  max-width: var(--zg-measure-read);
  margin-inline: auto;
}
/* A list item must not re-centre inside its own list or the bullets step inwards. */
body.zg-read main.jupiterx-main li {
  max-width: none;
  margin-inline: 0;
}

/* Headings are shrink-to-fit in several of these templates, which is why the FAQ title measured
   97px and stayed centred whatever max-width said. State the box. */
body.zg-read main.jupiterx-main :is(h1, h2, h3) {
  display: block;
  width: 100%;
  text-align: left;
}

body.zg-read main.jupiterx-main h1 {
  font-size: var(--zg-fs-h1) !important;
  line-height: var(--zg-lh-h1) !important;
  font-weight: var(--zg-fw-head) !important;
}
body.zg-read main.jupiterx-main h2 {
  font-size: var(--zg-fs-h2) !important;
  line-height: var(--zg-lh-h2) !important;
  font-weight: var(--zg-fw-head) !important;
  margin-block: 2.5em 0.55em;
}
body.zg-read main.jupiterx-main h3 {
  font-size: var(--zg-fs-h3) !important;
  line-height: var(--zg-lh-h3) !important;
  font-weight: var(--zg-fw-head) !important;
  margin-block: 2em 0.45em;
}
body.zg-read main.jupiterx-main :is(p, li) {
  font-size: var(--zg-fs-body) !important;
  line-height: var(--zg-lh-body) !important;
}

/* The one structural mark these pages carry. */
body.zg-read main.jupiterx-main h2::before {
  content: "";
  display: block;
  width: 2.25rem;
  border-top: 1px solid var(--zg-rule);
  margin-bottom: 1.5em;
}
body.zg-read main.jupiterx-main h2:first-of-type::before { display: none; }

/* The Audo decisions reach the same pages, and stay behind the same switch. */
body.zg-audo.zg-read main.jupiterx-main :is(p, li) { color: var(--zg-copy) !important; }
body.zg-audo.zg-read main.jupiterx-main h1 { font-weight: 400 !important; }
body.zg-audo.zg-read main.jupiterx-main :is(h2, h3) { color: var(--zg-ink); }

/* The heading WIDGET is sized to its content on some of these pages: on /contact/ the h1 box
   measured 152px wide inside a 1385px row, so stating width on the h1 itself filled 152px and
   the title stayed adrift of the copy below it. The widget is what needs the column. */
body.zg-read main.jupiterx-main .elementor-widget-heading {
  width: 100% !important;
  max-width: var(--zg-measure-read) !important;
  margin-inline: auto !important;
}

/* The journal archive is a card grid, not a reading page, so it keeps its centred layout and
   its grid. Only its title was off the scale, at 22px against 46 everywhere else. */
body.category main.jupiterx-main .elementor-widget-heading h1 {
  font-size: var(--zg-fs-h1) !important;
  line-height: var(--zg-lh-h1) !important;
  font-weight: var(--zg-fw-head) !important;
}

/* ---------------------------------------------------------------------------
   136. THE WISHLIST COUNT SITS WHERE THE BAG COUNT SITS
   ---------------------------------------------------------------------------
   MY REGRESSION, from section 129 the same day. Growing the wishlist link's hit box to 44px
   added 12px of padding above the icon, and its count badge is positioned against the LINK, not
   against the icon, so the badge rose with the padding: measured 16px above the icon's top edge
   while the bag's badge sits 5px above its own. On a phone that reads as one badge floating and
   the other attached, which is exactly what the owner saw.

   Both badges are already the same object otherwise: 12x12, 8px type, rgb(110,106,95). Only the
   vertical anchor was wrong, so only that is corrected here, and it is expressed in terms of the
   padding that caused it. If the hit area ever changes, the badge follows it instead of drifting
   again.

   The bag is the reference, not the other way round: its placement took two attempts to stop the
   count covering the bag's handle, and that work is not being redone.
   ------------------------------------------------------------------------ */

:root { --zg-touch-pad: 12px; }

@media (max-width: 1024px) {
  a.jet-wishlist-count-button__link {
    padding-block: var(--zg-touch-pad) !important;
    margin-block: calc(-1 * var(--zg-touch-pad)) !important;
  }
  /* The #header-row prefix is not decoration: section 124 sets this badge's top with an ID
     selector, which is (1,1,0) and beats any class rule however many !importants it carries.
     Matching the shape and coming later in the file is the only thing that wins. 5px above the
     icon is the bag's offset, measured from the padded box the badge is anchored to. */
  #header-row .jet-wishlist-count-button__count {
    top: calc(var(--zg-touch-pad) - 5px) !important;
    right: 4px !important;
  }
}

/* ---------------------------------------------------------------------------
   137. THE FAQ QUESTION ROW IS A CONTROL, NOT A SECTION HEADING
   ---------------------------------------------------------------------------
   Two faults, one of them mine. The FAQ's questions are marked up as h3, so section 135's
   generic heading rule caught them and set them in the serif at the h3 size: measured on a
   phone at FreightTextPro 19.09px/500, which is the same size and face as "Returns &
   Exchanges" directly above them. A question you click is a control with a label, not a
   section, and it should not compete with the section it sits under.

   The second fault is older and is what the owner saw at /faq/#return-policy: the label is the
   full width of its row with `padding-right: 0`, while the chevron sits at the right edge of
   that same row. Every one of the 49 questions ran under its own chevron, and the longer ones
   collided with it visibly. The label now reserves the icon's column.
   ------------------------------------------------------------------------ */

body.zg-read main.jupiterx-main h3.jx-ac-title,
body.zg-read main.jupiterx-main .jx-ac-title {
  font-family: Avenir, "Helvetica Neue", Helvetica, Arial, sans-serif !important;
  font-size: var(--zg-fs-body) !important;
  line-height: var(--zg-lh-small) !important;
  font-weight: var(--zg-fw-head) !important;
  /* The chevron is 11px at the right edge of the row; 28px leaves it clear at every width. */
  padding-right: 28px !important;
  margin-block: 0 !important;
}
/* It is a label, so it takes no section mark. */
body.zg-read main.jupiterx-main .jx-ac-title::before { content: none !important; }

/* ---------------------------------------------------------------------------
   138. THE LAST PAGES OFF THE SCALE
   ---------------------------------------------------------------------------
   From a sweep of all 54 URLs at 390 and 1440 on 2026-09-20. Four surfaces were still outside
   the scale, each for its own reason, none of them covered by the reading shell because none of
   them is a page of prose.
   ------------------------------------------------------------------------ */

/* The journal archive's card titles were h3 at 25px weight 400: one pixel off the h2 step and
   the wrong weight, which is what made the index look unrelated to the articles it lists. */
body.category main.jupiterx-main h3 {
  font-size: var(--zg-fs-h2) !important;
  line-height: var(--zg-lh-h2) !important;
  font-weight: var(--zg-fw-head) !important;
}

/* /products/ is the shop archive, denied the reading shell because it is a grid, but its intro
   copy carries real section headings and they were rendering in the FreightTextPro 900 black
   cut at 24px. Same fault as the Security page had: a heading nobody ever stated a weight for. */
body.post-type-archive-product main.jupiterx-main :is(h2, h3) {
  font-weight: var(--zg-fw-head) !important;
}
body.post-type-archive-product main.jupiterx-main h2 {
  font-size: var(--zg-fs-h2) !important;
  line-height: var(--zg-lh-h2) !important;
}
body.post-type-archive-product main.jupiterx-main h3 {
  font-size: var(--zg-fs-h3) !important;
  line-height: var(--zg-lh-h3) !important;
}

/* The account pages are function, not prose, so they keep their own layout; the sizes were
   simply nobody's decision. The title was 22px against 46 everywhere else, and the form notes
   were 12px, below the reading floor on a phone. */
body.woocommerce-account main.jupiterx-main h1 {
  font-size: var(--zg-fs-h1) !important;
  line-height: var(--zg-lh-h1) !important;
  font-weight: var(--zg-fw-head) !important;
}
body.woocommerce-account main.jupiterx-main :is(h2, h3) {
  font-size: var(--zg-fs-h3) !important;
  line-height: var(--zg-lh-h3) !important;
  font-weight: var(--zg-fw-head) !important;
}
body.woocommerce-account main.jupiterx-main :is(p, label, .woocommerce-privacy-policy-text) {
  font-size: var(--zg-fs-small) !important;
  line-height: var(--zg-lh-small) !important;
}

/* The wishlist title was 40px on a phone and 52px on desktop: two sizes, neither of them a step. */
body.page-id-20547 main.jupiterx-main h1 {
  font-size: var(--zg-fs-h1) !important;
  line-height: var(--zg-lh-h1) !important;
  font-weight: var(--zg-fw-head) !important;
}

/* ---------------------------------------------------------------------------
   139. THE DISPLAY STEP, AND THE LAST FOUR STRAGGLERS
   ---------------------------------------------------------------------------
   The sweep's remaining findings, resolved one way or the other.

   FIRST, A CORRECTION TO THE SCALE ITSELF. The homepage band headlines are 56px and 50px, and
   the sweep called both off-scale because the scale stopped at the h1's 46. They are not
   defects: a band headline on a showcase page is display type and should be larger than a page
   title. What was wrong is that there were TWO of them, 56 and 50, which is an accident rather
   than a decision. The scale now has an eighth step, `--zg-fs-display`, and both take it.

   (Cart and checkout appeared in the sweep with the same four findings. They 301 to the
   homepage for an empty session, so the sweep was measuring the homepage twice. Not a defect,
   and worth remembering before chasing "cart page" type problems.)
   ------------------------------------------------------------------------ */

:root { --zg-fs-display: clamp(32px, 3.6vw, 52px); --zg-lh-display: 1.1; }

body.home .zg-collections-title,
body.home main.jupiterx-main h2.elementor-heading-title {
  font-size: var(--zg-fs-display) !important;
  line-height: var(--zg-lh-display) !important;
  font-weight: var(--zg-fw-head) !important;
}
/* One of the band's statement lines was weight 300, a weight that exists nowhere else here and
   has no file to render it, so it was being faked. */
body.home main.jupiterx-main p.elementor-heading-title { font-weight: 400 !important; }

/* The sample note under the collection grids was 12.5px on a phone: between the label step and
   the small step, so on neither. It is a caption, so it takes small. */
main.jupiterx-main .zg-samples-note,
body.tax-product_cat main.jupiterx-main .elementor-widget-text-editor p:last-child {
  font-size: var(--zg-fs-small) !important;
  line-height: var(--zg-lh-small) !important;
}

/* The shop archive title was 22px while every other page title is 46 and the product category
   titles are their own display size. */
body.post-type-archive-product main.jupiterx-main h1 {
  font-size: var(--zg-fs-h1) !important;
  line-height: var(--zg-lh-h1) !important;
  font-weight: var(--zg-fw-head) !important;
}

/* "Related Products" was 25px, one pixel off the h2 step, on the sample product pages only. */
body.single-product main.jupiterx-main h2 {
  font-size: var(--zg-fs-h2) !important;
  line-height: var(--zg-lh-h2) !important;
}

/* ---------------------------------------------------------------------------
   140. THE LAST THREE
   ------------------------------------------------------------------------ */

/* The sample band's caption under the collection grids was 12.5px: between the label step and
   the small step, so on neither. */
main.jupiterx-main .zg-sample-band__sub {
  font-size: var(--zg-fs-small) !important;
  line-height: var(--zg-lh-small) !important;
}

/* A statement paragraph on the homepage was 50px while the heading above it is 52: a <p>
   competing with its own <h2>. Statement lines take a second display step, one size below the
   headings, so the hierarchy reads and both sizes are decisions rather than leftovers.
   The hero's tagline is the same kind of line and takes the same step. */
:root { --zg-fs-display-lead: clamp(22px, 2.2vw, 32px); }
body.home main.jupiterx-main p.elementor-heading-title {
  font-size: var(--zg-fs-display-lead) !important;
  line-height: 1.3 !important;
  font-weight: 400 !important;
}

/* On the thank-you pages the title was in the column and the copy was not: its text widget is
   its own 540px box starting at x213, so the paragraphs inside it were already the right width
   and simply in the wrong place. Same fix as the heading widget needed: give the WIDGET the
   column, not only what is inside it. */
body.zg-read main.jupiterx-main :is(.elementor-widget-text-editor, .elementor-widget-theme-post-content) {
  max-width: var(--zg-measure-read) !important;
  margin-inline: auto !important;
}

/* REVERTED 2026-09-20, within the hour, because it broke two pages the owner then photographed.
   The intent was narrow: on three pages the title widget sat in a 350px column while the copy
   had 540, so the title started 95px right of its own text. Widening every column on every
   reading page fixed that and blew out everything else those columns hold: the FAQ's accordion
   went edge to edge at 1385px against centred headings, and the cookie policy's table and body
   did the same. A rule that reaches every column on a page cannot be aimed at one widget.

   The narrow-column problem is solved below instead, on the heading widget's own parent only. */
body.zg-read main.jupiterx-main .elementor-element:has(> .elementor-widget-container > h1),
body.zg-read main.jupiterx-main .elementor-element:has(> .elementor-widget-container > .elementor-heading-title) {
  width: 100% !important;
  max-width: 100% !important;
}

/* Centring the copy needs to beat section 16's archive rule, which sets
   `margin-left: 0 !important` on text-editor paragraphs at (0,2,2). On the thank-you pages that
   rule pinned the copy to the left of a 1385px container while the title sat centred in the
   column; on /contact/ the copy sits in a bare div with no widget class at all, so the widget
   rules never reached it either. Both are covered by stating the margins again, later and at
   matching weight. */
body.zg-read main.jupiterx-main .elementor-widget-text-editor p,
body.zg-read main.jupiterx-main :is(p, ul, ol, blockquote) {
  margin-left: auto !important;
  margin-right: auto !important;
}
body.zg-read main.jupiterx-main h1.elementor-heading-title {
  font-size: var(--zg-fs-h1) !important;
  line-height: var(--zg-lh-h1) !important;
}

/* One block on /contact/ resisted: the postal address, 360px wide with margin-left 0, set by a
   rule more specific than the paragraph rules above. Stating it one level deeper catches it,
   and `width: auto` is what actually matters: a block narrower than the column centres as a
   360px box instead of sharing the column's left edge with the copy around it. */
body.zg-read main.jupiterx-main div :is(p, ul, ol) {
  width: auto !important;
  max-width: var(--zg-measure-read) !important;
  margin-left: auto !important;
  margin-right: auto !important;
}

/* ---------------------------------------------------------------------------
   141. THE COOKIE TABLE AND THE SETTINGS BUTTON JOIN THE COLUMN
   ---------------------------------------------------------------------------
   Both sat at x20 while the policy's prose sat at x443: a five-column table running the full
   1385px and a "Cookie settings" button alone at the far left of the page, which is what the
   owner photographed. The table genuinely needs more width than the 540px reading column, so
   it is not squeezed into it; instead both start ON the column's left edge and the table runs
   right as far as it needs. Below the column width the offset collapses to zero, so a phone
   gets the full width it needs.
   ------------------------------------------------------------------------ */

main.jupiterx-main table.zg-cookie-table {
  max-width: min(100%, 940px) !important;
  margin-left: max(0px, calc((100% - var(--zg-measure-read)) / 2)) !important;
  margin-right: auto !important;
}

main.jupiterx-main button.zg-cc-reopen {
  display: block;
  margin-left: max(0px, calc((100% - var(--zg-measure-read)) / 2)) !important;
  margin-right: auto;
}


/* The title on the legal and thank-you pages carries a 95px left margin from an Elementor
   responsive setting, which put it 95px right of its own copy on a phone. Zeroed for heading
   widgets on reading pages only: this is the margin, not the width, so it cannot blow out a
   component the way widening whole columns did. */
@media (max-width: 767px) {
  body.zg-read main.jupiterx-main .elementor-element:has(> .elementor-widget-container > .elementor-heading-title),
  body.zg-read main.jupiterx-main .elementor-widget-heading {
    margin-left: 0 !important;
    margin-right: 0 !important;
  }
}

/* The FAQ's headings must match its accordion, not the prose column. Section 134 set them to
   700 to sit on the questions' left edge; section 135's generic reading-page rule came later in
   the file and took them back to 540, so the title and every category heading sat 80px right of
   the rows they head. Stated last, because the cascade is decided by order here.
   The accordion keeps 700 rather than dropping to the 540 of the prose pages: a question is a
   list row, and at 540 half of them wrap onto a second line for nothing. */
body.page-id-20028 main.jupiterx-main :is(h1, h2, h3) {
  max-width: min(700px, 100%) !important;
  width: min(700px, 100%) !important;
  margin-inline: auto !important;
}

/* ---------------------------------------------------------------------------
   142. THE WISHLIST COUNT JUMPS ON EVERY NAVIGATION
   ---------------------------------------------------------------------------
   Measured 2026-09-21 by sampling the header through page load: at 1000ms the badge computes
   `position: static` and sits BELOW the heart at y49, with the heart's own box stretched to
   20x43 because the badge is still in normal flow. By 2500ms it is `position: absolute` at y16
   and the box is back to 30x20. That is the icon jumping up and down between pages, and the
   owner sees it on every navigation.

   The declaration that makes it absolute lives in the JetCompareWishlist stylesheet, which
   arrives after first paint. Our own stylesheet is render-blocking, so stating the geometry here
   means the badge is out of flow in the first frame and nothing moves afterwards. The offsets
   themselves are unchanged; only the position and the containing block are asserted earlier.
   ------------------------------------------------------------------------ */

#header-row .jet-wishlist-count-button,
#header-row .jet-wishlist-count-button__wrapper,
#header-row a.jet-wishlist-count-button__link {
  position: relative;
}
#header-row .jet-wishlist-count-button__count {
  position: absolute !important;
  line-height: 1;
  pointer-events: none;
}
/* The link's own width settles from 20px to 30px when the plugin's stylesheet lands, which is a
   smaller shift than the vertical one but still a shift. Reserve it. */
#header-row a.jet-wishlist-count-button__link {
  min-width: 28px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

/* ---------------------------------------------------------------------------
   143. THE WAITING LIST ON AN UNRELEASED FRAGRANCE
   ---------------------------------------------------------------------------
   zg-notify.php appends this under the pending panel: the house note, then one field. It is
   styled on the scale like everything else, and the controls clear the 24px minimum the touch
   target work set, without any new colour or device.
   ------------------------------------------------------------------------ */

.zg-notify { margin-top: 1.6rem; }

.zg-notify__note {
  font-size: var(--zg-fs-body);
  line-height: var(--zg-lh-body);
  margin: 0 0 .9em;
}

.zg-notify__form {
  margin-top: 1.4rem;
  padding-top: 1.2rem;
  border-top: 1px solid var(--zg-rule);
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.zg-notify__label {
  font-size: var(--zg-fs-small);
  line-height: var(--zg-lh-small);
  color: var(--zg-muted);
}

.zg-notify__row { display: flex; gap: 8px; flex-wrap: wrap; }

.zg-notify__email {
  flex: 1 1 200px;
  min-width: 0;
  min-height: 44px;
  padding: 10px 12px;
  font-family: Avenir, "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-size: var(--zg-fs-body);
  color: var(--zg-ink);
  background: transparent;
  border: 1px solid var(--zg-rule);
  border-radius: 0;
}
.zg-notify__email::placeholder { color: var(--zg-muted); opacity: 1; }

.zg-notify__submit {
  min-height: 44px;
  padding: 10px 22px;
  font-family: Avenir, "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-size: var(--zg-fs-small);
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--zg-cream);
  background: var(--zg-ink);
  border: 1px solid var(--zg-ink);
  border-radius: 0;
  cursor: pointer;
  transition: opacity 140ms var(--zg-ease);
}
.zg-notify__submit:hover { opacity: .88; }
.zg-notify__email:focus-visible,
.zg-notify__submit:focus-visible { outline: 2px solid var(--zg-ink); outline-offset: 2px; }

/* The consent line is a real checkbox, not a pre-ticked assumption, and it carries the link to
   the policy: both are what makes the address lawful to keep. */
.zg-notify__consent {
  display: flex;
  gap: 9px;
  align-items: flex-start;
  font-size: var(--zg-fs-small);
  line-height: var(--zg-lh-small);
  color: var(--zg-muted);
}
.zg-notify__consent input {
  width: 18px; height: 18px; margin: 3px 0 0; flex: none; accent-color: var(--zg-ink);
}

/* The honeypot must be unreachable for a person and invisible, without display:none, which some
   bots check for. */
.zg-notify__hp {
  position: absolute !important;
  left: -9999px !important;
  width: 1px; height: 1px; opacity: 0;
}

.zg-notify__ok {
  font-size: var(--zg-fs-body);
  line-height: var(--zg-lh-body);
  margin: 1.2rem 0 0;
  padding-top: 1.2rem;
  border-top: 1px solid var(--zg-rule);
}

/* ---------------------------------------------------------------------------
   144. THE LETTER, ABOVE THE FOOTER
   ---------------------------------------------------------------------------
   zg-signup.php prints one band between the page and the footer, on every page that is not part
   of buying something. It is deliberately quiet: a hairline, the cream ground the rest of the
   site already uses, one heading on the scale, one field, one consent box. No second colour, no
   box shadow, no device. The column is narrower than the reading measure because a single field
   reads worse the wider it gets.
   ------------------------------------------------------------------------ */

.zg-letter {
  border-top: 1px solid var(--zg-rule);
  background: var(--zg-cream);
  padding: clamp(2.4rem, 4.5vw, 3.8rem) 20px;
}

.zg-letter__inner { max-width: 520px; margin: 0 auto; }

.zg-letter__h {
  font-family: FreightTextPro, Georgia, "Times New Roman", serif;
  font-weight: var(--zg-fw-head);
  font-size: var(--zg-fs-h2);
  line-height: var(--zg-lh-h2);
  color: var(--zg-ink);
  margin: 0 0 .5em;
}

.zg-letter__lead {
  font-size: var(--zg-fs-body);
  line-height: var(--zg-lh-body);
  color: var(--zg-ink);
  margin: 0;
}

.zg-letter__form {
  margin-top: 1.4rem;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.zg-letter__row { display: flex; gap: 8px; flex-wrap: wrap; }

.zg-letter__email {
  flex: 1 1 220px;
  min-width: 0;
  min-height: 44px;
  padding: 10px 12px;
  font-family: Avenir, "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-size: var(--zg-fs-body);
  color: var(--zg-ink);
  background: transparent;
  border: 1px solid var(--zg-rule);
  border-radius: 0;
}
.zg-letter__email::placeholder { color: var(--zg-muted); opacity: 1; }

.zg-letter__submit {
  min-height: 44px;
  padding: 10px 22px;
  font-family: Avenir, "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-size: var(--zg-fs-small);
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--zg-cream);
  background: var(--zg-ink);
  border: 1px solid var(--zg-ink);
  border-radius: 0;
  cursor: pointer;
  transition: opacity 140ms var(--zg-ease);
}
.zg-letter__submit:hover { opacity: .88; }
.zg-letter__email:focus-visible,
.zg-letter__submit:focus-visible { outline: 2px solid var(--zg-ink); outline-offset: 2px; }

/* Ticked by hand or not at all, and the policy is one tap away. Both of those are what makes
   keeping the address lawful, and neither costs a conversion worth having. */
.zg-letter__consent {
  display: flex;
  gap: 9px;
  align-items: flex-start;
  font-size: var(--zg-fs-small);
  line-height: var(--zg-lh-small);
  color: var(--zg-muted);
}
.zg-letter__consent input {
  width: 18px; height: 18px; margin: 3px 0 0; flex: none; accent-color: var(--zg-ink);
}

/* The coupon's terms, in the same place as the coupon's promise. Reading them after the code
   fails at checkout is how a good offer turns into a complaint. */
.zg-letter__fine {
  font-size: var(--zg-fs-label);
  line-height: 1.55;
  color: var(--zg-muted);
  margin: 0;
}

.zg-letter__hp {
  position: absolute !important;
  left: -9999px !important;
  width: 1px; height: 1px; opacity: 0;
}

/* The theme sets its own size and colour on anchors, which made the policy link a step larger and
   a shade darker than the sentence holding it. Both consent lines are told to inherit. */
.zg-letter__consent a,
.zg-notify__consent a {
  font-size: inherit;
  font-family: inherit;
  line-height: inherit;
  color: var(--zg-ink);
  text-decoration: underline;
  text-underline-offset: .16em;
}

/* ---------------------------------------------------------------------------
   145. THE NEWSLETTER POPUP'S CONSENT LINE
   ---------------------------------------------------------------------------
   The popup gained a real acceptance checkbox and the coupon's terms. Elementor renders the
   acceptance label with its own type and strips the link's underline, which left "How we handle
   your address" looking like ordinary words: a policy link nobody can see is not a policy link.
   The box itself was 16px, under the 24px minimum the rest of the site now keeps.
   ------------------------------------------------------------------------ */

#elementor-popup-modal-21089 .zg-popup-fine {
  font-size: var(--zg-fs-small);
  line-height: var(--zg-lh-small);
  color: var(--zg-muted);
}

#elementor-popup-modal-21089 .elementor-field-option label a {
  color: inherit;
  text-decoration: underline;
  text-underline-offset: .16em;
}

#elementor-popup-modal-21089 .elementor-acceptance-field {
  width: 20px;
  height: 20px;
  margin: 2px 8px 0 0;
  padding: 2px;
  accent-color: var(--zg-ink);
}

#elementor-popup-modal-21089 .elementor-field-option {
  display: flex;
  align-items: flex-start;
  gap: 2px;
}

/* ---------------------------------------------------------------------------
   146. THE HEART ON THE GRID
   ---------------------------------------------------------------------------
   The wishlist button was already being printed inside every loop card by
   jet-compare-wishlist, and Jupiter X was hiding it:

       .raven-wc-products-custom ul.products li.product .jet-wishlist-button__container
           { display: none }

   so a visitor could only save a fragrance from its own product page, one page deep, and the
   nine customer accounts on this shop had no way to build a list while browsing.

   It is shown here as a heart in the corner of the image, absolutely positioned, which is the
   whole point: the card's flow is untouched, nothing below it moves, and the grid measures the
   same height with the heart as without it. The plugin's own stylesheet is not loaded on this
   site, so the two states are wired here by hand. The plugin's JS puts .added-to-wishlist on the
   link, and that is the only hook needed.

   The badge plugin puts its label at the card's LEFT edge, which is why the heart sits right.
   ------------------------------------------------------------------------ */

/* The doubled .product is not a typo. Jupiter X's own rule is
   `.raven-wc-products-custom ul.products li.product .jet-wishlist-button__container` at the same
   specificity as this one, and its stylesheet loads after ours, so an identical selector loses on
   source order alone and the heart stays hidden. Repeating a class the card genuinely carries
   wins the cascade without an !important that would then have to be fought later. */
.jupiterx-main ul.products li.product.product .jet-wishlist-button__container,
.raven-wc-products-custom ul.products li.product.product .jet-wishlist-button__container {
  display: block;
  position: absolute;
  top: 4px;
  right: 4px;
  /* 12, not 3. Raven lays a .raven-product-image-overlay across every card image at z-index 10,
     a 15% tan tint, and at z-index 3 the heart was painted correctly and then covered by it:
     the element measured 44x44 in the right place and the screenshot showed bare cream.
     elementFromPoint on its own centre is what named the culprit. */
  z-index: 12;
  margin: 0;
}

ul.products li.product .jet-wishlist-button__link {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  padding: 0;
  overflow: visible;
  background: none;
  border: 0;
}

/* the plugin's two coloured backing planes are not wanted on an image */
ul.products li.product .jet-wishlist-button__plane { display: none; }

ul.products li.product .jet-wishlist-button__state {
  position: static;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
}
ul.products li.product .jet-wishlist-button__state-added { display: none; }

/* The !important here is not laziness, it is the only thing that works. Jupiter X ships
       .jet-wishlist-button__link.added-to-wishlist .jet-wishlist-button__state-normal
           { display: flex !important }
   so a saved product painted BOTH hearts, outline and filled, side by side, spilling out of the
   44px box and past the right edge of the card. It looked like a broken sprite. An important
   declaration can only be beaten by another important one, and this selector is the more
   specific of the two, so it wins cleanly rather than by luck of source order.

   It was invisible in the first round of testing because the check only asked whether the FILLED
   heart had appeared. It had. Nobody asked whether the outline one had gone. */
ul.products li.product .jet-wishlist-button__link.added-to-wishlist .jet-wishlist-button__state-normal { display: none !important; }
ul.products li.product .jet-wishlist-button__link.added-to-wishlist .jet-wishlist-button__state-added { display: flex !important; }

/* The words stay in the page for a screen reader, which is what tells somebody what the heart
   does. They are taken out of sight, not out of the accessibility tree. */
ul.products li.product .jet-wishlist-button__label {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

ul.products li.product .jet-wishlist-button__state::before {
  content: "";
  display: block;
  width: 20px;
  height: 20px;
  background: center / contain no-repeat url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 572 504'%3E%3Cpath d='M280.9,66.2l5.1,5.5,5.1-5.5C357.1-3.6,466.1,4.6,522,83.6c49.6,70.2,37.8,169.5-26.9,224.3l-209.2,177.4-209.2-177.4C12.2,253.1.3,153.8,50,83.6,105.9,4.6,214.9-3.6,280.9,66.2Z' fill='none' stroke='%2314130F' stroke-width='38' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}
ul.products li.product .jet-wishlist-button__state-added::before {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 572 504'%3E%3Cpath d='M280.9,66.2l5.1,5.5,5.1-5.5C357.1-3.6,466.1,4.6,522,83.6c49.6,70.2,37.8,169.5-26.9,224.3l-209.2,177.4-209.2-177.4C12.2,253.1.3,153.8,50,83.6,105.9,4.6,214.9-3.6,280.9,66.2Z' fill='%2314130F' stroke='%2314130F' stroke-width='38' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}

ul.products li.product .jet-wishlist-button__link:focus-visible {
  outline: 2px solid var(--zg-ink);
  outline-offset: 2px;
}
@media (hover: hover) {
  ul.products li.product .jet-wishlist-button__link:hover .jet-wishlist-button__state::before { opacity: .6; }
}

/* ---------------------------------------------------------------------------
   147. FROM THE JOURNAL, AT THE FOOT OF THE HOMEPAGE
   ---------------------------------------------------------------------------
   Three pieces, printed on the same hook as the letter and one step above it, so the page ends
   with something to read and then somewhere to leave an address. Three columns on a desktop, one
   on a phone. No image: the journal's own pictures are not strong enough to carry a band, and
   three titles set properly are better than three thumbnails that are not.
   ------------------------------------------------------------------------ */

.zg-hj {
  border-top: 1px solid var(--zg-rule);
  background: var(--zg-cream);
  padding: clamp(2.4rem, 4.5vw, 3.8rem) 20px 0;
}

.zg-hj__inner { max-width: 1120px; margin: 0 auto; }

.zg-hj__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: clamp(1.2rem, 2.4vw, 2rem);
}

.zg-hj__h {
  font-family: FreightTextPro, Georgia, "Times New Roman", serif;
  font-weight: var(--zg-fw-head);
  font-size: var(--zg-fs-h2);
  line-height: var(--zg-lh-h2);
  color: var(--zg-ink);
  margin: 0;
}

.zg-hj__all {
  font-size: var(--zg-fs-small);
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--zg-ink);
  text-decoration: underline;
  text-underline-offset: .2em;
  white-space: nowrap;
  padding: 10px 0;
}

.zg-hj__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(20px, 3vw, 40px);
}
@media (max-width: 860px) {
  .zg-hj__list { grid-template-columns: minmax(0, 1fr); gap: 0; }
  .zg-hj__item + .zg-hj__item { border-top: 1px solid var(--zg-rule); }
}

.zg-hj__link {
  display: block;
  padding: 0 0 14px;
  text-decoration: none;
  color: inherit;
}
@media (max-width: 860px) { .zg-hj__link { padding: 16px 0; } }
.zg-hj__link:focus-visible { outline: 2px solid var(--zg-ink); outline-offset: 3px; }

.zg-hj__date {
  display: block;
  font-size: var(--zg-fs-label);
  line-height: var(--zg-lh-label);
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--zg-muted);
  margin-bottom: .6em;
}

.zg-hj__title {
  display: block;
  font-family: FreightTextPro, Georgia, "Times New Roman", serif;
  font-weight: var(--zg-fw-head);
  font-size: var(--zg-fs-h3);
  line-height: var(--zg-lh-h3);
  color: var(--zg-ink);
  margin-bottom: .45em;
  text-decoration: underline;
  text-decoration-color: transparent;
  text-underline-offset: .16em;
  transition: text-decoration-color 160ms var(--zg-ease);
}
@media (hover: hover) {
  .zg-hj__link:hover .zg-hj__title { text-decoration-color: currentColor; }
}

.zg-hj__excerpt {
  display: block;
  font-size: var(--zg-fs-small);
  line-height: var(--zg-lh-small);
  color: var(--zg-muted);
}

/* ---------------------------------------------------------------------------
   148. THE GIFT CARD'S IMAGE IS A DESIGN, NOT A PHOTOGRAPH
   ---------------------------------------------------------------------------
   Raven lays .raven-product-image-overlay across every product image, a tan wash at 15 per cent.
   On a photograph of a bottle it is a warming filter and it is meant. On the gift card it tints
   the card's own cream: measured rgb(238,228,212) inside the card against rgb(245,243,235) on the
   page beside it, which is exactly #F5F3EB under that wash. The card looked like it was printed
   on different paper from the site it lives on.

   The same overlay is the one that hid the wishlist heart in section 146. It is left alone
   everywhere except here, where the image is a piece of house design rather than a photograph.
   ------------------------------------------------------------------------ */

/* The wash is NOT the .raven-product-image-overlay element that hid the heart on the grids. On
   the single product page it is a ::before on the gallery item, rgb(207,142,86) at 0.15, which is
   why a rule written against the overlay class changed nothing and the measurement still came
   back tinted. Found with getComputedStyle(el, '::before') after elementFromPoint and every
   ancestor background had come back clean. */
body.postid-40419 li.jupiterx-product-gallery-stack-item::before,
body.product_cat-gift-card li.jupiterx-product-gallery-stack-item::before,
body.postid-40419 .raven-product-image-overlay,
body.product_cat-gift-card .raven-product-image-overlay {
  display: none;
}

/* ---------------------------------------------------------------------------
   149. CHOOSE YOUR OWN AMOUNT
   ---------------------------------------------------------------------------
   A second, smaller way to buy the same thing, sitting under the four fixed amounts. It is
   deliberately quieter than the Add to cart above it: the denominations are the path most people
   want, and this is for the person who has a number in mind already.
   ------------------------------------------------------------------------ */

.zg-gcc {
  margin-top: 1.4rem;
  padding-top: 1.2rem;
  border-top: 1px solid var(--zg-rule);
}

.zg-gcc__label {
  display: block;
  font-size: var(--zg-fs-label);
  line-height: var(--zg-lh-label);
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--zg-muted);
  margin-bottom: .8em;
}

.zg-gcc__row { display: flex; align-items: stretch; gap: 8px; flex-wrap: wrap; }

.zg-gcc__input {
  flex: 0 1 150px;
  min-width: 0;
  min-height: 44px;
  padding: 10px 12px;
  font-family: Avenir, "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-size: var(--zg-fs-body);
  color: var(--zg-ink);
  background: transparent;
  border: 1px solid var(--zg-rule);
  border-radius: 0;
}
.zg-gcc__input::placeholder { color: var(--zg-muted); opacity: 1; }

.zg-gcc__cur {
  display: flex;
  align-items: center;
  font-size: var(--zg-fs-small);
  letter-spacing: .12em;
  color: var(--zg-muted);
  margin-right: 4px;
}

.zg-gcc__submit {
  min-height: 44px;
  padding: 10px 22px;
  font-family: Avenir, "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-size: var(--zg-fs-small);
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--zg-ink);
  background: transparent;
  border: 1px solid var(--zg-ink);
  border-radius: 0;
  cursor: pointer;
  transition: background 140ms var(--zg-ease), color 140ms var(--zg-ease);
}
.zg-gcc__submit:hover { background: var(--zg-ink); color: var(--zg-cream); }

/* The theme styles every button black, and at one class deep this one lost: ink text on a black
   ground, which is unreadable rather than merely wrong. Three classes of its own beat it without
   an !important, and the input is pinned the same way because the theme paints inputs white while
   the rest of the page is cream. */
.zg-gcc .zg-gcc__form .zg-gcc__submit {
  background: transparent;
  color: var(--zg-ink);
  border: 1px solid var(--zg-ink);
}
.zg-gcc .zg-gcc__form .zg-gcc__submit:hover {
  background: var(--zg-ink);
  color: var(--zg-cream);
}
.zg-gcc .zg-gcc__form .zg-gcc__input {
  background: transparent;
  border: 1px solid var(--zg-rule);
  color: var(--zg-ink);
}
.zg-gcc__input:focus-visible,
.zg-gcc__submit:focus-visible { outline: 2px solid var(--zg-ink); outline-offset: 2px; }

.zg-gcc__note {
  margin: .9rem 0 0;
  font-size: var(--zg-fs-label);
  line-height: 1.6;
  color: var(--zg-muted);
  max-width: 46ch;
}

/* The single gift card row in the totals, and what is left on the card under it. */
.zg-gc-left th, .zg-gc-left td { color: var(--zg-muted); font-size: var(--zg-fs-small); }

/* ---------------------------------------------------------------------------
   150. THE GIFT CARD IN A BASKET
   ---------------------------------------------------------------------------
   The checkout draws each line's thumbnail in a bordered, light box sized for a bottle shot. A
   card is 1.41 wide to 1 tall and transparent, so it landed small in the middle of a white frame
   with the frame reading as part of the product. The box goes and the card is fitted rather than
   cropped, at both widths.
   ------------------------------------------------------------------------ */

.wfacp_cart_item img[src*="gift-card"],
.wfacp-order-summary img[src*="gift-card"],
.fkcart-item img[src*="gift-card"],
img.zg-gc-thumb {
  object-fit: contain;
  background: transparent;
  border: 0;
  box-shadow: none;
  mix-blend-mode: normal;
}

/* the frame the theme draws around a line thumbnail */
.wfacp_cart_item:has(img[src*="gift-card"]) .wfacp_product_image,
.wfacp-order-summary li:has(img[src*="gift-card"]) .wfacp_product_image,
.fkcart-item:has(img[src*="gift-card"]) .fkcart-item-thumbnail {
  background: transparent;
  border: 0;
  padding: 0;
}

/* ---------------------------------------------------------------------------
   151. THE CARD ON ITS OWN PAGE
   ---------------------------------------------------------------------------
   The artwork is now the card's own shape rather than a square, which took roughly a fifth of the
   height out of the block and lifted the card up the page on its own. This stops the gallery
   stretching it back out and keeps the two columns starting at the same height.
   ------------------------------------------------------------------------ */

body.postid-40419 .raven-product-gallery-stack-wrapper,
body.product_cat-gift-card .raven-product-gallery-stack-wrapper {
  align-self: start;
}

body.postid-40419 img.raven-product-gallery-stack-image,
body.product_cat-gift-card img.raven-product-gallery-stack-image {
  object-fit: contain;
  object-position: center top;
  background: transparent;
}

@media (max-width: 1024px) {
  /* On a phone the card is the first thing under the header, so it gets a little air above it
     and none of the square block's leftover space below. */
  body.postid-40419 .raven-product-gallery-wrapper,
  body.product_cat-gift-card .raven-product-gallery-wrapper {
    margin-bottom: 1.2rem;
  }
}

/* ---------------------------------------------------------------------------
   152. THE HEART IS TOO LOUD ON A PHONE
   ---------------------------------------------------------------------------
   The 20px icon was chosen against a 263px desktop card. On a phone the card is 141px, so the
   same heart is half again as big relative to what it sits on, and at top/right 4px it floats
   away from the corner instead of tucking into it. The icon shrinks and moves tight; the tap
   target stays 44px, because that is invisible and is what fingers need.
   ------------------------------------------------------------------------ */

@media (max-width: 767px) {
  .jupiterx-main ul.products li.product.product .jet-wishlist-button__container,
  .raven-wc-products-custom ul.products li.product.product .jet-wishlist-button__container {
    top: 0;
    right: 0;
  }

  ul.products li.product .jet-wishlist-button__state,
  ul.products li.product .jet-wishlist-button__state::before {
    width: 15px;
    height: 15px;
  }

  /* The 44px box stays, so the target is still a target. The icon is simply smaller inside it
     and pushed toward the corner it belongs in. */
  ul.products li.product .jet-wishlist-button__link {
    align-items: flex-start;
    justify-content: flex-end;
    padding: 9px 9px 0 0;
  }
}

/* ---------------------------------------------------------------------------
   153. THE MENU ON A PHONE IS 143 PIXELS WIDE
   ---------------------------------------------------------------------------
   There is no mobile menu on this site. JetMenu's separate mobile widget is not
   in use anywhere: on a phone the header renders the same desktop mega menu,
   in its push layout, inside the header column that holds the burger. That
   column is 142.5px wide on a 390px screen, so the whole menu inherits it. Every
   label wraps, "Discovery Box" breaks over two lines, and the mega panel inside
   it collapses to a strip roughly 100px across, which is why the panels looked
   like a column of pictures with no words.

   Measured before: menu container 143px, panel 102.5px, tile 31px.

   The header row itself must keep its three columns, so the column cannot simply
   be widened. Instead the menu breaks out of it when it opens. position: fixed
   takes it out of the column's flow entirely and pins it to the viewport under
   the header, which is what a drawer on a phone should be anyway. If a sticky
   header ever puts a transform on an ancestor, the containing block becomes the
   header, which is full width and starts at the left edge, so the result is the
   same either way.

   It touches nothing outside a phone-width viewport, and nothing on cart,
   checkout or account, which have no mega menu on any screen.
   ------------------------------------------------------------------------ */
@media (max-width: 767px) {

  .jet-mega-menu-container {
    position: fixed !important;
    left: 0 !important;
    right: 0 !important;
    top: var(--zg-header-h, 92px) !important;
    width: 100vw !important;
    max-width: 100vw !important;
    max-height: calc(100vh - var(--zg-header-h, 92px));
    overflow-y: auto;
    overscroll-behavior: contain;
    background-color: var(--zg-cream);
    z-index: 998;
  }

  /* Closed, it must take no space and catch no taps. JetMenu leaves the
     container in the document at zero height rather than removing it. */
  .jet-mega-menu-container:not(.jet-mega-menu-container--open) {
    max-height: 0;
    overflow: hidden;
    pointer-events: none;
  }

  .jet-mega-menu-list {
    width: 100%;
    padding: 4px 20px 28px;
  }

  .jet-mega-menu-item__link {
    padding-top: 14px;
    padding-bottom: 14px;
  }

  /* The panel inside it: full width, with the same gutter as the list. */
  .jet-mega-menu-mega-container,
  .jet-mega-menu-mega-container__inner {
    width: 100% !important;
    max-width: 100% !important;
    top: auto !important;
    box-shadow: none;
  }

  .jet-mega-menu-mega-container__inner {
    padding-left: 0;
    padding-right: 0;
  }

  /* The five tiles read as three across and two, at a size worth tapping. */
  .jet-mega-menu-mega-container .elementor-widget-image img {
    width: 100%;
    height: auto;
  }
}

/* The five tiles, on a phone. The captions are set at 22px for the desktop panel,
   where a tile is 175px wide; at 105px they clip and "Discovery Box" takes two
   lines while its neighbours take one, which is what pulled the row out of line.
   The column headings above them keep their own size, which is why they carry a
   class of their own rather than sharing one selector. */
@media (max-width: 767px) {

  .jet-mega-menu-mega-container .zg-mega-tile {
    align-self: flex-start;
  }

  .jet-mega-menu-mega-container .zg-mega-tile .elementor-heading-title {
    font-size: 11px;
    line-height: 1.35;
    letter-spacing: 0.1em;
    word-break: normal;
    overflow-wrap: anywhere;
  }

  /* Two lines of caption on one tile and one on the next must not stagger the row. */
  .jet-mega-menu-mega-container .zg-mega-tile .elementor-widget-heading {
    min-height: 2.7em;
  }

  .jet-mega-menu-mega-container .zg-mega-colhead .elementor-heading-title {
    font-size: 12px;
    letter-spacing: 0.22em;
    text-transform: uppercase;
    opacity: 0.62;
  }
}

/* The captions again, this time by what they are not. Custom classes do not reach
   container elements here, so the tile captions are addressed as every heading in
   the panel that is not one of the two column headings. Elementor sets the 22px on
   a per-element selector of equal weight and loads after this file, so the override
   has to be marked. */
@media (max-width: 767px) {

  .jet-mega-menu-mega-container .elementor-widget-heading:not(.zg-mega-colhead) .elementor-heading-title {
    font-size: 11px !important;
    line-height: 1.35 !important;
    letter-spacing: 0.1em;
  }

  .jet-mega-menu-mega-container .elementor-widget-heading:not(.zg-mega-colhead) {
    min-height: 2.8em;
  }

  .jet-mega-menu-mega-container .zg-mega-colhead .elementor-heading-title {
    font-size: 12px !important;
    letter-spacing: 0.22em;
    text-transform: uppercase;
    opacity: 0.62;
  }
}

/* ---------------------------------------------------------------------------
   154. THE REVIEW HEADING IS A PIXEL OFF THE SCALE
   ---------------------------------------------------------------------------
   The house sizes are 17, 19, 26 and 46. "Add a Review" renders at 25px on
   every product page that accepts one: close enough to look right, far enough
   to fail the type sweep on every run, and the only heading on the shop that
   sits off the scale.

   There is already a rule for this heading a few hundred lines up, setting it
   to --zg-fs-h2. It loses. The winner is an Elementor per-element rule from the
   single-product template,

     .elementor-20826 .elementor-element.elementor-element-09a2835
       .jupiterx-product-review-header { font-size: 25px }

   which is three classes deep and printed after this stylesheet. That is the
   usual shape of a losing override here: same weight, later in the cascade.
   Marking the declaration is what settles it, and it is marked on font-size
   alone so the template still owns colour, family and spacing.
   ------------------------------------------------------------------------ */
main.jupiterx-main h3.jupiterx-product-review-header,
.jupiterx-product-review-widget-wrapper .jupiterx-product-review-form-wrapper h3.jupiterx-product-review-header {
  font-size: var(--zg-fs-h2, 26px) !important;
}

/* ---------------------------------------------------------------------------
   155. THE HEART IS SIZED AGAINST THE CARD, NOT AGAINST THE WINDOW
   ---------------------------------------------------------------------------
   Sections 146 and 152 set the glyph in pixels and then changed it at one
   breakpoint. That works on the page the number was chosen against and drifts
   everywhere else, because the cards are not all the same size at the same
   window width. Measured across the site:

     archive @390     card 165px   glyph 15px   9.1% of the card
     homepage @390    card 141px   glyph 15px   10.6%
     homepage @360    card 126px   glyph 15px   11.9%
     archive @768     card 227px   glyph 20px   8.8%
     archive @767     card 354px   glyph 15px   4.2%

   So the same heart reads nearly three times louder on the tightest card than
   on the loosest, and at the 767/768 line it grows a third at exactly the width
   where the card shrinks by a third. That is what the owner was seeing on the
   homepage band: not a heart that is too big, a heart that is too big THERE.

   Tying the glyph to the card removes the question. 9% of the card reproduces
   today's accepted 15px on the archive at 390 almost exactly, so the context
   that looks right stays as it is and the others come to meet it. The floor and
   ceiling keep it sane on a 126px card and on a 354px one.

   The tap box is capped the same way on phones. At 360px the invisible 44px
   square was eating 12.1% of the homepage card image, so taps aimed at the
   bottle opened the wishlist. 28% of the card gives 35px there, which is still
   far above the 24px WCAG 2.5.8 minimum, and leaves the archive at 44px.

   This supersedes the fixed sizes in 146 and the 15px block in 152, which are
   left in place so the reasoning behind them survives; the cascade settles it.
   ------------------------------------------------------------------------ */

ul.products li.product {
  container-type: inline-size;
}

ul.products li.product .jet-wishlist-button__state,
ul.products li.product .jet-wishlist-button__state::before {
  width: clamp(12px, 9cqi, 20px);
  height: clamp(12px, 9cqi, 20px);
}

@media (max-width: 767px) {
  ul.products li.product .jet-wishlist-button__link {
    width: clamp(34px, 28cqi, 44px);
    height: clamp(34px, 28cqi, 44px);
  }
}

/* A browser without container queries keeps exactly what it had before. */
@supports not (container-type: inline-size) {
  ul.products li.product .jet-wishlist-button__state,
  ul.products li.product .jet-wishlist-button__state::before {
    width: 20px;
    height: 20px;
  }
  @media (max-width: 767px) {
    ul.products li.product .jet-wishlist-button__state,
    ul.products li.product .jet-wishlist-button__state::before {
      width: 15px;
      height: 15px;
    }
  }
}

/* ---------------------------------------------------------------------------
   156. NO HEART ON THE HOMEPAGE BAND
   ---------------------------------------------------------------------------
   This restores a decision the site had already made and section 146 undid by
   accident.

   Appearance > Customise carries `.swiper-slide .jet-wishlist-button__container
   { display: none }`, which is an explicit statement that cards inside a
   carousel get no heart. Section 146 had to beat Jupiter X's own display:none
   on loop cards, and used a doubled-class selector to do it. That selector also
   outranks the customizer rule, which nothing in 146 mentions and nobody
   intended: computed, 0,5,2 against 0,2,0. So the homepage "Find your
   signature" band started showing five hearts that the shop's own stylesheet
   says should not be there.

   The owner has confirmed which way it should go: no heart on the band.

   Excluding the carousel here rather than deleting the customizer rule keeps
   the reasoning in one place, and leaves the archives, the related products row
   and the shop page exactly as they are. The saved state still shows on those,
   and the band remains what it was meant to be: five photographs and their
   names, nothing hovering over them.
   ------------------------------------------------------------------------ */

.jupiterx-main ul.products li.product.product.swiper-slide .jet-wishlist-button__container,
.raven-wc-products-custom ul.products li.product.product.swiper-slide .jet-wishlist-button__container,
.elementor-widget-raven-products-carousel ul.products li.product .jet-wishlist-button__container {
  display: none;
}

/* ---------------------------------------------------------------------------
   157. GIFT BAND AT THE FOOT OF THE BOTTLE GRIDS
   ---------------------------------------------------------------------------
   Markup from mu-plugins/collection-gift-band.php, on the Classic and Exclusive
   archives only.

   It deliberately does NOT look like the sample band at the top of the same
   page. That one is sand, horizontal, one line and one button: an offer called
   out. This is cream, quiet, and shaped like the homepage "choosing" band,
   because it is the same kind of thing, a small set of options to read rather
   than a claim to notice. Two loud bands on one archive would compete, and the
   free samples offer is the one that should win at the top of the page.

   The band is hoisted out of the products grid. `woocommerce_after_shop_loop`
   fires inside the archive's own container, and on some of the theme's layouts
   that container is the grid itself, so without the full-width span a card
   would be dealt into the last row like a sixteenth product. That is the exact
   mistake this band exists to avoid, so it is guarded in CSS as well as in
   where the markup is placed.

   Two columns at every width that can hold them, one below 640px. There are
   only ever two cards, so no auto-fit is needed and a fixed pair keeps them the
   same width whatever the copy does.
   ------------------------------------------------------------------------ */

.zg-gift-band {
  grid-column: 1 / -1;
  display: block;
  clear: both;
  width: 100%;
  box-sizing: border-box;
  margin: clamp(2.5rem, 5vw, 4rem) 0 0;
  padding: clamp(2rem, 4vw, 3rem) clamp(1.25rem, 3vw, 2.5rem);
  background: var(--zg-cream);
  border-top: 1px solid var(--zg-rule);
}

.zg-gift-band__eyebrow {
  font-size: 11px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--zg-muted);
  margin: 0 0 10px;
}

.zg-gift-band__h {
  font-family: FreightTextPro, Georgia, 'Times New Roman', serif;
  font-size: clamp(22px, 2.4vw, 26px);
  font-weight: 500;
  line-height: 1.25;
  color: var(--zg-ink);
  margin: 0 0 8px;
}

.zg-gift-band__intro {
  font-size: 15px;
  line-height: 1.6;
  color: #4A473F;
  margin: 0 0 clamp(1.5rem, 3vw, 2.25rem);
  max-width: 46ch;
}

.zg-gift-band__grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(1rem, 2.5vw, 2rem);
}

.zg-gift-band__card {
  display: block;
  padding: 20px 22px;
  background: var(--zg-ground);
  border-radius: 2px;
  color: var(--zg-ink);
  text-decoration: none;
  transition: background-color 160ms var(--zg-ease);
}

.zg-gift-band__name {
  display: block;
  font-family: FreightTextPro, Georgia, 'Times New Roman', serif;
  font-size: 19px;
  font-weight: 500;
  line-height: 1.3;
  margin: 0 0 8px;
}

.zg-gift-band__line {
  display: block;
  font-size: 14px;
  line-height: 1.7;
  /* 4A473F on the EFEDE4 ground measures 10.4:1, well past AA. The lighter
     6E6A5F used for house facts elsewhere is not used here: this copy is the
     point of the band, not a footnote under a product name. */
  color: #4A473F;
}

.zg-gift-band__price {
  display: block;
  margin-top: 12px;
  font-size: 12px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--zg-ink);
}

/* wc_price() wraps the figure in its own markup, which carries the theme's
   product-tile price styling. Pull it back to this band's size and colour so it
   does not arrive as a large red number. */
.zg-gift-band__price .woocommerce-Price-amount,
.zg-gift-band__price bdi,
.zg-gift-band__price .woocommerce-Price-currencySymbol {
  font-size: 12px;
  letter-spacing: 0.1em;
  color: var(--zg-ink);
  font-weight: inherit;
}

@media (hover: hover) {
  .zg-gift-band__card:hover { background: var(--zg-sand); }
}

.zg-gift-band__card:focus-visible {
  outline: 2px solid var(--zg-ink);
  outline-offset: 3px;
}

@media (max-width: 640px) {
  .zg-gift-band__grid { grid-template-columns: 1fr; }
}

/* --- 157a. the heading, at a specificity that actually wins --------------
   Measured on the live page after the section above shipped: the heading came
   out 24px at weight 900, not the 26px/500 written here.

   Two single-class rules were beating it, both at 0,1,1 against this file's
   0,1,0:

     .elementor-kit-19984 h2   font-weight: 900   (Elementor's global kit)
     .woocommerce h2           font-size: 1.5rem  (WooCommerce's own sheet)

   This is the trap recorded from the homepage audit, and it is invisible
   without checking the computed value: the declaration is present, spelled
   correctly, in a stylesheet that loads, and still does nothing. Weight 900 is
   the black cut of FreightTextPro. On a band that is meant to be quiet it read
   as a shout, and against the rest of the type on the page, where headings sit
   at 500, it looked like a different site.

   Adding the element to the selector takes this to 0,2,1 without an
   !important, which keeps the rule beatable by anything more specific later
   rather than ending the argument permanently.
   ---------------------------------------------------------------------- */

.zg-gift-band h2.zg-gift-band__h {
  font-size: clamp(22px, 2.6vw, 26px);
  font-weight: 500;
  line-height: 1.25;
}

/* --- 157b. the heading again, and the lead card -------------------------
   157a did not work either, and the reason is worth writing down because it
   will happen again on this site.

   Measured, not reasoned about. Injecting each candidate selector into the
   live page and reading the computed value back gave this:

     .zg-gift-band__h                        no effect
     h2.zg-gift-band__h                      no effect
     .zg-gift-band h2.zg-gift-band__h        no effect      <- 157a
     aside.zg-gift-band h2.zg-gift-band__h   WINS
     body .zg-gift-band h2.zg-gift-band__h   WINS

   The rule being beaten is `.woocommerce h2, .woocommerce-page h2
   { font-size: 1.5rem }` in the theme's combined sheet, which reads as 0,1,1
   and carries no !important that the CSSOM will admit to. On paper 157a should
   have won and it did not. Disabling that one sheet moves the heading to 26px
   on its own, so the sheet is the source whatever the arithmetic says.

   Rather than reach for !important, which ends the argument for everybody
   downstream, this takes the selector one step past the observed threshold.
   The lesson for the next override here is the one already written on the
   cascade elsewhere in this file: read the computed value back off the live
   page. Counting selectors is not evidence.
   ---------------------------------------------------------------------- */

aside.zg-gift-band h2.zg-gift-band__h {
  font-size: clamp(22px, 2.6vw, 26px);
  font-weight: 500;
  line-height: 1.25;
}

aside.zg-gift-band p.zg-gift-band__intro {
  /* Longer copy now, so it gets the reading measure the rest of the site uses
     rather than running the full width of the band. */
  max-width: 62ch;
  font-size: 15px;
  line-height: 1.7;
}

/* --- the lead card ------------------------------------------------------
   The gift card answers the doubt the heading names, so it is first in the
   source and it is the one with weight. Sand against the quieter ground is
   the same pairing the sample band at the top of this page already uses, so
   the page keeps one visual language instead of inventing a second.

   It is a difference in emphasis, not in kind: both remain plain cards with a
   name, a sentence and a price, and neither shouts. A button or a badge here
   would turn a suggestion into a pitch.
   ---------------------------------------------------------------------- */

.zg-gift-band__card--lead {
  background: var(--zg-sand);
}

@media (hover: hover) {
  .zg-gift-band__card--lead:hover { background: #DFD4B6; }
}

/* ---------------------------------------------------------------------------
   158. THE PRODUCT PAGE JOINS THE TYPE SCALE
   ---------------------------------------------------------------------------
   Section 128 set the standard and the site-wide sweep passed 54 of 54 pages.
   It passed because prices, buttons, swatches, breadcrumbs, stock lines and
   card titles were classed as "chrome" and excluded. The product page is
   almost entirely chrome, so almost none of it was ever measured.

   Measured on the live page, 2026-09-22, 1440 wide, header and footer
   excluded: TWENTY-NINE distinct type styles on one page. Among them:

     10.5px   breadcrumb          = 0.75em of 14
     10.56px  note labels         = 0.88em of 12
     12.88px  "8 in stock"        = 0.92em of 14
     26px     related-card titles = 2x the same card on the collection grid

   None of those numbers was chosen. They are em multipliers compounding down
   a nest of widgets, which is why they are fractional: nobody types 12.88px.
   Eight different uppercase trackings (1.32, 1.47, 1.4784, 1.8, 1.98, 2, 2.4
   and 3.12px), three near-blacks (#000, #14130F, #111) and the same typeface
   under two names, Avenir and Avenir-Regular.

   The owner's word for it was "mixed fonts and styles", and read at 10.5px,
   "really hard to read". Both are accurate.

   WHAT THIS DOES, AND WHAT IT DELIBERATELY DOES NOT DO
   ---------------------------------------------------
   It puts each of those on the nearest step of the scale that already exists,
   sets one tracking for uppercase labels, and reduces three near-blacks to the
   two named inks. It changes no colour, spacing, border or layout, and it adds
   no new step to the scale. Nothing here is a new design decision. Where a
   token lands on the same pixel size the element already had, that is the
   point: the value stops being an accident.

   THE ONE VISIBLE CHANGE, stated plainly rather than slipped in: the product
   title drops from 57.6px to the scale's h1, 46px at this width. 57.6 is above
   even the display step used for homepage band headlines, so the product name
   was the largest type anywhere on the site. Every other h1 is 46.

   SPECIFICITY. Every rule here carries an element as well as its classes.
   `.elementor-kit-19984 h2` and `.woocommerce h2` both read as 0,1,1 and both
   beat a single class, and a rule that loses silently is worse than no rule.
   Checked by reading the computed value back off the live page, not by
   counting selectors, which has been wrong here before.
   ------------------------------------------------------------------------ */

/* --- the breadcrumb: 10.5px is below anything anyone should be asked to read */
body.single-product nav.woocommerce-breadcrumb,
body.single-product nav.woocommerce-breadcrumb a {
  font-size: var(--zg-fs-label);
  letter-spacing: 0.14em;
  color: var(--zg-muted);
}

/* --- the eyebrow over the title. Was 0.20em; every other eyebrow is 0.18em. */
body.single-product p.zg-product-eyebrow {
  font-size: var(--zg-fs-label);
  font-weight: 500;
  letter-spacing: 0.18em;
  color: var(--zg-muted);
}

/* --- the product name.
   Weight 400 is the Audo decision already in force on every other h1
   (section 130); it is restated here only so this rule cannot leave the
   heading on whatever weight the theme would otherwise hand it. */
body.single-product h1.elementor-heading-title {
  font-size: var(--zg-fs-h1);
  font-weight: 400;
  letter-spacing: -0.012em;
  line-height: 1.1;
  color: var(--zg-ink);
}

/* --- the standfirst under it. Already 19px, which is the lead step exactly,
   but declared as a raw number and rendered in pure black, one of the three
   near-blacks. Takes the token and the warm copy ink the rest of the site
   uses for running text. */
body.single-product .elementor-element-4056ed2 .elementor-widget-container,
body.single-product .elementor-element-4056ed2 .elementor-widget-container p {
  font-size: var(--zg-fs-lead);
  line-height: 1.55;
  color: #2F2B23;
}

/* --- the seven feature lines. Kept at the small step, which is the size they
   already render at, so the two-column block does not start wrapping. Only the
   pure black moves. */
body.single-product .jet-listing-dynamic-repeater__item span {
  font-size: var(--zg-fs-small);
  color: #2F2B23;
}

/* --- "SIZE". The only weight 700 on the page; everything else that is
   uppercase and tracked is 500. */
body.single-product table.variations th.label label {
  font-size: var(--zg-fs-label);
  font-weight: 500;
  letter-spacing: 0.18em;
  color: var(--zg-muted);
}

/* --- the 30ml / 50ml pills.
   The brand serif here is deliberate and stays. The 500 on the selected pill
   against 400 on the other is a STATE, not drift, so both weights stay too:
   only the size and the tracking are normalised. */
body.single-product .pv-pills .pill label {
  font-size: var(--zg-fs-label);
  letter-spacing: 0.16em;
}

/* --- the price. Size is chrome and stays; `text-transform: uppercase` on a
   number does nothing and the pure black becomes the named ink. */
body.single-product .elementor-element-a49e890 .elementor-heading-title .woocommerce-Price-amount,
body.single-product .elementor-element-a49e890 .elementor-heading-title .woocommerce-Price-currencySymbol {
  color: var(--zg-ink);
}

/* --- "8 in stock": 12.88px with 0.5152px of tracking, both compounded. */
body.single-product p.stock {
  font-size: var(--zg-fs-small);
  letter-spacing: normal;
}

/* --- the two label-shaped lines in the reassurance stack under the button,
   and the button itself. One tracking between them instead of three. */
body.single-product button.single_add_to_cart_button,
body.single-product .zg-retn b,
body.single-product p.zg-try__read {
  font-size: var(--zg-fs-label);
  font-weight: 500;
  letter-spacing: 0.18em;
}
body.single-product .zg-retn b,
body.single-product p.zg-try__read {
  color: var(--zg-muted);
}

/* --- THE ONE REAL BUG, not a matter of taste.
   The related-products cards render their titles at 26px with 3.12px of
   tracking. The identical card on the Classic and Exclusive grids renders at
   13px with 1.56px. Exactly double, both numbers, which is an em factor
   applied twice and not a decision anyone made. A perfume name set at 26px in
   tracked uppercase sans, directly below the same name set at 46px in the
   brand serif, is the single most jarring thing on the page.

   Pinned to the collection grid's values so the two surfaces agree. If the
   grid card is ever restyled, this is the other place to change. */
body.single-product ul.products h2.woocommerce-loop-product__title {
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 1.56px;
  line-height: 1.5;
}

/* --- the review block. Three more near-blacks and two more sizes. */
body.single-product h3.jupiterx-product-review-header {
  font-size: var(--zg-fs-h2);
  font-weight: 500;
  color: var(--zg-ink);
}
body.single-product .jupiterx-product-review-form h5 {
  font-size: var(--zg-fs-small);
  color: var(--zg-ink);
}
body.single-product .jx-product-review-secondary-text,
body.single-product label.jx-product-review-secondary-text {
  font-size: var(--zg-fs-small);
  color: var(--zg-muted);
}
body.single-product button.jupiterx-product-review-submit-new {
  font-size: var(--zg-fs-label);
  font-weight: 500;
  letter-spacing: 0.18em;
}

/* ---------------------------------------------------------------------------
   158a. THE SAME PASS, WITH THE CASCADE READ RATHER THAN ASSUMED
   ---------------------------------------------------------------------------
   Half of 158 landed and half did not. Reading the computed value back off the
   live page and listing every matching rule changed the diagnosis, so the
   corrections belong here with the reason attached rather than as a silent
   edit of the section above.

   THE 26px CARD TITLE WAS NOT AN EM FACTOR. I wrote in 158 that the related
   product cards were "exactly double" the collection grid and called it a
   compounding em. That reading was wrong, and the coincidence was a good one:
   13 to 26 and 1.56 to 3.12 really are both doubles.

   What actually wins is section 128's own rule:

       body.single-product main.jupiterx-main h2 { font-size: var(--zg-fs-h2) !important }

   A WooCommerce loop product title is an `h2`. So the type standard, doing
   exactly what it says, promotes every product card title on the page to a
   page-heading size. The standard is right about headings and wrong about this
   one element, which is a card label that happens to use a heading tag. That
   is a real gap in the standard, not drift on the page, and it is fixed by
   naming the exception rather than by weakening the h2 rule for everything.

   ON !important. This stylesheet already uses it heavily on this page, and a
   non-important rule cannot beat an important one at any specificity. Where it
   appears below it is because the declaration it has to beat is itself
   important, and each one says which. Nothing here uses it merely to win an
   argument it could have won on specificity.

   WHAT IS DELIBERATELY LEFT ALONE, and why, because "fix the fonts" is not a
   licence to restyle things somebody chose:

     * The product title at 57.6px. It is set by
       `.single-product main.jupiterx-main h1.elementor-heading-title
        { font-size: clamp(2.4rem, 4.2vw, 3.6rem) !important }`
       which is a specific, hand-written display size, not an accident. It sits
       above the scale's h1 (46px) and above even the display step (52px), so
       the product name is the largest type on the site. That may well be the
       intent on the one page whose whole job is to name a perfume. It is a
       design question, so it stays until the owner says otherwise.

     * The Add to cart label and the 30ml / 50ml pills at 11px. The label step
       is clamp(11px, ..., 12px): 11px is the bottom of that step, not outside
       it. Both are set on purpose and both are legible as tracked uppercase.
   ------------------------------------------------------------------------ */

/* --- A. the related product cards.
   Pinned to the values the identical card uses on the Classic and Exclusive
   grids, so the two surfaces finally agree. Important, because section 128's
   blanket h2 rule is important. */
body.single-product main.jupiterx-main ul.products h2.woocommerce-loop-product__title,
body.single-product main.jupiterx-main ul.products h2.raven-product-item-content {
  font-size: 13px !important;
  font-weight: 500 !important;
  letter-spacing: 1.56px !important;
  line-height: 1.5 !important;
}

/* --- B. "8 in stock" at 12.88px.
   `.woocommerce div.product p.stock { font-size: 0.92em }` was beating the
   site's own `.single-product p.stock { font-size: 12px }` on source order at
   equal specificity, and 0.92 of the inherited 14px is where the third decimal
   came from. Out-specified rather than made important, since neither is. */
body.single-product div.product p.stock,
body.single-product div.product p.stock.in-stock {
  font-size: var(--zg-fs-small);
  letter-spacing: normal;
}

/* --- C. the breadcrumb at 10.5px.
   Set deliberately as `.single-product .woocommerce-breadcrumb
   { font-size: 10.5px !important }`, so this has to be important to reach it.
   Deliberate or not, 10.5px is under the label step's floor and it is the line
   the owner meant by "really hard to read". Raised to the step, which is 12px
   at desktop and 11px on a phone. */
body.single-product nav.woocommerce-breadcrumb,
body.single-product nav.woocommerce-breadcrumb a,
body.single-product nav.woocommerce-breadcrumb span {
  font-size: var(--zg-fs-label) !important;
  letter-spacing: 0.14em;
  color: var(--zg-muted);
}

/* --- D. "SIZE" was the only weight 700 on the page, and pure black.
   `.woocommerce div.product form.cart .variations label` is (0,3,3), which is
   why the shorter selector in 158 lost. */
body.single-product div.product form.cart table.variations th.label label {
  font-weight: 500;
  letter-spacing: 0.18em;
  color: var(--zg-muted);
}

/* --- E. the review block's three stray inks: #000 on the heading, #111 on the
   sub-heading and #555 on the small print. The first two are near-blacks that
   exist nowhere else in the palette; the third is a grey that is not the
   muted token. Each of the rules being beaten is important, so these are. */
body.single-product main.jupiterx-main h3.jupiterx-product-review-header {
  color: var(--zg-ink) !important;
}
body.single-product main.jupiterx-main .jupiterx-product-review-form h5 {
  color: var(--zg-ink) !important;
  font-size: var(--zg-fs-small) !important;
}
body.single-product main.jupiterx-main .jx-product-review-secondary-text,
body.single-product main.jupiterx-main label.jx-product-review-secondary-text,
body.single-product main.jupiterx-main span.jx-product-review-secondary-text {
  color: var(--zg-muted) !important;
  font-size: var(--zg-fs-small) !important;
}

/* --- 158b. the "SIZE" label's weight, and an anomaly worth recording -------
   The colour in 158a reached this element. The weight and the tracking did
   not, and neither did an injected copy of the very rule that beats them,
   which should be impossible: same selector, later in the document, no
   inline style, one element, and it matches.

   The likely explanation is a limitation in how I was reading the cascade
   rather than anything strange in the CSS. The enumerator splits a rule's
   selectorText on commas, and this stylesheet contains `:is(...)` selectors
   whose internal commas that split destroys, so any important declaration
   inside one is invisible to it. Do not trust a "no rule matches" reading
   from that method again; it can only prove what it did find.

   So this is important and specific, and it was checked by reading the
   computed value back rather than by reasoning about it.

   Weight 700 was the only one on the page. Avenir here has 400, 500 and 700,
   so 700 is a real bold cut and "SIZE" was shouting next to a 500 eyebrow
   saying "EXCLUSIVE COLLECTION". */
body.single-product div.product form.cart table.variations th.label label,
body.single-product div.product form.cart .variations th.label label {
  font-weight: 500 !important;
  letter-spacing: 0.18em !important;
}

/* --- 158c. the last three pure blacks -------------------------------------
   Sweeping the page for `rgb(0,0,0)` after 158b left four elements. One is
   `label.screen-reader-text`, which is clipped to a zero-size rectangle and
   read only by assistive technology, so its colour is meaningless and it is
   left alone rather than given a cosmetic fix that nobody can see.

   The other three are real: the VARIATION price, which is a second price
   element beside the one 158 already caught and which only appears once a
   size is chosen, and the review form's "Alternative:" label. Pure black is
   not in this palette; the near-black is #14130F.

   The breadcrumb's grey is included here too. Its SIZE needed !important in
   158a and its colour did not get the same treatment, so it kept an older
   107,104,98 that is a shade off the muted token. Nobody would see it on its
   own; it is one more value that should not exist. */
body.single-product div.product .woocommerce-variation-price .woocommerce-Price-amount,
body.single-product div.product .woocommerce-variation-price .woocommerce-Price-amount bdi,
body.single-product div.product .woocommerce-variation-price .woocommerce-Price-currencySymbol {
  color: var(--zg-ink) !important;
}
body.single-product main.jupiterx-main .jupiterx-product-review-form label {
  color: var(--zg-ink);
}
body.single-product nav.woocommerce-breadcrumb,
body.single-product nav.woocommerce-breadcrumb a,
body.single-product nav.woocommerce-breadcrumb span {
  color: var(--zg-muted) !important;
}

/* --- 159. the gift card row under the buy block ---------------------------
   Markup from mu-plugins/product-gift-nudge.php, which carries the full
   reasoning. Rewritten 2026-09-23; what stood here before styled a paragraph
   called .zg-try__gift to look exactly like the four paragraphs around it,
   with this comment justifying it: "this is one more thing the page tells you
   while you are deciding, not a promotion wearing a different coat."

   Measured, that put it 5th of 5, at 15px under paragraphs of 17 and 19, in
   the same face, weight and colour, 465px below the button. The owner's
   verdict was that the gift card option was hidden, and he was right.

   The rule that was got wrong: matching the surrounding typography is correct
   for content that continues the same decision and wrong for content that
   offers a different one.

   WHAT THIS IS NOW. One outlined row, first child of .zg-try, so it lands
   directly under Add to cart.

   WHY OUTLINED AND NOT FILLED. It sits about 40px below a solid ink button.
   Anything filled here competes with the primary action, and an alternative
   that out-shouts the buy button costs more than it earns.

   WHY THE BORDER IS HEAVIER THAN EVERY OTHER RULE ON THE PAGE. The hairlines
   here are rgba(20,19,15,.12) and .14, which against cream measure 1.7:1 and
   below. That is fine for a divider and not fine for the boundary that tells
   somebody this is a control: WCAG 2.2 asks 3:1 of a UI component boundary.
   At .5 it measures 3.42:1 and passes. It is deliberately not the solid ink
   the button uses, so the two never read as equals.

   ONE TYPE SIZE, TWO WEIGHTS. Both lines take --zg-fs-small. The hierarchy is
   weight and colour, not size, because this page is carrying 31 distinct type
   styles already and a new step would make it 32.
   ======================================================================== */
body.single-product a.zg-giftrow {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 14px 18px;
  min-height: 44px;
  box-sizing: border-box;
  margin: 0 0 20px;
  border: 1px solid rgba(20, 19, 15, .5);
  border-radius: 2px;   /* the Add to cart button's radius, so they belong to one family */
  background: transparent;
  color: var(--zg-ink);
  text-decoration: none;
  transition: background-color 140ms var(--zg-ease);
}

/* The whole row is the anchor, so nothing inside it may draw its own underline
   or the row reads as a box with a link in it rather than as one target. */
body.single-product a.zg-giftrow,
body.single-product a.zg-giftrow:hover,
body.single-product a.zg-giftrow:focus {
  text-decoration: none;
}

body.single-product a.zg-giftrow:hover {
  background-color: rgba(20, 19, 15, .04);
}
body.single-product a.zg-giftrow:hover .zg-giftrow__go {
  transform: translateX(3px);
}

/* Keyboard users get the same affordance as the mouse. :focus-visible rather
   than :focus so a mouse click does not leave a ring behind it. */
body.single-product a.zg-giftrow:focus-visible {
  outline: 2px solid var(--zg-ink);
  outline-offset: 2px;
}

body.single-product .zg-giftrow__icon,
body.single-product .zg-giftrow__go {
  flex: 0 0 auto;
  color: var(--zg-ink);
}
body.single-product .zg-giftrow__go {
  transition: transform 140ms var(--zg-ease);
}

body.single-product .zg-giftrow__text {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  gap: 3px;
  min-width: 0;   /* or a long fragrance name pushes the chevron off the row */
}

body.single-product .zg-giftrow__q {
  font-size: var(--zg-fs-small);
  line-height: 1.3;
  font-weight: 500;
  color: var(--zg-ink);
}

body.single-product .zg-giftrow__a {
  font-size: var(--zg-fs-small);
  line-height: 1.4;
  font-weight: 400;
  color: var(--zg-muted);   /* 4.86:1 on cream */
}

/* wc_price() returns its own markup. Left alone it arrives at the theme's
   price size and colour, which on this row would be a third type style in a
   two-line block. */
body.single-product .zg-giftrow__a .woocommerce-Price-amount,
body.single-product .zg-giftrow__a .woocommerce-Price-currencySymbol,
body.single-product .zg-giftrow__a bdi {
  font-size: inherit;
  font-weight: inherit;
  font-family: inherit;
  color: inherit;
  letter-spacing: inherit;
}

body.single-product .zg-giftrow__sep {
  padding: 0 7px;
  opacity: .5;
}

@media (max-width: 767px) {
  body.single-product a.zg-giftrow {
    gap: 12px;
    padding: 13px 15px;
    margin-bottom: 18px;
  }
}

/* ---------------------------------------------------------------------------
   160. THE COLUMN UNDER THE BUTTON READS AS A WALL. THREE REASONS, MEASURED.
   ---------------------------------------------------------------------------
   The owner: "isn't it a mess, reading is hard and font is difficult, styling
   is bad". He is right, and sections 158 and 159 did not touch any of it,
   because none of it is a font size. Measured on the live page:

   1. THE PARAGRAPH GAP IS SMALLER THAN THE LINE GAP.
      Body copy here is 17px at line-height 1.7, so lines inside a paragraph
      sit 29px apart. The gap BETWEEN paragraphs is 8px.

      That is the whole problem in one number. When the space between two
      paragraphs is a third of the space between two lines, the eye has no
      way to see where one thought ends and the next begins, and six separate
      statements arrive as one undifferentiated block. Every other symptom he
      described follows from this.

      Fixed by making the paragraph gap larger than the line gap, which is
      what a paragraph gap is for.

   2. SIX BLOCKS, ALL THE SAME WEIGHT AND VERY NEARLY THE SAME SIZE.
      17 / 17 / list / 17 / 17 / 15, all weight 400. Nothing is emphasised,
      so nothing recedes either, and a reader scanning for one fact has no
      entry point. The free-samples line is the promise the page is built on
      and the strongest reason to buy; it now leads at the lead step instead
      of sharing a size with the note about a leaking atomiser.

   3. THREE ARTICLE TITLES SET IN TRACKED UPPERCASE, UNDERLINED, AND MY FAULT.
      "how a fragrance changes over a day", "fragrance families" and "the
      questions people ask" were rendering at 12px uppercase with 2.16px of
      tracking, wrapping over two lines. Section 158 swept `.zg-try__read`
      into the label group because the label "Worth reading:" is a label. The
      three LINKS inside it are not: they are sentences, and tracked uppercase
      is for two or three words. I made this line materially harder to read
      than it was before and it is the line he pointed at.

      The label keeps the label treatment. The titles become sentence case at
      the small step with normal tracking.

   Measure was checked and is not a problem: 46 characters a line, inside the
   comfortable 45 to 75.

   Nothing here changes a colour, a typeface or the copy.
   ------------------------------------------------------------------------ */

/* 1. rhythm. 20px against a 29px line gap gives a clear break without the
   blocks drifting apart into a list of unrelated notes. */
body.single-product .zg-try > p {
  margin-top: 0;
  margin-bottom: 20px;
}
body.single-product .zg-try > p:last-child {
  margin-bottom: 0;
}

/* 2. the promise leads. One step up and a slightly tighter line, so it reads
   as the opening statement rather than as the first of six equal notes. */
body.single-product p.zg-try__lead {
  font-size: var(--zg-fs-lead);
  line-height: 1.5;
  margin-bottom: 22px;
}

/* The atomiser steps are a procedure, not prose. Held closer to the paragraph
   that introduces them so the two read as one unit, and given room after. */
body.single-product .zg-try__spec {
  margin-bottom: 10px;
}
body.single-product .zg-atom--panel {
  margin-top: 4px;
  margin-bottom: 24px;
}

/* 3. "Worth reading" stops shouting its own links.
   The label keeps its uppercase; the titles are sentences and are set as
   sentences. `text-transform: none` has to beat the rule in 158, which is why
   the selector names the anchor as well as the paragraph. */
body.single-product p.zg-try__read {
  margin-top: 24px;
  line-height: 1.6;
}
body.single-product p.zg-try__read a {
  font-size: var(--zg-fs-small);
  font-weight: 400;
  text-transform: none;
  letter-spacing: normal;
  color: var(--zg-ink);
}
body.single-product p.zg-try__read .zg-try__sep {
  margin: 0 6px;
  color: var(--zg-muted);
}

/* One underline treatment for every link in this column. There were three
   sizes of underlined text in it, which reads as three kinds of link when
   they all do the same thing.

   :NOT(.ZG-GIFTROW), ADDED 2026-09-23. The gift row is a link too, and it was
   getting underlined twice over — once on its question and once on its answer
   — because text-decoration inherits down from the anchor to both spans. A
   bordered row with a chevron is already unmistakably a control; underlining
   it as well makes it read as a box with two links inside rather than as one
   target.

   WHY :not() AND NOT A LOUDER RULE IN SECTION 159. Both selectors weigh
   exactly (0,2,2) — two classes, two elements — and this one is 200 lines
   further down the file, so it wins on order alone. Escalating section 159
   with !important would have worked and would have left two rules fighting
   over the same element for whoever reads this next. Saying it once, here,
   costs nothing and stays true. */
body.single-product .zg-try a:not(.zg-giftrow) {
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
  text-decoration-color: rgba(20, 19, 15, 0.35);
}
body.single-product .zg-try a:not(.zg-giftrow):hover {
  text-decoration-color: var(--zg-ink);
}

/* ---------------------------------------------------------------------------
   161. THE MOVED BLOCK, AND THE REVIEW BUTTON
   ---------------------------------------------------------------------------
   Two pieces of furniture for the changes in product-try-panel.php and
   product-review-collapse.php. No new colours, no new type steps.
   ------------------------------------------------------------------------ */

/* The atomiser diagram, its steps and the journal links, now sitting full
   width above the Description rather than in the buy column. Given the page's
   own reading measure so three numbered instructions do not run the width of
   a desktop screen. */
.zg-aside {
  max-width: 1160px;
  margin: 0 auto clamp(2rem, 4vw, 3rem);
  padding: 0 20px;
}
.zg-aside__h {
  font-size: var(--zg-fs-label);
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--zg-muted);
  margin: 0 0 14px;
}
.zg-aside .zg-atom {
  max-width: 640px;
  margin: 0 0 20px;
}
.zg-aside .zg-try__read {
  font-size: var(--zg-fs-small);
  color: var(--zg-muted);
  margin: 0;
  max-width: 640px;
}
.zg-aside .zg-try__read a {
  color: var(--zg-ink);
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
  text-decoration-color: rgba(20, 19, 15, 0.35);
}
.zg-aside .zg-try__read a:hover { text-decoration-color: var(--zg-ink); }

/* The review button. It is an invitation, not a call to action, so it is the
   outlined treatment rather than the filled one the Add to cart button uses.
   A second black button on the page would compete with the only one that
   matters. */
button.zg-review-open {
  display: inline-block;
  background: transparent;
  border: 1px solid var(--zg-ink);
  border-radius: 2px;
  padding: 12px 26px;
  font-size: var(--zg-fs-label);
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--zg-ink);
  cursor: pointer;
  transition: background-color 160ms var(--zg-ease), color 160ms var(--zg-ease);
}
@media (hover: hover) {
  button.zg-review-open:hover { background: var(--zg-ink); color: var(--zg-cream); }
}
button.zg-review-open:focus-visible {
  outline: 2px solid var(--zg-ink);
  outline-offset: 3px;
}

/* ---------------------------------------------------------------------------
   162. THE BUY BAR, AND THE MOVED ASIDE IN ITS REAL CONTEXT
   ------------------------------------------------------------------------ */

/* 161 gave .zg-aside a 1160px measure and its own gutters on the assumption
   that it would land full width. It does not: the Description tabs live
   INSIDE the right-hand Elementor column, so the aside sits in a 485px track
   and those rules were doing nothing but adding padding to a narrow column.
   Corrected here rather than edited above, so the wrong assumption stays
   visible next to the measurement that disproved it. */
.zg-aside {
  max-width: none;
  margin: 0 0 clamp(1.5rem, 3vw, 2.25rem);
  padding: 0;
  border-top: 1px solid var(--zg-rule);
  padding-top: clamp(1.25rem, 2.5vw, 1.75rem);
}
.zg-aside .zg-atom,
.zg-aside .zg-try__read { max-width: none; }

/* --- the bar ---------------------------------------------------------------
   Cream rather than the near-black of the Add to cart button. It is a way
   back to a decision, not a second call to action competing with the first,
   and a black bar pinned across the foot of every product page would be the
   loudest thing on the site.

   It sits above the cookie banner's stacking context but below the mega menu.
   ------------------------------------------------------------------------ */
.zg-buybar {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 60;
  background: var(--zg-cream);
  border-top: 1px solid var(--zg-rule);
  box-shadow: 0 -6px 24px rgba(20, 19, 15, 0.06);
}
.zg-buybar[hidden] { display: none; }

.zg-buybar__inner {
  max-width: 1160px;
  margin-inline: auto;
  padding: 10px 20px;
  display: flex;
  align-items: center;
  gap: 16px;
}

.zg-buybar__name {
  font-family: FreightTextPro, Georgia, 'Times New Roman', serif;
  font-size: 19px;
  font-weight: 500;
  color: var(--zg-ink);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.zg-buybar__price {
  font-size: var(--zg-fs-small);
  color: var(--zg-muted);
  white-space: nowrap;
  margin-right: auto;
}

button.zg-buybar__cta {
  flex: none;
  background: var(--zg-ink);
  color: var(--zg-cream);
  border: 1px solid var(--zg-ink);
  border-radius: 2px;
  padding: 12px 30px;
  font-size: var(--zg-fs-label);
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  cursor: pointer;
}
button.zg-buybar__cta:focus-visible { outline: 2px solid var(--zg-ink); outline-offset: 3px; }

/* The bar covers the foot of the page while it is up, so the page gets that
   height back. Without this the footer's last line sits under it. */
body.zg-has-buybar { padding-bottom: 68px; }

@media (max-width: 600px) {
  .zg-buybar__inner { gap: 12px; padding: 8px 14px; }
  .zg-buybar__name { font-size: 16px; }
  /* The price is already inside the button's reach on a phone, and the name is
     what tells you which page you are on. */
  .zg-buybar__price { display: none; }
  .zg-buybar__name { margin-right: auto; }
  button.zg-buybar__cta { padding: 12px 20px; }
}

/* ---------------------------------------------------------------------------
   163. THE PRODUCT TITLE JOINS THE SCALE
   ---------------------------------------------------------------------------
   Agreed with the owner 2026-09-22. 158a left this alone on purpose and said
   why: it was not drift, it was a hand-written display size, and changing a
   decision somebody made is not the same as fixing an accident.

   What it was:

       .single-product main.jupiterx-main h1.elementor-heading-title
         { font-size: clamp(2.4rem, 4.2vw, 3.6rem) !important }

   3.6rem is 57.6px, which made the perfume name the largest type anywhere on
   the site, above the scale's h1 at 46px and above even the display step at
   52px that the homepage band headlines use. A product name set larger than
   the homepage's own headline is a hierarchy the site does not otherwise
   have.

   Now it takes --zg-fs-h1, the same token as every other h1.

   WHAT THIS DOES AT THE OTHER END, stated rather than buried: the token is
   clamp(30px, 4.40vw, 46px). On a phone the title goes from 38.4px to 30px,
   which is a larger relative change than the 57.6 to 46 on a desktop. That is
   the standard's own bottom step and it is what every other page title does at
   that width, so it is consistent by construction rather than by accident. If
   the title should stay bigger than the rest on a phone, that is a change to
   the STANDARD and belongs in section 128, not as another exception here.

   Important, and one step more specific than the rule it replaces, because
   that rule is important too and cannot be beaten any other way. Measured
   afterwards on the live page: 46px, not assumed.
   ------------------------------------------------------------------------ */

body.single-product main.jupiterx-main h1.elementor-heading-title {
  font-size: var(--zg-fs-h1) !important;
}

/* ---------------------------------------------------------------------------
   164. THE STANDARD NOW COVERS CHROME
   ---------------------------------------------------------------------------
   Section 128 set seven steps and the site passed 54 of 54 pages. It passed
   because the two auditors that enforce it EXCLUDE what they call chrome: form
   labels and help text, buttons, prices, badges, breadcrumbs, card labels.
   Nearly every readable defect on this site lives in that exclusion, which is
   how a page could be certified clean with 10.5px help text on it.

   Measured 2026-09-22 across 57 urls at 390 and 1440 by ops/audit-readability.mjs.

   THE POLICY, and it adds no new step to the scale.
   -------------------------------------------------
   Chrome is not a size. It is two kinds of thing, and they take two of the
   steps that already exist:

     A SENTENCE takes --zg-fs-small or larger. Never the label step.
       Anything with a verb and a full stop is being READ, however small the box
       it sits in. Consent copy, help text under a field, a card's scent line, a
       post excerpt, the footer's legal line. These were at 10.5 to 13px.

     A LABEL takes --zg-fs-label. Two or three words, usually uppercase and
       tracked, scanned rather than read. Badges, card meta, button text,
       pyramid labels. These were at 9.5 to 11px, several of them fractional.

   The test is what the text IS, not where it sits. That is the rule the
   original exclusion was missing, and it is why "chrome" was never a coherent
   category in the first place.

   WHAT THIS DELIBERATELY DOES NOT DO
   ----------------------------------
   It does not touch the seven steps, any colour, any spacing or any layout.
   Nothing here is a new design decision: every value is a token that was
   already defined and already in use somewhere else on the site.

   A NOTE ON THE NUMBERS, so the next person does not repeat my first pass.
   The scale is FLUID: every step is a clamp() interpolating on vw, so at 390px
   --zg-fs-body legitimately computes to 16.045px and --zg-fs-label to 11.035px.
   My first run reported 2,671 fractional sizes as defects; 2,493 of them were
   the scale working exactly as designed. An auditor must compute each step at
   the measured width before calling a fraction wrong. Likewise 11px is the
   label step's floor, not a fault.
   ------------------------------------------------------------------------ */

/* === SENTENCES ============================================================ */

/* The consent notice. Read by every first-time visitor, on all 57 pages, and
   it was the smallest running copy on the site. The lead is a sentence at 13px
   and the line under it a sentence at 12px. */
.zg-cc .zg-cc__lead,
.zg-cc__row .zg-cc__text p.zg-cc__lead {
  font-size: var(--zg-fs-small);
  line-height: 1.55;
}
.zg-cc .zg-cc__sub,
.zg-cc__row .zg-cc__text p.zg-cc__sub {
  font-size: var(--zg-fs-label);
  line-height: 1.5;
}

/* The footer's legal line: company name, CVR, address. Rarely read and always
   important when it is. 13px on 50 pages. */
.jupiterx-footer .elementor-widget-container > p,
footer .elementor-widget-container > p {
  font-size: var(--zg-fs-small);
}

/* The scent line under every product name on the four collection grids. This
   is the copy that was ADDED to those grids to give the tiles something to say,
   and it was being set two steps below the body it was written as. */
main.jupiterx-main p.zg-loop-note,
main.jupiterx-main p.zg-loop-note--house {
  font-size: var(--zg-fs-small);
}

/* The journal index excerpt, and the sample page's line about the full bottle. */
main.jupiterx-main .raven-post-excerpt,
main.jupiterx-main .zg-fullb p {
  font-size: var(--zg-fs-small);
}

/* The gift card's message field. The label was 11.375px against the 16px
   textarea it labels, which is the wrong way round: the label is read first
   and it was the harder of the two to read. Both were pure black as well, the
   only pure black left in that form. */
main.jupiterx-main .zg-gc-field label {
  font-size: var(--zg-fs-small);
  line-height: 1.45;
  color: var(--zg-ink);
}
main.jupiterx-main .zg-gc-field p,
main.jupiterx-main .zg-gc-field small,
main.jupiterx-main .zg-gc-field .zg-gc-field__hint {
  font-size: var(--zg-fs-small);
  line-height: 1.6;
  color: var(--zg-muted);
}

/* === LABELS =============================================================== */

/* The category line on a product card, "Classic" or "Exclusive", at 10px. */
main.jupiterx-main .raven-product-data span.posted_in {
  font-size: var(--zg-fs-label);
}

/* Top / Heart / Base down the side of the olfactive pyramid. 10.56px, which is
   0.88em of 12 compounding, so it was both too small and not a number anybody
   chose. */
main.jupiterx-main .zg-pyramid__label {
  font-size: var(--zg-fs-label);
  letter-spacing: 0.18em;
}

/* "Pending Release" at 9.5px, the smallest text on the site. This one comes
   from the Acowebs badge plugin and carries its own inline-ish styling, so it
   needs the weight. */
main.jupiterx-main .acoplw-badge .acoplw-blockText,
main.jupiterx-main span.acoplw-blockText {
  font-size: var(--zg-fs-label) !important;
  letter-spacing: 0.1em;
}

/* Consent buttons. 11px is the label floor rather than a defect, but these are
   the three controls a visitor has to hit before doing anything else, so they
   take the top of the step rather than the bottom. */
.zg-cc .zg-cc__btn {
  font-size: var(--zg-fs-label);
}

/* === OFF-SCALE ODDMENTS =================================================== */

/* Journal emphasis. Section 130 sets serif italic at 18px on purpose, to hold
   its own against the sans body. 18.02px is that 18 with an em factor applied
   on top of it. Stated as a flat number so it cannot drift again. */
main.jupiterx-main .elementor-widget-text-editor p > strong,
body.single-post .elementor-widget-raven-post-content p > strong {
  font-size: 18px;
}

/* "Further reading:" came out at 15.9px on some posts and 14.8877px on others,
   which is the same rule reached through two different parent sizes. */
main.jupiterx-main p.zg-further > strong {
  font-size: var(--zg-fs-small);
}

/* ---------------------------------------------------------------------------
   165. A SCRIM UNDER THE TWO PHOTO CAPTIONS
   ---------------------------------------------------------------------------
   This is the only confirmed WCAG failure the readability audit found, and it
   took pixel sampling to see it. Contrast against a photograph cannot be
   computed from CSS: the audit resolved every ancestor as transparent, fell
   back to the cream body and reported 1.11:1, which was nonsense. The real
   numbers come from drawing the background image into a canvas, cropping the
   caption's own rectangle out of it and measuring every pixel:

     "Sigurd Rossel"                27px  avg 15.34:1  worst 2.43:1  needs 3
     "Perfumer and founder"         20px  avg 14.22:1  worst 4.42:1  needs 4.5
     "The Lab"                      27px  avg 13.71:1  worst 5.56:1  PASSES
     "Where the batches are mixed"  20px  avg  2.96:1  worst 1.31:1  needs 4.5

   The last one is not marginal. The lab photograph is pale, near-white where
   the caption sits, and white 20px text on it averages 2.96:1 across the whole
   line. It is the least readable text on the site and no CSS audit would ever
   have found it.

   WHY A SCRIM AND NOT A COLOUR CHANGE. Making the captions dark would work on
   the lab photo and fail on the perfumer photo, which is nearly black. A
   gradient from transparent to a soft black at the foot of each tile fixes
   both without touching the photographs, the type or the layout, and it is
   invisible on the dark half of the perfumer image where nothing was wrong.

   It is anchored on the two Elementor container ids because these are two
   specific hand-built tiles, not a repeating component. If the homepage is
   rebuilt these ids change and this section stops matching, which is the right
   failure: it goes quiet rather than painting a gradient over something else.
   ------------------------------------------------------------------------ */

.elementor-element-bb22d84,
.elementor-element-11cf6a5 {
  position: relative;
  isolation: isolate;
}

.elementor-element-bb22d84::after,
.elementor-element-11cf6a5::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  /* Tall enough to cover a two line caption and its padding at every width the
     tile is used at, which is 428px tall on desktop and taller when it stacks. */
  height: 46%;
  background: linear-gradient(to top,
    rgba(20, 19, 15, 0.62) 0%,
    rgba(20, 19, 15, 0.42) 38%,
    rgba(20, 19, 15, 0) 100%);
  pointer-events: none;
  z-index: 0;
}

/* The caption has to sit above its own scrim. Everything inside these tiles is
   text, so lifting the whole content is simpler and safer than naming each
   heading, and there is nothing in them that should be behind it. */
.elementor-element-bb22d84 > *,
.elementor-element-11cf6a5 > * {
  position: relative;
  z-index: 1;
}

/* --- 165a. margin on the scrim ------------------------------------------
   With 0.62 at the foot, the pale lab photograph measured 4.54:1 at its worst
   pixel against a requirement of 4.5. Passing by four hundredths is not
   passing: my alpha figure is a model of the gradient, and the browser
   interpolates in premultiplied sRGB, so the true value can sit either side of
   it. A standard you clear by less than your own measurement error is one you
   have not cleared.

   0.68 at the foot puts the same pixel at about 5:1 and costs nothing visible:
   it is six per cent more black at the very bottom edge of a photograph, where
   there is no detail anybody is looking at. Re-measured after the change
   rather than assumed. */
.elementor-element-bb22d84::after,
.elementor-element-11cf6a5::after {
  background: linear-gradient(to top,
    rgba(20, 19, 15, 0.68) 0%,
    rgba(20, 19, 15, 0.48) 38%,
    rgba(20, 19, 15, 0) 100%);
}

/* --- 166. the card category label, with the weight it needs ---------------
   Section 164 set `.raven-product-data span.posted_in` to the label step and
   it did nothing. Read back off the live page, five rules beat it, and four of
   them are important:

     li.product .posted_in                  10px !important
     li.product span.posted_in              10px !important
     .jupiterx-products-wrapper .posted_in  10px !important
     li.product .posted_in                  9.5px !important
     .jupiterx-products-wrapper .posted_in  9.5px !important

   Somebody set this to 9.5px and then to 10px, twice each, with !important
   every time, which is what a rule that would not stick looks like from the
   other side. The label step is 11 to 12px.

   Found by the new readability guard in check.mjs, not by reading the CSS, and
   that is the point of having it: 164 shipped believing this was fixed. */
main.jupiterx-main li.product .raven-product-data span.posted_in,
main.jupiterx-main .jupiterx-products-wrapper span.posted_in {
  font-size: var(--zg-fs-label) !important;
}

/* ---------------------------------------------------------------------------
   167. THE FOUR RULES IN 164 THAT LOST, AND WHERE 18.02px CAME FROM
   ---------------------------------------------------------------------------
   Re-running the audit after 164 took the genuine size defects from 657 to 334.
   The remainder is not new ground: it is four of 164's own rules that never
   applied, each beaten by something important that I did not read first. The
   lesson is the one this file keeps relearning, so here it is with the
   measurements attached.

   18.02px, on 65 runs of emphasis across the journal, comes from OUR OWN rule
   in section 130:

       body.zg-audo.single-post .elementor-widget-raven-post-content p strong
         { font-size: 1.06em !important }

   1.06 of a 17px body is 18.02. The Audo decision was "serif italic at 18px"
   and 1.06em was how it was reached, which works until the body size moves and
   which can never produce a whole number. Stated flat here. The decision is
   unchanged; only the arithmetic is.
   ------------------------------------------------------------------------ */

/* The scent line on the collection grids. Beaten by
   `main.jupiterx-main ul.products li.product .zg-loop-note { font-size: 13px !important }`,
   which is also mine, from when that line was first added. These are full
   sentences on an indexed page and they take the small step. */
main.jupiterx-main ul.products li.product p.zg-loop-note,
main.jupiterx-main ul.products li.product p.zg-loop-note--house {
  font-size: var(--zg-fs-small) !important;
}

/* The archive eyebrow at a flat 10.5px, which was simply never in 164's list.
   Two or three words, so it takes the label step rather than small. */
main.jupiterx-main p.zg-archive-eyebrow,
p.zg-archive-eyebrow {
  font-size: var(--zg-fs-label);
  letter-spacing: 0.18em;
}

/* Journal emphasis: the 1.06em above. */
body.zg-audo.single-post .elementor-widget-raven-post-content p strong,
body.zg-audo.single-post .elementor-widget-raven-post-content p > strong,
body.single-post main.jupiterx-main .elementor-widget-raven-post-content p strong {
  font-size: 18px !important;
}

/* "Further reading:" inherits the same em factor through a different parent,
   which is why it came out 15.9px on some posts and 14.8877px on others. */
main.jupiterx-main p.zg-further > strong,
body.zg-audo main.jupiterx-main p.zg-further > strong {
  font-size: var(--zg-fs-small) !important;
}

/* The journal index excerpt. */
main.jupiterx-main .raven-post .raven-post-excerpt,
main.jupiterx-main div.raven-post-excerpt {
  font-size: var(--zg-fs-small) !important;
}

/* --- 168. the last two ----------------------------------------------------
   After 167 the site is down from 782 genuine size defects to 92, and 88 of
   those 92 are one line repeated across every page plus three stragglers.
   The rest of what the auditor still prints is not wrong:

     p.zg-product-eyebrow 12px    the label step at desktop, correct
     nav.woocommerce-breadcrumb 12px  the same
     h2.woocommerce-loop-product__title 13px  pinned in 158a to match the
       collection grid; a product name is a label, not a sentence
     div.zg-card__* 3.85 to 10.26px  the gift card ARTWORK, a scale drawing of
       a printed card, excluded from the health-check guard for the same reason

   The auditor flags those because it judges by character count and they are
   long labels. Living with a handful of explained false positives is better
   than teaching it to ignore a category, which is the mistake the original
   "chrome" exclusion made. */

/* The newsletter's terms, on all 57 pages, and a full sentence:
   "The code runs for thirty days, works once, on one order, and does not stack
   with another offer or apply to anything already reduced." At 12px it was the
   smallest running copy left on the site. */
.zg-letter .zg-letter__fine,
.zg-letter__form p.zg-letter__fine,
main.jupiterx-main p.zg-letter__fine,
footer p.zg-letter__fine {
  font-size: var(--zg-fs-small);
  line-height: 1.6;
}

/* Three runs of emphasis still at 18.02px. 167 fixed the journal, which is
   .elementor-widget-raven-post-content; these are in plain text-editor widgets
   on the other long-form pages, reached by the same 1.06em. */
body.zg-audo main.jupiterx-main .elementor-widget-text-editor p strong,
body.zg-audo main.jupiterx-main .elementor-widget-text-editor p > strong {
  font-size: 18px !important;
}

/* ---------------------------------------------------------------------------
   169. THE BUY BAR ON A PHONE: THE PRICE, AND THE BUTTON ON TOP OF IT
   ---------------------------------------------------------------------------
   Three faults in one screenshot from the owner, all of them mine.

   1. THE PRICE WAS MISSING. Section 162 hid it below 600px with the note that
      "the price is already inside the button's reach on a phone". That was a
      guess dressed as a reason, and it was wrong: the phone is exactly where
      the price has scrolled out of sight, which is the whole argument for the
      bar existing. It comes back, on its own line under the name, so the
      button keeps its width.

   2. THE SCROLL-TO-TOP BUTTON SAT ON THE ADD TO CART BUTTON. The theme pins it
      `position: fixed; bottom: 0; right: 0` at z-index 990 against this bar's
      60, so it painted over the right hand end and cut "ADD TO CART" off at
      "ADD TO C". The one control the bar exists to provide.

      Raising the bar above 990 would be the wrong way round: the scroll-top
      would go underneath and stop being clickable. So the bar publishes the
      room it occupies as --zg-buybar-clear, measured on the live element, and
      the corner button steps up by that much while the bar is showing. They
      stay in step at any viewport and while the consent notice lifts the bar.

   3. THE SCROLL-TO-TOP DID NOT LOOK LIKE THIS SITE. A 50px hard-edged square
      of #C0B7B0 with a black caret, a warm grey that appears nowhere else in
      the palette. Given cream, the hairline rule and the ink the rest of the
      site uses, and the same 2px radius as every other control. This is the
      one change here that is a matter of taste rather than a fault; revert
      this block alone if it is not wanted.
   ------------------------------------------------------------------------ */

/* --- 1. the price comes back --------------------------------------------- */
@media (max-width: 600px) {
  .zg-buybar__inner {
    gap: 12px;
    padding: 8px 14px;
    align-items: center;
  }
  /* Name and price stacked, so both fit beside a full-size button. */
  .zg-buybar__text {
    display: flex;
    flex-direction: column;
    justify-content: center;
    min-width: 0;
    margin-right: auto;
  }
  .zg-buybar__name {
    font-size: 16px;
    line-height: 1.2;
    margin-right: 0;
  }
  .zg-buybar__price {
    display: block;
    font-size: var(--zg-fs-label);
    line-height: 1.3;
    margin-right: 0;
    color: var(--zg-muted);
  }
  button.zg-buybar__cta { padding: 12px 18px; }
}

/* --- 2. the corner button steps over the bar ------------------------------
   The fallback matters: if the custom property is ever missing, 66px still
   clears a bar that measures 56. A var() with no fallback would collapse the
   button back onto the button it is meant to avoid. */
body.zg-has-buybar .jupiterx-corner-buttons {
  bottom: var(--zg-buybar-clear, 66px);
  transition: right 0.15s, bottom 0.15s;
}

/* --- 3. it looks like the rest of the site ------------------------------- */
.jupiterx-corner-buttons .jupiterx-scroll-top {
  background: var(--zg-cream);
  color: var(--zg-ink);
  border: 1px solid var(--zg-rule);
  border-radius: 2px;
  box-shadow: 0 2px 10px rgba(20, 19, 15, 0.08);
  transition: background-color 160ms var(--zg-ease), color 160ms var(--zg-ease);
}
@media (hover: hover) {
  .jupiterx-corner-buttons .jupiterx-scroll-top:hover {
    background: var(--zg-ink);
    color: var(--zg-cream);
  }
}
.jupiterx-corner-buttons .jupiterx-scroll-top:focus-visible {
  outline: 2px solid var(--zg-ink);
  outline-offset: 2px;
}

/* --- 169a. move the BUTTON, not its wrapper ------------------------------
   The rule in 169 aimed `bottom` at `.jupiterx-corner-buttons` and did nothing,
   and it took a while to see why because every instinct said cascade. It was
   not the cascade. Proved by setting the value inline, with !important, which
   bypasses the cascade entirely:

     inline bottom:120px !important on the WRAPPER   no movement at all
     inline bottom:120px on the BUTTON               moved, 16px to 136px

   The theme pins that wrapper with `top`, not `bottom`. On a fixed element
   with a resolved height, `top` wins and `bottom` is ignored, so no value of
   `bottom` and no amount of !important could ever have worked. `inset` failed
   for the same reason, which was the clue I should have read first.

   The button inside it is `position: static`, so making it relative and giving
   it an offset shifts it visually and changes no layout. The wrapper stays
   where the theme wants it.

   WORTH KEEPING: when a declaration set INLINE with !important still does
   nothing, stop looking at specificity. The property is not the one in charge.
   ------------------------------------------------------------------------ */

body.zg-has-buybar .jupiterx-corner-buttons .jupiterx-scroll-top {
  position: relative;
  bottom: var(--zg-buybar-clear, 66px);
  transition: bottom 0.15s, background-color 160ms var(--zg-ease), color 160ms var(--zg-ease);
}

/* 169 put the transition on the wrapper, where the offset it was animating is
   inert. The wrapper keeps only its own slide in from the right. */
body.zg-has-buybar .jupiterx-corner-buttons {
  bottom: auto;
  transition: right 0.15s;
}

/* --- 169b. put the wrapper back, and win the colour ----------------------
   169a added `bottom: auto` to the wrapper on the theory that the theme pinned
   it with `top`. That theory was wrong and the correction broke it: the wrapper
   dropped out of its fixed position and landed in the document flow near the
   footer, 6,489px below the fold.

   What actually happened earlier is duller than the theory. The wrapper IS
   pinned with `bottom`, and my inline test failed because at that moment the
   theme had not added `.jupiterx-scrolled`, so the element was not fixed at all
   and no offset applied to it. I measured one state and reasoned about another.

   So: the wrapper is left entirely alone, and only the button moves, which is
   what 169a got right. `bottom: auto` is reverted rather than deleted from 169a
   so the wrong turn stays legible next to the measurement that undid it. */
body.zg-has-buybar .jupiterx-corner-buttons {
  bottom: 0;
}

/* The grey is set on a more specific selector than 169 used. Measured, not
   guessed: 169's radius landed and its background did not, which is the
   signature of one declaration losing while its neighbours win. */
.jupiterx-corner-buttons button.jupiterx-scroll-top,
body .jupiterx-corner-buttons button.jupiterx-scroll-top {
  background-color: var(--zg-cream);
  color: var(--zg-ink);
  border: 1px solid var(--zg-rule);
}
@media (hover: hover) {
  .jupiterx-corner-buttons button.jupiterx-scroll-top:hover,
  body .jupiterx-corner-buttons button.jupiterx-scroll-top:hover {
    background-color: var(--zg-ink);
    color: var(--zg-cream);
  }
}

/* --- 169c. the scroll-top colour, with the weight it needs ---------------
   Bisecting every stylesheet for background-color on that button turned up six
   matching rules, and the winner is the last of them:

     .jupiterx-scroll-top { background: rgb(192,183,176) !important }

   That is a CUSTOMIZER value, printed as an inline block with !important, which
   is how Jupiter X emits its theme settings. Nothing declared without
   !important can beat it however specific, which is why 169's radius landed
   and its background did not: they were in the same rule but only one of them
   had competition.

   Worth the owner knowing: the real home of this colour is
   Appearance > Customise, and setting it there would be cleaner than this
   override. This is the override until then, and it is scoped to the corner
   button so it cannot touch anything else.
   ------------------------------------------------------------------------ */

.jupiterx-corner-buttons button.jupiterx-scroll-top {
  background-color: var(--zg-cream) !important;
  color: var(--zg-ink) !important;
  border: 1px solid var(--zg-rule) !important;
}
@media (hover: hover) {
  .jupiterx-corner-buttons button.jupiterx-scroll-top:hover {
    background-color: var(--zg-ink) !important;
    color: var(--zg-cream) !important;
  }
}

/* --- 169d. the offset is set by JavaScript now ---------------------------
   169a's `bottom: var(--zg-buybar-clear, 66px)` is superseded. Measured: the
   property was inherited by the button and correct at 239px, exactly one rule
   read it, and the computed value stayed on the 66px fallback; setting the
   property to 300px changed nothing. Rather than keep dissecting that, the
   buy bar writes the offset onto the element directly, which cannot disagree
   with itself.

   The rule is neutralised rather than deleted from 169a so the attempt stays
   readable next to what replaced it. The inline value would win regardless;
   this stops a dead declaration looking live to the next person. */
body.zg-has-buybar .jupiterx-corner-buttons .jupiterx-scroll-top {
  bottom: auto;
}

/* ---------------------------------------------------------------------------
   170. THE BLACK BAR OVER THE WISHLIST HEART IN THE DRAWER
   ---------------------------------------------------------------------------
   Reported by the owner: "add to favorite bar is still black in the shopping
   card, thought that was fixed". He is right on both counts. It was fixed, and
   it is still black, and those are not a contradiction.

   Section 122 gives the drawer's wishlist button a cream background and an ink
   border, and that rule IS applying. What it does not touch is the plugin's
   `__plane`, an absolutely positioned child that JetWishlist stacks inside the
   button for its hover animation. Measured on the live drawer:

       .jet-wishlist-button__plane   background rgb(0,0,0)   341x32   y=351

   The plane paints over the cream its parent was given, which is why the row
   reads as a solid black bar with a heart just barely visible on it.

   Section 88 already neutralises exactly these planes on the product page, and
   every selector in it is scoped `body.single-product main.jupiterx-main`. The
   drawer is rendered outside main, so none of it lands. Same root cause as 122
   itself, one layer deeper, which is why the earlier fix looked complete: the
   button was corrected and the thing covering it was not.

   Note 122's own measurement recorded the plane at `rgba(0,0,0,0)` in September.
   It is opaque now. Either the plugin changed or that reading caught the plane
   mid-animation; either way the lesson is to measure the CHILD as well as the
   control, because a background is only as good as what is stacked on it.

   Cosmetic only. No layout, no behaviour, nothing in the cart or checkout path.
   ------------------------------------------------------------------------ */

body [class*="fkcart"] .jet-wishlist-button .jet-wishlist-button__plane,
body [class*="fkcart"] .jet-wishlist-button .jet-wishlist-button__plane-normal,
body [class*="fkcart"] .jet-wishlist-button .jet-wishlist-button__plane-added,
body [class*="fkcart"] .jet-cw.jet-wishlist-button .jet-wishlist-button__plane,
body [class*="fkcart"] .jet-cw.jet-wishlist-button .jet-wishlist-button__plane-normal,
body [class*="fkcart"] .jet-cw.jet-wishlist-button .jet-wishlist-button__plane-added {
  background: transparent !important;
  background-color: transparent !important;
  box-shadow: none !important;
}

/* The saved state keeps its fill, but it comes from the BUTTON, which 122 already
   turns to ink, rather than from a layer stacked on top of it. */
body [class*="fkcart"] .jet-wishlist-button--added .jet-wishlist-button__plane,
body [class*="fkcart"] .jet-wishlist-button--added .jet-wishlist-button__plane-added {
  background: transparent !important;
  background-color: transparent !important;
}

/* ---------------------------------------------------------------------------
   172. PRODUCTS IN THE SEARCH RESULTS
   ---------------------------------------------------------------------------
   Markup from mu-plugins/search-products.php, which carries the reasoning for
   why it exists and why it does not reuse the WooCommerce loop card. Short
   version: Jupiter X and Raven have unhooked the entire product loop, so
   content-product.php renders an empty container on this install and there is
   no "real card" to inherit. This markup and these rules are the card.

   THE TYPE IS THE SCALE, NOT THE GRID'S. The collection cards set their names
   at 13px in a font-family string of their own ("Avenir-Regular", which is a
   fourth family declaration on a site with two faces). Copying that would have
   spread both faults onto a new page. These take --zg-fs-small, which is a
   step that already exists, and the one uppercase tracking ratio.

   ONE TRACK DEFINITION, NO BREAKPOINTS. auto-fill with a minimum means the
   grid finds its own column count at every width, so a phone gets two and a
   desktop gets five without this file naming a single device.
   ======================================================================== */
.zg-searchprod {
  margin: 0 0 56px;
}

.zg-searchprod__h {
  margin: 0 0 20px;
  font-size: var(--zg-fs-label);
  line-height: var(--zg-lh-label);
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--zg-muted);
}

.zg-searchprod__grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: 34px 18px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.zg-searchprod__item { margin: 0; }

.zg-searchprod__link {
  display: flex;
  flex-direction: column;
  gap: 6px;
  text-decoration: none;
  color: var(--zg-ink);
}
.zg-searchprod__link:hover { text-decoration: none; }
.zg-searchprod__link:focus-visible {
  outline: 2px solid var(--zg-ink);
  outline-offset: 4px;
}

/* The warm ground rather than white, for the same reason the product tiles use
   it: the shots are cut out on white and a pure-white tile leaves a visible
   rectangle edge around every bottle. */
.zg-searchprod__media {
  display: block;
  margin-bottom: 6px;
  background: var(--zg-ground);
  aspect-ratio: 3 / 4;
  overflow: hidden;
}
.zg-searchprod__media img,
.zg-searchprod__img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
  transition: transform 400ms var(--zg-ease);
}
.zg-searchprod__link:hover .zg-searchprod__media img {
  transform: scale(1.03);
}

.zg-searchprod__name {
  font-size: var(--zg-fs-small);
  line-height: 1.3;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--zg-ink);
}

/* Two lines and then it stops. A scent line that runs to five lines under one
   card and one under the next turns an even grid into a ragged one. */
.zg-searchprod__note {
  font-size: var(--zg-fs-small);
  line-height: 1.5;
  color: var(--zg-muted);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.zg-searchprod__price {
  font-size: var(--zg-fs-small);
  line-height: 1.4;
  color: var(--zg-ink);
}
/* wc_price() brings its own size and colour; left alone it is a third type
   style inside a three-line card. */
.zg-searchprod__price .woocommerce-Price-amount,
.zg-searchprod__price .woocommerce-Price-currencySymbol,
.zg-searchprod__price del,
.zg-searchprod__price ins,
.zg-searchprod__price bdi {
  font-size: inherit;
  font-weight: inherit;
  font-family: inherit;
  color: inherit;
  letter-spacing: inherit;
  text-decoration: none;
  background: none;
}

.zg-searchprod__flag {
  font-size: var(--zg-fs-label);
  line-height: var(--zg-lh-label);
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--zg-muted);
}

.zg-searchprod__more {
  margin: 26px 0 0;
  font-size: var(--zg-fs-small);
}
.zg-searchprod__more a {
  color: var(--zg-ink);
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
  text-decoration-color: rgba(20, 19, 15, 0.35);
}
.zg-searchprod__more a:hover { text-decoration-color: var(--zg-ink); }

@media (max-width: 767px) {
  .zg-searchprod { margin-bottom: 40px; }
  .zg-searchprod__grid { gap: 26px 14px; }
}

/* ---------------------------------------------------------------------------
   173. THE CRAFT PASS — one ink, one uppercase tracking, one heading weight
   ---------------------------------------------------------------------------
   Agreed 2026-09-23 off the full site review. Everything here was measured on
   the live pages first and every value is named with the count it affects.

   EVERY RULE CARRIES !important AND A FULLY QUALIFIED SELECTOR. That is not
   laziness. Elementor emits per-widget CSS shaped
   `.elementor-NNNNN .elementor-element.elementor-element-XXXX .elementor-heading-title`,
   which is (0,4,0), and it is emitted AFTER this file in the combined bundle,
   so even at equal specificity source order beats us. This is the rule the
   2026-09-05 homepage audit arrived at after writing six rules that measured
   as having done nothing at all.
   ======================================================================== */

:root {
  /* The one uppercase tracking. 0.16em was already in use on the size pills,
     so this makes the majority value the only value rather than inventing a
     tenth one. */
  --zg-track: 0.16em;
}

/* --- A. THE FOOTER JOINS THE PALETTE --------------------------------------
   Measured: every visible text element in the footer was #000000. Not one of
   them was --zg-ink, and there was no third colour in there at all, so this
   is a straight substitution with nothing to preserve.

   Pure black is not in this palette and never was. Against cream it reads
   colder and harder than the #14130F used everywhere above it, which is the
   whole reason the token exists. Twenty-eight elements. */
footer.jupiterx-footer .raven-menu-item.raven-link-item,
footer.jupiterx-footer .elementor-icon-list-text,
footer.jupiterx-footer .elementor-icon-list-text strong,
footer.jupiterx-footer .elementor-heading-title,
footer.jupiterx-footer .elementor-widget-container p,
footer.jupiterx-footer .elementor-widget-container p a,
footer.jupiterx-footer .zg-foot-social,
footer.jupiterx-footer .zg-foot-social a {
  color: var(--zg-ink) !important;
}

/* --- B. THE MEGA MENU'S TOP-LEVEL LABELS ----------------------------------
   Same fault, five elements, but it can only be fixed where the header is
   opaque. On the homepage the header floats transparent over the hero and
   these labels are WHITE; a blanket rule would paint them ink on the video
   and make the navigation unreadable. `jupiterx-header-overlapped` is the
   class the theme puts on exactly the pages where that happens, so the
   negation is the honest boundary rather than a guess at page types. */
body:not(.jupiterx-header-overlapped) .jet-mega-menu-item__link .jet-mega-menu-item__label {
  color: var(--zg-ink) !important;
}

/* --- C. ONE UPPERCASE TRACKING --------------------------------------------
   Nine different ratios were in use on uppercase text on the product page
   alone. Measured, with counts:

       0em      x36   mega-menu panel headings, footer strongs
       0.18em   x14   our own eyebrow, the Size label, Before you buy
       0.1em    x13   mega-menu category headings at 20px
       0.14em   x12   the breadcrumb
       0.2em    x5    mega-menu top-level labels
       0.12em   x3    product card titles
       0.16em   x2    the size pills
       0.118em  x2    the quantity + and - buttons
       0.167em  x1    the newsletter submit

   Uppercase tracking is one of the few typographic decisions a reader
   registers without being able to name: consistent tracking reads as
   considered, drifting tracking reads as assembled out of parts. Which is
   what it was.

   THE + AND - BUTTONS ARE LEFT ALONE. They are single glyphs, and letter
   spacing on a one-character string is padding on its right side, not
   tracking. Changing them would move the sign off centre in its box for no
   reading benefit whatsoever. */
.jet-mega-menu-item__label,
.jet-mega-menu-mega-container h3.elementor-heading-title,
nav.woocommerce-breadcrumb,
nav.woocommerce-breadcrumb a,
nav.woocommerce-breadcrumb span,
.woocommerce-loop-product__title,
.zg-letter__submit,
body.single-product .zg-product-eyebrow {
  letter-spacing: var(--zg-track) !important;
}

/* --- D. ONE HEADING WEIGHT IN THE MEGA PANEL ------------------------------
   The panel carried its headings at two weights: six at 700 ("Classic
   Collection") and thirteen at 400 ("Beauty", "Exclusive"). 700 is not a step
   on this site's scale, which runs 400 / 500 / 600, so the heavier six were
   both inconsistent with the panel and inconsistent with the rest of the
   site. Everything lands on --zg-fw-head, the same weight the headings above
   the fold use.

   h3 only: the H2 "View Collection" links in the same panel are not uppercase
   and are not headings in any real sense, and they keep what they have. */
.jet-mega-menu-mega-container h3.elementor-heading-title {
  font-weight: var(--zg-fw-head) !important;
}

/* --- E. THE NEWSLETTER HEADING WAS THE BLACK CUT --------------------------
   .zg-letter__h computed to FreightTextPro 900 against a scale whose heaviest
   step is 600. This is the trap recorded after the type scale was built: a
   hand-written block that names a family but no weight inherits whatever cut
   the font stack loads first, and for this face that is the black. It is our
   own class and our own bug. */
.zg-letter__h {
  font-weight: var(--zg-fw-head) !important;
}

/* --- F. THE TWO 9px COUNTERS ----------------------------------------------
   The wishlist and basket badges set their number at 9px. There is no reading
   distance at which that is a size, and 11px is the floor the rest of this
   stylesheet already respects.

   The badge is a 16px circle. 11px digits fit one character comfortably and
   two at a squeeze, so the circle is given a min-width and allowed to grow
   into a pill rather than clip the number — a "12" that does not fit is worse
   than a slightly wider badge. */
.jet-wishlist-count-button__count span,
.fkcart-shortcode-count.fkcart-item-count {
  font-size: 11px !important;
  line-height: 1 !important;
}
.jet-wishlist-count-button__count,
.fkcart-shortcode-count.fkcart-item-count {
  min-width: 16px;
  width: auto !important;
  padding: 0 3px;
  box-sizing: border-box;
}

/* ---------------------------------------------------------------------------
   174. FINISHING THE TRACKING, AND THE LAST TWO BLACKS
   ---------------------------------------------------------------------------
   Section 173 moved the biggest groups onto --zg-track and left the tail. That
   was worse than either doing all of it or none of it: measured after 173, the
   product page carried 36 distinct type styles against the 31 it started with,
   because half-unifying a value SPLITS a group before it merges it. This
   finishes the job.

   THE POLICY, WRITTEN DOWN SO THE NEXT PASS DOES NOT HAVE TO REDERIVE IT.
   The tracking applies to uppercase LABELS — eyebrows, navigation, section
   heads, buttons, card meta. It does NOT apply to:

     - PRICES. "1200 DKK" inherits text-transform from a parent, so it matches
       any naive "uppercase" sweep, and tracking a number reads as 1 2 0 0.
       Six elements on the product page alone.
     - SINGLE SYMBOLS. The quantity + and - are one glyph each; letter spacing
       on a one-character string is right-hand padding, and it pushes the sign
       off centre in its box.
     - THE CONSENT NOTICE (.zg-cc__btn, 0.14em). That is a separate installable
       plugin that must run on sites with none of these tokens, so its type is
       deliberately flat pixels. Changing it here would either do nothing or
       make the plugin depend on this file. It stays as it is, on purpose.
   ======================================================================== */

/* --- our own classes that were set at 0.18em ------------------------------ */
.zg-pyramid__label,
.zg-try__sep,
.zg-aside__h,
.zg-try__read,
.zg-review-open,
.zg-retn b,
body.single-product th.label label {
  letter-spacing: var(--zg-track) !important;
}

/* --- the footer's uppercase links and address, which had no tracking at all */
footer.jupiterx-footer .raven-menu-item.raven-link-item,
footer.jupiterx-footer .elementor-icon-list-text,
footer.jupiterx-footer .elementor-icon-list-text strong,
footer.jupiterx-footer .zg-foot-social,
footer.jupiterx-footer .zg-foot-social a {
  letter-spacing: var(--zg-track) !important;
}

/* --- the product cards ----------------------------------------------------
   Raven emits these at (0,3,0), so a two-class selector loses even with
   !important. Three classes and two elements clears it without an id. */
body .raven-product-data h2.woocommerce-loop-product__title.raven-product-item-content,
body .raven-product-data span.posted_in.raven-product-item-content {
  letter-spacing: var(--zg-track) !important;
}

/* --- the last two pure blacks --------------------------------------------
   Everything else was cleared in section 173. These two sit on the collection
   page: the intro paragraph's link and the result count. */
body .raven-archive-description p a,
body .raven-products-ordering-result-wrapper p.woocommerce-result-count {
  color: var(--zg-ink) !important;
}

/* ---------------------------------------------------------------------------
   175. THE LAST TWO TRACKING HOLDOUTS
   ---------------------------------------------------------------------------
   THE CARD TITLE NEEDED FIVE CLASSES. Raven emits its grid title rule as
   `.elementor-21107 .elementor-element.elementor-element-2312fb2
    .raven-wc-products-custom ul.products .woocommerce-loop-product__title`,
   which is (0,5,1). Section 174 aimed at it with (0,3,2) and !important and
   measured as having done nothing, which is the third time this stylesheet
   has learned the same lesson. The selector below is (0,5,4) and clears it
   without resorting to an id.

   WHAT IS DELIBERATELY LEFT AT ZERO, so the next audit does not "fix" it:
     - prices and currency symbols, which inherit uppercase from a parent and
       would read as 1 2 0 0 D K K;
     - the quantity + and -, single glyphs where tracking is right-hand
       padding and pushes the sign off centre;
     - the consent notice, a portable plugin that must not depend on these
       tokens.

   AND A NOTE ON "Avenir-Regular". An audit that counts font-family STRINGS
   reports this site as having a family called Avenir-Regular alongside
   Avenir, and concludes there is an extra typeface loose on the product
   grids. There is not. Section 40 declares Avenir-Regular as an @font-face
   alias pointing at the same file, precisely so that Elementor widgets asking
   for that name get the real thing. It renders identically. Do not "unify" it
   and do not count it as a second face.
   ======================================================================== */

body .raven-wc-products-custom ul.products li.product h2.woocommerce-loop-product__title.raven-product-item-content {
  letter-spacing: var(--zg-track) !important;
}

/* The copyright line is uppercase and was the one footer label the tracking
   pass missed, because it is a bare <p> with no class of its own. */
footer.jupiterx-footer .elementor-widget-container p {
  letter-spacing: var(--zg-track) !important;
}

/* ---------------------------------------------------------------------------
   176. THE SERIF CARRIES THE READING
   ---------------------------------------------------------------------------
   Agreed 2026-09-23. This reverses a decision written into section 128, which
   says in so many words: "serif belongs to headings here; body copy is Avenir
   at a single size". That was a defensible call and it is no longer the one we
   are making. The house sells on evocation, and the face that carries its
   voice was doing headings and then stopping; everything a person actually
   READ was set in the UI typeface.

   THE DIVISION, WHICH IS THE WHOLE POINT:
     SERIF  — running prose somebody reads for its content: the buy column,
              the Description tabs, journal articles, collection intros.
     SANS   — everything you operate rather than read: labels, buttons,
              navigation, form fields, prices, badges, counters, breadcrumbs.

   WHY 19px AND NOT 17. Measured on the live page with a canvas: the string
   "Bergamot and iris over wood" is 220px in Avenir at 17px and 196px in
   FreightTextPro at the same size — the serif runs about 11% narrower per em
   and reads correspondingly smaller. At 19px it measures 219px, which is the
   same apparent size as the sans it replaces. 19px is --zg-fs-lead, a step
   that already exists, so this adds no new size to a page that is carrying
   too many already.

   LINE HEIGHT STAYS --zg-lh-body. 19 x 1.7 is 32.3px against the 28.9px the
   17px sans had. Slightly more air, which is what a serif at a 68-character
   measure wants, and it costs no new token.

   SCOPED TO THE THREE CONTEXTS THAT WERE AGREED, by body class: the product
   page, the journal, and the collection archives. The homepage, About and the
   FAQ keep the sans until somebody has looked at these three and said yes.
   Widening it later is one more line, and doing it now would be deciding
   something nobody agreed to.

   WHAT DELIBERATELY STAYS SANS INSIDE THOSE PAGES:
     - .zg-retn, the "Before you buy" returns notice. It is a framed piece of
       functional small print, not editorial copy; it belongs with the UI.
     - .zg-giftrow and the search result cards, which are controls.
     - Every label, price and button, by omission.
   ======================================================================== */

body.single-product main.jupiterx-main .elementor-widget-text-editor p,
body.single-post main.jupiterx-main .elementor-widget-text-editor p,
/* THE JOURNAL IS A DIFFERENT WIDGET. Its articles render through
   elementor-widget-raven-post-content, not the text editor, so the first version of
   this section left every article in the sans and measured as having changed nothing
   on 24 paragraphs. Checked, not assumed, is the only way to know which of these two
   widgets a given page uses. */
body.single-post main.jupiterx-main .elementor-widget-raven-post-content p,
body.single-post main.jupiterx-main .elementor-widget-raven-post-content li,
body.tax-product_cat main.jupiterx-main .elementor-widget-text-editor p,
body.single-product main.jupiterx-main .elementor-widget-text-editor li,
body.single-post main.jupiterx-main .elementor-widget-text-editor li,
body.single-product main.jupiterx-main .jet-tabs__content p,
body.single-product main.jupiterx-main .jet-tabs__content li,
body.single-product main.jupiterx-main .jet-tabs__content td,
body.tax-product_cat main.jupiterx-main .raven-archive-description,
body.tax-product_cat main.jupiterx-main .raven-archive-description p {
  font-family: FreightTextPro, Georgia, 'Times New Roman', serif !important;
  font-size: var(--zg-fs-lead) !important;
  line-height: var(--zg-lh-body) !important;
  font-weight: var(--zg-fw-copy) !important;
}

/* The buy column's own paragraphs. .zg-try__lead keeps its step ABOVE the
   rest: it was 19px against 17px, and flattening both to 19 would lose the
   one piece of emphasis in the column. It goes to --zg-fs-h3, which keeps the
   same relationship using the next step up rather than a new number. */
body.single-product .zg-try__spec,
body.single-product .zg-try__own,
body.single-product .zg-try__alt {
  font-family: FreightTextPro, Georgia, 'Times New Roman', serif !important;
  font-size: var(--zg-fs-lead) !important;
  line-height: var(--zg-lh-body) !important;
}

/* The article's opening paragraph was 19px against 17px for the rest. Same treatment as
   the buy column's lead: one step up rather than a new number. */
body.single-post main.jupiterx-main .elementor-widget-raven-post-content > div > p:first-of-type {
  font-size: var(--zg-fs-h3) !important;
  line-height: 1.5 !important;
}

body.single-product .zg-try__lead {
  font-family: FreightTextPro, Georgia, 'Times New Roman', serif !important;
  font-size: var(--zg-fs-h3) !important;
  line-height: 1.5 !important;
}

/* The italic is the reason a text family is worth having. FreightTextPro
   ships a real italic at 400, so emphasis in an article is now a drawn italic
   rather than the browser slanting a roman. */
body.single-post main.jupiterx-main .elementor-widget-raven-post-content em,
body.single-post main.jupiterx-main .elementor-widget-raven-post-content i,
body.single-product main.jupiterx-main .jet-tabs__content em,
body.single-product main.jupiterx-main .jet-tabs__content i {
  font-family: FreightTextPro, Georgia, 'Times New Roman', serif !important;
  font-style: italic !important;
  font-weight: var(--zg-fw-copy) !important;
}

/* Section 130 raises <strong> by 1.06em, which was tuned against Avenir. On a
   serif at 19px that lands on 20.1px and reads as a size error rather than as
   emphasis. Weight is what emphasis is for. */
body.single-post main.jupiterx-main .elementor-widget-raven-post-content p strong,
body.single-product main.jupiterx-main .jet-tabs__content p strong {
  font-size: inherit !important;
  font-weight: var(--zg-fw-bold) !important;
}

/* ---------------------------------------------------------------------------
   177. THE TYPE CONSOLIDATION, AND THE OFFICIAL PAYMENT MARKS
   ---------------------------------------------------------------------------
   Agreed 2026-09-23 from the mockups. Three areas were carrying eighteen type
   styles between them; this brings them to eleven and, more to the point, onto
   the house typeface and the existing scale.

   Fully qualified selectors and !important throughout, for the reason section
   173 records: Elementor emits per-widget CSS at (0,4,0) AFTER this file in the
   bundle, so source order beats anything gentler.
   ======================================================================== */

/* --- A. THE PAYMENT MARKS -------------------------------------------------
   Markup from mu-plugins/footer-payment-badges.php, which carries the reasoning
   for why these are the official marks and not drawn ones.

   SIZED BY HEIGHT, NEVER BY WIDTH. Visa and Mastercard are 750x471, Apple Pay
   is 165x106 and MobilePay is a 32x32 square. Constraining width would leave
   them at wildly different optical sizes; one height and auto width is how a
   row of payment marks is laid out. */
footer.jupiterx-footer .zg-pay-row {
  display: inline-flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 14px;
}
footer.jupiterx-footer img.zg-pay {
  height: 26px !important;
  width: auto !important;
  max-width: none !important;
  display: block;
}
@media (max-width: 767px) {
  footer.jupiterx-footer .zg-pay-row { gap: 11px; justify-content: center; }
  footer.jupiterx-footer img.zg-pay { height: 22px !important; }
}

/* --- B. THE FOOTER --------------------------------------------------------
   THE FAMILY FIRST, BECAUSE IT IS THE REAL FAULT. Measured on the live page,
   the footer's declared font-family was the generic `sans-serif` - the browser
   default face, not Avenir. The proof is a measurement, not an opinion: the
   string "Hamburgefonstiv" at 40px renders 306px wide in Avenir and 302px in
   sans-serif, and the footer's stack measured 302px. Every visitor has been
   reading the footer in Arial or Liberation Sans since it was built.

   Then the sizes. Column headings were 25px, which is on no step of this
   scale, and they sat beside a 42px serif and 13px uppercase links. A footer
   is navigation, not an article: the headings become labels, the links become
   readable sentence case, and the one line worth reading gets the serif. */
footer.jupiterx-footer,
footer.jupiterx-footer .raven-menu-item.raven-link-item,
footer.jupiterx-footer .elementor-icon-list-text,
footer.jupiterx-footer .elementor-heading-title,
footer.jupiterx-footer .elementor-widget-container p,
footer.jupiterx-footer .zg-foot-social a {
  font-family: Avenir, "Avenir Next", "Helvetica Neue", Helvetica, sans-serif !important;
}

/* Column headings: 25px on no step, to the label step. */
footer.jupiterx-footer h3.elementor-heading-title {
  font-size: var(--zg-fs-label) !important;
  line-height: var(--zg-lh-label) !important;
  font-weight: 500 !important;
  letter-spacing: var(--zg-track) !important;
  text-transform: uppercase !important;
  color: var(--zg-muted) !important;
}

/* Links: sentence case at the small step. 13px uppercase with tracking is a
   label treatment, and there were fifteen of them in a column, which reads as
   shouting rather than as navigation. */
footer.jupiterx-footer .raven-menu-item.raven-link-item {
  font-size: var(--zg-fs-small) !important;
  line-height: 1.5 !important;
  letter-spacing: 0 !important;
  text-transform: none !important;
  color: var(--zg-ink) !important;
}

/* The address and phone are information, not labels. */
footer.jupiterx-footer .elementor-icon-list-text {
  font-size: var(--zg-fs-small) !important;
  line-height: 1.6 !important;
  letter-spacing: 0 !important;
  text-transform: none !important;
  color: var(--zg-muted) !important;
}
footer.jupiterx-footer .elementor-icon-list-text strong {
  font-weight: 500 !important;
  color: var(--zg-ink) !important;
}

/* "Follow us" at 42px was the largest thing in the footer and said the least.
   It becomes a label, and the sentence under it takes the serif, which is the
   one line down there anybody actually reads. */
footer.jupiterx-footer h2.elementor-heading-title {
  font-size: var(--zg-fs-label) !important;
  line-height: var(--zg-lh-label) !important;
  font-weight: 500 !important;
  letter-spacing: var(--zg-track) !important;
  text-transform: uppercase !important;
  color: var(--zg-muted) !important;
}
footer.jupiterx-footer .elementor-widget-text-editor p {
  font-family: FreightTextPro, Georgia, "Times New Roman", serif !important;
  font-size: var(--zg-fs-h3) !important;
  line-height: 1.4 !important;
  letter-spacing: 0 !important;
  text-transform: none !important;
  color: var(--zg-ink) !important;
}

/* The social line and the copyright: one is a link, one is fine print. */
footer.jupiterx-footer .zg-foot-social a {
  font-size: var(--zg-fs-small) !important;
  letter-spacing: 0 !important;
  text-transform: none !important;
  color: var(--zg-ink) !important;
}
footer.jupiterx-footer .elementor-widget-container p.zg-copyright,
footer.jupiterx-footer .elementor-element-72f5f18 p {
  font-family: Avenir, "Avenir Next", "Helvetica Neue", Helvetica, sans-serif !important;
  font-size: var(--zg-fs-label) !important;
  letter-spacing: var(--zg-track) !important;
  text-transform: uppercase !important;
  color: var(--zg-muted) !important;
}

/* --- C. THE MEGA MENU -----------------------------------------------------
   Nineteen headings at two sizes, 14px and 20px, become one label step.

   ALL OF THEM, NOT JUST THE TILE LABELS. The column headings and the tile
   labels are both h3.elementor-heading-title inside the panel, and the only
   structural difference is whether their container also holds an image widget.
   Half of those cases would need :has(), which on this site has form: a :has()
   rule blanked the whole sampler panel once. One treatment for all nineteen is
   the safe version of the same idea, and in a menu panel position carries the
   hierarchy well enough without a second size.

   The description copy was still pure #000000 - section 173 cleared the
   footer and the top-level labels but never reached inside the panel. */
.jet-mega-menu-mega-container h3.elementor-heading-title {
  font-size: var(--zg-fs-label) !important;
  line-height: var(--zg-lh-label) !important;
  font-weight: 500 !important;
  letter-spacing: var(--zg-track) !important;
  text-transform: uppercase !important;
  color: var(--zg-ink) !important;
}
.jet-mega-menu-mega-container .elementor-widget-text-editor p {
  font-family: FreightTextPro, Georgia, "Times New Roman", serif !important;
  font-size: var(--zg-fs-lead) !important;
  line-height: 1.6 !important;
  color: #2F2B23 !important;
}
/* "View Collection" is a link wearing an h2. It reads as one now. */
.jet-mega-menu-mega-container h2.elementor-heading-title {
  font-size: var(--zg-fs-small) !important;
  font-weight: 400 !important;
  letter-spacing: 0 !important;
  color: var(--zg-ink) !important;
}

/* --- D. THE FAQ -----------------------------------------------------------
   THE H1 WAS A THIRD TYPEFACE. Every h1 on this site is FreightTextPro at
   46px. The FAQ's was GlacialIndifference at 46px - one heading, on one page,
   in a display face used nowhere else, and in pure black rather than the ink.
   Nobody would ever have found that by looking; it took counting families.

   The answers take the serif, which is the same rule already live on the
   product page, the journal and the collection intros. The FAQ is a reading
   page and was the obvious omission from that list. */
body.page-id-20028 h1.elementor-heading-title {
  font-family: FreightTextPro, Georgia, "Times New Roman", serif !important;
  font-size: var(--zg-fs-h1) !important;
  line-height: var(--zg-lh-h1) !important;
  font-weight: 400 !important;
  color: var(--zg-ink) !important;
}
body.page-id-20028 main.jupiterx-main h2.elementor-heading-title {
  font-family: Avenir, "Avenir Next", "Helvetica Neue", Helvetica, sans-serif !important;
  font-size: var(--zg-fs-label) !important;
  line-height: var(--zg-lh-label) !important;
  font-weight: 500 !important;
  letter-spacing: var(--zg-track) !important;
  text-transform: uppercase !important;
  color: var(--zg-muted) !important;
}
body.page-id-20028 h3.jx-ac-title {
  font-family: Avenir, "Avenir Next", "Helvetica Neue", Helvetica, sans-serif !important;
  font-size: var(--zg-fs-small) !important;
  line-height: 1.4 !important;
  font-weight: 500 !important;
  letter-spacing: var(--zg-track) !important;
  text-transform: uppercase !important;
  color: var(--zg-ink) !important;
}
body.page-id-20028 .jupiterx-ac-content-is-editor p,
body.page-id-20028 .jupiterx-ac-content-is-editor li {
  font-family: FreightTextPro, Georgia, "Times New Roman", serif !important;
  font-size: var(--zg-fs-lead) !important;
  line-height: var(--zg-lh-body) !important;
  font-weight: var(--zg-fw-copy) !important;
  color: #2F2B23 !important;
}

/* ---------------------------------------------------------------------------
   178. THE MARKS ARE NOT ALWAYS IN A FOOTER, AND A SQUARE IS NOT A CARD
   ---------------------------------------------------------------------------
   TWO FAULTS, BOTH MEASURED ON THE LIVE PAGE.

   1. Section 177 scoped the mark sizing to `footer.jupiterx-footer`. On the
      FunnelKit checkout the same row is not inside a <footer> element at all,
      so none of it applied and the marks fell back to the Elementor widget's
      own sizing: MobilePay rendered 40x40 against 40x25 for everything else,
      which is exactly the row the owner photographed. Our own classes are
      specific enough on their own; the footer scope bought nothing and cost
      the page that matters most.

   2. Even where the sizing DID apply, MobilePay looked bigger than its
      neighbours while measuring the same height. Visa is 41x26, MobilePay is
      26x26. They are the same height and the square still wins, because a
      saturated blue square with no internal margin carries far more optical
      weight than a card mark whose artwork is inset inside its own frame.
      Matching numbers is not matching sizes.

   So: one box for every mark, and the square one is set a little smaller
   inside it so the row reads even. Sized by eye against the cards, which is
   the only way this can be judged.
   ======================================================================== */
.zg-pay-row {
  display: inline-flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 14px;
}

.zg-pay-row img.zg-pay,
img.zg-pay {
  height: 26px !important;
  width: 42px !important;
  max-width: none !important;
  object-fit: contain !important;
  display: block;
}

/* THE OPTICAL TWEAK WAS A GUESS, AND IT WAS WRONG.
   An earlier version set MobilePay smaller than the rest, to answer the fact
   that a saturated blue square looks heavier than a card mark at the same
   height. That judgement was made by eye and never measured, and on the
   checkout it produced the opposite complaint: MobilePay visibly SMALLER than
   its neighbours. The owner, twice: "can all icons be sized the same so its
   uniform", then "now mobilepay icon is too small at checkout".

   He is right both times, and the first report was never about optical weight
   at all. It was that the sizing rule was scoped to footer.jupiterx-footer and
   the checkout row sits outside any <footer>, so MobilePay rendered at its
   natural 40x40 while everything else was 40x25. Unscoping the rule fixed the
   real fault; the optical tweak was then fixing a problem that no longer
   existed, and introducing one of its own.

   So: one height for every mark, no exceptions. object-fit: contain does the
   rest, and a square simply ends up narrower than a card, which is correct. */

@media (max-width: 767px) {
  .zg-pay-row { gap: 10px; justify-content: center; }
  .zg-pay-row img.zg-pay,
  img.zg-pay { height: 22px !important; width: 35px !important; }
}

/* --- THE ADDRESS HANGS UNDER ITSELF, NOT UNDER THE LABEL ------------------
   The block is one text node: "A:" in a <strong>, then the company and three
   more lines separated by <br>. Every line after the first therefore started
   at the left edge, under the "A:", instead of under "HOUSE OF ZIGGIMAY".

   A hanging indent is the fix a list like this wants: indent the whole block
   by the width of the label and pull the first line back out by the same
   amount. 1.55em is the measured width of "A:" plus its following space at
   this size; ch units would be wrong here because the label is bold and the
   digits after it are not. */
footer.jupiterx-footer .elementor-icon-list-text {
  display: block;
  padding-left: 1.55em;
  text-indent: -1.55em;
}

/* ---------------------------------------------------------------------------
   179. THE HOMEPAGE PRODUCTS ARE A GRID ON A PHONE, NOT A CAROUSEL
   ---------------------------------------------------------------------------
   Agreed 2026-09-23. The owner: "mobile frontpage and maybe other pages are
   rendered broken in chrome browser and zen browser", with the third row of
   products sliced off in both.

   WHAT IT ACTUALLY IS, measured with an Android user agent and touch emulation
   rather than a plain headless window, because the two behave differently and
   that is the whole story:

     no touch    .swiper is overflow:visible, the five products lay out as a
                 2-column grid three rows deep, 854px tall, nothing clipped.
     with touch  Swiper initialises as a carousel: .swiper becomes
                 overflow:hidden with a height of 440px and all five slides are
                 stacked at one position, moved by transform.

   What a phone shows is the state in between: the grid layout, about 900px
   tall, inside the 440px overflow:hidden box the carousel put around it. The
   third row is simply cut off. It resolves itself if Swiper finishes; it does
   not if the script is late, deferred behind something slow, or rewritten by
   the optimiser, which on this site is a real possibility rather than a
   theoretical one.

   NOT CAUSED BY THE TYPE WORK, checked before blaming anything: the card
   heights are identical at the old 0.12em tracking and the new 0.16em - 227,
   227, 247, 247, 247 at 360px - and no rule in this file touches that widget.

   WHY A GRID RATHER THAN A SAFER CAROUSEL. A carousel on a phone hides three
   of the five fragrances this house makes behind a gesture nobody is told
   about. Five products is not a volume that needs paging. The grid also cannot
   half-initialise, because there is nothing to initialise.

   Swiper still loads and still runs; it is simply overruled. Every declaration
   here needs !important because Swiper writes width, margin and transform as
   INLINE styles on the wrapper and on each slide, and an inline style beats any
   selector without it.

   ONE WIDGET ON ONE PAGE: checked, .raven-products-carousel-swiper-container
   appears on the front page and nowhere else on the site.
   ======================================================================== */

@media (max-width: 767px) {

  .raven-products-carousel-swiper-container,
  .raven-products-carousel-swiper-container.swiper {
    overflow: visible !important;
    height: auto !important;
    /* Swiper keeps its touch handlers. pan-y guarantees a vertical swipe stays
       a page scroll and is never swallowed as a drag on a carousel that can no
       longer move. */
    touch-action: pan-y !important;
  }

  .raven-products-carousel-swiper-container .swiper-wrapper {
    display: grid !important;
    grid-template-columns: repeat(2, minmax(0, 1fr)) !important;
    gap: 30px 14px !important;
    transform: none !important;
    width: auto !important;
    height: auto !important;
  }

  .raven-products-carousel-swiper-container .swiper-slide {
    width: auto !important;
    max-width: none !important;
    margin: 0 !important;
    flex-shrink: 1 !important;
  }

  /* Loop mode clones slides. A clone in a grid is a product listed twice. */
  .raven-products-carousel-swiper-container .swiper-slide-duplicate {
    display: none !important;
  }

  /* Arrows and dots steer something that no longer moves. */
  .raven-products-carousel-swiper-container .swiper-button-next,
  .raven-products-carousel-swiper-container .swiper-button-prev,
  .raven-products-carousel-swiper-container .swiper-pagination,
  .elementor-widget-raven-products-carousel .swiper-pagination,
  .elementor-widget-raven-products-carousel .elementor-swiper-button {
    display: none !important;
  }

  /* --- AND THE SECTION AROUND IT CLIPS ----------------------------------
     Turning the carousel into a grid was only half of it. Measured with an
     Android user agent at 412px, after the grid rule above:

       .swiper container          902px, content 902   fine
       the carousel WIDGET        679px, content 975   reports short
       .zg-collections section    891px, content 1131  CLIPS

     Elementor puts `overflow: hidden` on every top-level container
     (.e-con.e-parent), and the section takes its height from what the widget
     REPORTS, not from what the widget actually holds. The carousel widget
     reports the height Swiper gave it for one row, so the section sizes to
     891px and hides the rest. That is the cream band stopping halfway down
     the last row, with the fifth bottle hanging below it.

     WHY THIS WAS NEVER THE TYPE CHANGE, checked three ways before touching
     anything: at 360, 390 and 412px with a real device emulation, the title
     heights are 25,25,45,45,45 and the grid is 814/859/892px at BOTH the old
     0.12em tracking and the new 0.16em. Identical. The content was already
     taller than 891px and the section was already hiding it.

     Everything in the chain is told to size to its content and not to clip.
     Only on phones, only on the home page, only this band. */
  body.home .zg-collections.e-con,
  body.home .zg-collections.e-con.e-parent {
    overflow: visible !important;
    height: auto !important;
  }
  body.home .zg-collections > .e-con-inner {
    height: auto !important;
  }
  /* FLEX ITEMS SHRINK, AND THAT IS THE WHOLE OF IT.
     .e-con-inner is a COLUMN flex container, so the carousel widget is a flex
     ITEM on the vertical axis and flex-shrink defaults to 1. The widget was
     measuring 679px while holding 975px of content, and the section 891px
     while holding 1131px, and neither had a height rule anywhere: the item was
     being squeezed to fit a box whose height it was itself supposed to set.
     Reading the widget's matched styles showed no height at all, which is what
     gave it away.

     An earlier version of this block answered that with min-height: 0, which
     is exactly backwards. min-height: auto is the automatic minimum that stops
     a flex item shrinking below its content in the first place; setting it to
     0 removes the only thing holding the box open. Refusing to shrink is the
     fix. */
  /* STOP FIGHTING THE FLEX CHAIN, TAKE IT OUT.
     .zg-collections is a flex container, .e-con-inner inside it is another,
     and .e-con > .e-con-inner carries height: 100%. That is a loop: the inner
     takes its height from the section, the section takes its height from the
     inner, and the carousel widget in the middle gets squeezed to whatever
     falls out. Setting height: auto at each level did not break the loop, and
     neither did refusing to shrink; the pair kept measuring 891px around
     1131px of content.

     A block box has none of this. It is as tall as what is in it, there is no
     shrink, and a percentage height against it resolves to auto. The section
     is a single column on a phone anyway, so flex is buying nothing here. */
  body.home .zg-collections.e-con,
  body.home .zg-collections.e-con.e-parent {
    display: block !important;
  }
  body.home .zg-collections > .e-con-inner {
    display: block !important;
    height: auto !important;
    min-height: 0 !important;
  }
  body.home .zg-collections > .e-con-inner > .elementor-element,
  body.home .zg-collections .elementor-widget-raven-products-carousel {
    height: auto !important;
  }
  body.home .zg-collections .elementor-widget-raven-products-carousel > .elementor-widget-container,
  body.home .zg-collections .raven-products-carousel,
  body.home .zg-collections .raven-swiper-slider {
    height: auto !important;
  }
}

/* ---------------------------------------------------------------------------
   180. NO "1/1" OVER A SINGLE PHOTOGRAPH
   ---------------------------------------------------------------------------
   The gallery prints a counter under the image. On a product with six shots
   "1/6" tells you there is more to swipe; on the gift card, which has one, it
   printed "1/1", which tells you only that somebody wrote a counter.

   Structural rather than per-product: the counter goes when its image is the
   ONLY child of the gallery wrapper. Measured, the gift card's wrapper holds
   one child and Oud Absolu's holds six, so the rule can never take the counter
   off a gallery that needs it.

   The counter is built in the browser, not printed by PHP, so this is the only
   place it can be answered. */
body.single-product .woocommerce-product-gallery__wrapper > .woocommerce-product-gallery__image:only-child .image_no {
  display: none !important;
}

/* ---------------------------------------------------------------------------
   181. THE MOBILE MENU IS A LIST OF PLACES
   ---------------------------------------------------------------------------
   Agreed 2026-09-23 from the mockups, option A.

   What it was, from the owner's screenshot: the links set in the SERIF, which
   no other navigation surface on this site uses; a section heading at a weight
   that appears nowhere else; rules about three times the weight of the
   hairlines used everywhere; and image tiles whose labels sat ON the
   photographs in white, one of them ("DISCOVERY BOX") clipped by its own tile,
   in a three-then-two grid that left the second row ragged.

   A menu is a list of places you tap, not something you read. Sentence case at
   the small step is quicker to scan than 22px serif and fits the whole shop on
   one screen without scrolling.

   THE FACE IS SET EXPLICITLY, both family and transform. Measured in the panel
   markup these links compute to Avenir 17px, yet the drawer renders them in a
   serif, so something between the two is restyling them and I have not found
   it. Naming the face here settles it either way rather than depending on
   which layer wins.

   THE TILES GO, on phones only. They duplicate the five links directly above
   them and push the actual navigation below the fold. `:has()` is the only way
   to say "a container holding an image widget" without an element id that
   Elementor rewrites on every save; a browser without it simply shows the
   tiles as before, which is today's behaviour and not a broken page.
   ======================================================================== */

@media (max-width: 767px) {

  /* Section headings become labels: the same 12px step as the collection grids
     and the footer, in muted ink so the links below them lead. */
  .jet-mega-menu-mega-container h3.elementor-heading-title,
  .jet-mega-menu-sub-menu h3.elementor-heading-title {
    font-family: Avenir, "Avenir Next", "Helvetica Neue", Helvetica, sans-serif !important;
    font-size: var(--zg-fs-label) !important;
    line-height: var(--zg-lh-label) !important;
    font-weight: 500 !important;
    letter-spacing: var(--zg-track) !important;
    text-transform: uppercase !important;
    color: var(--zg-muted) !important;
    margin: 0 0 4px !important;
  }

  /* The links themselves. 52px clears the 44px tap target with room, and the
     rule drops to the site hairline. */
  .jet-mega-menu-mega-container .raven-menu-item.raven-link-item,
  .jet-mega-menu-sub-menu .raven-menu-item.raven-link-item,
  .jet-mega-menu-mega-container .raven-nav-menu .menu-item > a {
    display: flex !important;
    align-items: center !important;
    min-height: 52px !important;
    font-family: Avenir, "Avenir Next", "Helvetica Neue", Helvetica, sans-serif !important;
    font-size: var(--zg-fs-small) !important;
    line-height: 1.3 !important;
    font-weight: 400 !important;
    letter-spacing: 0 !important;
    text-transform: none !important;
    color: var(--zg-ink) !important;
    border-bottom: 1px solid var(--zg-rule) !important;
    padding: 0 !important;
  }

  /* The top-level labels, the row you tap to get into a section. Same face and
     the one tracking; they were 25px at 4px, which is 0.16em already. */
  .jet-mega-menu-item__label {
    font-family: Avenir, "Avenir Next", "Helvetica Neue", Helvetica, sans-serif !important;
    font-size: var(--zg-fs-lead) !important;
    letter-spacing: var(--zg-track) !important;
    text-transform: uppercase !important;
  }

  /* The image tiles.
     HIDING A CONTAINER TOOK THE COLUMN WITH IT. The first version hid any
     .e-con holding an image widget as a direct child. Measured after: 13 of 13
     images gone, which was the intent, but also 17 of 19 headings and 8 of 16
     links, which was not. A column container in this panel holds its heading
     AND its tiles, so hiding the container hid the navigation as well.

     Hide the PARTS instead, never the box around them. An image widget goes;
     so does a heading immediately before or after one, which is a tile's
     label. A column heading is followed by a text editor or a nav menu rather
     than an image, so it is untouched.

     :has() is still needed for the label that comes BEFORE its image, because
     CSS has no previous-sibling combinator. Scoped to one element it can take
     nothing else with it, and a browser without :has() simply leaves that one
     label showing. */
  .jet-mega-menu-mega-container .elementor-widget-image,
  .jet-mega-menu-mega-container .elementor-widget-image + .elementor-widget-heading,
  .jet-mega-menu-mega-container .elementor-widget-heading:has(+ .elementor-widget-image) {
    display: none !important;
  }
}


/* ---------------------------------------------------------------------------
   182. HOVER IS A MOUSE STATE, AND A PHONE DOES NOT HAVE ONE
   ---------------------------------------------------------------------------
   Reported: tap the hamburger on the home page, close it again, and the header stays
   transparent over the hero instead of going back to a readable bar.

   Measured rather than guessed. Opening and closing the drawer changed exactly one computed
   property on #header-row, background-image, from the section 64 wash to none, and it never
   came back. The cause is that on a touch screen :hover is not a transient state: the browser
   leaves it on the last element tapped until something else is tapped. After the toggle is
   tapped, #header-row:hover keeps matching for as long as you stay on the page.

   Four things are driven by that hover, and all four flipped together:

       scrim   linear-gradient(...)  ->  none      (section 64)
       logo    invert(1)             ->  none      (the theme's :not(:hover) rule)
       icons   none                  ->  ink       (section 1)
       text                          ->  ink       (section 1)

   An earlier pass had already noticed the sticky hover and neutralised background-color inside
   @media (hover: none). That fixed one of the four and made the result WORSE rather than
   better: the bar lost its cream but kept the ink text, so the page ended up with dark labels
   on a transparent bar over a photograph, which is the least readable combination available.
   Patching one property at a time is what produced that, so this is done at the source instead:
   every hover-driven header rule in sections 1 and 64 now sits inside @media (hover: hover), so
   on a phone hover cannot reach the header at all and the bar simply stays in its resting
   state until a menu flag paints it.

   The one rule that cannot be fixed at the source is the theme's, which inverts the logo with
       body.jupiterx-header-overlapped:not(.stick) #header-row:not(:hover) .raven-site-logo img
   and so drops the inversion the moment hover sticks. It is overridden below rather than
   fought with: the :not() chain carries the same conditions the theme tests, plus the two menu
   flags, so the logo keeps its inversion exactly while the bar is genuinely transparent and
   hands it back the instant a drawer or a mega panel paints the bar cream.
   ------------------------------------------------------------------------ */
@media (hover: none) {
  body.jupiterx-header-overlapped:not(.stick):not(.zg-mega-open):not(.zg-mobile-menu-open)
    #header-row:hover .raven-site-logo img {
    filter: invert(1) !important;
  }

  /* THE LAST ONE, AND IT IS NOT IN THIS FILE.
     Jupiter X's own custom-code store carries

         body.home div#header-row:hover, body.stick div#header-row { background: #f5f3eb; }

     which is the theme's "hover turns the bar cream" and is right on a desktop. Two problems on
     a phone: it is not behind a hover query, and it uses the BACKGROUND SHORTHAND, so it resets
     background-image to none as a side effect nobody wrote down. At (1,2,2) it outranks
     section 64's (1,1,1), so the wash lost every time hover stuck and no amount of guarding
     rules in this file could have fixed it.

     That rule lives in the database, not on disk, so a grep over the theme never finds it. It is
     overridden here rather than edited there: it is still correct behaviour for a mouse, and the
     custom-code store is a fourth place for CSS to hide. !important is what does the work, since
     the theme rule carries none. */
  body.home:not(.stick):not(.zg-mega-open):not(.zg-mobile-menu-open) #header-row:hover {
    background-image: var(--zg-hero-scrim) !important;
  }
}


/* ---------------------------------------------------------------------------
   183. THE HEADER MARKS OVER THE HERO, ON TOUCH
   ---------------------------------------------------------------------------
   Reported from a phone with two screenshots: over the hero the hamburger and all four icons
   were dark while only the wordmark stayed white. The owner's rule, in his words: when the
   cream bar is NOT showing everything is white, and when the cream bar IS showing everything
   that was white turns dark.

   Same root cause as section 182 and as the logo. The site's own CSS keeps these marks white
   with selectors built on #header-row:not(:hover), for example

       body.jupiterx-header-overlapped:not(.stick) #header-row:not(:hover)
         a.jet-wishlist-count-button__link svg .cls-1 { stroke: #ffffff }

   On a touch screen :hover sticks to the last element tapped and never leaves, so :not(:hover)
   stops matching and every one of those marks falls back to its default black. Measured in the
   stuck state: hamburger, search, account and wishlist all dark; only the bag stayed white,
   because the bag is the one icon already written without :not(:hover) (see section 88). That
   is the pattern copied here.

   SECTION 76 TRIED THIS AND WAS WITHDRAWN. It set colour on the #header-row subtree, and the
   mobile drawer renders inside that subtree, so the menu links went white on cream and the
   drawer opened apparently blank. Its note says the fix belongs on individual icons and must be
   checked with the drawer open. So: every selector below names one icon, nothing here sets a
   text `color`, only svg paint, and every rule carries :not(.zg-mobile-menu-open) so none of it
   can reach the drawer. Section 79 keeps owning the drawer-open state.

   OUTLINE AND FILLED ICONS ARE SEPARATED ON PURPOSE. The account and wishlist marks are
   outlines: fill:none plus a stroke on path.cls-1. The search glyph is solid and carries its
   colour as a fill. A blanket fill would turn the outlines into solid blobs, which is exactly
   what went wrong once before. .cls-1 is the discriminator: stroke for those, fill for the rest.
   ------------------------------------------------------------------------ */
@media (hover: none) {

  /* Outline marks: the stroke carries the colour, the fill must stay none. */
  body.jupiterx-header-overlapped:not(.stick):not(.zg-mega-open):not(.zg-mobile-menu-open)
    #header-row a.jet-wishlist-count-button__link svg .cls-1,
  body.jupiterx-header-overlapped:not(.stick):not(.zg-mega-open):not(.zg-mobile-menu-open)
    #header-row .jet-cw-icon svg path.cls-1,
  body.jupiterx-header-overlapped:not(.stick):not(.zg-mega-open):not(.zg-mobile-menu-open)
    #header-row .elementor-icon svg path.cls-1 {
    stroke: #fff !important;
  }

  /* Solid glyphs: the search magnifier paints with fill, and has no stroke to set. */
  body.jupiterx-header-overlapped:not(.stick):not(.zg-mega-open):not(.zg-mobile-menu-open)
    #header-row .jet-ajax-search__field-icon svg path,
  body.jupiterx-header-overlapped:not(.stick):not(.zg-mega-open):not(.zg-mobile-menu-open)
    #header-row .elementor-icon svg path:not(.cls-1) {
    fill: #fff !important;
  }

  /* THE HAMBURGER IS NOT AN SVG YOU CAN COLOUR.
     There IS an inline <svg> of three <line>s inside the toggle, and it is a decoy: its <defs>
     is empty, nothing defines its .stfrggyh0 class, so the lines compute stroke:none and paint
     nothing at all. Setting stroke on them, which is what this rule did first, changed the
     measurement and not the picture. Proved by forcing those lines red in the page: the
     hamburger stayed black.

     What you actually see is a background-image on the toggle icon, the file
     uploads/2025/01/menu-icon.svg, which is drawn dark. A background-image cannot be recoloured
     with fill or stroke, so the site flips it with filter: invert(1) over the hero. That rule
     lives in the Jupiter X custom-code store, not on disk, and is written

         html:not(...) body.jupiterx-header-overlapped:not(.stick) #header-row:not(:hover) ...

     so it carries the same :not(:hover) that broke the logo and the icons: once hover sticks on
     a phone the inversion drops and the hamburger goes black over a dark photograph.

     :not(.active) keeps the open state alone, where the toggle becomes the close cross on a
     cream bar and must stay dark. */
  html:not(.darkmysite_dark_mode_enabled)
    body.jupiterx-header-overlapped:not(.stick):not(.zg-mega-open):not(.zg-mobile-menu-open)
    #header-row .jet-mobile-menu__toggle .jet-mobile-menu__toggle-icon {
    filter: invert(1) !important;
  }
}

/* JETMENU LEAVES .active ON THE TOGGLE AFTER THE DRAWER CLOSES.
   Measured with the drawer shut: aria-expanded="false", no drawer in the document, body flag
   off, and .active still on the toggle. It is stale, so :not(.active) is not a usable signal
   for "the menu is closed" and an earlier version of the rule above used it and did nothing.

   Two consequences. The filter above is keyed on our own body flag instead, which is computed
   from the drawer's real computed visibility and was correct in the same measurement. And the
   toggle keeps painting the close cross after closing, because the site's own rule

       .jet-mobile-menu__toggle:not(.active) .jet-mobile-menu__toggle-icon
         { background-image: url(.../menu-icon.svg) !important }

   stops matching for the same reason, so the icon falls through to JetMenu's opened glyph and
   you are left with an X and no menu. Same fix: ask whether the drawer is open, not whether a
   plugin remembered to remove a class. */
body:not(.zg-mobile-menu-open) .jet-mobile-menu__toggle .jet-mobile-menu__toggle-icon {
  background-image: url("/wp-content/uploads/2025/01/menu-icon.svg") !important;
}


/* ---------------------------------------------------------------------------
   184. THE BAG, AND THE TWO COUNTERS
   ---------------------------------------------------------------------------
   THE BAG IS THE FOURTH THING CAUGHT BY THE SAME :not(:hover). Reported after sections 182 and
   183 had fixed the bar, the logo, the hamburger and the other three icons: the bag alone was
   still dark over the hero.

   Like the hamburger it is not an svg you can colour. Its own <path> is set to opacity 0 and the
   mark is a background-image on the svg element, with two prepared files:

       zg-bag-dark-v2.svg    the default
       zg-bag-light-v2.svg   swapped in over the hero

   and the swap is written, in our CSS and again in the Jupiter X custom-code store, as

       body.jupiterx-header-overlapped:not(.stick) #header-row:not(:hover) ... { light }

   so on a phone the light bag lasts exactly until the first tap. The light file already exists
   and is correct; nothing here draws a new icon, it only stops hover from taking it away.

   THE COUNTERS. Measured side by side: the wishlist badge is 14x14 with 10px type, the bag badge
   12x12 with 11px type sitting 3px higher, so two identical-looking chips sat at two heights and
   two sizes. The wishlist one is the reference, as the owner asked. Only the bag moves.
   ------------------------------------------------------------------------ */
@media (hover: none) {
  body.jupiterx-header-overlapped:not(.stick):not(.zg-mega-open):not(.zg-mobile-menu-open)
    #header-row #cart-icon svg,
  body.jupiterx-header-overlapped:not(.stick):not(.zg-mega-open):not(.zg-mobile-menu-open)
    #header-row #fkcart-mini-toggler svg,
  body.jupiterx-header-overlapped:not(.stick):not(.zg-mega-open):not(.zg-mobile-menu-open)
    #header-row .fkcart-shortcode-icon-wrap svg {
    background-image: url("/wp-content/uploads/2026/09/zg-bag-light-v2.svg") !important;
    background-size: 20px 20px !important;
  }
}

/* Matched to the wishlist chip: same box, same type, same cream on the same taupe. The offset is
   what aligns the two centres; it is measured against the wishlist badge rather than guessed. */
/* right: -7px, not -6px. The badge is right-anchored, so growing it from 12px to 14px to match
   the wishlist chip moved its LEFT edge 2px inwards and it began covering the bag's handle by
   0.8px, which the "count badge clears bag handle" guard caught. One pixel out restores the
   clearance and changes neither the size nor the height that were the point of the change. */
#header-row .fkcart-item-count,
#header-row .fkcart-shortcode-container .fkcart-item-count {
  right: -7px !important;
  top: -2px !important;
  min-width: 14px !important;
  width: 14px !important;
  height: 14px !important;
  padding: 0 !important;
  font-size: 10px !important;
  line-height: 14px !important;
  text-align: center !important;
  color: var(--zg-cream) !important;
}


/* ---------------------------------------------------------------------------
   185. THE WORDMARK NEVER SLANTS
   ---------------------------------------------------------------------------
   Section 176 sets emphasis in reading copy as italic rather than bold, which is the Audo
   direction and is right for a phrase inside a sentence. It is wrong for the house name: the
   press page had "The house is written HOUSE OF ZIGGIMAY, in capitals" with the name itself in
   italic, which is a slanted wordmark in the one paragraph that exists to say how the wordmark
   is written.

   This is not a change to that decision. Emphasis stays italic everywhere else, including the
   fact labels and the fragrance names on the same page. Only an element explicitly marked as the
   wordmark opts out, and it keeps the weight so it still reads as emphasis.

   CSS cannot match text, so the name has to carry the class. Anywhere the wordmark is set inside
   running copy and needs to stand out, use <strong class="zg-wordmark">.
   ------------------------------------------------------------------------ */
.zg-wordmark,
.zg-guide p strong.zg-wordmark,
body.zg-audo .zg-guide p strong.zg-wordmark,
body.zg-audo .elementor-widget-raven-post-content p strong.zg-wordmark {
  font-style: normal !important;
  font-weight: 500 !important;
}


/* ---------------------------------------------------------------------------
   186. THE "NOT FOR EVERYONE" BAND
   ---------------------------------------------------------------------------
   From home-for-whom.php: a centred band on the homepage between the three promises under the
   hero and the collection grid, saying who the fragrances are for. Agreed with the owner on
   2026-10-03, in the style of the bands already there, so nothing new is introduced:

   - the eyebrow and the heading also carry .zg-choose__eyebrow and .zg-choose__h, and take their
     type from the rules those already have. Nothing is restated here, so the two cannot drift.
   - the paragraphs are band copy at the body step with the warm ink, as in the perfumer band,
     centred and held to a measure like the choosing band's intro.
   - the link is the perfumer band's "Read the whole story": a line of the text, not a button.
     A second dark button straight under "Explore samples" would shout.

   The band is cream like the collection section under it, and short at the bottom, so it reads
   as the way into the grid rather than as a block of its own.
   ------------------------------------------------------------------------ */
.zg-forwhom {
  background-color: var(--zg-cream);
  padding: clamp(3.5rem, 7vw, 6rem) 20px clamp(1.5rem, 3vw, 2.5rem);
}

.zg-forwhom__inner {
  max-width: 1160px;
  margin-inline: auto;
  text-align: center;
}

.zg-forwhom__p {
  max-width: min(56ch, 100%);
  margin: 0 auto 1.1em;
  font-size: var(--zg-fs-body);
  line-height: 1.55;
  color: var(--zg-copy, var(--zg-ink));
  text-wrap: pretty;
}

.zg-forwhom__more {
  display: inline-block;
  margin-top: 12px;
  padding: 5px 0 3px;
  border-bottom: 1px solid rgba(26, 24, 22, .3);
  color: #1A1816;
  font-family: FreightTextPro, Georgia, serif;
  font-style: italic;
  font-weight: 400;
  font-size: var(--zg-fs-lead);
  text-decoration: none;
  transition: border-color .18s ease;
}
.zg-forwhom__more:focus-visible { border-bottom-color: #1A1816; }
@media (hover: hover) {
  .zg-forwhom__more:hover { border-bottom-color: #1A1816; color: #1A1816; }
}
@media (prefers-reduced-motion: reduce) {
  .zg-forwhom__more { transition: none; }
}
