/* ============================================================================
 * Mammoth Mushrooms — storefront redesign
 * ============================================================================
 *
 * Applies the design system to Flatsome's and WooCommerce's own markup. Loaded
 * after the parent theme so it wins on equal specificity.
 *
 * EVERY value here is a var() from tokens.css. No raw hex, no bare px outside a
 * media query — that is the rule from `workspaces/site-as-code/CLAUDE.md` §5,
 * and it is checked by grep before every push.
 *
 * WHY CSS RATHER THAN TEMPLATE OVERRIDES
 * Flatsome ships heavily customised versions of the WooCommerce templates, and
 * those vendor files are not in this repo. Dropping a vanilla
 * `woocommerce/archive-product.php` in here would not restyle the shop, it
 * would replace Flatsome's shop with a plainer one and quietly lose behaviour.
 * So the redesign is done against the markup that already renders. Template
 * overrides come later, one at a time, once someone can diff them against the
 * Flatsome originals on staging.
 *
 * SPECIFICITY, AND WHY SECTION 10 EXISTS
 * Part of the storefront's current look lives in Customizer Custom CSS, which
 * is database, not files. WordPress prints it on `wp_head` at priority 101 —
 * after every enqueued stylesheet — so it wins any specificity tie. Matching
 * those rules is not enough; section 10 exceeds them, and names the exact rule
 * each override is beating so the pair can be retired together.
 *
 * That override war is a holding action, not the plan. The rules it fights
 * should be deleted in wp-admin: see
 * `workspaces/website-management/projects/site-redesign-2026/deliverables/customizer-css-to-remove.md`
 * in the brain repo. Every override in section 10 disappears with its partner.
 *
 * `!important` is used only where a Customizer rule already uses it, and every
 * instance is marked.
 *
 * Breakpoints are literal: custom properties do not resolve inside @media.
 * ========================================================================= */

/* ---------------------------------------------------------------------------
 * 1 · Ground and type
 * ------------------------------------------------------------------------ */

/* `html body`, not `body`, and that second element is load-bearing.
 *
 * Customizer Custom CSS carries `body { background-color: white; }`. That is
 * 0,0,1 — the same specificity this rule had — and WordPress prints the
 * Customizer block on `wp_head` at priority 101, after every enqueued
 * stylesheet, so it won the tie on document order and the page stayed white.
 *
 * Measured on the live shop page before this change: `.shop-container` painted
 * canvas across [15,167,360,3173] while `body` stayed rgb(255,255,255), which
 * is the white margin down both edges of the product grid that Tyler saw.
 *
 * Belongs to the section 10 family. The Customizer rule should be deleted, and
 * when it is, this can go back to a single `body`. */
html body,
.page-wrapper,
#main,
#wrapper {
  background-color: var(--mm-color-canvas);
}

/* `html` itself is rgb(77,77,77) — a dark grey nobody sees until the page is
 * over-scrolled, at which point iOS rubber-banding shows it above the header
 * or below the footer as a dark band. It is the element the browser paints the
 * overscroll area from, so it has to match. */
html {
  background-color: var(--mm-color-canvas);
}

body {
  font-family: var(--mm-font-body);
  font-weight: var(--mm-weight-body);
  font-size: var(--mm-text-base);
  line-height: var(--mm-leading-normal);
  color: var(--mm-color-ink);
}

h1, h2, h3, h4, h5, h6,
.entry-title,
.product-title,
.woocommerce-loop-product__title,
.page-title,
.section-title {
  font-family: var(--mm-font-display);
  color: var(--mm-color-ink);
  line-height: var(--mm-leading-tight);
}

h1, h2 { font-weight: var(--mm-weight-light); }
h3, h4, h5, h6 { font-weight: var(--mm-weight-regular); }

p, li, dd, td, .entry-content { color: var(--mm-color-ink); }

/* ...EXCEPT inside an Elementor text widget, which colours its WRAPPER and lets
 * the paragraph inherit. The rule above sets the colour on the paragraph
 * DIRECTLY, and a direct declaration beats an inherited one whatever the
 * specificity — so every Elementor text widget carrying a light colour on a
 * dark section rendered near-black on near-black.
 *
 * Tyler found it on the home page's "Myths / DEBUNKED" card, 2026-09-15:
 * measured, the widget computed #ffffff and the <p> inside it computed
 * #0a0a0a. That is not one card. It is every Elementor text widget on the site
 * that sets its own colour, and dark-on-dark is the failure that hides rather
 * than announces itself.
 *
 * `inherit` is right in both directions: where Elementor sets a colour the
 * paragraph takes it, and where it does not the widget inherits ink from
 * `body` and nothing changes. */
.elementor-widget-text-editor p,
.elementor-widget-text-editor li,
.elementor-widget-theme-post-content p,
.elementor-widget-theme-post-content li,
.elementor-widget-theme-post-excerpt p { color: inherit; }

/* Blog cards on the home page show their title and nothing else — Tyler,
 * 2026-09-15. The excerpt is still rendered for the archive and the post
 * itself; it is only the home page teaser row that drops it. */
body.home .elementor-post__excerpt { display: none; }

a { color: var(--mm-color-brand-deep); }
a:hover { color: var(--mm-color-ink); }

/* Numerals take the monospace: prices, review counts, stock, quantities.
 * Labels do NOT — in the design only the digits change face. */
.price,
.woocommerce-Price-amount,
.woocommerce-Price-currencySymbol,
.mm-per-gram-price,
.woocommerce-review-link,
.cart-subtotal .woocommerce-Price-amount,
.order-total .woocommerce-Price-amount,
.ux-quantity input.qty {
  font-family: var(--mm-font-numeric);
  font-variant-numeric: tabular-nums;
}

.price del,
.price del .woocommerce-Price-amount {
  color: var(--mm-color-ink-muted);
  font-size: var(--mm-text-sm);
}
.price ins { text-decoration: none; }

/* The category eyebrow above a product title. */
.product-cat,
.woocommerce-breadcrumb,
.breadcrumbs {
  font-family: var(--mm-font-display);
  font-size: var(--mm-text-xs);
  text-transform: uppercase;
  letter-spacing: var(--mm-tracking-wide);
  color: var(--mm-color-ink-muted);
}

/* ---------------------------------------------------------------------------
 * 2 · Buttons — amber with ink on it, near-square
 * ------------------------------------------------------------------------ */

.button,
button.button,
input[type="submit"].button,
.button.primary,
.add_to_cart_button,
.single_add_to_cart_button,
.checkout-button,
.wc-forward,
.woocommerce-Button {
  font-family: var(--mm-font-display);
  font-weight: var(--mm-weight-bold);
  font-size: var(--mm-text-xs);
  text-transform: uppercase;
  letter-spacing: var(--mm-tracking-wide);
  border-radius: var(--mm-radius-btn);
  border: 0;
  background-color: var(--mm-color-brand);
  color: var(--mm-color-on-brand);
  transition: background-color var(--mm-motion-base) var(--mm-ease),
              color var(--mm-motion-base) var(--mm-ease);
}

.button:hover,
button.button:hover,
.add_to_cart_button:hover,
.single_add_to_cart_button:hover,
.checkout-button:hover,
.woocommerce-Button:hover {
  background-color: var(--mm-color-brand-deep);
  color: var(--mm-color-on-contrast);
}

/* Secondary action: hairline outline, no fill. */
.button.is-outline,
.button.secondary.is-outline,
.button-continue-shopping,
.woocommerce-button--previous {
  background-color: transparent;
  color: var(--mm-color-ink);
  box-shadow: inset 0 0 0 var(--mm-hairline) var(--mm-color-border);
  border-radius: var(--mm-radius-btn);
}
.button.is-outline:hover,
.button-continue-shopping:hover {
  background-color: var(--mm-color-ink);
  color: var(--mm-color-on-contrast);
  box-shadow: none;
}

/* Focus must stay visible — Flatsome removes outlines in places. */
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
.button:focus-visible {
  outline: var(--mm-focus-ring) solid var(--mm-color-contrast);
  outline-offset: var(--mm-focus-ring);
}

/* ---------------------------------------------------------------------------
 * 3 · Product cards
 * ------------------------------------------------------------------------ */

.products .product .col-inner,
.product-small .col-inner {
  background-color: var(--mm-color-surface);
  border-radius: var(--mm-radius-card);
  box-shadow: var(--mm-shadow-card);
  overflow: hidden;
  height: 100%;
  display: flex;
  flex-direction: column;
  transition: box-shadow var(--mm-motion-base) var(--mm-ease);
}
.products .product .col-inner:hover,
.product-small .col-inner:hover {
  box-shadow: var(--mm-shadow-raised);
}

/* Flatsome nests `.box` INSIDE `.col-inner`, so the card above draws a white
 * rounded surface and then `.box` draws a hard black rectangle on top of it —
 * which is what the shop grid rendered as: sharp-cornered outlined boxes with
 * a 4px radius nobody could see. The surface, the radius and the shadow all
 * belong to one element, and that element is `.col-inner`.
 *
 * Beats: `.products .box { border: 1px solid black; }` — Customizer Custom CSS,
 * 0,2,0, printed at wp_head priority 101, so this needs 0,3,1 to win a
 * later-and-equal fight. Partner entry in `customizer-css-to-remove.md`. */
body .products .product .box,
body .products .product .box.product-small {
  border: 0;
  border-radius: 0;
  background-color: transparent;

  /* `.box` sits BETWEEN `.col-inner` and `.box-text`, so `flex: 1` on the text
   * block reached a grandchild of the flex container and did nothing: the text
   * sized to its content and `margin-top: auto` on the button had no free space
   * to push into. Flatsome's JS height equalisation was hiding that; with the
   * inline heights gone (see section 3) the buttons in a row stopped lining up
   * — measured 31px apart on the Chocolates and Tea cards at 1440px.
   *
   * Making `.box` a column that fills its parent restores the chain, and does
   * it from layout rather than from a JavaScript measurement. */
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  min-height: 0;
}

.product-small .box-image {
  background-color: var(--mm-color-sand);
  border-radius: 0;
}

/* `fill` is Flatsome's default and it squashes any thumbnail that is not
 * square. Every product image in the catalogue is 800x800 today, so this
 * changes nothing on screen now and stops the day one is not. */
.product-small .box-image img {
  object-fit: cover;
}

.product-small .box-text,
.product-small .box-text-products {
  background-color: var(--mm-color-surface);
  padding: var(--mm-space-5);
  text-align: left;
  display: flex;
  flex-direction: column;
  gap: var(--mm-space-2);
  flex: 1;
}

.product-small .product-title,
.product-small .woocommerce-loop-product__title {
  font-family: var(--mm-font-display);
  font-weight: var(--mm-weight-regular);
  font-size: var(--mm-text-lg);
  line-height: var(--mm-leading-tight);
  margin: 0;
}
.product-small .product-title a { color: var(--mm-color-ink); text-decoration: none; }

.product-small .price-wrapper,
.product-small .price { margin: 0; }

/* Flatsome equalises cards by writing INLINE pixel heights onto `.box-text`,
 * `.title-wrapper`, `.price-wrapper` and `.add-to-cart-button` from JavaScript,
 * so a row's buttons line up. Measured at 768px on the Tea card: the price
 * wrapper needs 75px and was pinned to 51px, which cut "C$10.30 / 1g" in half
 * under the button — the card above clips it because the radius needs
 * `overflow: hidden`.
 *
 * The equalising is redundant here: the card is already a flex column at
 * `height: 100%` with the button on `margin-top: auto`, which lines the buttons
 * up from layout rather than from a measurement taken before the fonts land.
 *
 * `!important` is the only thing that beats an inline style, and an inline
 * style written by vendor JavaScript is the one case the note at the top of
 * this file does not cover. It is scoped to the four wrappers that JS touches,
 * and to `height` alone. */
.product-small .box-text,
.product-small .box-text .title-wrapper,
.product-small .box-text .price-wrapper,
.product-small .box-text .add-to-cart-button { height: auto !important; }

/* The add-to-cart pins to the bottom so a grid of uneven titles lines up, and
 * fills the card the way the handoff draws it. Flatsome nests the button
 * inside .add-to-cart-button (and sometimes a bare wrapper), so both the
 * wrapper and the button itself have to be told. */
.product-small .box-text .add-to-cart-button,
.product-small .box-text .button-wrapper {
  margin-top: auto;
  width: 100%;
}
.product-small .box-text .add_to_cart_button,
.product-small .box-text .add-to-cart-button > a.button,
.product-small .box-text > .button,
.product-small .box-text a.button {
  margin-top: auto;
  margin-bottom: 0;
  display: block;
  width: 100%;
  text-align: center;
}

/* Ratings read as five black glyphs on the grid today, which is heavier than
 * anything else on the card and reads as a warning rather than a review score.
 * The design system draws them amber, with the unfilled remainder in the same
 * hairline grey that closes every card — so the fraction is legible.
 *
 * These lost at 0,1,1 before this pass. Beats, all Customizer Custom CSS at
 * wp_head priority 101 (partner entries in `customizer-css-to-remove.md`):
 *   `.star-rating span:before { color: black; }`              — 0,1,1
 *   `.star-rating:before, .woocommerce-page .star-rating:before
 *      { color: grey; }`                                      — 0,1,1
 *   `.woocommerce ul.products li.product .star-rating
 *      { color: black; }`                                     — 0,3,3
 * so the filled glyph is written at 0,4,4 and the track at 0,4,2. */
body.woocommerce .star-rating,
body.woocommerce-page .star-rating,
body .woocommerce ul.products li.product .star-rating,
body .products .product .star-rating { color: var(--mm-color-star); }

body .woocommerce ul.products li.product .star-rating span::before,
body .products .product .star-rating span::before,
body.woocommerce .star-rating span::before,
body.woocommerce-page .star-rating span::before { color: var(--mm-color-star); }

body .woocommerce ul.products li.product .star-rating::before,
body .products .product .star-rating::before,
body.woocommerce .star-rating::before,
body.woocommerce-page .star-rating::before { color: var(--mm-color-border); }

/* ---------------------------------------------------------------------------
 * 3b · What Tyler asked for on the cards, 2026-09-15
 * ------------------------------------------------------------------------ */

/* ADD TO CART on one line.
 *
 * The button wraps to two lines on a narrow card, which doubles the card's
 * height and pushes the price away from it. `nowrap` settles it; the padding
 * comes in so the label still fits the narrowest card in the grid rather than
 * overflowing it, which is the failure `nowrap` would otherwise trade for. */
body .product-small .box-text a.button,
body .product-small .box-text .add-to-cart-button a.button,
body .products .product .box-text a.button {
  white-space: nowrap;
  padding-left: var(--mm-space-2);
  padding-right: var(--mm-space-2);
  overflow: hidden;
  text-overflow: ellipsis;
}

/* The wishlist heart comes off every product card.
 *
 * Tyler, 2026-09-15: "Should also remove the heart to like the product." It is
 * hidden rather than dequeued — the YITH plugin still runs, so any existing
 * wishlist and the account page keep working, and restoring it is deleting
 * this block. `pointer-events` because an invisible control that still takes a
 * tap is worse than a visible one. */
body .product-small .wishlist-button,
body .products .product .wishlist-button,
body .product-small [class*="yith-wcwl"],
body .products .product [class*="yith-wcwl"] {
  display: none !important;   /* beats the theme's own inline show-on-hover */
  pointer-events: none;
}

/* The category eyebrow comes off the HOME page only.
 *
 * On a card under a heading that already names the category it is repetition,
 * and at 175px wide it truncated to "FUNCTIONAL FUNG". On the shop page the
 * same eyebrow is the only thing telling you what a product is, so it stays
 * there — hence `body.home` rather than a blanket rule. */
/* The category line on a product card, everywhere it appears — it used to be
 * hidden only on the home page.
 *
 * Tyler, 2026-09-16: "remove the product category from showing on the product
 * card here". On the shop page it is redundant twice over: the filter row above
 * the grid already names the category, and it is usually the one the visitor
 * just picked. It renders as `p.category.uppercase.is-smaller` and reads
 * "Capsules" above "Psilocybin Microdose Capsules - 90mg x 30", so it is also
 * repeating the next line.
 *
 * `display: none` rather than visually-hidden: a screen reader does not need
 * the category twice either. */
body .product-small .category,
body .product-small .product-cat,
body .products .product .category,
body .products .product .product-cat { display: none; }

/* ---------------------------------------------------------------------------
 * 4 · The offer badge
 * ------------------------------------------------------------------------ */
/* Solid amber pill, ink on it. Chosen 2026-09-04 after the tinted chip read as
 * clutter over a busy product photo — a solid shape holds its edge against any
 * image, a tinted one does not.
 *
 * The pill radius is the one deliberate exception to the near-square storefront
 * scale. A badge is a label, not a control, and the design's near-square rule
 * is about buttons and cards. --mm-radius-pill already exists for the email
 * templates, so no new token.
 *
 * The badge is declared twice: once in functions.php (tokenised) and once in
 * Customizer Custom CSS, which sets white on amber at 12px with
 * `border-radius: 0 !important`. See section 10 for the override. */

body .mm-product-badge {
  /* Sized down 2026-09-05. At --mm-text-xs with wide tracking and space-4
   * padding this was a 207px banner across a 247px card — it read as a label
   * applied TO the photograph rather than a mark on the card, and it covered
   * the product. The micro-label step, tighter tracking and half the padding
   * make it a chip tucked into the corner: measured 116px, and the product
   * inside the photo is visible again. */
  font-family: var(--mm-font-display);
  font-weight: var(--mm-weight-bold);
  font-size: var(--mm-text-2xs);
  text-transform: uppercase;
  letter-spacing: var(--mm-tracking-display);
  background-color: var(--mm-color-brand);
  color: var(--mm-color-on-brand);
  border: 0;
  /* Straddling the top edge of the photo, half on and half off — Tyler,
   * 2026-09-16. `top: 0` is the top of the card, which is also the top of the
   * image (measured: card top 595, image top 595), and the translate lifts it
   * by half its own height so the edge runs through its middle.
   *
   * Tighter than it was, too: the padding drops a step on each axis and the
   * tracking comes in. The font size stays at --mm-text-2xs because 12px is
   * the smallest step in the scale and a label is not the place to go under
   * it. */
  padding: var(--mm-space-1) var(--mm-space-2);
  letter-spacing: var(--mm-tracking-display);
  top: 0;
  left: var(--mm-space-2);
  transform: translateY(-50%);
  line-height: var(--mm-leading-tight);
  width: auto;
  box-shadow: var(--mm-shadow-card);

  /* The badge is written by inline JavaScript in the database, as an `<h2>`
   * with `width: auto` set from `.css()`, so nothing stops it growing past the
   * card. Measured at 390px: "LIMITED TIME OFFER" ran off the right edge of a
   * 170px card and was cut in half by the card's own `overflow: hidden`.
   *
   * The reserve here is small on purpose: at a 247px card "LIMITED TIME OFFER"
   * sets in one line inside 223px, and a wider reserve wrapped it to two for no
   * reason. `box-sizing` because the padding is on this element. */
  box-sizing: border-box;
  max-width: calc(100% - var(--mm-space-6));
}

/* The card has to let the badge hang over its top edge.
 *
 * `.col-inner` is `overflow: hidden` and its top edge is the image's top edge,
 * so a badge straddling that edge loses its upper half. Measured: three nested
 * clippers — `.image-fade_in_back`, `.box-image` and `.col-inner` — all
 * starting at the same y.
 *
 * Only the outermost one opens. The two inside it stay hidden, which is what
 * keeps the hover zoom inside the photo (see the zoom block in functions.php)
 * and what clips the photo to the card's corners.
 *
 * Scoped to product cards, so no other `.col-inner` on the site is touched. */
body .product-small .col-inner,
body .products .product .col-inner {
  overflow: visible;
}

/* "ADD TO CA…" — the button was ellipsising its own label.
 *
 * NOT caused by the badge work: measured identically on main before any of it.
 * At 390px the button is 138px wide and "Add to cart" needs 159px at 14px with
 * 8px of padding either side, so `text-overflow: ellipsis` did what it was told
 * and cut the word. That rule is there to keep the label on ONE line, which
 * Tyler asked for on 2026-09-15 — one line was the point, and a truncated line
 * is not what he asked for.
 *
 * The label is made to fit rather than the rule removed: a step down the type
 * scale and a step in on the padding gives back about 28px, which clears the
 * 21px shortfall. The ellipsis stays as the backstop for a longer label. */
@media (max-width: 549px) {

  body .product-small .box-text a.button,
  body .products .product .box-text a.button {
    font-size: var(--mm-text-2xs);
    padding-left: var(--mm-space-1);
    padding-right: var(--mm-space-1);
  }
}

/* Two columns of 170px cards. The reserve here was --mm-space-16, and at 64px
 * it left 106px of a 170px card — narrower than the two longest badges, so
 * "LIMITED TIME OFFER" (143px set in one line) and "HIGHEST POTENCY" (132px)
 * wrapped to two and covered a third of the product photo. Every other badge
 * on the shop page is 91px or less and already set in one line.
 *
 * The 64px was reserved for the wishlist button on the assumption that
 * Flatsome shows it without hover at touch widths. Measured on staging at
 * 390px, that is not what renders: the `.image-tools` cluster is a 5px box in
 * the top-right corner carrying `show-on-hover`. A --mm-space-4 reserve leaves
 * 154px, which sets the longest badge in one line and still stops its right
 * edge 15px short of that cluster.
 *
 * The cap stays rather than becoming `nowrap` so a longer badge someone types
 * in wp-admin later wraps instead of running out of the card. */
@media (max-width: 549px) {
  body .mm-product-badge {
    /* THREE PIXELS. Measured by cloning the badge and letting it size itself:
     * "LIMITED TIME OFFER" wants 157px on one line including its padding, and
     * the cap here gave it 154. So it wrapped, and two lines of 14.4 plus 8 of
     * padding is the 37px-tall block sitting across the product photo.
     *
     * Estimating that width from a character count said 142px and was wrong
     * twice — once before the tracking was removed and once after, which is how
     * a tracking change that could not have fixed it got written. The clone is
     * the measurement.
     *
     * Padding comes down to one step all round, which takes the requirement to
     * about 149, and the cap goes up to 162 so there is real headroom rather
     * than three pixels of it — a font that loads slightly wider should not put
     * the badge back on two lines. One line is 23px: the badge loses 38% of its
     * height and some of its width at the same time. */
    max-width: calc(100% - var(--mm-space-2));
    padding: var(--mm-space-1);

    /* Normal tracking HERE ONLY, and it is what makes the badge smaller.
     *
     * Measured at 390px: the badge was 154x37 — its cap is 154px on a 170px
     * image, "LIMITED TIME OFFER" needs about 142px at 12px with 0.72px of
     * tracking, and 16px of that 154 is padding. So it had 138px for 142px of
     * text and wrapped to two lines. 37px is two lines of 14.4 plus 8 of
     * padding, not one tall label.
     *
     * Dropping the tracking gives back roughly 13px, which is the difference
     * between wrapping and not. One line is 22px — the badge loses 40% of its
     * height without the font going below 12px, which is the smallest step in
     * the scale and not somewhere a label should go.
     *
     * The display tracking stays above this breakpoint, where a 247px card has
     * the room for it. */
    letter-spacing: normal;
  }
}

.badge-container .badge-inner {
  background-color: var(--mm-color-contrast);
  color: var(--mm-color-on-contrast);
  border-radius: var(--mm-radius-sm);
  font-family: var(--mm-font-display);
  font-size: var(--mm-text-xs);
  text-transform: uppercase;
  letter-spacing: var(--mm-tracking-wide);
}

/* ---------------------------------------------------------------------------
 * 5 · Shop and category archives
 * ------------------------------------------------------------------------ */

/* Background only. The shop and category archives currently render no <h1>
 * (baseline: 0 on both), so adding padding here opens an empty band rather
 * than framing a heading. Padding goes in when the heading does — that is part
 * of the category restructure, where each category gains an SEO <h1> and an
 * intro line. */
.woocommerce-shop .page-title,
.tax-product_cat .page-title,
.archive .page-title {
  background-color: var(--mm-color-sand);
  border-bottom: 0;
}
.woocommerce-shop .page-title:empty,
.tax-product_cat .page-title:empty {
  display: none;
}

.woocommerce-products-header__title,
.tax-product_cat h1.page-title,
.woocommerce-shop h1.page-title {
  font-family: var(--mm-font-display);
  font-weight: var(--mm-weight-light);
  font-size: var(--mm-text-3xl);
  margin-bottom: var(--mm-space-2);
}

.term-description,
.woocommerce-products-header .term-description {
  color: var(--mm-color-ink-muted);
  font-size: var(--mm-text-base);
  max-width: 66ch;
}

.woocommerce-ordering select,
.woocommerce-ordering .select-resize-ghost,
select.orderby {
  font-family: var(--mm-font-display);
  font-size: var(--mm-text-sm);
  background-color: var(--mm-color-surface);
  border: var(--mm-hairline) solid var(--mm-color-border);
  border-radius: var(--mm-radius-btn);
  color: var(--mm-color-ink);
}

.shop-container { background-color: var(--mm-color-canvas); }

/* ---------------------------------------------------------------------------
 * 6 · Single product
 * ------------------------------------------------------------------------ */

.single-product .product-main,
.single-product .product-container { background-color: var(--mm-color-canvas); }

.single-product .product-title,
.single-product h1.product-title {
  font-family: var(--mm-font-display);
  font-weight: var(--mm-weight-light);
  font-size: var(--mm-text-3xl);
  line-height: var(--mm-leading-tight);
}

.single-product .product-images,
.single-product .woocommerce-product-gallery {
  background-color: var(--mm-color-sand);
  border-radius: var(--mm-radius-card);
  overflow: hidden;
}

.single-product .price,
.single-product .product-page-price {
  font-size: var(--mm-text-xl);
  color: var(--mm-color-ink);
}

.ux-quantity {
  border: var(--mm-hairline) solid var(--mm-color-border);
  border-radius: var(--mm-radius-btn);
  background-color: var(--mm-color-surface);
  overflow: hidden;
}
.ux-quantity__button {
  background-color: transparent;
  color: var(--mm-color-ink);
  border: 0;
}
.ux-quantity__button:hover { background-color: var(--mm-color-sand); }

.woocommerce-tabs .nav > li > a,
.woocommerce-Tabs-panel {
  font-family: var(--mm-font-body);
  color: var(--mm-color-ink);
}
.woocommerce-tabs .nav > li > a {
  font-family: var(--mm-font-display);
  font-size: var(--mm-text-xs);
  text-transform: uppercase;
  letter-spacing: var(--mm-tracking-wide);
}
.woocommerce-tabs .nav > li.active > a { border-bottom-color: var(--mm-color-brand); }

.related.products,
.up-sells.products {
  border-top: var(--mm-hairline) solid var(--mm-color-border);
  padding-top: var(--mm-space-12);
}

/* ---------------------------------------------------------------------------
 * 7 · Cart and checkout
 * ------------------------------------------------------------------------ */

.woocommerce-cart-form,
.cart_totals,
.woocommerce-checkout-review-order,
.woocommerce-billing-fields {
  background-color: var(--mm-color-surface);
  border-radius: var(--mm-radius-card);
  box-shadow: var(--mm-shadow-card);
  padding: var(--mm-space-6);
}

.shop_table,
.shop_table th,
.shop_table td { border-color: var(--mm-color-border); }

.shop_table th {
  font-family: var(--mm-font-display);
  font-size: var(--mm-text-xs);
  text-transform: uppercase;
  letter-spacing: var(--mm-tracking-wide);
  color: var(--mm-color-ink-muted);
  font-weight: var(--mm-weight-regular);
}

.cart_item .product-name a { color: var(--mm-color-ink); text-decoration: none; }
.cart_item .product-thumbnail img { border-radius: var(--mm-radius-sm); }

.cart-sidebar .col-inner,
.checkout-sidebar .col-inner { background-color: transparent; }

.woocommerce-checkout .form-row label,
.woocommerce-billing-fields label,
.woocommerce-shipping-fields label {
  font-family: var(--mm-font-display);
  font-size: var(--mm-text-xs);
  text-transform: uppercase;
  letter-spacing: var(--mm-tracking-wide);
  color: var(--mm-color-ink-muted);
}

.woocommerce input[type="text"],
.woocommerce input[type="email"],
.woocommerce input[type="tel"],
.woocommerce input[type="password"],
.woocommerce input[type="number"],
.woocommerce textarea,
.woocommerce select,
.woocommerce .select2-container .select2-selection {
  font-family: var(--mm-font-body);
  font-size: var(--mm-text-base);
  color: var(--mm-color-ink);
  background-color: var(--mm-color-surface);
  border: var(--mm-hairline) solid var(--mm-color-border);
  border-radius: var(--mm-radius-btn);
  box-shadow: none;
}
.woocommerce input:focus,
.woocommerce textarea:focus,
.woocommerce select:focus { border-color: var(--mm-color-brand); }

.woocommerce-info,
.woocommerce-message,
.woocommerce-error {
  background-color: var(--mm-color-brand-tint);
  border: var(--mm-hairline) solid var(--mm-color-brand-tint-border);
  border-radius: var(--mm-radius-card);
  color: var(--mm-color-brand-deep);
}

.order-total .woocommerce-Price-amount { font-size: var(--mm-text-xl); }

/* ---------------------------------------------------------------------------
 * 8 · Header
 * ------------------------------------------------------------------------ */
/* The header is NOT a Flatsome header. It is an Elementor Theme Builder
 * template — `<header data-elementor-type="header" data-elementor-id="10">` —
 * so `.header-main`, `#masthead` and `.nav > li > a` match nothing on this
 * site. Rules written against them shipped on 2026-09-04 and did nothing at
 * all; they are gone, and this section is written against the markup that
 * actually renders. Verified against
 * `projects/site-redesign-2026/research/html/home-desktop.html`.
 *
 * The desktop header row is a flex container holding three sibling blocks, in
 * this source order: nav, cart, logo. That order lives in the Elementor
 * template, which is database — but flex `order` reseats them from here, which
 * is how a layout change that is nominally database gets made in files.
 *
 * The blocks are selected by WHAT THEY CONTAIN, not by their Elementor id.
 * Ids survive most builder edits but not a delete-and-recreate; "the block
 * holding the logo image" survives both. `:has()` is baseline in every browser
 * this site supports; where it is not, the rules simply do not apply and the
 * header renders in its current order rather than breaking. */

.elementor-location-header > .e-con:not(.elementor-hidden-desktop) .e-con:has(> .elementor-widget-image) {
  order: 1;
  flex: 0 0 auto;
  --width: 16%;
}
.elementor-location-header > .e-con:not(.elementor-hidden-desktop) .e-con:has(> .elementor-widget-nav-menu) {
  order: 2;
  flex: 1 1 auto;
  justify-content: center;
  --width: auto;
}
.elementor-location-header > .e-con:not(.elementor-hidden-desktop) .e-con:has(> .elementor-widget-woocommerce-menu-cart) {
  order: 3;
  flex: 0 0 auto;
  --width: 9%;
}

/* Eight nav items do not fit the bar as Elementor sizes it — measured, not
 * guessed: the menu wrapped onto a second row at 1440px. Three things buy the
 * room back, and none of them shrinks the logo as it appears on screen:
 *
 *   · the boxed header widens to the design system's container (1200px);
 *   · the logo BLOCK goes from 28% to 16%, and its image from 60% to 100% of
 *     that block — 0.28 × 0.60 and 0.16 × 1.00 land within a few pixels of
 *     each other, so the wordmark renders the same size and gives back ~130px;
 *   · the cart block goes from 12% to 9%, which is still wider than the icon.
 *
 * Elementor consumes `--width` on `.e-con`, so setting the custom property is
 * enough; no width rule has to out-specify anything. */
.elementor-location-header > .e-con:not(.elementor-hidden-desktop) > .e-con-inner {
  max-width: var(--mm-container-max);
}
.elementor-location-header > .e-con:not(.elementor-hidden-desktop) .elementor-widget-image img {
  width: 100%;
}

/* Spread the nav items across the space between logo and cart.
 *
 * Two things had to be true and only one of them was. Elementor's widget is
 * set to "stretch", so its <nav> fills the block — but the <ul> inside is a
 * flex item that shrinks to its content, and a `justify-content` on something
 * already exactly content-width moves nothing. Measured at 1440: the block ran
 * 313–1212, the <nav> 313–1192, and the <ul> 313–734, hard against the logo.
 *
 * So the list is told to fill its container first, and then to space its items
 * across it. Below 1024 the responsive block flips the same list to flex-start
 * and lets it scroll, which needs the full width just as much.
 *
 * HOW MUCH AIR — a settled judgement, not a default. Centred with no gap, the
 * four labels clustered in the middle of a wide bar. `space-evenly` across the
 * full width pushed them so far apart they stopped reading as one nav. Tyler
 * asked for the midpoint, so the group is centred again and the air goes
 * between the items rather than at the ends.
 *
 * Measured at 1440, first label's right edge to last label's right edge:
 * clustered 304px, space-evenly 533px — midpoint about 418px. A 40px gap gives
 * 424px, the closest any token lands, which is why this is `--mm-space-10` and
 * not a rounder-looking `--mm-space-12` (448px) or `--mm-space-8` (400px).
 *
 * The gap carries into the sub-1024 block too, where the list flips to
 * flex-start and scrolls. Four items at 421px of content plus three 40px gaps
 * is 541px against a 645px track at 900, so it still fits without scrolling. */
.elementor-location-header > .e-con:not(.elementor-hidden-desktop) .elementor-nav-menu--main > .elementor-nav-menu {
  flex: 1 1 auto;
  justify-content: center;
  column-gap: var(--mm-space-10);
}

/* Nav type, and the specificity it has to clear.
 *
 * Elementor writes per-element CSS into
 * `uploads/elementor/css/post-10.css`, and its nav rule is
 *
 *   .elementor-10 .elementor-element.elementor-element-8ef55dd
 *     .elementor-nav-menu .elementor-item
 *       { font-family:"Avenir"; font-size:19px; font-weight:600; }
 *
 * which is 0,5,0 — five classes. A sane selector like
 * `.elementor-location-header .elementor-nav-menu > li > a.elementor-item`
 * is 0,3,1 and loses. That is not a hypothetical: the first version of this
 * section rendered in Avenir at 19px and nobody would have known from reading
 * the diff.
 *
 * `.elementor-item` is repeated to reach 0,5,3 without naming
 * `elementor-element-8ef55dd`, which is a builder id and would break the day
 * the widget is recreated. It looks odd on purpose.
 *
 * The header ground is light — Elementor paints it #CFCFCF under a 50% white
 * overlay — so ink is a safe foreground. Checked against the render, not
 * assumed. */
body .elementor-location-header .elementor-nav-menu > li > a.elementor-item.elementor-item.elementor-item {
  font-family: var(--mm-font-display);
  font-size: var(--mm-text-xs);
  font-weight: var(--mm-weight-body);
  text-transform: uppercase;
  letter-spacing: var(--mm-tracking-wide);
  color: var(--mm-color-ink);
  padding-left: var(--mm-space-2);
  padding-right: var(--mm-space-2);
}

/* The nav sits between the logo and the cart with a real gap on the cart side,
 * so the amber pill never touches the cart icon. */
.elementor-location-header > .e-con:not(.elementor-hidden-desktop) .e-con:has(> .elementor-widget-nav-menu) {
  padding-right: var(--mm-space-5);
}

/* Hover and current page are never colour-only — an amber rule carries the
 * state, so it survives a greyscale print and a colour-blind reader. */
body .elementor-location-header .elementor-nav-menu > li > a.elementor-item.elementor-item.elementor-item:hover,
body .elementor-location-header .elementor-nav-menu > li > a.elementor-item.elementor-item.elementor-item-active {
  color: var(--mm-color-ink);
  box-shadow: inset 0 calc(-1 * var(--mm-focus-ring)) 0 0 var(--mm-color-brand);
}

/* The bar itself: surface white, no outline.
 *
 * Elementor paints it grey (#CFCFCF) inside a 1px #141414 stroke with 20px
 * corners — the ring you can see drawn around the logo, the nav and the cart.
 * The stroke is gone as of 2026-09-04; the fill stays.
 *
 * The fill is not decoration. The header is sticky and it sits over the home
 * page's dark forest hero, so a transparent bar would put ink nav labels on a
 * near-black photograph. Removing the ring is safe; removing the ground is a
 * contrast defect waiting for the first scroll.
 *
 * Applies to the mobile bar too — it carries the same ring, and there is no
 * reason for the two to disagree.
 *
 * Beats: `.elementor-10 .elementor-element.elementor-element-aeb8300
 *         { border-width:1px 1px 1px 1px; border-color:#141414; }` and the
 * matching `:not(.elementor-motion-effects-element-type-background)` background
 * rule — 0,3,0 and 0,5,0 respectively. The `:not(#no)` carries an id so both
 * are cleared without naming a builder element. */
body .elementor-location-header .e-con:has(> .e-con):not(#no) {
  background-color: var(--mm-color-surface);
  border-width: 0;
  --border-top-width: 0;
  --border-right-width: 0;
  --border-bottom-width: 0;
  --border-left-width: 0;
}

/* Submenus pick up the card treatment rather than Elementor's black hairline. */
body .elementor-location-header .elementor-nav-menu--dropdown {
  background-color: var(--mm-color-surface);
  border-color: var(--mm-color-border);
  border-radius: var(--mm-radius-card);
  box-shadow: var(--mm-shadow-card);
}
body .elementor-location-header .elementor-nav-menu--dropdown a.elementor-sub-item.elementor-sub-item.elementor-sub-item {
  font-family: var(--mm-font-display);
  font-size: var(--mm-text-xs);
  color: var(--mm-color-ink);
}
body .elementor-location-header .elementor-nav-menu--dropdown a.elementor-sub-item.elementor-sub-item.elementor-sub-item:hover {
  background-color: var(--mm-color-brand-tint);
  color: var(--mm-color-ink);
}

/* ---------------------------------------------------------------------------
 * 8b · The one highlighted nav item
 * ------------------------------------------------------------------------ */
/* Grizzly marks one destination with a filled green pill. This is the same
 * move in amber. The class is applied by the `mammoth-nav` plugin, which puts
 * it on whatever item points at `/shop/`; typing `mm-nav-highlight` into a
 * menu item's CSS Classes box in wp-admin does the same thing.
 *
 * Ink on amber, never white: white on #ffb301 measures about 1.9:1 and fails
 * WCAG AA. Settled in tokens.css, and this is one of the places it would be
 * easy to get wrong. */
body .elementor-location-header .elementor-nav-menu > li.mm-nav-highlight > a.elementor-item.elementor-item.elementor-item,
body .elementor-location-header .elementor-nav-menu > li.mm-nav-highlight > a.elementor-item.elementor-item.elementor-item-active {
  background-color: var(--mm-color-brand);
  color: var(--mm-color-on-brand);
  border-radius: var(--mm-radius-pill);
  padding-left: var(--mm-space-4);
  padding-right: var(--mm-space-4);
  box-shadow: none;
}
body .elementor-location-header .elementor-nav-menu > li.mm-nav-highlight > a.elementor-item.elementor-item.elementor-item:hover {
  background-color: var(--mm-color-brand-deep);
  color: var(--mm-color-on-contrast);
  box-shadow: none;
}

/* The mobile header keeps its own order (logo, cart, burger) — it is a
 * separate Elementor container and nothing above reaches it. The Elementor
 * footer is likewise untouched for now: its colours are set per widget inside
 * the builder, so recolouring it blind is how you get invisible text on a dark
 * band. It is stage-4 tidy-up work, done with eyes on staging. */

/* ---------------------------------------------------------------------------
 * 8c · The mobile header's negative bottom margin
 * ------------------------------------------------------------------------ */
/* The mobile header container carries `margin-bottom: -125px` in the Elementor
 * template. That is the transparent-header trick: it pulls the page body up so
 * the home hero starts at y=0 and the white header pill floats over it. On the
 * home page it is deliberate and it looks right.
 *
 * Every other page inherits it and has no hero to tuck under, so the top 125px
 * of the page body ends up behind an opaque header. Measured on staging at
 * 390px, header bottom 87:
 *
 *   /shop/     `.row.category-page-row` top -38 · its 80px padding gets the
 *              content down to 42, which is still 45px above the header's
 *              bottom edge, so the category filter row — ALL, FUNCTIONAL
 *              FUNGI, CAPSULES, WHOLE MUSHROOMS, TEA, TINCTURES, measured at
 *              46-80 — renders entirely behind the header. It is buried at
 *              every width swept from 320 to 700. The product cards start at
 *              134 and are NOT clipped; the filter row is the whole symptom.
 *   /product/  `.shop-container` top -38 — the full 125px is buried
 *   /          top -38, which is the point
 *
 * Desktop is untouched either way: up there this container is `display: none`
 * and the desktop one has no negative margin, which is why the bug is
 * mobile-only. Verified on staging before and after: desktop numbers identical
 * on all four pages, mobile content lands flush at the header's bottom edge.
 *
 * `body:not(.home)` keeps the home overlay. Doubling the class beats
 * Elementor's own `.elementor-10 .elementor-element.elementor-element-e276df1`
 * without naming that id, which a delete-and-recreate in the builder would
 * change. Both properties because Elementor writes the logical one. */

body:not(.home) .elementor-location-header > .elementor-element.elementor-element {
  margin-bottom: 0;
  margin-block-end: 0;
}

/* ---------------------------------------------------------------------------
 * 9 · Responsive
 * ------------------------------------------------------------------------ */
/* Literal breakpoints: custom properties do not resolve inside @media.
 * 1440 desktop / 768 tablet / 375 mobile are the three verified widths. */

/* Between the mobile breakpoint and a full desktop the eight nav items are
 * wider than the bar. Measured at 1100px: they wrapped. Tightening the
 * tracking to the display value and the padding to one step buys back about
 * 120px, which clears it — verified by re-rendering at 1100, not estimated. */
@media (min-width: 768px) and (max-width: 1199px) {
  body .elementor-location-header .elementor-nav-menu > li > a.elementor-item.elementor-item.elementor-item {
    letter-spacing: var(--mm-tracking-display);
    padding-left: var(--mm-space-1);
    padding-right: var(--mm-space-1);
  }
  .elementor-location-header > .e-con:not(.elementor-hidden-desktop) .e-con:has(> .elementor-widget-nav-menu) {
    padding-right: var(--mm-space-2);
  }
}

/* Below 1024 the seven items do not fit however tight the tracking gets — 900px
 * still wrapped. Elementor keeps showing the desktop header down to 768, so the
 * choice there is between hiding links and letting the row scroll. It scrolls:
 * every category stays reachable, and a swipeable category strip is the normal
 * pattern at that width anyway.
 *
 * `overflow-x` carries `!important` because Customizer Custom CSS sets
 * `overflow: visible !important` on `.elementor-nav-menu` to stop the old
 * dropdown being clipped. That rule can go once the Customizer block is cleaned
 * up — there are no dropdowns left in this nav to clip. */
@media (min-width: 768px) and (max-width: 1023px) {
  .elementor-location-header .elementor-nav-menu--main > .elementor-nav-menu {
    flex-wrap: nowrap;
    overflow-x: auto !important;   /* matches a Customizer !important; see above */
    overflow-y: visible;
    scrollbar-width: none;
    justify-content: flex-start;
  }
  .elementor-location-header .elementor-nav-menu--main > .elementor-nav-menu::-webkit-scrollbar {
    display: none;
  }
  .elementor-location-header .elementor-nav-menu > li {
    flex: 0 0 auto;
  }
  /* The highlight leads the row rather than trailing it. A scrolling strip
   * clips whatever is last, and the one thing that must never be half a pill
   * is the call to action — at 900px it rendered as "SHO". */
  .elementor-location-header .elementor-nav-menu > li.mm-nav-highlight {
    order: -1;
    margin-left: var(--mm-space-3);
    margin-right: var(--mm-space-2);
  }
}

@media (max-width: 849px) {
  .product-small .box-text { padding: var(--mm-space-4); }
  .single-product .product-title { font-size: var(--mm-text-2xl); }
  .woocommerce-cart-form,
  .cart_totals,
  .woocommerce-checkout-review-order,
  .woocommerce-billing-fields { padding: var(--mm-space-4); }
}



/* ---------------------------------------------------------------------------
 * 10 · Overriding Customizer Custom CSS
 * ------------------------------------------------------------------------ */
/* Each block below names the exact database rule it is beating, and by how
 * much. WordPress prints Customizer CSS on `wp_head` at priority 101, after
 * every enqueued stylesheet, so a tie loses — these have to be strictly more
 * specific.
 *
 * Delete the partner rule in wp-admin and the override here goes with it.
 * `deliverables/customizer-css-to-remove.md` in the brain repo is the list. */

/* Beats: `button.single_add_to_cart_button.button.alt { background-color: black; }`
 * Their 0,3,1 → ours 0,4,2. Without this the add-to-cart is a black button
 * with ink text on it, which is invisible. */
body.woocommerce button.single_add_to_cart_button.button.alt,
body.woocommerce-page button.single_add_to_cart_button.button.alt {
  background-color: var(--mm-color-brand);
  color: var(--mm-color-on-brand);
  border-radius: var(--mm-radius-btn);
}
body.woocommerce button.single_add_to_cart_button.button.alt:hover,
body.woocommerce-page button.single_add_to_cart_button.button.alt:hover {
  background-color: var(--mm-color-brand-deep);
  color: var(--mm-color-on-contrast);
}

/* Beats: `.cart_totals .button, button#place_order { background: black; }`
 * The ID selector is 1,0,1, so this needs an ID of its own to win. */
body .cart_totals .button,
body button#place_order,
body #place_order {
  background: var(--mm-color-brand);
  color: var(--mm-color-on-brand);
  border-radius: var(--mm-radius-btn);
}
body .cart_totals .button:hover,
body button#place_order:hover,
body #place_order:hover {
  background: var(--mm-color-brand-deep);
  color: var(--mm-color-on-contrast);
}

/* Beats: `a.button.product_type_simple.add_to_cart_button.ajax_add_to_cart
 *         { border-radius: 10px; }` — their 0,4,1 → ours 0,5,2. */
body.woocommerce a.button.add_to_cart_button.ajax_add_to_cart,
body.woocommerce-page a.button.add_to_cart_button.ajax_add_to_cart,
body a.button.product_type_simple.add_to_cart_button.ajax_add_to_cart,
body a.button.product_type_variable.add_to_cart_button {
  border-radius: var(--mm-radius-btn);
  background-color: var(--mm-color-brand);
  color: var(--mm-color-on-brand);
}

/* Beats: `.product-small { border-radius: 10px; }` and
 *        `.box-image { border-radius: 10px 10px 0 0; }`
 * The card is near-square in the design, and the image is flush inside it. */
body .product-small,
body .products .product .col-inner {
  border-radius: var(--mm-radius-card);
}
body .product-small .box-image {
  border-radius: 0;
}

/* Beats: `.mm-product-badge { border-radius: 0 !important; … }`
 * Radius is the only property they mark important, so it is the only one that
 * needs it here. Marked, and it goes when that rule does. */
body .mm-product-badge {
  border-radius: var(--mm-radius-pill) !important; /* the only !important here */
}

/* Beats: `.add-to-cart-button a { border-radius: 5px; }` */
body .add-to-cart-button a {
  border-radius: var(--mm-radius-btn);
}

/* The active product tab renders as a solid dark pill, which puts the label's
 * own dark text on a dark ground — unreadable. The design marks the active tab
 * with an amber rule under it and nothing else. */
body .woocommerce-tabs .nav-tabs > li > a,
body .woocommerce-tabs .nav > li > a,
body .product-tabs > li > a {
  background-color: transparent;
  border-radius: 0;
  color: var(--mm-color-ink-muted);
  border-bottom: var(--mm-focus-ring) solid transparent;
}
body .woocommerce-tabs .nav-tabs > li.active > a,
body .woocommerce-tabs .nav > li.active > a,
body .product-tabs > li.active > a {
  background-color: transparent;
  color: var(--mm-color-ink);
  border-bottom-color: var(--mm-color-brand);
}

/* Card titles size from the token scale wherever the card appears — the
 * related-products row was inheriting a much larger heading size. */
body .product-small .product-title,
body .product-small .woocommerce-loop-product__title,
body .products .product .product-title,
body .related .product-title,
body .up-sells .product-title {
  font-size: var(--mm-text-lg);
  line-height: var(--mm-leading-tight);
  font-weight: var(--mm-weight-regular);
}

/* The small-screen step of the same rule, and it has to live HERE rather than
 * with the other breakpoints in section 9. Both are 0,3,0, so the tie is broken
 * by document order and the block above — later in the file — was winning:
 * measured 18px at 390px, which wrapped "Psilocybin Microdose Capsules — 90mg
 * x 30" onto four lines in a two-column grid. */
@media (max-width: 549px) {
  body .product-small .product-title,
  body .product-small .woocommerce-loop-product__title,
  body .products .product .product-title { font-size: var(--mm-text-base); }
}

/* ---------------------------------------------------------------------------
 * 11 · Category content under the grid
 * ------------------------------------------------------------------------ */
/* Markup comes from plugins/mammoth-category-content, which renders on
 * `woocommerce_after_shop_loop`. The content is per-category term meta and
 * lives in the database; only the styling is here. Every block is absent when
 * its field is empty, so these rules match nothing until someone writes copy. */

.mm-cat-content {
  display: flex;
  flex-direction: column;
  gap: var(--mm-space-16);
  margin-top: var(--mm-space-16);
}

/* Trust strip */
.mm-trust {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--mm-space-6);
  list-style: none;
  margin: 0;
  padding: var(--mm-space-6);
  background-color: var(--mm-color-sand);
  border-radius: var(--mm-radius-card);
}
.mm-trust__item { display: flex; flex-direction: column; gap: var(--mm-space-1); }
.mm-trust__label {
  font-family: var(--mm-font-display);
  font-weight: var(--mm-weight-bold);
  font-size: var(--mm-text-xs);
  text-transform: uppercase;
  letter-spacing: var(--mm-tracking-wide);
  color: var(--mm-color-ink);
}
.mm-trust__detail { font-size: var(--mm-text-sm); color: var(--mm-color-ink-muted); }

/* FAQ — native <details>, no accordion library */
.mm-faq { max-width: 72ch; margin: 0 auto; width: 100%; }
.mm-faq__eyebrow {
  font-family: var(--mm-font-display);
  font-weight: var(--mm-weight-bold);
  font-size: var(--mm-text-xs);
  text-transform: uppercase;
  letter-spacing: var(--mm-tracking-wide);
  color: var(--mm-color-brand-deep);
  margin: 0 0 var(--mm-space-2);
}
.mm-faq__title {
  font-family: var(--mm-font-display);
  font-weight: var(--mm-weight-light);
  font-size: var(--mm-text-3xl);
  line-height: var(--mm-leading-tight);
  margin: 0 0 var(--mm-space-6);
}
.mm-faq__item {
  background-color: var(--mm-color-surface);
  border: var(--mm-hairline) solid var(--mm-color-border);
  border-radius: var(--mm-radius-card);
  margin-bottom: var(--mm-space-2);
  overflow: hidden;
}
.mm-faq__q {
  cursor: pointer;
  list-style: none;
  padding: var(--mm-space-4) var(--mm-space-5);
  font-family: var(--mm-font-display);
  font-weight: var(--mm-weight-bold);
  font-size: var(--mm-text-base);
  color: var(--mm-color-ink);
  display: flex;
  justify-content: space-between;
  gap: var(--mm-space-4);
  align-items: center;
}
.mm-faq__q::-webkit-details-marker { display: none; }
.mm-faq__q::after {
  content: "+";
  font-family: var(--mm-font-numeric);
  color: var(--mm-color-brand-deep);
  flex: none;
}
.mm-faq__item[open] .mm-faq__q::after { content: "\2212"; }
.mm-faq__item[open] .mm-faq__q { border-bottom: var(--mm-hairline) solid var(--mm-color-border); }
.mm-faq__a { padding: var(--mm-space-4) var(--mm-space-5); color: var(--mm-color-ink); }
.mm-faq__a p { margin: 0 0 var(--mm-space-3); }
.mm-faq__a p:last-child { margin-bottom: 0; }

/* Closing band */
.mm-cat-cta,
.mm-cat-cta p,
.mm-cat-cta li {
  color: var(--mm-color-on-contrast);
}
.mm-cat-cta {
  background-color: var(--mm-color-contrast);
  border-radius: var(--mm-radius-card);
  padding: var(--mm-space-12) var(--mm-space-8);
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--mm-space-6);
}
.mm-cat-cta__text {
  /* The global `p { color: var(--mm-color-ink) }` rule applies here too, and
   * this band is near-black — so the colour has to be stated, not inherited. */
  color: var(--mm-color-on-contrast);
  font-family: var(--mm-font-display);
  font-weight: var(--mm-weight-light);
  font-size: var(--mm-text-3xl);
  line-height: var(--mm-leading-tight);
  margin: 0;
  max-width: 24ch;
}
.mm-cat-cta__button,
.mm-cat-cta a.button.mm-cat-cta__button {
  background-color: var(--mm-color-brand);
  color: var(--mm-color-on-brand);
  border-radius: var(--mm-radius-btn);
  margin: 0;
}

@media (max-width: 849px) {
  .mm-trust { grid-template-columns: repeat(2, 1fr); }
  .mm-cat-cta__text { font-size: var(--mm-text-2xl); }
}
@media (max-width: 549px) {
  .mm-trust { grid-template-columns: 1fr; }
}

/* ---------------------------------------------------------------------------
 * 12 · The shop page header — heading, category tiles, filter pills
 * ------------------------------------------------------------------------ */
/* Markup comes from `plugins/mammoth-shop`, which renders on
 * `woocommerce_before_shop_loop` so Flatsome keeps owning the grid itself.
 *
 * The section shape is the handoff's own, used on every section of the
 * prototype: a light display heading with a wide-tracked uppercase eyebrow
 * BENEATH it — "Psilocybin Products" over "CONSIDERED", "Myths" over
 * "DEBUNKED". Here the eyebrow is the product count, so the line under the
 * heading is a fact rather than a slogan, and it takes the numeric face the
 * design system reserves for digits. */

/* The shop and category rows open with a deep top padding that existed to hold
 * empty space above a grid with no heading. Measured on /shop/: the row starts
 * at y=114 and its content at y=314 — a blank screen before anything appears.
 * Now that there IS a heading, that space is just distance.
 *
 * 80px still clears the sticky header, which is `position: fixed` and about
 * 110px tall, so content has to begin below it. It gives back 120px on the
 * shop and 80px on a category archive.
 *
 * These belong to the section 10 family — both partners live in Customizer
 * Custom CSS and should be deleted together. Beats:
 *   `.post-type-archive-product .row.category-page-row { padding-top:200px; }`
 *     — 0,3,0, and printed at wp_head priority 101, so it needs 0,3,1 to lose;
 *   `.category-page-row { padding-top:160px; }` — 0,1,0, the category archives. */
body.post-type-archive-product .row.category-page-row,
body .row.category-page-row {
  padding-top: var(--mm-space-20);
}

/* One block, not three floating fragments. The gaps were 40 / 40 / 48px, which
 * left the heading, the tiles and the filter reading as separate things that
 * happened to be near each other. */
/* The hairline is what makes this a shop header rather than three things
 * floating above a grid: it closes the block, and the grid starts under a
 * line instead of in mid-air. Same hairline that closes every card and panel
 * in the design system. */
.mm-shop-head {
  display: flex;
  flex-direction: column;
  gap: var(--mm-space-5);
  padding-bottom: var(--mm-space-5);
  border-bottom: var(--mm-hairline) solid var(--mm-color-border);
  margin-bottom: var(--mm-space-8);
}

.mm-shop-head__intro {
  display: flex;
  flex-direction: column;
  gap: var(--mm-space-2);
  max-width: var(--mm-measure, 62ch);
}

/* 3xl, the token labelled "section heading" — not 4xl, which is the 60px hero
 * display and would shout louder than anything on the page it introduces. */
.mm-shop-head__title {
  font-family: var(--mm-font-display);
  font-weight: var(--mm-weight-light);
  font-size: var(--mm-text-3xl);
  line-height: var(--mm-leading-tight);
  color: var(--mm-color-ink);
  margin: 0;
}

/* The eyebrow sits under the heading, per the handoff. */
.mm-shop-head__eyebrow {
  font-family: var(--mm-font-numeric);
  font-variant-numeric: tabular-nums;
  font-size: var(--mm-text-xs);
  text-transform: uppercase;
  letter-spacing: var(--mm-tracking-wide);
  color: var(--mm-color-ink-muted);
  margin: 0;
}

.mm-shop-head__lede {
  font-size: var(--mm-text-base);
  color: var(--mm-color-ink-muted);
  margin: 0;
}

/* The shop page's `<h1>` is here for search engines and for anyone moving
 * through the page by headings; nobody sees the word "Shop" at the top of the
 * page, which is what was asked for. The clip-rect pattern rather than
 * `display: none`, because a hidden-that-way heading is hidden from assistive
 * technology too, which would make this a deletion with extra steps.
 *
 * The two `1px` values are the canonical pattern's mechanism, not design
 * values — the box has to be non-zero for the text to stay in the
 * accessibility tree. They are not a token and should not become one. */
.mm-visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* Category tiles ------------------------------------------------------- */
/* An auto-fit grid rather than a fixed column count: the catalogue has six
 * categories today and the row should not break the day it has five or seven.
 * `1fr` in the max keeps the last row's tiles the same width as the rest
 * instead of stretching them across the gap. */
/* The `10rem` is a FALLBACK, not a design value, and it is load-bearing.
 *
 * On 2026-09-04 this shipped as `minmax(var(--mm-tile-min), 1fr)` with no
 * fallback, and the tile row rendered on staging as a single 1050px column
 * 1103px tall. Cause: `tokens.css` reaches the browser through an unversioned
 * `@import` in `style.css`, so a returning visitor kept a cached copy with no
 * `--mm-tile-min` in it, while `storefront.css` — versioned by filemtime —
 * updated immediately. An unresolved custom property inside `minmax()` makes
 * the whole `grid-template-columns` declaration invalid, and an invalid
 * template collapses the grid to one column.
 *
 * `functions.php` now enqueues tokens.css with its own filemtime, which is the
 * real fix. This fallback is the second one: a structural rule must not depend
 * on a stylesheet arriving, because when it does the failure is not a wrong
 * colour, it is a page-tall image. */
.mm-shop-tiles {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(var(--mm-tile-min, 10rem), 1fr));
  gap: var(--mm-space-4);
}

.mm-shop-tiles__item { margin: 0; }

.mm-shop-tiles__link {
  display: flex;
  flex-direction: column;
  height: 100%;
  background-color: var(--mm-color-surface);
  border-radius: var(--mm-radius-card);
  box-shadow: var(--mm-shadow-card);
  overflow: hidden;
  text-decoration: none;
  color: var(--mm-color-ink);
  transition: box-shadow var(--mm-motion-base) var(--mm-ease);
}
.mm-shop-tiles__link:hover { box-shadow: var(--mm-shadow-raised); }

/* Sand is the design system's image placeholder, so a category with no
 * thumbnail reads as an unfilled slot rather than a broken tile. */
.mm-shop-tiles__media {
  display: block;
  aspect-ratio: 1 / 1;
  background-color: var(--mm-color-sand);
  overflow: hidden;
}
.mm-shop-tiles__img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform var(--mm-motion-slow) var(--mm-ease);
}
.mm-shop-tiles__link:hover .mm-shop-tiles__img { transform: scale(var(--mm-hover-zoom)); }

.mm-shop-tiles__label {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--mm-space-3);
  padding: var(--mm-space-4) var(--mm-space-5);
}

.mm-shop-tiles__name {
  font-family: var(--mm-font-display);
  font-size: var(--mm-text-base);
  line-height: var(--mm-leading-tight);
}

.mm-shop-tiles__cta {
  font-family: var(--mm-font-display);
  font-weight: var(--mm-weight-bold);
  font-size: var(--mm-text-xs);
  text-transform: uppercase;
  letter-spacing: var(--mm-tracking-wide);
  color: var(--mm-color-brand-deep);
  flex: 0 0 auto;
}

/* Filter pills ---------------------------------------------------------- */
/* These are real links to the category archives; `assets/filter.js` upgrades
 * them to filter the grid in place. Styled as one row that scrolls rather than
 * wraps, so the grid below never shifts down by a line as the catalogue grows. */
/* `align-items: center` is not cosmetic here. A flex row defaults to `stretch`,
 * so every pill grew to the tallest one: measured 35px for the button and 49px
 * for all six links, from one row. Centring makes each chip size to its own
 * content, which is what makes the row read as a set. */
.mm-shop-filter {
  display: flex;
  align-items: center;
  /* Centred 2026-09-05 at Tyler's ask. With the heading gone the row is the
   * only thing above the grid, and a left-hugging row under a centred grid
   * looked like two different pages. `safe` keeps the first pill reachable
   * when the row is wider than the screen: plain `center` overflows equally in
   * both directions and puts the left end behind the edge with no way to
   * scroll back to it. */
  justify-content: safe center;
  flex-wrap: nowrap;
  gap: var(--mm-space-2);
  overflow-x: auto;
  scrollbar-width: none;
  padding-bottom: var(--mm-space-1);
}
.mm-shop-filter::-webkit-scrollbar { display: none; }

/* Measured before this pass: the pills rendered 52px AND 66px tall — two of
 * them wrapped to a second line — with widths from 66px to 209px. They read as
 * white balloons rather than a control. `nowrap` and a fixed line-height make
 * every chip the same height whatever its label; the padding comes down so the
 * row reads as one strip instead of seven objects. */
.mm-shop-filter__pill {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  white-space: nowrap;
  font-family: var(--mm-font-display);
  font-size: var(--mm-text-xs);
  font-weight: var(--mm-weight-regular);
  line-height: var(--mm-leading-tight);
  text-transform: uppercase;
  letter-spacing: var(--mm-tracking-wide);
  text-decoration: none;
  color: var(--mm-color-ink-muted);
  background-color: transparent;
  border: var(--mm-hairline) solid var(--mm-color-border);
  border-radius: var(--mm-radius-pill);
  padding: var(--mm-space-2) var(--mm-space-4);
  cursor: pointer;
  transition: background-color var(--mm-motion-base) var(--mm-ease),
              border-color var(--mm-motion-base) var(--mm-ease),
              color var(--mm-motion-base) var(--mm-ease);
}

.mm-shop-filter__pill:hover {
  border-color: var(--mm-color-ink);
  color: var(--mm-color-ink);
}

/* Ink on amber, never white — the same pairing as every other filled amber
 * surface on the site. */
.mm-shop-filter__pill.is-active {
  background-color: var(--mm-color-brand);
  border-color: var(--mm-color-brand);
  color: var(--mm-color-on-brand);
  font-weight: var(--mm-weight-bold);
}

/* A hidden product must not leave a grid cell behind it. Flatsome's grid items
 * carry `display:flex` from the theme, which outranks the [hidden] default. */
.shop-container .products .product[hidden],
.woocommerce .products .product[hidden] { display: none; }

/* A row that does not fill sits in the middle of the page rather than hugging
 * the left edge. Filtering to Tea leaves one card, and one card jammed into the
 * top-left corner of an empty four-column row reads as a layout that broke, not
 * as a result. Flatsome lays the grid out with flex, so this is one line.
 *
 * Full rows are unaffected — there is no free space to distribute. */
body .shop-container .products,
body .woocommerce .products {
  justify-content: center;
}

@media (max-width: 549px) {
  .mm-shop-head { gap: var(--mm-space-6); }
}

/* ---------------------------------------------------------------------------
 * 13 · The newsletter row in the footer
 * ------------------------------------------------------------------------ */
/* Tyler: "this 'claim now' button is not lined up properly."
 *
 * It is not a small nudge. Measured at 1440px on the live page:
 *
 *   field   x 683 → 1064   height 43   radius 7px
 *   button  x 954 → 1064   height 42   radius 4px
 *
 * The button sits ON TOP of the field's last 110px — the inset look is
 * intended — but it is a pixel shorter, a pixel lower, its corners disagree
 * with the field's, and it carries `margin: 0 16px 16px 0` that belongs to a
 * stacked form rather than a row. That stray bottom margin is what tips it.
 *
 * This keeps the inset design and makes it exact: same height as the field,
 * centred against it, corners that agree, and no margin. `em` for the radius so
 * it tracks the control rather than naming a pixel value that is not a token.
 *
 * FluentForms, not ours — the storefront button rules in section 2 never
 * matched `.ff-btn`. Written at 0,3,0 to clear the Customizer block. */
/* Both boxes take ONE height from a token, rather than one being told to
 * stretch to the other. Stretching was tried first and did nothing: the button
 * is not a flex child of the field's row, so `height: 100%` had no parent
 * height to resolve against. Naming the height on both is what actually makes
 * two independently positioned boxes agree.
 *
 * Measured after: 44 and 44, tops level, right edges level, corners equal. */
body .fluent_form_3 .ff-el-form-control,
body .fluent_form_3 .ff-btn-submit {
  height: var(--mm-control-height);
  min-height: var(--mm-control-height);
  box-sizing: border-box;
  border-radius: var(--mm-radius-card);
  vertical-align: middle;
}

body .fluent_form_3 .ff-btn-submit {
  margin: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  line-height: var(--mm-leading-tight);
}

/* The submit sat in a block wrapper carrying a 20px bottom margin meant for a
 * stacked form. In a single row it is just a gap under the control. */
body .fluent_form_3 .ff_submit_btn_wrapper,
body .fluent_form_3 .ff-el-group:last-child { margin-bottom: 0; }

/* §14 — the "$25 Gift" popup's close control is 15px tall
 *
 * While that popup is open it covers the whole viewport at z-index 9999, header
 * included. Every tap made while trying to shut it lands on the popup and does
 * nothing — including the taps on the hamburger. Measured on staging's own
 * markup at 390px: `document.elementFromPoint()` at the centre of the menu
 * button returns `#elementor-popup-modal-2623`, not the button. So how easily
 * that popup can be dismissed is not a nicety; it is half of why the mobile menu
 * "does nothing". The other half is the age gate, in `plugins/mammoth-age-gate/`.
 *
 * WHAT IS ACTUALLY WRONG WITH IT
 *
 * Elementor draws `.dialog-close-button` as a 15x15 anchor, absolutely
 * positioned 20px in from the dialog's top right. 15px is a third of the 44px
 * minimum, and a thumb aimed at that X misses far more often than it lands.
 *
 * Only a pseudo-element grows: the anchor keeps its own box, the X keeps its
 * size and position, and nothing on screen moves. Centring it works because the
 * anchor sits exactly where the X does — an earlier version of this block also
 * set `position: relative` on the anchor, which overrode Elementor's `absolute`,
 * dropped it back into flow where it stretched to the dialog's full 390px, and
 * so centred an invisible close target in the MIDDLE of the popup, over the
 * content, where nobody meant to close anything. Do not set `position` here; it
 * is already positioned, and that is what the pseudo-element resolves against.
 *
 * The only value named is `--mm-control-height`; its note in tokens.css already
 * says 44px is the smallest comfortable touch target. 0,3,0 to clear the
 * Customizer block. */
body .dialog-widget .dialog-close-button::after,
body .elementor-popup-modal .dialog-close-button::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: var(--mm-control-height);
  height: var(--mm-control-height);
  transform: translate(-50%, -50%);
}

/* §15 — the five category cards do not fit one phone screen
 *
 * Tyler: "condensed slightly so that all 5 product categories fit on 1 iphone
 * screen."
 *
 * Measured on staging's own markup, filtered to the elements actually on screen
 * — this block was parked twice before because both earlier measurements landed
 * on Elementor's HIDDEN desktop copy of the section, which reports h=0 at 390px
 * and makes any conclusion drawn from it fiction:
 *
 *     each card              130px
 *     space between them      60px   <- `gap` on the section's .e-con-inner
 *     five cards, four gaps  890px
 *
 *     iPhone 13/14/15  844 - 87px header = 757px   over by 133px
 *     iPhone Pro Max   932 - 93px header = 839px   over by  51px
 *     iPhone SE        667 - 85px header = 582px   over by 308px
 *
 * The 60px is the container's gap, not padding or margin on the cards, so the
 * whole of it can go without touching a card's own design: at 20px the section
 * is 730px and clears the 757px an iPhone 13/14/15 has, with room to spare.
 *
 * An iPhone SE still will not fit five 130px cards in 582px — that needs the
 * cards themselves cut to about 97px, which is a design change rather than a
 * condense, so it is not made here.
 *
 * Phones only, at 549px — the breakpoint this file already uses for a phone
 * rather than a third one invented for this block. Every iPhone in the table
 * above is 375-430px wide, so it covers all of them, and a tablet keeps the
 * 60px it has the height for. (A media query cannot read a custom property, so
 * the number is written out; that is why these breakpoints are literals
 * throughout this file.)
 *
 * `:has()` scopes this to containers that actually hold these cards, so no other
 * Elementor container on the site is touched. A browser without `:has()` support
 * matches nothing and simply keeps today's layout. */
@media (max-width: 549px) {

  body .e-con-inner:has( > .product-card ) {
    row-gap: var(--mm-space-5);
  }
}

@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; animation: none !important; }
}
